From 0b02945db5960cf09ad37336c54ef854508d1fbd Mon Sep 17 00:00:00 2001 From: Douglas Roark Date: Mon, 5 Feb 2018 17:05:32 -0800 Subject: [PATCH 1/4] Squashed 'cppForSwig/chacha20poly1305/' content from commit d7d214b git-subtree-dir: cppForSwig/chacha20poly1305 git-subtree-split: d7d214b879a65529739f2d526bf9d36c2c57128c --- .travis.yml | 43 ++++++++++ README.md | 30 +++++++ bench.c | 152 ++++++++++++++++++++++++++++++++ chacha.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++ chacha.h | 35 ++++++++ chacha.o | Bin 0 -> 7484 bytes chachapoly_aead.c | 150 ++++++++++++++++++++++++++++++++ chachapoly_aead.h | 20 +++++ poly1305.c | 198 ++++++++++++++++++++++++++++++++++++++++++ poly1305.h | 23 +++++ tests.c | 208 ++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 1074 insertions(+) create mode 100644 .travis.yml create mode 100644 README.md create mode 100644 bench.c create mode 100644 chacha.c create mode 100644 chacha.h create mode 100644 chacha.o create mode 100644 chachapoly_aead.c create mode 100644 chachapoly_aead.h create mode 100644 poly1305.c create mode 100644 poly1305.h create mode 100644 tests.c diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..fba39b020 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,43 @@ +language: c +os: + - osx + - linux + +compiler: + - clang + - gcc + - x86_64-w64-mingw32-gcc + +addons: + apt: + packages: + - valgrind + - binutils-mingw-w64 + - gcc-mingw-w64 + - wine + +before_install: + - pip install --user cpp-coveralls + - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then brew install valgrind gnu-sed --default-names; fi + +matrix: + fast_finish: + - true + exclude: + - os: osx + compiler: x86_64-w64-mingw32-gcc + +script: + - $CC -O3 poly1305.c chacha.c chachapoly_aead.c bench.c -o bench + - rm *.o + - $CC -O0 -g poly1305.c chacha.c chachapoly_aead.c tests.c -o test + - if ( [ "${TRAVIS_OS_NAME}" == "linux" ] ) && ( [ "$CC" == "gcc" ] ); then + valgrind --track-origins=yes --leak-check=full --error-exitcode=1 ./test; + ./test; + else + if ( [ "$CC" == x86_64-w64-mingw32-gcc ] ) || ( [ "$CC" == i686-w64-mingw32-gcc ] ); then + ls -la; + else + ./test; + fi + fi diff --git a/README.md b/README.md new file mode 100644 index 000000000..e77f10e59 --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +[![Build Status](https://travis-ci.org/jonasschnelli/chacha20poly1305.svg?branch=master)](https://travis-ci.org/jonasschnelli/chacha20poly1305) + +chacha20/poly1305/chacha20poly1305 openssh aead +===== + +Simple C module for chacha20, poly1305 and chacha20poly1305@openssh AEAD + +Features: +* Simple, pure C code without any dependencies. + +Performance +----------- + +- + +Build steps +----------- + +Object code: + + $ gcc -O3 -c poly1305.c chacha.c chachapoly_aead.c + +Tests: + + $ gcc -O3 poly1305.c chacha.c chachapoly_aead.c tests.c -o test + +Benchmark: + + $ gcc -O3 poly1305.c chacha.c chachapoly_aead.c bench.c -o bench + \ No newline at end of file diff --git a/bench.c b/bench.c new file mode 100644 index 000000000..a47a14f90 --- /dev/null +++ b/bench.c @@ -0,0 +1,152 @@ +#include "sys/time.h" +#include +#include + +#include "chachapoly_aead.h" +#include "poly1305.h" + +static const uint8_t testkey[32] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; + +static const uint8_t testnonce[32] = {0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07}; + +static const uint8_t testdata[12] = {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, + 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21}; + +static const uint64_t BUFFER_SIZE = 1000 * 1000; + +static const uint8_t aead_keys[64] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 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, 0x00}; + +static double gettimedouble(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_usec * 0.000001 + tv.tv_sec; +} + +static void print_number(double x) { + double y = x; + int c = 0; + if (y < 0.0) { + y = -y; + } + while (y < 100.0) { + y *= 10.0; + c++; + } + printf("%.*f", c, x); +} + +static void run_benchmark(char *name, void (*benchmark)(void *), + void (*setup)(void *), void (*teardown)(void *), + void *data, int count, int iter) { + int i; + double min = HUGE_VAL; + double sum = 0.0; + double max = 0.0; + for (i = 0; i < count; i++) { + double begin, total; + if (setup != NULL) { + setup(data); + } + begin = gettimedouble(); + benchmark(data); + total = gettimedouble() - begin; + if (teardown != NULL) { + teardown(data); + } + if (total < min) { + min = total; + } + if (total > max) { + max = total; + } + sum += total; + } + printf("%s: min ", name); + print_number(min * 1000000000.0 / iter); + printf("ns / avg "); + print_number((sum / count) * 1000000000.0 / iter); + printf("ns / max "); + print_number(max * 1000000000.0 / iter); + printf("ns\n"); +} + +static void bench_chacha_ivsetup(void *data) { + struct chacha_ctx *ctx = (struct chacha_ctx *)data; + int i; + for (i = 0; i < 50000; i++) { + chacha_ivsetup(ctx, testnonce, NULL); + } +} + +static void bench_chacha_keysetup(void *data) { + struct chacha_ctx *ctx = (struct chacha_ctx *)data; + int i; + for (i = 0; i < 50000; i++) { + chacha_keysetup(ctx, testkey, 256); + } +} + +static void bench_chacha_encrypt(void *data) { + struct chacha_ctx *ctx = (struct chacha_ctx *)data; + uint8_t scratch[16] = {0}; + int i; + for (i = 0; i < 4000000 / 16; i++) { + chacha_encrypt_bytes(ctx, scratch, scratch, 16); + } +} + +static void bench_poly1305_auth(void *data) { + struct chacha_ctx *ctx = (struct chacha_ctx *)data; + uint8_t poly1305_tag[16] = {0}; + int i; + for (i = 0; i < 4000000 / 12; i++) { + poly1305_auth(poly1305_tag, testdata, 12, testkey); + } +} + +static void bench_chacha20poly1305_init(void *data) { + struct chachapolyaead_ctx *ctx = (struct chachapolyaead_ctx *)data; + int i; + for (i = 0; i < 50000; i++) { + chacha20poly1305_init(ctx, aead_keys, 64); + } +} + +static void bench_chacha20poly1305_crypt(void *data) { + struct chachapolyaead_ctx *ctx = (struct chachapolyaead_ctx *)data; + int i; + uint32_t seqnr = 0; + + uint8_t buffer[BUFFER_SIZE + 16]; + for (i = 0; i < 30; i++) { + chacha20poly1305_crypt(ctx, seqnr, buffer, buffer, BUFFER_SIZE - 4, 4, 1); + } +} + +int main(void) { + struct chacha_ctx ctx_chacha; + struct chachapolyaead_ctx aead_ctx; + run_benchmark("chacha_ivsetup", bench_chacha_ivsetup, NULL, NULL, &ctx_chacha, + 20, 50000); + run_benchmark("chacha_keysetup", bench_chacha_keysetup, NULL, NULL, + &ctx_chacha, 20, 50000); + run_benchmark("chacha_encrypt", bench_chacha_encrypt, NULL, NULL, &ctx_chacha, + 20, 4000000); + run_benchmark("poly1305_auth", bench_poly1305_auth, NULL, NULL, &ctx_chacha, + 20, 4000000); + run_benchmark("chacha20poly1305_init", bench_chacha20poly1305_init, NULL, + NULL, &aead_ctx, 20, 4000000); + run_benchmark("chacha20poly1305_crypt 1MB", bench_chacha20poly1305_crypt, + NULL, NULL, &aead_ctx, 20, 30); + return 0; +} \ No newline at end of file diff --git a/chacha.c b/chacha.c new file mode 100644 index 000000000..0c7055b2e --- /dev/null +++ b/chacha.c @@ -0,0 +1,215 @@ +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +#include "chacha.h" + +/* $OpenBSD: chacha.c,v 1.1 2013/11/21 00:45:44 djm Exp $ */ + +typedef unsigned char u8; +typedef unsigned int u32; + +typedef struct chacha_ctx chacha_ctx; + +#define U8C(v) (v##U) +#define U32C(v) (v##U) + +#define U8V(v) ((u8)(v)&U8C(0xFF)) +#define U32V(v) ((u32)(v)&U32C(0xFFFFFFFF)) + +#define ROTL32(v, n) (U32V((v) << (n)) | ((v) >> (32 - (n)))) + +#define U8TO32_LITTLE(p) \ + (((u32)((p)[0])) | ((u32)((p)[1]) << 8) | ((u32)((p)[2]) << 16) | \ + ((u32)((p)[3]) << 24)) + +#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) + +#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); + +static const char sigma[16] = "expand 32-byte k"; +static const char tau[16] = "expand 16-byte k"; + +void chacha_keysetup(chacha_ctx *x, const u8 *k, u32 kbits) { + 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 chacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter) { + x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0); + x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4); + x->input[14] = U8TO32_LITTLE(iv + 0); + x->input[15] = U8TO32_LITTLE(iv + 4); +} + +void chacha_encrypt_bytes(chacha_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 = NULL; + u8 tmp[64]; + uint32_t 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; + } +} diff --git a/chacha.h b/chacha.h new file mode 100644 index 000000000..3105e770c --- /dev/null +++ b/chacha.h @@ -0,0 +1,35 @@ +/* $OpenBSD: chacha.h,v 1.4 2016/08/27 04:04:56 guenther Exp $ */ + +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +#ifndef CHACHA_H +#define CHACHA_H + +#include +#include + +struct chacha_ctx { + uint32_t input[16]; +}; + +#define CHACHA_MINKEYLEN 16 +#define CHACHA_NONCELEN 8 +#define CHACHA_CTRLEN 8 +#define CHACHA_STATELEN (CHACHA_NONCELEN + CHACHA_CTRLEN) +#define CHACHA_BLOCKLEN 64 + +void chacha_keysetup(struct chacha_ctx *x, const uint8_t *k, uint32_t kbits) + __attribute__((__bounded__(__minbytes__, 2, CHACHA_MINKEYLEN))); +void chacha_ivsetup(struct chacha_ctx *x, const uint8_t *iv, const uint8_t *ctr) + __attribute__((__bounded__(__minbytes__, 2, CHACHA_NONCELEN))) + __attribute__((__bounded__(__minbytes__, 3, CHACHA_CTRLEN))); +void chacha_encrypt_bytes(struct chacha_ctx *x, const uint8_t *m, uint8_t *c, + uint32_t bytes) + __attribute__((__bounded__(__buffer__, 2, 4))) + __attribute__((__bounded__(__buffer__, 3, 4))); + +#endif /* CHACHA_H */ diff --git a/chacha.o b/chacha.o new file mode 100644 index 0000000000000000000000000000000000000000..7a08d041398a1b03b64ed455e3ee1ccaf97a7dda GIT binary patch literal 7484 zcma)B-EUOK6~FcxyavNA#32iqut^MY5=d<90O2Ds3OBl{unHAKJQOVsn1J}G1MAjQ zP#M`b-Rbp}{6Hi>^2lSJc&L<$EtS&tCG_qAK(4&KR>kxK}#;6fAnjkU(iawGAco^o_;kbUUY5HiZU>`M5ZwV{CGSn zE0yZ#M3pLXRVqir<429uEE^?V$9TY&yMtgEn%aU%6y~Z_PW|T6mF9rYkN3okBY@(@ z=3LAeZi(?Oj*XnER>m*=?%bu*mCB)muD%FI&~=jk2SFc=2cJbWKa_MC53o?FjGnEW zxjb@lltr@tS$oH1yjiUdW@S7PgOx#W*3?n<(65Nf$`$y}WH9k0@x#yesk}fX;ex~T z!-Waqhxx&W&rFcyrCi4%^?jtSFGgzoi8}T;O2(fQ?yS?rCoT2)e8*o!Xsyo|t&pqF zmsnU-pBAM>yHurg_yh;L@5Vclng(Krs~B=QK`cD23%`&Bu7a|uAu3mINSoFe~Hiv zA|vEL1YuD{W!)hnS1^iQVLGxajKHoCRF9wx7rVlAWLFr0T_LDmL6Iw%i(O$lvMY?h zt`O8V>OEih3#h1Qngzj{1;H^(Ic6YPhmC%!(bx-mX{l)X0D|=a1nmPg z{4fb0Qn)Ot1AWhpH{aM{$7BBhX8i-f`Uiscj~bpQOtk9>@vK0nZ+HHm1DlJ)IpGvz( zAnS$-QzK;Ew{aWEusGq`-tcB&3gMzfRgaQmw}$>SxWdRowd$&`wJ>$JMKP#x7X)ee zHTm=wEzew}QaF;txg>_qR5+W&@Rtf_k{G^HVJ(T_ClyX7F?^)L$s~qwT%+Q%T!&{=e46WUjEYZk9ez>quelDlsQ5V7;T07h zrT^L^wC2IoH|(3jmp#kLAK`2+oMbyN(m*&%M?;cweR#IsD0ckaaA0OR=95{5lLI{6 z`g~_HJUNh}L%q>O2r}6-Zr&NUw4`y{opIO8xHCESBYPYM4}>#3Wv&m;$dt7!;J_Ta z#W?dC5bRjYI%P3MH$8E^M4^|1rf)fT`b*(xf0hGA2uCf)F~9+X#Tp1}YzNneYhs69 zMl61gm(&Ep1lxgjwu8l#MP2|MUZIzR?64ec$5J@R4wr-NKtmEv=Qw^j-Vta6;WXR9 z_2Fr;15(0)o8xdaL0kob+u05lQ^dEd2O3_$L3Uu&0dTM#kbaJX>~J~Q4$U!Z;)+t5 z$CXszx=jU02`8hmLno$=E4v;#uAKEi19C!Q*X6KwP`WvG0Q_PO8&{gci7Sd-EDYy| zPHCMVI;Bm1Kr+5U-K+;Ma&tZOnmg;E*WAlNc32L!V<{Xqt~7@eR}{Ng7|su5n#m8Y z+x&o(@GfNXTyLO&Hg_jk^X3Mnw_M~$mV@lD9Bju@IBZ;L4kxard4HwD;5ZwhlY{Fv zIUpsxDVZeaoge!vZ%wklHn%D4ui0^F;&xn~_|J~3_g6hGri`Nshr`rDs~myf{U~vJ zn3{1+U~fFc^_c|zi@09n96iYO=_H)YHIKe))R=qb0G!~K-RLaGAQmAP4{{6YW<~qB z1uix2*~TrHvB|<-Zb2HDc<$jA1XRMuRW2@bi;hREW-jjL7QM1?Q!XxX3+g)mb8#29 z97RhwOXvTs!ksm`_@br$DBtme2(9%;MJwd$k4has^xxOM(mjsg=8n)`EOTMYU0Az? z!L0(L8)$}gxUdy2Y^8-^1q4R-+YDRf!dAPmf`wtR1XdK-8W*z+WdXnD zf?s#RZ&+|M1_j(B;4LnAs|$Y9f}7zg;9dd0<$~XK!S7gbGqMFtkA3X0?JoFT7yO}2jCA}@E#Yu*Mgf_DByhp z-tU4xbip54FefahJm1M9_ou$We|qvM@FM_{pLM7-s0p{hwR+)BeG8r$YIr)BtF55M z`a(X_{)-k?6tjv}R+O@eoRG|9Rc*ARdRdmS!o#wh6&{v$VX0+V^0cXVSvpwZVIk`Y z;bB=REYn$*PTGUKEUQ@IVOh-z4@*H+OoVXYgpl7S<4C!%S)PtH>E65m)_*O zTrV4)hi;wGc^F?2M(ku+#!|vNqnB~L(Rmm*7@dc4qcCFo%QAK+d&*=&cpbIFk++4GWO`32QT9mqw_FsH98ODo5G0QIm_6q zZ%(|7ZyBA3@ol5?Fuo&<*wV9%+w{$kmvOt%c^Ka{IuGM}!iaMq%h;!HuDp!>M(1JN zVRRnG0b#`9k!2iA_)*@=_`cD375`^?$&qhUd9iM&cnFJ=sb*jg%QV8 zmT{lH`SddGH#!gFheqdN{D|L+{qYZUwCOiw$EfCgL$(V?AwL1|8?rg~4Ox_Ym8U5W z)yzw?=6kX~Q@dD&bC%BP+w^)h;hStN3^ul6=aAcrGBfi z=P}^+UFP0!u@H9TsmDI*s=YytJTr+d6D~fifsD*Lw`)k zd>OkhA6Z`2nvDL5d@TAAZ_V^4H!~!cx|tNe|5ea3QEVx8w&!PQ6ny`|$BD5=NTK%XX2CA7L}}=Gspc zM+|=XoE%iDBjZ8k)Y%dGtBhVcb@}R8wSu+0Vq4FTUcE9}9Urp|=YA`4rE;Y@a_T(6 e&sWZjoV!4u?VOg+$44%o4k}m9eSUES^Z7rhl6v(3 literal 0 HcmV?d00001 diff --git a/chachapoly_aead.c b/chachapoly_aead.c new file mode 100644 index 000000000..464808272 --- /dev/null +++ b/chachapoly_aead.c @@ -0,0 +1,150 @@ +#include "chachapoly_aead.h" + +#define __STDC_WANT_LIB_EXT1__ 1 +#include "poly1305.h" +#include + +#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && \ + !defined(__WINDOWS__) +#define __WINDOWS__ +#endif + +#if defined(__linux__) || defined(__CYGWIN__) +#include + +#elif defined(__APPLE__) +#include +#define htole32(x) OSSwapHostToLittleInt32(x) +#define le32toh(x) OSSwapLittleToHostInt32(x) +#define htole64(x) OSSwapHostToLittleInt64(x) +#define le64toh(x) OSSwapLittleToHostInt64(x) + +#elif defined(__OpenBSD__) +#include + +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) +#include +#define le32toh(x) letoh32(x) +#define le64toh(x) letoh64(x) + +#elif defined(__WINDOWS__) +#include +#include + +#if BYTE_ORDER == LITTLE_ENDIAN +#define htole32(x) (x) +#define le32toh(x) (x) + +#define htole64(x) (x) +#define le64toh(x) (x) + +#elif BYTE_ORDER == BIG_ENDIAN +#define htole32(x) __builtin_bswap32(x) +#define le32toh(x) __builtin_bswap32(x) + +#define htole64(x) __builtin_bswap64(x) +#define le64toh(x) __builtin_bswap64(x) + +#else +#error byte order not supported +#endif /* endif byteorder */ +#else + +#error platform not supported + +#endif /* endif platform */ + +#ifndef HAVE_TIMINGSAFE_BCMP + +int timingsafe_bcmp(const void *b1, const void *b2, size_t n) { + const unsigned char *p1 = b1, *p2 = b2; + int ret = 0; + + for (; n > 0; n--) + ret |= *p1++ ^ *p2++; + return (ret != 0); +} + +#endif /* TIMINGSAFE_BCMP */ + +#ifndef HAVE_MEMSET_S +void memory_cleanse(void *p, size_t n) { +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) + memset(p, 0, n); +#endif +#endif +} + +#else /* no memset_s available */ +void memory_cleanse(void *p, size_t n) { (void)memset_s(p, n, 0, n); } +#endif + +int chacha20poly1305_init(struct chachapolyaead_ctx *ctx, const uint8_t *key, + int keylen) { + if (keylen != (32 + 32)) /* 2 x 256 bit keys */ + return -1; + chacha_keysetup(&ctx->main_ctx, key, 256); + chacha_keysetup(&ctx->header_ctx, key + 32, 256); + return 0; +} + +int chacha20poly1305_crypt(struct chachapolyaead_ctx *ctx, uint32_t seqnr, + uint8_t *dest, const uint8_t *src, uint32_t len, + uint32_t aadlen, int is_encrypt) { + uint8_t seqbuf[8]; + const uint8_t one[8] = {1, 0, 0, 0, 0, 0, 0, 0}; /* NB little-endian */ + uint8_t expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; + int r = -1; + + uint64_t chacha_iv = htole64(seqnr); + memset(poly_key, 0, sizeof(poly_key)); + chacha_ivsetup(&ctx->main_ctx, (uint8_t *)&chacha_iv, NULL); + chacha_encrypt_bytes(&ctx->main_ctx, poly_key, poly_key, sizeof(poly_key)); + + if (!is_encrypt) { + const uint8_t *tag = src + aadlen + len; + + poly1305_auth(expected_tag, src, aadlen + len, poly_key); + if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) { + r = -1; + goto out; + } + } + + if (aadlen) { + chacha_ivsetup(&ctx->header_ctx, (uint8_t *)&chacha_iv, NULL); + chacha_encrypt_bytes(&ctx->header_ctx, src, dest, aadlen); + } + + /* Set Chacha's block counter to 1 */ + chacha_ivsetup(&ctx->main_ctx, (uint8_t *)&chacha_iv, one); + chacha_encrypt_bytes(&ctx->main_ctx, src + aadlen, dest + aadlen, len); + + /* If encrypting, calculate and append tag */ + if (is_encrypt) { + poly1305_auth(dest + aadlen + len, dest, aadlen + len, poly_key); + } + r = 0; +out: + memory_cleanse(expected_tag, sizeof(expected_tag)); + memory_cleanse(seqbuf, sizeof(seqbuf)); + memory_cleanse(&chacha_iv, sizeof(chacha_iv)); + memory_cleanse(poly_key, sizeof(poly_key)); + return r; +} + +int chacha20poly1305_get_length(struct chachapolyaead_ctx *ctx, + uint32_t *len_out, uint32_t seqnr, + const uint8_t *ciphertext, uint32_t len) { + uint8_t buf[4], seqbuf[8]; + + if (len < 4) + return -1; + uint64_t seqnr64 = seqnr; + seqnr64 = htole64(seqnr64); + chacha_ivsetup(&ctx->header_ctx, (uint8_t *)&seqnr64, NULL); + chacha_encrypt_bytes(&ctx->header_ctx, ciphertext, buf, 4); + *len_out = le32toh(buf[0]); + return 0; +} \ No newline at end of file diff --git a/chachapoly_aead.h b/chachapoly_aead.h new file mode 100644 index 000000000..11d05be32 --- /dev/null +++ b/chachapoly_aead.h @@ -0,0 +1,20 @@ +#ifndef CHACHA20_POLY_AEAD_H +#define CHACHA20_POLY_AEAD_H + +#include "chacha.h" + +#define CHACHA_KEYLEN 32 /* 2 x 256 bit keys */ + +struct chachapolyaead_ctx { + struct chacha_ctx main_ctx, header_ctx; +}; + +int chacha20poly1305_init(struct chachapolyaead_ctx *cpctx, const uint8_t *key, + int keylen); +int chacha20poly1305_crypt(struct chachapolyaead_ctx *ctx, uint32_t seqnr, + uint8_t *dest, const uint8_t *src, uint32_t len, + uint32_t aadlen, int is_encrypt); +int chacha20poly1305_get_length(struct chachapolyaead_ctx *ctx, + uint32_t *len_out, uint32_t seqnr, + const uint8_t *ciphertext, uint32_t len); +#endif /* CHACHA20_POLY_AEAD_H */ \ No newline at end of file diff --git a/poly1305.c b/poly1305.c new file mode 100644 index 000000000..8306d4db2 --- /dev/null +++ b/poly1305.c @@ -0,0 +1,198 @@ +/* + * Public Domain poly1305 from Andrew Moon + * poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna + */ + +/* $OpenBSD: poly1305.c,v 1.3 2013/12/19 22:57:13 djm Exp $ */ + +#include "poly1305.h" + +#define mul32x32_64(a, b) ((uint64_t)(a) * (b)) + +#define U8TO32_LE(p) \ + (((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | \ + ((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 24)) + +#define U32TO8_LE(p, v) \ + do { \ + (p)[0] = (uint8_t)((v)); \ + (p)[1] = (uint8_t)((v) >> 8); \ + (p)[2] = (uint8_t)((v) >> 16); \ + (p)[3] = (uint8_t)((v) >> 24); \ + } while (0) + +void poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, + size_t inlen, const unsigned char key[POLY1305_KEYLEN]) { + uint32_t t0, t1, t2, t3; + uint32_t h0, h1, h2, h3, h4; + uint32_t r0, r1, r2, r3, r4; + uint32_t s1, s2, s3, s4; + uint32_t b, nb; + size_t j; + uint64_t t[5]; + uint64_t f0, f1, f2, f3; + uint32_t g0, g1, g2, g3, g4; + uint64_t c; + unsigned char mp[16]; + + /* clamp key */ + t0 = U8TO32_LE(key + 0); + t1 = U8TO32_LE(key + 4); + t2 = U8TO32_LE(key + 8); + t3 = U8TO32_LE(key + 12); + + /* precompute multipliers */ + r0 = t0 & 0x3ffffff; + t0 >>= 26; + t0 |= t1 << 6; + r1 = t0 & 0x3ffff03; + t1 >>= 20; + t1 |= t2 << 12; + r2 = t1 & 0x3ffc0ff; + t2 >>= 14; + t2 |= t3 << 18; + r3 = t2 & 0x3f03fff; + t3 >>= 8; + r4 = t3 & 0x00fffff; + + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; + + /* init state */ + h0 = 0; + h1 = 0; + h2 = 0; + h3 = 0; + h4 = 0; + + /* full blocks */ + if (inlen < 16) + goto poly1305_donna_atmost15bytes; +poly1305_donna_16bytes: + m += 16; + inlen -= 16; + + t0 = U8TO32_LE(m - 16); + t1 = U8TO32_LE(m - 12); + t2 = U8TO32_LE(m - 8); + t3 = U8TO32_LE(m - 4); + + h0 += t0 & 0x3ffffff; + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; + h4 += (t3 >> 8) | (1 << 24); + +poly1305_donna_mul: + t[0] = mul32x32_64(h0, r0) + mul32x32_64(h1, s4) + mul32x32_64(h2, s3) + + mul32x32_64(h3, s2) + mul32x32_64(h4, s1); + t[1] = mul32x32_64(h0, r1) + mul32x32_64(h1, r0) + mul32x32_64(h2, s4) + + mul32x32_64(h3, s3) + mul32x32_64(h4, s2); + t[2] = mul32x32_64(h0, r2) + mul32x32_64(h1, r1) + mul32x32_64(h2, r0) + + mul32x32_64(h3, s4) + mul32x32_64(h4, s3); + t[3] = mul32x32_64(h0, r3) + mul32x32_64(h1, r2) + mul32x32_64(h2, r1) + + mul32x32_64(h3, r0) + mul32x32_64(h4, s4); + t[4] = mul32x32_64(h0, r4) + mul32x32_64(h1, r3) + mul32x32_64(h2, r2) + + mul32x32_64(h3, r1) + mul32x32_64(h4, r0); + + h0 = (uint32_t)t[0] & 0x3ffffff; + c = (t[0] >> 26); + t[1] += c; + h1 = (uint32_t)t[1] & 0x3ffffff; + b = (uint32_t)(t[1] >> 26); + t[2] += b; + h2 = (uint32_t)t[2] & 0x3ffffff; + b = (uint32_t)(t[2] >> 26); + t[3] += b; + h3 = (uint32_t)t[3] & 0x3ffffff; + b = (uint32_t)(t[3] >> 26); + t[4] += b; + h4 = (uint32_t)t[4] & 0x3ffffff; + b = (uint32_t)(t[4] >> 26); + h0 += b * 5; + + if (inlen >= 16) + goto poly1305_donna_16bytes; + +/* final bytes */ +poly1305_donna_atmost15bytes: + if (!inlen) + goto poly1305_donna_finish; + + for (j = 0; j < inlen; j++) + mp[j] = m[j]; + mp[j++] = 1; + for (; j < 16; j++) + mp[j] = 0; + inlen = 0; + + t0 = U8TO32_LE(mp + 0); + t1 = U8TO32_LE(mp + 4); + t2 = U8TO32_LE(mp + 8); + t3 = U8TO32_LE(mp + 12); + + h0 += t0 & 0x3ffffff; + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; + h4 += (t3 >> 8); + + goto poly1305_donna_mul; + +poly1305_donna_finish: + b = h0 >> 26; + h0 = h0 & 0x3ffffff; + h1 += b; + b = h1 >> 26; + h1 = h1 & 0x3ffffff; + h2 += b; + b = h2 >> 26; + h2 = h2 & 0x3ffffff; + h3 += b; + b = h3 >> 26; + h3 = h3 & 0x3ffffff; + h4 += b; + b = h4 >> 26; + h4 = h4 & 0x3ffffff; + h0 += b * 5; + b = h0 >> 26; + h0 = h0 & 0x3ffffff; + h1 += b; + + g0 = h0 + 5; + b = g0 >> 26; + g0 &= 0x3ffffff; + g1 = h1 + b; + b = g1 >> 26; + g1 &= 0x3ffffff; + g2 = h2 + b; + b = g2 >> 26; + g2 &= 0x3ffffff; + g3 = h3 + b; + b = g3 >> 26; + g3 &= 0x3ffffff; + g4 = h4 + b - (1 << 26); + + b = (g4 >> 31) - 1; + nb = ~b; + h0 = (h0 & nb) | (g0 & b); + h1 = (h1 & nb) | (g1 & b); + h2 = (h2 & nb) | (g2 & b); + h3 = (h3 & nb) | (g3 & b); + h4 = (h4 & nb) | (g4 & b); + + f0 = ((h0) | (h1 << 26)) + (uint64_t)U8TO32_LE(&key[16]); + f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)U8TO32_LE(&key[20]); + f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)U8TO32_LE(&key[24]); + f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)U8TO32_LE(&key[28]); + + U32TO8_LE(&out[0], f0); + f1 += (f0 >> 32); + U32TO8_LE(&out[4], f1); + f2 += (f1 >> 32); + U32TO8_LE(&out[8], f2); + f3 += (f2 >> 32); + U32TO8_LE(&out[12], f3); +} diff --git a/poly1305.h b/poly1305.h new file mode 100644 index 000000000..0d66ac325 --- /dev/null +++ b/poly1305.h @@ -0,0 +1,23 @@ +/* $OpenBSD: poly1305.h,v 1.4 2014/05/02 03:27:54 djm Exp $ */ + +/* + * Public Domain poly1305 from Andrew Moon + * poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna + */ + +#ifndef POLY1305_H +#define POLY1305_H + +#include +#include + +#define POLY1305_KEYLEN 32 +#define POLY1305_TAGLEN 16 + +void poly1305_auth(uint8_t out[POLY1305_TAGLEN], const uint8_t *m, size_t inlen, + const uint8_t key[POLY1305_KEYLEN]) + __attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN))) + __attribute__((__bounded__(__buffer__, 2, 3))) + __attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN))); + +#endif /* POLY1305_H */ diff --git a/tests.c b/tests.c new file mode 100644 index 000000000..322e2d609 --- /dev/null +++ b/tests.c @@ -0,0 +1,208 @@ +/********************************************************************* +* Copyright (c) 2016 Jonas Schnelli * +* Distributed under the MIT software license, see the accompanying * +* file COPYING or http://www.opensource.org/licenses/mit-license.php.* +**********************************************************************/ + +#include +#include +#include +#include + +#include "chacha.h" +#include "chachapoly_aead.h" +#include "poly1305.h" + +struct chacha20_testvector { + uint8_t key[32]; + uint8_t nonce[8]; + uint8_t resulting_keystream[512]; + int keystream_check_size; +}; + +struct poly1305_testvector { + uint8_t input[64]; + int inputlen; + uint8_t key[64]; + uint8_t resulting_tag[16]; +}; + +/* + Testvectors have been taken from the draft RFC + https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-7 +*/ + +static const struct chacha20_testvector chacha20_testvectors[] = { + {{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, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, 0x40, 0x5d, 0x6a, + 0xe5, 0x53, 0x86, 0xbd, 0x28, 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, + 0xed, 0x1a, 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7, 0xda, + 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d, 0x77, 0x24, 0xe0, 0x3f, + 0xb8, 0xd8, 0x4a, 0x37, 0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, + 0x1c, 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86}, + 64}, + {{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, 0x01}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x45, 0x40, 0xf0, 0x5a, 0x9f, 0x1f, 0xb2, 0x96, 0xd7, 0x73, 0x6e, + 0x7b, 0x20, 0x8e, 0x3c, 0x96, 0xeb, 0x4f, 0xe1, 0x83, 0x46, 0x88, + 0xd2, 0x60, 0x4f, 0x45, 0x09, 0x52, 0xed, 0x43, 0x2d, 0x41, 0xbb, + 0xe2, 0xa0, 0xb6, 0xea, 0x75, 0x66, 0xd2, 0xa5, 0xd1, 0xe7, 0xe2, + 0x0d, 0x42, 0xaf, 0x2c, 0x53, 0xd7, 0x92, 0xb1, 0xc4, 0x3f, 0xea, + 0x81, 0x7e, 0x9a, 0xd2, 0x75, 0xae, 0x54, 0x69, 0x63}, + 64}, + {{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, 0x00}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + {0xde, 0x9c, 0xba, 0x7b, 0xf3, 0xd6, 0x9e, 0xf5, 0xe7, 0x86, 0xdc, 0x63, + 0x97, 0x3f, 0x65, 0x3a, 0x0b, 0x49, 0xe0, 0x15, 0xad, 0xbf, 0xf7, 0x13, + 0x4f, 0xcb, 0x7d, 0xf1, 0x37, 0x82, 0x10, 0x31, 0xe8, 0x5a, 0x05, 0x02, + 0x78, 0xa7, 0x08, 0x45, 0x27, 0x21, 0x4f, 0x73, 0xef, 0xc7, 0xfa, 0x5b, + 0x52, 0x77, 0x06, 0x2e, 0xb7, 0xa0, 0x43, 0x3e, 0x44, 0x5f, 0x41, 0xe3}, + 60}, + {{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, 0x00}, + {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xef, 0x3f, 0xdf, 0xd6, 0xc6, 0x15, 0x78, 0xfb, 0xf5, 0xcf, 0x35, + 0xbd, 0x3d, 0xd3, 0x3b, 0x80, 0x09, 0x63, 0x16, 0x34, 0xd2, 0x1e, + 0x42, 0xac, 0x33, 0x96, 0x0b, 0xd1, 0x38, 0xe5, 0x0d, 0x32, 0x11, + 0x1e, 0x4c, 0xaf, 0x23, 0x7e, 0xe5, 0x3c, 0xa8, 0xad, 0x64, 0x26, + 0x19, 0x4a, 0x88, 0x54, 0x5d, 0xdc, 0x49, 0x7a, 0x0b, 0x46, 0x6e, + 0x7d, 0x6b, 0xbd, 0xb0, 0x04, 0x1b, 0x2f, 0x58, 0x6b}, + 64}, + {{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}, + {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, + {0xf7, 0x98, 0xa1, 0x89, 0xf1, 0x95, 0xe6, 0x69, 0x82, 0x10, 0x5f, 0xfb, + 0x64, 0x0b, 0xb7, 0x75, 0x7f, 0x57, 0x9d, 0xa3, 0x16, 0x02, 0xfc, 0x93, + 0xec, 0x01, 0xac, 0x56, 0xf8, 0x5a, 0xc3, 0xc1, 0x34, 0xa4, 0x54, 0x7b, + 0x73, 0x3b, 0x46, 0x41, 0x30, 0x42, 0xc9, 0x44, 0x00, 0x49, 0x17, 0x69, + 0x05, 0xd3, 0xbe, 0x59, 0xea, 0x1c, 0x53, 0xf1, 0x59, 0x16, 0x15, 0x5c, + 0x2b, 0xe8, 0x24, 0x1a, 0x38, 0x00, 0x8b, 0x9a, 0x26, 0xbc, 0x35, 0x94, + 0x1e, 0x24, 0x44, 0x17, 0x7c, 0x8a, 0xde, 0x66, 0x89, 0xde, 0x95, 0x26, + 0x49, 0x86, 0xd9, 0x58, 0x89, 0xfb, 0x60, 0xe8, 0x46, 0x29, 0xc9, 0xbd, + 0x9a, 0x5a, 0xcb, 0x1c, 0xc1, 0x18, 0xbe, 0x56, 0x3e, 0xb9, 0xb3, 0xa4, + 0xa4, 0x72, 0xf8, 0x2e, 0x09, 0xa7, 0xe7, 0x78, 0x49, 0x2b, 0x56, 0x2e, + 0xf7, 0x13, 0x0e, 0x88, 0xdf, 0xe0, 0x31, 0xc7, 0x9d, 0xb9, 0xd4, 0xf7, + 0xc7, 0xa8, 0x99, 0x15, 0x1b, 0x9a, 0x47, 0x50, 0x32, 0xb6, 0x3f, 0xc3, + 0x85, 0x24, 0x5f, 0xe0, 0x54, 0xe3, 0xdd, 0x5a, 0x97, 0xa5, 0xf5, 0x76, + 0xfe, 0x06, 0x40, 0x25, 0xd3, 0xce, 0x04, 0x2c, 0x56, 0x6a, 0xb2, 0xc5, + 0x07, 0xb1, 0x38, 0xdb, 0x85, 0x3e, 0x3d, 0x69, 0x59, 0x66, 0x09, 0x96, + 0x54, 0x6c, 0xc9, 0xc4, 0xa6, 0xea, 0xfd, 0xc7, 0x77, 0xc0, 0x40, 0xd7, + 0x0e, 0xaf, 0x46, 0xf7, 0x6d, 0xad, 0x39, 0x79, 0xe5, 0xc5, 0x36, 0x0c, + 0x33, 0x17, 0x16, 0x6a, 0x1c, 0x89, 0x4c, 0x94, 0xa3, 0x71, 0x87, 0x6a, + 0x94, 0xdf, 0x76, 0x28, 0xfe, 0x4e, 0xaa, 0xf2, 0xcc, 0xb2, 0x7d, 0x5a, + 0xaa, 0xe0, 0xad, 0x7a, 0xd0, 0xf9, 0xd4, 0xb6, 0xad, 0x3b, 0x54, 0x09, + 0x87, 0x46, 0xd4, 0x52, 0x4d, 0x38, 0x40, 0x7a, 0x6d, 0xeb, 0x3a, 0xb7, + 0x8f, 0xab, 0x78, 0xc9}, + 256}}; + +static const struct poly1305_testvector poly1305_testvectors[] = { + { + {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, 0x00}, + 32, + {0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x33, 0x32, 0x2d, + 0x62, 0x79, 0x74, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x50, 0x6f, 0x6c, 0x79, 0x31, 0x33, 0x30, 0x35}, + {0x49, 0xec, 0x78, 0x09, 0x0e, 0x48, 0x1e, 0xc6, 0xc2, 0x6b, 0x33, 0xb9, + 0x1c, 0xcc, 0x03, 0x07}, + }, + {{0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21}, + 12, + {0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x33, 0x32, 0x2d, + 0x62, 0x79, 0x74, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x50, 0x6f, 0x6c, 0x79, 0x31, 0x33, 0x30, 0x35}, + {0xa6, 0xf7, 0x45, 0x00, 0x8f, 0x81, 0xc9, 0x16, 0xa2, 0x0d, 0xcc, 0x74, + 0xee, 0xf2, 0xb2, 0xf0}}}; + +int main(void) { + struct chacha_ctx ctx; + uint8_t iv[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + unsigned int i = 0; + uint8_t keystream[512]; + uint8_t poly1305_tag[16]; + + /* test chacha20 */ + for (i = 0; + i < (sizeof(chacha20_testvectors) / sizeof(chacha20_testvectors[0])); + i++) { + chacha_ivsetup(&ctx, chacha20_testvectors[i].nonce, NULL); + memset(keystream, 0, 512); + chacha_keysetup(&ctx, chacha20_testvectors[i].key, 256); + chacha_encrypt_bytes(&ctx, keystream, keystream, 512); + assert(memcmp(keystream, chacha20_testvectors[i].resulting_keystream, + chacha20_testvectors[i].keystream_check_size) == 0); + } + + /* test poly1305 */ + for (i = 0; + i < (sizeof(poly1305_testvectors) / sizeof(poly1305_testvectors[0])); + i++) { + memset(poly1305_tag, 0, 16); + poly1305_auth(poly1305_tag, poly1305_testvectors[i].input, + poly1305_testvectors[i].inputlen, + poly1305_testvectors[i].key); + assert(memcmp(poly1305_tag, poly1305_testvectors[i].resulting_tag, 16) == + 0); + int i = 100; + } + + /* test chacha20poly1305 AEAD */ + struct chachapolyaead_ctx aead_ctx; + uint32_t seqnr = 100; + uint8_t aead_keys[64] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 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, 0x00}; + + uint8_t plaintext_buf[256] = { + 0xff, 0x00, 0x00, 0x00, 0xf1, 0x95, 0xe6, 0x69, 0x82, 0x10, 0x5f, 0xfb, + 0x64, 0x0b, 0xb7, 0x75, 0x7f, 0x57, 0x9d, 0xa3, 0x16, 0x02, 0xfc, 0x93, + 0xec, 0x01, 0xac, 0x56, 0xf8, 0x5a, 0xc3, 0xc1, 0x34, 0xa4, 0x54, 0x7b, + 0x73, 0x3b, 0x46, 0x41, 0x30, 0x42, 0xc9, 0x44, 0x00, 0x49, 0x17, 0x69, + 0x05, 0xd3, 0xbe, 0x59, 0xea, 0x1c, 0x53, 0xf1, 0x59, 0x16, 0x15, 0x5c, + 0x2b, 0xe8, 0x24, 0x1a, 0x38, 0x00, 0x8b, 0x9a, 0x26, 0xbc, 0x35, 0x94, + 0x1e, 0x24, 0x44, 0x17, 0x7c, 0x8a, 0xde, 0x66, 0x89, 0xde, 0x95, 0x26, + 0x49, 0x86, 0xd9, 0x58, 0x89, 0xfb, 0x60, 0xe8, 0x46, 0x29, 0xc9, 0xbd, + 0x9a, 0x5a, 0xcb, 0x1c, 0xc1, 0x18, 0xbe, 0x56, 0x3e, 0xb9, 0xb3, 0xa4, + 0xa4, 0x72, 0xf8, 0x2e, 0x09, 0xa7, 0xe7, 0x78, 0x49, 0x2b, 0x56, 0x2e, + 0xf7, 0x13, 0x0e, 0x88, 0xdf, 0xe0, 0x31, 0xc7, 0x9d, 0xb9, 0xd4, 0xf7, + 0xc7, 0xa8, 0x99, 0x15, 0x1b, 0x9a, 0x47, 0x50, 0x32, 0xb6, 0x3f, 0xc3, + 0x85, 0x24, 0x5f, 0xe0, 0x54, 0xe3, 0xdd, 0x5a, 0x97, 0xa5, 0xf5, 0x76, + 0xfe, 0x06, 0x40, 0x25, 0xd3, 0xce, 0x04, 0x2c, 0x56, 0x6a, 0xb2, 0xc5, + 0x07, 0xb1, 0x38, 0xdb, 0x85, 0x3e, 0x3d, 0x69, 0x59, 0x66, 0x09, 0x96, + 0x54, 0x6c, 0xc9, 0xc4, 0xa6, 0xea, 0xfd, 0xc7, 0x77, 0xc0, 0x40, 0xd7, + 0x0e, 0xaf, 0x46, 0xf7, 0x6d, 0xad, 0x39, 0x79, 0xe5, 0xc5, 0x36, 0x0c, + 0x33, 0x17, 0x16, 0x6a, 0x1c, 0x89, 0x4c, 0x94, 0xa3, 0x71, 0x87, 0x6a, + 0x94, 0xdf, 0x76, 0x28, 0xfe, 0x4e, 0xaa, 0xf2, 0xcc, 0xb2, 0x7d, 0x5a, + 0xaa, 0xe0, 0xad, 0x7a, 0xd0, 0xf9, 0xd4, 0xb6, 0xad, 0x3b, 0x54, 0x09, + 0x87, 0x46, 0xd4, 0x52, 0x4d, 0x38, 0x40, 0x7a, 0x6d, 0xeb, 0x3a, 0xb7, + 0x8f, 0xab, 0x78, 0xc9}; + + uint8_t ciphertext_buf[300]; + uint8_t plaintext_buf_new[256]; + memset(ciphertext_buf, 0, 300); + memset(plaintext_buf_new, 0, 256); + chacha20poly1305_init(&aead_ctx, aead_keys, 64); + assert((uint32_t)plaintext_buf[0] == 255); + chacha20poly1305_crypt(&aead_ctx, seqnr, ciphertext_buf, plaintext_buf, 252, + 4, 1); + uint32_t out_len = 0; + chacha20poly1305_get_length(&aead_ctx, &out_len, seqnr, ciphertext_buf, 4); + assert(out_len == 255); + chacha20poly1305_crypt(&aead_ctx, seqnr, plaintext_buf_new, ciphertext_buf, + 252, 4, 0); + assert(memcmp(plaintext_buf, plaintext_buf_new, 252) == 0); +} From f314fe87a4a1dbe1d95fb5b42c5b627f10493f5d Mon Sep 17 00:00:00 2001 From: Douglas Roark Date: Wed, 7 Feb 2018 21:54:48 -0800 Subject: [PATCH 2/4] Build ChaCha20Poly1305 library - Integrate Jona Schnelli's ChaCha20Poly1305 library into our code. - Miscellaneous build system cleanup. --- configure.ac | 36 +++++++++++++--------- cppForSwig/Makefile.am | 69 +++++++++++++++++++++++++----------------- 2 files changed, 64 insertions(+), 41 deletions(-) diff --git a/configure.ac b/configure.ac index b89c10f72..2ae8b97cd 100644 --- a/configure.ac +++ b/configure.ac @@ -16,9 +16,15 @@ AS_IF([test "$CXXFLAGS" = "-g -O2"] ,[AC_SUBST(CXXFLAGS, [ ])]) #build tests arg AC_ARG_ENABLE([tests], - AC_HELP_STRING([--enable-tests], - [build with test suites @<:@default=no@:>@]), - [want_tests="$enableval"], [want_tests=no]) + AC_HELP_STRING([--enable-tests], + [build with test suites @<:@default=no@:>@]), + [want_tests="$enableval"], [want_tests=no]) + +#build benchmarks +AC_ARG_ENABLE([benchmarks], + AC_HELP_STRING([--enable-benchmarks], + [build with benchmark suites @<:@default=no@:>@]), + [want_benchmarks=$enableval], [want_benchmarks=no]) #build debug arg AC_ARG_ENABLE([debug], @@ -166,6 +172,7 @@ AC_CONFIG_FILES(Makefile cppForSwig/Makefile cppForSwig/lmdb/Makefile) +AM_CONDITIONAL([BUILD_BENCH], [test x$want_benchmarks = xyes]) AM_CONDITIONAL([BUILD_TESTS], [test "x$want_tests" = "xyes"]) if test "x$want_tests" = "xyes"; then AC_CONFIG_FILES(cppForSwig/gtest/Makefile) @@ -173,14 +180,15 @@ fi AC_OUTPUT -echo " CC = $CC" -echo " CFLAGS = $CFLAGS" -echo " CPP = $CPP" -echo " CPPFLAGS = $CPPFLAGS" -echo " CXX = $CXX" -echo " CXXFLAGS = $CXXFLAGS" -echo " LDFLAGS = $LDFLAGS" -echo " LD = $LD" -echo " with tests = $want_tests" -echo " debug symbols = $want_debug" -echo " with GUI = $with_gui" +echo " CC = $CC" +echo " CFLAGS = $CFLAGS" +echo " CPP = $CPP" +echo " CPPFLAGS = $CPPFLAGS" +echo " CXX = $CXX" +echo " CXXFLAGS = $CXXFLAGS" +echo " LDFLAGS = $LDFLAGS" +echo " LD = $LD" +echo " with tests = $want_tests" +echo " with benchmarks = $want_benchmarks" +echo " debug symbols = $want_debug" +echo " with GUI = $with_gui" diff --git a/cppForSwig/Makefile.am b/cppForSwig/Makefile.am index 63080921a..dffd46d37 100644 --- a/cppForSwig/Makefile.am +++ b/cppForSwig/Makefile.am @@ -1,6 +1,19 @@ +bin_PROGRAMS = +noinst_PROGRAMS = +TESTS = +BENCHMARKS = +lib_LTLIBRARIES = MAYBE_BUILD = + if BUILD_TESTS MAYBE_BUILD += gtest +noinst_PROGRAMS += chacha20poly1305/chacha20poly1305test +TESTS += chacha20poly1305/chacha20poly1305test +endif + +if BUILD_BENCH +noinst_PROGRAMS += chacha20poly1305/chacha20poly1305bench +BENCHMARKS += chacha20poly1305/chacha20poly1305bench endif DIST_SUBDIRS = lmdb fcgi cryptopp @@ -20,22 +33,7 @@ if HAVE_CLANG SWIG_FLAGS += -D__CLANG__ endif -INCLUDE_FILES = UniversalTimer.h BinaryData.h lmdb_wrapper.h \ - BtcUtils.h DBUtils.h BlockObj.h BlockUtils.h EncryptionUtils.h \ - BtcWallet.h LedgerEntry.h ScrAddrObj.h Blockchain.h \ - BDM_mainthread.h BDM_supportClasses.h \ - BlockDataViewer.h HistoryPager.h Progress.h \ - txio.h TxClasses.h StoredBlockObj.h \ - DatabaseBuilder.h BlockchainScanner.h BlockDataMap.h \ - DataObject.h BitcoinP2p.h BDM_Server.h BDM_seder.h SocketObject.h \ - FcgiMessage.h BlockDataManagerConfig.h \ - Transactions.h Script.h Signer.h nodeRPC.h JSON_codec.h \ - ReentrantLock.h StringSockets.h log.h OS_TranslatePath.h \ - TransactionBatch.h BlockchainScanner_Super.h SigHashEnum.h TxEvalState.h \ - Accounts.h Addresses.h AssetEncryption.h Assets.h \ - DecryptedDataContainer.h DerviationScheme.h \ - bech32/ref/c++/bech32.h bech32/ref/c++/segwit_addr.h \ - SshParser.h +INCLUDE_FILES = -I. -Ibech32/ref/c++ -Ichacha20poly1305 DB_SOURCE_FILES = UniversalTimer.cpp BinaryData.cpp lmdb_wrapper.cpp \ BtcUtils.cpp DBUtils.cpp BlockObj.cpp BlockUtils.cpp EncryptionUtils.cpp \ @@ -64,16 +62,18 @@ CPPBLOCKUTILS_SOURCE_FILES = UniversalTimer.cpp BinaryData.cpp \ DecryptedDataContainer.cpp DerivationScheme.cpp \ bech32/ref/c++/bech32.cpp bech32/ref/c++/segwit_addr.cpp -#ArmoryDB -noinst_PROGRAMS = ArmoryDB +CHACHA20POLY1305_SOURCE_FILES = chacha20poly1305/poly1305.c \ + chacha20poly1305/chacha.c chacha20poly1305/chachapoly_aead.c -ArmoryDB_SOURCES = $(INCLUDE_FILES) \ - $(DB_SOURCE_FILES) +#ArmoryDB +bin_PROGRAMS += ArmoryDB +ArmoryDB_SOURCES = $(DB_SOURCE_FILES) ArmoryDB_CXXFLAGS = $(AM_CXXFLAGS) -Ilmdb \ -Icryptopp \ -Ifcgi -Ifcgi/include \ -D__STDC_LIMIT_MACROS +ArmoryDB_CPPFLAGS = $(AM_CPPFLAGS) $(INCLUDE_FILES) ArmoryDB_LDADD = -Llmdb -llmdb \ -Lcryptopp -lcryptopp \ @@ -84,23 +84,38 @@ ArmoryDB_LDFLAGS = -static $(LDFLAGS) #libCppBlockUtils if HAVE_GUI -lib_LTLIBRARIES = libCppBlockUtils.la - -libCppBlockUtils_la_SOURCES = $(INCLUDE_FILES) \ - $(CPPBLOCKUTILS_SOURCE_FILES) \ - CppBlockUtils_wrap.cxx +lib_LTLIBRARIES += libCppBlockUtils.la +libCppBlockUtils_la_SOURCES = $(CPPBLOCKUTILS_SOURCE_FILES) \ + CppBlockUtils_wrap.cxx +libCppBlockUtils_la_CPPFLAGS = $(AM_CPPFLAGS) $(INCLUDE_FILES) libCppBlockUtils_la_CXXFLAGS = $(AM_CXXFLAGS) -Ilmdb \ -Icryptopp \ $(AX_SWIG_PYTHON_CPPFLAGS) \ $(EXTRA_PYTHON_INCLUDES) \ -D__STDC_LIMIT_MACROS - libCppBlockUtils_la_LIBADD = -Llmdb -llmdb \ ./cryptopp/libcryptopp.la \ -lpthread - libCppBlockUtils_la_LDFLAGS = $(LDFLAGS) +# ChaCha20Poly1305 library +lib_LTLIBRARIES += libChaCha20Poly1305.la +libChaCha20Poly1305_la_SOURCES = $(CHACHA20POLY1305_SOURCE_FILES) +libChaCha20Poly1305_la_CPPFLAGS = $(AM_CPPFLAGS) $(INCLUDE_FILES) +libChaCha20Poly1305_la_CFLAGS = $(AM_CFLAGS) + +if BUILD_TESTS +chacha20poly1305test_SOURCE_FILES = $(CHACHA20POLY1305_SOURCE_FILES) chacha20poly1305/test.c +chacha20poly1305test_CPPFLAGS = $(AM_CPPFLAGS) $(INCLUDE_FILES) +chacha20poly1305test_CFLAGS = $(AM_CFLAGS) +endif + +if BUILD_BENCH +chacha20poly1305bench_SOURCE_FILES = $(CHACHA20POLY1305_SOURCE_FILES) chacha20poly1305/bench.c +chacha20poly1305bench_CPPFLAGS = $(AM_CPPFLAGS) $(INCLUDE_FILES) +chacha20poly1305bench_CFLAGS = $(AM_CFLAGS) +endif + if BUILD_DARWIN libCppBlockUtils_la_LDFLAGS += -Wl,-rpath,@executable_path/ -Wl,-rpath,@loader_path/ endif From ff613c3a9edc93000c63d39f93f192c8e663291f Mon Sep 17 00:00:00 2001 From: Douglas Roark Date: Mon, 12 Feb 2018 15:07:54 -0800 Subject: [PATCH 3/4] Squashed 'cppForSwig/libbtc/' content from commit a8506a0 git-subtree-dir: cppForSwig/libbtc git-subtree-split: a8506a03718257a7e6797bac4eafee0f60abb22b --- .clang-format | 51 + .gitignore | 40 + .travis.yml | 95 + Makefile.am | 193 + README.md | 115 + autogen.sh | 3 + build-aux/m4/ax_check_link_flag.m4 | 71 + build-aux/m4/ax_check_openssl.m4 | 124 + configure.ac | 159 + contrib/format.sh | 4 + contrib/github-merge.sh | 185 + depends/.gitignore | 10 + depends/Makefile | 181 + depends/builders/darwin.mk | 22 + depends/builders/default.mk | 20 + depends/builders/linux.mk | 2 + depends/config.guess | 1462 ++++++ depends/config.site.in | 99 + depends/config.sub | 1828 +++++++ depends/funcs.mk | 245 + depends/hosts/darwin.mk | 17 + depends/hosts/default.mk | 26 + depends/hosts/linux.mk | 31 + depends/hosts/mingw32.mk | 10 + depends/packages/libevent.mk | 30 + depends/packages/native_ccache.mk | 25 + depends/packages/native_cctools.mk | 65 + depends/packages/packages.mk | 12 + depends/patches/libevent/reuseaddr.patch | 21 + include/btc/aes256_cbc.h | 44 + include/btc/base58.h | 46 + include/btc/bip32.h | 81 + include/btc/block.h | 63 + include/btc/blockchain.h | 51 + include/btc/btc.h | 80 + include/btc/buffer.h | 57 + include/btc/chainparams.h | 75 + include/btc/checkpoints.h | 39 + include/btc/cstr.h | 66 + include/btc/ctaes.h | 49 + include/btc/ecc.h | 84 + include/btc/ecc_key.h | 91 + include/btc/hash.h | 75 + include/btc/headersdb.h | 81 + include/btc/headersdb_file.h | 94 + include/btc/memory.h | 61 + include/btc/net.h | 171 + include/btc/netspv.h | 97 + include/btc/portable_endian.h | 118 + include/btc/protocol.h | 186 + include/btc/random.h | 56 + include/btc/script.h | 248 + include/btc/segwit_addr.h | 101 + include/btc/serialize.h | 78 + include/btc/sha2.h | 79 + include/btc/tool.h | 57 + include/btc/tx.h | 133 + include/btc/utils.h | 85 + include/btc/vector.h | 64 + include/btc/wallet.h | 143 + libbtc.pc | 12 + libbtc.pc.in | 12 + m4/macros/with.m4 | 24 + rpctest/.gitignore | 2 + rpctest/spvtool.py | 68 + rpctest/test_framework/__init__.py | 0 rpctest/test_framework/address.py | 69 + rpctest/test_framework/authproxy.py | 190 + rpctest/test_framework/bignum.py | 97 + rpctest/test_framework/blockstore.py | 170 + rpctest/test_framework/blocktools.py | 105 + rpctest/test_framework/comptool.py | 410 ++ rpctest/test_framework/coverage.py | 103 + rpctest/test_framework/key.py | 232 + rpctest/test_framework/mininode.py | 1812 +++++++ rpctest/test_framework/netutil.py | 156 + rpctest/test_framework/script.py | 939 ++++ rpctest/test_framework/siphash.py | 63 + rpctest/test_framework/socks5.py | 159 + rpctest/test_framework/test_framework.py | 254 + rpctest/test_framework/util.py | 670 +++ src/aes256_cbc.c | 89 + src/base58.c | 245 + src/bip32.c | 385 ++ src/block.c | 110 + src/buffer.c | 51 + src/chainparams.c | 91 + src/commontools.c | 153 + src/cstr.c | 213 + src/ctaes.c | 556 ++ src/ecc_key.c | 244 + src/ecc_libsecp256k1.c | 203 + src/headersdb.c | 26 + src/headersdb_file.c | 356 ++ src/logdb/include/logdb/logdb.h | 67 + src/logdb/include/logdb/logdb_base.h | 71 + src/logdb/include/logdb/logdb_core.h | 155 + src/logdb/include/logdb/logdb_memdb_llist.h | 83 + src/logdb/include/logdb/logdb_memdb_rbtree.h | 80 + src/logdb/include/logdb/logdb_rec.h | 86 + src/logdb/include/logdb/red_black_tree.h | 94 + src/logdb/logdb_core.c | 513 ++ src/logdb/logdb_memdb_llist.c | 112 + src/logdb/logdb_memdb_rbtree.c | 131 + src/logdb/logdb_rec.c | 178 + src/logdb/red_black_tree.c | 646 +++ src/logdb/test/logdb_tests.c | 484 ++ src/logdb/test/logdb_tests_sample.h | 171 + src/logdb/test/tests_red_black_tree.c | 86 + src/memory.c | 129 + src/net.c | 603 +++ src/netspv.c | 547 ++ src/protocol.c | 288 ++ src/random.c | 107 + src/ripemd160.c | 337 ++ src/ripemd160.h | 32 + src/script.c | 493 ++ src/secp256k1/.gitignore | 48 + src/secp256k1/.travis.yml | 70 + src/secp256k1/COPYING | 19 + src/secp256k1/Makefile.am | 163 + src/secp256k1/README.md | 61 + src/secp256k1/TODO | 3 + src/secp256k1/autogen.sh | 3 + .../build-aux/m4/ax_jni_include_dir.m4 | 140 + .../build-aux/m4/ax_prog_cc_for_build.m4 | 125 + src/secp256k1/build-aux/m4/bitcoin_secp.m4 | 65 + src/secp256k1/configure.ac | 490 ++ src/secp256k1/contrib/lax_der_parsing.c | 150 + src/secp256k1/contrib/lax_der_parsing.h | 91 + .../contrib/lax_der_privatekey_parsing.c | 113 + .../contrib/lax_der_privatekey_parsing.h | 90 + src/secp256k1/include/secp256k1.h | 583 +++ src/secp256k1/include/secp256k1_ecdh.h | 31 + src/secp256k1/include/secp256k1_recovery.h | 110 + src/secp256k1/include/secp256k1_schnorr.h | 173 + src/secp256k1/libsecp256k1.pc.in | 13 + src/secp256k1/obj/.gitignore | 0 src/secp256k1/sage/group_prover.sage | 322 ++ src/secp256k1/sage/secp256k1.sage | 306 ++ src/secp256k1/sage/weierstrass_prover.sage | 264 + src/secp256k1/src/asm/field_10x26_arm.s | 919 ++++ src/secp256k1/src/basic-config.h | 32 + src/secp256k1/src/bench.h | 66 + src/secp256k1/src/bench_ecdh.c | 54 + src/secp256k1/src/bench_internal.c | 382 ++ src/secp256k1/src/bench_recover.c | 60 + src/secp256k1/src/bench_schnorr_verify.c | 73 + src/secp256k1/src/bench_sign.c | 56 + src/secp256k1/src/bench_verify.c | 112 + src/secp256k1/src/ecdsa.h | 21 + src/secp256k1/src/ecdsa_impl.h | 303 ++ src/secp256k1/src/eckey.h | 25 + src/secp256k1/src/eckey_impl.h | 99 + src/secp256k1/src/ecmult.h | 31 + src/secp256k1/src/ecmult_const.h | 15 + src/secp256k1/src/ecmult_const_impl.h | 239 + src/secp256k1/src/ecmult_gen.h | 43 + src/secp256k1/src/ecmult_gen_impl.h | 210 + src/secp256k1/src/ecmult_impl.h | 391 ++ src/secp256k1/src/field.h | 127 + src/secp256k1/src/field_10x26.h | 47 + src/secp256k1/src/field_10x26_impl.h | 1144 +++++ src/secp256k1/src/field_5x52.h | 47 + src/secp256k1/src/field_5x52_asm_impl.h | 502 ++ src/secp256k1/src/field_5x52_impl.h | 455 ++ src/secp256k1/src/field_5x52_int128_impl.h | 277 + src/secp256k1/src/field_impl.h | 315 ++ src/secp256k1/src/gen_context.c | 74 + src/secp256k1/src/group.h | 144 + src/secp256k1/src/group_impl.h | 650 +++ src/secp256k1/src/hash.h | 41 + src/secp256k1/src/hash_impl.h | 281 + .../src/java/org/bitcoin/NativeSecp256k1.java | 478 ++ .../java/org/bitcoin/NativeSecp256k1Test.java | 247 + .../java/org/bitcoin/NativeSecp256k1Util.java | 45 + .../java/org/bitcoin/Secp256k1Context.java | 51 + .../src/java/org_bitcoin_NativeSecp256k1.c | 411 ++ .../src/java/org_bitcoin_NativeSecp256k1.h | 127 + .../src/java/org_bitcoin_Secp256k1Context.c | 15 + .../src/java/org_bitcoin_Secp256k1Context.h | 22 + .../src/modules/ecdh/Makefile.am.include | 8 + src/secp256k1/src/modules/ecdh/main_impl.h | 54 + src/secp256k1/src/modules/ecdh/tests_impl.h | 75 + .../src/modules/recovery/Makefile.am.include | 8 + .../src/modules/recovery/main_impl.h | 193 + .../src/modules/recovery/tests_impl.h | 250 + .../src/modules/schnorr/Makefile.am.include | 10 + src/secp256k1/src/modules/schnorr/main_impl.h | 164 + src/secp256k1/src/modules/schnorr/schnorr.h | 20 + .../src/modules/schnorr/schnorr_impl.h | 207 + .../src/modules/schnorr/tests_impl.h | 175 + src/secp256k1/src/num.h | 74 + src/secp256k1/src/num_gmp.h | 20 + src/secp256k1/src/num_gmp_impl.h | 288 ++ src/secp256k1/src/num_impl.h | 24 + src/secp256k1/src/scalar.h | 104 + src/secp256k1/src/scalar_4x64.h | 19 + src/secp256k1/src/scalar_4x64_impl.h | 949 ++++ src/secp256k1/src/scalar_8x32.h | 19 + src/secp256k1/src/scalar_8x32_impl.h | 721 +++ src/secp256k1/src/scalar_impl.h | 335 ++ src/secp256k1/src/secp256k1.c | 561 ++ src/secp256k1/src/testrand.h | 38 + src/secp256k1/src/testrand_impl.h | 110 + src/secp256k1/src/tests.c | 4525 +++++++++++++++++ src/secp256k1/src/util.h | 110 + src/segwit_addr.c | 191 + src/serialize.c | 356 ++ src/sha2.c | 1024 ++++ src/tools/bitcoin-send-tx.c | 359 ++ src/tools/bitcoin-spv.c | 226 + src/tools/bitcointool.c | 438 ++ src/tx.c | 916 ++++ src/utils.c | 302 ++ src/vector.c | 185 + src/wallet.c | 752 +++ test/aes_tests.c | 602 +++ test/base58check_tests.c | 174 + test/bip32_tests.c | 249 + test/block_tests.c | 153 + test/buffer_tests.c | 26 + test/cstr_tests.c | 94 + test/ecc_tests.c | 64 + test/eckey_tests.c | 107 + test/hash_tests.c | 28 + test/memory_tests.c | 62 + test/net_tests.c | 201 + test/netspv_tests.c | 40 + test/protocol_tests.c | 133 + test/random_tests.c | 49 + test/serialize_tests.c | 89 + test/sha2_tests.c | 506 ++ test/tool_tests.c | 66 + test/tx_tests.c | 1365 +++++ test/unittester.c | 133 + test/utest.h | 229 + test/utils_tests.c | 56 + test/vector_tests.c | 109 + test/wallet_tests.c | 168 + tooltests.py | 62 + 241 files changed, 52300 insertions(+) create mode 100644 .clang-format create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 Makefile.am create mode 100644 README.md create mode 100755 autogen.sh create mode 100644 build-aux/m4/ax_check_link_flag.m4 create mode 100755 build-aux/m4/ax_check_openssl.m4 create mode 100644 configure.ac create mode 100755 contrib/format.sh create mode 100755 contrib/github-merge.sh create mode 100644 depends/.gitignore create mode 100644 depends/Makefile create mode 100644 depends/builders/darwin.mk create mode 100644 depends/builders/default.mk create mode 100644 depends/builders/linux.mk create mode 100755 depends/config.guess create mode 100644 depends/config.site.in create mode 100755 depends/config.sub create mode 100644 depends/funcs.mk create mode 100644 depends/hosts/darwin.mk create mode 100644 depends/hosts/default.mk create mode 100644 depends/hosts/linux.mk create mode 100644 depends/hosts/mingw32.mk create mode 100644 depends/packages/libevent.mk create mode 100644 depends/packages/native_ccache.mk create mode 100644 depends/packages/native_cctools.mk create mode 100644 depends/packages/packages.mk create mode 100644 depends/patches/libevent/reuseaddr.patch create mode 100644 include/btc/aes256_cbc.h create mode 100644 include/btc/base58.h create mode 100644 include/btc/bip32.h create mode 100644 include/btc/block.h create mode 100644 include/btc/blockchain.h create mode 100644 include/btc/btc.h create mode 100644 include/btc/buffer.h create mode 100644 include/btc/chainparams.h create mode 100644 include/btc/checkpoints.h create mode 100644 include/btc/cstr.h create mode 100644 include/btc/ctaes.h create mode 100644 include/btc/ecc.h create mode 100644 include/btc/ecc_key.h create mode 100644 include/btc/hash.h create mode 100644 include/btc/headersdb.h create mode 100644 include/btc/headersdb_file.h create mode 100644 include/btc/memory.h create mode 100644 include/btc/net.h create mode 100644 include/btc/netspv.h create mode 100644 include/btc/portable_endian.h create mode 100644 include/btc/protocol.h create mode 100644 include/btc/random.h create mode 100644 include/btc/script.h create mode 100644 include/btc/segwit_addr.h create mode 100644 include/btc/serialize.h create mode 100644 include/btc/sha2.h create mode 100644 include/btc/tool.h create mode 100644 include/btc/tx.h create mode 100644 include/btc/utils.h create mode 100644 include/btc/vector.h create mode 100644 include/btc/wallet.h create mode 100644 libbtc.pc create mode 100644 libbtc.pc.in create mode 100644 m4/macros/with.m4 create mode 100644 rpctest/.gitignore create mode 100755 rpctest/spvtool.py create mode 100644 rpctest/test_framework/__init__.py create mode 100644 rpctest/test_framework/address.py create mode 100644 rpctest/test_framework/authproxy.py create mode 100644 rpctest/test_framework/bignum.py create mode 100644 rpctest/test_framework/blockstore.py create mode 100644 rpctest/test_framework/blocktools.py create mode 100755 rpctest/test_framework/comptool.py create mode 100644 rpctest/test_framework/coverage.py create mode 100644 rpctest/test_framework/key.py create mode 100755 rpctest/test_framework/mininode.py create mode 100644 rpctest/test_framework/netutil.py create mode 100644 rpctest/test_framework/script.py create mode 100644 rpctest/test_framework/siphash.py create mode 100644 rpctest/test_framework/socks5.py create mode 100755 rpctest/test_framework/test_framework.py create mode 100644 rpctest/test_framework/util.py create mode 100644 src/aes256_cbc.c create mode 100644 src/base58.c create mode 100644 src/bip32.c create mode 100644 src/block.c create mode 100644 src/buffer.c create mode 100644 src/chainparams.c create mode 100644 src/commontools.c create mode 100644 src/cstr.c create mode 100644 src/ctaes.c create mode 100644 src/ecc_key.c create mode 100644 src/ecc_libsecp256k1.c create mode 100644 src/headersdb.c create mode 100644 src/headersdb_file.c create mode 100644 src/logdb/include/logdb/logdb.h create mode 100644 src/logdb/include/logdb/logdb_base.h create mode 100644 src/logdb/include/logdb/logdb_core.h create mode 100644 src/logdb/include/logdb/logdb_memdb_llist.h create mode 100644 src/logdb/include/logdb/logdb_memdb_rbtree.h create mode 100644 src/logdb/include/logdb/logdb_rec.h create mode 100644 src/logdb/include/logdb/red_black_tree.h create mode 100644 src/logdb/logdb_core.c create mode 100644 src/logdb/logdb_memdb_llist.c create mode 100644 src/logdb/logdb_memdb_rbtree.c create mode 100644 src/logdb/logdb_rec.c create mode 100644 src/logdb/red_black_tree.c create mode 100644 src/logdb/test/logdb_tests.c create mode 100644 src/logdb/test/logdb_tests_sample.h create mode 100644 src/logdb/test/tests_red_black_tree.c create mode 100644 src/memory.c create mode 100644 src/net.c create mode 100644 src/netspv.c create mode 100644 src/protocol.c create mode 100644 src/random.c create mode 100644 src/ripemd160.c create mode 100644 src/ripemd160.h create mode 100644 src/script.c create mode 100644 src/secp256k1/.gitignore create mode 100644 src/secp256k1/.travis.yml create mode 100644 src/secp256k1/COPYING create mode 100644 src/secp256k1/Makefile.am create mode 100644 src/secp256k1/README.md create mode 100644 src/secp256k1/TODO create mode 100755 src/secp256k1/autogen.sh create mode 100644 src/secp256k1/build-aux/m4/ax_jni_include_dir.m4 create mode 100644 src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 create mode 100644 src/secp256k1/build-aux/m4/bitcoin_secp.m4 create mode 100644 src/secp256k1/configure.ac create mode 100644 src/secp256k1/contrib/lax_der_parsing.c create mode 100644 src/secp256k1/contrib/lax_der_parsing.h create mode 100644 src/secp256k1/contrib/lax_der_privatekey_parsing.c create mode 100644 src/secp256k1/contrib/lax_der_privatekey_parsing.h create mode 100644 src/secp256k1/include/secp256k1.h create mode 100644 src/secp256k1/include/secp256k1_ecdh.h create mode 100644 src/secp256k1/include/secp256k1_recovery.h create mode 100644 src/secp256k1/include/secp256k1_schnorr.h create mode 100644 src/secp256k1/libsecp256k1.pc.in create mode 100644 src/secp256k1/obj/.gitignore create mode 100644 src/secp256k1/sage/group_prover.sage create mode 100644 src/secp256k1/sage/secp256k1.sage create mode 100644 src/secp256k1/sage/weierstrass_prover.sage create mode 100644 src/secp256k1/src/asm/field_10x26_arm.s create mode 100644 src/secp256k1/src/basic-config.h create mode 100644 src/secp256k1/src/bench.h create mode 100644 src/secp256k1/src/bench_ecdh.c create mode 100644 src/secp256k1/src/bench_internal.c create mode 100644 src/secp256k1/src/bench_recover.c create mode 100644 src/secp256k1/src/bench_schnorr_verify.c create mode 100644 src/secp256k1/src/bench_sign.c create mode 100644 src/secp256k1/src/bench_verify.c create mode 100644 src/secp256k1/src/ecdsa.h create mode 100644 src/secp256k1/src/ecdsa_impl.h create mode 100644 src/secp256k1/src/eckey.h create mode 100644 src/secp256k1/src/eckey_impl.h create mode 100644 src/secp256k1/src/ecmult.h create mode 100644 src/secp256k1/src/ecmult_const.h create mode 100644 src/secp256k1/src/ecmult_const_impl.h create mode 100644 src/secp256k1/src/ecmult_gen.h create mode 100644 src/secp256k1/src/ecmult_gen_impl.h create mode 100644 src/secp256k1/src/ecmult_impl.h create mode 100644 src/secp256k1/src/field.h create mode 100644 src/secp256k1/src/field_10x26.h create mode 100644 src/secp256k1/src/field_10x26_impl.h create mode 100644 src/secp256k1/src/field_5x52.h create mode 100644 src/secp256k1/src/field_5x52_asm_impl.h create mode 100644 src/secp256k1/src/field_5x52_impl.h create mode 100644 src/secp256k1/src/field_5x52_int128_impl.h create mode 100644 src/secp256k1/src/field_impl.h create mode 100644 src/secp256k1/src/gen_context.c create mode 100644 src/secp256k1/src/group.h create mode 100644 src/secp256k1/src/group_impl.h create mode 100644 src/secp256k1/src/hash.h create mode 100644 src/secp256k1/src/hash_impl.h create mode 100644 src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java create mode 100644 src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java create mode 100644 src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java create mode 100644 src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java create mode 100644 src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c create mode 100644 src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h create mode 100644 src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c create mode 100644 src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h create mode 100644 src/secp256k1/src/modules/ecdh/Makefile.am.include create mode 100644 src/secp256k1/src/modules/ecdh/main_impl.h create mode 100644 src/secp256k1/src/modules/ecdh/tests_impl.h create mode 100644 src/secp256k1/src/modules/recovery/Makefile.am.include create mode 100644 src/secp256k1/src/modules/recovery/main_impl.h create mode 100644 src/secp256k1/src/modules/recovery/tests_impl.h create mode 100644 src/secp256k1/src/modules/schnorr/Makefile.am.include create mode 100644 src/secp256k1/src/modules/schnorr/main_impl.h create mode 100644 src/secp256k1/src/modules/schnorr/schnorr.h create mode 100644 src/secp256k1/src/modules/schnorr/schnorr_impl.h create mode 100644 src/secp256k1/src/modules/schnorr/tests_impl.h create mode 100644 src/secp256k1/src/num.h create mode 100644 src/secp256k1/src/num_gmp.h create mode 100644 src/secp256k1/src/num_gmp_impl.h create mode 100644 src/secp256k1/src/num_impl.h create mode 100644 src/secp256k1/src/scalar.h create mode 100644 src/secp256k1/src/scalar_4x64.h create mode 100644 src/secp256k1/src/scalar_4x64_impl.h create mode 100644 src/secp256k1/src/scalar_8x32.h create mode 100644 src/secp256k1/src/scalar_8x32_impl.h create mode 100644 src/secp256k1/src/scalar_impl.h create mode 100644 src/secp256k1/src/secp256k1.c create mode 100644 src/secp256k1/src/testrand.h create mode 100644 src/secp256k1/src/testrand_impl.h create mode 100644 src/secp256k1/src/tests.c create mode 100644 src/secp256k1/src/util.h create mode 100644 src/segwit_addr.c create mode 100644 src/serialize.c create mode 100644 src/sha2.c create mode 100644 src/tools/bitcoin-send-tx.c create mode 100644 src/tools/bitcoin-spv.c create mode 100644 src/tools/bitcointool.c create mode 100644 src/tx.c create mode 100644 src/utils.c create mode 100644 src/vector.c create mode 100644 src/wallet.c create mode 100644 test/aes_tests.c create mode 100644 test/base58check_tests.c create mode 100644 test/bip32_tests.c create mode 100644 test/block_tests.c create mode 100644 test/buffer_tests.c create mode 100644 test/cstr_tests.c create mode 100644 test/ecc_tests.c create mode 100644 test/eckey_tests.c create mode 100644 test/hash_tests.c create mode 100644 test/memory_tests.c create mode 100644 test/net_tests.c create mode 100644 test/netspv_tests.c create mode 100644 test/protocol_tests.c create mode 100644 test/random_tests.c create mode 100644 test/serialize_tests.c create mode 100644 test/sha2_tests.c create mode 100644 test/tool_tests.c create mode 100644 test/tx_tests.c create mode 100644 test/unittester.c create mode 100644 test/utest.h create mode 100644 test/utils_tests.c create mode 100644 test/vector_tests.c create mode 100644 test/wallet_tests.c create mode 100755 tooltests.py diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..226a15d18 --- /dev/null +++ b/.clang-format @@ -0,0 +1,51 @@ +AccessModifierOffset: -4 +AlignEscapedNewlinesLeft: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +BinPackParameters: false +BreakBeforeBinaryOperators: false +BreakBeforeBraces: Linux +BreakBeforeTernaryOperators: false +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 0 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH, BOOST_REVERSE_FOREACH ] +IndentCaseLabels: false +IndentFunctionDeclarationAfterType: false +IndentWidth: 4 +KeepEmptyLinesAtTheStartOfBlocks: false +Language: Cpp +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: None +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +Standard: Cpp03 +TabWidth: 8 +UseTab: Never diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..64d47a505 --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +tests +tests.* +test-suite.log +*.exe +*.so +*.a +!.gitignore +bitcointool +bitcoin-send-tx + +Makefile +configure +.libs/ +Makefile.in +aclocal.m4 +autom4te.cache/ +config.log +config.status +*.tar.gz +*.la +libtool +.deps/ +.dirstamp +build-aux/ +*.lo +*.o +*~ +src/libbtc-config.h +src/libbtc-config.h.in +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 +src/stamp-h1 +libbtc256k1.pc +*.DS_Store +*.gcda +*.gcov +*.gcno diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..3e5b0e979 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,95 @@ +language: c + +cache: + apt: true + directories: + - depends/built + - depends/sdk-sources + - $HOME/Library/Caches/Homebrew + +addons: + apt: + packages: + - valgrind + - binutils-mingw-w64 + - g++-mingw-w64-x86-64 + - gcc-mingw-w64 + - wine1.6 + - libevent-dev + +before_install: + - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then brew install valgrind gnu-sed --default-names; fi + +matrix: + fast_finish: + - true + include: + - os: osx + compiler: clang + env: RUN_MAKE_CHECK="yes" $BUILD_CONFIG='--enable-debug' + - os: osx + compiler: gcc + env: RUN_TOOLTESTS="yes" $BUILD_CONFIG="" + - os: linux + compiler: gcc + env: VALGRIND_UNIT_TESTS="yes" RUN_TOOLTESTS="yes" SUBMIT_COVERALLS="yes" $BUILD_CONFIG='' + - os: linux + compiler: x86_64-w64-mingw32 + env: HOST="x86_64-w64-mingw32" CROSS_COMPILE="yes" RUN_WINE_UNIT_TESTS="yes" $BUILD_CONFIG="--disable-shared --enable-static --disable-net" + - os: linux + compiler: i686-w64-mingw32 + env: HOST="i686-w64-mingw32" CROSS_COMPILE="yes" RUN_WINE_UNIT_TESTS="yes" $BUILD_CONFIG="--disable-shared --enable-static --disable-net" + - os: linux + compiler: arm-linux-gnueabihf + env: HOST="arm-linux-gnueabihf" CROSS_COMPILE="yes" + addons: + apt: + packages: + - g++-arm-linux-gnueabihf + sources: + - ubuntu-toolchain-r-test +# - os: linux +# compiler: i686-pc-linux-gnu +# env: HOST="i686-pc-linux-gnu" CROSS_COMPILE="yes" +# addons: +# apt: +# packages: +# - g++-arm-linux-gnueabihf +# - g++-multilib + +before_script: + - ./autogen.sh + - if [ "$CROSS_COMPILE" == "yes" ]; then + make -C depends HOST=$HOST; + LIBTOOL_APP_LDFLAGS='-all-static' LDFLAGS='-static' ./configure --prefix=$TRAVIS_BUILD_DIR/depends/$HOST $BUILD_CONFIG; cat config.log; + elif [ "$SUBMIT_COVERALLS" == "yes" ]; then + ./configure $BUILD_CONFIG CFLAGS='-fprofile-arcs -ftest-coverage'; cat config.log; + else + ./configure $BUILD_CONFIG; cat config.log; + fi + +script: + - make -j2 V=1 + - ls -la + - if ( [ "$VALGRIND_UNIT_TESTS" == "yes" ] ); then + valgrind --track-origins=yes --leak-check=full --error-exitcode=1 ./tests; + ./tests; + fi + - if ( [ "$RUN_MAKE_CHECK" == "yes" ] ); then + make check; + if [ ! -f test-suite.log; ]; then + cat test-suite.log; + fi + fi + - if ( [ "$RUN_WINE_UNIT_TESTS" == "yes" ] ); then + wine /home/travis/build/libbtc/libbtc/tests.exe; + fi + - if ( [ "$RUN_TOOLTESTS" == "yes" ] ); then + ./tooltests.py; + fi + +after_success: + - if [ "$SUBMIT_COVERALLS" == "yes" ]; then + sudo pip install -U "cpp-coveralls"; + coveralls --verbose -i src -x c -e src/logdb -e src/secp256k1 -r $TRAVIS_BUILD_DIR -b $TRAVIS_BUILD_DIR --gcov-options '\-lp'; + fi \ No newline at end of file diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 000000000..6e50c773f --- /dev/null +++ b/Makefile.am @@ -0,0 +1,193 @@ +ACLOCAL_AMFLAGS = -I build-aux/m4 +.PHONY: gen +.INTERMEDIATE: $(GENBIN) + +DIST_SUBDIRS = src/secp256k1 + +LIBSECP256K1=src/secp256k1/libsecp256k1.la + +$(LIBSECP256K1): $(wildcard src/secp256k1/src/*) $(wildcard src/secp256k1/include/*) + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) + +lib_LTLIBRARIES = libbtc.la +include_HEADERS = \ + include/btc/aes256_cbc.h \ + include/btc/base58.h \ + include/btc/bip32.h \ + include/btc/block.h \ + include/btc/btc.h \ + include/btc/buffer.h \ + include/btc/chainparams.h \ + include/btc/cstr.h \ + include/btc/ctaes.h \ + include/btc/ecc_key.h \ + include/btc/ecc.h \ + include/btc/hash.h \ + include/btc/portable_endian.h \ + include/btc/random.h \ + include/btc/script.h \ + include/btc/segwit_addr.h \ + include/btc/serialize.h \ + include/btc/sha2.h \ + include/btc/tool.h \ + include/btc/tx.h \ + include/btc/utils.h \ + include/btc/vector.h + +noinst_HEADERS = \ + src/ripemd160.h + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libbtc.pc + +libbtc_la_SOURCES = \ + src/aes256_cbc.c \ + src/base58.c \ + src/bip32.c \ + src/block.c \ + src/buffer.c \ + src/chainparams.c \ + src/commontools.c \ + src/cstr.c \ + src/ctaes.c \ + src/ecc_key.c \ + src/ecc_libsecp256k1.c \ + src/memory.c \ + src/memory.h \ + src/random.c \ + src/ripemd160.c \ + src/script.c \ + src/segwit_addr.c \ + src/serialize.c \ + src/sha2.c \ + src/tx.c \ + src/utils.c \ + src/vector.c + +libbtc_la_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src/logdb/include +libbtc_la_LIBADD = $(LIBSECP256K1) + +if USE_TESTS +noinst_PROGRAMS = tests +tests_LDADD = libbtc.la +tests_SOURCES = \ + test/aes_tests.c \ + test/base58check_tests.c \ + test/bip32_tests.c \ + test/block_tests.c \ + test/buffer_tests.c \ + test/cstr_tests.c \ + test/ecc_tests.c \ + test/eckey_tests.c \ + test/hash_tests.c \ + test/memory_tests.c \ + test/random_tests.c \ + test/serialize_tests.c \ + test/sha2_tests.c \ + test/utest.h \ + test/unittester.c \ + test/tx_tests.c \ + test/utils_tests.c \ + test/vector_tests.c + +tests_CFLAGS = $(libbtc_la_CFLAGS) +tests_CPPFLAGS = -I$(top_srcdir)/src +tests_LDFLAGS = -static +TESTS = tests +endif + +if WITH_WALLET + +libbtc_la_SOURCES += \ + src/logdb/logdb_core.c \ + src/logdb/logdb_memdb_llist.c \ + src/logdb/logdb_memdb_rbtree.c \ + src/logdb/logdb_rec.c \ + src/logdb/red_black_tree.c + +include_HEADERS += \ + src/logdb/include/logdb/logdb_base.h \ + src/logdb/include/logdb/logdb_core.h \ + src/logdb/include/logdb/logdb_memdb_llist.h \ + src/logdb/include/logdb/logdb_memdb_rbtree.h \ + src/logdb/include/logdb/logdb_rec.h \ + src/logdb/include/logdb/logdb.h \ + src/logdb/include/logdb/red_black_tree.h + +include_HEADERS += \ + include/btc/wallet.h + +libbtc_la_SOURCES += \ + src/wallet.c + +if USE_TESTS +tests_SOURCES += \ + test/wallet_tests.c \ + src/logdb/test/logdb_tests.c \ + src/logdb/test/tests_red_black_tree.c +endif +endif + +if WITH_NET +include_HEADERS += \ + include/btc/headersdb.h \ + include/btc/headersdb_file.h \ + include/btc/protocol.h \ + include/btc/net.h \ + include/btc/netspv.h + +libbtc_la_SOURCES += \ + src/headersdb_file.c \ + src/net.c \ + src/netspv.c \ + src/protocol.c + +libbtc_la_LIBADD += $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) +libbtc_la_CFLAGS += $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) + +if USE_TESTS +tests_SOURCES += \ + test/net_tests.c \ + test/netspv_tests.c \ + test/protocol_tests.c +tests_LDADD += $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) +tests_LDFLAGS += -levent +endif +endif + +if WITH_TOOLS +if USE_TESTS +tests_SOURCES += \ + test/tool_tests.c +endif +instdir=$(prefix)/bin +inst_PROGRAMS = bitcointool +bitcointool_LDADD = libbtc.la +bitcointool_SOURCES = \ + src/tools/bitcointool.c +bitcointool_CFLAGS = $(libbtc_la_CFLAGS) +bitcointool_CPPFLAGS = -I$(top_srcdir)/src +bitcointool_LDFLAGS = -static + +if WITH_NET +inst_PROGRAMS += bitcoin-send-tx +bitcoin_send_tx_LDADD = libbtc.la $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) +bitcoin_send_tx_SOURCES = \ + src/tools/bitcoin-send-tx.c +bitcoin_send_tx_CFLAGS = $(libbtc_la_CFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS) +bitcoin_send_tx_CPPFLAGS = -I$(top_srcdir)/src +bitcoin_send_tx_LDFLAGS = -static + +inst_PROGRAMS += bitcoin-spv +bitcoin_spv_LDADD = libbtc.la +bitcoin_spv_SOURCES = \ + src/tools/bitcoin-spv.c +bitcoin_spv_CFLAGS = $(libbtc_la_CFLAGS) +bitcoin_spv_CPPFLAGS = -I$(top_srcdir)/src +bitcoin_spv_LDFLAGS = -static +endif + +endif + +clean-local: + -$(MAKE) -C src/secp256k1 clean diff --git a/README.md b/README.md new file mode 100644 index 000000000..c9fc718be --- /dev/null +++ b/README.md @@ -0,0 +1,115 @@ +Icon + +libbtc – A fast, clean and small bitcoin C library +============================================================= + +[![Build Status](https://travis-ci.org/libbtc/libbtc.svg?branch=master)](https://travis-ci.org/libbtc/libbtc) [![Coverage Status](https://coveralls.io/repos/libbtc/libbtc/badge.svg?branch=master&service=github)](https://coveralls.io/github/libbtc/libbtc?branch=master) + + +What is libbtc? +---------------- + +Libbtc is a very portable C library for creating and manipulating bitcoin data structures and interacting with the p2p network. + +Current features +---------------- +* Generating and storing private and public keys +* ECDSA secp256k1 signing and verification (through [libsecp256k1](https://github.com/bitcoin-core/secp256k1) included as git subtree) +* Generate recoverable signatures (and recover pubkey from signatures) +* BIP32 hierarchical deterministic key derivation +* Transaction generation, manipulation, signing and ser-/deserialization including P2PKH, P2SH, multisig +* Address generation +* Base58check encoding +* Native implementation of SHA256, SHA512, SHA512_HMAC, RIPEMD-160 including NIST testvectors +* Native constant time AES (+256CBC) cipher implementation including NIST testvectors +* Keystore (wallet) databases (through logdb https://github.com/liblogdb/liblogdb) +* Event based bitcoin P2P client capable of connecting to multiple nodes in a single thread (requires [libevent](https://github.com/libevent/libevent)) + +Advantages of libbtc? +---------------- + +* No dependencies in case no p2p network client is required (only dependency is [libsecp256k1](https://github.com/bitcoin-core/secp256k1) added as git subtree) +* The only dependency for the p2p network client is [libevent](https://github.com/libevent/libevent) (very portable) +* optimized for MCU and low mem environments +* ~full test coverage +* mem leak free (valgrind check during CI) + +The bitcointool CLI +---------------- + +##### Generate a new privatekey WIF and HEX encoded: + + ./bitcointool -command genkey + > privatekey WIF: KwmAqzEiP7nJbQi6ofQywSEad4j5b9BXDJvyypQDDLSvrV6wACG8 + > privatekey HEX: 102f1d9d91fa1c8d816ef469e74c1153a6b453d2a991e77fe187e5514a7b18ac + +##### Generate the public key and p2pkh address from a WIF encoded private key + + /bitcointool -command pubfrompriv -p KwmAqzEiP7nJbQi6ofQywSEad4j5b9BXDJvyypQDDLSvrV6wACG8 + > pubkey: 023d86ca58e2519cce1729b4d36dfe5a053ad5f4ae6f7ef9360bee4e657f7e41c9 + > p2pkh address: 1N5ZkjyabcZLLHMweJrSkn3qedsPGzAx9m + +##### Generate the P2PKH address from a hex encoded compact public key + + ./bitcointool -command addrfrompub -pubkey 023d86ca58e2519cce1729b4d36dfe5a053ad5f4ae6f7ef9360bee4e657f7e41c9 + > p2pkh address: 1N5ZkjyabcZLLHMweJrSkn3qedsPGzAx9m + + +##### Generate new BIP32 master key + + ./bitcointool -command hdgenmaster + > masterkey: xprv9s21ZrQH143K3C5hLMq2Upsh8mf9Z1p5C4QuXJkiodSSihp324YnWpFfRjvP7gqocJKz4oakVwZn5cUgRYTHtNRvGqU5DU2Gn8MPM9jHvfC + + +##### Print HD node + + ./bitcointool -command hdprintkey -privkey xprv9s21ZrQH143K3C5hLMq2Upsh8mf9Z1p5C4QuXJkiodSSihp324YnWpFfRjvP7gqocJKz4oakVwZn5cUgRYTHtNRvGqU5DU2Gn8MPM9jHvfC + > ext key: xprv9s21ZrQH143K3C5hLMq2Upsh8mf9Z1p5C4QuXJkiodSSihp324YnWpFfRjvP7gqocJKz4oakVwZn5cUgRYTHtNRvGqU5DU2Gn8MPM9jHvfC + > depth: 0 + > p2pkh address: 1Fh1zA8mD6S2LBbCqdViEGuV3oDhggX3k4 + > pubkey hex: 0394a83fcfa131afc47a3fcd1d32db399a0ffa7e68844546b2df7ed9f5ebd07b09 + > extended pubkey: xpub661MyMwAqRbcFgAASPN2qxpRgoVdxUXvZHLWKhALMxyRbW9BZbs34ca9H3LrdsKxdMD4o5Fc7eqDg19cRTj3V9dCCeM4R1DRn8DvUq3rMva + + +##### Derive child key (second child key at level 1 in this case) + + ./bitcointool -command hdderive -keypath m/1h -privkey xprv9s21ZrQH143K3C5hLMq2Upsh8mf9Z1p5C4QuXJkiodSSihp324YnWpFfRjvP7gqocJKz4oakVwZn5cUgRYTHtNRvGqU5DU2Gn8MPM9jHvfC + > ext key: xprv9v5qiRbzrbhUzAVBdtfqi1tQx5tiRJ2jpNtAw8bRec8sTivLw55H85SoRTizNdx2JSVL4sNxmjvseASZkwpUopby3iGiJWnVH3Wjg2GkjrD + > depth: 1 + > p2pkh address: 1DFBGZdcADGTcWwDEgf15RGPqnjmW2gokC + > pubkey hex: 0203a85ec401e66a218bf1583112599ee2a1268ebc90d91b7f457c87a50f2b011b + > extended pubkey: xpub695C7w8tgyFnCeZejvCr59q9W7jCpkkbBbomjX13CwfrLXFVUcPXfsmHGiSfpYds2JuHrXAFEoikMX6725W8VgrVL5x4ojBw9QFAPgtdw1G + +The bitcoin-send-tx CLI +---------------- +This tools can be used to broadcast a raw transaction to peers retrived from a dns seed or specified by ip/port. +The application will try to connect to max 6 peers, send the transaction two two of them and listens on the remaining ones if the transaction has been relayed back. + +##### Send a raw transaction to random peers on mainnet + + ./bitcoin-send-tx + +##### Send a raw transaction to random peers on testnet and show debug infos + + ./bitcoin-send-tx -d -t + +##### Send a raw transaction to specific peers on mainnet and show debug infos use a timeout of 5s + + ./bitcoin-send-tx -d -s 5 -i 192.168.1.110:8333,127.0.0.1:8333 + +How to Build +---------------- + +#### Full library including CLI tool and wallet database +``` +./autogen.sh +./configure +make check +``` + +#### Pure library without wallet support +``` +./autogen.sh +./configure --disable-wallet --disable-tools +make check +``` diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 000000000..65286b935 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,3 @@ +#!/bin/sh +set -e +autoreconf -if --warnings=all diff --git a/build-aux/m4/ax_check_link_flag.m4 b/build-aux/m4/ax_check_link_flag.m4 new file mode 100644 index 000000000..e2d0d363e --- /dev/null +++ b/build-aux/m4/ax_check_link_flag.m4 @@ -0,0 +1,71 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the linker or gives an error. +# (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the linker's default flags +# when the check is done. The check is thus made with the flags: "LDFLAGS +# EXTRA-FLAGS FLAG". This can for example be used to force the linker to +# issue an error when a bad flag is given. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# 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. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 2 + +AC_DEFUN([AX_CHECK_LINK_FLAG], +[AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl +AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ + ax_check_save_flags=$LDFLAGS + LDFLAGS="$LDFLAGS $4 $1" + AC_LINK_IFELSE([AC_LANG_PROGRAM()], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + LDFLAGS=$ax_check_save_flags]) +AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_LINK_FLAGS diff --git a/build-aux/m4/ax_check_openssl.m4 b/build-aux/m4/ax_check_openssl.m4 new file mode 100755 index 000000000..a87c5a6b6 --- /dev/null +++ b/build-aux/m4/ax_check_openssl.m4 @@ -0,0 +1,124 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_check_openssl.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_OPENSSL([action-if-found[, action-if-not-found]]) +# +# DESCRIPTION +# +# Look for OpenSSL in a number of default spots, or in a user-selected +# spot (via --with-openssl). Sets +# +# OPENSSL_INCLUDES to the include directives required +# OPENSSL_LIBS to the -l directives required +# OPENSSL_LDFLAGS to the -L or -R flags required +# +# and calls ACTION-IF-FOUND or ACTION-IF-NOT-FOUND appropriately +# +# This macro sets OPENSSL_INCLUDES such that source files should use the +# openssl/ directory in include directives: +# +# #include +# +# LICENSE +# +# Copyright (c) 2009,2010 Zmanda Inc. +# Copyright (c) 2009,2010 Dustin J. Mitchell +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 8 + +AU_ALIAS([CHECK_SSL], [AX_CHECK_OPENSSL]) +AC_DEFUN([AX_CHECK_OPENSSL], [ + found=false + AC_ARG_WITH([openssl], + [AS_HELP_STRING([--with-openssl=DIR], + [root of the OpenSSL directory])], + [ + case "$withval" in + "" | y | ye | yes | n | no) + AC_MSG_ERROR([Invalid --with-openssl value]) + ;; + *) ssldirs="$withval" + ;; + esac + ], [ + # if pkg-config is installed and openssl has installed a .pc file, + # then use that information and don't search ssldirs + AC_PATH_PROG([PKG_CONFIG], [pkg-config]) + if test x"$PKG_CONFIG" != x""; then + OPENSSL_LDFLAGS=`$PKG_CONFIG openssl --libs-only-L 2>/dev/null` + if test $? = 0; then + OPENSSL_LIBS=`$PKG_CONFIG openssl --libs-only-l 2>/dev/null` + OPENSSL_INCLUDES=`$PKG_CONFIG openssl --cflags-only-I 2>/dev/null` + found=true + fi + fi + + # no such luck; use some default ssldirs + if ! $found; then + ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr" + fi + ] + ) + + + # note that we #include , so the OpenSSL headers have to be in + # an 'openssl' subdirectory + + if ! $found; then + OPENSSL_INCLUDES= + for ssldir in $ssldirs; do + AC_MSG_CHECKING([for openssl/ssl.h in $ssldir]) + if test -f "$ssldir/include/openssl/ssl.h"; then + OPENSSL_INCLUDES="-I$ssldir/include" + OPENSSL_LDFLAGS="-L$ssldir/lib" + OPENSSL_LIBS="-lssl -lcrypto" + found=true + AC_MSG_RESULT([yes]) + break + else + AC_MSG_RESULT([no]) + fi + done + + # if the file wasn't found, well, go ahead and try the link anyway -- maybe + # it will just work! + fi + + # try the preprocessor and linker with our new flags, + # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS + + AC_MSG_CHECKING([whether compiling and linking against OpenSSL works]) + echo "Trying link with OPENSSL_LDFLAGS=$OPENSSL_LDFLAGS;" \ + "OPENSSL_LIBS=$OPENSSL_LIBS; OPENSSL_INCLUDES=$OPENSSL_INCLUDES" >&AS_MESSAGE_LOG_FD + + save_LIBS="$LIBS" + save_LDFLAGS="$LDFLAGS" + save_CPPFLAGS="$CPPFLAGS" + LDFLAGS="$LDFLAGS $OPENSSL_LDFLAGS" + LIBS="$OPENSSL_LIBS $LIBS" + CPPFLAGS="$OPENSSL_INCLUDES $CPPFLAGS" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([#include ], [SSL_new(NULL)])], + [ + AC_MSG_RESULT([yes]) + $1 + ], [ + AC_MSG_RESULT([no]) + $2 + ]) + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + + AC_SUBST([OPENSSL_INCLUDES]) + AC_SUBST([OPENSSL_LIBS]) + AC_SUBST([OPENSSL_LDFLAGS]) +]) diff --git a/configure.ac b/configure.ac new file mode 100644 index 000000000..d24c97140 --- /dev/null +++ b/configure.ac @@ -0,0 +1,159 @@ +dnl require autoconf 2.68 (AS_ECHO/AS_ECHO_N) +AC_PREREQ([2.68]) +AC_INIT([libbtc],[0.1],[https://github.com/jonasschnelli/libbtc/issues],[libbtc]) +AC_CONFIG_HEADERS([src/libbtc-config.h]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_MACRO_DIR([build-aux/m4]) +AC_CANONICAL_HOST +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) +AH_TOP([#ifndef LIBBTC_CONFIG_H]) +AH_TOP([#define LIBBTC_CONFIG_H]) +AH_BOTTOM([#endif /*LIBBTC_CONFIG_H*/]) +AM_INIT_AUTOMAKE([no-define subdir-objects foreign]) +AC_HEADER_STDBOOL +LT_INIT + +PKG_PROG_PKG_CONFIG +AC_PATH_TOOL(AR, ar) +AC_PATH_TOOL(RANLIB, ranlib) +AC_PATH_TOOL(STRIP, strip) +AM_PROG_CC_C_O +AC_PROG_CC_C99 + +CFLAGS="$CFLAGS -W" + +warn_CFLAGS="-std=gnu99 -pedantic -Wno-unused-function -Wno-long-long -Wno-overlength-strings" +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $warn_CFLAGS" +AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], + [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS" + ]) + +# Enable debug +AC_ARG_ENABLE([debug], + [AS_HELP_STRING([--enable-debug], + [use debug compiler flags and macros (default is no)])], + [enable_debug=$enableval], + [enable_debug=no]) + +AC_ARG_ENABLE([wallet], + [AS_HELP_STRING([--disable-wallet], + [disable wallet/database functions])], + [with_wallet=$enableval], + [with_wallet=yes]) + +AC_ARG_ENABLE([tools], + [AS_HELP_STRING([--disable-tools], + [disable bitcoin tool cli application])], + [with_tools=$enableval], + [with_tools=yes]) + +AC_ARG_ENABLE([net], + [AS_HELP_STRING([--disable-net], + [disable net functions])], + [with_net=$enableval], + [with_net=yes]) + +case $host in + *mingw*) + TARGET_OS=windows + ;; + *darwin*) + TARGET_OS=darwin + ;; + *linux*) + TARGET_OS=linux + ;; +esac + +if test "x$with_wallet" = xyes; then + AC_DEFINE_UNQUOTED([WITH_WALLET],[1],[Define to 1 to enable wallet compilation]) +fi + +if test "x$with_tools" = xyes; then +AC_DEFINE_UNQUOTED([WITH_TOOLS],[1],[Define to 1 to enable wallet compilation]) +fi + +if test "x$with_net" = xyes; then + AC_DEFINE_UNQUOTED([WITH_NET],[1],[Define to 1 to enable net compilation]) +fi + +if test "x$enable_debug" = xyes; then + CFLAGS="$CFLAGS -g3 -O0 -DDEBUG" + CXXFLAGS="$CXXFLAGS -g3 -O0 -DDEBUG" + AC_DEFINE_UNQUOTED([ENABLE_DEBUG],[1],[Define to 1 to enable debung output]) +fi + +AC_ARG_ENABLE(tests, + AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]), + [use_tests=$enableval], + [use_tests=yes]) + +AC_MSG_CHECKING([for __builtin_expect]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])], + [ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_EXPECT,1,[Define this symbol if __builtin_expect is available]) ], + [ AC_MSG_RESULT([no]) + ]) + +m4_include(m4/macros/with.m4) +ARG_WITH_SET([random-device], [/dev/urandom], [set the device to read random data from]) +if test "x$random_device" = x"/dev/urandom"; then + AC_DEFINE_UNQUOTED([FILE_RANDOM],[1],[Define to 1 to enable random retrieving over filehandle]) + AC_DEFINE([RANDOM_DEVICE],["/dev/urandom"],[Define to set random file handle]) +fi +if test "x$random_device" = x"/dev/random"; then + AC_DEFINE_UNQUOTED([FILE_RANDOM],[1],[Define to 1 to enable /dev/random as random device]) + AC_DEFINE([RANDOM_DEVICE],["/dev/random"],[Define to set random file handle]) +fi + +if test "$host" = "mingw"; then + # -static is interpreted by libtool, where it has a different meaning. + # In libtool-speak, it's -all-static. + AX_CHECK_LINK_FLAG([[-static]],[LIBTOOL_APP_LDFLAGS="$LIBTOOL_APP_LDFLAGS -all-static"]) +fi + +if test x$with_net = "xyes"; then + AC_CHECK_HEADER([event2/event.h],, AC_MSG_ERROR(libevent headers missing),) + AC_CHECK_LIB([event],[main],EVENT_LIBS=-levent,AC_MSG_ERROR(libevent missing)) + if test "$host" = "mingw"; then + AC_CHECK_LIB([event_pthreads],[main],EVENT_PTHREADS_LIBS=-levent_pthreads,AC_MSG_ERROR(libevent_pthreads missing)) + fi +fi + +AC_CONFIG_FILES([Makefile libbtc.pc]) +AC_SUBST(LIBTOOL_APP_LDFLAGS) +AC_SUBST(BUILD_EXEEXT) +AC_SUBST(EVENT_LIBS) +AC_SUBST(EVENT_PTHREADS_LIBS) +AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"]) +AM_CONDITIONAL([WITH_TOOLS], [test "x$with_tools" = "xyes"]) +AM_CONDITIONAL([WITH_WALLET], [test "x$with_wallet" = "xyes"]) +AM_CONDITIONAL([WITH_NET], [test "x$with_net" = "xyes"]) + +ac_configure_args="${ac_configure_args} --enable-module-recovery" +AC_CONFIG_SUBDIRS([src/secp256k1]) + +dnl make sure nothing new is exported so that we don't break the cache +PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH" +unset PKG_CONFIG_PATH +PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP" + +AC_OUTPUT + +echo +echo "Options used to compile and link:" +echo " with wallet = $with_wallet" +echo " with tools = $with_tools" +echo " with net = $with_net" +echo +echo " target os = $TARGET_OS" +echo +echo " CC = $CC" +echo " CFLAGS = $CFLAGS" +echo " CXX = $CXX" +echo " CXXFLAGS = $CXXFLAGS" +echo " LDFLAGS = $LDFLAGS" +echo diff --git a/contrib/format.sh b/contrib/format.sh new file mode 100755 index 000000000..2fa07c682 --- /dev/null +++ b/contrib/format.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +echo "execute from git root dir" +find . \( -not -path './src/secp256k1/*' -and \( -name '*.h' -or -name '*.c' \) \) -prune -print0 | xargs -0 "clang-format" -i diff --git a/contrib/github-merge.sh b/contrib/github-merge.sh new file mode 100755 index 000000000..afb53f039 --- /dev/null +++ b/contrib/github-merge.sh @@ -0,0 +1,185 @@ +#!/bin/bash + +# This script will locally construct a merge commit for a pull request on a +# github repository, inspect it, sign it and optionally push it. + +# The following temporary branches are created/overwritten and deleted: +# * pull/$PULL/base (the current master we're merging onto) +# * pull/$PULL/head (the current state of the remote pull request) +# * pull/$PULL/merge (github's merge) +# * pull/$PULL/local-merge (our merge) + +# In case of a clean merge that is accepted by the user, the local branch with +# name $BRANCH is overwritten with the merged result, and optionally pushed. + +REPO="$(git config --get githubmerge.repository)" +if [[ "d$REPO" == "d" ]]; then + echo "ERROR: No repository configured. Use this command to set:" >&2 + echo "git config githubmerge.repository /" >&2 + echo "In addition, you can set the following variables:" >&2 + echo "- githubmerge.host (default git@github.com)" >&2 + echo "- githubmerge.branch (default master)" >&2 + echo "- githubmerge.testcmd (default none)" >&2 + exit 1 +fi + +HOST="$(git config --get githubmerge.host)" +if [[ "d$HOST" == "d" ]]; then + HOST="git@github.com" +fi + +BRANCH="$(git config --get githubmerge.branch)" +if [[ "d$BRANCH" == "d" ]]; then + BRANCH="master" +fi + +TESTCMD="$(git config --get githubmerge.testcmd)" + +PULL="$1" + +if [[ "d$PULL" == "d" ]]; then + echo "Usage: $0 pullnumber [branch]" >&2 + exit 2 +fi + +if [[ "d$2" != "d" ]]; then + BRANCH="$2" +fi + +# Initialize source branches. +git checkout -q "$BRANCH" +if git fetch -q "$HOST":"$REPO" "+refs/pull/$PULL/*:refs/heads/pull/$PULL/*"; then + if ! git log -q -1 "refs/heads/pull/$PULL/head" >/dev/null 2>&1; then + echo "ERROR: Cannot find head of pull request #$PULL on $HOST:$REPO." >&2 + exit 3 + fi + if ! git log -q -1 "refs/heads/pull/$PULL/merge" >/dev/null 2>&1; then + echo "ERROR: Cannot find merge of pull request #$PULL on $HOST:$REPO." >&2 + exit 3 + fi +else + echo "ERROR: Cannot find pull request #$PULL on $HOST:$REPO." >&2 + exit 3 +fi +if git fetch -q "$HOST":"$REPO" +refs/heads/"$BRANCH":refs/heads/pull/"$PULL"/base; then + true +else + echo "ERROR: Cannot find branch $BRANCH on $HOST:$REPO." >&2 + exit 3 +fi +git checkout -q pull/"$PULL"/base +git branch -q -D pull/"$PULL"/local-merge 2>/dev/null +git checkout -q -b pull/"$PULL"/local-merge +TMPDIR="$(mktemp -d -t ghmXXXXX)" + +function cleanup() { + git checkout -q "$BRANCH" + git branch -q -D pull/"$PULL"/head 2>/dev/null + git branch -q -D pull/"$PULL"/base 2>/dev/null + git branch -q -D pull/"$PULL"/merge 2>/dev/null + git branch -q -D pull/"$PULL"/local-merge 2>/dev/null + rm -rf "$TMPDIR" +} + +# Create unsigned merge commit. +( + echo "Merge pull request #$PULL" + echo "" + git log --no-merges --topo-order --pretty='format:%h %s (%an)' pull/"$PULL"/base..pull/"$PULL"/head +)>"$TMPDIR/message" +if git merge -q --commit --no-edit --no-ff -m "$(<"$TMPDIR/message")" pull/"$PULL"/head; then + if [ "d$(git log --pretty='format:%s' -n 1)" != "dMerge pull request #$PULL" ]; then + echo "ERROR: Creating merge failed (already merged?)." >&2 + cleanup + exit 4 + fi +else + echo "ERROR: Cannot be merged cleanly." >&2 + git merge --abort + cleanup + exit 4 +fi + +# Run test command if configured. +if [[ "d$TESTCMD" != "d" ]]; then + # Go up to the repository's root. + while [ ! -d .git ]; do cd ..; done + if ! $TESTCMD; then + echo "ERROR: Running $TESTCMD failed." >&2 + cleanup + exit 5 + fi + # Show the created merge. + git diff pull/"$PULL"/merge..pull/"$PULL"/local-merge >"$TMPDIR"/diff + git diff pull/"$PULL"/base..pull/"$PULL"/local-merge + if [[ "$(<"$TMPDIR"/diff)" != "" ]]; then + echo "WARNING: merge differs from github!" >&2 + read -p "Type 'ignore' to continue. " -r >&2 + if [[ "d$REPLY" =~ ^d[iI][gG][nN][oO][rR][eE]$ ]]; then + echo "Difference with github ignored." >&2 + else + cleanup + exit 6 + fi + fi + read -p "Press 'd' to accept the diff. " -n 1 -r >&2 + echo + if [[ "d$REPLY" =~ ^d[dD]$ ]]; then + echo "Diff accepted." >&2 + else + echo "ERROR: Diff rejected." >&2 + cleanup + exit 6 + fi +else + # Verify the result. + echo "Dropping you on a shell so you can try building/testing the merged source." >&2 + echo "Run 'git diff HEAD~' to show the changes being merged." >&2 + echo "Type 'exit' when done." >&2 + if [[ -f /etc/debian_version ]]; then # Show pull number in prompt on Debian default prompt + export debian_chroot="$PULL" + fi + bash -i + read -p "Press 'm' to accept the merge. " -n 1 -r >&2 + echo + if [[ "d$REPLY" =~ ^d[Mm]$ ]]; then + echo "Merge accepted." >&2 + else + echo "ERROR: Merge rejected." >&2 + cleanup + exit 7 + fi +fi + +# Sign the merge commit. +read -p "Press 's' to sign off on the merge. " -n 1 -r >&2 +echo +if [[ "d$REPLY" =~ ^d[Ss]$ ]]; then + if [[ "$(git config --get user.signingkey)" == "" ]]; then + echo "ERROR: No GPG signing key set, not signing. Set one using:" >&2 + echo "git config --global user.signingkey " >&2 + cleanup + exit 1 + else + if ! git commit -q --gpg-sign --amend --no-edit; then + echo "Error signing, exiting." + cleanup + exit 1 + fi + fi +else + echo "Not signing off on merge, exiting." + cleanup + exit 1 +fi + +# Clean up temporary branches, and put the result in $BRANCH. +git checkout -q "$BRANCH" +git reset -q --hard pull/"$PULL"/local-merge +cleanup + +# Push the result. +read -p "Type 'push' to push the result to $HOST:$REPO, branch $BRANCH. " -r >&2 +if [[ "d$REPLY" =~ ^d[Pp][Uu][Ss][Hh]$ ]]; then + git push "$HOST":"$REPO" refs/heads/"$BRANCH" +fi diff --git a/depends/.gitignore b/depends/.gitignore new file mode 100644 index 000000000..3cb4b9ac1 --- /dev/null +++ b/depends/.gitignore @@ -0,0 +1,10 @@ +SDKs/ +work/ +built/ +sources/ +config.site +x86_64* +i686* +mips* +arm* +aarch64* diff --git a/depends/Makefile b/depends/Makefile new file mode 100644 index 000000000..dedb0674c --- /dev/null +++ b/depends/Makefile @@ -0,0 +1,181 @@ +.NOTPARALLEL : + +SOURCES_PATH ?= $(BASEDIR)/sources +BASE_CACHE ?= $(BASEDIR)/built +SDK_PATH ?= $(BASEDIR)/SDKs +NO_QT ?= +NO_WALLET ?= +NO_UPNP ?= +FALLBACK_DOWNLOAD_PATH ?= https://bitcoincore.org/depends-sources + +BUILD = $(shell ./config.guess) +HOST ?= $(BUILD) +PATCHES_PATH = $(BASEDIR)/patches +BASEDIR = $(CURDIR) +HASH_LENGTH:=11 +DOWNLOAD_CONNECT_TIMEOUT:=10 +DOWNLOAD_RETRIES:=3 +HOST_ID_SALT ?= salt +BUILD_ID_SALT ?= salt + +host:=$(BUILD) +ifneq ($(HOST),) +host:=$(HOST) +host_toolchain:=$(HOST)- +endif + +ifneq ($(DEBUG),) +release_type=debug +else +release_type=release +endif + +base_build_dir=$(BASEDIR)/work/build +base_staging_dir=$(BASEDIR)/work/staging +base_download_dir=$(BASEDIR)/work/download +canonical_host:=$(shell ./config.sub $(HOST)) +build:=$(shell ./config.sub $(BUILD)) + +build_arch =$(firstword $(subst -, ,$(build))) +build_vendor=$(word 2,$(subst -, ,$(build))) +full_build_os:=$(subst $(build_arch)-$(build_vendor)-,,$(build)) +build_os:=$(findstring linux,$(full_build_os)) +build_os+=$(findstring darwin,$(full_build_os)) +build_os:=$(strip $(build_os)) +ifeq ($(build_os),) +build_os=$(full_build_os) +endif + +host_arch=$(firstword $(subst -, ,$(canonical_host))) +host_vendor=$(word 2,$(subst -, ,$(canonical_host))) +full_host_os:=$(subst $(host_arch)-$(host_vendor)-,,$(canonical_host)) +host_os:=$(findstring linux,$(full_host_os)) +host_os+=$(findstring darwin,$(full_host_os)) +host_os+=$(findstring mingw32,$(full_host_os)) +host_os:=$(strip $(host_os)) +ifeq ($(host_os),) +host_os=$(full_host_os) +endif + +$(host_arch)_$(host_os)_prefix=$(BASEDIR)/$(host) +$(host_arch)_$(host_os)_host=$(host) +host_prefix=$($(host_arch)_$(host_os)_prefix) +build_prefix=$(host_prefix)/native +build_host=$(build) + +AT_$(V):= +AT_:=@ +AT:=$(AT_$(V)) + +all: install + +include hosts/$(host_os).mk +include hosts/default.mk +include builders/$(build_os).mk +include builders/default.mk +include packages/packages.mk + +build_id_string:=$(BUILD_ID_SALT) +build_id_string+=$(shell $(build_CC) --version 2>/dev/null) +build_id_string+=$(shell $(build_AR) --version 2>/dev/null) +build_id_string+=$(shell $(build_CXX) --version 2>/dev/null) +build_id_string+=$(shell $(build_RANLIB) --version 2>/dev/null) +build_id_string+=$(shell $(build_STRIP) --version 2>/dev/null) + +$(host_arch)_$(host_os)_id_string:=$(HOST_ID_SALT) +$(host_arch)_$(host_os)_id_string+=$(shell $(host_CC) --version 2>/dev/null) +$(host_arch)_$(host_os)_id_string+=$(shell $(host_AR) --version 2>/dev/null) +$(host_arch)_$(host_os)_id_string+=$(shell $(host_CXX) --version 2>/dev/null) +$(host_arch)_$(host_os)_id_string+=$(shell $(host_RANLIB) --version 2>/dev/null) +$(host_arch)_$(host_os)_id_string+=$(shell $(host_STRIP) --version 2>/dev/null) + +qt_packages_$(NO_QT) = $(qt_packages) $(qt_$(host_os)_packages) $(qt_$(host_arch)_$(host_os)_packages) +wallet_packages_$(NO_WALLET) = $(wallet_packages) +upnp_packages_$(NO_UPNP) = $(upnp_packages) + +packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(qt_packages_) $(wallet_packages_) $(upnp_packages_) +native_packages += $($(host_arch)_$(host_os)_native_packages) $($(host_os)_native_packages) + +ifneq ($(qt_packages_),) +native_packages += $(qt_native_packages) +endif + +all_packages = $(packages) $(native_packages) + +meta_depends = Makefile funcs.mk builders/default.mk hosts/default.mk hosts/$(host_os).mk builders/$(build_os).mk + +$(host_arch)_$(host_os)_native_toolchain?=$($(host_os)_native_toolchain) + +include funcs.mk + +toolchain_path=$($($(host_arch)_$(host_os)_native_toolchain)_prefixbin) +final_build_id_long+=$(shell $(build_SHA256SUM) config.site.in) +final_build_id+=$(shell echo -n "$(final_build_id_long)" | $(build_SHA256SUM) | cut -c-$(HASH_LENGTH)) +$(host_prefix)/.stamp_$(final_build_id): $(native_packages) $(packages) + $(AT)rm -rf $(@D) + $(AT)mkdir -p $(@D) + $(AT)echo copying packages: $^ + $(AT)echo to: $(@D) + $(AT)cd $(@D); $(foreach package,$^, tar xf $($(package)_cached); ) + $(AT)touch $@ + +$(host_prefix)/share/config.site : config.site.in $(host_prefix)/.stamp_$(final_build_id) + $(AT)@mkdir -p $(@D) + $(AT)sed -e 's|@HOST@|$(host)|' \ + -e 's|@CC@|$(toolchain_path)$(host_CC)|' \ + -e 's|@CXX@|$(toolchain_path)$(host_CXX)|' \ + -e 's|@AR@|$(toolchain_path)$(host_AR)|' \ + -e 's|@RANLIB@|$(toolchain_path)$(host_RANLIB)|' \ + -e 's|@NM@|$(toolchain_path)$(host_NM)|' \ + -e 's|@STRIP@|$(toolchain_path)$(host_STRIP)|' \ + -e 's|@build_os@|$(build_os)|' \ + -e 's|@host_os@|$(host_os)|' \ + -e 's|@CFLAGS@|$(strip $(host_CFLAGS) $(host_$(release_type)_CFLAGS))|' \ + -e 's|@CXXFLAGS@|$(strip $(host_CXXFLAGS) $(host_$(release_type)_CXXFLAGS))|' \ + -e 's|@CPPFLAGS@|$(strip $(host_CPPFLAGS) $(host_$(release_type)_CPPFLAGS))|' \ + -e 's|@LDFLAGS@|$(strip $(host_LDFLAGS) $(host_$(release_type)_LDFLAGS))|' \ + -e 's|@no_qt@|$(NO_QT)|' \ + -e 's|@no_wallet@|$(NO_WALLET)|' \ + -e 's|@no_upnp@|$(NO_UPNP)|' \ + -e 's|@debug@|$(DEBUG)|' \ + $< > $@ + $(AT)touch $@ + + +define check_or_remove_cached + mkdir -p $(BASE_CACHE)/$(host)/$(package) && cd $(BASE_CACHE)/$(host)/$(package); \ + $(build_SHA256SUM) -c $($(package)_cached_checksum) >/dev/null 2>/dev/null || \ + ( rm -f $($(package)_cached_checksum); \ + if test -f "$($(package)_cached)"; then echo "Checksum mismatch for $(package). Forcing rebuild.."; rm -f $($(package)_cached_checksum) $($(package)_cached); fi ) +endef + +define check_or_remove_sources + mkdir -p $($(package)_source_dir); cd $($(package)_source_dir); \ + test -f $($(package)_fetched) && ( $(build_SHA256SUM) -c $($(package)_fetched) >/dev/null 2>/dev/null || \ + ( echo "Checksum missing or mismatched for $(package) source. Forcing re-download."; \ + rm -f $($(package)_all_sources) $($(1)_fetched))) || true +endef + +check-packages: + @$(foreach package,$(all_packages),$(call check_or_remove_cached,$(package));) +check-sources: + @$(foreach package,$(all_packages),$(call check_or_remove_sources,$(package));) + +$(host_prefix)/share/config.site: check-packages + +check-packages: check-sources + +install: check-packages $(host_prefix)/share/config.site + + +download-one: check-sources $(all_sources) + +download-osx: + @$(MAKE) -s HOST=x86_64-apple-darwin11 download-one +download-linux: + @$(MAKE) -s HOST=x86_64-unknown-linux-gnu download-one +download-win: + @$(MAKE) -s HOST=x86_64-w64-mingw32 download-one +download: download-osx download-linux download-win + +.PHONY: install cached download-one download-osx download-linux download-win download check-packages check-sources diff --git a/depends/builders/darwin.mk b/depends/builders/darwin.mk new file mode 100644 index 000000000..27f550ab0 --- /dev/null +++ b/depends/builders/darwin.mk @@ -0,0 +1,22 @@ +build_darwin_CC: = $(shell xcrun -f clang) +build_darwin_CXX: = $(shell xcrun -f clang++) +build_darwin_AR: = $(shell xcrun -f ar) +build_darwin_RANLIB: = $(shell xcrun -f ranlib) +build_darwin_STRIP: = $(shell xcrun -f strip) +build_darwin_OTOOL: = $(shell xcrun -f otool) +build_darwin_NM: = $(shell xcrun -f nm) +build_darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool) +build_darwin_SHA256SUM = shasum -a 256 +build_darwin_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o + +#darwin host on darwin builder. overrides darwin host preferences. +darwin_CC=$(shell xcrun -f clang) -mmacosx-version-min=$(OSX_MIN_VERSION) +darwin_CXX:=$(shell xcrun -f clang++) -mmacosx-version-min=$(OSX_MIN_VERSION) -stdlib=libc++ +darwin_AR:=$(shell xcrun -f ar) +darwin_RANLIB:=$(shell xcrun -f ranlib) +darwin_STRIP:=$(shell xcrun -f strip) +darwin_LIBTOOL:=$(shell xcrun -f libtool) +darwin_OTOOL:=$(shell xcrun -f otool) +darwin_NM:=$(shell xcrun -f nm) +darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool) +darwin_native_toolchain= diff --git a/depends/builders/default.mk b/depends/builders/default.mk new file mode 100644 index 000000000..f097db65d --- /dev/null +++ b/depends/builders/default.mk @@ -0,0 +1,20 @@ +default_build_CC = gcc +default_build_CXX = g++ +default_build_AR = ar +default_build_RANLIB = ranlib +default_build_STRIP = strip +default_build_NM = nm +default_build_OTOOL = otool +default_build_INSTALL_NAME_TOOL = install_name_tool + +define add_build_tool_func +build_$(build_os)_$1 ?= $$(default_build_$1) +build_$(build_arch)_$(build_os)_$1 ?= $$(build_$(build_os)_$1) +build_$1=$$(build_$(build_arch)_$(build_os)_$1) +endef +$(foreach var,CC CXX AR RANLIB NM STRIP SHA256SUM DOWNLOAD OTOOL INSTALL_NAME_TOOL,$(eval $(call add_build_tool_func,$(var)))) +define add_build_flags_func +build_$(build_arch)_$(build_os)_$1 += $(build_$(build_os)_$1) +build_$1=$$(build_$(build_arch)_$(build_os)_$1) +endef +$(foreach flags, CFLAGS CXXFLAGS LDFLAGS, $(eval $(call add_build_flags_func,$(flags)))) diff --git a/depends/builders/linux.mk b/depends/builders/linux.mk new file mode 100644 index 000000000..b03f42401 --- /dev/null +++ b/depends/builders/linux.mk @@ -0,0 +1,2 @@ +build_linux_SHA256SUM = sha256sum +build_linux_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o diff --git a/depends/config.guess b/depends/config.guess new file mode 100755 index 000000000..bbd48b60e --- /dev/null +++ b/depends/config.guess @@ -0,0 +1,1462 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2017 Free Software Foundation, Inc. + +timestamp='2017-01-01' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# 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. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +# +# Please send patches to . + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2017 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval $set_cc_for_build + cat <<-EOF > $dummy.c + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || \ + echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently (or will in the future) and ABI. + case "${UNAME_MACHINE_ARCH}" in + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case "${UNAME_MACHINE_ARCH}" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}${abi}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:Sortix:*:*) + echo ${UNAME_MACHINE}-unknown-sortix + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE=alpha ;; + "EV4.5 (21064)") + UNAME_MACHINE=alpha ;; + "LCA4 (21066/21068)") + UNAME_MACHINE=alpha ;; + "EV5 (21164)") + UNAME_MACHINE=alphaev5 ;; + "EV5.6 (21164A)") + UNAME_MACHINE=alphaev56 ;; + "EV5.6 (21164PC)") + UNAME_MACHINE=alphapca56 ;; + "EV5.7 (21164PC)") + UNAME_MACHINE=alphapca57 ;; + "EV6 (21264)") + UNAME_MACHINE=alphaev6 ;; + "EV6.7 (21264A)") + UNAME_MACHINE=alphaev67 ;; + "EV6.8CB (21264C)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8AL (21264B)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8CX (21264D)") + UNAME_MACHINE=alphaev68 ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE=alphaev69 ;; + "EV7 (21364)") + UNAME_MACHINE=alphaev7 ;; + "EV7.9 (21364A)") + UNAME_MACHINE=alphaev79 ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH=i386 + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH=x86_64 + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = hppa2.0w ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH=hppa2.0w + else + HP_ARCH=hppa64 + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + *:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + else + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + e2k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + k1om:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + ;; + mips64el:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + openrisc*:Linux:*:*) + echo or1k-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-${LIBC} + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-${LIBC} + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} + exit ;; + riscv32:Linux:*:* | riscv64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-${LIBC} + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configure will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 + fi + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = x86; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = 386; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs + exit ;; +esac + +cat >&2 </dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/depends/config.site.in b/depends/config.site.in new file mode 100644 index 000000000..3d7c9fd43 --- /dev/null +++ b/depends/config.site.in @@ -0,0 +1,99 @@ +depends_prefix="`dirname ${ac_site_file}`/.." + +cross_compiling=maybe +host_alias=@HOST@ +ac_tool_prefix=${host_alias}- + +if test -z $with_boost; then + with_boost=$depends_prefix +fi +if test -z $with_qt_plugindir; then + with_qt_plugindir=$depends_prefix/plugins +fi +if test -z $with_qt_translationdir; then + with_qt_translationdir=$depends_prefix/translations +fi +if test -z $with_qt_bindir; then + with_qt_bindir=$depends_prefix/native/bin +fi +if test -z $with_protoc_bindir; then + with_protoc_bindir=$depends_prefix/native/bin +fi + + +if test -z $enable_wallet && test -n "@no_wallet@"; then + enable_wallet=no +fi + +if test -z $with_miniupnpc && test -n "@no_upnp@"; then + with_miniupnpc=no +fi + +if test -z $with_gui && test -n "@no_qt@"; then + with_gui=no +fi + +if test x@host_os@ = xdarwin; then + BREW=no + PORT=no +fi + +if test x@host_os@ = xmingw32; then + if test -z $with_qt_incdir; then + with_qt_incdir=$depends_prefix/include + fi + if test -z $with_qt_libdir; then + with_qt_libdir=$depends_prefix/lib + fi +fi + +PATH=$depends_prefix/native/bin:$PATH +PKG_CONFIG="`which pkg-config` --static" + +# These two need to remain exported because pkg-config does not see them +# otherwise. That means they must be unexported at the end of configure.ac to +# avoid ruining the cache. Sigh. + +export PKG_CONFIG_LIBDIR=$depends_prefix/lib/pkgconfig +export PKG_CONFIG_PATH=$depends_prefix/share/pkgconfig + +CPPFLAGS="-I$depends_prefix/include/ $CPPFLAGS" +LDFLAGS="-L$depends_prefix/lib $LDFLAGS" + +CC="@CC@" +CXX="@CXX@" +OBJC="${CC}" +CCACHE=$depends_prefix/native/bin/ccache +PYTHONPATH=$depends_prefix/native/lib/python/dist-packages:$PYTHONPATH + +if test -n "@AR@"; then + AR=@AR@ + ac_cv_path_ac_pt_AR=${AR} +fi + +if test -n "@RANLIB@"; then + RANLIB=@RANLIB@ + ac_cv_path_ac_pt_RANLIB=${RANLIB} +fi + +if test -n "@NM@"; then + NM=@NM@ + ac_cv_path_ac_pt_NM=${NM} +fi + +if test -n "@debug@"; then + enable_reduce_exports=no +fi + +if test -n "@CFLAGS@"; then + CFLAGS="@CFLAGS@ $CFLAGS" +fi +if test -n "@CXXFLAGS@"; then + CXXFLAGS="@CXXFLAGS@ $CXXFLAGS" +fi +if test -n "@CPPFLAGS@"; then + CPPFLAGS="@CPPFLAGS@ $CPPFLAGS" +fi +if test -n "@LDFLAGS@"; then + LDFLAGS="@LDFLAGS@ $LDFLAGS" +fi diff --git a/depends/config.sub b/depends/config.sub new file mode 100755 index 000000000..7e792b4ae --- /dev/null +++ b/depends/config.sub @@ -0,0 +1,1828 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2017 Free Software Foundation, Inc. + +timestamp='2017-01-01' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# 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. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2017 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + kopensolaris*-gnu* | cloudabi*-eabi* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze*) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | ba \ + | be32 | be64 \ + | bfin \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | e2k | epiphany \ + | fido | fr30 | frv | ft32 \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ + | ns16k | ns32k \ + | open8 | or1k | or1knd | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pru \ + | pyramid \ + | riscv32 | riscv64 \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | ba-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | e2k-* | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | k1om-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | or1k*-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pru-* \ + | pyramid-* \ + | riscv32-* | riscv64-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | visium-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + asmjs) + basic_machine=asmjs-unknown + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + e500v[12]) + basic_machine=powerpc-unknown + os=$os"spe" + ;; + e500v[12]-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + os=$os"spe" + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i686-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ + | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -ios) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + pru-*) + os=-elf + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/depends/funcs.mk b/depends/funcs.mk new file mode 100644 index 000000000..15e404e42 --- /dev/null +++ b/depends/funcs.mk @@ -0,0 +1,245 @@ +define int_vars +#Set defaults for vars which may be overridden per-package +$(1)_cc=$($($(1)_type)_CC) +$(1)_cxx=$($($(1)_type)_CXX) +$(1)_objc=$($($(1)_type)_OBJC) +$(1)_objcxx=$($($(1)_type)_OBJCXX) +$(1)_ar=$($($(1)_type)_AR) +$(1)_ranlib=$($($(1)_type)_RANLIB) +$(1)_libtool=$($($(1)_type)_LIBTOOL) +$(1)_nm=$($($(1)_type)_NM) +$(1)_cflags=$($($(1)_type)_CFLAGS) $($($(1)_type)_$(release_type)_CFLAGS) +$(1)_cxxflags=$($($(1)_type)_CXXFLAGS) $($($(1)_type)_$(release_type)_CXXFLAGS) +$(1)_ldflags=$($($(1)_type)_LDFLAGS) $($($(1)_type)_$(release_type)_LDFLAGS) -L$($($(1)_type)_prefix)/lib +$(1)_cppflags=$($($(1)_type)_CPPFLAGS) $($($(1)_type)_$(release_type)_CPPFLAGS) -I$($($(1)_type)_prefix)/include +$(1)_recipe_hash:= +endef + +define int_get_all_dependencies +$(sort $(foreach dep,$(2),$(2) $(call int_get_all_dependencies,$(1),$($(dep)_dependencies)))) +endef + +define fetch_file_inner + ( mkdir -p $$($(1)_download_dir) && echo Fetching $(3) from $(2) && \ + $(build_DOWNLOAD) "$$($(1)_download_dir)/$(4).temp" "$(2)/$(3)" && \ + echo "$(5) $$($(1)_download_dir)/$(4).temp" > $$($(1)_download_dir)/.$(4).hash && \ + $(build_SHA256SUM) -c $$($(1)_download_dir)/.$(4).hash && \ + mv $$($(1)_download_dir)/$(4).temp $$($(1)_source_dir)/$(4) && \ + rm -rf $$($(1)_download_dir) ) +endef + +define fetch_file + ( test -f $$($(1)_source_dir)/$(4) || \ + ( $(call fetch_file_inner,$(1),$(2),$(3),$(4),$(5)) || \ + $(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(3),$(4),$(5)))) +endef + +define int_get_build_recipe_hash +$(eval $(1)_all_file_checksums:=$(shell $(build_SHA256SUM) $(meta_depends) packages/$(1).mk $(addprefix $(PATCHES_PATH)/$(1)/,$($(1)_patches)) | cut -d" " -f1)) +$(eval $(1)_recipe_hash:=$(shell echo -n "$($(1)_all_file_checksums)" | $(build_SHA256SUM) | cut -d" " -f1)) +endef + +define int_get_build_id +$(eval $(1)_dependencies += $($(1)_$(host_arch)_$(host_os)_dependencies) $($(1)_$(host_os)_dependencies)) +$(eval $(1)_all_dependencies:=$(call int_get_all_dependencies,$(1),$($($(1)_type)_native_toolchain) $($(1)_dependencies))) +$(foreach dep,$($(1)_all_dependencies),$(eval $(1)_build_id_deps+=$(dep)-$($(dep)_version)-$($(dep)_recipe_hash))) +$(eval $(1)_build_id_long:=$(1)-$($(1)_version)-$($(1)_recipe_hash)-$(release_type) $($(1)_build_id_deps) $($($(1)_type)_id_string)) +$(eval $(1)_build_id:=$(shell echo -n "$($(1)_build_id_long)" | $(build_SHA256SUM) | cut -c-$(HASH_LENGTH))) +final_build_id_long+=$($(package)_build_id_long) + +#compute package-specific paths +$(1)_build_subdir?=. +$(1)_download_file?=$($(1)_file_name) +$(1)_source_dir:=$(SOURCES_PATH) +$(1)_source:=$$($(1)_source_dir)/$($(1)_file_name) +$(1)_staging_dir=$(base_staging_dir)/$(host)/$(1)/$($(1)_version)-$($(1)_build_id) +$(1)_staging_prefix_dir:=$$($(1)_staging_dir)$($($(1)_type)_prefix) +$(1)_extract_dir:=$(base_build_dir)/$(host)/$(1)/$($(1)_version)-$($(1)_build_id) +$(1)_download_dir:=$(base_download_dir)/$(1)-$($(1)_version) +$(1)_build_dir:=$$($(1)_extract_dir)/$$($(1)_build_subdir) +$(1)_cached_checksum:=$(BASE_CACHE)/$(host)/$(1)/$(1)-$($(1)_version)-$($(1)_build_id).tar.gz.hash +$(1)_patch_dir:=$(base_build_dir)/$(host)/$(1)/$($(1)_version)-$($(1)_build_id)/.patches-$($(1)_build_id) +$(1)_prefixbin:=$($($(1)_type)_prefix)/bin/ +$(1)_cached:=$(BASE_CACHE)/$(host)/$(1)/$(1)-$($(1)_version)-$($(1)_build_id).tar.gz +$(1)_all_sources=$($(1)_file_name) $($(1)_extra_sources) + +#stamps +$(1)_fetched=$(SOURCES_PATH)/download-stamps/.stamp_fetched-$(1)-$($(1)_file_name).hash +$(1)_extracted=$$($(1)_extract_dir)/.stamp_extracted +$(1)_preprocessed=$$($(1)_extract_dir)/.stamp_preprocessed +$(1)_cleaned=$$($(1)_extract_dir)/.stamp_cleaned +$(1)_built=$$($(1)_build_dir)/.stamp_built +$(1)_configured=$$($(1)_build_dir)/.stamp_configured +$(1)_staged=$$($(1)_staging_dir)/.stamp_staged +$(1)_postprocessed=$$($(1)_staging_prefix_dir)/.stamp_postprocessed +$(1)_download_path_fixed=$(subst :,\:,$$($(1)_download_path)) + + +#default commands +$(1)_fetch_cmds ?= $(call fetch_file,$(1),$(subst \:,:,$$($(1)_download_path_fixed)),$$($(1)_download_file),$($(1)_file_name),$($(1)_sha256_hash)) +$(1)_extract_cmds ?= mkdir -p $$($(1)_extract_dir) && echo "$$($(1)_sha256_hash) $$($(1)_source)" > $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_SHA256SUM) -c $$($(1)_extract_dir)/.$$($(1)_file_name).hash && tar --strip-components=1 -xf $$($(1)_source) +$(1)_preprocess_cmds ?= +$(1)_build_cmds ?= +$(1)_config_cmds ?= +$(1)_stage_cmds ?= +$(1)_set_vars ?= + + +all_sources+=$$($(1)_fetched) +endef +#$(foreach dep_target,$($(1)_all_dependencies),$(eval $(1)_dependency_targets=$($(dep_target)_cached))) + + +define int_config_attach_build_config +$(eval $(call $(1)_set_vars,$(1))) +$(1)_cflags+=$($(1)_cflags_$(release_type)) +$(1)_cflags+=$($(1)_cflags_$(host_arch)) $($(1)_cflags_$(host_arch)_$(release_type)) +$(1)_cflags+=$($(1)_cflags_$(host_os)) $($(1)_cflags_$(host_os)_$(release_type)) +$(1)_cflags+=$($(1)_cflags_$(host_arch)_$(host_os)) $($(1)_cflags_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_cxxflags+=$($(1)_cxxflags_$(release_type)) +$(1)_cxxflags+=$($(1)_cxxflags_$(host_arch)) $($(1)_cxxflags_$(host_arch)_$(release_type)) +$(1)_cxxflags+=$($(1)_cxxflags_$(host_os)) $($(1)_cxxflags_$(host_os)_$(release_type)) +$(1)_cxxflags+=$($(1)_cxxflags_$(host_arch)_$(host_os)) $($(1)_cxxflags_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_cppflags+=$($(1)_cppflags_$(release_type)) +$(1)_cppflags+=$($(1)_cppflags_$(host_arch)) $($(1)_cppflags_$(host_arch)_$(release_type)) +$(1)_cppflags+=$($(1)_cppflags_$(host_os)) $($(1)_cppflags_$(host_os)_$(release_type)) +$(1)_cppflags+=$($(1)_cppflags_$(host_arch)_$(host_os)) $($(1)_cppflags_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_ldflags+=$($(1)_ldflags_$(release_type)) +$(1)_ldflags+=$($(1)_ldflags_$(host_arch)) $($(1)_ldflags_$(host_arch)_$(release_type)) +$(1)_ldflags+=$($(1)_ldflags_$(host_os)) $($(1)_ldflags_$(host_os)_$(release_type)) +$(1)_ldflags+=$($(1)_ldflags_$(host_arch)_$(host_os)) $($(1)_ldflags_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_build_opts+=$$($(1)_build_opts_$(release_type)) +$(1)_build_opts+=$$($(1)_build_opts_$(host_arch)) $$($(1)_build_opts_$(host_arch)_$(release_type)) +$(1)_build_opts+=$$($(1)_build_opts_$(host_os)) $$($(1)_build_opts_$(host_os)_$(release_type)) +$(1)_build_opts+=$$($(1)_build_opts_$(host_arch)_$(host_os)) $$($(1)_build_opts_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_config_opts+=$$($(1)_config_opts_$(release_type)) +$(1)_config_opts+=$$($(1)_config_opts_$(host_arch)) $$($(1)_config_opts_$(host_arch)_$(release_type)) +$(1)_config_opts+=$$($(1)_config_opts_$(host_os)) $$($(1)_config_opts_$(host_os)_$(release_type)) +$(1)_config_opts+=$$($(1)_config_opts_$(host_arch)_$(host_os)) $$($(1)_config_opts_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_config_env+=$$($(1)_config_env_$(release_type)) +$(1)_config_env+=$($(1)_config_env_$(host_arch)) $($(1)_config_env_$(host_arch)_$(release_type)) +$(1)_config_env+=$($(1)_config_env_$(host_os)) $($(1)_config_env_$(host_os)_$(release_type)) +$(1)_config_env+=$($(1)_config_env_$(host_arch)_$(host_os)) $($(1)_config_env_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_config_env+=PKG_CONFIG_LIBDIR=$($($(1)_type)_prefix)/lib/pkgconfig +$(1)_config_env+=PKG_CONFIG_PATH=$($($(1)_type)_prefix)/share/pkgconfig +$(1)_config_env+=PATH=$(build_prefix)/bin:$(PATH) +$(1)_build_env+=PATH=$(build_prefix)/bin:$(PATH) +$(1)_stage_env+=PATH=$(build_prefix)/bin:$(PATH) +$(1)_autoconf=./configure --host=$($($(1)_type)_host) --disable-dependency-tracking --prefix=$($($(1)_type)_prefix) $$($(1)_config_opts) CC="$$($(1)_cc)" CXX="$$($(1)_cxx)" + +ifneq ($($(1)_nm),) +$(1)_autoconf += NM="$$($(1)_nm)" +endif +ifneq ($($(1)_ranlib),) +$(1)_autoconf += RANLIB="$$($(1)_ranlib)" +endif +ifneq ($($(1)_ar),) +$(1)_autoconf += AR="$$($(1)_ar)" +endif +ifneq ($($(1)_cflags),) +$(1)_autoconf += CFLAGS="$$($(1)_cflags)" +endif +ifneq ($($(1)_cxxflags),) +$(1)_autoconf += CXXFLAGS="$$($(1)_cxxflags)" +endif +ifneq ($($(1)_cppflags),) +$(1)_autoconf += CPPFLAGS="$$($(1)_cppflags)" +endif +ifneq ($($(1)_ldflags),) +$(1)_autoconf += LDFLAGS="$$($(1)_ldflags)" +endif +endef + +define int_add_cmds +$($(1)_fetched): + $(AT)mkdir -p $$(@D) $(SOURCES_PATH) + $(AT)rm -f $$@ + $(AT)touch $$@ + $(AT)cd $$(@D); $(call $(1)_fetch_cmds,$(1)) + $(AT)cd $($(1)_source_dir); $(foreach source,$($(1)_all_sources),$(build_SHA256SUM) $(source) >> $$(@);) + $(AT)touch $$@ +$($(1)_extracted): | $($(1)_fetched) + $(AT)echo Extracting $(1)... + $(AT)mkdir -p $$(@D) + $(AT)cd $$(@D); $(call $(1)_extract_cmds,$(1)) + $(AT)touch $$@ +$($(1)_preprocessed): | $($(1)_dependencies) $($(1)_extracted) + $(AT)echo Preprocessing $(1)... + $(AT)mkdir -p $$(@D) $($(1)_patch_dir) + $(AT)$(foreach patch,$($(1)_patches),cd $(PATCHES_PATH)/$(1); cp $(patch) $($(1)_patch_dir) ;) + $(AT)cd $$(@D); $(call $(1)_preprocess_cmds, $(1)) + $(AT)touch $$@ +$($(1)_configured): | $($(1)_preprocessed) + $(AT)echo Configuring $(1)... + $(AT)rm -rf $(host_prefix); mkdir -p $(host_prefix)/lib; cd $(host_prefix); $(foreach package,$($(1)_all_dependencies), tar xf $($(package)_cached); ) + $(AT)mkdir -p $$(@D) + $(AT)+cd $$(@D); $($(1)_config_env) $(call $(1)_config_cmds, $(1)) + $(AT)touch $$@ +$($(1)_built): | $($(1)_configured) + $(AT)echo Building $(1)... + $(AT)mkdir -p $$(@D) + $(AT)+cd $$(@D); $($(1)_build_env) $(call $(1)_build_cmds, $(1)) + $(AT)touch $$@ +$($(1)_staged): | $($(1)_built) + $(AT)echo Staging $(1)... + $(AT)mkdir -p $($(1)_staging_dir)/$(host_prefix) + $(AT)cd $($(1)_build_dir); $($(1)_stage_env) $(call $(1)_stage_cmds, $(1)) + $(AT)rm -rf $($(1)_extract_dir) + $(AT)touch $$@ +$($(1)_postprocessed): | $($(1)_staged) + $(AT)echo Postprocessing $(1)... + $(AT)cd $($(1)_staging_prefix_dir); $(call $(1)_postprocess_cmds) + $(AT)touch $$@ +$($(1)_cached): | $($(1)_dependencies) $($(1)_postprocessed) + $(AT)echo Caching $(1)... + $(AT)cd $$($(1)_staging_dir)/$(host_prefix); find . | sort | tar --no-recursion -czf $$($(1)_staging_dir)/$$(@F) -T - + $(AT)mkdir -p $$(@D) + $(AT)rm -rf $$(@D) && mkdir -p $$(@D) + $(AT)mv $$($(1)_staging_dir)/$$(@F) $$(@) + $(AT)rm -rf $($(1)_staging_dir) +$($(1)_cached_checksum): $($(1)_cached) + $(AT)cd $$(@D); $(build_SHA256SUM) $$( $$(@) + +.PHONY: $(1) +$(1): | $($(1)_cached_checksum) +.SECONDARY: $($(1)_cached) $($(1)_postprocessed) $($(1)_staged) $($(1)_built) $($(1)_configured) $($(1)_preprocessed) $($(1)_extracted) $($(1)_fetched) + +endef + +# These functions create the build targets for each package. They must be +# broken down into small steps so that each part is done for all packages +# before moving on to the next step. Otherwise, a package's info +# (build-id for example) would only be available to another package if it +# happened to be computed already. + +#set the type for host/build packages. +$(foreach native_package,$(native_packages),$(eval $(native_package)_type=build)) +$(foreach package,$(packages),$(eval $(package)_type=$(host_arch)_$(host_os))) + +#set overridable defaults +$(foreach package,$(all_packages),$(eval $(call int_vars,$(package)))) + +#include package files +$(foreach package,$(all_packages),$(eval include packages/$(package).mk)) + +#compute a hash of all files that comprise this package's build recipe +$(foreach package,$(all_packages),$(eval $(call int_get_build_recipe_hash,$(package)))) + +#generate a unique id for this package, incorporating its dependencies as well +$(foreach package,$(all_packages),$(eval $(call int_get_build_id,$(package)))) + +#compute final vars after reading package vars +$(foreach package,$(all_packages),$(eval $(call int_config_attach_build_config,$(package)))) + +#create build targets +$(foreach package,$(all_packages),$(eval $(call int_add_cmds,$(package)))) + +#special exception: if a toolchain package exists, all non-native packages depend on it +$(foreach package,$(packages),$(eval $($(package)_unpacked): |$($($(host_arch)_$(host_os)_native_toolchain)_cached) )) diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk new file mode 100644 index 000000000..4e58bec74 --- /dev/null +++ b/depends/hosts/darwin.mk @@ -0,0 +1,17 @@ +OSX_MIN_VERSION=10.8 +OSX_SDK_VERSION=10.11 +OSX_SDK=$(SDK_PATH)/MacOSX$(OSX_SDK_VERSION).sdk +LD64_VERSION=253.9 +darwin_CC=clang -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) +darwin_CXX=clang++ -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -stdlib=libc++ + +darwin_CFLAGS=-pipe +darwin_CXXFLAGS=$(darwin_CFLAGS) + +darwin_release_CFLAGS=-O2 +darwin_release_CXXFLAGS=$(darwin_release_CFLAGS) + +darwin_debug_CFLAGS=-O1 +darwin_debug_CXXFLAGS=$(darwin_debug_CFLAGS) + +darwin_native_toolchain=native_cctools diff --git a/depends/hosts/default.mk b/depends/hosts/default.mk new file mode 100644 index 000000000..6f60d6b3f --- /dev/null +++ b/depends/hosts/default.mk @@ -0,0 +1,26 @@ +default_host_CC = $(host_toolchain)gcc +default_host_CXX = $(host_toolchain)g++ +default_host_AR = $(host_toolchain)ar +default_host_RANLIB = $(host_toolchain)ranlib +default_host_STRIP = $(host_toolchain)strip +default_host_LIBTOOL = $(host_toolchain)libtool +default_host_INSTALL_NAME_TOOL = $(host_toolchain)install_name_tool +default_host_OTOOL = $(host_toolchain)otool +default_host_NM = $(host_toolchain)nm + +define add_host_tool_func +$(host_os)_$1?=$$(default_host_$1) +$(host_arch)_$(host_os)_$1?=$$($(host_os)_$1) +$(host_arch)_$(host_os)_$(release_type)_$1?=$$($(host_os)_$1) +host_$1=$$($(host_arch)_$(host_os)_$1) +endef + +define add_host_flags_func +$(host_arch)_$(host_os)_$1 += $($(host_os)_$1) +$(host_arch)_$(host_os)_$(release_type)_$1 += $($(host_os)_$(release_type)_$1) +host_$1 = $$($(host_arch)_$(host_os)_$1) +host_$(release_type)_$1 = $$($(host_arch)_$(host_os)_$(release_type)_$1) +endef + +$(foreach tool,CC CXX AR RANLIB STRIP NM LIBTOOL OTOOL INSTALL_NAME_TOOL,$(eval $(call add_host_tool_func,$(tool)))) +$(foreach flags,CFLAGS CXXFLAGS CPPFLAGS LDFLAGS, $(eval $(call add_host_flags_func,$(flags)))) diff --git a/depends/hosts/linux.mk b/depends/hosts/linux.mk new file mode 100644 index 000000000..b13a0f1ad --- /dev/null +++ b/depends/hosts/linux.mk @@ -0,0 +1,31 @@ +linux_CFLAGS=-pipe +linux_CXXFLAGS=$(linux_CFLAGS) + +linux_release_CFLAGS=-O2 +linux_release_CXXFLAGS=$(linux_release_CFLAGS) + +linux_debug_CFLAGS=-O1 +linux_debug_CXXFLAGS=$(linux_debug_CFLAGS) + +linux_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC + +ifeq (86,$(findstring 86,$(build_arch))) +i686_linux_CC=gcc -m32 +i686_linux_CXX=g++ -m32 +i686_linux_AR=ar +i686_linux_RANLIB=ranlib +i686_linux_NM=nm +i686_linux_STRIP=strip + +x86_64_linux_CC=gcc -m64 +x86_64_linux_CXX=g++ -m64 +x86_64_linux_AR=ar +x86_64_linux_RANLIB=ranlib +x86_64_linux_NM=nm +x86_64_linux_STRIP=strip +else +i686_linux_CC=$(default_host_CC) -m32 +i686_linux_CXX=$(default_host_CXX) -m32 +x86_64_linux_CC=$(default_host_CC) -m64 +x86_64_linux_CXX=$(default_host_CXX) -m64 +endif diff --git a/depends/hosts/mingw32.mk b/depends/hosts/mingw32.mk new file mode 100644 index 000000000..dbfb62fdc --- /dev/null +++ b/depends/hosts/mingw32.mk @@ -0,0 +1,10 @@ +mingw32_CFLAGS=-pipe +mingw32_CXXFLAGS=$(mingw32_CFLAGS) + +mingw32_release_CFLAGS=-O2 +mingw32_release_CXXFLAGS=$(mingw32_release_CFLAGS) + +mingw32_debug_CFLAGS=-O1 +mingw32_debug_CXXFLAGS=$(mingw32_debug_CFLAGS) + +mingw32_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC diff --git a/depends/packages/libevent.mk b/depends/packages/libevent.mk new file mode 100644 index 000000000..70f345e71 --- /dev/null +++ b/depends/packages/libevent.mk @@ -0,0 +1,30 @@ +package=libevent +$(package)_version=2.1.7 +$(package)_download_path=https://github.com/libevent/libevent/archive/ +$(package)_file_name=release-$($(package)_version)-rc.tar.gz +$(package)_sha256_hash=548362d202e22fe24d4c3fad38287b4f6d683e6c21503341373b89785fa6f991 + +define $(package)_preprocess_cmds + ./autogen.sh +endef + +define $(package)_set_vars + $(package)_config_opts=--disable-shared --disable-openssl --disable-libevent-regress + $(package)_config_opts_release=--disable-debug-mode + $(package)_config_opts_linux=--with-pic +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds +endef diff --git a/depends/packages/native_ccache.mk b/depends/packages/native_ccache.mk new file mode 100644 index 000000000..4ed61a49e --- /dev/null +++ b/depends/packages/native_ccache.mk @@ -0,0 +1,25 @@ +package=native_ccache +$(package)_version=3.3.3 +$(package)_download_path=https://samba.org/ftp/ccache +$(package)_file_name=ccache-$($(package)_version).tar.bz2 +$(package)_sha256_hash=2985bc5e32ebe38d2958d508eb54ddcad39eed909489c0c2988035214597ca54 + +define $(package)_set_vars +$(package)_config_opts= +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds + rm -rf lib include +endef diff --git a/depends/packages/native_cctools.mk b/depends/packages/native_cctools.mk new file mode 100644 index 000000000..44d238cc4 --- /dev/null +++ b/depends/packages/native_cctools.mk @@ -0,0 +1,65 @@ +package=native_cctools +$(package)_version=807d6fd1be5d2224872e381870c0a75387fe05e6 +$(package)_download_path=https://github.com/theuni/cctools-port/archive +$(package)_file_name=$($(package)_version).tar.gz +$(package)_sha256_hash=a09c9ba4684670a0375e42d9d67e7f12c1f62581a27f28f7c825d6d7032ccc6a +$(package)_build_subdir=cctools +$(package)_clang_version=3.7.1 +$(package)_clang_download_path=http://llvm.org/releases/$($(package)_clang_version) +$(package)_clang_download_file=clang+llvm-$($(package)_clang_version)-x86_64-linux-gnu-ubuntu-14.04.tar.xz +$(package)_clang_file_name=clang-llvm-$($(package)_clang_version)-x86_64-linux-gnu-ubuntu-14.04.tar.xz +$(package)_clang_sha256_hash=99b28a6b48e793705228a390471991386daa33a9717cd9ca007fcdde69608fd9 +$(package)_extra_sources=$($(package)_clang_file_name) + +define $(package)_fetch_cmds +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_download_file),$($(package)_file_name),$($(package)_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_clang_download_path),$($(package)_clang_download_file),$($(package)_clang_file_name),$($(package)_clang_sha256_hash)) +endef + +define $(package)_extract_cmds + mkdir -p $($(package)_extract_dir) && \ + echo "$($(package)_sha256_hash) $($(package)_source)" > $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + echo "$($(package)_clang_sha256_hash) $($(package)_source_dir)/$($(package)_clang_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + $(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + mkdir -p toolchain/bin toolchain/lib/clang/3.5/include && \ + tar --strip-components=1 -C toolchain -xf $($(package)_source_dir)/$($(package)_clang_file_name) && \ + rm -f toolchain/lib/libc++abi.so* && \ + echo "#!/bin/sh" > toolchain/bin/$(host)-dsymutil && \ + echo "exit 0" >> toolchain/bin/$(host)-dsymutil && \ + chmod +x toolchain/bin/$(host)-dsymutil && \ + tar --strip-components=1 -xf $($(package)_source) +endef + +define $(package)_set_vars +$(package)_config_opts=--target=$(host) --disable-lto-support +$(package)_ldflags+=-Wl,-rpath=\\$$$$$$$$\$$$$$$$$ORIGIN/../lib +$(package)_cc=$($(package)_extract_dir)/toolchain/bin/clang +$(package)_cxx=$($(package)_extract_dir)/toolchain/bin/clang++ +endef + +define $(package)_preprocess_cmds + cd $($(package)_build_subdir); ./autogen.sh && \ + sed -i.old "/define HAVE_PTHREADS/d" ld64/src/ld/InputFiles.h +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install && \ + cd $($(package)_extract_dir)/toolchain && \ + mkdir -p $($(package)_staging_prefix_dir)/lib/clang/$($(package)_clang_version)/include && \ + mkdir -p $($(package)_staging_prefix_dir)/bin $($(package)_staging_prefix_dir)/include && \ + cp bin/clang $($(package)_staging_prefix_dir)/bin/ &&\ + cp -P bin/clang++ $($(package)_staging_prefix_dir)/bin/ &&\ + cp lib/libLTO.so $($(package)_staging_prefix_dir)/lib/ && \ + cp -rf lib/clang/$($(package)_clang_version)/include/* $($(package)_staging_prefix_dir)/lib/clang/$($(package)_clang_version)/include/ && \ + cp bin/llvm-dsymutil $($(package)_staging_prefix_dir)/bin/$(host)-dsymutil && \ + if `test -d include/c++/`; then cp -rf include/c++/ $($(package)_staging_prefix_dir)/include/; fi && \ + if `test -d lib/c++/`; then cp -rf lib/c++/ $($(package)_staging_prefix_dir)/lib/; fi +endef diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk new file mode 100644 index 000000000..9bd618898 --- /dev/null +++ b/depends/packages/packages.mk @@ -0,0 +1,12 @@ +packages:=libevent +native_packages := native_ccache + +wallet_packages= + +upnp_packages= + +darwin_native_packages = + +ifneq ($(build_os),darwin) +darwin_native_packages += native_cctools +endif diff --git a/depends/patches/libevent/reuseaddr.patch b/depends/patches/libevent/reuseaddr.patch new file mode 100644 index 000000000..58695c11f --- /dev/null +++ b/depends/patches/libevent/reuseaddr.patch @@ -0,0 +1,21 @@ +--- old/evutil.c 2015-08-28 19:26:23.488765923 -0400 ++++ new/evutil.c 2015-08-28 19:27:41.392767019 -0400 +@@ -321,15 +321,16 @@ + int + evutil_make_listen_socket_reuseable(evutil_socket_t sock) + { +-#ifndef WIN32 + int one = 1; ++#ifndef WIN32 + /* REUSEADDR on Unix means, "don't hang on to this address after the + * listener is closed." On Windows, though, it means "don't keep other + * processes from binding to this address while we're using it. */ + return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &one, + (ev_socklen_t)sizeof(one)); + #else +- return 0; ++ return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*) &one, ++ (ev_socklen_t)sizeof(one)); + #endif + } + diff --git a/include/btc/aes256_cbc.h b/include/btc/aes256_cbc.h new file mode 100644 index 000000000..6b01ed1a5 --- /dev/null +++ b/include/btc/aes256_cbc.h @@ -0,0 +1,44 @@ +/* + The MIT License (MIT) + + Copyright (c) 2016 Jonas Schnelli + + 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 __LIBBTC_AES256_CBC_H_ +#define __LIBBTC_AES256_CBC_H_ + +#define AES_BLOCK_SIZE 16 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" + +#include + +LIBBTC_API int aes256_cbc_encrypt(const unsigned char aes_key[32], const unsigned char iv[AES_BLOCK_SIZE], const unsigned char* data, int size, int pad, unsigned char* out); +LIBBTC_API int aes256_cbc_decrypt(const unsigned char aes_key[32], const unsigned char iv[AES_BLOCK_SIZE], const unsigned char* data, int size, int pad, unsigned char* out); + +#ifdef __cplusplus +} +#endif + +#endif /* __LIBBTC_AES256_CBC_H_ */ diff --git a/include/btc/base58.h b/include/btc/base58.h new file mode 100644 index 000000000..7bc072caa --- /dev/null +++ b/include/btc/base58.h @@ -0,0 +1,46 @@ +/** + * 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 __LIBBTC_BASE58_H__ +#define __LIBBTC_BASE58_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" + +#include + +LIBBTC_API int btc_base58_encode_check(const uint8_t* data, int len, char* str, int strsize); +LIBBTC_API int btc_base58_decode_check(const char* str, uint8_t* data, size_t datalen); + +LIBBTC_API int btc_base58_encode(char* b58, size_t* b58sz, const void* data, size_t binsz); +LIBBTC_API int btc_base58_decode(void* bin, size_t* binszp, const char* b58); + + +#ifdef __cplusplus +} +#endif + +#endif //__LIBBTC_BASE58_H__ diff --git a/include/btc/bip32.h b/include/btc/bip32.h new file mode 100644 index 000000000..3071837b3 --- /dev/null +++ b/include/btc/bip32.h @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2015 Douglas J. Bakkumk + * Copyright (c) 2015 Jonas Schnelli + * + * 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 __LIBBTC_BIP32_H__ +#define __LIBBTC_BIP32_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" +#include "chainparams.h" + +#include + +#define BTC_BIP32_CHAINCODE_SIZE 32 + +typedef struct +{ + uint32_t depth; + uint32_t fingerprint; + uint32_t child_num; + uint8_t chain_code[BTC_BIP32_CHAINCODE_SIZE]; + uint8_t private_key[BTC_ECKEY_PKEY_LENGTH]; + uint8_t public_key[BTC_ECKEY_COMPRESSED_LENGTH]; +} btc_hdnode; + + +#define btc_hdnode_private_ckd_prime(X, I) btc_hdnode_private_ckd((X), ((I) | 0x80000000)) + + +LIBBTC_API btc_hdnode* btc_hdnode_new(); +LIBBTC_API btc_hdnode* btc_hdnode_copy(btc_hdnode* hdnode); +LIBBTC_API void btc_hdnode_free(btc_hdnode* node); +LIBBTC_API btc_bool btc_hdnode_public_ckd(btc_hdnode* inout, uint32_t i); +LIBBTC_API btc_bool btc_hdnode_from_seed(const uint8_t* seed, int seed_len, btc_hdnode* out); +LIBBTC_API btc_bool btc_hdnode_private_ckd(btc_hdnode* inout, uint32_t i); +LIBBTC_API void btc_hdnode_fill_public_key(btc_hdnode* node); +LIBBTC_API void btc_hdnode_serialize_public(const btc_hdnode* node, const btc_chainparams* chain, char* str, int strsize); +LIBBTC_API void btc_hdnode_serialize_private(const btc_hdnode* node, const btc_chainparams* chain, char* str, int strsize); + +/* gives out the raw sha256/ripemd160 hash */ +LIBBTC_API void btc_hdnode_get_hash160(const btc_hdnode* node, uint160 hash160_out); +LIBBTC_API void btc_hdnode_get_p2pkh_address(const btc_hdnode* node, const btc_chainparams* chain, char* str, int strsize); +LIBBTC_API btc_bool btc_hdnode_get_pub_hex(const btc_hdnode* node, char* str, size_t* strsize); +LIBBTC_API btc_bool btc_hdnode_deserialize(const char* str, const btc_chainparams* chain, btc_hdnode* node); + +//!derive btc_hdnode from extended private or extended public key orkey +//if you use pub child key derivation, pass usepubckd=true +LIBBTC_API btc_bool btc_hd_generate_key(btc_hdnode* node, const char* keypath, const uint8_t* keymaster, const uint8_t* chaincode, btc_bool usepubckd); + +//!checks if a node has the according private key (or if its a pubkey only node) +LIBBTC_API btc_bool btc_hdnode_has_privkey(btc_hdnode* node); + +#ifdef __cplusplus +} +#endif + +#endif // __LIBBTC_BIP32_H__ diff --git a/include/btc/block.h b/include/btc/block.h new file mode 100644 index 000000000..2740df604 --- /dev/null +++ b/include/btc/block.h @@ -0,0 +1,63 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Thomas Kerin + Copyright (c) 2016 libbtc developers + + 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 LIBBTC_BLOCK_H +#define LIBBTC_BLOCK_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" + +#include "buffer.h" +#include "cstr.h" +#include "hash.h" + +#include + +typedef struct btc_block_header_ { + int32_t version; + uint256 prev_block; + uint256 merkle_root; + uint32_t timestamp; + uint32_t bits; + uint32_t nonce; +} btc_block_header; + +LIBBTC_API btc_block_header* btc_block_header_new(); +LIBBTC_API void btc_block_header_free(btc_block_header* header); +LIBBTC_API int btc_block_header_deserialize(btc_block_header* header, struct const_buffer* buf); +LIBBTC_API void btc_block_header_serialize(cstring* s, const btc_block_header* header); +LIBBTC_API void btc_block_header_copy(btc_block_header* dest, const btc_block_header* src); +LIBBTC_API btc_bool btc_block_header_hash(btc_block_header* header, uint256 hash); + +#ifdef __cplusplus +} +#endif + +#endif //__LIBBTC_BLOCK_H__ diff --git a/include/btc/blockchain.h b/include/btc/blockchain.h new file mode 100644 index 000000000..531d3ab62 --- /dev/null +++ b/include/btc/blockchain.h @@ -0,0 +1,51 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Libbtc Developers + + 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 __LIBBTC_BLOCKCHAIN_H__ +#define __LIBBTC_BLOCKCHAIN_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "block.h" +#include "btc.h" + +#include +#include + +typedef struct btc_blockindex { + uint32_t height; + uint256 hash; + btc_block_header header; + struct btc_blockindex* prev; +} btc_blockindex; + +#ifdef __cplusplus +} +#endif + +#endif //__LIBBTC_BLOCKCHAIN_H__ diff --git a/include/btc/btc.h b/include/btc/btc.h new file mode 100644 index 000000000..b9bd5b356 --- /dev/null +++ b/include/btc/btc.h @@ -0,0 +1,80 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Jonas Schnelli + + 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 _LIBBTC_H_ +#define _LIBBTC_H_ + +#include +#include +#include + +typedef uint8_t btc_bool; //!serialize, c/c++ save bool + +#ifndef true +#define true 1 +#endif + +#ifndef false +#define false 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LIBBTC_API +#if defined(_WIN32) +#ifdef LIBBTC_BUILD +#define LIBBTC_API __declspec(dllexport) +#else +#define LIBBTC_API +#endif +#elif defined(__GNUC__) && defined(LIBBTC_BUILD) +#define LIBBTC_API __attribute__((visibility("default"))) +#else +#define LIBBTC_API +#endif +#endif + +#include "memory.h" + +#define BTC_ECKEY_UNCOMPRESSED_LENGTH 65 +#define BTC_ECKEY_COMPRESSED_LENGTH 33 +#define BTC_ECKEY_PKEY_LENGTH 32 +#define BTC_ECKEY_PKEY_LENGTH 32 +#define BTC_HASH_LENGTH 32 + +#define BTC_MIN(a,b) (((a)<(b))?(a):(b)) +#define BTC_MAX(a,b) (((a)>(b))?(a):(b)) + +typedef uint8_t uint256[32]; +typedef uint8_t uint160[20]; + +#ifdef __cplusplus +} +#endif + +#endif //_LIBBTC_H_ diff --git a/include/btc/buffer.h b/include/btc/buffer.h new file mode 100644 index 000000000..8b35550d2 --- /dev/null +++ b/include/btc/buffer.h @@ -0,0 +1,57 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2012 exMULTI, Inc. + Copyright (c) 2015 Jonas Schnelli + + 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 __LIBBTC_BUFFER_H__ +#define __LIBBTC_BUFFER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" + +#include + +struct buffer { + void* p; + size_t len; +}; + +struct const_buffer { + const void* p; + size_t len; +}; + +LIBBTC_API int buffer_equal(const void* a, const void* b); +LIBBTC_API void buffer_free(void* struct_buffer); +LIBBTC_API struct buffer* buffer_copy(const void* data, size_t data_len); + +#ifdef __cplusplus +} +#endif + +#endif /* __LIBBTC_BUFFER_H__ */ diff --git a/include/btc/chainparams.h b/include/btc/chainparams.h new file mode 100644 index 000000000..c00dc9624 --- /dev/null +++ b/include/btc/chainparams.h @@ -0,0 +1,75 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Jonas Schnelli + + 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 __LIBBTC_CHAINPARAMS_H__ +#define __LIBBTC_CHAINPARAMS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" + +#include +#include + +typedef struct btc_dns_seed_ { + char domain[256]; +} btc_dns_seed; + +typedef struct btc_chainparams_ { + char chainname[32]; + uint8_t b58prefix_pubkey_address; + uint8_t b58prefix_script_address; + const char bech32_hrp[5]; + uint8_t b58prefix_secret_address; //!private key + uint32_t b58prefix_bip32_privkey; + uint32_t b58prefix_bip32_pubkey; + const unsigned char netmagic[4]; + uint256 genesisblockhash; + int default_port; + btc_dns_seed dnsseeds[8]; +} btc_chainparams; + +typedef struct btc_checkpoint_ { + uint32_t height; + const char* hash; + uint32_t timestamp; + uint32_t target; +} btc_checkpoint; + +extern const btc_chainparams btc_chainparams_main; +extern const btc_chainparams btc_chainparams_test; +extern const btc_chainparams btc_chainparams_regtest; + +// the mainnet checkpoins, needs a fix size +extern const btc_checkpoint btc_mainnet_checkpoint_array[21]; + +#ifdef __cplusplus +} +#endif + +#endif //__LIBBTC_CHAINPARAMS_H__ diff --git a/include/btc/checkpoints.h b/include/btc/checkpoints.h new file mode 100644 index 000000000..5e5849b88 --- /dev/null +++ b/include/btc/checkpoints.h @@ -0,0 +1,39 @@ +/* + +The MIT License (MIT) + +Copyright (c) 2016 Jonas Schnelli + +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 __LIBBTC_CHECKPOINTS_H__ +#define __LIBBTC_CHECKPOINTS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef __cplusplus +} +#endif + +#endif //__LIBBTC_CHECKPOINTS_H__ diff --git a/include/btc/cstr.h b/include/btc/cstr.h new file mode 100644 index 000000000..9a42c6c35 --- /dev/null +++ b/include/btc/cstr.h @@ -0,0 +1,66 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 BitPay, Inc. + Copyright (c) 2015 Jonas Schnelli + + 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 __LIBBTC_CSTR_H__ +#define __LIBBTC_CSTR_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" + +#include + +typedef struct cstring { + char* str; /* string data, incl. NUL */ + size_t len; /* length of string, not including NUL */ + size_t alloc; /* total allocated buffer length */ +} cstring; + +LIBBTC_API cstring* cstr_new(const char* init_str); +LIBBTC_API cstring* cstr_new_sz(size_t sz); +LIBBTC_API cstring* cstr_new_buf(const void* buf, size_t sz); +LIBBTC_API cstring* cstr_new_cstr(const cstring* copy_str); +LIBBTC_API void cstr_free(cstring* s, int free_buf); + +LIBBTC_API int cstr_equal(const cstring* a, const cstring* b); +LIBBTC_API int cstr_compare(const cstring* a, const cstring* b); +LIBBTC_API int cstr_resize(cstring* s, size_t sz); +LIBBTC_API int cstr_erase(cstring* s, size_t pos, ssize_t len); + +LIBBTC_API int cstr_append_buf(cstring* s, const void* buf, size_t sz); +LIBBTC_API int cstr_append_cstr(cstring* s, cstring* append); + +LIBBTC_API int cstr_append_c(cstring* s, char ch); + +LIBBTC_API int cstr_alloc_minsize(cstring* s, size_t sz); +#ifdef __cplusplus +} +#endif + +#endif /* __LIBLOGDB_CSTR_H__ */ diff --git a/include/btc/ctaes.h b/include/btc/ctaes.h new file mode 100644 index 000000000..4d66c9068 --- /dev/null +++ b/include/btc/ctaes.h @@ -0,0 +1,49 @@ + /********************************************************************* + * Copyright (c) 2016 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _CTAES_H_ +#define _CTAES_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef struct { + uint16_t slice[8]; +} AES_state; + +typedef struct { + AES_state rk[11]; +} AES128_ctx; + +typedef struct { + AES_state rk[13]; +} AES192_ctx; + +typedef struct { + AES_state rk[15]; +} AES256_ctx; + +void AES128_init(AES128_ctx* ctx, const unsigned char* key16); +void AES128_encrypt(const AES128_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16); +void AES128_decrypt(const AES128_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16); + +void AES192_init(AES192_ctx* ctx, const unsigned char* key24); +void AES192_encrypt(const AES192_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16); +void AES192_decrypt(const AES192_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16); + +void AES256_init(AES256_ctx* ctx, const unsigned char* key32); +void AES256_encrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16); +void AES256_decrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/btc/ecc.h b/include/btc/ecc.h new file mode 100644 index 000000000..8226546d4 --- /dev/null +++ b/include/btc/ecc.h @@ -0,0 +1,84 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Jonas Schnelli + + 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 __LIBBTC_ECC_H__ +#define __LIBBTC_ECC_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" + +#include + +//!init static ecc context +LIBBTC_API void btc_ecc_start(void); + +//!destroys the static ecc context +LIBBTC_API void btc_ecc_stop(void); + +//!get public key from given private key +LIBBTC_API void btc_ecc_get_pubkey(const uint8_t* private_key, uint8_t* public_key, size_t* public_key_len, btc_bool compressed); + +//!ec mul tweak on given private key +LIBBTC_API btc_bool btc_ecc_private_key_tweak_add(uint8_t* private_key, const uint8_t* tweak); + +//!ec mul tweak on given public key +LIBBTC_API btc_bool btc_ecc_public_key_tweak_add(uint8_t* public_key_inout, const uint8_t* tweak); + +//!verifies a given 32byte key +LIBBTC_API btc_bool btc_ecc_verify_privatekey(const uint8_t* private_key); + +//!verifies a given public key (compressed[33] or uncompressed[65] bytes) +LIBBTC_API btc_bool btc_ecc_verify_pubkey(const uint8_t* public_key, btc_bool compressed); + +//!create a DER signature (72-74 bytes) with private key +LIBBTC_API btc_bool btc_ecc_sign(const uint8_t* private_key, const uint256 hash, unsigned char* sigder, size_t* outlen); + +//!create a compact (64bytes) signature with private key +LIBBTC_API btc_bool btc_ecc_sign_compact(const uint8_t* private_key, const uint256 hash, unsigned char* sigcomp, size_t* outlen); + +//!create a compact recoverable (65bytes) signature with private key +LIBBTC_API btc_bool btc_ecc_sign_compact_recoverable(const uint8_t* private_key, const uint256 hash, unsigned char* sigcomprec, size_t* outlen, int* recid); + +//!recover a pubkey from a signature and recid +LIBBTC_API btc_bool btc_ecc_recover_pubkey(const unsigned char* sigrec, const uint256 hash, const int recid, uint8_t* public_key, size_t *outlen); + +//!converts (and normalized) a compact signature to DER +LIBBTC_API btc_bool btc_ecc_compact_to_der_normalized(unsigned char* sigcomp_in, unsigned char* sigder_out, size_t* sigder_len_out); + +//!convert DER signature to compact +LIBBTC_API btc_bool btc_ecc_der_to_compact(unsigned char* sigder_in, size_t sigder_len, unsigned char* sigcomp_out); + +//!verify DER signature with public key +LIBBTC_API btc_bool btc_ecc_verify_sig(const uint8_t* public_key, btc_bool compressed, const uint256 hash, unsigned char* sigder, size_t siglen); + +#ifdef __cplusplus +} +#endif + +#endif //__LIBBTC_ECC_H__ diff --git a/include/btc/ecc_key.h b/include/btc/ecc_key.h new file mode 100644 index 000000000..0e3c7aac0 --- /dev/null +++ b/include/btc/ecc_key.h @@ -0,0 +1,91 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Jonas Schnelli + + 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 __LIBBTC_ECC_KEY_H__ +#define __LIBBTC_ECC_KEY_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" +#include "chainparams.h" + +#include + +typedef struct btc_key_ { + uint8_t privkey[BTC_ECKEY_PKEY_LENGTH]; +} btc_key; + +typedef struct btc_pubkey_ { + btc_bool compressed; + uint8_t pubkey[BTC_ECKEY_UNCOMPRESSED_LENGTH]; +} btc_pubkey; + +LIBBTC_API void btc_privkey_init(btc_key* privkey); +LIBBTC_API btc_bool btc_privkey_is_valid(const btc_key* privkey); +LIBBTC_API void btc_privkey_cleanse(btc_key* privkey); +LIBBTC_API void btc_privkey_gen(btc_key* privkey); +LIBBTC_API btc_bool btc_privkey_verify_pubkey(btc_key* privkey, btc_pubkey* pubkey); + +// form a WIF encoded string from the given pubkey, make sure privkey_wif is large enough and strsize_inout contains the size of the buffer +LIBBTC_API void btc_privkey_encode_wif(const btc_key* privkey, const btc_chainparams* chain, char *privkey_wif, size_t *strsize_inout); +LIBBTC_API btc_bool btc_privkey_decode_wif(const char *privkey_wif, const btc_chainparams* chain, btc_key* privkey); + +LIBBTC_API void btc_pubkey_init(btc_pubkey* pubkey); +LIBBTC_API btc_bool btc_pubkey_is_valid(const btc_pubkey* pubkey); +LIBBTC_API void btc_pubkey_cleanse(btc_pubkey* pubkey); +LIBBTC_API void btc_pubkey_from_key(const btc_key* privkey, btc_pubkey* pubkey_inout); + +//get the hash160 (single SHA256 + RIPEMD160) +LIBBTC_API void btc_pubkey_get_hash160(const btc_pubkey* pubkey, uint160 hash160); + +//get the hex representation of a pubkey, strsize must be at leat 66 bytes +LIBBTC_API btc_bool btc_pubkey_get_hex(const btc_pubkey* pubkey, char* str, size_t* strsize); + +//sign a 32byte message/hash and returns a DER encoded signature (through *sigout) +LIBBTC_API btc_bool btc_key_sign_hash(const btc_key* privkey, const uint256 hash, unsigned char* sigout, size_t* outlen); + +//sign a 32byte message/hash and returns a 64 byte compact signature (through *sigout) +LIBBTC_API btc_bool btc_key_sign_hash_compact(const btc_key* privkey, const uint256 hash, unsigned char* sigout, size_t* outlen); + +//sign a 32byte message/hash and returns a 64 byte compact signature (through *sigout) plus a 1byte recovery id +LIBBTC_API btc_bool btc_key_sign_hash_compact_recoverable(const btc_key* privkey, const uint256 hash, unsigned char* sigout, size_t* outlen, int *recid); + +LIBBTC_API btc_bool btc_key_sign_recover_pubkey(const unsigned char* sig, const uint256 hash, int recid, btc_pubkey* pubkey); + +//verifies a DER encoded signature with given pubkey and return true if valid +LIBBTC_API btc_bool btc_pubkey_verify_sig(const btc_pubkey* pubkey, const uint256 hash, unsigned char* sigder, int len); + +LIBBTC_API btc_bool btc_pubkey_getaddr_p2sh_p2wpkh(const btc_pubkey* pubkey, const btc_chainparams* chain, char *addrout); +LIBBTC_API btc_bool btc_pubkey_getaddr_p2pkh(const btc_pubkey* pubkey, const btc_chainparams* chain, char *addrout); +LIBBTC_API btc_bool btc_pubkey_getaddr_p2wpkh(const btc_pubkey* pubkey, const btc_chainparams* chain, char *addrout); + +#ifdef __cplusplus +} +#endif + +#endif //__LIBBTC_ECC_KEY_H__ diff --git a/include/btc/hash.h b/include/btc/hash.h new file mode 100644 index 000000000..3adf1258b --- /dev/null +++ b/include/btc/hash.h @@ -0,0 +1,75 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Jonas Schnelli + + 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 __LIBBTC_HASH_H__ +#define __LIBBTC_HASH_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "btc.h" + +#include "cstr.h" +#include "sha2.h" +#include "vector.h" + +LIBBTC_API static inline btc_bool btc_hash_is_empty(uint256 hash) +{ + return hash[0] == 0 && !memcmp(hash, hash + 1, 19); +} + +LIBBTC_API static inline void btc_hash_clear(uint256 hash) +{ + memset(hash, 0, BTC_HASH_LENGTH); +} + +LIBBTC_API static inline btc_bool btc_hash_equal(uint256 hash_a, uint256 hash_b) +{ + return (memcmp(hash_a, hash_b, BTC_HASH_LENGTH) == 0); +} + +//bitcoin double sha256 hash +LIBBTC_API static inline void btc_hash(const unsigned char* datain, size_t length, uint256 hashout) +{ + sha256_Raw(datain, length, hashout); + sha256_Raw(hashout, SHA256_DIGEST_LENGTH, hashout); +} + +//single sha256 hash +LIBBTC_API static inline void btc_hash_sngl_sha256(const unsigned char* datain, size_t length, uint256 hashout) +{ + sha256_Raw(datain, length, hashout); +} + +#ifdef __cplusplus +} +#endif + +#endif //__LIBBTC_HASH_H__ diff --git a/include/btc/headersdb.h b/include/btc/headersdb.h new file mode 100644 index 000000000..daf794bf9 --- /dev/null +++ b/include/btc/headersdb.h @@ -0,0 +1,81 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Jonas Schnelli + + 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 __LIBBTC_HEADERSDB_H__ +#define __LIBBTC_HEADERSDB_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" +#include "blockchain.h" +#include "buffer.h" +#include "chainparams.h" + +#include +#include +#include + +/* headers database interface, flexible function pointers in + order to support multiple backends +*/ +typedef struct btc_headers_db_interface_ +{ + /* init database handler */ + void* (*init)(const btc_chainparams* chainparams, btc_bool inmem_only); + + /* deallocs database handler */ + void (*free)(void *db); + + /* loads database from filename */ + btc_bool (*load)(void *db, const char *filename); + + /* fill in blocklocator up to the tip */ + void (*fill_blocklocator_tip)(void* db, vector *blocklocators); + + /* connect (append) a header */ + btc_blockindex *(*connect_hdr)(void* db, struct const_buffer *buf, btc_bool load_process, btc_bool *connected); + + /* get the chain tip */ + btc_blockindex* (*getchaintip)(void *db); + + /* disconnect the tip and return true if it was possible */ + btc_bool (*disconnect_tip)(void *db); + + /* check if we are using a pruned header db staring at a checkpoint */ + btc_bool (*has_checkpoint_start)(void *db); + + /* set that we are using a checkpoint as basepoint at given height with given hash */ + void (*set_checkpoint_start)(void *db, uint256 hash, uint32_t height); +} btc_headers_db_interface; + + +#ifdef __cplusplus +} +#endif + +#endif //__LIBBTC_HEADERSDB_H__ diff --git a/include/btc/headersdb_file.h b/include/btc/headersdb_file.h new file mode 100644 index 000000000..ec0d6f368 --- /dev/null +++ b/include/btc/headersdb_file.h @@ -0,0 +1,94 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Jonas Schnelli + + 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 __LIBBTC_HEADERSDB_FILE_H__ +#define __LIBBTC_HEADERSDB_FILE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" +#include "blockchain.h" +#include "buffer.h" +#include "chainparams.h" + +#include "headersdb.h" + +#include + +/* filebased headers database (including binary tree option for fast access) +*/ +typedef struct btc_headers_db_ +{ + FILE *headers_tree_file; + btc_bool read_write_file; + + void *tree_root; + btc_bool use_binary_tree; + + unsigned int max_hdr_in_mem; + btc_blockindex genesis; + btc_blockindex *chaintip; + btc_blockindex *chainbottom; +} btc_headers_db; + +btc_headers_db *btc_headers_db_new(const btc_chainparams* chainparams, btc_bool inmem_only); +void btc_headers_db_free(btc_headers_db *db); + +btc_bool btc_headers_db_load(btc_headers_db* db, const char *filename); +btc_blockindex * btc_headers_db_connect_hdr(btc_headers_db* db, struct const_buffer *buf, btc_bool load_process, btc_bool *connected); + +void btc_headers_db_fill_block_locator(btc_headers_db* db, vector *blocklocators); + +btc_blockindex * btc_headersdb_find(btc_headers_db* db, uint256 hash); +btc_blockindex * btc_headersdb_getchaintip(btc_headers_db* db); +btc_bool btc_headersdb_disconnect_tip(btc_headers_db* db); + +btc_bool btc_headersdb_has_checkpoint_start(btc_headers_db* db); +void btc_headersdb_set_checkpoint_start(btc_headers_db* db, uint256 hash, uint32_t height); + + +// interface function pointer bindings +static const btc_headers_db_interface btc_headers_db_interface_file = { + (void* (*)(const btc_chainparams*, btc_bool))btc_headers_db_new, + (void (*)(void *))btc_headers_db_free, + (btc_bool (*)(void *, const char *))btc_headers_db_load, + (void (*)(void* , vector *))btc_headers_db_fill_block_locator, + (btc_blockindex *(*)(void* , struct const_buffer *, btc_bool , btc_bool *))btc_headers_db_connect_hdr, + + (btc_blockindex* (*)(void *))btc_headersdb_getchaintip, + (btc_bool (*)(void *))btc_headersdb_disconnect_tip, + + (btc_bool (*)(void *))btc_headersdb_has_checkpoint_start, + (void (*)(void *, uint256, uint32_t))btc_headersdb_set_checkpoint_start +}; + +#ifdef __cplusplus +} +#endif + +#endif //__LIBBTC_HEADERSDB_FILE_H__ diff --git a/include/btc/memory.h b/include/btc/memory.h new file mode 100644 index 000000000..5cf69bf3c --- /dev/null +++ b/include/btc/memory.h @@ -0,0 +1,61 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2017 Jonas Schnelli + + 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 __LIBBTC_MEMORY_H__ +#define __LIBBTC_MEMORY_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" + +#include + +typedef struct btc_mem_mapper_ { + void* (*btc_malloc)(size_t size); + void* (*btc_calloc)(size_t count, size_t size); + void* (*btc_realloc)(void* ptr, size_t size); + void (*btc_free)(void* ptr); +} btc_mem_mapper; + +// set's a custom memory mapper +// this function is _not_ thread safe and must be called before anything else +LIBBTC_API void btc_mem_set_mapper(const btc_mem_mapper mapper); +LIBBTC_API void btc_mem_set_mapper_default(); + +LIBBTC_API void* btc_malloc(size_t size); +LIBBTC_API void* btc_calloc(size_t count, size_t size); +LIBBTC_API void* btc_realloc(void* ptr, size_t size); +LIBBTC_API void btc_free(void* ptr); + +LIBBTC_API volatile void *btc_mem_zero(volatile void *dst, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif //__LIBBTC_MEMORY_H__ diff --git a/include/btc/net.h b/include/btc/net.h new file mode 100644 index 000000000..e1429b791 --- /dev/null +++ b/include/btc/net.h @@ -0,0 +1,171 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Jonas Schnelli + + 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 __LIBBTC_NET_H__ +#define __LIBBTC_NET_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "btc.h" +#include "buffer.h" +#include "chainparams.h" +#include "cstr.h" +#include "protocol.h" +#include "vector.h" + +static const unsigned int BTC_P2P_MESSAGE_CHUNK_SIZE = 4096; + +enum NODE_STATE { + NODE_CONNECTING = (1 << 0), + NODE_CONNECTED = (1 << 1), + NODE_ERRORED = (1 << 2), + NODE_TIMEOUT = (1 << 3), + NODE_HEADERSYNC = (1 << 4), + NODE_BLOCKSYNC = (1 << 5), + NODE_MISSBEHAVED = (1 << 6), + NODE_DISCONNECTED = (1 << 7), + NODE_DISCONNECTED_FROM_REMOTE_PEER = (1 << 8), +}; + +/* basic group-of-nodes structure */ +struct btc_node_; +typedef struct btc_node_group_ { + void* ctx; /* flexible context usefull in conjunction with the callbacks */ + struct event_base* event_base; + vector* nodes; /* the groups nodes */ + char clientstr[1024]; + int desired_amount_connected_nodes; + const btc_chainparams* chainparams; + + /* callbacks */ + int (*log_write_cb)(const char* format, ...); /* log callback, default=printf */ + btc_bool (*parse_cmd_cb)(struct btc_node_* node, btc_p2p_msg_hdr* hdr, struct const_buffer* buf); + void (*postcmd_cb)(struct btc_node_* node, btc_p2p_msg_hdr* hdr, struct const_buffer* buf); + void (*node_connection_state_changed_cb)(struct btc_node_* node); + btc_bool (*should_connect_to_more_nodes_cb)(struct btc_node_* node); + void (*handshake_done_cb)(struct btc_node_* node); + btc_bool (*periodic_timer_cb)(struct btc_node_* node, uint64_t* time); // return false will cancle the internal logic +} btc_node_group; + +enum { + NODE_CONNECTIONSTATE_DISCONNECTED = 0, + NODE_CONNECTIONSTATE_CONNECTING = 5, + NODE_CONNECTIONSTATE_CONNECTED = 50, + NODE_CONNECTIONSTATE_ERRORED = 100, + NODE_CONNECTIONSTATE_ERRORED_TIMEOUT = 101, +}; + +/* basic node structure */ +typedef struct btc_node_ { + struct sockaddr addr; + struct bufferevent* event_bev; + struct event* timer_event; + btc_node_group* nodegroup; + int nodeid; + uint64_t lastping; + uint64_t time_started_con; + uint64_t time_last_request; + uint256 last_requested_inv; + + cstring* recvBuffer; + uint64_t nonce; + uint64_t services; + uint32_t state; + int missbehavescore; + btc_bool version_handshake; + + unsigned int bestknownheight; + + uint32_t hints; /* can be use for user defined state */ +} btc_node; + +LIBBTC_API int net_write_log_printf(const char* format, ...); + +/* =================================== */ +/* NODES */ +/* =================================== */ + +/* create new node object */ +LIBBTC_API btc_node* btc_node_new(); +LIBBTC_API void btc_node_free(btc_node* group); + +/* set the nodes ip address and port (ipv4 or ipv6)*/ +LIBBTC_API btc_bool btc_node_set_ipport(btc_node* node, const char* ipport); + +/* disconnect a node */ +LIBBTC_API void btc_node_disconnect(btc_node* node); + +/* mark a node missbehave and disconnect */ +LIBBTC_API btc_bool btc_node_missbehave(btc_node* node); + +/* =================================== */ +/* NODE GROUPS */ +/* =================================== */ + +/* create a new node group */ +LIBBTC_API btc_node_group* btc_node_group_new(const btc_chainparams* chainparams); +LIBBTC_API void btc_node_group_free(btc_node_group* group); + +/* disconnect all peers */ +LIBBTC_API void btc_node_group_shutdown(btc_node_group* group); + +/* add a node to a node group */ +LIBBTC_API void btc_node_group_add_node(btc_node_group* group, btc_node* node); + +/* start node groups event loop */ +LIBBTC_API void btc_node_group_event_loop(btc_node_group* group); + +/* connect to more nodex */ +LIBBTC_API btc_bool btc_node_group_connect_next_nodes(btc_node_group* group); + +/* get the amount of connected nodes */ +LIBBTC_API int btc_node_group_amount_of_connected_nodes(btc_node_group* group, enum NODE_STATE state); + +/* sends version command to node */ +LIBBTC_API void btc_node_send_version(btc_node* node); + +/* send arbitrary data to node */ +LIBBTC_API void btc_node_send(btc_node* node, cstring* data); + +LIBBTC_API int btc_node_parse_message(btc_node* node, btc_p2p_msg_hdr* hdr, struct const_buffer* buf); +LIBBTC_API void btc_node_connection_state_changed(btc_node* node); + +/* =================================== */ +/* DNS */ +/* =================================== */ + +LIBBTC_API btc_bool btc_node_group_add_peers_by_ip_or_seed(btc_node_group *group, const char *ips); +LIBBTC_API int btc_get_peers_from_dns(const char* seed, vector* ips_out, int port, int family); + +#ifdef __cplusplus +} +#endif + +#endif //__LIBBTC_NET_H__ diff --git a/include/btc/netspv.h b/include/btc/netspv.h new file mode 100644 index 000000000..2767ddd59 --- /dev/null +++ b/include/btc/netspv.h @@ -0,0 +1,97 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Jonas Schnelli + + 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 __LIBBTC_NETSPV_H__ +#define __LIBBTC_NETSPV_H__ + +#include "btc.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum SPV_CLIENT_STATE { + SPV_HEADER_SYNC_FLAG = (1 << 0), + SPV_FULLBLOCK_SYNC_FLAG = (1 << 1), +}; + +typedef struct btc_spv_client_ +{ + btc_node_group *nodegroup; + uint64_t last_headersrequest_time; + uint64_t oldest_item_of_interest; /* oldest key birthday (or similar) */ + btc_bool use_checkpoints; /* if false, the client will create a headers chain starting from genesis */ + const btc_chainparams *chainparams; + int stateflags; + uint64_t last_statecheck_time; + btc_bool called_sync_completed; + + void *headers_db_ctx; /* flexible headers db context */ + const btc_headers_db_interface *headers_db; /* headers db interface */ + + /* callbacks */ + /* ========= */ + + /* callback when a block(header) was connected */ + void (*header_connected)(struct btc_spv_client_ *client); + + /* callback called when we have reached the ~chaintip + will be called only once */ + void (*sync_completed)(struct btc_spv_client_ *client); + + /* callback when the header message has been processed */ + /* return false will abort further logic (like continue loading headers, etc.) */ + btc_bool (*header_message_processed)(struct btc_spv_client_ *client, btc_node *node, btc_blockindex *newtip); + + /* callback, executed on each transaction (when getting a block, merkle-block txns or inv txns) */ + void (*sync_transaction)(void *ctx, btc_tx *tx, unsigned int pos, btc_blockindex *blockindex); + void *sync_transaction_ctx; +} btc_spv_client; + + +LIBBTC_API btc_spv_client* btc_spv_client_new(const btc_chainparams *params, btc_bool debug, btc_bool headers_memonly); +LIBBTC_API void btc_spv_client_free(btc_spv_client *client); + +/* load the eventually existing headers db */ +LIBBTC_API btc_bool btc_spv_client_load(btc_spv_client *client, const char *file_path); + +/* discover peers or set peers by IP(s) (CSV) */ +LIBBTC_API void btc_spv_client_discover_peers(btc_spv_client *client, const char *ips); + +/* start the spv client main run loop */ +LIBBTC_API void btc_spv_client_runloop(btc_spv_client *client); + +/* try to request headers from a single node in the nodegroup */ +LIBBTC_API btc_bool btc_net_spv_request_headers(btc_spv_client *client); + +#ifdef __cplusplus +} +#endif + +#endif //__LIBBTC_NETSPV_H__ diff --git a/include/btc/portable_endian.h b/include/btc/portable_endian.h new file mode 100644 index 000000000..d717d4baf --- /dev/null +++ b/include/btc/portable_endian.h @@ -0,0 +1,118 @@ +/* "License": Public Domain +// I, Mathias Panzenböck, place this file hereby into the public domain. Use it at your own risk for whatever you like. +// In case there are jurisdictions that don't support putting things in the public domain you can also consider it to +// be "dual licensed" under the BSD, MIT and Apache licenses, if you want to. This code is trivial anyway. Consider it +// an example on how to get the endian conversion functions on different platforms. +*/ +#ifndef PORTABLE_ENDIAN_H__ +#define PORTABLE_ENDIAN_H__ + +#if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) + +#define __WINDOWS__ + +#endif + +#if defined(__linux__) || defined(__CYGWIN__) + +#include + +#elif defined(__APPLE__) + +#include + +#define htobe16(x) OSSwapHostToBigInt16(x) +#define htole16(x) OSSwapHostToLittleInt16(x) +#define be16toh(x) OSSwapBigToHostInt16(x) +#define le16toh(x) OSSwapLittleToHostInt16(x) + +#define htobe32(x) OSSwapHostToBigInt32(x) +#define htole32(x) OSSwapHostToLittleInt32(x) +#define be32toh(x) OSSwapBigToHostInt32(x) +#define le32toh(x) OSSwapLittleToHostInt32(x) + +#define htobe64(x) OSSwapHostToBigInt64(x) +#define htole64(x) OSSwapHostToLittleInt64(x) +#define be64toh(x) OSSwapBigToHostInt64(x) +#define le64toh(x) OSSwapLittleToHostInt64(x) + +#define __BYTE_ORDER BYTE_ORDER +#define __BIG_ENDIAN BIG_ENDIAN +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#define __PDP_ENDIAN PDP_ENDIAN + +#elif defined(__OpenBSD__) + +#include + +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) + +#include + +#define be16toh(x) betoh16(x) +#define le16toh(x) letoh16(x) + +#define be32toh(x) betoh32(x) +#define le32toh(x) letoh32(x) + +#define be64toh(x) betoh64(x) +#define le64toh(x) letoh64(x) + +#elif defined(__WINDOWS__) + +#include +#include + +#if BYTE_ORDER == LITTLE_ENDIAN + +#define htobe16(x) htons(x) +#define htole16(x) (x) +#define be16toh(x) ntohs(x) +#define le16toh(x) (x) + +#define htobe32(x) htonl(x) +#define htole32(x) (x) +#define be32toh(x) ntohl(x) +#define le32toh(x) (x) + +#define htobe64(x) htonll(x) +#define htole64(x) (x) +#define be64toh(x) ntohll(x) +#define le64toh(x) (x) + +#elif BYTE_ORDER == BIG_ENDIAN + +/* that would be xbox 360 */ +#define htobe16(x) (x) +#define htole16(x) __builtin_bswap16(x) +#define be16toh(x) (x) +#define le16toh(x) __builtin_bswap16(x) + +#define htobe32(x) (x) +#define htole32(x) __builtin_bswap32(x) +#define be32toh(x) (x) +#define le32toh(x) __builtin_bswap32(x) + +#define htobe64(x) (x) +#define htole64(x) __builtin_bswap64(x) +#define be64toh(x) (x) +#define le64toh(x) __builtin_bswap64(x) + +#else + +#error byte order not supported + +#endif + +#define __BYTE_ORDER BYTE_ORDER +#define __BIG_ENDIAN BIG_ENDIAN +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#define __PDP_ENDIAN PDP_ENDIAN + +#else + +#error platform not supported + +#endif + +#endif diff --git a/include/btc/protocol.h b/include/btc/protocol.h new file mode 100644 index 000000000..56f632b84 --- /dev/null +++ b/include/btc/protocol.h @@ -0,0 +1,186 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Jonas Schnelli + + 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 __LIBBTC_PROTOCOL_H__ +#define __LIBBTC_PROTOCOL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" + +#include "buffer.h" +#include "cstr.h" +#include "vector.h" + +#ifdef _WIN32 +#include +#include +#include +#else +#include +#include +#include +#endif + +static const unsigned int BTC_MAX_P2P_MSG_SIZE = 0x02000000; + +static const unsigned int BTC_P2P_HDRSZ = 24; //(4 + 12 + 4 + 4) magic, command, length, checksum + +static uint256 NULLHASH = {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, 0x00}; + +enum service_bits { + BTC_NODE_NETWORK = (1 << 0), +}; + +static const char* BTC_MSG_VERSION = "version"; +static const char* BTC_MSG_VERACK = "verack"; +static const char* BTC_MSG_PING = "ping"; +static const char* BTC_MSG_PONG = "pong"; +static const char* BTC_MSG_GETDATA = "getdata"; +static const char* BTC_MSG_GETHEADERS = "getheaders"; +static const char* BTC_MSG_HEADERS = "headers"; +static const char* BTC_MSG_BLOCK = "block"; +static const char* BTC_MSG_INV = "inv"; +static const char* BTC_MSG_TX = "tx"; + +enum BTC_INV_TYPE { + BTC_INV_TYPE_ERROR = 0, + BTC_INV_TYPE_TX = 1, + BTC_INV_TYPE_BLOCK = 2, + BTC_INV_TYPE_FILTERED_BLOCK = 3, + BTC_INV_TYPE_CMPCT_BLOCK = 4, +}; + +static const unsigned int MAX_HEADERS_RESULTS = 2000; +static const int BTC_PROTOCOL_VERSION = 70014; + +typedef struct btc_p2p_msg_hdr_ { + unsigned char netmagic[4]; + char command[12]; + uint32_t data_len; + unsigned char hash[4]; +} btc_p2p_msg_hdr; + +typedef struct btc_p2p_inv_msg_ { + uint32_t type; + uint256 hash; +} btc_p2p_inv_msg; + +typedef struct btc_p2p_address_ { + uint32_t time; + uint64_t services; + unsigned char ip[16]; + uint16_t port; +} btc_p2p_address; + +typedef struct btc_p2p_version_msg_ { + int32_t version; + uint64_t services; + int64_t timestamp; + btc_p2p_address addr_recv; + btc_p2p_address addr_from; + uint64_t nonce; + char useragent[128]; + int32_t start_height; + uint8_t relay; +} btc_p2p_version_msg; + +/* =================================== */ +/* VERSION MESSAGE */ +/* =================================== */ + +/* sets a version message*/ +LIBBTC_API void btc_p2p_msg_version_init(btc_p2p_version_msg* msg, const btc_p2p_address* addrFrom, const btc_p2p_address* addrTo, const char* strSubVer, btc_bool relay); + +/* serialize a p2p "version" message to an existing cstring */ +LIBBTC_API void btc_p2p_msg_version_ser(btc_p2p_version_msg* msg, cstring* buf); + +/* deserialize a p2p "version" message */ +LIBBTC_API btc_bool btc_p2p_msg_version_deser(btc_p2p_version_msg* msg, struct const_buffer* buf); + +/* =================================== */ +/* INV MESSAGE */ +/* =================================== */ + +/* sets an inv message-element*/ +LIBBTC_API void btc_p2p_msg_inv_init(btc_p2p_inv_msg* msg, uint32_t type, uint256 hash); + +/* serialize a p2p "inv" message to an existing cstring */ +LIBBTC_API void btc_p2p_msg_inv_ser(btc_p2p_inv_msg* msg, cstring* buf); + +/* deserialize a p2p "inv" message-element */ +LIBBTC_API btc_bool btc_p2p_msg_inv_deser(btc_p2p_inv_msg* msg, struct const_buffer* buf); + + +/* =================================== */ +/* ADDR MESSAGE */ +/* =================================== */ + +/* initializes a p2p address structure */ +LIBBTC_API void btc_p2p_address_init(btc_p2p_address* addr); + +/* copy over a sockaddr (IPv4/IPv6) to a p2p address struct */ +LIBBTC_API void btc_addr_to_p2paddr(struct sockaddr* addr, btc_p2p_address* addr_out); + +/* deserialize a p2p address */ +LIBBTC_API btc_bool btc_p2p_deser_addr(unsigned int protocol_version, btc_p2p_address* addr, struct const_buffer* buf); + +/* serialize a p2p addr */ +LIBBTC_API void btc_p2p_ser_addr(unsigned int protover, const btc_p2p_address* addr, cstring* str_out); + +/* copy over a p2p addr to a sockaddr object */ +LIBBTC_API void btc_p2paddr_to_addr(btc_p2p_address* p2p_addr, struct sockaddr* addr_out); + + +/* =================================== */ +/* P2P MSG-HDR */ +/* =================================== */ + +/* deserialize the p2p message header from a buffer */ +LIBBTC_API void btc_p2p_deser_msghdr(btc_p2p_msg_hdr* hdr, struct const_buffer* buf); + +/* btc_p2p_message_new does malloc a cstring, needs cleanup afterwards! */ +LIBBTC_API cstring* btc_p2p_message_new(const unsigned char netmagic[4], const char* command, const void* data, uint32_t data_len); + + +/* =================================== */ +/* GETHEADER MESSAGE */ +/* =================================== */ + +/* creates a getheader message */ +LIBBTC_API void btc_p2p_msg_getheaders(vector* blocklocators, uint256 hashstop, cstring* str_out); + +/* directly deserialize a getheaders message to blocklocators, hashstop */ +LIBBTC_API btc_bool btc_p2p_deser_msg_getheaders(vector* blocklocators, uint256 hashstop, struct const_buffer* buf); + + +#ifdef __cplusplus +} +#endif + +#endif // __LIBBTC_PROTOCOL_H__ diff --git a/include/btc/random.h b/include/btc/random.h new file mode 100644 index 000000000..6ce5b0c7c --- /dev/null +++ b/include/btc/random.h @@ -0,0 +1,56 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Douglas J. Bakkum + + 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 __LIBBTC_RANDOM_H__ +#define __LIBBTC_RANDOM_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" + +#include +#include + +typedef struct btc_rnd_mapper_ { + void (*btc_random_init)(void); + btc_bool (*btc_random_bytes)(uint8_t* buf, uint32_t len, const uint8_t update_seed); +} btc_rnd_mapper; + +// set's a custom random callback mapper +// this function is _not_ thread safe and should be called before anything else +LIBBTC_API void btc_rnd_set_mapper(const btc_rnd_mapper mapper); +LIBBTC_API void btc_rnd_set_mapper_default(); + +LIBBTC_API void btc_random_init(void); +LIBBTC_API btc_bool btc_random_bytes(uint8_t* buf, uint32_t len, const uint8_t update_seed); + +#ifdef __cplusplus +} +#endif + +#endif //__LIBBTC_TX_H__ diff --git a/include/btc/script.h b/include/btc/script.h new file mode 100644 index 000000000..f2539a8ea --- /dev/null +++ b/include/btc/script.h @@ -0,0 +1,248 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Jonas Schnelli + + 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 __LIBBTC_SCRIPT_H__ +#define __LIBBTC_SCRIPT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" + +#include "cstr.h" + +#include "ecc_key.h" +#include "vector.h" + +/** Sighash version types */ +enum btc_sig_version +{ + SIGVERSION_BASE = 0, + SIGVERSION_WITNESS_V0 = 1, +}; + +/** Signature hash types/flags */ +enum { + SIGHASH_ALL = 1, + SIGHASH_NONE = 2, + SIGHASH_SINGLE = 3, + SIGHASH_ANYONECANPAY = 0x80, +}; + +/** Script opcodes */ +enum opcodetype { + // push value + OP_0 = 0x00, + OP_FALSE = OP_0, + OP_PUSHDATA1 = 0x4c, + OP_PUSHDATA2 = 0x4d, + OP_PUSHDATA4 = 0x4e, + OP_1NEGATE = 0x4f, + OP_RESERVED = 0x50, + OP_1 = 0x51, + OP_TRUE = OP_1, + OP_2 = 0x52, + OP_3 = 0x53, + OP_4 = 0x54, + OP_5 = 0x55, + OP_6 = 0x56, + OP_7 = 0x57, + OP_8 = 0x58, + OP_9 = 0x59, + OP_10 = 0x5a, + OP_11 = 0x5b, + OP_12 = 0x5c, + OP_13 = 0x5d, + OP_14 = 0x5e, + OP_15 = 0x5f, + OP_16 = 0x60, + + // control + OP_NOP = 0x61, + OP_VER = 0x62, + OP_IF = 0x63, + OP_NOTIF = 0x64, + OP_VERIF = 0x65, + OP_VERNOTIF = 0x66, + OP_ELSE = 0x67, + OP_ENDIF = 0x68, + OP_VERIFY = 0x69, + OP_RETURN = 0x6a, + + // stack ops + OP_TOALTSTACK = 0x6b, + OP_FROMALTSTACK = 0x6c, + OP_2DROP = 0x6d, + OP_2DUP = 0x6e, + OP_3DUP = 0x6f, + OP_2OVER = 0x70, + OP_2ROT = 0x71, + OP_2SWAP = 0x72, + OP_IFDUP = 0x73, + OP_DEPTH = 0x74, + OP_DROP = 0x75, + OP_DUP = 0x76, + OP_NIP = 0x77, + OP_OVER = 0x78, + OP_PICK = 0x79, + OP_ROLL = 0x7a, + OP_ROT = 0x7b, + OP_SWAP = 0x7c, + OP_TUCK = 0x7d, + + // splice ops + OP_CAT = 0x7e, + OP_SUBSTR = 0x7f, + OP_LEFT = 0x80, + OP_RIGHT = 0x81, + OP_SIZE = 0x82, + + // bit logic + OP_INVERT = 0x83, + OP_AND = 0x84, + OP_OR = 0x85, + OP_XOR = 0x86, + OP_EQUAL = 0x87, + OP_EQUALVERIFY = 0x88, + OP_RESERVED1 = 0x89, + OP_RESERVED2 = 0x8a, + + // numeric + OP_1ADD = 0x8b, + OP_1SUB = 0x8c, + OP_2MUL = 0x8d, + OP_2DIV = 0x8e, + OP_NEGATE = 0x8f, + OP_ABS = 0x90, + OP_NOT = 0x91, + OP_0NOTEQUAL = 0x92, + + OP_ADD = 0x93, + OP_SUB = 0x94, + OP_MUL = 0x95, + OP_DIV = 0x96, + OP_MOD = 0x97, + OP_LSHIFT = 0x98, + OP_RSHIFT = 0x99, + + OP_BOOLAND = 0x9a, + OP_BOOLOR = 0x9b, + OP_NUMEQUAL = 0x9c, + OP_NUMEQUALVERIFY = 0x9d, + OP_NUMNOTEQUAL = 0x9e, + OP_LESSTHAN = 0x9f, + OP_GREATERTHAN = 0xa0, + OP_LESSTHANOREQUAL = 0xa1, + OP_GREATERTHANOREQUAL = 0xa2, + OP_MIN = 0xa3, + OP_MAX = 0xa4, + + OP_WITHIN = 0xa5, + + // crypto + OP_RIPEMD160 = 0xa6, + OP_SHA1 = 0xa7, + OP_SHA256 = 0xa8, + OP_HASH160 = 0xa9, + OP_HASH256 = 0xaa, + OP_CODESEPARATOR = 0xab, + OP_CHECKSIG = 0xac, + OP_CHECKSIGVERIFY = 0xad, + OP_CHECKMULTISIG = 0xae, + OP_CHECKMULTISIGVERIFY = 0xaf, + + // expansion + OP_NOP1 = 0xb0, + OP_NOP2 = 0xb1, + OP_CHECKLOCKTIMEVERIFY = OP_NOP2, + OP_NOP3 = 0xb2, + OP_NOP4 = 0xb3, + OP_NOP5 = 0xb4, + OP_NOP6 = 0xb5, + OP_NOP7 = 0xb6, + OP_NOP8 = 0xb7, + OP_NOP9 = 0xb8, + OP_NOP10 = 0xb9, + + + // template matching params + OP_SMALLINTEGER = 0xfa, + OP_PUBKEYS = 0xfb, + OP_PUBKEYHASH = 0xfd, + OP_PUBKEY = 0xfe, + + OP_INVALIDOPCODE = 0xff, +}; + +enum btc_tx_out_type { + BTC_TX_NONSTANDARD, + // 'standard' transaction types: + BTC_TX_PUBKEY, + BTC_TX_PUBKEYHASH, + BTC_TX_SCRIPTHASH, + BTC_TX_MULTISIG, + BTC_TX_WITNESS_V0_PUBKEYHASH, + BTC_TX_WITNESS_V0_SCRIPTHASH, +}; + +typedef struct btc_script_op_ { + enum opcodetype op; /* opcode found */ + unsigned char* data; /* associated data, if any */ + size_t datalen; +} btc_script_op; + +//copy a script without the codeseperator ops +btc_bool btc_script_copy_without_op_codeseperator(const cstring* scriptin, cstring* scriptout); + +LIBBTC_API btc_script_op* btc_script_op_new(); +LIBBTC_API void btc_script_op_free(btc_script_op* script_op); +void btc_script_op_free_cb(void* data); +btc_bool btc_script_get_ops(const cstring* script_in, vector* ops_out); + +LIBBTC_API enum btc_tx_out_type btc_script_classify_ops(const vector* ops); +LIBBTC_API enum btc_tx_out_type btc_script_classify(const cstring* script, vector* data_out); +LIBBTC_API btc_bool btc_script_extract_pkh(const cstring* script, uint8_t* data); + +LIBBTC_API enum opcodetype btc_encode_op_n(const int n); +LIBBTC_API void btc_script_append_op(cstring* script_in, enum opcodetype op); +LIBBTC_API void btc_script_append_pushdata(cstring* script_in, const unsigned char* data, const size_t datalen); + +LIBBTC_API btc_bool btc_script_build_multisig(cstring* script_in, const unsigned int required_signatures, const vector* pubkeys_chars); +LIBBTC_API btc_bool btc_script_build_p2pkh(cstring* script, const uint160 hash160); +LIBBTC_API btc_bool btc_script_build_p2wpkh(cstring* script, const uint160 hash160); +LIBBTC_API btc_bool btc_script_build_p2sh(cstring* script_in, const uint160 hash160); +LIBBTC_API btc_bool btc_script_get_scripthash(const cstring* script_in, uint160 scripthash); + +LIBBTC_API const char * btc_tx_out_type_to_str(const enum btc_tx_out_type type); + +LIBBTC_API btc_bool btc_script_is_witnessprogram(const cstring* script, uint8_t* version_out, uint8_t *program_out, int *programm_len_out); + +#ifdef __cplusplus +} +#endif + +#endif // __LIBBTC_SCRIPT_H__ diff --git a/include/btc/segwit_addr.h b/include/btc/segwit_addr.h new file mode 100644 index 000000000..dbec91b02 --- /dev/null +++ b/include/btc/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/include/btc/serialize.h b/include/btc/serialize.h new file mode 100644 index 000000000..b351e0f26 --- /dev/null +++ b/include/btc/serialize.h @@ -0,0 +1,78 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2012 exMULTI, Inc. + Copyright (c) 2015 Jonas Schnelli + + 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 __LIBBTC_SERIALIZE_H__ +#define __LIBBTC_SERIALIZE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" + +#include "buffer.h" +#include "cstr.h" + +#include "portable_endian.h" + +#include +#include + +LIBBTC_API void ser_bytes(cstring* s, const void* p, size_t len); +LIBBTC_API void ser_u16(cstring* s, uint16_t v_); +LIBBTC_API void ser_u32(cstring* s, uint32_t v_); +LIBBTC_API void ser_u64(cstring* s, uint64_t v_); +LIBBTC_API void ser_u256(cstring* s, const unsigned char* v_); +LIBBTC_API void ser_varlen(cstring* s, uint32_t vlen); +LIBBTC_API void ser_str(cstring* s, const char* s_in, size_t maxlen); +LIBBTC_API void ser_varstr(cstring* s, cstring* s_in); + +LIBBTC_API void ser_s32(cstring* s, int32_t v_); + +LIBBTC_API void ser_s64(cstring* s, int64_t v_); + +LIBBTC_API int deser_skip(struct const_buffer* buf, size_t len); +LIBBTC_API int deser_bytes(void* po, struct const_buffer* buf, size_t len); +LIBBTC_API int deser_u16(uint16_t* vo, struct const_buffer* buf); +LIBBTC_API int deser_u32(uint32_t* vo, struct const_buffer* buf); +LIBBTC_API int deser_s32(int32_t* vo, struct const_buffer* buf); +LIBBTC_API int deser_u64(uint64_t* vo, struct const_buffer* buf); +LIBBTC_API int deser_u256(uint256 vo, struct const_buffer* buf); + +LIBBTC_API int deser_varlen(uint32_t* lo, struct const_buffer* buf); +LIBBTC_API int deser_varlen_from_file(uint32_t* lo, FILE* file); +LIBBTC_API int deser_varlen_file(uint32_t* lo, FILE* file, uint8_t* rawdata, size_t* buflen_inout); +LIBBTC_API int deser_str(char* so, struct const_buffer* buf, size_t maxlen); +LIBBTC_API int deser_varstr(cstring** so, struct const_buffer* buf); + +LIBBTC_API int deser_s64(int64_t* vo, struct const_buffer* buf); + +#ifdef __cplusplus +} +#endif + +#endif /* __LIBBTC_SERIALIZE_H__ */ diff --git a/include/btc/sha2.h b/include/btc/sha2.h new file mode 100644 index 000000000..a2d9a5923 --- /dev/null +++ b/include/btc/sha2.h @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2000-2001 Aaron D. Gifford + * Copyright (c) 2013 Pavol Rusnak + * Copyright (c) 2015 Jonas Schnelli + * 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 __LIBBTC_SHA2_H__ +#define __LIBBTC_SHA2_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" + +#include +#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; + +LIBBTC_API void sha256_Init(SHA256_CTX*); +LIBBTC_API void sha256_Update(SHA256_CTX*, const uint8_t*, size_t); +LIBBTC_API void sha256_Final(uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*); +LIBBTC_API void sha256_Raw(const uint8_t*, size_t, uint8_t[SHA256_DIGEST_LENGTH]); + +LIBBTC_API void sha512_Init(SHA512_CTX*); +LIBBTC_API void sha512_Update(SHA512_CTX*, const uint8_t*, size_t); +LIBBTC_API void sha512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); +LIBBTC_API void sha512_Raw(const uint8_t*, size_t, uint8_t[SHA512_DIGEST_LENGTH]); + +LIBBTC_API void hmac_sha256(const uint8_t* key, const uint32_t keylen, const uint8_t* msg, const uint32_t msglen, uint8_t* hmac); +LIBBTC_API void hmac_sha512(const uint8_t* key, const uint32_t keylen, const uint8_t* msg, const uint32_t msglen, uint8_t* hmac); + +#ifdef __cplusplus +} +#endif + +#endif /* __LIBBTC_SHA2_H__ */ diff --git a/include/btc/tool.h b/include/btc/tool.h new file mode 100644 index 000000000..1273d793f --- /dev/null +++ b/include/btc/tool.h @@ -0,0 +1,57 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Jonas Schnelli + + 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 __LIBBTC_TOOL_H__ +#define __LIBBTC_TOOL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" +#include "tx.h" + +#include +#include + +/* generate the p2pkh address from a given hex pubkey */ +LIBBTC_API btc_bool addresses_from_pubkey(const btc_chainparams* chain, const char* pubkey_hex, char* p2pkh_address, char* p2sh_p2wpkh_address, char *p2wpkh_address); + +/* generate the hex publickey from a given hex private key */ +LIBBTC_API btc_bool pubkey_from_privatekey(const btc_chainparams* chain, const char* privkey_hex, char* pubkey_hex, size_t* sizeout); + +/* generate a new private key (hex) */ +LIBBTC_API btc_bool gen_privatekey(const btc_chainparams* chain, char* privkey_wif, size_t strsize_wif, char* privkey_hex); + +LIBBTC_API btc_bool hd_gen_master(const btc_chainparams* chain, char* masterkeyhex, size_t strsize); +LIBBTC_API btc_bool hd_print_node(const btc_chainparams* chain, const char* nodeser); +LIBBTC_API btc_bool hd_derive(const btc_chainparams* chain, const char* masterkey, const char* keypath, char* extkeyout, size_t extkeyout_size); + +#ifdef __cplusplus +} +#endif + +#endif //__LIBBTC_TOOL_H__ diff --git a/include/btc/tx.h b/include/btc/tx.h new file mode 100644 index 000000000..57aa20473 --- /dev/null +++ b/include/btc/tx.h @@ -0,0 +1,133 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Jonas Schnelli + + 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 __LIBBTC_TX_H__ +#define __LIBBTC_TX_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "btc.h" + +#include "chainparams.h" +#include "cstr.h" +#include "hash.h" +#include "script.h" +#include "vector.h" + + +typedef struct btc_script_ { + int* data; + size_t limit; // Total size of the vector + size_t current; //Number of vectors in it at present +} btc_script; + +typedef struct btc_tx_outpoint_ { + uint256 hash; + uint32_t n; +} btc_tx_outpoint; + +typedef struct btc_tx_in_ { + btc_tx_outpoint prevout; + cstring* script_sig; + uint32_t sequence; + vector* witness_stack; +} btc_tx_in; + +typedef struct btc_tx_out_ { + int64_t value; + cstring* script_pubkey; +} btc_tx_out; + +typedef struct btc_tx_ { + int32_t version; + vector* vin; + vector* vout; + uint32_t locktime; +} btc_tx; + + +//!create a new tx input +LIBBTC_API btc_tx_in* btc_tx_in_new(); +LIBBTC_API void btc_tx_in_free(btc_tx_in* tx_in); +LIBBTC_API void btc_tx_in_copy(btc_tx_in* dest, const btc_tx_in* src); + +//!create a new tx output +LIBBTC_API btc_tx_out* btc_tx_out_new(); +LIBBTC_API void btc_tx_out_free(btc_tx_out* tx_out); +LIBBTC_API void btc_tx_out_copy(btc_tx_out* dest, const btc_tx_out* src); + +//!create a new tx input +LIBBTC_API btc_tx* btc_tx_new(); +LIBBTC_API void btc_tx_free(btc_tx* tx); +LIBBTC_API void btc_tx_copy(btc_tx* dest, const btc_tx* src); + +//!deserialize/parse a p2p serialized bitcoin transaction +LIBBTC_API int btc_tx_deserialize(const unsigned char* tx_serialized, size_t inlen, btc_tx* tx, size_t* consumed_length, btc_bool allow_witness); + +//!serialize a lbc bitcoin data structure into a p2p serialized buffer +LIBBTC_API void btc_tx_serialize(cstring* s, const btc_tx* tx, btc_bool allow_witness); + +LIBBTC_API void btc_tx_hash(const btc_tx* tx, uint8_t* hashout); + +LIBBTC_API btc_bool btc_tx_sighash(const btc_tx* tx_to, const cstring* fromPubKey, unsigned int in_num, int hashtype, const uint64_t amount, const enum btc_sig_version sigversion, uint8_t* hash); + +LIBBTC_API btc_bool btc_tx_add_address_out(btc_tx* tx, const btc_chainparams* chain, int64_t amount, const char* address); +LIBBTC_API btc_bool btc_tx_add_p2sh_hash160_out(btc_tx* tx, int64_t amount, uint160 hash160); +LIBBTC_API btc_bool btc_tx_add_p2pkh_hash160_out(btc_tx* tx, int64_t amount, uint160 hash160); +LIBBTC_API btc_bool btc_tx_add_p2pkh_out(btc_tx* tx, int64_t amount, const btc_pubkey* pubkey); + +LIBBTC_API btc_bool btc_tx_add_data_out(btc_tx* tx, const int64_t amount, const uint8_t *data, const size_t datalen); +LIBBTC_API btc_bool btc_tx_add_puzzle_out(btc_tx* tx, const int64_t amount, const uint8_t *puzzle, const size_t puzzlelen); + +LIBBTC_API btc_bool btc_tx_outpoint_is_null(btc_tx_outpoint* tx); +LIBBTC_API btc_bool btc_tx_is_coinbase(btc_tx* tx); + +LIBBTC_API btc_bool btc_tx_has_witness(const btc_tx *tx); + +enum btc_tx_sign_result { + BTC_SIGN_UNKNOWN = 0, + BTC_SIGN_INVALID_KEY = -2, + BTC_SIGN_NO_KEY_MATCH = -3, //if the key found in the script doesn't match the given key, will sign anyways + BTC_SIGN_SIGHASH_FAILED = -4, + BTC_SIGN_UNKNOWN_SCRIPT_TYPE = -5, + BTC_SIGN_INVALID_TX_OR_SCRIPT = -6, + BTC_SIGN_INPUTINDEX_OUT_OF_RANGE = -7, + BTC_SIGN_OK = 1, +}; +const char* btc_tx_sign_result_to_str(const enum btc_tx_sign_result result); +enum btc_tx_sign_result btc_tx_sign_input(btc_tx *tx_in_out, const cstring *script, uint64_t amount, const btc_key *privkey, int inputindex, int sighashtype, uint8_t *sigcompact_out, uint8_t *sigder_out, int *sigder_len); + +#ifdef __cplusplus +} +#endif + +#endif //__LIBBTC_TX_H__ diff --git a/include/btc/utils.h b/include/btc/utils.h new file mode 100644 index 000000000..06cccfcf5 --- /dev/null +++ b/include/btc/utils.h @@ -0,0 +1,85 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Douglas J. Bakkum + Copyright (c) 2015 Jonas Schnelli + + 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 __LIBBTC_UTILS_H__ +#define __LIBBTC_UTILS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" +#include + +#include +#include + +#define TO_UINT8_HEX_BUF_LEN 2048 +#define VARINT_LEN 20 + +#define strlens(s) (s == NULL ? 0 : strlen(s)) + +LIBBTC_API void utils_clear_buffers(void); +LIBBTC_API void utils_hex_to_bin(const char* str, unsigned char* out, int inLen, int* outLen); +LIBBTC_API void utils_bin_to_hex(unsigned char* bin_in, size_t inlen, char* hex_out); +LIBBTC_API uint8_t* utils_hex_to_uint8(const char* str); +LIBBTC_API char* utils_uint8_to_hex(const uint8_t* bin, size_t l); +LIBBTC_API void utils_reverse_hex(char* h, int len); +LIBBTC_API void utils_uint256_sethex(char* psz, uint8_t* out); +LIBBTC_API void* safe_malloc(size_t size); +LIBBTC_API void btc_cheap_random_bytes(uint8_t* buf, uint32_t len); +LIBBTC_API void btc_get_default_datadir(cstring *path_out); +LIBBTC_API void btc_file_commit(FILE *file); + + +/* support substitude for GNU only tdestroy */ +/* Let's hope the node struct is always compatible */ + +struct btc_btree_node { + void *key; + struct btc_btree_node *left; + struct btc_btree_node *right; +}; + +static inline void btc_btree_tdestroy(void *root, void (*freekey)(void *)) +{ + struct btc_btree_node *r = root; + + if (r == 0) + return; + btc_btree_tdestroy(r->left, freekey); + btc_btree_tdestroy(r->right, freekey); + + if (freekey) freekey(r->key); + btc_free(r); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __LIBBTC_UTILS_H__*/ diff --git a/include/btc/vector.h b/include/btc/vector.h new file mode 100644 index 000000000..fd2d71748 --- /dev/null +++ b/include/btc/vector.h @@ -0,0 +1,64 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Jonas Schnelli + + 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 __LIBBTC_VECTOR_H__ +#define __LIBBTC_VECTOR_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" + +#include +#include + +typedef struct vector { + void** data; /* array of pointers */ + size_t len; /* array element count */ + size_t alloc; /* allocated array elements */ + + void (*elem_free_f)(void*); +} vector; + +LIBBTC_API vector* vector_new(size_t res, void (*free_f)(void*)); +LIBBTC_API void vector_free(vector* vec, btc_bool free_array); + +LIBBTC_API btc_bool vector_add(vector* vec, void* data); +LIBBTC_API btc_bool vector_remove(vector* vec, void* data); +LIBBTC_API void vector_remove_idx(vector* vec, size_t idx); +LIBBTC_API void vector_remove_range(vector* vec, size_t idx, size_t len); +LIBBTC_API btc_bool vector_resize(vector* vec, size_t newsz); + +LIBBTC_API ssize_t vector_find(vector* vec, void* data); + +#define vector_idx(vec, idx) ((vec)->data[(idx)]) + +#ifdef __cplusplus +} +#endif + +#endif /* __LIBBTC_VECTOR_H__ */ diff --git a/include/btc/wallet.h b/include/btc/wallet.h new file mode 100644 index 000000000..0a3c73aa3 --- /dev/null +++ b/include/btc/wallet.h @@ -0,0 +1,143 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Jonas Schnelli + + 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 __LIBBTC_WALLET_H__ +#define __LIBBTC_WALLET_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "btc.h" + +#include + +#include "bip32.h" +#include "buffer.h" +#include "tx.h" + +#include +#include + +/** single key/value record */ +typedef struct btc_wallet { + FILE *dbfile; + btc_hdnode* masterkey; + uint32_t next_childindex; //cached next child index + const btc_chainparams* chain; + uint32_t bestblockheight; + vector* spends; + + /* use binary trees for in-memory mapping for wtxs, keys */ + void* wtxes_rbtree; + void* hdkeys_rbtree; +} btc_wallet; + +typedef struct btc_wtx_ { + uint256 tx_hash_cache; + uint32_t height; + btc_tx* tx; +} btc_wtx; + +typedef struct btc_wallet_hdnode_ { + uint160 pubkeyhash; + btc_hdnode *hdnode; +} btc_wallet_hdnode; + +typedef struct btc_output_ { + uint32_t i; + btc_wtx* wtx; +} btc_output; + +/** wallet transaction (wtx) functions */ +LIBBTC_API btc_wtx* btc_wallet_wtx_new(); +LIBBTC_API void btc_wallet_wtx_free(btc_wtx* wtx); +LIBBTC_API void btc_wallet_wtx_serialize(cstring* s, const btc_wtx* wtx); +LIBBTC_API btc_bool btc_wallet_wtx_deserialize(btc_wtx* wtx, struct const_buffer* buf); +/** ------------------------------------ */ + +/** wallet hdnode (wallet_hdnode) functions */ +LIBBTC_API btc_wallet_hdnode* btc_wallet_hdnode_new(); +LIBBTC_API void btc_wallet_hdnode_free(btc_wallet_hdnode* whdnode); +LIBBTC_API void btc_wallet_hdnode_serialize(cstring* s, const btc_chainparams *params, const btc_wallet_hdnode* whdnode); +LIBBTC_API btc_bool btc_wallet_hdnode_deserialize(btc_wallet_hdnode* whdnode, const btc_chainparams *params, struct const_buffer* buf); +/** ------------------------------------ */ + +/** wallet outputs (prev wtx + n) functions */ +LIBBTC_API btc_output* btc_wallet_output_new(); +LIBBTC_API void btc_wallet_output_free(btc_output* output); +/** ------------------------------------ */ + +LIBBTC_API btc_wallet* btc_wallet_new(const btc_chainparams *params); +LIBBTC_API void btc_wallet_free(btc_wallet* wallet); + +/** load the wallet, sets masterkey, sets next_childindex */ +LIBBTC_API btc_bool btc_wallet_load(btc_wallet* wallet, const char* file_path, int *error, btc_bool *created); + +/** writes the wallet state to disk */ +LIBBTC_API btc_bool btc_wallet_flush(btc_wallet* wallet); + +/** set the master key of new created wallet + consuming app needs to ensure that we don't override exiting masterkeys */ +LIBBTC_API void btc_wallet_set_master_key_copy(btc_wallet* wallet, btc_hdnode* masterkey); + +/** derives the next child hdnode (memory is owned by the wallet) */ +LIBBTC_API btc_wallet_hdnode* btc_wallet_next_key(btc_wallet* wallet); + +/** writes all available addresses (P2PKH) to the addr_out vector */ +LIBBTC_API void btc_wallet_get_addresses(btc_wallet* wallet, vector* addr_out); + +/** searches after a hdnode by given P2PKH (base58(hash160)) address */ +LIBBTC_API btc_wallet_hdnode* btc_wallet_find_hdnode_byaddr(btc_wallet* wallet, const char* search_addr); + +/** adds transaction to the wallet (hands over memory management) */ +LIBBTC_API btc_bool btc_wallet_add_wtx_move(btc_wallet* wallet, btc_wtx* wtx); + +/** looks if a key with the hash160 (SHA256/RIPEMD) exists */ +LIBBTC_API btc_bool btc_wallet_have_key(btc_wallet* wallet, uint160 hash160); + +/** gets credit from given transaction */ +LIBBTC_API int64_t btc_wallet_get_balance(btc_wallet* wallet); + +/** gets credit from given transaction */ +LIBBTC_API int64_t btc_wallet_wtx_get_credit(btc_wallet* wallet, btc_wtx* wtx); + +/** checks if a transaction outpoint is owned by the wallet */ +LIBBTC_API btc_bool btc_wallet_txout_is_mine(btc_wallet* wallet, btc_tx_out* tx_out); + +/** checks if a transaction outpoint is owned by the wallet */ +LIBBTC_API void btc_wallet_add_to_spent(btc_wallet* wallet, btc_wtx* wtx); +LIBBTC_API btc_bool btc_wallet_is_spent(btc_wallet* wallet, uint256 hash, uint32_t n); +LIBBTC_API btc_bool btc_wallet_get_unspent(btc_wallet* wallet, vector* unspents); + +/** checks a transaction or relevance to the wallet */ +LIBBTC_API void btc_wallet_check_transaction(void *ctx, btc_tx *tx, unsigned int pos, btc_blockindex *pindex); + +#ifdef __cplusplus +} +#endif + +#endif //__LIBBTC_WALLET_H__ diff --git a/libbtc.pc b/libbtc.pc new file mode 100644 index 000000000..4586da4ae --- /dev/null +++ b/libbtc.pc @@ -0,0 +1,12 @@ +prefix=/usr/local +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: libbtc +Description: C library for manipulating bitcoin data structures +URL: https://github.com/jonasschnelli/libbtc +Version: 0.1 +Cflags: -I${includedir} +Libs: -L${libdir} -lbtc + diff --git a/libbtc.pc.in b/libbtc.pc.in new file mode 100644 index 000000000..3494a55cf --- /dev/null +++ b/libbtc.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libbtc +Description: C library for manipulating bitcoin data structures +URL: https://github.com/jonasschnelli/libbtc +Version: @PACKAGE_VERSION@ +Cflags: -I${includedir} +Libs: -L${libdir} -lbtc + diff --git a/m4/macros/with.m4 b/m4/macros/with.m4 new file mode 100644 index 000000000..908333b47 --- /dev/null +++ b/m4/macros/with.m4 @@ -0,0 +1,24 @@ + +# ARG_WITH_SUBST(option, default, help) +# ----------------------------------- +# Create a --with-$1 option with helptext, AC_SUBST($1) to $withval/default +AC_DEFUN([ARG_WITH_SUBST], + [AC_ARG_WITH( + [$1], + AS_HELP_STRING([--with-$1=arg], [$3 (default: $2).]), + [AC_SUBST(patsubst([$1], [-], [_]), ["$withval"])], + [AC_SUBST(patsubst([$1], [-], [_]), ["$2"])] + )] +) + +# ARG_WITH_SET(option, default, help) +# ----------------------------------- +# Create a --with-$1 option with helptext, set a variable $1 to $withval/default +AC_DEFUN([ARG_WITH_SET], + [AC_ARG_WITH( + [$1], + AS_HELP_STRING([--with-$1=arg], [$3 (default: $2).]), + patsubst([$1], [-], [_])="$withval", + patsubst([$1], [-], [_])=$2 + )] +) diff --git a/rpctest/.gitignore b/rpctest/.gitignore new file mode 100644 index 000000000..cb41d9442 --- /dev/null +++ b/rpctest/.gitignore @@ -0,0 +1,2 @@ +*.pyc +cache diff --git a/rpctest/spvtool.py b/rpctest/spvtool.py new file mode 100755 index 000000000..65751d907 --- /dev/null +++ b/rpctest/spvtool.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +# Copyright (c) 2017 Jonas Schnelli +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import * +import subprocess + +class SPVToolTest (BitcoinTestFramework): + def __init__(self): + super().__init__() + self.setup_clean_chain = True + self.num_nodes = 1 + self.extra_args = [['-debug=net']] + + def setup_network(self, split=False): + self.nodes = start_nodes(1, self.options.tmpdir, self.extra_args[:3]) + self.is_network_split=False + self.sync_all() + cur_time = int(time.time())- 100*600 + for i in range(100): + self.nodes[0].setmocktime(cur_time + 600) + self.nodes[0].generate(1) + cur_time += 600 + + self.nodes[0].setmocktime(cur_time + 1600) + + def execute_and_get_response(self, cmd): + dummyfile = self.options.tmpdir + "/dummy" + try: + os.remove(dummyfile) + except OSError: + pass + proc = subprocess.call(cmd+" > dummy", shell=True) + with open("dummy") as f: + data=f.read().replace('\n', '') + try: + os.remove(dummyfile) + except OSError: + pass + return data + + def run_test (self): + max_size = 1000 + log_stdout = tempfile.SpooledTemporaryFile(max_size=2**16) + log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16) + + #sync with no headers database (-f 0) and debug (-d) only against localhost + cmd = "./bitcoin-spv --regtest -f 0 -d -i 127.0.0.1:"+str(p2p_port(0))+" scan" + data = self.execute_and_get_response(cmd) + assert("parsing 1 tx(s) from block at height: 100" in data) + + # do the same with a headers db + try: + os.remove("headers.db") + except OSError: + pass + cmd = "./bitcoin-spv --regtest -d -i 127.0.0.1:"+str(p2p_port(0))+" scan" + data = self.execute_and_get_response(cmd) + assert("parsing 1 tx(s) from block at height: 100" in data) + try: + os.remove("headers.db") + except OSError: + pass + +if __name__ == '__main__': + SPVToolTest().main() diff --git a/rpctest/test_framework/__init__.py b/rpctest/test_framework/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/rpctest/test_framework/address.py b/rpctest/test_framework/address.py new file mode 100644 index 000000000..96bebe1ea --- /dev/null +++ b/rpctest/test_framework/address.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +# Copyright (c) 2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Encode and decode BASE58, P2PKH and P2SH addresses.""" + +from .script import hash256, hash160, sha256, CScript, OP_0 +from .util import bytes_to_hex_str, hex_str_to_bytes + +chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' + +def byte_to_base58(b, version): + result = '' + str = bytes_to_hex_str(b) + str = bytes_to_hex_str(chr(version).encode('latin-1')) + str + checksum = bytes_to_hex_str(hash256(hex_str_to_bytes(str))) + str += checksum[:8] + value = int('0x'+str,0) + while value > 0: + result = chars[value % 58] + result + value //= 58 + while (str[:2] == '00'): + result = chars[0] + result + str = str[2:] + return result + +# TODO: def base58_decode + +def keyhash_to_p2pkh(hash, main = False): + assert (len(hash) == 20) + version = 0 if main else 111 + return byte_to_base58(hash, version) + +def scripthash_to_p2sh(hash, main = False): + assert (len(hash) == 20) + version = 5 if main else 196 + return byte_to_base58(hash, version) + +def key_to_p2pkh(key, main = False): + key = check_key(key) + return keyhash_to_p2pkh(hash160(key), main) + +def script_to_p2sh(script, main = False): + script = check_script(script) + return scripthash_to_p2sh(hash160(script), main) + +def key_to_p2sh_p2wpkh(key, main = False): + key = check_key(key) + p2shscript = CScript([OP_0, hash160(key)]) + return script_to_p2sh(p2shscript, main) + +def script_to_p2sh_p2wsh(script, main = False): + script = check_script(script) + p2shscript = CScript([OP_0, sha256(script)]) + return script_to_p2sh(p2shscript, main) + +def check_key(key): + if (type(key) is str): + key = hex_str_to_bytes(key) # Assuming this is hex string + if (type(key) is bytes and (len(key) == 33 or len(key) == 65)): + return key + assert(False) + +def check_script(script): + if (type(script) is str): + script = hex_str_to_bytes(script) # Assuming this is hex string + if (type(script) is bytes or type(script) is CScript): + return script + assert(False) diff --git a/rpctest/test_framework/authproxy.py b/rpctest/test_framework/authproxy.py new file mode 100644 index 000000000..9ab3094b0 --- /dev/null +++ b/rpctest/test_framework/authproxy.py @@ -0,0 +1,190 @@ +# Copyright (c) 2011 Jeff Garzik +# +# Previous copyright, from python-jsonrpc/jsonrpc/proxy.py: +# +# Copyright (c) 2007 Jan-Klaas Kollhof +# +# This file is part of jsonrpc. +# +# jsonrpc 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 2.1 of the License, or +# (at your option) any later version. +# +# This software 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 software; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +"""HTTP proxy for opening RPC connection to bitcoind. + +AuthServiceProxy has the following improvements over python-jsonrpc's +ServiceProxy class: + +- HTTP connections persist for the life of the AuthServiceProxy object + (if server supports HTTP/1.1) +- sends protocol 'version', per JSON-RPC 1.1 +- sends proper, incrementing 'id' +- sends Basic HTTP authentication headers +- parses all JSON numbers that look like floats as Decimal +- uses standard Python json lib +""" + +try: + import http.client as httplib +except ImportError: + import httplib +import base64 +import decimal +import json +import logging +import socket +try: + import urllib.parse as urlparse +except ImportError: + import urlparse + +USER_AGENT = "AuthServiceProxy/0.1" + +HTTP_TIMEOUT = 30 + +log = logging.getLogger("BitcoinRPC") + +class JSONRPCException(Exception): + def __init__(self, rpc_error): + try: + errmsg = '%(message)s (%(code)i)' % rpc_error + except (KeyError, TypeError): + errmsg = '' + Exception.__init__(self, errmsg) + self.error = rpc_error + + +def EncodeDecimal(o): + if isinstance(o, decimal.Decimal): + return str(o) + raise TypeError(repr(o) + " is not JSON serializable") + +class AuthServiceProxy(object): + __id_count = 0 + + # ensure_ascii: escape unicode as \uXXXX, passed to json.dumps + def __init__(self, service_url, service_name=None, timeout=HTTP_TIMEOUT, connection=None, ensure_ascii=True): + self.__service_url = service_url + self._service_name = service_name + self.ensure_ascii = ensure_ascii # can be toggled on the fly by tests + self.__url = urlparse.urlparse(service_url) + if self.__url.port is None: + port = 80 + else: + port = self.__url.port + (user, passwd) = (self.__url.username, self.__url.password) + try: + user = user.encode('utf8') + except AttributeError: + pass + try: + passwd = passwd.encode('utf8') + except AttributeError: + pass + authpair = user + b':' + passwd + self.__auth_header = b'Basic ' + base64.b64encode(authpair) + + if connection: + # Callables re-use the connection of the original proxy + self.__conn = connection + elif self.__url.scheme == 'https': + self.__conn = httplib.HTTPSConnection(self.__url.hostname, port, + timeout=timeout) + else: + self.__conn = httplib.HTTPConnection(self.__url.hostname, port, + timeout=timeout) + + def __getattr__(self, name): + if name.startswith('__') and name.endswith('__'): + # Python internal stuff + raise AttributeError + if self._service_name is not None: + name = "%s.%s" % (self._service_name, name) + return AuthServiceProxy(self.__service_url, name, connection=self.__conn) + + def _request(self, method, path, postdata): + ''' + Do a HTTP request, with retry if we get disconnected (e.g. due to a timeout). + This is a workaround for https://bugs.python.org/issue3566 which is fixed in Python 3.5. + ''' + headers = {'Host': self.__url.hostname, + 'User-Agent': USER_AGENT, + 'Authorization': self.__auth_header, + 'Content-type': 'application/json'} + try: + self.__conn.request(method, path, postdata, headers) + return self._get_response() + except httplib.BadStatusLine as e: + if e.line == "''": # if connection was closed, try again + self.__conn.close() + self.__conn.request(method, path, postdata, headers) + return self._get_response() + else: + raise + except (BrokenPipeError,ConnectionResetError): + # Python 3.5+ raises BrokenPipeError instead of BadStatusLine when the connection was reset + # ConnectionResetError happens on FreeBSD with Python 3.4 + self.__conn.close() + self.__conn.request(method, path, postdata, headers) + return self._get_response() + + def __call__(self, *args, **argsn): + AuthServiceProxy.__id_count += 1 + + log.debug("-%s-> %s %s"%(AuthServiceProxy.__id_count, self._service_name, + json.dumps(args, default=EncodeDecimal, ensure_ascii=self.ensure_ascii))) + if args and argsn: + raise ValueError('Cannot handle both named and positional arguments') + postdata = json.dumps({'version': '1.1', + 'method': self._service_name, + 'params': args or argsn, + 'id': AuthServiceProxy.__id_count}, default=EncodeDecimal, ensure_ascii=self.ensure_ascii) + response = self._request('POST', self.__url.path, postdata.encode('utf-8')) + if response['error'] is not None: + raise JSONRPCException(response['error']) + elif 'result' not in response: + raise JSONRPCException({ + 'code': -343, 'message': 'missing JSON-RPC result'}) + else: + return response['result'] + + def _batch(self, rpc_call_list): + postdata = json.dumps(list(rpc_call_list), default=EncodeDecimal, ensure_ascii=self.ensure_ascii) + log.debug("--> "+postdata) + return self._request('POST', self.__url.path, postdata.encode('utf-8')) + + def _get_response(self): + try: + http_response = self.__conn.getresponse() + except socket.timeout as e: + raise JSONRPCException({ + 'code': -344, + 'message': '%r RPC took longer than %f seconds. Consider ' + 'using larger timeout for calls that take ' + 'longer to return.' % (self._service_name, + self.__conn.timeout)}) + if http_response is None: + raise JSONRPCException({ + 'code': -342, 'message': 'missing HTTP response from server'}) + + content_type = http_response.getheader('Content-Type') + if content_type != 'application/json': + raise JSONRPCException({ + 'code': -342, 'message': 'non-JSON HTTP response with \'%i %s\' from server' % (http_response.status, http_response.reason)}) + + responsedata = http_response.read().decode('utf8') + response = json.loads(responsedata, parse_float=decimal.Decimal) + if "error" in response and response["error"] is None: + log.debug("<-%s- %s"%(response["id"], json.dumps(response["result"], default=EncodeDecimal, ensure_ascii=self.ensure_ascii))) + else: + log.debug("<-- "+responsedata) + return response diff --git a/rpctest/test_framework/bignum.py b/rpctest/test_framework/bignum.py new file mode 100644 index 000000000..024611da6 --- /dev/null +++ b/rpctest/test_framework/bignum.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +# +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Big number routines. + +This file is copied from python-bitcoinlib. +""" + +import struct + + +# generic big endian MPI format + +def bn_bytes(v, have_ext=False): + ext = 0 + if have_ext: + ext = 1 + return ((v.bit_length()+7)//8) + ext + +def bn2bin(v): + s = bytearray() + i = bn_bytes(v) + while i > 0: + s.append((v >> ((i-1) * 8)) & 0xff) + i -= 1 + return s + +def bin2bn(s): + l = 0 + for ch in s: + l = (l << 8) | ch + return l + +def bn2mpi(v): + have_ext = False + if v.bit_length() > 0: + have_ext = (v.bit_length() & 0x07) == 0 + + neg = False + if v < 0: + neg = True + v = -v + + s = struct.pack(b">I", bn_bytes(v, have_ext)) + ext = bytearray() + if have_ext: + ext.append(0) + v_bin = bn2bin(v) + if neg: + if have_ext: + ext[0] |= 0x80 + else: + v_bin[0] |= 0x80 + return s + ext + v_bin + +def mpi2bn(s): + if len(s) < 4: + return None + s_size = bytes(s[:4]) + v_len = struct.unpack(b">I", s_size)[0] + if len(s) != (v_len + 4): + return None + if v_len == 0: + return 0 + + v_str = bytearray(s[4:]) + neg = False + i = v_str[0] + if i & 0x80: + neg = True + i &= ~0x80 + v_str[0] = i + + v = bin2bn(v_str) + + if neg: + return -v + return v + +# bitcoin-specific little endian format, with implicit size +def mpi2vch(s): + r = s[4:] # strip size + r = r[::-1] # reverse string, converting BE->LE + return r + +def bn2vch(v): + return bytes(mpi2vch(bn2mpi(v))) + +def vch2mpi(s): + r = struct.pack(b">I", len(s)) # size + r += s[::-1] # reverse string, converting LE->BE + return r + +def vch2bn(s): + return mpi2bn(vch2mpi(s)) + diff --git a/rpctest/test_framework/blockstore.py b/rpctest/test_framework/blockstore.py new file mode 100644 index 000000000..4cfd682bb --- /dev/null +++ b/rpctest/test_framework/blockstore.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""BlockStore and TxStore helper classes.""" + +from .mininode import * +from io import BytesIO +import dbm.dumb as dbmd + +logger = logging.getLogger("TestFramework.blockstore") + +class BlockStore(object): + """BlockStore helper class. + + BlockStore keeps a map of blocks and implements helper functions for + responding to getheaders and getdata, and for constructing a getheaders + message. + """ + + def __init__(self, datadir): + self.blockDB = dbmd.open(datadir + "/blocks", 'c') + self.currentBlock = 0 + self.headers_map = dict() + + def close(self): + self.blockDB.close() + + def erase(self, blockhash): + del self.blockDB[repr(blockhash)] + + # lookup an entry and return the item as raw bytes + def get(self, blockhash): + value = None + try: + value = self.blockDB[repr(blockhash)] + except KeyError: + return None + return value + + # lookup an entry and return it as a CBlock + def get_block(self, blockhash): + ret = None + serialized_block = self.get(blockhash) + if serialized_block is not None: + f = BytesIO(serialized_block) + ret = CBlock() + ret.deserialize(f) + ret.calc_sha256() + return ret + + def get_header(self, blockhash): + try: + return self.headers_map[blockhash] + except KeyError: + return None + + # Note: this pulls full blocks out of the database just to retrieve + # the headers -- perhaps we could keep a separate data structure + # to avoid this overhead. + def headers_for(self, locator, hash_stop, current_tip=None): + if current_tip is None: + current_tip = self.currentBlock + current_block_header = self.get_header(current_tip) + if current_block_header is None: + return None + + response = msg_headers() + headersList = [ current_block_header ] + maxheaders = 2000 + while (headersList[0].sha256 not in locator.vHave): + prevBlockHash = headersList[0].hashPrevBlock + prevBlockHeader = self.get_header(prevBlockHash) + if prevBlockHeader is not None: + headersList.insert(0, prevBlockHeader) + else: + break + headersList = headersList[:maxheaders] # truncate if we have too many + hashList = [x.sha256 for x in headersList] + index = len(headersList) + if (hash_stop in hashList): + index = hashList.index(hash_stop)+1 + response.headers = headersList[:index] + return response + + def add_block(self, block): + block.calc_sha256() + try: + self.blockDB[repr(block.sha256)] = bytes(block.serialize()) + except TypeError as e: + logger.exception("Unexpected error") + self.currentBlock = block.sha256 + self.headers_map[block.sha256] = CBlockHeader(block) + + def add_header(self, header): + self.headers_map[header.sha256] = header + + # lookup the hashes in "inv", and return p2p messages for delivering + # blocks found. + def get_blocks(self, inv): + responses = [] + for i in inv: + if (i.type == 2): # MSG_BLOCK + data = self.get(i.hash) + if data is not None: + # Use msg_generic to avoid re-serialization + responses.append(msg_generic(b"block", data)) + return responses + + def get_locator(self, current_tip=None): + if current_tip is None: + current_tip = self.currentBlock + r = [] + counter = 0 + step = 1 + lastBlock = self.get_block(current_tip) + while lastBlock is not None: + r.append(lastBlock.hashPrevBlock) + for i in range(step): + lastBlock = self.get_block(lastBlock.hashPrevBlock) + if lastBlock is None: + break + counter += 1 + if counter > 10: + step *= 2 + locator = CBlockLocator() + locator.vHave = r + return locator + +class TxStore(object): + def __init__(self, datadir): + self.txDB = dbmd.open(datadir + "/transactions", 'c') + + def close(self): + self.txDB.close() + + # lookup an entry and return the item as raw bytes + def get(self, txhash): + value = None + try: + value = self.txDB[repr(txhash)] + except KeyError: + return None + return value + + def get_transaction(self, txhash): + ret = None + serialized_tx = self.get(txhash) + if serialized_tx is not None: + f = BytesIO(serialized_tx) + ret = CTransaction() + ret.deserialize(f) + ret.calc_sha256() + return ret + + def add_transaction(self, tx): + tx.calc_sha256() + try: + self.txDB[repr(tx.sha256)] = bytes(tx.serialize()) + except TypeError as e: + logger.exception("Unexpected error") + + def get_transactions(self, inv): + responses = [] + for i in inv: + if (i.type == 1): # MSG_TX + tx = self.get(i.hash) + if tx is not None: + responses.append(msg_generic(b"tx", tx)) + return responses diff --git a/rpctest/test_framework/blocktools.py b/rpctest/test_framework/blocktools.py new file mode 100644 index 000000000..2c9a0857d --- /dev/null +++ b/rpctest/test_framework/blocktools.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Utilities for manipulating blocks and transactions.""" + +from .mininode import * +from .script import CScript, OP_TRUE, OP_CHECKSIG, OP_RETURN + +# Create a block (with regtest difficulty) +def create_block(hashprev, coinbase, nTime=None): + block = CBlock() + if nTime is None: + import time + block.nTime = int(time.time()+600) + else: + block.nTime = nTime + block.hashPrevBlock = hashprev + block.nBits = 0x207fffff # Will break after a difficulty adjustment... + block.vtx.append(coinbase) + block.hashMerkleRoot = block.calc_merkle_root() + block.calc_sha256() + return block + +# From BIP141 +WITNESS_COMMITMENT_HEADER = b"\xaa\x21\xa9\xed" + +# According to BIP141, blocks with witness rules active must commit to the +# hash of all in-block transactions including witness. +def add_witness_commitment(block, nonce=0): + # First calculate the merkle root of the block's + # transactions, with witnesses. + witness_nonce = nonce + witness_root = block.calc_witness_merkle_root() + witness_commitment = uint256_from_str(hash256(ser_uint256(witness_root)+ser_uint256(witness_nonce))) + # witness_nonce should go to coinbase witness. + block.vtx[0].wit.vtxinwit = [CTxInWitness()] + block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(witness_nonce)] + + # witness commitment is the last OP_RETURN output in coinbase + output_data = WITNESS_COMMITMENT_HEADER + ser_uint256(witness_commitment) + block.vtx[0].vout.append(CTxOut(0, CScript([OP_RETURN, output_data]))) + block.vtx[0].rehash() + block.hashMerkleRoot = block.calc_merkle_root() + block.rehash() + + +def serialize_script_num(value): + r = bytearray(0) + if value == 0: + return r + neg = value < 0 + absvalue = -value if neg else value + while (absvalue): + r.append(int(absvalue & 0xff)) + absvalue >>= 8 + if r[-1] & 0x80: + r.append(0x80 if neg else 0) + elif neg: + r[-1] |= 0x80 + return r + +# Create a coinbase transaction, assuming no miner fees. +# If pubkey is passed in, the coinbase output will be a P2PK output; +# otherwise an anyone-can-spend output. +def create_coinbase(height, pubkey = None): + coinbase = CTransaction() + coinbase.vin.append(CTxIn(COutPoint(0, 0xffffffff), + ser_string(serialize_script_num(height)), 0xffffffff)) + coinbaseoutput = CTxOut() + coinbaseoutput.nValue = 50 * COIN + halvings = int(height/150) # regtest + coinbaseoutput.nValue >>= halvings + if (pubkey != None): + coinbaseoutput.scriptPubKey = CScript([pubkey, OP_CHECKSIG]) + else: + coinbaseoutput.scriptPubKey = CScript([OP_TRUE]) + coinbase.vout = [ coinbaseoutput ] + coinbase.calc_sha256() + return coinbase + +# Create a transaction. +# If the scriptPubKey is not specified, make it anyone-can-spend. +def create_transaction(prevtx, n, sig, value, scriptPubKey=CScript()): + tx = CTransaction() + assert(n < len(prevtx.vout)) + tx.vin.append(CTxIn(COutPoint(prevtx.sha256, n), sig, 0xffffffff)) + tx.vout.append(CTxOut(value, scriptPubKey)) + tx.calc_sha256() + return tx + +def get_legacy_sigopcount_block(block, fAccurate=True): + count = 0 + for tx in block.vtx: + count += get_legacy_sigopcount_tx(tx, fAccurate) + return count + +def get_legacy_sigopcount_tx(tx, fAccurate=True): + count = 0 + for i in tx.vout: + count += i.scriptPubKey.GetSigOpCount(fAccurate) + for j in tx.vin: + # scriptSig might be of type bytes, so convert to CScript for the moment + count += CScript(j.scriptSig).GetSigOpCount(fAccurate) + return count diff --git a/rpctest/test_framework/comptool.py b/rpctest/test_framework/comptool.py new file mode 100755 index 000000000..25c18bda8 --- /dev/null +++ b/rpctest/test_framework/comptool.py @@ -0,0 +1,410 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Compare two or more bitcoinds to each other. + +To use, create a class that implements get_tests(), and pass it in +as the test generator to TestManager. get_tests() should be a python +generator that returns TestInstance objects. See below for definition. + +TestNode behaves as follows: + Configure with a BlockStore and TxStore + on_inv: log the message but don't request + on_headers: log the chain tip + on_pong: update ping response map (for synchronization) + on_getheaders: provide headers via BlockStore + on_getdata: provide blocks via BlockStore +""" + +from .mininode import * +from .blockstore import BlockStore, TxStore +from .util import p2p_port + +import logging + +logger=logging.getLogger("TestFramework.comptool") + +global mininode_lock + +class RejectResult(object): + """Outcome that expects rejection of a transaction or block.""" + def __init__(self, code, reason=b''): + self.code = code + self.reason = reason + def match(self, other): + if self.code != other.code: + return False + return other.reason.startswith(self.reason) + def __repr__(self): + return '%i:%s' % (self.code,self.reason or '*') + +class TestNode(NodeConnCB): + + def __init__(self, block_store, tx_store): + super().__init__() + self.conn = None + self.bestblockhash = None + self.block_store = block_store + self.block_request_map = {} + self.tx_store = tx_store + self.tx_request_map = {} + self.block_reject_map = {} + self.tx_reject_map = {} + + # When the pingmap is non-empty we're waiting for + # a response + self.pingMap = {} + self.lastInv = [] + self.closed = False + + def on_close(self, conn): + self.closed = True + + def add_connection(self, conn): + self.conn = conn + + def on_headers(self, conn, message): + if len(message.headers) > 0: + best_header = message.headers[-1] + best_header.calc_sha256() + self.bestblockhash = best_header.sha256 + + def on_getheaders(self, conn, message): + response = self.block_store.headers_for(message.locator, message.hashstop) + if response is not None: + conn.send_message(response) + + def on_getdata(self, conn, message): + [conn.send_message(r) for r in self.block_store.get_blocks(message.inv)] + [conn.send_message(r) for r in self.tx_store.get_transactions(message.inv)] + + for i in message.inv: + if i.type == 1: + self.tx_request_map[i.hash] = True + elif i.type == 2: + self.block_request_map[i.hash] = True + + def on_inv(self, conn, message): + self.lastInv = [x.hash for x in message.inv] + + def on_pong(self, conn, message): + try: + del self.pingMap[message.nonce] + except KeyError: + raise AssertionError("Got pong for unknown ping [%s]" % repr(message)) + + def on_reject(self, conn, message): + if message.message == b'tx': + self.tx_reject_map[message.data] = RejectResult(message.code, message.reason) + if message.message == b'block': + self.block_reject_map[message.data] = RejectResult(message.code, message.reason) + + def send_inv(self, obj): + mtype = 2 if isinstance(obj, CBlock) else 1 + self.conn.send_message(msg_inv([CInv(mtype, obj.sha256)])) + + def send_getheaders(self): + # We ask for headers from their last tip. + m = msg_getheaders() + m.locator = self.block_store.get_locator(self.bestblockhash) + self.conn.send_message(m) + + def send_header(self, header): + m = msg_headers() + m.headers.append(header) + self.conn.send_message(m) + + # This assumes BIP31 + def send_ping(self, nonce): + self.pingMap[nonce] = True + self.conn.send_message(msg_ping(nonce)) + + def received_ping_response(self, nonce): + return nonce not in self.pingMap + + def send_mempool(self): + self.lastInv = [] + self.conn.send_message(msg_mempool()) + +# TestInstance: +# +# Instances of these are generated by the test generator, and fed into the +# comptool. +# +# "blocks_and_transactions" should be an array of +# [obj, True/False/None, hash/None]: +# - obj is either a CBlock, CBlockHeader, or a CTransaction, and +# - the second value indicates whether the object should be accepted +# into the blockchain or mempool (for tests where we expect a certain +# answer), or "None" if we don't expect a certain answer and are just +# comparing the behavior of the nodes being tested. +# - the third value is the hash to test the tip against (if None or omitted, +# use the hash of the block) +# - NOTE: if a block header, no test is performed; instead the header is +# just added to the block_store. This is to facilitate block delivery +# when communicating with headers-first clients (when withholding an +# intermediate block). +# sync_every_block: if True, then each block will be inv'ed, synced, and +# nodes will be tested based on the outcome for the block. If False, +# then inv's accumulate until all blocks are processed (or max inv size +# is reached) and then sent out in one inv message. Then the final block +# will be synced across all connections, and the outcome of the final +# block will be tested. +# sync_every_tx: analogous to behavior for sync_every_block, except if outcome +# on the final tx is None, then contents of entire mempool are compared +# across all connections. (If outcome of final tx is specified as true +# or false, then only the last tx is tested against outcome.) + +class TestInstance(object): + def __init__(self, objects=None, sync_every_block=True, sync_every_tx=False): + self.blocks_and_transactions = objects if objects else [] + self.sync_every_block = sync_every_block + self.sync_every_tx = sync_every_tx + +class TestManager(object): + + def __init__(self, testgen, datadir): + self.test_generator = testgen + self.connections = [] + self.test_nodes = [] + self.block_store = BlockStore(datadir) + self.tx_store = TxStore(datadir) + self.ping_counter = 1 + + def add_all_connections(self, nodes): + for i in range(len(nodes)): + # Create a p2p connection to each node + test_node = TestNode(self.block_store, self.tx_store) + self.test_nodes.append(test_node) + self.connections.append(NodeConn('127.0.0.1', p2p_port(i), nodes[i], test_node)) + # Make sure the TestNode (callback class) has a reference to its + # associated NodeConn + test_node.add_connection(self.connections[-1]) + + def clear_all_connections(self): + self.connections = [] + self.test_nodes = [] + + def wait_for_disconnections(self): + def disconnected(): + return all(node.closed for node in self.test_nodes) + return wait_until(disconnected, timeout=10) + + def wait_for_verack(self): + def veracked(): + return all(node.verack_received for node in self.test_nodes) + return wait_until(veracked, timeout=10) + + def wait_for_pings(self, counter): + def received_pongs(): + return all(node.received_ping_response(counter) for node in self.test_nodes) + return wait_until(received_pongs) + + # sync_blocks: Wait for all connections to request the blockhash given + # then send get_headers to find out the tip of each node, and synchronize + # the response by using a ping (and waiting for pong with same nonce). + def sync_blocks(self, blockhash, num_blocks): + def blocks_requested(): + return all( + blockhash in node.block_request_map and node.block_request_map[blockhash] + for node in self.test_nodes + ) + + # --> error if not requested + if not wait_until(blocks_requested, attempts=20*num_blocks): + raise AssertionError("Not all nodes requested block") + + # Send getheaders message + [ c.cb.send_getheaders() for c in self.connections ] + + # Send ping and wait for response -- synchronization hack + [ c.cb.send_ping(self.ping_counter) for c in self.connections ] + self.wait_for_pings(self.ping_counter) + self.ping_counter += 1 + + # Analogous to sync_block (see above) + def sync_transaction(self, txhash, num_events): + # Wait for nodes to request transaction (50ms sleep * 20 tries * num_events) + def transaction_requested(): + return all( + txhash in node.tx_request_map and node.tx_request_map[txhash] + for node in self.test_nodes + ) + + # --> error if not requested + if not wait_until(transaction_requested, attempts=20*num_events): + raise AssertionError("Not all nodes requested transaction") + + # Get the mempool + [ c.cb.send_mempool() for c in self.connections ] + + # Send ping and wait for response -- synchronization hack + [ c.cb.send_ping(self.ping_counter) for c in self.connections ] + self.wait_for_pings(self.ping_counter) + self.ping_counter += 1 + + # Sort inv responses from each node + with mininode_lock: + [ c.cb.lastInv.sort() for c in self.connections ] + + # Verify that the tip of each connection all agree with each other, and + # with the expected outcome (if given) + def check_results(self, blockhash, outcome): + with mininode_lock: + for c in self.connections: + if outcome is None: + if c.cb.bestblockhash != self.connections[0].cb.bestblockhash: + return False + elif isinstance(outcome, RejectResult): # Check that block was rejected w/ code + if c.cb.bestblockhash == blockhash: + return False + if blockhash not in c.cb.block_reject_map: + logger.error('Block not in reject map: %064x' % (blockhash)) + return False + if not outcome.match(c.cb.block_reject_map[blockhash]): + logger.error('Block rejected with %s instead of expected %s: %064x' % (c.cb.block_reject_map[blockhash], outcome, blockhash)) + return False + elif ((c.cb.bestblockhash == blockhash) != outcome): + return False + return True + + # Either check that the mempools all agree with each other, or that + # txhash's presence in the mempool matches the outcome specified. + # This is somewhat of a strange comparison, in that we're either comparing + # a particular tx to an outcome, or the entire mempools altogether; + # perhaps it would be useful to add the ability to check explicitly that + # a particular tx's existence in the mempool is the same across all nodes. + def check_mempool(self, txhash, outcome): + with mininode_lock: + for c in self.connections: + if outcome is None: + # Make sure the mempools agree with each other + if c.cb.lastInv != self.connections[0].cb.lastInv: + return False + elif isinstance(outcome, RejectResult): # Check that tx was rejected w/ code + if txhash in c.cb.lastInv: + return False + if txhash not in c.cb.tx_reject_map: + logger.error('Tx not in reject map: %064x' % (txhash)) + return False + if not outcome.match(c.cb.tx_reject_map[txhash]): + logger.error('Tx rejected with %s instead of expected %s: %064x' % (c.cb.tx_reject_map[txhash], outcome, txhash)) + return False + elif ((txhash in c.cb.lastInv) != outcome): + return False + return True + + def run(self): + # Wait until verack is received + self.wait_for_verack() + + test_number = 1 + for test_instance in self.test_generator.get_tests(): + # We use these variables to keep track of the last block + # and last transaction in the tests, which are used + # if we're not syncing on every block or every tx. + [ block, block_outcome, tip ] = [ None, None, None ] + [ tx, tx_outcome ] = [ None, None ] + invqueue = [] + + for test_obj in test_instance.blocks_and_transactions: + b_or_t = test_obj[0] + outcome = test_obj[1] + # Determine if we're dealing with a block or tx + if isinstance(b_or_t, CBlock): # Block test runner + block = b_or_t + block_outcome = outcome + tip = block.sha256 + # each test_obj can have an optional third argument + # to specify the tip we should compare with + # (default is to use the block being tested) + if len(test_obj) >= 3: + tip = test_obj[2] + + # Add to shared block_store, set as current block + # If there was an open getdata request for the block + # previously, and we didn't have an entry in the + # block_store, then immediately deliver, because the + # node wouldn't send another getdata request while + # the earlier one is outstanding. + first_block_with_hash = True + if self.block_store.get(block.sha256) is not None: + first_block_with_hash = False + with mininode_lock: + self.block_store.add_block(block) + for c in self.connections: + if first_block_with_hash and block.sha256 in c.cb.block_request_map and c.cb.block_request_map[block.sha256] == True: + # There was a previous request for this block hash + # Most likely, we delivered a header for this block + # but never had the block to respond to the getdata + c.send_message(msg_block(block)) + else: + c.cb.block_request_map[block.sha256] = False + # Either send inv's to each node and sync, or add + # to invqueue for later inv'ing. + if (test_instance.sync_every_block): + # if we expect success, send inv and sync every block + # if we expect failure, just push the block and see what happens. + if outcome == True: + [ c.cb.send_inv(block) for c in self.connections ] + self.sync_blocks(block.sha256, 1) + else: + [ c.send_message(msg_block(block)) for c in self.connections ] + [ c.cb.send_ping(self.ping_counter) for c in self.connections ] + self.wait_for_pings(self.ping_counter) + self.ping_counter += 1 + if (not self.check_results(tip, outcome)): + raise AssertionError("Test failed at test %d" % test_number) + else: + invqueue.append(CInv(2, block.sha256)) + elif isinstance(b_or_t, CBlockHeader): + block_header = b_or_t + self.block_store.add_header(block_header) + [ c.cb.send_header(block_header) for c in self.connections ] + + else: # Tx test runner + assert(isinstance(b_or_t, CTransaction)) + tx = b_or_t + tx_outcome = outcome + # Add to shared tx store and clear map entry + with mininode_lock: + self.tx_store.add_transaction(tx) + for c in self.connections: + c.cb.tx_request_map[tx.sha256] = False + # Again, either inv to all nodes or save for later + if (test_instance.sync_every_tx): + [ c.cb.send_inv(tx) for c in self.connections ] + self.sync_transaction(tx.sha256, 1) + if (not self.check_mempool(tx.sha256, outcome)): + raise AssertionError("Test failed at test %d" % test_number) + else: + invqueue.append(CInv(1, tx.sha256)) + # Ensure we're not overflowing the inv queue + if len(invqueue) == MAX_INV_SZ: + [ c.send_message(msg_inv(invqueue)) for c in self.connections ] + invqueue = [] + + # Do final sync if we weren't syncing on every block or every tx. + if (not test_instance.sync_every_block and block is not None): + if len(invqueue) > 0: + [ c.send_message(msg_inv(invqueue)) for c in self.connections ] + invqueue = [] + self.sync_blocks(block.sha256, len(test_instance.blocks_and_transactions)) + if (not self.check_results(tip, block_outcome)): + raise AssertionError("Block test failed at test %d" % test_number) + if (not test_instance.sync_every_tx and tx is not None): + if len(invqueue) > 0: + [ c.send_message(msg_inv(invqueue)) for c in self.connections ] + invqueue = [] + self.sync_transaction(tx.sha256, len(test_instance.blocks_and_transactions)) + if (not self.check_mempool(tx.sha256, tx_outcome)): + raise AssertionError("Mempool test failed at test %d" % test_number) + + logger.info("Test %d: PASS" % test_number) + test_number += 1 + + [ c.disconnect_node() for c in self.connections ] + self.wait_for_disconnections() + self.block_store.close() + self.tx_store.close() diff --git a/rpctest/test_framework/coverage.py b/rpctest/test_framework/coverage.py new file mode 100644 index 000000000..3f87ef91f --- /dev/null +++ b/rpctest/test_framework/coverage.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Utilities for doing coverage analysis on the RPC interface. + +Provides a way to track which RPC commands are exercised during +testing. +""" + +import os + + +REFERENCE_FILENAME = 'rpc_interface.txt' + + +class AuthServiceProxyWrapper(object): + """ + An object that wraps AuthServiceProxy to record specific RPC calls. + + """ + def __init__(self, auth_service_proxy_instance, coverage_logfile=None): + """ + Kwargs: + auth_service_proxy_instance (AuthServiceProxy): the instance + being wrapped. + coverage_logfile (str): if specified, write each service_name + out to a file when called. + + """ + self.auth_service_proxy_instance = auth_service_proxy_instance + self.coverage_logfile = coverage_logfile + + def __getattr__(self, *args, **kwargs): + return_val = self.auth_service_proxy_instance.__getattr__( + *args, **kwargs) + + return AuthServiceProxyWrapper(return_val, self.coverage_logfile) + + def __call__(self, *args, **kwargs): + """ + Delegates to AuthServiceProxy, then writes the particular RPC method + called to a file. + + """ + return_val = self.auth_service_proxy_instance.__call__(*args, **kwargs) + rpc_method = self.auth_service_proxy_instance._service_name + + if self.coverage_logfile: + with open(self.coverage_logfile, 'a+', encoding='utf8') as f: + f.write("%s\n" % rpc_method) + + return return_val + + @property + def url(self): + return self.auth_service_proxy_instance.url + + +def get_filename(dirname, n_node): + """ + Get a filename unique to the test process ID and node. + + This file will contain a list of RPC commands covered. + """ + pid = str(os.getpid()) + return os.path.join( + dirname, "coverage.pid%s.node%s.txt" % (pid, str(n_node))) + + +def write_all_rpc_commands(dirname, node): + """ + Write out a list of all RPC functions available in `bitcoin-cli` for + coverage comparison. This will only happen once per coverage + directory. + + Args: + dirname (str): temporary test dir + node (AuthServiceProxy): client + + Returns: + bool. if the RPC interface file was written. + + """ + filename = os.path.join(dirname, REFERENCE_FILENAME) + + if os.path.isfile(filename): + return False + + help_output = node.help().split('\n') + commands = set() + + for line in help_output: + line = line.strip() + + # Ignore blanks and headers + if line and not line.startswith('='): + commands.add("%s\n" % line.split()[0]) + + with open(filename, 'w', encoding='utf8') as f: + f.writelines(list(commands)) + + return True diff --git a/rpctest/test_framework/key.py b/rpctest/test_framework/key.py new file mode 100644 index 000000000..85a6158a2 --- /dev/null +++ b/rpctest/test_framework/key.py @@ -0,0 +1,232 @@ +# Copyright (c) 2011 Sam Rushing +"""ECC secp256k1 OpenSSL wrapper. + +WARNING: This module does not mlock() secrets; your private keys may end up on +disk in swap! Use with caution! + +This file is modified from python-bitcoinlib. +""" + +import ctypes +import ctypes.util +import hashlib +import sys + +ssl = ctypes.cdll.LoadLibrary(ctypes.util.find_library ('ssl') or 'libeay32') + +ssl.BN_new.restype = ctypes.c_void_p +ssl.BN_new.argtypes = [] + +ssl.BN_bin2bn.restype = ctypes.c_void_p +ssl.BN_bin2bn.argtypes = [ctypes.c_char_p, ctypes.c_int, ctypes.c_void_p] + +ssl.BN_CTX_free.restype = None +ssl.BN_CTX_free.argtypes = [ctypes.c_void_p] + +ssl.BN_CTX_new.restype = ctypes.c_void_p +ssl.BN_CTX_new.argtypes = [] + +ssl.ECDH_compute_key.restype = ctypes.c_int +ssl.ECDH_compute_key.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p] + +ssl.ECDSA_sign.restype = ctypes.c_int +ssl.ECDSA_sign.argtypes = [ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] + +ssl.ECDSA_verify.restype = ctypes.c_int +ssl.ECDSA_verify.argtypes = [ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p] + +ssl.EC_KEY_free.restype = None +ssl.EC_KEY_free.argtypes = [ctypes.c_void_p] + +ssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p +ssl.EC_KEY_new_by_curve_name.argtypes = [ctypes.c_int] + +ssl.EC_KEY_get0_group.restype = ctypes.c_void_p +ssl.EC_KEY_get0_group.argtypes = [ctypes.c_void_p] + +ssl.EC_KEY_get0_public_key.restype = ctypes.c_void_p +ssl.EC_KEY_get0_public_key.argtypes = [ctypes.c_void_p] + +ssl.EC_KEY_set_private_key.restype = ctypes.c_int +ssl.EC_KEY_set_private_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p] + +ssl.EC_KEY_set_conv_form.restype = None +ssl.EC_KEY_set_conv_form.argtypes = [ctypes.c_void_p, ctypes.c_int] + +ssl.EC_KEY_set_public_key.restype = ctypes.c_int +ssl.EC_KEY_set_public_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p] + +ssl.i2o_ECPublicKey.restype = ctypes.c_void_p +ssl.i2o_ECPublicKey.argtypes = [ctypes.c_void_p, ctypes.c_void_p] + +ssl.EC_POINT_new.restype = ctypes.c_void_p +ssl.EC_POINT_new.argtypes = [ctypes.c_void_p] + +ssl.EC_POINT_free.restype = None +ssl.EC_POINT_free.argtypes = [ctypes.c_void_p] + +ssl.EC_POINT_mul.restype = ctypes.c_int +ssl.EC_POINT_mul.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] + +# this specifies the curve used with ECDSA. +NID_secp256k1 = 714 # from openssl/obj_mac.h + +SECP256K1_ORDER = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 +SECP256K1_ORDER_HALF = SECP256K1_ORDER // 2 + +# Thx to Sam Devlin for the ctypes magic 64-bit fix. +def _check_result(val, func, args): + if val == 0: + raise ValueError + else: + return ctypes.c_void_p (val) + +ssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p +ssl.EC_KEY_new_by_curve_name.errcheck = _check_result + +class CECKey(object): + """Wrapper around OpenSSL's EC_KEY""" + + POINT_CONVERSION_COMPRESSED = 2 + POINT_CONVERSION_UNCOMPRESSED = 4 + + def __init__(self): + self.k = ssl.EC_KEY_new_by_curve_name(NID_secp256k1) + + def __del__(self): + if ssl: + ssl.EC_KEY_free(self.k) + self.k = None + + def set_secretbytes(self, secret): + priv_key = ssl.BN_bin2bn(secret, 32, ssl.BN_new()) + group = ssl.EC_KEY_get0_group(self.k) + pub_key = ssl.EC_POINT_new(group) + ctx = ssl.BN_CTX_new() + if not ssl.EC_POINT_mul(group, pub_key, priv_key, None, None, ctx): + raise ValueError("Could not derive public key from the supplied secret.") + ssl.EC_POINT_mul(group, pub_key, priv_key, None, None, ctx) + ssl.EC_KEY_set_private_key(self.k, priv_key) + ssl.EC_KEY_set_public_key(self.k, pub_key) + ssl.EC_POINT_free(pub_key) + ssl.BN_CTX_free(ctx) + return self.k + + def set_privkey(self, key): + self.mb = ctypes.create_string_buffer(key) + return ssl.d2i_ECPrivateKey(ctypes.byref(self.k), ctypes.byref(ctypes.pointer(self.mb)), len(key)) + + def set_pubkey(self, key): + self.mb = ctypes.create_string_buffer(key) + return ssl.o2i_ECPublicKey(ctypes.byref(self.k), ctypes.byref(ctypes.pointer(self.mb)), len(key)) + + def get_privkey(self): + size = ssl.i2d_ECPrivateKey(self.k, 0) + mb_pri = ctypes.create_string_buffer(size) + ssl.i2d_ECPrivateKey(self.k, ctypes.byref(ctypes.pointer(mb_pri))) + return mb_pri.raw + + def get_pubkey(self): + size = ssl.i2o_ECPublicKey(self.k, 0) + mb = ctypes.create_string_buffer(size) + ssl.i2o_ECPublicKey(self.k, ctypes.byref(ctypes.pointer(mb))) + return mb.raw + + def get_raw_ecdh_key(self, other_pubkey): + ecdh_keybuffer = ctypes.create_string_buffer(32) + r = ssl.ECDH_compute_key(ctypes.pointer(ecdh_keybuffer), 32, + ssl.EC_KEY_get0_public_key(other_pubkey.k), + self.k, 0) + if r != 32: + raise Exception('CKey.get_ecdh_key(): ECDH_compute_key() failed') + return ecdh_keybuffer.raw + + def get_ecdh_key(self, other_pubkey, kdf=lambda k: hashlib.sha256(k).digest()): + # FIXME: be warned it's not clear what the kdf should be as a default + r = self.get_raw_ecdh_key(other_pubkey) + return kdf(r) + + def sign(self, hash, low_s = True): + # FIXME: need unit tests for below cases + if not isinstance(hash, bytes): + raise TypeError('Hash must be bytes instance; got %r' % hash.__class__) + if len(hash) != 32: + raise ValueError('Hash must be exactly 32 bytes long') + + sig_size0 = ctypes.c_uint32() + sig_size0.value = ssl.ECDSA_size(self.k) + mb_sig = ctypes.create_string_buffer(sig_size0.value) + result = ssl.ECDSA_sign(0, hash, len(hash), mb_sig, ctypes.byref(sig_size0), self.k) + assert 1 == result + assert mb_sig.raw[0] == 0x30 + assert mb_sig.raw[1] == sig_size0.value - 2 + total_size = mb_sig.raw[1] + assert mb_sig.raw[2] == 2 + r_size = mb_sig.raw[3] + assert mb_sig.raw[4 + r_size] == 2 + s_size = mb_sig.raw[5 + r_size] + s_value = int.from_bytes(mb_sig.raw[6+r_size:6+r_size+s_size], byteorder='big') + if (not low_s) or s_value <= SECP256K1_ORDER_HALF: + return mb_sig.raw[:sig_size0.value] + else: + low_s_value = SECP256K1_ORDER - s_value + low_s_bytes = (low_s_value).to_bytes(33, byteorder='big') + while len(low_s_bytes) > 1 and low_s_bytes[0] == 0 and low_s_bytes[1] < 0x80: + low_s_bytes = low_s_bytes[1:] + new_s_size = len(low_s_bytes) + new_total_size_byte = (total_size + new_s_size - s_size).to_bytes(1,byteorder='big') + new_s_size_byte = (new_s_size).to_bytes(1,byteorder='big') + return b'\x30' + new_total_size_byte + mb_sig.raw[2:5+r_size] + new_s_size_byte + low_s_bytes + + def verify(self, hash, sig): + """Verify a DER signature""" + return ssl.ECDSA_verify(0, hash, len(hash), sig, len(sig), self.k) == 1 + + def set_compressed(self, compressed): + if compressed: + form = self.POINT_CONVERSION_COMPRESSED + else: + form = self.POINT_CONVERSION_UNCOMPRESSED + ssl.EC_KEY_set_conv_form(self.k, form) + + +class CPubKey(bytes): + """An encapsulated public key + + Attributes: + + is_valid - Corresponds to CPubKey.IsValid() + is_fullyvalid - Corresponds to CPubKey.IsFullyValid() + is_compressed - Corresponds to CPubKey.IsCompressed() + """ + + def __new__(cls, buf, _cec_key=None): + self = super(CPubKey, cls).__new__(cls, buf) + if _cec_key is None: + _cec_key = CECKey() + self._cec_key = _cec_key + self.is_fullyvalid = _cec_key.set_pubkey(self) != 0 + return self + + @property + def is_valid(self): + return len(self) > 0 + + @property + def is_compressed(self): + return len(self) == 33 + + def verify(self, hash, sig): + return self._cec_key.verify(hash, sig) + + def __str__(self): + return repr(self) + + def __repr__(self): + # Always have represent as b'' so test cases don't have to + # change for py2/3 + if sys.version > '3': + return '%s(%s)' % (self.__class__.__name__, super(CPubKey, self).__repr__()) + else: + return '%s(b%s)' % (self.__class__.__name__, super(CPubKey, self).__repr__()) + diff --git a/rpctest/test_framework/mininode.py b/rpctest/test_framework/mininode.py new file mode 100755 index 000000000..d57d46f2f --- /dev/null +++ b/rpctest/test_framework/mininode.py @@ -0,0 +1,1812 @@ +#!/usr/bin/env python3 +# Copyright (c) 2010 ArtForz -- public domain half-a-node +# Copyright (c) 2012 Jeff Garzik +# Copyright (c) 2010-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Bitcoin P2P network half-a-node. + +This python code was modified from ArtForz' public domain half-a-node, as +found in the mini-node branch of http://github.com/jgarzik/pynode. + +NodeConn: an object which manages p2p connectivity to a bitcoin node +NodeConnCB: a base class that describes the interface for receiving + callbacks with network messages from a NodeConn +CBlock, CTransaction, CBlockHeader, CTxIn, CTxOut, etc....: + data structures that should map to corresponding structures in + bitcoin/primitives +msg_block, msg_tx, msg_headers, etc.: + data structures that represent network messages +ser_*, deser_*: functions that handle serialization/deserialization +""" + +import struct +import socket +import asyncore +import time +import sys +import random +from .util import hex_str_to_bytes, bytes_to_hex_str +from io import BytesIO +from codecs import encode +import hashlib +from threading import RLock +from threading import Thread +import logging +import copy +from test_framework.siphash import siphash256 + +BIP0031_VERSION = 60000 +MY_VERSION = 70014 # past bip-31 for ping/pong +MY_SUBVERSION = b"/python-mininode-tester:0.0.3/" +MY_RELAY = 1 # from version 70001 onwards, fRelay should be appended to version messages (BIP37) + +MAX_INV_SZ = 50000 +MAX_BLOCK_BASE_SIZE = 1000000 + +COIN = 100000000 # 1 btc in satoshis + +NODE_NETWORK = (1 << 0) +NODE_GETUTXO = (1 << 1) +NODE_BLOOM = (1 << 2) +NODE_WITNESS = (1 << 3) + +logger = logging.getLogger("TestFramework.mininode") + +# Keep our own socket map for asyncore, so that we can track disconnects +# ourselves (to workaround an issue with closing an asyncore socket when +# using select) +mininode_socket_map = dict() + +# One lock for synchronizing all data access between the networking thread (see +# NetworkThread below) and the thread running the test logic. For simplicity, +# NodeConn acquires this lock whenever delivering a message to to a NodeConnCB, +# and whenever adding anything to the send buffer (in send_message()). This +# lock should be acquired in the thread running the test logic to synchronize +# access to any data shared with the NodeConnCB or NodeConn. +mininode_lock = RLock() + +# Serialization/deserialization tools +def sha256(s): + return hashlib.new('sha256', s).digest() + +def ripemd160(s): + return hashlib.new('ripemd160', s).digest() + +def hash256(s): + return sha256(sha256(s)) + +def ser_compact_size(l): + r = b"" + if l < 253: + r = struct.pack("B", l) + elif l < 0x10000: + r = struct.pack(">= 32 + return rs + + +def uint256_from_str(s): + r = 0 + t = struct.unpack("> 24) & 0xFF + v = (c & 0xFFFFFF) << (8 * (nbytes - 3)) + return v + + +def deser_vector(f, c): + nit = deser_compact_size(f) + r = [] + for i in range(nit): + t = c() + t.deserialize(f) + r.append(t) + return r + + +# ser_function_name: Allow for an alternate serialization function on the +# entries in the vector (we use this for serializing the vector of transactions +# for a witness block). +def ser_vector(l, ser_function_name=None): + r = ser_compact_size(len(l)) + for i in l: + if ser_function_name: + r += getattr(i, ser_function_name)() + else: + r += i.serialize() + return r + + +def deser_uint256_vector(f): + nit = deser_compact_size(f) + r = [] + for i in range(nit): + t = deser_uint256(f) + r.append(t) + return r + + +def ser_uint256_vector(l): + r = ser_compact_size(len(l)) + for i in l: + r += ser_uint256(i) + return r + + +def deser_string_vector(f): + nit = deser_compact_size(f) + r = [] + for i in range(nit): + t = deser_string(f) + r.append(t) + return r + + +def ser_string_vector(l): + r = ser_compact_size(len(l)) + for sv in l: + r += ser_string(sv) + return r + + +def deser_int_vector(f): + nit = deser_compact_size(f) + r = [] + for i in range(nit): + t = struct.unpack("H", f.read(2))[0] + + def serialize(self): + r = b"" + r += struct.pack("H", self.port) + return r + + def __repr__(self): + return "CAddress(nServices=%i ip=%s port=%i)" % (self.nServices, + self.ip, self.port) + +MSG_WITNESS_FLAG = 1<<30 + +class CInv(object): + typemap = { + 0: "Error", + 1: "TX", + 2: "Block", + 1|MSG_WITNESS_FLAG: "WitnessTx", + 2|MSG_WITNESS_FLAG : "WitnessBlock", + 4: "CompactBlock" + } + + def __init__(self, t=0, h=0): + self.type = t + self.hash = h + + def deserialize(self, f): + self.type = struct.unpack(" 21000000 * COIN: + return False + return True + + def __repr__(self): + return "CTransaction(nVersion=%i vin=%s vout=%s wit=%s nLockTime=%i)" \ + % (self.nVersion, repr(self.vin), repr(self.vout), repr(self.wit), self.nLockTime) + + +class CBlockHeader(object): + def __init__(self, header=None): + if header is None: + self.set_null() + else: + self.nVersion = header.nVersion + self.hashPrevBlock = header.hashPrevBlock + self.hashMerkleRoot = header.hashMerkleRoot + self.nTime = header.nTime + self.nBits = header.nBits + self.nNonce = header.nNonce + self.sha256 = header.sha256 + self.hash = header.hash + self.calc_sha256() + + def set_null(self): + self.nVersion = 1 + self.hashPrevBlock = 0 + self.hashMerkleRoot = 0 + self.nTime = 0 + self.nBits = 0 + self.nNonce = 0 + self.sha256 = None + self.hash = None + + def deserialize(self, f): + self.nVersion = struct.unpack(" 1: + newhashes = [] + for i in range(0, len(hashes), 2): + i2 = min(i+1, len(hashes)-1) + newhashes.append(hash256(hashes[i] + hashes[i2])) + hashes = newhashes + return uint256_from_str(hashes[0]) + + def calc_merkle_root(self): + hashes = [] + for tx in self.vtx: + tx.calc_sha256() + hashes.append(ser_uint256(tx.sha256)) + return self.get_merkle_root(hashes) + + def calc_witness_merkle_root(self): + # For witness root purposes, the hash of the + # coinbase, with witness, is defined to be 0...0 + hashes = [ser_uint256(0)] + + for tx in self.vtx[1:]: + # Calculate the hashes with witness data + hashes.append(ser_uint256(tx.calc_sha256(True))) + + return self.get_merkle_root(hashes) + + def is_valid(self): + self.calc_sha256() + target = uint256_from_compact(self.nBits) + if self.sha256 > target: + return False + for tx in self.vtx: + if not tx.is_valid(): + return False + if self.calc_merkle_root() != self.hashMerkleRoot: + return False + return True + + def solve(self): + self.rehash() + target = uint256_from_compact(self.nBits) + while self.sha256 > target: + self.nNonce += 1 + self.rehash() + + def __repr__(self): + return "CBlock(nVersion=%i hashPrevBlock=%064x hashMerkleRoot=%064x nTime=%s nBits=%08x nNonce=%08x vtx=%s)" \ + % (self.nVersion, self.hashPrevBlock, self.hashMerkleRoot, + time.ctime(self.nTime), self.nBits, self.nNonce, repr(self.vtx)) + + +class CUnsignedAlert(object): + def __init__(self): + self.nVersion = 1 + self.nRelayUntil = 0 + self.nExpiration = 0 + self.nID = 0 + self.nCancel = 0 + self.setCancel = [] + self.nMinVer = 0 + self.nMaxVer = 0 + self.setSubVer = [] + self.nPriority = 0 + self.strComment = b"" + self.strStatusBar = b"" + self.strReserved = b"" + + def deserialize(self, f): + self.nVersion = struct.unpack("= 106: + self.addrFrom = CAddress() + self.addrFrom.deserialize(f) + self.nNonce = struct.unpack("= 209: + self.nStartingHeight = struct.unpack("= 70001: + # Relay field is optional for version 70001 onwards + try: + self.nRelay = struct.unpack(" +class msg_headers(object): + command = b"headers" + + def __init__(self): + self.headers = [] + + def deserialize(self, f): + # comment in bitcoind indicates these should be deserialized as blocks + blocks = deser_vector(f, CBlock) + for x in blocks: + self.headers.append(CBlockHeader(x)) + + def serialize(self): + blocks = [CBlock(x) for x in self.headers] + return ser_vector(blocks) + + def __repr__(self): + return "msg_headers(headers=%s)" % repr(self.headers) + + +class msg_reject(object): + command = b"reject" + REJECT_MALFORMED = 1 + + def __init__(self): + self.message = b"" + self.code = 0 + self.reason = b"" + self.data = 0 + + def deserialize(self, f): + self.message = deser_string(f) + self.code = struct.unpack(" BIP0031_VERSION: + conn.send_message(msg_pong(message.nonce)) + + def on_pong(self, conn, message): + self.last_pong = message + + def on_verack(self, conn, message): + conn.ver_recv = conn.ver_send + self.verack_received = True + + def on_version(self, conn, message): + if message.nVersion >= 209: + conn.send_message(msg_verack()) + conn.ver_send = min(MY_VERSION, message.nVersion) + if message.nVersion < 209: + conn.ver_recv = conn.ver_send + conn.nServices = message.nServices + + # Helper functions + ################## + + def add_connection(self, conn): + self.connection = conn + + # Wrapper for the NodeConn's send_message function + def send_message(self, message): + self.connection.send_message(message) + + def send_and_ping(self, message): + self.send_message(message) + self.sync_with_ping() + + # Sync up with the node + def sync_with_ping(self, timeout=60): + def received_pong(): + return (self.last_pong.nonce == self.ping_counter) + self.send_message(msg_ping(nonce=self.ping_counter)) + success = wait_until(received_pong, timeout=timeout) + if not success: + logger.error("sync_with_ping failed!") + raise AssertionError("sync_with_ping failed!") + self.ping_counter += 1 + + return success + + # Spin until verack message is received from the node. + # Tests may want to use this as a signal that the test can begin. + # This can be called from the testing thread, so it needs to acquire the + # global lock. + def wait_for_verack(self): + while True: + with mininode_lock: + if self.verack_received: + return + time.sleep(0.05) + +# The actual NodeConn class +# This class provides an interface for a p2p connection to a specified node +class NodeConn(asyncore.dispatcher): + messagemap = { + b"version": msg_version, + b"verack": msg_verack, + b"addr": msg_addr, + b"alert": msg_alert, + b"inv": msg_inv, + b"getdata": msg_getdata, + b"getblocks": msg_getblocks, + b"tx": msg_tx, + b"block": msg_block, + b"getaddr": msg_getaddr, + b"ping": msg_ping, + b"pong": msg_pong, + b"headers": msg_headers, + b"getheaders": msg_getheaders, + b"reject": msg_reject, + b"mempool": msg_mempool, + b"feefilter": msg_feefilter, + b"sendheaders": msg_sendheaders, + b"sendcmpct": msg_sendcmpct, + b"cmpctblock": msg_cmpctblock, + b"getblocktxn": msg_getblocktxn, + b"blocktxn": msg_blocktxn + } + MAGIC_BYTES = { + "mainnet": b"\xf9\xbe\xb4\xd9", # mainnet + "testnet3": b"\x0b\x11\x09\x07", # testnet3 + "regtest": b"\xfa\xbf\xb5\xda", # regtest + } + + def __init__(self, dstaddr, dstport, rpc, callback, net="regtest", services=NODE_NETWORK, send_version=True): + asyncore.dispatcher.__init__(self, map=mininode_socket_map) + self.dstaddr = dstaddr + self.dstport = dstport + self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + self.sendbuf = b"" + self.recvbuf = b"" + self.ver_send = 209 + self.ver_recv = 209 + self.last_sent = 0 + self.state = "connecting" + self.network = net + self.cb = callback + self.disconnect = False + self.nServices = 0 + + if send_version: + # stuff version msg into sendbuf + vt = msg_version() + vt.nServices = services + vt.addrTo.ip = self.dstaddr + vt.addrTo.port = self.dstport + vt.addrFrom.ip = "0.0.0.0" + vt.addrFrom.port = 0 + self.send_message(vt, True) + + logger.info('Connecting to Bitcoin Node: %s:%d' % (self.dstaddr, self.dstport)) + + try: + self.connect((dstaddr, dstport)) + except: + self.handle_close() + self.rpc = rpc + + def handle_connect(self): + if self.state != "connected": + logger.debug("Connected & Listening: %s:%d" % (self.dstaddr, self.dstport)) + self.state = "connected" + self.cb.on_open(self) + + def handle_close(self): + logger.debug("Closing connection to: %s:%d" % (self.dstaddr, self.dstport)) + self.state = "closed" + self.recvbuf = b"" + self.sendbuf = b"" + try: + self.close() + except: + pass + self.cb.on_close(self) + + def handle_read(self): + try: + t = self.recv(8192) + if len(t) > 0: + self.recvbuf += t + self.got_data() + except: + pass + + def readable(self): + return True + + def writable(self): + with mininode_lock: + pre_connection = self.state == "connecting" + length = len(self.sendbuf) + return (length > 0 or pre_connection) + + def handle_write(self): + with mininode_lock: + # asyncore does not expose socket connection, only the first read/write + # event, thus we must check connection manually here to know when we + # actually connect + if self.state == "connecting": + self.handle_connect() + if not self.writable(): + return + + try: + sent = self.send(self.sendbuf) + except: + self.handle_close() + return + self.sendbuf = self.sendbuf[sent:] + + def got_data(self): + try: + while True: + if len(self.recvbuf) < 4: + return + if self.recvbuf[:4] != self.MAGIC_BYTES[self.network]: + raise ValueError("got garbage %s" % repr(self.recvbuf)) + if self.ver_recv < 209: + if len(self.recvbuf) < 4 + 12 + 4: + return + command = self.recvbuf[4:4+12].split(b"\x00", 1)[0] + msglen = struct.unpack("= 209: + th = sha256(data) + h = sha256(th) + tmsg += h[:4] + tmsg += data + with mininode_lock: + self.sendbuf += tmsg + self.last_sent = time.time() + + def got_message(self, message): + if message.command == b"version": + if message.nVersion <= BIP0031_VERSION: + self.messagemap[b'ping'] = msg_ping_prebip31 + if self.last_sent + 30 * 60 < time.time(): + self.send_message(self.messagemap[b'ping']()) + self._log_message("receive", message) + self.cb.deliver(self, message) + + def _log_message(self, direction, msg): + if direction == "send": + log_message = "Send message to " + elif direction == "receive": + log_message = "Received message from " + log_message += "%s:%d: %s" % (self.dstaddr, self.dstport, repr(msg)[:500]) + if len(log_message) > 500: + log_message += "... (msg truncated)" + logger.debug(log_message) + + def disconnect_node(self): + self.disconnect = True + + +class NetworkThread(Thread): + def run(self): + while mininode_socket_map: + # We check for whether to disconnect outside of the asyncore + # loop to workaround the behavior of asyncore when using + # select + disconnected = [] + for fd, obj in mininode_socket_map.items(): + if obj.disconnect: + disconnected.append(obj) + [ obj.handle_close() for obj in disconnected ] + asyncore.loop(0.1, use_poll=True, map=mininode_socket_map, count=1) + + +# An exception we can raise if we detect a potential disconnect +# (p2p or rpc) before the test is complete +class EarlyDisconnectError(Exception): + def __init__(self, value): + self.value = value + + def __str__(self): + return repr(self.value) diff --git a/rpctest/test_framework/netutil.py b/rpctest/test_framework/netutil.py new file mode 100644 index 000000000..45d8e22d2 --- /dev/null +++ b/rpctest/test_framework/netutil.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Linux network utilities. + +Roughly based on http://voorloopnul.com/blog/a-python-netstat-in-less-than-100-lines-of-code/ by Ricardo Pascal +""" + +import sys +import socket +import fcntl +import struct +import array +import os +from binascii import unhexlify, hexlify + +STATE_ESTABLISHED = '01' +STATE_SYN_SENT = '02' +STATE_SYN_RECV = '03' +STATE_FIN_WAIT1 = '04' +STATE_FIN_WAIT2 = '05' +STATE_TIME_WAIT = '06' +STATE_CLOSE = '07' +STATE_CLOSE_WAIT = '08' +STATE_LAST_ACK = '09' +STATE_LISTEN = '0A' +STATE_CLOSING = '0B' + +def get_socket_inodes(pid): + ''' + Get list of socket inodes for process pid. + ''' + base = '/proc/%i/fd' % pid + inodes = [] + for item in os.listdir(base): + target = os.readlink(os.path.join(base, item)) + if target.startswith('socket:'): + inodes.append(int(target[8:-1])) + return inodes + +def _remove_empty(array): + return [x for x in array if x !=''] + +def _convert_ip_port(array): + host,port = array.split(':') + # convert host from mangled-per-four-bytes form as used by kernel + host = unhexlify(host) + host_out = '' + for x in range(0, len(host) // 4): + (val,) = struct.unpack('=I', host[x*4:(x+1)*4]) + host_out += '%08x' % val + + return host_out,int(port,16) + +def netstat(typ='tcp'): + ''' + Function to return a list with status of tcp connections at linux systems + To get pid of all network process running on system, you must run this script + as superuser + ''' + with open('/proc/net/'+typ,'r',encoding='utf8') as f: + content = f.readlines() + content.pop(0) + result = [] + for line in content: + line_array = _remove_empty(line.split(' ')) # Split lines and remove empty spaces. + tcp_id = line_array[0] + l_addr = _convert_ip_port(line_array[1]) + r_addr = _convert_ip_port(line_array[2]) + state = line_array[3] + inode = int(line_array[9]) # Need the inode to match with process pid. + nline = [tcp_id, l_addr, r_addr, state, inode] + result.append(nline) + return result + +def get_bind_addrs(pid): + ''' + Get bind addresses as (host,port) tuples for process pid. + ''' + inodes = get_socket_inodes(pid) + bind_addrs = [] + for conn in netstat('tcp') + netstat('tcp6'): + if conn[3] == STATE_LISTEN and conn[4] in inodes: + bind_addrs.append(conn[1]) + return bind_addrs + +# from: http://code.activestate.com/recipes/439093/ +def all_interfaces(): + ''' + Return all interfaces that are up + ''' + is_64bits = sys.maxsize > 2**32 + struct_size = 40 if is_64bits else 32 + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + max_possible = 8 # initial value + while True: + bytes = max_possible * struct_size + names = array.array('B', b'\0' * bytes) + outbytes = struct.unpack('iL', fcntl.ioctl( + s.fileno(), + 0x8912, # SIOCGIFCONF + struct.pack('iL', bytes, names.buffer_info()[0]) + ))[0] + if outbytes == bytes: + max_possible *= 2 + else: + break + namestr = names.tostring() + return [(namestr[i:i+16].split(b'\0', 1)[0], + socket.inet_ntoa(namestr[i+20:i+24])) + for i in range(0, outbytes, struct_size)] + +def addr_to_hex(addr): + ''' + Convert string IPv4 or IPv6 address to binary address as returned by + get_bind_addrs. + Very naive implementation that certainly doesn't work for all IPv6 variants. + ''' + if '.' in addr: # IPv4 + addr = [int(x) for x in addr.split('.')] + elif ':' in addr: # IPv6 + sub = [[], []] # prefix, suffix + x = 0 + addr = addr.split(':') + for i,comp in enumerate(addr): + if comp == '': + if i == 0 or i == (len(addr)-1): # skip empty component at beginning or end + continue + x += 1 # :: skips to suffix + assert(x < 2) + else: # two bytes per component + val = int(comp, 16) + sub[x].append(val >> 8) + sub[x].append(val & 0xff) + nullbytes = 16 - len(sub[0]) - len(sub[1]) + assert((x == 0 and nullbytes == 0) or (x == 1 and nullbytes > 0)) + addr = sub[0] + ([0] * nullbytes) + sub[1] + else: + raise ValueError('Could not parse address %s' % addr) + return hexlify(bytearray(addr)).decode('ascii') + +def test_ipv6_local(): + ''' + Check for (local) IPv6 support. + ''' + import socket + # By using SOCK_DGRAM this will not actually make a connection, but it will + # fail if there is no route to IPv6 localhost. + have_ipv6 = True + try: + s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) + s.connect(('::1', 0)) + except socket.error: + have_ipv6 = False + return have_ipv6 diff --git a/rpctest/test_framework/script.py b/rpctest/test_framework/script.py new file mode 100644 index 000000000..3d9572788 --- /dev/null +++ b/rpctest/test_framework/script.py @@ -0,0 +1,939 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Functionality to build scripts, as well as SignatureHash(). + +This file is modified from python-bitcoinlib. +""" + +from .mininode import CTransaction, CTxOut, sha256, hash256, uint256_from_str, ser_uint256, ser_string +from binascii import hexlify +import hashlib + +import sys +bchr = chr +bord = ord +if sys.version > '3': + long = int + bchr = lambda x: bytes([x]) + bord = lambda x: x + +import struct + +from .bignum import bn2vch + +MAX_SCRIPT_SIZE = 10000 +MAX_SCRIPT_ELEMENT_SIZE = 520 +MAX_SCRIPT_OPCODES = 201 + +OPCODE_NAMES = {} + +def hash160(s): + return hashlib.new('ripemd160', sha256(s)).digest() + + +_opcode_instances = [] +class CScriptOp(int): + """A single script opcode""" + __slots__ = [] + + @staticmethod + def encode_op_pushdata(d): + """Encode a PUSHDATA op, returning bytes""" + if len(d) < 0x4c: + return b'' + bchr(len(d)) + d # OP_PUSHDATA + elif len(d) <= 0xff: + return b'\x4c' + bchr(len(d)) + d # OP_PUSHDATA1 + elif len(d) <= 0xffff: + return b'\x4d' + struct.pack(b'>= 8 + if r[-1] & 0x80: + r.append(0x80 if neg else 0) + elif neg: + r[-1] |= 0x80 + return bytes(bchr(len(r)) + r) + + +class CScript(bytes): + """Serialized script + + A bytes subclass, so you can use this directly whenever bytes are accepted. + Note that this means that indexing does *not* work - you'll get an index by + byte rather than opcode. This format was chosen for efficiency so that the + general case would not require creating a lot of little CScriptOP objects. + + iter(script) however does iterate by opcode. + """ + @classmethod + def __coerce_instance(cls, other): + # Coerce other into bytes + if isinstance(other, CScriptOp): + other = bchr(other) + elif isinstance(other, CScriptNum): + if (other.value == 0): + other = bchr(CScriptOp(OP_0)) + else: + other = CScriptNum.encode(other) + elif isinstance(other, int): + if 0 <= other <= 16: + other = bytes(bchr(CScriptOp.encode_op_n(other))) + elif other == -1: + other = bytes(bchr(OP_1NEGATE)) + else: + other = CScriptOp.encode_op_pushdata(bn2vch(other)) + elif isinstance(other, (bytes, bytearray)): + other = CScriptOp.encode_op_pushdata(other) + return other + + def __add__(self, other): + # Do the coercion outside of the try block so that errors in it are + # noticed. + other = self.__coerce_instance(other) + + try: + # bytes.__add__ always returns bytes instances unfortunately + return CScript(super(CScript, self).__add__(other)) + except TypeError: + raise TypeError('Can not add a %r instance to a CScript' % other.__class__) + + def join(self, iterable): + # join makes no sense for a CScript() + raise NotImplementedError + + def __new__(cls, value=b''): + if isinstance(value, bytes) or isinstance(value, bytearray): + return super(CScript, cls).__new__(cls, value) + else: + def coerce_iterable(iterable): + for instance in iterable: + yield cls.__coerce_instance(instance) + # Annoyingly on both python2 and python3 bytes.join() always + # returns a bytes instance even when subclassed. + return super(CScript, cls).__new__(cls, b''.join(coerce_iterable(value))) + + def raw_iter(self): + """Raw iteration + + Yields tuples of (opcode, data, sop_idx) so that the different possible + PUSHDATA encodings can be accurately distinguished, as well as + determining the exact opcode byte indexes. (sop_idx) + """ + i = 0 + while i < len(self): + sop_idx = i + opcode = bord(self[i]) + i += 1 + + if opcode > OP_PUSHDATA4: + yield (opcode, None, sop_idx) + else: + datasize = None + pushdata_type = None + if opcode < OP_PUSHDATA1: + pushdata_type = 'PUSHDATA(%d)' % opcode + datasize = opcode + + elif opcode == OP_PUSHDATA1: + pushdata_type = 'PUSHDATA1' + if i >= len(self): + raise CScriptInvalidError('PUSHDATA1: missing data length') + datasize = bord(self[i]) + i += 1 + + elif opcode == OP_PUSHDATA2: + pushdata_type = 'PUSHDATA2' + if i + 1 >= len(self): + raise CScriptInvalidError('PUSHDATA2: missing data length') + datasize = bord(self[i]) + (bord(self[i+1]) << 8) + i += 2 + + elif opcode == OP_PUSHDATA4: + pushdata_type = 'PUSHDATA4' + if i + 3 >= len(self): + raise CScriptInvalidError('PUSHDATA4: missing data length') + datasize = bord(self[i]) + (bord(self[i+1]) << 8) + (bord(self[i+2]) << 16) + (bord(self[i+3]) << 24) + i += 4 + + else: + assert False # shouldn't happen + + + data = bytes(self[i:i+datasize]) + + # Check for truncation + if len(data) < datasize: + raise CScriptTruncatedPushDataError('%s: truncated data' % pushdata_type, data) + + i += datasize + + yield (opcode, data, sop_idx) + + def __iter__(self): + """'Cooked' iteration + + Returns either a CScriptOP instance, an integer, or bytes, as + appropriate. + + See raw_iter() if you need to distinguish the different possible + PUSHDATA encodings. + """ + for (opcode, data, sop_idx) in self.raw_iter(): + if data is not None: + yield data + else: + opcode = CScriptOp(opcode) + + if opcode.is_small_int(): + yield opcode.decode_op_n() + else: + yield CScriptOp(opcode) + + def __repr__(self): + # For Python3 compatibility add b before strings so testcases don't + # need to change + def _repr(o): + if isinstance(o, bytes): + return b"x('%s')" % hexlify(o).decode('ascii') + else: + return repr(o) + + ops = [] + i = iter(self) + while True: + op = None + try: + op = _repr(next(i)) + except CScriptTruncatedPushDataError as err: + op = '%s...' % (_repr(err.data), err) + break + except CScriptInvalidError as err: + op = '' % err + break + except StopIteration: + break + finally: + if op is not None: + ops.append(op) + + return "CScript([%s])" % ', '.join(ops) + + def GetSigOpCount(self, fAccurate): + """Get the SigOp count. + + fAccurate - Accurately count CHECKMULTISIG, see BIP16 for details. + + Note that this is consensus-critical. + """ + n = 0 + lastOpcode = OP_INVALIDOPCODE + for (opcode, data, sop_idx) in self.raw_iter(): + if opcode in (OP_CHECKSIG, OP_CHECKSIGVERIFY): + n += 1 + elif opcode in (OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY): + if fAccurate and (OP_1 <= lastOpcode <= OP_16): + n += opcode.decode_op_n() + else: + n += 20 + lastOpcode = opcode + return n + + +SIGHASH_ALL = 1 +SIGHASH_NONE = 2 +SIGHASH_SINGLE = 3 +SIGHASH_ANYONECANPAY = 0x80 + +def FindAndDelete(script, sig): + """Consensus critical, see FindAndDelete() in Satoshi codebase""" + r = b'' + last_sop_idx = sop_idx = 0 + skip = True + for (opcode, data, sop_idx) in script.raw_iter(): + if not skip: + r += script[last_sop_idx:sop_idx] + last_sop_idx = sop_idx + if script[sop_idx:sop_idx + len(sig)] == sig: + skip = True + else: + skip = False + if not skip: + r += script[last_sop_idx:] + return CScript(r) + + +def SignatureHash(script, txTo, inIdx, hashtype): + """Consensus-correct SignatureHash + + Returns (hash, err) to precisely match the consensus-critical behavior of + the SIGHASH_SINGLE bug. (inIdx is *not* checked for validity) + """ + HASH_ONE = b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' + + if inIdx >= len(txTo.vin): + return (HASH_ONE, "inIdx %d out of range (%d)" % (inIdx, len(txTo.vin))) + txtmp = CTransaction(txTo) + + for txin in txtmp.vin: + txin.scriptSig = b'' + txtmp.vin[inIdx].scriptSig = FindAndDelete(script, CScript([OP_CODESEPARATOR])) + + if (hashtype & 0x1f) == SIGHASH_NONE: + txtmp.vout = [] + + for i in range(len(txtmp.vin)): + if i != inIdx: + txtmp.vin[i].nSequence = 0 + + elif (hashtype & 0x1f) == SIGHASH_SINGLE: + outIdx = inIdx + if outIdx >= len(txtmp.vout): + return (HASH_ONE, "outIdx %d out of range (%d)" % (outIdx, len(txtmp.vout))) + + tmp = txtmp.vout[outIdx] + txtmp.vout = [] + for i in range(outIdx): + txtmp.vout.append(CTxOut(-1)) + txtmp.vout.append(tmp) + + for i in range(len(txtmp.vin)): + if i != inIdx: + txtmp.vin[i].nSequence = 0 + + if hashtype & SIGHASH_ANYONECANPAY: + tmp = txtmp.vin[inIdx] + txtmp.vin = [] + txtmp.vin.append(tmp) + + s = txtmp.serialize() + s += struct.pack(b"> (64 - b) | (n & ((1 << (64 - b)) - 1)) << b + +def siphash_round(v0, v1, v2, v3): + v0 = (v0 + v1) & ((1 << 64) - 1) + v1 = rotl64(v1, 13) + v1 ^= v0 + v0 = rotl64(v0, 32) + v2 = (v2 + v3) & ((1 << 64) - 1) + v3 = rotl64(v3, 16) + v3 ^= v2 + v0 = (v0 + v3) & ((1 << 64) - 1) + v3 = rotl64(v3, 21) + v3 ^= v0 + v2 = (v2 + v1) & ((1 << 64) - 1) + v1 = rotl64(v1, 17) + v1 ^= v2 + v2 = rotl64(v2, 32) + return (v0, v1, v2, v3) + +def siphash256(k0, k1, h): + n0 = h & ((1 << 64) - 1) + n1 = (h >> 64) & ((1 << 64) - 1) + n2 = (h >> 128) & ((1 << 64) - 1) + n3 = (h >> 192) & ((1 << 64) - 1) + v0 = 0x736f6d6570736575 ^ k0 + v1 = 0x646f72616e646f6d ^ k1 + v2 = 0x6c7967656e657261 ^ k0 + v3 = 0x7465646279746573 ^ k1 ^ n0 + v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) + v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) + v0 ^= n0 + v3 ^= n1 + v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) + v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) + v0 ^= n1 + v3 ^= n2 + v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) + v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) + v0 ^= n2 + v3 ^= n3 + v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) + v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) + v0 ^= n3 + v3 ^= 0x2000000000000000 + v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) + v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) + v0 ^= 0x2000000000000000 + v2 ^= 0xFF + v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) + v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) + v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) + v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) + return v0 ^ v1 ^ v2 ^ v3 diff --git a/rpctest/test_framework/socks5.py b/rpctest/test_framework/socks5.py new file mode 100644 index 000000000..a08b03ed2 --- /dev/null +++ b/rpctest/test_framework/socks5.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Dummy Socks5 server for testing.""" + +import socket, threading, queue +import logging + +logger = logging.getLogger("TestFramework.socks5") + +### Protocol constants +class Command: + CONNECT = 0x01 + +class AddressType: + IPV4 = 0x01 + DOMAINNAME = 0x03 + IPV6 = 0x04 + +### Utility functions +def recvall(s, n): + """Receive n bytes from a socket, or fail.""" + rv = bytearray() + while n > 0: + d = s.recv(n) + if not d: + raise IOError('Unexpected end of stream') + rv.extend(d) + n -= len(d) + return rv + +### Implementation classes +class Socks5Configuration(object): + """Proxy configuration.""" + def __init__(self): + self.addr = None # Bind address (must be set) + self.af = socket.AF_INET # Bind address family + self.unauth = False # Support unauthenticated + self.auth = False # Support authentication + +class Socks5Command(object): + """Information about an incoming socks5 command.""" + def __init__(self, cmd, atyp, addr, port, username, password): + self.cmd = cmd # Command (one of Command.*) + self.atyp = atyp # Address type (one of AddressType.*) + self.addr = addr # Address + self.port = port # Port to connect to + self.username = username + self.password = password + def __repr__(self): + return 'Socks5Command(%s,%s,%s,%s,%s,%s)' % (self.cmd, self.atyp, self.addr, self.port, self.username, self.password) + +class Socks5Connection(object): + def __init__(self, serv, conn, peer): + self.serv = serv + self.conn = conn + self.peer = peer + + def handle(self): + """Handle socks5 request according to RFC192.""" + try: + # Verify socks version + ver = recvall(self.conn, 1)[0] + if ver != 0x05: + raise IOError('Invalid socks version %i' % ver) + # Choose authentication method + nmethods = recvall(self.conn, 1)[0] + methods = bytearray(recvall(self.conn, nmethods)) + method = None + if 0x02 in methods and self.serv.conf.auth: + method = 0x02 # username/password + elif 0x00 in methods and self.serv.conf.unauth: + method = 0x00 # unauthenticated + if method is None: + raise IOError('No supported authentication method was offered') + # Send response + self.conn.sendall(bytearray([0x05, method])) + # Read authentication (optional) + username = None + password = None + if method == 0x02: + ver = recvall(self.conn, 1)[0] + if ver != 0x01: + raise IOError('Invalid auth packet version %i' % ver) + ulen = recvall(self.conn, 1)[0] + username = str(recvall(self.conn, ulen)) + plen = recvall(self.conn, 1)[0] + password = str(recvall(self.conn, plen)) + # Send authentication response + self.conn.sendall(bytearray([0x01, 0x00])) + + # Read connect request + (ver,cmd,rsv,atyp) = recvall(self.conn, 4) + if ver != 0x05: + raise IOError('Invalid socks version %i in connect request' % ver) + if cmd != Command.CONNECT: + raise IOError('Unhandled command %i in connect request' % cmd) + + if atyp == AddressType.IPV4: + addr = recvall(self.conn, 4) + elif atyp == AddressType.DOMAINNAME: + n = recvall(self.conn, 1)[0] + addr = recvall(self.conn, n) + elif atyp == AddressType.IPV6: + addr = recvall(self.conn, 16) + else: + raise IOError('Unknown address type %i' % atyp) + port_hi,port_lo = recvall(self.conn, 2) + port = (port_hi << 8) | port_lo + + # Send dummy response + self.conn.sendall(bytearray([0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) + + cmdin = Socks5Command(cmd, atyp, addr, port, username, password) + self.serv.queue.put(cmdin) + logger.info('Proxy: %s', cmdin) + # Fall through to disconnect + except Exception as e: + logger.exception("socks5 request handling failed.") + self.serv.queue.put(e) + finally: + self.conn.close() + +class Socks5Server(object): + def __init__(self, conf): + self.conf = conf + self.s = socket.socket(conf.af) + self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.s.bind(conf.addr) + self.s.listen(5) + self.running = False + self.thread = None + self.queue = queue.Queue() # report connections and exceptions to client + + def run(self): + while self.running: + (sockconn, peer) = self.s.accept() + if self.running: + conn = Socks5Connection(self, sockconn, peer) + thread = threading.Thread(None, conn.handle) + thread.daemon = True + thread.start() + + def start(self): + assert(not self.running) + self.running = True + self.thread = threading.Thread(None, self.run) + self.thread.daemon = True + self.thread.start() + + def stop(self): + self.running = False + # connect to self to end run loop + s = socket.socket(self.conf.af) + s.connect(self.conf.addr) + s.close() + self.thread.join() + diff --git a/rpctest/test_framework/test_framework.py b/rpctest/test_framework/test_framework.py new file mode 100755 index 000000000..473b7c14a --- /dev/null +++ b/rpctest/test_framework/test_framework.py @@ -0,0 +1,254 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Base class for RPC testing.""" + +from collections import deque +import logging +import optparse +import os +import sys +import shutil +import tempfile +import time + +from .util import ( + initialize_chain, + start_nodes, + connect_nodes_bi, + sync_blocks, + sync_mempools, + stop_nodes, + stop_node, + enable_coverage, + check_json_precision, + initialize_chain_clean, + PortSeed, +) +from .authproxy import JSONRPCException + +class BitcoinTestFramework(object): + + TEST_EXIT_PASSED = 0 + TEST_EXIT_FAILED = 1 + TEST_EXIT_SKIPPED = 77 + + def __init__(self): + self.num_nodes = 4 + self.setup_clean_chain = False + self.nodes = None + + def run_test(self): + raise NotImplementedError + + def add_options(self, parser): + pass + + def setup_chain(self): + self.log.info("Initializing test directory "+self.options.tmpdir) + if self.setup_clean_chain: + initialize_chain_clean(self.options.tmpdir, self.num_nodes) + else: + initialize_chain(self.options.tmpdir, self.num_nodes, self.options.cachedir) + + def stop_node(self, num_node): + stop_node(self.nodes[num_node], num_node) + + def setup_nodes(self): + return start_nodes(self.num_nodes, self.options.tmpdir) + + def setup_network(self, split = False): + self.nodes = self.setup_nodes() + + # Connect the nodes as a "chain". This allows us + # to split the network between nodes 1 and 2 to get + # two halves that can work on competing chains. + + # If we joined network halves, connect the nodes from the joint + # on outward. This ensures that chains are properly reorganised. + if not split: + connect_nodes_bi(self.nodes, 1, 2) + sync_blocks(self.nodes[1:3]) + sync_mempools(self.nodes[1:3]) + + connect_nodes_bi(self.nodes, 0, 1) + connect_nodes_bi(self.nodes, 2, 3) + self.is_network_split = split + self.sync_all() + + def split_network(self): + """ + Split the network of four nodes into nodes 0/1 and 2/3. + """ + assert not self.is_network_split + stop_nodes(self.nodes) + self.setup_network(True) + + def sync_all(self): + if self.is_network_split: + sync_blocks(self.nodes[:2]) + sync_blocks(self.nodes[2:]) + sync_mempools(self.nodes[:2]) + sync_mempools(self.nodes[2:]) + else: + sync_blocks(self.nodes) + sync_mempools(self.nodes) + + def join_network(self): + """ + Join the (previously split) network halves together. + """ + assert self.is_network_split + stop_nodes(self.nodes) + self.setup_network(False) + + def main(self): + + parser = optparse.OptionParser(usage="%prog [options]") + parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true", + help="Leave bitcoinds and test.* datadir on exit or error") + parser.add_option("--noshutdown", dest="noshutdown", default=False, action="store_true", + help="Don't stop bitcoinds after the test execution") + parser.add_option("--srcdir", dest="srcdir", default=os.path.normpath(os.path.dirname(os.path.realpath(__file__))+"/../../../src"), + help="Source directory containing bitcoind/bitcoin-cli (default: %default)") + parser.add_option("--cachedir", dest="cachedir", default=os.path.normpath(os.path.dirname(os.path.realpath(__file__))+"/../../cache"), + help="Directory for caching pregenerated datadirs") + parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"), + help="Root directory for datadirs") + parser.add_option("-l", "--loglevel", dest="loglevel", default="INFO", + help="log events at this level and higher to the console. Can be set to DEBUG, INFO, WARNING, ERROR or CRITICAL. Passing --loglevel DEBUG will output all logs to console. Note that logs at all levels are always written to the test_framework.log file in the temporary test directory.") + parser.add_option("--tracerpc", dest="trace_rpc", default=False, action="store_true", + help="Print out all RPC calls as they are made") + parser.add_option("--portseed", dest="port_seed", default=os.getpid(), type='int', + help="The seed to use for assigning port numbers (default: current process id)") + parser.add_option("--coveragedir", dest="coveragedir", + help="Write tested RPC commands into this directory") + self.add_options(parser) + (self.options, self.args) = parser.parse_args() + + # backup dir variable for removal at cleanup + self.options.root, self.options.tmpdir = self.options.tmpdir, self.options.tmpdir + '/' + str(self.options.port_seed) + + if self.options.coveragedir: + enable_coverage(self.options.coveragedir) + + PortSeed.n = self.options.port_seed + + os.environ['PATH'] = self.options.srcdir+":"+self.options.srcdir+"/qt:"+os.environ['PATH'] + + check_json_precision() + + # Set up temp directory and start logging + os.makedirs(self.options.tmpdir, exist_ok=False) + self._start_logging() + + success = False + + try: + self.setup_chain() + self.setup_network() + self.run_test() + success = True + except JSONRPCException as e: + self.log.exception("JSONRPC error") + except AssertionError as e: + self.log.exception("Assertion failed") + except KeyError as e: + self.log.exception("Key error") + except Exception as e: + self.log.exception("Unexpected exception caught during testing") + except KeyboardInterrupt as e: + self.log.warning("Exiting after keyboard interrupt") + + if not self.options.noshutdown: + self.log.info("Stopping nodes") + stop_nodes(self.nodes) + else: + self.log.info("Note: bitcoinds were not stopped and may still be running") + + if not self.options.nocleanup and not self.options.noshutdown and success: + self.log.info("Cleaning up") + shutil.rmtree(self.options.tmpdir) + if not os.listdir(self.options.root): + os.rmdir(self.options.root) + else: + self.log.warning("Not cleaning up dir %s" % self.options.tmpdir) + if os.getenv("PYTHON_DEBUG", ""): + # Dump the end of the debug logs, to aid in debugging rare + # travis failures. + import glob + filenames = [self.options.tmpdir + "/test_framework.log"] + filenames += glob.glob(self.options.tmpdir + "/node*/regtest/debug.log") + MAX_LINES_TO_PRINT = 1000 + for fn in filenames: + try: + with open(fn, 'r') as f: + print("From" , fn, ":") + print("".join(deque(f, MAX_LINES_TO_PRINT))) + except OSError: + print("Opening file %s failed." % fn) + traceback.print_exc() + if success: + self.log.info("Tests successful") + sys.exit(self.TEST_EXIT_PASSED) + else: + self.log.error("Test failed. Test logging available at %s/test_framework.log", self.options.tmpdir) + logging.shutdown() + sys.exit(self.TEST_EXIT_FAILED) + + def _start_logging(self): + # Add logger and logging handlers + self.log = logging.getLogger('TestFramework') + self.log.setLevel(logging.DEBUG) + # Create file handler to log all messages + fh = logging.FileHandler(self.options.tmpdir + '/test_framework.log') + fh.setLevel(logging.DEBUG) + # Create console handler to log messages to stderr. By default this logs only error messages, but can be configured with --loglevel. + ch = logging.StreamHandler(sys.stdout) + # User can provide log level as a number or string (eg DEBUG). loglevel was caught as a string, so try to convert it to an int + ll = int(self.options.loglevel) if self.options.loglevel.isdigit() else self.options.loglevel.upper() + ch.setLevel(ll) + # Format logs the same as bitcoind's debug.log with microprecision (so log files can be concatenated and sorted) + formatter = logging.Formatter(fmt = '%(asctime)s.%(msecs)03d000 %(name)s (%(levelname)s): %(message)s', datefmt='%Y-%m-%d %H:%M:%S') + formatter.converter = time.gmtime + fh.setFormatter(formatter) + ch.setFormatter(formatter) + # add the handlers to the logger + self.log.addHandler(fh) + self.log.addHandler(ch) + + if self.options.trace_rpc: + rpc_logger = logging.getLogger("BitcoinRPC") + rpc_logger.setLevel(logging.DEBUG) + rpc_handler = logging.StreamHandler(sys.stdout) + rpc_handler.setLevel(logging.DEBUG) + rpc_logger.addHandler(rpc_handler) + +# Test framework for doing p2p comparison testing, which sets up some bitcoind +# binaries: +# 1 binary: test binary +# 2 binaries: 1 test binary, 1 ref binary +# n>2 binaries: 1 test binary, n-1 ref binaries + +class ComparisonTestFramework(BitcoinTestFramework): + + def __init__(self): + super().__init__() + self.num_nodes = 2 + self.setup_clean_chain = True + + def add_options(self, parser): + parser.add_option("--testbinary", dest="testbinary", + default=os.getenv("BITCOIND", "bitcoind"), + help="bitcoind binary to test") + parser.add_option("--refbinary", dest="refbinary", + default=os.getenv("BITCOIND", "bitcoind"), + help="bitcoind binary to use for reference nodes (if any)") + + def setup_network(self): + self.nodes = start_nodes( + self.num_nodes, self.options.tmpdir, + extra_args=[['-whitelist=127.0.0.1']] * self.num_nodes, + binary=[self.options.testbinary] + + [self.options.refbinary]*(self.num_nodes-1)) diff --git a/rpctest/test_framework/util.py b/rpctest/test_framework/util.py new file mode 100644 index 000000000..899b0b5a1 --- /dev/null +++ b/rpctest/test_framework/util.py @@ -0,0 +1,670 @@ +#!/usr/bin/env python3 +# Copyright (c) 2014-2016 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Helpful routines for regression testing.""" + +import os +import sys + +from binascii import hexlify, unhexlify +from base64 import b64encode +from decimal import Decimal, ROUND_DOWN +import json +import http.client +import random +import shutil +import subprocess +import tempfile +import time +import re +import errno +import logging + +from . import coverage +from .authproxy import AuthServiceProxy, JSONRPCException + +COVERAGE_DIR = None + +logger = logging.getLogger("TestFramework.utils") + +# The maximum number of nodes a single test can spawn +MAX_NODES = 8 +# Don't assign rpc or p2p ports lower than this +PORT_MIN = 11000 +# The number of ports to "reserve" for p2p and rpc, each +PORT_RANGE = 5000 + +BITCOIND_PROC_WAIT_TIMEOUT = 60 + + +class PortSeed: + # Must be initialized with a unique integer for each process + n = None + +#Set Mocktime default to OFF. +#MOCKTIME is only needed for scripts that use the +#cached version of the blockchain. If the cached +#version of the blockchain is used without MOCKTIME +#then the mempools will not sync due to IBD. +MOCKTIME = 0 + +def enable_mocktime(): + #For backwared compatibility of the python scripts + #with previous versions of the cache, set MOCKTIME + #to Jan 1, 2014 + (201 * 10 * 60) + global MOCKTIME + MOCKTIME = 1388534400 + (201 * 10 * 60) + +def disable_mocktime(): + global MOCKTIME + MOCKTIME = 0 + +def get_mocktime(): + return MOCKTIME + +def enable_coverage(dirname): + """Maintain a log of which RPC calls are made during testing.""" + global COVERAGE_DIR + COVERAGE_DIR = dirname + + +def get_rpc_proxy(url, node_number, timeout=None): + """ + Args: + url (str): URL of the RPC server to call + node_number (int): the node number (or id) that this calls to + + Kwargs: + timeout (int): HTTP timeout in seconds + + Returns: + AuthServiceProxy. convenience object for making RPC calls. + + """ + proxy_kwargs = {} + if timeout is not None: + proxy_kwargs['timeout'] = timeout + + proxy = AuthServiceProxy(url, **proxy_kwargs) + proxy.url = url # store URL on proxy for info + + coverage_logfile = coverage.get_filename( + COVERAGE_DIR, node_number) if COVERAGE_DIR else None + + return coverage.AuthServiceProxyWrapper(proxy, coverage_logfile) + + +def p2p_port(n): + assert(n <= MAX_NODES) + return PORT_MIN + n + (MAX_NODES * PortSeed.n) % (PORT_RANGE - 1 - MAX_NODES) + +def rpc_port(n): + return PORT_MIN + PORT_RANGE + n + (MAX_NODES * PortSeed.n) % (PORT_RANGE - 1 - MAX_NODES) + +def check_json_precision(): + """Make sure json library being used does not lose precision converting BTC values""" + n = Decimal("20000000.00000003") + satoshis = int(json.loads(json.dumps(float(n)))*1.0e8) + if satoshis != 2000000000000003: + raise RuntimeError("JSON encode/decode loses precision") + +def count_bytes(hex_string): + return len(bytearray.fromhex(hex_string)) + +def bytes_to_hex_str(byte_str): + return hexlify(byte_str).decode('ascii') + +def hex_str_to_bytes(hex_str): + return unhexlify(hex_str.encode('ascii')) + +def str_to_b64str(string): + return b64encode(string.encode('utf-8')).decode('ascii') + +def sync_blocks(rpc_connections, *, wait=1, timeout=60): + """ + Wait until everybody has the same tip. + + sync_blocks needs to be called with an rpc_connections set that has least + one node already synced to the latest, stable tip, otherwise there's a + chance it might return before all nodes are stably synced. + """ + # Use getblockcount() instead of waitforblockheight() to determine the + # initial max height because the two RPCs look at different internal global + # variables (chainActive vs latestBlock) and the former gets updated + # earlier. + maxheight = max(x.getblockcount() for x in rpc_connections) + start_time = cur_time = time.time() + while cur_time <= start_time + timeout: + tips = [r.waitforblockheight(maxheight, int(wait * 1000)) for r in rpc_connections] + if all(t["height"] == maxheight for t in tips): + if all(t["hash"] == tips[0]["hash"] for t in tips): + return + raise AssertionError("Block sync failed, mismatched block hashes:{}".format( + "".join("\n {!r}".format(tip) for tip in tips))) + cur_time = time.time() + raise AssertionError("Block sync to height {} timed out:{}".format( + maxheight, "".join("\n {!r}".format(tip) for tip in tips))) + +def sync_chain(rpc_connections, *, wait=1, timeout=60): + """ + Wait until everybody has the same best block + """ + while timeout > 0: + best_hash = [x.getbestblockhash() for x in rpc_connections] + if best_hash == [best_hash[0]]*len(best_hash): + return + time.sleep(wait) + timeout -= wait + raise AssertionError("Chain sync failed: Best block hashes don't match") + +def sync_mempools(rpc_connections, *, wait=1, timeout=60): + """ + Wait until everybody has the same transactions in their memory + pools + """ + while timeout > 0: + pool = set(rpc_connections[0].getrawmempool()) + num_match = 1 + for i in range(1, len(rpc_connections)): + if set(rpc_connections[i].getrawmempool()) == pool: + num_match = num_match+1 + if num_match == len(rpc_connections): + return + time.sleep(wait) + timeout -= wait + raise AssertionError("Mempool sync failed") + +bitcoind_processes = {} + +def initialize_datadir(dirname, n): + datadir = os.path.join(dirname, "node"+str(n)) + if not os.path.isdir(datadir): + os.makedirs(datadir) + rpc_u, rpc_p = rpc_auth_pair(n) + with open(os.path.join(datadir, "bitcoin.conf"), 'w', encoding='utf8') as f: + f.write("regtest=1\n") + f.write("rpcuser=" + rpc_u + "\n") + f.write("rpcpassword=" + rpc_p + "\n") + f.write("port="+str(p2p_port(n))+"\n") + f.write("rpcport="+str(rpc_port(n))+"\n") + f.write("listenonion=0\n") + return datadir + +def rpc_auth_pair(n): + return 'rpcuser💻' + str(n), 'rpcpass🔑' + str(n) + +def rpc_url(i, rpchost=None): + rpc_u, rpc_p = rpc_auth_pair(i) + host = '127.0.0.1' + port = rpc_port(i) + if rpchost: + parts = rpchost.split(':') + if len(parts) == 2: + host, port = parts + else: + host = rpchost + return "http://%s:%s@%s:%d" % (rpc_u, rpc_p, host, int(port)) + +def wait_for_bitcoind_start(process, url, i): + ''' + Wait for bitcoind to start. This means that RPC is accessible and fully initialized. + Raise an exception if bitcoind exits during initialization. + ''' + while True: + if process.poll() is not None: + raise Exception('bitcoind exited with status %i during initialization' % process.returncode) + try: + rpc = get_rpc_proxy(url, i) + blocks = rpc.getblockcount() + break # break out of loop on success + except IOError as e: + if e.errno != errno.ECONNREFUSED: # Port not yet open? + raise # unknown IO error + except JSONRPCException as e: # Initialization phase + if e.error['code'] != -28: # RPC in warmup? + raise # unknown JSON RPC exception + time.sleep(0.25) + +def initialize_chain(test_dir, num_nodes, cachedir): + """ + Create a cache of a 200-block-long chain (with wallet) for MAX_NODES + Afterward, create num_nodes copies from the cache + """ + + assert num_nodes <= MAX_NODES + create_cache = False + for i in range(MAX_NODES): + if not os.path.isdir(os.path.join(cachedir, 'node'+str(i))): + create_cache = True + break + + if create_cache: + logger.debug("Creating data directories from cached datadir") + + #find and delete old cache directories if any exist + for i in range(MAX_NODES): + if os.path.isdir(os.path.join(cachedir,"node"+str(i))): + shutil.rmtree(os.path.join(cachedir,"node"+str(i))) + + # Create cache directories, run bitcoinds: + for i in range(MAX_NODES): + datadir=initialize_datadir(cachedir, i) + args = [ os.getenv("BITCOIND", "bitcoind"), "-server", "-keypool=1", "-datadir="+datadir, "-discover=0" ] + if i > 0: + args.append("-connect=127.0.0.1:"+str(p2p_port(0))) + bitcoind_processes[i] = subprocess.Popen(args) + logger.debug("initialize_chain: bitcoind started, waiting for RPC to come up") + wait_for_bitcoind_start(bitcoind_processes[i], rpc_url(i), i) + logger.debug("initialize_chain: RPC successfully started") + + rpcs = [] + for i in range(MAX_NODES): + try: + rpcs.append(get_rpc_proxy(rpc_url(i), i)) + except: + sys.stderr.write("Error connecting to "+url+"\n") + sys.exit(1) + + # Create a 200-block-long chain; each of the 4 first nodes + # gets 25 mature blocks and 25 immature. + # Note: To preserve compatibility with older versions of + # initialize_chain, only 4 nodes will generate coins. + # + # blocks are created with timestamps 10 minutes apart + # starting from 2010 minutes in the past + enable_mocktime() + block_time = get_mocktime() - (201 * 10 * 60) + for i in range(2): + for peer in range(4): + for j in range(25): + set_node_times(rpcs, block_time) + rpcs[peer].generate(1) + block_time += 10*60 + # Must sync before next peer starts generating blocks + sync_blocks(rpcs) + + # Shut them down, and clean up cache directories: + stop_nodes(rpcs) + disable_mocktime() + for i in range(MAX_NODES): + os.remove(log_filename(cachedir, i, "debug.log")) + os.remove(log_filename(cachedir, i, "db.log")) + os.remove(log_filename(cachedir, i, "peers.dat")) + os.remove(log_filename(cachedir, i, "fee_estimates.dat")) + + for i in range(num_nodes): + from_dir = os.path.join(cachedir, "node"+str(i)) + to_dir = os.path.join(test_dir, "node"+str(i)) + shutil.copytree(from_dir, to_dir) + initialize_datadir(test_dir, i) # Overwrite port/rpcport in bitcoin.conf + +def initialize_chain_clean(test_dir, num_nodes): + """ + Create an empty blockchain and num_nodes wallets. + Useful if a test case wants complete control over initialization. + """ + for i in range(num_nodes): + datadir=initialize_datadir(test_dir, i) + + +def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None, stderr=None): + """ + Start a bitcoind and return RPC connection to it + """ + datadir = os.path.join(dirname, "node"+str(i)) + if binary is None: + binary = os.getenv("BITCOIND", "bitcoind") + args = [binary, "-datadir=" + datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-logtimemicros", "-debug", "-debugexclude=libevent", "-debugexclude=leveldb", "-mocktime=" + str(get_mocktime())] + if extra_args is not None: args.extend(extra_args) + bitcoind_processes[i] = subprocess.Popen(args, stderr=stderr) + logger.debug("initialize_chain: bitcoind started, waiting for RPC to come up") + url = rpc_url(i, rpchost) + wait_for_bitcoind_start(bitcoind_processes[i], url, i) + logger.debug("initialize_chain: RPC successfully started") + proxy = get_rpc_proxy(url, i, timeout=timewait) + + if COVERAGE_DIR: + coverage.write_all_rpc_commands(COVERAGE_DIR, proxy) + + return proxy + +def assert_start_raises_init_error(i, dirname, extra_args=None, expected_msg=None): + with tempfile.SpooledTemporaryFile(max_size=2**16) as log_stderr: + try: + node = start_node(i, dirname, extra_args, stderr=log_stderr) + stop_node(node, i) + except Exception as e: + assert 'bitcoind exited' in str(e) #node must have shutdown + if expected_msg is not None: + log_stderr.seek(0) + stderr = log_stderr.read().decode('utf-8') + if expected_msg not in stderr: + raise AssertionError("Expected error \"" + expected_msg + "\" not found in:\n" + stderr) + else: + if expected_msg is None: + assert_msg = "bitcoind should have exited with an error" + else: + assert_msg = "bitcoind should have exited with expected error " + expected_msg + raise AssertionError(assert_msg) + +def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None): + """ + Start multiple bitcoinds, return RPC connections to them + """ + if extra_args is None: extra_args = [ None for _ in range(num_nodes) ] + if binary is None: binary = [ None for _ in range(num_nodes) ] + rpcs = [] + try: + for i in range(num_nodes): + rpcs.append(start_node(i, dirname, extra_args[i], rpchost, timewait=timewait, binary=binary[i])) + except: # If one node failed to start, stop the others + stop_nodes(rpcs) + raise + return rpcs + +def log_filename(dirname, n_node, logname): + return os.path.join(dirname, "node"+str(n_node), "regtest", logname) + +def stop_node(node, i): + logger.debug("Stopping node %d" % i) + try: + node.stop() + except http.client.CannotSendRequest as e: + logger.exception("Unable to stop node") + return_code = bitcoind_processes[i].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT) + assert_equal(return_code, 0) + del bitcoind_processes[i] + +def stop_nodes(nodes): + for i, node in enumerate(nodes): + stop_node(node, i) + assert not bitcoind_processes.values() # All connections must be gone now + +def set_node_times(nodes, t): + for node in nodes: + node.setmocktime(t) + +def connect_nodes(from_connection, node_num): + ip_port = "127.0.0.1:"+str(p2p_port(node_num)) + from_connection.addnode(ip_port, "onetry") + # poll until version handshake complete to avoid race conditions + # with transaction relaying + while any(peer['version'] == 0 for peer in from_connection.getpeerinfo()): + time.sleep(0.1) + +def connect_nodes_bi(nodes, a, b): + connect_nodes(nodes[a], b) + connect_nodes(nodes[b], a) + +def find_output(node, txid, amount): + """ + Return index to output of txid with value amount + Raises exception if there is none. + """ + txdata = node.getrawtransaction(txid, 1) + for i in range(len(txdata["vout"])): + if txdata["vout"][i]["value"] == amount: + return i + raise RuntimeError("find_output txid %s : %s not found"%(txid,str(amount))) + + +def gather_inputs(from_node, amount_needed, confirmations_required=1): + """ + Return a random set of unspent txouts that are enough to pay amount_needed + """ + assert(confirmations_required >=0) + utxo = from_node.listunspent(confirmations_required) + random.shuffle(utxo) + inputs = [] + total_in = Decimal("0.00000000") + while total_in < amount_needed and len(utxo) > 0: + t = utxo.pop() + total_in += t["amount"] + inputs.append({ "txid" : t["txid"], "vout" : t["vout"], "address" : t["address"] } ) + if total_in < amount_needed: + raise RuntimeError("Insufficient funds: need %d, have %d"%(amount_needed, total_in)) + return (total_in, inputs) + +def make_change(from_node, amount_in, amount_out, fee): + """ + Create change output(s), return them + """ + outputs = {} + amount = amount_out+fee + change = amount_in - amount + if change > amount*2: + # Create an extra change output to break up big inputs + change_address = from_node.getnewaddress() + # Split change in two, being careful of rounding: + outputs[change_address] = Decimal(change/2).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN) + change = amount_in - amount - outputs[change_address] + if change > 0: + outputs[from_node.getnewaddress()] = change + return outputs + +def random_transaction(nodes, amount, min_fee, fee_increment, fee_variants): + """ + Create a random transaction. + Returns (txid, hex-encoded-transaction-data, fee) + """ + from_node = random.choice(nodes) + to_node = random.choice(nodes) + fee = min_fee + fee_increment*random.randint(0,fee_variants) + + (total_in, inputs) = gather_inputs(from_node, amount+fee) + outputs = make_change(from_node, total_in, amount, fee) + outputs[to_node.getnewaddress()] = float(amount) + + rawtx = from_node.createrawtransaction(inputs, outputs) + signresult = from_node.signrawtransaction(rawtx) + txid = from_node.sendrawtransaction(signresult["hex"], True) + + return (txid, signresult["hex"], fee) + +def assert_fee_amount(fee, tx_size, fee_per_kB): + """Assert the fee was in range""" + target_fee = tx_size * fee_per_kB / 1000 + if fee < target_fee: + raise AssertionError("Fee of %s BTC too low! (Should be %s BTC)"%(str(fee), str(target_fee))) + # allow the wallet's estimation to be at most 2 bytes off + if fee > (tx_size + 2) * fee_per_kB / 1000: + raise AssertionError("Fee of %s BTC too high! (Should be %s BTC)"%(str(fee), str(target_fee))) + +def assert_equal(thing1, thing2, *args): + if thing1 != thing2 or any(thing1 != arg for arg in args): + raise AssertionError("not(%s)" % " == ".join(str(arg) for arg in (thing1, thing2) + args)) + +def assert_greater_than(thing1, thing2): + if thing1 <= thing2: + raise AssertionError("%s <= %s"%(str(thing1),str(thing2))) + +def assert_greater_than_or_equal(thing1, thing2): + if thing1 < thing2: + raise AssertionError("%s < %s"%(str(thing1),str(thing2))) + +def assert_raises(exc, fun, *args, **kwds): + assert_raises_message(exc, None, fun, *args, **kwds) + +def assert_raises_message(exc, message, fun, *args, **kwds): + try: + fun(*args, **kwds) + except exc as e: + if message is not None and message not in e.error['message']: + raise AssertionError("Expected substring not found:"+e.error['message']) + except Exception as e: + raise AssertionError("Unexpected exception raised: "+type(e).__name__) + else: + raise AssertionError("No exception raised") + +def assert_raises_jsonrpc(code, message, fun, *args, **kwds): + """Run an RPC and verify that a specific JSONRPC exception code and message is raised. + + Calls function `fun` with arguments `args` and `kwds`. Catches a JSONRPCException + and verifies that the error code and message are as expected. Throws AssertionError if + no JSONRPCException was returned or if the error code/message are not as expected. + + Args: + code (int), optional: the error code returned by the RPC call (defined + in src/rpc/protocol.h). Set to None if checking the error code is not required. + message (string), optional: [a substring of] the error string returned by the + RPC call. Set to None if checking the error string is not required + fun (function): the function to call. This should be the name of an RPC. + args*: positional arguments for the function. + kwds**: named arguments for the function. + """ + try: + fun(*args, **kwds) + except JSONRPCException as e: + # JSONRPCException was thrown as expected. Check the code and message values are correct. + if (code is not None) and (code != e.error["code"]): + raise AssertionError("Unexpected JSONRPC error code %i" % e.error["code"]) + if (message is not None) and (message not in e.error['message']): + raise AssertionError("Expected substring not found:"+e.error['message']) + except Exception as e: + raise AssertionError("Unexpected exception raised: "+type(e).__name__) + else: + raise AssertionError("No exception raised") + +def assert_is_hex_string(string): + try: + int(string, 16) + except Exception as e: + raise AssertionError( + "Couldn't interpret %r as hexadecimal; raised: %s" % (string, e)) + +def assert_is_hash_string(string, length=64): + if not isinstance(string, str): + raise AssertionError("Expected a string, got type %r" % type(string)) + elif length and len(string) != length: + raise AssertionError( + "String of length %d expected; got %d" % (length, len(string))) + elif not re.match('[abcdef0-9]+$', string): + raise AssertionError( + "String %r contains invalid characters for a hash." % string) + +def assert_array_result(object_array, to_match, expected, should_not_find = False): + """ + Pass in array of JSON objects, a dictionary with key/value pairs + to match against, and another dictionary with expected key/value + pairs. + If the should_not_find flag is true, to_match should not be found + in object_array + """ + if should_not_find == True: + assert_equal(expected, { }) + num_matched = 0 + for item in object_array: + all_match = True + for key,value in to_match.items(): + if item[key] != value: + all_match = False + if not all_match: + continue + elif should_not_find == True: + num_matched = num_matched+1 + for key,value in expected.items(): + if item[key] != value: + raise AssertionError("%s : expected %s=%s"%(str(item), str(key), str(value))) + num_matched = num_matched+1 + if num_matched == 0 and should_not_find != True: + raise AssertionError("No objects matched %s"%(str(to_match))) + if num_matched > 0 and should_not_find == True: + raise AssertionError("Objects were found %s"%(str(to_match))) + +def satoshi_round(amount): + return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN) + +# Helper to create at least "count" utxos +# Pass in a fee that is sufficient for relay and mining new transactions. +def create_confirmed_utxos(fee, node, count): + node.generate(int(0.5*count)+101) + utxos = node.listunspent() + iterations = count - len(utxos) + addr1 = node.getnewaddress() + addr2 = node.getnewaddress() + if iterations <= 0: + return utxos + for i in range(iterations): + t = utxos.pop() + inputs = [] + inputs.append({ "txid" : t["txid"], "vout" : t["vout"]}) + outputs = {} + send_value = t['amount'] - fee + outputs[addr1] = satoshi_round(send_value/2) + outputs[addr2] = satoshi_round(send_value/2) + raw_tx = node.createrawtransaction(inputs, outputs) + signed_tx = node.signrawtransaction(raw_tx)["hex"] + txid = node.sendrawtransaction(signed_tx) + + while (node.getmempoolinfo()['size'] > 0): + node.generate(1) + + utxos = node.listunspent() + assert(len(utxos) >= count) + return utxos + +# Create large OP_RETURN txouts that can be appended to a transaction +# to make it large (helper for constructing large transactions). +def gen_return_txouts(): + # Some pre-processing to create a bunch of OP_RETURN txouts to insert into transactions we create + # So we have big transactions (and therefore can't fit very many into each block) + # create one script_pubkey + script_pubkey = "6a4d0200" #OP_RETURN OP_PUSH2 512 bytes + for i in range (512): + script_pubkey = script_pubkey + "01" + # concatenate 128 txouts of above script_pubkey which we'll insert before the txout for change + txouts = "81" + for k in range(128): + # add txout value + txouts = txouts + "0000000000000000" + # add length of script_pubkey + txouts = txouts + "fd0402" + # add script_pubkey + txouts = txouts + script_pubkey + return txouts + +def create_tx(node, coinbase, to_address, amount): + inputs = [{ "txid" : coinbase, "vout" : 0}] + outputs = { to_address : amount } + rawtx = node.createrawtransaction(inputs, outputs) + signresult = node.signrawtransaction(rawtx) + assert_equal(signresult["complete"], True) + return signresult["hex"] + +# Create a spend of each passed-in utxo, splicing in "txouts" to each raw +# transaction to make it large. See gen_return_txouts() above. +def create_lots_of_big_transactions(node, txouts, utxos, num, fee): + addr = node.getnewaddress() + txids = [] + for _ in range(num): + t = utxos.pop() + inputs=[{ "txid" : t["txid"], "vout" : t["vout"]}] + outputs = {} + change = t['amount'] - fee + outputs[addr] = satoshi_round(change) + rawtx = node.createrawtransaction(inputs, outputs) + newtx = rawtx[0:92] + newtx = newtx + txouts + newtx = newtx + rawtx[94:] + signresult = node.signrawtransaction(newtx, None, None, "NONE") + txid = node.sendrawtransaction(signresult["hex"], True) + txids.append(txid) + return txids + +def mine_large_block(node, utxos=None): + # generate a 66k transaction, + # and 14 of them is close to the 1MB block limit + num = 14 + txouts = gen_return_txouts() + utxos = utxos if utxos is not None else [] + if len(utxos) < num: + utxos.clear() + utxos.extend(node.listunspent()) + fee = 100 * node.getnetworkinfo()["relayfee"] + create_lots_of_big_transactions(node, txouts, utxos, num, fee=fee) + node.generate(1) + +def get_bip9_status(node, key): + info = node.getblockchaininfo() + return info['bip9_softforks'][key] diff --git a/src/aes256_cbc.c b/src/aes256_cbc.c new file mode 100644 index 000000000..3f4298293 --- /dev/null +++ b/src/aes256_cbc.c @@ -0,0 +1,89 @@ + +#include +#include + +#include + +int aes256_cbc_encrypt(const unsigned char aes_key[32], const unsigned char iv[AES_BLOCK_SIZE], const unsigned char* data, int size, int pad, unsigned char* out) +{ + int written = 0; + int padsize = size % AES_BLOCK_SIZE; + unsigned char mixed[AES_BLOCK_SIZE]; + + if (!data || !size || !out) + return 0; + + if (!pad && padsize != 0) + return 0; + + AES256_ctx aes_ctx; + // Set cipher key + AES256_init(&aes_ctx, aes_key); + + memcpy(mixed, iv, AES_BLOCK_SIZE); + + // Write all but the last block + while (written + AES_BLOCK_SIZE <= size) { + for (int i = 0; i != AES_BLOCK_SIZE; i++) + mixed[i] ^= *data++; + AES256_encrypt(&aes_ctx, 1, out + written, mixed); + memcpy(mixed, out + written, AES_BLOCK_SIZE); + written += AES_BLOCK_SIZE; + } + if (pad) { + // For all that remains, pad each byte with the value of the remaining + // space. If there is none, pad by a full block. + for (int i = 0; i != padsize; i++) + mixed[i] ^= *data++; + for (int i = padsize; i != AES_BLOCK_SIZE; i++) + mixed[i] ^= AES_BLOCK_SIZE - padsize; + AES256_encrypt(&aes_ctx, 1, out + written, mixed); + written += AES_BLOCK_SIZE; + } + return written; +} + +int aes256_cbc_decrypt(const unsigned char aes_key[32], const unsigned char iv[AES_BLOCK_SIZE], const unsigned char* data, int size, int pad, unsigned char* out) +{ + unsigned char padsize = 0; + int written = 0; + int fail = 0; + const unsigned char* prev = iv; + + if (!data || !size || !out) + return 0; + + if (size % AES_BLOCK_SIZE != 0) + return 0; + + AES256_ctx aes_ctx; + // Set cipher key + AES256_init(&aes_ctx, aes_key); + + // Decrypt all data. Padding will be checked in the output. + while (written != size) { + AES256_decrypt(&aes_ctx, 1, out, data + written); + for (int i = 0; i != AES_BLOCK_SIZE; i++) + *out++ ^= prev[i]; + prev = data + written; + written += AES_BLOCK_SIZE; + } + + // When decrypting padding, attempt to run in constant-time + if (pad) { + // If used, padding size is the value of the last decrypted byte. For + // it to be valid, It must be between 1 and AES_BLOCK_SIZE. + padsize = *--out; + fail = !padsize | (padsize > AES_BLOCK_SIZE); + + // If not well-formed, treat it as though there's no padding. + padsize *= !fail; + + // All padding must equal the last byte otherwise it's not well-formed + for (int i = AES_BLOCK_SIZE; i != 0; i--) + fail |= ((i > AES_BLOCK_SIZE - padsize) & (*out-- != padsize)); + + written -= padsize; + } + return written * !fail; +} diff --git a/src/base58.c b/src/base58.c new file mode 100644 index 000000000..ed0fe659d --- /dev/null +++ b/src/base58.c @@ -0,0 +1,245 @@ +/** + * Copyright (c) 2012-2014 Luke Dashjr + * 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 +#include + +#include + +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, +}; + +int btc_base58_decode(void* bin, size_t* binszp, const char* b58) +{ + size_t binsz = *binszp; + const unsigned char* b58u = (const 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) + memset(outi, 0, outisz * sizeof(*outi)); + return false; + } + if (outi[0] & zeromask) { + // Output number too big (last int32 filled too far) + memset(outi, 0, outisz * sizeof(*outi)); + 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; + } + + 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; + } + --*binszp; + } + *binszp += zerocount; + + memset(outi, 0, outisz * sizeof(*outi)); + return true; +} + +int btc_b58check(const void* bin, size_t binsz, const char* base58str) +{ + uint256 buf; + const uint8_t* binc = bin; + unsigned i; + if (binsz < 4) { + return -4; + } + sha256_Raw(bin, binsz - 4, buf); + sha256_Raw(buf, sizeof(buf), 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"; + +int btc_base58_encode(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; + } + } + + for (j = 0; j < (ssize_t)size && !buf[j]; ++j) + ; + + if (*b58sz <= zcount + size - j) { + *b58sz = zcount + size - j + 1; + memset(buf, 0, size); + 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; + + memset(buf, 0, size); + return true; +} + +int btc_base58_encode_check(const uint8_t* data, int datalen, char* str, int strsize) +{ + int ret; + 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 (btc_base58_encode(str, &res, buf, datalen + 4) != true) { + ret = 0; + } else { + ret = res; + } + memset(buf, 0, sizeof(buf)); + return ret; +} + +int btc_base58_decode_check(const char* str, uint8_t* data, size_t datalen) +{ + int ret; + size_t strl = strlen(str); + + /* buffer needs to be at least the strsize, will be used + for the whole decoding */ + if (strl > 128 || datalen < strl) { + return 0; + } + + size_t binsize = strl; + if (btc_base58_decode(data, &binsize, str) != true) { + ret = 0; + } + + memmove(data, data + strl - binsize, binsize); + memset(data + binsize, 0, datalen - binsize); + + if (btc_b58check(data, binsize, str) < 0) { + ret = 0; + } else { + ret = binsize; + } + return ret; +} diff --git a/src/bip32.c b/src/bip32.c new file mode 100644 index 000000000..e12fd764b --- /dev/null +++ b/src/bip32.c @@ -0,0 +1,385 @@ +/** + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * Copyright (c) 2015 Douglas J. Bakkumk + * + * 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 +#include + +#include +#include +#include +#include +#include +#include + +#include "memory.h" + +#include "ripemd160.h" + +// write 4 big endian bytes +static void write_be(uint8_t* data, uint32_t x) +{ + data[0] = x >> 24; + data[1] = x >> 16; + data[2] = x >> 8; + data[3] = x; +} + + +// read 4 big endian bytes +static 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])); +} + +btc_hdnode* btc_hdnode_new() +{ + btc_hdnode* hdnode; + hdnode = btc_calloc(1, sizeof(*hdnode)); + return hdnode; +} + +btc_hdnode* btc_hdnode_copy(btc_hdnode* hdnode) +{ + btc_hdnode* newnode = btc_hdnode_new(); + + newnode->depth = hdnode->depth; + newnode->fingerprint = hdnode->fingerprint; + newnode->child_num = hdnode->child_num; + memcpy(newnode->chain_code, hdnode->chain_code, sizeof(hdnode->chain_code)); + memcpy(newnode->private_key, hdnode->private_key, sizeof(hdnode->private_key)); + memcpy(newnode->public_key, hdnode->public_key, sizeof(hdnode->public_key)); + + return newnode; +} + +void btc_hdnode_free(btc_hdnode* hdnode) +{ + memset(hdnode->chain_code, 0, sizeof(hdnode->chain_code)); + memset(hdnode->private_key, 0, sizeof(hdnode->private_key)); + memset(hdnode->public_key, 0, sizeof(hdnode->public_key)); + btc_free(hdnode); +} + +btc_bool btc_hdnode_from_seed(const uint8_t* seed, int seed_len, btc_hdnode* out) +{ + uint8_t I[BTC_ECKEY_PKEY_LENGTH + BTC_BIP32_CHAINCODE_SIZE]; + memset(out, 0, sizeof(btc_hdnode)); + out->depth = 0; + out->fingerprint = 0x00000000; + out->child_num = 0; + hmac_sha512((const uint8_t*)"Bitcoin seed", 12, seed, seed_len, I); + memcpy(out->private_key, I, BTC_ECKEY_PKEY_LENGTH); + + if (!btc_ecc_verify_privatekey(out->private_key)) { + memset(I, 0, sizeof(I)); + return false; + } + + memcpy(out->chain_code, I + BTC_ECKEY_PKEY_LENGTH, BTC_BIP32_CHAINCODE_SIZE); + btc_hdnode_fill_public_key(out); + memset(I, 0, sizeof(I)); + return true; +} + + +btc_bool btc_hdnode_public_ckd(btc_hdnode* inout, uint32_t i) +{ + uint8_t data[1 + 32 + 4]; + uint8_t I[32 + BTC_BIP32_CHAINCODE_SIZE]; + uint8_t fingerprint[32]; + + if (i & 0x80000000) { // private derivation + return false; + } else { // public derivation + memcpy(data, inout->public_key, BTC_ECKEY_COMPRESSED_LENGTH); + } + write_be(data + BTC_ECKEY_COMPRESSED_LENGTH, i); + + sha256_Raw(inout->public_key, BTC_ECKEY_COMPRESSED_LENGTH, fingerprint); + ripemd160(fingerprint, 32, fingerprint); + inout->fingerprint = (fingerprint[0] << 24) + (fingerprint[1] << 16) + (fingerprint[2] << 8) + fingerprint[3]; + + memset(inout->private_key, 0, 32); + + int failed = 0; + hmac_sha512(inout->chain_code, 32, data, sizeof(data), I); + memcpy(inout->chain_code, I + 32, BTC_BIP32_CHAINCODE_SIZE); + + + if (!btc_ecc_public_key_tweak_add(inout->public_key, I)) + failed = false; + + if (!failed) { + inout->depth++; + inout->child_num = i; + } + + // Wipe all stack data. + memset(data, 0, sizeof(data)); + memset(I, 0, sizeof(I)); + memset(fingerprint, 0, sizeof(fingerprint)); + + return failed ? false : true; +} + + +btc_bool btc_hdnode_private_ckd(btc_hdnode* inout, uint32_t i) +{ + uint8_t data[1 + BTC_ECKEY_PKEY_LENGTH + 4]; + uint8_t I[BTC_ECKEY_PKEY_LENGTH + BTC_BIP32_CHAINCODE_SIZE]; + uint8_t fingerprint[BTC_BIP32_CHAINCODE_SIZE]; + uint8_t p[BTC_ECKEY_PKEY_LENGTH], z[BTC_ECKEY_PKEY_LENGTH]; + + if (i & 0x80000000) { // private derivation + data[0] = 0; + memcpy(data + 1, inout->private_key, BTC_ECKEY_PKEY_LENGTH); + } else { // public derivation + memcpy(data, inout->public_key, BTC_ECKEY_COMPRESSED_LENGTH); + } + write_be(data + BTC_ECKEY_COMPRESSED_LENGTH, i); + + sha256_Raw(inout->public_key, BTC_ECKEY_COMPRESSED_LENGTH, fingerprint); + ripemd160(fingerprint, 32, fingerprint); + inout->fingerprint = (fingerprint[0] << 24) + (fingerprint[1] << 16) + + (fingerprint[2] << 8) + fingerprint[3]; + + memset(fingerprint, 0, sizeof(fingerprint)); + memcpy(p, inout->private_key, BTC_ECKEY_PKEY_LENGTH); + + hmac_sha512(inout->chain_code, BTC_BIP32_CHAINCODE_SIZE, data, sizeof(data), I); + memcpy(inout->chain_code, I + BTC_ECKEY_PKEY_LENGTH, BTC_BIP32_CHAINCODE_SIZE); + memcpy(inout->private_key, I, BTC_ECKEY_PKEY_LENGTH); + + memcpy(z, inout->private_key, BTC_ECKEY_PKEY_LENGTH); + + int failed = 0; + if (!btc_ecc_verify_privatekey(z)) { + failed = 1; + return false; + } + + memcpy(inout->private_key, p, BTC_ECKEY_PKEY_LENGTH); + if (!btc_ecc_private_key_tweak_add(inout->private_key, z)) { + failed = 1; + } + + if (!failed) { + inout->depth++; + inout->child_num = i; + btc_hdnode_fill_public_key(inout); + } + + memset(data, 0, sizeof(data)); + memset(I, 0, sizeof(I)); + memset(p, 0, sizeof(p)); + memset(z, 0, sizeof(z)); + return true; +} + + +void btc_hdnode_fill_public_key(btc_hdnode* node) +{ + size_t outsize = BTC_ECKEY_COMPRESSED_LENGTH; + btc_ecc_get_pubkey(node->private_key, node->public_key, &outsize, true); +} + + +static void btc_hdnode_serialize(const btc_hdnode* node, 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 + 9, node->child_num); + memcpy(node_data + 13, node->chain_code, BTC_BIP32_CHAINCODE_SIZE); + if (use_public) { + memcpy(node_data + 45, node->public_key, BTC_ECKEY_COMPRESSED_LENGTH); + } else { + node_data[45] = 0; + memcpy(node_data + 46, node->private_key, BTC_ECKEY_PKEY_LENGTH); + } + btc_base58_encode_check(node_data, 78, str, strsize); +} + + +void btc_hdnode_serialize_public(const btc_hdnode* node, const btc_chainparams* chain, char* str, int strsize) +{ + btc_hdnode_serialize(node, chain->b58prefix_bip32_pubkey, 1, str, strsize); +} + + +void btc_hdnode_serialize_private(const btc_hdnode* node, const btc_chainparams* chain, char* str, int strsize) +{ + btc_hdnode_serialize(node, chain->b58prefix_bip32_privkey, 0, str, strsize); +} + + +void btc_hdnode_get_hash160(const btc_hdnode* node, uint160 hash160_out) +{ + uint256 hashout; + btc_hash_sngl_sha256(node->public_key, BTC_ECKEY_COMPRESSED_LENGTH, hashout); + ripemd160(hashout, sizeof(hashout), hash160_out); +} + +void btc_hdnode_get_p2pkh_address(const btc_hdnode* node, const btc_chainparams* chain, char* str, int strsize) +{ + uint8_t hash160[sizeof(uint160)+1]; + hash160[0] = chain->b58prefix_pubkey_address; + btc_hdnode_get_hash160(node, hash160 + 1); + btc_base58_encode_check(hash160, sizeof(hash160), str, strsize); +} + +btc_bool btc_hdnode_get_pub_hex(const btc_hdnode* node, char* str, size_t* strsize) +{ + btc_pubkey pubkey; + btc_pubkey_init(&pubkey); + memcpy(&pubkey.pubkey, node->public_key, BTC_ECKEY_COMPRESSED_LENGTH); + pubkey.compressed = true; + + return btc_pubkey_get_hex(&pubkey, str, strsize); +} + + +// check for validity of curve point in case of public data not performed +btc_bool btc_hdnode_deserialize(const char* str, const btc_chainparams* chain, btc_hdnode* node) +{ + uint8_t node_data[strlen(str)]; + memset(node, 0, sizeof(btc_hdnode)); + size_t outlen = 0; + + outlen = btc_base58_decode_check(str, node_data, sizeof(node_data)); + if (!outlen) { + return false; + } + uint32_t version = read_be(node_data); + if (version == chain->b58prefix_bip32_pubkey) { // public node + memcpy(node->public_key, node_data + 45, BTC_ECKEY_COMPRESSED_LENGTH); + } else if (version == chain->b58prefix_bip32_privkey) { // private node + if (node_data[45]) { // invalid data + return false; + } + memcpy(node->private_key, node_data + 46, BTC_ECKEY_PKEY_LENGTH); + btc_hdnode_fill_public_key(node); + } else { + return false; // 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, BTC_BIP32_CHAINCODE_SIZE); + return true; +} + +btc_bool btc_hd_generate_key(btc_hdnode* node, const char* keypath, const uint8_t* keymaster, const uint8_t* chaincode, btc_bool usepubckd) +{ + static char delim[] = "/"; + static char prime[] = "phH\'"; + static char digits[] = "0123456789"; + uint64_t idx = 0; + assert(strlens(keypath) < 1024); + char *pch, *kp = btc_malloc(strlens(keypath) + 1); + + if (!kp) { + return false; + } + + if (strlens(keypath) < strlens("m/")) { + goto err; + } + + memset(kp, 0, strlens(keypath) + 1); + memcpy(kp, keypath, strlens(keypath)); + + if (kp[0] != 'm' || kp[1] != '/') { + goto err; + } + + node->depth = 0; + node->child_num = 0; + node->fingerprint = 0; + memcpy(node->chain_code, chaincode, BTC_BIP32_CHAINCODE_SIZE); + if (usepubckd == true) { + memcpy(node->public_key, keymaster, BTC_ECKEY_COMPRESSED_LENGTH); + } else { + memcpy(node->private_key, keymaster, BTC_ECKEY_PKEY_LENGTH); + btc_hdnode_fill_public_key(node); + } + + pch = strtok(kp + 2, delim); + while (pch != NULL) { + size_t i = 0; + int prm = 0; + for (; i < strlens(pch); i++) { + if (strchr(prime, pch[i])) { + if ((i != strlens(pch) - 1) || usepubckd == true) { + goto err; + } + prm = 1; + } else if (!strchr(digits, pch[i])) { + goto err; + } + } + + idx = strtoull(pch, NULL, 10); + if (idx > UINT32_MAX) { + goto err; + } + + if (prm) { + if (btc_hdnode_private_ckd_prime(node, idx) != true) { + goto err; + } + } else { + if ((usepubckd == true ? btc_hdnode_public_ckd(node, idx) : btc_hdnode_private_ckd(node, idx)) != true) { + goto err; + } + } + pch = strtok(NULL, delim); + } + btc_free(kp); + return true; + +err: + btc_free(kp); + return false; +} + +btc_bool btc_hdnode_has_privkey(btc_hdnode* node) +{ + int i; + for (i = 0; i < BTC_ECKEY_PKEY_LENGTH; ++i) { + if (node->private_key[i] != 0) + return true; + } + return false; +} diff --git a/src/block.c b/src/block.c new file mode 100644 index 000000000..9d542d877 --- /dev/null +++ b/src/block.c @@ -0,0 +1,110 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Thomas Kerin + Copyright (c) 2016 libbtc developers + + 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 +#include +#include + +btc_block_header* btc_block_header_new() +{ + btc_block_header* header; + header = btc_calloc(1, sizeof(*header)); + + return header; +} + +void btc_block_header_free(btc_block_header* header) +{ + if (!header) + return; + + header->version = 1; + memset(&header->prev_block, 0, BTC_HASH_LENGTH); + memset(&header->merkle_root, 0, BTC_HASH_LENGTH); + header->bits = 0; + header->timestamp = 0; + header->nonce = 0; + btc_free(header); +} + +int btc_block_header_deserialize(btc_block_header* header, struct const_buffer* buf) +{ + if (!deser_s32(&header->version, buf)) + return false; + if (!deser_u256(header->prev_block, buf)) + return false; + if (!deser_u256(header->merkle_root, buf)) + return false; + if (!deser_u32(&header->timestamp, buf)) + return false; + if (!deser_u32(&header->bits, buf)) + return false; + if (!deser_u32(&header->nonce, buf)) + return false; + + return true; +} + +void btc_block_header_serialize(cstring* s, const btc_block_header* header) +{ + ser_s32(s, header->version); + ser_u256(s, header->prev_block); + ser_u256(s, header->merkle_root); + ser_u32(s, header->timestamp); + ser_u32(s, header->bits); + ser_u32(s, header->nonce); +} + +void btc_block_header_copy(btc_block_header* dest, const btc_block_header* src) +{ + dest->version = src->version; + memcpy(&dest->prev_block, &src->prev_block, sizeof(src->prev_block)); + memcpy(&dest->merkle_root, &src->merkle_root, sizeof(src->merkle_root)); + dest->timestamp = src->timestamp; + dest->bits = src->bits; + dest->nonce = src->nonce; +} + +btc_bool btc_block_header_hash(btc_block_header* header, uint256 hash) +{ + cstring* s = cstr_new_sz(80); + btc_block_header_serialize(s, header); + + sha256_Raw((const uint8_t*)s->str, s->len, hash); + sha256_Raw(hash, SHA256_DIGEST_LENGTH, hash); + cstr_free(s, true); + + btc_bool ret = true; + return ret; +} diff --git a/src/buffer.c b/src/buffer.c new file mode 100644 index 000000000..8b8259138 --- /dev/null +++ b/src/buffer.c @@ -0,0 +1,51 @@ +/* Copyright 2012 exMULTI, Inc. + * Distributed under the MIT/X11 software license, see the accompanying + * file COPYING or http://www.opensource.org/licenses/mit-license.php. + */ + +#include + +#include +#include + +int buffer_equal(const void* a_, const void* b_) +{ + const struct buffer* a = a_; + const struct buffer* b = b_; + + if (a->len != b->len) + return 0; + return memcmp(a->p, b->p, a->len) == 0; +} + +void buffer_free(void* struct_buffer) +{ + struct buffer* buf = struct_buffer; + if (!buf) + return; + + btc_free(buf->p); + btc_free(buf); +} + +struct buffer* buffer_copy(const void* data, size_t data_len) +{ + struct buffer* buf; + buf = btc_malloc(sizeof(*buf)); + if (!buf) + goto err_out; + + buf->p = btc_malloc(data_len); + if (!buf->p) + goto err_out_free; + + memcpy(buf->p, data, data_len); + buf->len = data_len; + + return buf; + +err_out_free: + btc_free(buf); +err_out: + return NULL; +} diff --git a/src/chainparams.c b/src/chainparams.c new file mode 100644 index 000000000..1e364fd51 --- /dev/null +++ b/src/chainparams.c @@ -0,0 +1,91 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2017 Jonas Schnelli + + 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 + +const btc_chainparams btc_chainparams_main = { + "main", + 0x00, + 0x05, + "bc", + 0x80, + 0x0488ADE4, + 0x0488B21E, + {0xf9, 0xbe, 0xb4, 0xd9}, + {0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, 0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f, 0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c, 0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00}, + 8333, + {{"seed.bitcoin.jonasschnelli.ch"}, 0}, +}; +const btc_chainparams btc_chainparams_test = { + "testnet3", + 0x6f, + 0xc4, + "tb", + 0xEF, + 0x04358394, + 0x043587CF, + {0x0b, 0x11, 0x09, 0x07}, + {0x43, 0x49, 0x7f, 0xd7, 0xf8, 0x26, 0x95, 0x71, 0x08, 0xf4, 0xa3, 0x0f, 0xd9, 0xce, 0xc3, 0xae, 0xba, 0x79, 0x97, 0x20, 0x84, 0xe9, 0x0e, 0xad, 0x01, 0xea, 0x33, 0x09, 0x00, 0x00, 0x00, 0x00}, + 18333, + {{"testnet-seed.bitcoin.jonasschnelli.ch"}, 0}, +}; +const btc_chainparams btc_chainparams_regtest = { + "regtest", + 0x6f, + 0xc4, + "bcrt", + 0xEF, + 0x04358394, + 0x043587CF, + {0xfa, 0xbf, 0xb5, 0xda}, + {0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b, 0x59, 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb, 0x5b, 0xbf, 0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a, 0x1f, 0xc7, 0xb2, 0xb7, 0x3c, 0xf1, 0x88, 0x91, 0x0f}, + 18444, + {0}, +}; + + +const btc_checkpoint btc_mainnet_checkpoint_array[] = { + {0, "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", 1231006505, 0x1d00ffff}, + {20160, "000000000f1aef56190aee63d33a373e6487132d522ff4cd98ccfc96566d461e", 1248481816, 0x1d00ffff}, + {40320, "0000000045861e169b5a961b7034f8de9e98022e7a39100dde3ae3ea240d7245", 1266191579, 0x1c654657}, + {60480, "000000000632e22ce73ed38f46d5b408ff1cff2cc9e10daaf437dfd655153837", 1276298786, 0x1c0eba64}, + {80640, "0000000000307c80b87edf9f6a0697e2f01db67e518c8a4d6065d1d859a3a659", 1284861847, 0x1b4766ed}, + {100800, "000000000000e383d43cc471c64a9a4a46794026989ef4ff9611d5acb704e47a", 1294031411, 0x1b0404cb}, + {120960, "0000000000002c920cf7e4406b969ae9c807b5c4f271f490ca3de1b0770836fc", 1304131980, 0x1b0098fa}, + {141120, "00000000000002d214e1af085eda0a780a8446698ab5c0128b6392e189886114", 1313451894, 0x1a094a86}, + {161280, "00000000000005911fe26209de7ff510a8306475b75ceffd434b68dc31943b99", 1326047176, 0x1a0d69d7}, + {181440, "00000000000000e527fc19df0992d58c12b98ef5a17544696bbba67812ef0e64", 1337883029, 0x1a0a8b5f}, + {201600, "00000000000003a5e28bef30ad31f1f9be706e91ae9dda54179a95c9f9cd9ad0", 1349226660, 0x1a057e08}, + {221760, "00000000000000fc85dd77ea5ed6020f9e333589392560b40908d3264bd1f401", 1361148470, 0x1a04985c}, + {241920, "00000000000000b79f259ad14635739aaf0cc48875874b6aeecc7308267b50fa", 1371418654, 0x1a00de15}, + {262080, "000000000000000aa77be1c33deac6b8d3b7b0757d02ce72fffddc768235d0e2", 1381070552, 0x1916b0ca}, + {282240, "0000000000000000ef9ee7529607286669763763e0c46acfdefd8a2306de5ca8", 1390570126, 0x1901f52c}, + {302400, "0000000000000000472132c4daaf358acaf461ff1c3e96577a74e5ebf91bb170", 1400928750, 0x18692842}, + {322560, "000000000000000002df2dd9d4fe0578392e519610e341dd09025469f101cfa1", 1411680080, 0x181fb893}, + {342720, "00000000000000000f9cfece8494800d3dcbf9583232825da640c8703bcd27e7", 1423496415, 0x1818bb87}, + {362880, "000000000000000014898b8e6538392702ffb9450f904c80ebf9d82b519a77d5", 1435475246, 0x1816418e}, + {383040, "00000000000000000a974fa1a3f84055ad5ef0b2f96328bc96310ce83da801c9", 1447236692, 0x1810b289}, + {403200, "000000000000000000c4272a5c68b4f55e5af734e88ceab09abf73e9ac3b6d01", 1458292068, 0x1806a4c3}}; diff --git a/src/commontools.c b/src/commontools.c new file mode 100644 index 000000000..55fd2c1bb --- /dev/null +++ b/src/commontools.c @@ -0,0 +1,153 @@ +/********************************************************************** + * Copyright (c) 2016 Jonas Schnelli * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +btc_bool addresses_from_pubkey(const btc_chainparams* chain, const char* pubkey_hex, char* p2pkh_address, char* p2sh_p2wpkh_address, char *p2wpkh_address) +{ + if (!pubkey_hex || strlen(pubkey_hex) != 66) + return false; + + btc_pubkey pubkey; + btc_pubkey_init(&pubkey); + pubkey.compressed = 1; + + size_t outlen = 0; + utils_hex_to_bin(pubkey_hex, pubkey.pubkey, strlen(pubkey_hex), (int*)&outlen); + if (outlen != BTC_ECKEY_COMPRESSED_LENGTH) { + return false; + } + assert(btc_pubkey_is_valid(&pubkey) == 1); + + btc_pubkey_getaddr_p2pkh(&pubkey, chain, p2pkh_address); + btc_pubkey_getaddr_p2sh_p2wpkh(&pubkey, chain, p2sh_p2wpkh_address); + btc_pubkey_getaddr_p2wpkh(&pubkey, chain, p2wpkh_address); + return true; +} + +btc_bool pubkey_from_privatekey(const btc_chainparams* chain, const char* privkey_wif, char* pubkey_hex, size_t* sizeout) +{ + btc_key key; + btc_privkey_init(&key); + if (!btc_privkey_decode_wif(privkey_wif, chain, &key)) { + return false; + } + + btc_pubkey pubkey; + btc_pubkey_init(&pubkey); + assert(btc_pubkey_is_valid(&pubkey) == 0); + btc_pubkey_from_key(&key, &pubkey); + btc_privkey_cleanse(&key); + + btc_pubkey_get_hex(&pubkey, pubkey_hex, sizeout); + btc_pubkey_cleanse(&pubkey); + + return true; +} + +btc_bool gen_privatekey(const btc_chainparams* chain, char* privkey_wif, size_t strsize_wif, char* privkey_hex_or_null) +{ + btc_key key; + btc_privkey_init(&key); + btc_privkey_gen(&key); + btc_privkey_encode_wif(&key, chain, privkey_wif, &strsize_wif); + + // also export the hex privkey if use had passed in a valid pointer + // will always export 32 bytes + if (privkey_hex_or_null != NULL) + utils_bin_to_hex(key.privkey, BTC_ECKEY_PKEY_LENGTH, privkey_hex_or_null); + btc_privkey_cleanse(&key); + return true; +} + +btc_bool hd_gen_master(const btc_chainparams* chain, char* masterkeyhex, size_t strsize) +{ + btc_hdnode node; + uint8_t seed[32]; + assert(btc_random_bytes(seed, 32, true)); + btc_hdnode_from_seed(seed, 32, &node); + memset(seed, 0, 32); + btc_hdnode_serialize_private(&node, chain, masterkeyhex, strsize); + memset(&node, 0, sizeof(node)); + return true; +} + +btc_bool hd_print_node(const btc_chainparams* chain, const char* nodeser) +{ + btc_hdnode node; + if (!btc_hdnode_deserialize(nodeser, chain, &node)) + return false; + + size_t strsize = 128; + char str[strsize]; + btc_hdnode_get_p2pkh_address(&node, chain, str, strsize); + + printf("ext key: %s\n", nodeser); + + size_t privkey_wif_size_bin = 34; + uint8_t pkeybase58c[privkey_wif_size_bin]; + pkeybase58c[0] = chain->b58prefix_secret_address; + pkeybase58c[33] = 1; /* always use compressed keys */ + size_t privkey_wif_size = 128; + char privkey_wif[privkey_wif_size]; + memcpy(&pkeybase58c[1], node.private_key, BTC_ECKEY_PKEY_LENGTH); + assert(btc_base58_encode_check(pkeybase58c, privkey_wif_size_bin, privkey_wif, privkey_wif_size) != 0); + if (btc_hdnode_has_privkey(&node)) { + printf("privatekey WIF: %s\n", privkey_wif); + } + + printf("depth: %d\n", node.depth); + printf("child index: %d\n", node.child_num); + printf("p2pkh address: %s\n", str); + + if (!btc_hdnode_get_pub_hex(&node, str, &strsize)) + return false; + printf("pubkey hex: %s\n", str); + + strsize = 128; + btc_hdnode_serialize_public(&node, chain, str, strsize); + printf("extended pubkey: %s\n", str); + return true; +} + +btc_bool hd_derive(const btc_chainparams* chain, const char* masterkey, const char* keypath, char* extkeyout, size_t extkeyout_size) +{ + if (!keypath || !masterkey || !extkeyout) { + return false; + } + btc_hdnode node, nodenew; + if (!btc_hdnode_deserialize(masterkey, chain, &node)) + return false; + + //check if we only have the publickey + bool pubckd = !btc_hdnode_has_privkey(&node); + + //derive child key, use pubckd or privckd + if (!btc_hd_generate_key(&nodenew, keypath, pubckd ? node.public_key : node.private_key, node.chain_code, pubckd)) + return false; + + if (pubckd) + btc_hdnode_serialize_public(&nodenew, chain, extkeyout, extkeyout_size); + else + btc_hdnode_serialize_private(&nodenew, chain, extkeyout, extkeyout_size); + return true; +} diff --git a/src/cstr.c b/src/cstr.c new file mode 100644 index 000000000..50b605cb8 --- /dev/null +++ b/src/cstr.c @@ -0,0 +1,213 @@ +/* Copyright 2015 BitPay, Inc. + * Distributed under the MIT/X11 software license, see the accompanying + * file COPYING or http://www.opensource.org/licenses/mit-license.php. + */ + +#include + +#include +#include + +static int cstr_alloc_min_sz(cstring* s, size_t sz) +{ + unsigned int shift; + unsigned int al_sz; + char* new_s; + + sz++; /* NULL overhead */ + + if (s->alloc && (s->alloc >= sz)) + return 1; + + shift = 3; + while ((al_sz = (1 << shift)) < sz) + shift++; + + new_s = btc_realloc(s->str, al_sz); + if (!new_s) + return 0; + + s->str = new_s; + s->alloc = al_sz; + s->str[s->len] = 0; + + return 1; +} + +int cstr_alloc_minsize(cstring* s, size_t new_sz) +{ + /* no change */ + if (new_sz == s->len) + return 1; + + /* truncate string */ + if (new_sz <= s->len) { + return 0; + } + + /* increase string size */ + if (!cstr_alloc_min_sz(s, new_sz)) + return 0; + + /* contents of string tail undefined */ + //s->len = new_sz; + s->str[s->len] = 0; + + return 1; +} + +cstring* cstr_new_sz(size_t sz) +{ + cstring* s = btc_calloc(1, sizeof(cstring)); + if (!s) + return NULL; + + if (!cstr_alloc_min_sz(s, sz)) { + btc_free(s); + return NULL; + } + + return s; +} + +cstring* cstr_new_buf(const void* buf, size_t sz) +{ + cstring* s = cstr_new_sz(sz); + if (!s) + return NULL; + + memcpy(s->str, buf, sz); + s->len = sz; + s->str[s->len] = 0; + + return s; +} + +cstring* cstr_new_cstr(const cstring* copy_str) +{ + return cstr_new_buf(copy_str->str, copy_str->len); +} + +cstring* cstr_new(const char* init_str) +{ + size_t slen; + + if (!init_str || !*init_str) + return cstr_new_sz(0); + + slen = strlen(init_str); + return cstr_new_buf(init_str, slen); +} + +void cstr_free(cstring* s, int free_buf) +{ + if (!s) + return; + + if (free_buf) + btc_free(s->str); + + memset(s, 0, sizeof(*s)); + btc_free(s); +} + +int cstr_resize(cstring* s, size_t new_sz) +{ + /* no change */ + if (new_sz == s->len) + return 1; + + /* truncate string */ + if (new_sz <= s->len) { + s->len = new_sz; + s->str[s->len] = 0; + return 1; + } + + /* increase string size */ + if (!cstr_alloc_min_sz(s, new_sz)) + return 0; + + /* contents of string tail undefined */ + + s->len = new_sz; + s->str[s->len] = 0; + + return 1; +} + +int cstr_append_buf(cstring* s, const void* buf, size_t sz) +{ + if (!cstr_alloc_min_sz(s, s->len + sz)) + return 0; + + memcpy(s->str + s->len, buf, sz); + s->len += sz; + s->str[s->len] = 0; + + return 1; +} + +int cstr_append_cstr(cstring* s, cstring* append) +{ + return cstr_append_buf(s, append->str, append->len); +} + + +int cstr_append_c(cstring* s, char ch) +{ + return cstr_append_buf(s, &ch, 1); +} + + +int cstr_equal(const cstring* a, const cstring* b) +{ + if (a == b) + return 1; + if (!a || !b) + return 0; + if (a->len != b->len) + return 0; + return (memcmp(a->str, b->str, a->len) == 0); +} + +int cstr_compare(const cstring* a, const cstring* b) +{ + unsigned int i; + if (a->len > b->len) + return (1); + if (a->len < b->len) + return (-1); + + /* length equal, byte per byte compare */ + for (i = 0; i < a->len; i++) { + char a1 = a->str[i]; + char b1 = b->str[i]; + + if (a1 > b1) + return (1); + if (a1 < b1) + return (-1); + } + return (0); +} + +int cstr_erase(cstring* s, size_t pos, ssize_t len) +{ + ssize_t old_tail; + + if (pos == s->len && len == 0) + return 1; + if (pos >= s->len) + return 0; + + old_tail = s->len - pos; + if ((len >= 0) && (len > old_tail)) + return 0; + + memmove(&s->str[pos], &s->str[pos + len], old_tail - len); + s->len -= len; + s->str[s->len] = 0; + + return 1; +} diff --git a/src/ctaes.c b/src/ctaes.c new file mode 100644 index 000000000..f8a5d736c --- /dev/null +++ b/src/ctaes.c @@ -0,0 +1,556 @@ + /********************************************************************* + * Copyright (c) 2016 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +/* Constant time, unoptimized, concise, plain C, AES implementation + * Based On: + * Emilia Kasper and Peter Schwabe, Faster and Timing-Attack Resistant AES-GCM + * http://www.iacr.org/archive/ches2009/57470001/57470001.pdf + * But using 8 16-bit integers representing a single AES state rather than 8 128-bit + * integers representing 8 AES states. + */ + +#include + +/* Slice variable slice_i contains the i'th bit of the 16 state variables in this order: + * 0 1 2 3 + * 4 5 6 7 + * 8 9 10 11 + * 12 13 14 15 + */ + +/** Convert a byte to sliced form, storing it corresponding to given row and column in s */ +static void LoadByte(AES_state* s, unsigned char byte, int r, int c) { + int i; + for (i = 0; i < 8; i++) { + s->slice[i] |= (byte & 1) << (r * 4 + c); + byte >>= 1; + } +} + +/** Load 16 bytes of data into 8 sliced integers */ +static void LoadBytes(AES_state *s, const unsigned char* data16) { + int c; + for (c = 0; c < 4; c++) { + int r; + for (r = 0; r < 4; r++) { + LoadByte(s, *(data16++), r, c); + } + } +} + +/** Convert 8 sliced integers into 16 bytes of data */ +static void SaveBytes(unsigned char* data16, const AES_state *s) { + int c; + for (c = 0; c < 4; c++) { + int r; + for (r = 0; r < 4; r++) { + int b; + uint8_t v = 0; + for (b = 0; b < 8; b++) { + v |= ((s->slice[b] >> (r * 4 + c)) & 1) << b; + } + *(data16++) = v; + } + } +} + +/* S-box implementation based on the gate logic from: + * Joan Boyar and Rene Peralta, A depth-16 circuit for the AES S-box. + * https://eprint.iacr.org/2011/332.pdf +*/ +static void SubBytes(AES_state *s, int inv) { + /* Load the bit slices */ + uint16_t U0 = s->slice[7], U1 = s->slice[6], U2 = s->slice[5], U3 = s->slice[4]; + uint16_t U4 = s->slice[3], U5 = s->slice[2], U6 = s->slice[1], U7 = s->slice[0]; + + uint16_t T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16; + uint16_t T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, D; + uint16_t M1, M6, M11, M13, M15, M20, M21, M22, M23, M25, M37, M38, M39, M40; + uint16_t M41, M42, M43, M44, M45, M46, M47, M48, M49, M50, M51, M52, M53, M54; + uint16_t M55, M56, M57, M58, M59, M60, M61, M62, M63; + + if (inv) { + uint16_t R5, R13, R17, R18, R19; + /* Undo linear postprocessing */ + T23 = U0 ^ U3; + T22 = ~(U1 ^ U3); + T2 = ~(U0 ^ U1); + T1 = U3 ^ U4; + T24 = ~(U4 ^ U7); + R5 = U6 ^ U7; + T8 = ~(U1 ^ T23); + T19 = T22 ^ R5; + T9 = ~(U7 ^ T1); + T10 = T2 ^ T24; + T13 = T2 ^ R5; + T3 = T1 ^ R5; + T25 = ~(U2 ^ T1); + R13 = U1 ^ U6; + T17 = ~(U2 ^ T19); + T20 = T24 ^ R13; + T4 = U4 ^ T8; + R17 = ~(U2 ^ U5); + R18 = ~(U5 ^ U6); + R19 = ~(U2 ^ U4); + D = U0 ^ R17; + T6 = T22 ^ R17; + T16 = R13 ^ R19; + T27 = T1 ^ R18; + T15 = T10 ^ T27; + T14 = T10 ^ R18; + T26 = T3 ^ T16; + } else { + /* Linear preprocessing. */ + T1 = U0 ^ U3; + T2 = U0 ^ U5; + T3 = U0 ^ U6; + T4 = U3 ^ U5; + T5 = U4 ^ U6; + T6 = T1 ^ T5; + T7 = U1 ^ U2; + T8 = U7 ^ T6; + T9 = U7 ^ T7; + T10 = T6 ^ T7; + T11 = U1 ^ U5; + T12 = U2 ^ U5; + T13 = T3 ^ T4; + T14 = T6 ^ T11; + T15 = T5 ^ T11; + T16 = T5 ^ T12; + T17 = T9 ^ T16; + T18 = U3 ^ U7; + T19 = T7 ^ T18; + T20 = T1 ^ T19; + T21 = U6 ^ U7; + T22 = T7 ^ T21; + T23 = T2 ^ T22; + T24 = T2 ^ T10; + T25 = T20 ^ T17; + T26 = T3 ^ T16; + T27 = T1 ^ T12; + D = U7; + } + + /* Non-linear transformation (shared between the forward and backward case) */ + M1 = T13 & T6; + M6 = T3 & T16; + M11 = T1 & T15; + M13 = (T4 & T27) ^ M11; + M15 = (T2 & T10) ^ M11; + M20 = T14 ^ M1 ^ (T23 & T8) ^ M13; + M21 = (T19 & D) ^ M1 ^ T24 ^ M15; + M22 = T26 ^ M6 ^ (T22 & T9) ^ M13; + M23 = (T20 & T17) ^ M6 ^ M15 ^ T25; + M25 = M22 & M20; + M37 = M21 ^ ((M20 ^ M21) & (M23 ^ M25)); + M38 = M20 ^ M25 ^ (M21 | (M20 & M23)); + M39 = M23 ^ ((M22 ^ M23) & (M21 ^ M25)); + M40 = M22 ^ M25 ^ (M23 | (M21 & M22)); + M41 = M38 ^ M40; + M42 = M37 ^ M39; + M43 = M37 ^ M38; + M44 = M39 ^ M40; + M45 = M42 ^ M41; + M46 = M44 & T6; + M47 = M40 & T8; + M48 = M39 & D; + M49 = M43 & T16; + M50 = M38 & T9; + M51 = M37 & T17; + M52 = M42 & T15; + M53 = M45 & T27; + M54 = M41 & T10; + M55 = M44 & T13; + M56 = M40 & T23; + M57 = M39 & T19; + M58 = M43 & T3; + M59 = M38 & T22; + M60 = M37 & T20; + M61 = M42 & T1; + M62 = M45 & T4; + M63 = M41 & T2; + + if (inv){ + /* Undo linear preprocessing */ + uint16_t P0 = M52 ^ M61; + uint16_t P1 = M58 ^ M59; + uint16_t P2 = M54 ^ M62; + uint16_t P3 = M47 ^ M50; + uint16_t P4 = M48 ^ M56; + uint16_t P5 = M46 ^ M51; + uint16_t P6 = M49 ^ M60; + uint16_t P7 = P0 ^ P1; + uint16_t P8 = M50 ^ M53; + uint16_t P9 = M55 ^ M63; + uint16_t P10 = M57 ^ P4; + uint16_t P11 = P0 ^ P3; + uint16_t P12 = M46 ^ M48; + uint16_t P13 = M49 ^ M51; + uint16_t P14 = M49 ^ M62; + uint16_t P15 = M54 ^ M59; + uint16_t P16 = M57 ^ M61; + uint16_t P17 = M58 ^ P2; + uint16_t P18 = M63 ^ P5; + uint16_t P19 = P2 ^ P3; + uint16_t P20 = P4 ^ P6; + uint16_t P22 = P2 ^ P7; + uint16_t P23 = P7 ^ P8; + uint16_t P24 = P5 ^ P7; + uint16_t P25 = P6 ^ P10; + uint16_t P26 = P9 ^ P11; + uint16_t P27 = P10 ^ P18; + uint16_t P28 = P11 ^ P25; + uint16_t P29 = P15 ^ P20; + s->slice[7] = P13 ^ P22; + s->slice[6] = P26 ^ P29; + s->slice[5] = P17 ^ P28; + s->slice[4] = P12 ^ P22; + s->slice[3] = P23 ^ P27; + s->slice[2] = P19 ^ P24; + s->slice[1] = P14 ^ P23; + s->slice[0] = P9 ^ P16; + } else { + /* Linear postprocessing */ + uint16_t L0 = M61 ^ M62; + uint16_t L1 = M50 ^ M56; + uint16_t L2 = M46 ^ M48; + uint16_t L3 = M47 ^ M55; + uint16_t L4 = M54 ^ M58; + uint16_t L5 = M49 ^ M61; + uint16_t L6 = M62 ^ L5; + uint16_t L7 = M46 ^ L3; + uint16_t L8 = M51 ^ M59; + uint16_t L9 = M52 ^ M53; + uint16_t L10 = M53 ^ L4; + uint16_t L11 = M60 ^ L2; + uint16_t L12 = M48 ^ M51; + uint16_t L13 = M50 ^ L0; + uint16_t L14 = M52 ^ M61; + uint16_t L15 = M55 ^ L1; + uint16_t L16 = M56 ^ L0; + uint16_t L17 = M57 ^ L1; + uint16_t L18 = M58 ^ L8; + uint16_t L19 = M63 ^ L4; + uint16_t L20 = L0 ^ L1; + uint16_t L21 = L1 ^ L7; + uint16_t L22 = L3 ^ L12; + uint16_t L23 = L18 ^ L2; + uint16_t L24 = L15 ^ L9; + uint16_t L25 = L6 ^ L10; + uint16_t L26 = L7 ^ L9; + uint16_t L27 = L8 ^ L10; + uint16_t L28 = L11 ^ L14; + uint16_t L29 = L11 ^ L17; + s->slice[7] = L6 ^ L24; + s->slice[6] = ~(L16 ^ L26); + s->slice[5] = ~(L19 ^ L28); + s->slice[4] = L6 ^ L21; + s->slice[3] = L20 ^ L22; + s->slice[2] = L25 ^ L29; + s->slice[1] = ~(L13 ^ L27); + s->slice[0] = ~(L6 ^ L23); + } +} + +#define BIT_RANGE(from,to) (((1 << ((to) - (from))) - 1) << (from)) + +#define BIT_RANGE_LEFT(x,from,to,shift) (((x) & BIT_RANGE((from), (to))) << (shift)) +#define BIT_RANGE_RIGHT(x,from,to,shift) (((x) & BIT_RANGE((from), (to))) >> (shift)) + +static void ShiftRows(AES_state* s) { + int i; + for (i = 0; i < 8; i++) { + uint16_t v = s->slice[i]; + s->slice[i] = + (v & BIT_RANGE(0, 4)) | + BIT_RANGE_LEFT(v, 4, 5, 3) | BIT_RANGE_RIGHT(v, 5, 8, 1) | + BIT_RANGE_LEFT(v, 8, 10, 2) | BIT_RANGE_RIGHT(v, 10, 12, 2) | + BIT_RANGE_LEFT(v, 12, 15, 1) | BIT_RANGE_RIGHT(v, 15, 16, 3); + } +} + +static void InvShiftRows(AES_state* s) { + int i; + for (i = 0; i < 8; i++) { + uint16_t v = s->slice[i]; + s->slice[i] = + (v & BIT_RANGE(0, 4)) | + BIT_RANGE_LEFT(v, 4, 7, 1) | BIT_RANGE_RIGHT(v, 7, 8, 3) | + BIT_RANGE_LEFT(v, 8, 10, 2) | BIT_RANGE_RIGHT(v, 10, 12, 2) | + BIT_RANGE_LEFT(v, 12, 13, 3) | BIT_RANGE_RIGHT(v, 13, 16, 1); + } +} + +#define ROT(x,b) (((x) >> ((b) * 4)) | ((x) << ((4-(b)) * 4))) + +static void MixColumns(AES_state* s, int inv) { + /* The MixColumns transform treats the bytes of the columns of the state as + * coefficients of a 3rd degree polynomial over GF(2^8) and multiplies them + * by the fixed polynomial a(x) = {03}x^3 + {01}x^2 + {01}x + {02}, modulo + * x^4 + {01}. + * + * In the inverse transform, we multiply by the inverse of a(x), + * a^-1(x) = {0b}x^3 + {0d}x^2 + {09}x + {0e}. This is equal to + * a(x) * ({04}x^2 + {05}), so we can reuse the forward transform's code + * (found in OpenSSL's bsaes-x86_64.pl, attributed to Jussi Kivilinna) + * + * In the bitsliced representation, a multiplication of every column by x + * mod x^4 + 1 is simply a right rotation. + */ + + /* Shared for both directions is a multiplication by a(x), which can be + * rewritten as (x^3 + x^2 + x) + {02}*(x^3 + {01}). + * + * First compute s into the s? variables, (x^3 + {01}) * s into the s?_01 + * variables and (x^3 + x^2 + x)*s into the s?_123 variables. + */ + uint16_t s0 = s->slice[0], s1 = s->slice[1], s2 = s->slice[2], s3 = s->slice[3]; + uint16_t s4 = s->slice[4], s5 = s->slice[5], s6 = s->slice[6], s7 = s->slice[7]; + uint16_t s0_01 = s0 ^ ROT(s0, 1), s0_123 = ROT(s0_01, 1) ^ ROT(s0, 3); + uint16_t s1_01 = s1 ^ ROT(s1, 1), s1_123 = ROT(s1_01, 1) ^ ROT(s1, 3); + uint16_t s2_01 = s2 ^ ROT(s2, 1), s2_123 = ROT(s2_01, 1) ^ ROT(s2, 3); + uint16_t s3_01 = s3 ^ ROT(s3, 1), s3_123 = ROT(s3_01, 1) ^ ROT(s3, 3); + uint16_t s4_01 = s4 ^ ROT(s4, 1), s4_123 = ROT(s4_01, 1) ^ ROT(s4, 3); + uint16_t s5_01 = s5 ^ ROT(s5, 1), s5_123 = ROT(s5_01, 1) ^ ROT(s5, 3); + uint16_t s6_01 = s6 ^ ROT(s6, 1), s6_123 = ROT(s6_01, 1) ^ ROT(s6, 3); + uint16_t s7_01 = s7 ^ ROT(s7, 1), s7_123 = ROT(s7_01, 1) ^ ROT(s7, 3); + /* Now compute s = s?_123 + {02} * s?_01. */ + s->slice[0] = s7_01 ^ s0_123; + s->slice[1] = s7_01 ^ s0_01 ^ s1_123; + s->slice[2] = s1_01 ^ s2_123; + s->slice[3] = s7_01 ^ s2_01 ^ s3_123; + s->slice[4] = s7_01 ^ s3_01 ^ s4_123; + s->slice[5] = s4_01 ^ s5_123; + s->slice[6] = s5_01 ^ s6_123; + s->slice[7] = s6_01 ^ s7_123; + if (inv) { + /* In the reverse direction, we further need to multiply by + * {04}x^2 + {05}, which can be written as {04} * (x^2 + {01}) + {01}. + * + * First compute (x^2 + {01}) * s into the t?_02 variables: */ + uint16_t t0_02 = s->slice[0] ^ ROT(s->slice[0], 2); + uint16_t t1_02 = s->slice[1] ^ ROT(s->slice[1], 2); + uint16_t t2_02 = s->slice[2] ^ ROT(s->slice[2], 2); + uint16_t t3_02 = s->slice[3] ^ ROT(s->slice[3], 2); + uint16_t t4_02 = s->slice[4] ^ ROT(s->slice[4], 2); + uint16_t t5_02 = s->slice[5] ^ ROT(s->slice[5], 2); + uint16_t t6_02 = s->slice[6] ^ ROT(s->slice[6], 2); + uint16_t t7_02 = s->slice[7] ^ ROT(s->slice[7], 2); + /* And then update s += {04} * t?_02 */ + s->slice[0] ^= t6_02; + s->slice[1] ^= t6_02 ^ t7_02; + s->slice[2] ^= t0_02 ^ t7_02; + s->slice[3] ^= t1_02 ^ t6_02; + s->slice[4] ^= t2_02 ^ t6_02 ^ t7_02; + s->slice[5] ^= t3_02 ^ t7_02; + s->slice[6] ^= t4_02; + s->slice[7] ^= t5_02; + } +} + +static void AddRoundKey(AES_state* s, const AES_state* round) { + int b; + for (b = 0; b < 8; b++) { + s->slice[b] ^= round->slice[b]; + } +} + +/** column_0(s) = column_c(a) */ +static void GetOneColumn(AES_state* s, const AES_state* a, int c) { + int b; + for (b = 0; b < 8; b++) { + s->slice[b] = (a->slice[b] >> c) & 0x1111; + } +} + +/** column_c1(r) |= (column_0(s) ^= column_c2(a)) */ +static void KeySetupColumnMix(AES_state* s, AES_state* r, const AES_state* a, int c1, int c2) { + int b; + for (b = 0; b < 8; b++) { + r->slice[b] |= ((s->slice[b] ^= ((a->slice[b] >> c2) & 0x1111)) & 0x1111) << c1; + } +} + +/** Rotate the rows in s one position upwards, and xor in r */ +static void KeySetupTransform(AES_state* s, const AES_state* r) { + int b; + for (b = 0; b < 8; b++) { + s->slice[b] = ((s->slice[b] >> 4) | (s->slice[b] << 12)) ^ r->slice[b]; + } +} + +/* Multiply the cells in s by x, as polynomials over GF(2) mod x^8 + x^4 + x^3 + x + 1 */ +static void MultX(AES_state* s) { + uint16_t top = s->slice[7]; + s->slice[7] = s->slice[6]; + s->slice[6] = s->slice[5]; + s->slice[5] = s->slice[4]; + s->slice[4] = s->slice[3] ^ top; + s->slice[3] = s->slice[2] ^ top; + s->slice[2] = s->slice[1]; + s->slice[1] = s->slice[0] ^ top; + s->slice[0] = top; +} + +/** Expand the cipher key into the key schedule. + * + * state must be a pointer to an array of size nrounds + 1. + * key must be a pointer to 4 * nkeywords bytes. + * + * AES128 uses nkeywords = 4, nrounds = 10 + * AES192 uses nkeywords = 6, nrounds = 12 + * AES256 uses nkeywords = 8, nrounds = 14 + */ +static void AES_setup(AES_state* rounds, const uint8_t* key, int nkeywords, int nrounds) +{ + int i; + + /* The one-byte round constant */ + AES_state rcon = {{1,0,0,0,0,0,0,0}}; + /* The number of the word being generated, modulo nkeywords */ + int pos = 0; + /* The column representing the word currently being processed */ + AES_state column; + + for (i = 0; i < nrounds + 1; i++) { + int b; + for (b = 0; b < 8; b++) { + rounds[i].slice[b] = 0; + } + } + + /* The first nkeywords round columns are just taken from the key directly. */ + for (i = 0; i < nkeywords; i++) { + int r; + for (r = 0; r < 4; r++) { + LoadByte(&rounds[i >> 2], *(key++), r, i & 3); + } + } + + GetOneColumn(&column, &rounds[(nkeywords - 1) >> 2], (nkeywords - 1) & 3); + + for (i = nkeywords; i < 4 * (nrounds + 1); i++) { + /* Transform column */ + if (pos == 0) { + SubBytes(&column, 0); + KeySetupTransform(&column, &rcon); + MultX(&rcon); + } else if (nkeywords > 6 && pos == 4) { + SubBytes(&column, 0); + } + if (++pos == nkeywords) pos = 0; + KeySetupColumnMix(&column, &rounds[i >> 2], &rounds[(i - nkeywords) >> 2], i & 3, (i - nkeywords) & 3); + } +} + +static void AES_encrypt(const AES_state* rounds, int nrounds, unsigned char* cipher16, const unsigned char* plain16) { + AES_state s = {{0}}; + int round; + + LoadBytes(&s, plain16); + AddRoundKey(&s, rounds++); + + for (round = 1; round < nrounds; round++) { + SubBytes(&s, 0); + ShiftRows(&s); + MixColumns(&s, 0); + AddRoundKey(&s, rounds++); + } + + SubBytes(&s, 0); + ShiftRows(&s); + AddRoundKey(&s, rounds); + + SaveBytes(cipher16, &s); +} + +static void AES_decrypt(const AES_state* rounds, int nrounds, unsigned char* plain16, const unsigned char* cipher16) { + /* Most AES decryption implementations use the alternate scheme + * (the Equivalent Inverse Cipher), which allows for more code reuse between + * the encryption and decryption code, but requires separate setup for both. + */ + AES_state s = {{0}}; + int round; + + rounds += nrounds; + + LoadBytes(&s, cipher16); + AddRoundKey(&s, rounds--); + + for (round = 1; round < nrounds; round++) { + InvShiftRows(&s); + SubBytes(&s, 1); + AddRoundKey(&s, rounds--); + MixColumns(&s, 1); + } + + InvShiftRows(&s); + SubBytes(&s, 1); + AddRoundKey(&s, rounds); + + SaveBytes(plain16, &s); +} + +void AES128_init(AES128_ctx* ctx, const unsigned char* key16) { + AES_setup(ctx->rk, key16, 4, 10); +} + +void AES128_encrypt(const AES128_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16) { + while (blocks--) { + AES_encrypt(ctx->rk, 10, cipher16, plain16); + cipher16 += 16; + plain16 += 16; + } +} + +void AES128_decrypt(const AES128_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16) { + while (blocks--) { + AES_decrypt(ctx->rk, 10, plain16, cipher16); + cipher16 += 16; + plain16 += 16; + } +} + +void AES192_init(AES192_ctx* ctx, const unsigned char* key24) { + AES_setup(ctx->rk, key24, 6, 12); +} + +void AES192_encrypt(const AES192_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16) { + while (blocks--) { + AES_encrypt(ctx->rk, 12, cipher16, plain16); + cipher16 += 16; + plain16 += 16; + } + +} + +void AES192_decrypt(const AES192_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16) { + while (blocks--) { + AES_decrypt(ctx->rk, 12, plain16, cipher16); + cipher16 += 16; + plain16 += 16; + } +} + +void AES256_init(AES256_ctx* ctx, const unsigned char* key32) { + AES_setup(ctx->rk, key32, 8, 14); +} + +void AES256_encrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* cipher16, const unsigned char* plain16) { + while (blocks--) { + AES_encrypt(ctx->rk, 14, cipher16, plain16); + cipher16 += 16; + plain16 += 16; + } +} + +void AES256_decrypt(const AES256_ctx* ctx, size_t blocks, unsigned char* plain16, const unsigned char* cipher16) { + while (blocks--) { + AES_decrypt(ctx->rk, 14, plain16, cipher16); + cipher16 += 16; + plain16 += 16; + } +} diff --git a/src/ecc_key.c b/src/ecc_key.c new file mode 100644 index 000000000..28b7243e8 --- /dev/null +++ b/src/ecc_key.c @@ -0,0 +1,244 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Jonas Schnelli + + 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ripemd160.h" + + +void btc_privkey_init(btc_key* privkey) +{ + memset(&privkey->privkey, 0, BTC_ECKEY_PKEY_LENGTH); +} + + +btc_bool btc_privkey_is_valid(const btc_key* privkey) +{ + if (!privkey) { + return false; + } + return btc_ecc_verify_privatekey(privkey->privkey); +} + + +void btc_privkey_cleanse(btc_key* privkey) +{ + btc_mem_zero(&privkey->privkey, BTC_ECKEY_PKEY_LENGTH); +} + + +void btc_privkey_gen(btc_key* privkey) +{ + if (privkey == NULL) + return; + + do { + assert(btc_random_bytes(privkey->privkey, BTC_ECKEY_PKEY_LENGTH, 0)); + } while (btc_ecc_verify_privatekey(privkey->privkey) == 0); +} + + +btc_bool btc_privkey_verify_pubkey(btc_key* privkey, btc_pubkey* pubkey) +{ + uint256 rnddata, hash; + assert(btc_random_bytes(rnddata, BTC_HASH_LENGTH, 0)); + btc_hash(rnddata, BTC_HASH_LENGTH, hash); + + unsigned char sig[74]; + size_t siglen = 74; + + if (!btc_key_sign_hash(privkey, hash, sig, &siglen)) + return false; + + return btc_pubkey_verify_sig(pubkey, hash, sig, siglen); +} + +void btc_privkey_encode_wif(const btc_key* privkey, const btc_chainparams* chain, char *privkey_wif, size_t *strsize_inout) { + uint8_t pkeybase58c[34]; + pkeybase58c[0] = chain->b58prefix_secret_address; + pkeybase58c[33] = 1; /* always use compressed keys */ + + memcpy(&pkeybase58c[1], privkey->privkey, BTC_ECKEY_PKEY_LENGTH); + assert(btc_base58_encode_check(pkeybase58c, 34, privkey_wif, *strsize_inout) != 0); + btc_mem_zero(&pkeybase58c, 34); +} + +btc_bool btc_privkey_decode_wif(const char *privkey_wif, const btc_chainparams* chain, btc_key* privkey) { + + if (!privkey_wif || strlen(privkey_wif) < 50) { + return false; + } + uint8_t privkey_data[strlen(privkey_wif)]; + memset(privkey_data, 0, sizeof(privkey_data)); + size_t outlen = 0; + + outlen = btc_base58_decode_check(privkey_wif, privkey_data, sizeof(privkey_data)); + if (!outlen) { + return false; + } + if (privkey_data[0] != chain->b58prefix_secret_address) { + return false; + } + memcpy(privkey->privkey, &privkey_data[1], BTC_ECKEY_PKEY_LENGTH); + btc_mem_zero(&privkey_data, sizeof(privkey_data)); + return true; +} + +void btc_pubkey_init(btc_pubkey* pubkey) +{ + if (pubkey == NULL) + return; + + memset(pubkey->pubkey, 0, BTC_ECKEY_UNCOMPRESSED_LENGTH); + pubkey->compressed = false; +} + + +btc_bool btc_pubkey_is_valid(const btc_pubkey* pubkey) +{ + return btc_ecc_verify_pubkey(pubkey->pubkey, pubkey->compressed); +} + + +void btc_pubkey_cleanse(btc_pubkey* pubkey) +{ + if (pubkey == NULL) + return; + + btc_mem_zero(pubkey->pubkey, BTC_ECKEY_UNCOMPRESSED_LENGTH); +} + + +void btc_pubkey_get_hash160(const btc_pubkey* pubkey, uint160 hash160) +{ + uint256 hashout; + btc_hash_sngl_sha256(pubkey->pubkey, pubkey->compressed ? BTC_ECKEY_COMPRESSED_LENGTH : BTC_ECKEY_UNCOMPRESSED_LENGTH, hashout); + + ripemd160(hashout, sizeof(hashout), hash160); +} + + +btc_bool btc_pubkey_get_hex(const btc_pubkey* pubkey, char* str, size_t* strsize) +{ + if (*strsize < BTC_ECKEY_COMPRESSED_LENGTH * 2) + return false; + utils_bin_to_hex((unsigned char*)pubkey->pubkey, BTC_ECKEY_COMPRESSED_LENGTH, str); + *strsize = BTC_ECKEY_COMPRESSED_LENGTH * 2; + return true; +} + + +void btc_pubkey_from_key(const btc_key* privkey, btc_pubkey* pubkey_inout) +{ + if (pubkey_inout == NULL || privkey == NULL) + return; + + size_t in_out_len = BTC_ECKEY_COMPRESSED_LENGTH; + + btc_ecc_get_pubkey(privkey->privkey, pubkey_inout->pubkey, &in_out_len, true); + pubkey_inout->compressed = true; +} + + +btc_bool btc_key_sign_hash(const btc_key* privkey, const uint256 hash, unsigned char* sigout, size_t* outlen) +{ + return btc_ecc_sign(privkey->privkey, hash, sigout, outlen); +} + + +btc_bool btc_key_sign_hash_compact(const btc_key* privkey, const uint256 hash, unsigned char* sigout, size_t* outlen) +{ + return btc_ecc_sign_compact(privkey->privkey, hash, sigout, outlen); +} + +btc_bool btc_key_sign_hash_compact_recoverable(const btc_key* privkey, const uint256 hash, unsigned char* sigout, size_t* outlen, int* recid) +{ + return btc_ecc_sign_compact_recoverable(privkey->privkey, hash, sigout, outlen, recid); +} + +btc_bool btc_key_sign_recover_pubkey(const unsigned char* sig, const uint256 hash, int recid, btc_pubkey* pubkey) +{ + uint8_t pubkeybuf[128]; + size_t outlen = 128; + if (!btc_ecc_recover_pubkey(sig, hash, recid, pubkeybuf, &outlen) || outlen > BTC_ECKEY_UNCOMPRESSED_LENGTH) { + return 0; + } + memset(pubkey->pubkey, 0, sizeof(pubkey->pubkey)); + memcpy(pubkey->pubkey, pubkeybuf, outlen); + if (outlen == BTC_ECKEY_COMPRESSED_LENGTH) { + pubkey->compressed = true; + } + return 1; +} + +btc_bool btc_pubkey_verify_sig(const btc_pubkey* pubkey, const uint256 hash, unsigned char* sigder, int len) +{ + return btc_ecc_verify_sig(pubkey->pubkey, pubkey->compressed, hash, sigder, len); +} + +btc_bool btc_pubkey_getaddr_p2sh_p2wpkh(const btc_pubkey* pubkey, const btc_chainparams* chain, char *addrout) { + cstring *p2wphk_script = cstr_new_sz(22); + uint160 keyhash; + btc_pubkey_get_hash160(pubkey, keyhash); + btc_script_build_p2wpkh(p2wphk_script, keyhash); + + uint8_t hash160[sizeof(uint160)+1]; + hash160[0] = chain->b58prefix_script_address; + btc_script_get_scripthash(p2wphk_script, hash160+1); + cstr_free(p2wphk_script, true); + + btc_base58_encode_check(hash160, sizeof(hash160), addrout, 100); + return true; +} + +btc_bool btc_pubkey_getaddr_p2pkh(const btc_pubkey* pubkey, const btc_chainparams* chain, char *addrout) { + uint8_t hash160[sizeof(uint160)+1]; + hash160[0] = chain->b58prefix_pubkey_address; + btc_pubkey_get_hash160(pubkey, hash160 + 1); + btc_base58_encode_check(hash160, sizeof(hash160), addrout, 100); + return true; +} + +btc_bool btc_pubkey_getaddr_p2wpkh(const btc_pubkey* pubkey, const btc_chainparams* chain, char *addrout) { + uint160 hash160; + btc_pubkey_get_hash160(pubkey, hash160); + segwit_addr_encode(addrout, chain->bech32_hrp, 0, hash160, sizeof(hash160)); + return true; +} diff --git a/src/ecc_libsecp256k1.c b/src/ecc_libsecp256k1.c new file mode 100644 index 000000000..203c6489a --- /dev/null +++ b/src/ecc_libsecp256k1.c @@ -0,0 +1,203 @@ +#include "secp256k1/include/secp256k1.h" +#include "secp256k1/include/secp256k1_recovery.h" + +#include +#include +#include + +#include +#include + +static secp256k1_context* secp256k1_ctx = NULL; + +void btc_ecc_start(void) +{ + btc_random_init(); + + secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + assert(secp256k1_ctx != NULL); + + uint8_t seed[32]; + assert(btc_random_bytes(seed, 32, 0)); + int ret = secp256k1_context_randomize(secp256k1_ctx, seed); + assert(ret); +} + + +void btc_ecc_stop(void) +{ + secp256k1_context* ctx = secp256k1_ctx; + secp256k1_ctx = NULL; + + if (ctx) { + secp256k1_context_destroy(ctx); + } +} + + +void btc_ecc_get_pubkey(const uint8_t* private_key, uint8_t* public_key, size_t* in_outlen, btc_bool compressed) +{ + secp256k1_pubkey pubkey; + assert(secp256k1_ctx); + assert((int)*in_outlen == (compressed ? 33 : 65)); + memset(public_key, 0, *in_outlen); + + if (!secp256k1_ec_pubkey_create(secp256k1_ctx, &pubkey, (const unsigned char*)private_key)) { + return; + } + + if (!secp256k1_ec_pubkey_serialize(secp256k1_ctx, public_key, in_outlen, &pubkey, compressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED)) { + return; + } + + return; +} + +btc_bool btc_ecc_private_key_tweak_add(uint8_t* private_key, const uint8_t* tweak) +{ + assert(secp256k1_ctx); + return secp256k1_ec_privkey_tweak_add(secp256k1_ctx, (unsigned char*)private_key, (const unsigned char*)tweak); +} + +btc_bool btc_ecc_public_key_tweak_add(uint8_t* public_key_inout, const uint8_t* tweak) +{ + size_t out = BTC_ECKEY_COMPRESSED_LENGTH; + secp256k1_pubkey pubkey; + + assert(secp256k1_ctx); + if (!secp256k1_ec_pubkey_parse(secp256k1_ctx, &pubkey, public_key_inout, 33)) + return false; + + if (!secp256k1_ec_pubkey_tweak_add(secp256k1_ctx, &pubkey, (const unsigned char*)tweak)) + return false; + + if (!secp256k1_ec_pubkey_serialize(secp256k1_ctx, public_key_inout, &out, &pubkey, SECP256K1_EC_COMPRESSED)) + return false; + + return true; +} + + +btc_bool btc_ecc_verify_privatekey(const uint8_t* private_key) +{ + assert(secp256k1_ctx); + return secp256k1_ec_seckey_verify(secp256k1_ctx, (const unsigned char*)private_key); +} + +btc_bool btc_ecc_verify_pubkey(const uint8_t* public_key, btc_bool compressed) +{ + secp256k1_pubkey pubkey; + + assert(secp256k1_ctx); + if (!secp256k1_ec_pubkey_parse(secp256k1_ctx, &pubkey, public_key, compressed ? 33 : 65)) { + memset(&pubkey, 0, sizeof(pubkey)); + return false; + } + + memset(&pubkey, 0, sizeof(pubkey)); + return true; +} + +btc_bool btc_ecc_sign(const uint8_t* private_key, const uint256 hash, unsigned char* sigder, size_t* outlen) +{ + assert(secp256k1_ctx); + + secp256k1_ecdsa_signature sig; + if (!secp256k1_ecdsa_sign(secp256k1_ctx, &sig, hash, private_key, secp256k1_nonce_function_rfc6979, NULL)) + return 0; + + if (!secp256k1_ecdsa_signature_serialize_der(secp256k1_ctx, sigder, outlen, &sig)) + return 0; + + return 1; +} + +btc_bool btc_ecc_sign_compact(const uint8_t* private_key, const uint256 hash, unsigned char* sigcomp, size_t* outlen) +{ + assert(secp256k1_ctx); + + secp256k1_ecdsa_signature sig; + if (!secp256k1_ecdsa_sign(secp256k1_ctx, &sig, hash, private_key, secp256k1_nonce_function_rfc6979, NULL)) + return 0; + + *outlen = 64; + if (!secp256k1_ecdsa_signature_serialize_compact(secp256k1_ctx, sigcomp, &sig)) + return 0; + + return 1; +} + +btc_bool btc_ecc_sign_compact_recoverable(const uint8_t* private_key, const uint256 hash, unsigned char* sigrec, size_t* outlen, int *recid) +{ + assert(secp256k1_ctx); + + secp256k1_ecdsa_recoverable_signature sig; + if (!secp256k1_ecdsa_sign_recoverable(secp256k1_ctx, &sig, hash, private_key, secp256k1_nonce_function_rfc6979, NULL)) + return 0; + + *outlen = 65; + if (!secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_ctx, sigrec, recid, &sig)) + return 0; + + return 1; +} + +btc_bool btc_ecc_recover_pubkey(const unsigned char* sigrec, const uint256 hash, const int recid, uint8_t* public_key, size_t *outlen) +{ + assert(secp256k1_ctx); + + secp256k1_pubkey pubkey; + secp256k1_ecdsa_recoverable_signature sig; + + if (!secp256k1_ecdsa_recoverable_signature_parse_compact(secp256k1_ctx, &sig, sigrec, recid)) + return false; + + if (!secp256k1_ecdsa_recover(secp256k1_ctx, &pubkey, &sig, hash)) + return 0; + + if (!secp256k1_ec_pubkey_serialize(secp256k1_ctx, public_key, outlen, &pubkey, SECP256K1_EC_COMPRESSED)) + return 0; + + return 1; +} + +btc_bool btc_ecc_verify_sig(const uint8_t* public_key, btc_bool compressed, const uint256 hash, unsigned char* sigder, size_t siglen) +{ + assert(secp256k1_ctx); + + secp256k1_ecdsa_signature sig; + secp256k1_pubkey pubkey; + + if (!secp256k1_ec_pubkey_parse(secp256k1_ctx, &pubkey, public_key, compressed ? 33 : 65)) + return false; + + if (!secp256k1_ecdsa_signature_parse_der(secp256k1_ctx, &sig, sigder, siglen)) + return false; + + return secp256k1_ecdsa_verify(secp256k1_ctx, &sig, hash, &pubkey); +} + +btc_bool btc_ecc_compact_to_der_normalized(unsigned char* sigcomp_in, unsigned char* sigder_out, size_t* sigder_len_out) +{ + assert(secp256k1_ctx); + + secp256k1_ecdsa_signature sig; + if (!secp256k1_ecdsa_signature_parse_compact(secp256k1_ctx, &sig, sigcomp_in)) + return false; + + secp256k1_ecdsa_signature sigNorm; + secp256k1_ecdsa_signature_normalize(secp256k1_ctx, &sigNorm, &sig); + + return secp256k1_ecdsa_signature_serialize_der(secp256k1_ctx, sigder_out, sigder_len_out, &sigNorm); +} + +btc_bool btc_ecc_der_to_compact(unsigned char* sigder_in, size_t sigder_len, unsigned char* sigcomp_out) +{ + assert(secp256k1_ctx); + + secp256k1_ecdsa_signature sig; + if (!secp256k1_ecdsa_signature_parse_der(secp256k1_ctx, &sig, sigder_in, sigder_len)) + return false; + + return secp256k1_ecdsa_signature_serialize_compact(secp256k1_ctx, sigcomp_out, &sig); +} diff --git a/src/headersdb.c b/src/headersdb.c new file mode 100644 index 000000000..68a47c99a --- /dev/null +++ b/src/headersdb.c @@ -0,0 +1,26 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2017 Jonas Schnelli + + 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/src/headersdb_file.c b/src/headersdb_file.c new file mode 100644 index 000000000..230710621 --- /dev/null +++ b/src/headersdb_file.c @@ -0,0 +1,356 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2017 Jonas Schnelli + + 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 + +#include + +static const unsigned char file_hdr_magic[4] = {0xA8, 0xF0, 0x11, 0xC5}; /* header magic */ +static const uint32_t current_version = 1; + +int btc_header_compare(const void *l, const void *r) +{ + const btc_blockindex *lm = l; + const btc_blockindex *lr = r; + + uint8_t *hashA = (uint8_t *)lm->hash; + uint8_t *hashB = (uint8_t *)lr->hash; + + /* byte per byte compare */ + for (unsigned int i = 0; i < sizeof(uint256); i++) { + uint8_t iA = hashA[i]; + uint8_t iB = hashB[i]; + if (iA > iB) + return -1; + else if (iA < iB) + return 1; + } + + return 0; +} + +btc_headers_db* btc_headers_db_new(const btc_chainparams* chainparams, btc_bool inmem_only) { + btc_headers_db* db; + db = btc_calloc(1, sizeof(*db)); + + db->read_write_file = !inmem_only; + db->use_binary_tree = true; + db->max_hdr_in_mem = 144; + + db->genesis.height = 0; + db->genesis.prev = NULL; + memcpy(db->genesis.hash, chainparams->genesisblockhash, BTC_HASH_LENGTH); + db->chaintip = &db->genesis; + db->chainbottom = &db->genesis; + + if (db->use_binary_tree) { + db->tree_root = 0; + } + + return db; +} + +void btc_headers_db_free(btc_headers_db* db) { + + if (!db) + return; + + if (db->headers_tree_file) + { + fclose(db->headers_tree_file); + db->headers_tree_file = NULL; + } + + if (db->tree_root) { + btc_btree_tdestroy(db->tree_root, btc_free); + db->tree_root = NULL; + } + + btc_free(db); +} + +btc_bool btc_headers_db_load(btc_headers_db* db, const char *file_path) { + if (!db->read_write_file) { + /* stop at this point if we do inmem only */ + return 1; + } + + char *file_path_local = (char *)file_path; + cstring *path_ret = cstr_new_sz(1024); + if (!file_path) + { + btc_get_default_datadir(path_ret); + char *filename = "/headers.db"; + cstr_append_buf(path_ret, filename, strlen(filename)); + cstr_append_c(path_ret, 0); + file_path_local = path_ret->str; + } + + struct stat buffer; + btc_bool create = true; + if (stat(file_path_local, &buffer) == 0) + create = false; + + db->headers_tree_file = fopen(file_path_local, create ? "a+b" : "r+b"); + cstr_free(path_ret, true); + if (create) { + // write file-header-magic + fwrite(file_hdr_magic, 4, 1, db->headers_tree_file); + uint32_t v = htole32(current_version); + fwrite(&v, sizeof(v), 1, db->headers_tree_file); /* uint32_t, LE */ + } + else { + // check file-header-magic + uint8_t buf[sizeof(file_hdr_magic)+sizeof(current_version)]; + if ( (uint32_t)buffer.st_size < (uint32_t)(sizeof(file_hdr_magic)+sizeof(current_version)) || + fread(buf, sizeof(file_hdr_magic)+sizeof(current_version), 1, db->headers_tree_file) != 1 || + memcmp(buf, file_hdr_magic, sizeof(file_hdr_magic)) + ) + { + fprintf(stderr, "Error reading database file\n"); + return false; + } + if (le32toh(*(buf+sizeof(file_hdr_magic))) > current_version) { + fprintf(stderr, "Unsupported file version\n"); + return false; + } + } + btc_bool firstblock = true; + size_t connected_headers_count = 0; + if (db->headers_tree_file && !create) + { + while (!feof(db->headers_tree_file)) + { + uint8_t buf_all[32+4+80]; + if (fread(buf_all, sizeof(buf_all), 1, db->headers_tree_file) == 1) { + struct const_buffer cbuf_all = {buf_all, sizeof(buf_all)}; + + //load all + + /* deserialize the p2p header */ + uint256 hash; + uint32_t height; + deser_u256(hash, &cbuf_all); + deser_u32(&height, &cbuf_all); + if (height >= 1120874) { + //TODO: test hack, remove me + continue; + } + btc_bool connected; + if (firstblock) + { + btc_blockindex *chainheader = calloc(1, sizeof(btc_blockindex)); + chainheader->height = height; + if (!btc_block_header_deserialize(&chainheader->header, &cbuf_all)) { + btc_free(chainheader); + fprintf(stderr, "Error: Invalid data found.\n"); + return -1; + } + btc_block_header_hash(&chainheader->header, (uint8_t *)&chainheader->hash); + chainheader->prev = NULL; + db->chaintip = chainheader; + firstblock = false; + } + else { + btc_headers_db_connect_hdr(db, &cbuf_all, true, &connected); + if (!connected) + { + printf("Connecting header failed (at height: %d)\n", db->chaintip->height); + } + else { + connected_headers_count++; + } + } + } + } + } + printf("Connected %ld headers, now at height: %d\n", connected_headers_count, db->chaintip->height); + return (db->headers_tree_file != NULL); +} + +btc_bool btc_headers_db_write(btc_headers_db* db, btc_blockindex *blockindex) { + cstring *rec = cstr_new_sz(100); + ser_u256(rec, blockindex->hash); + ser_u32(rec, blockindex->height); + btc_block_header_serialize(rec, &blockindex->header); + size_t res = fwrite(rec->str, rec->len, 1, db->headers_tree_file); + btc_file_commit(db->headers_tree_file); + cstr_free(rec, true); + return (res == 1); +} + +btc_blockindex * btc_headers_db_connect_hdr(btc_headers_db* db, struct const_buffer *buf, btc_bool load_process, btc_bool *connected) { + *connected = false; + + btc_blockindex *blockindex = btc_calloc(1, sizeof(btc_blockindex)); + if (!btc_block_header_deserialize(&blockindex->header, buf)) return NULL; + + /* calculate block hash */ + btc_block_header_hash(&blockindex->header, (uint8_t *)&blockindex->hash); + + btc_blockindex *connect_at = NULL; + btc_blockindex *fork_from_block = NULL; + /* try to connect it to the chain tip */ + if (memcmp(blockindex->header.prev_block, db->chaintip->hash, BTC_HASH_LENGTH) == 0) + { + connect_at = db->chaintip; + } + else { + // check if we know the prevblock + fork_from_block = btc_headersdb_find(db, blockindex->header.prev_block); + if (fork_from_block) { + /* block found */ + printf("Block found on a fork...\n"); + connect_at = fork_from_block; + } + } + + if (connect_at != NULL) { + /* TODO: check claimed PoW */ + blockindex->prev = connect_at; + blockindex->height = connect_at->height+1; + + /* TODO: check if we should switch to the fork with most work (instead of height) */ + if (blockindex->height > db->chaintip->height) { + if (fork_from_block) { + /* TODO: walk back to the fork point and call reorg callback */ + printf("Switch to the fork!\n"); + } + db->chaintip = blockindex; + } + /* store in db */ + if (!load_process && db->read_write_file) + { + if (!btc_headers_db_write(db, blockindex)) { + fprintf(stderr, "Error writing blockheader to database\n"); + } + } + if (db->use_binary_tree) { + btc_blockindex *retval = tsearch(blockindex, &db->tree_root, btc_header_compare); + } + + if (db->max_hdr_in_mem > 0) { + // de-allocate no longer required headers + // keep them only on-disk + btc_blockindex *scan_tip = db->chaintip; + for(unsigned int i = 0; imax_hdr_in_mem+1;i++) + { + if (scan_tip->prev) + scan_tip = scan_tip->prev; + else { + break; + } + + if (scan_tip && i == db->max_hdr_in_mem && scan_tip != &db->genesis) { + if (scan_tip->prev && scan_tip->prev != &db->genesis) { + tdelete(scan_tip->prev, &db->tree_root, btc_header_compare); + btc_free(scan_tip->prev); + + scan_tip->prev = NULL; + db->chainbottom = scan_tip; + } + } + } + } + *connected = true; + } + else { + //TODO, add to orphans + char hex[65] = {0}; + utils_bin_to_hex(blockindex->hash, BTC_HASH_LENGTH, hex); + printf("Failed connecting header at height %d (%s)\n", db->chaintip->height, hex); + } + + return blockindex; +} + +void btc_headers_db_fill_block_locator(btc_headers_db* db, vector *blocklocators) +{ + btc_blockindex *scan_tip = db->chaintip; + if (scan_tip->height > 0) + { + for(int i = 0; i<10;i++) + { + //TODO: try to share memory and avoid heap allocation + uint256 *hash = btc_calloc(1, sizeof(uint256)); + memcpy(hash, scan_tip->hash, sizeof(uint256)); + + vector_add(blocklocators, (void *)hash); + if (scan_tip->prev) + scan_tip = scan_tip->prev; + else + break; + } + } +} + +btc_blockindex * btc_headersdb_find(btc_headers_db* db, uint256 hash) { + if (db->use_binary_tree) + { + btc_blockindex *blockindex = btc_calloc(1, sizeof(btc_blockindex)); + memcpy(blockindex->hash, hash, sizeof(uint256)); + btc_blockindex *blockindex_f = tfind(blockindex, &db->tree_root, btc_header_compare); /* read */ + if (blockindex_f) { + blockindex_f = *(btc_blockindex **)blockindex_f; + } + btc_free(blockindex); + return blockindex_f; + } + return NULL; +} + +btc_blockindex * btc_headersdb_getchaintip(btc_headers_db* db) { + return db->chaintip; +} + +btc_bool btc_headersdb_disconnect_tip(btc_headers_db* db) { + if (db->chaintip->prev) + { + btc_blockindex *oldtip = db->chaintip; + db->chaintip = db->chaintip->prev; + /* disconnect/remove the chaintip */ + tdelete(oldtip, &db->tree_root, btc_header_compare); + btc_free(oldtip); + return true; + } + return false; +} + +btc_bool btc_headersdb_has_checkpoint_start(btc_headers_db* db) { + return (db->chainbottom->height != 0); +} + +void btc_headersdb_set_checkpoint_start(btc_headers_db* db, uint256 hash, uint32_t height) { + db->chainbottom = btc_calloc(1, sizeof(btc_blockindex)); + db->chainbottom->height = height; + memcpy(db->chainbottom->hash, hash, sizeof(uint256)); + db->chaintip = db->chainbottom; +} diff --git a/src/logdb/include/logdb/logdb.h b/src/logdb/include/logdb/logdb.h new file mode 100644 index 000000000..3cedb99af --- /dev/null +++ b/src/logdb/include/logdb/logdb.h @@ -0,0 +1,67 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Jonas Schnelli + + 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. + +*/ + + +/* + File Format + + [8 bytes] per file magic 0xF9, 0xAA, 0x03, 0xBA + [int32_t/4 bytes] version number + [int32_t/4 bytes] version flags + ---- records + [8 bytes] static per record magic 0x88, 0x61, 0xAD, 0xFC, 0x5A, 0x11, 0x22, 0xF8 + [16 bytes] partial sha256 hash (first 16 bytes) of the record body + ---- record-body start ---- + [1 byte] record type (0 = write | 1 = erase) + [varint] length of the key + [variable] key data + [varint] length of the value + [variable] value data + ---- record-body end ---- + [16 bytes] partial sha256 of *all data* up to this point in logdb + ---- record end --- + ---- more records +*/ + +#ifndef __LIBLOGDB_H__ +#define __LIBLOGDB_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include +#include +#include +#include + +#ifdef __cplusplus +} +#endif + +#endif /* __LIBLOGDB_H__ */ diff --git a/src/logdb/include/logdb/logdb_base.h b/src/logdb/include/logdb/logdb_base.h new file mode 100644 index 000000000..76d8ccac6 --- /dev/null +++ b/src/logdb/include/logdb/logdb_base.h @@ -0,0 +1,71 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Jonas Schnelli + + 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 + +#ifndef __LIBLOGDB_BASE_H__ +#define __LIBLOGDB_BASE_H__ + +#define UNUSED(x) (void)(x) + +typedef uint8_t logdb_bool; /*!serialize, c/c++ save bool*/ + +#ifndef true +#define true 1 +#endif + +#ifndef false +#define false 0 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef LIBLOGDB_API +#if defined(_WIN32) +#ifdef LIBBTC_BUILD +#define LIBLOGDB_API __declspec(dllexport) +#else +#define LIBLOGDB_API +#endif +#elif defined(__GNUC__) && defined(LIBBTC_BUILD) +#define LIBLOGDB_API __attribute__((visibility("default"))) +#else +#define LIBLOGDB_API +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __LIBLOGDB_BASE_H__ */ diff --git a/src/logdb/include/logdb/logdb_core.h b/src/logdb/include/logdb/logdb_core.h new file mode 100644 index 000000000..3025b62e3 --- /dev/null +++ b/src/logdb/include/logdb/logdb_core.h @@ -0,0 +1,155 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Jonas Schnelli + + 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 __LIBLOGDB_LOGDB_H__ +#define __LIBLOGDB_LOGDB_H__ + +#include +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** error types */ +enum logdb_error { + LOGDB_SUCCESS = 0, + LOGDB_ERROR_UNKNOWN = 100, + LOGDB_ERROR_FOPEN_FAILED = 200, + LOGDB_ERROR_WRONG_FILE_FORMAT = 300, + LOGDB_ERROR_DATASTREAM_ERROR = 400, + LOGDB_ERROR_CHECKSUM = 500, + LOGDB_ERROR_FILE_ALREADY_OPEN = 600 +}; + +typedef struct logdb_memmapper_ logdb_memmapper; /* forware declaration */ + +/** logdb handle */ +typedef struct logdb_log_db { + FILE *file; + logdb_memmapper *mem_mapper; + void *cb_ctx; + logdb_record *cache_head; + SHA256_CTX hashctx; + uint8_t hashlen; + uint32_t version; + uint32_t support_flags; +} logdb_log_db; + +typedef struct logdb_txn { + logdb_record *txn_head; +} logdb_txn; + +/* function pointer interface for flexible memory mapping functions*/ +struct logdb_memmapper_ +{ + /* callback called when appending (incl. deletes) a record + the 2nd parameter (bool) tells the cb if the record was added + during the load wallet phase + */ + void (*append_cb)(void*, logdb_bool, logdb_record *); + + /* callback called when initializing the database */ + void (*init_cb)(logdb_log_db*); + + /* callback called when database gets destroyed */ + void (*cleanup_cb)(void*); + + /* callback for finding a record with given key */ + cstring* (*find_cb)(logdb_log_db*, cstring *); + + /* callback which expect the get back the total amount of keys in the database */ + size_t (*size_cb)(logdb_log_db*); +}; + +/* DB HANDLING +////////////////////////////////// */ +/** creates new logdb handle, sets default values */ +LIBLOGDB_API logdb_log_db* logdb_new(); + +/** creates new logdb handle, sets default values + used red black tree for memory mapping */ +LIBLOGDB_API logdb_log_db* logdb_rbtree_new(); + +/** frees database and all in-memory records, closes file if open */ +LIBLOGDB_API void logdb_free(logdb_log_db* db); + +/** set the callback for all memory mapping operations + the callback will be called when a record will be loaded from disk, appended, deleted + this will allow to do a application specific memory mapping + */ +LIBLOGDB_API void logdb_set_memmapper(logdb_log_db* db, logdb_memmapper *mapper, void *ctx); + +/** loads given file as database (memory mapping) */ +LIBLOGDB_API logdb_bool logdb_load(logdb_log_db* handle, const char *file_path, logdb_bool create, enum logdb_error *error); + +/** flushes database: writes down new records */ +LIBLOGDB_API logdb_bool logdb_flush(logdb_log_db* db); + +/** deletes record with key */ +LIBLOGDB_API void logdb_delete(logdb_log_db* db, logdb_txn *txn, cstring *key); + +/** appends record to the logdb */ +LIBLOGDB_API void logdb_append(logdb_log_db* db, logdb_txn *txn, cstring *key, cstring *value); + +/** find and get value from key */ +LIBLOGDB_API cstring * logdb_find_cache(logdb_log_db* db, cstring *key); +LIBLOGDB_API cstring * logdb_find(logdb_log_db* db, cstring *key); + +/** get the amount of in-memory-records */ +LIBLOGDB_API size_t logdb_cache_size(logdb_log_db* db); +LIBLOGDB_API size_t logdb_count_keys(logdb_log_db* db); + +/** writes down single record, internal */ +void logdb_write_record(logdb_log_db* db, logdb_record *rec); + +/** deserializes next logdb record from file */ +logdb_bool logdb_record_deser_from_file(logdb_record* rec, logdb_log_db *db, enum logdb_error *error); + +/** remove records with given key (to keep memory clean) */ +logdb_bool logdb_remove_existing_records(logdb_record *usehead, cstring *key); + + +/* TRANSACTION HANDLING +////////////////////////////////// */ + +/** create a new transaction object **/ +LIBLOGDB_API logdb_txn* logdb_txn_new(); + +/** releases a transaction object **/ +LIBLOGDB_API void logdb_txn_free(logdb_txn* db); + +/** writes transaction to the internal cache **/ +LIBLOGDB_API void logdb_txn_commit(logdb_log_db* db, logdb_txn *txn); +#ifdef __cplusplus +} +#endif + +#endif /* __LIBLOGDB_LOGDB_H__ */ diff --git a/src/logdb/include/logdb/logdb_memdb_llist.h b/src/logdb/include/logdb/logdb_memdb_llist.h new file mode 100644 index 000000000..57723e5ba --- /dev/null +++ b/src/logdb/include/logdb/logdb_memdb_llist.h @@ -0,0 +1,83 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Jonas Schnelli + + 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. + + */ + +/* + A simple linkes list memory DB, + extremly slow and only for callback demo purposes + + If you are going to write a memory mapper for logdb, use a red black tree + http://web.mit.edu/~emin/Desktop/ref_to_emin/www.old/source_code/red_black_tree/index.html + + Logdb does currently not provide an efficient memory map +*/ + +#ifndef __LIBLOGDB_MEMDB_H__ +#define __LIBLOGDB_MEMDB_H__ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef struct logdb_llist_db_ { + logdb_record *head; +} logdb_llist_db; + +logdb_llist_db* logdb_llist_db_new(); +void logdb_llist_db_free(void *ctx); + +LIBLOGDB_API void logdb_llistdb_init(logdb_log_db* db); + +/** appends record to the mem db */ +LIBLOGDB_API void logdb_llistdb_append(void* ctx, logdb_bool load_phase, logdb_record *rec); + +LIBLOGDB_API cstring * logdb_llistdb_find(logdb_log_db* db, cstring *key); + +LIBLOGDB_API size_t logdb_llistdb_size(logdb_log_db* db); + +LIBLOGDB_API void logdb_llistdb_cleanup(void* ctx); + +/* static interface */ +static logdb_memmapper logdb_llistdb_mapper = { + logdb_llistdb_append, + logdb_llistdb_init, + logdb_llist_db_free, + logdb_llistdb_find, + logdb_llistdb_size +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __LIBLOGDB_MEMDB_H__ */ diff --git a/src/logdb/include/logdb/logdb_memdb_rbtree.h b/src/logdb/include/logdb/logdb_memdb_rbtree.h new file mode 100644 index 000000000..c15d2635c --- /dev/null +++ b/src/logdb/include/logdb/logdb_memdb_rbtree.h @@ -0,0 +1,80 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Jonas Schnelli + + 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. + + */ + +/* + Memory mapping with a red black tree +*/ + +#ifndef __LIBLOGDB_RBTREE_H__ +#define __LIBLOGDB_RBTREE_H__ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef struct logdb_rbtree_db_ { + struct rb_red_blk_tree *tree; +} logdb_rbtree_db; + +logdb_rbtree_db* logdb_rbtree_db_new(); +void logdb_rbtree_free(void *ctx); + +/** appends record to the rbtree */ +LIBLOGDB_API void logdb_rbtree_init(logdb_log_db* db); + +/** appends record to the rbtree */ +LIBLOGDB_API void logdb_rbtree_append(void* ctx, logdb_bool load_phase, logdb_record *rec); + +/** find a record by key */ +LIBLOGDB_API cstring * logdb_rbtree_find(logdb_log_db* db, cstring *key); + +/** count all red black tree nodes */ +LIBLOGDB_API size_t logdb_rbtree_size(logdb_log_db* db); + +/* static interface */ +static logdb_memmapper logdb_rbtree_mapper = { + logdb_rbtree_append, + logdb_rbtree_init, + logdb_rbtree_free, + logdb_rbtree_find, + logdb_rbtree_size +}; + + +#ifdef __cplusplus +} +#endif + +#endif /* __LIBLOGDB_RBTREE_H__ */ diff --git a/src/logdb/include/logdb/logdb_rec.h b/src/logdb/include/logdb/logdb_rec.h new file mode 100644 index 000000000..47a399923 --- /dev/null +++ b/src/logdb/include/logdb/logdb_rec.h @@ -0,0 +1,86 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Jonas Schnelli + + 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 __LIBLOGDB_REC_H__ +#define __LIBLOGDB_REC_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +#include +#include + +/** record types */ +enum logdb_record_type { + RECORD_TYPE_WRITE = 0, + RECORD_TYPE_ERASE = 1 +}; + +/** single key/value record (linked list node) */ +typedef struct logdb_record { + cstring* key; + cstring* value; + struct logdb_record* next; /* linked list -> next node (NULL if end) */ + struct logdb_record* prev; /* linked list -> prev node (NULL if end) */ + int written; /* 0 = not written to databse, 1 = written */ + uint8_t mode; /* record mode, 0 = WRITE, 1 = ERASE */ +} logdb_record; + +/* RECORD HANDLING */ +/** creates new logdb key/value record */ +LIBLOGDB_API logdb_record* logdb_record_new(); + +/** free record including containing key/value data */ +LIBLOGDB_API void logdb_record_free(logdb_record* rec); + +/** sets key value (binary buffer copy) */ +LIBLOGDB_API void logdb_record_set(logdb_record* rec, cstring *key, cstring *val); + +/** copy database record */ +LIBLOGDB_API logdb_record* logdb_record_copy(logdb_record* b_rec); + +/** serialize a record into a cstring */ +LIBLOGDB_API void logdb_record_ser(logdb_record* rec, cstring *buf); + +/** get current height in linkes list */ +LIBLOGDB_API size_t logdb_record_height(logdb_record* head); + +/** find the next record with key downwards the linkes list */ +LIBLOGDB_API cstring * logdb_record_find_desc(logdb_record* head, cstring *key); + +/** remove records with given key (to keep memory clean) */ +LIBLOGDB_API logdb_record* logdb_record_rm_desc(logdb_record *usehead, cstring *key); + +#ifdef __cplusplus +} +#endif + +#endif /* __LIBLOGDB_REC_H__ */ diff --git a/src/logdb/include/logdb/red_black_tree.h b/src/logdb/include/logdb/red_black_tree.h new file mode 100644 index 000000000..19f75dbf4 --- /dev/null +++ b/src/logdb/include/logdb/red_black_tree.h @@ -0,0 +1,94 @@ +/* CONVENTIONS: All data structures for red-black trees have the prefix */ +/* "rb_" to prevent name conflicts. */ +/* */ +/* Function names: Each word in a function name begins with */ +/* a capital letter. An example funcntion name is */ +/* CreateRedTree(a,b,c). Furthermore, each function name */ +/* should begin with a capital letter to easily distinguish */ +/* them from variables. */ +/* */ +/* Variable names: Each word in a variable name begins with */ +/* a capital letter EXCEPT the first letter of the variable */ +/* name. For example, int newLongInt. Global variables have */ +/* names beginning with "g". An example of a global */ +/* variable name is gNewtonsConstant. */ + +#ifndef __LIBLOGDB_RED_BLACK_TREE_H__ +#define __LIBLOGDB_RED_BLACK_TREE_H__ + +#ifndef DATA_TYPE +#define DATA_TYPE void * +#endif + +#include +#include + +typedef struct stk_stack_node { + DATA_TYPE info; + struct stk_stack_node * next; +} stk_stack_node; + +typedef struct stk_stack { + stk_stack_node * top; + stk_stack_node * tail; +} stk_stack ; + +typedef struct rb_red_blk_node { + void* key; + void* info; + int red; /* if red=0 then the node is black */ + struct rb_red_blk_node* left; + struct rb_red_blk_node* right; + struct rb_red_blk_node* parent; +} rb_red_blk_node; + + +/* Compare(a,b) should return 1 if *a > *b, -1 if *a < *b, and 0 otherwise */ +/* Destroy(a) takes a pointer to whatever key might be and frees it accordingly */ +typedef struct rb_red_blk_tree { + int (*Compare)(const void* a, const void* b); + void (*destroy_key_callback)(void* a); + void (*info_destroy_callback)(void* a); + void (*PrintKey)(const void* a); + void (*PrintInfo)(void* a); + /* A sentinel is used for root and for nil. These sentinels are */ + /* created when RBTreeCreate is caled. root->left should always */ + /* point to the node which is the root of the tree. nil points to a */ + /* node which should always be black but has aribtrary children and */ + /* parent and no key or info. The point of using these sentinels is so */ + /* that the root and nil nodes do not require special cases in the code */ + rb_red_blk_node* root; + rb_red_blk_node* nil; + rb_red_blk_node* it; /* iterator */ + int it_node; +} rb_red_blk_tree; + +rb_red_blk_tree* RBTreeCreate(int (*CompFunc)(const void*, const void*), + void (*DestFunc)(void*), + void (*info_destroy_callback)(void*), + void (*PrintFunc)(const void*), + void (*PrintInfo)(void*)); +rb_red_blk_node * RBTreeInsert(rb_red_blk_tree*, void* key, void* info); +void RBTreePrint(rb_red_blk_tree*); +void RBDelete(rb_red_blk_tree* , rb_red_blk_node* ); +void RBTreeDestroy(rb_red_blk_tree*); +rb_red_blk_node* TreePredecessor(rb_red_blk_tree*,rb_red_blk_node*); +rb_red_blk_node* TreeSuccessor(rb_red_blk_tree*,rb_red_blk_node*); +rb_red_blk_node* RBExactQuery(rb_red_blk_tree*, void*); +stk_stack * RBEnumerate(rb_red_blk_tree* tree,void* low, void* high); +size_t rbtree_count(rb_red_blk_tree* tree); +void NullFunction(void*); +/* These functions are all very straightforward and self-commenting so */ +/* I didn't think additional comments would be useful */ +stk_stack * StackJoin(stk_stack * stack1, stk_stack * stack2); +stk_stack * StackCreate(); +void StackPush(stk_stack * theStack, DATA_TYPE newInfoPointer); +void * StackPop(stk_stack * theStack); +int StackNotEmpty(stk_stack *); +void StackDestroy(stk_stack * theStack,void DestFunc(void * a)); + +void rbtree_it_reset(rb_red_blk_tree* tree); +rb_red_blk_node* rbtree_enumerate_next(rb_red_blk_tree* tree); + + +#endif /* __LIBLOGDB_RED_BLACK_TREE_H__ */ diff --git a/src/logdb/logdb_core.c b/src/logdb/logdb_core.c new file mode 100644 index 000000000..6fc7e2cb0 --- /dev/null +++ b/src/logdb/logdb_core.c @@ -0,0 +1,513 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Jonas Schnelli + + 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 +#include +#include +#include + +/* reduce sha256 hash to 8 bytes for checksum */ +#define kLOGDB_DEFAULT_HASH_LEN 16 +#define kLOGDB_DEFAULT_VERSION 1 + +static const unsigned char file_hdr_magic[4] = {0xF9, 0xAA, 0x03, 0xBA}; /* header magic */ +static const unsigned char record_magic[8] = {0x88, 0x61, 0xAD, 0xFC, 0x5A, 0x11, 0x22, 0xF8}; /* record magic */ + + +logdb_log_db* logdb_new_internal() +{ + logdb_log_db* db; + db = calloc(1, sizeof(*db)); + db->mem_mapper = NULL; + db->cache_head = NULL; + db->hashlen = kLOGDB_DEFAULT_HASH_LEN; + db->version = kLOGDB_DEFAULT_VERSION; + db->support_flags = 0; /* reserved for future changes */ + sha256_Init(&db->hashctx); + + return db; +} + +logdb_log_db* logdb_new() +{ + logdb_log_db* db = logdb_new_internal(); + + /* use a linked list for default memory mapping */ + /* Will be slow */ + logdb_set_memmapper(db, &logdb_llistdb_mapper, NULL); + + return db; +} + +logdb_log_db* logdb_rbtree_new() +{ + logdb_log_db* db = logdb_new_internal(); + + /* use a red black tree as default memory mapping */ + logdb_set_memmapper(db, &logdb_rbtree_mapper, NULL); + return db; +} + +logdb_txn* logdb_txn_new() +{ + logdb_txn* txn; + txn = calloc(1, sizeof(*txn)); + txn->txn_head = NULL; + return txn; +} + +void logdb_free_txn_records(logdb_txn* txn) +{ + /* free the unwritten records list */ + logdb_record *rec = txn->txn_head; + while (rec) + { + logdb_record *prev_rec = rec->prev; + logdb_record_free(rec); + rec = prev_rec; + } + txn->txn_head = NULL; +} + +void logdb_txn_free(logdb_txn* txn) +{ + if (!txn) + return; + + logdb_free_txn_records(txn); + free(txn); +} + +void logdb_set_memmapper(logdb_log_db* db, logdb_memmapper *mapper, void *ctx) +{ + /* allow the previos memory mapper to do a cleanup */ + if (db->mem_mapper && db->mem_mapper->cleanup_cb) + db->mem_mapper->cleanup_cb(db->cb_ctx); + + db->mem_mapper = mapper; + if (db->mem_mapper && db->mem_mapper->init_cb) + db->mem_mapper->init_cb(db); + + if (ctx) + db->cb_ctx = ctx; +} + +void logdb_free_cachelist(logdb_log_db* db) +{ + /* free the unwritten records list */ + logdb_record *rec = db->cache_head; + while (rec) + { + logdb_record *prev_rec = rec->prev; + logdb_record_free(rec); + rec = prev_rec; + } + db->cache_head = NULL; +} + +void logdb_free(logdb_log_db* db) +{ + if (!db) + return; + + if (db->file) + { + fclose(db->file); + db->file = NULL; + } + + logdb_free_cachelist(db); + + /* allow the memory mapper to do a cleanup */ + if (db->mem_mapper && db->mem_mapper->cleanup_cb) + db->mem_mapper->cleanup_cb(db->cb_ctx); + + free(db); +} + +logdb_bool logdb_load(logdb_log_db* handle, const char *file_path, logdb_bool create, enum logdb_error *error) +{ + uint32_t v; + logdb_record *rec; + enum logdb_error record_error; + + handle->file = fopen(file_path, create ? "a+b" : "r+b"); + if (handle->file == NULL) + { + if (error != NULL) + *error = LOGDB_ERROR_FOPEN_FAILED; + return false; + } + + /* write header magic */ + if (create) + { + /* write header magic, version & support flags */ + fwrite(file_hdr_magic, 4, 1, handle->file); + v = htole32(handle->version); + fwrite(&v, sizeof(v), 1, handle->file); /* uint32_t, LE */ + v = htole32(handle->support_flags); + fwrite(&v, sizeof(v), 1, handle->file); /* uint32_t, LE */ + } + else + { + /* read file magic, version, etc. */ + unsigned char buf[4]; + if (fread(buf, 4, 1, handle->file) != 1 || memcmp(buf, file_hdr_magic, 4) != 0) + { + if (error != NULL) + *error = LOGDB_ERROR_WRONG_FILE_FORMAT; + return false; + } + + /* read and set version */ + v = 0; + if (fread(&v, sizeof(v), 1, handle->file) != 1) + { + if (error != NULL) + *error = LOGDB_ERROR_WRONG_FILE_FORMAT; + return false; + } + handle->version = le32toh(v); + + /* read and set support flags */ + if (fread(&v, sizeof(v), 1, handle->file) != 1) + { + if (error != NULL) + *error = LOGDB_ERROR_WRONG_FILE_FORMAT; + return false; + } + handle->support_flags = le32toh(v); + + rec = logdb_record_new(); + while (logdb_record_deser_from_file(rec, handle, &record_error)) + { + if (record_error != LOGDB_SUCCESS) + break; + + /* if a memory mapping function was provided, + pass the record together with the context to + this function. + */ + if (handle->mem_mapper && handle->mem_mapper->append_cb) + handle->mem_mapper->append_cb(handle->cb_ctx, true, rec); + } + logdb_record_free(rec); + + if (record_error != LOGDB_SUCCESS) + { + if (error) + *error = record_error; + return false; + } + } + + return true; +} + +logdb_bool logdb_flush(logdb_log_db* db) +{ + logdb_record *flush_rec; + + if (!db->file) + return false; + + flush_rec = db->cache_head; + + /* search deepest non written record */ + while (flush_rec != NULL) + { + if (flush_rec->written == true) + { + flush_rec = flush_rec->next; + break; + } + + if (flush_rec->prev != NULL) + flush_rec = flush_rec->prev; + else + break; + } + + /* write records */ + while (flush_rec != NULL) + { + logdb_write_record(db, flush_rec); + flush_rec->written = true; + flush_rec = flush_rec->next; + } + + /*reset cache list + no need to longer cache the written records + */ + logdb_free_cachelist(db); + + return true; +} + +void logdb_delete(logdb_log_db* db, logdb_txn *txn, cstring *key) +{ + if (key == NULL) + return; + + /* A NULL value will result in a delete-mode record */ + logdb_append(db, txn, key, NULL); +} + +void logdb_append(logdb_log_db* db, logdb_txn *txn, cstring *key, cstring *val) +{ + logdb_record *rec; + logdb_record *current_head; + + if (key == NULL) + return; + + rec = logdb_record_new(); + logdb_record_set(rec, key, val); + if (txn) + current_head = txn->txn_head; + else + current_head = db->cache_head; + + /* if the list is NOT empty, link the current head */ + if (current_head != NULL) + current_head->next = rec; + + /* link to previous element */ + rec->prev = current_head; + + /* set the current head */ + if (txn) + txn->txn_head = rec; + else + db->cache_head = rec; + + /* update mem mapped database (only non TXN) */ + if (db->mem_mapper && db->mem_mapper->append_cb &&!txn) + db->mem_mapper->append_cb(db->cb_ctx, false, rec); +} + +void logdb_txn_commit(logdb_log_db* db, logdb_txn *txn) +{ + logdb_record *work_head = txn->txn_head; + /* search deepest non written record */ + while (work_head != NULL) + { + if (work_head->prev != NULL) + work_head = work_head->prev; + else + break; + } + /* write records */ + while (work_head != NULL) + { + logdb_append(db, NULL, work_head->key, work_head->value); + work_head = work_head->next; + } +} + +cstring * logdb_find_cache(logdb_log_db* db, cstring *key) +{ + return logdb_record_find_desc(db->cache_head, key); +} + +cstring * logdb_find(logdb_log_db* db, cstring *key) +{ + if (db->mem_mapper && db->mem_mapper->find_cb) + return db->mem_mapper->find_cb(db, key); + + return NULL; +} + +size_t logdb_count_keys(logdb_log_db* db) +{ + if (db->mem_mapper && db->mem_mapper->size_cb) + return db->mem_mapper->size_cb(db); + + return 0; +} + +size_t logdb_cache_size(logdb_log_db* db) +{ + return logdb_record_height(db->cache_head); +} + +void logdb_write_record(logdb_log_db* db, logdb_record *rec) +{ + SHA256_CTX ctx = db->hashctx; + SHA256_CTX ctx_final; + uint8_t hash[SHA256_DIGEST_LENGTH]; + + /* serialize record to buffer */ + cstring *serbuf = cstr_new_sz(1024); + logdb_record_ser(rec, serbuf); + + /* create hash of the body */ + sha256_Raw((const uint8_t*)serbuf->str, serbuf->len, hash); + + /* write record header */ + assert(fwrite(record_magic, 8, 1, db->file) == 1); + sha256_Update(&ctx, record_magic, 8); + + /* write partial hash as body checksum&indicator (body start) */ + assert(fwrite(hash, db->hashlen, 1, db->file) == 1); + sha256_Update(&ctx, hash, db->hashlen); + + /* write the body */ + fwrite(serbuf->str, serbuf->len, 1, db->file); + sha256_Update(&ctx, (uint8_t *)serbuf->str, serbuf->len); + + /* write partial hash as body checksum&indicator (body end) */ + assert(fwrite(hash, db->hashlen, 1, db->file) == 1); + sha256_Update(&ctx, hash, db->hashlen); + + cstr_free(serbuf, true); + + ctx_final = ctx; + sha256_Final(hash, &ctx_final); + assert(fwrite(hash, db->hashlen, 1, db->file) == 1); + db->hashctx = ctx; +} + +logdb_bool logdb_record_deser_from_file(logdb_record* rec, logdb_log_db *db, enum logdb_error *error) +{ + uint32_t len = 0; + SHA256_CTX ctx = db->hashctx; /* prepare a copy of context that allows rollback */ + SHA256_CTX ctx_final; + uint8_t magic_buf[8]; + uint8_t hashcheck[SHA256_DIGEST_LENGTH]; + unsigned char check[SHA256_DIGEST_LENGTH]; + + /* prepate a buffer for the varint data (max 4 bytes) */ + size_t buflen = sizeof(uint32_t); + uint8_t readbuf[sizeof(uint32_t)]; + + *error = LOGDB_SUCCESS; + + /* read record magic */ + if (fread(magic_buf, 8, 1, db->file) != 1) + { + /* very likely end of file reached */ + return false; + } + sha256_Update(&ctx, magic_buf, 8); + + /* read start hash/magic per record */ + if (fread(hashcheck, db->hashlen, 1, db->file) != 1) + { + *error = LOGDB_ERROR_DATASTREAM_ERROR; + return false; + } + sha256_Update(&ctx, hashcheck, db->hashlen); + + /* read record mode (write / delete) */ + if (fread(&rec->mode, 1, 1, db->file) != 1) + { + *error = LOGDB_ERROR_DATASTREAM_ERROR; + return false; + } + + sha256_Update(&ctx, (const uint8_t *)&rec->mode, 1); + + /* key */ + if (!deser_varlen_file(&len, db->file, readbuf, &buflen)) + { + *error = LOGDB_ERROR_DATASTREAM_ERROR; + return false; + } + + sha256_Update(&ctx, readbuf, buflen); + + cstr_resize(rec->key, len); + if (fread(rec->key->str, 1, len, db->file) != len) + { + *error = LOGDB_ERROR_DATASTREAM_ERROR; + return false; + } + + sha256_Update(&ctx, (const uint8_t *)rec->key->str, len); + + if (rec->mode == RECORD_TYPE_WRITE) + { + /* read value (not for delete mode) */ + buflen = sizeof(uint32_t); + if (!deser_varlen_file(&len, db->file, readbuf, &buflen)) + { + *error = LOGDB_ERROR_DATASTREAM_ERROR; + return false; + } + + sha256_Update(&ctx, readbuf, buflen); + + cstr_resize(rec->value, len); + if (fread(rec->value->str, 1, len, db->file) != len) + { + *error = LOGDB_ERROR_DATASTREAM_ERROR; + return false; + } + + sha256_Update(&ctx, (const uint8_t *)rec->value->str, len); + } + + /* read start hash/magic per record */ + if (fread(hashcheck, db->hashlen, 1, db->file) != 1) + { + /* very likely end of file reached */ + *error = LOGDB_ERROR_DATASTREAM_ERROR; + return false; + } + sha256_Update(&ctx, hashcheck, db->hashlen); + + /* generate final checksum in a context copy */ + ctx_final = ctx; + sha256_Final(hashcheck, &ctx_final); + + /* read checksum from file, compare */ + if (fread(check, 1, db->hashlen, db->file) != db->hashlen) + { + *error = LOGDB_ERROR_DATASTREAM_ERROR; + return false; + } + + if (memcmp(hashcheck,check,(size_t)db->hashlen) != 0) + { + *error = LOGDB_ERROR_CHECKSUM; + return false; + } + + /* mark record as written because we have + just loaded it from disk */ + rec->written = true; + + /* update sha256 context */ + db->hashctx = ctx; + return true; +} diff --git a/src/logdb/logdb_memdb_llist.c b/src/logdb/logdb_memdb_llist.c new file mode 100644 index 000000000..7c0afb33d --- /dev/null +++ b/src/logdb/logdb_memdb_llist.c @@ -0,0 +1,112 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Jonas Schnelli + + 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 +#include + +logdb_llist_db* logdb_llist_db_new() +{ + logdb_llist_db* handle = calloc(1, sizeof(logdb_llist_db)); + handle->head = NULL; + return handle; +} + +void logdb_llist_db_free(void *ctx) +{ + logdb_record *rec; + logdb_record *prev_rec; + + logdb_llist_db *handle = (logdb_llist_db *)ctx; + if (!handle) + return; + + /* free the internal database */ + rec = handle->head; + while (rec) + { + prev_rec = rec->prev; + logdb_record_free(rec); + rec = prev_rec; + } + + memset(handle, 0, sizeof(*handle)); + free(handle); +} + +void logdb_llistdb_init(logdb_log_db* db) +{ + logdb_llist_db* handle = logdb_llist_db_new(); + db->cb_ctx = handle; +} + +void logdb_llistdb_append(void* ctx, logdb_bool load_phase, logdb_record *rec) +{ + logdb_llist_db *handle = (logdb_llist_db *)ctx; + logdb_record *rec_dup; + logdb_record *current_db_head; + UNUSED(load_phase); + + if (rec->mode == RECORD_TYPE_ERASE && handle->head) + { + handle->head = logdb_record_rm_desc(handle->head, rec->key); + return; + } + + /* internal database: + copy record and append to internal mem db (linked list) + */ + rec_dup = logdb_record_copy(rec); + current_db_head = handle->head; + + /* if the list is NOT empty, link the current head */ + if (current_db_head != NULL) + current_db_head->next = rec_dup; + + /* link to previous element */ + rec_dup->prev = current_db_head; + + /* set the current head */ + handle->head = rec_dup; + + logdb_record_rm_desc(current_db_head, rec_dup->key); +} + +cstring * logdb_llistdb_find(logdb_log_db* db, cstring *key) +{ + logdb_llist_db *handle = (logdb_llist_db *)db->cb_ctx; + return logdb_record_find_desc(handle->head, key); +} + +size_t logdb_llistdb_size(logdb_log_db* db) +{ + logdb_llist_db *handle = (logdb_llist_db *)db->cb_ctx; + return logdb_record_height(handle->head); +} diff --git a/src/logdb/logdb_memdb_rbtree.c b/src/logdb/logdb_memdb_rbtree.c new file mode 100644 index 000000000..0a472ed0f --- /dev/null +++ b/src/logdb/logdb_memdb_rbtree.c @@ -0,0 +1,131 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Jonas Schnelli + + 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 +#include +#include + +void logdb_rbtree_free_key(void* a) { + /* key needs no releasing, value contains key */ + UNUSED(a); +} + +void logdb_rbtree_free_value(void *a){ + /* free the record which also frees the key */ + logdb_record *rec = (logdb_record *)a; + logdb_record_free(rec); +} + +int logdb_rbtree_IntComp(const void* a,const void* b) { + return cstr_compare((cstring *)a, (cstring *)b); +} + +void logdb_rbtree_IntPrint(const void* a) { + printf("%i",*(int*)a); +} + +void logdb_rbtree_InfoPrint(void* a) { + UNUSED(a); +} + +logdb_rbtree_db* logdb_rbtree_db_new() +{ + logdb_rbtree_db* handle = calloc(1, sizeof(logdb_rbtree_db)); + handle->tree = RBTreeCreate(logdb_rbtree_IntComp,logdb_rbtree_free_key,logdb_rbtree_free_value,logdb_rbtree_IntPrint,logdb_rbtree_InfoPrint); + + return handle; +} + +void logdb_rbtree_free(void *ctx) +{ + logdb_rbtree_db *handle = (logdb_rbtree_db *)ctx; + if (!handle) + return; + + RBTreeDestroy(handle->tree); + + memset(handle, 0, sizeof(*handle)); + free(handle); +} + +void logdb_rbtree_init(logdb_log_db* db) +{ + logdb_rbtree_db* handle = logdb_rbtree_db_new(); + db->cb_ctx = handle; +} + +void logdb_rbtree_append(void* ctx, logdb_bool load_phase, logdb_record *rec) +{ + logdb_record *rec_new; + /* get the rbtree struct from the context */ + logdb_rbtree_db *handle = (logdb_rbtree_db *)ctx; + UNUSED(load_phase); + + if (!handle) + return; + + /* remove record if recode mode is ERASE */ + if (rec->mode == RECORD_TYPE_ERASE) + { + rb_red_blk_node* node = RBExactQuery(handle->tree, rec->key); + if (node) + RBDelete(handle->tree, node); + return; + } + + /* copy the record, rbtree does its own mem handling */ + rec_new = logdb_record_copy(rec); + + /* insert the node */ + RBTreeInsert(handle->tree,rec_new->key,rec_new); +} + +cstring * logdb_rbtree_find(logdb_log_db* db, cstring *key) +{ + logdb_record *rec_new = 0; + logdb_rbtree_db* handle = (logdb_rbtree_db *)db->cb_ctx; + rb_red_blk_node* node = RBExactQuery(handle->tree, key); + + if (node && node->info) + rec_new = (logdb_record *)node->info; + + if (rec_new) + return rec_new->value; + + return NULL; +} + +size_t logdb_rbtree_size(logdb_log_db* db) +{ + logdb_rbtree_db* handle = (logdb_rbtree_db *)db->cb_ctx; + size_t val = rbtree_count(handle->tree); + return val; +} diff --git a/src/logdb/logdb_rec.c b/src/logdb/logdb_rec.c new file mode 100644 index 000000000..e0da0ae43 --- /dev/null +++ b/src/logdb/logdb_rec.c @@ -0,0 +1,178 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Jonas Schnelli + + 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 +#include +#include + +logdb_record* logdb_record_new() +{ + logdb_record* record; + record = calloc(1, sizeof(*record)); + record->key = cstr_new_sz(32); + record->value = cstr_new_sz(128); + record->written = false; + record->mode = RECORD_TYPE_WRITE; + return record; +} + +void logdb_record_free(logdb_record* rec) +{ + if (!rec) + return; + + cstr_free(rec->key, true); + cstr_free(rec->value, true); + rec->next = NULL; + rec->prev = NULL; + + free(rec); +} + +void logdb_record_set(logdb_record* rec, cstring *key, cstring *val) +{ + if (key == NULL) + return; + + if (rec->key) + cstr_free(rec->key, true); + + rec->key = cstr_new_cstr(key); + + if (rec->value) + { + cstr_free(rec->value, true); + rec->value = 0; + } + if (val) + { + rec->value = cstr_new_cstr(val); + rec->mode = RECORD_TYPE_WRITE; + } + else + rec->mode = RECORD_TYPE_ERASE; +} + +logdb_record* logdb_record_copy(logdb_record* b_rec) +{ + logdb_record* a_rec = logdb_record_new(); + cstr_append_cstr(a_rec->key, b_rec->key); + cstr_append_cstr(a_rec->value, b_rec->value); + a_rec->written = b_rec->written; + a_rec->mode = b_rec->mode; + return a_rec; +} + +void logdb_record_ser(logdb_record* rec, cstring *buf) +{ + ser_bytes(buf, &rec->mode, 1); + ser_varlen(buf, rec->key->len); + ser_bytes(buf, rec->key->str, rec->key->len); + + /* write value for a WRITE operation */ + if (rec->mode == RECORD_TYPE_WRITE) + { + ser_varlen(buf, rec->value->len); + ser_bytes(buf, rec->value->str, rec->value->len); + } +} + +size_t logdb_record_height(logdb_record* head) +{ + size_t cnt = 0; + logdb_record *rec_loop = head; + while (rec_loop) + { + if (rec_loop->mode == RECORD_TYPE_WRITE) + cnt++; + + rec_loop = rec_loop->prev; + } + + return cnt; +} + +cstring * logdb_record_find_desc(logdb_record* head, cstring *key) +{ + cstring *found_value = NULL; + cstring *keycstr; + logdb_record *rec; + + if (key == NULL) + return NULL; + + rec = head; + while (rec) + { + if (cstr_equal(rec->key, key)) + { + /* found */ + found_value = rec->value; + + /* found, but deleted */ + if (rec->mode == RECORD_TYPE_ERASE) + found_value = NULL; + + break; + } + rec = rec->prev; + } + return found_value; +} + +logdb_record * logdb_record_rm_desc(logdb_record *usehead, cstring *key) +{ + /* remove old records with same key */ + logdb_record *rec_loop = usehead; + logdb_record *rec_head = usehead; + while (rec_loop) + { + logdb_record *prev_rec = rec_loop->prev; + if (cstr_equal(rec_loop->key, key)) + { + /* remove from linked list */ + if (rec_loop->prev) + rec_loop->prev->next = rec_loop->next; + + if (rec_loop->next && rec_loop->next->prev) + rec_loop->next->prev = rec_loop->prev; + + /* if we are going to delete the head, report new head */ + if (rec_loop == usehead) + rec_head = rec_loop->prev; + + logdb_record_free(rec_loop); + } + + rec_loop = prev_rec; + } + return rec_head; +} diff --git a/src/logdb/red_black_tree.c b/src/logdb/red_black_tree.c new file mode 100644 index 000000000..5af6015fb --- /dev/null +++ b/src/logdb/red_black_tree.c @@ -0,0 +1,646 @@ +#include +#include +#include + + +/***********************************************************************/ +/* FUNCTION: RBTreeCreate */ +/**/ +/* INPUTS: All the inputs are names of functions. CompFunc takes to */ +/* void pointers to keys and returns 1 if the first arguement is */ +/* "greater than" the second. DestFunc takes a pointer to a key and */ +/* destroys it in the appropriate manner when the node containing that */ +/* key is deleted. info_destroy_callback is similiar to DestFunc except it */ +/* recieves a pointer to the info of a node and destroys it. */ +/* PrintFunc recieves a pointer to the key of a node and prints it. */ +/* PrintInfo recieves a pointer to the info of a node and prints it. */ +/* If RBTreePrint is never called the print functions don't have to be */ +/* defined and NullFunction can be used. */ +/**/ +/* OUTPUT: This function returns a pointer to the newly created */ +/* red-black tree. */ +/**/ +/* Modifies Input: none */ +/***********************************************************************/ + +rb_red_blk_tree* RBTreeCreate( int (*CompFunc) (const void*,const void*), + void (*destroy_key_callback) (void*), + void (*info_destroy_callback) (void*), + void (*PrintFunc) (const void*), + void (*PrintInfo)(void*)) { + rb_red_blk_tree* newTree; + rb_red_blk_node* temp; + + newTree=(rb_red_blk_tree*) safe_malloc(sizeof(rb_red_blk_tree)); + newTree->Compare= CompFunc; + newTree->destroy_key_callback= destroy_key_callback; + newTree->PrintKey= PrintFunc; + newTree->PrintInfo= PrintInfo; + newTree->info_destroy_callback = info_destroy_callback; + newTree->it = NULL; + + /* see the comment in the rb_red_blk_tree structure in red_black_tree.h */ + /* for information on nil and root */ + temp=newTree->nil= (rb_red_blk_node*) safe_malloc(sizeof(rb_red_blk_node)); + temp->parent=temp->left=temp->right=temp; + temp->red=0; + temp->key=0; + temp=newTree->root= (rb_red_blk_node*) safe_malloc(sizeof(rb_red_blk_node)); + temp->parent=temp->left=temp->right=newTree->nil; + temp->key=0; + temp->red=0; + return(newTree); +} + +/***********************************************************************/ +/* FUNCTION: LeftRotate */ +/**/ +/* INPUTS: This takes a tree so that it can access the appropriate */ +/* root and nil pointers, and the node to rotate on. */ +/**/ +/* OUTPUT: None */ +/**/ +/* Modifies Input: tree, x */ +/**/ +/* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */ +/* Cormen, Leiserson, Rivest (Chapter 14). Basically this */ +/* makes the parent of x be to the left of x, x the parent of */ +/* its parent before the rotation and fixes other pointers */ +/* accordingly. */ +/***********************************************************************/ + +void LeftRotate(rb_red_blk_tree* tree, rb_red_blk_node* x) { + rb_red_blk_node* y; + rb_red_blk_node* nil=tree->nil; + + /* I originally wrote this function to use the sentinel for */ + /* nil to avoid checking for nil. However this introduces a */ + /* very subtle bug because sometimes this function modifies */ + /* the parent pointer of nil. This can be a problem if a */ + /* function which calls LeftRotate also uses the nil sentinel */ + /* and expects the nil sentinel's parent pointer to be unchanged */ + /* after calling this function. For example, when RBDeleteFixUP */ + /* calls LeftRotate it expects the parent pointer of nil to be */ + /* unchanged. */ + + y=x->right; + x->right=y->left; + + if (y->left != nil) y->left->parent=x; /* used to use sentinel here */ + /* and do an unconditional assignment instead of testing for nil */ + + y->parent=x->parent; + + /* instead of checking if x->parent is the root as in the book, we */ + /* count on the root sentinel to implicitly take care of this case */ + if( x == x->parent->left) { + x->parent->left=y; + } else { + x->parent->right=y; + } + y->left=x; + x->parent=y; +} + + +/***********************************************************************/ +/* FUNCTION: RighttRotate */ +/**/ +/* INPUTS: This takes a tree so that it can access the appropriate */ +/* root and nil pointers, and the node to rotate on. */ +/**/ +/* OUTPUT: None */ +/**/ +/* Modifies Input?: tree, y */ +/**/ +/* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */ +/* Cormen, Leiserson, Rivest (Chapter 14). Basically this */ +/* makes the parent of x be to the left of x, x the parent of */ +/* its parent before the rotation and fixes other pointers */ +/* accordingly. */ +/***********************************************************************/ + +void RightRotate(rb_red_blk_tree* tree, rb_red_blk_node* y) { + rb_red_blk_node* x; + rb_red_blk_node* nil=tree->nil; + + /* I originally wrote this function to use the sentinel for */ + /* nil to avoid checking for nil. However this introduces a */ + /* very subtle bug because sometimes this function modifies */ + /* the parent pointer of nil. This can be a problem if a */ + /* function which calls LeftRotate also uses the nil sentinel */ + /* and expects the nil sentinel's parent pointer to be unchanged */ + /* after calling this function. For example, when RBDeleteFixUP */ + /* calls LeftRotate it expects the parent pointer of nil to be */ + /* unchanged. */ + + x=y->left; + y->left=x->right; + + if (nil != x->right) x->right->parent=y; /*used to use sentinel here */ + /* and do an unconditional assignment instead of testing for nil */ + + /* instead of checking if x->parent is the root as in the book, we */ + /* count on the root sentinel to implicitly take care of this case */ + x->parent=y->parent; + if( y == y->parent->left) { + y->parent->left=x; + } else { + y->parent->right=x; + } + x->right=y; + y->parent=x; +} + +/***********************************************************************/ +/* FUNCTION: TreeInsertHelp */ +/**/ +/* INPUTS: tree is the tree to insert into and z is the node to insert */ +/**/ +/* OUTPUT: none */ +/**/ +/* Modifies Input: tree, z */ +/**/ +/* EFFECTS: Inserts z into the tree as if it were a regular binary tree */ +/* using the algorithm described in _Introduction_To_Algorithms_ */ +/* by Cormen et al. This funciton is only intended to be called */ +/* by the RBTreeInsert function and not by the user */ +/***********************************************************************/ + +void TreeInsertHelp(rb_red_blk_tree* tree, rb_red_blk_node* z) { + /* This function should only be called by InsertRBTree (see above) */ + rb_red_blk_node* x; + rb_red_blk_node* y; + rb_red_blk_node* nil=tree->nil; + + z->left=z->right=nil; + y=tree->root; + x=tree->root->left; + while( x != nil) { + y=x; + if (1 == tree->Compare(x->key,z->key)) { /* x.key > z.key */ + x=x->left; + } else { /* x,key <= z.key */ + x=x->right; + } + } + z->parent=y; + if ( (y == tree->root) || + (1 == tree->Compare(y->key,z->key))) { /* y.key > z.key */ + y->left=z; + } else { + y->right=z; + } +} + +/* Before calling Insert RBTree the node x should have its key set */ + +/***********************************************************************/ +/* FUNCTION: RBTreeInsert */ +/**/ +/* INPUTS: tree is the red-black tree to insert a node which has a key */ +/* pointed to by key and info pointed to by info. */ +/**/ +/* OUTPUT: This function returns a pointer to the newly inserted node */ +/* which is guarunteed to be valid until this node is deleted. */ +/* What this means is if another data structure stores this */ +/* pointer then the tree does not need to be searched when this */ +/* is to be deleted. */ +/**/ +/* Modifies Input: tree */ +/**/ +/* EFFECTS: Creates a node node which contains the appropriate key and */ +/* info pointers and inserts it into the tree. */ +/***********************************************************************/ + +rb_red_blk_node * RBTreeInsert(rb_red_blk_tree* tree, void* key, void* info) { + rb_red_blk_node * y; + rb_red_blk_node * x; + rb_red_blk_node * newNode; + + x=(rb_red_blk_node*) safe_malloc(sizeof(rb_red_blk_node)); + x->key=key; + x->info=info; + + TreeInsertHelp(tree,x); + newNode=x; + x->red=1; + while(x->parent->red) { /* use sentinel instead of checking for root */ + if (x->parent == x->parent->parent->left) { + y=x->parent->parent->right; + if (y->red) { + x->parent->red=0; + y->red=0; + x->parent->parent->red=1; + x=x->parent->parent; + } else { + if (x == x->parent->right) { + x=x->parent; + LeftRotate(tree,x); + } + x->parent->red=0; + x->parent->parent->red=1; + RightRotate(tree,x->parent->parent); + } + } else { /* case for x->parent == x->parent->parent->right */ + y=x->parent->parent->left; + if (y->red) { + x->parent->red=0; + y->red=0; + x->parent->parent->red=1; + x=x->parent->parent; + } else { + if (x == x->parent->left) { + x=x->parent; + RightRotate(tree,x); + } + x->parent->red=0; + x->parent->parent->red=1; + LeftRotate(tree,x->parent->parent); + } + } + } + tree->root->left->red=0; + return(newNode); +} + +/***********************************************************************/ +/* FUNCTION: TreeSuccessor */ +/**/ +/* INPUTS: tree is the tree in question, and x is the node we want the */ +/* the successor of. */ +/**/ +/* OUTPUT: This function returns the successor of x or NULL if no */ +/* successor exists. */ +/**/ +/* Modifies Input: none */ +/**/ +/* Note: uses the algorithm in _Introduction_To_Algorithms_ */ +/***********************************************************************/ + +rb_red_blk_node* TreeSuccessor(rb_red_blk_tree* tree,rb_red_blk_node* x) { + rb_red_blk_node* y; + rb_red_blk_node* nil=tree->nil; + rb_red_blk_node* root=tree->root; + + if (nil != (y = x->right)) { /* assignment to y is intentional */ + while(y->left != nil) { /* returns the minium of the right subtree of x */ + y=y->left; + } + return(y); + } else { + y=x->parent; + while(x == y->right) { /* sentinel used instead of checking for nil */ + x=y; + y=y->parent; + } + if (y == root) return(nil); + return(y); + } +} + +/***********************************************************************/ +/* FUNCTION: Treepredecessor */ +/**/ +/* INPUTS: tree is the tree in question, and x is the node we want the */ +/* the predecessor of. */ +/**/ +/* OUTPUT: This function returns the predecessor of x or NULL if no */ +/* predecessor exists. */ +/**/ +/* Modifies Input: none */ +/**/ +/* Note: uses the algorithm in _Introduction_To_Algorithms_ */ +/***********************************************************************/ + +rb_red_blk_node* TreePredecessor(rb_red_blk_tree* tree, rb_red_blk_node* x) { + rb_red_blk_node* y; + rb_red_blk_node* nil=tree->nil; + rb_red_blk_node* root=tree->root; + + if (nil != (y = x->left)) { /* assignment to y is intentional */ + while(y->right != nil) { /* returns the maximum of the left subtree of x */ + y=y->right; + } + return(y); + } else { + y=x->parent; + while(x == y->left) { + if (y == root) return(nil); + x=y; + y=y->parent; + } + return(y); + } +} + +/***********************************************************************/ +/* FUNCTION: InorderTreePrint */ +/**/ +/* INPUTS: tree is the tree to print and x is the current inorder node */ +/**/ +/* OUTPUT: none */ +/**/ +/* EFFECTS: This function recursively prints the nodes of the tree */ +/* inorder using the PrintKey and PrintInfo functions. */ +/**/ +/* Modifies Input: none */ +/**/ +/* Note: This function should only be called from RBTreePrint */ +/***********************************************************************/ + +void InorderTreePrint(rb_red_blk_tree* tree, rb_red_blk_node* x) { + rb_red_blk_node* nil=tree->nil; + rb_red_blk_node* root=tree->root; + if (x != tree->nil) { + InorderTreePrint(tree,x->left); + printf("info="); + tree->PrintInfo(x->info); + printf(" key="); + tree->PrintKey(x->key); + printf(" l->key="); + if( x->left == nil) printf("NULL"); else tree->PrintKey(x->left->key); + printf(" r->key="); + if( x->right == nil) printf("NULL"); else tree->PrintKey(x->right->key); + printf(" p->key="); + if( x->parent == root) printf("NULL"); else tree->PrintKey(x->parent->key); + printf(" red=%i\n",x->red); + InorderTreePrint(tree,x->right); + } +} + + +/***********************************************************************/ +/* FUNCTION: TreeDestHelper */ +/**/ +/* INPUTS: tree is the tree to destroy and x is the current node */ +/**/ +/* OUTPUT: none */ +/**/ +/* EFFECTS: This function recursively destroys the nodes of the tree */ +/* postorder using the destroy_key_callback and */ +/* info_destroy_callback functions. */ +/**/ +/* Modifies Input: tree, x */ +/**/ +/* Note: This function should only be called by RBTreeDestroy */ +/***********************************************************************/ + +void TreeDestHelper(rb_red_blk_tree* tree, rb_red_blk_node* x) { + rb_red_blk_node* nil=tree->nil; + if (x != nil) { + TreeDestHelper(tree,x->left); + TreeDestHelper(tree,x->right); + tree->destroy_key_callback(x->key); + tree->info_destroy_callback(x->info); + free(x); + } +} + + +/***********************************************************************/ +/* FUNCTION: RBTreeDestroy */ +/**/ +/* INPUTS: tree is the tree to destroy */ +/**/ +/* OUTPUT: none */ +/**/ +/* EFFECT: Destroys the key and frees memory */ +/**/ +/* Modifies Input: tree */ +/**/ +/***********************************************************************/ + +void RBTreeDestroy(rb_red_blk_tree* tree) { + TreeDestHelper(tree,tree->root->left); + free(tree->root); + free(tree->nil); + free(tree); +} + + +/***********************************************************************/ +/* FUNCTION: RBTreePrint */ +/**/ +/* INPUTS: tree is the tree to print */ +/**/ +/* OUTPUT: none */ +/**/ +/* EFFECT: This function recursively prints the nodes of the tree */ +/* inorder using the PrintKey and PrintInfo functions. */ +/**/ +/* Modifies Input: none */ +/**/ +/***********************************************************************/ + +void RBTreePrint(rb_red_blk_tree* tree) { + InorderTreePrint(tree,tree->root->left); +} + + +/***********************************************************************/ +/* FUNCTION: RBExactQuery */ +/**/ +/* INPUTS: tree is the tree to print and q is a pointer to the key */ +/* we are searching for */ +/**/ +/* OUTPUT: returns the a node with key equal to q. If there are */ +/* multiple nodes with key equal to q this function returns */ +/* the one highest in the tree */ +/**/ +/* Modifies Input: none */ +/**/ +/***********************************************************************/ + +rb_red_blk_node* RBExactQuery(rb_red_blk_tree* tree, void* q) { + rb_red_blk_node* x=tree->root->left; + rb_red_blk_node* nil=tree->nil; + int compVal; + if (x == nil) return(0); + compVal=tree->Compare(x->key,(int*) q); + while(0 != compVal) {/*assignemnt*/ + if (1 == compVal) { /* x->key > q */ + x=x->left; + } else { + x=x->right; + } + if ( x == nil) return(0); + compVal=tree->Compare(x->key,(int*) q); + } + return(x); +} + + +/***********************************************************************/ +/* FUNCTION: RBDeleteFixUp */ +/**/ +/* INPUTS: tree is the tree to fix and x is the child of the spliced */ +/* out node in RBTreeDelete. */ +/**/ +/* OUTPUT: none */ +/**/ +/* EFFECT: Performs rotations and changes colors to restore red-black */ +/* properties after a node is deleted */ +/**/ +/* Modifies Input: tree, x */ +/**/ +/* The algorithm from this function is from _Introduction_To_Algorithms_ */ +/***********************************************************************/ + +void RBDeleteFixUp(rb_red_blk_tree* tree, rb_red_blk_node* x) { + rb_red_blk_node* root=tree->root->left; + rb_red_blk_node* w; + + while( (!x->red) && (root != x)) { + if (x == x->parent->left) { + w=x->parent->right; + if (w->red) { + w->red=0; + x->parent->red=1; + LeftRotate(tree,x->parent); + w=x->parent->right; + } + if ( (!w->right->red) && (!w->left->red) ) { + w->red=1; + x=x->parent; + } else { + if (!w->right->red) { + w->left->red=0; + w->red=1; + RightRotate(tree,w); + w=x->parent->right; + } + w->red=x->parent->red; + x->parent->red=0; + w->right->red=0; + LeftRotate(tree,x->parent); + x=root; /* this is to exit while loop */ + } + } else { /* the code below is has left and right switched from above */ + w=x->parent->left; + if (w->red) { + w->red=0; + x->parent->red=1; + RightRotate(tree,x->parent); + w=x->parent->left; + } + if ( (!w->right->red) && (!w->left->red) ) { + w->red=1; + x=x->parent; + } else { + if (!w->left->red) { + w->right->red=0; + w->red=1; + LeftRotate(tree,w); + w=x->parent->left; + } + w->red=x->parent->red; + x->parent->red=0; + w->left->red=0; + RightRotate(tree,x->parent); + x=root; /* this is to exit while loop */ + } + } + } + x->red=0; +} + + +/***********************************************************************/ +/* FUNCTION: RBDelete */ +/**/ +/* INPUTS: tree is the tree to delete node z from */ +/**/ +/* OUTPUT: none */ +/**/ +/* EFFECT: Deletes z from tree and frees the key and info of z */ +/* using DestoryKey and DestoryInfo. Then calls */ +/* RBDeleteFixUp to restore red-black properties */ +/**/ +/* Modifies Input: tree, z */ +/**/ +/* The algorithm from this function is from _Introduction_To_Algorithms_ */ +/***********************************************************************/ + +void RBDelete(rb_red_blk_tree* tree, rb_red_blk_node* z){ + rb_red_blk_node* y; + rb_red_blk_node* x; + rb_red_blk_node* nil=tree->nil; + rb_red_blk_node* root=tree->root; + + y= ((z->left == nil) || (z->right == nil)) ? z : TreeSuccessor(tree,z); + x= (y->left == nil) ? y->right : y->left; + if (root == (x->parent = y->parent)) { /* assignment of y->p to x->p is intentional */ + root->left=x; + } else { + if (y == y->parent->left) { + y->parent->left=x; + } else { + y->parent->right=x; + } + } + if (y != z) { /* y should not be nil in this case */ + /* y is the node to splice out and x is its child */ + + if (!(y->red)) RBDeleteFixUp(tree,x); + + tree->destroy_key_callback(z->key); + tree->info_destroy_callback(z->info); + y->left=z->left; + y->right=z->right; + y->parent=z->parent; + y->red=z->red; + z->left->parent=z->right->parent=y; + if (z == z->parent->left) { + z->parent->left=y; + } else { + z->parent->right=y; + } + free(z); + } else { + tree->destroy_key_callback(y->key); + tree->info_destroy_callback(y->info); + if (!(y->red)) RBDeleteFixUp(tree,x); + free(y); + } +} + +size_t rbtree_count_intern(rb_red_blk_tree* tree, rb_red_blk_node* x) { + size_t cnt = 0; + if (x != tree->nil) { + cnt++; + cnt += rbtree_count_intern(tree,x->left); + cnt += rbtree_count_intern(tree,x->right); + } + return cnt; +} + +size_t rbtree_count(rb_red_blk_tree* tree) { + return rbtree_count_intern(tree, tree->root->left); +} + +void rbtree_it_reset(rb_red_blk_tree* tree) +{ + tree->it = NULL; +} + +rb_red_blk_node* rbtree_enumerate_next(rb_red_blk_tree* tree) +{ + rb_red_blk_node* nil=tree->nil; + + if (tree->it == NULL) + tree->it = tree->root; + + if (tree->it != nil) + { + tree->it=TreePredecessor(tree,tree->it); + } + if (tree->it == nil) + { + rbtree_it_reset(tree); + /* end enumeration */ + return NULL; + } + + return tree->it; +} diff --git a/src/logdb/test/logdb_tests.c b/src/logdb/test/logdb_tests.c new file mode 100644 index 000000000..b65b4a7fb --- /dev/null +++ b/src/logdb/test/logdb_tests.c @@ -0,0 +1,484 @@ +/********************************************************************** + * Copyright (c) 2015 Jonas Schnelli * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "../../../test/utest.h" + +#include +#include + + +#include "logdb_tests_sample.h" + +static const char *dbtmpfile = "/tmp/dummy"; + +static const char *key1str = "ALorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; + +static const char *value1str = "BLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; + +void test_logdb(logdb_log_db* (*new_func)()) +{ + logdb_log_db *db; + enum logdb_error error = 0; + cstring *key;// key= {"key0", 4}; + cstring *value;// = {"val0", 4}; + cstring *key1; + cstring *value1; + cstring *outtest; + cstring *value_test; + unsigned char testbin[4] = {0x00, 0x10, 0x20, 0x30}; + cstring *value0;// = {"dumb", 4}; + cstring *key2;// = {"pkey", 4}; + cstring *value2; + cstring *smp_value; + cstring *smp_key; + uint8_t txbin[10240]; + uint8_t txbin_rev[10240]; + char hexrev[98]; + int outlenrev; + long fsize; + uint8_t *buf; + uint8_t *wrk_buf; + FILE *f; + unsigned int i; + char bufs[300][65]; + rb_red_blk_node *nodetest; + unsigned int cnt = 0; + logdb_record* rec; + + key = cstr_new("key0"); + value = cstr_new("val0"); + + value0 = cstr_new("dumb"); + value1 = cstr_new_sz(10); + value2 = cstr_new_sz(10); + key1 = cstr_new_sz(10); + key2 = cstr_new("key2"); + + cstr_append_buf(value2, testbin, sizeof(testbin)); + cstr_append_buf(value2, testbin, sizeof(testbin)); + cstr_append_buf(key1, key1str, strlen(key1str)); + cstr_append_buf(value1, value1str, strlen(value1str)); + + unlink(dbtmpfile); + db = new_func(); + u_assert_int_eq(logdb_load(db, "file_that_should_not_exists.dat", false, NULL), false); + u_assert_int_eq(logdb_load(db, dbtmpfile, true, NULL), true); + + logdb_append(db, NULL, key, value); + logdb_append(db, NULL, key1, value1); + + u_assert_int_eq(logdb_cache_size(db), 2); + outtest = logdb_find_cache(db, key1); + u_assert_int_eq(strcmp(outtest->str, value1str),0); + logdb_flush(db); + logdb_free(db); + + db = new_func(); + u_assert_int_eq(logdb_load(db, dbtmpfile, false, NULL), true); + u_assert_int_eq(logdb_count_keys(db), 2); + + value_test = logdb_find(db, key1); + u_assert_int_eq(strcmp(value_test->str, value1str), 0); + value_test = logdb_find(db, key); + u_assert_int_eq(memcmp(value_test->str, value->str, value->len), 0); + logdb_free(db); + + db = new_func(); + u_assert_int_eq(logdb_load(db, dbtmpfile, false, NULL), true); + + + + logdb_append(db, NULL, key2, value2); + logdb_flush(db); + logdb_free(db); + + /* check if private key is available */ + db = new_func(); + u_assert_int_eq(logdb_load(db, dbtmpfile, false, NULL), true); + + value_test = logdb_find(db, key2); + u_assert_int_eq(memcmp(value_test->str, value2->str, value2->len), 0); + value_test = logdb_find(db, key); + u_assert_int_eq(memcmp(value_test->str, value->str, value->len), 0); + + /* delete a record */ + logdb_delete(db, NULL, key2); + logdb_flush(db); + logdb_free(db); + + /* find and check the deleted record */ + db = new_func(); + u_assert_int_eq(logdb_load(db, dbtmpfile, false, NULL), true); + + value_test = logdb_find(db, key); + u_assert_int_eq(memcmp(value_test->str, value->str, value->len), 0); + + value_test = logdb_find(db, key2); + u_assert_is_null(value_test); + + /* overwrite a key */ + logdb_append(db, NULL, key, value0); + + value_test = logdb_find(db, key); + u_assert_int_eq(memcmp(value_test->str, value0->str, value0->len), 0); + + logdb_flush(db); + logdb_free(db); + + db = new_func(); + u_assert_int_eq(logdb_load(db, dbtmpfile, false, NULL), true); + value_test = logdb_find(db, key); + u_assert_int_eq(memcmp(value_test->str, value0->str, value0->len), 0); + + logdb_flush(db); + logdb_free(db); + + + + + /* simulate corruption */ + f = fopen(dbtmpfile, "rb"); + fseek(f, 0, SEEK_END); + fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + buf = malloc(fsize + 1); + fread(buf, fsize, 1, f); + fclose(f); + + /* ---------------------------------------------------- */ + wrk_buf = safe_malloc(fsize + 1); + memcpy(wrk_buf, buf, fsize); + wrk_buf[0] = 0x88; /* wrong header */ + + unlink(dbtmpfile); + f = fopen(dbtmpfile, "wb"); + fwrite(wrk_buf, 1, fsize, f); + fclose(f); + + db = new_func(); + u_assert_int_eq(logdb_load(db, dbtmpfile, false, &error), false); + u_assert_int_eq(error, LOGDB_ERROR_WRONG_FILE_FORMAT); + logdb_free(db); + + /* ---------------------------------------------------- */ + memcpy(wrk_buf, buf, fsize); + wrk_buf[66] = 0x00; /* wrong checksum hash */ + + unlink(dbtmpfile); + f = fopen(dbtmpfile, "wb"); + fwrite(wrk_buf, 1, fsize, f); + fclose(f); + + db = new_func(); + u_assert_int_eq(logdb_load(db, dbtmpfile, false, &error), false); + u_assert_int_eq(error, LOGDB_ERROR_CHECKSUM); + logdb_free(db); + + /* ---------------------------------------------------- */ + memcpy(wrk_buf, buf, fsize); + wrk_buf[42] = 0xFF; /* wrong value length */ + + unlink(dbtmpfile); + f = fopen(dbtmpfile, "wb"); + fwrite(wrk_buf, 1, fsize, f); + fclose(f); + + db = new_func(); + u_assert_int_eq(logdb_load(db, dbtmpfile, false, &error), false); + u_assert_int_eq(error, LOGDB_ERROR_DATASTREAM_ERROR); + logdb_free(db); + + free(buf); + free(wrk_buf); + + + /* --- large db test */ + unlink(dbtmpfile); + + db = new_func(); + u_assert_int_eq(logdb_load(db, dbtmpfile, true, NULL), true); + + smp_key = cstr_new_sz(100); + smp_value = cstr_new_sz(100); + for (i = 0; i < (sizeof(sampledata) / sizeof(sampledata[0])); i++) { + const struct txtest *tx = &sampledata[i]; + + uint8_t hashbin[sizeof(tx->txhash) / 2]; + int outlen = sizeof(tx->txhash) / 2; + utils_hex_to_bin(tx->txhash, hashbin, strlen(tx->txhash), &outlen); + + cstr_erase(smp_key, 0, smp_key->len); + cstr_append_buf(smp_key, hashbin, outlen); + + outlen = sizeof(tx->hextx) / 2; + utils_hex_to_bin(tx->hextx, txbin, strlen(tx->hextx), &outlen); + + cstr_erase(smp_value, 0, smp_value->len); + cstr_append_buf(smp_value, txbin, outlen); + + logdb_append(db, NULL, smp_key, smp_value); + } + + u_assert_int_eq(logdb_count_keys(db), (sizeof(sampledata) / sizeof(sampledata[0]))); + + /* check all records */ + for (i = 0; i < (sizeof(sampledata) / sizeof(sampledata[0])); i++) { + const struct txtest *tx = &sampledata[i]; + + uint8_t hashbin[sizeof(tx->txhash) / 2]; + int outlen = sizeof(tx->txhash) / 2; + utils_hex_to_bin(tx->txhash, hashbin, strlen(tx->txhash), &outlen); + + cstr_erase(smp_key, 0, smp_key->len); + cstr_append_buf(smp_key, hashbin, outlen); + outtest = logdb_find(db, smp_key); + + outlen = sizeof(tx->hextx) / 2; + utils_hex_to_bin(tx->hextx, txbin, strlen(tx->hextx), &outlen); + + u_assert_int_eq(outlen, outtest->len); + } + + logdb_flush(db); + logdb_free(db); + + db = new_func(); + error = 0; + u_assert_int_eq(logdb_load(db, dbtmpfile, false, &error), true); + u_assert_int_eq(logdb_count_keys(db), (sizeof(sampledata) / sizeof(sampledata[0]))); + + /* check all records */ + for (i = 0; i < (sizeof(sampledata) / sizeof(sampledata[0])); i++) { + const struct txtest *tx = &sampledata[i]; + + uint8_t hashbin[sizeof(tx->txhash) / 2]; + int outlen = sizeof(tx->txhash) / 2; + utils_hex_to_bin(tx->txhash, hashbin, strlen(tx->txhash), &outlen); + + memcpy(hexrev, tx->txhash, sizeof(tx->txhash)); + utils_reverse_hex(hexrev, strlen(tx->txhash)); + outlenrev = sizeof(tx->txhash) / 2; + utils_hex_to_bin(hexrev, txbin_rev, strlen(hexrev), &outlenrev); + + cstr_erase(smp_key, 0, smp_key->len); + cstr_append_buf(smp_key, hashbin, outlen); + outtest = logdb_find(db, smp_key); + + outlen = strlen(tx->hextx) / 2; + utils_hex_to_bin(tx->hextx, txbin, strlen(tx->hextx), &outlen); + u_assert_int_eq(outlen, outtest->len); + + /* hash transaction data and check hashes */ + if (strlen(tx->hextx) > 2) + { + uint8_t tx_hash_check[SHA256_DIGEST_LENGTH]; + sha256_Raw(txbin, outlen, tx_hash_check); + sha256_Raw(tx_hash_check, 32, tx_hash_check); + u_assert_int_eq(memcmp(tx_hash_check, txbin_rev, SHA256_DIGEST_LENGTH), 0); + } + + } + + /* check all records */ + for (i = 0; i < (sizeof(sampledata) / sizeof(sampledata[0])); i++) { + const struct txtest *tx = &sampledata[i]; + + uint8_t hashbin[sizeof(tx->txhash) / 2]; + int outlen = sizeof(tx->txhash) / 2; + utils_hex_to_bin(tx->txhash, hashbin, strlen(tx->txhash), &outlen); + + cstr_erase(smp_key, 0, smp_key->len); + cstr_append_buf(smp_key, hashbin, outlen); + logdb_delete(db, NULL, smp_key); + } + u_assert_int_eq(logdb_count_keys(db), 0); + + logdb_flush(db); + logdb_free(db); + + db = new_func(); + error = 0; + u_assert_int_eq(logdb_load(db, dbtmpfile, false, &error), true); + u_assert_int_eq(error, LOGDB_SUCCESS); + u_assert_int_eq(logdb_count_keys(db), 0); + + for (i = 0; i < (sizeof(sampledata) / sizeof(sampledata[0])); i++) { + const struct txtest *tx = &sampledata[i]; + + uint8_t hashbin[sizeof(tx->txhash) / 2]; + int outlen = sizeof(tx->txhash) / 2; + utils_hex_to_bin(tx->txhash, hashbin, strlen(tx->txhash), &outlen); + + cstr_erase(smp_key, 0, smp_key->len); + cstr_append_buf(smp_key, hashbin, outlen); + + outlen = sizeof(tx->hextx) / 2; + utils_hex_to_bin(tx->hextx, txbin, strlen(tx->hextx), &outlen); + + cstr_erase(smp_value, 0, smp_value->len); + cstr_append_buf(smp_value, txbin, outlen); + + logdb_append(db, NULL, smp_key, smp_value); + } + + logdb_flush(db); + logdb_free(db); + + db = new_func(); + error = 0; + u_assert_int_eq(logdb_load(db, dbtmpfile, false, &error), true); + u_assert_int_eq(error, LOGDB_SUCCESS); + u_assert_int_eq(logdb_count_keys(db), (sizeof(sampledata) / sizeof(sampledata[0]))); + + logdb_flush(db); + logdb_free(db); + + db = new_func(); + error = 0; + u_assert_int_eq(logdb_load(db, dbtmpfile, false, &error), true); + u_assert_int_eq(error, LOGDB_SUCCESS); + u_assert_int_eq(logdb_count_keys(db), (sizeof(sampledata) / sizeof(sampledata[0]))); + + if(new_func == logdb_rbtree_new) + { + logdb_rbtree_db* handle = (logdb_rbtree_db *)db->cb_ctx; + size_t size = rbtree_count(handle->tree); + + nodetest = NULL; + while ((nodetest = rbtree_enumerate_next(handle->tree))) + { + rec = (logdb_record *)nodetest->info; + utils_bin_to_hex((unsigned char *)rec->key->str, rec->key->len, bufs[cnt]); + + for(i = 0; i < cnt; i++) + { + u_assert_int_eq(strcmp(bufs[i], bufs[cnt]) != 0, 1); + } + cnt++; + } + u_assert_int_eq(size, cnt); + } + + for (i = 0; i < (sizeof(sampledata) / sizeof(sampledata[0])); i++) { + const struct txtest *tx = &sampledata[i]; + + uint8_t hashbin[sizeof(tx->txhash) / 2]; + int outlen = sizeof(tx->txhash) / 2; + utils_hex_to_bin(tx->txhash, hashbin, strlen(tx->txhash), &outlen); + + cstr_erase(smp_key, 0, smp_key->len); + cstr_append_buf(smp_key, hashbin, outlen); + + outlen = sizeof(tx->hextx) / 2; + utils_hex_to_bin(tx->hextx, txbin, strlen(tx->hextx), &outlen); + + cstr_erase(smp_value, 0, smp_value->len); + cstr_append_buf(smp_value, txbin, outlen); + + logdb_append(db, NULL, smp_key, smp_value); + } + + logdb_flush(db); + logdb_free(db); + + /* test switch mem mapper after initialitaion. */ + db = logdb_new(); + logdb_set_memmapper(db, &logdb_rbtree_mapper, NULL); + logdb_flush(db); + logdb_free(db); + + + unlink(dbtmpfile); + + db = new_func(); + u_assert_int_eq(logdb_load(db, dbtmpfile, true, NULL), true); + + // create transaction, don't store + logdb_txn* txn = logdb_txn_new(); + logdb_append(db, txn, key, value); + logdb_append(db, txn, key1, value1); + u_assert_int_eq(logdb_cache_size(db), 0); + logdb_txn_free(txn); + + logdb_flush(db); + logdb_free(db); + + db = new_func(); + u_assert_int_eq(logdb_load(db, dbtmpfile, false, NULL), true); + // db should still be empty + u_assert_int_eq(logdb_count_keys(db), 0); + + // create transaction, store it this time + txn = logdb_txn_new(); + logdb_append(db, txn, key, value); + logdb_append(db, txn, key1, value1); + logdb_txn_commit(db, txn); + u_assert_int_eq(logdb_cache_size(db), 2); + logdb_txn_free(txn); + + logdb_flush(db); + logdb_free(db); + + db = new_func(); + u_assert_int_eq(logdb_load(db, dbtmpfile, false, NULL), true); + // now we should have the two persisted items from the txn + u_assert_int_eq(logdb_count_keys(db), 2); + logdb_flush(db); + logdb_free(db); + + cstr_free(key, true); + cstr_free(value, true); + cstr_free(value0, true); + cstr_free(value1, true); + cstr_free(value2, true); + cstr_free(key1, true); + cstr_free(key2, true); + cstr_free(smp_key, true); + cstr_free(smp_value, true); +} + +void test_logdb_rbtree() +{ + test_logdb(logdb_rbtree_new); +} + +void test_logdb_memdb() +{ + test_logdb(logdb_new); +} + +void test_examples() +{ + cstring *value; + cstring *key; + logdb_log_db *db; + enum logdb_error error = 0; + int create_database = 1; + + /* create a new database object */ + db = logdb_new(); + + /* create a database file (will overwrite existing) */ + logdb_load(db, "/tmp/test.logdb", create_database, &error); + + /* append a record */ + value = cstr_new("testkey"); + key = cstr_new("somevalue"); + /* second parameter NULL means we don't use a transaction */ + logdb_append(db, NULL, key, value); + + /* flush database (write its state to disk) */ + logdb_flush(db); + + /* cleanup */ + logdb_free(db); + cstr_free(key, true); + cstr_free(value, true); +} diff --git a/src/logdb/test/logdb_tests_sample.h b/src/logdb/test/logdb_tests_sample.h new file mode 100644 index 000000000..e9fddf7a9 --- /dev/null +++ b/src/logdb/test/logdb_tests_sample.h @@ -0,0 +1,171 @@ + +struct txtest { + char txhash[65]; + char hextx[1024*10]; +}; + +static const struct txtest sampledata[] = +{ + { "466a41042c04a0e8393d3d39864597f4b395c356b4dfe9899f8dbc9a337f59bc","01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6403c4210637e4b883e5bda9e7a59ee4bb99e9b1bc468ae3c311fe570bbbaadade4d0c6ae4fd009f2045e7808d8c569b1eb63ecdb802000000f09f909f0f4d696e6564206279206368656e626f000000000000000000000000000000000000000000000000c036008601bb734c95000000001976a914c825a1ecf2a6830c4401620c3a16f1995057c2ab88aca7525e3a" }, + { "0a297ae41b920be08728d9f1bcae16f26ff1b720889f9a6fb06b1e694505a8c3","0100000001390032c3d2cf8d5531902e21e68ad46d6bbb2a62e98ba4e1ddb38a2bd46b3d69000000006a47304402200a0cfe5e8417feec48e23d06d956f1eedbf748c37359275553f6014796bce15d022026bea1b7c5de47349c72e2893139ebe491678eee6b4b3e40d8acd126994ae130012103ae284b75833c28fb4bc96a313d5b67a2034eb20df44618f3f750300078e49cbbfeffffff02002d3101000000001976a9142e9639b50862d710736e3371235ad9768694f66488acbdf2d261010000001976a9148003329d0169bb3decab6a902c1598aeb3ffbb4288ac95210600" }, + { "bf4808dfe849ab315f588b680a08487121eecb5ddc91c576e0c2a3d3bdff5b3d","010000000118c9e359893a1f51151dfe5290b54576d8c2c2124c5250cdf207911012be2461010000006a473044022054ceb71dea8786e5c64db398b19be1b97d7bb260848cf629d24ecf37460ff56f0220732334547d0341d9696a8a348ec4963a123fcb35875fd175edccc18a30653ca901210266d96f36fdb8f1cfd7399298df9ef9f9e735b51aa66d043d0c204dc543b0fedbfeffffff02005a6202000000001976a914931d499b89d0a423e79926417dec15754b19ee7888acb0bfabe6020000001976a914d15c23f8cc3d5acdac57f362845c4035754f8e1888acb8210600" }, + { "14a7d56e36326db3144b6b5b9cdb0062d456b2cd89be7530fce1908c84e2cfc8","0100000001bb23b9eb39266c9cb77e5db1f8d45973ef11476291314b9b8d77abdde87d98f3000000006b4830450221008dfb61e9a3d7c0ce82fb1cdd6a0793044b4db44c3c7168451d13ddb6a0a7c05302207b22d4e6aa28fd4e837a783cd2826406e40369f9afde1bb6bfe34c6bca630d67012103fe9fc0b9987f57924a4638ea14e63189b67f8617f2a1c6cc7d73dce42376658efeffffff021ad62903000000001976a9146df24eb7273fcd727fe707b1bea9b28812c30f5888ac536fd21b030000001976a914a4149062cba8e9c7c5449faaf292d294923337a388acb8210600" }, + { "832f49637b60f96850bc1f7b4ced929162daa7f33735cf8e44c2ed0e60eab178","010000000153ffcb5c74e242142bece8be63f2fe8994ab34dae5050d6563e3d63fd74a481b010000006b483045022100d7a0803bfa725810c49059b655befc4f7812b2925621d6f77bede1c3d92422d6022030589c3c19a0753ff1fbfb8dc761d027fd428477a9e595590e06f0edc9a552c701210266c737db56cca1a7dd753b36f9a56728ae0d924487adc8b840071f6dca7c4075feffffff02dd7fffb1000000001976a914b63d78645030323f24a2df230ddaea089e297a1f88ac40e7ae8c010000001976a914bfe304f1d387fca798c2cf404aa879feb246a89488acb8210600" }, + { "ac3c26bec5ee494f5088f43cef737654530b56d2aed71cd9fc5d5b9afeca1e6f","01000000018735ca6f9a7e56f3b562f57065f9fd6d3030b2f025fec277c050d99f1d636d4f010000006b483045022100bbc142218fe102ee996ce7b93a328926f051996b04c761dd56aa9354e1503b930220480c0ea99a7de372ee7efd1a5a9c8392514512cea4b7038551c27973c856fa27012102324af517f305022d93f9e06936af42499937101800a5003dceb25faf59b96534feffffff0200b4c404000000001976a914464b47d9e57026aa58033203663e6e0b348c6f2588accc19b961010000001976a9148a7ecafe4ad6da4cb07611334dddd7bd46c1cc4788aca1210600" }, + { "aecdbb829de64c4f94b0eac9200aa722a4aaceba6e31359f14e8c94b3300c55f","0100000001bcd391a6671e7e4567aca0d10e2beebb6e58232a59852f31ef673d2ab239b421000000006b483045022100ddcbba20f2cfc93d303dce776307331d99a21afe9c449e6b106528eeefd68e1702204b2edc5a7b3fcd1839e5d0c69973bd3c3c7fc0b2894ec181eb74eb6062e2e1c60121021003c0ec7dafaf61fd10713c7df93fce2d1b7a48f765c988317ead347e5984e9feffffff02005a6202000000001976a91473f3aaa743f7454caabb4341772ab97448f5245f88acc230fa75010000001976a9144636b96acd12de4c101ae3683f4e0a5b729f84d488acb8210600" }, + { "5aa7e4db42c8685450b193f5d7954aebf0abb9cd1964d4123577efb6a9337d28","0100000001e946cff3179dc829991259c9bd809ff5b2c37daf6b8a7c5b11d8779ca6b4a0a1010000006b4830450221009856f14dcf0241849b053029525953e904f10e968e38eecb8a623f9b64ea51b402204b47b47447d8e63fdf2bdac4d216415f8749b04d447cb12fbe96fd7e901be3c001210285069b92563525b7dadca1efd1b7399d1bda70afb5d00b57c45b5aafa4acf2fbfeffffff025e9e460e010000001976a9142b9fcd98381682c00832159aa3ebcab1802ea36788acf531dc00000000001976a914ed5fd0b88a279780fbdbe82a8d4057911ad8e89588acb8210600" }, + { "49e4382c81d7e1c41d20004f352d61fddd922b783dc7c275d0630f62df296b11","0100000001850952b31f5abe1b2b6ab5979eed3e70055369ab0121ebd2801b307367e1eae2010000006b48304502210084e868fc6db3d4509afda4fb05edf615c480f3df4062272424b79612b3e3f3830220474873a73f6d254ae38d747ed1af96cdeba1137c448da677c0d851fff4e2ec1a0121025efa0a1c877dcc484443025c6758b003325b228fc0f31dd6503cf8b0aa3bed71feffffff024a9fa5e6020000001976a914d253813264020d005a63d40ca63146fb8084e74188ac002d3101000000001976a9141e912671b33faa41f90864cef6d79a89df3b7d4888acb8210600" }, + { "ac510c75b70675203b075449d41f5254220b1d4ebfcb87af4a069e9b3e319d33","0100000001d4a7c755103fa46dcb581141fc562806e327209ab70711f1fab45853293df0b3030000006a473044022061b82925871405b4ef797192a41bbfedd21e9362986a72f1733a63bb59f9d3ba022071fb9879147b98cdba12ffda7caec240d6f4eda371df06fde48aba4158879deb01210295f955ee4f8015c76ebe467f1bf5b6754466623e8f11bc350f9d8879f3a2e0c4feffffff047063f905000000001976a9146735f91f1f0f34f3b8792d6c47a8d7f2967a268f88ac40e13300000000001976a9144584f350cb37f342c5bdee6053f64a63dabf85e888ac971b4a00000000001976a9141e724666c35f676c859180d3c29ed134cf9f837788acc325a716000000001976a914bd6ded677567ea4345e577df73580e13f38f2c5c88acb8210600" }, + { "a8995f822f74f6c0a962280651ed829ec8630b1ff5f0e5e23e5f4d6e67a14c04","0100000001bdd2ff07d52b055d83d3151e43cb96637f272745982d8673257e70cb6350d20701000000d90047304402205d7f1f977b2a1683543ee2aaa998ffe507c2230ab4555a1280e4a48213dfb9690220117f53f1b8666bcaeaed4c428c94e5b8bee8614fd5304626cc97930e80ff6b87014730440220268014b1d9d10c5229846dfd540e331222cace0687cc65672339c091c7b643f1022065f3a05f5f6ed466f5d2791c3b557e12d83c9de52dd6f79314f93a825cfa3e6d01475221039eaf521ef886ce641922d5be4757a59edf476226e8ce41347b97b78d43f80df12103835ae12a254ed7e77fcc0ef9d39de29959a46a723b7f494f6f329b750a9a9c4b52aeffffffff02d0f51b00000000001976a91471a5e8c399f374b55eeeaafd143ee8942026720388acd0aa03030000000017a9142cc4a6f7f8547a13653f53236397e4a5b034a7e78700000000" }, + { "406c47e5faf78a31dce1ad55771cb450c7039c76400cbc6c0ebb8bc0ac58450f","01000000015f5953ad04512d84af4a84310ff72c6e676352e13ca0c4e70645168b0009b86501000000da0047304402202e62a6cff8ee5f54430d1c2c4062def157505705d369b26423b2e6f24112053e02201d8180bfed980c8201650fb4e664d0112d900872f5902f6dd53886ab231e38be01483045022100ec2e94e3567d268872c06dd4cb6098a195195bdd632048775bd5a0141038ea120220613d462d3e4c53a4c4ccfa5a18abf38e5d05027cb4b48b396cc69a0ba1a20a5301475221038bcb748606c0629fc4fe415aac2d822a6fe1f46a427176b4ea25b80951122d5b2103835ae12a254ed7e77fcc0ef9d39de29959a46a723b7f494f6f329b750a9a9c4b52aeffffffff02d0b60000000000001976a91414eaa7749b5a157b032d4ea3c523e765cf7738a188ac73dd5f000000000017a914a849babf51f34453a87fc594f3a0ccd95d0c49278700000000" }, + { "68f334be45d03d3c4172a0d5d255c9c9e72bc62af2bc0b8dca730bd8b2c3b6ee","010000000199bf4585745675891edc33ddfcc43ca7b71f6932822ead195524a405daf296a101000000db00483045022100ef5b1c3f1b48bad55fea3f8b7471cb8674ba1423b961cb05b6549653f487185f02204f1d86c1c41d8f9a4fc809bf07a78f046feb2d5d4af82b25b60085ede1ebcab901483045022100ee758e096626337251469e8507b7f040faf8ee203d7d665e7e1f6160486469b102200847f20dbcf4cd83d7f6cf6b310c5df911261915d26ba6de0f26c584861cac020147522102f9cb2e360c588d6599e778caf7c4ab281b9a7b94623a949edb3e37367e7a6d1a2102ddf50cdef4e1ae6201f5bc5f5688abea1ab09bf4809812f7a58f1ba46ebdbed452aeffffffff0211270000000000001976a914b248c2c73e66e366952b1faf6813a56fbcc9565c88ac07cf00000000000017a914f4257616f6a076f3e49f7cb5eff377fb60c54bde8700000000" }, + { "1a1eebb8e4b19cc46d527e8311266a978cc9b43aadbf841dc406afa10d0e727d","01000000010d561e1ce922174f91b5c71c8369249fca04656fe161f2e616c3b4033b40052c000000006a4730440220719af8f20b3f206fb0584404eda85563e1da48a8271c9e1af9fea144d45bc86e022069cbb30631b422ad9d029d1d5b1e97760775006940b4e30968ee46d9ff07aea50121020e0e202fa95c665570e086c3d8ac9aa83c5c29df4250dee2ce869246af75ba4effffffff02e1005200000000001976a91465b7e859f7f40b7904737e9b5ac9f96eb1f796bf88ac678f1100000000001976a91475499e278bfeeecfe340e3191ae9d6b1764cb7ff88ac00000000" }, + { "697a1e60f8a308075bd11d3913c4008739126e460f6da0cab91093a22ed8bbf5","0100000001bd1196f5f899ea381a42f2b7aa360a60a580038c0e35bbafc769a28120a520b0010000006b483045022100d094cc9d951acc068622ca82260bd16211e8f5d68696b20fe3aea1e8233f14de02206edc1fc0e877672d4d991a8e8f48d72a3393ba5609bcc15e8e3cd63df64baff30121023f3b646885accda3bed53819bcd8e8bef30ab4f22d44a84a69d1c1af280372c8ffffffff0280969800000000001976a9143b519219348ddb73f1bd8fd4b6e5201bbe822c0c88ac603c8a56000000001976a914f3b507dfdd8f5f6b67b890d4771977623d00b5bf88ac00000000" }, + { "e8459ecc1d54df138b3b0015306858c2715e0d7e6313efacf2bc3f7f24767423","01000000018f41a03fe5f6325ae4541f7c30a660648b9286a9c6474962ed2f0fb0e3950075010000006b48304502210082f62e68f74864dde587e6f01225f998e2bbef4f67f020e36c66bf41c4b47c2f02202518f57c97b4b281c08b94ef30b619194d962fd4344f0c1cc1b621f78543fbc9012103f4ec4aafbd12440853aa4732f9b52e50306198484459cd0af929eb47760abc82feffffff02002d3101000000001976a914c5213bfb7b4792a15cc1f55016e020a270b756c088aca6007904030000001976a9149c1fdc059e7423500d6ac1c712332c94736700ff88acb8210600" }, + { "3d7e3e7e395e9a5c6ddaa48b3d637d03136811e136b57f81493f3a3c8ab781c8","01000000021f8d6ba3041fc848eb1c0913a95add419da23eb5cab06a9bca60b9c1d8f14611000000006a4730440220009c101d0a8563424e9468b32f0666e5a94fd3204db302f28e6e634e329799020220320ae743ad3d467ea7d823e21f46217151fdd58f9b66d71cf366aea0c8e315830121027988c28f03751c63c011def0e73f1719c7bd677a2a26d0f3e30a9539b9ac3829feffffff681264c2a5a6e7d8a4c56d467dfd8489273de189e289120c5d39998ce36da59c010000006a473044022051a7bbe8d5ba2a049f6e868cb7dc3eaded30c31bfd38131072c5e8b1382cae2d02202154f14c7c24882ae4fb66ab41673962d2d94e0d7115aeb5510b99ff53562df0012103536ccaef320c72dd6934a9ef135b3c7da73825cae4c7fc53f75722ff7bae5119feffffff02eb6e1f00000000001976a914de8d2181af058ec67c7a65dd06c63c91cf50c2bf88acb3ce1000000000001976a9144d9cc8326b3125182e2ed4031c6be7e800759a5788ac75210600" }, + { "9491fb2b528860c6ff18fde8f6838ab742eb40be1232691d6761792630887713","0100000001572bb6d34853aa7b0a477096f192d18d89f22693c5e279a1409922e74c48e006070000008a47304402201adc52645e61dcbd6aa58ccab65e17c7e4974bcbb60c1083528f52c3b9fd6c16022060ea681f7326995f5ec8d1ca6f2ff190b57d8728552f98f5e081c4011f3600ed0141049de1c8260ad5729982fa9589f0aa795a76dbd9695418c232963098eac9c1a2b3c74669555f94f6e3fe7800916a8e30651dc7eefdb82e773bb096358420818d5affffffff0230e60200000000001976a914bd6539861c0d31c62a794214e0dcaa5818b681f588acf00d0c00000000001976a914f0dd368cc5ce378301947691548fb9b2c8a0b69088ac00000000" }, + { "1009ae59e4043347290a5cb9dfbfdc8fe7c0d569d2e13037a6baaf751ef58d73","01000000013c74ee2e14b4215405635844482717d07b95a35fb5e85174e191f4d1204d8a9d000000006b483045022100823d1e4d03ecb4297df0a1ef7bb5fa63de3b9dbe2e164957f488973fd273263302203e3f84fca121a1b987dffcaed0e03f01d1557274c642fd51105773e7b9522abe012103452464988cd2fddac254a268e54f2fc36938a93422d3e30a767724892d1446b3ffffffff0380841e00000000001976a914da5dde883cc084fad0d72ab4cdeb11205fc63bf888ac001bb7000000000017a914b233b9f4d880f32cf1b8cab050a2c3eabcfd28228780de0f00000000001976a914c24ff6644bfcfb900b5cc829db4cc65331090db988ac00000000" }, + { "d1923bb5b1090edd65b1793120ba8e59efbb000585e60689cb49807ebee4f852","01000000014158c202b19de65f7cd3029f2665728da8267225d5ee51cd4260cae9e9abbcea010000006a47304402204390c77651edc8ecbbde33cded6319da625705037adf6daeefd777e3a71e7d21022055343896254c275aa1eb9c4fda46082d9e3b5a06a6db49b727c158f40ab5cf2b012103efacf04f2a8cc0cdc09dd46949a4ce63e1e5e8d85a6ec6aa87eb9703b18a3179ffffffff0270ad0800000000001976a9141a7989f68496d3d179e210ca3e70b226974e0dc588ac64432600000000001976a914424ff786ed08d9f4e5dc17dc789e51c5da3de61e88ac00000000" }, + { "0d04eb1b5ffbd224d2c0911e4b7a94da3eb7fafab3a780a5f6f94a475afdf907","01000000011e6dc6915877248cf3c11f80e0fedf3e2a16819de956bf79a22a64a2ce3c6b4c000000006a47304402204edcfb5075aaa71b20b26e62a7596814b2cb3c42748e75887f50800d4eb6151402205c82cc2e50dcb330ee248c5e146840c8d067f25fb32a92dac851bcc1e999fc580121021e0c0d86474f9fcb3541bd572f4dc55a5b0cf7387aa5acbe0605fcb0126b3920feffffff02c0e6ce07000000001976a91450623318edcf49fdfd2961ac516d75c6385cc91988acd364d408000000001976a91461bbaa9fc7327d0367b540601444f67d907f469c88acb8210600" }, + { "ca0d868fdc4c2e5d0d0a756fc9efca0533ea7c1ea7d49df5fdf6de5f851a5fd1","01000000018f87946cb655d5c0cf4434504880e071c615c10082319a7e1ff426b482068cd1010000006b483045022100a41f33d4b31c5106a6924a88431d193e1c7f8fad1864eeef713948115efe6a11022009bbb034511fc9dc85acdbff5cba91c8bd54372225ba40a6bece2ec7612c0ddd01210373d5ef8b817d75072b8c9ad42d5915fc30f0d65eacf8292abca74f532b40b35fffffffff02400d0300000000001976a914da5dde8cbf20315f3e00ad8d6b610c14bb6d0ab888ac893d0100000000001976a914c65ccf9ac73bdcfbd5b64bfed1bd9d811586ef0588ac00000000" }, + { "f5c187b6e78f17537d59d092cce00794f86305577ec5451c8efb158923ed8cb1","0100000001ced35333f97f247216f02172a1fde5043fe23ae7880cc9a99ebe0e3713bab82a000000006b483045022100a852e3d45aba3f341104027040b064545bcc3f5c0170f22a032b037e2482ea0e022047df325bacbf2c1a74afd0f0fb62d32059903269d81ec8dcff7ef3a9bb563daf012102b5414952d96c40aaf28ed24d54c4fac1ae0be1860b63df5c5208f9fa9e885610ffffffff0204a60000000000001976a914012c0ba9ba3adba4dd46623ebb1f3901c8cc172b88ac64e21701000000001976a91400b4ec22e19700a459fa0fdfc5ce787fba709ab188ac00000000" }, + { "9758078f5cf476e38bdb7c8f12138cfc80f572646cb2f4c9c5b4cd8af0720423","010000000669e2e8b6e7050251d1e7d7bc8978512a0e7df1d319499e353e9546a6e98dfc73010000006b483045022100e54850f0d8843b8d5ebecf232269be1188196aa55acc57cc15ec7b999a47c62202205fab19f5a0991916897db68aa1f580269f8dcee71519a707664abff0b9c5999b012102b7b884372aa8e68d2c4e1a9f798067a4ead7bef7eeddc80cf5484f3b23940a23feffffffd6064f50daa67239a7cc7383653ea1a53512df827445068d742792f83355640e0a0000006a47304402201ef69ad29299ddbb2483083de68b1f5ba9e5ad117cb32b76b2f2d18d2126538a02201241f844b064be17fd609e1989e48b635ad3e06b95ce4914f08da5a6aab19c8e012103da342d56a58dd8d69e167fb8dbee44ebad940fc298eac7cc5cf8831f248a6047fefffffff242cab3c714758829a4bcd99aef01eee6fefb4982e2224c7dc69e6ccc61e8b9090000006b48304502210088d72c29e70b885f684126a89bac8dee3deeb39e3daa85dce6a32c81b048c33a02201320098b876c95a0d752c176539b01ab3020868e715098bc524c038f7ee10c990121034cae7a0490ebedd72b0ffa7bbc00d7846a753fc96021901c06296283ff8ace4cfefffffff251fcee02ec90e2023747df767b8bbc6fa1f177c5455306c632812a5cead7a1050000006a473044022033094c0f6233700fab8136655a389d55ba1d51f632297d290e4a13a28719b96c02205aeebee06aebc57b64b4441979c2bd95d7846cfdace3c5df538f16ed6233bc94012103f50a1468c16b29e7012358ad39a99a283e21f96912527fc15e9c356e63fe44c9feffffffcc72d94166a35b4e1164905fc6926ff1fee69ca45a5cfbade86372592217b6a5000000006a47304402205133c2e51e665e9fce6f489eda55299372cecd3ff00e33943902284f4b77bcf302206c57dd11019e0f5cdc92380dfbe1d7c3ba4e60a24fe600db80bddf4da92288880121027545494c85bdf06b8d9b4db27a04fcd8dfa42af7a16f3226359d12faee3d52b3feffffff54f674f122469b3684c4c9adc5d44704fabeafa38ed1c111b75f3ec70d46ec31050000006b483045022100d44f1d80a3fe8448938180e21c8a655edc59f12a5abc4c03648ec2c13748ec0802200f4248c372b2dc1e2cac6fee2e43d824b2baa971dd613791709daebebda4d6a20121022d41501ef6fe343435c1c37716aadcce3520e5341f707640bb14b507ea284bfefeffffff08729ada11000000001976a914ac4968a5908ce7e418b392c1f2e0bb52dc31e78488ac58d91700000000001976a914de98f9e5791bf99bf649e171d8b0b487cc4670a188ac8c7b2e00000000001976a914ac4d49a921eaed6b90e24fca212dd8b6bc446f1388ac60e31600000000001976a914d2bb28e9bb10970ebd1910815e467ece4e2ad6fc88ace069f902000000001976a91443d8941f95d1479c21d772c9bb129b647de991e888ac002da203000000001976a914581d0f88316927963b1e97ac7a10ede8879ce8ad88ac454df401000000001976a91493ed62e4f1535adbb7696a7e0a5d45242fdd708c88ac34a09f06000000001976a914e53f68fbd643e4e624c02933af20bd5047c3b97d88acb8210600" }, + { "5792fc06acab90d1d9a112e94ee3e8263387d48df86cf9a3248035a8d3cda6da","0100000001f48eef277d1338def6e6656b9226a82cb63b0591d15844e896fb875d95990edb000000006b483045022100ed3681313a3a52c1beb2f94f4cbba80d341652676463516cfd3e7fcfb00fdb8902201ff1acfba71bbb4436a990eac8f2ec3944a917859e2b02c9c113445147f23b9c0121021b8f3b66d044fabca1295e6ed16558909ebea941404ff376dcaec106cefe3526feffffff02e5b32400000000001976a91444d6af9359434935f1e9a0f43643eae59bf64d1388ace417541a030000001976a914cc9e11d38e99d10ae7ababf067a5906c61e87a0b88acb8210600" }, + { "dc6e3d4bc89518e8c0907053b36677d7ee237ec07cb5ca79dd8bad55e5f3a4fc","010000000190725d0bff11e4bba0eb9d1a95a266045552c34178cee26e660dec3d60be5290000000006a4730440220332acd662629a5b45884670278763bd24f3b294db6419e3029fbe3d19e8a7ad00220742bfa56bd1207c888c653ac66ee2536e3d8e50547f424d45b9fcb2cc486cc48012102d8601975aedb55f8dfe3b5a4813de215efacabc17606fede8f33abd78da81efcffffffff0150c9f900000000001976a9149905450032d308f2ea0a20965196fd9756da337188ac00000000" }, + { "048ceee25fc38570cb2265b10add480bb165ead490e55ea1f2f5090bec6de4ec","0100000001c3a80545691e6bb06f9a9f8820b7f16ff216aebcf1d92887e00b921be47a290a000000006a47304402203d3b8ca10facd3015f0d5b9dfbce5cb13439526ef37f8c758efad3cd296887f902201d2d475d9228d415b9123d00c117d927961a096ec73ca299307e8ea82d2806eb01210216de097c4f9c987fb0c2e0551f7c756e9fce01b2533f991137dea3edf07c45fcffffffff01f0053101000000001976a9147a5aaa74b91d84bc9bdc370c108b20bc39b9d24988ac00000000" }, + { "510533729d67c62005764d67f7af81075494fdc760afe00ef69ebca92bb013db","01000000013c1818a5327d6c011d32f8320dee21c7d03d045e49f33136211df80b093f179a000000006a47304402203ed80220360e18cfb74bf426e23811926d4c27f0434a9a5bd0f58332d55fb1b30220273c9d03e58a4119a348227a3e39956a71bc56c1074a83a0aad24d455dd6c6ea01210291e40a7ba817068c9f8edba5435ace5fa94b17b8f6f39112b1f1d5d245d4ac27ffffffff01e0273b01000000001976a9149905450032d308f2ea0a20965196fd9756da337188ac00000000" }, + { "08eb9d90384de108b6a9e475185c70881fe3f2f78885bda2443e36bc29d046be","0100000001a78bbb5a345058a19eba06438ad551e62c79f14ad53c0257d0c3637f3a00a998000000006a47304402203a8bba890397ba0fa224883278dfb65e5c9ba69fd3d23bba972f755da725c5410220613c6c7c7d0d515e736eb2da627fba917072d9f63441e596551ee333e8fe9d470121023338e26ccb70790596c6924ae2ce515ee9ea6d99333277e50eb6fce84d7bf086ffffffff012e004903000000001976a9149905450032d308f2ea0a20965196fd9756da337188ac00000000" }, + { "3307ae6eea1afa2a553d3522abdf3ca21b0d4c60769ac712001440bb2a58bbac","01000000015e7519810be1fc0e0eb32ae2de64d57c1812f02b9b400e0641cb0dbfb7915f9b000000006a473044022016d42449b8fab579f1d4f88872e8986c3f123e3bb8241375479e112093264b390220045b88be32c9edbd10299a087624141102d77d7c6c01e343cecff4507e6dc1d501210291e40a7ba817068c9f8edba5435ace5fa94b17b8f6f39112b1f1d5d245d4ac27ffffffff011013a401000000001976a9149905450032d308f2ea0a20965196fd9756da337188ac00000000" }, + { "e4d8bd19f0ad1f54022fc565e2edd94acdff19f2a58c32d0e816fd3f904611a5","0100000001637e191366453d0e1faa80cf9712b9e2899d21b63921dd453574d75040d88674000000006a47304402206dfb410a433712e24ce7e0301e58ad123559c5f9b137159d31e0a622485a06a5022065d835fc9315ca4abe10a0f84ac00c3db587ddd2537858d5b814dc98c68b7f1f012103bd76bb7e3bb39a108be7bfbf40194dd68063ef20c9c24cfaa2f10b70dcd56064ffffffff01d8439328000000001976a9149e897cbfe5a44f596ba2073b41feb73a9444611b88ac00000000" }, + { "4ffba615c4ac21cf377b14f574dd6e7968af58c73b9c53c12ef952568eb3c8a1","010000000118b34ae9b3203587730b515077f2ca37c608c89d34830988817a7d15f7d8869b000000006a473044022062694a41c597253423c18318ae9260854213058aec496b3fd7b9852c01ae2daa02206c09164936189c5b9939e2a63777b321a1f36b3c41df801e47f012eacb265eb3012102d8601975aedb55f8dfe3b5a4813de215efacabc17606fede8f33abd78da81efcffffffff019fa04e00000000001976a9149905450032d308f2ea0a20965196fd9756da337188ac00000000" }, + { "88b069403aac45319d02a789337abe9c2388930b3c5840bfaf4bf78c72df38a0","010000000138baafaebd5c1c76d1a9b867b20b9de35d37ff66c552c6c36ee18603a3a9f73d010000006a47304402207ffcb1ed6142d9154b166bf515f3e6b148dddfd1c9b2b42008f054d83e7d14f7022018c6856592138f6120275f63d600a6d03a5ec940d8c4ce1016d7cd31d177ddbf01210263a54f5912d15a1fd6c949ce9dfc132fd73ba1095a2d9cee857261b494b71030ffffffff01a03d9901000000001976a914d1e88ccd214eecbc3cc722a8dd370a37ffea883588ac00000000" }, + { "57befd99ff40ff386a730972f75ba83c3c45a022784602fcf35aa1e7f71dba8f","01000000016f1ecafe9a5b5dfcd91cd7aed2560b53547673ef3cf488504f49eec5be263cac000000006a473044022039e5a96a860d444438a68c4b2a9fddbf92019bcdf055eff4b5a00dbb9b2797e102205d24141f462a71f63739336dea7a78f0d57c65b3d686f2b08276f8298fc9d29f012103e2b8c3c9a37d046fd71e0d44c760e8c3ed33ca148b7db1224b9c402a239099bdffffffff01f08cc404000000001976a9143079bdfc5750ddf17013f13c954f07e4513c350c88ac00000000" }, + { "dfda0dc9a98be2fe464ac3632ca986411e73ba5e1c5f03076f7e03b0e612a46b","01000000014a9798de8f926cc6147412202a849d7cfed8583ba5aff1a9766fdc2368648095000000006a4730440220542e16c9956961c297b9ee45d65fb0a90f9533cb56a8d31b3b0b347e05bc455f02206b74e843d86385e93f5e016bd2e4dfcd794f2480cf78767506f30e4d527bb26c012102d8601975aedb55f8dfe3b5a4813de215efacabc17606fede8f33abd78da81efcffffffff017143ef03000000001976a9149905450032d308f2ea0a20965196fd9756da337188ac00000000" }, + { "b1f3c19fca03a6072a726d41743705d0b08cedff5eb3e5a323eccc4f5365663d","0100000001f93037ecec547459e34faf4527506d520d736b3a20c067bc1cddc163f1eb5f97000000006a473044022014ddf137b2abc5041593bcb38828f7a9314a1301696f424ebc7618c02698d4bf022055377c432269cd33b90a7636420e60956061b435d8227cb611e77e0c7109788e01210291e40a7ba817068c9f8edba5435ace5fa94b17b8f6f39112b1f1d5d245d4ac27ffffffff01f0906a05000000001976a9149905450032d308f2ea0a20965196fd9756da337188ac00000000" }, + { "3ce445bbb4f932e89f28162217fe7be19bdf772652626d6d7994e0106c69a219","01000000014ba79785b17c94f1e2e2d6dff6e5ae61216e91fbbc89b1f040635f5ef35a7694000000006a473044022009da5d12f27c19bcb983e06165048a084528988afaed56559d98fdef1221a9d702200565c0c5e70744c01f1b4db4a2bf7c1b2e0b207e64166c40c2471c5125852893012102d8601975aedb55f8dfe3b5a4813de215efacabc17606fede8f33abd78da81efcffffffff01432b9b01000000001976a9149905450032d308f2ea0a20965196fd9756da337188ac00000000" }, + { "095f8418fc958ff860b1fde3627afb024f92e22f86e55db415047fd8a76b0efe","01000000015c8198db7e079d19406a6e23c518278e1e46abc9bbf300dc5e03d8833892522c000000006b483045022100e6932dcde17507e481fcf2cb0b90da360fb05a238f4a8a62044ec1ed485130e20220756cad44b9a6f295dbb0566864bfd22915582fbc987d865ef3d78601a673523c0121025495d2a858e74a5d43c704838802f5ec2708db917365d85d3c8033832b05898fffffffff0166fa0e00000000001976a9149f89572359be0cc06b2c160236f9b7a99aaffdf888ac00000000" }, + { "e2b9a888d7a771c6b2e95a4e3a2daf44b08659eaadeede88e6b70321ea15aae7","0100000001fd0ac4d6917c7e899c43dfdd5df8c4de2dd194a79893da6536b5a7a3b31de098000000006b483045022100ecb2259f5a4e91d3c5f3b105ad86e9cf429655edbf47524aedc462b4bf89f3a9022079a834e5b055671a9b47d5c560933c59935883d42f16fbe53c5c296c4234392701210291e40a7ba817068c9f8edba5435ace5fa94b17b8f6f39112b1f1d5d245d4ac27ffffffff0110cd0e00000000001976a9149905450032d308f2ea0a20965196fd9756da337188ac00000000" }, + { "3a33126101d0f1567206cd602ed1c658dc85d679238e32a73ad747ac01e359e5","0100000001154e5a58ca8adffbf8b68665a2ca43de2327e515964e573e1bfcb238844a1799000000006b4830450221008060551a5608c2ad09b2da0718e9efb5ea63ea225eb9d89a4605a8730bb3a0d802204fc1e2517e936fb1576fcc53ff842128790db88f5c7411691e37970ec25bf18901210291e40a7ba817068c9f8edba5435ace5fa94b17b8f6f39112b1f1d5d245d4ac27ffffffff0110cd0e00000000001976a9149905450032d308f2ea0a20965196fd9756da337188ac00000000" }, + { "5c048562dfe6b0badc431730cb99d655cb031eacda0625a8013664e3e8c88be2","0100000001116b29df620f63d075c2c73d782b92ddfd612d354f00201dc4e1d7812c38e449010000006b483045022100af5a4e57b7dda870120871cdb2e35408b1e6a5addaa3633549109f65132c0d4b0220737e82b403ea94e4d954e91d3cb714194d5c91be596f0e09419764cab67c8fe10121022962260b33650c22887760ab5882efc7798e70b4fae21c5912c2bc088fdd83b2ffffffff01f0053101000000001976a914503b1eb54a4abe5aab56b598502232164289ebf688ac00000000" }, + { "f33331fcdb2c32f679dce1001166a672bcc16f0ca8afbe5e0d230e005edd7eaa","01000000018505ae8d30ddef9fbac26de9bcf1716befd0a3fee5b5429a7fea79e88be63791000000006b4830450221009d922c3d4003231bbc1690505645efe3af62a4f17ee8d765d5ed74393c575654022068e2166ddcba9969140a4ec6358ddf3b20ebed3edc9709a0abb39a3a964d93a20121023338e26ccb70790596c6924ae2ce515ee9ea6d99333277e50eb6fce84d7bf086ffffffff01083a0400000000001976a9149905450032d308f2ea0a20965196fd9756da337188ac00000000" }, + { "7cf1182e0a5313d14ca2b1b75312087caedf1be5dc3eb2b7567de4932aab70aa","01000000015fc500334bc9e8149f35316ebaceaaa422a70a20c9eab0944f4ce69d82bbcdae000000006b483045022100a9b4a8a17d457622b2d75503e2a845a61e2073aa928f46978fc59dd6d00f860c0220324f790de8049c082b0dc5a918b9e6dee5a43bdbd383ed57b5667e4dc2b42d18012103c836df2c1f547be4699f7bdaf17234cfc66a11d46dcee292914469a1d811daafffffffff01f0326202000000001976a914e9693abf059439217542acd6de01e87329ae3efd88ac00000000" }, + { "35568dce03af5f5b911541cf5730d3c9f51a8e6c2120c8ff83ffbc0448afefa7","01000000013d5bffbdd3a3c2e076c591dc5dcbee217148080a688b585f31ab49e8df0848bf000000006b4830450221009128df9b1ac145995253f8f19cc0b8388062c0faa948765f92f27611083d9a23022052faf5d68cf9da8019f3f16d4b2431c3fbcb11f89a0dbd7e238d2ea0c0fe506f012102864d9d2eb79aad22854db47c69efb9cab04b5ef7545b19d84e8a25c3c4defffaffffffff01f0326202000000001976a914f7c641235ec3927fa9949c6fbddddf2680e3210488ac00000000" }, + { "8ba6b1438662a7e9ccc69bec67eb414a84c65ee71fc6d91c8cee040f3cd78e54","01000000012ce474a751e8626ed153ea8d5dcd279a49d4af47579f0797b0c64733fe69479a000000006b483045022100949d8904b5b42f44bb0b687dc709186951bcdca67a8bdb6ce4e7dfe03cb65bf70220611aa114779533ab5cb8f714d76d49527e2ad54cb8cc5f9a3a38906f00d5afa90121023338e26ccb70790596c6924ae2ce515ee9ea6d99333277e50eb6fce84d7bf086ffffffff01cc08c600000000001976a9149905450032d308f2ea0a20965196fd9756da337188ac00000000" }, + { "fa7804088f315a0aa5d2aac117dd75f588bfd9e072a221077b6062c5a9163d50","01000000015785efb5e2a83c69f5039f8b4d2607c26422f1c7d2a36d1a7c1b65737b5fe595000000006b483045022100bb680f5bd40db3c281634f3bbf14e4c647bbb4e477aa97662d0b4e8fb654ed70022004a395f6740ffc4fff2b20fec17653e30dd5726e0f05b4a4d799d064a7e6460401210291e40a7ba817068c9f8edba5435ace5fa94b17b8f6f39112b1f1d5d245d4ac27ffffffff0150219800000000001976a9149905450032d308f2ea0a20965196fd9756da337188ac00000000" }, + { "2badf0b1d7762cd5329208537d62ce98baedc65b79a1634838beb168bed0624a","010000000113913217864724c3afc011265c8abee66e7da4942798307d8e27c8f18ca8a895000000006b483045022100f1e05c68378442f990e1bc3b1ad57c399eb90251de5bc236a374396e69ae3928022035f82af76e105fd94ff35798820a353ee28cbbc51a6d9ce4899833e861f2299201210291e40a7ba817068c9f8edba5435ace5fa94b17b8f6f39112b1f1d5d245d4ac27ffffffff0110df8800000000001976a9149905450032d308f2ea0a20965196fd9756da337188ac00000000" }, + { "baf84285a3b498e4b6d59cb29ce9fde3eedcea9668a40cdf451a5df0789f6d29","0100000001dbc159df077369e5002c53414199d62c99a91074eb1dd7b79e4e415e30d4e192000000006b483045022100f23929cf4449384633b6c852cfae3a76c2f43dac77e693f75040e8f3324d4e900220380c27bca6cd87a26e8e637ecbf56416120bf58337e76c9e4171f294ebca211c012102d8601975aedb55f8dfe3b5a4813de215efacabc17606fede8f33abd78da81efcffffffff011579c400000000001976a9149905450032d308f2ea0a20965196fd9756da337188ac00000000" }, + { "9857cb61114e624cb7c46159e9379ad7f62920b28cda66ce8706fa8f81174828","0100000001237476247f3fbcf2acef13637e0d5e71c258683015003b8b13df541dcc9e45e8000000006b483045022100e935f52f3a7020b289fe7c3e59f8436eb837a3cc1cdb7e2757a8ee350b6c72e902200582ccf7f7c7ce7113e05ce2a8aeb98775aaddec06d31b0770b1977f2a320453012103533ed04a3e41f1b1bc9c942426ce21133308ce92c9bb6244f0d5874225181847ffffffff01f0053101000000001976a914cf7bc4180ddd77dcbb185448081b514a6844f3fb88ac00000000" }, + { "9ad0e70fd709c300cb3896bdcf34ad8ba8e886f28debcd6a26475cbc379d9b64","010000000ae13b584c2920561ad579eec6937fca923e77f368f7c5bdca4c55d3f1ff5905500a0000006a47304402205bb0dee8a733af1a0907d54da86b6eb79b1ed6460dcf8dac3b0cec8262cc9704022061916345e366a014bc71881e462fd9ebf0c7d8fba73608edabcab38c5494510701210238f26954881f9473079db0cac3ded2d59c94c526526e682ab03fcca2184c92acffffffff005dafa264e2c4a1c269fbbb2aea2d4464f36d86e57d3bddb690d4e660ec87c5170000006b483045022100c4c3b020c7dec991e75cf0844ffe66b3af9ca778b65fc84dff05825c108b486702200457edffffcf527254e4c378206f05bad23906d96265d00d986907c329b3048a012103b928b609bf2813b2f1594e28f61e2fbc0c7e679dea10edb3cf0df5ca920174a5ffffffffe13b584c2920561ad579eec6937fca923e77f368f7c5bdca4c55d3f1ff590550030000006a473044022048f7bcc220b4a547299142a56363c55a6fea5dc3ee60a8d57304686f77bbb1e6022055cd6412c48abea50cccc0294df47046b9e8dd3d93d6fca77e3f1acc9c238e67012103ce8250fbb78b90dc1546f42937a70b2d8b22f9b9316b2f8841c8ebb4418fb175ffffffff45c355a755ecfe749c1a26903e698d14f65920c67c60a359878962d9166c9696000000006b483045022100ea91a81eb3d7849c531432fed0aa1fc071a016be30edd679405c303eaac3e0040220178177c92c72dff768af5b26512620a8921a2470e53f9f5a0b02959a127426080121030da4bf851f315aee816b41182d809684b520c5137001fb0372f83239a720356bffffffff57543c0b10b630d6c3bae170ce6bd4e209a95c5362c8dfa71229bde0529b2134010000006946304302207afdc18c24cb686c8d90b8bdc5a08dfe786a099a1bdef7eb57abfa90a655cf07021f1cd123cbe006b6c8e1d5b2674e71278377edeea37ea3321be705fb47a2af5f012102b7e0d9756b6281e096d57fc5ca736dd92cae5dcf9ec9747ed059ff6adc8f83deffffffff3c48a04ea3946c011c0602aa1287d6249e732305abaa057efa10961c7151cb31000000006b4830450221009806dc5189020346721f2d34781ccee747e624034ebddd33ffdfbea7be0b7f3f022012a226aac26b4e54923f1aeb3cb27506bb97231c210043ad0bcf083e4e2338b3012103d31d226585f85b5a5a7d0c6ac17abf218989e93e638e165b237971daec3b9f3cffffffff8b08d2fdb85616b2128079ceee663a52bef001c8d906f206d008fba790050389000000006b483045022100fb058a9b79fd8f33926863629d41b8e1f4bec1687d7fd027b61890a3c8a614f7022028e93dd752539c713447c1031ae47384de9e6d8d547ce60da6c9aaf3ebf61b0d012102b3add2dff2c9b890acbd385272022f68c7baf8168c51e912ad49c2c2d04e147dffffffff3090f21fcdfa37812379aad4e38fc244494da18f411bc14d869e62902b88ac1f010000006a4730440220752fbbb1d545e740086943ff2a57c8caf63b4e362a95d056deada104ab63020d02201a003e9bec3771d9e96382e086b2073280ddac935102e7227a5467ab642a303e012102a3b0d40aabab2b92caa90018e6df1a371b5180db381e7e5bdc5e25a8ece25402fffffffffbb478eab36288924de8b3ec786c23a41c2b91137651496a12e5317e8ad0b0aa000000006b48304502210086f535b60b92b36cc048b3005affb18d4390598f1f58932abd0dd991ca22758702205b342a01f5f1c2a473a84a2f9a18ac3d19f86cab70bc9a285e8395f86b55ecc1012102c086394fdf9cdd17413728d45339b1ec41cc20820aa295886f4f1cbe7bafc97affffffff92f2c9444c2f40013e90607888471dad3799f2d29914ae90cd2e89227fbc27a6010000006a47304402206daa9fed856782c1bea253db3004ace0c38a4f6c380298933339024193f7f1dc02200813f03ef932be786cc5d56c1d6e2a876d2ad6ec312c6ec13017412c5a28a8a20121039f5d8c57c7ea1afa453c46b3b1fe07862e8846b4326086e01025b2910c5d0446ffffffff028a8fa232010000001976a914380be08bf3b7d41efea1f3d89e68e8430d4a6d1f88ac00ca9a3b0000000017a9145b43d39d672a3c7ead02929afc420f2a8e0af51c8700000000" }, + { "d5b7f91d2c6c3977e794e9a8ddab1b5cae9ff789ad5a0072a6dd25ee0ce156ee","010000000aa8e8cc750290412058e1cf7ffe48f31ce5fb3863d56be2f4f2b38bc599995c3e010000006b4830450221009ae47b05f8b1d5dc82e354b4875ac0c8186ceb8488ff05dc90c2a20f1b8c2d0f0220157611469dd2cb4c483e8de2183cc8208409d018d936813e8b2e5bd4aa4f7a95012102d3d666e0bf0588b1ec7d032ef1e67bbefedf6d2fb09f3d731f1af5d7f24225e2ffffffff48e0cf35c7d371d64ce9deead0a0b67fc3c1b478ea1cfabed9acb0afba6c20db010000006a47304402207919d1a6758c7b74975eac0c8d6521c21feca46237b88b6edd4fead6bffc4f9c02206b4ddaf78c263bccc9ad807f18c66fca5f3f3f5089bb60fdcfbcd2aa0fbe7025012102be42fae22eb9e120c3edac98b75fc830286bbacea546af6b1023bc70c9ed82edffffffff2428e189faa9e45d367bb3f30f6bbd2eec90a8b9f74491ca3477735f328d1028070000006b4830450221009ef0357dacf6ccfd3018ca827eb13cf372b70c7a7921d6934580d44d788dd09302203f0a2fbfae00c9176b17b52579d5702180f73a21baf90e9ff04aa34ce8032d930121030cddd0fa5a28bdd66ff0fd6799398370ad43566c200c441b3670a200924dddfaffffffff97c1c0ca5bd05f6a65ba1337a9e2d87ced595c4a3467409273f323f2962099c25a0000006a47304402204fb8bc89429e830ba08f1e215ff532b179ccfbbd40107e22c7cd61d9fba1abec02207e61316cb5702e397966c47d8eb4bab2c84aecbbe72f1a82a4e012b57ae46d600121024e377b8712812c551144e8267ccff59fd63008b1a8ae0b746451b940c7407974fffffffffa7c9d5d7577a0cf262113aa35f1eb0b486b22972d0b6c4d415e7de8b2497407010000006b483045022100bf8054a94d72968e944ca16df83c796f02cee0ed509e328fa8b93a24ed7f549d02204fe2c42a9fcb3b3abb3e76dcbd2a0e037087fecb78ccedd14bc2b52781377ce1012102cac516e07a82b56e7ba5a773dc344a100e1c1a4a64944a593cdf37862ce03323ffffffffb6fb8c26c82e420ff9f65133a9b119d5b9df72117d0e18113caaa2bc3bf000b0010000006b483045022100fc09e1a6ea5602fd5f027b1c94081b84bac15e4344de397fdef0d7021f15abb4022055d9b196cb0b963419a7df47681edb891ad2e9356c7833af4c6d29e845e322ad012102301084e86345b81932970f9d35ac91f0ad53a88842c30012a46e062c1446788affffffff1f96d44ca7ac63bc88ab42f1e4a930b85edf116352e70610801e952ca1ec80be010000006b483045022100ef87c72ec0a38e50f624dce9b1674cda9dcb6a0ced1c99cf806733b7e4e0951402201c26a0600575ba2887bbcd361e9d7b7b43cfeee73f23dfa2a8dcadc043bcf63f012103b94b40755c4e287ea515546bba5f93bdfc5d2ec7cec5fc698bf65dc4772c852dffffffff272f72081674fa0b0f52a230b4a24f361e57fe5349c7ff15fb65dbc7b2482ec2070000006a4730440220706de7cd31e5e9bbfa88e38bb0d7c81a5a5c1f319f234c36cc6856a9ae3edd4902200619fc97ca63b1bad481785f4bb2328e0d1c9850feb4e3f8e803b08ab49419b6012103a69adb0837201e0dec801c8c3b00bad1a412b54d5c513f69e09d5806408f98ccffffffffae99188d894722d18ee8fee1b541ce2e4eaaf18ee4132d8ced029aca7cd616d72d0000006b4830450221008cb5a9a76d424604d1fd425c633c59baacb8657f8eb6cf4a183ab4b7960260ec0220601f35420d539f99c59f2ec0c0d8171fb002b9bc13781efb6a0778302822b6cf012102d7012fc4e1a17982b28ff003ed39aec0bd9e775fb9ba187b9795df4ea83b40ebffffffffa47e19b9510873880b3ecefed2e09da5a283879b0a66a2f9dff4ab543f11c4da010000006b483045022100dba269da30b9a14c27971c4f306661f32f827e634801be957bdd35aad433ae8d022000c3ac24eb3fabb3df0e334610cc58a446e8f30360bae7852bdb495c44b7b1fc012102e489ff2513acdfb4abf7e2d4afd2ce0141151a0a65f4f7444864a369f110b875ffffffff0223f38f00000000001976a9140917fc4e823072f80255d2f607e0dbc5bf3d0dcb88ac30861200000000001976a9147ffcda8b52c69eeaca140fe158ed0b2a17545f1088ac00000000" }, + { "ce8cdacb1ecf5c37d8c8d862689b1a0816c99ae4bfd00a64bd00d7611c9a9b88","0100000003230a09e9763e2c85c69cfd37b0d2dcea6f1aef330336fbfac748375ce291a02a000000008b483045022100b596e092ffb7d8b418ea6e1c63b84caab1ce761d6c3b3ff2d85403fdeb55e1d902201c53f6864492d6da1eb13614ed7edcc5695a73a83ed050ff518c99fcffba7d370141042c8c6d13388008a6a67a59c7be6e689d6e6d659721068f626e34fcb1a4683ba73351f7569c4347fbb8788dded73d4bf0c5e2b6845bad6c811e6615467355558affffffffea5339b3dea94cd7db6febed8fa3476dae63ffb4bc649dac2db7a1c6593d0d97010000008a47304402203c66a64a315d9187c6e1eff1f2a46f8ab519977ccf6f88abe0989e50dc5c01d602202f9d8951d378af1edc1ee18e8fb65be73eb914bd733af1c3ed69efee6bf83ee1014104e05d78fecb498bb9c096450e5645bc59b7c594e08fdcb70c4807acd315c4dff9cb2bc4fe103cc2e3ffc53e87da1404aab03201143fa71b224622abc8f1af5faeffffffff7221c30b3b9cb4aa029c0132a4373edbb51a9afe851a833a139175488bc6aab4000000008b483045022100df77e9b0820c159e165702c5d94a30f45ad6c407188e35b50f50a5eaec28935502201cb62372a0b059d9ac7926a8e5a2ffe0218ebdc141bf16ef403cd7b9b0e4b61f01410449eca6fabcf8de907dc9399f44a18a267e565540015d9ac4d9ad2b2279f2c5b73718197cc2142ad0747d16a43b95ed637bfd72d1fa3531a3514beda1cb574d86ffffffff0274a40600000000001976a914ff1729dea27bfd3b8515e694188bff2943ba2d5588ac20ce3801000000001976a91487d2f5c92e25689e90b31624c833afc502de57a688ac00000000" }, + { "c6c961552677554edb09b427138188a8e8188cdada58ffdc0824db07ace20ec5","010000000a05932b7695624c54af0b1e27db061b13426d4fca513cc4b66cccd212d90a790c000000006a47304402204ea64ae633bbcf4bbd372ed7d2adee43b966e560181f126500dc04c6bcc9915d022074c311f7b1425f8bee84c463bd9789eceb2397b94aa9d451ba932b15afc2cc2c0121039e5a4f5ffc42023bcfcd7dce68ccafa79847121b797c1479b3326a1bcb880a95ffffffff1519f5f868cb6c33390fc79dd17fe2eebf3d6986fb1ac99c0219362e421fce2e010000006b483045022100e51c5cf75fb7327f0b140084c9d01f47d8af1f036f414cec793b82ee9e83b1eb022022014ebdbcb936ce1796e2359d79088f8886728844f5933081e805ffa8f24f5b012103d5db7eadc41cd4e311141371b08d2abfe77549035a4b8c4d50214d541d9fc018ffffffff4fdcbbf035d58a3b63b52a0228c59ab7a0e2df1d500df3004a49492383c638e4010000006a4730440220198e02e2042cabf696be54c418525f9795b0f1287402712dad30d05ec49d51f002200cdacd68c96276e2367102d3b1ace1d1e8c18053d334850283af21ee0aeec5d40121022c6dab4218bca4d346c7ca8020f26f1134cf22c417a25493380675a9800a7facffffffff8c98bf3b708ffae4b64033070704122f869bbaa3c068a9eadba670cdaafe0b99040000006a47304402202617975ee7ac531bf63c90dd484960fd6dad8d4029711d26e11599f1f576c60802207dd4d8c10c2c6c4f124ec9bbf7d5fd62a8fba4f3e5f7fb784bf988332ad1c892012102df1fc40295d7f87b16c216b1aa9df87c73e7762b819dc2b00d8a10062ebccbf7ffffffff27b1cd98b4e0b22dd4a8016d5158f5077649850bd7a9ba344e8031579dac51e8540000006a473044022012a7013b98e69aec491632b3eef1f9608545205a4576c29f2fd5a5f66949cb740220018632304b2d3b7fb70bade70ae17cc090b51223bfd683d3b65d37ad053037bc012103e6d96b8c8136da50351a4d7e17247f608fb90f3bf9528f1c21e4607b609fdb53ffffffff1db125ceeaf532157475e82c96c9ca4e59594f1776b6d58f0ad6a0e6316b2a76010000006a473044022007dc56e1a94368912f7427516188c8a875a6392728eb8b3e10930aa04263dc21022062fa5e1894e81caa3cab28b4177bf8803c79dd851867d8c8c6d1e8a5589c4677012102622c79ce2554332ecabb8e07c87aa3dbcf4a1c561afaaf964723515282a4df1bffffffff5c03c979b962593f26215c9f996dcd1a6ae7218046d11788876fe9ffc4cd6dd1010000008a473044022067e06c0ae5c72f164c6b19527f304b5cd795134df8f3f7a6e76135a7627c6e0b0220478433f145f72a2d99b863b2b3cf9e08cf283040b196c1d2896a265bb5ff1211014104d7c8ce41471063749052652898d0509960f4d4e2ea45af3fceb77fb42d7794dc1e97b03c3aa26f6a1c58711d05da9a399fdb814fd16aff7e27745882eb1944e4ffffffff2a83a87ca1443aee171ff0f466701466ef4f1df74b4156f2a93c96f12c412a8eb00300006a47304402201e28b8913e22e7c3a24ef39cf556557b26456e9a179f9f6fb799f06a6b8d245d02204ed68ddf534ef8f69ab321a45f2309784e846b5f62011d1280e99732bf78e3d1012103b913ae5e0f8df959c606532fda2d19cac0399e60d707e3ef55cce6b96df61132ffffffffedfe5f49a5c457f6062cab8e26a6e080492664582a548577874553506d63c7b1010000006a473044022038d2a286dc17d3abe87735761f904af8840400e70cb470cf2b16ae32fa9c6f760220632264377a88223209e6a8fe43f2e8395d971b42a864984bd6f8973422a2c4f7012102249410be801087e161ae1d012a8064c1a1919e92516d04a587d9b7aedcf98a5fffffffffed1045a3b1d1d38847426ac36b47c23e0cf13188947043286d447fa047509ca5010000006a473044022074e58b67f714b3239edea9dfa53996424d3498b4cbbb01ad271e41c8c9974136022010e8f03a77a1fa9a17e68ea97319b65cd4164ecda53552b213054ac7a99794b00121025fc202756e0d46758b76d011e9601d1b9f49ddbad1d9843b389a5039422c91d8ffffffff02401d2a00000000001976a914f86b638e21ed7c32b697cacb6da20960e2a6477e88ac12c67700000000001976a91461e2f88fd0c5929c34493f98fb7fb7fc30e3261788ac00000000" }, + { "6452f91639731f447b124bcd5a7e0e98d827a2e4d77941ce1a35874b7c0e0e91","010000000a4d7189e4dfb3ab2dc0f88c04844d573138d73d16dda9a04b7bb79da400553c3c010000006a47304402205e90cb8b640b196649b2f9b8ffd6a637708479bf5c6308cb6c46cc81ba4f6b9a022010141a621f39098f9cde0315e7800a5bf51d6adf809dbe9af86d01c15aa9b54c01210301bdfdf0162b8e44e2524065bd6cdc75f13e19c53f3c51ec9fb04fbcae771d2dffffffff0ff7ed070b467c15a293471682baa486fa146d612df4b800198bfadcab443914020500006a473044022035cdf0f33139cc2752ff4060128046b81ac7f7e426286067819b2d9b5c8c2a720220013fc28a6e3180db672eff4073fd2209d39500b94dab42e4d0b80ed4932b47dd01210222d9988b654276dc5350561bc9cd96ae372de7fce684ec3b2b73932ebddf209fffffffffdd967fdd1ac75f3948e32e63043d6c46df9478e3adb18c966bac83be8d807b8dc00600006a4730440220030e8bc853ce3c55e4f02eb4f9a50e638b6b13611092256ece136085e33ae92402203a00ca45f39dee0a950c976683d571802a2bf589fe15f306c14f62451680d1b7012102f367fe2edd5f380d3da8460d63ad2fd6c23ee8ea522ef07d4f2e4ea9842f7bccffffffffe9880e9d04e2a87df7d30c2e05defbfd1481d38db1dfd5eed5e468f7fe9a68999a0000006a473044022060aaa9c1baac03a0a22eec9d59fb5b44258e4d3e4fbdb9921e1e7f2317985b260220371e58989817fdbe4522cfacde384079ca19ee8389a1aac7b69b64525a2b01dd01210388732b7e759bd6c615e8fe2a3d40a78f95031644003fd2bc15ae72c0ceca2884ffffffffd1adae8c8559f3d046e8bde20df79307fead539b7eb63bee051c3c3eb5d0c674f30000006a47304402200ace395d395c80c47c0d1f49b5a068b9753d3a4a256c2c836faa9ddec4ff31890220153a92e7990f6644640bcae437e4302b1848c47ea6fca5118386e946d057ba1d012103238fd8f67a2e8ada9e0f436c26116aa48cb6302b7e3f37bbd9deb6c74d6239c0ffffffff1ec127b9e30bdf227aad8620abed4b66e90c6bd016304023d86ca93291e2cb73820300006b483045022100ed01890db609c19580c897c97e332c82c3d74f1138a439db98bfc2c39ababa6202204514aef20d41d50dba356a93706891dd5290f5601e5f093d5bbcce134b93683e012103bb95cc89b25056d37b73629824b6591f0dc5cdd4d3b1a0443c5b73b2d6ff2d98ffffffff2504cc634d8b5fd5dfd2a49a59fb91600d06ef5b9944d63d9f783a61a3379a22660700006b483045022100a5df4ddfd93e634f924ac61ece52c9952cde0b0edf8fb62e526cbad183b3d84a022078d4669753d84cdcfa226747e48cd86d3c693954d71958a91957916b976ca5cf0121027a9b4e2f420be5f13012d296374f3146dd6154eee9bdaf03bd643cfbb8a0669cffffffff773727161094bb6fa33c468fdc2cef50620165d33f548dbb8edf269bee086feff30000006a473044022048da13bb71db66a1fb8c75c213dde8e3b535ca3bff42344f14636ce050d250fa02205ac2854feb0333befc7489b9b6e2e0fdd6501ca9d4c798a7f1be0af0c6e62ee3012103209b1f587957402c67e1f528510bc38d47239b893ac7ea7c714e40d09498ede2ffffffff59ce7fee5786e133344309837f7eae55ec5140ea459e01d3d8c5386bb94a1ccaf90000008a4730440220402fbe4667f0efc2449580e8426bc7c3dce446fd3eff0248ecdaa400751cc0320220395f7d6108e23167fe9355b0c24614b21ed4379884bd84a6a30089fb0493c2e401410499b0ec28adb87ba729b8bd550ad06aa84a9bbb6e6cab60768823ac1243bd8058607217aff87b2a3043ed3a341a7a7499214042df06293c549dcde1966eb529e8ffffffff14710baf2ed3fa8b05073f271e30d4a752c42a9a78486ee4dc4b67f57b7e43cd790000006b483045022100de9665f55ace5d82fcf937060f615fa2fe6e2d1a7f0ede762098bf4fcc3f005702201bec9841d53a5f7047dfefd7b673754ae449f61377da46f955f36885239569c20121028d7aa03811e4e375e51dccdc3564ce1a6a1bc26517c2b9fdbb65786b0895d77affffffff023eda0400000000001976a914e20df1592476e3f59ff60a9d1edcd6becb44ae2688ac4ca20000000000001976a914b5eed8504d89ad240d6523e7cfad8789a4f38b4288ac00000000" }, + { "5660d29ab35a9f595f9eacd9ac635b28c8c7ba953ccf93362562ea1e8962ebef","010000000a3fe71e4baa8ffec11b2d349e7093a82a1bbca1001bdb7a5af2d55c91dcee6879010000006b483045022100ae65050338850830e1f54b119d61b36da3d931806fa694119583beafe2ae1df602206f37299ce6c3f4b2f15a15390337c012a6a3937044c56f3de9f32149737fe121012102e05093575b4ed0d5893beacce9e3049ee0189213dd788235cd2c48f53b537cf6fffffffff205bf52bdc1955ff58e13f5d0cd038bf3beb6772cb5994ffa9756626aba7b8b040000006b483045022100c9be06990c099dd13c330c1a7a3ff5e87ab1d42fca76b32b3e1aed70d20ac79f0220101404ebcce1c6fe04528efedf2751b4d18294ce7c80133847874d9bb50b364f01210272c577fd3dbcbbdf67c9a8b7f3fc0b65022a4799fbd7f2be1bb0d40f07b05b62ffffffffe02820d27fe22fcc8e5fd9552c8be25a79c0682b65e39d02caa15e7e46a70548010000006a47304402200237dd96de2e0ab6599c459a411c624409111c18fd047d7cc8dea902543c96b502202764a83c80164c2e588c26ff48cd3bde45ff9d031d5e7b5174d757d3fccfda33012103f710dcdc0257ae5461f4bfd7bf9dcfe59f79b8ca2f7a36d4dee6265fe978b705ffffffff24fe90f0cb64f8d975eb81ce784e06dcbb5bda3cfd01617c7ccf4e8d48bdcb913a0000006b483045022100b95ecd2614d23966a7fb5cb9ff5e88be5175c1e144c9d76fe298798e269f2bc402200ad1123fb15d2cb1d50e09c29a732ea8245ee842a9f4c5208d2089f7317c8e4a0121034882d44d15e985c0b68dac468725b3c53506a9fb20e88ae02f3012b86466a9d5ffffffff15be5835696a94cdb6f73eb9688155f8bbdc85a49d7a051bead7ea1cf25c0b83010000006a47304402200b81ffb025b58d71bb29aa7dd706770965e2aa037f064e143e2df5e4a10747b202201b5ec178a770dba6e5945c32303024930474edcfa7eb14a459e5b087be080589012103eea2dff7fc621f0bc6f7f95ec83a5dfb28b4333beeb09c27c5c7d5954b5bca77ffffffff07988bf7480ac709333b57ded56c8a6af511d1adf74e423e0648ead11844526e010000006a473044022011fd12fb90769c8edb4ff6e0886908ff8abc20c7078128fd143a11bb1d0a156a02207911d4d4693917f70def0122036406c1b56f13e7acc25ffa6ea562563f5df91601210341223bced45d9da0a5d2295d826aee6cb650c91f0c32ca35e2e42e11a8bb58e1ffffffff35f693dcb6d0ef264a3895d679f98f3fa36bd86f2929ffc625f0c823c3fba997010000006a47304402202a74165f4e25f8dad9664bdf78bba78b1d5a5081e327243a6920eb5c6165e7c602203d456b2bd0f1fd83ea34827d7a771ffa99e410b52e9ba5c1f7608f4071c1d309012103ddda0a0b5031ae32490c0414f404d6b679f8a8c9a6a2e2968a95ac5b1135c8a1ffffffffd3a5dda98bff937b1ed4944ded7ee310c666611d48e66dfa31cb0ab9094142021a0000006a47304402203b25f48e69a1f67a98ac1250dfb724817c9b920d6dab478755092e39eb9546b0022037bfb5725aea981d26387028108f55c496075002655c413a3d7f5911837d0aad0121024e697f530c47d4d14d6b8b3c9c8b4059eb8b1e88ef3738e26d1607547813692cffffffff31848e1edaad90c5672998160d90942bfb161c51e87c48476f2880c3b9461202010000006b483045022100e1a830a7e4c1b8777e53c928de9a8121397151b5b4e236e0b10d3ec65cbe729402206e3296226250a3ba3c55efe7e44d51d5c2d5829e710739cc01c85980e385188e0121037cf02fc1ef82543985cbaa41fdc9b428b60f1c80d5d4c8e2f89f046849d4838dffffffff4b33693d68b299e7e2040f22848818a68018a132e4c6b9ac770c5aa1516caf27150000008b483045022100fb35d868a4363d534d150315b7bf420943eaf30a6891f473886d506d604f77700220575061ac9de4d04635be69efa46691b5ef334db72333a327d3b18c3c2f623f4d01410400871fb20585423608f7a88f8bc38e1866b8bc24d0922a29bc3a151ebf28e50f3f43b004542da1b92370a46f1400d3e460e705f8bf03a8f1eb3c443353b98a25ffffffff02e3d85d00000000001976a914c3092437df7c0db7b4169e7290433541e23ac2e388ac20aa4400000000001976a914af36d7925f5b6030ab52352614f74249a1c777cb88ac00000000" }, + { "3f52b156cd7522454f29c1bc98ea6844ff5f134d7c25869d01ecc1cf578b4460","0100000021ccf4f9f6c7ceff2750bf3a58bb9af793ec92a85c47280ad059c04c3c7f143dc99f0900006b4830450221009c3482b18aeb5d18ad2aaa5a5b7acda830e3b3fa996dc63b9fac6b743c0d6feb02204a205eb66310a3112261737e7d16fa7d77114a660d041516e8d0b496fc081bea012103774010a308190cd5370b01fbda1001df34c273d71446bc15d1f9e3ed8ffd8416ffffffffcd69dc9c83dcc9a24a54f6013ebf9537aee54e91a6eaaf950231d607aa175edd000000008a47304402203d40abf5ec57541cad7bc8d8d097511ff15968453feb4e34913508c779b616790220276d8226af0ccc0b4a41a80617f74350c34b85b85592f49e6a4bc1559e4e2ae60141043a76312f6862f58d90b4a901fafc6ebab51be67dea57920a53de23629dc4896ea81eba4385e203a8af515d9dff02f9b56082e8c31baba7567f4da9aa76c14bddffffffffb49cdc67226dc85d5cf5116bcd90e1dab7d25cb22db7f8b3d7d7b10600f8e8b2000000006b483045022100d80e7c17874233586719888c82d99f6242053e0cea1cd7de1105b51eb1afc3f00220283b4c747164e69a1bf3d6420e4739660655f5253af50f5cb2bbb20c2ccfb0140121028a7fb274440e15b53be902aa8f0fca2ab2020c656de1674b20c3b39f0371db99ffffffffcd301585a56b78bdaedebe4203267fd7c91d91df93cd6406c756614cfc3e5c24010000006b483045022100f1362c38159861ad915f3a426029723f9b95b51688dd46ee8d198dd01cd4c95702201c6a4f140cdd6891a1ab3d91899ab5321dfdcbc4d58f5697bb6b1dad3a65344701210328551ce975e3b05272792e457df6f95e95455f396a33f7d726edbc4766a8f5e2ffffffffdef04b84560e9bbbcb884d6745e4f8ca3356f85bebb6eda65df68a103382a757010000006a47304402203fcefcfea8dec91a8eae5ee1a1de05f23e2d10bb354690d0acf3e6a1c464f0460220700101bc37491352a8788d89cde461926668dad608ded2a2c3e65d65e6a0431501210276815a7936c38dd6198c25745d1a2c40588ac6278ff2f563f9b8d5f0e3d9c60cffffffff18d8800b9f477f8a365585aeb3ab7ef7a0775a45a18b7efee30660415af922ff010000006b4830450221009c044e3909bfa6358f33a8bf35da2a41e4c894b35428a399a1e9425748e9a1f5022028f83a10806bbf4853f48c2fd741b8f81943638771af3d878415b92d6bd350a70121038ba69f045eab72ab5d4cfc7acb462d7decd57e25bca3e88e316f616cbb3c5a22ffffffffeca27af316c2bf0bfebbe0f76ce1902f4de4d1edc37d8f8cb13af2656f8adb30010000006b483045022100e1a67588336168c75f8d9cd74050dffc2cc1308098485a0139c9890f58ec3a1a02207c6f97d29fdf65d51fd7efa5688ce7fa5441ca6e17683fbc398ffc0a30ac622d012103421945ba7bb32c586730b54c6112a52a73fefd6e6d6d9a0ab2f7e26a0b1afb9affffffffd0f404f412e86208cc77b901eb702caf42663d719aaf3ff115f3e40a5756f9c0010000006b483045022100c2347810194d9e768b61a2c5b12be2328e87754c263511f77bdab3ada24f5e87022063f0c247c99fd6bf5dd6e5d28535e6e296e4041b8046ab4186aabc74e94b91b5012102c725fead9501b51fde39a466bab6f74f7e68647ccbae3b1c1d797e2263cb7676ffffffff53365ee2123aea7b7975a3dab95849f56e2a2e83f889377702ee9016e99cbaf3010000006b483045022100d34d32527fa4956fff3bf9585eca2f50bc97f590962be5c914553c77db93a71c022069385a2fa0bb4752ae5ffed74723cc5a67b09f3b17e1d7042aaced8dfa47f6d9012102f77acb697be074535c9d5695bb5f027927780926918c74c3dffb9b2e1ed1bfc6ffffffff3648c960758c02beb5d8bd0d03023010231b3c7e72a757f087adb87e5c03a0a9010000006a473044022015b0d383edd917619a127b441cc661a49186eb5fce23812e7432978cc66d216c022026e2c8a5a9893e3ff8096f14ccd16fa87a610e49931b183b9143038af3989f5a012102af4ebe331bc2a1f44e4ab42fed65f77b56e68fb9c89d23855b321e3f1a757a62fffffffffe12275353ba67aa24cc7f2bb4a184ee9a64136adeef97c9bcbb0d24366f35b5010000006a473044022004cc97957a0f616b2b0c61dee651a6b5b8fa466ae55a11c55d9e74d1566021c8022017abe790b5aea0d9caaf051fb6bc9ead1a5aafd110af7523f2162315cb98bd06012102dd935a3e718efe10d904802e78a399f24941950f5ff2cfc7ea4a6c352fa566f7ffffffff826233b0c0c0dc696ae0d6d3f0b5befcd5bb6e3afaa805dd8a3c53c8ffe41478010000006b483045022100a948c712301e6b086c93a0824263ff8f24affad6c5a8a25b5d49bc7d3e2231b602202beee4e84dee541bc53c3124905b50d08eeb8cb3ef22fdf5541186a8fdd65984012103cd6a4a5cd8c4e0ada3293755eed46f731417b1554595b1cf1082a5c5a5bc00f8ffffffff5a3e067c78ebe46edbbc18d9932f135110f3d4bf4d5cacafcf75542659597c6d010000006a4730440220600e75c9b2d9e079c6c5201d88790e878002b8d518c9df6496ed2395c44419f70220656ba47dd306022bbeef967f48cb3f70f923de4ed429dc0c7e710f07078c245f0121030bd2e52a065c999aff216b941d460189a1215f230650cb3197a61b9eaf0b8d82ffffffffdf362fa0011b0d51a746c13ddaa9d91d82d7eaea996d2d850a71ccb4b252fa97010000006b483045022100d5eef88556d26fca638e469d1de818283a42a53cbb3e5712601d9e172a3fb7f2022038a825d2c1545ba698298a54b468c716a18ff853ce76dd0b707d6bdb6ed3b4b7012103c5ec0fa4d571c53f27e714048a796df92155a2a882a1d68ca20e9c40a267a48effffffff2b0679f35b7c85defea176681da5ae6fd8f2314088002258c2f2eddb8924f1db0c0000006b483045022100e8c7fe43c0268366dc9e40605ac8272e30a9f19630521d1e0bf8630dd270cf41022055ee8b664d5e2bffc0697f4c166bef57f2a75b0ea3619182706c7ea120368a4e012103b80bfa6ea25c5770a4c12bd0defa27f7228b1729d2221b8e91669567650a221affffffff3d76f4c61e0e282779cf03023e0d7f82adaf41a26a9ef4e510edb0a272310f13010000006b483045022100f9700a5389ecbf0eeab30ff09f4e612dbc1bb0df911d1ec766117f6f2a187e3f02201e5a1b0afdc69041f2bbb2ddde1f2e618f7d1d43ce4feea4f4993d5694a84e060121032b5591db8d99b9d5b44a1e37e8876809debd45e9a9dfc4955f3f1986b9add563ffffffffb6c256451691fd481ce6bef5ec2b06ce48f7de8a9fb3cc1c2e8ac88a8327d9c2010000006b483045022100a3dd03910e634c9cd57e9ca0303d2ad665fa0aca7fba4829e33c1014af074cec022071796b7d7347450cceae0c16a1c2355c3df331329db9435c63fe25144feaf47e0121028111dae7579235b37232244abf1dd8fc1267857b7493396ae6ce3e093ca02507ffffffffe2473606735d07d1cd8c132df3e431fa41800b78bbaa8e682637714fadde1cd45b0000006a4730440220595ff94eda5bc98a8f8a91d1f32a525f18a4dab753041c9cbdb41306113afad702205facdba67485eb8421dc780c90472d754d2a88374781e69789394f2aa12ddb98012103468cffd06ae64de61a1a17fb496c98a7208834a66ef626e11d08649e6b554389ffffffff940835890dbc6e84d8305279c10d5c449fd24bd801e414943de7e91db917f344000000006a4730440220464b21c328be4fe4fe032c31a0460e2fe8f8da003bdd0e16f752f6baec1a826e022039d031c28c496667c4114f6b4d5b5d3fac099a80094f5f827188171fa4f7d0610121031d5d970f549da49ffb153da298325e9f46a168c6cdad17df67d55f2dd6d53e68ffffffff7a0f71671816c7617fbcf1ec7fafd349e36c0eb44145e91a1f3f491e5cf1943c090000006946304302207c35e6e7eeefe8bf11435ef1f4a5c725ec25f841a4812d519f304c320d0bb272021f70d30bf317c5104096aa26153ecd9ff0fbe754bd480db95df447db3a286ffd012103e6b69083e98f582e76f51a4844a3f4771bea0ee3aa046a76b9ee5e170970fd3bffffffffe00d92beeb2730b643555e2685629f44b69acc2d807fa224db48a7ee27719999720000008a4730440220181e4b2f79f08e070a63e50431baa06bfcad97ea81ab77d968249161dc249d43022051e33907aa61fc2331286431a5012a1183383b7566e1b804d6807b3494a79723014104350dd9cebb4ed670083e2fa439d28ab3b7fcd8456888df924abef5ff443ddad3e018b5e9a50aafcbbea8f3a8fc60358a660915afc09376914a3ab54336b24739ffffffff2c3ed3f1902dfb5f9b1ede1cbf176cb7df7925ae847c46944ff013d419a8d67c010000006b483045022100807cf97761c91527c5d5bd7bb062721f818f649b45d2b858a6089ada4061efa5022028b4ea5500ab9f317af37468e198181957087eb984a09149707c12ae44533854012102252137ba0a6be87c71952ddfadd559d8a25fa1144532ac3d69b719c314742ce1ffffffff168d5ced4389eb35e1900e3e3ad34d414ffe951981ddd31146f86184b2c23dd1d10000008a4730440220038e0b7cae77df1e0b8e1b1f3eb1576d7bc18db129b4b275ae4e906bca3dedf6022059e41b9d4259fb5b11e4dd3de0e63db78cffee38b11afcbe1c24c850819e8110014104ea1568e4ad9ef1af1bf1a8a7ab60f6a91085a7bdebaf351030c5e33c569f6f80def2724027f639fe4aaf35c6dd7eab12d5f48510d84f37dc61d520896d731a4dffffffff617c95b42f75f2071b6afb1daed87c37a56d3c394bb49f765c1695cc43548b5a320000006b483045022100be340a5e4e897ac0cc706fb901dc13263fb4a88e21df8d30930d35d642ccc25c0220737c998701458743e9a13c31588c2a7a71cfc5fa72cf655275d6ba33e07ecccb0121035a1897832dbc189e82ce763a3f8fd7fca3a2c53f63ab59bc7045002b375cbafbffffffffa694ecf86593f196811bdd36c33cfb49449e9d66ff3bdf0b8ffc8e6d24e1f728010000006a47304402207339fd3d70fb7b8a8e58362c40032ee5c127e07564acb167e0f9b69820ecdf5202203583bc818e8ce35c1dd34dab15da5df1d42c3a2496e8ca05bf27957d601f7d580121027dd414629cbe841dc6d9e1c18db23202e61e3f2d19466d9444bac3725a409e2affffffff7602217a83d308f94fa1a856a81522cbe7a40da340d3bacfebdd68c7f0f3d6d2000000006a47304402207843e2769a1057d066c7c4b87b0fe2980ba2371bdf1a0c83079f041f7067fdd30220579063be44c233cb9797dfdd2df8e098a2ed94beeea980e4635f48a29628c3c70121025413d56c570ac890977fe5a6f5588b57cf52f17799fa5102d6091c1abe26c295ffffffff9a165dd947bff418db8fd818930467b06d60edfeab92d331c3c213f21a7a35bd000000006b483045022100bca9f102d2ef53da3336e94b6ac96ec69c7d4f2fe3aea06b8eb426ff6bdca8e502204bbdc456564728d799a54ea0100e0419ad88ae44b343001d5f05fd70a644ebbc0121038225b0c5dfe554ac0000aee746eaa3bada53886e815d5a1812d8d370724cea4fffffffff446b0fe3d40cd4d3e54a30083ffc39e2baf60ab4ca531a6e489c768ed14bdaba010000006a47304402200baeaf8d229f177ae62a79b42916a20b79ed908681f84f87401c27ea50a82abd022051860701409c19a6672da2437faaf06d805fa62f243fe63a17052f687a7446750121033be9b7f2b6a59bde956c1e1aae53bc5c541447294baff67a1cea4f8edb91ca86ffffffff848a396ee87ab657d8ec4fb631ce03845638354b6bfd650cd833f1a89a30237a010000006b483045022100b397b185dc36938a1c35beab1c4d6b664ee2ffa9a0bd2537454f5caedd7d6bb902200f8b2e34dde5ce0310bf4fba63dd50e8502941962c0591cf7bfa4357757d98d6012102992ffe631a767fda0b03fa795e103c78d4b218bd055f743fac11598d12ffd3edffffffffad727af812f72fd821962b200d715f802f2f1bf8cf8cd20e26dd12cedcbfc6a6010000006a4730440220373487dfd6640c565bef0ff580ddc1b3c17ae0c54b24362d06db37321eb2e66b0220466b034b2d5e2bde8b07bd82333b0272491d778de0bb20d8f788213a16b23c49012102377a7ba9f0d3bec471a319f81fbf2e6a09b5fb37a378a12f8c326067baae51c6ffffffffde4e4d6b5071dabf80823dafbba4bc12257811f2ef7b9b7d6c1f7cc3c36ab00c010000006b483045022100c7482663d5746de55a5aa3ccd59c41731b200832124a40e88098616e4ccab4ba022040b82a9eb8b802487e1fd50efb6c50345af53f478b31c67cf1e87da23fbfa52b01210200943b68c52d3a740dda512bb8287938aa98b4e4e4e5e8509f62b54bd42aea56ffffffffed348ce947d11907b04ef8ffe48dff5db812a41ed0c727c540dc840ed34b70a2280000008b483045022100fde7fdbda3f901068de34624b8f9d92a606029ef685dd4780b4914183e8421be0220504c0d78d80bc0cc3e69d9fcde5501ba24f8b6f573874354848d2a33ce21b50e01410464e95413867e64e00ce73f7745f0ab8d99816a4eb3744701890338df4f0460f64411ac7344eb4ebdeb76327176fe3959fc365244f3259028e92e62f056eaab59ffffffff53799df78597336b0e1218cee867381895231d740d195a609a966ab29a8bb9ad010000006b483045022100e18f662c812e77876920a5be00ec8eab9760b96de9bbab1a40f37aea847e8892022017d776bed9f0018b07572c27bf051602eb3134cda015433a94cb0af62adc1feb01210399d34885fb8b2c7f07e45537b90ba43f9994bbd4c9dc9ea2d01a3f7e08db8917ffffffff02f0bf0c02000000001976a914e8edcbd36b0b0207f4e522da11433cd967cceaf688ac85280a00000000001976a914da6c971de677d3a901b681fe0a6c326938af464888ac00000000" }, + { "8acc971f37ae67f5bc78deafcef207f1080c42b39d471cb507373469eddd17c3","010000000e3cd21af36b050dd8496e2144204059b0a015bad0ab6b1dcf4ddbffe5e3dcc69c520000006b4830450221008c1d3e199fb8f8083d09819f9f54a9fbd2f607bb395fc487e00d77e07d00786a022024952d539c0ed4f04558c3a03dc740c391f5f036a59d90aa6d6aaf94f495468b012102a5dea7f0a90a5efc8ea34551fbe1b34adee9539913ab1992c1ba776937dfd5f9ffffffffa4f174249654ad63e621092a59a8845d35c3bc877642aa7cc3997319bb51575d000000008a473044022036c61cf9c122acd29974902afe6e740b833eff7dcd552eb79257d9a40bd5747b0220343b65653825abd81ef38738d70928824f7ebaaa9b8f5793f09b431cdf472d2f0141047acc82a670a6a03048f62411201d24a84303b403cefcfaf2d33d60f97ec2b4fc4c7711dc16d559e49eaaf9fa20d6ccd3d470746c1169c695536d6bb0147aa37affffffff6284318e4565afb2b8fd2cd1159a79d7e40edfd01701d05fb700cac1658074ca010000006b48304502210086d0d8e8dc50ff14338d3fc9644e5639b821611607adb35a3443aeac537279fd0220047f0532d34503eacb94c40405cc0d3c843f070d7ea5b97b5740109128f9fd410121039706e844f6914b643a05b23701e2448b77423f68c89c6150552abb668b783851ffffffffc08bd6d51fe331dcc975d66b17464407459cff96ae0ecc95f1c6be3b17ad83ef040000006a47304402200f5231a34813e026057a4361725061d75258e2c25bd27f6891c8d67dbccb8fc802200e220396df9fb690ce68b83594da33df4d5baaafd07d6c4656273e4aa08cd1dd012102d0788fa026661053a8a23e8713cd7940063a3fd350ed17e36d598f2a9f3108dfffffffffa469c0670de9b32ec504ab9f4bb38873d483e2af4d933799c23e2bbe1963bbdd000000006a473044022070da8d6c481ddd6fbea0e69750896a4dc2e370990e489443ea666a3e1fc1a08402206856df3ddd0627d751dd8f8980f74f15d405dfed31c8ca455c64b2d2df1ec7fe012102cefafb751789725841609b1b89130c61e80d89165653ea6f7c662465f95dbecfffffffff7e64526dcad7152af4a65d10c13c6ea1e2b9f2331fe6a6828fd22eadfc1c9c0b010000006b483045022100d1676d213d68f756b761ce8acb0a5055017840b7da5be22ee49678c1a23dcdcd022044e5233360e9c7e329cf846d6ec48839e53331251bea23214c06138bad82b7d6012103287b22bcc78bda4f2627240ce4cd7b2acf9b967b18e4d3d07ab9ce57e67573e1ffffffff867f0300faf25a75612ebcd576418a422ab64260b94d28b8f2623a50f0217c51070000006a47304402206bea3470d58ad6f68316a06c990b0b19f16cbd9746bb93eb5ccd53e8fd149b6e022036c4d7f914b428cdead01ccc1db2781e556d526564c5ca5e66cdf034d372134701210356061604ee956703ee5cb2a87230cdc5bc53c166996baf762baa1ba8209bcc95ffffffffa26039a5afcef03dc9450a8e365c7b99d9f9f28960bec27e6f60b36356e9295e010000006a473044022050d298f65b94868b13fcf46238e55ab9f98562dfc88e2c85adca0556c21ca977022026cf79fdcfa83d6201c61e5fbdf13461bbb1239d9be5d7ee9bce10971a8eb3d1012102926cc431a3e49c88e844fcad3ca0c396684c629f4842427dafd8ac4b0f8db5d1ffffffff3d7a634c3c791a10486ee0e80881b3195d868be5a1629600aac421aaa088d6ab010000006b48304502210095c02921a4c75b9a8071df6452acd38b3e4a9ea1a82941f989d55c22da54a0e10220753517baa7995d58c8d3bd0bb3f1293af1314894db76bf22cc4889051638ef02012102a3e820b9a247ff29ae5e7fe2e5e70bfd12d986d9e8ae4aa69fe89f52067ba6c2ffffffff25156b36235ca6e80872fde00c3269b05e5d5c98bf00ec844d53dbb15a0ae1a6010000006a473044022076adea28bf7f255e06fc0f82c2b9011d63973b072b1a2a5029cbc756b35ac3ef02204dae62295b830281c1a55c06e484abafe3c0a5c9e1304be29b580a058c73266d01210372376e98f49ebbda97f3e1a5649bc557611c259f658c3b508addf18965ef4b1bffffffffbe7a257ba6661177f92060d68233cd6ea7b82f5e95c5c365970e36512c8953f70a0000008a47304402206e9e57757638279862f6d7ea2571d68859333cea24ca0697de6e9b457b8f284c0220537a07daee2c75e85a084c2adf02454c8608afc290d925f2f09c4ec9b99ac73a01410490e3f532d4cde4132df6ca09ba1b2ff15334d7840368d4162a438f5b2b1950039f1f0e26ab4943962f1831dc864d0dbe46ebbd58b727bbaffaa313414b229abeffffffff5ad375aaa9333f0b20cb81cdc32a2b4a142b1d712ae0d06889228db639a19d48010000006a473044022009661750f8a23b390771399d8778e3ab6ad1cac3afc8c389b9d3ae28d18b51b8022066e47b2f18395c01208342e790e5888a055456ff4b9de28b7601dc07b2c42004012102559e0d747b53e712a043775f28b9d115285450c57e34974470168bb09bfd5bc5ffffffffd7cce63c89ae17eb8b87ce72170a2bf2d4cc9141d2c4a0982cdcac55fdbebe76010000006b483045022100fabd4de453fa097d2adba774970e1278134303fc7d78e2356de7600acc7696e302207789bb2f9ee41b0c4dd9e7758060cab139a6aba09e254b47c3fd64f146f0424d01210345e2dbfe26097cab6f53684284a27efd5eb704e40846f8139e2175d8b3bc0db8ffffffff7af1de4cff12d425621614b1497f4cc9b83b2c3590f9c399ae677726e078c048000000006b483045022100d70c92757c4b9bc073b56932cb25a229b9f3435abcebd19bc07103629217caaf022035a02f69dbbcc7d0c31ddc194ea7bb5eed6d80f9b5fb5968e3e5bfdb3ab849be012102fcfb0d761ab52de086180a5743d7b0bd8bc8176e01313b824c643827967b2a61ffffffff02325b0300000000001976a914995292c35f9439c503f1922854f5ef5df25883d688acc0ffdf00000000001976a9143b7cb2c7f9c71654792e9bd300fc2a16661299c488ac00000000" }, + { "4338106bae97ed82cc0a45edcd65cf8fde624d0da21e5ae82924964586fefe88","010000000752baa34d16695fc1ac2a4df8f6f5ce4cb85a56fcb0b20634646e6177ea950b9c010000006b48304502210084198bc998bc0f6854cf884ce6a95ae0e2b9c2f4827e14be245e4da6860924f1022051aad7f39659a61dcdcff7da0f99e988c14471ad109b30f2266e794de172bf24012103255d6ad4a0aa5089ea66d8ab52fc8ed121e7b9b8918bfa2c69782f294dee025bfeffffff7f88d022e20dcfd9dfa8ed4dd983191f9ae949e6243396630e380fad81a9354d010000006b483045022100d7c615f3746c9bf15e3a187c61c1c10322b508f4e74dd92c6b89d4a1d2e1e55302200ad7fe01ecc10c00fb036d32974fb6bd9024a5a389063297e586081c403b99240121031a89dde708addb93c5150f8235452f8f9ad2b6f6a5ab4acab705bdbc85fd6854feffffff53c54afa1726584184ce6269d06f14a279af4b0bcf2e209d587a424e893c801e080000006a473044022018ad07e954f63d2f557ba8dfbdce5adc409101d0e4331aad3bdd600175d987fd02207e3332db29bcd74d2eb3cbe21b263971a1c10aae024e45eac26249885c6e21e9012103ae4d119977317e721078f4384324c00c4f9515af6bf0c8206a9f239a2bfddd49fefffffffd9a4b25eb18cd5b8b5d1586149489dab8b2b57f3d4c68f7db954ec4bb3aa924010000006b483045022100dba0bbd520ee96c4957ea90338316fa95f23fd75e7a80621825d738705faa96402203d905a4bb4d8c4e925c3b152efd6cfb3db86cec970fcc5b13f436a6d59d3cee9012102759568466e5b27bea867fa746243942365dcb466098a6edd0ffe3f399154a2c3feffffff766613364d87734d9ffcc6bf1f03a388e4500de293a5225ceda703a6b88c1b11010000006a473044022032637b801e22561daa787a2092834a025bd51b8e9f4168a38bd02c0212770ee602204de4486f8a8ca00ca48245f08e6daebbe68f6d3fdd788ac0962fd22441c0a4cf012102d9beb8388825b87cb38e84d277a77d370b2782889a41e97581b823df7e31a816feffffff2ba8a45ba2e605ef711afe9f7b6980daf15bbd2b6e9a2fd6ac19765903d5b172010000006a4730440220215f1d30b77f106068c730ee4309cddc41040af4ddc3792d8d14940b39858132022006ea32f81b8ebb775a39c57db150f3c79e7b9044a9d550abde826fed3fbd4391012103e34fe60bf0ca25fbbea1828c888e8ade1ab29fdf9349021e583cac650c2c917ffeffffff52ea243d4b084d63f00bd2f76c2b7dd773e7956c1cc0bf1a75417afb746c9327010000006a473044022072ce505aa5c6f8946eef812e9da4acd5e2badb027227b7c1e9f11b79b8d1545302205bdedd1b27e201c2ebe3dfa155225cd7a2da71e6bc3e33fe3b3a3c0e71c10f4b012103f462af6fdeadab356fadf94a64cc7aadbcb899879926cdfa91cdb1264e3c1cf8feffffff02c476b703000000001976a914d571e611ac0aecc54185bbeaddbb32e545abf52688ac15a20f00000000001976a914bf37e914744034b76751e071692daaeac52fc77d88acc2210600" }, + { "3cb5ef1a3be37800550f3b66276d5cf6220e72c2b42ea406f30448f540e2f478","010000000a117f96b4bab16b481954fad73062bc4d86adb259527dfa378303caa5fa7aced4280000008b48304502210084d028c12460425f0f5e10e1ea35a5929ff5a76188988422aab1ad3e414111560220204cceae43f9523e71450213218d51adff533805a207c40c8d37c2c65d7ab54601410464e95413867e64e00ce73f7745f0ab8d99816a4eb3744701890338df4f0460f64411ac7344eb4ebdeb76327176fe3959fc365244f3259028e92e62f056eaab59ffffffffff65812d714f64dd24592fcb77cabc55154a1be91fbd5e9ae320b30410c2a5e8010000006b48304502210082a7575ba55e5edd7811fbbaa8d49b92716d382b8abbc328dfd27404947fc97a022078248744ba5fa47d95fe7a5f65c080891ed42b204c5f7fb9bf6feeac48a757580121026ee861f23bfbeedd24aa3538498bff7e50319493857ec32cc473e7768bb19aecffffffff05ef81a068cd982f3f1da3c2ac7333584698e821ee35716531941c21e6a665d2010000006a47304402205622fe4581502ff493d74520929c3887be923d356a25e3a59396e6a5ba62e7de022077feed1a087dfdd526db3f4f8b6baca0d64e5d08be5a4de09421d29201648bc701210371cdecf6fc91e24908cffa7e9ff3af107e59f77b3cfa467d09480345fc4026b8ffffffffbcb5041d9f05704f34cdfcfcc8cd8486c8b4bfa2906dfd7e0f5bd0acc7074fad010000006a47304402203a4f38cf6cf8352b73a63faf6aa0cb35cd02f3c4083fdaae592075da529a89920220457fcf7b6c96ad3b6713af1b27bc74cba379e3f40fe6897ec57ecddaeb4831ff012102d28bf0c9888ccb7b6f0f9e106b9fca08ff7d62d0d8aabb1a4c1f0a03d1c7b7b2fffffffff50dd9ff03d5d4db7a8f04fb3132ed2671c7874e116e474b7669ec8505cd5ea50f0000008b483045022100f93078e141f66a28b865f36cf098dcf444f92956b2d98b1bb7dc3e7fb55e88ea02205f42ac6e1e3a8dcdaea6cd2e6e1dc15a2ba31b1bed072321c7b42d92700ea969014104b870ca4578f6ce3fc3e184675e9c17ef6d6d94078ca35c8ac003d63de276c09fec5c7f3b0510e66d7e1fcd95e047f16eeeb46fd73d25fbb502cbdee423e6765dffffffff38f82a008b05d85ab65b5b7872f2b78bae8f0a9013b7571832ec0a33ea5e6b68010000006b483045022100bf81e9abb7b4f225fcfd17a357a8cde007417ce91f9594b67657198c8b3e2ba4022004ca6f58cc2299d3722ce2b576f2facafd7d3183b30c23cb72f6680cab52bef801210389ba179720e46959a5b0a89967f9aae5a682228b067bdfd22038275b89b4a2f2ffffffff6ebd33b8257dca01fe00ba3adbf0701b17341a4830559ab085c6b65e773dde62010000006b483045022100e22b056fa091bd2170994520af7e0796f2a3b0c6d1f2dbaba93a61a5448c155f02203fbf2a6982aee38b237874db6c245e45bd7ef341200f3219d4f875a68348d7090121025d294af5bb846ca076ba443c72135afd205c0b754f03c1c96f84978555299296ffffffff68b8f57b1a3f57576014e62d023311091a9b4b9a90e1adfe95b5d707c293dadd010000006b483045022100c7be3c1a152dae92956277e237599ff331f9448ebb6ed7b981e5812e9cba5eb5022079c0f14466e5ab72c233aac4fa1820728dc59e7ce7524c3873d5436bcd512b8f0121021c683cda9956b4435ee63fe8d9521751aae22644b370f9429c2de41f0f1c2940ffffffffae99188d894722d18ee8fee1b541ce2e4eaaf18ee4132d8ced029aca7cd616d7610000006b4830450221009e8889a8fc502fc221cbc756b734875b89b2b5e9aa1945c61db23c734315f9f902201cef39c5b57b9f6e8d34b6c9da6b2890d04031f1ac617dfc4fbd18ce1873af9501210270d9a037b27e63285871018b1c283f89c3c427c36af63119be75bf495801862dffffffffb862258f1966bb7b5f7fbafefec51a6bd2575db1e506c5236dff2bcd857c7fb7000000006b4830450221008ed9eed6f8c62241e28bb2da44332d9b9547012d4d19483bb82d9ed04c47ddda02201f2b37a45872827e4a8a17cbfbe32cfeed0a8ac1f6878645c1e18c4f196ab1220121037771a92625a49b8f7b9a041f5a025b2bdad24137d832b7ed6a9ae7552946f5a9ffffffff0230d39700000000001976a91480f4593e933b850de8b290ec0876b37dd472da1588acbc180a00000000001976a9141e6738f1b31ce65f525ba3c321ca9c2dff16d75e88ac00000000" }, + { "f710bfe14e5d9cd13a6a15c8012b7434b9371566895552086126a3e480eaf38d","010000000a25702f006ca205d7ce338f15631beebad8349514aa5a6ec4dd8d66b8bf6ebb4dec0000008b483045022100f68bcbc29a0060a20b1389c9f89766b60653235633b3b9e479668d517f09074002203c85ededbd12ea9fc98a5dbc43d5fe24bf42b66319491631578f1d3fcd6a4656014104acdb0e610ac7465dd577f0aad154bcbc899f7b2cd4157403071b13164bae37b1b512ec9e24ea8d584f0cb2c52d7509fbb736f1f2c7d85c762a13b3acc58d18c8ffffffffdfe9bbc516896b0dc87c6414528bc1416e6ee3fcb9aaadbca04ae0865c30db94000200006a4730440220687722112bc1cd2cdcb0cf04c11a5a1a339ff9bc4d907cfc3c5497c69836ace702201c23dd97d4a059fe100604a6d0ee4dc294b04685118fd8240346c7871e81edd001210383962c3ba63ff45118575e995569b6d3880853d79b2eca855472eb1ba66756d6ffffffffb12f599a3f0166cd17e32ce0b00d78f35d05eab934ccbf1413f8f6b86e2eb3c2010000006b483045022100e604e2313501fd1a361dc91cd266cc175d131e790a6ad31c9ef7a19e3363badf02206caac7c77aba1c14a6aec9a896ebabc92e837f4f89de6aa74b39f2616c2193af012103d13bf7bd8ea276f8c0a9e503d7a4ec5b264d3d85bb9c2aec910a8ff27a841024ffffffff82c5ec81e71d87c24080f2865ec71bc8e7828439319d1ef5d0af1ee5ac88013f210000006a47304402204cdf3a0d6047786b6de89a312a052e4748625c24150321921ba2487c316cc1b1022030cee7e2f973628e60d411e7bcf657d929db4fcfb99fc3bbe1ead8e822b9d76b012102848e51522284e4d5cbc093a3428e1bc939347e1aafb3cc8f0c43aa20bcf91c2fffffffff1eb00ec7229d703fd30bcae46494850556498fa94b515c77af16ce2c45521e50250200006b4830450221009b82599398bdc518cec358207d0dcf83a3622ed5acb3ae2baae7156ec8180e62022072441375f8a1fb08617c98fbdb56d2b8e98c60729002f12a075a8504654c1497012102d5329cc656820da883b596223b94e1865123334a1fc8589d2894146eeaab8059ffffffff3934a50c4e953912ff56f8eefd65d8ca971d01cbe02a51b62e13c74ffab8b219450300008a47304402200c335f4a0165a0d2231cb562b53d627300639ad9803bcd462786a7ad02c2410402200508307e7b79bf8dba434bb5243b4fe58a575ec2f900b44e78deb8d341db9d910141040a630791b21f484de593b6c868f97c72c9b62476569a9e0a1444b29f2d68176c2f50a0b7a672d2f056f5cb35f977a3ffe9171063a30803aa4293fc0e96062bdaffffffff27787ac83f550d7d175cc6d2ed2a955c90b130598735b402411efa6199fb217a270000008a473044022056e96258a49985470a4f4f6eddd1e0997bb8f3bab02cae345c71a8d421e39056022002e47f891a4c2dfbcfe784a9c32e38c6bc97289a7b9f870ea69d22dab5176b590141047692834c63f2c25d68505431fbc40243f1ab3bf7772646fe9530ab91296e61ac431cdd4cb0e4b5258cef16d9d07a8fc7305fc404dd41f72ea09cc4ff05ae96b8ffffffffafec175cd47be13d394aa2f5fb150a5c2628ac6cd4563272580c7864bfa47ffa0e0000006a47304402202154eb21a2905fa67eb57571d280a76f8f5ac665e86deffea31191708d40682a02204bc8625029c4a4047f7d540563e818f25a89e183a32de54a2ecf375838493fc3012103ce664cd838bddd78926aa78ffadb68a2fe7d2c114279ed2f39c18cdadc68d4fcffffffff9d23c8a13fd40d0f38c9f5867ebe83ad6bf43e9774be93b599cb9583c1faf52f580000006b483045022100b058ce84767f1d940bab34d435486bef41c4a736abad37b84b335a4c8980d15802207fe1f6247ce03991ec55fbb11452010fa200c1ea3c9a7294ae8a4543e8a228900121032000d2a0f2ce60d67dbac0ea0415a5c5e15867d83bde558c6ef28e4b16a30f95ffffffff7277eaa3baa631486caf464cd87178fb41b8e98b3905c020b34e035ad13403bf7c0000006a473044022050486c3be63ffa0fcbeedd15834409498678e344e249ae73d624a326c1ba3e5102202e0f534915eaf4884a4f4a4f6be196ed2eafaea03bba50c53b7f83e6c96734ac0121025c2f36509dd635d56ba650ff111c4959a2d9c64f34834a49b2a4ef2c84b7d592ffffffff02106d0200000000001976a914e26d805c0e9bbc4d35eaeab93d7c5e977bef2c2e88ac465d0000000000001976a914d016d20d5eeed082e0254cc5863501214ce003fe88ac00000000" }, + { "fbf768cda9742b18b4f86410b91652329305374491530926bf8699c4f8b46fa1","010000000afea71736782824ccc968f551e73fa14d3b409ff6606b4c47eb68804d5b6c980c7a0000006a47304402206c6d5542cf31a5452616db71760b0e1925b3a292d8a50334f03acac688aca3dd02201a209b687bb96b630bebe6a57507603d29a2dcce45e3201a25843adf6e909f7a0121030a0f7dad2f4ad38c5c6ea7afe9e1236961137014e84f827dfdd9ede22affde0cffffffffc4ed5e46c3b7c5050c779575880beb41464b05690efe5daef592b8c4b93d122b190000006b483045022100bcca32d46b8f87868041b8886061cee9388661f672464dd239adfd0f06aebcf102200d11e30ed90d23fb6ee5c4595f42a044f757bf80a7159e57e5fe02dc1e9877e601210268e4c285a7724f115253bef0722027641b9e01c6b1da830c9edd7f3e5b6c3cd8ffffffff44ec88908fd56c5897fa3e293bd44b541fdab775ba2af4952a7ade76bc5d2dd72d0000008a47304402207dd895b26a15d57520b1b24cfea642496aa50490b42e231142122a33e2fe7c1102200af3c9038813cb2e1f6c5a35246cacd15eac1ff9172c8579d90a109a79284695014104f7fb9f62c2563cbe6da4695599600652a823d18ce7155b9806fb6fb97a7056a44a2b86d1eb0250694768ddafb48d398a8bcdbb78a76a8e8541cdc49f30d0b1eeffffffffc8a0545c9b655e5f7a75c8548bfebd786a58eb9da62c984b8411da473547dc39010000006b4830450221009b41e34c03e76688b383dfaee71b0533a37e41f969426ff32dcacfe76710a0a402207b1ee61807266e0cbc092e8a1653db4861fe04370699cb2cac08d712d031228a012103dd13fbf78cc80fc7bdcf24a10025d061d37fea6a513910a68bcb25c86af6ed15ffffffffc39b0964196a91ff28d85726c4d0b4506a9e95b762a7356a7c1e0d5607281dbc450000008a47304402205dd8797a08d5c050248c8b42098ec0e89a27617ef848db6dfbcfda5512d813940220472c59f35460b6c1d344b39acf4149992970ae25104d6d1aa78bf747371e3707014104ea59343fbbe8b5733503aca0b4daa04805eb6e166a643bf4fa7a60f7fb6395dcb29dca6bb8db05251281e3b16fe5413f251dbc32c7c3eed5f8b4e7f5d220b2dffffffffffa1344953297c710e1daf51df685792c055af681722b0ed8c18b1a92cf6a8d3e0a0000006b483045022100c8607c3ac5e8430aee23dcdd9ba1f38dc73261b8c30c4bcac7e301873f7d5cc10220789283cb8e48da40bb5d9630f1b5a90386ca02726eec572aedf76ef3bc9eb790012103f5f3c9d0acdb4167d9237e900bdec198aa87c5b8261b6cf09fd75a153dc6a490ffffffff062e5300af4d08432c989c2050aa93ea8b6c076d08749028f23460897e44af191a0000006b483045022100e78345d4feff5f6d5c53a378eaa9237c5e045a1b462e1013aad6ac93c310e89e0220325667b6f1569a7c0e336b0348cada01e5ca98fff9b0d8a60e55c32e76b67748012102aaa5e76d1a71f6d072ccdff9753a4a61880c46f2159cccd8e04c798794c2d466ffffffffdf27dbdcef1f4db877330631cf51c3b36e233e743bdf31862187bdb3160e0d6f080100006a47304402207b47670880a785f74ad78d0988751f0fdcf66c7afa2e0c0a747e9e2855dc8a9902200de2b1c5c0dcfffd858a6fe6dbd696100cd56a30c5f0af82b0059fda620ac05c01210261b07ced5c8a578dddf69fa40c9f1ecb08da8bfdba04d3d2c27132d9b8fc819cffffffff28ce51ff5da44aa61f807e2aec9383428bf575f81d7a4108ab5f4bbd7c1641361b0000008b483045022100ef02ea894e88d22313a54b001719a9e9f6f7c3587cfa018f236e55f95bcfe02102201dbee0788057dd65b4868cc7552ebcf78ed55ea2b0dabbb1859bead0bfc1f639014104ff3cf105f487d02a9a3eeff847ee76bfef86001b3006d70ada70c4286d35ecbdd8ba97249f4ead3ad103b62388cc8bb10afcb325075eb2613fa2b9df23ac366cffffffff6476fd8ad374f8dbf731b094907d4ac4fc68195d7466d092f1201e20bef4137b520000006a4730440220028964f41f2c6b3387485e378ba302aec57f43188d0e30d38970e914f415295102205a2b2aac7029ebaf6b4912d3ac2bc0ab6f663a4208778aa2bebf935421d6f200012103a5ac1c3c2ce5b716f6291509e6e9db1bdcf66b3a58b5a6d2aa1194d3bbfc0079ffffffff0207650000000000001976a91498fab36b8bcbd61a8b228ae714bfe6f84f4b3d5888acd5b20200000000001976a914df4689852702444a1099ffce3dbb918f4252f9fc88ac00000000" }, + { "ee6a63c243483f084c21cec59acba033613ef05d8b56cb46ec1c86123aa6ab5a","010000000a845169109e84487e56fc1801ce00254097c562fd7291588fb616615aeaef395b010000008a473044022071e04b5ae5801eee9de632712da60f8743e043b98f0e10ef2c6f9ce36db6719702206b5da4e80a0cb4842dedd16f6479eb666638173e5c59fb0de93980bb2e6da2ba014104cd9d17e3e96958340448fb79feb3712620ead92e43385f7465a70b8a0997466cab9e72e2317c47bb581a4d3b12ae1c492e8e65524b0d22e0973c1d2481ed8f22ffffffff6dd4263230a80a97599f1ab869fee1c982c4f7c1d5cc0982229a0606d0661b5b000000008a47304402207ce61c6924afde082b3c2c4403060ee2a466302c7d792416a53543d2974e5b8402204309a7ec1a69ed5e8a49d3383e4d4b52962390606e429465ac33b07efb5e34850141044b0e9dddfb8fab0cca70da39340a78c76aaf672bee8f6ddd1e23e2ec27dc12f52f23033a41fb034f34ca80bbc554aab843b74faba46e7953e19198e07eb07691fffffffffd28a8ca4b77518a813c32f7c34c1be6eb01cce2c2b198ecf5dcb5602d256543010000006b483045022100ae84aab4e061396162645aab88d5e3d8e773c6dc914dc9a9f900905dda92de61022017ff9cd96008a3f2bf39e0bc0ddacd3b8d18061d6624b078df9f35b3282a2e8501210214daeeb90ed49a404e7c292cca423e4bd6a5b56e8f584323c16472b046f3214effffffff4fae6fe2a56d5a6f44104350f7ec6228ff0ba75beeae1979020bbff147438926010000006b483045022100f7341d1970d40c2425289084c979cc354d988336a0658e9e2fb9c0865093e2e902203e16d043581c4d2365ca3b82d4b787ae21d475a67b7b9e8bc4bb6001867c11c10121030ca282d7ca4ce738b377d34df8b7a9b204d234079bb549d9f52a460d9dcc4a1bffffffff8cbede0ec7bbf39ab680f611b546f8aea3b020f9589a93f9bb72a336133cc076010000006a473044022056e99c35cff93cb2c1642d3e7afec596f9393c22451ebae18bd788c232bb43b00220242ff723fcccd54b2ba979d3365cfc0b042a328a632a5c16d00ecdefead2c0c6012102bbaa6c8b3dfdbdc2c66750bc3b46499724b5a09f9e635e2afe1bd259ccc8f7ecffffffffd7ba6c1e4352da270abef93d5353fd0603119723b1dd6638749fdaacc299a1b3010000006b483045022100fe522f2209ea50e2d08ae0d92f78edb3098eda814aa5f4f31146c251dcd16b7e02205c59b31e7795183100e42c838b28c9ff2d87cac41eccf9599a70813ba44f6ca3012103f5b19ee42056b74c0d48d2966f45bc8c488b3b56409268149014b474c6205142ffffffffa40abd2a264a937b5129a618af7c28e4734c7c0b06501dbf73f5250594dd015a5c0000006a473044022058c836d8dfe1eb9d896c031c43038602c00574735cb7cc5b9357efbe2ae58dd7022077b81c5d6008406369de57f1bddb2df3b2b656dfd7ca1e621976a3d840ea06b1012102b85f172f8e98f1faeb5a83b86f4208100aab758002cd622f7ba77e0acf73f11dffffffff279cd977a3bddbebf7354baa637a8e506f706c873d884c78a8bf65194641a4f26f0000006a473044022033831770b44a21a34a16b3289e9edc0e8f693a465c0b442cd3760bd2192c437802202b243897d65b17504421916f9b3f2117ba3a103bc9a21ba8a105261c4e0b7cf8012102475148da601c7e1e8ae685d1ed5e0283221068aff89695a1d295644529f1bb25ffffffff50f869f532ae3a8279a73bf46905999b95e54b2f249ca4c2dae49e72f06b1353010000008b4830450221009a6b9c471d63da9a4e49a17c9567efbd3b976d64ad0af10b71b9a43164edc85b0220381acac9e99f104a9829c81d36683848b6833dcbda7f422cc84dc07e2507a1cd014104e27167fc182e172ba4614c4d42bac392ea0b6462a120cf56350f0662409872263c3f2c0363bc1a0a02bab765bf31b30190786dec460cb9e0fdcf862699fe0feaffffffff2fa1b1fc3cf795faa64a316a1bdefc8f412149a1c4d49ae4a9d3728d4bbc958e010000006b48304502210091fa57f1bc7ea5394ccebfb14b638bb8a24a82ce8c06a5c639d46b0a46cc913b022010333a2f8b51b12b409bc9087ca7c132c857b76ad9d76fa905e391a812373be101210330410d351572f7fa2a78256d272beb4883b060ffc6e9f85bce64e4cd85e87a93ffffffff0264289300000000001976a914763d173eedd8085a10acb73b7e6b96232a9a007a88acfb720f00000000001976a914e8243d97f3b0d413397c48ed0ec52b43c320cbda88ac00000000" }, + { "2923ff137f98885621cc9ee25ca3fbc09487be4abce055343c2d7b27ea758af7","010000000a5629e57272dce2c52823598bed075f301fb70b5d80e22715ba5d7608baa45f5c5d0000008b483045022100d82b22b1e9d43187d6bd75cd4bbb9957d8ca2e241992fe7866a7b1e3da39c6a7022030a98d028ba422db5901088c7b357ddbdae1e4003be6fa4a9db9ac25e6ea7e05014104a1fad4a14acd154248a578d0417c42bab54f5e9648569bdadec23421b723ae21eb39d301f2acadab071f7adf7f21c5e949fb3c0c7b2751179e990141f7d2a4e8ffffffff17abc055a791218317b5ca422b2a99911c7b80e09d95ec4633980a31583230b3fb0000006a47304402201fcdaa9589ce7bafff5b726f4a8f500b3cdb2771eecb51c0baa1c403b540df15022008f6efcd0354a09e3fca1bacdd0de50a0f287ab7c68d618bdf2f6b8df3c0204f012102b2e7baab80fa6667fda99cd1e6fc86891e96e755cfc224cd100b800a656bcc2cffffffffd4563edf159f892f3bf8bacc50bd58efbad6f516b9cca353de1765b88789e56baf0000006b483045022100df50900dc8c7b1bbf7b7e1a7dc2947db30287e94737c05152c7d5207617d6307022021f73788beec73743c37f2a0822993b94ff938c34258f557636e51abea967119012103aa533a1affc0a8eda69bb864c127a8b39235333e01cf74d7ebf5dfd7a442537effffffff5402488b4a445d39d53442dfb81eab394db1ff9da519311c33d1244246701c7bc40000006a473044022022b020293a0eb7fb1079584871c50dcd05c096f76bd99585bfecbadbf5c7fca402207f51dadaf17ab7bd44804578190deda2780194813c97b17b851e8b129fcc50a6012102277d02b63cfe8594bc89a0976842374eb5d511a886ffdefcbe32f7965cd6e72fffffffff42fa01798cf8d9a67396d54cf006a3f0f84f9b6614032e575d16e0ae887607a2590000008b483045022100c085a48038330d20ed6e1a974a34c6cca99ce76b3f467deb2e0879f7ae48787f02200f9752ed865d26cb7bbb83eb4b8e71fc4234b8432862208d20a820fd0ac47418014104b03a03f587d99f78f28f7051b86db4f3f76ec507e881f8522cd1297282ee2531fbf046e974bc6b9e79dae5a3e897831e8c313e2fd6d4f15a06b872a883e2e561ffffffff17abc055a791218317b5ca422b2a99911c7b80e09d95ec4633980a31583230b3f90000008b48304502210095eeee15b6c7a58001cf4505f6d19604cba105a15c9a7b0a826ae3d31b48f400022015bc4086614916203138e13d7cbdfed286aec70c3ad3f9c03f42be7dcda90133014104c3c0ffa6f3d4a07f7d2e7fc58bc9e92abe0cde590e03326342551b69018e6622466e271effd5927bd9956831a036b313343c58cf9f10d37c26715c0f2e6d4eceffffffffddb54c07b15e00be782ea857e6b53aa1e5d5ee6ddcc536a3bea8a149dcdaf608010000006a47304402201fa171689905dbfa6852b90c34c82af521fd6f0db0ab56633c3d2dd0c05b61260220621d76b13183dc68bfd28dda14bc3309c97e554944032c0396850e0986a880ca01210272360f5a7a0d37c3290a6615376a8d4bc1c6082dfb2eab2b56b2420d798d8825ffffffff17abc055a791218317b5ca422b2a99911c7b80e09d95ec4633980a31583230b3e40000006b483045022100a279a116a7b35901d9f1895e395c6f081ab5cfd4754f784b258e245e846fecca0220327fbe5e59b5099dc1b4b368fc756483886ad3638691b9a8a85dc08716d5015c0121036c8660fe8badefcc5267ea3c89141c71e0df0276d8aa32e7f7ffd7ac3bdc1ce3ffffffff3f002bd61c223fad479ee941c7a8d7e061a41e46558e53ec10ad468933b3ae73010900006b483045022100836c13acfa23727923fca86df9e4a19a350e893e34dca690aa99262baec71b3602203ea0613442742fcc5c08abbc1d88d817d9369417538d24e48b58dd29bca30b9d0121024ebaa3682849368c229f9683cd454c638c1c56653c0b26866b6af0d78f85fca7ffffffff0eb9b8e3eaccbaf5e9e0880a00af8fc0dfb74a3c795f212132b942287456a57b010000006a473044022016610b65746a0e3bd47226f16f15c91d1e63b2fc149890b648f09a216c2fa8ef0220435b1169e2f4030b17f9cae58b941e5f54887ae5e7fbdd0152e2b1b06d072e92012102a633622eab61a92a849974155ed872709c73ada4bb2eb0c42d458811af682a17ffffffff0201720000000000001976a9146066aa54181d222695b12d9a0079f274cc66028488ac9d270300000000001976a9147b18c29a14fdf90eeeba844f3e60f8f5f361c3eb88ac00000000" }, + { "d982523c3ae2e93aee84cf813093cbe3f00e547fa90c78d7f5d5c2b03ccfb192","010000000ad36f37cd5a59619049ca3d095275a0a940d32015d5063f27a219e9b1df409b0ad10000008a473044022014f0f599d98f3743f04dc467b1c7486817613fb318bf3542c432346fe232a2e5022005107a7c4879fa29a7951e41190997a828e3384e5591cf5f411422c477671b170141049a1fd608aabda1f8a45631a588b43bb346061d8b074662a003a1c93dc381104acaef2efb4db1d6a6cda0d0cd3967451387e2c6f056a8b7ec15dc96606e40b58fffffffff7af72f6659de00e384374aad00bd711fe01a4f03ebc732b8cccfd744d510ca05210000008a4730440220124fb22d750e442dace0ee7e93a27d221f04c788a3c59e4e63e0527f285a1dfa02207cd1a7720246ded03b6dbf7a0d2481ca93bc50ce45a52167db50eafe5d3358c5014104eccb0ce432c0aa5d1c54612cd723d74a7606badbec0933795491fa7a0bea2af0ad22679c0a40db6bcb67b6aa48b66d8bcc3f684e9ccc9b2aa4a8178df72f3756ffffffffa4e9334c54188a10958a1973abb4087baaf1b6f2b4ef53c1454f8319279b2328100000006b483045022100a9168ab68686b03bf76e8cc54e49f845d4ec6adffa64aa894ce60f58cf4bd2d502204693f82b6230b15e279a1f1b42785d5f8b966b7df45ec5ab18ff4ef9fc5904f2012103078ab4c9abc773f3beefb68b5b2536761abadce17634bbea413232b146877d11ffffffff4e4b8da7f7bc42bf045ef8e41a8e691134fb3853f01087211e4dc21b5e27b99d700000006b48304502210095165ff4275a28e84bd7978ff18ef4a1c5a1c4daac753dcdf583ff81f5c2f7a1022074475c3c0bbba2f84da36f42c88fc7ef51cbad40f90caf7dc7fc79f0f886975c0121024d56d6d4e443ee06ab75b095b76b4ecad949d3f0ca6d4cec0e511cd9d1eef9c9ffffffffcaa3183de583261f3f72fcfe357855f80095c5b32b96efe502a2a5fc6b4980209f0000008b483045022100fb0395e32d267bc7e8e96a12c62b9f21801576173b8ba872d8ccf28b6e4f68cc02207376636d047369c09da1ee8a0cd84511c2d13b1050fb296245f164dc0f63965b01410468da018513010a9d11cba92138d674c34b62e77e5a2a1301e8b98c4909cdf121d78d6743128f5ae69aac90fdbf5b8b3ccceaa93db0da0c202dec6bb936a456a4ffffffff4e299d20dc64b500c236328b6ea4aaa51234ac3dd044fc5b7c9c1a6deef0fa60630300006b483045022100efd1effceff2bfa8d7132d35f0d8121f8ecb69b2cc00f690d555b771e6b5e076022007d0102094a1bdbbc9f1293fcc3a72f4522a1cce942726f67a5bba5c85304d0f0121039b2335995024c37efc038fff73bcda111dcefc7a7db27da5715ef994e678fbe4ffffffff917f10cd69b7db834bd971c01a1d1b61a53178c938e9af3ed27badda53d55b7fc70000006a47304402205e96dd26c6a370e0fe364abb427af1145b56c16ea22788fd0aabcea37944ad15022039e79cf6409f883aa8ca73e8a8725e7515fc3ae62d571108a763e38f929d8c9401210235a211c46c3350ead76a58ed298cbef5505772803348280f45c08c3eece2ca27ffffffff4e299d20dc64b500c236328b6ea4aaa51234ac3dd044fc5b7c9c1a6deef0fa60e80000006a473044022054930c55e9a1e30e97ef4c280d8398c9dfaa9cacdc7f7b1900aee882682f6c00022029ca60a442ec89a8f69418bf8165c02779473a2a8c0fdd28bd59461fc5c94dd10121031d16aead3e5a98f0e6950d4027ade752c63614560d838849709da14f0e554d5dffffffffaaeb9ad4c6612d79edab7323acecc68d6960413603b41a58cb1744ae4c7a8de4010000008b483045022100d8857f3939015249f1faac8e1afc0ce17861d840a1dff556c83c1a705c4a6e8902201c6216880a5d4a589d102ee21cfa5b117df77063942d760d01b152ad181a498f014104e2ac346584493f09ad7bb6167a659502536db8dc814250e85eca77d7b15f080c001974850faffca358e2198ea0e99b87ac79f501a1ba24797afe9cbd39accbddffffffff4e299d20dc64b500c236328b6ea4aaa51234ac3dd044fc5b7c9c1a6deef0fa601d0200006a473044022003b0450725a6ba29abbdb1d6914155eea640f4dc61e3a1c560b55aed4eee1be4022020b0927bca47278ca24011225083d99562004c4e514ce3ae7fd6caae828d10d0012103c5b950b815f728a2780273703a194c56ea4699d7d8d3b36ccfb78843a2288e57ffffffff02ea5f0200000000001976a914fe603115fe3673360349421ee9262667eccf545b88acd05b0000000000001976a914ec680da34250f5f0106d9078c6daa73c4e43558288ac00000000" }, + { "5d0d5e24883a3480fd59d97af83831d9a0321d4eb81b3e2ed46df68b084d2068","010000000ae08c1460dc4c25efb5cdbd5e3a8b4a3d29d881dfd8ddbe7f578b62b398ab12b2940000008b483045022100cfc10ac0ae41342a7b1edf3f977c0c869d404ea55a561ad7db3fa88b7172233c022024303c7b154f3fd9d7924799fdcefc1adadb6bfcb9f85d5f4a76e6a9933a7f3b0141047dc1aebfa5635f6a2a05c578e02c7d81345d294922c8627d5a77bef932a759602d03852432460c8f2c0810c80c3e9add001157cfadda18654db0f4fe50d1de4fffffffffec4def9fd2bed289861ef31dd8564b125e5611533bc1772de006339854801f58000000006a4730440220610e419832954a2a486622ed2e78922fab349bf838f0b67a160e49f9329fbdde022054273526e935de73b193b0008ea93d12e5a60a804bc6c865b0571f2bd3d4153e01210342f67f65989887c72d08dd19e2109516b9ad1219f5e5c73f7eaa8d85d0850e0affffffff4c98d3dae9c7d2e7321520805c49826782e7082c62ce691ecf3e6865fd30ed922c0000008b483045022100b95e7768bb7d8c0865346a4c0ad531c0a5b13f1789aeee40762d13f1a79b800302201e6256227cdb2efae113c125131a943d19ec77eeaa44d577e17c68e0b90324730141041c2bccc4573ac535d89de7dca1004363e9fc4fbf94efd20b4a4d958590e65ba09c65138f59c9a24b3a7deb65c3262f4a938abef42859eb1d751ba3be4a63641bffffffffbe8e13a416b94faa0f6c628965e2aa3cb4e3066b5c3b2e9697f852b893520acd360100006a47304402204c7366585576522b52dee884bddfc9b69e5916a161b7666164e886c9787e4a8a02200c02ece6d1ade110274fb61734ad70bb9f2d276b72ca2b82985bcc492910649801210230dbaba41ec8dca18d52e83241fc31deb719f0565dfb622733c6621fc24f86eaffffffffdfd9723990a3fffbf0a596749acf6bc5687430f6ff012e703a46c62f167b69a0000000006a47304402205c77aa7fd946a8adc89f3b554c0b61e44daa51b6a76345a4755f3ab774e8a54c02206e71042bfb79dd383c176f37c4ddf63581fac13dc5e9bef29e4eb485cebd52980121032794cdd4914c90501867eace82bd84bbcdd80fc5c2250ebce7f72a8f646d248bffffffff6e00e82b41b5dd2915e53f37ecd7c06f83609df0efb44cf59bd2e0e1157496ab9c0200008a47304402206e6c167337d7dbd21839639a3afeb9ee24dbd7a7daebc0d35e365b30b3088bfb02203fb97e58d4f5b37ab6398a6f3247f2d159b48e579d2662dcde7ec71581e44fe6014104feb9dfc1330cfcb2cda62598cda3cd861d342bc732c487e981f0e077ee8e0c2a77aa6665974434e074e499c578e4f9367c0a868962ccc354844f5ea12f110e40ffffffff932a1f4acd24db5f88d182bd7b96563b629f8d7d86dc9fbc7d89dd6759c1ff31060000006b483045022100d645cdc7fb98a8ce77d99f48beca438cf4c363261cb136d7d62b6da6e5a4dd0e022053178607835afce400980e4eec86c82eb32fa0293ae85c696a4ab9f6f3e5d1fb0121030004aea7cdf702c25c9616b79e1960830b2f21f735acf867f8a20a9bc2e2d81dffffffff32596e8fe19e8428bcb0ef3e24a7562d1d15a4fc91fbb5bff3920ab5d47d13fc0d0a00008b483045022100d56e130566c886fd4646605e34ec10471510ecdffb32ea479faa5feaf747462502201d96028b98593baeb985c776337cb00805fa5ba32194c10502d1756d0e251e48014104442cf93ca6dbc8e3ebf5f3011ec405cb8dff5fd0ff8a36c29e339ea1f540118bf9284efe741f747ede7f48724c487154e773cd82b090d6a23aa81721124df25dffffffff959c0ee064dea7e5d7564ffbfdbc0fc090fc9a35b46660216df53de46d321e8e320200006a47304402200b252123a192a18a0e07b74e6cc66d66fb37d404544e32ffa796b4fae071eb97022052518f648d5cdd2646a5651eec391c052e5c804789ae4d5627367d2d99194f1f01210217fc3b94cc6b00fce843100c4ae7a49b079cba23a423af71fe87b0a2b0964d80ffffffff1a18d6ac728bd386ca30483bcc0de5bfed273477c3da72d2d80ee01209362396c30000006b483045022100f39ecc941b744c4173d3154f02215f1c6f1603f37a05e32d25a6e8128a4841ec02201ab265263bad356404c15ed91529c63022e138e391d1e7bfd800e6e05485bce1012103ce3ff8f8da7bef76db8784e1254c2b0ef4c0d62db92db0e0381a77ce33c40706ffffffff022cd20200000000001976a914d9e6918430ebc15d76265bf4cc4064edff1eb56588ac82680000000000001976a914647128589e1f4887cffa0681691d924d663e483188ac00000000" }, + { "ca032960a0be064f9aff94bebcd780a76186a129fb331dbc1596be73c3b980c8","010000000a96c4fc41622285ca76a35900990e60be4991e4524b607daf30d0a26adab32bd3010000008b483045022100fba83e16605584ebd28a177f6cb9d29313f79e4d3b7c6f918e80aeecc94f1cb002206955848b20cb961c2a666732f195a36853ce7355937812d210c22d991cab44c6014104ffd4e0a5fed166852aec9f2ccdcfa14c985df242d67df7cb199ded4ca2a5a9c0f29ee81a7bc7096afb102ba0211cbab7bccc77a6624b948c69035bc9587743d6ffffffff319c2e76e6eabc05142be5b89958ec5b09dff1fc70e8ea155d85e43707a71d792b0000006b483045022100939ef9903caec0d5dcc9724abcee7dd564caef5fa7d2a0f3a1b2b621536575b302202d7751c2796d699a606dfc2a8e118292bbc73c2fc713d7a56a6e11e87725b37001210271d8bf3982cdb453ff4ef188e33e8912a3d51759c82070e689268b3ca72e386bffffffff206557bab66ae2c9a2f9a02910e29e3a6d0aa76bc05c89f368cd2d201264ec9f980300008b483045022100c2f9091ddf749ae9d98d1b6da10cd484ebcf735c7ee888fa46acaf78dedfd96c02204fd31f358f4cd5f742bcb6dbdffde482c7182ce804b6846e5e10f1ef4419f97b01410460161f22b247fa9883fb2c16bd83df14892e8d89a349b26da27c09a211ec0c0c179401aef8c40b0af31a6dae28de5de11a65e994420a3bbebf13bf1bf55975d7ffffffffbe8e13a416b94faa0f6c628965e2aa3cb4e3066b5c3b2e9697f852b893520acd800300006a47304402202698ca30749bbdae17a69cee0c7d159a11429602410921f66a5f420a05c3b2d102206ba2e18c04c081c06a4293f89b4551326150a5f4513d44f6b670029579d3ccdc0121020ddd30876a23bf220de6e831bd30e47529c06a7e5803eb4918b8cf6a6d4a2ae8ffffffffe46fd28b7fba86e4386da0348b553bcf5d2d338c11dc31611b4773b0e9533a92050000008a47304402201289cf822d268bb516f412e628e11ca519db48e198dd015c5fe83f9040f1c3ad02200c343b2bfecc6f42391ebca4f95c8e4f63d4fcec944034aae73ae733f869512b014104795e5e285cb9f32a2c90e2db385033577502aed910215e5c7fecef089162558d5ec02327f2a6e62da26fc8b191996ad439793d41fbcac3a3a87c67899c2b6947ffffffff27e0a83a6811b16f626dec41179760eae2021048a61a50ebfb08d623280f256d000000006b4830450221009e8f3f782c218fee6fa8078af459deb0c76814e827a07e23d35ccac7c52e37d502204c9cdea23b1ac3c3aa610510632d8b4671c14679b151594e0d101178558d4012012102a37225859872e931f9887a29c44e5318b2ab75568461e6c9657951bc205e5edfffffffff9f32a84a7f7f9684e7fc77ca598b2d3448a5c2375c8ed7b9f14173dc411c6cd1f60200008a473044022036e96e1ae1bd595f012f0d8e11c87a843f9d061cc64513b72e1afa622490970b02202fb746cf8058156d8ce77cdba2c730f840f6cf4903bc0cc48d2a1b54557b55eb014104bbf438d2b151bc82f4212ef6c73e8bd78dd969c3913e2da933e70d06272aa78e19ad1ea6b1c29103af954b3518bacf9cf645b8f4f71897800e7efa7147faec29ffffffff5904cfff4be7b6ece7c40ecefb65287d4f4a244b45eb1ad24f018cb2f04a0a62010000006b483045022100d4ddedf2f4edce320b8fdf5ff13b5993df8d566ab17f68907975e161ea9d277602206dbf1da03cdfc6b53cfc54ebbe24572b98ad9487aad19c999b5d2784666fd9050121022783852b95f6f562a39dd7e3e1e53635af9c2eafdb057fb5154c8db91bfb6cebffffffff23d79393b2fbc4c0db1a99f4ff7e567149ec9cf1d8f9d330c365a6b17ab36491000000006a47304402204c90927b58f16463d4ac1eb0e4999e1b67b8e6efd2054de565b25ff0e562e327022078a801e03474812e95364da0307f855c9cca6e65fc7ed9019985139ae3e765bc012102ec610da7b7afaa2e7c46597101055b18e77a8cead6373158f221be49e301285dffffffff48c3181595a8167cc5a9005cb1a7f0925f2cb712ee700b1202f85d702b5135ca650000006b483045022100f377d0f5b06016ec55635898e4c9100d51af6031df042f7d23da488c42bd5d11022040ac973e36d41fe14941aa1c55bd30b7d92566cd3558336625ceeef198024afe01210357cd361ec00aa23805d68c68275f39696934cf239a645b5328860c61cb95b1ddffffffff02f0b00300000000001976a914c377723c448fd0bdaa86134770d7047c335e473d88ac43810000000000001976a91466f5ba9673e83c37ab4f7f8300f865fd7664536c88ac00000000" }, + { "18a3c03c7b63746a4e77a2192d1ec6acaa4fe0e8453a2467a8b047880e2f4988","010000000a7449d431ceb7dbf0112eac3d34732d7eb29f13e901204b847e3e8ab5499d1339010000006a47304402202d623d764b3f20809e9b6ee45189157819c18baed10ae1aa72192b0f708d37c202204d88a5c310812f0e4504c18352a5afcf37ed0423b8b750a6c4a1bfeb5c9dc670012103d190578cc11a72c7c45cc605a14d115b07f625c1ae0fe36f21dcc8fc630c94baffffffffb0a92e2c815c36bab438e37b1fc1c90859f3ba0e011c0745e550edb511e66906690000008b483045022100e5dc427b58c75a83b12caf75fd321a0d237b1bdb88f24f412d2fca1be3500a8002201dca752f3ff67971fe0ff6ea43bbc3c57129aca09c3ceedba11944ed879d1e9101410497f74d749f178b80ea78a353f9670aa03d8ab1e0b294c51defc4f88a808acd7390b26459fcb1cba6dcf09aa6fdc6d91d6388342e1806d46c84dbc812bdb92915ffffffff691e1df9bf9333d3b915d13577bef5881027d0d718fad329b3d214375fa40f1bbf0900006b483045022100f031c79cbb982293eeb39435485858a1b3db194547e016b3d555dba47d3b3d58022074636bd92e1b826d3005429c36fdb3aa81f7e87abba8e6a7b1822cc2c459872b012103f16365c8160a783ceb275ebc46aea0f54e2741d54fd7e3e9d4e55748fb76addeffffffff9e35c38087872839a1ea04fba186af22b0c4a074d202620b89366df5ea7d2fc0ac0700006a4730440220221011d0316966ba4368eda461154701a6199ce3d2d9f7320dc0ececb4eae677022031317f97d2321b4bcf6f516e600983fbd283dc6a4a48cb480a3a58857923354a012102b6bb30557d52f69a8d3a7d39349b2783e2ed225713fc4d0bf29d586ad499c08bffffffff634a2ba0cde204ff456d7ddede8efe3db33b4ae4386dddc6b562b01f54dcaca2010000008b483045022100f16dba9078b91dbe3a4b2926a76ef18a8be64ae18b72580b2a570df729c94aff02200ab0758df0f7d86d07d61df346919d15ff8cd0cdf5adc5681a9f7cb0c3d1387e014104f95647e005dc84f4de0fb1246250b0941e085c4f7d38cd36f186d50175b5b78bd97600333ed73be77f3de347c10e5c08fc402fd96a8623be734da43d1d265335ffffffff0f47573baedbaec48bacd762c9b692c7d0765117443ab404e0eae548000f1edd4d0000006b483045022100a5ca64e92fd98ef4a1bfb439af5a5b365b79c78ffcfb07d25ed135657712b43002202fd46f8bdb55bb6da40509ffac63f8f86bd6e160335acecad37132d113408c40012102cb6edf704a2be8cdb4d567846a154cfc13921ccf7e2367f9f360d03e5fd58addffffffffa4a3ea169896381720438e90e6b94457a608c2c6edcbafa5c3f46ed39d2cb574750000006b4830450221008eaf5565ea92322fb9d2669b1d6b8bf1713d3674707b91ec47f0e7fe6a1f5eb702201ac546561a4ff24219552bb3ddc992cc85f2837f489358a8a326f9547689541a012102b7fc7c4d50c4e176ce20fd46a18a91ee8b25c3215844cc5e8244bdff6de8e118ffffffff8b282adfd73fc3f3f4891abdbe9499efa0156f665a6a41f140d0af84a205ae6d3a0000008a473044022060bd2ccdf8525549fe174d582a1a8e1c5a952aa75e30103d7193690a55c2fa2702201e10414d3ade21610fb8b07a5051376a89effa493a47cd63c0ad2c75bcf363aa0141040b04b2c7447af390fce0cf431e7485384cf2bae5c19391dc36fb7ec2f0f529fa0bd6078a5851b1cd60e16acbb6e92e555af4ea33a7ee7433bb950bac238d2b7affffffffd115fa1ae8fd0b6d5878dc787fe79712b546b53316a1f1cd5450abed7ef892065a0100008b483045022100b4c0b75b500196f2f5899c24db03441bd38eb5fd61b677e526deeb25e617e1c50220556d4719f90edc50f13b788f44f2d43eafeac75f0043f85dd6b7ae2c113535f2014104c8d2b7c9b09e38244f565e3022c7657d1b314d5922c06f4151098b3aece0ecf236e9ffb79c1d9122aa058b177f0328d26ea87cdf59240931a57abac02bd50f7dfffffffff9d4460efac521b951629549524ec359d7e342cf5526baf6abbe0c58ce8778501d0000006a47304402203e4a8bea260c57bcd71cb883df75f9f4ae1c5bb953b9fb9adc1cf0bc25ef226d022012b8e796ecc7ac12cf92991f58a4d8c0f9a7da9736c8502edf8c219600ed87fe0121023c09600ee30e1aafbf97df7a052b226e811961a61a191df2910e002e4fba21caffffffff02f0440300000000001976a914b038e40d42536ba5e8c08f04a1cf36f1a3a06c2d88ac43750000000000001976a914f98b663cc480ce4b302e211e1bc31811121810d688ac00000000" }, + { "b6f36a092836ea9d008a897639ae12a0d14b4a813557008997a3ad9d94a49712","010000000b586b1fd479698b3ba218217d7755d695f4bd82496fa6f2c7c66c2589f83e8992010000006b483045022100cb33798c9de0a01c8cd9c6ead7b13afd9b728d77efed4b8a4ac209b5747993cf0220725de80aa29f011e75e9d480cb4fdf25f23fe68c7e3042366a739e3bd759f9e7012103805ad16e351ffc0f4312870a0455fff025c348f3ede509748a55db0d5034d608ffffffffb5cbae85284196ab83ead5c4ad1eb05de9fbd37dffbd302ecde790fcd3a258a2040000008b483045022100c3ff01761b696e94cd056f44e401fd351837227277780f8e65d2280de233c75202207a0b234b39485e38f8bc3cbb241af1ebf5552d89d62be36df83b2987fc06ad99014104751cacac0ca2ff315db27aa931969d07220fbfd7d788021a81102063a12684971037f620f131d432b231fc8c58ba511ad3407a43dc2e672af1ea8905e5561d65ffffffffd3bb658073b458d2f4bf12484ef2f357f0cab35ae25bc918817902d960921817190000008b483045022100ef382df9b6f550c8a2d0d02294f039227a0d4db3ce53a4259e75756600db2ff5022076bf048bf3dc4a654865a5e27c82ba96b304acf7a0270438b7c4076491f29f6b014104dc213eb434cd4cba623ae6c7009767797d8a5ab8cfe1c84d3229a91f8bfcfef7d866e7de75d6b5ff5e7ccb86a5d811097252a3ca439c8029119b9388f77af911ffffffff6ec5f78a05a716bf2f141a28e1169d04d86eefdadbd754dc658b51e8d1bc6035610000006b483045022100806c2ea14a05c4b1156d18dfbbc7489f2f0d64b23f55d75dcdf34b7af55fd2f00220022f65d53a875ffde470c111eb22266a2eb93666a87e9d25da648e8e82e8b554012103b731b2cf0f1418612471e78ce0110b10a15916b8e33f0f6721ac4d50f78c3966ffffffff4150b3ad50d41cea1c22cc1cc88e2e6a83560cdc1c1cdad1b47cf322f27f450d010000008a47304402203130a40cb629abf7f0caa8fd93b92c4cd869b7d29837165a97477bade3e8a780022051574f302f1dd8c228f69161b8c7d625226ca233e744d532479535b41a59be2e01410411a681592e58e93ff8f7eedb9980865879dba2ffcb96c2dce451c1b404cc8d131d280397ee83e0a3600c1abffa9049ad3d7f51e374d65e289c7ae8ba2fd573d3ffffffff0bbc885285b06d5a1539fd73b4ba671319f9d92cd6a3c6b880d0683e04e4ef94010000006a473044022076769b5c601b3eaba18403b52e6c0133e39dcb934527c66c3513be6255794ff5022024f393af16d39a8f301570617b2de7c65dbfe9cdd39f7bd5fdc2dafa5eb5c313012103b623489be2f649fbc8026014f4587b80bcd86d0d91328cb136e06538b2fef955ffffffff953bd8e64ce0fcf5da944d7a491e267741cce00511a14e2ecf2f85be758dcc91010000006a473044022069243f550902bbbbc7444e1d48f7380c55d0cc257c8a1259b0394ed9af29bfc502203f86a325ab3de6ba9dc53991e51c83d9d4100643093ac5b1c91a4c97475ad51f0121032177402fc0e040e527cd616a46a1b05d5ad07fa7a4d277374a2e410744489346ffffffff52091991f92a6835f1b54c26f1670e2807562632648ef9f9b3537858719dffac010000008a473044022066c87efdce27f335fb39c794a53a7877609ce9c9656af7f26d4dcff209211d0e02203bc3729297894904acca0dc5ff536af3f3bc08b35d05bbfae2342472a82900b20141042586113727b57e13d8ef3ac5ba860f3f4f976613e241fdb6338b44984a9d9c1f530c4793294c3331e89ca6c1bce89e497c45c40328e987ec6a89c6ab8d409eb0ffffffffa98a206e56e87fc56082793b9e1193247bf92f516baecd49f66c9eba71c49cae2c0000006b483045022100f7ff4a61d43d80e0c268c6613337ffae4001d1845246c2f2a2725b02af73573e022066d992f2a182c432e41294fa4150762f16d65f98bf022a69daab0cad3f2a5f060121034d5e696cf6a427455302801092e19ada0ec221dad812ee3ba5122a0aeeb26195ffffffffa54fd07611ddfc2fb400d7d204909afb2693aa0d59a55c83f80d203249a7dc223f0000006a47304402205c5f81cc99f5945bc5d88f3ac1203f013c4046f36f925bf39b5a52ddcc13e47c022062590f2fd1b1ccc032f37779dca65dfdb2ba52266297ba277b12641808757169012102ab3a57dc5ea60d2adfe60a76e466fafea5be01ecb9d5de61f1c8d7159ff2cf8bffffffffe2232ed3602099bf8b794aed4a76c6ab9e25b171e0101b1a517d390be7bd7e04220000008b483045022100e2ec7cd83206d7e3a9cd1a682054b4935691dcbbb4e31c5fc9cb1b9ebbc12d7402204a3ff6b8c8b2a5cdd0293dc7f3adee8515a80a29c69df7ae8ec7a0040bc3a596014104326f6e58a1fe317fefcd51c7e5cb3b452a91937bf56d9004cb34c697a5ffd18760ee2598b1e4d71bbd8f307aac6688fa0561d224dc29ef52ca10c26a7c7fe3dcffffffff02b0b7a600000000001976a914f510c9cc9ec23d493b365c7cb38117dd759aefa088acdb1d0c00000000001976a914fdfb005bfe44404a80b53cac4bc09993de76219a88ac00000000" }, + { "230d9525d8f4496463e3313e27a755232b43afe1b9587f0da12f3ebdf599ff7f","010000000a0a5a773a4803013afc218d3dcfc968fd918e8acf780c113f8fcda39abdb280e81c0000008a47304402200a78a867e63bbe57f17f98ad1fabd6474d236962cc8c8bc6805079fe0ee9061202207754786254fa14948a84d857129d59068d5a23d2f4dbbbeb6c0394d9b99b7ecb014104bbcfb8618de04dd4f704303299dd958d000d0a71103c28dcdb0d548b205b06e0aaf7624a57b913e9a7b55ada77fb778fffc6f65ac9c7da4fdd8b3b85cd4c99acffffffff46a3c7a575f206c0948059903f3a6c4ea6e3363f1045ccce0bfe353726bc9929070000006b483045022100e29a009b796ab7158414613182e524c312cffb85be8f64aa90d6874bc419a69202205bbfc13361c768683fa9335a63ac144b8e1b9a8e7d8f976a6f8c338e87a3484b01210217c62e1951147997e91224f41c37f72a2e6d73ff808b1aa16bd9122bbe7eae51ffffffff191daa7ff643d01aea489519f3f5eb84817fe985ea4ac5bb70896462a51abf900b0000006a473044022022f32d2c3a1d5aaeb68d824b343f1f84b74a43cac4d1199363ee329ca07b48ea02206abd72e302d54bd1930488593db9b598ef27cd5e45c8d59fbf0a27a17495e4020121035e19802334f627d1fe014553f15bd2904b6c1604d679883dba5d59f5af35f02affffffff851f428aca96879388fd733fb13160eb2c1481b21b41ce998ba9529b77946b8f4e0000008a473044022022e27c75838ab0a878fbb2487305956db49e9fc12cf20101e0bce05589295ddf02201f2c9450598540663cb23878a09beb5d73a38806eed9f41a972f189f6de30d10014104686f7aeea078774ee048e555dca7220391dfb8842b9f1352a5de68a8411ebb44c2b077228b9ec3f529d2af61f78830dfe351a08b31cc70b0f83b8badb0d8c08dffffffff4ccaed9814b92341ce8ed64ac5108fb2cac8bf866c55eda2d8b15ea5076c0d0c020000008a473044022026d8e9030c76549b1b523dee9bec00e0090101007032876bd7114e1ccb0fd3f8022033f7ff1e6cfe8cb8cf7e8800aaad136e30817dc9b24520ef6ff64445e9ed5069014104013e294737cd0f9d7f47020af9ffb14b7576e6de4b969748b7eed87280fd667818ffe9198a7e1a58f26aaf406d2374f13fdff41d57f1ea7295d48163724d2727ffffffff432e4e2658cb69849f60291a94034504d9f5bafaa2739fa5011d5f146d185e8e820800006b483045022100e77796477259c57d6d89cafb2e7c8062fa0eabcc37e32c0676b33853629c3b76022078a245162a6e9dd420217f72cd816d70d05fbf28cf49db26adaaad8f7ebd70be01210255b63ac87c4d81ef811e10a6e4aa267a5f17618ef04caff62684a075d5445ab4ffffffff27d59542a08d5094ebbe5013338357386b99352226eb5e12bf99972a297de2dc290700008b483045022100e305dbf0e09c2df4f482e7b9cc082345c086d2e95319bc136972843603876f6a022024fe279edaec2cfad07dc3789107b125dd92bf218968e03c4cb03ab8285fc96f0141046bb0b594a00ca0e32df9868a5c911d8f4f9b561c0bd5350f67732e7af2cfaefd84df4374aa900851dd43422485f7677efe8811b8160ef80cd772fbd65f3f8bafffffffffa3b018aa6b37965792b306ed1330a2463dd737751ac60980db9200eef238fea7e00100006b483045022100d1e8e314043595ffb46dc0f9373e379ea80f4941e432dfb7f9233c8f8aae087802206f3a0c810f9262abad35096fb90ea51cd07ce6bcf421bb76347b32fbedd5d8970121034f1c92bc7a3b5a3af2be107c14439b4ed1109a1eb446174efd1eadde23b2f317ffffffff8ad875bbf0b8a5866039ab574f54d0cc3dcb349dc4e8b5c633fbc0c77a0f53e48501000069463043021f14773db7d6d2ca7ad17f61650cced6c2d367a8d66bb30a64393aa15700217202202a18cd230a57f7346ec2dbba3479119b7de2b5eab7703db663d307ce5c89bb21012102dda4a4afc27328414ffb08ea76f4c871e2068fa8c95aa39e4bc3173d8d584740ffffffff2ba77a9288125bb665a3056730fd7b2fb21190470e44e2f65513e7f117193b384f0000008a473044022009e20745730c073aa0f1ff1ff6ddc7d1a0e6ec65b5039f9409f026ec71cd0b0102204a0741afe20e872201549dd9b1eb383c359561ee229ce7447bb69f36a0ce03f3014104886fc507c00844927196b51bf74db1bd5bce40e8a880e1639db413e19db4c800df42f0729fa0706083d8c696b206f8d9621654a8c7305fe0e0e5b90beec69266ffffffff02a2670000000000001976a91440950a1554ddb23a7643f7a38b6f5d72753af7dd88ac49ca0200000000001976a9146df2aeb91ab97497405db286a3aaded1c5db817888ac00000000" }, + { "4d3397549819f61cabe25ae5dbd31b2f1dae15dbd7f9787b8c140b171125ded3","010000000a6b76375b3911fef6c494bfd15fdf08efb61c0ba76cc739adbb5b43c04ef93e2cc40500008a473044022063ee26c761076bc00307cc13242a721ccae605abb597626982e87d738e3091ff0220350e075de4e615a707da25be9c0c016397829b42d5c534709855846f98ad5713014104188a06872d16b0383423ce6898c1c10f80cf71a2d039ba3939fe9737c6f531e10b46680223e45867790c0eecfdbe373ea0eec84983142d69ef463fd9f05a2dacffffffff01fe38756af00cdb4d6fa2adbd90836771780f70e78f05f917663f82dfcdcba6e90000008a473044022027ec54a5a20ea3b702a16db49a6c27310f086955d752791c9103cf6f2e7f13600220201ed68edf08aef8bfc721a6cde66eb4e2f5654cdd4949f3dc0cfcdb6f959cdd014104c48e56c68d2589104d2f1a16fd3bed4f6bbeb567b4679976b7afc84ecb04e7c32c4d45d31e2629cd10dc6c5ff342e43db2822e2992c1aa178f03781330ff9cd9ffffffffe91befc049d0409a32f92070fdfe1f6af712cf8353713a2777cff250807eed4ad30400006b48304502210095d4914156fa6986d4aeaee2411c018801ad5399bd332b27a865d50958dd600e02202edeb3a9d2e9ab58fab181799133498113c81aefd089cc756332334d000dc25701210328f0e42e3a457e5597891b567ea9f35b2a8dca0c535f64addcd6067a120c15cafffffffff76eace82b14a5c78d91d4940b47432eebcdd1028c5545ef41dc339a9de9bcc20b0100006a473044022050e784c149395b54aa2a7991dfc6a7d2d721735c1fe8d8be4cd50b11b92c49cc02204e3908f9e85c35d53df2144145aeea592d86f9f706ebe2cad36b2e2744c29c4a012103713aeb4fac0d5bdbaecc239184a607eb8c61112e37baf82e89abf854762c5c6dffffffff94ad16e5f6a1dcfd3e2d03419057c11a7c18353d23f5ea99554b1ec78fe4e7ac060000008b483045022100b51090419bf321321bb406f20a3d39b77ec298dfc984b40ad681610efe70646a02204b669b396870ad2d34ff50389d967e717cc2e31364f65796a88fee08b4eaeedb014104f993829421839a5d1c7ee086d28a761d7311f3b7d3dd422910f76b237a316af4332e24670a2780e42ed3a54c8ac4ab2c84bf871571b9bccd36fa1909510ff020ffffffffb3855aafd25b4115bee4664ffb20e68afbb02aaf610ed9e3f67bae8b828bc119be02000069463043021f0e721e16e8f0ac87981e60d742d4fac2ea4d29cf4b90d58799592690beebf6022018cfea3dd82d2397e20bff463f3217ce11c5c44c7cc9e1674cecadb2a248d043012102fd189a18e1e65e0704119f85883e7e14232f56a99388d57711770d92b92cdc93ffffffffbc10eced7e055b9ae456d4117f27b57abb08bd01819c4cfcb55c04b28aacf1197a0000006b483045022100b1dbeb1d690dd2fad25d1e1745d3fd73ff2a6e7f57f0ab54202907878023166902200950d347e94340d158a10fabd8a09c9404b37be5493ee6694e001c7a1cf3f1800121027a744485bf9a870372468e6853cb7f2efa1a82ad824cd117dd164f1206795e87ffffffff2b46e2c1248f8c32fd558287eb0128377b9bd6cc69e19bec3dbf661992f5ce72870000008b483045022100bca917992dc1f0cd015b9dcc5c9be1172f6806ba1f3abdb2cc2ed300306dfc59022006aa34f996b0030e643d9ada81037f1e8d90ed7b491cb9b1d2250be30bbca798014104b0ca392848909a295a7f93a89854f911e33d39a836e1545ee96f25d7bc72531c621795da949f494d68c7a6866bcd0cff84ca6d17525247a6a7e58919f27cd38cfffffffffd01fe80c1da242803fcd1d615c59036c21b166e489d26ab868e24f1e322002a140000006a47304402201695a5158490e5608e6029844814d99168e582ca3e24769e64d2fca8a5727c7202203107c534cf245398e96ca4609be2c2f8367eb4946ecb2ab52930fcea12242598012102ae6976ba3b1ab19badb2280abbce4d0b1017faf686814e4b3a44adcc4f64f0bcfffffffff49456d22cb26b158664c5fc20ce464007bd405cd6de9a64bfd31dd82f8bc54abf0100008b483045022100a585da29858b6e22087a4346febe2ea46bfaa87b5e978d35c4acaed6e2fe1c8802204fd9719d161e5c112c884e449d7cdb4d81291376162ee4e4b558797c1377c878014104a708f79b0ddcbf9fee372e208e441a78c65e738630b3000b8420c577aac68c0e2019af86035a290d2ad52b4f1c56af9cf5b586d1fd88e052b048c3324330f7d6ffffffff02d0c30000000000001976a914859e79e8e578f9b96a50e1fcb5fd25f7c8118ed888acde070600000000001976a9146981174b80157fb69a5abc37a5dd3ebe7fbb4d6088ac00000000" }, + { "dc16d0441dea08f3bb30a0cb861135f204482132434b016219fb1a34f7de75dd","010000000a72e266d8d6f8d95cd8720f7cada2e98480a522d3fcfc8fdc386a6b498e53eb475e0000006b4830450221008a02f59411dc1f39e936f0221cbd832a8c4c74b6df854949a1fb781ea3cd2d69022043378759be59793a0cb325843afbee5d0360a499b3f4fd7c63add7e017a81b7c0121034ca90559d622f42320c494206e8ac557118b47e3940facd499ae325f16e9f23bffffffff2c273981b3496ea82c859b22c89513b885a6122a6deccfb1087f641ae64d3382e30300008b483045022100e217d605e585684e17eaef1194b7861d49bd00fb756ea08b14f9ea175246801c022041166a2802991d4189f34bf6ffee8fc96cacd6ecd8cd5b52d9c5b36a0a854a9f014104fc7f74d00995564e58e8e8faf676ff50c4307120c02a9e92a70d71cdab900499aac26ba4407fa6c0069dffffe0712e20ae5eff64ecb02b459ac01ee3691f8ee1ffffffffbc5001a360ca38505f26f593b837b5a4d16ef1a3c50dbf8fdda0087f7b82c150ee0000006b483045022100af2592b834b4f6ec01e17964badb16c445e35cfb0fd4a02d2d5ff6019952be8702205e768794a97817d5d69d94a432f02abcb39a0eb5d37b857130b0d9072783db300121034bca597fd104d12fb06b275f7bdeff704142bf29045cc717eeb8dd01353150c4ffffffff65ff0c155f3ad5cc9ed9be618a4561292499a2725ea1bbe57841fe0f06d64fd8770300006b483045022100ddcd09e10929ead15a60e561b12dcef50d8c0ebe332c4a306dd2fbd853d915e902202b29a9dc6482f0baa3712b7df3ffa46676aa17045041578454c0f75a9e157be50121021ccb67bf898fca54e44405ae4e0f5b2e92e1d0861121dc9dae8fcc8b543dc3a1ffffffff8d3d35b3e6830772ce2ce423727092e3cb024470d7fb9acfe8abde971e735e1a330600008a47304402202ac0a88ae8ddd041be1754a231aec9365ff0a300e7de473fc47a880e7c511b0102201cd4877b7f81a0c1d7a0e278944008547f0f643a0ee6a1d9c99719a7173d1708014104b65cef75d454625e3cc348defe7dcb356e663fdf05370d194bfc45ab0b4ca8e505e65b0048ead0b42f4e2411f8f80cfb24126f2c1aa27f748c0f5a3ba027d1e6fffffffff79a11c516976dddc30d2532d9c9014eb68ad8403dbafd0643b9a5de4fa511dca40000006a47304402202d50d0ad8b750b4d8f71a4079fbdd176c60aa2a396f34b83aec44017c83ca2c20220453eea29d321bdfc6164fcb577278722a8bb3c0cce6d3a4d11a0b2e235fd1dfb012103a9f8c0e01fdfb14dd6cd7c829b8d0709d2ead24b5863a1475faee7d2764f7786ffffffff99efa9ea238e747453816c92c6b8d6b1aa948cab17d8501ee6980aa98ab6826c870000008a47304402202c0f10ddd350d899b9c08d7231bf4f098f8b7c74f39047ecd8b716a5b9dd22e20220634a009168c6943674acde107cd02352386a99f0e56d412c744aa16d2c2ca28c01410463f32bbc393dbb76d023eae5cdedd8d71e4dbb354bb0fd03b16a0d9ffe3b47b00c72c39db5e3e07d1044c99f7a69b4f79840a08ef27906ca19282a0a3e656d5dffffffff7c12f46f919490fe73423a3d48818f1add76b03234e043a58df1e666f3d87b430c0000008b483045022100ae2061ad21854f550087de3896fb704a9d907804748b55534fb08dff97d3672702203cf1ff26125524dc70a1e23a0cd0f4140f06239b45ea3219cfa5bf8f90ff5a9601410403c3fa0fd34c0a0b5e777d4eadc406e2be509e181dc490d529bef8e871bdb8f39cb1bab1b104d055f8c2224802f7da7ecbad519114b4a9b55c5d6a37d60ac45bffffffffaf00a46d95c756ea9ca81b70a6e1b689d62ac22994cf26d8e5693bb0ad2bec61da0000006a4730440220710268794c59caa63512b305058258bdb8a13f7231bcf0224bb6673f963fffd2022026392eb6a60987f033112bbc3205b40ce4e0b28ee441abad0b5d361c5385c74f01210348eaa93e921712c92cacc1c886191773bdcc1fcb9e75254382387831dbb8a2eeffffffffea6232c0a0f068e289b62fa81d09d343070833ffa86e8b63be58732b8a317447a20000008a47304402202a4e03b49840b1260f02d8685f80a008528f7427bcd2c3d17838ccdeef866c81022005dfa71ad70678188eb36a58bf9384238c698b1ea12793cda502574214f284e40141045378e577b5a9e34a1303f41dccc7e215735bd7bdd16eaa19ccc92fe2647bfb3f7b5cfd4381a15a4b71e0f966a97710cde9c1c9084870b09d13eca03e9d2a7a67ffffffff0205310500000000001976a914509cff4a19641d3e5acf8a0abfbbf05dba3658f288acf0ab0000000000001976a9141ae85733cc2372b7ba36d297f05fc369124978e388ac00000000" }, + { "f9a13d982adb81b47f2b61adb227e38eec6147f7048eee75138bc8c3f806f8f1","010000000a793e14fecd964eed392a63a0c020a1457262419c3d9294ded1c8e863f6d815f9460100006a4730440220173392188b1dedc33f4be60aac72ad4a159e8389f461f56111bb0e506cc3f86b02200129ab4cddf8071069214acdbb794657981c298019d78f5bc2f4d3486b1e1599012102ba72ab150d7ef032d5d8ffcf2df36322dcf512f0c280af87a53a9d0ffe8d47b1ffffffff8c90a78c1bfccb5edbb0b29b3c99f04525adea2e3ec2da26338b967baa553e300a0100008b483045022100d82aab97eeaaaed4d9674c76f42cc68798c96dfaa5d3618fc098fc9d3764bfa802201581b2140c4acc53023aab76483a67c9b2981f6089000179a79794eb808b87ff014104937656b1de76b3479b92268d04703db972bda417f9712a5717890bc7d495a25abe9e6843020cfa8930db408ce2c1cd306efeb88f17bfc6f0ce5b2e74a6de775bfffffffffb343eb66c59fdf6446f7b2c4c13c8cd0efd5af39f899635cb23b41ef2d7eb04000000006a47304402202c97b5e85b92de57bb98e77aa2e855d1cbcc98a0a9804f237c5a305f3e869d0e0220231d187e0b945827e5b05f000e24df2f084aa7efc9dadbe75f30e42b87a3fe28012103e645fc920f96d7165bb2677221063fa7711cf315b6b8d62c55689a13b44627bdffffffff05964dab63e39df35f691e1e7bb0fac31511acf386cd8788c1cc8833d115b1d32f0200008b483045022100d93355b965eb3ce4f44d98ee599e21c2e0dbb0bc5bc4e05b055687873cba08f502205c5a8bf185b4aa5ba59d28935e2f4618a9ef0c2a161cafddd901ac4fd1154930014104a84e78ae89f9b52084ffb72e8f716b5190fe196738e0c4e3ff97ec7ff202c978072e4996ffeb4ae6b03a1e0d61d746d5d1d94df2b6751ef88627f12d9ba48b4affffffff397cd8f87e6e9698ba6164b554cc5cb7377643a00a6e28a5d180046cbf131b2b220700008a47304402205c588a1153b3ffb9b06db65261b5660885abec3e162d949d70b36fa77371fa72022057b9315b778471b0cd068d784f4eb6a5000f93d0a6e49965c2c26dd8145ccaa1014104b3a14c69eb3bb38f26a3bbf7d251d67d934f6a6ff04fe9b995791a99050835b81d4ff51425c3f352eade4d91007ce202e1379b1ef846a575745dfe915af0714dffffffff4e2d6b120f6726ff13030f2cccf815fae3624ac98b9fcbb6febdbb1cba9af657a70000008b483045022100a2290798068ea2f8dd5c1ef94e1e532ab37a74ae1bd66dc0635d7d1c1ca8c26102201728993dc94b2054fa38782c173ee3c14cffe7bc51c9945211318a95b1bbe03c0141043c9fc57a6ab7f9926ba9849eaaf0d781c32b61b75816524e36ca4d9f11bb95e8f7fa965f2235ed789b526acabdfe1b4a9c092c58b566f54e519a15fc0f2f12d2ffffffff594d96cafc301769d797e1e3fbc70446e3d84e7ee65f04c40d33cea38fd20206f90400006a47304402205574b68ba2f03cc8fba1546011dab77dc439583e6cdda3af00235180e0eae67902206f794461300808f5159dd295304af518b6bc956faba30aeb329a2d732f8bf40f0121033d5f4b1d65377c8782fff56d6b67b690009b871800f746a0331e95440a92ecd5ffffffff2da763d30f8267358e40be3b17f6475a3994ec9bd75173c4f698cc90cde5b5ac4d0000006b483045022100ce89e96b1d050b74a16123f8e6e9f14ef1e3a6705dc87bad8513919b8611aa2902201b09f651aeb770dd07e854d8a4a6232384cdfb5a8f52b80fdf8bc856bb2669ac0121020f9a90e8dd8681afc3ee481fec86d7a1d0a3aaf201bd593479e2106bdc06c691ffffffff04c07296b9f7a130291756ebba8a73508cf7f52fb0c15c5681f6157263f1b1953b0000006b48304502210092dbc18c72e63ff4e5231e57c47b3a744432bd459107a2fa7d71b81b8c04e79402200341a49212d1da7ece6d927f510964eb45b1ca0e71abf4a7290bead70426aa33012102b54f4982ee0d780417a6cd988544c6044a63d8a6de823f540cb2c0102907363affffffff0f9c5fb2b1f57751447ab243e97f26d2c5db4b148d0c5ac9249746407e869d78300000008b483045022100e7652cd0ab2291f51a0a80a26c3c1da9ef5aa699bc294a357be5c0bdc15c61ac02206c08f7cc2219ca8a50f939566d42d30e134fea82447e5baecfbf66ba0b93aa75014104b317c501579b9c6f02f01db808b03fea29abfd68dc4d8b6a6d5a8d2a815f34800b20beae4c8404182d88d25784ef97d5b1bc8a6543f247297be40b8bed9617d2ffffffff02fa7b0000000000001976a914736f569c25cd29950c022f794897d8ccc5a4d23788ac60810300000000001976a914554611a8be6ca20fcfa0eb4e744d6cd12912370e88ac00000000" }, + { "6a6f67f049873212854118a6e7c57a7eab3f6366cce62b3b0dcd170318b214a9","010000000a943065e35fab42526177381951b635939430de8faa119b88bfb691ae7545a563000000006b483045022100b8ce00b04e254b6fa82e19450a468df56b6f9fe4aeec01e6a5f62cd2a3074f63022049278cf0af5dc1b3e2de6d904c0ad3c49323df7b98fd3124cb6df7a72fd2a329012102018f333d21b7f7ae220e7ac79f19a518af91a287a6114f3f57b02cccc0d06316ffffffffc50acd83c17d53dbadc29b7ae59a2baeaefb1098ac01783bf24546829916b05e000000006b48304502210094f800e18e0830ed12ed481fac0d0c6178be7bf37ca84d5e5ff02b248beb693e02206623162b45aea76441c1138fe957b61467e142210f099a662dac2eb006f38471012102018f333d21b7f7ae220e7ac79f19a518af91a287a6114f3f57b02cccc0d06316ffffffffb7f5e4abb6e225a663e6b463ad29f2354ca9aee2bbc99eaf08579381296eadc6ea0000008a47304402206b033b4d77edeb7b9086ea15b54f10a8c9b424cf99c2df122a3c7b2d693288d3022066b9b467cbf7108634d6e17ef7e9e14a6573db5eecff883add4fece0ecbe8546014104f804dab8a2523b0b16434ba0797e06d9b7ae95bcbe8ea1b941280456f02dedbb83dea81079526545fae697c1f73d6e789bdf9a96326e27839376397a9f5e8078ffffffff0f5fb1ba71ef0acd449b89582dc7284a76f77dc9def36c4170b5051d7c708bd1000000006b483045022100907e33dd9bfa0e3bb6ac60557c33e2aff3b962474756909d46a88be38e901de602206186ac743d58b8f0d0990c95f51f3a0f1d8806033c7d4069737360877902a2ac012102018f333d21b7f7ae220e7ac79f19a518af91a287a6114f3f57b02cccc0d06316ffffffffb1faaed91b3d78eaafa56a86c508f2f024dbd30a840e0c608de03ef5e4f23c95680300008b4830450221009cb4e9c804cebb53e8f1eee8d461a46e02a20735e59901032a03d6919376ddbe02205a23778732b1be58524981d13c38f8e6a27e7a44877653bd7f940f1189ff590101410405bead420792fb842f95c737c0bdf4457677d0ff4b87d9c90d8efe67a5696d7eefa5c6c822ce76d5993c800c57620469f0f89da42209e7dd7427416d680de38bffffffff28f3e51fec7f3ebf3d434212c73c780aad5b0410ee29022177cad058188de0b2000000006b4830450221009968f03f01a332a7dc05e0e21f773a4f8040ae9620324d0b4a39a0eb51c13daf02207ef9d686a2287d45c072470261a79c19c38dbffd7d8ab630b6a8485cd47b0b7c012102018f333d21b7f7ae220e7ac79f19a518af91a287a6114f3f57b02cccc0d06316ffffffffed7731676cf0ae990f4affb8e7e4a31ca4074b751ee17f608a4317bf16cef8c0000000008a47304402207baf75344764365abe6658d184da3969847b9c4609e6e30ac30206d177dc13b502205fca2be759fae3ce93f2efa87e128e00b8a54ca4ccff8b1ceca987085a7e9313014104f1c529cf3ea6ccf7a764c1bc4c1898346110658a8917bee5a8492393612545bbb1226540f84648ea73136f572e7c54276638594d62fbe3cd9c90d659d3cb9e70ffffffff297143e99986248c9ab551bdbc74b5a9a20e970e7fadf1bfb8c835fc0a4bee1b070100006a4730440220116c02ca007f108353e6101e18f5792b8cc47c9d0008170dc3117e27ae7807ba02203922b9736ee4e74066e3e491d4aa44289102190bc21c20dd2a8768b5ebd7633c01210270497c187e1a8a36bee137b0dfaec7ae46e3a03e876dbf518d2a9c24f6ba24fdffffffff884ad457e8d8ee348ac214c962269d2725af638fa96c49074f25d4f69a187f71b30400008b483045022100fdddd46fc0c63c074d1f4f22535cfacfb5ced1d26fdcc4970a2622b5f06fde9a0220447a0320a5990e3abbdc5de8a854b3aef8741ccd5b765cbb784d889e823fb4a70141044d3cc494dc9f7fba85f3bba50c2a38ae5934937b07a40a5ccf97740b4077d689bf69cb2fb1b58c5f3ef3621b33b9bc77d75bed908de65f045c2c0f879f8118b4fffffffffec78e80b1ed61d963d520d5411d7c0f9db851ba87699589e9f89c05e1f7fa8d0f0900008a473044022014bf8e2956bf7c53bbb01d3b38403599e21393194dcb37d9932d5458ff0c987202201f5d5f6afed08922b1307d08a2f088fa85108dd613867199a105ace4a011288f01410422252bc9c3ca381f138545f47711a79aa720633d5eef06a6d8982f4eb20f94301aebf943af495308376f36a48a8d4bf55355c1e543958870d5635414bf1f328bffffffff024bbf0200000000001976a914c059452d86d50dfb3115cb761233fb76e021ed8e88ac69660000000000001976a914a4b52a35b0ab7ae450745f490d49d86a0abaf49688ac00000000" }, + { "220025aef3faf1d6f83be507a4d0fa5a452e1439c126d87c2fc9c78f6fe76fa8","010000000a447bd56486c89f87105d5e2a88761ef9703f3f627b291a34eeacdca48ee23346160000006b483045022100ee332f7d0af64854d3b3f078d08aace450778aad4196d4fb2b2e1646a1e850dc02206a43ac848e64e4859e9eb18bf04e73fc8adaf57e58fa3e4a57d82c9d3eafec8e0121024b1b56c23c4088bb1c3a892006ac25b4c6d19694abc57ec403759218d966a95fffffffff5f04cf9fb8b52a20365c317a076413afb8a711f55d584e24fa94e6ac6f81c50c2f0000008b483045022100facdb5c8891cfc70759fc5b26f3a7f92355bc728f38a8353a1f0e29fddf9602002201150be9f11522041a8023f79153caa6588666d9efdc7c6235767cbf106d41cb801410424821eca5649711311156dbeb2e46c74dc749359aa3c144e13fcc19891c75f1ec9d157ec2aca02f2e75d1a7ff1a520e2f4c6c5a37ec06bac73a662fe45c6c90affffffff9df3ac4b3db4a8b27331884b4b2d0b58728849212dcd26ae922786d639e65b0f650000006a47304402204ce023b961417bb33074d1ee152bcd9d19a84d89c746b9d8ca4b0a1364be766d0220402af332d610c2f4bb06d59f3381fa94449d1e3538480f4a1420ea03729a4bbc012103566deb74b80fbe34754772c0b1d1117b79af3450e7907faa2694582d8f0c9622ffffffff06578b9cdddccabca3e410c97f5aaa1a4f9aee0634dc2596dfe271ec47912b35b10000006b4830450221008e1a0d1c32b348e6e7256924f6644773b8a8862701bb3f258087631f3f4a8cb0022079709cbc3c7b9c3aa74dadb495a87eb334e1934fb12597e22403632fdda0452401210313f8a44bdbbf9afddd7bf414896484131c05ef7d9d880587b615dbe2b5144b42ffffffff5f0ab55c97ef8d0820c6de2e3a6a002b403db59d369bc5fcc63b97ddd10350bdc10000006b483045022100c132225ca477901e3c76b2583d5c4870c095fb3891b708ddcb87b8304d5efe430220699ee9850f53b68f1c2f13a3813da0a2966d298da389312a7e6bceab2de3eff0012102068c8079efacb694af44a0df3ba84a6ded693e9c5a496a68074efb5ddf118710ffffffff2d01d0643a9d08eda93f2f973cfc42232f4a338002e096d71922cdbbaee79a4b0a0000008b4830450221009b59de31f2de02d4d1d58ab5dec4df1673be0562c1a910bda0bd30a58214c8770220329061da61b13912ff9634b15e88ca5b9d1c2ac9d84b247ea057c8d783b10b0f01410441c4ee43796b7c6e01cbf1a4da39da5cca15b30a914d5925edf6e0ce49f1a03564fb5835f66f26eb73ae28a1fe0eeac61a693e1aea93c2c31c111e4687d38d36ffffffffdd69105644654bde0d0ab9bb42bc905e28c0932cc9fd8b84909b34ea3fb6611f1d0000008b4830450221009cdedde9c5dd626554358210ad3450a69c4825630d0b625c964a3e7567a26471022077b97f823d84a4404bb6601068bf2ce8f11046967e6baeba724a52c489c870670141048bfdd714ccbc3af2ac0aa33dd6e07fde0bb5a310cb008aa36c5b4a17970b74ed94b88f3a4a2da03ec6fc9e14621d95a8a8debdd99681ef64e8cb3ceeb9204316ffffffff6533e93f9da39dbde40e7ee03765204d667b03c452ebcea7d8e7568c668088f1340000006a4730440220230f3776ec4ea75caefe82c02b7209495aa23eeb13e638aa763c13a6be569222022039d86bf7d4e0134c9a9921380d61503d770ca0f8f37013650e49ce836ee58ae70121033bc80e394c2b7d6c816601be7bb459641f60c56c48d1baafc864a96940c1dfb0ffffffff5d3af11c9acbd3b265f204189de35c5034798672bf2a3787ae2f901209142325780200008a47304402206c08362dbc38d0d09fb77afe3ceb7b8465e95eabd28114790db86d873138ea9d02205d49b6430039f2e1395db6a4de142dc778dcd86643523245c90a6cd8db57a7370141049d1556530aa175716dd99c88d579671702930fe20d0c27db0317a6ee5b7126d18f2cae5bf5c24b38e268e50128e0980dcfa63163f7bfc820a43612ae10563a91ffffffff46d5dcecffe22f3cefcd96036fb02626bd8f81fd9434b44e35359ab078bbddffcb0500008a473044022048d86a4d3c6c8c19aac346e9b599ffd178e4451bfd9c4fd12e6bad0cdb754003022010cb19a303b2ca38117809c3752e756e2b494fbee579641acab5924394de55d601410461bca23ac53b72c2123f46ad1e91a03450763000dc7cf3c7da5319c720b3b5cc1a48dc9c02afed178f82ac9174f2879481b40a877cb5873fa8c6522b0a8a7c4affffffff02b9390200000000001976a9141f3017425a383c2e1362baf6c1508a59a12070b188ac92570000000000001976a914b83e64314b34f7983937b43651bdd7f72b4b4d3488ac00000000" }, + { "86186075089494809fedd576a9c4de3dc801962b73fce45e6e9cd5ee0c2f9100","010000000161e8538f3782c20d5a330fc00b962243676a755e8b435a2a2d6bfc10f7b56c5b010000006a47304402203b78b0059ab991ac48b80e80da14bd1b5f853d3709e169393157bb719a21d7eb022003838ace9dc32a01f88e31dd6875f34da16309c454cb5db30524c049e38d979f012102aa8c3dd365a43e28d69925ca20e6eb88781f4aa620b5da4f1f00004229383700feffffff02ed09e783000000001976a914beba265362b06111fb11fad38401d53ffff9e7ef88acd9095804000000001976a9149b26925b5de8f14a131e9373c878b4af34e8ddae88acc2210600" }, + { "8edb2e5836911c397d247c55380ba85b15a97463a2ed09b31f90f0590f3325c5","010000000a54f9ad9e067068e69517fbcbd7fe10293391c893e2a0dd8acab43946212a42b0eb0100006a47304402202fdd81295cc9a300efc80f5ad49c757fdb36bfa14c51e63768ee24494e474bfa0220412a67eebcb8e3ae177d39dc91983d258b2cce4c5d3ff54ff05a5bff90d47e21012103bad61d43b7a730c9eb4d5fad30659385905a7731614fc126ee60c2be9ae53a52fffffffff779505e6d356db525e76f2044391e325ba9ecffbff785b88ba21ca2678d194e610000008a473044022044ff97844f932559654023d4a1738802e08a4bc64a615f86e07135a2e28cfe36022058e91389fa956ce2b2bf7c58abab48e5461238468a9731f05beed98ba6baa70d0141049b3e168e261c0ddefcf03afedfb3accc8a6680a8e918943472b347eedd1735d81f8532a078f28e4dc77086baa1bd4547921519850c93cd62aaccd408725a93d6ffffffff9694e626699f1e0d335e0302e55e168277cdc9bb9a0eb73a057599c75a073503520400008b483045022100fcc2939384dd152bec0b56f98e4254fcecedb7f773532a3e6d5524f626aabf0902201b8503ccbfbd026e505b82fa615710e2fc7c9a36bb90df0872c72bfa6cc1975b0141040814f19865323507f779abda81d66a1a0ceb2c427f8682fa0fa313af56b5a0095db5340d54ed0d5ceb59736534804d1b57cdbd11e28286ff515eaf2951614cf5ffffffff22ba829073169e1616a09eb58819d9181a1c0c36bd252c0cbd3d6e274ff35f344d0000008a47304402200f0434bab0f2ee9644b32d87ad1b18b40e26aa48d385eefdf169e7f7077f96b0022071094cb569e962046c5dfc00a49687241a506fef91e00bf8a4bca0ae9b78697f01410470ce230f6b0c1712e7532412e2bf8f7e079f533d910e541de93d39ee2dba6ac71f8b3cf9a04bec42d55c4a0940c17099be01b46d75dd14fd6fc00eaf8d2957c6ffffffffeaeebc70d3e4b5100a08eda00ce2287879a74ce9acf178ef714534377d9d5b0efc0000006a473044022059d962dac535d27c0a454c03ea6f22bc31d56ba24efe163b8ba26998e784b6f80220398d6bcb9939ccd1cbb2f57f6d2d445a4a0236cd2e4143e081936e36a0094d2a0121024c7665d8ad80091da50fee0067f2266e44151a52ad46fec524857897694ae7e9ffffffff3208e170a9d105edcc0a3a298d6bd0ea973ce4eae6750899856fb2c00fe517ce910100006a47304402200712c7aa84d8a47d2b32b3a5d956948fc3d31022fc65cf712b4e64be042ab311022015fb69a049b36422f24f66e371746194cf6517a64023934be0358a4e89b2b11b0121021d6ba682f57c7f3c6eccb9dece3113cd905ff49fd8d1a6a9feb551c9c43025aaffffffffc1d4895d735afa2294bf5e825ac19e01e2581e2ef06c96d5d46b5ae82d22b3beb80600006b483045022100ba5866ba8376c273fecc1c42b7ca855668635a0257c99ddb75128f7a407f719f022044d34c29e8bc77ca21c7db7b26c1a5a36e7b699a55e295b13f5d80be82f2be41012102a275fc43ca10138101f247f94b08c84818577512d40f55f483d3b1bc3e67ebe3ffffffffabfd8ff412a8862cde94db7fc5da525384fd93bfb2bba5cece347f52466b5d08030000008a473044022024d7e63adc951f41a11a37d639c5db7b370d9797670bcdaf5457edaef6e4e06b02206b0f81a636255667a19c26eaabae34fc46bcb1b78f64e962409467c024c29f0701410427608f8fcf9a37aae78c117f08ae9b4c083af8015aff4347f1af1873f33574c62a8086a959e3d78668b49da585e124bc9881df74a05f436632f114943f189b6cffffffff49ea2469e80fd7370df6a78c21220fc2231965d45e7e29dd7a8930c82e59e510c00300008b483045022100f2ede7c00f494940da8793dfd71bf2f15b2c2dd7b97af48ea8bfe7b1213cedc2022059efb17080dd1ec406815efbb73ffab2869d4a29f1055526099ff205bc93156f014104441df54474be10c1ec29a183f90f9bb8369b66cb023dc6986e0e868c68dd94201720eca391396521411ae6e0402b7f80480581616038e3fae5509e7513c7e6d5ffffffff58740dd8d2d191f72e87d2433eb10db78bfef4ce5fef1d0cc3a1ab7e9c6f78c51b0000008a47304402206b3e058e0c01412fbe9ff987a396d84d99af46f359efcb1893bc25a8f463f59702204978d173915eb3105e7d83837d4ac8795afea1984775f991287c8c22ad5cb6bf01410461311f10568803e26dab5140f770ade6b2a5cfa1f4058e705dcb775ec6b90537433e2294e6aafbf65413044a9d1b647f142f054c0e52825b92d9679756dbdd17ffffffff025a520000000000001976a9141d226143f324af1aaaefbd6a3e7385563ba706f588acc40a0200000000001976a91493cc36e6cd87c4a3b7883a9ce0228e2b7aa38a8688ac00000000" }, + { "d04d926d06e971f3e00882b56fbb4e1f4b92359d9dbcbdc6d8095c5eed3d5bf7","0100000001df3f6053a753978e0a9515681dbfa3dcc2c7e8433d13c0b7e4d049af5e0c5450010000006b483045022100baca348bee08cf039d9d3a623e295824e50815b552a96f905fb68993045e86b802204af18c2d7df3a14ff4bf1e914f1582c60c32f6ab4b07433fca20c6ad21be96f101210245dbd4f2603eab16a2c5203ff4232e8db2374b67a1205e727ac0a515ed5ee347feffffff02d0fb01000000000017a914d94e5f406e7f52cb33e4bd7ed5c63d85917745cf875d2a1000000000001976a914675bc9a1ca507c939a8fce58feb238ab0b49680788acb8210600" }, + { "033ce9c8866badde94d698d57dbc900876c21ad0c3ddd99fcc9326aa9efaf551","0100000001a26b1d4317f7a3d493e1ec71b9cbd511411a68ad3f54769566d07158eeb05277010000006b483045022100bbcbc07bca115bfa33e2e8e78c121a483996dd5c3585b6f662a6b5c7123dec3102207c13680a7827321273ba7fb4bcc69d2a93b58d0f75de034e0ca1d34df350824901210351555b6d4de035dfecfe974c66bdd099ca45c83ec6876f93afef3e17fced9337feffffff02adb56072010000001976a914d2cd6b2cf8ac48e7fa05c663b0413ff9dd0b7e6088ac5ea934010000000017a9148750dada5d438556d46d7b7163cbb77e8c10f80b87b8210600" }, + { "ce156a152053bf5389117bfe8d6ed8e2ee1770a8f5bb414bbcabf01b958205fe","010000000a525ad4219bd2cc707edf226d4a4913ba22c3be993148bf43db351b0212243055b30100008a473044022056e052f3c44720d2950c37861bb5de5787ab6355b21a4db474bab95ec3c193a002206737aa38552a02849c5d65f55fc36c3be12e53bfa79a258d3e6cbaacda3696ba014104838cd6b02bad89552509be013edf695b1aad84f726ae3a532893e519e5d871e21a306ac98240b6382772c8103c779319ca2da1a11c1a999d5937927a4d9a4cd5ffffffff2a8019f6ac16b73989de4e0b3c8ade80c34655ff3384dbe902bcc2bbf3b357203c0100006b483045022100b9a10aad2a3b5325ade2ec757966129eaf36649e606497d879e66db10a91fbc502205928472003552583571ffdbfc6b905f27240cf720e633991d88714e32264535b01210359208e97709098b2a4f97fe431897f076065faa809c320abeef42d4bc0f87d57ffffffff78b84381a2d52a00ace3efe627c6c759a52b08b7da50477ec865db5486fc8eff6f0100006a47304402207cff5dfe154891d8b8bb486415fd427ab6704cf1b1118e1116107b32bcb5f33b02201542f7eb441d6164680749e4dcc0bf8e5b41a1c283f44c02e21edf0aa6e0f6e80121025a0b7dd1753f1d624b50c8b37a7dff3f34d84ec9268e11aa8b1c1418509a04f4ffffffffe85443c26d89fffe411ceafc73bdd2a7f70bee67ceaa998b55c79b6f4eebae418b0000008a473044022067830a045dfae144fe08d5c3e335c13dce31ecb3e44a0a5d328adb51994b000e02203731d1418aabda59c20d6ab2d1a12c9550f5c3c2fc2506b8bb5502737bb0f47b014104d3325939c6ec8314f45511e271b3bad36372c4445a45a66c6d708ee1acf8dd8fd2085fd77a25c7a96d4fbf4f21f75234745057118d8c622f744645a34c62508effffffffb66f39785bd9a535ebaaab4cfeee157188aaa028cd244bb48367594d6efbeb71000000006b4830450221008a6be9124e3235e4f83932960ec4048e06a368932f2cc7b616b72cbd75e4577102201036380c1a00c5ed310a491b8084f9996749e7b1d7067dbefc9e99923d2f98b80121025a064161c337f36f5305b5caae1af1bc1bbffe6f6956957ab616473470bd4280ffffffffce480d288baf26258b8dd253cf29699fb0525d5e152542e971138c147f845d5c8e0000008b483045022100c60848b8cf06d8fd374f51e73e5b6400bc84fda0e3be3855f70aa77bac0533e40220342603187cb99d224364b4e1209b3269c776cf410f542f4f5417a747460e684801410463be78d6680d4a25310bf3fab555328f887be5820347a8a9b01da61ea51550cfe5f6e8c9e674a635bf03d1f9e44c2465987521c8efd194247a6adc011b8c5befffffffff9fc763c004c7df3359bcd2a54642b0394dfa3f94018f5c472a6627faabcb6d91860000006b4830450221009939e536eb78698e6b38d02824016fd3be1eaf3c5c9e11d31ea1cfb61da342270220701fdb1a0f10ea1e342ed0008c6d51c9066579783da636f65781bb674cbe4050012103dba2c2b976be908c55435678c592cf805be92b9d5d29c0a3d5c1c98efd18c348ffffffff5a1a27f05eb3685c3b54c55cf46656d1ea4e9b6e7dfcb4d0b77e1de85e90f21e0d0000008b4830450221008c38790bc2dc8595fe5c0de1d0355bac19dfe4eb7c0890fa5283842b774b209b02202a084fb53eed8bbc51011b2d4ea607045321a0712cc78c4ff1b6f94b65c8d395014104d059a56f591d4d7252063df138acb86765621c299b38aa0967b044ebe8de07e4ec55213c3065e02ac08868f1d694e667f2fd38d106f761e58a143deb703719b3ffffffff381cca716ab0e321645934e72c077b9339bafe1d4fba4a3a57ecea6be685d64dc20400008a47304402203d60718c2fb5fd58a8e3cfdb8ae42e1dfa86dea3cca2010794d327d3d51ee05a02202e91a8efebfa3c115aecabe2d83989604bb8bfc184f8dcedae027aa93b3eee7101410484d0212899c9dc16a0f95095b7c4adc8034f945e8024f5ce9f1f47da135dd2462aafe19190d795a0b6bca271b4b1abf4eee41b0be341794a6c0f1931d3299ee2ffffffff25bf0057ff12c5b0b9960d676e04cd125d7692b1cf615ec65629eadb8a3b6bf59e0100008b483045022100b35769835539bc685a3bdf321bbf442e8e980bc8e26b34e76c8dd46ed4919e0002206fba1d8b4eac8844d53653d52f8811c57ce5eb97485e8a043e79904d3e12aca1014104deabf0f3440913228eb2bd8faffeb935101c1aa141acf2bfb919e041a547b52b1ef4955cdde581ef52467c311574e4f86e131dd518f40cbf375729fa3ea7987effffffff02e38d0200000000001976a914ab2f40e505f16b34512905d01c2ee2385481a81488acec600000000000001976a914312e121220c102cee9145ad7bea686e03aa3165988ac00000000" }, + { "94329fed2198e0593dae67d40f4e7aaeaa4593439cc5221cb8e6c411fdffa69f","010000000af7c6b75734fc8f8cbe30a9f7a06e477be8b25af2594c263dbd781a1874d660170e0000006b4830450221009981c8b9425fb7205e0007746a8659257df174476ac5e6140343d378d7b195ba02205862157fcd87085f38f028092a205d7a85e6409818e672d64aa79656317f7539012103a7a48867d273f3baf77dd3a0e49a2bb7926954d1b3d9019c34235bb40f75b3e4fffffffff0e5fd1bc3017e1ff449b0f7f44e3caa15d182e23e154392c97fad2a99536097000000008b483045022100fb5cc9c6e904d998b0a515422b8c284b030eab573c374975641ec20c770b48c2022003fb38388fc4fa48167bbf25d578bc99a3a60ab7f9092c53ec24e253cc58637a014104e8b65af61837378772ba2153b7270a441145c2794fe06748f5358195f5e640679e14d346fe44835bcac32873ee7d6477a149d6ecf80b49c52ee0de8b7e9f487fffffffffb54d60ff07c3322124c3774c0e7cbbd49419158ed46a5b6cf7b77c8e3c1ff92a910000006b483045022100f0020582c8f4a8dc59b37a3469619a1b188faa57c89e90e80192b7373c8a547c02202ea1b5b73964ec5011d052a784508e7d089abe2aa227377a146e519eb879ad300121029a95ea5119703d0574e5681fd825c9265cc7b4c65d483cf030e467be47378f47ffffffff1f485e431751956d6878a69b2a5a5207f05b13ddf857fc35694f59dc7ac31289010000006b483045022100a6939e82c95fb59ed3585ca450a1917c611ade67ad6deeea99639691215e0153022028a4afe837af269e5579195c32c966961a68e50375b30c89ac455707213ebb0d0121029df96f76acc1023c95edc5d455a22253a717176921493b88a56e300cf685cd6effffffffd8491c0b310bb6195338112504aa40f1855b6b970b3f8848d363362be69f262b400300008a473044022073076566d9c323525773970793abeb90f30bc3657205d820ca9fff4a503c9c7a02201eb5e5e6b0493add7153b5b84c27f7054067ca0049947c9337f6bf9d6ad1bfed014104cff54106be4520b13088191a75f748991750176c5d65e295c309b6e140269d12ecee52b3b08842bfdd9f7699b4961dcd56ee69bb494bdbf0a4831075b27acbebffffffffe16f6a4778d06fa7ca2bad0e751d1d4fd67a2ab202eb87c945c20bd0b073410b2c0000008b483045022100d2e6c4343ac18330c6a7538319f5525c619f123da2126c83309ad29e4ed5b6720220124c1ca66ce6f36ea8f485c060443725b6af1b75da6a0e1925dd45aeb4ae10e3014104d9debe4dc10600042b7c8270544ac0942ec83e285de64c641a3b36208900bf58fb2957ebd46697dbec828d6a4641ae63ed2faac37a26f633bb8414af43a9ef72ffffffffad9664ed93073f460296668cdb44f0832b94a9fd24d4bc926a5c1e8be29c9bba590000008b483045022100816bc74f470ff8650761a9f79bcf6164857fd6d1fa8706fb2d79e429690fb192022047b4009edc93a069141815b8531ae226bb444eeb9cae2aa7678d0d26dd5e2ed101410435c9ee74f39e7da7d87e0b5bb860c7b3481f1a3f6eb927c0fae544723840139dfc1ccb2283ae7b078873e88ab82bde87529031315ee8572074b7899aec656cacffffffffb0a92e2c815c36bab438e37b1fc1c90859f3ba0e011c0745e550edb511e66906150000008b4830450221008a5410f0396ddc5607fc50a606d1eb682d246b79c038bea39654e6661c9b2e7d02201db3e8c2f74b442f06f42775c2eacf71ab61927ae087098ab252ccc898ad57c1014104cd20f3ba02fb9e4994b02a46be84aea089ee13c4ea3145dda280652a81bc7a1e4f691c4f4c2e7e905947228d65a7804e6dd4256d1df32679eabdaaf0d53f64bbffffffff3e39cdf8177a5f73146f80977f3f29da1705ea5f1cb15aeeed3d58ba3d877152c70000006b483045022100bfd175280bd029996918567a8c797448b985ed293ee8be86d057703778cc377302206de9a87843938061783bbd7bc347c7ff38bae7ebba7b061772d408b805e93d990121022729958bd9e91d16207ebae22c32a16aa55d5022b54ea256344e8ab88c4091f8ffffffff397cd8f87e6e9698ba6164b554cc5cb7377643a00a6e28a5d180046cbf131b2b5c0500008a4730440220474aaff51c009b0dbd571a9aaa729aa62544a6212a3ceda2a6b8dec5e2f20717022066108bfa2ab14af24a0a1a91b0f6c5185d61e105f18cb8a783a784d40bea66060141046c7a2641892c6eba73fa39795ee7b7938d6b397b513dfb64979556d1d21a4126e83e5dc0146e7f62275e601503e4e97b40714dbc234a6798f55eabe281f15457ffffffff023b7b0000000000001976a9147f989a4a2ecf8d019545b8d00d45a17431ed16ee88aca37a0300000000001976a9141d913421a7e046511e51e24e630fdade72ad7a9c88ac00000000" }, + { "11e6fce4c880688c2fbc85428de064991ba9f983c44f78f4efc4522deb75d781","010000000af7c8facd5b896bd2dac8e4e58a8a750c90e06c5c760bbcd7b7a9b579c2f23e3ec20000006b483045022100ab76244b1d0604d4c6a1cfcdac0ca5ff693a6716b92069080a7bc9a1c3c7d2ea02205014bfcfe28edcde3fc72cc19a23811e99c9da5eccbe2a14426800824f681b030121034e439c8a3cc2e483dda72b2ab2751e58efa58eb58e9b5f5652c3ae5d3640e202ffffffffab5b6dce9485c25f9ecf6aebd3eede6d43c74ae49e1d81c4f1804b912f121a6a320200008b483045022100eb07f0dc35aa1af81622559f87f3b7d6c3bee2f0062185150701f8890375395e022047f7560f123b71ea3fae6b56464fe124e270f8e9dde6ea7f8e89cb49d515522d0141048089e6a683c871fa0c435cd9a8caa9cb7951a04e8ea3313fb10d328fc845a8c6455d85eb748612f84cde242b40f8d8b9d60eba9df5c2810d3d75fd0b1a2f09a5fffffffff7c8facd5b896bd2dac8e4e58a8a750c90e06c5c760bbcd7b7a9b579c2f23e3e5d0300008b48304502210090e7eaa5be450729671c4126810564976db1e8453730cdfcafa9147e7ce4468302202673bbd2d2f1eb9aa7a98af0b1a289046d003a6d4c9bfe510eb9558bfc3f407a014104f6ce0bb6ab64c65af461ee58205c64dc23b1e1534554c03718bd6804ba3001ddeebd8cc92c05902e5265db819ba60605da754cebccd3693583be6d73b5cad3e2fffffffff7c8facd5b896bd2dac8e4e58a8a750c90e06c5c760bbcd7b7a9b579c2f23e3e9d0200008b483045022100d0dd041e77f6b4d507f2a6b9c8f7651f3fbad6580248b4225e7336e786ed802a02206fac8de1be03dc24401caac0bdf045f384fe523178ff00d9c7647ac452a1218c014104ffdeda5330582c075b8ad270ca405bc300f5d0ae134b86f76de66ffb0414b52a87c20fd097b74a8b486d9b0fcd949c2b04d1dbd4b136d30353acc33bb89edb98ffffffffd6d14313cf8db9f8d117cdd7a03311076c288d1e7d9e489d168dd93594693c31000000008b483045022100fd8c2a036c92b0e237299179c0ea884b6b2b7ef09e76736ca515eaa12027759c022010d632d062d27d342dd06ee174242fe94df49f71ce7cd2a251a1a42bcf08a9c60141048c15bc95a304f7c7a8f4ac080011941bad3cf25be88a9f71d3bbdb4ced97f57f09aa4d2af94b6be5c3eb85bf710597f74ca5701a0c1e95549346b28dcc64f6dffffffffff7c8facd5b896bd2dac8e4e58a8a750c90e06c5c760bbcd7b7a9b579c2f23e3e040300006b483045022100da5c2ce5bee1ff4867ba44fce57ad0d37d1cff78206b4f37e1e8b2a8b03b3b6a022015236796cc811b656ea5c8c5f11c079fbf675f01417034127535d88abadf5a10012103e1aa34c2cdca2b1c97e1f7dd70513419bd877cd7c1965e873bfce33c933970dcfffffffff7c8facd5b896bd2dac8e4e58a8a750c90e06c5c760bbcd7b7a9b579c2f23e3e580000006a47304402206119512f19fb0c3112ca8b790e5e55a43948d5e83c9ad4b46eaf90a366d024fe02200140c4d8030ae7de21b188e42bfc8e3be7f6ebb8bf2b0dc0b60889612a5dc440012103d8895d742b3fff6d69dd7df9d18b751d7ae62f1bdad580ee0f461cea603f7d1bffffffffc0276eb2b6744f3edc4b1500ca39ab7ded7a911e95ea036d3d5c83c44a98f5ca0f0000008b483045022100a002d02653a4be62ebf06d48df58ddf8056b8d6ce2297c9860938ec39d316cc002200672a5e187a2b9481300665c52f7233c9ec0fe92c4eca5713445ac7f19baea6d014104bb5f42c702c8de841981e3c84f02162b457c0855894311e2c429378d5133954a41ee7d8a5ffa819cbd2f2ad7d07e52c45a7cafc6a188dcae900d7ab8996292b0fffffffff7c8facd5b896bd2dac8e4e58a8a750c90e06c5c760bbcd7b7a9b579c2f23e3e650000008b483045022100d167fa6873733fde53700e562f8ae9c8497bb49aabb783d052672d1ef10aabf3022031652b7c97832c56a6554cd9433b2164e9b7636caeb33b518ba3f623fd0e9a910141044c078b1567844e5137fbbe5eee3fe14cf346c256a0dac856a5ce79e573e3713b3d2f9da7774d72dfe11721dd7b0517c287494772b67aef4836ee67ad1d6366b2fffffffff7c8facd5b896bd2dac8e4e58a8a750c90e06c5c760bbcd7b7a9b579c2f23e3e1a0200006b483045022100c75fe2686293e12771cded1a0b684690251e8c1ec20bde8184aaf755a73ed03b022040ccb81919fdda5083c834a72614148c905943a8f7ff6dbacbf48a1ee5ab7c7b012102e978f0959c604f315c317d84f317c39c0a318682f24a8688dcfe64bbf8daa36fffffffff0250c10400000000001976a914de5ff2a158dae59201d928a508061d1d8c74ed4e88ac869f0000000000001976a91417b78bdb2f6db8b986156f0bbfbd3ee4bf144e4a88ac00000000" }, + { "30e38ae89e2cf8106c37107d20ad86ed19531a1860477062998fea79886bbbfe","0100000001d3a674633b9e1df35ca9349ae66ebc0bcfbd8935f1905273fe9540253b61c596000000006a47304402203e8ec9350f673165f2d57c31386b6628c81a52aee027a24c8b1934a33bd735e202202f5cb84309ee974c568352922443cc386b51ddfc384ee13753fa8dd6b4515f77012103f0aa7dcd4fe16a3e9f34c3ce8d2ad43e4ce2be49e8fec7b9976e6c53c298f146ffffffff02db920448000000001976a914a739fe2a7743f2301b7940d1915d4473ef99c1bc88ac55615100000000001976a914d05499dab3f96386edcd7dfbb81bf88e0b11e83288ac00000000" }, + { "cda3d749122ad9635f11546a7b1d06b63b12056201eb31c0ac53c3e48401bcd8","0100000001c0d4b86b0f8cdcd5f5ba6e7c2cfe5196f7db3c67fcda721d0c1a3bb24e8c1a23000000006a4730440220557028a8fa23d7064954cc7e6870df191003dcd5bf788f402e113bc752018eab02204cdfc4c7751980e34214d5f39568037f656fabd2bf6678db1c538f011c56c5fa0121035273f2d741c39a3409270ea22b38a8df93f2f5ad50b2ddfc83065d8e549bfe5effffffff02d73f3800000000001976a914c77f2c9698537cb34586532a318cc1e355663a0b88ac60a5bc01000000001976a914af5a61e275d97ad7623f232b0dfd93a053d6e89b88ac00000000" }, + { "aae8deb2fcce97e5c42e7c9689a1c2c48af2991fd9683e8bf4c0077f267744b5","0100000001c4262e5464cbbcc3144b880345a01bb33060038136ef8e5cdab661ada40533c4000000006a4730440220367ff658326f171f636c2ca64641d9a19455b6c863de2bfb1ff3065988b19595022058e1c5889b904b7e18ff07257740bdc068bb2a632c964a8e36b7d9d629c7c81b01210372fb73b6bdfbfe35102d773c2f00c65533bacf3311736cb87aee576f5918c6a6ffffffff0225f2c400000000001976a9144bc2c0e2217b39cae285cc9725ddc89bea8c47ca88ac6be41905000000001976a91491a2c6517d978b869d31b989710a65885bf5c5b588ac00000000" }, + { "017def7893015d2e9ffd7914d5a66d8a67159f0eb8e775a1ae4bf4ef388461b2","01000000015d6b87c8958d4fe7f58f2991741e461c20e45aa067d230fbb170b7b025bdb36c000000006a47304402205215684d8f83a25b735a807a3a941aff5970045f632b9fdc2c7ec84cd65b9aa102207a8c61e7bbd1c50ae1e8837449a481fd33454d113d8d2948a5e8fe62a7a2603b012102cf0e621a86c2fa35e5a14e809d7224d41d1ce73b1d41f4b5dce74fd5e6fcc9fdffffffff026e85ac00000000001976a914a1ec1caa683a3416f19e1880889f3e3a7a1aa70988acf1897201000000001976a914ff2eb7a1dd90d9a7b9d722bd61ca38d38d36545988ac00000000" }, + { "6ed1b09d017e5eb218b801ac96ecfb58bd58fa458424e025287a8662b18ebfa9","010000000162830105ad7f8cd1ce907fb4c5421eccca7378e6db0c4fdc1a589e1fe3c23ccd010000006a47304402207f42cf872c0a52930106f396161c33a99381227b1786706aead4b13fe4acd410022009ca20ee75303672854c5ebd2bee3bc8bcd8dab897dd6e6d02890c3ca8696c8e012103abfcc4d5c581c262d5a8f0eb4d9922392c77f280ea2b69ac0d9f9fabd4f8efe1ffffffff0200e1f505000000001976a914a3e9396ce2e8925d9155b41004f10bffd69ada8188ac96d2cf2e000000001976a9148638c10759ea3152e2ea13fddbc613fe9a5a01b888ac00000000" }, + { "d5905d5a84f9ead87f3e787c49ae2af0868ec468e68df16f01376fea74d73c94","0100000001c117fdfc4cd8737438a2371e0b5a4aa4dea64789efd9be6f6d32fb03e8e4e65b000000006a473044022100c1d7afe9b55b9328b931ef1b1f5dc4e9a2edec714fcec61b668947f6895a45c3021f7d658cf1d4072bea6040a23b6784b91115ebab1269f9d8e69f0236621ac3ad01210392e7b76ecc314a38a890e491989676617f67debdd32dadb3efd5fa81d200a7e0feffffff0241e36608000000001976a9146f741da7f858347a091cf6be6012a4bc9c5374aa88acdf40dc00000000001976a9140aa2535858216d21b640314bfd44feb7e357a1d188acb8210600" }, + { "67f18cfef3388e9c3b9c8031c81371dcbd52cbdcfc664e777c5f515bc786887d","0100000001058e48f1433f656f16abafd358998bae24aec5489ac0d9d508c9bf9d510cbc9c000000006a47304402201687b02b4b05dce0e573a02a737a8d91cd480976d9c0c658f9a790221f5bd8d3022059527b778575d017b7d098e965164069e76e12674e3d7ac18e863c2d32949d1c0121023338e26ccb70790596c6924ae2ce515ee9ea6d99333277e50eb6fce84d7bf086ffffffff0233362119000000001976a9144801fdf97a241b675a7bbd61bbd8245032e1335d88ac368dcb09000000001976a9149905450032d308f2ea0a20965196fd9756da337188ac00000000" }, + { "4eba293176c7f7968cb5efc8d65fa5e1ceca093d58fe0738c3030930ca435970","0100000001eca5aa0bc6ffb747fb97edd67b72ce71b6150a8b4bae1387a75fc68796b1f8d7010000006a47304402206a3b3d5ebe8304a5def7263a6b7f64bdb055380453dbd8eeebe8cefd6990bb75022046f6dda8f74eb74b7093042bf1d40b37b6ea5ba964cd63dd541483d96c640a90012102d5690e011993475b579b2cb075c00a541616b9d24751725ecbdf5925379b4556ffffffff02119c0500000000001976a9142f6bb79188d934c10422b7f0dee5e2f91d2e65d788accb0d2500000000001976a91468a26eb5a19faaff81539773e3e074a62045e6f388ac00000000" }, + { "60b9004615d0e0a759798866bf06a64ad0e5e85b063e9763728014d971bebf45","010000000155a68da26cd6587b911a804a6800b2eef73fcd0df44402589adb7c8848cec725010000006a473044022059bc44a34bc2d570358505f820b8d31d82ac9a2a34f71bbadd17443bd0868f4b022034dd8a5a3cd61efc9195016c6e3268e755c8e1a409d865d6539fcc1d2dbbaaa00121030257ddf909134c74c2e7c865a80a3326932febbea29796da299e924b1cc40ce9ffffffff0298d1bd03000000001976a914e919622df93beff52cba89284c6933dd6cb4b6a288ac64ab4b00000000001976a914cdd5d3291f0588efa88966f0ec5fe8108cfdf26288ac00000000" }, + { "660b8ab641edd9a5e5fc91d58856f9539cbaaa1dca713b4c99bdae58ba348c2f","0100000001c0c3eea77aabc543f6958aa48ccf4da0e08faa4d48377ff1fdc348fc501b098a010000006a47304402203173b6dbdeb5955686c03a9e38f8f8df5580e1a985060f3c9f277bbbc76f78bc022063f3ddf06654d5b80e4088dddf411e45c8da977485e50e23f32f771679c47c630121028b700ae7f5b2ed8ea70d795d637e666d0f555b18d4a534e28115146b141eb54bffffffff0270460d00000000001976a914c606957837cc3dd9444147250d43c7c19337ac7488acf1c60d00000000001976a914d7072ea0a247ecfbbe6d280160c53fbff2e39eed88ac00000000" }, + { "dcd4536c77da0e1eb3de2472d49dd208714efbaf7ab6cad37e649a1a8bb78b18","0100000001a60a099bab7fa58be14a5a1913d293867171d8597e0e9cc717e9d5b45d12cacc010000006a473044022005b05eb3ff1aa3187eac6e7c362e4ba5b1bcf3decda2f8674699aeeb5c90a42802201668d39f664f1928c7cc3a028d2fa39db951bd8d415a3e1989693c9b85f1a7e1012103bab4014c147f01684f6b2a08837adb044c978872cffd65796adf8923a3740696feffffff029d696310000000001976a9143d4edac20a685b03bc3931249d5c9a4f6e638d9c88ac5c3dc203000000001976a914730fb5e9cd5aed83371e329e73ed499b5934c30d88acb8210600" }, + { "501a8f0d10145924875f15044a7f72cc62f27c9d1d71ac3b5765174ef5bff413","0100000001b3376a23322309d37b9722dae9b61de25107bda2134277fae8ad51224b26a01e010000006a47304402204bab53b54ff805c9dd98dfad99eaa4db7c7207f8c78d0cbd8e86798bebbdebd4022002e36ea3ff3553e64c24f0248cab2a42d5b0b8a33c251115df0d25025061e405012103a9251c29c8deb9bb8231e54cab42c7ba78ed6c654f23b96691993f619d9228efffffffff028fce0000000000001976a9144723df777bba3e1f6728a420a7274c7a2a48f39688ac58628500000000001976a914be99162613b0247ee1995c5fc3a3d0db9fddca6988ac00000000" }, + { "61d5700dc92905877046841edfe989e39420443cd0e402bbeb8cb8dbd0756fdc","0100000001f043d324a708da228db8227a2d7ffe5adce8d8bf74cee1de1b67e129469ca226010000006b483045022100a74d3c7eea6b53aed6148d934ddfa955f6943614fbabd11c07929a66db05d77502206d705504618cb8a4bf2aad6371a14d3b9fd2d52efeedb9d07c057ae9a797e1dd012103fef2d308e43f97dfd0eec16529a59646eac9bf0079cf30c58fed757c33879006ffffffff0270af3a00000000001976a91458a262e3b698cd4dc5fddba418d45de6b512469e88acb8ac7101000000001976a9143ed3a9acdde9fc5ccee5c11e1be5412cc56b3f7388ac00000000" }, + { "598f92c589fdcf89a5b9a2a6fe7b0f319301e9cb153ad7fd978c39ae670f868f","0100000001f45ecdf9ac644b115e01dfcfdae3089f46017a6267db63da4cb331b6e4d6e8e0010000006b483045022100f4e8384e5016a9549a6dae421c16793a212bf8e5d368e18fa815dd0b3c1e0dce02205e90c1ec7220c1b96f509c6ab9548eaef3e421112af5f8372a6ab51ec5d8238b01210360ff5ae3e9babb677ec13f889f97ca28f3c36c03af7d3f2018b3b3e1846689ebffffffff02d8cf8103000000001976a914718892e3f7ae1bf7ff0af6a3f83249f675e2362488ac7095c4bb010000001976a9147a90830a0f1a194872d7f4b7e5ee56ff0c697d7988ac00000000" }, + { "0200893bf5cdeca8be9d409231cf4cf08504640501c62558c9614beb50d77871","01000000018a80e4664a3189f860c52fc979c1e8fd81739589b6345d6bb1bd74c3ea4e4580010000006b483045022100b3af93d7eb01fadcfb71bc0deac5770b700f57cd9f8bd16d8fa8a83d2de0ef2b0220756491943215262a048ca7a1aae45d99ef07ce4e853052074457b3eaf09762c4012103003de0706de5d8744f076b33c4c16996361548ebd25907ffdf1914ae972e944bfeffffff02306fda32000000001976a914e01e58e81b54583c2efcb80b5a2e90bbac181e6288ac0084d717000000001976a914dd3b0fae2b1e36c3417a151da5a9eb723a42f26688acb8210600" }, + { "dc594b97ffb60b65679de415e9f1586c8eeae761f4c70242156becd9e7a3a230","010000000165ba8dc39d910eeda3ca39353f194a11b779a48b3424200ad612355d093b52ab010000006b483045022100d1f65ca25e356db9e87c3def0ae986263863979f5e4f1e355fe93c3baa1e0d3002200fb64790cde0bfa397b8d288742b6596d7e8822cb899663a7d1aed3ab2b8ed260121028831d9260a8cb3eaa0495bed50a6f9dd2e60b0f8f1e4b0c1b0331b983e8ce7bfffffffff02c0d8a700000000001976a9141374ceee5768044df609a3bfaa415ebca19d71b488ac8a52aa00000000001976a91472c563a65ab710115940785db85c4e766f064a5588ac00000000" }, + { "312340508c379f6e83a22510a36fc8f2d1a4b96f417be148ba31a756d2f1ee2b","010000000108dad123240a8b19c7fec67893b3070b3e73abe5d582bd682a4f7c8c5bc84e7a010000006b48304502210097982cb619d0107fe6adbf419070f35cde6950e0187bbc93c036e34b7b0e755d0220766ebbe7fc8966cbc14546484b8824bc2d9e0baabea1315afd3cc07f8cc5e4d9012102eb27c35e2c82ce380c53295449cd7307b7c8378de6f828f7cc704e8645c12fecffffffff025a003b00000000001976a91436f688e74254a94ec8d14844f2a573feb1ae9a8c88acd681f52b040000001976a914438f8a08caa1b0b0ffe8d254f3397d3d1aec403488ac00000000" }, + { "7d3b6a74b0d2c8b9476f68a237f8739e10ba086d61dd3ec4a9b52bf619b03e26","01000000018f9443643e5c951736b17fa1dc4eaaad575087174bcd3ef2f362f45a05fe7137010000006b483045022100d163817966d9fdd28451f12c438348e6bf98d4749881466661d3a7ae7ae9f78502201683025ca86b1f0d1face3d6c1630a2ac22b40f6725654776ff2c7e802876f600121032cf1bf56b4c2d37b2cd478f0a6f89a552594b9aafb04b9770f62bd6b9dee958cffffffff023d680700000000001976a914174dbcf0141d88a4ff936944f658bf7a81844bda88acd0f28400000000001976a914d46672702ea66812cf5b21e7366797d09d54510288ac00000000" }, + { "c95b7543b7a8bfcab1d098d90a73ee7fa038f0de1ec2c28a103548a0e5234c32","010000000a53122df99924dfe945439977dbce08e5633f8afa4dbce412d3ddf1aa094f2ec0360300006b483045022100fc8591d7716042ef4214d4e1e0ba1be2c088ee250d34346d616593da2a6b23b002204c60fea56b987287b49ebf1453a2aa8f92dcbe246598416c9ebb78336e899a0801210260de69454b79f6d698b1c1279d8ed38966fadfc95f2cbc74ee1ac75fb5263a56ffffffffad97ad486d2fdd57847ffe82f7d29d31839f1fbc38bd609c40bb2b429814b5483a0000008b483045022100cbb57a744ebbd97e516aa9a096757124e1da3859446eed193a3592e506e2dfb602203ee0507499b3c4b991b3bf31af5665a3e0e1ecf3ece8b998c4dc72de875e02df01410411377c8a82aed18e9de2533206c0587162a0626565639a9a11aa8a2172d9d7eed4fea5a30c5ef1a103ce7b350beb730354ef93a8ad969796e07cfbf958d98468ffffffffa5ac0330ee720c525dcc8292fbd5fe01d2100265ccf34e32accfc0b5d0e90b06520000008a47304402202772555c49132ba5d6e70d33fa3d0dab9721c00c71f3b47c919ad68f7805b1a1022061b530645abc1cca6aea874f3d7ab7e152fa1bcfadf182421510c80b6830b347014104b016de0f5e9bdd0f89d66c8d8256097c1be5eb07812cfefe28d69b1c4495b2c2cc5f12c3e8d28d9d6da3c05b7af5c58f9a08a53ec883a5302bdaebff79af8bd7ffffffff69808b969437f013810324d4e3882da943fdbde58e34bc167b0375907de60a803f0000008b483045022100c231d445450df124e67497ee072bfbd6e211afd5ec1f16caa0bba5cc792f85b902203d85e96c1792cabc5f0488e420376d3cc54a32b28f9ebb5fddbd0419b562da65014104b2467768043b0b864f319d115f7309c9994e527f9f6d4f44d4de5c73a66291b78c824b125d0f0731ba8df145849ee784eee60edd6c956e7b0492afcd2fa8df46ffffffff69808b969437f013810324d4e3882da943fdbde58e34bc167b0375907de60a800e0000008a47304402200dfb993cb5faf60fe94726880dbbf4c8c9dc4db42cb6fbe7ae0a99227de4218602203eaf22e19b47e86fd2dbe9d6b274ffe162408804ebaa554fa2e3122fad9079d501410493bfa623cec05584c46452e0d970e1464e0af28968cd4a93fc80cc71b913b9d0fe51743651e4be0070b41a39adffc332fdccb6755c00f5f6f117ce279d697d3fffffffff938db3e1b67a1c0fe5b778bd4e2f2883771fd7ed72c02d9e63159987f4bcd7da7e0000008b483045022100a36bcbadb8346110202f90594d0f43cba30851d6ca56707b62dc3b5ce8d5b13602202967f8390504f8c549d4d0a4ce1b8485fa52347ba709a0c61dafbb134eb11c8f014104c4631c7253a60e47843e1d4e376bc8e46cf21b5c9768188f00f26f484a6e56b7bdd671174dd870b189af4c964f5132b6155956b0f00fe117523e4de6d3ebe2acffffffffc26c9a92ef1c675084df3e6729cb32c9e279c95d0bd19aeab6ba21eadb03699b6d0000006a47304402201d5adb39a93db445bb215d6a3fe4ad0fcb4710fd008bfbf78aa6f1c3633f9e6c0220694e6b3988865c807bd65e1e0e2ac4b372a6fe98b45a4181f3950c3d5c589ec201210318efb66eece0cc63fa587bc88ede0ea4448e1da3d55f928e28de3f8f19c80b8affffffff9b48e0ee87390ab2d6790e8315472b1d55a0d8729bfbba0a5d414729e75ed5e5ac0000008a47304402206ceadbc96aeb576dce6d3fdc74ac298b1a45d4bde5910d28a5f23770be3703bf022065fb18ffd769daf9811ee681706bfbee5d72ae240d26138cd0fa32d62fc1c715014104e3cc8201c6d34a7ea6522c2c2c0dbc833578a4e169278db6866c80399cee2e80b11f184d9a82db9523c4e8a6656a603ebb866784d016fb5d26e5939511a96f6effffffff43aeade61c7b718d980540fc007a27581f94f727bc7c7dff8211310f7f17c3e63b0100006a47304402206f9bde338f7487f3569eed96eb0df340f9eea6737c476b4583a62ed0ed593119022041f4845887e05f0a32a52a059ff69520d151b373f01c2e6c2f462170ac4312da012102968147c3260db1bcffaf0a00b1a99413060d2fa7585ce4f27a48484b87e5bc7dffffffff1e33e7814cdefd8a02316cdad49a76247a31b1e514c753da2172d9b18d5ede79660000008b483045022100825fb7f4658cdee59a1cdb68e4b4940329bb3e003df23b06d967daba24333081022076e0ca15b6bf10d476e329777abfd27447fe9c49aaac44ed37cb830f92557aba0141046536e89cf3d550778f63cfbfb63b18ee047bd217a50a4c3b727b40758e39c565813c20effd179832581b06bd554ebd7e7ef2f5c41d6415b2707dd7b9fd9b5f06ffffffff0279d40300000000001976a9147af58def9867577ad9e390d8dc2614f9e14d980988ac36850000000000001976a914fdcc6b2fe940fe5805cde2c7bafcdd5a44519a6a88ac00000000" }, + { "b16ced8fcb58dbad1bf32f5dc4ae82d0de2f401f48865f1c5243f4746bf2ec19","010000000aecfb931255ec9ea265fc116f28c25f1982a1a01148b32d8b79c43ca2e8dd1fb90e0300006b483045022100e45d5cdacd05dfbfa26256e68e7647dfba5916f9f663ef409ea324a5d430d53a02201f279ee047c0037bdd342862a0179d10d9e4f81605c03369199bca53725e27360121036ff5fe5c1467357f2a580a2e259b8b8c06c21a7b6f221c306d1bd036bf97f5a3ffffffff8372563925682e1119219bbcd544a98ec371f46101b60bf89303229a68e1f854c80100008b483045022100e3beb140adf7a85f2832f95cc894496c14ceffa885015fd1fcb059a01a2d5bc20220677bc4f01529ba630b177e06bd549f06a1a314ea77d60b8386e98312b6f245dd01410488c18edb978b161dbe08814e88c8d246b2788159a2c5692525f1debaa83011b5fe1b36d13ae39ca2c2eb93ce741a12f017a89e0fefe0e3d61ce866b555340b48ffffffff27e1ad22e4c0c5a0ba9810b826a04963494e9bd17391d201fee4f6f2e01566acdc0300008b483045022100f087d4f2c9690d7907866c3a0dbc772a6988b7ea93db75d1b2f12b96dd67668f02201fe3598031d9c0cd52e23be64db3825bb800ddf3120f81bdbec69a3e87f12ff5014104a09bcaa8642dbf72b811085ff3aa18c4c4ab5af76370f777b36eb30f5ea89b0b00e60318ec84585e804ea72e2688681d9b2565a7d635010d7a168fd31bd894b6ffffffff27e1ad22e4c0c5a0ba9810b826a04963494e9bd17391d201fee4f6f2e01566ac750500008b483045022100a562147e87f435e4637f7d323ae736a8884fcd144577e71bb8a84c113ea1045a02206e662629a609be2064607afa02632f2a712452605d27f64714fba2b74c462e0d014104dc67955ede085f735c5e8effaf7ef940cf000cb9e1ebb28c8e762aafd84f3700171b34850adf046a2d3e855f9e7b1eab4c18fbc1cfa4d154296cad902567fe97ffffffff264488d1d527f14eb48279cb18cae07d0f86e7a797abff4c7750e5c9b7685cc3d90000008a47304402206642da5ac63022a69ea9d1888f91dce48c463c1bbca3f2039ad7c0a1be592cda02207d5b1b069c3849243031912c97f6c0382c3d169e528cb06563d742c9f1a57410014104c64aa999d3f70483da94b29fab955c78c37216bd806dee85d9e4ac63f2d6239b1a4908b056741cb23450983e51e944408a06a804c4a16a34b2af4d2e767df23fffffffff27e1ad22e4c0c5a0ba9810b826a04963494e9bd17391d201fee4f6f2e01566acd90000006b483045022100a35046df9bf241e4a04a8cf2cb98766cbe5a5c7bbc6a4701bafa194537d58567022026462d7612d37a226c33352a118f5bd50cfddadbeee9687d2076f72695d3e924012102ce164fc8746bee4bfa966b21ad5adfe69f2d026e6851a18dd471777ffeb469adffffffff432e8494a81f71d004ddd06ee897998154dc2ba86d4037e62d71b4ee0160964de70200008b4830450221008e6556da6dd88a4bf19dac65939cbc2754d00759586089fc5e0fd8f15090d23a022012c3344ca80e3a65c00c55d4495f0ebd65ef6d16c4e95b9f8828d5b916831be4014104c1c73f99f7bef9933ed4a672ba2cef72adf90eb67ce1c14154dd32a81a494c9f9b573baa1ee516f776367ef3e6c11c7807470054db88990ca6ed16743e0a5031ffffffff4a47fd194e9ac6dddc72b74b24f597370ebf814abbeeae35d77589e9d4c6f88a870000006a47304402202db6042ba9016e7c949dfabf2c6d1f0b690d606dfdc9d21fcd0da92deb4d6cdb02207c7b1574587cd435fa09c7f7bef19c5a97f7a14753744be7aed6e3429cc65b9501210206bdc7a0e608e98b67c2e636443c760f12afadc2fb42def2ff3f2285b5a41b58ffffffff901ad94235fdc54a711fe3e1aa3bd8f96b0119f00050620a5d8bc3ec7a553fb8370500008a473044022059f83d853f92ec2058b5b613801fea08e9d38df58e4ee8f67e18b0bc62c5abeb02206d378f5d337286e85bf38a67c29f150c30df5b5fb9312e1d36dd47bc0da78f8c014104b2acacbab7c04feb5def9f4b63233cc4cc2485f5036e9cbdc835aa1a6fcfd1f783a81827ec8ef59ced02aa0a2f36293a00c1b026101c4431bd22185f2b34059ffffffffffb57b46bc0db827b187b5c2d1d0f0c778cdd5554fd753f9153ecd098275e701a4c0900008a473044022052fcfbbfff4d30a0c8901c3800032fea810bfd56f48829ff0181c0ed4fce233002201c7acb690efea037751cd10799ab04d9727264f6c35f44c23bc8e4aebc464125014104eedef4cadda9fd9d2f292ee3a6ce2c65ae66e5547efdc84019a5adb1d95b20e51fc9193373defc9a2a59030728250ebd327b35014630b75e9852bf18449220efffffffff02fb2d0300000000001976a914d35769dd617e0b886e81c9b554f75c66a16975e488acb6720000000000001976a914e69ff0908abd7b06c1cd23f50ecf184e5679fe8988ac00000000" }, + { "3a1d212ba80de637c085a5ab9cc91903bf72fd90e3fc727c091a02c1ad930916","010000000a29d637fd8c4931c003fb5b89babe297c1bf327b41eb81f31fc81b7abb6185a44010000008b483045022100aed96ad6464ffbc87356a682af7603f513733f0e74202f9b758706abe2da08df02201c55bff7e11d88c0eb2452b576cb8de975f79e4dadd6e47b3a79ea5a13e2f0f7014104d53689d4c4bef42cacaf70706b80c78ae332561b8e999318c66a09c7d8249813e4cba5c1bba8858dc543d9dbc8932b9d7074af6452a30a29e1628362ea244bfdffffffff74719045b8eba432bb1cdd18f548ce6c33677b974926f55661a7e336497025765b0000008b483045022100e23f66d282ee6f8413f4707c299feed060bfc1acb98fc419cb647f0d2538afb302202cbd0c11490d6ac18b65fb6543cb7bb1c79fe430f4f2443c19782a534cf0e142014104419e27d983b087ce6672334bba6d941c8bfde8a40ed0e73c09bbe159711ed4f05c17226e6e016ea9cb0cae7b67b5646a49669e4f477494c854b8f714f055e08affffffff5844c706a4ad5d10dd7712ef411bfab944ee032f77240159130e2b44c706627a9b0300006b483045022100b0d6f11307e97b2b84b0a8bdbcb1ac2a73d1a8cca9ee315148320ebc677246a502205c32f3d6c521230a843d332de4890487afd864841835f66e5878d8ca687afba5012102c48df889cc379f4fe7887c66f9794541ef1fc22e5f195cfa74ca8b19ea55c433ffffffff4c4ccae49662d779e2d4941a5fed060a8ae9f426c3140a4c43974f1fa67e9b60640100008a473044022068b011746012fb0bc175cd931a51ad390cf8dd1133da5a861f674394f2aa5ada02200d859224072e6569d706c14334ba8743a0e38d2868732ed3196e2c651009000f014104516c969acd3331b1117c448e1222d62150ce21e46caea91a3ce6061a67d17f870aec3f4b5db64cb31902072694081c5f88db007dcde19011ba87adafac41d53fffffffff53babf4de3789938496f41aa65b7aadf7d74f3e543765e4066e2671147b4b63b260400008b4830450221008faa586127e651270cb95c27a0930d6ade55ff8401aaa33923a73f83bc2ed407022051f0f5e93ab42dc7413d917ea3ad263b30387dcc3d31cbffda8515e8ef1b3622014104e99bef50a680f80fe599e2c0c8387e32b5064f079ddf7b383438b7c60af33a4cbed22d27caca338a0c56d449146aac222497701510f0895de95983766e17b5b9ffffffff514eba8598cc974c7e7fa0f6cf97556f19aaa628ddde0d8aabc9ca5e93399079200000008a473044022079b13903abbe5c501aa8e037ba698a2f20bf830ce00e7a3c799e9b49fff82b3a02200bf62aaedfa1f766e92893a7d2e4c40dca55a6ca974434547040ca02a3d5a2d601410489ae7a9c1d6b94f2051e005d77f298f97e2a9aa322ad2dad1efb6575df99869e8e153a9d41d5c54dec06408706761244f570a2f0db155dd1ee1cf1b1f71b44b9ffffffff6cc7d6e41edb3bbda4d1cce68a6f64cd1091b60f60ac5e6dc4701b38c1775caa3a0000008b483045022100942e274219e0f8bcb8fd14d7b89f570900d375d6a95459db1980976ba73effbf0220334711e0144616f83dc54d342d15b03ff706a13c20f4ffc6d4a389c354e9ac10014104debb15cd5d1d8fcd431de7749cbe635f9123200b71e7aa004af424f761036dac47d563454a5dbc40866de21312c7810446d662fde804bca2004ba70fa5fb8cb6fffffffff51271de8174362a9f36a6e73ccf17f9e0ce9f6d163e48df0369c89762508105110000008b4830450221008441c595f73cf883df5cf2c81f854a67087d32f6442a4bd57b9b0d16a7eafcd602204013c1518d999059c758ae6997c9f96f0708d0ca234d2bcaeefe57f4666bf5e1014104c273701edc77df9788fb57ad6c4c5d6012644e0ac1a505ed7e969829bd41a2310170f06f050737ae88945fd138f70c80ea76540912ae7fab29d637ba10322f26ffffffffb7355040e333de280e7cca8ea3f69e192f71513504e56fd80a305346fb4420ca390000006a47304402200737ea86b30b5242a275876cb5fba80a54b7d052e2bf8c5c634fe31c41b5eca6022071f56f10cbf78571179c07cdd390e77fd172333a5b968f7946259aafc260bcbc01210399ce89d50c5e1f186f44aa28cf5e41ad681981932f0c945e4d306c1673ef6f56ffffffffb2bf8755186060323a0f4adb565416b2a56779790523819e1b6b672d1a5c250c010000006b483045022100f8906de8d53a7a66b12b0317c49f4b321b2bb01a9b169b7e78da77020fb824e702206b5f35529a4f0846afb729069c1046fe6d65033d6d79682473a1dc33508e024701210266aeee5c007cd63b3ee08f944f9404849dd98d9b09e2407c5d790d9bec415872ffffffff025e8f0000000000001976a9143651c3988de8ba5867249b94954010b4253233c688ace12f0400000000001976a914b20e46eae1c03222caf22e8afe39af875c48091d88ac00000000" }, + { "d5519e73a3a6c8eb3c5415fcc734d9c7f0bcbe494bd67bb0bb56dac86f9a486e","0100000001d8cb5d713283bd8190859d1e93826ef03e59846e3125fa8fadb0e9cca893243101000000fc00473044022033a4d0d9bde599d71d411d299f67d03b998d5460332f78b3bfce55a536b91f68022046e3ef53d055f3209de71feb0714f9b0ccc8031a5d2217e830d8839ed1f2f5f9014730440220288650646d658d2c52eb765e86be85901a7866a1904eb28e015b972f6517ab9502202bb0e4f291466b3c7fd863f64eb88895b8a391a7005327a01f2941c1ed9b03f3014c69522103385adff37fd3d0a620ebc4e9866e81dda8ba8616e5ebcae899c7f51899267ae721034c08511718f947d1a3e152195c5e2756588e3e0c2c7730927eb6647af494210721033da9f8938a5b947a723df21b73fbd3985b719249324d2c705acfb97d63a5df9e53aeffffffff02c0739702000000001976a9146dcb4b2bb7e951ce810e16e49f9dd3e333dad12988ac74cbc4120000000017a914735d4de855597997b21588cc78ca2db696be1c5d8700000000" }, + { "99972b437ec908fe2eb252f729959d8905c0684076bcab7959ede500a91980c2","010000000af74366edafabd5e28ecdd5a90e75da3d691da450b90a4f32e8d8763d871c9bad070100008b483045022100f6d8a03f0183cb301bddcddba901acb77be47196cbb742d23fdefd7326d8bfa2022068c0e79768d97258d2bae4d43d21ed3bfe348071fcf81a0ce4bcd50d02704da80141045e222f8e76b1ca107ed5f62d056714638aa498e9e0dd4795479f8bd33699dea1fc518242def6c25b823d81bdca256de3fc6646935903099b7731f50897fa6d9affffffffceb27214898d1f6c283d38973a685ae70e133e40effa80a6aa576cada3bc4675500000008a473044022033abc69016d21db135b65ebd2a960865126eb39e4169fc534c7ff609a0fdc03f02207b8f5b5e481430a4c886fb17f5a6b5cd77d8d99bec968fedd70e0a717beb018a0141047aca5bd156ee3a62fea23cfa258d892e873acfb5d0428e2c44f8a5e0b76c2d4f24d219952f1ac92839aca526e0733f8f24ddc0a22953d6377e06402f8de50eecffffffffa55fafbacbf8b8b643ff5ff4b82639ac41bef402829de117b45ad556c4a6fdbe0d0500008a47304402206664addd91da888c0e80e49c357840650e08c682d3d21c57e9bb6dac07d5a477022002e73a3749fc0020acb9afb7e61e26684ea347f202d1cdb60d68f319236e247b0141048a4e20c456edd4807753d8c676723e61965a0b8bf1af9f1c801269b85dacbb59bca5206215b305104b7f085756a253f410fc520dd24816c8ac8c67ef26c44165ffffffff7114e6ce93f85a100f857084d11d7573e97edd3ba92a897d0f6e0f4df0a04e8b3f0000006a4730440220245158e58104afec9eda031f7e9d2b2a81ec51e24caf37bebf026b3737f77b25022063328caacefec3253310a88560d933008807aa9c6ee5b98bfb57edd2183fdd1d012103a0844873430f430ec153e10158591080893a88e45c0bd9a3936c77940e05b3faffffffff9cb24c6edea05dc0d791a5baae9110c1155624c9b7c4b051cf4d474d73f3d67c1f0000008b483045022100b92848b12778be2ee8439b68fa991a615c85515e40282889c0166a8ba8adf89a022046402c9254d259b0077dd5c6d6d5f4cd818ab58e1217fb8d13a7ecf255347b4a014104a1014df3b1dcb87c05b32e114c8034eabcf35fa31b4be29a9510f6a8577f2fcfd148b2e157d043a6c9eb4cbd8b13147d93a6cefeadecb3d3bd223924d659a35cffffffff37141971046a074095e976f7add667ec985862a5c76da6bb22fdf6c60101fb41010000008a4730440220181bded3d51670f4635179510bd925544affe9d6f6dd5b7e0b331119bfe51d3b02200148c22203795996ad1878e07c37e758d1a98fd9893c72c39a6aabf3fa227c9b014104c0a8493265463c5f195dcb6e526e4716e50e0055e609d3c6c2fa417d942171b1ac045cc0a810ee8942900061e7df6928e47ec42252df7ee36a13dbdeff2f77fcffffffff67948d74fbcd0f7050ca94651f323456b81cf441f60405ca37329fff3cbfe577100000008a47304402203dc7140f9c3d09a6a818230ed483f381d5835fd27e4953507202ef0b61e77ead02201ee0fe0afaceda1e039d5a1e84beacffcfe8cbd9858071757eb496b2c1a8d244014104a1014df3b1dcb87c05b32e114c8034eabcf35fa31b4be29a9510f6a8577f2fcfd148b2e157d043a6c9eb4cbd8b13147d93a6cefeadecb3d3bd223924d659a35cffffffff7fb5eeb9410f72ef8eecec8940e00a5e3995638552c9e298ba1d784bb85f65f46a0400006a47304402201f5fefc9531b3746a16ef845cfbc767cbf4f5e69957f436beeece9324a56fd1402200ef1b74bd39658b2a6ecefe4b18f7bfc5bbdcdd7596dac34c0ea1bda19b4d046012103020dfa4fe3c14736647137a0a1773acd3542dd0ce69a3a66060ad28d40927c16ffffffff2204f77ff0b477bef3ccc0d4a488ed56d6cc4ec7863c8c8bdde36ae959afc4d0410000008a4730440220797a8a0e9a88a20172178109143eb40f24fafd75030754bf1907e9a7da322249022010dcf520bffc01bbcbcfd75ba4981c2d505a226249ac52b0c16c1f2414666cd5014104316ee3c277d56f3e75a8cb86ece35f8aeff5c36e97ca58e9280f1d4c215e12ffcfa1de8e144ed8fd5cbefa0f0fc729e52a15a1787f3c9b64c51284ee75ff97a4ffffffff2204f77ff0b477bef3ccc0d4a488ed56d6cc4ec7863c8c8bdde36ae959afc4d07b0000008a47304402201abf1f25d428c34fde0541555635f36aac522fecd67f46d3fae84fd3701e7cf102207b006379744e87f52d849c2e6b0b492691b7ac5ed37e152cbab58f7497e5b41f0141040ba955b4f3a4b4b6c7658d87bd8b00b37027c129ea7da957d83d4419c90c94c1aaa8aec8bd1ad86e5bd2dbf8ac7319f3c22d4d82d4cfdec5d9da72b4db57a49cffffffff02b6090200000000001976a914a0b2cff82aca668b6e01a5fd6e4fd1c54a6e1a2b88ac3c520000000000001976a914457207deb3ce41ba79c5846b7bbc11a3462234ea88ac00000000" }, + { "6521c3ca1c34d8dfb6bbb901d29e55317385e20ee064eed54cf95eab173318d5","010000000abf3d0d2a1841d6d1a5c7a7cfa39be8e9fe8082c0ad3f60c2640d8e95861c04ccd90100006b483045022100de45906bbdecd6f69084dfccf0b4692bd0691ede848cb1ab6cd426a64579b66d02203cd14e034d405667d0e5068d5e8c873895ec9e31086ea036dfd0aa0d383f466f0121036365bbd13dd4b5f0f8e635a99c138e41aa8aa532d82be53f6641fd3f343c36d8ffffffff71b0b0c8a5e2a251dee7a169b53b953ea41d2782cb96c2ba37a0aed9b290e4f3010000008b483045022100f333e482646602575b3eb4ece8cca098e3b8519eedadcf380a1087bd6ab5ed2e022000c7dadebeb212a0dd46d997a8ef29036a4ea7dda6c8364fdfb0041711b9046b0141040902d2c51ff4c4e0331592992896422398cac70b03710bee5911d38d0adf9ebc53b3ad8e5039e1f58a8b40657bb00aa4077a8da499c13482878b1c4c9c76dee1ffffffffc3d2cb1fcdbc6160c6b8b8c6b13e26b25efe2d3e090922d037338c5da0e377d8550000008b483045022100e8d1d0ec6e30c91d2628738cfd12ea6375fea7b74d93be299a39d94bb9cf7dfd022001c8d7c801bdc61f8f3cef51e45e49fcec3affb1e840a98a87f8cdd9f460fa6b0141044c754e06790eabc800960ab282c6acd0a42aab1ebf02d4fbfda8e5109153a8d39e6257189849ed082b7fcb3ec0369d27e68f0e167cfcb9f829bdbcf6e3a61897fffffffff3f01d9c57d5cf30ccf99f38974fed40ca47ca20ab4713bf09d2af1aaf12272f100000008b483045022100dca6e46f4ea6a4c0b2cce6710cc53ecb100dfa4b12f65dbcab15bc2031c83968022049b9394edf616614881c487dac4ab414d0fd298e3bc237f1a4dd07e364b7ba9b01410463e8825f42623d670aac2009a75c0cd0497dd3006c627bc3c781041fd6111bc3c41e63d4a39d4000a0cced7f386523f66880c3bbc144cc265f11d7d7e53e7b68ffffffff595931923509ed6d4cad954b54476f2919db98aa7ecbd2d9d17b4bf32e0058bdc70100008a47304402206ab819f652017f8476534ad9d89b00f204a191e5485b1290ce0c8d5e8c416730022008a409c8bf0a0ba4f635a04e603ab38d99c94b2be7311b7c389bee069855286b01410406be423c18e785b0cb92ca3a4795f7ab43f8be2ac36e0051a07266e72a0ef573e78f6281ee357f5380a0915da05608b5f46f14ebb9f4663656b9256ad18b57c2ffffffffb176bcafa4a1f364476dc816902862d91bd5b6cf5aef89dae10c5fbe3c8f0447d40100008a47304402205df72572c78d204ed9c11b51729b77795a393da768dd2a35bd33ab79532cdb060220321b37571d10be436e26dec465309915f3cf41435580180532ab7fc1e85cd0d9014104cc4c9c1c68e255f5a17fdaa9470bfc0ef1eae1e2b9c747c44aa63fcc6dd079699928891c1b498fa50377bda79a69481ea3ac1e3fa8d6d9e5ae18e9a236a5ecf1ffffffff7b5d543c2de2079d71f07d6383c83ddb9bad964c729c2e80bfaf49d27b845fc7010000008b483045022100ce47c0dcdedcd8203c5bb24e5d53cdee06d383deb41d4240fb35d86155e5340802200e6994dd4f849c93e906170249000e233ceac61ed0c42bf93f402d79dd99c39d014104cfd5a3a0c2ebacf92da8f832877b1133cdd6c95a516210f3e21e45be138226dd77a1c1afcaed85e712243700c619acbb65c62d063cd1770414717159dc375a61ffffffff05e879ec5a999d793c61f015373593e7601931373b164ef933ee325410f89f55010000006a4730440220750a3808e007ef1b7134240407cb572d18fb1ca748f7fad19263c13456c54e27022005693c8fa139457a5e66a149d274bc7106a8aebf3400d6a6261febb2124cf42501210361f2a9276f738ebaf7dc7b4d591d86290f2f723333c1c775c3987b6bc158240affffffff24cd4964872ce70f2f90c1b1103c474f6934c978b3b72afe5b7be455fa05ff2e5f0000008b483045022100c3d6e6ee5cc9e0cc7b3c525a296afe07aa485d8c865afe39659455b8f2a5532102202e908f0b21f5696a548d9859b0bdf7bac179227aceae4a9b4df8b78a21d7e39b0141049b356f705315c986a50ecbef8a1aaa53b570d674be174f858ab22624a8d87b4dbf69533025f8ea08cbfa3e6183ab4a8675e521ae2121ecde71f291334174fda3ffffffffd6b58965a7fb10130d950b4b3f05b694e9b215dc370b20f242f3972de1a6a397510000008a47304402201285c6730964cf216ff0afe2ffbd4155b92903c889985917b8bed0334729029e0220722a39d94f4e7833e5b5b8b44f77c2ed0aa343f7a0c65f41b0349aaecfe5c5050141043bbcf22a209c4e4e7be45bff8e6a3f37ae11d15ffec2dea5593a27eb07b81efde201d42922d90d365000c9f2af56363ef9a353ddeb82de3a1df173823501684affffffff02306d0000000000001976a9141b5815828f8222125cd8544831b181f5162d3b5488ac46fc0200000000001976a91400478575781e52310e0d0e8475859e236c663b7988ac00000000" }, + { "80fecb94615331187070db06d21776a74f69937e3da651d4d45ea19b292d0349","0100000001aa0f970856eac901a774441abaf293da162e6239268b9a91d93abcfd2550a36101000000fdfd0000483045022100d08505c69a29414bbde401e97d9f446ba945070fa82d7c615d4f22131ba54d29022012c69647802cbab0debdfa02173d88072a23624ea197aa17653f969119d4812d01473044022067cb7ea1c13a6a971967615a5f7abc69c675a9dd2be4744da98fc5397a6482e6022069a303c8a178a3dbb22113465b93642d30d2b593d70e7449361f3d22bde2e131014c69522103385adff37fd3d0a620ebc4e9866e81dda8ba8616e5ebcae899c7f51899267ae721034c08511718f947d1a3e152195c5e2756588e3e0c2c7730927eb6647af494210721033da9f8938a5b947a723df21b73fbd3985b719249324d2c705acfb97d63a5df9e53aeffffffff0220a10700000000001976a9146423f2dd4b12968be97bd4cf795d2bd32e0e51da88acba53a51a0000000017a914735d4de855597997b21588cc78ca2db696be1c5d8700000000" }, + { "6683cf4b2b6255393456476f5f599d58076b094d5457d3d9d1555cf3ed628d19","01000000024d1504c215f2fcdb9205e4e09cb224ce88676b36254b42802a0f84864d43292f000000006b483045022100d2003b08527f7ab6502cea64bdc28b91a10588506d5c8b438f1811548b1d20c702207b6d49db2637c40c43d900fff082fd55c4b1412551b13355a3729a9b8670b6c401210223b58a7f1a72d65ecfb2867d01b7549f5811fadad003c3e3b088bd802ec5d177ffffffffc8e69691166712677a565af9b547bd46b10319c21d3858e6d942adadccb3cddc000000006b483045022100c0070b3692143b5d2d0df5b8c99307356fa30dce627c864c0b6dc3b082722209022047087152f529c57b759169f2a4dcee2d8e3bfe5fe4d36e336b807939570001310121039d28476e72fd679a6261d87007c76ab94225c98eb73b683deffe98cb546d7000ffffffff02a2820000000000001976a914e246ecc475f16a903a386759f728b598c28f764788acf16e0200000000001976a914e604a9444326395b7e4d57567da15add9c2de18c88ac00000000" }, + { "3485d4426113d7949bb7b7ada95edbd3fc60fd5eec4dbe588bcc3d4ab50af55f","0100000001c92cdb6087dd3806bda75a196b94cc93718f6d60ccba97d23e74d7abb2467a05000000006b483045022100e2e3bbbbb8ef5970c8fb0d475d37dfe4e959cfe58939bc294a246070f60c2530022053f32718f536091194478038b0036397c5e86d0c3483874470253a7301450fe801210216b876a014349b5e804e4bb31ae3ea14574e61594da51fce36e5f7f1a314dad3ffffffff0224130400000000001976a91416fcd59f7fd929e5f1e9e054ff22d9ba1e0bffd388acd0220800000000001976a91469c802aed848e59199f7e8e3b741e59a5a529d0d88ac00000000" }, + { "2b240173776847425e46a5d974a8681003dc845c6bd1191cd730e11310881741","0100000001c42fa3f358e9484a9d2fb8f4439795aa1b2ce6f807096d9b25da788626a0e639010000008a47304402202437a3e470b94967a2dc0787f137cb973a87f35dee55c8abdaba57b36c0ec1d902205f866723819914bcb07c5b3d60710e5a41f739691780142d3151f5488b4599dc0141042b151734caa47ac6a12a3bcd8623dab3e20a7b8a44d3d77d4d57d2754413097d671bcea18f296370ec4b3cfe0aa88b3fb04b929404ab086f8958a39efecd62b6ffffffff0260ea0000000000001976a9142feaab036680297e5338084de2a777c71a73a2ef88ac70880200000000001976a914f6e609e36befb149310ad289c8eb6f6d61ae38c088ac00000000" }, + { "871a5e1ab82c9fad71727678110048673c94bcd056ad4abe02b917f46f6a9f25","010000000185cf663fc47f8b3697c982bc2538a2f806c893d4646ffdf92e468fb38e0f848a010000008b48304502210099638bf18ccef5102894c44118860a035720a8d2ba72d55b056b3f2734778cc902200abd6ef13de9a8fd9d055a9e4efd6ead5ed5f6f3db984d3c9b6db884e112f9440141046e47be3fd9728a49573c889dcb5047431f8ccb76e2703470b42203f535eebdeabe99d06d3fece70cf4151e0eed8cb0f7ab40471dca9ef5205162ce1f1cc126d9ffffffff02e113e502000000001976a914c0bec5e6bef3cb15759ba8690d43b47a1ea558ae88ac26ed1000000000001976a914f6ea36ce6193fd62d66328f518159177a287c50c88ac00000000" }, + { "1516dcaaee67ec281bb9154bf00f2746a2d79f22fbebfcd15ac038ac459d1a20","0100000001d6bb05e0267c5a461d3cd14d7a5f18c98ce3b4b4f048169da36a01aeffbcab07010000008b483045022100e9a811c393cff0966910f6c4eb9153780dc9158a229a328ce4595870e45402c5022026035182ee2cc647f28d99912912960f6481c5716c87f3d176ec2fe6ab57fb7e014104357e9790f1f95fdb2077675335fe0221c0e9f842db177c2b4689d4b58c56deca172733c4798141c07450be895a65b81aefb508d3148ab790db2359308bf5be8affffffff0230bb9501000000001976a9141a656065b1b8100e8467d88c6add81e1865f926988ac80a2bf0e000000001976a914c405ebb63cd4e0367bc22d0048616c8f5a7feec488ac00000000" }, + { "7651a42125b38047e96b9636cc9b7f077db0748a1cbdd1a66d83c4847802c101","01000000014117881013e130d71c19d16b5c84dc031068a874d9a5465e424768777301242b010000008b483045022100f925d2df82d958e2f907ee3757f427c6b95dfea7979271c74e979ceeb431c1b2022031e9e2d5ca6351bd46a103bfce66756ed775e68ff185e08ebd1b21b3d8064ed60141042b151734caa47ac6a12a3bcd8623dab3e20a7b8a44d3d77d4d57d2754413097d671bcea18f296370ec4b3cfe0aa88b3fb04b929404ab086f8958a39efecd62b6ffffffff0260ea0000000000001976a9142feaab036680297e5338084de2a777c71a73a2ef88ac00770100000000001976a914f6e609e36befb149310ad289c8eb6f6d61ae38c088ac00000000" }, + { "6b87e063a7d3b633bc5dcb92ea7c712d34e2b551812ae3901c014db1130b051e","0100000005d3cc9462e54a921a1944ee1f585ae9c15dbae0dbfb1082e19b92e54cbb3d8079010000006a473044022021875d87040e7e6622c711b2bf9516306a49eec669b9fa08daf237147575106402204af4a9ae601667b34e1fa96f56cabfb1cab4e9601eb33dde541ebaaef2ad8d0d0121030888863fcb4cdf5b7d33b40e613af35df8f39d576e7972238b0d396cd3fcc3f2ffffffff36d87b04a5fc38bd94c00ded8204a83aabc78eae1e70c8e50bda6473e1bb2371010000006a47304402204dbf3bfc44e4f96303034049e053a1857bd553797e28e01715ce81b0d1a7a11b0220082aeebdc1bfc4363c033376088a63831b26155fa6261416d4cc130e2084469b0121030888863fcb4cdf5b7d33b40e613af35df8f39d576e7972238b0d396cd3fcc3f2fffffffff0c4063bea630d359a559c9580ccab511726700107e56e079c2138791c075c59020000006b483045022100b45bb9e8f620e2f69e7c0c5a9ed0ffeee3898c93b5158ca0e2a137ea5bc4744c02201b76cbf75c19646d2d82217604ff3dd955fd9cf998890e722b614484c3a967d70121030888863fcb4cdf5b7d33b40e613af35df8f39d576e7972238b0d396cd3fcc3f2ffffffffba28edc348cc76012e43dca26e9a77ad18979a38fee17923a1536c4601c51a01020000006a47304402206ed25ed2f7a6180718bfb0ff444346bd82c872574bd405f93f1ac96030935b620220468a2b7421ae82ce9f1bd063294703669103571b576b8c8260111ac8d99221290121030888863fcb4cdf5b7d33b40e613af35df8f39d576e7972238b0d396cd3fcc3f2ffffffff65b631aa7feff3ce75442aa699ade351f80dff64b3723c8db02a1df82192cb64020000006a4730440220275b24a965274d2528b2a0035935d2333b0c23ad92cbb19f9482d3cb31fbcf120220635f37d9139b68c63a621821976f1ebcb4b4df2afa1f2aa0322797070ad5b62f0121030888863fcb4cdf5b7d33b40e613af35df8f39d576e7972238b0d396cd3fcc3f2ffffffff030000000000000000166a146f6d6e6900000000000000030000000000003942e62d0700000000001976a91488d924f51033b74a895863a5fb57fd545529df7d88acaa0a0000000000001976a91406deff8c8190970dfcb10eaef5949389bccc250288ac00000000" }, + { "cd330b81de6f07b267b6c128807db6fad16a59ed1a24a4f6f7b16f35803c7c8d","010000000302e03611385a10cd52f31784797b9964206df6fa8b5acc72712d2f1814736af3000000006b483045022100a2bc03c92a41861b62d17193408f43acfa0dd2acf7653e92ef42f595da20d5990220729f987a29f185f44d1fe77d14ae3a0b9c60c8688dac3fa43eb10618f7bab45601210267ca97025b6b687e37e5fd242b1c71178e7029b009c6adbb4b4d46f4de9436b2fefffffffeb60ad9da606a799b9b48e8fda7542352d93eb3be5bb5801a07828316e8806c000000006a47304402200a93a375b94df599f48931ba1fe536352d8a14409b3e49140d1ee526168174eb0220119140e3f31d961bc2c55182e5df5418f4cd5b47bfeab1f2c7ed1bcb87d7d7f7012103843e69d4cf97911a2a73fd1cf4d42e27b385351f22d7621d3fd6e5c52e3aca5afeffffffb33d98616ed98ca901096c55f68bfc2551810cc7676668e0a08342d4e0c7cbce010000006b4830450221009e978392090d5de16b988904c566c1f7249843f25bc68b140be7bd3b1cf67ebc02205a04ed2c88682fa373fdf98fd0f1a8bf8330e3826a40b2301a6ab6b1dd106cd801210398ab910da6c238bba2ee8ea436bb333d76e91daa1b42cdd31866508ffe4f16a3feffffff02a0d908000000000017a9148df26e819089a1190eb8b1adac6bd5a0ab6ffda587bc450f00000000001976a9147feeec547a6c4726c9b43063cdc02407f29a0a0f88acb7210600" }, + { "d9377ca14eb9869e82c838ab5b59abdc7b1672fb3f8970239b99944e07e068aa","0100000001c40ae2a141d32da5cd25e0603de7d3c2d2c99b6c18ce825401dbad378733d004020000006a47304402202d7c8851895f3059a80d66e7990c5b16aa8feffc782781411c4a4036f5fa8e97022030d3ad4fe5700aefae4ad7d1abc0ad9200aed7258b911d47ec3a084358013ff201210303cfcf545f437d3590face7f387e6ded60f449cccf739262c6bd6f7b379a73b4ffffffff0336150000000000001976a914f236863313ab6f35a394076738f48e2577ab3c3d88ac00000000000000001e6a1c0babaee7a3558ad3759bef2c654679b8c9c1c12838d784dad396c9f3fc1c0000000000001976a9146c6e821a7435cb8535958dac5dba54f5a3841c9a88ac00000000" }, + { "843bde072ba31c51a548469d7b12be2f0c48a7f2e10dfe47d6e32e886bf03d67","0100000001d22748e453ef7a169b8a7637dd2cf5ee828ae9f437bdd00975fb27b53700b60d010000006b483045022100d7fb68d0583c52e24a73d985394697d41f8d5697d6c8c23dd28655c58048d48602203e785d5dac16313c980af7cdaf4699037d47118f98abd648caa15bf128b3652a012103ade264cbe1b262c1e0d45b535cf4c9e3f3cbc81988df72007df9a952ee8e1e63ffffffff0336150000000000001976a9141337a0fbbb1206fa815e23d01e9e9a6ea07e5e6f88ac00000000000000001e6a1c9c09a21786ab812db0f33e440ce9757b8b425ee8815b4753e0c87403fa050f00000000001976a914d3597a834c49e243150c6aa4c7a1efa1a406dff188ac00000000" }, + { "10a934d61d5780a648ca02e4bf3a22b8ad2e33fb1529f65517a224caf0e26948","010000000128c9302ecc91d6d794170ea4057a78e463aac64b76bba2ce930011018b2555ed000000006b483045022100b3635d587edf75b75162b2506955734988dd23ab256a036fff4d46e5c0248aa0022015d41a5295521cfa6c9836647d96b8f6cc7815cf0963208622bf6cd6f57e04ed012103fe3a115e5c9641b1a9bdbe90221b4c9622ee83c9d0082bd2b7f81526ca1ca9a9ffffffff0336150000000000001976a9143d86c22f3bfb7198f93851623fb9ee61aae8656388ac00000000000000001e6a1c3ab26a72e9a1ea543245df5a5cce87200620e3a05c5e6bc28f78eb40da640700000000001976a91469e12a40d4a2218d33f208b9a0447894dc9bea3188ac00000000" }, + { "56b47ddc11b999ae1b4e9ed02955640ac0d6726da803d3cbcebf6c2957999424","01000000011f6114004ae562bfe1e692ce1e493103008891ab206924914e6e23261a79a6a3010000006b483045022100996b1c8e2945ab40e9ad3bf98386740e36b2547f5e785492d4cc5415ea4b015d022066b429b2ecd0cb75ac0d57da525221a7aca46c60e6ff106ee558ab34384ae2a20121022c2810e8bc767e7be7d314bc3dfadae05e3fef7c4b6e22a15f50652ea0f7b5b6ffffffff0336150000000000001976a9142e9c712a2746c16f76a616c1cbd7622fa3fc841c88ac00000000000000001e6a1c9d909d00103c7748258288a616a0a15e6b670edca3612b594280453712d90000000000001976a914e0869f0a96e6f7ebe27340a49d5dfcffd56a4cd088ac00000000" }, + { "d3f5864bcc56d81597a03072dc31048d3def64fc0457e1b97d748a8604fd6e5f","010000000274fe36d1a8895331dc514d8fbae57c339f5af3665421d7a8c6ef56fd37c628a2010000008a473044022071e1f0f168e82335b16002705b914f3ad1b8e969369589a9f60a4e343eba37f602201298a2ec478b19bd99447c39b71e3d510cd350a582bd0ec69e8e664c7a630b7f014104c6da9684daab6a473cf81b4b935eb9f218ec6a1a0c94ff7276b20bc17bbd651a0e3ae53b66306108fc8919af94391a81ecffd84569480d1cdbcc732c273ceee8ffffffffdca93149078d51f181ea21c910cde454fec56549229b97177bd352d4508f239a000000008a473044022037eb55578199027cfa65b1783f553ba65ff7139ba9f2788b2fedb864cfd32a7b022079ee1d5a1735df697418c3523d1431a8ec8c81f7effc2b4ae9d9df7703474bab014104c6da9684daab6a473cf81b4b935eb9f218ec6a1a0c94ff7276b20bc17bbd651a0e3ae53b66306108fc8919af94391a81ecffd84569480d1cdbcc732c273ceee8ffffffff01403b2500000000001976a914282ced83cf66bfced9add23073f31070064d372d88ac00000000" }, + { "0591fc4d6d046a61be98d04fea0cef39702cf38b52da7dedfc87bb97bf11ef5e","010000000115766e64e14164c899cf871266f73225fe592ff03fd3f8436305002d93ad0444ba000000fc0047304402203989d5ebc576e700963dd5076ee309c90a428b7103a060913d573804dc35f57902204f00e64e8e7484579962b46fd35b235f8883571318bf4bdde4d131c87abea2350147304402206401c1c014b31a5fdef762239bcd0975bfc61731027802a1d3a7ba204e28c76d02205fc7a7d6ecb97a56d59bf0bd4e835a1573019edd6ca13c580f9c3735abaaa8f8014c695221024b83993ee623326d7f9721645fd81d11bcd38405053829a7f92fcc6969d7c5af2102b983c1ebb297e4a1279701df0e040bd129b3cd0fd7bd75aff741d47f24744dd821022a8fcadb6e51a619475daccee975fbb4b554afb68825ba35fbb496024428c1e453aeffffffff02d95ca8120000000017a914da34824e352a2a5ed8eaac02222a69260a8c511887203df228000000001976a91424a093b7fda6e1f5c4e4f3a4a0e6e5f79a8feed288ac00000000" }, + { "796c0841b60960f3ce02388d59abd48f41b53a62cfb8ffdbaa9d808a7de21763","010000000115766e64e14164c899cf871266f73225fe592ff03fd3f8436305002d93ad0444bb000000fdfd0000483045022100fc55afcad66e6245f4fac70f0df9dad942f3290143204cc215a30169408bbb720220408ec30ca318e1a6f4aa237edcaa8709e32d746f42180eb0b0cc0b2b6925de78014730440220532bb02865a2bd3a85b9070b4b1030c36787904c21b646d47d4d2e44071de97d022032b177b766a4f851107ab147486c2d008126b3c521719939836edacf9e6d01d5014c695221024b83993ee623326d7f9721645fd81d11bcd38405053829a7f92fcc6969d7c5af2102b983c1ebb297e4a1279701df0e040bd129b3cd0fd7bd75aff741d47f24744dd821022a8fcadb6e51a619475daccee975fbb4b554afb68825ba35fbb496024428c1e453aeffffffff02b49e5520000000001976a91490b2085702cc79aa3301b7b42ee1ac55d3d7df9888ac45fb441b0000000017a914e4fed8e8519eb2b9453206c61ccf57f3faabdf458700000000" }, + { "cc1b1261b78680abfc3af0b9bb9567cf1694c628732da670b7a76587858fa4d7","010000000377684d855f7b22cdb5eaad0f8ce98d7ba42b63d10a652d0c94cbe7efe3d981b0010000006b483045022100cca427bb9be2b122140c266b6d763c99a11cfe0ea42d47723fb881c33a34dcfd02203043b3ab1b8311ecc3256d7850ac533c33826d1447c983ba02df70353cc108c901210245a6edb87d4f4195345915cc65d5b0357b1ebfa18f51cdf444539a60f685049effffffffeff33f118579c06921cd7c58b49646c13c47b2e9098b866c68320293e7a4f854000000006b483045022100855ac18a13dec4f09ef470e234756ced69ca3e8b8063e70e6e30c56e7cd39f8002204ccea3036e0dd21033e2c0a159420eda2f10d3b8d864cf03b83445bcc726809901210340cdcfb90240cfd24fa317af1c60c8e7350f14c8b7a3c8b1bfa04372ac2d345cffffffff60c4cd2aa3a5f258eec747c1ed036e057d8c19c6fcccba590ed0767cbb34ddaf000000006a473044022011775cbf1498fd7a8e11c1394dd352e82af5571ebb93b9b9ab7f18e76f91acac022007590d8e6625eb524f376cba7b0cd7a7f78bbf4c6bcb0abb60b13c1202dc031f012103741857fb954ab1ffceaf4dced6eecf96b89809031659667569e09b4544d067eaffffffff029c710f00000000001976a9146490df525ac29c143a31b147a6bd1a01b5c29f7e88ac13d80900000000001976a914a8734bd4498908b220c42d0a3137b240513479cb88ac00000000" }, + { "e6b5ea0fc055cee0045a949385fe40e08e7eb20ca9a9c14dd4b17cba94428823","0100000001fd5aa531073c7579880e540fb1d85dadc9b73f05ab5be1b54842f75ae9a620ed000000006b483045022100a5298285459781b5c793fecd357931e7bb7fb47f2a872b38eb2964373b7b8fff02204463bbc160b2bcd1869a4a0a6b23be1e1936508c0be52a9b0d8662cc2d0bc325012102f2aa7870c4d14597e0716296e825601a305ea14e2b5056176b92db53083aa0b5ffffffff02d08972010000000017a914f130c8c277fe8b718bbe469aed8386afb3f4ae818774cc4a1a000000001976a9147c1def3a02ef0ad4490cc9ea876792a82b6a19c788ac00000000" }, + { "6192df227d2d4bb92c0c9d447c92c1c79ba1f8d584b2d1b2237e1649fca066db","010000000491ae028a16afa2adb8131687b9183cf14e8e873d3ce830339e1532d4c0b2ec18000000006b4830450221009e58ddca12e15516844ae62a6556e7b231dc7c7e5aa141869531b3e150a1604502202600ed05ab80ecd2fe6cac0c1ed50a7a9ebac1e2a5f35590e33dc9f75342e9900121027d64c4851542f008514561ee1952afc3a6f4389d984d387a3c1661f5f41a6cbeffffffff5ca7537e5a033fb53a4ebbec5298d19502a2089e07e15022bd289c5357e67b40000000006a4730440220263ece0b043a54693c4f56dddfe259d3fefa0adbc37ed01433cc60f58f9a19c7022059223c70e590f05407879ff6edb70bee155cf4e227f0388cc5c1c84d0d17c30101210240a54f92660b409fcc444f2a9971a4e2f73d25e77a4ab54c19c6850088e3c368ffffffff55053636c05067a1f65dcfe66042d205bff9b8705b0ef40f249c7fa587f70ea6000000006b483045022100b6b523d520bab14fb10db0c805dc240599ce0adb6de0ba78b357f779fdf6d7ec02206eebc72c8005dd859e3f56620282efaf0ce2887dc1b06e5d891e651545663788012103cb871c2e221abc703cc40aeb9c76a6866e0c913d2e54e49b430029ebc55df668ffffffffc8fcef42cfd1a3c52283e91f780a3ec776a8591e6756f6199deb8aa6364bc3f0000000006a47304402207f03da1d22e3a64fcd513ee4d6be1881acf65617b191e4184bf8d0f4865f8a6902203552403bd940ff185025710c9a099416a0abfb32c051b89a2f5b0534c2daf175012102bd154a0cb6f5c2345ef7c5e62498b747814a433cf1efc08eb34476170bc4333effffffff02ed190000000000001976a91401a298b2cbecb5d209fd644d9f889a30fe8929ef88ac003e49000000000017a914b87eae52e652e1122d9d4c4382bf8c5f8c19602e8700000000" }, + { "59cf31cabef6b34e8a74149dc5dde4dd1233588767f43f965d60cb441f68aff5","0100000001b721b7f08920c24b86ddfbedb9518bbe293abfff88a1bc115d18c248c030615e010000006a47304402205e473cdea7c2a4a25fbdd192b6bc546918a65c9ef57859ac935ebc3fe15ca6f502202e4c2bcf6861a65da48fd8f2c348d9cc2f3d3e7bf21d0bc52a3dcb64301f4a9c012103b40ea587c346b0f0ae636596de3a30c9bf8c80ea54b5d3fda0e0ecece079da83ffffffff02965e0200000000001976a91454749ae58a2c057678c829f144de807aa1e3af0c88ac7a9f0200000000001976a9146f4876d1d12b4f371fadb4ecea2bc014fd45426888ac00000000" }, + { "27010337d1176b2149ee9ebbbcfc921bf39cfee01f607245bbaf7a6a3eee2b18","010000000182c4ccc66442f880f43eaf8843866d054caf9c39950a3f7f8b0016d482997b2f010000006b483045022100d8cf05d7c26d578f349620f064c8076f8df66d6d822484981ef9426b33c881ff022068ae66df0b2e625933042dedfe3d7bbb377a32745f8dac3c6931aa7ec2208d9e0121024c6e9b3e3bd23e071a4e52ac759e3dfe08ecd3e828083279b8cac827aee55dc9ffffffff0280f0fa02000000001976a9149bf0015391b3c74232fb47529097ec456ca2793e88ac98ecec0b000000001976a9144cc8d4ffb15c4d93cf1416bf91b849a8fdafe81e88ac00000000" }, + { "4753ccee413515464bcd84fb802fabc84bbc6da7e83d1af4daa72a0f646cc374","0100000001182bee3e6a7aafbb4572601fe0fe9cf31b92fcbcbb9eee49216b17d137030127000000006a4730440220028f283238287f0cb60442816b2d8e25f7f8449af3eaeb49bcd8f4722f4944b0022044da8dd0d0e71a868b1d0b69d44b191b8182f2a899708c014f65c17a0ab04a720121026ca5e7117f17353f1f9f28afdc735464e2841171a99701480fef0d9b1734e5ddffffffff0170c9fa02000000001976a91476072d5358d077fbf2e6db92ed7242036747d46288ac00000000" }, + { "03fe8d38a6fa61aaa94244ef1506070c0ac7913389e378dafb179e757b244a9c","0100000002059a2f44ae988da8f505b0828334a23037f06c9fb493c74b4d27ae621cca39ee06000000fdfd0000483045022100b4d65ff280f7363dc1d0688cf9375b7b82c4b674b53f00b79c08bcf3ec6a64f802200b56bf27d42664e4255f4580042ba1e531e81850a17756261ef3b72dc19e46d401473044022022853d91a4ad269e09d02adb1cdc57db0f88a448c1aa0ee77d02bf6c8b3fd1390220565f4b66cdd373dbd1a1810893eb99a64a559c1a9e7ad96771ccfc3904ea0a21014c69522103c820e41455b5549109376b7d0dafe7cc96349acc819b6b239a794ad9b470d94121024a470762f98386355eeeec091c5e3b4375d2bf2c308ffc247a7d7fed9375f98c2102a2a453af48114f09e6206749f7e4651270d9d73f6e5085e8374d40d723413dd753aefffffffff99dec92a51121a3375d7a070c32d11eba8b33ab750edafc8ca20ab8a0914d3801000000fdfe0000483045022100ec6f1772b8b4cf8727e0d9d86415d6ab6a45b2ac2d8be144c227b245a925a0f9022052e413cfd1b2453755b5b586dbcfcaf0d8c6bc0f9aef3c4ff2d141f7b1ec18e401483045022100fd5d034394be86ae7995f3266a469e321e0c8de59d1e23f5a8a5f9f3525094330220777c45a44924fcad24467708e8ff962063cfcbfc8fdfa56ae906b5db5847bee0014c6952210382fde54fc8b7192ed17dcdf777a60acbeef10d45fbb06beb7c6dde1f1071853021037411798ccf6b7caabbedfa9d03f6f94229bb163e092606ad8e6b6fa261a4e8af21031bd6e08f243d4d1825b185b960c54e0118ab32346f9abbfd5146e981fe7fc63c53aeffffffff028a3db800000000001976a914f93350877cbba7d61090d4463a6964f25bda51a088acc4eb75010000000017a91459fa0cf39622fb2af0992600b543f555ce13f95f8700000000" }, + { "88ed76b5f6ab017b2236d70359d88cf7f238717e6c896e88ce36021d40b62296","0100000001096c9ca7d69c51eab60e6e396a408d30c185195ef6791f141c45e82f18ac47c8040000006a4730440220074da2fb53802e0546c4d6a2a6112cf9a94ff608e8420a8a520afa85462719e702206dda362d37f2f250e6c67529c7df6d469a870afb380bfd343cf28134e3c7121e01210317bf6e9e73a0af9edf6009cc7501ed7d79ec8185af4266ef2955cadf9a27ad26feffffff0461600932000000001976a914a752c1c6dbf772547267dd1d70c7a5a2e963f2f688ac006d7c4d000000001976a914d00ee997e8bbd9e9ba110c831fe0607438a83f9b88ace02be50e000000001976a91479cc1605103a7a8402c5993e9134c0de746bedca88ac00e1f505000000001976a914ff68f2bce6781dcca9a3c9fc719fa353055cc5f388acb8210600" }, + { "413e3ba26ec16c82d04362ffaf685928b26fa6a6be3c938b89cbb6d5fc4ea61a","010000000238f0a7e5156d714b0b55637f755f0039a1dfc7c65134a29ebb00345108ef977f010000006a47304402203a2229e94afc182fe49bdf3b3bdd9021081d6056ea8a321e822cfdfbeab1db910220313545e1b061cba822d4d74423badf30d5aae32d7815079b8d614389a1cb51ca012103041d5c19ab5eda5761a2e1d0e980bfccca8d5b54a62d932b4d8918d962cd056effffffff3b9bfaae06e5bf0f963bf99d370d2fdb26450c2dde29191eca7ee1f2388091f7010000006b483045022100b003f38bf7efe92912e431058c92f06f8d19b435a2efbf14818b2b55bccc451b02200d09c66565aa3bb8062264b47ed067c2f521a336b2c2f496d9dd298b0d90087c012103041d5c19ab5eda5761a2e1d0e980bfccca8d5b54a62d932b4d8918d962cd056effffffff016c1a7807000000001976a9143d83f515981445c07c8442f9abba1972f31f53fd88ac00000000" }, + { "ebdf6a0bbd8cf6f86c024b7ef66b556b03add114a614ade91b1d86748c4e345d","0100000003d888cf17edae2a46e7c34bc1d0c468bd2349f7730582354741f8492ddced566800000000fdfe00004830450221008668793410b12be559fecc682346e91edf5b6765405af680c50d67b4ce4372a502207c7bb62ef13b69277bdf299d689c314a9bfb936978d15b238a28d6d0d410bbab01483045022100d282d0f9f00513e685409c03fde70a8e33ad764be03250eda9732ac4790b03d302203e3a8dc621b11abe53c670f6a5a699518cf7526c465ee1bc1357d090003a956d014c695221028d87a7a836c80d60769ffbe219fc66ba83e45d4018eba55e1cb8ffcc164b40372103422a68f45a1ba927f492c79955fbfd41eb36392e3e9ebe9474ed435924f2a2702103a15849d6469920e0f8ed4260fa9e67641b2b6e0973996fb3070eb776b829e09853aeffffffffe87963552d08e7b7837e73181f8cef2fbed1f63f8e874e6f90d8f67333369e2e01000000fdfd0000483045022100d4c80a3ba25579d179019baab3bed0cec8186c9cb332a15cb562fcf010c7ef8002202147d3866915460cfe3a1469e22f5ba4ef7492d259f0a33c143294a0d04e8e980147304402200efbbed4eb4511c45556faeb9e8a57e016b7e87100454b2f060c64bd588b729c022051463dfb20bbdb27381a9e073f3fc84e849445b499396cbc9931e62003dce7dd014c69522103c03dcbd6c0044d210a2f8cfb8fd02e730b1cc85bcd083e4677bdadcc930e04d32103a5589f026742594dab7417ac627f449d1f4228695bb0c58e5722e78bedc131c2210285eea434a5d2ddccb366c9998a03d377902c2d3805c386c1b44b404f8cd6c02253aeffffffffbd09db4f10592aead5f0532fa87792f02971ab129ebd0a2faa7fca4f84a9123601000000fdfd00004730440220761af19a5e8625ebd89f3ac98d3ba85676003ebb000345fbc0bde7e9310ffbf402207e8aa25bf92ce8dcf884f81017366c4cdfbcb1d017221759892d1635c16ad7e301483045022100ec39e72f2538fbf95116ef2a79d6aae795ccb640fdac9311fbeaa942e284b6d00220102d1e0aee82445d212fa2d3d7449f631d2c5932730ca99838ab31a3533bda1e014c6952210376508a692729664c28e0db42bf7cecced0f271f133c87175d329952a379957de21031d7ac7f82a0964ebae2c936808f9d1beab6347b630530d28e8f34776fabed39b210348a63bafa80f2e8b9374beea8c6eb72b1b2940ae4d4bba035eebcbe89e945fdc53aeffffffff0273351e060000000017a914b93f02a42aa47da08744e252f6c61c4fe0ac6d7e87794e68010000000017a9148d396cab7dcbf26c1eac7015c360d3f4c5287cea8700000000" }, + { "eaf9a0ce6bd5e6f9a8f789335b05c6ba94c2d4eb6feb58f6dfc4f4b0c12553e5","01000000031fff721169fc147996f043a76633484e5e17336e9cacee6c7c68386a1c7b1d20000000006a473044022015b039988149cbef69d299f3db4634fe7ad9663fe32e32c62c837360e473f27802201b9665e8c38e81d687e3af447e7dc6d538ba0a561ddcb6765e3796a529913b6f012102ee6a96bbb9dc7e358b5d5bc21fd167b7e555c40d20d874398fec792ce51060adffffffff8583145a6dd52a0a0b25d012a09c9778715262816c61e014662402be14433ffe000000006a4730440220118be6ce1c605e693b936720f00a230acc6cc8f912938660a901da2c253452dc02206873cbcf5393cbe641b744782db2a0afc1877a4da35995b3be3e517ddc8e84e7012103adefee762bc66dc59274a4ae559bee03253c80e7bd38618d07edac8c62151bf9ffffffffa3facba448915cc5b0a94b473e2ee68a7601dbbd7e4d96c1cae70969bba1c86d010000006a47304402200f07b1ed86ce396e6f611e4a7ffd443d061e8807e4dccdeb7db74462ba93c132022043ba2dad0f748e7cfcb3aee567f72be60cf9a7976225f23d48a14e8d1f790614012103cd7eb1c53082dc4e696ae4a5cabc67ffca44bbaabee97dd6a6b2fae779d2b1d2ffffffff02400d0300000000001976a914da5dde8cbf20315f3e00ad8d6b610c14bb6d0ab888acb5a50000000000001976a914ab39d19e1c8dae943ad8b884cc5c6e9773af2bc588ac00000000" }, + { "76e6957a3002c222c4154d33eb03ae05f553226bf90072c0df13587979ecd69d","0100000001285a31b8ee43ce10c752d15cb32545e3f26db7a480a2e1fceca9649e25aa0bb901000000fdfd0000483045022100ed5a6714d83924b3b55b2d261bfc9cf766291f774e286d78e0311c67d71e891b022008e45c73c0b65853632e3c5899d077d4d16eecce04c2ae87cd546522b762f53c014730440220649c58517ff7ca9e10e771b562493e515d0b7c42d6dbdb7c128082e59fd3a663022054af3077944eed1a3b2bbe56ec74dbfbb85d76af258febd7e15cf4658d18e805014c69522102075e9ea5b585b3e8ee56300ebda79dc7f32508975cbffd7663b7ec333b5f83b521026e14970b57da755f471ef8fdeabde59209ffdac932407cfd10cfc03fdc050bfa21030474b8023f9ea9857123919503ec2c41918eae761b7ebaf94f1ef4b00deec3ab53aeffffffff026beeea000000000017a914089884ef47a5d0cd16db5ee69697e960e3b6ddc3878912d6020000000017a91492fcc3062461a514371ebcdeaf9a31448e4a2a288700000000" }, + { "6c29a955e27b54eeab7aff7b923eafb087ef4249e3aca9d2ceb31a6bf6cf0c6a","010000000144b10ed37d71ec1040e6ceaeedc19bc12aa39ca31fb091714dbcb34060b6333a00000000fdfd0000473044022071d72ce1f2598e01c300e2aef2e590cb1f0067fbdebff0a35b79b149668fa3dc02201db8792b1729dd766785640581c268ab5958ec3a16816d2111a241851c0dab2201483045022100d0b6873ebc72155cac390673596f2bd7767cf5496e1ec105c33039cbead4ce5a02206115de89779ef0459aae51b05ae0b34e3173969caf7e0ef9a6d99091b4994537014c69522103b3a377dfbbfda7d4fc3738e34daa68f95281a18f655a64a8a857e800163f1aae2103ecbcec72c79570626b6e34867e179891b2dd378b0ae714e12b4f379e60bb30fd21026f2577723337ef26f10b2969ceb3fc22c749f94441a9d0b43d04319e7a6e116753aeffffffff021cdf11020000000017a9149da9724a122e212806f8f2f4d67886cab20f970887f29e9c000000000017a91466be7bf44c85d0a03edf9dbc129dfc4d5911908c8700000000" }, + { "5919c292ebab1c5073f92007eead7f91e4465c007ed9ab47590cc13a138c365e","010000000114cfb74be16b1dd3a281560a815db63d0d7cdf7d13acfb1b664811a882ec71c001000000fdfd0000473044022045a6d65613010291ecb10565e95dcf45ff21b5b2170528422824f5c5809754f80220101b735e3bff2cff354d0fb12b30d6d34db0be68c063805afc5e9ba29fe3a10e014830450221008995ff39f84bcea06f83b49bd068d8b18c5974cbe76f39046834f879ab9e30a00220370dd40c46b43de65fc6d5ca7efce13f9b506ebba47c62b31453b81c7c692bc9014c69522103039507833df411998329aa1779d9a7fc5deeb271e2575e940a8879b068b3bbe32102fc8cd9e800085bbfba5c116086f1e12c23c7e2c6f167326dbc393dbdf2f1d3cf2103e24d0604069f2c4c17fb40a42eec72efefca6ef96a04bf32f86035f3a294d20153aeffffffff021482b7010000000017a914b0bb86ff7e3d1001f9c367da402a0515a588000287bc2727000000000017a9143849fe763295dac756dde7639b54104f3b3b92848700000000" }, + { "fcb15d651d94cf1e53172844fb7448e0342147176e3000389683e02372d5bcaa","0100000001306bcb1dd2ee01aa3496f845edace68555817dd49b698158d22d439b24104e9301000000fdfd0000483045022100b674ccfaa0e33a56445a099a788d907fdaec8099b5b5ead353f46736536a842702203877d8a174c8922c22e0cf51b5b9e09122b2ecc3818f04c7a23bad3f23e7e42d01473044022059b32743a4a78c16dcc50211e41727a1b939fb84019743b76c465311f8ef11fc022048839397feaff8e8381393c32b74da952ac6451c7645b29dc3e52fde4e9656e3014c695221034a8464a30f025a7a1612c60fcb0552b088c5ad15669ed3c011e5bea81b435e9c21029d43e667553987e1a7a4294eea43926e691746a440246ade79f03e6051e79b672103bd8ff670157bc37fac87ba2e6f01d967099a531970adfabdf03f68b016a3d5cb53aeffffffff02bc272700000000001976a91495773668b0f78c919e2745d4000e77283f5cc8e688ac2ad159010000000017a914282da3cafe2fa12d92b820ca242101b6cdd31bf48700000000" }, + { "41fd0f67365cd4774fbc4e743702cef5e58aa65a28afbfbea451d6b3dcceba49","01000000019eee8fa598d132eaff6d8901d59c71d5139840212bf99f03ceb9f8a4fbb9c8b901000000fdfd0000483045022100c4807f06a4e02bcb27f7e071f42f29069f621ab1e0a651af86b2a7eaddc0a4d5022057b8141c43453a2347ad9031c54b98f71186d78b6dfa3aba3a48edcd0225f72a0147304402207ebe1a6fd52de348df0112a7f1a8832f52c4e2b3cff84a5585d2028d453aef28022052c3b2968234cd9115a4d3a835e02076368c3576dbe6460c1ebb8199debc3888014c69522102ea580af6b37f56c004fe6944a0e53fe6fd7470502624f8176f79357e68f8d8f02103187da83bc711d57cc9331481b558ac4e1b4eba8d0268b2b5af39d881fe3d41a72103dd6491c1580f5733f7e8a9001031d5f6df6012334e26917862ebc1735f19b38253aeffffffff02ff720b040000000017a9144cd420049a8dbc57d5f4d2a446cc794ed4b64f1787cffe0100000000001976a914e3d5051ca3ad279f96d62719f1fb7f15639855ee88ac00000000" }, + { "e1a21c224a21b709f9ad87f67e3cda72f6539fbff36fc30cf0422df89b3026b7","0100000004af5107eb753bd63dc69b46ae43a95d3b4d51109af8a172ddef36a626ac856fa2000000006a47304402201535a4df5c39a745bb0c924f836ebc8d07337760999fb08e8f542d34f5f48e200220244c5aa2089e107b8a9bcd3d63ef83a55f43e5479508f3cb252de1b2b99681670121027eff6ca03410906043638badd7fe49af894b3d4ef8a55f14665c696f3bc4433bfeffffff7c476255bdcedd429613e302d429a5e619c7c52dc87ef08bab2252720f040405000000006a4730440220610bc4f27c4e3b54accc459b6a692f446fbc71d4f22d537dd68f795a027d97d702203d26c2909dfb1aa44f64403ca16478e18a6da531a81089e26d1bf0f15bd814b0012103fc55f53af315f08feb4cd38c239ea2f9a2b10eb8cb3ae64932cad136c74f6e09feffffffd8f9136579c973037acb561404264e83161a47d0f16c67d22deb9c1932f8a823000000006a47304402200d58dfcb94d1ce15f7624e0c893425370213d2b54058756deca9d5dfd99d384002206c82e1a0d2d120f413dd74cf8dacfc7c5a7b76829a9e9dedaa9fe22ca9249745012103c5f47e1bd4ae801ed45b736de60ad89893c42212941ba9580f67dd126b9636a1feffffffacfb2916e44a771c2a9ad56f39b49b321d4571a4d559007268ec2721450a2197000000006a473044022043b5433a14fa8d02e37df6e8af4f63cad9453710c9852ea61474bc73e7681ff702207456fe4e595f62e14724da218252a680b0c56a9b3f59253ce60e00c7a756d314012102b445a39d67562679a5b5729ba52dfeae7fa8849bd54001125fdfba3f3f1fa580feffffff025b420f00000000001976a9146463a277a2fc31d683c45e999b989c8ab26a6e9c88ac40420f00000000001976a914f86ae959167281f93ad7686b3132d5e67dc221cb88ac62210600" }, + { "3633de47d27ed7b8a2ffb2a9ccf9f476d1dc64c6a5416a079a69f006a9373ea7","0100000002a9ce4fd1f73bdaf215b5fbe4351e335b07dd3e256ea1d9d41e6110b0442c32d0010000006a473044022069561fcfba521b59a15889e6f106a06345d97f8de2c34a81745575e8a7e4c1e90220260ca89a1febb9877848ca7c8e03d22b96c1d69f41b81445b4cf66a5986e9a46012103b88ff01dbd99d2ec1453c24cf0efe1cd9c3e010c5f3c0cef4ae714afc871aed6ffffffff09f1e5dc8f05bf5dbd063c7ff26449c30cb89921bce54ea09e5a0bee4f720e17000000006a47304402200946857bc7e9d77d51094b9776a05e150f8f74d50ab26d87f21433f113cef66b02205df949b39be0b0f0037cfde80c8909a18d88cec036349c250d00a0a8bac414ac012103b88ff01dbd99d2ec1453c24cf0efe1cd9c3e010c5f3c0cef4ae714afc871aed6ffffffff022ac4f10c000000001976a9142607369930c81cb823b462361b53f7df207aa47888aca9680600000000001976a91444ed6c22dfe9ec10f1269d54f29a98549ffbf6b388ac00000000" }, + { "6a6c1958e0620a6d019eb234a2fdcf688e30769972409e19835cba081a546a69","0100000002aac046ff3e6e4c85b4bb4d42a7cf11905e0e3e5ae9ad2cbcd7b6a9e5633acfa9010000006a47304402205156bedb98b9a78b34552aa2509b6307e6c58e092282f5169a670b346add8e62022058f2a35131c85263f7a32a668802e2925ff089d798b96200622be2e615008f55012102d7ede62fe880a33ddab68de9052692baebd4415e95f5a721a72267c17e560323ffffffff9e37e73955fbfb9169cc29536153e24bc8662b7267918bfd3362d2f25094e2ed000000006a47304402202a96dd59709d81dd6d18b6b713f50e26b0fa7a342b15a22290044c131a50474a022036ec02850a29e8ba1c39d857671c5736359cfef2f1a8afac3df7285c43b70fef012102d7ede62fe880a33ddab68de9052692baebd4415e95f5a721a72267c17e560323ffffffff025fc22800000000001976a914d9fb612ed069c83889707dbadbebfc3dca7fd50f88ac46781000000000001976a914ae842ee6f47025a87fcbe9f6a058ac8ad89affc588ac00000000" }, + { "f3a87c24f9f58d2b6a53dbd5c7e213820c79cfb79181146b022dcfb4d457aa34","0100000002acf0585e9a1456dbaad1f430132164e346f85d4fb64020643b3574702940878d010000006a47304402205b64d53f9bd205ad98b0c5e3ded2476c7f55dddb9303360ef82b8bbfe39be68602202882eb90d05641be5925ba1392eb80cd067c293377b100435edf2927459856700121025d2b09a9851d142e2e7c0ab90c96736eb0de9fbe22acf20897da9bf285bbc5f2feffffff5184d63842ffbc9c8e2b650d1784fbbed335b5d6835ae9180d4712d13a6b78cd010000006a4730440220129e810ecb5062087e508fc546399b6dd863befc6e6e5d64835088625bcc724402203cfcdcc88734fdf43129725f2a6df621255dc363eaadbffa96a4f353cd6b2b80012103242e5c2fcc7657d4de9e85ab63909269c10971796025bce03f90d73430d5a432feffffff021cd92400000000001976a9141d01260a456ccf9b02611eda7cba4b800394d76088acbd021200000000001976a914a0ffa85f72f9fc801796c3db2711263fef62ac2488acb8210600" }, + { "8f9c4944149ebaf10a954ef4b32211626951025c85b9d448bc2f7864f7df58de","0100000002ec95f16172259668f24dfdaa992935dc98b5989fb372b98704e06807a273ac2a010000006a47304402205d640722bc75cb549ff52597c5be5e483b2bddb8afff80d39ac658c3663cf00702203d71bbd73d80b8c32525575f6a7a8d8b5b28067c79d3c271b6b01eeb1d7db53e012103fef2d308e43f97dfd0eec16529a59646eac9bf0079cf30c58fed757c33879006ffffffff6713adce58bd5fdc3f58012442d70ff7a030737c55ca516283e356ac23ae325a010000006b483045022100d69c83daf205ad5817b3a5cd1d2fa976d7a3b8a5ca42f0975ae79d33d6b8f1b502200812ee012bac3884f9903bf73ff7d10534ee0504e33f6b25c37ef5f87f043e02012103fef2d308e43f97dfd0eec16529a59646eac9bf0079cf30c58fed757c33879006ffffffff02f03b2e00000000001976a91472f5cef2166dffec1865d67a9b2ec0a7dc8c94cc88ac21c62100000000001976a9143ed3a9acdde9fc5ccee5c11e1be5412cc56b3f7388ac00000000" }, + { "def2762ed1a0a3f889054a56d9dd819494e1edb33c85d12b47ebb213de9ce6cc","01000000023031cf9e126999107859414c5d222b47fe7814f57f942d4eeb569c72ce178cf0010000006b483045022100cfa8b82a475bb1b6d08e1759abebb6c74a2934eff9e4acbd7d4fdb0bceacf01302203da99a9453933d0bceb0dcf740bd48cddbc7d64f98f2523325db0ca170f84cb80121029ffece79dba4a6d19e7035970738381878357fe235280df0cb5dd6cad8d4b340ffffffff5e3ae4deba14aeb786636cff74cf3bdde12204433f1e5f3e0740ceb8f407a95f010000006a4730440220228f369f443976c1beb09975d7c6a87806d9b46b3d98e3c38370b680ca09622d02201c0be74ed79546a0d977a5fe377b0f720df4b45c44d2c32838292b096142dd3a012103540cdbbfb2423b7299f77666736000181ddce80bd3f466e50e48393adcf3d793ffffffff02c0fc9b01000000001976a91418997f7c97a25043309f699a953a3688c3dfd03288ac865a6300000000001976a914dc9fe4d13cdd10bac781cd1e2add5ba5249fe50c88ac00000000" }, + { "8cb871af1d784b9eb1765e0aec01e924f7e2b3bb4e95e3158e63388eb38baa61","01000000027259cb074b8dd099d0bd774f3a7f986f55a08bd34947f2f44b7fb718f401a7df000000006b483045022100c95abbbca8723f4e4c049f799408bcc598b41cace729fa5c538d63ba5820df4a02205d801ed3420663cae6c70efaf339e573041e6c312c4d519b76aca151bd4c75c9012102a7ba410a1cc2c5099d9a83ae7d8a9526c1b4603a19a071645a2163ebc9969009ffffffff7cd5d89f148a742db5045c7a2e10e09076ac707f7d7000f9a7cae942a289dadb010000006a47304402203e463fe671a8786c2a61f75759c1e7022e8d4927c77b3e00d35a58c190001bb902202a04f744b5c51c280dec8d272a4f637312f5c64628f6d729ea834cd6e880677101210397a2625d2c1a75243bbff627edb4fa00e3b6498a25024e8cd55cf0a1ce98dba9ffffffff0263db1c00000000001976a914512316ea445bcc89df3fc47c7f1172ec9c418b1c88aca0860100000000001976a914612125d19485553f50b49259b0502e989c604da988ac00000000" }, + { "884f44b33d4fc63bb011e65860018e22d77787504963f0b095c50b4ec3b46d2d","010000000226bdd5515fdd621d6d774f7f7241236ad5da7453e61a8e967f5e1a48cadf87d9000000006a473044022053a583f4afdfb333c8a07ea6cf7ec81a121d39749220e640957e7345b1702fb50220211d08296f76b81ae33628a0b0bd85fc7da26107022173f59522d5df8c1540550121034410c8a04f3b65ad9a375b48e39168c02aec50efe57a647e73be9c36a2699c71ffffffff89a3dfff9718105df9c07394f7d6b7496813e3ec2fd7037858b0323d195042d5000000006b483045022100de4d11150b66d7ac616d0056722c8ae5a8152caefa2bb7750f4970e2ab431b0b02202ec6831e7abf593658677aa598e6780ce2e1b07a31d4c911d4bba114549915b3012103e21131ab1175338911d8bb0e9d03452bd55a466e05773e8cfe9955ad4bd2c391ffffffff02543e7502000000001976a914061d7dad16183e335539d7fc2586dd68134c792588accc180700000000001976a91472c563a65ab710115940785db85c4e766f064a5588ac00000000" }, + { "83ae5383a067c7eab269e81e0e9103a34974c43ba1570579000aa73e7efe990b","0100000002c05169e4bebc855178d74e541387ccecda5de8a92ef1111af0c349c1b593157c000000006a47304402206c4dd49b5fab0464975036eb9a0cb2e1239b4e1a2207eeeb6cbfc66244a46e87022010f8996cc308b700151eb7070f465488cf1cb526863fe0cfd6ca7c2f23cb4864012102263ebafaa8035e2daf3ffa0024ba50b0bc346e0316692e012639688b8438018bffffffff0ba8fdcbbf8496e38405cc6f730ee067c25442d4a39d301c153b8c5b97770dbd000000006b4830450221008a1be1649d9bf69c062d4144180cf1398fed4018b1223529bf7d7682e7213141022006a8a4c22a10e6b98d01921f54d6945202d452b0e50f79a2883f53717bfe417401210309d2ff77b5dd80d695b43ed55180cb33f222d5e6f882b0692f877a746f24ab79ffffffff020061100c000000001976a914cfb04aa4ff1b45db068d0a7fe61c0a4fa908df4e88ac707b1900000000001976a914ffc01c4ddce4679adb2b961fc43ed50366688b5e88ac00000000" }, + { "b0913fd41fbbf7d150a0ad04e9e95e3376910e9b7fd6b9c079a3c9d030c68946","0100000002a9e83f09b0d34011f6e574bc42b3883d2428d3ad5c0a617b4178a7e9337a1682000000006b483045022100867e95d17245264926016df82da1415c1cc8226d1ab2f6b51047651e3154f2ce022018bb3d3ea972096d07aa781e8b36ec76088e8c223d12534723cd8ebb0f207b510121039f257134013617ae17160b2355b6ee1c7465e1ca79bf67840b1936b659f40bfdffffffff1113828f8d0119462acc1f0657dfff1708f7995f77c2f02c4c8758421b4fce08010000006a47304402206b5e5ac35439b39a66a197eb73b2d9bca31176448e87dcf8c6ecfa4fe7372bfc02203c4b60ae6dffaf17593631084520655aea450a1ad059aa6e30f2ee249e06a756012102cd39a6646c6a42c2f5a9121cb975720df89621d2458267948acfb9f5394f2405ffffffff022092c500000000001976a914b70e9045bfaf72e2a9e23e64aada09996d6c788688ac288f6b00000000001976a914e9f47d1670425452ddbd691092cde49232e3806388ac00000000" }, + { "659a4afbcd1d879a045251ffdd386aaa27cf6afc8cc185b2266d008455cf0192","01000000018654b115181da29ad32d1def7c4b8d8135da29b3e24f5c69cbf93ea2fd1167b1010000008b483045022100b2896ae31e8afe5b88248bce2f178160c1c5aeec82f2bbcd153e084677eedfe702206f85ec78dd22eca4b2d346754db8d661a314cb9da3289e7cfd7cc09872e4b0b6014104d64612dcd34384f0e84233715363c4bef544084b2ccdd9b933c3c6d84b6901208fd6f373d47a6d27fbbf5f0f6dca38c49b996a5f95ec48762a48f59e072538e7ffffffff0210757000000000001976a9144f3822b226e63b421952a8a51629ddb911d6638888ac26710529000000001976a91402094dc4dbe6464b2e39579310dbfa064e11a20588ac00000000" }, + { "04375783d06b394e5e4869aac59ea80eb4fb4b6070209ab25438f5ecf8ec7f67","0100000002673df06b882ee3d647fe0de1f2a7480c2fbe127b9d4648a5511ca32b07de3b84000000006b483045022100e4dc895a155ca1d04037abe8d99ac60a7cbb3f4f39209b1c0a2f2809c8156ef30220454ee10b2b2cf2bb898d3a9d5c18e9d720112d475f080b7b7a097295cf173418012102a3a5731b128b439d128fc6444239c448f7e6038b96fbc3ac296875220939048fffffffff98141336452581e695f2c7df082a990736c671803beadda68ea9f316670b6b3f010000006a473044022004b84766f9288e526d32b32ed2bb4aca485135859651353bcc1c6d344ab4e89b0220275fe11c095ce6353b9bef195f671cdb11ca820237d15c5e0ac84bd615665786012102a3a5731b128b439d128fc6444239c448f7e6038b96fbc3ac296875220939048fffffffff0336150000000000001976a9145127b1754836413054987e0891d342605f3c173388ac00000000000000001e6a1cd06607f088c438bc6547c87105f69d0a5aa65222096a97fb10e26bb6706f9800000000001976a9141337a0fbbb1206fa815e23d01e9e9a6ea07e5e6f88ac00000000" }, + { "cc6f761c15b0e460e96a8abc607b9d46643e06def81ef5c3244c87acd6c2b03a","01000000028e7cf29bec7451075bf2c9de978ca8f68a02c23edfcad4a4f869f2fab53bfe65000000006a47304402203ccf3573cff9050bf43df26e890485f223ec76abf331793452518815a88c63f702204d50a8e426e24cf948fc04aea1bd6a6520de00710bce327a878f655692454a6a012103f4b97d208e31f6cc6f4e736330fb48187deea477556ec48456838a13faa19e65ffffffff80534135538a121aaa2989827f13a060bd41ca68dd86f14834b8380eacb5d146000000006b483045022100eb70f56f85074837d41e18eade6bed908db3f53e0f0ee3177ed2611087422650022078e49c9c118522245863b378c3bb8fb43be643519482792362f6787e05844ea5012103f4b97d208e31f6cc6f4e736330fb48187deea477556ec48456838a13faa19e65ffffffff0336150000000000001976a9141337a0fbbb1206fa815e23d01e9e9a6ea07e5e6f88ac00000000000000001e6a1c7963f8968617b69701ff5af6682d4ecb542f41a91ba4e220061b66f0706f9800000000001976a91483cea67041baef57c305beac9ded69407b8b396f88ac00000000" }, + { "80e69a0699117dfbc3ebc1db347fa215a0ebb6e7af3176c6c3a0bd01f9fd9893","0100000003a37577878eba8cc8e80a0065a8ee91b811a5dcd691a3ebe7f05139768e39ce8b010000008a473044022041f1978094a1d692a7d15194760f68adde4290709cfe890232d1e8c4c240d44f02205c9047ac19dc12341519320110a8bc06adb1e9c7fea8c437178db03160a6690a014104fcf07bb1222f7925f2b7cc15183a40443c578e62ea17100aa3b44ba66905c95d4980aec4cd2f6eb426d1b1ec45d76724f26901099416b9265b76ba67c8b0b73dffffffff207b14e4dc98bce1ad8a24010773dc4d61c5a87a06fdd7a5afb30a0b6109f407020000008b483045022100cc7c8e98ac2ae736c4997914ab70261a0fc49412b9aa9fb576b59d17148c644d022010c493a14eaeb54908007424f1023a454a1457c38e6ad3a5e75c44aedd001a27014104fcf07bb1222f7925f2b7cc15183a40443c578e62ea17100aa3b44ba66905c95d4980aec4cd2f6eb426d1b1ec45d76724f26901099416b9265b76ba67c8b0b73dffffffffa2d5fc323d49702ac65bb0c3348f9ac6188e600304c9b9dc11e6e50c18303719020000008b48304502210091836986c92a8de183086117cef56ce14f2c97d658e27636760c94b8b8aa437d022046d71116b09f027a5938a0fd448383c66ce7173d315d8b80464afd5ca6f27595014104fcf07bb1222f7925f2b7cc15183a40443c578e62ea17100aa3b44ba66905c95d4980aec4cd2f6eb426d1b1ec45d76724f26901099416b9265b76ba67c8b0b73dffffffff030000000000000000166a146f6d6e69000000000000000300000000000000011ca60500000000001976a914fa0692278afe508514b5ffee8fe5e97732ce066988acaa0a0000000000001976a9146bd54203e2b64fa174dbde2504009a7a179d1ac288ac00000000" }, + { "3353d02013ddc92d1add6bd79da372963aaa649f20504be72bf63a4192f40af2","010000000226d6de4092d680229b1228def4fc5b9876e0de2435f51b85720324fbcf7abcb2010000008b483045022100cdabcc0152c42ffd8e2d813741fd315541aee69c0ebc2000e06d7a36aa824e16022006ef557054f8441b72e041d70ab0f4c4702565d5b53ae2d26ff16fd2a555782c01410470b62127642163a0ba5eb72d350b11523c9ecb7472d4e93881434b6cb04281c979a8f1261cbd666b9fb01440ea332b52f38ae73f10da44652de33d9d23ddc268ffffffff8fd36c08c7fe5f886871a5d629532a14aa951ffb42fe8a5d02b7c8896a9b8184000000008b4830450221008d9b1a2fda09bd09748bf573c20e963e7d037dd91edfb6d03bed176e78c60c7f022018875e010be14f122504327126b7c9be79c63ffd5d4376049e97787543a7897301410470b62127642163a0ba5eb72d350b11523c9ecb7472d4e93881434b6cb04281c979a8f1261cbd666b9fb01440ea332b52f38ae73f10da44652de33d9d23ddc268ffffffff0205140900000000001976a914300ebce37935c12a29f0f9285e8fce03e25b952b88ace3080300000000001976a91422ed65dfb8153c51cfd96fe19e993fa2cba18ee388ac00000000" }, + { "e752d8c8577710e8ee387a0a6d74ebc6e0829175f0c73ad2654f9197d62be4d5","01000000039c7c14372e35432c10af740d5df7ac5788f983f40f9d8652e93298d1db51ed87000000006a47304402207a2d88f48d46d5d94e922fa803a92035c9445fc3f40aeceaf5fd2ea010c2e14c0220422625b67e64ca1f1096c14e0a5da08a208f644b2953aca4dec22ac6aaab394a012102f0bf5066cc6676b3926a581dfa0fc85066be62abffbd99f88ab80d7f9a1c6654ffffffffd8fada494b273f623898c69548e230a0ba4af2aaedb50929c83505c713d64ce5000000006b483045022100f41154f123594c2254fcc17dbd0d835d1b544ab31f6a12af8406ca2833bb2887022056a0b3d34faa6d9c958ccea96df285dfad5124b3e67a40c31ceda05cee3fca30012103e256cf232f1faa0b6c8b8dba55d9ded5016fb7544dcae4815abe348d07e76448ffffffff1b986ef07714f5a9fbaec6cb6443d1bd7f4e52abc294781e5e512762b9a311f4000000006a473044022100f246299002fac360b3df12934779ec2d2ab194ace156e06ed0959d4d1f48866b021f5614eda547fd1848afce850edea0cb866d80f8d5070c376f9be7b3e485c2ea0121036d4976c56a3577068fbd0b7740e808efab077ae1011233394bcea3faf6020a52ffffffff014791cd29000000001976a9144ce9bf1234ff33b0d881c99e5c279b031b9e82c588ac00000000" }, + { "bdadcf939442a580f3da483a6f0c23bd3f619bd9d73b23ea3640ce8d30155a3b","0100000001a2d69bd8727e69ad5071b1fbe2b057993f1a087e5712232c3e034fb335b425a7010000008b4830450221008d771d03b11102603b1cfd6405871c9ab729f4d3ba93a0b56435f5e77a5be00002205ffbd944f3e24b0076e5020cf91a7260cc1ac6c773b96a4f73dcb982e50356b3014104d4ffeba22bad8260af390e4d2b0129b4cd87f46351b742080400683998373987c438597bb7769989a8a6733d2052deadbf937d65e58a6b94899d05bbce7f2652ffffffff02c0cf6a000000000017a9142b12f6a661cfc7a5575b6d0763b26af02c7c633e87232ea402000000001976a91470680c0994b1744b07f4cd4d635c7d0573314b9b88ac00000000" }, + { "37df7dab81ef0f5f5cd039dac497bcd30b3bcd29bd245704a445d36ec0f3e116","0100000003488c79c77af683cc61da0df54c1622633cd7c44389d219a0135e324866c00433010000006a473044022060a83d25a76134022ceb69e87c43ec6f1c739d2261cd403c6f6a0f3b75aa384302204f3d6bce987b4359297cf9890270ed7b90210ffdcc80ea9d094a4cfc6188c1b901210320baf8f44a5923582dc7f29e01dc9c48ed455b3f995638dfe4a632f2572bb750feffffff364b53649891e564782189471f85015e7ef99616bc6081a7304f0095db905b7f010000006b483045022100f935c94984325c659273fef6600d84234f253bf450d5e37d4cbbdc14041003ef02201ddbfe0d436652667df25dde55ab6c821c91c7d317394bc2b3ae0510ea70e2ce0121029278fb69568b226da032dfa6037ad1f200acefd7b106e40904d1ee346141efcefeffffff3d4e2be99987e010fe9f69574574f0b9d5dbe4ede00c46349fce7bfde064db27010000006a47304402201dfccf0193f6d9848f1bef6e6ff49f2808e17850e5d3726eeaa5d541cb30e88e022010f6e30fcf7c0793dfe6eda12a9d728a6cfee1e12b4ab5b33e610b793eb57239012103ef3c2d2c1f027bdd9f1773e50cc06dd5f353615b6d3b4d756fd68a3360573d9ffeffffff0214771900000000001976a9148242c581d8d03fbddd9aaf2ecd4bb324d3344e0188ac60ceab07000000001976a91430fcf4b7a5e44f82b3a2f4247d758ecc9f3c1add88acb8210600" }, + { "e1a4ea04149b4e60ce8e8097344b831a0880ffcb27df192b5d11952bb2f81fd8","01000000063c23d0e5414af8598854f3d74550c984ed689d3ddbe4d0a4ba2b922373aedf028e0000006b483045022100e82c34f0c2bc22d9220396028ed51b350c11120feb4491a4d927dff44f0fb52c0220546bb192a7dd87e4ea54ee1bcdce22d3d7d524b1e70e9c0fba8902c72492fee0012103d3004c4dd56e724217171cf39e706da2c48b64f1ce7a2dce783282e8ee92da26ffffffffe836fe4d5abac77f24431fa53194cb2eb318b6b045b6d03bb102384073e25c24250100006b483045022100b31f6354a8a88a28353c196a82327092297b8c1a8d0bef9fd34f49a37750c72902204f866029efc24f50ca53efb04347528cfac6ba70be1922d9188a96659b11a6ac012103d3004c4dd56e724217171cf39e706da2c48b64f1ce7a2dce783282e8ee92da26ffffffff61dd0d351acd668fe1d85c06dc402485e9f912684f43e75ef42687868c81f938610000006a473044022075068bf7402ca52ec003d3aa222b3cbede4c731139869a59a6ed34c71e23d439022039af22acf610ca360af6fa485645768e4b752638dd386011891dbf72e630610f012103d3004c4dd56e724217171cf39e706da2c48b64f1ce7a2dce783282e8ee92da26ffffffff4aa4c949842b400a39d9b7d737702f2fdd44373357eb05dcb343f90d787c5988340000006b4830450221008e988f60aba8cf9c6911ed35e39a85fa857b0526289ec5d16efb027bd0f9cb5a022030d8ad35f7006f5343c93573fa93678e9ae49bcd9084d3e4f0987b9fb94575ca012103d3004c4dd56e724217171cf39e706da2c48b64f1ce7a2dce783282e8ee92da26fffffffffe5c4bc2b130d20faf36c6e18307294017d4dfcd0a9a2a22ff5afd680c5eee9c190100006a473044022075e94119ba747b23c4b9a5f252bbd82d6842fcf13101796486814a9d25d1d5ca02203b9b2b219f1df5b680fb4510022bec0ce9110c1148820cb39f84fdfa810a1474012103d3004c4dd56e724217171cf39e706da2c48b64f1ce7a2dce783282e8ee92da26ffffffff28170b630a7fa42cfcc34a69d090b8dbfe634d30de404eb572cd4bb89b8ceed0a60000006a47304402207eb8132977d33dca3f806fe3910ac49f98d4a5c3c31f3ee5147c88778b56c91502202964a7beaa50a5b931f878731c3b3caf4ab4d13ff32790ac75f6ac4fb3056b74012103d3004c4dd56e724217171cf39e706da2c48b64f1ce7a2dce783282e8ee92da26ffffffff0212050000000000001976a914fad393f039488c8ffc6792b23ccc98ee482ad52988acb0ad0100000000001976a914eea6c715345d3a92823b86942af09f1d8a249ccc88ac00000000" }, + { "04708e7170b8a79248c53ca989ef030513c4d2b85b22789fa555c406d4c94e50","" }, + { "9382808049dc620bdd8761279d3ed854e76bc3cf888336775bc1aa84730602e8","0100000001504ec9d406c455a59f78225bb8d2c4130503ef89a93cc54892a7b870718e7004010000006b483045022100db2284cf7b3f14c38c216e24180a6287b5323d81ee09aa1dc1be4f56cd65944a02202b21bf79397bffd90ef2fe0088df74f96b08f52e96c331e05fd7b2839c4f2a5a012102671f6d2a1a190d8d57b1e4f539a42a3105db16a97b91ac723c5f15516992ffacffffffff020000000000000000386a365ba21ae48cc71c7eb310df43d7295e6a3dbc93b639c875b36e6ae2a8e96d29342b7b0ace4d41b3a41378b4fcfbb1697eb0b67b8b0e7052971f00000000001976a9143e24f61429e05db5655d1ba8b71bc7d1fe4f03b388ac00000000" }, + { "610f5ef642818f02132422489faf78165aabf0826d0b37d41e1a3691bc096f62","" }, + { "da3b476d4082b976305cc536d4ff6a93d944194d45de56dccd82e2c040108b8e","" }, + { "3125b62775d46ac9ee04ea32ced67eadaa436fad9c7c894a32718dc1333e8e06","01000000018e8b1040c0e282cddc56de454d1944d9936affd436c55c3076b982406d473bda020000006a4730440220539942a9fa5ea2be749091c3b082854b054ba18e23d34d6b2b0719c34d2d50660220780cab38acc8808573e534a91fda4b48cdf910504183ff553da6f4471fdb217f012103e91b97df0999cd99fb7f293a1c9189eae9b554262ea908055ebf24f607c03aa5ffffffff0336150000000000001976a914edee861dff4de166683e4c54ae3869cd05c7ae0f88ac00000000000000001e6a1ca738ed28117d0975853866f789963128094c8cdb2c104d154501ee5490926500000000001976a91418d7d921d511ac33875b53b113435111bac6fb8688ac00000000" }, + { "5f89af45eb52b512643765d210e4d439ce2b5fbf2329ac65c39b4fa85d79e70d","01000000028e8b1040c0e282cddc56de454d1944d9936affd436c55c3076b982406d473bda000000006b483045022100c6306a14c792caefa2191c62f96b7af4e182bc9f682f407c9736d494d3af57d702203ea45299c14a20ed5381ad79916131df3d9415d25089d97e7d9eaa1fe43d5755012103024f0ed5a4022c65eaccaf1ce1c70a388cca10ec49ec4e6c33bf264dd1c6aedaffffffff626f09bc91361a1ed4370b6d82f0ab5a1678af9f48222413028f8142f65e0f61020000006a47304402203ca17e32c04307cc774c6e4ba82c9acd3a2df02502cb4ba77ccc1a9a249f01f202202c4920cbc0c85515517dd259d2d1f919169167f22c51618ed2f2cb571a6bbf68012103024f0ed5a4022c65eaccaf1ce1c70a388cca10ec49ec4e6c33bf264dd1c6aedaffffffff0336150000000000001976a914edee861dff4de166683e4c54ae3869cd05c7ae0f88ac00000000000000001e6a1ca738ed28117d0975853866f7899631290bbfc4322c104d09a94c7254f65a0400000000001976a914f7f9e2aade3600b07171f81c299c51c1d790991788ac00000000" } +}; diff --git a/src/logdb/test/tests_red_black_tree.c b/src/logdb/test/tests_red_black_tree.c new file mode 100644 index 000000000..8976620cb --- /dev/null +++ b/src/logdb/test/tests_red_black_tree.c @@ -0,0 +1,86 @@ +#include +#include + +#include "../../../test/utest.h" + +#include +#include +#include + +/* this file has functions to test a red-black tree of integers */ + +void free_key(void* a) { + free((int*)a); +} + +void free_value(void *a){ + free((int*)a); +} + +int IntComp(const void* a,const void* b) { + if( *(int*)a > *(int*)b) return(1); + if( *(int*)a < *(int*)b) return(-1); + return(0); +} + +void IntPrint(const void* a) { + printf("%i",*(int*)a); +} + +void InfoPrint(void* a) { + UNUSED(a); +} + + +void test_red_black_tree() { + char *akey; + char *avalue; + char *akey2; + char *avalue2; + rb_red_blk_node* newNode; + rb_red_blk_node* newNode2; + rb_red_blk_tree* tree; + size_t size; + + tree=RBTreeCreate(IntComp,free_key,free_value,IntPrint,InfoPrint); + + + akey = malloc(10); + memcpy(akey, (void *)"akey", 4); + avalue = malloc(10); + memcpy(avalue, (void *)"avalue", 6); + RBTreeInsert(tree,akey,avalue); + + akey2 = malloc(10); + memcpy(akey2, (void *)"bkey", 4); + avalue2 = malloc(10); + memcpy(avalue2, (void *)"bvalue", 6); + RBTreeInsert(tree,akey2,avalue2); + + newNode2 = RBExactQuery(tree,akey2); + newNode = RBExactQuery(tree,akey); + newNode = TreeSuccessor(tree,newNode); + newNode = TreePredecessor(tree,newNode); + + size = rbtree_count(tree); + while((newNode2 = rbtree_enumerate_next(tree))) + { + size--; + } + /* test reset */ + while((newNode2 = rbtree_enumerate_next(tree))) + { + size++; + } + while((newNode2 = rbtree_enumerate_next(tree))) + { + size--; + } + + u_assert_int_eq(size, 0); + + RBDelete(tree, newNode); + + RBTreePrint(tree); + RBTreeDestroy(tree); +} diff --git a/src/memory.c b/src/memory.c new file mode 100644 index 000000000..19feb3b21 --- /dev/null +++ b/src/memory.c @@ -0,0 +1,129 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2017 libbtc developers + + 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 + +void* btc_malloc_internal(size_t size); +void* btc_calloc_internal(size_t count, size_t size); +void* btc_realloc_internal(void *ptr, size_t size); +void btc_free_internal(void* ptr); + +static const btc_mem_mapper default_mem_mapper = {btc_malloc_internal, btc_calloc_internal, btc_realloc_internal, btc_free_internal}; +static btc_mem_mapper current_mem_mapper = {btc_malloc_internal, btc_calloc_internal, btc_realloc_internal, btc_free_internal}; + +void btc_mem_set_mapper_default() +{ + current_mem_mapper = default_mem_mapper; +} + +void btc_mem_set_mapper(const btc_mem_mapper mapper) +{ + current_mem_mapper = mapper; +} + +void* btc_malloc(size_t size) +{ + return current_mem_mapper.btc_malloc(size); +} + +void* btc_calloc(size_t count, size_t size) +{ + return current_mem_mapper.btc_calloc(count, size); +} + +void* btc_realloc(void *ptr, size_t size) +{ + return current_mem_mapper.btc_realloc(ptr, size); +} + +void btc_free(void* ptr) +{ + current_mem_mapper.btc_free(ptr); +} + +void* btc_malloc_internal(size_t size) +{ + void* result; + + if ((result = malloc(size))) { /* assignment intentional */ + return (result); + } else { + printf("memory overflow: malloc failed in btc_malloc."); + printf(" Exiting Program.\n"); + exit(-1); + return (0); + } +} + +void* btc_calloc_internal(size_t count, size_t size) +{ + void* result; + + if ((result = calloc(count, size))) { /* assignment intentional */ + return (result); + } else { + printf("memory overflow: calloc failed in btc_malloc."); + printf(" Exiting Program.\n"); + exit(-1); + return (0); + } +} + +void* btc_realloc_internal(void *ptr, size_t size) +{ + void* result; + + if ((result = realloc(ptr, size))) { /* assignment intentional */ + return (result); + } else { + printf("memory overflow: calloc failed in btc_malloc."); + printf(" Exiting Program.\n"); + exit(-1); + return (0); + } +} + +void btc_free_internal(void* ptr) +{ + free(ptr); +} + +#ifdef HAVE_MEMSET_S +volatile void *btc_mem_zero(volatile void *dst, size_t len) +{ + memset_s(dst, len, 0, len); +} +#else +volatile void *btc_mem_zero(volatile void *dst, size_t len) +{ + volatile char *buf; + for (buf = (volatile char *)dst; len; buf[--len] = 0); + return dst; +} +#endif diff --git a/src/net.c b/src/net.c new file mode 100644 index 000000000..a39a2d0a6 --- /dev/null +++ b/src/net.c @@ -0,0 +1,603 @@ +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#include +#else +#include +#include +#include +#endif + +#include +#include +#include +#include + +#include + +#define UNUSED(x) (void)(x) + +static const int BTC_PERIODICAL_NODE_TIMER_S = 3; +static const int BTC_PING_INTERVAL_S = 180; +static const int BTC_CONNECT_TIMEOUT_S = 10; + +int net_write_log_printf(const char* format, ...) +{ + va_list args; + va_start(args, format); + printf("DEBUG :"); + vprintf(format, args); + va_end(args); + return 1; +} + +int net_write_log_null(const char* format, ...) +{ + UNUSED(format); + return 1; +} + +void read_cb(struct bufferevent* bev, void* ctx) +{ + struct evbuffer* input = bufferevent_get_input(bev); + if (!input) + return; + + size_t length = evbuffer_get_length(input); + + btc_node* node = (btc_node*)ctx; + + if ((node->state & NODE_CONNECTED) != NODE_CONNECTED) { + // ignore messages from disconnected peers + return; + } + // expand the cstring buffer if required + cstr_alloc_minsize(node->recvBuffer, node->recvBuffer->len + length); + + // copy direct to cstring, avoid another heap buffer + evbuffer_copyout(input, node->recvBuffer->str + node->recvBuffer->len, length); + node->recvBuffer->len += length; + + // drain the event buffer + evbuffer_drain(input, length); + + struct const_buffer buf = {node->recvBuffer->str, node->recvBuffer->len}; + btc_p2p_msg_hdr hdr; + char* read_upto = NULL; + + do { + //check if message is complete + if (buf.len < BTC_P2P_HDRSZ) { + break; + } + + btc_p2p_deser_msghdr(&hdr, &buf); + if (hdr.data_len > BTC_MAX_P2P_MSG_SIZE) { + // check for invalid message lengths + btc_node_missbehave(node); + return; + } + if (buf.len < hdr.data_len) { + //if we haven't read the whole message, continue and wait for the next chunk + break; + } + if (buf.len >= hdr.data_len) { + //at least one message is complete + + struct const_buffer cmd_data_buf = {buf.p, buf.len}; + if ((node->state & NODE_CONNECTED) != NODE_CONNECTED) { + // ignore messages from disconnected peers + return; + } + btc_node_parse_message(node, &hdr, &cmd_data_buf); + + //skip the size of the whole message + buf.p = (const unsigned char*)buf.p + hdr.data_len; + buf.len -= hdr.data_len; + + read_upto = (void*)buf.p; + } + if (buf.len == 0) { + //if we have "consumed" the whole buffer + node->recvBuffer->len = 0; + break; + } + } while (1); + + if (read_upto != NULL && node->recvBuffer->len != 0 && read_upto != (node->recvBuffer->str + node->recvBuffer->len)) { + char* end = node->recvBuffer->str + node->recvBuffer->len; + size_t available_chunk_data = end - read_upto; + //partial message + cstring* tmp = cstr_new_buf(read_upto, available_chunk_data); + cstr_free(node->recvBuffer, true); + node->recvBuffer = tmp; + } +} + +void write_cb(struct bufferevent* ev, void* ctx) +{ + UNUSED(ev); + UNUSED(ctx); +} + +void node_periodical_timer(int fd, short event, void* ctx) +{ + UNUSED(fd); + UNUSED(event); + btc_node* node = (btc_node*)ctx; + uint64_t now = time(NULL); + + /* pass data to the callback and give it a chance to cancle the call */ + if (node->nodegroup->periodic_timer_cb) + if (!node->nodegroup->periodic_timer_cb(node, &now)) + return; + + if (node->time_started_con + BTC_CONNECT_TIMEOUT_S < now && ((node->state & NODE_CONNECTING) == NODE_CONNECTING)) { + node->state = 0; + node->time_started_con = 0; + node->state |= NODE_ERRORED; + node->state |= NODE_TIMEOUT; + btc_node_connection_state_changed(node); + } + + if (((node->state & NODE_CONNECTED) == NODE_CONNECTED) && node->lastping + BTC_PING_INTERVAL_S < now) { + //time for a ping + uint64_t nonce; + btc_cheap_random_bytes((uint8_t*)&nonce, sizeof(nonce)); + cstring* pingmsg = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, BTC_MSG_PING, &nonce, sizeof(nonce)); + btc_node_send(node, pingmsg); + cstr_free(pingmsg, true); + node->lastping = now; + } +} + +void event_cb(struct bufferevent* ev, short type, void* ctx) +{ + UNUSED(ev); + btc_node* node = (btc_node*)ctx; + node->nodegroup->log_write_cb("Event callback on node %d\n", node->nodeid); + + if (((type & BEV_EVENT_TIMEOUT) != 0) && ((node->state & NODE_CONNECTING) == NODE_CONNECTING)) { + node->nodegroup->log_write_cb("Timout connecting to node %d.\n", node->nodeid); + node->state = 0; + node->state |= NODE_ERRORED; + node->state |= NODE_TIMEOUT; + btc_node_connection_state_changed(node); + } else if (((type & BEV_EVENT_EOF) != 0) || + ((type & BEV_EVENT_ERROR) != 0)) { + node->state = 0; + node->state |= NODE_ERRORED; + node->state |= NODE_DISCONNECTED; + if ((type & BEV_EVENT_EOF) != 0) { + node->nodegroup->log_write_cb("Disconnected from the remote peer %d.\n", node->nodeid); + node->state |= NODE_DISCONNECTED_FROM_REMOTE_PEER; + } + else { + node->nodegroup->log_write_cb("Error connecting to node %d.\n", node->nodeid); + } + btc_node_connection_state_changed(node); + } else if (type & BEV_EVENT_CONNECTED) { + node->nodegroup->log_write_cb("Successfull connected to node %d.\n", node->nodeid); + node->state |= NODE_CONNECTED; + node->state &= ~NODE_CONNECTING; + node->state &= ~NODE_ERRORED; + btc_node_connection_state_changed(node); + /* if callback is set, fire */ + } + node->nodegroup->log_write_cb("Connected nodes: %d\n", btc_node_group_amount_of_connected_nodes(node->nodegroup, NODE_CONNECTED)); +} + +btc_node* btc_node_new() +{ + btc_node* node; + node = btc_calloc(1, sizeof(*node)); + node->version_handshake = false; + node->state = 0; + node->nonce = 0; + node->services = 0; + node->lastping = 0; + node->time_started_con = 0; + node->time_last_request = 0; + btc_hash_clear(node->last_requested_inv); + + node->recvBuffer = cstr_new_sz(BTC_P2P_MESSAGE_CHUNK_SIZE); + node->hints = 0; + return node; +} + +btc_bool btc_node_set_ipport(btc_node* node, const char* ipport) +{ + int outlen = (int)sizeof(node->addr); + + //return true in case of success (0 == no error) + return (evutil_parse_sockaddr_port(ipport, &node->addr, &outlen) == 0); +} + +void btc_node_release_events(btc_node* node) +{ + if (node->event_bev) { + bufferevent_free(node->event_bev); + node->event_bev = NULL; + } + + if (node->timer_event) { + event_del(node->timer_event); + event_free(node->timer_event); + node->timer_event = NULL; + } +} + +btc_bool btc_node_missbehave(btc_node* node) +{ + node->nodegroup->log_write_cb("Mark node %d as missbehaved\n", node->nodeid); + node->state |= NODE_MISSBEHAVED; + btc_node_connection_state_changed(node); + return 0; +} + +void btc_node_disconnect(btc_node* node) +{ + if ((node->state & NODE_CONNECTED) == NODE_CONNECTED || (node->state & NODE_CONNECTING) == NODE_CONNECTING) { + node->nodegroup->log_write_cb("Disconnect node %d\n", node->nodeid); + } + /* release buffer and timer event */ + btc_node_release_events(node); + + node->state &= ~NODE_CONNECTING; + node->state &= ~NODE_CONNECTED; + node->state |= NODE_DISCONNECTED; + + node->time_started_con = 0; +} + +void btc_node_free(btc_node* node) +{ + btc_node_disconnect(node); + cstr_free(node->recvBuffer, true); + btc_free(node); +} + +void btc_node_free_cb(void* obj) +{ + btc_node* node = (btc_node*)obj; + btc_node_free(node); +} + +btc_node_group* btc_node_group_new(const btc_chainparams* chainparams) +{ + btc_node_group* node_group; + node_group = btc_calloc(1, sizeof(*node_group)); + node_group->event_base = event_base_new(); + if (!node_group->event_base) { + return NULL; + }; + + node_group->nodes = vector_new(1, btc_node_free_cb); + node_group->chainparams = (chainparams ? chainparams : &btc_chainparams_main); + node_group->parse_cmd_cb = NULL; + strcpy(node_group->clientstr, "libbtc 0.1"); + + /* nullify callbacks */ + node_group->postcmd_cb = NULL; + node_group->node_connection_state_changed_cb = NULL; + node_group->should_connect_to_more_nodes_cb = NULL; + node_group->handshake_done_cb = NULL; + node_group->log_write_cb = net_write_log_null; + node_group->desired_amount_connected_nodes = 3; + + return node_group; +} + +void btc_node_group_shutdown(btc_node_group *group) { + for (size_t i = 0; i < group->nodes->len; i++) { + btc_node* node = vector_idx(group->nodes, i); + btc_node_disconnect(node); + } +} + +void btc_node_group_free(btc_node_group* group) +{ + if (!group) + return; + + if (group->event_base) { + event_base_free(group->event_base); + } + + if (group->nodes) { + vector_free(group->nodes, true); + } + btc_free(group); +} + +void btc_node_group_event_loop(btc_node_group* group) +{ + event_base_dispatch(group->event_base); +} + +void btc_node_group_add_node(btc_node_group* group, btc_node* node) +{ + vector_add(group->nodes, node); + node->nodegroup = group; + node->nodeid = group->nodes->len; +} + +int btc_node_group_amount_of_connected_nodes(btc_node_group* group, enum NODE_STATE state) +{ + int cnt = 0; + for (size_t i = 0; i < group->nodes->len; i++) { + btc_node* node = vector_idx(group->nodes, i); + if ((node->state & state) == state) + cnt++; + } + return cnt; +} + +btc_bool btc_node_group_connect_next_nodes(btc_node_group* group) +{ + btc_bool connected_at_least_to_one_node = false; + int connect_amount = group->desired_amount_connected_nodes - btc_node_group_amount_of_connected_nodes(group, NODE_CONNECTED); + if (connect_amount <= 0) + return true; + + connect_amount = connect_amount*3; + /* search for a potential node that has not errored and is not connected or in connecting state */ + for (size_t i = 0; i < group->nodes->len; i++) { + btc_node* node = vector_idx(group->nodes, i); + if ( + !((node->state & NODE_CONNECTED) == NODE_CONNECTED) && + !((node->state & NODE_CONNECTING) == NODE_CONNECTING) && + !((node->state & NODE_DISCONNECTED) == NODE_DISCONNECTED) && + !((node->state & NODE_ERRORED) == NODE_ERRORED)) { + /* setup buffer event */ + node->event_bev = bufferevent_socket_new(group->event_base, -1, BEV_OPT_CLOSE_ON_FREE); + bufferevent_setcb(node->event_bev, read_cb, write_cb, event_cb, node); + bufferevent_enable(node->event_bev, EV_READ | EV_WRITE); + if (bufferevent_socket_connect(node->event_bev, (struct sockaddr*)&node->addr, sizeof(node->addr)) < 0) { + /* Error starting connection */ + if (node->event_bev) + bufferevent_free(node->event_bev); + return false; + } + + /* setup periodic timer */ + node->time_started_con = time(NULL); + struct timeval tv; + tv.tv_sec = BTC_PERIODICAL_NODE_TIMER_S; + tv.tv_usec = 0; + node->timer_event = event_new(group->event_base, 0, EV_TIMEOUT | EV_PERSIST, node_periodical_timer, + (void*)node); + event_add(node->timer_event, &tv); + node->state |= NODE_CONNECTING; + connected_at_least_to_one_node = true; + + node->nodegroup->log_write_cb("Trying to connect to %d...\n", node->nodeid); + + connect_amount--; + if (connect_amount <= 0) + return true; + } + } + /* node group misses a node to connect to */ + return connected_at_least_to_one_node; +} + +void btc_node_connection_state_changed(btc_node* node) +{ + if (node->nodegroup->node_connection_state_changed_cb) + node->nodegroup->node_connection_state_changed_cb(node); + + if ((node->state & NODE_ERRORED) == NODE_ERRORED) { + btc_node_release_events(node); + + /* connect to more nodes are required */ + btc_bool should_connect_to_more_nodes = true; + if (node->nodegroup->should_connect_to_more_nodes_cb) + should_connect_to_more_nodes = node->nodegroup->should_connect_to_more_nodes_cb(node); + + if (should_connect_to_more_nodes && (btc_node_group_amount_of_connected_nodes(node->nodegroup, NODE_CONNECTED) + btc_node_group_amount_of_connected_nodes(node->nodegroup, NODE_CONNECTING) < node->nodegroup->desired_amount_connected_nodes)) + btc_node_group_connect_next_nodes(node->nodegroup); + } + if ((node->state & NODE_MISSBEHAVED) == NODE_MISSBEHAVED) { + if ((node->state & NODE_CONNECTED) == NODE_CONNECTED || (node->state & NODE_CONNECTING) == NODE_CONNECTING) { + btc_node_disconnect(node); + } + } else + btc_node_send_version(node); +} + +void btc_node_send(btc_node* node, cstring* data) +{ + if ((node->state & NODE_CONNECTED) != NODE_CONNECTED) + return; + + bufferevent_write(node->event_bev, data->str, data->len); + char* dummy = data->str + 4; + node->nodegroup->log_write_cb("sending message to node %d: %s\n", node->nodeid, dummy); +} + +void btc_node_send_version(btc_node* node) +{ + if (!node) + return; + + /* get new string buffer */ + cstring* version_msg_cstr = cstr_new_sz(256); + + /* copy socket_addr to p2p addr */ + btc_p2p_address fromAddr; + btc_p2p_address_init(&fromAddr); + btc_p2p_address toAddr; + btc_p2p_address_init(&toAddr); + btc_addr_to_p2paddr(&node->addr, &toAddr); + + /* create a version message struct */ + btc_p2p_version_msg version_msg; + memset(&version_msg, 0, sizeof(version_msg)); + + /* create a serialized version message */ + btc_p2p_msg_version_init(&version_msg, &fromAddr, &toAddr, node->nodegroup->clientstr, true); + btc_p2p_msg_version_ser(&version_msg, version_msg_cstr); + + /* create p2p message */ + cstring* p2p_msg = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, BTC_MSG_VERSION, version_msg_cstr->str, version_msg_cstr->len); + + /* send message */ + btc_node_send(node, p2p_msg); + + /* cleanup */ + cstr_free(version_msg_cstr, true); + cstr_free(p2p_msg, true); +} + +int btc_node_parse_message(btc_node* node, btc_p2p_msg_hdr* hdr, struct const_buffer* buf) +{ + node->nodegroup->log_write_cb("received command from node %d: %s\n", node->nodeid, hdr->command); + if (memcmp(hdr->netmagic, node->nodegroup->chainparams->netmagic, sizeof(node->nodegroup->chainparams->netmagic)) != 0) { + return btc_node_missbehave(node); + } + + /* send the header and buffer to the possible callback */ + /* callback can decide to run the internal base message logic */ + if (!node->nodegroup->parse_cmd_cb || node->nodegroup->parse_cmd_cb(node, hdr, buf)) { + if (strcmp(hdr->command, BTC_MSG_VERSION) == 0) { + btc_p2p_version_msg v_msg_check; + if (!btc_p2p_msg_version_deser(&v_msg_check, buf)) { + return btc_node_missbehave(node); + } + if ((v_msg_check.services & BTC_NODE_NETWORK) != BTC_NODE_NETWORK) { + btc_node_disconnect(node); + } + node->bestknownheight = v_msg_check.start_height; + node->nodegroup->log_write_cb("Connected to node %d: %s (%d)\n", node->nodeid, v_msg_check.useragent, v_msg_check.start_height); + /* confirm version via verack */ + cstring* verack = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, BTC_MSG_VERACK, NULL, 0); + btc_node_send(node, verack); + cstr_free(verack, true); + } else if (strcmp(hdr->command, BTC_MSG_VERACK) == 0) { + /* complete handshake if verack has been received */ + node->version_handshake = true; + + /* execute callback and inform that the node is ready for custom message logic */ + if (node->nodegroup->handshake_done_cb) + node->nodegroup->handshake_done_cb(node); + } else if (strcmp(hdr->command, BTC_MSG_PING) == 0) { + /* response pings */ + uint64_t nonce = 0; + if (!deser_u64(&nonce, buf)) { + return btc_node_missbehave(node); + } + cstring* pongmsg = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, BTC_MSG_PONG, &nonce, 8); + btc_node_send(node, pongmsg); + cstr_free(pongmsg, true); + } + } + + /* pass data to the "post command" callback */ + if (node->nodegroup->postcmd_cb) + node->nodegroup->postcmd_cb(node, hdr, buf); + + return true; +} + +/* utility function to get peers (ips/port as char*) from a seed */ +int btc_get_peers_from_dns(const char* seed, vector* ips_out, int port, int family) +{ + if (!seed || !ips_out || (family != AF_INET && family != AF_INET6) || port > 99999) { + return 0; + } + char def_port[6] = {0}; + sprintf(def_port, "%d", port); + struct evutil_addrinfo hints, *aiTrav = NULL, *aiRes = NULL; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + int err = evutil_getaddrinfo(seed, NULL, &hints, &aiRes); + if (err) + return 0; + + aiTrav = aiRes; + while (aiTrav != NULL) { + int maxlen = 256; + char* ipaddr = btc_calloc(1, maxlen); + if (aiTrav->ai_family == AF_INET) { + assert(aiTrav->ai_addrlen >= sizeof(struct sockaddr_in)); + evutil_inet_ntop(aiTrav->ai_family, &((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr, ipaddr, maxlen); + } + + if (aiTrav->ai_family == AF_INET6) { + assert(aiTrav->ai_addrlen >= sizeof(struct sockaddr_in6)); + evutil_inet_ntop(aiTrav->ai_family, &((struct sockaddr_in6*)(aiTrav->ai_addr))->sin6_addr, ipaddr, maxlen); + } + + memcpy(ipaddr + strlen(ipaddr), ":", 1); + memcpy(ipaddr + strlen(ipaddr), def_port, strlen(def_port)); + + vector_add(ips_out, ipaddr); + + aiTrav = aiTrav->ai_next; + } + evutil_freeaddrinfo(aiRes); + return ips_out->len; +} + +btc_bool btc_node_group_add_peers_by_ip_or_seed(btc_node_group *group, const char *ips) { + if (ips == NULL) { + /* === DNS QUERY === */ + /* get a couple of peers from a seed */ + vector* ips_dns = vector_new(10, free); + const btc_dns_seed seed = group->chainparams->dnsseeds[0]; + if (strlen(seed.domain) == 0) { + return false; + } + /* todo: make sure we have enought peers, eventually */ + /* call another seeder */ + btc_get_peers_from_dns(seed.domain, ips_dns, group->chainparams->default_port, AF_INET); + for (unsigned int i = 0; i < ips_dns->len; i++) { + char* ip = (char*)vector_idx(ips_dns, i); + + /* create a node */ + btc_node* node = btc_node_new(); + if (btc_node_set_ipport(node, ip) > 0) { + /* add the node to the group */ + btc_node_group_add_node(group, node); + } + } + vector_free(ips_dns, true); + } else { + // add comma seperated ips (nodes) + char working_str[64]; + memset(working_str, 0, sizeof(working_str)); + size_t offset = 0; + for (unsigned int i = 0; i <= strlen(ips); i++) { + if (i == strlen(ips) || ips[i] == ',') { + btc_node* node = btc_node_new(); + if (btc_node_set_ipport(node, working_str) > 0) { + btc_node_group_add_node(group, node); + } + offset = 0; + memset(working_str, 0, sizeof(working_str)); + } else if (ips[i] != ' ' && offset < sizeof(working_str)) { + working_str[offset] = ips[i]; + offset++; + } + } + } + return true; +} diff --git a/src/netspv.c b/src/netspv.c new file mode 100644 index 000000000..dde089f0a --- /dev/null +++ b/src/netspv.c @@ -0,0 +1,547 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Jonas Schnelli + + 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 +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#include +#else +#include +#include +#include +#endif + +#include +#include +#include +#include +#include + +static const unsigned int HEADERS_MAX_RESPONSE_TIME = 60; +static const unsigned int MIN_TIME_DELTA_FOR_STATE_CHECK = 5; +static const unsigned int BLOCK_GAP_TO_DEDUCT_TO_START_SCAN_FROM = 5; +static const unsigned int BLOCKS_DELTA_IN_S = 600; +static const unsigned int COMPLETED_WHEN_NUM_NODES_AT_SAME_HEIGHT = 2; + +static btc_bool btc_net_spv_node_timer_callback(btc_node *node, uint64_t *now); +void btc_net_spv_post_cmd(btc_node *node, btc_p2p_msg_hdr *hdr, struct const_buffer *buf); +void btc_net_spv_node_handshake_done(btc_node *node); + +void btc_net_set_spv(btc_node_group *nodegroup) +{ + nodegroup->postcmd_cb = btc_net_spv_post_cmd; + nodegroup->handshake_done_cb = btc_net_spv_node_handshake_done; + nodegroup->node_connection_state_changed_cb = NULL; + nodegroup->periodic_timer_cb = btc_net_spv_node_timer_callback; +} + +btc_spv_client* btc_spv_client_new(const btc_chainparams *params, btc_bool debug, btc_bool headers_memonly) +{ + btc_spv_client* client; + client = calloc(1, sizeof(*client)); + + client->last_headersrequest_time = 0; //!< time when we requested the last header package + client->last_statecheck_time = 0; + client->oldest_item_of_interest = time(NULL)-5*60; + client->stateflags = SPV_HEADER_SYNC_FLAG; + + client->chainparams = params; + + client->nodegroup = btc_node_group_new(params); + client->nodegroup->ctx = client; + client->nodegroup->desired_amount_connected_nodes = 3; /* TODO */ + + btc_net_set_spv(client->nodegroup); + + if (debug) { + client->nodegroup->log_write_cb = net_write_log_printf; + } + + if (params == &btc_chainparams_main) { + client->use_checkpoints = true; + } + client->headers_db = &btc_headers_db_interface_file; + client->headers_db_ctx = client->headers_db->init(params, headers_memonly); + + // set callbacks + client->header_connected = NULL; + client->called_sync_completed = false; + client->sync_completed = NULL; + client->header_message_processed = NULL; + client->sync_transaction = NULL; + + return client; +} + +void btc_spv_client_discover_peers(btc_spv_client* client, const char *ips) +{ + btc_node_group_add_peers_by_ip_or_seed(client->nodegroup, ips); +} + +void btc_spv_client_runloop(btc_spv_client* client) +{ + btc_node_group_connect_next_nodes(client->nodegroup); + btc_node_group_event_loop(client->nodegroup); +} + +void btc_spv_client_free(btc_spv_client *client) +{ + if (!client) + return; + + if (client->headers_db) + { + client->headers_db->free(client->headers_db_ctx); + client->headers_db_ctx = NULL; + client->headers_db = NULL; + } + + if (client->nodegroup) { + btc_node_group_free(client->nodegroup); + client->nodegroup = NULL; + } + + free(client); +} + +btc_bool btc_spv_client_load(btc_spv_client *client, const char *file_path) +{ + if (!client) + return false; + + if (!client->headers_db) + return false; + + return client->headers_db->load(client->headers_db_ctx, file_path); + +} + +void btc_net_spv_periodic_statecheck(btc_node *node, uint64_t *now) +{ + /* statecheck logic */ + /* ================ */ + + btc_spv_client *client = (btc_spv_client*)node->nodegroup->ctx; + + client->nodegroup->log_write_cb("Statecheck: amount of connected nodes: %d\n", btc_node_group_amount_of_connected_nodes(client->nodegroup, NODE_CONNECTED)); + + /* check if the node chosen for NODE_HEADERSYNC during SPV_HEADER_SYNC has stalled */ + if (client->last_headersrequest_time > 0 && *now > client->last_headersrequest_time) + { + int64_t timedetla = *now - client->last_headersrequest_time; + if (timedetla > HEADERS_MAX_RESPONSE_TIME) + { + client->nodegroup->log_write_cb("No header response in time (used %d) for node %d\n", timedetla, node->nodeid); + /* disconnect the node if we haven't got a header after requesting some with a getheaders message */ + node->state &= ~NODE_HEADERSYNC; + btc_node_disconnect(node); + client->last_headersrequest_time = 0; + btc_net_spv_request_headers(client); + } + } + if (node->time_last_request > 0 && *now > node->time_last_request) + { + // we are downloading blocks from this peer + int64_t timedetla = *now - node->time_last_request; + + client->nodegroup->log_write_cb("No block response in time (used %d) for node %d\n", timedetla, node->nodeid); + if (timedetla > HEADERS_MAX_RESPONSE_TIME) + { + /* disconnect the node if a blockdownload has stalled */ + btc_node_disconnect(node); + node->time_last_request = 0; + btc_net_spv_request_headers(client); + } + } + + /* check if we need to sync headers from a different peer */ + if ((client->stateflags & SPV_HEADER_SYNC_FLAG) == SPV_HEADER_SYNC_FLAG) + { + btc_net_spv_request_headers(client); + } + else + { + /* headers sync should be done at this point */ + + } + + client->last_statecheck_time = *now; +} + +static btc_bool btc_net_spv_node_timer_callback(btc_node *node, uint64_t *now) +{ + btc_spv_client *client = (btc_spv_client*)node->nodegroup->ctx; + + if (client->last_statecheck_time + MIN_TIME_DELTA_FOR_STATE_CHECK < *now) + { + /* do a state check only every seconds */ + btc_net_spv_periodic_statecheck(node, now); + } + + /* return true = run internal timer logic (ping, disconnect-timeout, etc.) */ + return true; +} + +void btc_net_spv_fill_block_locator(btc_spv_client *client, vector *blocklocators) +{ + if (client->headers_db->getchaintip(client->headers_db_ctx)->height == 0) + { + if (client->use_checkpoints && client->oldest_item_of_interest > BLOCK_GAP_TO_DEDUCT_TO_START_SCAN_FROM * BLOCKS_DELTA_IN_S) { + /* jump to checkpoint */ + /* check oldest item of interest and set genesis/checkpoint */ + + int64_t min_timestamp = client->oldest_item_of_interest - BLOCK_GAP_TO_DEDUCT_TO_START_SCAN_FROM * BLOCKS_DELTA_IN_S; /* ensure we going back ~144 blocks */ + for (int i = (sizeof(btc_mainnet_checkpoint_array) / sizeof(btc_mainnet_checkpoint_array[0]))-1; i >= 0 ; i--) + { + const btc_checkpoint *cp = &btc_mainnet_checkpoint_array[i]; + if ( btc_mainnet_checkpoint_array[i].timestamp < min_timestamp) + { + uint256 *hash = btc_calloc(1, sizeof(uint256)); + utils_uint256_sethex((char *)btc_mainnet_checkpoint_array[i].hash, (uint8_t *)hash); + vector_add(blocklocators, (void *)hash); + + if (!client->headers_db->has_checkpoint_start(client->headers_db_ctx)) { + client->headers_db->set_checkpoint_start(client->headers_db_ctx, *hash, btc_mainnet_checkpoint_array[i].height); + } + } + } + if (blocklocators->len > 0) { + // return if we could fill up the blocklocator with checkpoints + return; + } + } + uint256 *hash = btc_calloc(1, sizeof(uint256)); + memcpy(hash, &client->chainparams->genesisblockhash, sizeof(uint256)); + vector_add(blocklocators, (void *)hash); + client->nodegroup->log_write_cb("Setting blocklocator with genesis block\n"); + } + else + { + client->headers_db->fill_blocklocator_tip(client->headers_db_ctx, blocklocators); + } +} + +void btc_net_spv_node_request_headers_or_blocks(btc_node *node, btc_bool blocks) +{ + // request next headers + vector *blocklocators = vector_new(1, free); + + btc_net_spv_fill_block_locator((btc_spv_client *)node->nodegroup->ctx, blocklocators); + + cstring *getheader_msg = cstr_new_sz(256); + btc_p2p_msg_getheaders(blocklocators, NULL, getheader_msg); + + /* create p2p message */ + cstring *p2p_msg = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, (blocks ? "getblocks" : "getheaders"), getheader_msg->str, getheader_msg->len); + cstr_free(getheader_msg, true); + + /* send message */ + btc_node_send(node, p2p_msg); + node->state |= ( blocks ? NODE_BLOCKSYNC : NODE_HEADERSYNC); + + /* remember last headers request time */ + if (blocks) { + node->time_last_request = time(NULL); + } + else { + ((btc_spv_client*)node->nodegroup->ctx)->last_headersrequest_time = time(NULL); + } + + /* cleanup */ + vector_free(blocklocators, true); + cstr_free(p2p_msg, true); +} + +btc_bool btc_net_spv_request_headers(btc_spv_client *client) +{ + /* make sure only one node is used for header sync */ + for(size_t i =0;i< client->nodegroup->nodes->len; i++) + { + btc_node *check_node = vector_idx(client->nodegroup->nodes, i); + if ( ( (check_node->state & NODE_HEADERSYNC) == NODE_HEADERSYNC + || + (check_node->state & NODE_BLOCKSYNC) == NODE_BLOCKSYNC + ) + && + (check_node->state & NODE_CONNECTED) == NODE_CONNECTED) + return true; + } + + /* We are not downloading headers at this point */ + /* try to request headers from a peer where the version handshake has been done */ + btc_bool new_headers_available = false; + unsigned int nodes_at_same_height = 0; + if (client->headers_db->getchaintip(client->headers_db_ctx)->header.timestamp > client->oldest_item_of_interest - (BLOCK_GAP_TO_DEDUCT_TO_START_SCAN_FROM * BLOCKS_DELTA_IN_S) ) + { + // no need to fetch headers; + } + else { + for(size_t i =0;i< client->nodegroup->nodes->len; i++) + { + btc_node *check_node = vector_idx(client->nodegroup->nodes, i); + if ( ((check_node->state & NODE_CONNECTED) == NODE_CONNECTED) && check_node->version_handshake) + { + if (check_node->bestknownheight > client->headers_db->getchaintip(client->headers_db_ctx)->height) { + btc_net_spv_node_request_headers_or_blocks(check_node, false); + new_headers_available = true; + return true; + } else if (check_node->bestknownheight == client->headers_db->getchaintip(client->headers_db_ctx)->height) { + nodes_at_same_height++; + } + } + } + } + + if (!new_headers_available && btc_node_group_amount_of_connected_nodes(client->nodegroup, NODE_CONNECTED) > 0) { + // try to fetch blocks if no new headers are available but connected nodes are reachable + for(size_t i =0;i< client->nodegroup->nodes->len; i++) + { + btc_node *check_node = vector_idx(client->nodegroup->nodes, i); + if ( ((check_node->state & NODE_CONNECTED) == NODE_CONNECTED) && check_node->version_handshake) + { + if (check_node->bestknownheight > client->headers_db->getchaintip(client->headers_db_ctx)->height) { + btc_net_spv_node_request_headers_or_blocks(check_node, true); + return true; + } else if (check_node->bestknownheight == client->headers_db->getchaintip(client->headers_db_ctx)->height) { + nodes_at_same_height++; + } + } + } + } + + if ( nodes_at_same_height >= COMPLETED_WHEN_NUM_NODES_AT_SAME_HEIGHT && + !client->called_sync_completed && + client->sync_completed ) + { + client->sync_completed(client); + client->called_sync_completed = true; + } + + /* we could not request more headers, need more peers to connect to */ + return false; +} +void btc_net_spv_node_handshake_done(btc_node *node) +{ + btc_net_spv_request_headers((btc_spv_client*)node->nodegroup->ctx); +} + +void btc_net_spv_post_cmd(btc_node *node, btc_p2p_msg_hdr *hdr, struct const_buffer *buf) +{ + btc_spv_client *client = (btc_spv_client *)node->nodegroup->ctx; + + if (strcmp(hdr->command, BTC_MSG_INV) == 0 && (node->state & NODE_BLOCKSYNC) == NODE_BLOCKSYNC) + { + struct const_buffer original_inv = { buf->p, buf->len }; + uint32_t varlen; + deser_varlen(&varlen, buf); + btc_bool contains_block = false; + + client->nodegroup->log_write_cb("Get inv request with %d items\n", varlen); + + for (unsigned int i=0;ilast_requested_inv, buf); + } + else { + deser_skip(buf, 32); + } + } + + if (contains_block) + { + node->time_last_request = time(NULL); + + /* request the blocks */ + client->nodegroup->log_write_cb("Requesting %d blocks\n", varlen); + cstring *p2p_msg = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, BTC_MSG_GETDATA, original_inv.p, original_inv.len); + btc_node_send(node, p2p_msg); + cstr_free(p2p_msg, true); + + if (varlen >= 500) { + /* directly request more blocks */ + /* not sure if this is clever if we want to download, as example, the complete chain */ + btc_net_spv_node_request_headers_or_blocks(node, true); + } + } + } + if (strcmp(hdr->command, BTC_MSG_BLOCK) == 0) + { + btc_bool connected; + btc_blockindex *pindex = client->headers_db->connect_hdr(client->headers_db_ctx, buf, false, &connected); + /* deserialize the p2p header */ + if (!pindex) { + /* deserialization failed */ + return; + } + + uint32_t amount_of_txs; + if (!deser_varlen(&amount_of_txs, buf)) { + /* deserialization transaction varint failed */ + return; + } + + // flag off the block request stall check + node->time_last_request = time(NULL); + + // for now, turn of stall checks if we are near the tip + if (pindex->header.timestamp > node->time_last_request - 30*60) { + node->time_last_request = 0; + } + + /* for now, only scan if the block could be connected on top */ + if (connected) { + if (client->header_connected) { client->header_connected(client); } + time_t lasttime = pindex->header.timestamp; + printf("Downloaded new block with size %d at height %d (%s)\n", hdr->data_len, pindex->height, ctime(&lasttime)); + uint64_t start = time(NULL); + printf("Start parsing %d transactions...", amount_of_txs); + + size_t consumedlength = 0; + for (unsigned int i=0;ip, buf->len, tx, &consumedlength, true)) { + printf("Error deserializing transaction\n"); + } + deser_skip(buf, consumedlength); + + /* send info to possible callback */ + if (client->sync_transaction) { client->sync_transaction(client->sync_transaction_ctx, tx, i, pindex); } + + btc_tx_free(tx); + } + printf("done (took %llu secs)\n", time(NULL) - start); + } + else { + fprintf(stderr, "Could not connect block on top of the chain\n"); + } + + if (btc_hash_equal(node->last_requested_inv, pindex->hash)) { + // last requested block reached, consider stop syncing + if (!client->called_sync_completed && client->sync_completed) { client->sync_completed(client); client->called_sync_completed = true; } + } + } + if (strcmp(hdr->command, BTC_MSG_HEADERS) == 0) + { + uint32_t amount_of_headers; + if (!deser_varlen(&amount_of_headers, buf)) return; + uint64_t now = time(NULL); + client->nodegroup->log_write_cb("Got %d headers (took %d s) from node %d\n", amount_of_headers, now - client->last_headersrequest_time, node->nodeid); + + // flag off the request stall check + client->last_headersrequest_time = 0; + + unsigned int connected_headers = 0; + for (unsigned int i=0;iheaders_db->connect_hdr(client->headers_db_ctx, buf, false, &connected); + /* deserialize the p2p header */ + if (!pindex) + { + client->nodegroup->log_write_cb("Header deserialization failed (node %d)\n", node->nodeid); + return; + } + + /* skip tx count */ + if (!deser_skip(buf, 1)) { + client->nodegroup->log_write_cb("Header deserialization (tx count skip) failed (node %d)\n", node->nodeid); + return; + } + + if (!connected) + { + /* error, header sequence missmatch + mark node as missbehaving */ + client->nodegroup->log_write_cb("Got invalid headers (not in sequence) from node %d\n", node->nodeid); + node->state &= ~NODE_HEADERSYNC; + btc_node_missbehave(node); + + /* see if we can fetch headers from a different peer */ + btc_net_spv_request_headers(client); + } + else { + connected_headers++; + if (pindex->header.timestamp > client->oldest_item_of_interest - (BLOCK_GAP_TO_DEDUCT_TO_START_SCAN_FROM * BLOCKS_DELTA_IN_S) ) { + + /* we should start loading block from this point */ + client->stateflags &= ~SPV_HEADER_SYNC_FLAG; + client->stateflags |= SPV_FULLBLOCK_SYNC_FLAG; + node->state &= ~NODE_HEADERSYNC; + node->state |= NODE_BLOCKSYNC; + + client->nodegroup->log_write_cb("start loading block from node %d at height %d at time: %ld\n", node->nodeid, client->headers_db->getchaintip(client->headers_db_ctx)->height, client->headers_db->getchaintip(client->headers_db_ctx)->header.timestamp); + btc_net_spv_node_request_headers_or_blocks(node, true); + + /* ignore the rest of the headers */ + /* we are going to request blocks now */ + break; + } + } + } + btc_blockindex *chaintip = client->headers_db->getchaintip(client->headers_db_ctx); + + client->nodegroup->log_write_cb("Connected %d headers\n", connected_headers); + client->nodegroup->log_write_cb("Chaintip at height %d\n", chaintip->height); + + /* call the header message processed callback and allow canceling the further logic commands */ + if (client->header_message_processed && client->header_message_processed(client, node, chaintip) == false) + return; + + if (amount_of_headers == MAX_HEADERS_RESULTS && ((node->state & NODE_BLOCKSYNC) != NODE_BLOCKSYNC)) + { + /* peer sent maximal amount of headers, very likely, there will be more */ + time_t lasttime = chaintip->header.timestamp; + client->nodegroup->log_write_cb("chain size: %d, last time %s", chaintip->height, ctime(&lasttime)); + btc_net_spv_node_request_headers_or_blocks(node, false); + } + else + { + /* headers download seems to be completed */ + /* we should have switched to block request if the oldest_item_of_interest was set correctly */ + } + } +} diff --git a/src/protocol.c b/src/protocol.c new file mode 100644 index 000000000..42f75460a --- /dev/null +++ b/src/protocol.c @@ -0,0 +1,288 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Jonas Schnelli + + 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 +#include + +#include +#include + +enum { + BTC_ADDR_TIME_VERSION = 31402, + BTC_MIN_PROTO_VERSION = 70000, +}; + +/* IPv4 addresses are mapped to 16bytes with a prefix of 10 x 0x00 + 2 x 0xff */ +static const uint8_t BTC_IPV4_PREFIX[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff}; +static inline btc_bool is_ipv4_mapped(const unsigned char* ipaddr) +{ + return memcmp(ipaddr, BTC_IPV4_PREFIX, 12) == 0; +} + +void btc_p2p_address_init(btc_p2p_address* addr) +{ + memset(addr, 0, sizeof(*addr)); +} + +cstring* btc_p2p_message_new(const unsigned char netmagic[4], const char* command, const void* data, uint32_t data_len) +{ + cstring* s = cstr_new_sz(BTC_P2P_HDRSZ + data_len); + + /* network identifier (magic number) */ + cstr_append_buf(s, netmagic, 4); + + /* command string */ + char command_null[12]; + memset(command_null, 0, 12); + memcpy(command_null, command, strlen(command)); + //memset(command_null+strlen(command), 0, 12-strlen(command)); + cstr_append_buf(s, command_null, 12); + + /* data length, always 4 bytes */ + uint32_t data_len_le = htole32(data_len); + cstr_append_buf(s, &data_len_le, 4); + + /* data checksum (first 4 bytes of the double sha256 hash of the pl) */ + uint256 msghash; + btc_hash(data, data_len, msghash); + cstr_append_buf(s, &msghash[0], 4); + + /* data payload */ + if (data_len > 0) + cstr_append_buf(s, data, data_len); + + return s; +} + +btc_bool btc_p2p_deser_addr(unsigned int protocol_version, btc_p2p_address* addr, struct const_buffer* buf) +{ + if (protocol_version >= BTC_ADDR_TIME_VERSION) { + if (!deser_u32(&addr->time, buf)) + return false; + } else + addr->time = 0; + + if (!deser_u64(&addr->services, buf)) + return false; + if (!deser_bytes(&addr->ip, buf, 16)) + return false; + if (!deser_u16(&addr->port, buf)) + return false; + return true; +} + +void btc_p2p_ser_addr(unsigned int protover, const btc_p2p_address* addr, cstring* s) +{ + if (protover >= BTC_ADDR_TIME_VERSION) + ser_u32(s, addr->time); + ser_u64(s, addr->services); + ser_bytes(s, addr->ip, 16); + ser_u16(s, addr->port); +} + + +void btc_addr_to_p2paddr(struct sockaddr* addr, btc_p2p_address* addr_out) +{ + if (addr->sa_family == AF_INET6) { + struct sockaddr_in6* saddr = (struct sockaddr_in6*)addr; + memcpy(&addr_out->ip, &saddr->sin6_addr, 16); + addr_out->port = ntohs(saddr->sin6_port); + } else if (addr->sa_family == AF_INET) { + struct sockaddr_in* saddr = (struct sockaddr_in*)addr; + memset(&addr_out->ip[0], 0, 10); + memset(&addr_out->ip[10], 0xff, 2); + memcpy(&addr_out->ip[12], &saddr->sin_addr, 4); + addr_out->port = ntohs(saddr->sin_port); + } +} + +void btc_p2paddr_to_addr(btc_p2p_address* p2p_addr, struct sockaddr* addr_out) +{ + if (!p2p_addr || !addr_out) + return; + + if (!is_ipv4_mapped(p2p_addr->ip)) { + /* ipv6 */ + struct sockaddr_in6* saddr = (struct sockaddr_in6*)addr_out; + memcpy(&saddr->sin6_addr, p2p_addr->ip, 16); + saddr->sin6_port = htons(p2p_addr->port); + } else { + struct sockaddr_in* saddr = (struct sockaddr_in*)addr_out; + memcpy(&saddr->sin_addr, &p2p_addr->ip[12], 4); + saddr->sin_port = htons(p2p_addr->port); + } +} + +void btc_p2p_msg_version_init(btc_p2p_version_msg* msg, const btc_p2p_address* addrFrom, const btc_p2p_address* addrTo, const char* strSubVer, btc_bool relay) +{ + msg->version = BTC_PROTOCOL_VERSION; + msg->services = 0; + msg->timestamp = time(NULL); + msg->timestamp = time(NULL); + if (addrTo) + msg->addr_recv = *addrTo; + else + btc_p2p_address_init(&msg->addr_recv); + if (addrFrom) + msg->addr_from = *addrFrom; + else + btc_p2p_address_init(&msg->addr_from); + btc_cheap_random_bytes((uint8_t*)&msg->nonce, sizeof(msg->nonce)); + if (strSubVer && strlen(strSubVer) < 128) + memcpy(msg->useragent, strSubVer, strlen(strSubVer)); + + msg->start_height = 0; + msg->relay = relay; +} + +void btc_p2p_msg_version_ser(btc_p2p_version_msg* msg, cstring* buf) +{ + ser_s32(buf, msg->version); + ser_u64(buf, msg->services); + ser_s64(buf, msg->timestamp); + btc_p2p_ser_addr(0, &msg->addr_recv, buf); + btc_p2p_ser_addr(0, &msg->addr_from, buf); + ser_u64(buf, msg->nonce); + ser_str(buf, msg->useragent, 1024); + ser_s32(buf, msg->start_height); + cstr_append_c(buf, msg->relay); +} + +btc_bool btc_p2p_msg_version_deser(btc_p2p_version_msg* msg, struct const_buffer* buf) +{ + memset(msg, 0, sizeof(*msg)); + if (!deser_s32(&msg->version, buf)) + return false; + if (!deser_u64(&msg->services, buf)) + return false; + if (!deser_s64(&msg->timestamp, buf)) + return false; + if (!btc_p2p_deser_addr(0, &msg->addr_recv, buf)) + return false; + if (!btc_p2p_deser_addr(0, &msg->addr_from, buf)) + return false; + if (!deser_u64(&msg->nonce, buf)) + return false; + + uint32_t ua_len; + uint32_t cpy_len; + if (!deser_varlen(&ua_len, buf)) + return false; + + cpy_len = ua_len; + if (cpy_len > 128) + cpy_len = 128; + /* we only support user agent strings up to 1024 chars */ + /* we only copy 128bytes to the message structure */ + if (ua_len > 1024) + return false; + + char ua_str[1024]; + if (!deser_bytes(ua_str, buf, ua_len)) + return false; + memset(msg->useragent, 0, sizeof(msg->useragent)); + memcpy(&msg->useragent, ua_str, cpy_len); + + if (!deser_s32(&msg->start_height, buf)) + return false; + if (msg->version > 70001) + if (!deser_bytes(&msg->relay, buf, 1)) + return false; + + return true; +} + +void btc_p2p_msg_inv_init(btc_p2p_inv_msg* msg, uint32_t type, uint256 hash) +{ + msg->type = type; + memcpy(&msg->hash, hash, BTC_HASH_LENGTH); +} + +void btc_p2p_msg_inv_ser(btc_p2p_inv_msg* msg, cstring* buf) +{ + ser_u32(buf, msg->type); + ser_bytes(buf, msg->hash, BTC_HASH_LENGTH); +} + +btc_bool btc_p2p_msg_inv_deser(btc_p2p_inv_msg* msg, struct const_buffer* buf) +{ + memset(msg, 0, sizeof(*msg)); + if (!deser_u32(&msg->type, buf)) + return false; + if (!deser_u256(msg->hash, buf)) + return false; + return true; +} + +void btc_p2p_msg_getheaders(vector* blocklocators, uint256 hashstop, cstring* s) +{ + unsigned int i; + + ser_u32(s, BTC_PROTOCOL_VERSION); + ser_varlen(s, blocklocators->len); + for (i = 0; i < blocklocators->len; i++) { + uint256 *hash = vector_idx(blocklocators, i); + ser_bytes(s, hash, BTC_HASH_LENGTH); + } + if (hashstop) + ser_bytes(s, hashstop, BTC_HASH_LENGTH); + else + ser_bytes(s, NULLHASH, BTC_HASH_LENGTH); +} + +btc_bool btc_p2p_deser_msg_getheaders(vector* blocklocators, uint256 hashstop, struct const_buffer* buf) +{ + int32_t version; + uint32_t vsize; + if (!deser_s32(&version, buf)) + return false; + if (!deser_varlen(&vsize, buf)) + return false; + vector_resize(blocklocators, vsize); + for (unsigned int i = 0; i < vsize; i++) { + uint256 *hash = btc_malloc(BTC_HASH_LENGTH); + if (!deser_u256(*hash, buf)) { + btc_free(hash); + return false; + } + vector_add(blocklocators, hash); + } + if (!deser_u256(hashstop, buf)) + return false; + return true; +} + +void btc_p2p_deser_msghdr(btc_p2p_msg_hdr* hdr, struct const_buffer* buf) +{ + deser_bytes(hdr->netmagic, buf, 4); + deser_bytes(hdr->command, buf, 12); + deser_u32(&hdr->data_len, buf); + deser_bytes(hdr->hash, buf, 4); +} diff --git a/src/random.c b/src/random.c new file mode 100644 index 000000000..47339a4d9 --- /dev/null +++ b/src/random.c @@ -0,0 +1,107 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Douglas J. Bakkum + + 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 "libbtc-config.h" + +#include +#include +#include +#include + +#ifdef WIN32 +#include +#include +#endif + +void btc_random_init_internal(void); +btc_bool btc_random_bytes_internal(uint8_t* buf, uint32_t len, const uint8_t update_seed); + +static const btc_rnd_mapper default_rnd_mapper = {btc_random_init_internal, btc_random_bytes_internal}; +static btc_rnd_mapper current_rnd_mapper = {btc_random_init_internal, btc_random_bytes_internal}; + +void btc_rnd_set_mapper_default() +{ + current_rnd_mapper = default_rnd_mapper; +} + +void btc_rnd_set_mapper(const btc_rnd_mapper mapper) +{ + current_rnd_mapper = mapper; +} + +void btc_random_init(void) +{ + current_rnd_mapper.btc_random_init(); +} + +btc_bool btc_random_bytes(uint8_t* buf, uint32_t len, const uint8_t update_seed) +{ + return current_rnd_mapper.btc_random_bytes(buf, len, update_seed); +} + +#ifdef TESTING +void btc_random_init_internal(void) +{ + srand(time(NULL)); +} + + +btc_bool btc_random_bytes_internal(uint8_t* buf, uint32_t len, uint8_t update_seed) +{ + (void)update_seed; + for (uint32_t i = 0; i < len; i++) { + buf[i] = rand(); + } + + return true; +} +#else +void btc_random_init_internal(void) {} +btc_bool btc_random_bytes_internal(uint8_t* buf, uint32_t len, const uint8_t update_seed) +{ +#ifdef WIN32 + HCRYPTPROV hProvider; + int ret = CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + assert(ret); + ret = CryptGenRandom(hProvider, len, buf); + assert(ret); + CryptReleaseContext(hProvider, 0); +#else + (void)update_seed; //unused + FILE* frand = fopen(RANDOM_DEVICE, "r"); + if (!frand) { + return false; + } + + size_t len_read = fread(buf, 1, len, frand); + assert(len_read == len); + fclose(frand); + return true; +#endif +} +#endif diff --git a/src/ripemd160.c b/src/ripemd160.c new file mode 100644 index 000000000..8c39df2ad --- /dev/null +++ b/src/ripemd160.c @@ -0,0 +1,337 @@ +/** + * 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 "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) +{ + 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/src/ripemd160.h b/src/ripemd160.h new file mode 100644 index 000000000..5b6ad6609 --- /dev/null +++ b/src/ripemd160.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 __RIPEMD160_H__ +#define __RIPEMD160_H__ + +#include + +void ripemd160(const uint8_t* msg, uint32_t msg_len, uint8_t* hash); + +#endif diff --git a/src/script.c b/src/script.c new file mode 100644 index 000000000..65c910b69 --- /dev/null +++ b/src/script.c @@ -0,0 +1,493 @@ +/* + + The MIT License (MIT) + + Copyright 2012 exMULTI, Inc. + Copyright (c) 2015 Jonas Schnelli + + 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 +#include +#include + +btc_bool btc_script_copy_without_op_codeseperator(const cstring* script_in, cstring* script_out) +{ + if (script_in->len == 0) + return false; /* EOF */ + + struct const_buffer buf = {script_in->str, script_in->len}; + unsigned char opcode; + while (buf.len > 0) { + if (!deser_bytes(&opcode, &buf, 1)) + goto err_out; + + uint32_t data_len = 0; + + if (opcode < OP_PUSHDATA1 && opcode > OP_0) { + data_len = opcode; + cstr_append_buf(script_out, &opcode, 1); + } else if (opcode == OP_PUSHDATA1) { + uint8_t v8; + if (!deser_bytes(&v8, &buf, 1)) + goto err_out; + cstr_append_buf(script_out, &opcode, 1); + cstr_append_buf(script_out, &v8, 1); + data_len = v8; + } else if (opcode == OP_PUSHDATA2) { + uint16_t v16; + if (!deser_u16(&v16, &buf)) + goto err_out; + cstr_append_buf(script_out, &opcode, 1); + cstr_append_buf(script_out, &v16, 2); + data_len = v16; + } else if (opcode == OP_PUSHDATA4) { + uint32_t v32; + if (!deser_u32(&v32, &buf)) + goto err_out; + cstr_append_buf(script_out, &opcode, 1); + cstr_append_buf(script_out, &v32, 5); + data_len = v32; + } else if (opcode == OP_CODESEPARATOR) + continue; + + if (data_len > 0) { + assert(data_len < 16777215); //limit max push to 0xFFFFFF + unsigned char bufpush[data_len]; + deser_bytes(&bufpush, &buf, data_len); + cstr_append_buf(script_out, &bufpush, data_len); + } else + cstr_append_buf(script_out, &opcode, 1); + } + + return true; + +err_out: + return false; +} + +btc_script_op* btc_script_op_new() +{ + btc_script_op* script_op; + script_op = btc_calloc(1, sizeof(*script_op)); + + return script_op; +} + + +void btc_script_op_free(btc_script_op* script_op) +{ + if (script_op->data) { + btc_free(script_op->data); + script_op->data = NULL; + } + script_op->datalen = 0; + script_op->op = OP_0; +} + +void btc_script_op_free_cb(void* data) +{ + btc_script_op* script_op = data; + btc_script_op_free(script_op); + + btc_free(script_op); +} + +btc_bool btc_script_get_ops(const cstring* script_in, vector* ops_out) +{ + if (script_in->len == 0) + return false; /* EOF */ + + struct const_buffer buf = {script_in->str, script_in->len}; + unsigned char opcode; + + btc_script_op* op = NULL; + while (buf.len > 0) { + op = btc_script_op_new(); + + if (!deser_bytes(&opcode, &buf, 1)) + goto err_out; + + op->op = opcode; + + uint32_t data_len; + + if (opcode < OP_PUSHDATA1) { + data_len = opcode; + } else if (opcode == OP_PUSHDATA1) { + uint8_t v8; + if (!deser_bytes(&v8, &buf, 1)) + goto err_out; + data_len = v8; + } else if (opcode == OP_PUSHDATA2) { + uint16_t v16; + if (!deser_u16(&v16, &buf)) + goto err_out; + data_len = v16; + } else if (opcode == OP_PUSHDATA4) { + uint32_t v32; + if (!deser_u32(&v32, &buf)) + goto err_out; + data_len = v32; + } else { + vector_add(ops_out, op); + continue; + } + + op->data = btc_calloc(1, data_len); + memcpy(op->data, buf.p, data_len); + op->datalen = data_len; + + vector_add(ops_out, op); + + if (!deser_skip(&buf, data_len)) + goto err_out; + } + + return true; +err_out: + btc_script_op_free(op); + return false; +} + +static inline btc_bool btc_script_is_pushdata(const enum opcodetype op) +{ + return (op <= OP_PUSHDATA4); +} + +static btc_bool btc_script_is_op(const btc_script_op* op, enum opcodetype opcode) +{ + return (op->op == opcode); +} + +static btc_bool btc_script_is_op_pubkey(const btc_script_op* op) +{ + if (!btc_script_is_pushdata(op->op)) + return false; + if (op->datalen < 33 || op->datalen > 120) + return false; + return true; +} + +static btc_bool btc_script_is_op_pubkeyhash(const btc_script_op* op) +{ + if (!btc_script_is_pushdata(op->op)) + return false; + if (op->datalen != 20) + return false; + return true; +} + +// OP_PUBKEY, OP_CHECKSIG +btc_bool btc_script_is_pubkey(const vector* ops) +{ + return ((ops->len == 2) && + btc_script_is_op(vector_idx(ops, 1), OP_CHECKSIG) && + btc_script_is_op_pubkey(vector_idx(ops, 0))); +} + +// OP_DUP, OP_HASH160, OP_PUBKEYHASH, OP_EQUALVERIFY, OP_CHECKSIG, +btc_bool btc_script_is_pubkeyhash(const vector* ops, vector* data_out) +{ + if ((ops->len == 5) && + btc_script_is_op(vector_idx(ops, 0), OP_DUP) && + btc_script_is_op(vector_idx(ops, 1), OP_HASH160) && + btc_script_is_op_pubkeyhash(vector_idx(ops, 2)) && + btc_script_is_op(vector_idx(ops, 3), OP_EQUALVERIFY) && + btc_script_is_op(vector_idx(ops, 4), OP_CHECKSIG)) { + if (data_out) { + //copy the data (hash160) in case of a non empty vector + const btc_script_op* op = vector_idx(ops, 2); + uint8_t* buffer = btc_calloc(1, sizeof(uint160)); + memcpy(buffer, op->data, sizeof(uint160)); + vector_add(data_out, buffer); + } + return true; + } + return false; +} + +// OP_HASH160, OP_PUBKEYHASH, OP_EQUAL +btc_bool btc_script_is_scripthash(const vector* ops) +{ + return ((ops->len == 3) && + btc_script_is_op(vector_idx(ops, 0), OP_HASH160) && + btc_script_is_op_pubkeyhash(vector_idx(ops, 1)) && + btc_script_is_op(vector_idx(ops, 2), OP_EQUAL)); +} + +static btc_bool btc_script_is_op_smallint(const btc_script_op* op) +{ + return ((op->op == OP_0) || + (op->op >= OP_1 && op->op <= OP_16)); +} + +btc_bool btc_script_is_multisig(const vector* ops) +{ + if ((ops->len < 3) || (ops->len > (16 + 3)) || + !btc_script_is_op_smallint(vector_idx(ops, 0)) || + !btc_script_is_op_smallint(vector_idx(ops, ops->len - 2)) || + !btc_script_is_op(vector_idx(ops, ops->len - 1), OP_CHECKMULTISIG)) + return false; + + unsigned int i; + for (i = 1; i < (ops->len - 2); i++) + if (!btc_script_is_op_pubkey(vector_idx(ops, i))) + return false; + + return true; +} + +enum btc_tx_out_type btc_script_classify_ops(const vector* ops) +{ + if (btc_script_is_pubkeyhash(ops, NULL)) + return BTC_TX_PUBKEYHASH; + if (btc_script_is_scripthash(ops)) + return BTC_TX_SCRIPTHASH; + if (btc_script_is_pubkey(ops)) + return BTC_TX_PUBKEY; + if (btc_script_is_multisig(ops)) + return BTC_TX_MULTISIG; + + return BTC_TX_NONSTANDARD; +} + +enum btc_tx_out_type btc_script_classify(const cstring* script, vector* data_out) +{ + //INFO: could be speed up by not forming a vector + // and directly parse the script cstring + + enum btc_tx_out_type tx_out_type = BTC_TX_NONSTANDARD; + vector* ops = vector_new(10, btc_script_op_free_cb); + btc_script_get_ops(script, ops); + + if (btc_script_is_pubkeyhash(ops, data_out)) + tx_out_type = BTC_TX_PUBKEYHASH; + if (btc_script_is_scripthash(ops)) + tx_out_type = BTC_TX_SCRIPTHASH; + if (btc_script_is_pubkey(ops)) + tx_out_type = BTC_TX_PUBKEY; + if (btc_script_is_multisig(ops)) + tx_out_type = BTC_TX_MULTISIG; + uint8_t version = 0; + uint8_t witness_program[40] = {0}; + int witness_program_len = 0; + if (btc_script_is_witnessprogram(script, &version, witness_program, &witness_program_len)) { + if (version == 0 && witness_program_len == 20) { + tx_out_type = BTC_TX_WITNESS_V0_PUBKEYHASH; + if (data_out) { + uint8_t *witness_program_cpy = btc_calloc(1, witness_program_len); + memcpy(witness_program_cpy, witness_program, witness_program_len); + vector_add(data_out, witness_program_cpy); + } + } + if (version == 0 && witness_program_len == 32) { + tx_out_type = BTC_TX_WITNESS_V0_SCRIPTHASH; + if (data_out) { + uint8_t *witness_program_cpy = btc_calloc(1, witness_program_len); + memcpy(witness_program_cpy, witness_program, witness_program_len); + vector_add(data_out, witness_program_cpy); + } + } + } + vector_free(ops, true); + return tx_out_type; +} + +btc_bool btc_script_extract_pkh(const cstring* script, uint8_t* data) +{ + // expected that data is a 20byte buffer + + btc_bool suc = false; + + vector* ops = vector_new(10, btc_script_op_free_cb); + btc_script_get_ops(script, ops); + btc_script_op* op = vector_idx(ops, 2); + if (op && btc_script_is_op_pubkeyhash(op)) { + memcpy(data, op->data, 20); + suc = true; + } + vector_free(ops, true); + return suc; +} + +enum opcodetype btc_encode_op_n(const int n) +{ + assert(n >= 0 && n <= 16); + if (n == 0) + return OP_0; + return (enum opcodetype)(OP_1 + n - 1); +} + + +void btc_script_append_op(cstring* script_in, enum opcodetype op) +{ + cstr_append_buf(script_in, &op, 1); +} + + +void btc_script_append_pushdata(cstring* script_in, const unsigned char* data, const size_t datalen) +{ + if (datalen < OP_PUSHDATA1) { + cstr_append_buf(script_in, (unsigned char*)&datalen, 1); + } else if (datalen <= 0xff) { + btc_script_append_op(script_in, OP_PUSHDATA1); + cstr_append_buf(script_in, (unsigned char*)&datalen, 1); + } else if (datalen <= 0xffff) { + btc_script_append_op(script_in, OP_PUSHDATA2); + uint16_t v = htole16(datalen); + cstr_append_buf(script_in, &v, sizeof(v)); + } else { + btc_script_append_op(script_in, OP_PUSHDATA4); + uint32_t v = htole32(datalen); + cstr_append_buf(script_in, &v, sizeof(v)); + } + cstr_append_buf(script_in, data, datalen); +} + +btc_bool btc_script_build_multisig(cstring* script_in, const unsigned int required_signatures, const vector* pubkeys_chars) +{ + cstr_resize(script_in, 0); //clear script + + if (required_signatures > 16 || pubkeys_chars->len > 16) + return false; + enum opcodetype op_req_sig = btc_encode_op_n(required_signatures); + cstr_append_buf(script_in, &op_req_sig, 1); + + int i; + for (i = 0; i < (int)pubkeys_chars->len; i++) { + btc_pubkey* pkey = pubkeys_chars->data[i]; + btc_script_append_pushdata(script_in, pkey->pubkey, (pkey->compressed ? BTC_ECKEY_COMPRESSED_LENGTH : BTC_ECKEY_UNCOMPRESSED_LENGTH)); + } + + enum opcodetype op_pub_len = btc_encode_op_n(pubkeys_chars->len); + cstr_append_buf(script_in, &op_pub_len, 1); + + enum opcodetype op_checkmultisig = OP_CHECKMULTISIG; + cstr_append_buf(script_in, &op_checkmultisig, 1); + + return true; +} + +btc_bool btc_script_build_p2pkh(cstring* script_in, const uint160 hash160) +{ + cstr_resize(script_in, 0); //clear script + + btc_script_append_op(script_in, OP_DUP); + btc_script_append_op(script_in, OP_HASH160); + + + btc_script_append_pushdata(script_in, (unsigned char*)hash160, sizeof(uint160)); + btc_script_append_op(script_in, OP_EQUALVERIFY); + btc_script_append_op(script_in, OP_CHECKSIG); + + return true; +} + +btc_bool btc_script_build_p2wpkh(cstring* script_in, const uint160 hash160) +{ + cstr_resize(script_in, 0); //clear script + + btc_script_append_op(script_in, OP_0); + btc_script_append_pushdata(script_in, (unsigned char*)hash160, sizeof(uint160)); + + return true; +} + +btc_bool btc_script_build_p2sh(cstring* script_in, const uint160 hash160) +{ + cstr_resize(script_in, 0); //clear script + btc_script_append_op(script_in, OP_HASH160); + btc_script_append_pushdata(script_in, (unsigned char*)hash160, sizeof(uint160)); + btc_script_append_op(script_in, OP_EQUAL); + + return true; +} + +btc_bool btc_script_get_scripthash(const cstring* script_in, uint160 scripthash) +{ + if (!script_in) { + return false; + } + uint256 hash; + btc_hash_sngl_sha256((const unsigned char *)script_in->str, script_in->len, hash); + ripemd160(hash, sizeof(hash), scripthash); + + return true; +} + +const char * btc_tx_out_type_to_str(const enum btc_tx_out_type type) { + if (type == BTC_TX_PUBKEY) { + return "TX_PUBKEY"; + } + else if (type == BTC_TX_PUBKEYHASH) { + return "TX_PUBKEYHASH"; + } + else if (type == BTC_TX_SCRIPTHASH) { + return "TX_SCRIPTHASH"; + } + else if (type == BTC_TX_MULTISIG) { + return "TX_MULTISIG"; + } + else { + return "TX_NONSTANDARD"; + } +} + +static uint8_t btc_decode_op_n(enum opcodetype op) +{ + if (op == OP_0) { + return 0; + } + assert(op >= OP_1 && op <= OP_16); + return (uint8_t)op - (uint8_t)(OP_1 - 1); +} + +// A witness program is any valid script that consists of a 1-byte push opcode +// followed by a data push between 2 and 40 bytes. +btc_bool btc_script_is_witnessprogram(const cstring* script, uint8_t* version_out, uint8_t *program_out, int *programm_len_out) +{ + if (!version_out || !program_out) { + return false; + } + if (script->len < 4 || script->len > 42) { + return false; + } + if (script->str[0] != OP_0 && (script->str[0] < OP_1 || script->str[0] > OP_16)) { + return false; + } + if ((size_t)(script->str[1] + 2) == script->len) { + *version_out = btc_decode_op_n((enum opcodetype)script->str[0]); + if (program_out) { + assert(script->len - 2 <= 40); + memcpy(program_out, script->str + 2, script->len - 2); + *programm_len_out = script->len - 2; + } + return true; + } + return false; +} diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore new file mode 100644 index 000000000..efb277d34 --- /dev/null +++ b/src/secp256k1/.gitignore @@ -0,0 +1,48 @@ +bench_inv +bench_ecdh +bench_sign +bench_verify +bench_schnorr_verify +bench_recover +bench_internal +tests +gen_context +*.exe +*.so +*.a +!.gitignore + +Makefile +configure +.libs/ +Makefile.in +aclocal.m4 +autom4te.cache/ +config.log +config.status +*.tar.gz +*.la +libtool +.deps/ +.dirstamp +*.lo +*.o +*~ +src/libsecp256k1-config.h +src/libsecp256k1-config.h.in +src/ecmult_static_context.h +build-aux/config.guess +build-aux/config.sub +build-aux/depcomp +build-aux/install-sh +build-aux/ltmain.sh +build-aux/m4/libtool.m4 +build-aux/m4/lt~obsolete.m4 +build-aux/m4/ltoptions.m4 +build-aux/m4/ltsugar.m4 +build-aux/m4/ltversion.m4 +build-aux/missing +build-aux/compile +build-aux/test-driver +src/stamp-h1 +libsecp256k1.pc diff --git a/src/secp256k1/.travis.yml b/src/secp256k1/.travis.yml new file mode 100644 index 000000000..2c5c63ada --- /dev/null +++ b/src/secp256k1/.travis.yml @@ -0,0 +1,70 @@ +language: c +sudo: false +addons: + apt: + packages: libgmp-dev +compiler: + - clang + - gcc +cache: + directories: + - src/java/guava/ +env: + global: + - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no schnorr=no RECOVERY=no EXPERIMENTAL=no + - GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar + matrix: + - SCALAR=32bit RECOVERY=yes + - SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes + - SCALAR=64bit + - FIELD=64bit RECOVERY=yes + - FIELD=64bit ENDOMORPHISM=yes + - FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes + - FIELD=64bit ASM=x86_64 + - FIELD=64bit ENDOMORPHISM=yes ASM=x86_64 + - FIELD=32bit SCHNORR=yes EXPERIMENTAL=yes + - FIELD=32bit ENDOMORPHISM=yes + - BIGNUM=no + - BIGNUM=no ENDOMORPHISM=yes SCHNORR=yes RECOVERY=yes EXPERIMENTAL=yes + - BIGNUM=no STATICPRECOMPUTATION=no + - BUILD=distcheck + - EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC + - EXTRAFLAGS=CFLAGS=-O0 + - BUILD=check-java ECDH=yes SCHNORR=yes EXPERIMENTAL=yes +matrix: + fast_finish: true + include: + - compiler: clang + env: HOST=i686-linux-gnu ENDOMORPHISM=yes + addons: + apt: + packages: + - gcc-multilib + - libgmp-dev:i386 + - compiler: clang + env: HOST=i686-linux-gnu + addons: + apt: + packages: + - gcc-multilib + - compiler: gcc + env: HOST=i686-linux-gnu ENDOMORPHISM=yes + addons: + apt: + packages: + - gcc-multilib + - compiler: gcc + env: HOST=i686-linux-gnu + addons: + apt: + packages: + - gcc-multilib + - libgmp-dev:i386 +before_install: mkdir -p `dirname $GUAVA_JAR` +install: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi +before_script: ./autogen.sh +script: + - if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi + - if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi + - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-schnorr=$SCHNORR --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD +os: linux diff --git a/src/secp256k1/COPYING b/src/secp256k1/COPYING new file mode 100644 index 000000000..4522a5990 --- /dev/null +++ b/src/secp256k1/COPYING @@ -0,0 +1,19 @@ +Copyright (c) 2013 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. diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am new file mode 100644 index 000000000..3d130bdcb --- /dev/null +++ b/src/secp256k1/Makefile.am @@ -0,0 +1,163 @@ +ACLOCAL_AMFLAGS = -I build-aux/m4 + +lib_LTLIBRARIES = libsecp256k1.la +if USE_JNI +JNI_LIB = libsecp256k1_jni.la +noinst_LTLIBRARIES = $(JNI_LIB) +else +JNI_LIB = +endif +include_HEADERS = include/secp256k1.h +noinst_HEADERS = +noinst_HEADERS += src/scalar.h +noinst_HEADERS += src/scalar_4x64.h +noinst_HEADERS += src/scalar_8x32.h +noinst_HEADERS += src/scalar_impl.h +noinst_HEADERS += src/scalar_4x64_impl.h +noinst_HEADERS += src/scalar_8x32_impl.h +noinst_HEADERS += src/group.h +noinst_HEADERS += src/group_impl.h +noinst_HEADERS += src/num_gmp.h +noinst_HEADERS += src/num_gmp_impl.h +noinst_HEADERS += src/ecdsa.h +noinst_HEADERS += src/ecdsa_impl.h +noinst_HEADERS += src/eckey.h +noinst_HEADERS += src/eckey_impl.h +noinst_HEADERS += src/ecmult.h +noinst_HEADERS += src/ecmult_impl.h +noinst_HEADERS += src/ecmult_const.h +noinst_HEADERS += src/ecmult_const_impl.h +noinst_HEADERS += src/ecmult_gen.h +noinst_HEADERS += src/ecmult_gen_impl.h +noinst_HEADERS += src/num.h +noinst_HEADERS += src/num_impl.h +noinst_HEADERS += src/field_10x26.h +noinst_HEADERS += src/field_10x26_impl.h +noinst_HEADERS += src/field_5x52.h +noinst_HEADERS += src/field_5x52_impl.h +noinst_HEADERS += src/field_5x52_int128_impl.h +noinst_HEADERS += src/field_5x52_asm_impl.h +noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h +noinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h +noinst_HEADERS += src/util.h +noinst_HEADERS += src/testrand.h +noinst_HEADERS += src/testrand_impl.h +noinst_HEADERS += src/hash.h +noinst_HEADERS += src/hash_impl.h +noinst_HEADERS += src/field.h +noinst_HEADERS += src/field_impl.h +noinst_HEADERS += src/bench.h +noinst_HEADERS += contrib/lax_der_parsing.h +noinst_HEADERS += contrib/lax_der_parsing.c +noinst_HEADERS += contrib/lax_der_privatekey_parsing.h +noinst_HEADERS += contrib/lax_der_privatekey_parsing.c + +if USE_EXTERNAL_ASM +COMMON_LIB = libsecp256k1_common.la +noinst_LTLIBRARIES = $(COMMON_LIB) +else +COMMON_LIB = +endif + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libsecp256k1.pc + +if USE_EXTERNAL_ASM +if USE_ASM_ARM +libsecp256k1_common_la_SOURCES = src/asm/field_10x26_arm.s +endif +endif + +libsecp256k1_la_SOURCES = src/secp256k1.c +libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) +libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB) + +libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c +libsecp256k1_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES) + +noinst_PROGRAMS = +if USE_BENCHMARK +noinst_PROGRAMS += bench_verify bench_sign bench_internal +bench_verify_SOURCES = src/bench_verify.c +bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) +bench_sign_SOURCES = src/bench_sign.c +bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) +bench_internal_SOURCES = src/bench_internal.c +bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB) +bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES) +endif + +if USE_TESTS +noinst_PROGRAMS += tests +tests_SOURCES = src/tests.c +tests_CPPFLAGS = -DSECP256K1_BUILD -DVERIFY -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) +tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) +tests_LDFLAGS = -static +TESTS = tests +endif + +JAVAROOT=src/java +JAVAORG=org/bitcoin +JAVA_GUAVA=$(srcdir)/$(JAVAROOT)/guava/guava-18.0.jar +CLASSPATH_ENV=CLASSPATH=$(JAVA_GUAVA) +JAVA_FILES= \ + $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1.java \ + $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Test.java \ + $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Util.java \ + $(JAVAROOT)/$(JAVAORG)/Secp256k1Context.java + +if USE_JNI + +$(JAVA_GUAVA): + @echo Guava is missing. Fetch it via: \ + wget https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar -O $(@) + @false + +.stamp-java: $(JAVA_FILES) + @echo Compiling $^ + $(AM_V_at)$(CLASSPATH_ENV) javac $^ + @touch $@ + +if USE_TESTS + +check-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java + $(AM_V_at)java -Djava.library.path="./:./src:./src/.libs:.libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test + +endif +endif + +if USE_ECMULT_STATIC_PRECOMPUTATION +CPPFLAGS_FOR_BUILD +=-I$(top_srcdir) +CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function + +gen_context_OBJECTS = gen_context.o +gen_context_BIN = gen_context$(BUILD_EXEEXT) +gen_%.o: src/gen_%.c + $(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@ + +$(gen_context_BIN): $(gen_context_OBJECTS) + $(CC_FOR_BUILD) $^ -o $@ + +$(libsecp256k1_la_OBJECTS): src/ecmult_static_context.h +$(tests_OBJECTS): src/ecmult_static_context.h +$(bench_internal_OBJECTS): src/ecmult_static_context.h + +src/ecmult_static_context.h: $(gen_context_BIN) + ./$(gen_context_BIN) + +CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java +endif + +EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h $(JAVA_FILES) + +if ENABLE_MODULE_ECDH +include src/modules/ecdh/Makefile.am.include +endif + +if ENABLE_MODULE_SCHNORR +include src/modules/schnorr/Makefile.am.include +endif + +if ENABLE_MODULE_RECOVERY +include src/modules/recovery/Makefile.am.include +endif diff --git a/src/secp256k1/README.md b/src/secp256k1/README.md new file mode 100644 index 000000000..8cd344ea8 --- /dev/null +++ b/src/secp256k1/README.md @@ -0,0 +1,61 @@ +libsecp256k1 +============ + +[![Build Status](https://travis-ci.org/bitcoin-core/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-core/secp256k1) + +Optimized C library for EC operations on curve secp256k1. + +This library is a work in progress and is being used to research best practices. Use at your own risk. + +Features: +* secp256k1 ECDSA signing/verification and key generation. +* Adding/multiplying private/public keys. +* Serialization/parsing of private keys, public keys, signatures. +* Constant time, constant memory access signing and pubkey generation. +* Derandomized DSA (via RFC6979 or with a caller provided function.) +* Very efficient implementation. + +Implementation details +---------------------- + +* General + * No runtime heap allocation. + * Extensive testing infrastructure. + * Structured to facilitate review and analysis. + * Intended to be portable to any system with a C89 compiler and uint64_t support. + * Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.") +* Field operations + * Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1). + * Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys). + * Using 10 26-bit limbs. + * Field inverses and square roots using a sliding window over blocks of 1s (by Peter Dettman). +* Scalar operations + * Optimized implementation without data-dependent branches of arithmetic modulo the curve's order. + * Using 4 64-bit limbs (relying on __int128 support in the compiler). + * Using 8 32-bit limbs. +* Group operations + * Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7). + * Use addition between points in Jacobian and affine coordinates where possible. + * Use a unified addition/doubling formula where necessary to avoid data-dependent branches. + * Point/x comparison without a field inversion by comparison in the Jacobian coordinate space. +* Point multiplication for verification (a*P + b*G). + * Use wNAF notation for point multiplicands. + * Use a much larger window for multiples of G, using precomputed multiples. + * Use Shamir's trick to do the multiplication with the public key and the generator simultaneously. + * Optionally (off by default) use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones. +* Point multiplication for signing + * Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions. + * Access the table with branch-free conditional moves so memory access is uniform. + * No data-dependent branches + * The precomputed tables add and eventually subtract points for which no known scalar (private key) is known, preventing even an attacker with control over the private key used to control the data internally. + +Build steps +----------- + +libsecp256k1 is built using autotools: + + $ ./autogen.sh + $ ./configure + $ make + $ ./tests + $ sudo make install # optional diff --git a/src/secp256k1/TODO b/src/secp256k1/TODO new file mode 100644 index 000000000..a300e1c5e --- /dev/null +++ b/src/secp256k1/TODO @@ -0,0 +1,3 @@ +* Unit tests for fieldelem/groupelem, including ones intended to + trigger fieldelem's boundary cases. +* Complete constant-time operations for signing/keygen diff --git a/src/secp256k1/autogen.sh b/src/secp256k1/autogen.sh new file mode 100755 index 000000000..65286b935 --- /dev/null +++ b/src/secp256k1/autogen.sh @@ -0,0 +1,3 @@ +#!/bin/sh +set -e +autoreconf -if --warnings=all diff --git a/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4 b/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4 new file mode 100644 index 000000000..1fc362761 --- /dev/null +++ b/src/secp256k1/build-aux/m4/ax_jni_include_dir.m4 @@ -0,0 +1,140 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_JNI_INCLUDE_DIR +# +# DESCRIPTION +# +# AX_JNI_INCLUDE_DIR finds include directories needed for compiling +# programs using the JNI interface. +# +# JNI include directories are usually in the Java distribution. This is +# deduced from the value of $JAVA_HOME, $JAVAC, or the path to "javac", in +# that order. When this macro completes, a list of directories is left in +# the variable JNI_INCLUDE_DIRS. +# +# Example usage follows: +# +# AX_JNI_INCLUDE_DIR +# +# for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS +# do +# CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR" +# done +# +# If you want to force a specific compiler: +# +# - at the configure.in level, set JAVAC=yourcompiler before calling +# AX_JNI_INCLUDE_DIR +# +# - at the configure level, setenv JAVAC +# +# Note: This macro can work with the autoconf M4 macros for Java programs. +# This particular macro is not part of the original set of macros. +# +# LICENSE +# +# Copyright (c) 2008 Don Anderson +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 10 + +AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR]) +AC_DEFUN([AX_JNI_INCLUDE_DIR],[ + +JNI_INCLUDE_DIRS="" + +if test "x$JAVA_HOME" != x; then + _JTOPDIR="$JAVA_HOME" +else + if test "x$JAVAC" = x; then + JAVAC=javac + fi + AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no]) + if test "x$_ACJNI_JAVAC" = xno; then + AC_MSG_WARN([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME]) + fi + _ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC") + _JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'` +fi + +case "$host_os" in + darwin*) _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` + _JINC="$_JTOPDIR/Headers";; + *) _JINC="$_JTOPDIR/include";; +esac +_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR]) +_AS_ECHO_LOG([_JINC=$_JINC]) + +# On Mac OS X 10.6.4, jni.h is a symlink: +# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h +# -> ../../CurrentJDK/Headers/jni.h. + +AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path, +[ +if test -f "$_JINC/jni.h"; then + ac_cv_jni_header_path="$_JINC" + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path" +else + _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` + if test -f "$_JTOPDIR/include/jni.h"; then + ac_cv_jni_header_path="$_JTOPDIR/include" + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path" + else + ac_cv_jni_header_path=none + fi +fi +]) + + + +# get the likely subdirectories for system specific java includes +case "$host_os" in +bsdi*) _JNI_INC_SUBDIRS="bsdos";; +darwin*) _JNI_INC_SUBDIRS="darwin";; +freebsd*) _JNI_INC_SUBDIRS="freebsd";; +linux*) _JNI_INC_SUBDIRS="linux genunix";; +osf*) _JNI_INC_SUBDIRS="alpha";; +solaris*) _JNI_INC_SUBDIRS="solaris";; +mingw*) _JNI_INC_SUBDIRS="win32";; +cygwin*) _JNI_INC_SUBDIRS="win32";; +*) _JNI_INC_SUBDIRS="genunix";; +esac + +if test "x$ac_cv_jni_header_path" != "xnone"; then + # add any subdirectories that are present + for JINCSUBDIR in $_JNI_INC_SUBDIRS + do + if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR" + fi + done +fi +]) + +# _ACJNI_FOLLOW_SYMLINKS +# Follows symbolic links on , +# finally setting variable _ACJNI_FOLLOWED +# ---------------------------------------- +AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[ +# find the include directory relative to the javac executable +_cur="$1" +while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do + AC_MSG_CHECKING([symlink for $_cur]) + _slink=`ls -ld "$_cur" | sed 's/.* -> //'` + case "$_slink" in + /*) _cur="$_slink";; + # 'X' avoids triggering unwanted echo options. + *) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";; + esac + AC_MSG_RESULT([$_cur]) +done +_ACJNI_FOLLOWED="$_cur" +])# _ACJNI diff --git a/src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 b/src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 new file mode 100644 index 000000000..77fd346a7 --- /dev/null +++ b/src/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 @@ -0,0 +1,125 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_prog_cc_for_build.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PROG_CC_FOR_BUILD +# +# DESCRIPTION +# +# This macro searches for a C compiler that generates native executables, +# that is a C compiler that surely is not a cross-compiler. This can be +# useful if you have to generate source code at compile-time like for +# example GCC does. +# +# The macro sets the CC_FOR_BUILD and CPP_FOR_BUILD macros to anything +# needed to compile or link (CC_FOR_BUILD) and preprocess (CPP_FOR_BUILD). +# The value of these variables can be overridden by the user by specifying +# a compiler with an environment variable (like you do for standard CC). +# +# It also sets BUILD_EXEEXT and BUILD_OBJEXT to the executable and object +# file extensions for the build platform, and GCC_FOR_BUILD to `yes' if +# the compiler we found is GCC. All these variables but GCC_FOR_BUILD are +# substituted in the Makefile. +# +# LICENSE +# +# Copyright (c) 2008 Paolo Bonzini +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 8 + +AU_ALIAS([AC_PROG_CC_FOR_BUILD], [AX_PROG_CC_FOR_BUILD]) +AC_DEFUN([AX_PROG_CC_FOR_BUILD], [dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_CPP])dnl +AC_REQUIRE([AC_EXEEXT])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl + +dnl Use the standard macros, but make them use other variable names +dnl +pushdef([ac_cv_prog_CPP], ac_cv_build_prog_CPP)dnl +pushdef([ac_cv_prog_gcc], ac_cv_build_prog_gcc)dnl +pushdef([ac_cv_prog_cc_works], ac_cv_build_prog_cc_works)dnl +pushdef([ac_cv_prog_cc_cross], ac_cv_build_prog_cc_cross)dnl +pushdef([ac_cv_prog_cc_g], ac_cv_build_prog_cc_g)dnl +pushdef([ac_cv_exeext], ac_cv_build_exeext)dnl +pushdef([ac_cv_objext], ac_cv_build_objext)dnl +pushdef([ac_exeext], ac_build_exeext)dnl +pushdef([ac_objext], ac_build_objext)dnl +pushdef([CC], CC_FOR_BUILD)dnl +pushdef([CPP], CPP_FOR_BUILD)dnl +pushdef([CFLAGS], CFLAGS_FOR_BUILD)dnl +pushdef([CPPFLAGS], CPPFLAGS_FOR_BUILD)dnl +pushdef([LDFLAGS], LDFLAGS_FOR_BUILD)dnl +pushdef([host], build)dnl +pushdef([host_alias], build_alias)dnl +pushdef([host_cpu], build_cpu)dnl +pushdef([host_vendor], build_vendor)dnl +pushdef([host_os], build_os)dnl +pushdef([ac_cv_host], ac_cv_build)dnl +pushdef([ac_cv_host_alias], ac_cv_build_alias)dnl +pushdef([ac_cv_host_cpu], ac_cv_build_cpu)dnl +pushdef([ac_cv_host_vendor], ac_cv_build_vendor)dnl +pushdef([ac_cv_host_os], ac_cv_build_os)dnl +pushdef([ac_cpp], ac_build_cpp)dnl +pushdef([ac_compile], ac_build_compile)dnl +pushdef([ac_link], ac_build_link)dnl + +save_cross_compiling=$cross_compiling +save_ac_tool_prefix=$ac_tool_prefix +cross_compiling=no +ac_tool_prefix= + +AC_PROG_CC +AC_PROG_CPP +AC_EXEEXT + +ac_tool_prefix=$save_ac_tool_prefix +cross_compiling=$save_cross_compiling + +dnl Restore the old definitions +dnl +popdef([ac_link])dnl +popdef([ac_compile])dnl +popdef([ac_cpp])dnl +popdef([ac_cv_host_os])dnl +popdef([ac_cv_host_vendor])dnl +popdef([ac_cv_host_cpu])dnl +popdef([ac_cv_host_alias])dnl +popdef([ac_cv_host])dnl +popdef([host_os])dnl +popdef([host_vendor])dnl +popdef([host_cpu])dnl +popdef([host_alias])dnl +popdef([host])dnl +popdef([LDFLAGS])dnl +popdef([CPPFLAGS])dnl +popdef([CFLAGS])dnl +popdef([CPP])dnl +popdef([CC])dnl +popdef([ac_objext])dnl +popdef([ac_exeext])dnl +popdef([ac_cv_objext])dnl +popdef([ac_cv_exeext])dnl +popdef([ac_cv_prog_cc_g])dnl +popdef([ac_cv_prog_cc_cross])dnl +popdef([ac_cv_prog_cc_works])dnl +popdef([ac_cv_prog_gcc])dnl +popdef([ac_cv_prog_CPP])dnl + +dnl Finally, set Makefile variables +dnl +BUILD_EXEEXT=$ac_build_exeext +BUILD_OBJEXT=$ac_build_objext +AC_SUBST(BUILD_EXEEXT)dnl +AC_SUBST(BUILD_OBJEXT)dnl +AC_SUBST([CFLAGS_FOR_BUILD])dnl +AC_SUBST([CPPFLAGS_FOR_BUILD])dnl +AC_SUBST([LDFLAGS_FOR_BUILD])dnl +]) diff --git a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4 new file mode 100644 index 000000000..b25d8adb9 --- /dev/null +++ b/src/secp256k1/build-aux/m4/bitcoin_secp.m4 @@ -0,0 +1,65 @@ +dnl libsecp25k1 helper checks +AC_DEFUN([SECP_INT128_CHECK],[ +has_int128=$ac_cv_type___int128 +]) + +dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell. +AC_DEFUN([SECP_64BIT_ASM_CHECK],[ +AC_MSG_CHECKING(for x86_64 assembly availability) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include ]],[[ + uint64_t a = 11, tmp; + __asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx"); + ]])],[has_64bit_asm=yes],[has_64bit_asm=no]) +AC_MSG_RESULT([$has_64bit_asm]) +]) + +dnl +AC_DEFUN([SECP_OPENSSL_CHECK],[ + has_libcrypto=no + m4_ifdef([PKG_CHECK_MODULES],[ + PKG_CHECK_MODULES([CRYPTO], [libcrypto], [has_libcrypto=yes],[has_libcrypto=no]) + if test x"$has_libcrypto" = x"yes"; then + TEMP_LIBS="$LIBS" + LIBS="$LIBS $CRYPTO_LIBS" + AC_CHECK_LIB(crypto, main,[AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])],[has_libcrypto=no]) + LIBS="$TEMP_LIBS" + fi + ]) + if test x$has_libcrypto = xno; then + AC_CHECK_HEADER(openssl/crypto.h,[ + AC_CHECK_LIB(crypto, main,[ + has_libcrypto=yes + CRYPTO_LIBS=-lcrypto + AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed]) + ]) + ]) + LIBS= + fi +if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then + AC_MSG_CHECKING(for EC functions in libcrypto) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #include + #include ]],[[ + EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp256k1); + ECDSA_sign(0, NULL, 0, NULL, NULL, eckey); + ECDSA_verify(0, NULL, 0, NULL, 0, eckey); + EC_KEY_free(eckey); + ]])],[has_openssl_ec=yes],[has_openssl_ec=no]) + AC_MSG_RESULT([$has_openssl_ec]) +fi +]) + +dnl +AC_DEFUN([SECP_GMP_CHECK],[ +if test x"$has_gmp" != x"yes"; then + CPPFLAGS_TEMP="$CPPFLAGS" + CPPFLAGS="$GMP_CPPFLAGS $CPPFLAGS" + LIBS_TEMP="$LIBS" + LIBS="$GMP_LIBS $LIBS" + AC_CHECK_HEADER(gmp.h,[AC_CHECK_LIB(gmp, __gmpz_init,[has_gmp=yes; GMP_LIBS="$GMP_LIBS -lgmp"; AC_DEFINE(HAVE_LIBGMP,1,[Define this symbol if libgmp is installed])])]) + CPPFLAGS="$CPPFLAGS_TEMP" + LIBS="$LIBS_TEMP" +fi +]) diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac new file mode 100644 index 000000000..0743c3669 --- /dev/null +++ b/src/secp256k1/configure.ac @@ -0,0 +1,490 @@ +AC_PREREQ([2.60]) +AC_INIT([libsecp256k1],[0.1]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_MACRO_DIR([build-aux/m4]) +AC_CANONICAL_HOST +AH_TOP([#ifndef LIBSECP256K1_CONFIG_H]) +AH_TOP([#define LIBSECP256K1_CONFIG_H]) +AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/]) +AM_INIT_AUTOMAKE([foreign subdir-objects]) +LT_INIT + +dnl make the compilation flags quiet unless V=1 is used +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +PKG_PROG_PKG_CONFIG + +AC_PATH_TOOL(AR, ar) +AC_PATH_TOOL(RANLIB, ranlib) +AC_PATH_TOOL(STRIP, strip) +AX_PROG_CC_FOR_BUILD + +if test "x$CFLAGS" = "x"; then + CFLAGS="-O3 -g" +fi + +AM_PROG_CC_C_O + +AC_PROG_CC_C89 +if test x"$ac_cv_prog_cc_c89" = x"no"; then + AC_MSG_ERROR([c89 compiler support required]) +fi +AM_PROG_AS + +case $host_os in + *darwin*) + if test x$cross_compiling != xyes; then + AC_PATH_PROG([BREW],brew,) + if test x$BREW != x; then + dnl These Homebrew packages may be keg-only, meaning that they won't be found + dnl in expected paths because they may conflict with system files. Ask + dnl Homebrew where each one is located, then adjust paths accordingly. + + openssl_prefix=`$BREW --prefix openssl 2>/dev/null` + gmp_prefix=`$BREW --prefix gmp 2>/dev/null` + if test x$openssl_prefix != x; then + PKG_CONFIG_PATH="$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH" + export PKG_CONFIG_PATH + fi + if test x$gmp_prefix != x; then + GMP_CPPFLAGS="-I$gmp_prefix/include" + GMP_LIBS="-L$gmp_prefix/lib" + fi + else + AC_PATH_PROG([PORT],port,) + dnl if homebrew isn't installed and macports is, add the macports default paths + dnl as a last resort. + if test x$PORT != x; then + CPPFLAGS="$CPPFLAGS -isystem /opt/local/include" + LDFLAGS="$LDFLAGS -L/opt/local/lib" + fi + fi + fi + ;; +esac + +CFLAGS="$CFLAGS -W" + +warn_CFLAGS="-std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wno-unused-function -Wno-long-long -Wno-overlength-strings" +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $warn_CFLAGS" +AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], + [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS" + ]) + +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -fvisibility=hidden" +AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], + [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS" + ]) + +AC_ARG_ENABLE(benchmark, + AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is no)]), + [use_benchmark=$enableval], + [use_benchmark=no]) + +AC_ARG_ENABLE(tests, + AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]), + [use_tests=$enableval], + [use_tests=yes]) + +AC_ARG_ENABLE(openssl_tests, + AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests, if OpenSSL is available (default is auto)]), + [enable_openssl_tests=$enableval], + [enable_openssl_tests=auto]) + +AC_ARG_ENABLE(experimental, + AS_HELP_STRING([--enable-experimental],[allow experimental configure options (default is no)]), + [use_experimental=$enableval], + [use_experimental=no]) + +AC_ARG_ENABLE(endomorphism, + AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]), + [use_endomorphism=$enableval], + [use_endomorphism=no]) + +AC_ARG_ENABLE(ecmult_static_precomputation, + AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]), + [use_ecmult_static_precomputation=$enableval], + [use_ecmult_static_precomputation=auto]) + +AC_ARG_ENABLE(module_ecdh, + AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (experimental)]), + [enable_module_ecdh=$enableval], + [enable_module_ecdh=no]) + +AC_ARG_ENABLE(module_schnorr, + AS_HELP_STRING([--enable-module-schnorr],[enable Schnorr signature module (experimental)]), + [enable_module_schnorr=$enableval], + [enable_module_schnorr=no]) + +AC_ARG_ENABLE(module_recovery, + AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]), + [enable_module_recovery=$enableval], + [enable_module_recovery=no]) + +AC_ARG_ENABLE(jni, + AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]), + [use_jni=$enableval], + [use_jni=auto]) + +AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto], +[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto]) + +AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto], +[Specify Bignum Implementation. Default is auto])],[req_bignum=$withval], [req_bignum=auto]) + +AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto], +[Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto]) + +AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto] +[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[req_asm=$withval], [req_asm=auto]) + +AC_CHECK_TYPES([__int128]) + +AC_MSG_CHECKING([for __builtin_expect]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])], + [ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_EXPECT,1,[Define this symbol if __builtin_expect is available]) ], + [ AC_MSG_RESULT([no]) + ]) + +if test x"$use_ecmult_static_precomputation" != x"no"; then + save_cross_compiling=$cross_compiling + cross_compiling=no + TEMP_CC="$CC" + CC="$CC_FOR_BUILD" + AC_MSG_CHECKING([native compiler: ${CC_FOR_BUILD}]) + AC_RUN_IFELSE( + [AC_LANG_PROGRAM([], [return 0])], + [working_native_cc=yes], + [working_native_cc=no],[dnl]) + CC="$TEMP_CC" + cross_compiling=$save_cross_compiling + + if test x"$working_native_cc" = x"no"; then + set_precomp=no + if test x"$use_ecmult_static_precomputation" = x"yes"; then + AC_MSG_ERROR([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD]) + else + AC_MSG_RESULT([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD]) + fi + else + AC_MSG_RESULT([ok]) + set_precomp=yes + fi +else + set_precomp=no +fi + +if test x"$req_asm" = x"auto"; then + SECP_64BIT_ASM_CHECK + if test x"$has_64bit_asm" = x"yes"; then + set_asm=x86_64 + fi + if test x"$set_asm" = x; then + set_asm=no + fi +else + set_asm=$req_asm + case $set_asm in + x86_64) + SECP_64BIT_ASM_CHECK + if test x"$has_64bit_asm" != x"yes"; then + AC_MSG_ERROR([x86_64 assembly optimization requested but not available]) + fi + ;; + arm) + ;; + no) + ;; + *) + AC_MSG_ERROR([invalid assembly optimization selection]) + ;; + esac +fi + +if test x"$req_field" = x"auto"; then + if test x"set_asm" = x"x86_64"; then + set_field=64bit + fi + if test x"$set_field" = x; then + SECP_INT128_CHECK + if test x"$has_int128" = x"yes"; then + set_field=64bit + fi + fi + if test x"$set_field" = x; then + set_field=32bit + fi +else + set_field=$req_field + case $set_field in + 64bit) + if test x"$set_asm" != x"x86_64"; then + SECP_INT128_CHECK + if test x"$has_int128" != x"yes"; then + AC_MSG_ERROR([64bit field explicitly requested but neither __int128 support or x86_64 assembly available]) + fi + fi + ;; + 32bit) + ;; + *) + AC_MSG_ERROR([invalid field implementation selection]) + ;; + esac +fi + +if test x"$req_scalar" = x"auto"; then + SECP_INT128_CHECK + if test x"$has_int128" = x"yes"; then + set_scalar=64bit + fi + if test x"$set_scalar" = x; then + set_scalar=32bit + fi +else + set_scalar=$req_scalar + case $set_scalar in + 64bit) + SECP_INT128_CHECK + if test x"$has_int128" != x"yes"; then + AC_MSG_ERROR([64bit scalar explicitly requested but __int128 support not available]) + fi + ;; + 32bit) + ;; + *) + AC_MSG_ERROR([invalid scalar implementation selected]) + ;; + esac +fi + +if test x"$req_bignum" = x"auto"; then + SECP_GMP_CHECK + if test x"$has_gmp" = x"yes"; then + set_bignum=gmp + fi + + if test x"$set_bignum" = x; then + set_bignum=no + fi +else + set_bignum=$req_bignum + case $set_bignum in + gmp) + SECP_GMP_CHECK + if test x"$has_gmp" != x"yes"; then + AC_MSG_ERROR([gmp bignum explicitly requested but libgmp not available]) + fi + ;; + no) + ;; + *) + AC_MSG_ERROR([invalid bignum implementation selection]) + ;; + esac +fi + +# select assembly optimization +use_external_asm=no + +case $set_asm in +x86_64) + AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations]) + ;; +arm) + use_external_asm=yes + ;; +no) + ;; +*) + AC_MSG_ERROR([invalid assembly optimizations]) + ;; +esac + +# select field implementation +case $set_field in +64bit) + AC_DEFINE(USE_FIELD_5X52, 1, [Define this symbol to use the FIELD_5X52 implementation]) + ;; +32bit) + AC_DEFINE(USE_FIELD_10X26, 1, [Define this symbol to use the FIELD_10X26 implementation]) + ;; +*) + AC_MSG_ERROR([invalid field implementation]) + ;; +esac + +# select bignum implementation +case $set_bignum in +gmp) + AC_DEFINE(HAVE_LIBGMP, 1, [Define this symbol if libgmp is installed]) + AC_DEFINE(USE_NUM_GMP, 1, [Define this symbol to use the gmp implementation for num]) + AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation]) + AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation]) + ;; +no) + AC_DEFINE(USE_NUM_NONE, 1, [Define this symbol to use no num implementation]) + AC_DEFINE(USE_FIELD_INV_BUILTIN, 1, [Define this symbol to use the native field inverse implementation]) + AC_DEFINE(USE_SCALAR_INV_BUILTIN, 1, [Define this symbol to use the native scalar inverse implementation]) + ;; +*) + AC_MSG_ERROR([invalid bignum implementation]) + ;; +esac + +#select scalar implementation +case $set_scalar in +64bit) + AC_DEFINE(USE_SCALAR_4X64, 1, [Define this symbol to use the 4x64 scalar implementation]) + ;; +32bit) + AC_DEFINE(USE_SCALAR_8X32, 1, [Define this symbol to use the 8x32 scalar implementation]) + ;; +*) + AC_MSG_ERROR([invalid scalar implementation]) + ;; +esac + +if test x"$use_tests" = x"yes"; then + SECP_OPENSSL_CHECK + if test x"$has_openssl_ec" = x"yes"; then + if test x"$enable_openssl_tests" != x"no"; then + AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available]) + SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS" + SECP_TEST_LIBS="$CRYPTO_LIBS" + + case $host in + *mingw*) + SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32" + ;; + esac + fi + else + if test x"$enable_openssl_tests" = x"yes"; then + AC_MSG_ERROR([OpenSSL tests requested but OpenSSL with EC support is not available]) + fi + fi +else + if test x"$enable_openssl_tests" = x"yes"; then + AC_MSG_ERROR([OpenSSL tests requested but tests are not enabled]) + fi +fi + +if test x"$use_jni" != x"no"; then + AX_JNI_INCLUDE_DIR + have_jni_dependencies=yes + if test x"$enable_module_schnorr" = x"no"; then + have_jni_dependencies=no + fi + if test x"$enable_module_ecdh" = x"no"; then + have_jni_dependencies=no + fi + if test "x$JNI_INCLUDE_DIRS" = "x"; then + have_jni_dependencies=no + fi + if test "x$have_jni_dependencies" = "xno"; then + if test x"$use_jni" = x"yes"; then + AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and Schnorr and try again.]) + fi + AC_MSG_WARN([jni headers/dependencies not found. jni support disabled]) + use_jni=no + else + use_jni=yes + for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do + JNI_INCLUDES="$JNI_INCLUDES -I$JNI_INCLUDE_DIR" + done + fi +fi + +if test x"$set_bignum" = x"gmp"; then + SECP_LIBS="$SECP_LIBS $GMP_LIBS" + SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS" +fi + +if test x"$use_endomorphism" = x"yes"; then + AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization]) +fi + +if test x"$use_ecmult_static_precomputation" = x"yes"; then + AC_DEFINE(USE_ECMULT_STATIC_PRECOMPUTATION, 1, [Define this symbol to use a statically generated ecmult table]) +fi + +if test x"$enable_module_ecdh" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module]) +fi + +if test x"$enable_module_schnorr" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_SCHNORR, 1, [Define this symbol to enable the Schnorr signature module]) +fi + +if test x"$enable_module_recovery" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module]) +fi + +AC_C_BIGENDIAN() + +if test x"$use_external_asm" = x"yes"; then + AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used]) +fi + +AC_MSG_NOTICE([Using static precomputation: $set_precomp]) +AC_MSG_NOTICE([Using assembly optimizations: $set_asm]) +AC_MSG_NOTICE([Using field implementation: $set_field]) +AC_MSG_NOTICE([Using bignum implementation: $set_bignum]) +AC_MSG_NOTICE([Using scalar implementation: $set_scalar]) +AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism]) +AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) +AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr]) +AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery]) +AC_MSG_NOTICE([Using jni: $use_jni]) + +if test x"$enable_experimental" = x"yes"; then + AC_MSG_NOTICE([******]) + AC_MSG_NOTICE([WARNING: experimental build]) + AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.]) + AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) + AC_MSG_NOTICE([Building Schnorr signatures module: $enable_module_schnorr]) + AC_MSG_NOTICE([******]) +else + if test x"$enable_module_schnorr" = x"yes"; then + AC_MSG_ERROR([Schnorr signature module is experimental. Use --enable-experimental to allow.]) + fi + if test x"$enable_module_ecdh" = x"yes"; then + AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.]) + fi + if test x"$set_asm" = x"arm"; then + AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.]) + fi +fi + +AC_CONFIG_HEADERS([src/libsecp256k1-config.h]) +AC_CONFIG_FILES([Makefile libsecp256k1.pc]) +AC_SUBST(JNI_INCLUDES) +AC_SUBST(SECP_INCLUDES) +AC_SUBST(SECP_LIBS) +AC_SUBST(SECP_TEST_LIBS) +AC_SUBST(SECP_TEST_INCLUDES) +AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"]) +AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"]) +AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$use_ecmult_static_precomputation" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_SCHNORR], [test x"$enable_module_schnorr" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) +AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"]) +AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"]) +AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"]) + +dnl make sure nothing new is exported so that we don't break the cache +PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH" +unset PKG_CONFIG_PATH +PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP" + +AC_OUTPUT diff --git a/src/secp256k1/contrib/lax_der_parsing.c b/src/secp256k1/contrib/lax_der_parsing.c new file mode 100644 index 000000000..5b141a994 --- /dev/null +++ b/src/secp256k1/contrib/lax_der_parsing.c @@ -0,0 +1,150 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "lax_der_parsing.h" + +int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { + size_t rpos, rlen, spos, slen; + size_t pos = 0; + size_t lenbyte; + unsigned char tmpsig[64] = {0}; + int overflow = 0; + + /* Hack to initialize sig with a correctly-parsed but invalid signature. */ + secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + + /* Sequence tag byte */ + if (pos == inputlen || input[pos] != 0x30) { + return 0; + } + pos++; + + /* Sequence length bytes */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + pos += lenbyte; + } + + /* Integer tag byte for R */ + if (pos == inputlen || input[pos] != 0x02) { + return 0; + } + pos++; + + /* Integer length for R */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + while (lenbyte > 0 && input[pos] == 0) { + pos++; + lenbyte--; + } + if (lenbyte >= sizeof(size_t)) { + return 0; + } + rlen = 0; + while (lenbyte > 0) { + rlen = (rlen << 8) + input[pos]; + pos++; + lenbyte--; + } + } else { + rlen = lenbyte; + } + if (rlen > inputlen - pos) { + return 0; + } + rpos = pos; + pos += rlen; + + /* Integer tag byte for S */ + if (pos == inputlen || input[pos] != 0x02) { + return 0; + } + pos++; + + /* Integer length for S */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + while (lenbyte > 0 && input[pos] == 0) { + pos++; + lenbyte--; + } + if (lenbyte >= sizeof(size_t)) { + return 0; + } + slen = 0; + while (lenbyte > 0) { + slen = (slen << 8) + input[pos]; + pos++; + lenbyte--; + } + } else { + slen = lenbyte; + } + if (slen > inputlen - pos) { + return 0; + } + spos = pos; + pos += slen; + + /* Ignore leading zeroes in R */ + while (rlen > 0 && input[rpos] == 0) { + rlen--; + rpos++; + } + /* Copy R value */ + if (rlen > 32) { + overflow = 1; + } else { + memcpy(tmpsig + 32 - rlen, input + rpos, rlen); + } + + /* Ignore leading zeroes in S */ + while (slen > 0 && input[spos] == 0) { + slen--; + spos++; + } + /* Copy S value */ + if (slen > 32) { + overflow = 1; + } else { + memcpy(tmpsig + 64 - slen, input + spos, slen); + } + + if (!overflow) { + overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + } + if (overflow) { + memset(tmpsig, 0, 64); + secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + } + return 1; +} + diff --git a/src/secp256k1/contrib/lax_der_parsing.h b/src/secp256k1/contrib/lax_der_parsing.h new file mode 100644 index 000000000..6d27871a7 --- /dev/null +++ b/src/secp256k1/contrib/lax_der_parsing.h @@ -0,0 +1,91 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +/**** + * Please do not link this file directly. It is not part of the libsecp256k1 + * project and does not promise any stability in its API, functionality or + * presence. Projects which use this code should instead copy this header + * and its accompanying .c file directly into their codebase. + ****/ + +/* This file defines a function that parses DER with various errors and + * violations. This is not a part of the library itself, because the allowed + * violations are chosen arbitrarily and do not follow or establish any + * standard. + * + * In many places it matters that different implementations do not only accept + * the same set of valid signatures, but also reject the same set of signatures. + * The only means to accomplish that is by strictly obeying a standard, and not + * accepting anything else. + * + * Nonetheless, sometimes there is a need for compatibility with systems that + * use signatures which do not strictly obey DER. The snippet below shows how + * certain violations are easily supported. You may need to adapt it. + * + * Do not use this for new systems. Use well-defined DER or compact signatures + * instead if you have the choice (see secp256k1_ecdsa_signature_parse_der and + * secp256k1_ecdsa_signature_parse_compact). + * + * The supported violations are: + * - All numbers are parsed as nonnegative integers, even though X.609-0207 + * section 8.3.3 specifies that integers are always encoded as two's + * complement. + * - Integers can have length 0, even though section 8.3.1 says they can't. + * - Integers with overly long padding are accepted, violation section + * 8.3.2. + * - 127-byte long length descriptors are accepted, even though section + * 8.1.3.5.c says that they are not. + * - Trailing garbage data inside or after the signature is ignored. + * - The length descriptor of the sequence is ignored. + * + * Compared to for example OpenSSL, many violations are NOT supported: + * - Using overly long tag descriptors for the sequence or integers inside, + * violating section 8.1.2.2. + * - Encoding primitive integers as constructed values, violating section + * 8.3.1. + */ + +#ifndef _SECP256K1_CONTRIB_LAX_DER_PARSING_H_ +#define _SECP256K1_CONTRIB_LAX_DER_PARSING_H_ + +#include + +# ifdef __cplusplus +extern "C" { +# endif + +/** Parse a signature in "lax DER" format + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input: a pointer to the signature to be parsed + * inputlen: the length of the array pointed to be input + * + * This function will accept any valid DER encoded signature, even if the + * encoded numbers are out of range. In addition, it will accept signatures + * which violate the DER spec in various ways. Its purpose is to allow + * validation of the Bitcoin blockchain, which includes non-DER signatures + * from before the network rules were updated to enforce DER. Note that + * the set of supported violations is a strict subset of what OpenSSL will + * accept. + * + * After the call, sig will always be initialized. If parsing failed or the + * encoded numbers are out of range, signature validation with it is + * guaranteed to fail for every message and public key. + */ +int ecdsa_signature_parse_der_lax( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature* sig, + const unsigned char *input, + size_t inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/secp256k1/contrib/lax_der_privatekey_parsing.c b/src/secp256k1/contrib/lax_der_privatekey_parsing.c new file mode 100644 index 000000000..c2e63b4b8 --- /dev/null +++ b/src/secp256k1/contrib/lax_der_privatekey_parsing.c @@ -0,0 +1,113 @@ +/********************************************************************** + * Copyright (c) 2014, 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "lax_der_privatekey_parsing.h" + +int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) { + const unsigned char *end = privkey + privkeylen; + int lenb = 0; + int len = 0; + memset(out32, 0, 32); + /* sequence header */ + if (end < privkey+1 || *privkey != 0x30) { + return 0; + } + privkey++; + /* sequence length constructor */ + if (end < privkey+1 || !(*privkey & 0x80)) { + return 0; + } + lenb = *privkey & ~0x80; privkey++; + if (lenb < 1 || lenb > 2) { + return 0; + } + if (end < privkey+lenb) { + return 0; + } + /* sequence length */ + len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0); + privkey += lenb; + if (end < privkey+len) { + return 0; + } + /* sequence element 0: version number (=1) */ + if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) { + return 0; + } + privkey += 3; + /* sequence element 1: octet string, up to 32 bytes */ + if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) { + return 0; + } + memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]); + if (!secp256k1_ec_seckey_verify(ctx, out32)) { + memset(out32, 0, 32); + return 0; + } + return 1; +} + +int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) { + secp256k1_pubkey pubkey; + size_t pubkeylen = 0; + if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) { + *privkeylen = 0; + return 0; + } + if (compressed) { + static const unsigned char begin[] = { + 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20 + }; + static const unsigned char middle[] = { + 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, + 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, + 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, + 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, + 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, + 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00 + }; + unsigned char *ptr = privkey; + memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); + memcpy(ptr, key32, 32); ptr += 32; + memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); + pubkeylen = 33; + secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED); + ptr += pubkeylen; + *privkeylen = ptr - privkey; + } else { + static const unsigned char begin[] = { + 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20 + }; + static const unsigned char middle[] = { + 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, + 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, + 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, + 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, + 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11, + 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10, + 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, + 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00 + }; + unsigned char *ptr = privkey; + memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); + memcpy(ptr, key32, 32); ptr += 32; + memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); + pubkeylen = 65; + secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED); + ptr += pubkeylen; + *privkeylen = ptr - privkey; + } + return 1; +} diff --git a/src/secp256k1/contrib/lax_der_privatekey_parsing.h b/src/secp256k1/contrib/lax_der_privatekey_parsing.h new file mode 100644 index 000000000..2fd088f8a --- /dev/null +++ b/src/secp256k1/contrib/lax_der_privatekey_parsing.h @@ -0,0 +1,90 @@ +/********************************************************************** + * Copyright (c) 2014, 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +/**** + * Please do not link this file directly. It is not part of the libsecp256k1 + * project and does not promise any stability in its API, functionality or + * presence. Projects which use this code should instead copy this header + * and its accompanying .c file directly into their codebase. + ****/ + +/* This file contains code snippets that parse DER private keys with + * various errors and violations. This is not a part of the library + * itself, because the allowed violations are chosen arbitrarily and + * do not follow or establish any standard. + * + * It also contains code to serialize private keys in a compatible + * manner. + * + * These functions are meant for compatibility with applications + * that require BER encoded keys. When working with secp256k1-specific + * code, the simple 32-byte private keys normally used by the + * library are sufficient. + */ + +#ifndef _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_ +#define _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_ + +#include + +# ifdef __cplusplus +extern "C" { +# endif + +/** Export a private key in DER format. + * + * Returns: 1 if the private key was valid. + * Args: ctx: pointer to a context object, initialized for signing (cannot + * be NULL) + * Out: privkey: pointer to an array for storing the private key in BER. + * Should have space for 279 bytes, and cannot be NULL. + * privkeylen: Pointer to an int where the length of the private key in + * privkey will be stored. + * In: seckey: pointer to a 32-byte secret key to export. + * compressed: 1 if the key should be exported in + * compressed format, 0 otherwise + * + * This function is purely meant for compatibility with applications that + * require BER encoded keys. When working with secp256k1-specific code, the + * simple 32-byte private keys are sufficient. + * + * Note that this function does not guarantee correct DER output. It is + * guaranteed to be parsable by secp256k1_ec_privkey_import_der + */ +SECP256K1_WARN_UNUSED_RESULT int ec_privkey_export_der( + const secp256k1_context* ctx, + unsigned char *privkey, + size_t *privkeylen, + const unsigned char *seckey, + int compressed +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Import a private key in DER format. + * Returns: 1 if a private key was extracted. + * Args: ctx: pointer to a context object (cannot be NULL). + * Out: seckey: pointer to a 32-byte array for storing the private key. + * (cannot be NULL). + * In: privkey: pointer to a private key in DER format (cannot be NULL). + * privkeylen: length of the DER private key pointed to be privkey. + * + * This function will accept more than just strict DER, and even allow some BER + * violations. The public key stored inside the DER-encoded private key is not + * verified for correctness, nor are the curve parameters. Use this function + * only if you know in advance it is supposed to contain a secp256k1 private + * key. + */ +SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der( + const secp256k1_context* ctx, + unsigned char *seckey, + const unsigned char *privkey, + size_t privkeylen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h new file mode 100644 index 000000000..7145dbcc5 --- /dev/null +++ b/src/secp256k1/include/secp256k1.h @@ -0,0 +1,583 @@ +#ifndef _SECP256K1_ +# define _SECP256K1_ + +# ifdef __cplusplus +extern "C" { +# endif + +#include + +/* These rules specify the order of arguments in API calls: + * + * 1. Context pointers go first, followed by output arguments, combined + * output/input arguments, and finally input-only arguments. + * 2. Array lengths always immediately the follow the argument whose length + * they describe, even if this violates rule 1. + * 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated + * later go first. This means: signatures, public nonces, private nonces, + * messages, public keys, secret keys, tweaks. + * 4. Arguments that are not data pointers go last, from more complex to less + * complex: function pointers, algorithm names, messages, void pointers, + * counts, flags, booleans. + * 5. Opaque data pointers follow the function pointer they are to be passed to. + */ + +/** Opaque data structure that holds context information (precomputed tables etc.). + * + * The purpose of context structures is to cache large precomputed data tables + * that are expensive to construct, and also to maintain the randomization data + * for blinding. + * + * Do not create a new context object for each operation, as construction is + * far slower than all other API calls (~100 times slower than an ECDSA + * verification). + * + * A constructed context can safely be used from multiple threads + * simultaneously, but API call that take a non-const pointer to a context + * need exclusive access to it. In particular this is the case for + * secp256k1_context_destroy and secp256k1_context_randomize. + * + * Regarding randomization, either do it once at creation time (in which case + * you do not need any locking for the other calls), or use a read-write lock. + */ +typedef struct secp256k1_context_struct secp256k1_context; + +/** Opaque data structure that holds a parsed and valid public key. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage or transmission, use + * secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. + * + * Furthermore, it is guaranteed that identical public keys (ignoring + * compression) will have identical representation, so they can be memcmp'ed. + */ +typedef struct { + unsigned char data[64]; +} secp256k1_pubkey; + +/** Opaque data structured that holds a parsed ECDSA signature. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage or transmission, use + * the secp256k1_ecdsa_signature_serialize_* and + * secp256k1_ecdsa_signature_serialize_* functions. + * + * Furthermore, it is guaranteed to identical signatures will have identical + * representation, so they can be memcmp'ed. + */ +typedef struct { + unsigned char data[64]; +} secp256k1_ecdsa_signature; + +/** A pointer to a function to deterministically generate a nonce. + * + * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail. + * Out: nonce32: pointer to a 32-byte array to be filled by the function. + * In: msg32: the 32-byte message hash being verified (will not be NULL) + * key32: pointer to a 32-byte secret key (will not be NULL) + * algo16: pointer to a 16-byte array describing the signature + * algorithm (will be NULL for ECDSA for compatibility). + * data: Arbitrary data pointer that is passed through. + * attempt: how many iterations we have tried to find a nonce. + * This will almost always be 0, but different attempt values + * are required to result in a different nonce. + * + * Except for test cases, this function should compute some cryptographic hash of + * the message, the algorithm, the key and the attempt. + */ +typedef int (*secp256k1_nonce_function)( + unsigned char *nonce32, + const unsigned char *msg32, + const unsigned char *key32, + const unsigned char *algo16, + void *data, + unsigned int attempt +); + +# if !defined(SECP256K1_GNUC_PREREQ) +# if defined(__GNUC__)&&defined(__GNUC_MINOR__) +# define SECP256K1_GNUC_PREREQ(_maj,_min) \ + ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) +# else +# define SECP256K1_GNUC_PREREQ(_maj,_min) 0 +# endif +# endif + +# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if SECP256K1_GNUC_PREREQ(2,7) +# define SECP256K1_INLINE __inline__ +# elif (defined(_MSC_VER)) +# define SECP256K1_INLINE __inline +# else +# define SECP256K1_INLINE +# endif +# else +# define SECP256K1_INLINE inline +# endif + +#ifndef SECP256K1_API +# if defined(_WIN32) +# ifdef SECP256K1_BUILD +# define SECP256K1_API __declspec(dllexport) +# else +# define SECP256K1_API +# endif +# elif defined(__GNUC__) && defined(SECP256K1_BUILD) +# define SECP256K1_API __attribute__ ((visibility ("default"))) +# else +# define SECP256K1_API +# endif +#endif + +/**Warning attributes + * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out + * some paranoid null checks. */ +# if defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4) +# define SECP256K1_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) +# else +# define SECP256K1_WARN_UNUSED_RESULT +# endif +# if !defined(SECP256K1_BUILD) && defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4) +# define SECP256K1_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x))) +# else +# define SECP256K1_ARG_NONNULL(_x) +# endif + +/** All flags' lower 8 bits indicate what they're for. Do not use directly. */ +#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1) +#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0) +#define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1) +/** The higher bits contain the actual data. Do not use directly. */ +#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8) +#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9) +#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8) + +/** Flags to pass to secp256k1_context_create. */ +#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) +#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN) +#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT) + +/** Flag to pass to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export. */ +#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) +#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION) + +/** Create a secp256k1 context object. + * + * Returns: a newly created context object. + * In: flags: which parts of the context to initialize. + */ +SECP256K1_API secp256k1_context* secp256k1_context_create( + unsigned int flags +) SECP256K1_WARN_UNUSED_RESULT; + +/** Copies a secp256k1 context object. + * + * Returns: a newly created context object. + * Args: ctx: an existing context to copy (cannot be NULL) + */ +SECP256K1_API secp256k1_context* secp256k1_context_clone( + const secp256k1_context* ctx +) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; + +/** Destroy a secp256k1 context object. + * + * The context pointer may not be used afterwards. + * Args: ctx: an existing context to destroy (cannot be NULL) + */ +SECP256K1_API void secp256k1_context_destroy( + secp256k1_context* ctx +); + +/** Set a callback function to be called when an illegal argument is passed to + * an API call. It will only trigger for violations that are mentioned + * explicitly in the header. + * + * The philosophy is that these shouldn't be dealt with through a + * specific return value, as calling code should not have branches to deal with + * the case that this code itself is broken. + * + * On the other hand, during debug stage, one would want to be informed about + * such mistakes, and the default (crashing) may be inadvisable. + * When this callback is triggered, the API function called is guaranteed not + * to cause a crash, though its return value and output arguments are + * undefined. + * + * Args: ctx: an existing context object (cannot be NULL) + * In: fun: a pointer to a function to call when an illegal argument is + * passed to the API, taking a message and an opaque pointer + * (NULL restores a default handler that calls abort). + * data: the opaque pointer to pass to fun above. + */ +SECP256K1_API void secp256k1_context_set_illegal_callback( + secp256k1_context* ctx, + void (*fun)(const char* message, void* data), + const void* data +) SECP256K1_ARG_NONNULL(1); + +/** Set a callback function to be called when an internal consistency check + * fails. The default is crashing. + * + * This can only trigger in case of a hardware failure, miscompilation, + * memory corruption, serious bug in the library, or other error would can + * otherwise result in undefined behaviour. It will not trigger due to mere + * incorrect usage of the API (see secp256k1_context_set_illegal_callback + * for that). After this callback returns, anything may happen, including + * crashing. + * + * Args: ctx: an existing context object (cannot be NULL) + * In: fun: a pointer to a function to call when an internal error occurs, + * taking a message and an opaque pointer (NULL restores a default + * handler that calls abort). + * data: the opaque pointer to pass to fun above. + */ +SECP256K1_API void secp256k1_context_set_error_callback( + secp256k1_context* ctx, + void (*fun)(const char* message, void* data), + const void* data +) SECP256K1_ARG_NONNULL(1); + +/** Parse a variable-length public key into the pubkey object. + * + * Returns: 1 if the public key was fully valid. + * 0 if the public key could not be parsed or is invalid. + * Args: ctx: a secp256k1 context object. + * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a + * parsed version of input. If not, its value is undefined. + * In: input: pointer to a serialized public key + * inputlen: length of the array pointed to by input + * + * This function supports parsing compressed (33 bytes, header byte 0x02 or + * 0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header + * byte 0x06 or 0x07) format public keys. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse( + const secp256k1_context* ctx, + secp256k1_pubkey* pubkey, + const unsigned char *input, + size_t inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize a pubkey object into a serialized byte sequence. + * + * Returns: 1 always. + * Args: ctx: a secp256k1 context object. + * Out: output: a pointer to a 65-byte (if compressed==0) or 33-byte (if + * compressed==1) byte array to place the serialized key + * in. + * In/Out: outputlen: a pointer to an integer which is initially set to the + * size of output, and is overwritten with the written + * size. + * In: pubkey: a pointer to a secp256k1_pubkey containing an + * initialized public key. + * flags: SECP256K1_EC_COMPRESSED if serialization should be in + * compressed format, otherwise SECP256K1_EC_UNCOMPRESSED. + */ +SECP256K1_API int secp256k1_ec_pubkey_serialize( + const secp256k1_context* ctx, + unsigned char *output, + size_t *outputlen, + const secp256k1_pubkey* pubkey, + unsigned int flags +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Parse an ECDSA signature in compact (64 bytes) format. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input64: a pointer to the 64-byte array to parse + * + * The signature must consist of a 32-byte big endian R value, followed by a + * 32-byte big endian S value. If R or S fall outside of [0..order-1], the + * encoding is invalid. R and S with value 0 are allowed in the encoding. + * + * After the call, sig will always be initialized. If parsing failed or R or + * S are zero, the resulting sig value is guaranteed to fail validation for any + * message and public key. + */ +SECP256K1_API int secp256k1_ecdsa_signature_parse_compact( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature* sig, + const unsigned char *input64 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Parse a DER ECDSA signature. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input: a pointer to the signature to be parsed + * inputlen: the length of the array pointed to be input + * + * This function will accept any valid DER encoded signature, even if the + * encoded numbers are out of range. + * + * After the call, sig will always be initialized. If parsing failed or the + * encoded numbers are out of range, signature validation with it is + * guaranteed to fail for every message and public key. + */ +SECP256K1_API int secp256k1_ecdsa_signature_parse_der( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature* sig, + const unsigned char *input, + size_t inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize an ECDSA signature in DER format. + * + * Returns: 1 if enough space was available to serialize, 0 otherwise + * Args: ctx: a secp256k1 context object + * Out: output: a pointer to an array to store the DER serialization + * In/Out: outputlen: a pointer to a length integer. Initially, this integer + * should be set to the length of output. After the call + * it will be set to the length of the serialization (even + * if 0 was returned). + * In: sig: a pointer to an initialized signature object + */ +SECP256K1_API int secp256k1_ecdsa_signature_serialize_der( + const secp256k1_context* ctx, + unsigned char *output, + size_t *outputlen, + const secp256k1_ecdsa_signature* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Serialize an ECDSA signature in compact (64 byte) format. + * + * Returns: 1 + * Args: ctx: a secp256k1 context object + * Out: output64: a pointer to a 64-byte array to store the compact serialization + * In: sig: a pointer to an initialized signature object + * + * See secp256k1_ecdsa_signature_parse_compact for details about the encoding. + */ +SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact( + const secp256k1_context* ctx, + unsigned char *output64, + const secp256k1_ecdsa_signature* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Verify an ECDSA signature. + * + * Returns: 1: correct signature + * 0: incorrect or unparseable signature + * Args: ctx: a secp256k1 context object, initialized for verification. + * In: sig: the signature being verified (cannot be NULL) + * msg32: the 32-byte message hash being verified (cannot be NULL) + * pubkey: pointer to an initialized public key to verify with (cannot be NULL) + * + * To avoid accepting malleable signatures, only ECDSA signatures in lower-S + * form are accepted. + * + * If you need to accept ECDSA signatures from sources that do not obey this + * rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to + * validation, but be aware that doing so results in malleable signatures. + * + * For details, see the comments for that function. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( + const secp256k1_context* ctx, + const secp256k1_ecdsa_signature *sig, + const unsigned char *msg32, + const secp256k1_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Convert a signature to a normalized lower-S form. + * + * Returns: 1 if sigin was not normalized, 0 if it already was. + * Args: ctx: a secp256k1 context object + * Out: sigout: a pointer to a signature to fill with the normalized form, + * or copy if the input was already normalized. (can be NULL if + * you're only interested in whether the input was already + * normalized). + * In: sigin: a pointer to a signature to check/normalize (cannot be NULL, + * can be identical to sigout) + * + * With ECDSA a third-party can forge a second distinct signature of the same + * message, given a single initial signature, but without knowing the key. This + * is done by negating the S value modulo the order of the curve, 'flipping' + * the sign of the random point R which is not included in the signature. + * + * Forgery of the same message isn't universally problematic, but in systems + * where message malleability or uniqueness of signatures is important this can + * cause issues. This forgery can be blocked by all verifiers forcing signers + * to use a normalized form. + * + * The lower-S form reduces the size of signatures slightly on average when + * variable length encodings (such as DER) are used and is cheap to verify, + * making it a good choice. Security of always using lower-S is assured because + * anyone can trivially modify a signature after the fact to enforce this + * property anyway. + * + * The lower S value is always between 0x1 and + * 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, + * inclusive. + * + * No other forms of ECDSA malleability are known and none seem likely, but + * there is no formal proof that ECDSA, even with this additional restriction, + * is free of other malleability. Commonly used serialization schemes will also + * accept various non-unique encodings, so care should be taken when this + * property is required for an application. + * + * The secp256k1_ecdsa_sign function will by default create signatures in the + * lower-S form, and secp256k1_ecdsa_verify will not accept others. In case + * signatures come from a system that cannot enforce this property, + * secp256k1_ecdsa_signature_normalize must be called before verification. + */ +SECP256K1_API int secp256k1_ecdsa_signature_normalize( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature *sigout, + const secp256k1_ecdsa_signature *sigin +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3); + +/** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function. + * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of + * extra entropy. + */ +SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; + +/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */ +SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_default; + +/** Create an ECDSA signature. + * + * Returns: 1: signature created + * 0: the nonce generation function failed, or the private key was invalid. + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) + * In: msg32: the 32-byte message hash being signed (cannot be NULL) + * seckey: pointer to a 32-byte secret key (cannot be NULL) + * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used + * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) + * + * The created signature is always in lower-S form. See + * secp256k1_ecdsa_signature_normalize for more details. + */ +SECP256K1_API int secp256k1_ecdsa_sign( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature *sig, + const unsigned char *msg32, + const unsigned char *seckey, + secp256k1_nonce_function noncefp, + const void *ndata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Verify an ECDSA secret key. + * + * Returns: 1: secret key is valid + * 0: secret key is invalid + * Args: ctx: pointer to a context object (cannot be NULL) + * In: seckey: pointer to a 32-byte secret key (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify( + const secp256k1_context* ctx, + const unsigned char *seckey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +/** Compute the public key for a secret key. + * + * Returns: 1: secret was valid, public key stores + * 0: secret was invalid, try again + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * Out: pubkey: pointer to the created public key (cannot be NULL) + * In: seckey: pointer to a 32-byte private key (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const unsigned char *seckey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Tweak a private key by adding tweak to it. + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or if the resulting private key + * would be invalid (only when the tweak is the complement of the + * private key). 1 otherwise. + * Args: ctx: pointer to a context object (cannot be NULL). + * In/Out: seckey: pointer to a 32-byte private key. + * In: tweak: pointer to a 32-byte tweak. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add( + const secp256k1_context* ctx, + unsigned char *seckey, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Tweak a public key by adding tweak times the generator to it. + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or if the resulting public key + * would be invalid (only when the tweak is the complement of the + * corresponding private key). 1 otherwise. + * Args: ctx: pointer to a context object initialized for validation + * (cannot be NULL). + * In/Out: pubkey: pointer to a public key object. + * In: tweak: pointer to a 32-byte tweak. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Tweak a private key by multiplying it by a tweak. + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or equal to zero. 1 otherwise. + * Args: ctx: pointer to a context object (cannot be NULL). + * In/Out: seckey: pointer to a 32-byte private key. + * In: tweak: pointer to a 32-byte tweak. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( + const secp256k1_context* ctx, + unsigned char *seckey, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Tweak a public key by multiplying it by a tweak value. + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or equal to zero. 1 otherwise. + * Args: ctx: pointer to a context object initialized for validation + * (cannot be NULL). + * In/Out: pubkey: pointer to a public key obkect. + * In: tweak: pointer to a 32-byte tweak. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Updates the context randomization. + * Returns: 1: randomization successfully updated + * 0: error + * Args: ctx: pointer to a context object (cannot be NULL) + * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize( + secp256k1_context* ctx, + const unsigned char *seed32 +) SECP256K1_ARG_NONNULL(1); + +/** Add a number of public keys together. + * Returns: 1: the sum of the public keys is valid. + * 0: the sum of the public keys is not valid. + * Args: ctx: pointer to a context object + * Out: out: pointer to a public key object for placing the resulting public key + * (cannot be NULL) + * In: ins: pointer to array of pointers to public keys (cannot be NULL) + * n: the number of public keys to add together (must be at least 1) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine( + const secp256k1_context* ctx, + secp256k1_pubkey *out, + const secp256k1_pubkey * const * ins, + size_t n +) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/secp256k1/include/secp256k1_ecdh.h b/src/secp256k1/include/secp256k1_ecdh.h new file mode 100644 index 000000000..4b84d7a96 --- /dev/null +++ b/src/secp256k1/include/secp256k1_ecdh.h @@ -0,0 +1,31 @@ +#ifndef _SECP256K1_ECDH_ +# define _SECP256K1_ECDH_ + +# include "secp256k1.h" + +# ifdef __cplusplus +extern "C" { +# endif + +/** Compute an EC Diffie-Hellman secret in constant time + * Returns: 1: exponentiation was successful + * 0: scalar was invalid (zero or overflow) + * Args: ctx: pointer to a context object (cannot be NULL) + * Out: result: a 32-byte array which will be populated by an ECDH + * secret computed from the point and scalar + * In: pubkey: a pointer to a secp256k1_pubkey containing an + * initialized public key + * privkey: a 32-byte scalar with which to multiply the point + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh( + const secp256k1_context* ctx, + unsigned char *result, + const secp256k1_pubkey *pubkey, + const unsigned char *privkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/secp256k1/include/secp256k1_recovery.h b/src/secp256k1/include/secp256k1_recovery.h new file mode 100644 index 000000000..055379725 --- /dev/null +++ b/src/secp256k1/include/secp256k1_recovery.h @@ -0,0 +1,110 @@ +#ifndef _SECP256K1_RECOVERY_ +# define _SECP256K1_RECOVERY_ + +# include "secp256k1.h" + +# ifdef __cplusplus +extern "C" { +# endif + +/** Opaque data structured that holds a parsed ECDSA signature, + * supporting pubkey recovery. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 65 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage or transmission, use + * the secp256k1_ecdsa_signature_serialize_* and + * secp256k1_ecdsa_signature_parse_* functions. + * + * Furthermore, it is guaranteed that identical signatures (including their + * recoverability) will have identical representation, so they can be + * memcmp'ed. + */ +typedef struct { + unsigned char data[65]; +} secp256k1_ecdsa_recoverable_signature; + +/** Parse a compact ECDSA signature (64 bytes + recovery id). + * + * Returns: 1 when the signature could be parsed, 0 otherwise + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input64: a pointer to a 64-byte compact signature + * recid: the recovery id (0, 1, 2 or 3) + */ +SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact( + const secp256k1_context* ctx, + secp256k1_ecdsa_recoverable_signature* sig, + const unsigned char *input64, + int recid +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Convert a recoverable signature into a normal signature. + * + * Returns: 1 + * Out: sig: a pointer to a normal signature (cannot be NULL). + * In: sigin: a pointer to a recoverable signature (cannot be NULL). + */ +SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature* sig, + const secp256k1_ecdsa_recoverable_signature* sigin +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize an ECDSA signature in compact format (64 bytes + recovery id). + * + * Returns: 1 + * Args: ctx: a secp256k1 context object + * Out: output64: a pointer to a 64-byte array of the compact signature (cannot be NULL) + * recid: a pointer to an integer to hold the recovery id (can be NULL). + * In: sig: a pointer to an initialized signature object (cannot be NULL) + */ +SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact( + const secp256k1_context* ctx, + unsigned char *output64, + int *recid, + const secp256k1_ecdsa_recoverable_signature* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Create a recoverable ECDSA signature. + * + * Returns: 1: signature created + * 0: the nonce generation function failed, or the private key was invalid. + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) + * In: msg32: the 32-byte message hash being signed (cannot be NULL) + * seckey: pointer to a 32-byte secret key (cannot be NULL) + * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used + * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) + */ +SECP256K1_API int secp256k1_ecdsa_sign_recoverable( + const secp256k1_context* ctx, + secp256k1_ecdsa_recoverable_signature *sig, + const unsigned char *msg32, + const unsigned char *seckey, + secp256k1_nonce_function noncefp, + const void *ndata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Recover an ECDSA public key from a signature. + * + * Returns: 1: public key successfully recovered (which guarantees a correct signature). + * 0: otherwise. + * Args: ctx: pointer to a context object, initialized for verification (cannot be NULL) + * Out: pubkey: pointer to the recovered public key (cannot be NULL) + * In: sig: pointer to initialized signature that supports pubkey recovery (cannot be NULL) + * msg32: the 32-byte message hash assumed to be signed (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const secp256k1_ecdsa_recoverable_signature *sig, + const unsigned char *msg32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/secp256k1/include/secp256k1_schnorr.h b/src/secp256k1/include/secp256k1_schnorr.h new file mode 100644 index 000000000..dc32fec1e --- /dev/null +++ b/src/secp256k1/include/secp256k1_schnorr.h @@ -0,0 +1,173 @@ +#ifndef _SECP256K1_SCHNORR_ +# define _SECP256K1_SCHNORR_ + +# include "secp256k1.h" + +# ifdef __cplusplus +extern "C" { +# endif + +/** Create a signature using a custom EC-Schnorr-SHA256 construction. It + * produces non-malleable 64-byte signatures which support public key recovery + * batch validation, and multiparty signing. + * Returns: 1: signature created + * 0: the nonce generation function failed, or the private key was + * invalid. + * Args: ctx: pointer to a context object, initialized for signing + * (cannot be NULL) + * Out: sig64: pointer to a 64-byte array where the signature will be + * placed (cannot be NULL) + * In: msg32: the 32-byte message hash being signed (cannot be NULL) + * seckey: pointer to a 32-byte secret key (cannot be NULL) + * noncefp:pointer to a nonce generation function. If NULL, + * secp256k1_nonce_function_default is used + * ndata: pointer to arbitrary data used by the nonce generation + * function (can be NULL) + */ +SECP256K1_API int secp256k1_schnorr_sign( + const secp256k1_context* ctx, + unsigned char *sig64, + const unsigned char *msg32, + const unsigned char *seckey, + secp256k1_nonce_function noncefp, + const void *ndata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Verify a signature created by secp256k1_schnorr_sign. + * Returns: 1: correct signature + * 0: incorrect signature + * Args: ctx: a secp256k1 context object, initialized for verification. + * In: sig64: the 64-byte signature being verified (cannot be NULL) + * msg32: the 32-byte message hash being verified (cannot be NULL) + * pubkey: the public key to verify with (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_verify( + const secp256k1_context* ctx, + const unsigned char *sig64, + const unsigned char *msg32, + const secp256k1_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Recover an EC public key from a Schnorr signature created using + * secp256k1_schnorr_sign. + * Returns: 1: public key successfully recovered (which guarantees a correct + * signature). + * 0: otherwise. + * Args: ctx: pointer to a context object, initialized for + * verification (cannot be NULL) + * Out: pubkey: pointer to a pubkey to set to the recovered public key + * (cannot be NULL). + * In: sig64: signature as 64 byte array (cannot be NULL) + * msg32: the 32-byte message hash assumed to be signed (cannot + * be NULL) + */ +SECP256K1_API int secp256k1_schnorr_recover( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const unsigned char *sig64, + const unsigned char *msg32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Generate a nonce pair deterministically for use with + * secp256k1_schnorr_partial_sign. + * Returns: 1: valid nonce pair was generated. + * 0: otherwise (nonce generation function failed) + * Args: ctx: pointer to a context object, initialized for signing + * (cannot be NULL) + * Out: pubnonce: public side of the nonce (cannot be NULL) + * privnonce32: private side of the nonce (32 byte) (cannot be NULL) + * In: msg32: the 32-byte message hash assumed to be signed (cannot + * be NULL) + * sec32: the 32-byte private key (cannot be NULL) + * noncefp: pointer to a nonce generation function. If NULL, + * secp256k1_nonce_function_default is used + * noncedata: pointer to arbitrary data used by the nonce generation + * function (can be NULL) + * + * Do not use the output as a private/public key pair for signing/validation. + */ +SECP256K1_API int secp256k1_schnorr_generate_nonce_pair( + const secp256k1_context* ctx, + secp256k1_pubkey *pubnonce, + unsigned char *privnonce32, + const unsigned char *msg32, + const unsigned char *sec32, + secp256k1_nonce_function noncefp, + const void* noncedata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Produce a partial Schnorr signature, which can be combined using + * secp256k1_schnorr_partial_combine, to end up with a full signature that is + * verifiable using secp256k1_schnorr_verify. + * Returns: 1: signature created successfully. + * 0: no valid signature exists with this combination of keys, nonces + * and message (chance around 1 in 2^128) + * -1: invalid private key, nonce, or public nonces. + * Args: ctx: pointer to context object, initialized for signing (cannot + * be NULL) + * Out: sig64: pointer to 64-byte array to put partial signature in + * In: msg32: pointer to 32-byte message to sign + * sec32: pointer to 32-byte private key + * pubnonce_others: pointer to pubkey containing the sum of the other's + * nonces (see secp256k1_ec_pubkey_combine) + * secnonce32: pointer to 32-byte array containing our nonce + * + * The intended procedure for creating a multiparty signature is: + * - Each signer S[i] with private key x[i] and public key Q[i] runs + * secp256k1_schnorr_generate_nonce_pair to produce a pair (k[i],R[i]) of + * private/public nonces. + * - All signers communicate their public nonces to each other (revealing your + * private nonce can lead to discovery of your private key, so it should be + * considered secret). + * - All signers combine all the public nonces they received (excluding their + * own) using secp256k1_ec_pubkey_combine to obtain an + * Rall[i] = sum(R[0..i-1,i+1..n]). + * - All signers produce a partial signature using + * secp256k1_schnorr_partial_sign, passing in their own private key x[i], + * their own private nonce k[i], and the sum of the others' public nonces + * Rall[i]. + * - All signers communicate their partial signatures to each other. + * - Someone combines all partial signatures using + * secp256k1_schnorr_partial_combine, to obtain a full signature. + * - The resulting signature is validatable using secp256k1_schnorr_verify, with + * public key equal to the result of secp256k1_ec_pubkey_combine of the + * signers' public keys (sum(Q[0..n])). + * + * Note that secp256k1_schnorr_partial_combine and secp256k1_ec_pubkey_combine + * function take their arguments in any order, and it is possible to + * pre-combine several inputs already with one call, and add more inputs later + * by calling the function again (they are commutative and associative). + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_sign( + const secp256k1_context* ctx, + unsigned char *sig64, + const unsigned char *msg32, + const unsigned char *sec32, + const secp256k1_pubkey *pubnonce_others, + const unsigned char *secnonce32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); + +/** Combine multiple Schnorr partial signatures. + * Returns: 1: the passed signatures were successfully combined. + * 0: the resulting signature is not valid (chance of 1 in 2^256) + * -1: some inputs were invalid, or the signatures were not created + * using the same set of nonces + * Args: ctx: pointer to a context object + * Out: sig64: pointer to a 64-byte array to place the combined signature + * (cannot be NULL) + * In: sig64sin: pointer to an array of n pointers to 64-byte input + * signatures + * n: the number of signatures to combine (at least 1) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorr_partial_combine( + const secp256k1_context* ctx, + unsigned char *sig64, + const unsigned char * const * sig64sin, + size_t n +) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/secp256k1/libsecp256k1.pc.in b/src/secp256k1/libsecp256k1.pc.in new file mode 100644 index 000000000..a0d006f11 --- /dev/null +++ b/src/secp256k1/libsecp256k1.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libsecp256k1 +Description: Optimized C library for EC operations on curve secp256k1 +URL: https://github.com/bitcoin-core/secp256k1 +Version: @PACKAGE_VERSION@ +Cflags: -I${includedir} +Libs.private: @SECP_LIBS@ +Libs: -L${libdir} -lsecp256k1 + diff --git a/src/secp256k1/obj/.gitignore b/src/secp256k1/obj/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/src/secp256k1/sage/group_prover.sage b/src/secp256k1/sage/group_prover.sage new file mode 100644 index 000000000..ab580c5b2 --- /dev/null +++ b/src/secp256k1/sage/group_prover.sage @@ -0,0 +1,322 @@ +# This code supports verifying group implementations which have branches +# or conditional statements (like cmovs), by allowing each execution path +# to independently set assumptions on input or intermediary variables. +# +# The general approach is: +# * A constraint is a tuple of two sets of of symbolic expressions: +# the first of which are required to evaluate to zero, the second of which +# are required to evaluate to nonzero. +# - A constraint is said to be conflicting if any of its nonzero expressions +# is in the ideal with basis the zero expressions (in other words: when the +# zero expressions imply that one of the nonzero expressions are zero). +# * There is a list of laws that describe the intended behaviour, including +# laws for addition and doubling. Each law is called with the symbolic point +# coordinates as arguments, and returns: +# - A constraint describing the assumptions under which it is applicable, +# called "assumeLaw" +# - A constraint describing the requirements of the law, called "require" +# * Implementations are transliterated into functions that operate as well on +# algebraic input points, and are called once per combination of branches +# exectured. Each execution returns: +# - A constraint describing the assumptions this implementation requires +# (such as Z1=1), called "assumeFormula" +# - A constraint describing the assumptions this specific branch requires, +# but which is by construction guaranteed to cover the entire space by +# merging the results from all branches, called "assumeBranch" +# - The result of the computation +# * All combinations of laws with implementation branches are tried, and: +# - If the combination of assumeLaw, assumeFormula, and assumeBranch results +# in a conflict, it means this law does not apply to this branch, and it is +# skipped. +# - For others, we try to prove the require constraints hold, assuming the +# information in assumeLaw + assumeFormula + assumeBranch, and if this does +# not succeed, we fail. +# + To prove an expression is zero, we check whether it belongs to the +# ideal with the assumed zero expressions as basis. This test is exact. +# + To prove an expression is nonzero, we check whether each of its +# factors is contained in the set of nonzero assumptions' factors. +# This test is not exact, so various combinations of original and +# reduced expressions' factors are tried. +# - If we succeed, we print out the assumptions from assumeFormula that +# weren't implied by assumeLaw already. Those from assumeBranch are skipped, +# as we assume that all constraints in it are complementary with each other. +# +# Based on the sage verification scripts used in the Explicit-Formulas Database +# by Tanja Lange and others, see http://hyperelliptic.org/EFD + +class fastfrac: + """Fractions over rings.""" + + def __init__(self,R,top,bot=1): + """Construct a fractional, given a ring, a numerator, and denominator.""" + self.R = R + if parent(top) == ZZ or parent(top) == R: + self.top = R(top) + self.bot = R(bot) + elif top.__class__ == fastfrac: + self.top = top.top + self.bot = top.bot * bot + else: + self.top = R(numerator(top)) + self.bot = R(denominator(top)) * bot + + def iszero(self,I): + """Return whether this fraction is zero given an ideal.""" + return self.top in I and self.bot not in I + + def reduce(self,assumeZero): + zero = self.R.ideal(map(numerator, assumeZero)) + return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot)) + + def __add__(self,other): + """Add two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top + self.bot * other,self.bot) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.bot + self.bot * other.top,self.bot * other.bot) + return NotImplemented + + def __sub__(self,other): + """Subtract two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top - self.bot * other,self.bot) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.bot - self.bot * other.top,self.bot * other.bot) + return NotImplemented + + def __neg__(self): + """Return the negation of a fraction.""" + return fastfrac(self.R,-self.top,self.bot) + + def __mul__(self,other): + """Multiply two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top * other,self.bot) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.top,self.bot * other.bot) + return NotImplemented + + def __rmul__(self,other): + """Multiply something else with a fraction.""" + return self.__mul__(other) + + def __div__(self,other): + """Divide two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top,self.bot * other) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.bot,self.bot * other.top) + return NotImplemented + + def __pow__(self,other): + """Compute a power of a fraction.""" + if parent(other) == ZZ: + if other < 0: + # Negative powers require flipping top and bottom + return fastfrac(self.R,self.bot ^ (-other),self.top ^ (-other)) + else: + return fastfrac(self.R,self.top ^ other,self.bot ^ other) + return NotImplemented + + def __str__(self): + return "fastfrac((" + str(self.top) + ") / (" + str(self.bot) + "))" + def __repr__(self): + return "%s" % self + + def numerator(self): + return self.top + +class constraints: + """A set of constraints, consisting of zero and nonzero expressions. + + Constraints can either be used to express knowledge or a requirement. + + Both the fields zero and nonzero are maps from expressions to description + strings. The expressions that are the keys in zero are required to be zero, + and the expressions that are the keys in nonzero are required to be nonzero. + + Note that (a != 0) and (b != 0) is the same as (a*b != 0), so all keys in + nonzero could be multiplied into a single key. This is often much less + efficient to work with though, so we keep them separate inside the + constraints. This allows higher-level code to do fast checks on the individual + nonzero elements, or combine them if needed for stronger checks. + + We can't multiply the different zero elements, as it would suffice for one of + the factors to be zero, instead of all of them. Instead, the zero elements are + typically combined into an ideal first. + """ + + def __init__(self, **kwargs): + if 'zero' in kwargs: + self.zero = dict(kwargs['zero']) + else: + self.zero = dict() + if 'nonzero' in kwargs: + self.nonzero = dict(kwargs['nonzero']) + else: + self.nonzero = dict() + + def negate(self): + return constraints(zero=self.nonzero, nonzero=self.zero) + + def __add__(self, other): + zero = self.zero.copy() + zero.update(other.zero) + nonzero = self.nonzero.copy() + nonzero.update(other.nonzero) + return constraints(zero=zero, nonzero=nonzero) + + def __str__(self): + return "constraints(zero=%s,nonzero=%s)" % (self.zero, self.nonzero) + + def __repr__(self): + return "%s" % self + + +def conflicts(R, con): + """Check whether any of the passed non-zero assumptions is implied by the zero assumptions""" + zero = R.ideal(map(numerator, con.zero)) + if 1 in zero: + return True + # First a cheap check whether any of the individual nonzero terms conflict on + # their own. + for nonzero in con.nonzero: + if nonzero.iszero(zero): + return True + # It can be the case that entries in the nonzero set do not individually + # conflict with the zero set, but their combination does. For example, knowing + # that either x or y is zero is equivalent to having x*y in the zero set. + # Having x or y individually in the nonzero set is not a conflict, but both + # simultaneously is, so that is the right thing to check for. + if reduce(lambda a,b: a * b, con.nonzero, fastfrac(R, 1)).iszero(zero): + return True + return False + + +def get_nonzero_set(R, assume): + """Calculate a simple set of nonzero expressions""" + zero = R.ideal(map(numerator, assume.zero)) + nonzero = set() + for nz in map(numerator, assume.nonzero): + for (f,n) in nz.factor(): + nonzero.add(f) + rnz = zero.reduce(nz) + for (f,n) in rnz.factor(): + nonzero.add(f) + return nonzero + + +def prove_nonzero(R, exprs, assume): + """Check whether an expression is provably nonzero, given assumptions""" + zero = R.ideal(map(numerator, assume.zero)) + nonzero = get_nonzero_set(R, assume) + expl = set() + ok = True + for expr in exprs: + if numerator(expr) in zero: + return (False, [exprs[expr]]) + allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1) + for (f, n) in allexprs.factor(): + if f not in nonzero: + ok = False + if ok: + return (True, None) + ok = True + for (f, n) in zero.reduce(numerator(allexprs)).factor(): + if f not in nonzero: + ok = False + if ok: + return (True, None) + ok = True + for expr in exprs: + for (f,n) in numerator(expr).factor(): + if f not in nonzero: + ok = False + if ok: + return (True, None) + ok = True + for expr in exprs: + for (f,n) in zero.reduce(numerator(expr)).factor(): + if f not in nonzero: + expl.add(exprs[expr]) + if expl: + return (False, list(expl)) + else: + return (True, None) + + +def prove_zero(R, exprs, assume): + """Check whether all of the passed expressions are provably zero, given assumptions""" + r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume) + if not r: + return (False, map(lambda x: "Possibly zero denominator: %s" % x, e)) + zero = R.ideal(map(numerator, assume.zero)) + nonzero = prod(x for x in assume.nonzero) + expl = [] + for expr in exprs: + if not expr.iszero(zero): + expl.append(exprs[expr]) + if not expl: + return (True, None) + return (False, expl) + + +def describe_extra(R, assume, assumeExtra): + """Describe what assumptions are added, given existing assumptions""" + zerox = assume.zero.copy() + zerox.update(assumeExtra.zero) + zero = R.ideal(map(numerator, assume.zero)) + zeroextra = R.ideal(map(numerator, zerox)) + nonzero = get_nonzero_set(R, assume) + ret = set() + # Iterate over the extra zero expressions + for base in assumeExtra.zero: + if base not in zero: + add = [] + for (f, n) in numerator(base).factor(): + if f not in nonzero: + add += ["%s" % f] + if add: + ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base]) + # Iterate over the extra nonzero expressions + for nz in assumeExtra.nonzero: + nzr = zeroextra.reduce(numerator(nz)) + if nzr not in zeroextra: + for (f,n) in nzr.factor(): + if zeroextra.reduce(f) not in nonzero: + ret.add("%s != 0" % zeroextra.reduce(f)) + return ", ".join(x for x in ret) + + +def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require): + """Check a set of zero and nonzero requirements, given a set of zero and nonzero assumptions""" + assume = assumeLaw + assumeAssert + assumeBranch + + if conflicts(R, assume): + # This formula does not apply + return None + + describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert) + + ok, msg = prove_zero(R, require.zero, assume) + if not ok: + return "FAIL, %s fails (assuming %s)" % (str(msg), describe) + + res, expl = prove_nonzero(R, require.nonzero, assume) + if not res: + return "FAIL, %s fails (assuming %s)" % (str(expl), describe) + + if describe != "": + return "OK (assuming %s)" % describe + else: + return "OK" + + +def concrete_verify(c): + for k in c.zero: + if k != 0: + return (False, c.zero[k]) + for k in c.nonzero: + if k == 0: + return (False, c.nonzero[k]) + return (True, None) diff --git a/src/secp256k1/sage/secp256k1.sage b/src/secp256k1/sage/secp256k1.sage new file mode 100644 index 000000000..a97e732f7 --- /dev/null +++ b/src/secp256k1/sage/secp256k1.sage @@ -0,0 +1,306 @@ +# Test libsecp256k1' group operation implementations using prover.sage + +import sys + +load("group_prover.sage") +load("weierstrass_prover.sage") + +def formula_secp256k1_gej_double_var(a): + """libsecp256k1's secp256k1_gej_double_var, used by various addition functions""" + rz = a.Z * a.Y + rz = rz * 2 + t1 = a.X^2 + t1 = t1 * 3 + t2 = t1^2 + t3 = a.Y^2 + t3 = t3 * 2 + t4 = t3^2 + t4 = t4 * 2 + t3 = t3 * a.X + rx = t3 + rx = rx * 4 + rx = -rx + rx = rx + t2 + t2 = -t2 + t3 = t3 * 6 + t3 = t3 + t2 + ry = t1 * t3 + t2 = -t4 + ry = ry + t2 + return jacobianpoint(rx, ry, rz) + +def formula_secp256k1_gej_add_var(branch, a, b): + """libsecp256k1's secp256k1_gej_add_var""" + if branch == 0: + return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), b) + if branch == 1: + return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) + z22 = b.Z^2 + z12 = a.Z^2 + u1 = a.X * z22 + u2 = b.X * z12 + s1 = a.Y * z22 + s1 = s1 * b.Z + s2 = b.Y * z12 + s2 = s2 * a.Z + h = -u1 + h = h + u2 + i = -s1 + i = i + s2 + if branch == 2: + r = formula_secp256k1_gej_double_var(a) + return (constraints(), constraints(zero={h : 'h=0', i : 'i=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}), r) + if branch == 3: + return (constraints(), constraints(zero={h : 'h=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={i : 'i!=0'}), point_at_infinity()) + i2 = i^2 + h2 = h^2 + h3 = h2 * h + h = h * b.Z + rz = a.Z * h + t = u1 * h2 + rx = t + rx = rx * 2 + rx = rx + h3 + rx = -rx + rx = rx + i2 + ry = -rx + ry = ry + t + ry = ry * i + h3 = h3 * s1 + h3 = -h3 + ry = ry + h3 + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_ge_var(branch, a, b): + """libsecp256k1's secp256k1_gej_add_ge_var, which assume bz==1""" + if branch == 0: + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(nonzero={a.Infinity : 'a_infinite'}), b) + if branch == 1: + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) + z12 = a.Z^2 + u1 = a.X + u2 = b.X * z12 + s1 = a.Y + s2 = b.Y * z12 + s2 = s2 * a.Z + h = -u1 + h = h + u2 + i = -s1 + i = i + s2 + if (branch == 2): + r = formula_secp256k1_gej_double_var(a) + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) + if (branch == 3): + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) + i2 = i^2 + h2 = h^2 + h3 = h * h2 + rz = a.Z * h + t = u1 * h2 + rx = t + rx = rx * 2 + rx = rx + h3 + rx = -rx + rx = rx + i2 + ry = -rx + ry = ry + t + ry = ry * i + h3 = h3 * s1 + h3 = -h3 + ry = ry + h3 + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_zinv_var(branch, a, b): + """libsecp256k1's secp256k1_gej_add_zinv_var""" + bzinv = b.Z^(-1) + if branch == 0: + return (constraints(), constraints(nonzero={b.Infinity : 'b_infinite'}), a) + if branch == 1: + bzinv2 = bzinv^2 + bzinv3 = bzinv2 * bzinv + rx = b.X * bzinv2 + ry = b.Y * bzinv3 + rz = 1 + return (constraints(), constraints(zero={b.Infinity : 'b_finite'}, nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz)) + azz = a.Z * bzinv + z12 = azz^2 + u1 = a.X + u2 = b.X * z12 + s1 = a.Y + s2 = b.Y * z12 + s2 = s2 * azz + h = -u1 + h = h + u2 + i = -s1 + i = i + s2 + if branch == 2: + r = formula_secp256k1_gej_double_var(a) + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) + if branch == 3: + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) + i2 = i^2 + h2 = h^2 + h3 = h * h2 + rz = a.Z + rz = rz * h + t = u1 * h2 + rx = t + rx = rx * 2 + rx = rx + h3 + rx = -rx + rx = rx + i2 + ry = -rx + ry = ry + t + ry = ry * i + h3 = h3 * s1 + h3 = -h3 + ry = ry + h3 + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_ge(branch, a, b): + """libsecp256k1's secp256k1_gej_add_ge""" + zeroes = {} + nonzeroes = {} + a_infinity = False + if (branch & 4) != 0: + nonzeroes.update({a.Infinity : 'a_infinite'}) + a_infinity = True + else: + zeroes.update({a.Infinity : 'a_finite'}) + zz = a.Z^2 + u1 = a.X + u2 = b.X * zz + s1 = a.Y + s2 = b.Y * zz + s2 = s2 * a.Z + t = u1 + t = t + u2 + m = s1 + m = m + s2 + rr = t^2 + m_alt = -u2 + tt = u1 * m_alt + rr = rr + tt + degenerate = (branch & 3) == 3 + if (branch & 1) != 0: + zeroes.update({m : 'm_zero'}) + else: + nonzeroes.update({m : 'm_nonzero'}) + if (branch & 2) != 0: + zeroes.update({rr : 'rr_zero'}) + else: + nonzeroes.update({rr : 'rr_nonzero'}) + rr_alt = s1 + rr_alt = rr_alt * 2 + m_alt = m_alt + u1 + if not degenerate: + rr_alt = rr + m_alt = m + n = m_alt^2 + q = n * t + n = n^2 + if degenerate: + n = m + t = rr_alt^2 + rz = a.Z * m_alt + infinity = False + if (branch & 8) != 0: + if not a_infinity: + infinity = True + zeroes.update({rz : 'r.z=0'}) + else: + nonzeroes.update({rz : 'r.z!=0'}) + rz = rz * 2 + q = -q + t = t + q + rx = t + t = t * 2 + t = t + q + t = t * rr_alt + t = t + n + ry = -t + rx = rx * 4 + ry = ry * 4 + if a_infinity: + rx = b.X + ry = b.Y + rz = 1 + if infinity: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity()) + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_ge_old(branch, a, b): + """libsecp256k1's old secp256k1_gej_add_ge, which fails when ay+by=0 but ax!=bx""" + a_infinity = (branch & 1) != 0 + zero = {} + nonzero = {} + if a_infinity: + nonzero.update({a.Infinity : 'a_infinite'}) + else: + zero.update({a.Infinity : 'a_finite'}) + zz = a.Z^2 + u1 = a.X + u2 = b.X * zz + s1 = a.Y + s2 = b.Y * zz + s2 = s2 * a.Z + z = a.Z + t = u1 + t = t + u2 + m = s1 + m = m + s2 + n = m^2 + q = n * t + n = n^2 + rr = t^2 + t = u1 * u2 + t = -t + rr = rr + t + t = rr^2 + rz = m * z + infinity = False + if (branch & 2) != 0: + if not a_infinity: + infinity = True + else: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(nonzero={z : 'conflict_a'}, zero={z : 'conflict_b'}), point_at_infinity()) + zero.update({rz : 'r.z=0'}) + else: + nonzero.update({rz : 'r.z!=0'}) + rz = rz * (0 if a_infinity else 2) + rx = t + q = -q + rx = rx + q + q = q * 3 + t = t * 2 + t = t + q + t = t * rr + t = t + n + ry = -t + rx = rx * (0 if a_infinity else 4) + ry = ry * (0 if a_infinity else 4) + t = b.X + t = t * (1 if a_infinity else 0) + rx = rx + t + t = b.Y + t = t * (1 if a_infinity else 0) + ry = ry + t + t = (1 if a_infinity else 0) + rz = rz + t + if infinity: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), point_at_infinity()) + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz)) + +if __name__ == "__main__": + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old) + + if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive": + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43) diff --git a/src/secp256k1/sage/weierstrass_prover.sage b/src/secp256k1/sage/weierstrass_prover.sage new file mode 100644 index 000000000..03ef2ec90 --- /dev/null +++ b/src/secp256k1/sage/weierstrass_prover.sage @@ -0,0 +1,264 @@ +# Prover implementation for Weierstrass curves of the form +# y^2 = x^3 + A * x + B, specifically with a = 0 and b = 7, with group laws +# operating on affine and Jacobian coordinates, including the point at infinity +# represented by a 4th variable in coordinates. + +load("group_prover.sage") + + +class affinepoint: + def __init__(self, x, y, infinity=0): + self.x = x + self.y = y + self.infinity = infinity + def __str__(self): + return "affinepoint(x=%s,y=%s,inf=%s)" % (self.x, self.y, self.infinity) + + +class jacobianpoint: + def __init__(self, x, y, z, infinity=0): + self.X = x + self.Y = y + self.Z = z + self.Infinity = infinity + def __str__(self): + return "jacobianpoint(X=%s,Y=%s,Z=%s,inf=%s)" % (self.X, self.Y, self.Z, self.Infinity) + + +def point_at_infinity(): + return jacobianpoint(1, 1, 1, 1) + + +def negate(p): + if p.__class__ == affinepoint: + return affinepoint(p.x, -p.y) + if p.__class__ == jacobianpoint: + return jacobianpoint(p.X, -p.Y, p.Z) + assert(False) + + +def on_weierstrass_curve(A, B, p): + """Return a set of zero-expressions for an affine point to be on the curve""" + return constraints(zero={p.x^3 + A*p.x + B - p.y^2: 'on_curve'}) + + +def tangential_to_weierstrass_curve(A, B, p12, p3): + """Return a set of zero-expressions for ((x12,y12),(x3,y3)) to be a line that is tangential to the curve at (x12,y12)""" + return constraints(zero={ + (p12.y - p3.y) * (p12.y * 2) - (p12.x^2 * 3 + A) * (p12.x - p3.x): 'tangential_to_curve' + }) + + +def colinear(p1, p2, p3): + """Return a set of zero-expressions for ((x1,y1),(x2,y2),(x3,y3)) to be collinear""" + return constraints(zero={ + (p1.y - p2.y) * (p1.x - p3.x) - (p1.y - p3.y) * (p1.x - p2.x): 'colinear_1', + (p2.y - p3.y) * (p2.x - p1.x) - (p2.y - p1.y) * (p2.x - p3.x): 'colinear_2', + (p3.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p3.x - p1.x): 'colinear_3' + }) + + +def good_affine_point(p): + return constraints(nonzero={p.x : 'nonzero_x', p.y : 'nonzero_y'}) + + +def good_jacobian_point(p): + return constraints(nonzero={p.X : 'nonzero_X', p.Y : 'nonzero_Y', p.Z^6 : 'nonzero_Z'}) + + +def good_point(p): + return constraints(nonzero={p.Z^6 : 'nonzero_X'}) + + +def finite(p, *affine_fns): + con = good_point(p) + constraints(zero={p.Infinity : 'finite_point'}) + if p.Z != 0: + return con + reduce(lambda a, b: a + b, (f(affinepoint(p.X / p.Z^2, p.Y / p.Z^3)) for f in affine_fns), con) + else: + return con + +def infinite(p): + return constraints(nonzero={p.Infinity : 'infinite_point'}) + + +def law_jacobian_weierstrass_add(A, B, pa, pb, pA, pB, pC): + """Check whether the passed set of coordinates is a valid Jacobian add, given assumptions""" + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + on_weierstrass_curve(A, B, pb) + + finite(pA) + + finite(pB) + + constraints(nonzero={pa.x - pb.x : 'different_x'})) + require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) + + colinear(pa, pb, negate(pc)))) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_double(A, B, pa, pb, pA, pB, pC): + """Check whether the passed set of coordinates is a valid Jacobian doubling, given assumptions""" + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + on_weierstrass_curve(A, B, pb) + + finite(pA) + + finite(pB) + + constraints(zero={pa.x - pb.x : 'equal_x', pa.y - pb.y : 'equal_y'})) + require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) + + tangential_to_weierstrass_curve(A, B, pa, negate(pc)))) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_opposites(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + on_weierstrass_curve(A, B, pb) + + finite(pA) + + finite(pB) + + constraints(zero={pa.x - pb.x : 'equal_x', pa.y + pb.y : 'opposite_y'})) + require = infinite(pC) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_infinite_a(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pb) + + infinite(pA) + + finite(pB)) + require = finite(pC, lambda pc: constraints(zero={pc.x - pb.x : 'c.x=b.x', pc.y - pb.y : 'c.y=b.y'})) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_infinite_b(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + infinite(pB) + + finite(pA)) + require = finite(pC, lambda pc: constraints(zero={pc.x - pa.x : 'c.x=a.x', pc.y - pa.y : 'c.y=a.y'})) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_infinite_ab(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + infinite(pA) + + infinite(pB)) + require = infinite(pC) + return (assumeLaw, require) + + +laws_jacobian_weierstrass = { + 'add': law_jacobian_weierstrass_add, + 'double': law_jacobian_weierstrass_double, + 'add_opposite': law_jacobian_weierstrass_add_opposites, + 'add_infinite_a': law_jacobian_weierstrass_add_infinite_a, + 'add_infinite_b': law_jacobian_weierstrass_add_infinite_b, + 'add_infinite_ab': law_jacobian_weierstrass_add_infinite_ab +} + + +def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p): + """Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field""" + F = Integers(p) + print "Formula %s on Z%i:" % (name, p) + points = [] + for x in xrange(0, p): + for y in xrange(0, p): + point = affinepoint(F(x), F(y)) + r, e = concrete_verify(on_weierstrass_curve(A, B, point)) + if r: + points.append(point) + + for za in xrange(1, p): + for zb in xrange(1, p): + for pa in points: + for pb in points: + for ia in xrange(2): + for ib in xrange(2): + pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia) + pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib) + for branch in xrange(0, branches): + assumeAssert, assumeBranch, pC = formula(branch, pA, pB) + pC.X = F(pC.X) + pC.Y = F(pC.Y) + pC.Z = F(pC.Z) + pC.Infinity = F(pC.Infinity) + r, e = concrete_verify(assumeAssert + assumeBranch) + if r: + match = False + for key in laws_jacobian_weierstrass: + assumeLaw, require = laws_jacobian_weierstrass[key](A, B, pa, pb, pA, pB, pC) + r, e = concrete_verify(assumeLaw) + if r: + if match: + print " multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity) + else: + match = True + r, e = concrete_verify(require) + if not r: + print " failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e) + print + + +def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC): + assumeLaw, require = f(A, B, pa, pb, pA, pB, pC) + return check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require) + +def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula): + """Verify an implementation of addition of Jacobian points on a Weierstrass curve symbolically""" + R. = PolynomialRing(QQ,8,order='invlex') + lift = lambda x: fastfrac(R,x) + ax = lift(ax) + ay = lift(ay) + Az = lift(Az) + bx = lift(bx) + by = lift(by) + Bz = lift(Bz) + Ai = lift(Ai) + Bi = lift(Bi) + + pa = affinepoint(ax, ay, Ai) + pb = affinepoint(bx, by, Bi) + pA = jacobianpoint(ax * Az^2, ay * Az^3, Az, Ai) + pB = jacobianpoint(bx * Bz^2, by * Bz^3, Bz, Bi) + + res = {} + + for key in laws_jacobian_weierstrass: + res[key] = [] + + print ("Formula " + name + ":") + count = 0 + for branch in xrange(branches): + assumeFormula, assumeBranch, pC = formula(branch, pA, pB) + pC.X = lift(pC.X) + pC.Y = lift(pC.Y) + pC.Z = lift(pC.Z) + pC.Infinity = lift(pC.Infinity) + + for key in laws_jacobian_weierstrass: + res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch)) + + for key in res: + print " %s:" % key + val = res[key] + for x in val: + if x[0] is not None: + print " branch %i: %s" % (x[1], x[0]) + + print diff --git a/src/secp256k1/src/asm/field_10x26_arm.s b/src/secp256k1/src/asm/field_10x26_arm.s new file mode 100644 index 000000000..5df561f2f --- /dev/null +++ b/src/secp256k1/src/asm/field_10x26_arm.s @@ -0,0 +1,919 @@ +@ vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab syntax=armasm: +/********************************************************************** + * Copyright (c) 2014 Wladimir J. van der Laan * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ +/* +ARM implementation of field_10x26 inner loops. + +Note: + +- To avoid unnecessary loads and make use of available registers, two + 'passes' have every time been interleaved, with the odd passes accumulating c' and d' + which will be added to c and d respectively in the the even passes + +*/ + + .syntax unified + .arch armv7-a + @ eabi attributes - see readelf -A + .eabi_attribute 8, 1 @ Tag_ARM_ISA_use = yes + .eabi_attribute 9, 0 @ Tag_Thumb_ISA_use = no + .eabi_attribute 10, 0 @ Tag_FP_arch = none + .eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte + .eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP + .eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Agressive Speed + .eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6 + .text + + @ Field constants + .set field_R0, 0x3d10 + .set field_R1, 0x400 + .set field_not_M, 0xfc000000 @ ~M = ~0x3ffffff + + .align 2 + .global secp256k1_fe_mul_inner + .type secp256k1_fe_mul_inner, %function + @ Arguments: + @ r0 r Restrict: can overlap with a, not with b + @ r1 a + @ r2 b + @ Stack (total 4+10*4 = 44) + @ sp + #0 saved 'r' pointer + @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 +secp256k1_fe_mul_inner: + stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} + sub sp, sp, #48 @ frame=44 + alignment + str r0, [sp, #0] @ save result address, we need it only at the end + + /****************************************** + * Main computation code. + ****************************************** + + Allocation: + r0,r14,r7,r8 scratch + r1 a (pointer) + r2 b (pointer) + r3:r4 c + r5:r6 d + r11:r12 c' + r9:r10 d' + + Note: do not write to r[] here, it may overlap with a[] + */ + + /* A - interleaved with B */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #9*4] @ b[9] + ldr r0, [r1, #1*4] @ a[1] + umull r5, r6, r7, r8 @ d = a[0] * b[9] + ldr r14, [r2, #8*4] @ b[8] + umull r9, r10, r0, r8 @ d' = a[1] * b[9] + ldr r7, [r1, #2*4] @ a[2] + umlal r5, r6, r0, r14 @ d += a[1] * b[8] + ldr r8, [r2, #7*4] @ b[7] + umlal r9, r10, r7, r14 @ d' += a[2] * b[8] + ldr r0, [r1, #3*4] @ a[3] + umlal r5, r6, r7, r8 @ d += a[2] * b[7] + ldr r14, [r2, #6*4] @ b[6] + umlal r9, r10, r0, r8 @ d' += a[3] * b[7] + ldr r7, [r1, #4*4] @ a[4] + umlal r5, r6, r0, r14 @ d += a[3] * b[6] + ldr r8, [r2, #5*4] @ b[5] + umlal r9, r10, r7, r14 @ d' += a[4] * b[6] + ldr r0, [r1, #5*4] @ a[5] + umlal r5, r6, r7, r8 @ d += a[4] * b[5] + ldr r14, [r2, #4*4] @ b[4] + umlal r9, r10, r0, r8 @ d' += a[5] * b[5] + ldr r7, [r1, #6*4] @ a[6] + umlal r5, r6, r0, r14 @ d += a[5] * b[4] + ldr r8, [r2, #3*4] @ b[3] + umlal r9, r10, r7, r14 @ d' += a[6] * b[4] + ldr r0, [r1, #7*4] @ a[7] + umlal r5, r6, r7, r8 @ d += a[6] * b[3] + ldr r14, [r2, #2*4] @ b[2] + umlal r9, r10, r0, r8 @ d' += a[7] * b[3] + ldr r7, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r14 @ d += a[7] * b[2] + ldr r8, [r2, #1*4] @ b[1] + umlal r9, r10, r7, r14 @ d' += a[8] * b[2] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r8 @ d += a[8] * b[1] + ldr r14, [r2, #0*4] @ b[0] + umlal r9, r10, r0, r8 @ d' += a[9] * b[1] + ldr r7, [r1, #0*4] @ a[0] + umlal r5, r6, r0, r14 @ d += a[9] * b[0] + @ r7,r14 used in B + + bic r0, r5, field_not_M @ t9 = d & M + str r0, [sp, #4 + 4*9] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + /* B */ + umull r3, r4, r7, r14 @ c = a[0] * b[0] + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u0 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u0 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t0 = c & M + str r14, [sp, #4 + 0*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u0 * R1 + umlal r3, r4, r0, r14 + + /* C - interleaved with D */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #2*4] @ b[2] + ldr r14, [r2, #1*4] @ b[1] + umull r11, r12, r7, r8 @ c' = a[0] * b[2] + ldr r0, [r1, #1*4] @ a[1] + umlal r3, r4, r7, r14 @ c += a[0] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r11, r12, r0, r14 @ c' += a[1] * b[1] + ldr r7, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r8 @ c += a[1] * b[0] + ldr r14, [r2, #9*4] @ b[9] + umlal r11, r12, r7, r8 @ c' += a[2] * b[0] + ldr r0, [r1, #3*4] @ a[3] + umlal r5, r6, r7, r14 @ d += a[2] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umull r9, r10, r0, r14 @ d' = a[3] * b[9] + ldr r7, [r1, #4*4] @ a[4] + umlal r5, r6, r0, r8 @ d += a[3] * b[8] + ldr r14, [r2, #7*4] @ b[7] + umlal r9, r10, r7, r8 @ d' += a[4] * b[8] + ldr r0, [r1, #5*4] @ a[5] + umlal r5, r6, r7, r14 @ d += a[4] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r9, r10, r0, r14 @ d' += a[5] * b[7] + ldr r7, [r1, #6*4] @ a[6] + umlal r5, r6, r0, r8 @ d += a[5] * b[6] + ldr r14, [r2, #5*4] @ b[5] + umlal r9, r10, r7, r8 @ d' += a[6] * b[6] + ldr r0, [r1, #7*4] @ a[7] + umlal r5, r6, r7, r14 @ d += a[6] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r9, r10, r0, r14 @ d' += a[7] * b[5] + ldr r7, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r8 @ d += a[7] * b[4] + ldr r14, [r2, #3*4] @ b[3] + umlal r9, r10, r7, r8 @ d' += a[8] * b[4] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r14 @ d += a[8] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r9, r10, r0, r14 @ d' += a[9] * b[3] + umlal r5, r6, r0, r8 @ d += a[9] * b[2] + + bic r0, r5, field_not_M @ u1 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u1 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t1 = c & M + str r14, [sp, #4 + 1*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u1 * R1 + umlal r3, r4, r0, r14 + + /* D */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u2 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u2 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t2 = c & M + str r14, [sp, #4 + 2*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u2 * R1 + umlal r3, r4, r0, r14 + + /* E - interleaved with F */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #4*4] @ b[4] + umull r11, r12, r7, r8 @ c' = a[0] * b[4] + ldr r8, [r2, #3*4] @ b[3] + umlal r3, r4, r7, r8 @ c += a[0] * b[3] + ldr r7, [r1, #1*4] @ a[1] + umlal r11, r12, r7, r8 @ c' += a[1] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r3, r4, r7, r8 @ c += a[1] * b[2] + ldr r7, [r1, #2*4] @ a[2] + umlal r11, r12, r7, r8 @ c' += a[2] * b[2] + ldr r8, [r2, #1*4] @ b[1] + umlal r3, r4, r7, r8 @ c += a[2] * b[1] + ldr r7, [r1, #3*4] @ a[3] + umlal r11, r12, r7, r8 @ c' += a[3] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r3, r4, r7, r8 @ c += a[3] * b[0] + ldr r7, [r1, #4*4] @ a[4] + umlal r11, r12, r7, r8 @ c' += a[4] * b[0] + ldr r8, [r2, #9*4] @ b[9] + umlal r5, r6, r7, r8 @ d += a[4] * b[9] + ldr r7, [r1, #5*4] @ a[5] + umull r9, r10, r7, r8 @ d' = a[5] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umlal r5, r6, r7, r8 @ d += a[5] * b[8] + ldr r7, [r1, #6*4] @ a[6] + umlal r9, r10, r7, r8 @ d' += a[6] * b[8] + ldr r8, [r2, #7*4] @ b[7] + umlal r5, r6, r7, r8 @ d += a[6] * b[7] + ldr r7, [r1, #7*4] @ a[7] + umlal r9, r10, r7, r8 @ d' += a[7] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r5, r6, r7, r8 @ d += a[7] * b[6] + ldr r7, [r1, #8*4] @ a[8] + umlal r9, r10, r7, r8 @ d' += a[8] * b[6] + ldr r8, [r2, #5*4] @ b[5] + umlal r5, r6, r7, r8 @ d += a[8] * b[5] + ldr r7, [r1, #9*4] @ a[9] + umlal r9, r10, r7, r8 @ d' += a[9] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r5, r6, r7, r8 @ d += a[9] * b[4] + + bic r0, r5, field_not_M @ u3 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u3 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t3 = c & M + str r14, [sp, #4 + 3*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u3 * R1 + umlal r3, r4, r0, r14 + + /* F */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u4 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u4 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t4 = c & M + str r14, [sp, #4 + 4*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u4 * R1 + umlal r3, r4, r0, r14 + + /* G - interleaved with H */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #6*4] @ b[6] + ldr r14, [r2, #5*4] @ b[5] + umull r11, r12, r7, r8 @ c' = a[0] * b[6] + ldr r0, [r1, #1*4] @ a[1] + umlal r3, r4, r7, r14 @ c += a[0] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r11, r12, r0, r14 @ c' += a[1] * b[5] + ldr r7, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r8 @ c += a[1] * b[4] + ldr r14, [r2, #3*4] @ b[3] + umlal r11, r12, r7, r8 @ c' += a[2] * b[4] + ldr r0, [r1, #3*4] @ a[3] + umlal r3, r4, r7, r14 @ c += a[2] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r11, r12, r0, r14 @ c' += a[3] * b[3] + ldr r7, [r1, #4*4] @ a[4] + umlal r3, r4, r0, r8 @ c += a[3] * b[2] + ldr r14, [r2, #1*4] @ b[1] + umlal r11, r12, r7, r8 @ c' += a[4] * b[2] + ldr r0, [r1, #5*4] @ a[5] + umlal r3, r4, r7, r14 @ c += a[4] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r11, r12, r0, r14 @ c' += a[5] * b[1] + ldr r7, [r1, #6*4] @ a[6] + umlal r3, r4, r0, r8 @ c += a[5] * b[0] + ldr r14, [r2, #9*4] @ b[9] + umlal r11, r12, r7, r8 @ c' += a[6] * b[0] + ldr r0, [r1, #7*4] @ a[7] + umlal r5, r6, r7, r14 @ d += a[6] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umull r9, r10, r0, r14 @ d' = a[7] * b[9] + ldr r7, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r8 @ d += a[7] * b[8] + ldr r14, [r2, #7*4] @ b[7] + umlal r9, r10, r7, r8 @ d' += a[8] * b[8] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r14 @ d += a[8] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r9, r10, r0, r14 @ d' += a[9] * b[7] + umlal r5, r6, r0, r8 @ d += a[9] * b[6] + + bic r0, r5, field_not_M @ u5 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u5 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t5 = c & M + str r14, [sp, #4 + 5*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u5 * R1 + umlal r3, r4, r0, r14 + + /* H */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u6 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u6 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t6 = c & M + str r14, [sp, #4 + 6*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u6 * R1 + umlal r3, r4, r0, r14 + + /* I - interleaved with J */ + ldr r8, [r2, #8*4] @ b[8] + ldr r7, [r1, #0*4] @ a[0] + ldr r14, [r2, #7*4] @ b[7] + umull r11, r12, r7, r8 @ c' = a[0] * b[8] + ldr r0, [r1, #1*4] @ a[1] + umlal r3, r4, r7, r14 @ c += a[0] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r11, r12, r0, r14 @ c' += a[1] * b[7] + ldr r7, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r8 @ c += a[1] * b[6] + ldr r14, [r2, #5*4] @ b[5] + umlal r11, r12, r7, r8 @ c' += a[2] * b[6] + ldr r0, [r1, #3*4] @ a[3] + umlal r3, r4, r7, r14 @ c += a[2] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r11, r12, r0, r14 @ c' += a[3] * b[5] + ldr r7, [r1, #4*4] @ a[4] + umlal r3, r4, r0, r8 @ c += a[3] * b[4] + ldr r14, [r2, #3*4] @ b[3] + umlal r11, r12, r7, r8 @ c' += a[4] * b[4] + ldr r0, [r1, #5*4] @ a[5] + umlal r3, r4, r7, r14 @ c += a[4] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r11, r12, r0, r14 @ c' += a[5] * b[3] + ldr r7, [r1, #6*4] @ a[6] + umlal r3, r4, r0, r8 @ c += a[5] * b[2] + ldr r14, [r2, #1*4] @ b[1] + umlal r11, r12, r7, r8 @ c' += a[6] * b[2] + ldr r0, [r1, #7*4] @ a[7] + umlal r3, r4, r7, r14 @ c += a[6] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r11, r12, r0, r14 @ c' += a[7] * b[1] + ldr r7, [r1, #8*4] @ a[8] + umlal r3, r4, r0, r8 @ c += a[7] * b[0] + ldr r14, [r2, #9*4] @ b[9] + umlal r11, r12, r7, r8 @ c' += a[8] * b[0] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r14 @ d += a[8] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umull r9, r10, r0, r14 @ d' = a[9] * b[9] + umlal r5, r6, r0, r8 @ d += a[9] * b[8] + + bic r0, r5, field_not_M @ u7 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u7 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t7 = c & M + str r14, [sp, #4 + 7*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u7 * R1 + umlal r3, r4, r0, r14 + + /* J */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u8 = d & M + str r0, [sp, #4 + 8*4] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u8 * R0 + umlal r3, r4, r0, r14 + + /****************************************** + * compute and write back result + ****************************************** + Allocation: + r0 r + r3:r4 c + r5:r6 d + r7 t0 + r8 t1 + r9 t2 + r11 u8 + r12 t9 + r1,r2,r10,r14 scratch + + Note: do not read from a[] after here, it may overlap with r[] + */ + ldr r0, [sp, #0] + add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9 + ldmia r1, {r2,r7,r8,r9,r10,r11,r12} + add r1, r0, #3*4 + stmia r1, {r2,r7,r8,r9,r10} + + bic r2, r3, field_not_M @ r[8] = c & M + str r2, [r0, #8*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u8 * R1 + umlal r3, r4, r11, r14 + movw r14, field_R0 @ c += d * R0 + umlal r3, r4, r5, r14 + adds r3, r3, r12 @ c += t9 + adc r4, r4, #0 + + add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2 + ldmia r1, {r7,r8,r9} + + ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4) + str r2, [r0, #9*4] + mov r3, r3, lsr #22 @ c >>= 22 + orr r3, r3, r4, asl #10 + mov r4, r4, lsr #22 + movw r14, field_R1 << 4 @ c += d * (R1 << 4) + umlal r3, r4, r5, r14 + + movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add) + umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4) + adds r5, r5, r7 @ d.lo += t0 + mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4) + adc r6, r6, 0 @ d.hi += carry + + bic r2, r5, field_not_M @ r[0] = d & M + str r2, [r0, #0*4] + + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add) + umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4) + adds r5, r5, r8 @ d.lo += t1 + adc r6, r6, #0 @ d.hi += carry + adds r5, r5, r1 @ d.lo += tmp.lo + mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4) + adc r6, r6, r2 @ d.hi += carry + tmp.hi + + bic r2, r5, field_not_M @ r[1] = d & M + str r2, [r0, #1*4] + mov r5, r5, lsr #26 @ d >>= 26 (ignore hi) + orr r5, r5, r6, asl #6 + + add r5, r5, r9 @ d += t2 + str r5, [r0, #2*4] @ r[2] = d + + add sp, sp, #48 + ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} + .size secp256k1_fe_mul_inner, .-secp256k1_fe_mul_inner + + .align 2 + .global secp256k1_fe_sqr_inner + .type secp256k1_fe_sqr_inner, %function + @ Arguments: + @ r0 r Can overlap with a + @ r1 a + @ Stack (total 4+10*4 = 44) + @ sp + #0 saved 'r' pointer + @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 +secp256k1_fe_sqr_inner: + stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} + sub sp, sp, #48 @ frame=44 + alignment + str r0, [sp, #0] @ save result address, we need it only at the end + /****************************************** + * Main computation code. + ****************************************** + + Allocation: + r0,r14,r2,r7,r8 scratch + r1 a (pointer) + r3:r4 c + r5:r6 d + r11:r12 c' + r9:r10 d' + + Note: do not write to r[] here, it may overlap with a[] + */ + /* A interleaved with B */ + ldr r0, [r1, #1*4] @ a[1]*2 + ldr r7, [r1, #0*4] @ a[0] + mov r0, r0, asl #1 + ldr r14, [r1, #9*4] @ a[9] + umull r3, r4, r7, r7 @ c = a[0] * a[0] + ldr r8, [r1, #8*4] @ a[8] + mov r7, r7, asl #1 + umull r5, r6, r7, r14 @ d = a[0]*2 * a[9] + ldr r7, [r1, #2*4] @ a[2]*2 + umull r9, r10, r0, r14 @ d' = a[1]*2 * a[9] + ldr r14, [r1, #7*4] @ a[7] + umlal r5, r6, r0, r8 @ d += a[1]*2 * a[8] + mov r7, r7, asl #1 + ldr r0, [r1, #3*4] @ a[3]*2 + umlal r9, r10, r7, r8 @ d' += a[2]*2 * a[8] + ldr r8, [r1, #6*4] @ a[6] + umlal r5, r6, r7, r14 @ d += a[2]*2 * a[7] + mov r0, r0, asl #1 + ldr r7, [r1, #4*4] @ a[4]*2 + umlal r9, r10, r0, r14 @ d' += a[3]*2 * a[7] + ldr r14, [r1, #5*4] @ a[5] + mov r7, r7, asl #1 + umlal r5, r6, r0, r8 @ d += a[3]*2 * a[6] + umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[6] + umlal r5, r6, r7, r14 @ d += a[4]*2 * a[5] + umlal r9, r10, r14, r14 @ d' += a[5] * a[5] + + bic r0, r5, field_not_M @ t9 = d & M + str r0, [sp, #4 + 9*4] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + /* B */ + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u0 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u0 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t0 = c & M + str r14, [sp, #4 + 0*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u0 * R1 + umlal r3, r4, r0, r14 + + /* C interleaved with D */ + ldr r0, [r1, #0*4] @ a[0]*2 + ldr r14, [r1, #1*4] @ a[1] + mov r0, r0, asl #1 + ldr r8, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r14 @ c += a[0]*2 * a[1] + mov r7, r8, asl #1 @ a[2]*2 + umull r11, r12, r14, r14 @ c' = a[1] * a[1] + ldr r14, [r1, #9*4] @ a[9] + umlal r11, r12, r0, r8 @ c' += a[0]*2 * a[2] + ldr r0, [r1, #3*4] @ a[3]*2 + ldr r8, [r1, #8*4] @ a[8] + umlal r5, r6, r7, r14 @ d += a[2]*2 * a[9] + mov r0, r0, asl #1 + ldr r7, [r1, #4*4] @ a[4]*2 + umull r9, r10, r0, r14 @ d' = a[3]*2 * a[9] + ldr r14, [r1, #7*4] @ a[7] + umlal r5, r6, r0, r8 @ d += a[3]*2 * a[8] + mov r7, r7, asl #1 + ldr r0, [r1, #5*4] @ a[5]*2 + umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[8] + ldr r8, [r1, #6*4] @ a[6] + mov r0, r0, asl #1 + umlal r5, r6, r7, r14 @ d += a[4]*2 * a[7] + umlal r9, r10, r0, r14 @ d' += a[5]*2 * a[7] + umlal r5, r6, r0, r8 @ d += a[5]*2 * a[6] + umlal r9, r10, r8, r8 @ d' += a[6] * a[6] + + bic r0, r5, field_not_M @ u1 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u1 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t1 = c & M + str r14, [sp, #4 + 1*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u1 * R1 + umlal r3, r4, r0, r14 + + /* D */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u2 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u2 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t2 = c & M + str r14, [sp, #4 + 2*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u2 * R1 + umlal r3, r4, r0, r14 + + /* E interleaved with F */ + ldr r7, [r1, #0*4] @ a[0]*2 + ldr r0, [r1, #1*4] @ a[1]*2 + ldr r14, [r1, #2*4] @ a[2] + mov r7, r7, asl #1 + ldr r8, [r1, #3*4] @ a[3] + ldr r2, [r1, #4*4] + umlal r3, r4, r7, r8 @ c += a[0]*2 * a[3] + mov r0, r0, asl #1 + umull r11, r12, r7, r2 @ c' = a[0]*2 * a[4] + mov r2, r2, asl #1 @ a[4]*2 + umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[3] + ldr r8, [r1, #9*4] @ a[9] + umlal r3, r4, r0, r14 @ c += a[1]*2 * a[2] + ldr r0, [r1, #5*4] @ a[5]*2 + umlal r11, r12, r14, r14 @ c' += a[2] * a[2] + ldr r14, [r1, #8*4] @ a[8] + mov r0, r0, asl #1 + umlal r5, r6, r2, r8 @ d += a[4]*2 * a[9] + ldr r7, [r1, #6*4] @ a[6]*2 + umull r9, r10, r0, r8 @ d' = a[5]*2 * a[9] + mov r7, r7, asl #1 + ldr r8, [r1, #7*4] @ a[7] + umlal r5, r6, r0, r14 @ d += a[5]*2 * a[8] + umlal r9, r10, r7, r14 @ d' += a[6]*2 * a[8] + umlal r5, r6, r7, r8 @ d += a[6]*2 * a[7] + umlal r9, r10, r8, r8 @ d' += a[7] * a[7] + + bic r0, r5, field_not_M @ u3 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u3 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t3 = c & M + str r14, [sp, #4 + 3*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u3 * R1 + umlal r3, r4, r0, r14 + + /* F */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u4 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u4 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t4 = c & M + str r14, [sp, #4 + 4*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u4 * R1 + umlal r3, r4, r0, r14 + + /* G interleaved with H */ + ldr r7, [r1, #0*4] @ a[0]*2 + ldr r0, [r1, #1*4] @ a[1]*2 + mov r7, r7, asl #1 + ldr r8, [r1, #5*4] @ a[5] + ldr r2, [r1, #6*4] @ a[6] + umlal r3, r4, r7, r8 @ c += a[0]*2 * a[5] + ldr r14, [r1, #4*4] @ a[4] + mov r0, r0, asl #1 + umull r11, r12, r7, r2 @ c' = a[0]*2 * a[6] + ldr r7, [r1, #2*4] @ a[2]*2 + umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[5] + mov r7, r7, asl #1 + ldr r8, [r1, #3*4] @ a[3] + umlal r3, r4, r0, r14 @ c += a[1]*2 * a[4] + mov r0, r2, asl #1 @ a[6]*2 + umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[4] + ldr r14, [r1, #9*4] @ a[9] + umlal r3, r4, r7, r8 @ c += a[2]*2 * a[3] + ldr r7, [r1, #7*4] @ a[7]*2 + umlal r11, r12, r8, r8 @ c' += a[3] * a[3] + mov r7, r7, asl #1 + ldr r8, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r14 @ d += a[6]*2 * a[9] + umull r9, r10, r7, r14 @ d' = a[7]*2 * a[9] + umlal r5, r6, r7, r8 @ d += a[7]*2 * a[8] + umlal r9, r10, r8, r8 @ d' += a[8] * a[8] + + bic r0, r5, field_not_M @ u5 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u5 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t5 = c & M + str r14, [sp, #4 + 5*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u5 * R1 + umlal r3, r4, r0, r14 + + /* H */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u6 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u6 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t6 = c & M + str r14, [sp, #4 + 6*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u6 * R1 + umlal r3, r4, r0, r14 + + /* I interleaved with J */ + ldr r7, [r1, #0*4] @ a[0]*2 + ldr r0, [r1, #1*4] @ a[1]*2 + mov r7, r7, asl #1 + ldr r8, [r1, #7*4] @ a[7] + ldr r2, [r1, #8*4] @ a[8] + umlal r3, r4, r7, r8 @ c += a[0]*2 * a[7] + ldr r14, [r1, #6*4] @ a[6] + mov r0, r0, asl #1 + umull r11, r12, r7, r2 @ c' = a[0]*2 * a[8] + ldr r7, [r1, #2*4] @ a[2]*2 + umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[7] + ldr r8, [r1, #5*4] @ a[5] + umlal r3, r4, r0, r14 @ c += a[1]*2 * a[6] + ldr r0, [r1, #3*4] @ a[3]*2 + mov r7, r7, asl #1 + umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[6] + ldr r14, [r1, #4*4] @ a[4] + mov r0, r0, asl #1 + umlal r3, r4, r7, r8 @ c += a[2]*2 * a[5] + mov r2, r2, asl #1 @ a[8]*2 + umlal r11, r12, r0, r8 @ c' += a[3]*2 * a[5] + umlal r3, r4, r0, r14 @ c += a[3]*2 * a[4] + umlal r11, r12, r14, r14 @ c' += a[4] * a[4] + ldr r8, [r1, #9*4] @ a[9] + umlal r5, r6, r2, r8 @ d += a[8]*2 * a[9] + @ r8 will be used in J + + bic r0, r5, field_not_M @ u7 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u7 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t7 = c & M + str r14, [sp, #4 + 7*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u7 * R1 + umlal r3, r4, r0, r14 + + /* J */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + umlal r5, r6, r8, r8 @ d += a[9] * a[9] + + bic r0, r5, field_not_M @ u8 = d & M + str r0, [sp, #4 + 8*4] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u8 * R0 + umlal r3, r4, r0, r14 + + /****************************************** + * compute and write back result + ****************************************** + Allocation: + r0 r + r3:r4 c + r5:r6 d + r7 t0 + r8 t1 + r9 t2 + r11 u8 + r12 t9 + r1,r2,r10,r14 scratch + + Note: do not read from a[] after here, it may overlap with r[] + */ + ldr r0, [sp, #0] + add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9 + ldmia r1, {r2,r7,r8,r9,r10,r11,r12} + add r1, r0, #3*4 + stmia r1, {r2,r7,r8,r9,r10} + + bic r2, r3, field_not_M @ r[8] = c & M + str r2, [r0, #8*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u8 * R1 + umlal r3, r4, r11, r14 + movw r14, field_R0 @ c += d * R0 + umlal r3, r4, r5, r14 + adds r3, r3, r12 @ c += t9 + adc r4, r4, #0 + + add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2 + ldmia r1, {r7,r8,r9} + + ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4) + str r2, [r0, #9*4] + mov r3, r3, lsr #22 @ c >>= 22 + orr r3, r3, r4, asl #10 + mov r4, r4, lsr #22 + movw r14, field_R1 << 4 @ c += d * (R1 << 4) + umlal r3, r4, r5, r14 + + movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add) + umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4) + adds r5, r5, r7 @ d.lo += t0 + mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4) + adc r6, r6, 0 @ d.hi += carry + + bic r2, r5, field_not_M @ r[0] = d & M + str r2, [r0, #0*4] + + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add) + umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4) + adds r5, r5, r8 @ d.lo += t1 + adc r6, r6, #0 @ d.hi += carry + adds r5, r5, r1 @ d.lo += tmp.lo + mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4) + adc r6, r6, r2 @ d.hi += carry + tmp.hi + + bic r2, r5, field_not_M @ r[1] = d & M + str r2, [r0, #1*4] + mov r5, r5, lsr #26 @ d >>= 26 (ignore hi) + orr r5, r5, r6, asl #6 + + add r5, r5, r9 @ d += t2 + str r5, [r0, #2*4] @ r[2] = d + + add sp, sp, #48 + ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} + .size secp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner + diff --git a/src/secp256k1/src/basic-config.h b/src/secp256k1/src/basic-config.h new file mode 100644 index 000000000..c4c16eb7c --- /dev/null +++ b/src/secp256k1/src/basic-config.h @@ -0,0 +1,32 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_BASIC_CONFIG_ +#define _SECP256K1_BASIC_CONFIG_ + +#ifdef USE_BASIC_CONFIG + +#undef USE_ASM_X86_64 +#undef USE_ENDOMORPHISM +#undef USE_FIELD_10X26 +#undef USE_FIELD_5X52 +#undef USE_FIELD_INV_BUILTIN +#undef USE_FIELD_INV_NUM +#undef USE_NUM_GMP +#undef USE_NUM_NONE +#undef USE_SCALAR_4X64 +#undef USE_SCALAR_8X32 +#undef USE_SCALAR_INV_BUILTIN +#undef USE_SCALAR_INV_NUM + +#define USE_NUM_NONE 1 +#define USE_FIELD_INV_BUILTIN 1 +#define USE_SCALAR_INV_BUILTIN 1 +#define USE_FIELD_10X26 1 +#define USE_SCALAR_8X32 1 + +#endif // USE_BASIC_CONFIG +#endif // _SECP256K1_BASIC_CONFIG_ diff --git a/src/secp256k1/src/bench.h b/src/secp256k1/src/bench.h new file mode 100644 index 000000000..3a71b4aaf --- /dev/null +++ b/src/secp256k1/src/bench.h @@ -0,0 +1,66 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_BENCH_H_ +#define _SECP256K1_BENCH_H_ + +#include +#include +#include "sys/time.h" + +static double gettimedouble(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_usec * 0.000001 + tv.tv_sec; +} + +void print_number(double x) { + double y = x; + int c = 0; + if (y < 0.0) { + y = -y; + } + while (y < 100.0) { + y *= 10.0; + c++; + } + printf("%.*f", c, x); +} + +void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), void (*teardown)(void*), void* data, int count, int iter) { + int i; + double min = HUGE_VAL; + double sum = 0.0; + double max = 0.0; + for (i = 0; i < count; i++) { + double begin, total; + if (setup != NULL) { + setup(data); + } + begin = gettimedouble(); + benchmark(data); + total = gettimedouble() - begin; + if (teardown != NULL) { + teardown(data); + } + if (total < min) { + min = total; + } + if (total > max) { + max = total; + } + sum += total; + } + printf("%s: min ", name); + print_number(min * 1000000.0 / iter); + printf("us / avg "); + print_number((sum / count) * 1000000.0 / iter); + printf("us / max "); + print_number(max * 1000000.0 / iter); + printf("us\n"); +} + +#endif diff --git a/src/secp256k1/src/bench_ecdh.c b/src/secp256k1/src/bench_ecdh.c new file mode 100644 index 000000000..cde5e2dbb --- /dev/null +++ b/src/secp256k1/src/bench_ecdh.c @@ -0,0 +1,54 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include + +#include "include/secp256k1.h" +#include "include/secp256k1_ecdh.h" +#include "util.h" +#include "bench.h" + +typedef struct { + secp256k1_context *ctx; + secp256k1_pubkey point; + unsigned char scalar[32]; +} bench_ecdh_t; + +static void bench_ecdh_setup(void* arg) { + int i; + bench_ecdh_t *data = (bench_ecdh_t*)arg; + const unsigned char point[] = { + 0x03, + 0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06, + 0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd, + 0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb, + 0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f + }; + + /* create a context with no capabilities */ + data->ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT); + for (i = 0; i < 32; i++) { + data->scalar[i] = i + 1; + } + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1); +} + +static void bench_ecdh(void* arg) { + int i; + unsigned char res[32]; + bench_ecdh_t *data = (bench_ecdh_t*)arg; + + for (i = 0; i < 20000; i++) { + CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar) == 1); + } +} + +int main(void) { + bench_ecdh_t data; + + run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, 20000); + return 0; +} diff --git a/src/secp256k1/src/bench_internal.c b/src/secp256k1/src/bench_internal.c new file mode 100644 index 000000000..0809f77bd --- /dev/null +++ b/src/secp256k1/src/bench_internal.c @@ -0,0 +1,382 @@ +/********************************************************************** + * Copyright (c) 2014-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ +#include + +#include "include/secp256k1.h" + +#include "util.h" +#include "hash_impl.h" +#include "num_impl.h" +#include "field_impl.h" +#include "group_impl.h" +#include "scalar_impl.h" +#include "ecmult_const_impl.h" +#include "ecmult_impl.h" +#include "bench.h" +#include "secp256k1.c" + +typedef struct { + secp256k1_scalar scalar_x, scalar_y; + secp256k1_fe fe_x, fe_y; + secp256k1_ge ge_x, ge_y; + secp256k1_gej gej_x, gej_y; + unsigned char data[64]; + int wnaf[256]; +} bench_inv_t; + +void bench_setup(void* arg) { + bench_inv_t *data = (bench_inv_t*)arg; + + static const unsigned char init_x[32] = { + 0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13, + 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35, + 0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59, + 0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83 + }; + + static const unsigned char init_y[32] = { + 0x82, 0x83, 0x85, 0x87, 0x8b, 0x8d, 0x81, 0x83, + 0x97, 0xad, 0xaf, 0xb5, 0xb9, 0xbb, 0xbf, 0xc5, + 0xdb, 0xdd, 0xe3, 0xe7, 0xe9, 0xef, 0xf3, 0xf9, + 0x11, 0x15, 0x17, 0x1b, 0x1d, 0xb1, 0xbf, 0xd3 + }; + + secp256k1_scalar_set_b32(&data->scalar_x, init_x, NULL); + secp256k1_scalar_set_b32(&data->scalar_y, init_y, NULL); + secp256k1_fe_set_b32(&data->fe_x, init_x); + secp256k1_fe_set_b32(&data->fe_y, init_y); + CHECK(secp256k1_ge_set_xo_var(&data->ge_x, &data->fe_x, 0)); + CHECK(secp256k1_ge_set_xo_var(&data->ge_y, &data->fe_y, 1)); + secp256k1_gej_set_ge(&data->gej_x, &data->ge_x); + secp256k1_gej_set_ge(&data->gej_y, &data->ge_y); + memcpy(data->data, init_x, 32); + memcpy(data->data + 32, init_y, 32); +} + +void bench_scalar_add(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 2000000; i++) { + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +void bench_scalar_negate(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 2000000; i++) { + secp256k1_scalar_negate(&data->scalar_x, &data->scalar_x); + } +} + +void bench_scalar_sqr(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_scalar_sqr(&data->scalar_x, &data->scalar_x); + } +} + +void bench_scalar_mul(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_scalar_mul(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +#ifdef USE_ENDOMORPHISM +void bench_scalar_split(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_scalar l, r; + secp256k1_scalar_split_lambda(&l, &r, &data->scalar_x); + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} +#endif + +void bench_scalar_inverse(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 2000; i++) { + secp256k1_scalar_inverse(&data->scalar_x, &data->scalar_x); + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +void bench_scalar_inverse_var(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 2000; i++) { + secp256k1_scalar_inverse_var(&data->scalar_x, &data->scalar_x); + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +void bench_field_normalize(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 2000000; i++) { + secp256k1_fe_normalize(&data->fe_x); + } +} + +void bench_field_normalize_weak(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 2000000; i++) { + secp256k1_fe_normalize_weak(&data->fe_x); + } +} + +void bench_field_mul(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_fe_mul(&data->fe_x, &data->fe_x, &data->fe_y); + } +} + +void bench_field_sqr(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_fe_sqr(&data->fe_x, &data->fe_x); + } +} + +void bench_field_inverse(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_fe_inv(&data->fe_x, &data->fe_x); + secp256k1_fe_add(&data->fe_x, &data->fe_y); + } +} + +void bench_field_inverse_var(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_fe_inv_var(&data->fe_x, &data->fe_x); + secp256k1_fe_add(&data->fe_x, &data->fe_y); + } +} + +void bench_field_sqrt(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_fe_sqrt(&data->fe_x, &data->fe_x); + secp256k1_fe_add(&data->fe_x, &data->fe_y); + } +} + +void bench_group_double_var(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_gej_double_var(&data->gej_x, &data->gej_x, NULL); + } +} + +void bench_group_add_var(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y, NULL); + } +} + +void bench_group_add_affine(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_gej_add_ge(&data->gej_x, &data->gej_x, &data->ge_y); + } +} + +void bench_group_add_affine_var(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y, NULL); + } +} + +void bench_group_jacobi_var(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_gej_has_quad_y_var(&data->gej_x); + } +} + +void bench_ecmult_wnaf(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar_x, WINDOW_A); + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +void bench_wnaf_const(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A); + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + + +void bench_sha256(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + secp256k1_sha256_t sha; + + for (i = 0; i < 20000; i++) { + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, data->data, 32); + secp256k1_sha256_finalize(&sha, data->data); + } +} + +void bench_hmac_sha256(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + secp256k1_hmac_sha256_t hmac; + + for (i = 0; i < 20000; i++) { + secp256k1_hmac_sha256_initialize(&hmac, data->data, 32); + secp256k1_hmac_sha256_write(&hmac, data->data, 32); + secp256k1_hmac_sha256_finalize(&hmac, data->data); + } +} + +void bench_rfc6979_hmac_sha256(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + secp256k1_rfc6979_hmac_sha256_t rng; + + for (i = 0; i < 20000; i++) { + secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64); + secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32); + } +} + +void bench_context_verify(void* arg) { + int i; + (void)arg; + for (i = 0; i < 20; i++) { + secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_VERIFY)); + } +} + +void bench_context_sign(void* arg) { + int i; + (void)arg; + for (i = 0; i < 200; i++) { + secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_SIGN)); + } +} + +#ifndef USE_NUM_NONE +void bench_num_jacobi(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + secp256k1_num nx, norder; + + secp256k1_scalar_get_num(&nx, &data->scalar_x); + secp256k1_scalar_order_get_num(&norder); + secp256k1_scalar_get_num(&norder, &data->scalar_y); + + for (i = 0; i < 200000; i++) { + secp256k1_num_jacobi(&nx, &norder); + } +} +#endif + +int have_flag(int argc, char** argv, char *flag) { + char** argm = argv + argc; + argv++; + if (argv == argm) { + return 1; + } + while (argv != NULL && argv != argm) { + if (strcmp(*argv, flag) == 0) { + return 1; + } + argv++; + } + return 0; +} + +int main(int argc, char **argv) { + bench_inv_t data; + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, 2000000); + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, 2000000); + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, 200000); +#ifdef USE_ENDOMORPHISM + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, 20000); +#endif + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, 2000); + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse_var", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, 2000); + + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, 2000000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, 2000000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, 20000); + + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, 20000); + + if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000); + + if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, 20000); + + if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 20); + if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 200); + +#ifndef USE_NUM_NONE + if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, 200000); +#endif + return 0; +} diff --git a/src/secp256k1/src/bench_recover.c b/src/secp256k1/src/bench_recover.c new file mode 100644 index 000000000..6489378cc --- /dev/null +++ b/src/secp256k1/src/bench_recover.c @@ -0,0 +1,60 @@ +/********************************************************************** + * Copyright (c) 2014-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include "include/secp256k1.h" +#include "include/secp256k1_recovery.h" +#include "util.h" +#include "bench.h" + +typedef struct { + secp256k1_context *ctx; + unsigned char msg[32]; + unsigned char sig[64]; +} bench_recover_t; + +void bench_recover(void* arg) { + int i; + bench_recover_t *data = (bench_recover_t*)arg; + secp256k1_pubkey pubkey; + unsigned char pubkeyc[33]; + + for (i = 0; i < 20000; i++) { + int j; + size_t pubkeylen = 33; + secp256k1_ecdsa_recoverable_signature sig; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(data->ctx, &sig, data->sig, i % 2)); + CHECK(secp256k1_ecdsa_recover(data->ctx, &pubkey, &sig, data->msg)); + CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pubkeyc, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED)); + for (j = 0; j < 32; j++) { + data->sig[j + 32] = data->msg[j]; /* Move former message to S. */ + data->msg[j] = data->sig[j]; /* Move former R to message. */ + data->sig[j] = pubkeyc[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */ + } + } +} + +void bench_recover_setup(void* arg) { + int i; + bench_recover_t *data = (bench_recover_t*)arg; + + for (i = 0; i < 32; i++) { + data->msg[i] = 1 + i; + } + for (i = 0; i < 64; i++) { + data->sig[i] = 65 + i; + } +} + +int main(void) { + bench_recover_t data; + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + + run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, 20000); + + secp256k1_context_destroy(data.ctx); + return 0; +} diff --git a/src/secp256k1/src/bench_schnorr_verify.c b/src/secp256k1/src/bench_schnorr_verify.c new file mode 100644 index 000000000..5f137dda2 --- /dev/null +++ b/src/secp256k1/src/bench_schnorr_verify.c @@ -0,0 +1,73 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "include/secp256k1.h" +#include "include/secp256k1_schnorr.h" +#include "util.h" +#include "bench.h" + +typedef struct { + unsigned char key[32]; + unsigned char sig[64]; + unsigned char pubkey[33]; + size_t pubkeylen; +} benchmark_schnorr_sig_t; + +typedef struct { + secp256k1_context *ctx; + unsigned char msg[32]; + benchmark_schnorr_sig_t sigs[64]; + int numsigs; +} benchmark_schnorr_verify_t; + +static void benchmark_schnorr_init(void* arg) { + int i, k; + benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg; + + for (i = 0; i < 32; i++) { + data->msg[i] = 1 + i; + } + for (k = 0; k < data->numsigs; k++) { + secp256k1_pubkey pubkey; + for (i = 0; i < 32; i++) { + data->sigs[k].key[i] = 33 + i + k; + } + secp256k1_schnorr_sign(data->ctx, data->sigs[k].sig, data->msg, data->sigs[k].key, NULL, NULL); + data->sigs[k].pubkeylen = 33; + CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->sigs[k].key)); + CHECK(secp256k1_ec_pubkey_serialize(data->ctx, data->sigs[k].pubkey, &data->sigs[k].pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED)); + } +} + +static void benchmark_schnorr_verify(void* arg) { + int i; + benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg; + + for (i = 0; i < 20000 / data->numsigs; i++) { + secp256k1_pubkey pubkey; + data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF); + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->sigs[0].pubkey, data->sigs[0].pubkeylen)); + CHECK(secp256k1_schnorr_verify(data->ctx, data->sigs[0].sig, data->msg, &pubkey) == ((i & 0xFF) == 0)); + data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF); + } +} + + + +int main(void) { + benchmark_schnorr_verify_t data; + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + data.numsigs = 1; + run_benchmark("schnorr_verify", benchmark_schnorr_verify, benchmark_schnorr_init, NULL, &data, 10, 20000); + + secp256k1_context_destroy(data.ctx); + return 0; +} diff --git a/src/secp256k1/src/bench_sign.c b/src/secp256k1/src/bench_sign.c new file mode 100644 index 000000000..ed7224d75 --- /dev/null +++ b/src/secp256k1/src/bench_sign.c @@ -0,0 +1,56 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include "include/secp256k1.h" +#include "util.h" +#include "bench.h" + +typedef struct { + secp256k1_context* ctx; + unsigned char msg[32]; + unsigned char key[32]; +} bench_sign_t; + +static void bench_sign_setup(void* arg) { + int i; + bench_sign_t *data = (bench_sign_t*)arg; + + for (i = 0; i < 32; i++) { + data->msg[i] = i + 1; + } + for (i = 0; i < 32; i++) { + data->key[i] = i + 65; + } +} + +static void bench_sign(void* arg) { + int i; + bench_sign_t *data = (bench_sign_t*)arg; + + unsigned char sig[74]; + for (i = 0; i < 20000; i++) { + size_t siglen = 74; + int j; + secp256k1_ecdsa_signature signature; + CHECK(secp256k1_ecdsa_sign(data->ctx, &signature, data->msg, data->key, NULL, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_der(data->ctx, sig, &siglen, &signature)); + for (j = 0; j < 32; j++) { + data->msg[j] = sig[j]; + data->key[j] = sig[j + 32]; + } + } +} + +int main(void) { + bench_sign_t data; + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + + run_benchmark("ecdsa_sign", bench_sign, bench_sign_setup, NULL, &data, 10, 20000); + + secp256k1_context_destroy(data.ctx); + return 0; +} diff --git a/src/secp256k1/src/bench_verify.c b/src/secp256k1/src/bench_verify.c new file mode 100644 index 000000000..418defa0a --- /dev/null +++ b/src/secp256k1/src/bench_verify.c @@ -0,0 +1,112 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "include/secp256k1.h" +#include "util.h" +#include "bench.h" + +#ifdef ENABLE_OPENSSL_TESTS +#include +#include +#include +#endif + +typedef struct { + secp256k1_context *ctx; + unsigned char msg[32]; + unsigned char key[32]; + unsigned char sig[72]; + size_t siglen; + unsigned char pubkey[33]; + size_t pubkeylen; +#ifdef ENABLE_OPENSSL_TESTS + EC_GROUP* ec_group; +#endif +} benchmark_verify_t; + +static void benchmark_verify(void* arg) { + int i; + benchmark_verify_t* data = (benchmark_verify_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1); + CHECK(secp256k1_ecdsa_verify(data->ctx, &sig, data->msg, &pubkey) == (i == 0)); + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + } +} + +#ifdef ENABLE_OPENSSL_TESTS +static void benchmark_verify_openssl(void* arg) { + int i; + benchmark_verify_t* data = (benchmark_verify_t*)arg; + + for (i = 0; i < 20000; i++) { + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + { + EC_KEY *pkey = EC_KEY_new(); + const unsigned char *pubkey = &data->pubkey[0]; + int result; + + CHECK(pkey != NULL); + result = EC_KEY_set_group(pkey, data->ec_group); + CHECK(result); + result = (o2i_ECPublicKey(&pkey, &pubkey, data->pubkeylen)) != NULL; + CHECK(result); + result = ECDSA_verify(0, &data->msg[0], sizeof(data->msg), &data->sig[0], data->siglen, pkey) == (i == 0); + CHECK(result); + EC_KEY_free(pkey); + } + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + } +} +#endif + +int main(void) { + int i; + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; + benchmark_verify_t data; + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + for (i = 0; i < 32; i++) { + data.msg[i] = 1 + i; + } + for (i = 0; i < 32; i++) { + data.key[i] = 33 + i; + } + data.siglen = 72; + CHECK(secp256k1_ecdsa_sign(data.ctx, &sig, data.msg, data.key, NULL, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig)); + CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key)); + data.pubkeylen = 33; + CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + + run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000); +#ifdef ENABLE_OPENSSL_TESTS + data.ec_group = EC_GROUP_new_by_curve_name(NID_secp256k1); + run_benchmark("ecdsa_verify_openssl", benchmark_verify_openssl, NULL, NULL, &data, 10, 20000); + EC_GROUP_free(data.ec_group); +#endif + + secp256k1_context_destroy(data.ctx); + return 0; +} diff --git a/src/secp256k1/src/ecdsa.h b/src/secp256k1/src/ecdsa.h new file mode 100644 index 000000000..54ae101b9 --- /dev/null +++ b/src/secp256k1/src/ecdsa.h @@ -0,0 +1,21 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_ECDSA_ +#define _SECP256K1_ECDSA_ + +#include + +#include "scalar.h" +#include "group.h" +#include "ecmult.h" + +static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *r, secp256k1_scalar *s, const unsigned char *sig, size_t size); +static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar *r, const secp256k1_scalar *s); +static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar* r, const secp256k1_scalar* s, const secp256k1_ge *pubkey, const secp256k1_scalar *message); +static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid); + +#endif diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h new file mode 100644 index 000000000..d110b4bb1 --- /dev/null +++ b/src/secp256k1/src/ecdsa_impl.h @@ -0,0 +1,303 @@ +/********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + + +#ifndef _SECP256K1_ECDSA_IMPL_H_ +#define _SECP256K1_ECDSA_IMPL_H_ + +#include "scalar.h" +#include "field.h" +#include "group.h" +#include "ecmult.h" +#include "ecmult_gen.h" +#include "ecdsa.h" + +/** Group order for secp256k1 defined as 'n' in "Standards for Efficient Cryptography" (SEC2) 2.7.1 + * sage: for t in xrange(1023, -1, -1): + * .. p = 2**256 - 2**32 - t + * .. if p.is_prime(): + * .. print '%x'%p + * .. break + * 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f' + * sage: a = 0 + * sage: b = 7 + * sage: F = FiniteField (p) + * sage: '%x' % (EllipticCurve ([F (a), F (b)]).order()) + * 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141' + */ +static const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, + 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364141UL +); + +/** Difference between field and order, values 'p' and 'n' values defined in + * "Standards for Efficient Cryptography" (SEC2) 2.7.1. + * sage: p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F + * sage: a = 0 + * sage: b = 7 + * sage: F = FiniteField (p) + * sage: '%x' % (p - EllipticCurve ([F (a), F (b)]).order()) + * '14551231950b75fc4402da1722fc9baee' + */ +static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST( + 0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL +); + +static int secp256k1_der_read_len(const unsigned char **sigp, const unsigned char *sigend) { + int lenleft, b1; + size_t ret = 0; + if (*sigp >= sigend) { + return -1; + } + b1 = *((*sigp)++); + if (b1 == 0xFF) { + /* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */ + return -1; + } + if ((b1 & 0x80) == 0) { + /* X.690-0207 8.1.3.4 short form length octets */ + return b1; + } + if (b1 == 0x80) { + /* Indefinite length is not allowed in DER. */ + return -1; + } + /* X.690-207 8.1.3.5 long form length octets */ + lenleft = b1 & 0x7F; + if (lenleft > sigend - *sigp) { + return -1; + } + if (**sigp == 0) { + /* Not the shortest possible length encoding. */ + return -1; + } + if ((size_t)lenleft > sizeof(size_t)) { + /* The resulting length would exceed the range of a size_t, so + * certainly longer than the passed array size. + */ + return -1; + } + while (lenleft > 0) { + if ((ret >> ((sizeof(size_t) - 1) * 8)) != 0) { + } + ret = (ret << 8) | **sigp; + if (ret + lenleft > (size_t)(sigend - *sigp)) { + /* Result exceeds the length of the passed array. */ + return -1; + } + (*sigp)++; + lenleft--; + } + if (ret < 128) { + /* Not the shortest possible length encoding. */ + return -1; + } + return ret; +} + +static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char **sig, const unsigned char *sigend) { + int overflow = 0; + unsigned char ra[32] = {0}; + int rlen; + + if (*sig == sigend || **sig != 0x02) { + /* Not a primitive integer (X.690-0207 8.3.1). */ + return 0; + } + (*sig)++; + rlen = secp256k1_der_read_len(sig, sigend); + if (rlen <= 0 || (*sig) + rlen > sigend) { + /* Exceeds bounds or not at least length 1 (X.690-0207 8.3.1). */ + return 0; + } + if (**sig == 0x00 && rlen > 1 && (((*sig)[1]) & 0x80) == 0x00) { + /* Excessive 0x00 padding. */ + return 0; + } + if (**sig == 0xFF && rlen > 1 && (((*sig)[1]) & 0x80) == 0x80) { + /* Excessive 0xFF padding. */ + return 0; + } + if ((**sig & 0x80) == 0x80) { + /* Negative. */ + overflow = 1; + } + while (rlen > 0 && **sig == 0) { + /* Skip leading zero bytes */ + rlen--; + (*sig)++; + } + if (rlen > 32) { + overflow = 1; + } + if (!overflow) { + memcpy(ra + 32 - rlen, *sig, rlen); + secp256k1_scalar_set_b32(r, ra, &overflow); + } + if (overflow) { + secp256k1_scalar_set_int(r, 0); + } + (*sig) += rlen; + return 1; +} + +static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *rr, secp256k1_scalar *rs, const unsigned char *sig, size_t size) { + const unsigned char *sigend = sig + size; + int rlen; + if (sig == sigend || *(sig++) != 0x30) { + /* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */ + return 0; + } + rlen = secp256k1_der_read_len(&sig, sigend); + if (rlen < 0 || sig + rlen > sigend) { + /* Tuple exceeds bounds */ + return 0; + } + if (sig + rlen != sigend) { + /* Garbage after tuple. */ + return 0; + } + + if (!secp256k1_der_parse_integer(rr, &sig, sigend)) { + return 0; + } + if (!secp256k1_der_parse_integer(rs, &sig, sigend)) { + return 0; + } + + if (sig != sigend) { + /* Trailing garbage inside tuple. */ + return 0; + } + + return 1; +} + +static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar* ar, const secp256k1_scalar* as) { + unsigned char r[33] = {0}, s[33] = {0}; + unsigned char *rp = r, *sp = s; + size_t lenR = 33, lenS = 33; + secp256k1_scalar_get_b32(&r[1], ar); + secp256k1_scalar_get_b32(&s[1], as); + while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; } + while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; } + if (*size < 6+lenS+lenR) { + *size = 6 + lenS + lenR; + return 0; + } + *size = 6 + lenS + lenR; + sig[0] = 0x30; + sig[1] = 4 + lenS + lenR; + sig[2] = 0x02; + sig[3] = lenR; + memcpy(sig+4, rp, lenR); + sig[4+lenR] = 0x02; + sig[5+lenR] = lenS; + memcpy(sig+lenR+6, sp, lenS); + return 1; +} + +static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar *sigs, const secp256k1_ge *pubkey, const secp256k1_scalar *message) { + unsigned char c[32]; + secp256k1_scalar sn, u1, u2; + secp256k1_fe xr; + secp256k1_gej pubkeyj; + secp256k1_gej pr; + + if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) { + return 0; + } + + secp256k1_scalar_inverse_var(&sn, sigs); + secp256k1_scalar_mul(&u1, &sn, message); + secp256k1_scalar_mul(&u2, &sn, sigr); + secp256k1_gej_set_ge(&pubkeyj, pubkey); + secp256k1_ecmult(ctx, &pr, &pubkeyj, &u2, &u1); + if (secp256k1_gej_is_infinity(&pr)) { + return 0; + } + secp256k1_scalar_get_b32(c, sigr); + secp256k1_fe_set_b32(&xr, c); + + /** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n) + * in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p), + * compute the remainder modulo n, and compare it to xr. However: + * + * xr == X(pr) mod n + * <=> exists h. (xr + h * n < p && xr + h * n == X(pr)) + * [Since 2 * n > p, h can only be 0 or 1] + * <=> (xr == X(pr)) || (xr + n < p && xr + n == X(pr)) + * [In Jacobian coordinates, X(pr) is pr.x / pr.z^2 mod p] + * <=> (xr == pr.x / pr.z^2 mod p) || (xr + n < p && xr + n == pr.x / pr.z^2 mod p) + * [Multiplying both sides of the equations by pr.z^2 mod p] + * <=> (xr * pr.z^2 mod p == pr.x) || (xr + n < p && (xr + n) * pr.z^2 mod p == pr.x) + * + * Thus, we can avoid the inversion, but we have to check both cases separately. + * secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test. + */ + if (secp256k1_gej_eq_x_var(&xr, &pr)) { + /* xr * pr.z^2 mod p == pr.x, so the signature is valid. */ + return 1; + } + if (secp256k1_fe_cmp_var(&xr, &secp256k1_ecdsa_const_p_minus_order) >= 0) { + /* xr + n >= p, so we can skip testing the second case. */ + return 0; + } + secp256k1_fe_add(&xr, &secp256k1_ecdsa_const_order_as_fe); + if (secp256k1_gej_eq_x_var(&xr, &pr)) { + /* (xr + n) * pr.z^2 mod p == pr.x, so the signature is valid. */ + return 1; + } + return 0; +} + +static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid) { + unsigned char b[32]; + secp256k1_gej rp; + secp256k1_ge r; + secp256k1_scalar n; + int overflow = 0; + + secp256k1_ecmult_gen(ctx, &rp, nonce); + secp256k1_ge_set_gej(&r, &rp); + secp256k1_fe_normalize(&r.x); + secp256k1_fe_normalize(&r.y); + secp256k1_fe_get_b32(b, &r.x); + secp256k1_scalar_set_b32(sigr, b, &overflow); + if (secp256k1_scalar_is_zero(sigr)) { + /* P.x = order is on the curve, so technically sig->r could end up zero, which would be an invalid signature. + * This branch is cryptographically unreachable as hitting it requires finding the discrete log of P.x = N. + */ + secp256k1_gej_clear(&rp); + secp256k1_ge_clear(&r); + return 0; + } + if (recid) { + /* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log + * of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria. + */ + *recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0); + } + secp256k1_scalar_mul(&n, sigr, seckey); + secp256k1_scalar_add(&n, &n, message); + secp256k1_scalar_inverse(sigs, nonce); + secp256k1_scalar_mul(sigs, sigs, &n); + secp256k1_scalar_clear(&n); + secp256k1_gej_clear(&rp); + secp256k1_ge_clear(&r); + if (secp256k1_scalar_is_zero(sigs)) { + return 0; + } + if (secp256k1_scalar_is_high(sigs)) { + secp256k1_scalar_negate(sigs, sigs); + if (recid) { + *recid ^= 1; + } + } + return 1; +} + +#endif diff --git a/src/secp256k1/src/eckey.h b/src/secp256k1/src/eckey.h new file mode 100644 index 000000000..42739a3be --- /dev/null +++ b/src/secp256k1/src/eckey.h @@ -0,0 +1,25 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_ECKEY_ +#define _SECP256K1_ECKEY_ + +#include + +#include "group.h" +#include "scalar.h" +#include "ecmult.h" +#include "ecmult_gen.h" + +static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size); +static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed); + +static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak); +static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak); +static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak); +static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak); + +#endif diff --git a/src/secp256k1/src/eckey_impl.h b/src/secp256k1/src/eckey_impl.h new file mode 100644 index 000000000..ce38071ac --- /dev/null +++ b/src/secp256k1/src/eckey_impl.h @@ -0,0 +1,99 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_ECKEY_IMPL_H_ +#define _SECP256K1_ECKEY_IMPL_H_ + +#include "eckey.h" + +#include "scalar.h" +#include "field.h" +#include "group.h" +#include "ecmult_gen.h" + +static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) { + if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) { + secp256k1_fe x; + return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == 0x03); + } else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) { + secp256k1_fe x, y; + if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) { + return 0; + } + secp256k1_ge_set_xy(elem, &x, &y); + if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07)) { + return 0; + } + return secp256k1_ge_is_valid_var(elem); + } else { + return 0; + } +} + +static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed) { + if (secp256k1_ge_is_infinity(elem)) { + return 0; + } + secp256k1_fe_normalize_var(&elem->x); + secp256k1_fe_normalize_var(&elem->y); + secp256k1_fe_get_b32(&pub[1], &elem->x); + if (compressed) { + *size = 33; + pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00); + } else { + *size = 65; + pub[0] = 0x04; + secp256k1_fe_get_b32(&pub[33], &elem->y); + } + return 1; +} + +static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) { + secp256k1_scalar_add(key, key, tweak); + if (secp256k1_scalar_is_zero(key)) { + return 0; + } + return 1; +} + +static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) { + secp256k1_gej pt; + secp256k1_scalar one; + secp256k1_gej_set_ge(&pt, key); + secp256k1_scalar_set_int(&one, 1); + secp256k1_ecmult(ctx, &pt, &pt, &one, tweak); + + if (secp256k1_gej_is_infinity(&pt)) { + return 0; + } + secp256k1_ge_set_gej(key, &pt); + return 1; +} + +static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak) { + if (secp256k1_scalar_is_zero(tweak)) { + return 0; + } + + secp256k1_scalar_mul(key, key, tweak); + return 1; +} + +static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) { + secp256k1_scalar zero; + secp256k1_gej pt; + if (secp256k1_scalar_is_zero(tweak)) { + return 0; + } + + secp256k1_scalar_set_int(&zero, 0); + secp256k1_gej_set_ge(&pt, key); + secp256k1_ecmult(ctx, &pt, &pt, tweak, &zero); + secp256k1_ge_set_gej(key, &pt); + return 1; +} + +#endif diff --git a/src/secp256k1/src/ecmult.h b/src/secp256k1/src/ecmult.h new file mode 100644 index 000000000..20484134f --- /dev/null +++ b/src/secp256k1/src/ecmult.h @@ -0,0 +1,31 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_ECMULT_ +#define _SECP256K1_ECMULT_ + +#include "num.h" +#include "group.h" + +typedef struct { + /* For accelerating the computation of a*P + b*G: */ + secp256k1_ge_storage (*pre_g)[]; /* odd multiples of the generator */ +#ifdef USE_ENDOMORPHISM + secp256k1_ge_storage (*pre_g_128)[]; /* odd multiples of 2^128*generator */ +#endif +} secp256k1_ecmult_context; + +static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx); +static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb); +static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst, + const secp256k1_ecmult_context *src, const secp256k1_callback *cb); +static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx); +static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx); + +/** Double multiply: R = na*A + ng*G */ +static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng); + +#endif diff --git a/src/secp256k1/src/ecmult_const.h b/src/secp256k1/src/ecmult_const.h new file mode 100644 index 000000000..2b0097655 --- /dev/null +++ b/src/secp256k1/src/ecmult_const.h @@ -0,0 +1,15 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_ECMULT_CONST_ +#define _SECP256K1_ECMULT_CONST_ + +#include "scalar.h" +#include "group.h" + +static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q); + +#endif diff --git a/src/secp256k1/src/ecmult_const_impl.h b/src/secp256k1/src/ecmult_const_impl.h new file mode 100644 index 000000000..7a6a25318 --- /dev/null +++ b/src/secp256k1/src/ecmult_const_impl.h @@ -0,0 +1,239 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_ECMULT_CONST_IMPL_ +#define _SECP256K1_ECMULT_CONST_IMPL_ + +#include "scalar.h" +#include "group.h" +#include "ecmult_const.h" +#include "ecmult_impl.h" + +#ifdef USE_ENDOMORPHISM + #define WNAF_BITS 128 +#else + #define WNAF_BITS 256 +#endif +#define WNAF_SIZE(w) ((WNAF_BITS + (w) - 1) / (w)) + +/* This is like `ECMULT_TABLE_GET_GE` but is constant time */ +#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \ + int m; \ + int abs_n = (n) * (((n) > 0) * 2 - 1); \ + int idx_n = abs_n / 2; \ + secp256k1_fe neg_y; \ + VERIFY_CHECK(((n) & 1) == 1); \ + VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ + VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ + VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \ + VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \ + for (m = 0; m < ECMULT_TABLE_SIZE(w); m++) { \ + /* This loop is used to avoid secret data in array indices. See + * the comment in ecmult_gen_impl.h for rationale. */ \ + secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \ + secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == idx_n); \ + } \ + (r)->infinity = 0; \ + secp256k1_fe_negate(&neg_y, &(r)->y, 1); \ + secp256k1_fe_cmov(&(r)->y, &neg_y, (n) != abs_n); \ +} while(0) + + +/** Convert a number to WNAF notation. The number becomes represented by sum(2^{wi} * wnaf[i], i=0..return_val) + * with the following guarantees: + * - each wnaf[i] an odd integer between -(1 << w) and (1 << w) + * - each wnaf[i] is nonzero + * - the number of words set is returned; this is always (WNAF_BITS + w - 1) / w + * + * Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar + * Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.) + * CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlagy Berlin Heidelberg 2003 + * + * Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335 + */ +static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) { + int global_sign; + int skew = 0; + int word = 0; + + /* 1 2 3 */ + int u_last; + int u; + + int flip; + int bit; + secp256k1_scalar neg_s; + int not_neg_one; + /* Note that we cannot handle even numbers by negating them to be odd, as is + * done in other implementations, since if our scalars were specified to have + * width < 256 for performance reasons, their negations would have width 256 + * and we'd lose any performance benefit. Instead, we use a technique from + * Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even) + * or 2 (for odd) to the number we are encoding, returning a skew value indicating + * this, and having the caller compensate after doing the multiplication. */ + + /* Negative numbers will be negated to keep their bit representation below the maximum width */ + flip = secp256k1_scalar_is_high(&s); + /* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */ + bit = flip ^ (s.d[0] & 1); + /* We check for negative one, since adding 2 to it will cause an overflow */ + secp256k1_scalar_negate(&neg_s, &s); + not_neg_one = !secp256k1_scalar_is_one(&neg_s); + secp256k1_scalar_cadd_bit(&s, bit, not_neg_one); + /* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects + * that we added two to it and flipped it. In fact for -1 these operations are + * identical. We only flipped, but since skewing is required (in the sense that + * the skew must be 1 or 2, never zero) and flipping is not, we need to change + * our flags to claim that we only skewed. */ + global_sign = secp256k1_scalar_cond_negate(&s, flip); + global_sign *= not_neg_one * 2 - 1; + skew = 1 << bit; + + /* 4 */ + u_last = secp256k1_scalar_shr_int(&s, w); + while (word * w < WNAF_BITS) { + int sign; + int even; + + /* 4.1 4.4 */ + u = secp256k1_scalar_shr_int(&s, w); + /* 4.2 */ + even = ((u & 1) == 0); + sign = 2 * (u_last > 0) - 1; + u += sign * even; + u_last -= sign * even * (1 << w); + + /* 4.3, adapted for global sign change */ + wnaf[word++] = u_last * global_sign; + + u_last = u; + } + wnaf[word] = u * global_sign; + + VERIFY_CHECK(secp256k1_scalar_is_zero(&s)); + VERIFY_CHECK(word == WNAF_SIZE(w)); + return skew; +} + + +static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) { + secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_ge tmpa; + secp256k1_fe Z; + + int skew_1; + int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)]; +#ifdef USE_ENDOMORPHISM + secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; + int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)]; + int skew_lam; + secp256k1_scalar q_1, q_lam; +#endif + + int i; + secp256k1_scalar sc = *scalar; + + /* build wnaf representation for q. */ +#ifdef USE_ENDOMORPHISM + /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */ + secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc); + skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1); + skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1); +#else + skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1); +#endif + + /* Calculate odd multiples of a. + * All multiples are brought to the same Z 'denominator', which is stored + * in Z. Due to secp256k1' isomorphism we can do all operations pretending + * that the Z coordinate was 1, use affine addition formulae, and correct + * the Z coordinate of the result once at the end. + */ + secp256k1_gej_set_ge(r, a); + secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r); + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_fe_normalize_weak(&pre_a[i].y); + } +#ifdef USE_ENDOMORPHISM + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); + } +#endif + + /* first loop iteration (separated out so we can directly set r, rather + * than having it start at infinity, get doubled several times, then have + * its new value added to it) */ + i = wnaf_1[WNAF_SIZE(WINDOW_A - 1)]; + VERIFY_CHECK(i != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); + secp256k1_gej_set_ge(r, &tmpa); +#ifdef USE_ENDOMORPHISM + i = wnaf_lam[WNAF_SIZE(WINDOW_A - 1)]; + VERIFY_CHECK(i != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A); + secp256k1_gej_add_ge(r, r, &tmpa); +#endif + /* remaining loop iterations */ + for (i = WNAF_SIZE(WINDOW_A - 1) - 1; i >= 0; i--) { + int n; + int j; + for (j = 0; j < WINDOW_A - 1; ++j) { + secp256k1_gej_double_nonzero(r, r, NULL); + } + + n = wnaf_1[i]; + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); + VERIFY_CHECK(n != 0); + secp256k1_gej_add_ge(r, r, &tmpa); +#ifdef USE_ENDOMORPHISM + n = wnaf_lam[i]; + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A); + VERIFY_CHECK(n != 0); + secp256k1_gej_add_ge(r, r, &tmpa); +#endif + } + + secp256k1_fe_mul(&r->z, &r->z, &Z); + + { + /* Correct for wNAF skew */ + secp256k1_ge correction = *a; + secp256k1_ge_storage correction_1_stor; +#ifdef USE_ENDOMORPHISM + secp256k1_ge_storage correction_lam_stor; +#endif + secp256k1_ge_storage a2_stor; + secp256k1_gej tmpj; + secp256k1_gej_set_ge(&tmpj, &correction); + secp256k1_gej_double_var(&tmpj, &tmpj, NULL); + secp256k1_ge_set_gej(&correction, &tmpj); + secp256k1_ge_to_storage(&correction_1_stor, a); +#ifdef USE_ENDOMORPHISM + secp256k1_ge_to_storage(&correction_lam_stor, a); +#endif + secp256k1_ge_to_storage(&a2_stor, &correction); + + /* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */ + secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2); +#ifdef USE_ENDOMORPHISM + secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2); +#endif + + /* Apply the correction */ + secp256k1_ge_from_storage(&correction, &correction_1_stor); + secp256k1_ge_neg(&correction, &correction); + secp256k1_gej_add_ge(r, r, &correction); + +#ifdef USE_ENDOMORPHISM + secp256k1_ge_from_storage(&correction, &correction_lam_stor); + secp256k1_ge_neg(&correction, &correction); + secp256k1_ge_mul_lambda(&correction, &correction); + secp256k1_gej_add_ge(r, r, &correction); +#endif + } +} + +#endif diff --git a/src/secp256k1/src/ecmult_gen.h b/src/secp256k1/src/ecmult_gen.h new file mode 100644 index 000000000..eb2cc9ead --- /dev/null +++ b/src/secp256k1/src/ecmult_gen.h @@ -0,0 +1,43 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_ECMULT_GEN_ +#define _SECP256K1_ECMULT_GEN_ + +#include "scalar.h" +#include "group.h" + +typedef struct { + /* For accelerating the computation of a*G: + * To harden against timing attacks, use the following mechanism: + * * Break up the multiplicand into groups of 4 bits, called n_0, n_1, n_2, ..., n_63. + * * Compute sum(n_i * 16^i * G + U_i, i=0..63), where: + * * U_i = U * 2^i (for i=0..62) + * * U_i = U * (1-2^63) (for i=63) + * where U is a point with no known corresponding scalar. Note that sum(U_i, i=0..63) = 0. + * For each i, and each of the 16 possible values of n_i, (n_i * 16^i * G + U_i) is + * precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0..63). + * None of the resulting prec group elements have a known scalar, and neither do any of + * the intermediate sums while computing a*G. + */ + secp256k1_ge_storage (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */ + secp256k1_scalar blind; + secp256k1_gej initial; +} secp256k1_ecmult_gen_context; + +static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context* ctx); +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, const secp256k1_callback* cb); +static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst, + const secp256k1_ecmult_gen_context* src, const secp256k1_callback* cb); +static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx); +static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx); + +/** Multiply with the generator: R = a*G */ +static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp256k1_gej *r, const secp256k1_scalar *a); + +static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32); + +#endif diff --git a/src/secp256k1/src/ecmult_gen_impl.h b/src/secp256k1/src/ecmult_gen_impl.h new file mode 100644 index 000000000..b63c4d866 --- /dev/null +++ b/src/secp256k1/src/ecmult_gen_impl.h @@ -0,0 +1,210 @@ +/********************************************************************** + * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_ECMULT_GEN_IMPL_H_ +#define _SECP256K1_ECMULT_GEN_IMPL_H_ + +#include "scalar.h" +#include "group.h" +#include "ecmult_gen.h" +#include "hash_impl.h" +#ifdef USE_ECMULT_STATIC_PRECOMPUTATION +#include "ecmult_static_context.h" +#endif +static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context *ctx) { + ctx->prec = NULL; +} + +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, const secp256k1_callback* cb) { +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + secp256k1_ge prec[1024]; + secp256k1_gej gj; + secp256k1_gej nums_gej; + int i, j; +#endif + + if (ctx->prec != NULL) { + return; + } +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + ctx->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*ctx->prec)); + + /* get the generator */ + secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); + + /* Construct a group element with no known corresponding scalar (nothing up my sleeve). */ + { + static const unsigned char nums_b32[33] = "The scalar for this x is unknown"; + secp256k1_fe nums_x; + secp256k1_ge nums_ge; + int r; + r = secp256k1_fe_set_b32(&nums_x, nums_b32); + (void)r; + VERIFY_CHECK(r); + r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0); + (void)r; + VERIFY_CHECK(r); + secp256k1_gej_set_ge(&nums_gej, &nums_ge); + /* Add G to make the bits in x uniformly distributed. */ + secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g, NULL); + } + + /* compute prec. */ + { + secp256k1_gej precj[1024]; /* Jacobian versions of prec. */ + secp256k1_gej gbase; + secp256k1_gej numsbase; + gbase = gj; /* 16^j * G */ + numsbase = nums_gej; /* 2^j * nums. */ + for (j = 0; j < 64; j++) { + /* Set precj[j*16 .. j*16+15] to (numsbase, numsbase + gbase, ..., numsbase + 15*gbase). */ + precj[j*16] = numsbase; + for (i = 1; i < 16; i++) { + secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase, NULL); + } + /* Multiply gbase by 16. */ + for (i = 0; i < 4; i++) { + secp256k1_gej_double_var(&gbase, &gbase, NULL); + } + /* Multiply numbase by 2. */ + secp256k1_gej_double_var(&numsbase, &numsbase, NULL); + if (j == 62) { + /* In the last iteration, numsbase is (1 - 2^j) * nums instead. */ + secp256k1_gej_neg(&numsbase, &numsbase); + secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL); + } + } + secp256k1_ge_set_all_gej_var(1024, prec, precj, cb); + } + for (j = 0; j < 64; j++) { + for (i = 0; i < 16; i++) { + secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*16 + i]); + } + } +#else + (void)cb; + ctx->prec = (secp256k1_ge_storage (*)[64][16])secp256k1_ecmult_static_context; +#endif + secp256k1_ecmult_gen_blind(ctx, NULL); +} + +static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx) { + return ctx->prec != NULL; +} + +static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst, + const secp256k1_ecmult_gen_context *src, const secp256k1_callback* cb) { + if (src->prec == NULL) { + dst->prec = NULL; + } else { +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + dst->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*dst->prec)); + memcpy(dst->prec, src->prec, sizeof(*dst->prec)); +#else + (void)cb; + dst->prec = src->prec; +#endif + dst->initial = src->initial; + dst->blind = src->blind; + } +} + +static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) { +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + free(ctx->prec); +#endif + secp256k1_scalar_clear(&ctx->blind); + secp256k1_gej_clear(&ctx->initial); + ctx->prec = NULL; +} + +static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) { + secp256k1_ge add; + secp256k1_ge_storage adds; + secp256k1_scalar gnb; + int bits; + int i, j; + memset(&adds, 0, sizeof(adds)); + *r = ctx->initial; + /* Blind scalar/point multiplication by computing (n-b)G + bG instead of nG. */ + secp256k1_scalar_add(&gnb, gn, &ctx->blind); + add.infinity = 0; + for (j = 0; j < 64; j++) { + bits = secp256k1_scalar_get_bits(&gnb, j * 4, 4); + for (i = 0; i < 16; i++) { + /** This uses a conditional move to avoid any secret data in array indexes. + * _Any_ use of secret indexes has been demonstrated to result in timing + * sidechannels, even when the cache-line access patterns are uniform. + * See also: + * "A word of warning", CHES 2013 Rump Session, by Daniel J. Bernstein and Peter Schwabe + * (https://cryptojedi.org/peter/data/chesrump-20130822.pdf) and + * "Cache Attacks and Countermeasures: the Case of AES", RSA 2006, + * by Dag Arne Osvik, Adi Shamir, and Eran Tromer + * (http://www.tau.ac.il/~tromer/papers/cache.pdf) + */ + secp256k1_ge_storage_cmov(&adds, &(*ctx->prec)[j][i], i == bits); + } + secp256k1_ge_from_storage(&add, &adds); + secp256k1_gej_add_ge(r, r, &add); + } + bits = 0; + secp256k1_ge_clear(&add); + secp256k1_scalar_clear(&gnb); +} + +/* Setup blinding values for secp256k1_ecmult_gen. */ +static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32) { + secp256k1_scalar b; + secp256k1_gej gb; + secp256k1_fe s; + unsigned char nonce32[32]; + secp256k1_rfc6979_hmac_sha256_t rng; + int retry; + unsigned char keydata[64] = {0}; + if (seed32 == NULL) { + /* When seed is NULL, reset the initial point and blinding value. */ + secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g); + secp256k1_gej_neg(&ctx->initial, &ctx->initial); + secp256k1_scalar_set_int(&ctx->blind, 1); + } + /* The prior blinding value (if not reset) is chained forward by including it in the hash. */ + secp256k1_scalar_get_b32(nonce32, &ctx->blind); + /** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data, + * and guards against weak or adversarial seeds. This is a simpler and safer interface than + * asking the caller for blinding values directly and expecting them to retry on failure. + */ + memcpy(keydata, nonce32, 32); + if (seed32 != NULL) { + memcpy(keydata + 32, seed32, 32); + } + secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32); + memset(keydata, 0, sizeof(keydata)); + /* Retry for out of range results to achieve uniformity. */ + do { + secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + retry = !secp256k1_fe_set_b32(&s, nonce32); + retry |= secp256k1_fe_is_zero(&s); + } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > Fp. */ + /* Randomize the projection to defend against multiplier sidechannels. */ + secp256k1_gej_rescale(&ctx->initial, &s); + secp256k1_fe_clear(&s); + do { + secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + secp256k1_scalar_set_b32(&b, nonce32, &retry); + /* A blinding value of 0 works, but would undermine the projection hardening. */ + retry |= secp256k1_scalar_is_zero(&b); + } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > order. */ + secp256k1_rfc6979_hmac_sha256_finalize(&rng); + memset(nonce32, 0, 32); + secp256k1_ecmult_gen(ctx, &gb, &b); + secp256k1_scalar_negate(&b, &b); + ctx->blind = b; + ctx->initial = gb; + secp256k1_scalar_clear(&b); + secp256k1_gej_clear(&gb); +} + +#endif diff --git a/src/secp256k1/src/ecmult_impl.h b/src/secp256k1/src/ecmult_impl.h new file mode 100644 index 000000000..81ae08e10 --- /dev/null +++ b/src/secp256k1/src/ecmult_impl.h @@ -0,0 +1,391 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_ECMULT_IMPL_H_ +#define _SECP256K1_ECMULT_IMPL_H_ + +#include "group.h" +#include "scalar.h" +#include "ecmult.h" + +#include + +/* optimal for 128-bit and 256-bit exponents. */ +#define WINDOW_A 5 + +/** larger numbers may result in slightly better performance, at the cost of + exponentially larger precomputed tables. */ +#ifdef USE_ENDOMORPHISM +/** Two tables for window size 15: 1.375 MiB. */ +#define WINDOW_G 15 +#else +/** One table for window size 16: 1.375 MiB. */ +#define WINDOW_G 16 +#endif + +/** The number of entries a table with precomputed multiples needs to have. */ +#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2)) + +/** Fill a table 'prej' with precomputed odd multiples of a. Prej will contain + * the values [1*a,3*a,...,(2*n-1)*a], so it space for n values. zr[0] will + * contain prej[0].z / a.z. The other zr[i] values = prej[i].z / prej[i-1].z. + * Prej's Z values are undefined, except for the last value. + */ +static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_gej *prej, secp256k1_fe *zr, const secp256k1_gej *a) { + secp256k1_gej d; + secp256k1_ge a_ge, d_ge; + int i; + + VERIFY_CHECK(!a->infinity); + + secp256k1_gej_double_var(&d, a, NULL); + + /* + * Perform the additions on an isomorphism where 'd' is affine: drop the z coordinate + * of 'd', and scale the 1P starting value's x/y coordinates without changing its z. + */ + d_ge.x = d.x; + d_ge.y = d.y; + d_ge.infinity = 0; + + secp256k1_ge_set_gej_zinv(&a_ge, a, &d.z); + prej[0].x = a_ge.x; + prej[0].y = a_ge.y; + prej[0].z = a->z; + prej[0].infinity = 0; + + zr[0] = d.z; + for (i = 1; i < n; i++) { + secp256k1_gej_add_ge_var(&prej[i], &prej[i-1], &d_ge, &zr[i]); + } + + /* + * Each point in 'prej' has a z coordinate too small by a factor of 'd.z'. Only + * the final point's z coordinate is actually used though, so just update that. + */ + secp256k1_fe_mul(&prej[n-1].z, &prej[n-1].z, &d.z); +} + +/** Fill a table 'pre' with precomputed odd multiples of a. + * + * There are two versions of this function: + * - secp256k1_ecmult_odd_multiples_table_globalz_windowa which brings its + * resulting point set to a single constant Z denominator, stores the X and Y + * coordinates as ge_storage points in pre, and stores the global Z in rz. + * It only operates on tables sized for WINDOW_A wnaf multiples. + * - secp256k1_ecmult_odd_multiples_table_storage_var, which converts its + * resulting point set to actually affine points, and stores those in pre. + * It operates on tables of any size, but uses heap-allocated temporaries. + * + * To compute a*P + b*G, we compute a table for P using the first function, + * and for G using the second (which requires an inverse, but it only needs to + * happen once). + */ +static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) { + secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)]; + + /* Compute the odd multiples in Jacobian form. */ + secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), prej, zr, a); + /* Bring them to the same Z denominator. */ + secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A), pre, globalz, prej, zr); +} + +static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, secp256k1_ge_storage *pre, const secp256k1_gej *a, const secp256k1_callback *cb) { + secp256k1_gej *prej = (secp256k1_gej*)checked_malloc(cb, sizeof(secp256k1_gej) * n); + secp256k1_ge *prea = (secp256k1_ge*)checked_malloc(cb, sizeof(secp256k1_ge) * n); + secp256k1_fe *zr = (secp256k1_fe*)checked_malloc(cb, sizeof(secp256k1_fe) * n); + int i; + + /* Compute the odd multiples in Jacobian form. */ + secp256k1_ecmult_odd_multiples_table(n, prej, zr, a); + /* Convert them in batch to affine coordinates. */ + secp256k1_ge_set_table_gej_var(n, prea, prej, zr); + /* Convert them to compact storage form. */ + for (i = 0; i < n; i++) { + secp256k1_ge_to_storage(&pre[i], &prea[i]); + } + + free(prea); + free(prej); + free(zr); +} + +/** The following two macro retrieves a particular odd multiple from a table + * of precomputed multiples. */ +#define ECMULT_TABLE_GET_GE(r,pre,n,w) do { \ + VERIFY_CHECK(((n) & 1) == 1); \ + VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ + VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ + if ((n) > 0) { \ + *(r) = (pre)[((n)-1)/2]; \ + } else { \ + secp256k1_ge_neg((r), &(pre)[(-(n)-1)/2]); \ + } \ +} while(0) + +#define ECMULT_TABLE_GET_GE_STORAGE(r,pre,n,w) do { \ + VERIFY_CHECK(((n) & 1) == 1); \ + VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ + VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ + if ((n) > 0) { \ + secp256k1_ge_from_storage((r), &(pre)[((n)-1)/2]); \ + } else { \ + secp256k1_ge_from_storage((r), &(pre)[(-(n)-1)/2]); \ + secp256k1_ge_neg((r), (r)); \ + } \ +} while(0) + +static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx) { + ctx->pre_g = NULL; +#ifdef USE_ENDOMORPHISM + ctx->pre_g_128 = NULL; +#endif +} + +static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb) { + secp256k1_gej gj; + + if (ctx->pre_g != NULL) { + return; + } + + /* get the generator */ + secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); + + ctx->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); + + /* precompute the tables with odd multiples */ + secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj, cb); + +#ifdef USE_ENDOMORPHISM + { + secp256k1_gej g_128j; + int i; + + ctx->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); + + /* calculate 2^128*generator */ + g_128j = gj; + for (i = 0; i < 128; i++) { + secp256k1_gej_double_var(&g_128j, &g_128j, NULL); + } + secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g_128, &g_128j, cb); + } +#endif +} + +static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst, + const secp256k1_ecmult_context *src, const secp256k1_callback *cb) { + if (src->pre_g == NULL) { + dst->pre_g = NULL; + } else { + size_t size = sizeof((*dst->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); + dst->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, size); + memcpy(dst->pre_g, src->pre_g, size); + } +#ifdef USE_ENDOMORPHISM + if (src->pre_g_128 == NULL) { + dst->pre_g_128 = NULL; + } else { + size_t size = sizeof((*dst->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); + dst->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, size); + memcpy(dst->pre_g_128, src->pre_g_128, size); + } +#endif +} + +static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx) { + return ctx->pre_g != NULL; +} + +static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx) { + free(ctx->pre_g); +#ifdef USE_ENDOMORPHISM + free(ctx->pre_g_128); +#endif + secp256k1_ecmult_context_init(ctx); +} + +/** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits), + * with the following guarantees: + * - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1) + * - two non-zero entries in wnaf are separated by at least w-1 zeroes. + * - the number of set values in wnaf is returned. This number is at most 256, and at most one more + * than the number of bits in the (absolute value) of the input. + */ +static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a, int w) { + secp256k1_scalar s = *a; + int last_set_bit = -1; + int bit = 0; + int sign = 1; + int carry = 0; + + VERIFY_CHECK(wnaf != NULL); + VERIFY_CHECK(0 <= len && len <= 256); + VERIFY_CHECK(a != NULL); + VERIFY_CHECK(2 <= w && w <= 31); + + memset(wnaf, 0, len * sizeof(wnaf[0])); + + if (secp256k1_scalar_get_bits(&s, 255, 1)) { + secp256k1_scalar_negate(&s, &s); + sign = -1; + } + + while (bit < len) { + int now; + int word; + if (secp256k1_scalar_get_bits(&s, bit, 1) == (unsigned int)carry) { + bit++; + continue; + } + + now = w; + if (now > len - bit) { + now = len - bit; + } + + word = secp256k1_scalar_get_bits_var(&s, bit, now) + carry; + + carry = (word >> (w-1)) & 1; + word -= carry << w; + + wnaf[bit] = sign * word; + last_set_bit = bit; + + bit += now; + } +#ifdef VERIFY + CHECK(carry == 0); + while (bit < 256) { + CHECK(secp256k1_scalar_get_bits(&s, bit++, 1) == 0); + } +#endif + return last_set_bit + 1; +} + +static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) { + secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_ge tmpa; + secp256k1_fe Z; +#ifdef USE_ENDOMORPHISM + secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_scalar na_1, na_lam; + /* Splitted G factors. */ + secp256k1_scalar ng_1, ng_128; + int wnaf_na_1[130]; + int wnaf_na_lam[130]; + int bits_na_1; + int bits_na_lam; + int wnaf_ng_1[129]; + int bits_ng_1; + int wnaf_ng_128[129]; + int bits_ng_128; +#else + int wnaf_na[256]; + int bits_na; + int wnaf_ng[256]; + int bits_ng; +#endif + int i; + int bits; + +#ifdef USE_ENDOMORPHISM + /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */ + secp256k1_scalar_split_lambda(&na_1, &na_lam, na); + + /* build wnaf representation for na_1 and na_lam. */ + bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, 130, &na_1, WINDOW_A); + bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, 130, &na_lam, WINDOW_A); + VERIFY_CHECK(bits_na_1 <= 130); + VERIFY_CHECK(bits_na_lam <= 130); + bits = bits_na_1; + if (bits_na_lam > bits) { + bits = bits_na_lam; + } +#else + /* build wnaf representation for na. */ + bits_na = secp256k1_ecmult_wnaf(wnaf_na, 256, na, WINDOW_A); + bits = bits_na; +#endif + + /* Calculate odd multiples of a. + * All multiples are brought to the same Z 'denominator', which is stored + * in Z. Due to secp256k1' isomorphism we can do all operations pretending + * that the Z coordinate was 1, use affine addition formulae, and correct + * the Z coordinate of the result once at the end. + * The exception is the precomputed G table points, which are actually + * affine. Compared to the base used for other points, they have a Z ratio + * of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same + * isomorphism to efficiently add with a known Z inverse. + */ + secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, a); + +#ifdef USE_ENDOMORPHISM + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); + } + + /* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */ + secp256k1_scalar_split_128(&ng_1, &ng_128, ng); + + /* Build wnaf representation for ng_1 and ng_128 */ + bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G); + bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G); + if (bits_ng_1 > bits) { + bits = bits_ng_1; + } + if (bits_ng_128 > bits) { + bits = bits_ng_128; + } +#else + bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, 256, ng, WINDOW_G); + if (bits_ng > bits) { + bits = bits_ng; + } +#endif + + secp256k1_gej_set_infinity(r); + + for (i = bits - 1; i >= 0; i--) { + int n; + secp256k1_gej_double_var(r, r, NULL); +#ifdef USE_ENDOMORPHISM + if (i < bits_na_1 && (n = wnaf_na_1[i])) { + ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); + secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); + } + if (i < bits_na_lam && (n = wnaf_na_lam[i])) { + ECMULT_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A); + secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); + } + if (i < bits_ng_1 && (n = wnaf_ng_1[i])) { + ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); + secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); + } + if (i < bits_ng_128 && (n = wnaf_ng_128[i])) { + ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g_128, n, WINDOW_G); + secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); + } +#else + if (i < bits_na && (n = wnaf_na[i])) { + ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); + secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); + } + if (i < bits_ng && (n = wnaf_ng[i])) { + ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); + secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); + } +#endif + } + + if (!r->infinity) { + secp256k1_fe_mul(&r->z, &r->z, &Z); + } +} + +#endif diff --git a/src/secp256k1/src/field.h b/src/secp256k1/src/field.h new file mode 100644 index 000000000..c5ba07424 --- /dev/null +++ b/src/secp256k1/src/field.h @@ -0,0 +1,127 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_FIELD_ +#define _SECP256K1_FIELD_ + +/** Field element module. + * + * Field elements can be represented in several ways, but code accessing + * it (and implementations) need to take certain properties into account: + * - Each field element can be normalized or not. + * - Each field element has a magnitude, which represents how far away + * its representation is away from normalization. Normalized elements + * always have a magnitude of 1, but a magnitude of 1 doesn't imply + * normality. + */ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#if defined(USE_FIELD_10X26) +#include "field_10x26.h" +#elif defined(USE_FIELD_5X52) +#include "field_5x52.h" +#else +#error "Please select field implementation" +#endif + +/** Normalize a field element. */ +static void secp256k1_fe_normalize(secp256k1_fe *r); + +/** Weakly normalize a field element: reduce it magnitude to 1, but don't fully normalize. */ +static void secp256k1_fe_normalize_weak(secp256k1_fe *r); + +/** Normalize a field element, without constant-time guarantee. */ +static void secp256k1_fe_normalize_var(secp256k1_fe *r); + +/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field + * implementation may optionally normalize the input, but this should not be relied upon. */ +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r); + +/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field + * implementation may optionally normalize the input, but this should not be relied upon. */ +static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r); + +/** Set a field element equal to a small integer. Resulting field element is normalized. */ +static void secp256k1_fe_set_int(secp256k1_fe *r, int a); + +/** Verify whether a field element is zero. Requires the input to be normalized. */ +static int secp256k1_fe_is_zero(const secp256k1_fe *a); + +/** Check the "oddness" of a field element. Requires the input to be normalized. */ +static int secp256k1_fe_is_odd(const secp256k1_fe *a); + +/** Compare two field elements. Requires magnitude-1 inputs. */ +static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b); + +/** Same as secp256k1_fe_equal, but may be variable time. */ +static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b); + +/** Compare two field elements. Requires both inputs to be normalized */ +static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); + +/** Set a field element equal to 32-byte big endian value. If successful, the resulting field element is normalized. */ +static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a); + +/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ +static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a); + +/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input + * as an argument. The magnitude of the output is one higher. */ +static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m); + +/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that + * small integer. */ +static void secp256k1_fe_mul_int(secp256k1_fe *r, int a); + +/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */ +static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a); + +/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8. + * The output magnitude is 1 (but not guaranteed to be normalized). */ +static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b); + +/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8. + * The output magnitude is 1 (but not guaranteed to be normalized). */ +static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a); + +/** If a has a square root, it is computed in r and 1 is returned. If a does not + * have a square root, the root of its negation is computed and 0 is returned. + * The input's magnitude can be at most 8. The output magnitude is 1 (but not + * guaranteed to be normalized). The result in r will always be a square + * itself. */ +static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a); + +/** Checks whether a field element is a quadratic residue. */ +static int secp256k1_fe_is_quad_var(const secp256k1_fe *a); + +/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be + * at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */ +static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a); + +/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */ +static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a); + +/** Calculate the (modular) inverses of a batch of field elements. Requires the inputs' magnitudes to be + * at most 8. The output magnitudes are 1 (but not guaranteed to be normalized). The inputs and + * outputs must not overlap in memory. */ +static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k1_fe *a); + +/** Convert a field element to the storage type. */ +static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); + +/** Convert a field element back from the storage type. */ +static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a); + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ +static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag); + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ +static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); + +#endif diff --git a/src/secp256k1/src/field_10x26.h b/src/secp256k1/src/field_10x26.h new file mode 100644 index 000000000..61ee1e096 --- /dev/null +++ b/src/secp256k1/src/field_10x26.h @@ -0,0 +1,47 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_FIELD_REPR_ +#define _SECP256K1_FIELD_REPR_ + +#include + +typedef struct { + /* X = sum(i=0..9, elem[i]*2^26) mod n */ + uint32_t n[10]; +#ifdef VERIFY + int magnitude; + int normalized; +#endif +} secp256k1_fe; + +/* Unpacks a constant into a overlapping multi-limbed FE element. */ +#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ + (d0) & 0x3FFFFFFUL, \ + (((uint32_t)d0) >> 26) | (((uint32_t)(d1) & 0xFFFFFUL) << 6), \ + (((uint32_t)d1) >> 20) | (((uint32_t)(d2) & 0x3FFFUL) << 12), \ + (((uint32_t)d2) >> 14) | (((uint32_t)(d3) & 0xFFUL) << 18), \ + (((uint32_t)d3) >> 8) | (((uint32_t)(d4) & 0x3UL) << 24), \ + (((uint32_t)d4) >> 2) & 0x3FFFFFFUL, \ + (((uint32_t)d4) >> 28) | (((uint32_t)(d5) & 0x3FFFFFUL) << 4), \ + (((uint32_t)d5) >> 22) | (((uint32_t)(d6) & 0xFFFFUL) << 10), \ + (((uint32_t)d6) >> 16) | (((uint32_t)(d7) & 0x3FFUL) << 16), \ + (((uint32_t)d7) >> 10) \ +} + +#ifdef VERIFY +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1} +#else +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))} +#endif + +typedef struct { + uint32_t n[8]; +} secp256k1_fe_storage; + +#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }} +#define SECP256K1_FE_STORAGE_CONST_GET(d) d.n[7], d.n[6], d.n[5], d.n[4],d.n[3], d.n[2], d.n[1], d.n[0] +#endif diff --git a/src/secp256k1/src/field_10x26_impl.h b/src/secp256k1/src/field_10x26_impl.h new file mode 100644 index 000000000..7b8c07960 --- /dev/null +++ b/src/secp256k1/src/field_10x26_impl.h @@ -0,0 +1,1144 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_FIELD_REPR_IMPL_H_ +#define _SECP256K1_FIELD_REPR_IMPL_H_ + +#include "util.h" +#include "num.h" +#include "field.h" + +#ifdef VERIFY +static void secp256k1_fe_verify(const secp256k1_fe *a) { + const uint32_t *d = a->n; + int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; + r &= (d[0] <= 0x3FFFFFFUL * m); + r &= (d[1] <= 0x3FFFFFFUL * m); + r &= (d[2] <= 0x3FFFFFFUL * m); + r &= (d[3] <= 0x3FFFFFFUL * m); + r &= (d[4] <= 0x3FFFFFFUL * m); + r &= (d[5] <= 0x3FFFFFFUL * m); + r &= (d[6] <= 0x3FFFFFFUL * m); + r &= (d[7] <= 0x3FFFFFFUL * m); + r &= (d[8] <= 0x3FFFFFFUL * m); + r &= (d[9] <= 0x03FFFFFUL * m); + r &= (a->magnitude >= 0); + r &= (a->magnitude <= 32); + if (a->normalized) { + r &= (a->magnitude <= 1); + if (r && (d[9] == 0x03FFFFFUL)) { + uint32_t mid = d[8] & d[7] & d[6] & d[5] & d[4] & d[3] & d[2]; + if (mid == 0x3FFFFFFUL) { + r &= ((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL); + } + } + } + VERIFY_CHECK(r == 1); +} +#else +static void secp256k1_fe_verify(const secp256k1_fe *a) { + (void)a; +} +#endif + +static void secp256k1_fe_normalize(secp256k1_fe *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + uint32_t m; + uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; m = t2; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; m &= t3; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; m &= t4; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; m &= t5; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; m &= t6; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; m &= t7; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; m &= t8; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + /* At most a single final reduction is needed; check if the value is >= the field characteristic */ + x = (t9 >> 22) | ((t9 == 0x03FFFFFUL) & (m == 0x3FFFFFFUL) + & ((t1 + 0x40UL + ((t0 + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); + + /* Apply the final reduction (for constant-time behaviour, we do it always) */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; + + /* If t9 didn't carry to bit 22 already, then it should have after any final reduction */ + VERIFY_CHECK(t9 >> 22 == x); + + /* Mask off the possible multiple of 2^256 from the final reduction */ + t9 &= 0x03FFFFFUL; + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; + +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +#endif +} + +static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; + +#ifdef VERIFY + r->magnitude = 1; + secp256k1_fe_verify(r); +#endif +} + +static void secp256k1_fe_normalize_var(secp256k1_fe *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + uint32_t m; + uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; m = t2; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; m &= t3; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; m &= t4; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; m &= t5; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; m &= t6; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; m &= t7; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; m &= t8; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + /* At most a single final reduction is needed; check if the value is >= the field characteristic */ + x = (t9 >> 22) | ((t9 == 0x03FFFFFUL) & (m == 0x3FFFFFFUL) + & ((t1 + 0x40UL + ((t0 + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); + + if (x) { + t0 += 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; + + /* If t9 didn't carry to bit 22 already, then it should have after any final reduction */ + VERIFY_CHECK(t9 >> 22 == x); + + /* Mask off the possible multiple of 2^256 from the final reduction */ + t9 &= 0x03FFFFFUL; + } + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; + +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +#endif +} + +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + uint32_t z0, z1; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; z0 = t0; z1 = t0 ^ 0x3D0UL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; z0 |= t4; z1 &= t4; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; z0 |= t5; z1 &= t5; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; z0 |= t6; z1 &= t6; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; z0 |= t7; z1 &= t7; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; z0 |= t8; z1 &= t8; + z0 |= t9; z1 &= t9 ^ 0x3C00000UL; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + return (z0 == 0) | (z1 == 0x3FFFFFFUL); +} + +static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) { + uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint32_t z0, z1; + uint32_t x; + + t0 = r->n[0]; + t9 = r->n[9]; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + x = t9 >> 22; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + z0 = t0 & 0x3FFFFFFUL; + z1 = z0 ^ 0x3D0UL; + + /* Fast return path should catch the majority of cases */ + if ((z0 != 0UL) & (z1 != 0x3FFFFFFUL)) { + return 0; + } + + t1 = r->n[1]; + t2 = r->n[2]; + t3 = r->n[3]; + t4 = r->n[4]; + t5 = r->n[5]; + t6 = r->n[6]; + t7 = r->n[7]; + t8 = r->n[8]; + + t9 &= 0x03FFFFFUL; + t1 += (x << 6); + + t1 += (t0 >> 26); + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; z0 |= t4; z1 &= t4; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; z0 |= t5; z1 &= t5; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; z0 |= t6; z1 &= t6; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; z0 |= t7; z1 &= t7; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; z0 |= t8; z1 &= t8; + z0 |= t9; z1 &= t9 ^ 0x3C00000UL; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + return (z0 == 0) | (z1 == 0x3FFFFFFUL); +} + +SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { + r->n[0] = a; + r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +#endif +} + +SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { + const uint32_t *t = a->n; +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_fe_verify(a); +#endif + return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0; +} + +SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_fe_verify(a); +#endif + return a->n[0] & 1; +} + +SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { + int i; +#ifdef VERIFY + a->magnitude = 0; + a->normalized = 1; +#endif + for (i=0; i<10; i++) { + a->n[i] = 0; + } +} + +static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { + int i; +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + VERIFY_CHECK(b->normalized); + secp256k1_fe_verify(a); + secp256k1_fe_verify(b); +#endif + for (i = 9; i >= 0; i--) { + if (a->n[i] > b->n[i]) { + return 1; + } + if (a->n[i] < b->n[i]) { + return -1; + } + } + return 0; +} + +static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { + int i; + r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; + r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; + for (i=0; i<32; i++) { + int j; + for (j=0; j<4; j++) { + int limb = (8*i+2*j)/26; + int shift = (8*i+2*j)%26; + r->n[limb] |= (uint32_t)((a[31-i] >> (2*j)) & 0x3) << shift; + } + } + if (r->n[9] == 0x3FFFFFUL && (r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL && (r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL) { + return 0; + } +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +#endif + return 1; +} + +/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ +static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { + int i; +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_fe_verify(a); +#endif + for (i=0; i<32; i++) { + int j; + int c = 0; + for (j=0; j<4; j++) { + int limb = (8*i+2*j)/26; + int shift = (8*i+2*j)%26; + c |= ((a->n[limb] >> shift) & 0x3) << (2 * j); + } + r[31-i] = c; + } +} + +SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { +#ifdef VERIFY + VERIFY_CHECK(a->magnitude <= m); + secp256k1_fe_verify(a); +#endif + r->n[0] = 0x3FFFC2FUL * 2 * (m + 1) - a->n[0]; + r->n[1] = 0x3FFFFBFUL * 2 * (m + 1) - a->n[1]; + r->n[2] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[2]; + r->n[3] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[3]; + r->n[4] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[4]; + r->n[5] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[5]; + r->n[6] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[6]; + r->n[7] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[7]; + r->n[8] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[8]; + r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9]; +#ifdef VERIFY + r->magnitude = m + 1; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { + r->n[0] *= a; + r->n[1] *= a; + r->n[2] *= a; + r->n[3] *= a; + r->n[4] *= a; + r->n[5] *= a; + r->n[6] *= a; + r->n[7] *= a; + r->n[8] *= a; + r->n[9] *= a; +#ifdef VERIFY + r->magnitude *= a; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { +#ifdef VERIFY + secp256k1_fe_verify(a); +#endif + r->n[0] += a->n[0]; + r->n[1] += a->n[1]; + r->n[2] += a->n[2]; + r->n[3] += a->n[3]; + r->n[4] += a->n[4]; + r->n[5] += a->n[5]; + r->n[6] += a->n[6]; + r->n[7] += a->n[7]; + r->n[8] += a->n[8]; + r->n[9] += a->n[9]; +#ifdef VERIFY + r->magnitude += a->magnitude; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +#if defined(USE_EXTERNAL_ASM) + +/* External assembler implementation */ +void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b); +void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a); + +#else + +#ifdef VERIFY +#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) +#else +#define VERIFY_BITS(x, n) do { } while(0) +#endif + +SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b) { + uint64_t c, d; + uint64_t u0, u1, u2, u3, u4, u5, u6, u7, u8; + uint32_t t9, t1, t0, t2, t3, t4, t5, t6, t7; + const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL; + + VERIFY_BITS(a[0], 30); + VERIFY_BITS(a[1], 30); + VERIFY_BITS(a[2], 30); + VERIFY_BITS(a[3], 30); + VERIFY_BITS(a[4], 30); + VERIFY_BITS(a[5], 30); + VERIFY_BITS(a[6], 30); + VERIFY_BITS(a[7], 30); + VERIFY_BITS(a[8], 30); + VERIFY_BITS(a[9], 26); + VERIFY_BITS(b[0], 30); + VERIFY_BITS(b[1], 30); + VERIFY_BITS(b[2], 30); + VERIFY_BITS(b[3], 30); + VERIFY_BITS(b[4], 30); + VERIFY_BITS(b[5], 30); + VERIFY_BITS(b[6], 30); + VERIFY_BITS(b[7], 30); + VERIFY_BITS(b[8], 30); + VERIFY_BITS(b[9], 26); + + /** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n. + * px is a shorthand for sum(a[i]*b[x-i], i=0..x). + * Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0]. + */ + + d = (uint64_t)a[0] * b[9] + + (uint64_t)a[1] * b[8] + + (uint64_t)a[2] * b[7] + + (uint64_t)a[3] * b[6] + + (uint64_t)a[4] * b[5] + + (uint64_t)a[5] * b[4] + + (uint64_t)a[6] * b[3] + + (uint64_t)a[7] * b[2] + + (uint64_t)a[8] * b[1] + + (uint64_t)a[9] * b[0]; + /* VERIFY_BITS(d, 64); */ + /* [d 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ + t9 = d & M; d >>= 26; + VERIFY_BITS(t9, 26); + VERIFY_BITS(d, 38); + /* [d t9 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ + + c = (uint64_t)a[0] * b[0]; + VERIFY_BITS(c, 60); + /* [d t9 0 0 0 0 0 0 0 0 c] = [p9 0 0 0 0 0 0 0 0 p0] */ + d += (uint64_t)a[1] * b[9] + + (uint64_t)a[2] * b[8] + + (uint64_t)a[3] * b[7] + + (uint64_t)a[4] * b[6] + + (uint64_t)a[5] * b[5] + + (uint64_t)a[6] * b[4] + + (uint64_t)a[7] * b[3] + + (uint64_t)a[8] * b[2] + + (uint64_t)a[9] * b[1]; + VERIFY_BITS(d, 63); + /* [d t9 0 0 0 0 0 0 0 0 c] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + u0 = d & M; d >>= 26; c += u0 * R0; + VERIFY_BITS(u0, 26); + VERIFY_BITS(d, 37); + VERIFY_BITS(c, 61); + /* [d u0 t9 0 0 0 0 0 0 0 0 c-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + t0 = c & M; c >>= 26; c += u0 * R1; + VERIFY_BITS(t0, 26); + VERIFY_BITS(c, 37); + /* [d u0 t9 0 0 0 0 0 0 0 c-u0*R1 t0-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + + c += (uint64_t)a[0] * b[1] + + (uint64_t)a[1] * b[0]; + VERIFY_BITS(c, 62); + /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 p1 p0] */ + d += (uint64_t)a[2] * b[9] + + (uint64_t)a[3] * b[8] + + (uint64_t)a[4] * b[7] + + (uint64_t)a[5] * b[6] + + (uint64_t)a[6] * b[5] + + (uint64_t)a[7] * b[4] + + (uint64_t)a[8] * b[3] + + (uint64_t)a[9] * b[2]; + VERIFY_BITS(d, 63); + /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + u1 = d & M; d >>= 26; c += u1 * R0; + VERIFY_BITS(u1, 26); + VERIFY_BITS(d, 37); + VERIFY_BITS(c, 63); + /* [d u1 0 t9 0 0 0 0 0 0 0 c-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + t1 = c & M; c >>= 26; c += u1 * R1; + VERIFY_BITS(t1, 26); + VERIFY_BITS(c, 38); + /* [d u1 0 t9 0 0 0 0 0 0 c-u1*R1 t1-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + + c += (uint64_t)a[0] * b[2] + + (uint64_t)a[1] * b[1] + + (uint64_t)a[2] * b[0]; + VERIFY_BITS(c, 62); + /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + d += (uint64_t)a[3] * b[9] + + (uint64_t)a[4] * b[8] + + (uint64_t)a[5] * b[7] + + (uint64_t)a[6] * b[6] + + (uint64_t)a[7] * b[5] + + (uint64_t)a[8] * b[4] + + (uint64_t)a[9] * b[3]; + VERIFY_BITS(d, 63); + /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + u2 = d & M; d >>= 26; c += u2 * R0; + VERIFY_BITS(u2, 26); + VERIFY_BITS(d, 37); + VERIFY_BITS(c, 63); + /* [d u2 0 0 t9 0 0 0 0 0 0 c-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + t2 = c & M; c >>= 26; c += u2 * R1; + VERIFY_BITS(t2, 26); + VERIFY_BITS(c, 38); + /* [d u2 0 0 t9 0 0 0 0 0 c-u2*R1 t2-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + + c += (uint64_t)a[0] * b[3] + + (uint64_t)a[1] * b[2] + + (uint64_t)a[2] * b[1] + + (uint64_t)a[3] * b[0]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + d += (uint64_t)a[4] * b[9] + + (uint64_t)a[5] * b[8] + + (uint64_t)a[6] * b[7] + + (uint64_t)a[7] * b[6] + + (uint64_t)a[8] * b[5] + + (uint64_t)a[9] * b[4]; + VERIFY_BITS(d, 63); + /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + u3 = d & M; d >>= 26; c += u3 * R0; + VERIFY_BITS(u3, 26); + VERIFY_BITS(d, 37); + /* VERIFY_BITS(c, 64); */ + /* [d u3 0 0 0 t9 0 0 0 0 0 c-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + t3 = c & M; c >>= 26; c += u3 * R1; + VERIFY_BITS(t3, 26); + VERIFY_BITS(c, 39); + /* [d u3 0 0 0 t9 0 0 0 0 c-u3*R1 t3-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + + c += (uint64_t)a[0] * b[4] + + (uint64_t)a[1] * b[3] + + (uint64_t)a[2] * b[2] + + (uint64_t)a[3] * b[1] + + (uint64_t)a[4] * b[0]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + d += (uint64_t)a[5] * b[9] + + (uint64_t)a[6] * b[8] + + (uint64_t)a[7] * b[7] + + (uint64_t)a[8] * b[6] + + (uint64_t)a[9] * b[5]; + VERIFY_BITS(d, 62); + /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + u4 = d & M; d >>= 26; c += u4 * R0; + VERIFY_BITS(u4, 26); + VERIFY_BITS(d, 36); + /* VERIFY_BITS(c, 64); */ + /* [d u4 0 0 0 0 t9 0 0 0 0 c-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + t4 = c & M; c >>= 26; c += u4 * R1; + VERIFY_BITS(t4, 26); + VERIFY_BITS(c, 39); + /* [d u4 0 0 0 0 t9 0 0 0 c-u4*R1 t4-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + + c += (uint64_t)a[0] * b[5] + + (uint64_t)a[1] * b[4] + + (uint64_t)a[2] * b[3] + + (uint64_t)a[3] * b[2] + + (uint64_t)a[4] * b[1] + + (uint64_t)a[5] * b[0]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)a[6] * b[9] + + (uint64_t)a[7] * b[8] + + (uint64_t)a[8] * b[7] + + (uint64_t)a[9] * b[6]; + VERIFY_BITS(d, 62); + /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + u5 = d & M; d >>= 26; c += u5 * R0; + VERIFY_BITS(u5, 26); + VERIFY_BITS(d, 36); + /* VERIFY_BITS(c, 64); */ + /* [d u5 0 0 0 0 0 t9 0 0 0 c-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + t5 = c & M; c >>= 26; c += u5 * R1; + VERIFY_BITS(t5, 26); + VERIFY_BITS(c, 39); + /* [d u5 0 0 0 0 0 t9 0 0 c-u5*R1 t5-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + + c += (uint64_t)a[0] * b[6] + + (uint64_t)a[1] * b[5] + + (uint64_t)a[2] * b[4] + + (uint64_t)a[3] * b[3] + + (uint64_t)a[4] * b[2] + + (uint64_t)a[5] * b[1] + + (uint64_t)a[6] * b[0]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)a[7] * b[9] + + (uint64_t)a[8] * b[8] + + (uint64_t)a[9] * b[7]; + VERIFY_BITS(d, 61); + /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + u6 = d & M; d >>= 26; c += u6 * R0; + VERIFY_BITS(u6, 26); + VERIFY_BITS(d, 35); + /* VERIFY_BITS(c, 64); */ + /* [d u6 0 0 0 0 0 0 t9 0 0 c-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + t6 = c & M; c >>= 26; c += u6 * R1; + VERIFY_BITS(t6, 26); + VERIFY_BITS(c, 39); + /* [d u6 0 0 0 0 0 0 t9 0 c-u6*R1 t6-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + + c += (uint64_t)a[0] * b[7] + + (uint64_t)a[1] * b[6] + + (uint64_t)a[2] * b[5] + + (uint64_t)a[3] * b[4] + + (uint64_t)a[4] * b[3] + + (uint64_t)a[5] * b[2] + + (uint64_t)a[6] * b[1] + + (uint64_t)a[7] * b[0]; + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x8000007C00000007ULL); + /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)a[8] * b[9] + + (uint64_t)a[9] * b[8]; + VERIFY_BITS(d, 58); + /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + u7 = d & M; d >>= 26; c += u7 * R0; + VERIFY_BITS(u7, 26); + VERIFY_BITS(d, 32); + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x800001703FFFC2F7ULL); + /* [d u7 0 0 0 0 0 0 0 t9 0 c-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + t7 = c & M; c >>= 26; c += u7 * R1; + VERIFY_BITS(t7, 26); + VERIFY_BITS(c, 38); + /* [d u7 0 0 0 0 0 0 0 t9 c-u7*R1 t7-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + + c += (uint64_t)a[0] * b[8] + + (uint64_t)a[1] * b[7] + + (uint64_t)a[2] * b[6] + + (uint64_t)a[3] * b[5] + + (uint64_t)a[4] * b[4] + + (uint64_t)a[5] * b[3] + + (uint64_t)a[6] * b[2] + + (uint64_t)a[7] * b[1] + + (uint64_t)a[8] * b[0]; + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x9000007B80000008ULL); + /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)a[9] * b[9]; + VERIFY_BITS(d, 57); + /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + u8 = d & M; d >>= 26; c += u8 * R0; + VERIFY_BITS(u8, 26); + VERIFY_BITS(d, 31); + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x9000016FBFFFC2F8ULL); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + r[3] = t3; + VERIFY_BITS(r[3], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[4] = t4; + VERIFY_BITS(r[4], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[5] = t5; + VERIFY_BITS(r[5], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[6] = t6; + VERIFY_BITS(r[6], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[7] = t7; + VERIFY_BITS(r[7], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + r[8] = c & M; c >>= 26; c += u8 * R1; + VERIFY_BITS(r[8], 26); + VERIFY_BITS(c, 39); + /* [d u8 0 0 0 0 0 0 0 0 t9+c-u8*R1 r8-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 0 0 t9+c r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += d * R0 + t9; + VERIFY_BITS(c, 45); + /* [d 0 0 0 0 0 0 0 0 0 c-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[9] = c & (M >> 4); c >>= 22; c += d * (R1 << 4); + VERIFY_BITS(r[9], 22); + VERIFY_BITS(c, 46); + /* [d 0 0 0 0 0 0 0 0 r9+((c-d*R1<<4)<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 -d*R1 r9+(c<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + d = c * (R0 >> 4) + t0; + VERIFY_BITS(d, 56); + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 d-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[0] = d & M; d >>= 26; + VERIFY_BITS(r[0], 26); + VERIFY_BITS(d, 30); + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1+d r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += c * (R1 >> 4) + t1; + VERIFY_BITS(d, 53); + VERIFY_CHECK(d <= 0x10000003FFFFBFULL); + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 d-c*R1>>4 r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [r9 r8 r7 r6 r5 r4 r3 t2 d r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[1] = d & M; d >>= 26; + VERIFY_BITS(r[1], 26); + VERIFY_BITS(d, 27); + VERIFY_CHECK(d <= 0x4000000ULL); + /* [r9 r8 r7 r6 r5 r4 r3 t2+d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += t2; + VERIFY_BITS(d, 27); + /* [r9 r8 r7 r6 r5 r4 r3 d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[2] = d; + VERIFY_BITS(r[2], 27); + /* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ +} + +SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a) { + uint64_t c, d; + uint64_t u0, u1, u2, u3, u4, u5, u6, u7, u8; + uint32_t t9, t0, t1, t2, t3, t4, t5, t6, t7; + const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL; + + VERIFY_BITS(a[0], 30); + VERIFY_BITS(a[1], 30); + VERIFY_BITS(a[2], 30); + VERIFY_BITS(a[3], 30); + VERIFY_BITS(a[4], 30); + VERIFY_BITS(a[5], 30); + VERIFY_BITS(a[6], 30); + VERIFY_BITS(a[7], 30); + VERIFY_BITS(a[8], 30); + VERIFY_BITS(a[9], 26); + + /** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n. + * px is a shorthand for sum(a[i]*a[x-i], i=0..x). + * Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0]. + */ + + d = (uint64_t)(a[0]*2) * a[9] + + (uint64_t)(a[1]*2) * a[8] + + (uint64_t)(a[2]*2) * a[7] + + (uint64_t)(a[3]*2) * a[6] + + (uint64_t)(a[4]*2) * a[5]; + /* VERIFY_BITS(d, 64); */ + /* [d 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ + t9 = d & M; d >>= 26; + VERIFY_BITS(t9, 26); + VERIFY_BITS(d, 38); + /* [d t9 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ + + c = (uint64_t)a[0] * a[0]; + VERIFY_BITS(c, 60); + /* [d t9 0 0 0 0 0 0 0 0 c] = [p9 0 0 0 0 0 0 0 0 p0] */ + d += (uint64_t)(a[1]*2) * a[9] + + (uint64_t)(a[2]*2) * a[8] + + (uint64_t)(a[3]*2) * a[7] + + (uint64_t)(a[4]*2) * a[6] + + (uint64_t)a[5] * a[5]; + VERIFY_BITS(d, 63); + /* [d t9 0 0 0 0 0 0 0 0 c] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + u0 = d & M; d >>= 26; c += u0 * R0; + VERIFY_BITS(u0, 26); + VERIFY_BITS(d, 37); + VERIFY_BITS(c, 61); + /* [d u0 t9 0 0 0 0 0 0 0 0 c-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + t0 = c & M; c >>= 26; c += u0 * R1; + VERIFY_BITS(t0, 26); + VERIFY_BITS(c, 37); + /* [d u0 t9 0 0 0 0 0 0 0 c-u0*R1 t0-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + + c += (uint64_t)(a[0]*2) * a[1]; + VERIFY_BITS(c, 62); + /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 p1 p0] */ + d += (uint64_t)(a[2]*2) * a[9] + + (uint64_t)(a[3]*2) * a[8] + + (uint64_t)(a[4]*2) * a[7] + + (uint64_t)(a[5]*2) * a[6]; + VERIFY_BITS(d, 63); + /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + u1 = d & M; d >>= 26; c += u1 * R0; + VERIFY_BITS(u1, 26); + VERIFY_BITS(d, 37); + VERIFY_BITS(c, 63); + /* [d u1 0 t9 0 0 0 0 0 0 0 c-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + t1 = c & M; c >>= 26; c += u1 * R1; + VERIFY_BITS(t1, 26); + VERIFY_BITS(c, 38); + /* [d u1 0 t9 0 0 0 0 0 0 c-u1*R1 t1-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[2] + + (uint64_t)a[1] * a[1]; + VERIFY_BITS(c, 62); + /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + d += (uint64_t)(a[3]*2) * a[9] + + (uint64_t)(a[4]*2) * a[8] + + (uint64_t)(a[5]*2) * a[7] + + (uint64_t)a[6] * a[6]; + VERIFY_BITS(d, 63); + /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + u2 = d & M; d >>= 26; c += u2 * R0; + VERIFY_BITS(u2, 26); + VERIFY_BITS(d, 37); + VERIFY_BITS(c, 63); + /* [d u2 0 0 t9 0 0 0 0 0 0 c-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + t2 = c & M; c >>= 26; c += u2 * R1; + VERIFY_BITS(t2, 26); + VERIFY_BITS(c, 38); + /* [d u2 0 0 t9 0 0 0 0 0 c-u2*R1 t2-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[3] + + (uint64_t)(a[1]*2) * a[2]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + d += (uint64_t)(a[4]*2) * a[9] + + (uint64_t)(a[5]*2) * a[8] + + (uint64_t)(a[6]*2) * a[7]; + VERIFY_BITS(d, 63); + /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + u3 = d & M; d >>= 26; c += u3 * R0; + VERIFY_BITS(u3, 26); + VERIFY_BITS(d, 37); + /* VERIFY_BITS(c, 64); */ + /* [d u3 0 0 0 t9 0 0 0 0 0 c-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + t3 = c & M; c >>= 26; c += u3 * R1; + VERIFY_BITS(t3, 26); + VERIFY_BITS(c, 39); + /* [d u3 0 0 0 t9 0 0 0 0 c-u3*R1 t3-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[4] + + (uint64_t)(a[1]*2) * a[3] + + (uint64_t)a[2] * a[2]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + d += (uint64_t)(a[5]*2) * a[9] + + (uint64_t)(a[6]*2) * a[8] + + (uint64_t)a[7] * a[7]; + VERIFY_BITS(d, 62); + /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + u4 = d & M; d >>= 26; c += u4 * R0; + VERIFY_BITS(u4, 26); + VERIFY_BITS(d, 36); + /* VERIFY_BITS(c, 64); */ + /* [d u4 0 0 0 0 t9 0 0 0 0 c-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + t4 = c & M; c >>= 26; c += u4 * R1; + VERIFY_BITS(t4, 26); + VERIFY_BITS(c, 39); + /* [d u4 0 0 0 0 t9 0 0 0 c-u4*R1 t4-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[5] + + (uint64_t)(a[1]*2) * a[4] + + (uint64_t)(a[2]*2) * a[3]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)(a[6]*2) * a[9] + + (uint64_t)(a[7]*2) * a[8]; + VERIFY_BITS(d, 62); + /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + u5 = d & M; d >>= 26; c += u5 * R0; + VERIFY_BITS(u5, 26); + VERIFY_BITS(d, 36); + /* VERIFY_BITS(c, 64); */ + /* [d u5 0 0 0 0 0 t9 0 0 0 c-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + t5 = c & M; c >>= 26; c += u5 * R1; + VERIFY_BITS(t5, 26); + VERIFY_BITS(c, 39); + /* [d u5 0 0 0 0 0 t9 0 0 c-u5*R1 t5-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[6] + + (uint64_t)(a[1]*2) * a[5] + + (uint64_t)(a[2]*2) * a[4] + + (uint64_t)a[3] * a[3]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)(a[7]*2) * a[9] + + (uint64_t)a[8] * a[8]; + VERIFY_BITS(d, 61); + /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + u6 = d & M; d >>= 26; c += u6 * R0; + VERIFY_BITS(u6, 26); + VERIFY_BITS(d, 35); + /* VERIFY_BITS(c, 64); */ + /* [d u6 0 0 0 0 0 0 t9 0 0 c-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + t6 = c & M; c >>= 26; c += u6 * R1; + VERIFY_BITS(t6, 26); + VERIFY_BITS(c, 39); + /* [d u6 0 0 0 0 0 0 t9 0 c-u6*R1 t6-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[7] + + (uint64_t)(a[1]*2) * a[6] + + (uint64_t)(a[2]*2) * a[5] + + (uint64_t)(a[3]*2) * a[4]; + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x8000007C00000007ULL); + /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)(a[8]*2) * a[9]; + VERIFY_BITS(d, 58); + /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + u7 = d & M; d >>= 26; c += u7 * R0; + VERIFY_BITS(u7, 26); + VERIFY_BITS(d, 32); + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x800001703FFFC2F7ULL); + /* [d u7 0 0 0 0 0 0 0 t9 0 c-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + t7 = c & M; c >>= 26; c += u7 * R1; + VERIFY_BITS(t7, 26); + VERIFY_BITS(c, 38); + /* [d u7 0 0 0 0 0 0 0 t9 c-u7*R1 t7-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[8] + + (uint64_t)(a[1]*2) * a[7] + + (uint64_t)(a[2]*2) * a[6] + + (uint64_t)(a[3]*2) * a[5] + + (uint64_t)a[4] * a[4]; + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x9000007B80000008ULL); + /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)a[9] * a[9]; + VERIFY_BITS(d, 57); + /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + u8 = d & M; d >>= 26; c += u8 * R0; + VERIFY_BITS(u8, 26); + VERIFY_BITS(d, 31); + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x9000016FBFFFC2F8ULL); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + r[3] = t3; + VERIFY_BITS(r[3], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[4] = t4; + VERIFY_BITS(r[4], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[5] = t5; + VERIFY_BITS(r[5], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[6] = t6; + VERIFY_BITS(r[6], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[7] = t7; + VERIFY_BITS(r[7], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + r[8] = c & M; c >>= 26; c += u8 * R1; + VERIFY_BITS(r[8], 26); + VERIFY_BITS(c, 39); + /* [d u8 0 0 0 0 0 0 0 0 t9+c-u8*R1 r8-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 0 0 t9+c r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += d * R0 + t9; + VERIFY_BITS(c, 45); + /* [d 0 0 0 0 0 0 0 0 0 c-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[9] = c & (M >> 4); c >>= 22; c += d * (R1 << 4); + VERIFY_BITS(r[9], 22); + VERIFY_BITS(c, 46); + /* [d 0 0 0 0 0 0 0 0 r9+((c-d*R1<<4)<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 -d*R1 r9+(c<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + d = c * (R0 >> 4) + t0; + VERIFY_BITS(d, 56); + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 d-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[0] = d & M; d >>= 26; + VERIFY_BITS(r[0], 26); + VERIFY_BITS(d, 30); + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1+d r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += c * (R1 >> 4) + t1; + VERIFY_BITS(d, 53); + VERIFY_CHECK(d <= 0x10000003FFFFBFULL); + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 d-c*R1>>4 r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [r9 r8 r7 r6 r5 r4 r3 t2 d r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[1] = d & M; d >>= 26; + VERIFY_BITS(r[1], 26); + VERIFY_BITS(d, 27); + VERIFY_CHECK(d <= 0x4000000ULL); + /* [r9 r8 r7 r6 r5 r4 r3 t2+d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += t2; + VERIFY_BITS(d, 27); + /* [r9 r8 r7 r6 r5 r4 r3 d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[2] = d; + VERIFY_BITS(r[2], 27); + /* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ +} +#endif + +static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { +#ifdef VERIFY + VERIFY_CHECK(a->magnitude <= 8); + VERIFY_CHECK(b->magnitude <= 8); + secp256k1_fe_verify(a); + secp256k1_fe_verify(b); + VERIFY_CHECK(r != b); +#endif + secp256k1_fe_mul_inner(r->n, a->n, b->n); +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { +#ifdef VERIFY + VERIFY_CHECK(a->magnitude <= 8); + secp256k1_fe_verify(a); +#endif + secp256k1_fe_sqr_inner(r->n, a->n); +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { + uint32_t mask0, mask1; + mask0 = flag + ~((uint32_t)0); + mask1 = ~mask0; + r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); + r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); + r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); + r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); + r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); + r->n[5] = (r->n[5] & mask0) | (a->n[5] & mask1); + r->n[6] = (r->n[6] & mask0) | (a->n[6] & mask1); + r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); + r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1); + r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1); +#ifdef VERIFY + if (a->magnitude > r->magnitude) { + r->magnitude = a->magnitude; + } + r->normalized &= a->normalized; +#endif +} + +static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { + uint32_t mask0, mask1; + mask0 = flag + ~((uint32_t)0); + mask1 = ~mask0; + r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); + r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); + r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); + r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); + r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); + r->n[5] = (r->n[5] & mask0) | (a->n[5] & mask1); + r->n[6] = (r->n[6] & mask0) | (a->n[6] & mask1); + r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); +} + +static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { +#ifdef VERIFY + VERIFY_CHECK(a->normalized); +#endif + r->n[0] = a->n[0] | a->n[1] << 26; + r->n[1] = a->n[1] >> 6 | a->n[2] << 20; + r->n[2] = a->n[2] >> 12 | a->n[3] << 14; + r->n[3] = a->n[3] >> 18 | a->n[4] << 8; + r->n[4] = a->n[4] >> 24 | a->n[5] << 2 | a->n[6] << 28; + r->n[5] = a->n[6] >> 4 | a->n[7] << 22; + r->n[6] = a->n[7] >> 10 | a->n[8] << 16; + r->n[7] = a->n[8] >> 16 | a->n[9] << 10; +} + +static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { + r->n[0] = a->n[0] & 0x3FFFFFFUL; + r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL); + r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL); + r->n[3] = a->n[2] >> 14 | ((a->n[3] << 18) & 0x3FFFFFFUL); + r->n[4] = a->n[3] >> 8 | ((a->n[4] << 24) & 0x3FFFFFFUL); + r->n[5] = (a->n[4] >> 2) & 0x3FFFFFFUL; + r->n[6] = a->n[4] >> 28 | ((a->n[5] << 4) & 0x3FFFFFFUL); + r->n[7] = a->n[5] >> 22 | ((a->n[6] << 10) & 0x3FFFFFFUL); + r->n[8] = a->n[6] >> 16 | ((a->n[7] << 16) & 0x3FFFFFFUL); + r->n[9] = a->n[7] >> 10; +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; +#endif +} + +#endif diff --git a/src/secp256k1/src/field_5x52.h b/src/secp256k1/src/field_5x52.h new file mode 100644 index 000000000..8e69a560d --- /dev/null +++ b/src/secp256k1/src/field_5x52.h @@ -0,0 +1,47 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_FIELD_REPR_ +#define _SECP256K1_FIELD_REPR_ + +#include + +typedef struct { + /* X = sum(i=0..4, elem[i]*2^52) mod n */ + uint64_t n[5]; +#ifdef VERIFY + int magnitude; + int normalized; +#endif +} secp256k1_fe; + +/* Unpacks a constant into a overlapping multi-limbed FE element. */ +#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ + (d0) | (((uint64_t)(d1) & 0xFFFFFUL) << 32), \ + ((uint64_t)(d1) >> 20) | (((uint64_t)(d2)) << 12) | (((uint64_t)(d3) & 0xFFUL) << 44), \ + ((uint64_t)(d3) >> 8) | (((uint64_t)(d4) & 0xFFFFFFFUL) << 24), \ + ((uint64_t)(d4) >> 28) | (((uint64_t)(d5)) << 4) | (((uint64_t)(d6) & 0xFFFFUL) << 36), \ + ((uint64_t)(d6) >> 16) | (((uint64_t)(d7)) << 16) \ +} + +#ifdef VERIFY +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1} +#else +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))} +#endif + +typedef struct { + uint64_t n[4]; +} secp256k1_fe_storage; + +#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ \ + (d0) | (((uint64_t)(d1)) << 32), \ + (d2) | (((uint64_t)(d3)) << 32), \ + (d4) | (((uint64_t)(d5)) << 32), \ + (d6) | (((uint64_t)(d7)) << 32) \ +}} + +#endif diff --git a/src/secp256k1/src/field_5x52_asm_impl.h b/src/secp256k1/src/field_5x52_asm_impl.h new file mode 100644 index 000000000..98cc004bf --- /dev/null +++ b/src/secp256k1/src/field_5x52_asm_impl.h @@ -0,0 +1,502 @@ +/********************************************************************** + * Copyright (c) 2013-2014 Diederik Huys, Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +/** + * Changelog: + * - March 2013, Diederik Huys: original version + * - November 2014, Pieter Wuille: updated to use Peter Dettman's parallel multiplication algorithm + * - December 2014, Pieter Wuille: converted from YASM to GCC inline assembly + */ + +#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_ +#define _SECP256K1_FIELD_INNER5X52_IMPL_H_ + +SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { +/** + * Registers: rdx:rax = multiplication accumulator + * r9:r8 = c + * r15:rcx = d + * r10-r14 = a0-a4 + * rbx = b + * rdi = r + * rsi = a / t? + */ + uint64_t tmp1, tmp2, tmp3; +__asm__ __volatile__( + "movq 0(%%rsi),%%r10\n" + "movq 8(%%rsi),%%r11\n" + "movq 16(%%rsi),%%r12\n" + "movq 24(%%rsi),%%r13\n" + "movq 32(%%rsi),%%r14\n" + + /* d += a3 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r13\n" + "movq %%rax,%%rcx\n" + "movq %%rdx,%%r15\n" + /* d += a2 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a1 * b2 */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d = a0 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r10\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* c = a4 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r14\n" + "movq %%rax,%%r8\n" + "movq %%rdx,%%r9\n" + /* d += (c & M) * R */ + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* c >>= 52 (%%r8 only) */ + "shrdq $52,%%r9,%%r8\n" + /* t3 (tmp1) = d & M */ + "movq %%rcx,%%rsi\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rsi\n" + "movq %%rsi,%q1\n" + /* d >>= 52 */ + "shrdq $52,%%r15,%%rcx\n" + "xorq %%r15,%%r15\n" + /* d += a4 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a3 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a2 * b2 */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a1 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a0 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r10\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += c * R */ + "movq %%r8,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* t4 = d & M (%%rsi) */ + "movq %%rcx,%%rsi\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rsi\n" + /* d >>= 52 */ + "shrdq $52,%%r15,%%rcx\n" + "xorq %%r15,%%r15\n" + /* tx = t4 >> 48 (tmp3) */ + "movq %%rsi,%%rax\n" + "shrq $48,%%rax\n" + "movq %%rax,%q3\n" + /* t4 &= (M >> 4) (tmp2) */ + "movq $0xffffffffffff,%%rax\n" + "andq %%rax,%%rsi\n" + "movq %%rsi,%q2\n" + /* c = a0 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r10\n" + "movq %%rax,%%r8\n" + "movq %%rdx,%%r9\n" + /* d += a4 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a3 * b2 */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a2 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a1 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* u0 = d & M (%%rsi) */ + "movq %%rcx,%%rsi\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rsi\n" + /* d >>= 52 */ + "shrdq $52,%%r15,%%rcx\n" + "xorq %%r15,%%r15\n" + /* u0 = (u0 << 4) | tx (%%rsi) */ + "shlq $4,%%rsi\n" + "movq %q3,%%rax\n" + "orq %%rax,%%rsi\n" + /* c += u0 * (R >> 4) */ + "movq $0x1000003d1,%%rax\n" + "mulq %%rsi\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* r[0] = c & M */ + "movq %%r8,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq %%rax,0(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += a1 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* c += a0 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r10\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d += a4 * b2 */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a3 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a2 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* c += (d & M) * R */ + "movq %%rcx,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d >>= 52 */ + "shrdq $52,%%r15,%%rcx\n" + "xorq %%r15,%%r15\n" + /* r[1] = c & M */ + "movq %%r8,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq %%rax,8(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += a2 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* c += a1 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* c += a0 * b2 (last use of %%r10 = a0) */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r10\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* fetch t3 (%%r10, overwrites a0), t4 (%%rsi) */ + "movq %q2,%%rsi\n" + "movq %q1,%%r10\n" + /* d += a4 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a3 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* c += (d & M) * R */ + "movq %%rcx,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d >>= 52 (%%rcx only) */ + "shrdq $52,%%r15,%%rcx\n" + /* r[2] = c & M */ + "movq %%r8,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq %%rax,16(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += t3 */ + "addq %%r10,%%r8\n" + /* c += d * R */ + "movq %%rcx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* r[3] = c & M */ + "movq %%r8,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq %%rax,24(%%rdi)\n" + /* c >>= 52 (%%r8 only) */ + "shrdq $52,%%r9,%%r8\n" + /* c += t4 (%%r8 only) */ + "addq %%rsi,%%r8\n" + /* r[4] = c */ + "movq %%r8,32(%%rdi)\n" +: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3) +: "b"(b), "D"(r) +: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory" +); +} + +SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) { +/** + * Registers: rdx:rax = multiplication accumulator + * r9:r8 = c + * rcx:rbx = d + * r10-r14 = a0-a4 + * r15 = M (0xfffffffffffff) + * rdi = r + * rsi = a / t? + */ + uint64_t tmp1, tmp2, tmp3; +__asm__ __volatile__( + "movq 0(%%rsi),%%r10\n" + "movq 8(%%rsi),%%r11\n" + "movq 16(%%rsi),%%r12\n" + "movq 24(%%rsi),%%r13\n" + "movq 32(%%rsi),%%r14\n" + "movq $0xfffffffffffff,%%r15\n" + + /* d = (a0*2) * a3 */ + "leaq (%%r10,%%r10,1),%%rax\n" + "mulq %%r13\n" + "movq %%rax,%%rbx\n" + "movq %%rdx,%%rcx\n" + /* d += (a1*2) * a2 */ + "leaq (%%r11,%%r11,1),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* c = a4 * a4 */ + "movq %%r14,%%rax\n" + "mulq %%r14\n" + "movq %%rax,%%r8\n" + "movq %%rdx,%%r9\n" + /* d += (c & M) * R */ + "andq %%r15,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* c >>= 52 (%%r8 only) */ + "shrdq $52,%%r9,%%r8\n" + /* t3 (tmp1) = d & M */ + "movq %%rbx,%%rsi\n" + "andq %%r15,%%rsi\n" + "movq %%rsi,%q1\n" + /* d >>= 52 */ + "shrdq $52,%%rcx,%%rbx\n" + "xorq %%rcx,%%rcx\n" + /* a4 *= 2 */ + "addq %%r14,%%r14\n" + /* d += a0 * a4 */ + "movq %%r10,%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d+= (a1*2) * a3 */ + "leaq (%%r11,%%r11,1),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d += a2 * a2 */ + "movq %%r12,%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d += c * R */ + "movq %%r8,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* t4 = d & M (%%rsi) */ + "movq %%rbx,%%rsi\n" + "andq %%r15,%%rsi\n" + /* d >>= 52 */ + "shrdq $52,%%rcx,%%rbx\n" + "xorq %%rcx,%%rcx\n" + /* tx = t4 >> 48 (tmp3) */ + "movq %%rsi,%%rax\n" + "shrq $48,%%rax\n" + "movq %%rax,%q3\n" + /* t4 &= (M >> 4) (tmp2) */ + "movq $0xffffffffffff,%%rax\n" + "andq %%rax,%%rsi\n" + "movq %%rsi,%q2\n" + /* c = a0 * a0 */ + "movq %%r10,%%rax\n" + "mulq %%r10\n" + "movq %%rax,%%r8\n" + "movq %%rdx,%%r9\n" + /* d += a1 * a4 */ + "movq %%r11,%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d += (a2*2) * a3 */ + "leaq (%%r12,%%r12,1),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* u0 = d & M (%%rsi) */ + "movq %%rbx,%%rsi\n" + "andq %%r15,%%rsi\n" + /* d >>= 52 */ + "shrdq $52,%%rcx,%%rbx\n" + "xorq %%rcx,%%rcx\n" + /* u0 = (u0 << 4) | tx (%%rsi) */ + "shlq $4,%%rsi\n" + "movq %q3,%%rax\n" + "orq %%rax,%%rsi\n" + /* c += u0 * (R >> 4) */ + "movq $0x1000003d1,%%rax\n" + "mulq %%rsi\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* r[0] = c & M */ + "movq %%r8,%%rax\n" + "andq %%r15,%%rax\n" + "movq %%rax,0(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* a0 *= 2 */ + "addq %%r10,%%r10\n" + /* c += a0 * a1 */ + "movq %%r10,%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d += a2 * a4 */ + "movq %%r12,%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d += a3 * a3 */ + "movq %%r13,%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* c += (d & M) * R */ + "movq %%rbx,%%rax\n" + "andq %%r15,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d >>= 52 */ + "shrdq $52,%%rcx,%%rbx\n" + "xorq %%rcx,%%rcx\n" + /* r[1] = c & M */ + "movq %%r8,%%rax\n" + "andq %%r15,%%rax\n" + "movq %%rax,8(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += a0 * a2 (last use of %%r10) */ + "movq %%r10,%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* fetch t3 (%%r10, overwrites a0),t4 (%%rsi) */ + "movq %q2,%%rsi\n" + "movq %q1,%%r10\n" + /* c += a1 * a1 */ + "movq %%r11,%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d += a3 * a4 */ + "movq %%r13,%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* c += (d & M) * R */ + "movq %%rbx,%%rax\n" + "andq %%r15,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d >>= 52 (%%rbx only) */ + "shrdq $52,%%rcx,%%rbx\n" + /* r[2] = c & M */ + "movq %%r8,%%rax\n" + "andq %%r15,%%rax\n" + "movq %%rax,16(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += t3 */ + "addq %%r10,%%r8\n" + /* c += d * R */ + "movq %%rbx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* r[3] = c & M */ + "movq %%r8,%%rax\n" + "andq %%r15,%%rax\n" + "movq %%rax,24(%%rdi)\n" + /* c >>= 52 (%%r8 only) */ + "shrdq $52,%%r9,%%r8\n" + /* c += t4 (%%r8 only) */ + "addq %%rsi,%%r8\n" + /* r[4] = c */ + "movq %%r8,32(%%rdi)\n" +: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3) +: "D"(r) +: "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory" +); +} + +#endif diff --git a/src/secp256k1/src/field_5x52_impl.h b/src/secp256k1/src/field_5x52_impl.h new file mode 100644 index 000000000..7a99eb21e --- /dev/null +++ b/src/secp256k1/src/field_5x52_impl.h @@ -0,0 +1,455 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_FIELD_REPR_IMPL_H_ +#define _SECP256K1_FIELD_REPR_IMPL_H_ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include "util.h" +#include "num.h" +#include "field.h" + +#if defined(USE_ASM_X86_64) +#include "field_5x52_asm_impl.h" +#else +#include "field_5x52_int128_impl.h" +#endif + +/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F, + * represented as 5 uint64_t's in base 2^52. The values are allowed to contain >52 each. In particular, + * each FieldElem has a 'magnitude' associated with it. Internally, a magnitude M means each element + * is at most M*(2^53-1), except the most significant one, which is limited to M*(2^49-1). All operations + * accept any input with magnitude at most M, and have different rules for propagating magnitude to their + * output. + */ + +#ifdef VERIFY +static void secp256k1_fe_verify(const secp256k1_fe *a) { + const uint64_t *d = a->n; + int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; + /* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ + r &= (d[0] <= 0xFFFFFFFFFFFFFULL * m); + r &= (d[1] <= 0xFFFFFFFFFFFFFULL * m); + r &= (d[2] <= 0xFFFFFFFFFFFFFULL * m); + r &= (d[3] <= 0xFFFFFFFFFFFFFULL * m); + r &= (d[4] <= 0x0FFFFFFFFFFFFULL * m); + r &= (a->magnitude >= 0); + r &= (a->magnitude <= 2048); + if (a->normalized) { + r &= (a->magnitude <= 1); + if (r && (d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) { + r &= (d[0] < 0xFFFFEFFFFFC2FULL); + } + } + VERIFY_CHECK(r == 1); +} +#else +static void secp256k1_fe_verify(const secp256k1_fe *a) { + (void)a; +} +#endif + +static void secp256k1_fe_normalize(secp256k1_fe *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t m; + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; m = t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; m &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; m &= t3; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + /* At most a single final reduction is needed; check if the value is >= the field characteristic */ + x = (t4 >> 48) | ((t4 == 0x0FFFFFFFFFFFFULL) & (m == 0xFFFFFFFFFFFFFULL) + & (t0 >= 0xFFFFEFFFFFC2FULL)); + + /* Apply the final reduction (for constant-time behaviour, we do it always) */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; + + /* If t4 didn't carry to bit 48 already, then it should have after any final reduction */ + VERIFY_CHECK(t4 >> 48 == x); + + /* Mask off the possible multiple of 2^256 from the final reduction */ + t4 &= 0x0FFFFFFFFFFFFULL; + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +#endif +} + +static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + +#ifdef VERIFY + r->magnitude = 1; + secp256k1_fe_verify(r); +#endif +} + +static void secp256k1_fe_normalize_var(secp256k1_fe *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t m; + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; m = t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; m &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; m &= t3; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + /* At most a single final reduction is needed; check if the value is >= the field characteristic */ + x = (t4 >> 48) | ((t4 == 0x0FFFFFFFFFFFFULL) & (m == 0xFFFFFFFFFFFFFULL) + & (t0 >= 0xFFFFEFFFFFC2FULL)); + + if (x) { + t0 += 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; + + /* If t4 didn't carry to bit 48 already, then it should have after any final reduction */ + VERIFY_CHECK(t4 >> 48 == x); + + /* Mask off the possible multiple of 2^256 from the final reduction */ + t4 &= 0x0FFFFFFFFFFFFULL; + } + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +#endif +} + +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + uint64_t z0, z1; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; z0 = t0; z1 = t0 ^ 0x1000003D0ULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3; + z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); +} + +static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) { + uint64_t t0, t1, t2, t3, t4; + uint64_t z0, z1; + uint64_t x; + + t0 = r->n[0]; + t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + x = t4 >> 48; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + z0 = t0 & 0xFFFFFFFFFFFFFULL; + z1 = z0 ^ 0x1000003D0ULL; + + /* Fast return path should catch the majority of cases */ + if ((z0 != 0ULL) & (z1 != 0xFFFFFFFFFFFFFULL)) { + return 0; + } + + t1 = r->n[1]; + t2 = r->n[2]; + t3 = r->n[3]; + + t4 &= 0x0FFFFFFFFFFFFULL; + + t1 += (t0 >> 52); + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3; + z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); +} + +SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { + r->n[0] = a; + r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +#endif +} + +SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { + const uint64_t *t = a->n; +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_fe_verify(a); +#endif + return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0; +} + +SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_fe_verify(a); +#endif + return a->n[0] & 1; +} + +SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { + int i; +#ifdef VERIFY + a->magnitude = 0; + a->normalized = 1; +#endif + for (i=0; i<5; i++) { + a->n[i] = 0; + } +} + +static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { + int i; +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + VERIFY_CHECK(b->normalized); + secp256k1_fe_verify(a); + secp256k1_fe_verify(b); +#endif + for (i = 4; i >= 0; i--) { + if (a->n[i] > b->n[i]) { + return 1; + } + if (a->n[i] < b->n[i]) { + return -1; + } + } + return 0; +} + +static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { + int i; + r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; + for (i=0; i<32; i++) { + int j; + for (j=0; j<2; j++) { + int limb = (8*i+4*j)/52; + int shift = (8*i+4*j)%52; + r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift; + } + } + if (r->n[4] == 0x0FFFFFFFFFFFFULL && (r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL && r->n[0] >= 0xFFFFEFFFFFC2FULL) { + return 0; + } +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +#endif + return 1; +} + +/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ +static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { + int i; +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_fe_verify(a); +#endif + for (i=0; i<32; i++) { + int j; + int c = 0; + for (j=0; j<2; j++) { + int limb = (8*i+4*j)/52; + int shift = (8*i+4*j)%52; + c |= ((a->n[limb] >> shift) & 0xF) << (4 * j); + } + r[31-i] = c; + } +} + +SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { +#ifdef VERIFY + VERIFY_CHECK(a->magnitude <= m); + secp256k1_fe_verify(a); +#endif + r->n[0] = 0xFFFFEFFFFFC2FULL * 2 * (m + 1) - a->n[0]; + r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[1]; + r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[2]; + r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[3]; + r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4]; +#ifdef VERIFY + r->magnitude = m + 1; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { + r->n[0] *= a; + r->n[1] *= a; + r->n[2] *= a; + r->n[3] *= a; + r->n[4] *= a; +#ifdef VERIFY + r->magnitude *= a; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { +#ifdef VERIFY + secp256k1_fe_verify(a); +#endif + r->n[0] += a->n[0]; + r->n[1] += a->n[1]; + r->n[2] += a->n[2]; + r->n[3] += a->n[3]; + r->n[4] += a->n[4]; +#ifdef VERIFY + r->magnitude += a->magnitude; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { +#ifdef VERIFY + VERIFY_CHECK(a->magnitude <= 8); + VERIFY_CHECK(b->magnitude <= 8); + secp256k1_fe_verify(a); + secp256k1_fe_verify(b); + VERIFY_CHECK(r != b); +#endif + secp256k1_fe_mul_inner(r->n, a->n, b->n); +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { +#ifdef VERIFY + VERIFY_CHECK(a->magnitude <= 8); + secp256k1_fe_verify(a); +#endif + secp256k1_fe_sqr_inner(r->n, a->n); +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { + uint64_t mask0, mask1; + mask0 = flag + ~((uint64_t)0); + mask1 = ~mask0; + r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); + r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); + r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); + r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); + r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); +#ifdef VERIFY + if (a->magnitude > r->magnitude) { + r->magnitude = a->magnitude; + } + r->normalized &= a->normalized; +#endif +} + +static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { + uint64_t mask0, mask1; + mask0 = flag + ~((uint64_t)0); + mask1 = ~mask0; + r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); + r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); + r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); + r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); +} + +static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { +#ifdef VERIFY + VERIFY_CHECK(a->normalized); +#endif + r->n[0] = a->n[0] | a->n[1] << 52; + r->n[1] = a->n[1] >> 12 | a->n[2] << 40; + r->n[2] = a->n[2] >> 24 | a->n[3] << 28; + r->n[3] = a->n[3] >> 36 | a->n[4] << 16; +} + +static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { + r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL; + r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL); + r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL); + r->n[3] = a->n[2] >> 28 | ((a->n[3] << 36) & 0xFFFFFFFFFFFFFULL); + r->n[4] = a->n[3] >> 16; +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; +#endif +} + +#endif diff --git a/src/secp256k1/src/field_5x52_int128_impl.h b/src/secp256k1/src/field_5x52_int128_impl.h new file mode 100644 index 000000000..0bf22bdd3 --- /dev/null +++ b/src/secp256k1/src/field_5x52_int128_impl.h @@ -0,0 +1,277 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_ +#define _SECP256K1_FIELD_INNER5X52_IMPL_H_ + +#include + +#ifdef VERIFY +#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) +#else +#define VERIFY_BITS(x, n) do { } while(0) +#endif + +SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { + uint128_t c, d; + uint64_t t3, t4, tx, u0; + uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; + const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; + + VERIFY_BITS(a[0], 56); + VERIFY_BITS(a[1], 56); + VERIFY_BITS(a[2], 56); + VERIFY_BITS(a[3], 56); + VERIFY_BITS(a[4], 52); + VERIFY_BITS(b[0], 56); + VERIFY_BITS(b[1], 56); + VERIFY_BITS(b[2], 56); + VERIFY_BITS(b[3], 56); + VERIFY_BITS(b[4], 52); + VERIFY_CHECK(r != b); + + /* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. + * px is a shorthand for sum(a[i]*b[x-i], i=0..x). + * Note that [x 0 0 0 0 0] = [x*R]. + */ + + d = (uint128_t)a0 * b[3] + + (uint128_t)a1 * b[2] + + (uint128_t)a2 * b[1] + + (uint128_t)a3 * b[0]; + VERIFY_BITS(d, 114); + /* [d 0 0 0] = [p3 0 0 0] */ + c = (uint128_t)a4 * b[4]; + VERIFY_BITS(c, 112); + /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + d += (c & M) * R; c >>= 52; + VERIFY_BITS(d, 115); + VERIFY_BITS(c, 60); + /* [c 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + t3 = d & M; d >>= 52; + VERIFY_BITS(t3, 52); + VERIFY_BITS(d, 63); + /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + + d += (uint128_t)a0 * b[4] + + (uint128_t)a1 * b[3] + + (uint128_t)a2 * b[2] + + (uint128_t)a3 * b[1] + + (uint128_t)a4 * b[0]; + VERIFY_BITS(d, 115); + /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + d += c * R; + VERIFY_BITS(d, 116); + /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + t4 = d & M; d >>= 52; + VERIFY_BITS(t4, 52); + VERIFY_BITS(d, 64); + /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + tx = (t4 >> 48); t4 &= (M >> 4); + VERIFY_BITS(tx, 4); + VERIFY_BITS(t4, 48); + /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + + c = (uint128_t)a0 * b[0]; + VERIFY_BITS(c, 112); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ + d += (uint128_t)a1 * b[4] + + (uint128_t)a2 * b[3] + + (uint128_t)a3 * b[2] + + (uint128_t)a4 * b[1]; + VERIFY_BITS(d, 115); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = d & M; d >>= 52; + VERIFY_BITS(u0, 52); + VERIFY_BITS(d, 63); + /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = (u0 << 4) | tx; + VERIFY_BITS(u0, 56); + /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + c += (uint128_t)u0 * (R >> 4); + VERIFY_BITS(c, 115); + /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + r[0] = c & M; c >>= 52; + VERIFY_BITS(r[0], 52); + VERIFY_BITS(c, 61); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ + + c += (uint128_t)a0 * b[1] + + (uint128_t)a1 * b[0]; + VERIFY_BITS(c, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ + d += (uint128_t)a2 * b[4] + + (uint128_t)a3 * b[3] + + (uint128_t)a4 * b[2]; + VERIFY_BITS(d, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + c += (d & M) * R; d >>= 52; + VERIFY_BITS(c, 115); + VERIFY_BITS(d, 62); + /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + r[1] = c & M; c >>= 52; + VERIFY_BITS(r[1], 52); + VERIFY_BITS(c, 63); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + + c += (uint128_t)a0 * b[2] + + (uint128_t)a1 * b[1] + + (uint128_t)a2 * b[0]; + VERIFY_BITS(c, 114); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint128_t)a3 * b[4] + + (uint128_t)a4 * b[3]; + VERIFY_BITS(d, 114); + /* [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += (d & M) * R; d >>= 52; + VERIFY_BITS(c, 115); + VERIFY_BITS(d, 62); + /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[2] = c & M; c >>= 52; + VERIFY_BITS(r[2], 52); + VERIFY_BITS(c, 63); + /* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += d * R + t3; + VERIFY_BITS(c, 100); + /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[3] = c & M; c >>= 52; + VERIFY_BITS(r[3], 52); + VERIFY_BITS(c, 48); + /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += t4; + VERIFY_BITS(c, 49); + /* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[4] = c; + VERIFY_BITS(r[4], 49); + /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ +} + +SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) { + uint128_t c, d; + uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; + int64_t t3, t4, tx, u0; + const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; + + VERIFY_BITS(a[0], 56); + VERIFY_BITS(a[1], 56); + VERIFY_BITS(a[2], 56); + VERIFY_BITS(a[3], 56); + VERIFY_BITS(a[4], 52); + + /** [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. + * px is a shorthand for sum(a[i]*a[x-i], i=0..x). + * Note that [x 0 0 0 0 0] = [x*R]. + */ + + d = (uint128_t)(a0*2) * a3 + + (uint128_t)(a1*2) * a2; + VERIFY_BITS(d, 114); + /* [d 0 0 0] = [p3 0 0 0] */ + c = (uint128_t)a4 * a4; + VERIFY_BITS(c, 112); + /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + d += (c & M) * R; c >>= 52; + VERIFY_BITS(d, 115); + VERIFY_BITS(c, 60); + /* [c 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + t3 = d & M; d >>= 52; + VERIFY_BITS(t3, 52); + VERIFY_BITS(d, 63); + /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + + a4 *= 2; + d += (uint128_t)a0 * a4 + + (uint128_t)(a1*2) * a3 + + (uint128_t)a2 * a2; + VERIFY_BITS(d, 115); + /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + d += c * R; + VERIFY_BITS(d, 116); + /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + t4 = d & M; d >>= 52; + VERIFY_BITS(t4, 52); + VERIFY_BITS(d, 64); + /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + tx = (t4 >> 48); t4 &= (M >> 4); + VERIFY_BITS(tx, 4); + VERIFY_BITS(t4, 48); + /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + + c = (uint128_t)a0 * a0; + VERIFY_BITS(c, 112); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ + d += (uint128_t)a1 * a4 + + (uint128_t)(a2*2) * a3; + VERIFY_BITS(d, 114); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = d & M; d >>= 52; + VERIFY_BITS(u0, 52); + VERIFY_BITS(d, 62); + /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = (u0 << 4) | tx; + VERIFY_BITS(u0, 56); + /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + c += (uint128_t)u0 * (R >> 4); + VERIFY_BITS(c, 113); + /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + r[0] = c & M; c >>= 52; + VERIFY_BITS(r[0], 52); + VERIFY_BITS(c, 61); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ + + a0 *= 2; + c += (uint128_t)a0 * a1; + VERIFY_BITS(c, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ + d += (uint128_t)a2 * a4 + + (uint128_t)a3 * a3; + VERIFY_BITS(d, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + c += (d & M) * R; d >>= 52; + VERIFY_BITS(c, 115); + VERIFY_BITS(d, 62); + /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + r[1] = c & M; c >>= 52; + VERIFY_BITS(r[1], 52); + VERIFY_BITS(c, 63); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + + c += (uint128_t)a0 * a2 + + (uint128_t)a1 * a1; + VERIFY_BITS(c, 114); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint128_t)a3 * a4; + VERIFY_BITS(d, 114); + /* [d 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += (d & M) * R; d >>= 52; + VERIFY_BITS(c, 115); + VERIFY_BITS(d, 62); + /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[2] = c & M; c >>= 52; + VERIFY_BITS(r[2], 52); + VERIFY_BITS(c, 63); + /* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + c += d * R + t3; + VERIFY_BITS(c, 100); + /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[3] = c & M; c >>= 52; + VERIFY_BITS(r[3], 52); + VERIFY_BITS(c, 48); + /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += t4; + VERIFY_BITS(c, 49); + /* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[4] = c; + VERIFY_BITS(r[4], 49); + /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ +} + +#endif diff --git a/src/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h new file mode 100644 index 000000000..52cd902eb --- /dev/null +++ b/src/secp256k1/src/field_impl.h @@ -0,0 +1,315 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_FIELD_IMPL_H_ +#define _SECP256K1_FIELD_IMPL_H_ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include "util.h" + +#if defined(USE_FIELD_10X26) +#include "field_10x26_impl.h" +#elif defined(USE_FIELD_5X52) +#include "field_5x52_impl.h" +#else +#error "Please select field implementation" +#endif + +SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe na; + secp256k1_fe_negate(&na, a, 1); + secp256k1_fe_add(&na, b); + return secp256k1_fe_normalizes_to_zero(&na); +} + +SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe na; + secp256k1_fe_negate(&na, a, 1); + secp256k1_fe_add(&na, b); + return secp256k1_fe_normalizes_to_zero_var(&na); +} + +static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) { + /** Given that p is congruent to 3 mod 4, we can compute the square root of + * a mod p as the (p+1)/4'th power of a. + * + * As (p+1)/4 is an even number, it will have the same result for a and for + * (-a). Only one of these two numbers actually has a square root however, + * so we test at the end by squaring and comparing to the input. + * Also because (p+1)/4 is an even number, the computed square root is + * itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)). + */ + secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; + int j; + + /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in + * { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: + * 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] + */ + + secp256k1_fe_sqr(&x2, a); + secp256k1_fe_mul(&x2, &x2, a); + + secp256k1_fe_sqr(&x3, &x2); + secp256k1_fe_mul(&x3, &x3, a); + + x6 = x3; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x6, &x6); + } + secp256k1_fe_mul(&x6, &x6, &x3); + + x9 = x6; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x9, &x9); + } + secp256k1_fe_mul(&x9, &x9, &x3); + + x11 = x9; + for (j=0; j<2; j++) { + secp256k1_fe_sqr(&x11, &x11); + } + secp256k1_fe_mul(&x11, &x11, &x2); + + x22 = x11; + for (j=0; j<11; j++) { + secp256k1_fe_sqr(&x22, &x22); + } + secp256k1_fe_mul(&x22, &x22, &x11); + + x44 = x22; + for (j=0; j<22; j++) { + secp256k1_fe_sqr(&x44, &x44); + } + secp256k1_fe_mul(&x44, &x44, &x22); + + x88 = x44; + for (j=0; j<44; j++) { + secp256k1_fe_sqr(&x88, &x88); + } + secp256k1_fe_mul(&x88, &x88, &x44); + + x176 = x88; + for (j=0; j<88; j++) { + secp256k1_fe_sqr(&x176, &x176); + } + secp256k1_fe_mul(&x176, &x176, &x88); + + x220 = x176; + for (j=0; j<44; j++) { + secp256k1_fe_sqr(&x220, &x220); + } + secp256k1_fe_mul(&x220, &x220, &x44); + + x223 = x220; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x223, &x223); + } + secp256k1_fe_mul(&x223, &x223, &x3); + + /* The final result is then assembled using a sliding window over the blocks. */ + + t1 = x223; + for (j=0; j<23; j++) { + secp256k1_fe_sqr(&t1, &t1); + } + secp256k1_fe_mul(&t1, &t1, &x22); + for (j=0; j<6; j++) { + secp256k1_fe_sqr(&t1, &t1); + } + secp256k1_fe_mul(&t1, &t1, &x2); + secp256k1_fe_sqr(&t1, &t1); + secp256k1_fe_sqr(r, &t1); + + /* Check that a square root was actually calculated */ + + secp256k1_fe_sqr(&t1, r); + return secp256k1_fe_equal(&t1, a); +} + +static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a) { + secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; + int j; + + /** The binary representation of (p - 2) has 5 blocks of 1s, with lengths in + * { 1, 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: + * [1], [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] + */ + + secp256k1_fe_sqr(&x2, a); + secp256k1_fe_mul(&x2, &x2, a); + + secp256k1_fe_sqr(&x3, &x2); + secp256k1_fe_mul(&x3, &x3, a); + + x6 = x3; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x6, &x6); + } + secp256k1_fe_mul(&x6, &x6, &x3); + + x9 = x6; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x9, &x9); + } + secp256k1_fe_mul(&x9, &x9, &x3); + + x11 = x9; + for (j=0; j<2; j++) { + secp256k1_fe_sqr(&x11, &x11); + } + secp256k1_fe_mul(&x11, &x11, &x2); + + x22 = x11; + for (j=0; j<11; j++) { + secp256k1_fe_sqr(&x22, &x22); + } + secp256k1_fe_mul(&x22, &x22, &x11); + + x44 = x22; + for (j=0; j<22; j++) { + secp256k1_fe_sqr(&x44, &x44); + } + secp256k1_fe_mul(&x44, &x44, &x22); + + x88 = x44; + for (j=0; j<44; j++) { + secp256k1_fe_sqr(&x88, &x88); + } + secp256k1_fe_mul(&x88, &x88, &x44); + + x176 = x88; + for (j=0; j<88; j++) { + secp256k1_fe_sqr(&x176, &x176); + } + secp256k1_fe_mul(&x176, &x176, &x88); + + x220 = x176; + for (j=0; j<44; j++) { + secp256k1_fe_sqr(&x220, &x220); + } + secp256k1_fe_mul(&x220, &x220, &x44); + + x223 = x220; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x223, &x223); + } + secp256k1_fe_mul(&x223, &x223, &x3); + + /* The final result is then assembled using a sliding window over the blocks. */ + + t1 = x223; + for (j=0; j<23; j++) { + secp256k1_fe_sqr(&t1, &t1); + } + secp256k1_fe_mul(&t1, &t1, &x22); + for (j=0; j<5; j++) { + secp256k1_fe_sqr(&t1, &t1); + } + secp256k1_fe_mul(&t1, &t1, a); + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&t1, &t1); + } + secp256k1_fe_mul(&t1, &t1, &x2); + for (j=0; j<2; j++) { + secp256k1_fe_sqr(&t1, &t1); + } + secp256k1_fe_mul(r, a, &t1); +} + +static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a) { +#if defined(USE_FIELD_INV_BUILTIN) + secp256k1_fe_inv(r, a); +#elif defined(USE_FIELD_INV_NUM) + secp256k1_num n, m; + static const secp256k1_fe negone = SECP256K1_FE_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0xFFFFFC2EUL + ); + /* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ + static const unsigned char prime[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F + }; + unsigned char b[32]; + int res; + secp256k1_fe c = *a; + secp256k1_fe_normalize_var(&c); + secp256k1_fe_get_b32(b, &c); + secp256k1_num_set_bin(&n, b, 32); + secp256k1_num_set_bin(&m, prime, 32); + secp256k1_num_mod_inverse(&n, &n, &m); + secp256k1_num_get_bin(b, 32, &n); + res = secp256k1_fe_set_b32(r, b); + (void)res; + VERIFY_CHECK(res); + /* Verify the result is the (unique) valid inverse using non-GMP code. */ + secp256k1_fe_mul(&c, &c, r); + secp256k1_fe_add(&c, &negone); + CHECK(secp256k1_fe_normalizes_to_zero_var(&c)); +#else +#error "Please select field inverse implementation" +#endif +} + +static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe *r, const secp256k1_fe *a) { + secp256k1_fe u; + size_t i; + if (len < 1) { + return; + } + + VERIFY_CHECK((r + len <= a) || (a + len <= r)); + + r[0] = a[0]; + + i = 0; + while (++i < len) { + secp256k1_fe_mul(&r[i], &r[i - 1], &a[i]); + } + + secp256k1_fe_inv_var(&u, &r[--i]); + + while (i > 0) { + size_t j = i--; + secp256k1_fe_mul(&r[j], &r[i], &u); + secp256k1_fe_mul(&u, &u, &a[j]); + } + + r[0] = u; +} + +static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) { +#ifndef USE_NUM_NONE + unsigned char b[32]; + secp256k1_num n; + secp256k1_num m; + /* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ + static const unsigned char prime[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F + }; + + secp256k1_fe c = *a; + secp256k1_fe_normalize_var(&c); + secp256k1_fe_get_b32(b, &c); + secp256k1_num_set_bin(&n, b, 32); + secp256k1_num_set_bin(&m, prime, 32); + return secp256k1_num_jacobi(&n, &m) >= 0; +#else + secp256k1_fe r; + return secp256k1_fe_sqrt(&r, a); +#endif +} + +#endif diff --git a/src/secp256k1/src/gen_context.c b/src/secp256k1/src/gen_context.c new file mode 100644 index 000000000..1835fd491 --- /dev/null +++ b/src/secp256k1/src/gen_context.c @@ -0,0 +1,74 @@ +/********************************************************************** + * Copyright (c) 2013, 2014, 2015 Thomas Daede, Cory Fields * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#define USE_BASIC_CONFIG 1 + +#include "basic-config.h" +#include "include/secp256k1.h" +#include "field_impl.h" +#include "scalar_impl.h" +#include "group_impl.h" +#include "ecmult_gen_impl.h" + +static void default_error_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); + abort(); +} + +static const secp256k1_callback default_error_callback = { + default_error_callback_fn, + NULL +}; + +int main(int argc, char **argv) { + secp256k1_ecmult_gen_context ctx; + int inner; + int outer; + FILE* fp; + + (void)argc; + (void)argv; + + fp = fopen("src/ecmult_static_context.h","w"); + if (fp == NULL) { + fprintf(stderr, "Could not open src/ecmult_static_context.h for writing!\n"); + return -1; + } + + fprintf(fp, "#ifndef _SECP256K1_ECMULT_STATIC_CONTEXT_\n"); + fprintf(fp, "#define _SECP256K1_ECMULT_STATIC_CONTEXT_\n"); + fprintf(fp, "#include \"group.h\"\n"); + fprintf(fp, "#define SC SECP256K1_GE_STORAGE_CONST\n"); + fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_static_context[64][16] = {\n"); + + secp256k1_ecmult_gen_context_init(&ctx); + secp256k1_ecmult_gen_context_build(&ctx, &default_error_callback); + for(outer = 0; outer != 64; outer++) { + fprintf(fp,"{\n"); + for(inner = 0; inner != 16; inner++) { + fprintf(fp," SC(%uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu)", SECP256K1_GE_STORAGE_CONST_GET((*ctx.prec)[outer][inner])); + if (inner != 15) { + fprintf(fp,",\n"); + } else { + fprintf(fp,"\n"); + } + } + if (outer != 63) { + fprintf(fp,"},\n"); + } else { + fprintf(fp,"}\n"); + } + } + fprintf(fp,"};\n"); + secp256k1_ecmult_gen_context_clear(&ctx); + + fprintf(fp, "#undef SC\n"); + fprintf(fp, "#endif\n"); + fclose(fp); + + return 0; +} diff --git a/src/secp256k1/src/group.h b/src/secp256k1/src/group.h new file mode 100644 index 000000000..d51571674 --- /dev/null +++ b/src/secp256k1/src/group.h @@ -0,0 +1,144 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_GROUP_ +#define _SECP256K1_GROUP_ + +#include "num.h" +#include "field.h" + +/** A group element of the secp256k1 curve, in affine coordinates. */ +typedef struct { + secp256k1_fe x; + secp256k1_fe y; + int infinity; /* whether this represents the point at infinity */ +} secp256k1_ge; + +#define SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), 0} +#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} + +/** A group element of the secp256k1 curve, in jacobian coordinates. */ +typedef struct { + secp256k1_fe x; /* actual X: x/z^2 */ + secp256k1_fe y; /* actual Y: y/z^3 */ + secp256k1_fe z; + int infinity; /* whether this represents the point at infinity */ +} secp256k1_gej; + +#define SECP256K1_GEJ_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), 0} +#define SECP256K1_GEJ_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} + +typedef struct { + secp256k1_fe_storage x; + secp256k1_fe_storage y; +} secp256k1_ge_storage; + +#define SECP256K1_GE_STORAGE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_STORAGE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_STORAGE_CONST((i),(j),(k),(l),(m),(n),(o),(p))} + +#define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y) + +/** Set a group element equal to the point with given X and Y coordinates */ +static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y); + +/** Set a group element (affine) equal to the point with the given X coordinate + * and a Y coordinate that is a quadratic residue modulo p. The return value + * is true iff a coordinate with the given X coordinate exists. + */ +static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x); + +/** Set a group element (affine) equal to the point with the given X coordinate, and given oddness + * for Y. Return value indicates whether the result is valid. */ +static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd); + +/** Check whether a group element is the point at infinity. */ +static int secp256k1_ge_is_infinity(const secp256k1_ge *a); + +/** Check whether a group element is valid (i.e., on the curve). */ +static int secp256k1_ge_is_valid_var(const secp256k1_ge *a); + +static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a); + +/** Set a group element equal to another which is given in jacobian coordinates */ +static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a); + +/** Set a batch of group elements equal to the inputs given in jacobian coordinates */ +static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_callback *cb); + +/** Set a batch of group elements equal to the inputs given in jacobian + * coordinates (with known z-ratios). zr must contain the known z-ratios such + * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. */ +static void secp256k1_ge_set_table_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr); + +/** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to + * the same global z "denominator". zr must contain the known z-ratios such + * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. The x and y + * coordinates of the result are stored in r, the common z coordinate is + * stored in globalz. */ +static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr); + +/** Set a group element (jacobian) equal to the point at infinity. */ +static void secp256k1_gej_set_infinity(secp256k1_gej *r); + +/** Set a group element (jacobian) equal to another which is given in affine coordinates. */ +static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a); + +/** Compare the X coordinate of a group element (jacobian). */ +static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a); + +/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */ +static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a); + +/** Check whether a group element is the point at infinity. */ +static int secp256k1_gej_is_infinity(const secp256k1_gej *a); + +/** Check whether a group element's y coordinate is a quadratic residue. */ +static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a); + +/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). + * a may not be zero. Constant time. */ +static void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr); + +/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). */ +static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr); + +/** Set r equal to the sum of a and b. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */ +static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr); + +/** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */ +static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b); + +/** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient + than secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge but without constant-time + guarantee, and b is allowed to be infinity. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */ +static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr); + +/** Set r equal to the sum of a and b (with the inverse of b's Z coordinate passed as bzinv). */ +static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv); + +#ifdef USE_ENDOMORPHISM +/** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */ +static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a); +#endif + +/** Clear a secp256k1_gej to prevent leaking sensitive information. */ +static void secp256k1_gej_clear(secp256k1_gej *r); + +/** Clear a secp256k1_ge to prevent leaking sensitive information. */ +static void secp256k1_ge_clear(secp256k1_ge *r); + +/** Convert a group element to the storage type. */ +static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a); + +/** Convert a group element back from the storage type. */ +static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a); + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ +static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag); + +/** Rescale a jacobian point by b which must be non-zero. Constant-time. */ +static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b); + +#endif diff --git a/src/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h new file mode 100644 index 000000000..3e9c4c410 --- /dev/null +++ b/src/secp256k1/src/group_impl.h @@ -0,0 +1,650 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_GROUP_IMPL_H_ +#define _SECP256K1_GROUP_IMPL_H_ + +#include "num.h" +#include "field.h" +#include "group.h" + +/** Generator for secp256k1, value 'g' defined in + * "Standards for Efficient Cryptography" (SEC2) 2.7.1. + */ +static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( + 0x79BE667EUL, 0xF9DCBBACUL, 0x55A06295UL, 0xCE870B07UL, + 0x029BFCDBUL, 0x2DCE28D9UL, 0x59F2815BUL, 0x16F81798UL, + 0x483ADA77UL, 0x26A3C465UL, 0x5DA4FBFCUL, 0x0E1108A8UL, + 0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL +); + +static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) { + secp256k1_fe zi2; + secp256k1_fe zi3; + secp256k1_fe_sqr(&zi2, zi); + secp256k1_fe_mul(&zi3, &zi2, zi); + secp256k1_fe_mul(&r->x, &a->x, &zi2); + secp256k1_fe_mul(&r->y, &a->y, &zi3); + r->infinity = a->infinity; +} + +static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) { + r->infinity = 0; + r->x = *x; + r->y = *y; +} + +static int secp256k1_ge_is_infinity(const secp256k1_ge *a) { + return a->infinity; +} + +static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) { + *r = *a; + secp256k1_fe_normalize_weak(&r->y); + secp256k1_fe_negate(&r->y, &r->y, 1); +} + +static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) { + secp256k1_fe z2, z3; + r->infinity = a->infinity; + secp256k1_fe_inv(&a->z, &a->z); + secp256k1_fe_sqr(&z2, &a->z); + secp256k1_fe_mul(&z3, &a->z, &z2); + secp256k1_fe_mul(&a->x, &a->x, &z2); + secp256k1_fe_mul(&a->y, &a->y, &z3); + secp256k1_fe_set_int(&a->z, 1); + r->x = a->x; + r->y = a->y; +} + +static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { + secp256k1_fe z2, z3; + r->infinity = a->infinity; + if (a->infinity) { + return; + } + secp256k1_fe_inv_var(&a->z, &a->z); + secp256k1_fe_sqr(&z2, &a->z); + secp256k1_fe_mul(&z3, &a->z, &z2); + secp256k1_fe_mul(&a->x, &a->x, &z2); + secp256k1_fe_mul(&a->y, &a->y, &z3); + secp256k1_fe_set_int(&a->z, 1); + r->x = a->x; + r->y = a->y; +} + +static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_callback *cb) { + secp256k1_fe *az; + secp256k1_fe *azi; + size_t i; + size_t count = 0; + az = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * len); + for (i = 0; i < len; i++) { + if (!a[i].infinity) { + az[count++] = a[i].z; + } + } + + azi = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * count); + secp256k1_fe_inv_all_var(count, azi, az); + free(az); + + count = 0; + for (i = 0; i < len; i++) { + r[i].infinity = a[i].infinity; + if (!a[i].infinity) { + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &azi[count++]); + } + } + free(azi); +} + +static void secp256k1_ge_set_table_gej_var(size_t len, secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr) { + size_t i = len - 1; + secp256k1_fe zi; + + if (len > 0) { + /* Compute the inverse of the last z coordinate, and use it to compute the last affine output. */ + secp256k1_fe_inv(&zi, &a[i].z); + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi); + + /* Work out way backwards, using the z-ratios to scale the x/y values. */ + while (i > 0) { + secp256k1_fe_mul(&zi, &zi, &zr[i]); + i--; + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi); + } + } +} + +static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr) { + size_t i = len - 1; + secp256k1_fe zs; + + if (len > 0) { + /* The z of the final point gives us the "global Z" for the table. */ + r[i].x = a[i].x; + r[i].y = a[i].y; + *globalz = a[i].z; + r[i].infinity = 0; + zs = zr[i]; + + /* Work our way backwards, using the z-ratios to scale the x/y values. */ + while (i > 0) { + if (i != len - 1) { + secp256k1_fe_mul(&zs, &zs, &zr[i]); + } + i--; + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zs); + } + } +} + +static void secp256k1_gej_set_infinity(secp256k1_gej *r) { + r->infinity = 1; + secp256k1_fe_set_int(&r->x, 0); + secp256k1_fe_set_int(&r->y, 0); + secp256k1_fe_set_int(&r->z, 0); +} + +static void secp256k1_gej_clear(secp256k1_gej *r) { + r->infinity = 0; + secp256k1_fe_clear(&r->x); + secp256k1_fe_clear(&r->y); + secp256k1_fe_clear(&r->z); +} + +static void secp256k1_ge_clear(secp256k1_ge *r) { + r->infinity = 0; + secp256k1_fe_clear(&r->x); + secp256k1_fe_clear(&r->y); +} + +static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) { + secp256k1_fe x2, x3, c; + r->x = *x; + secp256k1_fe_sqr(&x2, x); + secp256k1_fe_mul(&x3, x, &x2); + r->infinity = 0; + secp256k1_fe_set_int(&c, 7); + secp256k1_fe_add(&c, &x3); + return secp256k1_fe_sqrt(&r->y, &c); +} + +static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) { + if (!secp256k1_ge_set_xquad(r, x)) { + return 0; + } + secp256k1_fe_normalize_var(&r->y); + if (secp256k1_fe_is_odd(&r->y) != odd) { + secp256k1_fe_negate(&r->y, &r->y, 1); + } + return 1; + +} + +static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) { + r->infinity = a->infinity; + r->x = a->x; + r->y = a->y; + secp256k1_fe_set_int(&r->z, 1); +} + +static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) { + secp256k1_fe r, r2; + VERIFY_CHECK(!a->infinity); + secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x); + r2 = a->x; secp256k1_fe_normalize_weak(&r2); + return secp256k1_fe_equal_var(&r, &r2); +} + +static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) { + r->infinity = a->infinity; + r->x = a->x; + r->y = a->y; + r->z = a->z; + secp256k1_fe_normalize_weak(&r->y); + secp256k1_fe_negate(&r->y, &r->y, 1); +} + +static int secp256k1_gej_is_infinity(const secp256k1_gej *a) { + return a->infinity; +} + +static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) { + secp256k1_fe y2, x3, z2, z6; + if (a->infinity) { + return 0; + } + /** y^2 = x^3 + 7 + * (Y/Z^3)^2 = (X/Z^2)^3 + 7 + * Y^2 / Z^6 = X^3 / Z^6 + 7 + * Y^2 = X^3 + 7*Z^6 + */ + secp256k1_fe_sqr(&y2, &a->y); + secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); + secp256k1_fe_sqr(&z2, &a->z); + secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2); + secp256k1_fe_mul_int(&z6, 7); + secp256k1_fe_add(&x3, &z6); + secp256k1_fe_normalize_weak(&x3); + return secp256k1_fe_equal_var(&y2, &x3); +} + +static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) { + secp256k1_fe y2, x3, c; + if (a->infinity) { + return 0; + } + /* y^2 = x^3 + 7 */ + secp256k1_fe_sqr(&y2, &a->y); + secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); + secp256k1_fe_set_int(&c, 7); + secp256k1_fe_add(&x3, &c); + secp256k1_fe_normalize_weak(&x3); + return secp256k1_fe_equal_var(&y2, &x3); +} + +static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { + /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate. + * + * Note that there is an implementation described at + * https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l + * which trades a multiply for a square, but in practice this is actually slower, + * mainly because it requires more normalizations. + */ + secp256k1_fe t1,t2,t3,t4; + /** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity, + * Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have + * y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p. + * + * Having said this, if this function receives a point on a sextic twist, e.g. by + * a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6, + * since -6 does have a cube root mod p. For this point, this function will not set + * the infinity flag even though the point doubles to infinity, and the result + * point will be gibberish (z = 0 but infinity = 0). + */ + r->infinity = a->infinity; + if (r->infinity) { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 1); + } + return; + } + + if (rzr != NULL) { + *rzr = a->y; + secp256k1_fe_normalize_weak(rzr); + secp256k1_fe_mul_int(rzr, 2); + } + + secp256k1_fe_mul(&r->z, &a->z, &a->y); + secp256k1_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */ + secp256k1_fe_sqr(&t1, &a->x); + secp256k1_fe_mul_int(&t1, 3); /* T1 = 3*X^2 (3) */ + secp256k1_fe_sqr(&t2, &t1); /* T2 = 9*X^4 (1) */ + secp256k1_fe_sqr(&t3, &a->y); + secp256k1_fe_mul_int(&t3, 2); /* T3 = 2*Y^2 (2) */ + secp256k1_fe_sqr(&t4, &t3); + secp256k1_fe_mul_int(&t4, 2); /* T4 = 8*Y^4 (2) */ + secp256k1_fe_mul(&t3, &t3, &a->x); /* T3 = 2*X*Y^2 (1) */ + r->x = t3; + secp256k1_fe_mul_int(&r->x, 4); /* X' = 8*X*Y^2 (4) */ + secp256k1_fe_negate(&r->x, &r->x, 4); /* X' = -8*X*Y^2 (5) */ + secp256k1_fe_add(&r->x, &t2); /* X' = 9*X^4 - 8*X*Y^2 (6) */ + secp256k1_fe_negate(&t2, &t2, 1); /* T2 = -9*X^4 (2) */ + secp256k1_fe_mul_int(&t3, 6); /* T3 = 12*X*Y^2 (6) */ + secp256k1_fe_add(&t3, &t2); /* T3 = 12*X*Y^2 - 9*X^4 (8) */ + secp256k1_fe_mul(&r->y, &t1, &t3); /* Y' = 36*X^3*Y^2 - 27*X^6 (1) */ + secp256k1_fe_negate(&t2, &t4, 2); /* T2 = -8*Y^4 (3) */ + secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */ +} + +static SECP256K1_INLINE void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { + VERIFY_CHECK(!secp256k1_gej_is_infinity(a)); + secp256k1_gej_double_var(r, a, rzr); +} + +static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) { + /* Operations: 12 mul, 4 sqr, 2 normalize, 12 mul_int/add/negate */ + secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + + if (a->infinity) { + VERIFY_CHECK(rzr == NULL); + *r = *b; + return; + } + + if (b->infinity) { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 1); + } + *r = *a; + return; + } + + r->infinity = 0; + secp256k1_fe_sqr(&z22, &b->z); + secp256k1_fe_sqr(&z12, &a->z); + secp256k1_fe_mul(&u1, &a->x, &z22); + secp256k1_fe_mul(&u2, &b->x, &z12); + secp256k1_fe_mul(&s1, &a->y, &z22); secp256k1_fe_mul(&s1, &s1, &b->z); + secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); + secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); + secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); + if (secp256k1_fe_normalizes_to_zero_var(&h)) { + if (secp256k1_fe_normalizes_to_zero_var(&i)) { + secp256k1_gej_double_var(r, a, rzr); + } else { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 0); + } + r->infinity = 1; + } + return; + } + secp256k1_fe_sqr(&i2, &i); + secp256k1_fe_sqr(&h2, &h); + secp256k1_fe_mul(&h3, &h, &h2); + secp256k1_fe_mul(&h, &h, &b->z); + if (rzr != NULL) { + *rzr = h; + } + secp256k1_fe_mul(&r->z, &a->z, &h); + secp256k1_fe_mul(&t, &u1, &h2); + r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2); + secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i); + secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1); + secp256k1_fe_add(&r->y, &h3); +} + +static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) { + /* 8 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */ + secp256k1_fe z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + if (a->infinity) { + VERIFY_CHECK(rzr == NULL); + secp256k1_gej_set_ge(r, b); + return; + } + if (b->infinity) { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 1); + } + *r = *a; + return; + } + r->infinity = 0; + + secp256k1_fe_sqr(&z12, &a->z); + u1 = a->x; secp256k1_fe_normalize_weak(&u1); + secp256k1_fe_mul(&u2, &b->x, &z12); + s1 = a->y; secp256k1_fe_normalize_weak(&s1); + secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); + secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); + secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); + if (secp256k1_fe_normalizes_to_zero_var(&h)) { + if (secp256k1_fe_normalizes_to_zero_var(&i)) { + secp256k1_gej_double_var(r, a, rzr); + } else { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 0); + } + r->infinity = 1; + } + return; + } + secp256k1_fe_sqr(&i2, &i); + secp256k1_fe_sqr(&h2, &h); + secp256k1_fe_mul(&h3, &h, &h2); + if (rzr != NULL) { + *rzr = h; + } + secp256k1_fe_mul(&r->z, &a->z, &h); + secp256k1_fe_mul(&t, &u1, &h2); + r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2); + secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i); + secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1); + secp256k1_fe_add(&r->y, &h3); +} + +static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) { + /* 9 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */ + secp256k1_fe az, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + + if (b->infinity) { + *r = *a; + return; + } + if (a->infinity) { + secp256k1_fe bzinv2, bzinv3; + r->infinity = b->infinity; + secp256k1_fe_sqr(&bzinv2, bzinv); + secp256k1_fe_mul(&bzinv3, &bzinv2, bzinv); + secp256k1_fe_mul(&r->x, &b->x, &bzinv2); + secp256k1_fe_mul(&r->y, &b->y, &bzinv3); + secp256k1_fe_set_int(&r->z, 1); + return; + } + r->infinity = 0; + + /** We need to calculate (rx,ry,rz) = (ax,ay,az) + (bx,by,1/bzinv). Due to + * secp256k1's isomorphism we can multiply the Z coordinates on both sides + * by bzinv, and get: (rx,ry,rz*bzinv) = (ax,ay,az*bzinv) + (bx,by,1). + * This means that (rx,ry,rz) can be calculated as + * (ax,ay,az*bzinv) + (bx,by,1), when not applying the bzinv factor to rz. + * The variable az below holds the modified Z coordinate for a, which is used + * for the computation of rx and ry, but not for rz. + */ + secp256k1_fe_mul(&az, &a->z, bzinv); + + secp256k1_fe_sqr(&z12, &az); + u1 = a->x; secp256k1_fe_normalize_weak(&u1); + secp256k1_fe_mul(&u2, &b->x, &z12); + s1 = a->y; secp256k1_fe_normalize_weak(&s1); + secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &az); + secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); + secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); + if (secp256k1_fe_normalizes_to_zero_var(&h)) { + if (secp256k1_fe_normalizes_to_zero_var(&i)) { + secp256k1_gej_double_var(r, a, NULL); + } else { + r->infinity = 1; + } + return; + } + secp256k1_fe_sqr(&i2, &i); + secp256k1_fe_sqr(&h2, &h); + secp256k1_fe_mul(&h3, &h, &h2); + r->z = a->z; secp256k1_fe_mul(&r->z, &r->z, &h); + secp256k1_fe_mul(&t, &u1, &h2); + r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2); + secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i); + secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1); + secp256k1_fe_add(&r->y, &h3); +} + + +static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b) { + /* Operations: 7 mul, 5 sqr, 4 normalize, 21 mul_int/add/negate/cmov */ + static const secp256k1_fe fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr; + secp256k1_fe m_alt, rr_alt; + int infinity, degenerate; + VERIFY_CHECK(!b->infinity); + VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); + + /** In: + * Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks. + * In D. Naccache and P. Paillier, Eds., Public Key Cryptography, vol. 2274 of Lecture Notes in Computer Science, pages 335-345. Springer-Verlag, 2002. + * we find as solution for a unified addition/doubling formula: + * lambda = ((x1 + x2)^2 - x1 * x2 + a) / (y1 + y2), with a = 0 for secp256k1's curve equation. + * x3 = lambda^2 - (x1 + x2) + * 2*y3 = lambda * (x1 + x2 - 2 * x3) - (y1 + y2). + * + * Substituting x_i = Xi / Zi^2 and yi = Yi / Zi^3, for i=1,2,3, gives: + * U1 = X1*Z2^2, U2 = X2*Z1^2 + * S1 = Y1*Z2^3, S2 = Y2*Z1^3 + * Z = Z1*Z2 + * T = U1+U2 + * M = S1+S2 + * Q = T*M^2 + * R = T^2-U1*U2 + * X3 = 4*(R^2-Q) + * Y3 = 4*(R*(3*Q-2*R^2)-M^4) + * Z3 = 2*M*Z + * (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.) + * + * This formula has the benefit of being the same for both addition + * of distinct points and doubling. However, it breaks down in the + * case that either point is infinity, or that y1 = -y2. We handle + * these cases in the following ways: + * + * - If b is infinity we simply bail by means of a VERIFY_CHECK. + * + * - If a is infinity, we detect this, and at the end of the + * computation replace the result (which will be meaningless, + * but we compute to be constant-time) with b.x : b.y : 1. + * + * - If a = -b, we have y1 = -y2, which is a degenerate case. + * But here the answer is infinity, so we simply set the + * infinity flag of the result, overriding the computed values + * without even needing to cmov. + * + * - If y1 = -y2 but x1 != x2, which does occur thanks to certain + * properties of our curve (specifically, 1 has nontrivial cube + * roots in our field, and the curve equation has no x coefficient) + * then the answer is not infinity but also not given by the above + * equation. In this case, we cmov in place an alternate expression + * for lambda. Specifically (y1 - y2)/(x1 - x2). Where both these + * expressions for lambda are defined, they are equal, and can be + * obtained from each other by multiplication by (y1 + y2)/(y1 + y2) + * then substitution of x^3 + 7 for y^2 (using the curve equation). + * For all pairs of nonzero points (a, b) at least one is defined, + * so this covers everything. + */ + + secp256k1_fe_sqr(&zz, &a->z); /* z = Z1^2 */ + u1 = a->x; secp256k1_fe_normalize_weak(&u1); /* u1 = U1 = X1*Z2^2 (1) */ + secp256k1_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */ + s1 = a->y; secp256k1_fe_normalize_weak(&s1); /* s1 = S1 = Y1*Z2^3 (1) */ + secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z1^2 (1) */ + secp256k1_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */ + t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (2) */ + m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (2) */ + secp256k1_fe_sqr(&rr, &t); /* rr = T^2 (1) */ + secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */ + secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */ + secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (3) */ + /** If lambda = R/M = 0/0 we have a problem (except in the "trivial" + * case that Z = z1z2 = 0, and this is special-cased later on). */ + degenerate = secp256k1_fe_normalizes_to_zero(&m) & + secp256k1_fe_normalizes_to_zero(&rr); + /* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2. + * This means either x1 == beta*x2 or beta*x1 == x2, where beta is + * a nontrivial cube root of one. In either case, an alternate + * non-indeterminate expression for lambda is (y1 - y2)/(x1 - x2), + * so we set R/M equal to this. */ + rr_alt = s1; + secp256k1_fe_mul_int(&rr_alt, 2); /* rr = Y1*Z2^3 - Y2*Z1^3 (2) */ + secp256k1_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 */ + + secp256k1_fe_cmov(&rr_alt, &rr, !degenerate); + secp256k1_fe_cmov(&m_alt, &m, !degenerate); + /* Now Ralt / Malt = lambda and is guaranteed not to be 0/0. + * From here on out Ralt and Malt represent the numerator + * and denominator of lambda; R and M represent the explicit + * expressions x1^2 + x2^2 + x1x2 and y1 + y2. */ + secp256k1_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */ + secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*Malt^2 (1) */ + /* These two lines use the observation that either M == Malt or M == 0, + * so M^3 * Malt is either Malt^4 (which is computed by squaring), or + * zero (which is "computed" by cmov). So the cost is one squaring + * versus two multiplications. */ + secp256k1_fe_sqr(&n, &n); + secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */ + secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */ + secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Malt*Z (1) */ + infinity = secp256k1_fe_normalizes_to_zero(&r->z) * (1 - a->infinity); + secp256k1_fe_mul_int(&r->z, 2); /* r->z = Z3 = 2*Malt*Z (2) */ + secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */ + secp256k1_fe_add(&t, &q); /* t = Ralt^2-Q (3) */ + secp256k1_fe_normalize_weak(&t); + r->x = t; /* r->x = Ralt^2-Q (1) */ + secp256k1_fe_mul_int(&t, 2); /* t = 2*x3 (2) */ + secp256k1_fe_add(&t, &q); /* t = 2*x3 - Q: (4) */ + secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*x3 - Q) (1) */ + secp256k1_fe_add(&t, &n); /* t = Ralt*(2*x3 - Q) + M^3*Malt (3) */ + secp256k1_fe_negate(&r->y, &t, 3); /* r->y = Ralt*(Q - 2x3) - M^3*Malt (4) */ + secp256k1_fe_normalize_weak(&r->y); + secp256k1_fe_mul_int(&r->x, 4); /* r->x = X3 = 4*(Ralt^2-Q) */ + secp256k1_fe_mul_int(&r->y, 4); /* r->y = Y3 = 4*Ralt*(Q - 2x3) - 4*M^3*Malt (4) */ + + /** In case a->infinity == 1, replace r with (b->x, b->y, 1). */ + secp256k1_fe_cmov(&r->x, &b->x, a->infinity); + secp256k1_fe_cmov(&r->y, &b->y, a->infinity); + secp256k1_fe_cmov(&r->z, &fe_1, a->infinity); + r->infinity = infinity; +} + +static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) { + /* Operations: 4 mul, 1 sqr */ + secp256k1_fe zz; + VERIFY_CHECK(!secp256k1_fe_is_zero(s)); + secp256k1_fe_sqr(&zz, s); + secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */ + secp256k1_fe_mul(&r->y, &r->y, &zz); + secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */ + secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */ +} + +static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) { + secp256k1_fe x, y; + VERIFY_CHECK(!a->infinity); + x = a->x; + secp256k1_fe_normalize(&x); + y = a->y; + secp256k1_fe_normalize(&y); + secp256k1_fe_to_storage(&r->x, &x); + secp256k1_fe_to_storage(&r->y, &y); +} + +static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a) { + secp256k1_fe_from_storage(&r->x, &a->x); + secp256k1_fe_from_storage(&r->y, &a->y); + r->infinity = 0; +} + +static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) { + secp256k1_fe_storage_cmov(&r->x, &a->x, flag); + secp256k1_fe_storage_cmov(&r->y, &a->y, flag); +} + +#ifdef USE_ENDOMORPHISM +static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) { + static const secp256k1_fe beta = SECP256K1_FE_CONST( + 0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul, + 0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul + ); + *r = *a; + secp256k1_fe_mul(&r->x, &r->x, &beta); +} +#endif + +static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) { + secp256k1_fe yz; + + if (a->infinity) { + return 0; + } + + /* We rely on the fact that the Jacobi symbol of 1 / a->z^3 is the same as + * that of a->z. Thus a->y / a->z^3 is a quadratic residue iff a->y * a->z + is */ + secp256k1_fe_mul(&yz, &a->y, &a->z); + return secp256k1_fe_is_quad_var(&yz); +} + +#endif diff --git a/src/secp256k1/src/hash.h b/src/secp256k1/src/hash.h new file mode 100644 index 000000000..fca98cab9 --- /dev/null +++ b/src/secp256k1/src/hash.h @@ -0,0 +1,41 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_HASH_ +#define _SECP256K1_HASH_ + +#include +#include + +typedef struct { + uint32_t s[8]; + uint32_t buf[16]; /* In big endian */ + size_t bytes; +} secp256k1_sha256_t; + +static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash); +static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t size); +static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32); + +typedef struct { + secp256k1_sha256_t inner, outer; +} secp256k1_hmac_sha256_t; + +static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t size); +static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size); +static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32); + +typedef struct { + unsigned char v[32]; + unsigned char k[32]; + int retry; +} secp256k1_rfc6979_hmac_sha256_t; + +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen); +static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen); +static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng); + +#endif diff --git a/src/secp256k1/src/hash_impl.h b/src/secp256k1/src/hash_impl.h new file mode 100644 index 000000000..b47e65f83 --- /dev/null +++ b/src/secp256k1/src/hash_impl.h @@ -0,0 +1,281 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_HASH_IMPL_H_ +#define _SECP256K1_HASH_IMPL_H_ + +#include "hash.h" + +#include +#include +#include + +#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) +#define Maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) +#define Sigma0(x) (((x) >> 2 | (x) << 30) ^ ((x) >> 13 | (x) << 19) ^ ((x) >> 22 | (x) << 10)) +#define Sigma1(x) (((x) >> 6 | (x) << 26) ^ ((x) >> 11 | (x) << 21) ^ ((x) >> 25 | (x) << 7)) +#define sigma0(x) (((x) >> 7 | (x) << 25) ^ ((x) >> 18 | (x) << 14) ^ ((x) >> 3)) +#define sigma1(x) (((x) >> 17 | (x) << 15) ^ ((x) >> 19 | (x) << 13) ^ ((x) >> 10)) + +#define Round(a,b,c,d,e,f,g,h,k,w) do { \ + uint32_t t1 = (h) + Sigma1(e) + Ch((e), (f), (g)) + (k) + (w); \ + uint32_t t2 = Sigma0(a) + Maj((a), (b), (c)); \ + (d) += t1; \ + (h) = t1 + t2; \ +} while(0) + +#ifdef WORDS_BIGENDIAN +#define BE32(x) (x) +#else +#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) +#endif + +static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash) { + hash->s[0] = 0x6a09e667ul; + hash->s[1] = 0xbb67ae85ul; + hash->s[2] = 0x3c6ef372ul; + hash->s[3] = 0xa54ff53aul; + hash->s[4] = 0x510e527ful; + hash->s[5] = 0x9b05688cul; + hash->s[6] = 0x1f83d9abul; + hash->s[7] = 0x5be0cd19ul; + hash->bytes = 0; +} + +/** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */ +static void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) { + uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7]; + uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15; + + Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = BE32(chunk[0])); + Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = BE32(chunk[1])); + Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = BE32(chunk[2])); + Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = BE32(chunk[3])); + Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = BE32(chunk[4])); + Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = BE32(chunk[5])); + Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = BE32(chunk[6])); + Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = BE32(chunk[7])); + Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = BE32(chunk[8])); + Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = BE32(chunk[9])); + Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = BE32(chunk[10])); + Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = BE32(chunk[11])); + Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = BE32(chunk[12])); + Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = BE32(chunk[13])); + Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = BE32(chunk[14])); + Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = BE32(chunk[15])); + + Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0)); + + s[0] += a; + s[1] += b; + s[2] += c; + s[3] += d; + s[4] += e; + s[5] += f; + s[6] += g; + s[7] += h; +} + +static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t len) { + size_t bufsize = hash->bytes & 0x3F; + hash->bytes += len; + while (bufsize + len >= 64) { + /* Fill the buffer, and process it. */ + memcpy(((unsigned char*)hash->buf) + bufsize, data, 64 - bufsize); + data += 64 - bufsize; + len -= 64 - bufsize; + secp256k1_sha256_transform(hash->s, hash->buf); + bufsize = 0; + } + if (len) { + /* Fill the buffer with what remains. */ + memcpy(((unsigned char*)hash->buf) + bufsize, data, len); + } +} + +static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32) { + static const unsigned char pad[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}; + uint32_t sizedesc[2]; + uint32_t out[8]; + int i = 0; + sizedesc[0] = BE32(hash->bytes >> 29); + sizedesc[1] = BE32(hash->bytes << 3); + secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64)); + secp256k1_sha256_write(hash, (const unsigned char*)sizedesc, 8); + for (i = 0; i < 8; i++) { + out[i] = BE32(hash->s[i]); + hash->s[i] = 0; + } + memcpy(out32, (const unsigned char*)out, 32); +} + +static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t keylen) { + int n; + unsigned char rkey[64]; + if (keylen <= 64) { + memcpy(rkey, key, keylen); + memset(rkey + keylen, 0, 64 - keylen); + } else { + secp256k1_sha256_t sha256; + secp256k1_sha256_initialize(&sha256); + secp256k1_sha256_write(&sha256, key, keylen); + secp256k1_sha256_finalize(&sha256, rkey); + memset(rkey + 32, 0, 32); + } + + secp256k1_sha256_initialize(&hash->outer); + for (n = 0; n < 64; n++) { + rkey[n] ^= 0x5c; + } + secp256k1_sha256_write(&hash->outer, rkey, 64); + + secp256k1_sha256_initialize(&hash->inner); + for (n = 0; n < 64; n++) { + rkey[n] ^= 0x5c ^ 0x36; + } + secp256k1_sha256_write(&hash->inner, rkey, 64); + memset(rkey, 0, 64); +} + +static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size) { + secp256k1_sha256_write(&hash->inner, data, size); +} + +static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32) { + unsigned char temp[32]; + secp256k1_sha256_finalize(&hash->inner, temp); + secp256k1_sha256_write(&hash->outer, temp, 32); + memset(temp, 0, 32); + secp256k1_sha256_finalize(&hash->outer, out32); +} + + +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen) { + secp256k1_hmac_sha256_t hmac; + static const unsigned char zero[1] = {0x00}; + static const unsigned char one[1] = {0x01}; + + memset(rng->v, 0x01, 32); /* RFC6979 3.2.b. */ + memset(rng->k, 0x00, 32); /* RFC6979 3.2.c. */ + + /* RFC6979 3.2.d. */ + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_write(&hmac, zero, 1); + secp256k1_hmac_sha256_write(&hmac, key, keylen); + secp256k1_hmac_sha256_finalize(&hmac, rng->k); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + + /* RFC6979 3.2.f. */ + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_write(&hmac, one, 1); + secp256k1_hmac_sha256_write(&hmac, key, keylen); + secp256k1_hmac_sha256_finalize(&hmac, rng->k); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + rng->retry = 0; +} + +static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen) { + /* RFC6979 3.2.h. */ + static const unsigned char zero[1] = {0x00}; + if (rng->retry) { + secp256k1_hmac_sha256_t hmac; + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_write(&hmac, zero, 1); + secp256k1_hmac_sha256_finalize(&hmac, rng->k); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + } + + while (outlen > 0) { + secp256k1_hmac_sha256_t hmac; + int now = outlen; + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + if (now > 32) { + now = 32; + } + memcpy(out, rng->v, now); + out += now; + outlen -= now; + } + + rng->retry = 1; +} + +static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng) { + memset(rng->k, 0, 32); + memset(rng->v, 0, 32); + rng->retry = 0; +} + +#undef BE32 +#undef Round +#undef sigma1 +#undef sigma0 +#undef Sigma1 +#undef Sigma0 +#undef Maj +#undef Ch + +#endif diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java new file mode 100644 index 000000000..be67048fb --- /dev/null +++ b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java @@ -0,0 +1,478 @@ +/* + * Copyright 2013 Google Inc. + * Copyright 2014-2016 the libsecp256k1 contributors + * + * 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. + */ + +package org.bitcoin; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import java.math.BigInteger; +import com.google.common.base.Preconditions; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import static org.bitcoin.NativeSecp256k1Util.*; + +/** + *

This class holds native methods to handle ECDSA verification.

+ * + *

You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1

+ * + *

To build secp256k1 for use with bitcoinj, run + * `./configure --enable-jni --enable-experimental --enable-module-schnorr --enable-module-ecdh` + * and `make` then copy `.libs/libsecp256k1.so` to your system library path + * or point the JVM to the folder containing it with -Djava.library.path + *

+ */ +public class NativeSecp256k1 { + + private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); + private static final Lock r = rwl.readLock(); + private static final Lock w = rwl.writeLock(); + private static ThreadLocal nativeECDSABuffer = new ThreadLocal(); + /** + * Verifies the given secp256k1 signature in native code. + * Calling when enabled == false is undefined (probably library not loaded) + * + * @param data The data which was signed, must be exactly 32 bytes + * @param signature The signature + * @param pub The public key which did the signing + */ + public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{ + Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < 520) { + byteBuff = ByteBuffer.allocateDirect(520); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(data); + byteBuff.put(signature); + byteBuff.put(pub); + + byte[][] retByteArray; + + r.lock(); + try { + return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1; + } finally { + r.unlock(); + } + } + + /** + * libsecp256k1 Create an ECDSA signature. + * + * @param data Message hash, 32 bytes + * @param key Secret key, 32 bytes + * + * Return values + * @param sig byte array of signature + */ + public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{ + Preconditions.checkArgument(data.length == 32 && sec.length <= 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < 32 + 32) { + byteBuff = ByteBuffer.allocateDirect(32 + 32); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(data); + byteBuff.put(sec); + + byte[][] retByteArray; + + r.lock(); + try { + retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] sigArr = retByteArray[0]; + int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(sigArr.length, sigLen, "Got bad signature length."); + + return retVal == 0 ? new byte[0] : sigArr; + } + + /** + * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid + * + * @param seckey ECDSA Secret key, 32 bytes + */ + public static boolean secKeyVerify(byte[] seckey) { + Preconditions.checkArgument(seckey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < seckey.length) { + byteBuff = ByteBuffer.allocateDirect(seckey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + + r.lock(); + try { + return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1; + } finally { + r.unlock(); + } + } + + + /** + * libsecp256k1 Compute Pubkey - computes public key from secret key + * + * @param seckey ECDSA Secret key, 32 bytes + * + * Return values + * @param pubkey ECDSA Public key, 33 or 65 bytes + */ + //TODO add a 'compressed' arg + public static byte[] computePubkey(byte[] seckey) throws AssertFailException{ + Preconditions.checkArgument(seckey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < seckey.length) { + byteBuff = ByteBuffer.allocateDirect(seckey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + + byte[][] retByteArray; + + r.lock(); + try { + retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] pubArr = retByteArray[0]; + int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); + + return retVal == 0 ? new byte[0]: pubArr; + } + + /** + * libsecp256k1 Cleanup - This destroys the secp256k1 context object + * This should be called at the end of the program for proper cleanup of the context. + */ + public static synchronized void cleanup() { + w.lock(); + try { + secp256k1_destroy_context(Secp256k1Context.getContext()); + } finally { + w.unlock(); + } + } + + public static long cloneContext() { + r.lock(); + try { + return secp256k1_ctx_clone(Secp256k1Context.getContext()); + } finally { r.unlock(); } + } + + /** + * libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it + * + * @param tweak some bytes to tweak with + * @param seckey 32-byte seckey + */ + public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(privkey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(privkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] privArr = retByteArray[0]; + + int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(privArr.length, privLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return privArr; + } + + /** + * libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it + * + * @param tweak some bytes to tweak with + * @param seckey 32-byte seckey + */ + public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(privkey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(privkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] privArr = retByteArray[0]; + + int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(privArr.length, privLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return privArr; + } + + /** + * libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it + * + * @param tweak some bytes to tweak with + * @param pubkey 32-byte seckey + */ + public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(pubkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length); + } finally { + r.unlock(); + } + + byte[] pubArr = retByteArray[0]; + + int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return pubArr; + } + + /** + * libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it + * + * @param tweak some bytes to tweak with + * @param pubkey 32-byte seckey + */ + public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(pubkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length); + } finally { + r.unlock(); + } + + byte[] pubArr = retByteArray[0]; + + int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return pubArr; + } + + /** + * libsecp256k1 create ECDH secret - constant time ECDH calculation + * + * @param seckey byte array of secret key used in exponentiaion + * @param pubkey byte array of public key used in exponentiaion + */ + public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{ + Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) { + byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + byteBuff.put(pubkey); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length); + } finally { + r.unlock(); + } + + byte[] resArr = retByteArray[0]; + int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + + assertEquals(resArr.length, 32, "Got bad result length."); + assertEquals(retVal, 1, "Failed return value check."); + + return resArr; + } + + /** + * libsecp256k1 randomize - updates the context randomization + * + * @param seed 32-byte random seed + */ + public static synchronized boolean randomize(byte[] seed) throws AssertFailException{ + Preconditions.checkArgument(seed.length == 32 || seed == null); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < seed.length) { + byteBuff = ByteBuffer.allocateDirect(seed.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seed); + + w.lock(); + try { + return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1; + } finally { + w.unlock(); + } + } + + public static byte[] schnorrSign(byte[] data, byte[] sec) throws AssertFailException { + Preconditions.checkArgument(data.length == 32 && sec.length <= 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null) { + byteBuff = ByteBuffer.allocateDirect(32 + 32); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(data); + byteBuff.put(sec); + + byte[][] retByteArray; + + r.lock(); + try { + retByteArray = secp256k1_schnorr_sign(byteBuff, Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] sigArr = retByteArray[0]; + int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + + assertEquals(sigArr.length, 64, "Got bad signature length."); + + return retVal == 0 ? new byte[0] : sigArr; + } + + private static native long secp256k1_ctx_clone(long context); + + private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen); + + private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen); + + private static native void secp256k1_destroy_context(long context); + + private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen); + + private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context); + + private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen); + + private static native byte[][] secp256k1_schnorr_sign(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen); + +} diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java new file mode 100644 index 000000000..f18ce9581 --- /dev/null +++ b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -0,0 +1,247 @@ +package org.bitcoin; + +import com.google.common.io.BaseEncoding; +import java.util.Arrays; +import java.math.BigInteger; +import javax.xml.bind.DatatypeConverter; +import static org.bitcoin.NativeSecp256k1Util.*; + +/** + * This class holds test cases defined for testing this library. + */ +public class NativeSecp256k1Test { + + //TODO improve comments/add more tests + /** + * This tests verify() for a valid signature + */ + public static void testVerifyPos() throws AssertFailException{ + boolean result = false; + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + + result = NativeSecp256k1.verify( data, sig, pub); + assertEquals( result, true , "testVerifyPos"); + } + + /** + * This tests verify() for a non-valid signature + */ + public static void testVerifyNeg() throws AssertFailException{ + boolean result = false; + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing" + byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + + result = NativeSecp256k1.verify( data, sig, pub); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, false , "testVerifyNeg"); + } + + /** + * This tests secret key verify() for a valid secretkey + */ + public static void testSecKeyVerifyPos() throws AssertFailException{ + boolean result = false; + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + result = NativeSecp256k1.secKeyVerify( sec ); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, true , "testSecKeyVerifyPos"); + } + + /** + * This tests secret key verify() for a invalid secretkey + */ + public static void testSecKeyVerifyNeg() throws AssertFailException{ + boolean result = false; + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + result = NativeSecp256k1.secKeyVerify( sec ); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, false , "testSecKeyVerifyNeg"); + } + + /** + * This tests public key create() for a valid secretkey + */ + public static void testPubKeyCreatePos() throws AssertFailException{ + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.computePubkey( sec); + String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos"); + } + + /** + * This tests public key create() for a invalid secretkey + */ + public static void testPubKeyCreateNeg() throws AssertFailException{ + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.computePubkey( sec); + String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( pubkeyString, "" , "testPubKeyCreateNeg"); + } + + /** + * This tests sign() for a valid secretkey + */ + public static void testSignPos() throws AssertFailException{ + + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.sign(data, sec); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos"); + } + + /** + * This tests sign() for a invalid secretkey + */ + public static void testSignNeg() throws AssertFailException{ + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.sign(data, sec); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString, "" , "testSignNeg"); + } + + /** + * This tests private key tweak-add + */ + public static void testPrivKeyTweakAdd_1() throws AssertFailException { + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "testPrivKeyAdd_1"); + } + + /** + * This tests private key tweak-mul + */ + public static void testPrivKeyTweakMul_1() throws AssertFailException { + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "testPrivKeyMul_1"); + } + + /** + * This tests private key tweak-add uncompressed + */ + public static void testPrivKeyTweakAdd_2() throws AssertFailException { + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "testPrivKeyAdd_2"); + } + + /** + * This tests private key tweak-mul uncompressed + */ + public static void testPrivKeyTweakMul_2() throws AssertFailException { + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "testPrivKeyMul_2"); + } + + /** + * This tests seed randomization + */ + public static void testRandomize() throws AssertFailException { + byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random" + boolean result = NativeSecp256k1.randomize(seed); + assertEquals( result, true, "testRandomize"); + } + + /** + * This tests signSchnorr() for a valid secretkey + */ + public static void testSchnorrSign() throws AssertFailException{ + + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.schnorrSign(data, sec); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString, "C5E929AA058B982048760422D3B563749B7D0E50C5EBD8CD2FFC23214BD6A2F1B072C13880997EBA847CF20F2F90FCE07C1CA33A890A4127095A351127F8D95F" , "testSchnorrSign"); + } + + /** + * This tests signSchnorr() for a valid secretkey + */ + public static void testCreateECDHSecret() throws AssertFailException{ + + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub); + String ecdhString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( ecdhString, "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043" , "testCreateECDHSecret"); + } + + public static void main(String[] args) throws AssertFailException{ + + + System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n"); + + assertEquals( Secp256k1Context.isEnabled(), true, "isEnabled" ); + + //Test verify() success/fail + testVerifyPos(); + testVerifyNeg(); + + //Test secKeyVerify() success/fail + testSecKeyVerifyPos(); + testSecKeyVerifyNeg(); + + //Test computePubkey() success/fail + testPubKeyCreatePos(); + testPubKeyCreateNeg(); + + //Test sign() success/fail + testSignPos(); + testSignNeg(); + + //Test Schnorr (partial support) //TODO + testSchnorrSign(); + //testSchnorrVerify + //testSchnorrRecovery + + //Test privKeyTweakAdd() 1 + testPrivKeyTweakAdd_1(); + + //Test privKeyTweakMul() 2 + testPrivKeyTweakMul_1(); + + //Test privKeyTweakAdd() 3 + testPrivKeyTweakAdd_2(); + + //Test privKeyTweakMul() 4 + testPrivKeyTweakMul_2(); + + //Test randomize() + testRandomize(); + + //Test ECDH + testCreateECDHSecret(); + + NativeSecp256k1.cleanup(); + + System.out.println(" All tests passed." ); + + } +} diff --git a/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java new file mode 100644 index 000000000..04732ba04 --- /dev/null +++ b/src/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014-2016 the libsecp256k1 contributors + * + * 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. + */ + +package org.bitcoin; + +public class NativeSecp256k1Util{ + + public static void assertEquals( int val, int val2, String message ) throws AssertFailException{ + if( val != val2 ) + throw new AssertFailException("FAIL: " + message); + } + + public static void assertEquals( boolean val, boolean val2, String message ) throws AssertFailException{ + if( val != val2 ) + throw new AssertFailException("FAIL: " + message); + else + System.out.println("PASS: " + message); + } + + public static void assertEquals( String val, String val2, String message ) throws AssertFailException{ + if( !val.equals(val2) ) + throw new AssertFailException("FAIL: " + message); + else + System.out.println("PASS: " + message); + } + + public static class AssertFailException extends Exception { + public AssertFailException(String message) { + super( message ); + } + } +} diff --git a/src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java b/src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java new file mode 100644 index 000000000..216c986a8 --- /dev/null +++ b/src/secp256k1/src/java/org/bitcoin/Secp256k1Context.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014-2016 the libsecp256k1 contributors + * + * 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. + */ + +package org.bitcoin; + +/** + * This class holds the context reference used in native methods + * to handle ECDSA operations. + */ +public class Secp256k1Context { + private static final boolean enabled; //true if the library is loaded + private static final long context; //ref to pointer to context obj + + static { //static initializer + boolean isEnabled = true; + long contextRef = -1; + try { + System.loadLibrary("secp256k1"); + contextRef = secp256k1_init_context(); + } catch (UnsatisfiedLinkError e) { + System.out.println("UnsatisfiedLinkError: " + e.toString()); + isEnabled = false; + } + enabled = isEnabled; + context = contextRef; + } + + public static boolean isEnabled() { + return enabled; + } + + public static long getContext() { + if(!enabled) return -1; //sanity check + return context; + } + + private static native long secp256k1_init_context(); +} diff --git a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c new file mode 100644 index 000000000..dba9524dd --- /dev/null +++ b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c @@ -0,0 +1,411 @@ +#include +#include +#include +#include "org_bitcoin_NativeSecp256k1.h" +#include "include/secp256k1.h" +#include "include/secp256k1_ecdh.h" +#include "include/secp256k1_recovery.h" +#include "include/secp256k1_schnorr.h" + + +SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone + (JNIEnv* env, jclass classObject, jlong ctx_l) +{ + const secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + jlong ctx_clone_l = (uintptr_t) secp256k1_context_clone(ctx); + + (void)classObject;(void)env; + + return ctx_clone_l; + +} + +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + (void)classObject; + + return secp256k1_context_randomize(ctx, seed); + +} + +SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context + (JNIEnv* env, jclass classObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + secp256k1_context_destroy(ctx); + + (void)classObject;(void)env; +} + +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* sigdata = { (unsigned char*) (data + 32) }; + const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) }; + + secp256k1_ecdsa_signature sig; + secp256k1_pubkey pubkey; + + int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen); + + if( ret ) { + ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); + + if( ret ) { + ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey); + } + } + + (void)classObject; + + return ret; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + unsigned char* secKey = (unsigned char*) (data + 32); + + jobjectArray retArray; + jbyteArray sigArray, intsByteArray; + unsigned char intsarray[2]; + + secp256k1_ecdsa_signature sig[72]; + + int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL ); + + unsigned char outputSer[72]; + size_t outputLen = 72; + + if( ret ) { + int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, sig ); (void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + sigArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, sigArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + (void)classObject; + + return secp256k1_ec_seckey_verify(ctx, secKey); +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + secp256k1_pubkey pubkey; + + jobjectArray retArray; + jbyteArray pubkeyArray, intsByteArray; + unsigned char intsarray[2]; + + int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey); + + unsigned char outputSer[65]; + size_t outputLen = 65; + + if( ret ) { + int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubkeyArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; + +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (privkey + 32); + + jobjectArray retArray; + jbyteArray privArray, intsByteArray; + unsigned char intsarray[2]; + + int privkeylen = 32; + + int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak); + + intsarray[0] = privkeylen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + privArray = (*env)->NewByteArray(env, privkeylen); + (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); + (*env)->SetObjectArrayElement(env, retArray, 0, privArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (privkey + 32); + + jobjectArray retArray; + jbyteArray privArray, intsByteArray; + unsigned char intsarray[2]; + + int privkeylen = 32; + + int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak); + + intsarray[0] = privkeylen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + privArray = (*env)->NewByteArray(env, privkeylen); + (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); + (*env)->SetObjectArrayElement(env, retArray, 0, privArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; +/* secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/ + unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (pkey + publen); + + jobjectArray retArray; + jbyteArray pubArray, intsByteArray; + unsigned char intsarray[2]; + unsigned char outputSer[65]; + size_t outputLen = 65; + + secp256k1_pubkey pubkey; + int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen); + + if( ret ) { + ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak); + } + + if( ret ) { + int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (pkey + publen); + + jobjectArray retArray; + jbyteArray pubArray, intsByteArray; + unsigned char intsarray[2]; + unsigned char outputSer[65]; + size_t outputLen = 65; + + secp256k1_pubkey pubkey; + int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen); + + if ( ret ) { + ret = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, tweak); + } + + if( ret ) { + int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine + (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys) +{ + (void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys; + + return 0; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1schnorr_1sign + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + unsigned char* secKey = (unsigned char*) (data + 32); + + jobjectArray retArray; + jbyteArray sigArray, intsByteArray; + unsigned char intsarray[1]; + unsigned char sig[64]; + + int ret = secp256k1_schnorr_sign(ctx, sig, data, secKey, NULL, NULL); + + intsarray[0] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + sigArray = (*env)->NewByteArray(env, 64); + (*env)->SetByteArrayRegion(env, sigArray, 0, 64, (jbyte*)sig); + (*env)->SetObjectArrayElement(env, retArray, 0, sigArray); + + intsByteArray = (*env)->NewByteArray(env, 1); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* pubdata = (const unsigned char*) (secdata + 32); + + jobjectArray retArray; + jbyteArray outArray, intsByteArray; + unsigned char intsarray[1]; + secp256k1_pubkey pubkey; + unsigned char nonce_res[32]; + size_t outputLen = 32; + + int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); + + if (ret) { + ret = secp256k1_ecdh( + ctx, + nonce_res, + &pubkey, + secdata + ); + } + + intsarray[0] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + outArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res); + (*env)->SetObjectArrayElement(env, retArray, 0, outArray); + + intsByteArray = (*env)->NewByteArray(env, 1); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} diff --git a/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h new file mode 100644 index 000000000..4125a1f52 --- /dev/null +++ b/src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h @@ -0,0 +1,127 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +#include "include/secp256k1.h" +/* Header for class org_bitcoin_NativeSecp256k1 */ + +#ifndef _Included_org_bitcoin_NativeSecp256k1 +#define _Included_org_bitcoin_NativeSecp256k1 +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ctx_clone + * Signature: (J)J + */ +SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone + (JNIEnv *, jclass, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_context_randomize + * Signature: (Ljava/nio/ByteBuffer;J)I + */ +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_privkey_tweak_add + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_privkey_tweak_mul + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_pubkey_tweak_add + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_pubkey_tweak_mul + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_destroy_context + * Signature: (J)V + */ +SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context + (JNIEnv *, jclass, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdsa_verify + * Signature: (Ljava/nio/ByteBuffer;JII)I + */ +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify + (JNIEnv *, jclass, jobject, jlong, jint, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdsa_sign + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_seckey_verify + * Signature: (Ljava/nio/ByteBuffer;J)I + */ +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_pubkey_create + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_pubkey_parse + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_schnorr_sign + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1schnorr_1sign + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdh + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c new file mode 100644 index 000000000..a52939e7e --- /dev/null +++ b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c @@ -0,0 +1,15 @@ +#include +#include +#include "org_bitcoin_Secp256k1Context.h" +#include "include/secp256k1.h" + +SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context + (JNIEnv* env, jclass classObject) +{ + secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + (void)classObject;(void)env; + + return (uintptr_t)ctx; +} + diff --git a/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h new file mode 100644 index 000000000..0d2bc84b7 --- /dev/null +++ b/src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h @@ -0,0 +1,22 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +#include "include/secp256k1.h" +/* Header for class org_bitcoin_Secp256k1Context */ + +#ifndef _Included_org_bitcoin_Secp256k1Context +#define _Included_org_bitcoin_Secp256k1Context +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_bitcoin_Secp256k1Context + * Method: secp256k1_init_context + * Signature: ()J + */ +SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/secp256k1/src/modules/ecdh/Makefile.am.include b/src/secp256k1/src/modules/ecdh/Makefile.am.include new file mode 100644 index 000000000..e3088b469 --- /dev/null +++ b/src/secp256k1/src/modules/ecdh/Makefile.am.include @@ -0,0 +1,8 @@ +include_HEADERS += include/secp256k1_ecdh.h +noinst_HEADERS += src/modules/ecdh/main_impl.h +noinst_HEADERS += src/modules/ecdh/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_ecdh +bench_ecdh_SOURCES = src/bench_ecdh.c +bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) +endif diff --git a/src/secp256k1/src/modules/ecdh/main_impl.h b/src/secp256k1/src/modules/ecdh/main_impl.h new file mode 100644 index 000000000..c23e4f82f --- /dev/null +++ b/src/secp256k1/src/modules/ecdh/main_impl.h @@ -0,0 +1,54 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_ECDH_MAIN_ +#define _SECP256K1_MODULE_ECDH_MAIN_ + +#include "include/secp256k1_ecdh.h" +#include "ecmult_const_impl.h" + +int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const secp256k1_pubkey *point, const unsigned char *scalar) { + int ret = 0; + int overflow = 0; + secp256k1_gej res; + secp256k1_ge pt; + secp256k1_scalar s; + ARG_CHECK(result != NULL); + ARG_CHECK(point != NULL); + ARG_CHECK(scalar != NULL); + (void)ctx; + + secp256k1_pubkey_load(ctx, &pt, point); + secp256k1_scalar_set_b32(&s, scalar, &overflow); + if (overflow || secp256k1_scalar_is_zero(&s)) { + ret = 0; + } else { + unsigned char x[32]; + unsigned char y[1]; + secp256k1_sha256_t sha; + + secp256k1_ecmult_const(&res, &pt, &s); + secp256k1_ge_set_gej(&pt, &res); + /* Compute a hash of the point in compressed form + * Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not + * expect its output to be secret and has a timing sidechannel. */ + secp256k1_fe_normalize(&pt.x); + secp256k1_fe_normalize(&pt.y); + secp256k1_fe_get_b32(x, &pt.x); + y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y); + + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, y, sizeof(y)); + secp256k1_sha256_write(&sha, x, sizeof(x)); + secp256k1_sha256_finalize(&sha, result); + ret = 1; + } + + secp256k1_scalar_clear(&s); + return ret; +} + +#endif diff --git a/src/secp256k1/src/modules/ecdh/tests_impl.h b/src/secp256k1/src/modules/ecdh/tests_impl.h new file mode 100644 index 000000000..7badc9033 --- /dev/null +++ b/src/secp256k1/src/modules/ecdh/tests_impl.h @@ -0,0 +1,75 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_ECDH_TESTS_ +#define _SECP256K1_MODULE_ECDH_TESTS_ + +void test_ecdh_generator_basepoint(void) { + unsigned char s_one[32] = { 0 }; + secp256k1_pubkey point[2]; + int i; + + s_one[31] = 1; + /* Check against pubkey creation when the basepoint is the generator */ + for (i = 0; i < 100; ++i) { + secp256k1_sha256_t sha; + unsigned char s_b32[32]; + unsigned char output_ecdh[32]; + unsigned char output_ser[32]; + unsigned char point_ser[33]; + size_t point_ser_len = sizeof(point_ser); + secp256k1_scalar s; + + random_scalar_order(&s); + secp256k1_scalar_get_b32(s_b32, &s); + + /* compute using ECDH function */ + CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1); + CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32) == 1); + /* compute "explicitly" */ + CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1); + CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); + CHECK(point_ser_len == sizeof(point_ser)); + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, point_ser, point_ser_len); + secp256k1_sha256_finalize(&sha, output_ser); + /* compare */ + CHECK(memcmp(output_ecdh, output_ser, sizeof(output_ser)) == 0); + } +} + +void test_bad_scalar(void) { + unsigned char s_zero[32] = { 0 }; + unsigned char s_overflow[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 + }; + unsigned char s_rand[32] = { 0 }; + unsigned char output[32]; + secp256k1_scalar rand; + secp256k1_pubkey point; + + /* Create random point */ + random_scalar_order(&rand); + secp256k1_scalar_get_b32(s_rand, &rand); + CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1); + + /* Try to multiply it by bad values */ + CHECK(secp256k1_ecdh(ctx, output, &point, s_zero) == 0); + CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 0); + /* ...and a good one */ + s_overflow[31] -= 1; + CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 1); +} + +void run_ecdh_tests(void) { + test_ecdh_generator_basepoint(); + test_bad_scalar(); +} + +#endif diff --git a/src/secp256k1/src/modules/recovery/Makefile.am.include b/src/secp256k1/src/modules/recovery/Makefile.am.include new file mode 100644 index 000000000..bf23c26e7 --- /dev/null +++ b/src/secp256k1/src/modules/recovery/Makefile.am.include @@ -0,0 +1,8 @@ +include_HEADERS += include/secp256k1_recovery.h +noinst_HEADERS += src/modules/recovery/main_impl.h +noinst_HEADERS += src/modules/recovery/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_recover +bench_recover_SOURCES = src/bench_recover.c +bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) +endif diff --git a/src/secp256k1/src/modules/recovery/main_impl.h b/src/secp256k1/src/modules/recovery/main_impl.h new file mode 100644 index 000000000..ec42f4bb6 --- /dev/null +++ b/src/secp256k1/src/modules/recovery/main_impl.h @@ -0,0 +1,193 @@ +/********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_RECOVERY_MAIN_ +#define _SECP256K1_MODULE_RECOVERY_MAIN_ + +#include "include/secp256k1_recovery.h" + +static void secp256k1_ecdsa_recoverable_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const secp256k1_ecdsa_recoverable_signature* sig) { + (void)ctx; + if (sizeof(secp256k1_scalar) == 32) { + /* When the secp256k1_scalar type is exactly 32 byte, use its + * representation inside secp256k1_ecdsa_signature, as conversion is very fast. + * Note that secp256k1_ecdsa_signature_save must use the same representation. */ + memcpy(r, &sig->data[0], 32); + memcpy(s, &sig->data[32], 32); + } else { + secp256k1_scalar_set_b32(r, &sig->data[0], NULL); + secp256k1_scalar_set_b32(s, &sig->data[32], NULL); + } + *recid = sig->data[64]; +} + +static void secp256k1_ecdsa_recoverable_signature_save(secp256k1_ecdsa_recoverable_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s, int recid) { + if (sizeof(secp256k1_scalar) == 32) { + memcpy(&sig->data[0], r, 32); + memcpy(&sig->data[32], s, 32); + } else { + secp256k1_scalar_get_b32(&sig->data[0], r); + secp256k1_scalar_get_b32(&sig->data[32], s); + } + sig->data[64] = recid; +} + +int secp256k1_ecdsa_recoverable_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature* sig, const unsigned char *input64, int recid) { + secp256k1_scalar r, s; + int ret = 1; + int overflow = 0; + + (void)ctx; + ARG_CHECK(sig != NULL); + ARG_CHECK(input64 != NULL); + ARG_CHECK(recid >= 0 && recid <= 3); + + secp256k1_scalar_set_b32(&r, &input64[0], &overflow); + ret &= !overflow; + secp256k1_scalar_set_b32(&s, &input64[32], &overflow); + ret &= !overflow; + if (ret) { + secp256k1_ecdsa_recoverable_signature_save(sig, &r, &s, recid); + } else { + memset(sig, 0, sizeof(*sig)); + } + return ret; +} + +int secp256k1_ecdsa_recoverable_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, int *recid, const secp256k1_ecdsa_recoverable_signature* sig) { + secp256k1_scalar r, s; + + (void)ctx; + ARG_CHECK(output64 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(recid != NULL); + + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, recid, sig); + secp256k1_scalar_get_b32(&output64[0], &r); + secp256k1_scalar_get_b32(&output64[32], &s); + return 1; +} + +int secp256k1_ecdsa_recoverable_signature_convert(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const secp256k1_ecdsa_recoverable_signature* sigin) { + secp256k1_scalar r, s; + int recid; + + (void)ctx; + ARG_CHECK(sig != NULL); + ARG_CHECK(sigin != NULL); + + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, sigin); + secp256k1_ecdsa_signature_save(sig, &r, &s); + return 1; +} + +static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar* sigs, secp256k1_ge *pubkey, const secp256k1_scalar *message, int recid) { + unsigned char brx[32]; + secp256k1_fe fx; + secp256k1_ge x; + secp256k1_gej xj; + secp256k1_scalar rn, u1, u2; + secp256k1_gej qj; + int r; + + if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) { + return 0; + } + + secp256k1_scalar_get_b32(brx, sigr); + r = secp256k1_fe_set_b32(&fx, brx); + (void)r; + VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */ + if (recid & 2) { + if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) { + return 0; + } + secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe); + } + if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) { + return 0; + } + secp256k1_gej_set_ge(&xj, &x); + secp256k1_scalar_inverse_var(&rn, sigr); + secp256k1_scalar_mul(&u1, &rn, message); + secp256k1_scalar_negate(&u1, &u1); + secp256k1_scalar_mul(&u2, &rn, sigs); + secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1); + secp256k1_ge_set_gej_var(pubkey, &qj); + return !secp256k1_gej_is_infinity(&qj); +} + +int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { + secp256k1_scalar r, s; + secp256k1_scalar sec, non, msg; + int recid; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(seckey != NULL); + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_default; + } + + secp256k1_scalar_set_b32(&sec, seckey, &overflow); + /* Fail if the secret key is invalid. */ + if (!overflow && !secp256k1_scalar_is_zero(&sec)) { + unsigned int count = 0; + secp256k1_scalar_set_b32(&msg, msg32, NULL); + while (1) { + unsigned char nonce32[32]; + ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); + if (!ret) { + break; + } + secp256k1_scalar_set_b32(&non, nonce32, &overflow); + memset(nonce32, 0, 32); + if (!secp256k1_scalar_is_zero(&non) && !overflow) { + if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) { + break; + } + } + count++; + } + secp256k1_scalar_clear(&msg); + secp256k1_scalar_clear(&non); + secp256k1_scalar_clear(&sec); + } + if (ret) { + secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid); + } else { + memset(signature, 0, sizeof(*signature)); + } + return ret; +} + +int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32) { + secp256k1_ge q; + secp256k1_scalar r, s; + secp256k1_scalar m; + int recid; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(pubkey != NULL); + + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature); + ARG_CHECK(recid >= 0 && recid < 4); + secp256k1_scalar_set_b32(&m, msg32, NULL); + if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) { + secp256k1_pubkey_save(pubkey, &q); + return 1; + } else { + memset(pubkey, 0, sizeof(*pubkey)); + return 0; + } +} + +#endif diff --git a/src/secp256k1/src/modules/recovery/tests_impl.h b/src/secp256k1/src/modules/recovery/tests_impl.h new file mode 100644 index 000000000..8932d5f0a --- /dev/null +++ b/src/secp256k1/src/modules/recovery/tests_impl.h @@ -0,0 +1,250 @@ +/********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_MODULE_RECOVERY_TESTS_ +#define _SECP256K1_MODULE_RECOVERY_TESTS_ + +void test_ecdsa_recovery_end_to_end(void) { + unsigned char extra[32] = {0x00}; + unsigned char privkey[32]; + unsigned char message[32]; + secp256k1_ecdsa_signature signature[5]; + secp256k1_ecdsa_recoverable_signature rsignature[5]; + unsigned char sig[74]; + secp256k1_pubkey pubkey; + secp256k1_pubkey recpubkey; + int recid = 0; + + /* Generate a random key and message. */ + { + secp256k1_scalar msg, key; + random_scalar_order_test(&msg); + random_scalar_order_test(&key); + secp256k1_scalar_get_b32(privkey, &key); + secp256k1_scalar_get_b32(message, &msg); + } + + /* Construct and verify corresponding public key. */ + CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + + /* Serialize/parse compact and verify/recover. */ + extra[0] = 0; + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[4], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[1], message, privkey, NULL, extra) == 1); + extra[31] = 1; + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[2], message, privkey, NULL, extra) == 1); + extra[31] = 0; + extra[0] = 1; + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); + CHECK(memcmp(&signature[4], &signature[0], 64) == 0); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); + memset(&rsignature[4], 0, sizeof(rsignature[4])); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); + /* Parse compact (with recovery id) and recover. */ + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 1); + CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0); + /* Serialize/destroy/parse signature and verify again. */ + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); + sig[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0); + /* Recover again */ + CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 0 || + memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0); +} + +/* Tests several edge cases. */ +void test_ecdsa_recovery_edge_cases(void) { + const unsigned char msg32[32] = { + 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', + 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's', + 'e', 'c', 'r', 'e', 't', ' ', 'm', 'e', + 's', 's', 'a', 'g', 'e', '.', '.', '.' + }; + const unsigned char sig64[64] = { + /* Generated by signing the above message with nonce 'This is the nonce we will use...' + * and secret key 0 (which is not valid), resulting in recid 0. */ + 0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8, + 0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96, + 0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63, + 0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32, + 0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E, + 0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD, + 0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86, + 0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57 + }; + secp256k1_pubkey pubkey; + /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */ + const unsigned char sigb64[64] = { + 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, 0x04, + 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, 0x04, + }; + secp256k1_pubkey pubkeyb; + secp256k1_ecdsa_recoverable_signature rsig; + secp256k1_ecdsa_signature sig; + int recid; + + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 0)); + CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 1)); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 2)); + CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 3)); + CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + + for (recid = 0; recid < 4; recid++) { + int i; + int recid2; + /* (4,4) encoded in DER. */ + unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04}; + unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01}; + unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00}; + unsigned char sigbderalt1[39] = { + 0x30, 0x25, 0x02, 0x20, 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, 0x04, 0x02, 0x01, 0x04, + }; + unsigned char sigbderalt2[39] = { + 0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 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, 0x04, + }; + unsigned char sigbderalt3[40] = { + 0x30, 0x26, 0x02, 0x21, 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, 0x00, 0x04, 0x02, 0x01, 0x04, + }; + unsigned char sigbderalt4[40] = { + 0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 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, 0x00, 0x04, + }; + /* (order + r,4) encoded in DER. */ + unsigned char sigbderlong[40] = { + 0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, + 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, + 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04 + }; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1); + for (recid2 = 0; recid2 < 4; recid2++) { + secp256k1_pubkey pubkey2b; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkey2b, &rsig, msg32) == 1); + /* Verifying with (order + r,4) should always fail. */ + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + } + /* DER parsing tests. */ + /* Zero length r/s. */ + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0); + /* Leading zeros. */ + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0); + sigbderalt3[4] = 1; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + sigbderalt4[7] = 1; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + /* Damage signature. */ + sigbder[7]++; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + sigbder[7]--; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, 6) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder) - 1) == 0); + for(i = 0; i < 8; i++) { + int c; + unsigned char orig = sigbder[i]; + /*Try every single-byte change.*/ + for (c = 0; c < 256; c++) { + if (c == orig ) { + continue; + } + sigbder[i] = c; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + } + sigbder[i] = orig; + } + } + + /* Test r/s equal to zero */ + { + /* (1,1) encoded in DER. */ + unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; + unsigned char sigc64[64] = { + 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, 0x01, + 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, 0x01, + }; + secp256k1_pubkey pubkeyc; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyc, &rsig, msg32) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 1); + sigcder[4] = 0; + sigc64[31] = 0; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); + sigcder[4] = 1; + sigcder[7] = 0; + sigc64[31] = 1; + sigc64[63] = 0; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); + } +} + +void run_recovery_tests(void) { + int i; + for (i = 0; i < 64*count; i++) { + test_ecdsa_recovery_end_to_end(); + } + test_ecdsa_recovery_edge_cases(); +} + +#endif diff --git a/src/secp256k1/src/modules/schnorr/Makefile.am.include b/src/secp256k1/src/modules/schnorr/Makefile.am.include new file mode 100644 index 000000000..f1af8e832 --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/Makefile.am.include @@ -0,0 +1,10 @@ +include_HEADERS += include/secp256k1_schnorr.h +noinst_HEADERS += src/modules/schnorr/main_impl.h +noinst_HEADERS += src/modules/schnorr/schnorr.h +noinst_HEADERS += src/modules/schnorr/schnorr_impl.h +noinst_HEADERS += src/modules/schnorr/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_schnorr_verify +bench_schnorr_verify_SOURCES = src/bench_schnorr_verify.c +bench_schnorr_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) +endif diff --git a/src/secp256k1/src/modules/schnorr/main_impl.h b/src/secp256k1/src/modules/schnorr/main_impl.h new file mode 100644 index 000000000..fa176a176 --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/main_impl.h @@ -0,0 +1,164 @@ +/********************************************************************** + * Copyright (c) 2014-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_SCHNORR_MAIN +#define SECP256K1_MODULE_SCHNORR_MAIN + +#include "include/secp256k1_schnorr.h" +#include "modules/schnorr/schnorr_impl.h" + +static void secp256k1_schnorr_msghash_sha256(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) { + secp256k1_sha256_t sha; + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, r32, 32); + secp256k1_sha256_write(&sha, msg32, 32); + secp256k1_sha256_finalize(&sha, h32); +} + +static const unsigned char secp256k1_schnorr_algo16[17] = "Schnorr+SHA256 "; + +int secp256k1_schnorr_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { + secp256k1_scalar sec, non; + int ret = 0; + int overflow = 0; + unsigned int count = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(seckey != NULL); + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_default; + } + + secp256k1_scalar_set_b32(&sec, seckey, NULL); + while (1) { + unsigned char nonce32[32]; + ret = noncefp(nonce32, msg32, seckey, secp256k1_schnorr_algo16, (void*)noncedata, count); + if (!ret) { + break; + } + secp256k1_scalar_set_b32(&non, nonce32, &overflow); + memset(nonce32, 0, 32); + if (!secp256k1_scalar_is_zero(&non) && !overflow) { + if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, NULL, secp256k1_schnorr_msghash_sha256, msg32)) { + break; + } + } + count++; + } + if (!ret) { + memset(sig64, 0, 64); + } + secp256k1_scalar_clear(&non); + secp256k1_scalar_clear(&sec); + return ret; +} + +int secp256k1_schnorr_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg32, const secp256k1_pubkey *pubkey) { + secp256k1_ge q; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(pubkey != NULL); + + secp256k1_pubkey_load(ctx, &q, pubkey); + return secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32); +} + +int secp256k1_schnorr_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *sig64, const unsigned char *msg32) { + secp256k1_ge q; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(pubkey != NULL); + + if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &q, secp256k1_schnorr_msghash_sha256, msg32)) { + secp256k1_pubkey_save(pubkey, &q); + return 1; + } else { + memset(pubkey, 0, sizeof(*pubkey)); + return 0; + } +} + +int secp256k1_schnorr_generate_nonce_pair(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, unsigned char *privnonce32, const unsigned char *sec32, const unsigned char *msg32, secp256k1_nonce_function noncefp, const void* noncedata) { + int count = 0; + int ret = 1; + secp256k1_gej Qj; + secp256k1_ge Q; + secp256k1_scalar sec; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sec32 != NULL); + ARG_CHECK(pubnonce != NULL); + ARG_CHECK(privnonce32 != NULL); + + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_default; + } + + do { + int overflow; + ret = noncefp(privnonce32, sec32, msg32, secp256k1_schnorr_algo16, (void*)noncedata, count++); + if (!ret) { + break; + } + secp256k1_scalar_set_b32(&sec, privnonce32, &overflow); + if (overflow || secp256k1_scalar_is_zero(&sec)) { + continue; + } + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sec); + secp256k1_ge_set_gej(&Q, &Qj); + + secp256k1_pubkey_save(pubnonce, &Q); + break; + } while(1); + + secp256k1_scalar_clear(&sec); + if (!ret) { + memset(pubnonce, 0, sizeof(*pubnonce)); + } + return ret; +} + +int secp256k1_schnorr_partial_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const unsigned char *sec32, const secp256k1_pubkey *pubnonce_others, const unsigned char *secnonce32) { + int overflow = 0; + secp256k1_scalar sec, non; + secp256k1_ge pubnon; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sig64 != NULL); + ARG_CHECK(sec32 != NULL); + ARG_CHECK(secnonce32 != NULL); + ARG_CHECK(pubnonce_others != NULL); + + secp256k1_scalar_set_b32(&sec, sec32, &overflow); + if (overflow || secp256k1_scalar_is_zero(&sec)) { + return -1; + } + secp256k1_scalar_set_b32(&non, secnonce32, &overflow); + if (overflow || secp256k1_scalar_is_zero(&non)) { + return -1; + } + secp256k1_pubkey_load(ctx, &pubnon, pubnonce_others); + return secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64, &sec, &non, &pubnon, secp256k1_schnorr_msghash_sha256, msg32); +} + +int secp256k1_schnorr_partial_combine(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char * const *sig64sin, size_t n) { + ARG_CHECK(sig64 != NULL); + ARG_CHECK(n >= 1); + ARG_CHECK(sig64sin != NULL); + return secp256k1_schnorr_sig_combine(sig64, n, sig64sin); +} + +#endif diff --git a/src/secp256k1/src/modules/schnorr/schnorr.h b/src/secp256k1/src/modules/schnorr/schnorr.h new file mode 100644 index 000000000..de18147bd --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/schnorr.h @@ -0,0 +1,20 @@ +/*********************************************************************** + * Copyright (c) 2014-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php. * + ***********************************************************************/ + +#ifndef _SECP256K1_MODULE_SCHNORR_H_ +#define _SECP256K1_MODULE_SCHNORR_H_ + +#include "scalar.h" +#include "group.h" + +typedef void (*secp256k1_schnorr_msghash)(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32); + +static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32); +static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32); +static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32); +static int secp256k1_schnorr_sig_combine(unsigned char *sig64, size_t n, const unsigned char * const *sig64ins); + +#endif diff --git a/src/secp256k1/src/modules/schnorr/schnorr_impl.h b/src/secp256k1/src/modules/schnorr/schnorr_impl.h new file mode 100644 index 000000000..e13ab6db7 --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/schnorr_impl.h @@ -0,0 +1,207 @@ +/*********************************************************************** + * Copyright (c) 2014-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php. * + ***********************************************************************/ + +#ifndef _SECP256K1_SCHNORR_IMPL_H_ +#define _SECP256K1_SCHNORR_IMPL_H_ + +#include + +#include "schnorr.h" +#include "num.h" +#include "field.h" +#include "group.h" +#include "ecmult.h" +#include "ecmult_gen.h" + +/** + * Custom Schnorr-based signature scheme. They support multiparty signing, public key + * recovery and batch validation. + * + * Rationale for verifying R's y coordinate: + * In order to support batch validation and public key recovery, the full R point must + * be known to verifiers, rather than just its x coordinate. In order to not risk + * being more strict in batch validation than normal validation, validators must be + * required to reject signatures with incorrect y coordinate. This is only possible + * by including a (relatively slow) field inverse, or a field square root. However, + * batch validation offers potentially much higher benefits than this cost. + * + * Rationale for having an implicit y coordinate oddness: + * If we commit to having the full R point known to verifiers, there are two mechanism. + * Either include its oddness in the signature, or give it an implicit fixed value. + * As the R y coordinate can be flipped by a simple negation of the nonce, we choose the + * latter, as it comes with nearly zero impact on signing or validation performance, and + * saves a byte in the signature. + * + * Signing: + * Inputs: 32-byte message m, 32-byte scalar key x (!=0), 32-byte scalar nonce k (!=0) + * + * Compute point R = k * G. Reject nonce if R's y coordinate is odd (or negate nonce). + * Compute 32-byte r, the serialization of R's x coordinate. + * Compute scalar h = Hash(r || m). Reject nonce if h == 0 or h >= order. + * Compute scalar s = k - h * x. + * The signature is (r, s). + * + * + * Verification: + * Inputs: 32-byte message m, public key point Q, signature: (32-byte r, scalar s) + * + * Signature is invalid if s >= order. + * Signature is invalid if r >= p. + * Compute scalar h = Hash(r || m). Signature is invalid if h == 0 or h >= order. + * Option 1 (faster for single verification): + * Compute point R = h * Q + s * G. Signature is invalid if R is infinity or R's y coordinate is odd. + * Signature is valid if the serialization of R's x coordinate equals r. + * Option 2 (allows batch validation and pubkey recovery): + * Decompress x coordinate r into point R, with odd y coordinate. Fail if R is not on the curve. + * Signature is valid if R + h * Q + s * G == 0. + */ + +static int secp256k1_schnorr_sig_sign(const secp256k1_ecmult_gen_context* ctx, unsigned char *sig64, const secp256k1_scalar *key, const secp256k1_scalar *nonce, const secp256k1_ge *pubnonce, secp256k1_schnorr_msghash hash, const unsigned char *msg32) { + secp256k1_gej Rj; + secp256k1_ge Ra; + unsigned char h32[32]; + secp256k1_scalar h, s; + int overflow; + secp256k1_scalar n; + + if (secp256k1_scalar_is_zero(key) || secp256k1_scalar_is_zero(nonce)) { + return 0; + } + n = *nonce; + + secp256k1_ecmult_gen(ctx, &Rj, &n); + if (pubnonce != NULL) { + secp256k1_gej_add_ge(&Rj, &Rj, pubnonce); + } + secp256k1_ge_set_gej(&Ra, &Rj); + secp256k1_fe_normalize(&Ra.y); + if (secp256k1_fe_is_odd(&Ra.y)) { + /* R's y coordinate is odd, which is not allowed (see rationale above). + Force it to be even by negating the nonce. Note that this even works + for multiparty signing, as the R point is known to all participants, + which can all decide to flip the sign in unison, resulting in the + overall R point to be negated too. */ + secp256k1_scalar_negate(&n, &n); + } + secp256k1_fe_normalize(&Ra.x); + secp256k1_fe_get_b32(sig64, &Ra.x); + hash(h32, sig64, msg32); + overflow = 0; + secp256k1_scalar_set_b32(&h, h32, &overflow); + if (overflow || secp256k1_scalar_is_zero(&h)) { + secp256k1_scalar_clear(&n); + return 0; + } + secp256k1_scalar_mul(&s, &h, key); + secp256k1_scalar_negate(&s, &s); + secp256k1_scalar_add(&s, &s, &n); + secp256k1_scalar_clear(&n); + secp256k1_scalar_get_b32(sig64 + 32, &s); + return 1; +} + +static int secp256k1_schnorr_sig_verify(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, const secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) { + secp256k1_gej Qj, Rj; + secp256k1_ge Ra; + secp256k1_fe Rx; + secp256k1_scalar h, s; + unsigned char hh[32]; + int overflow; + + if (secp256k1_ge_is_infinity(pubkey)) { + return 0; + } + hash(hh, sig64, msg32); + overflow = 0; + secp256k1_scalar_set_b32(&h, hh, &overflow); + if (overflow || secp256k1_scalar_is_zero(&h)) { + return 0; + } + overflow = 0; + secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow); + if (overflow) { + return 0; + } + if (!secp256k1_fe_set_b32(&Rx, sig64)) { + return 0; + } + secp256k1_gej_set_ge(&Qj, pubkey); + secp256k1_ecmult(ctx, &Rj, &Qj, &h, &s); + if (secp256k1_gej_is_infinity(&Rj)) { + return 0; + } + secp256k1_ge_set_gej_var(&Ra, &Rj); + secp256k1_fe_normalize_var(&Ra.y); + if (secp256k1_fe_is_odd(&Ra.y)) { + return 0; + } + return secp256k1_fe_equal_var(&Rx, &Ra.x); +} + +static int secp256k1_schnorr_sig_recover(const secp256k1_ecmult_context* ctx, const unsigned char *sig64, secp256k1_ge *pubkey, secp256k1_schnorr_msghash hash, const unsigned char *msg32) { + secp256k1_gej Qj, Rj; + secp256k1_ge Ra; + secp256k1_fe Rx; + secp256k1_scalar h, s; + unsigned char hh[32]; + int overflow; + + hash(hh, sig64, msg32); + overflow = 0; + secp256k1_scalar_set_b32(&h, hh, &overflow); + if (overflow || secp256k1_scalar_is_zero(&h)) { + return 0; + } + overflow = 0; + secp256k1_scalar_set_b32(&s, sig64 + 32, &overflow); + if (overflow) { + return 0; + } + if (!secp256k1_fe_set_b32(&Rx, sig64)) { + return 0; + } + if (!secp256k1_ge_set_xo_var(&Ra, &Rx, 0)) { + return 0; + } + secp256k1_gej_set_ge(&Rj, &Ra); + secp256k1_scalar_inverse_var(&h, &h); + secp256k1_scalar_negate(&s, &s); + secp256k1_scalar_mul(&s, &s, &h); + secp256k1_ecmult(ctx, &Qj, &Rj, &h, &s); + if (secp256k1_gej_is_infinity(&Qj)) { + return 0; + } + secp256k1_ge_set_gej(pubkey, &Qj); + return 1; +} + +static int secp256k1_schnorr_sig_combine(unsigned char *sig64, size_t n, const unsigned char * const *sig64ins) { + secp256k1_scalar s = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + size_t i; + for (i = 0; i < n; i++) { + secp256k1_scalar si; + int overflow; + secp256k1_scalar_set_b32(&si, sig64ins[i] + 32, &overflow); + if (overflow) { + return -1; + } + if (i) { + if (memcmp(sig64ins[i - 1], sig64ins[i], 32) != 0) { + return -1; + } + } + secp256k1_scalar_add(&s, &s, &si); + } + if (secp256k1_scalar_is_zero(&s)) { + return 0; + } + memcpy(sig64, sig64ins[0], 32); + secp256k1_scalar_get_b32(sig64 + 32, &s); + secp256k1_scalar_clear(&s); + return 1; +} + +#endif diff --git a/src/secp256k1/src/modules/schnorr/tests_impl.h b/src/secp256k1/src/modules/schnorr/tests_impl.h new file mode 100644 index 000000000..5bd14a03e --- /dev/null +++ b/src/secp256k1/src/modules/schnorr/tests_impl.h @@ -0,0 +1,175 @@ +/********************************************************************** + * Copyright (c) 2014-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_SCHNORR_TESTS +#define SECP256K1_MODULE_SCHNORR_TESTS + +#include "include/secp256k1_schnorr.h" + +void test_schnorr_end_to_end(void) { + unsigned char privkey[32]; + unsigned char message[32]; + unsigned char schnorr_signature[64]; + secp256k1_pubkey pubkey, recpubkey; + + /* Generate a random key and message. */ + { + secp256k1_scalar key; + random_scalar_order_test(&key); + secp256k1_scalar_get_b32(privkey, &key); + secp256k1_rand256_test(message); + } + + /* Construct and verify corresponding public key. */ + CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + + /* Schnorr sign. */ + CHECK(secp256k1_schnorr_sign(ctx, schnorr_signature, message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 1); + CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) == 1); + CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0); + /* Destroy signature and verify again. */ + schnorr_signature[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255); + CHECK(secp256k1_schnorr_verify(ctx, schnorr_signature, message, &pubkey) == 0); + CHECK(secp256k1_schnorr_recover(ctx, &recpubkey, schnorr_signature, message) != 1 || + memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0); +} + +/** Horribly broken hash function. Do not use for anything but tests. */ +void test_schnorr_hash(unsigned char *h32, const unsigned char *r32, const unsigned char *msg32) { + int i; + for (i = 0; i < 32; i++) { + h32[i] = r32[i] ^ msg32[i]; + } +} + +void test_schnorr_sign_verify(void) { + unsigned char msg32[32]; + unsigned char sig64[3][64]; + secp256k1_gej pubkeyj[3]; + secp256k1_ge pubkey[3]; + secp256k1_scalar nonce[3], key[3]; + int i = 0; + int k; + + secp256k1_rand256_test(msg32); + + for (k = 0; k < 3; k++) { + random_scalar_order_test(&key[k]); + + do { + random_scalar_order_test(&nonce[k]); + if (secp256k1_schnorr_sig_sign(&ctx->ecmult_gen_ctx, sig64[k], &key[k], &nonce[k], NULL, &test_schnorr_hash, msg32)) { + break; + } + } while(1); + + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubkeyj[k], &key[k]); + secp256k1_ge_set_gej_var(&pubkey[k], &pubkeyj[k]); + CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32)); + + for (i = 0; i < 4; i++) { + int pos = secp256k1_rand_bits(6); + int mod = 1 + secp256k1_rand_int(255); + sig64[k][pos] ^= mod; + CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64[k], &pubkey[k], &test_schnorr_hash, msg32) == 0); + sig64[k][pos] ^= mod; + } + } +} + +void test_schnorr_threshold(void) { + unsigned char msg[32]; + unsigned char sec[5][32]; + secp256k1_pubkey pub[5]; + unsigned char nonce[5][32]; + secp256k1_pubkey pubnonce[5]; + unsigned char sig[5][64]; + const unsigned char* sigs[5]; + unsigned char allsig[64]; + const secp256k1_pubkey* pubs[5]; + secp256k1_pubkey allpub; + int n, i; + int damage; + int ret = 0; + + damage = secp256k1_rand_bits(1) ? (1 + secp256k1_rand_int(4)) : 0; + secp256k1_rand256_test(msg); + n = 2 + secp256k1_rand_int(4); + for (i = 0; i < n; i++) { + do { + secp256k1_rand256_test(sec[i]); + } while (!secp256k1_ec_seckey_verify(ctx, sec[i])); + CHECK(secp256k1_ec_pubkey_create(ctx, &pub[i], sec[i])); + CHECK(secp256k1_schnorr_generate_nonce_pair(ctx, &pubnonce[i], nonce[i], msg, sec[i], NULL, NULL)); + pubs[i] = &pub[i]; + } + if (damage == 1) { + nonce[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); + } else if (damage == 2) { + sec[secp256k1_rand_int(n)][secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); + } + for (i = 0; i < n; i++) { + secp256k1_pubkey allpubnonce; + const secp256k1_pubkey *pubnonces[4]; + int j; + for (j = 0; j < i; j++) { + pubnonces[j] = &pubnonce[j]; + } + for (j = i + 1; j < n; j++) { + pubnonces[j - 1] = &pubnonce[j]; + } + CHECK(secp256k1_ec_pubkey_combine(ctx, &allpubnonce, pubnonces, n - 1)); + ret |= (secp256k1_schnorr_partial_sign(ctx, sig[i], msg, sec[i], &allpubnonce, nonce[i]) != 1) * 1; + sigs[i] = sig[i]; + } + if (damage == 3) { + sig[secp256k1_rand_int(n)][secp256k1_rand_bits(6)] ^= 1 + secp256k1_rand_int(255); + } + ret |= (secp256k1_ec_pubkey_combine(ctx, &allpub, pubs, n) != 1) * 2; + if ((ret & 1) == 0) { + ret |= (secp256k1_schnorr_partial_combine(ctx, allsig, sigs, n) != 1) * 4; + } + if (damage == 4) { + allsig[secp256k1_rand_int(32)] ^= 1 + secp256k1_rand_int(255); + } + if ((ret & 7) == 0) { + ret |= (secp256k1_schnorr_verify(ctx, allsig, msg, &allpub) != 1) * 8; + } + CHECK((ret == 0) == (damage == 0)); +} + +void test_schnorr_recovery(void) { + unsigned char msg32[32]; + unsigned char sig64[64]; + secp256k1_ge Q; + + secp256k1_rand256_test(msg32); + secp256k1_rand256_test(sig64); + secp256k1_rand256_test(sig64 + 32); + if (secp256k1_schnorr_sig_recover(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1) { + CHECK(secp256k1_schnorr_sig_verify(&ctx->ecmult_ctx, sig64, &Q, &test_schnorr_hash, msg32) == 1); + } +} + +void run_schnorr_tests(void) { + int i; + for (i = 0; i < 32*count; i++) { + test_schnorr_end_to_end(); + } + for (i = 0; i < 32 * count; i++) { + test_schnorr_sign_verify(); + } + for (i = 0; i < 16 * count; i++) { + test_schnorr_recovery(); + } + for (i = 0; i < 10 * count; i++) { + test_schnorr_threshold(); + } +} + +#endif diff --git a/src/secp256k1/src/num.h b/src/secp256k1/src/num.h new file mode 100644 index 000000000..7bb9c5be8 --- /dev/null +++ b/src/secp256k1/src/num.h @@ -0,0 +1,74 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_NUM_ +#define _SECP256K1_NUM_ + +#ifndef USE_NUM_NONE + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#if defined(USE_NUM_GMP) +#include "num_gmp.h" +#else +#error "Please select num implementation" +#endif + +/** Copy a number. */ +static void secp256k1_num_copy(secp256k1_num *r, const secp256k1_num *a); + +/** Convert a number's absolute value to a binary big-endian string. + * There must be enough place. */ +static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num *a); + +/** Set a number to the value of a binary big-endian string. */ +static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsigned int alen); + +/** Compute a modular inverse. The input must be less than the modulus. */ +static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m); + +/** Compute the jacobi symbol (a|b). b must be positive and odd. */ +static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b); + +/** Compare the absolute value of two numbers. */ +static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b); + +/** Test whether two number are equal (including sign). */ +static int secp256k1_num_eq(const secp256k1_num *a, const secp256k1_num *b); + +/** Add two (signed) numbers. */ +static void secp256k1_num_add(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b); + +/** Subtract two (signed) numbers. */ +static void secp256k1_num_sub(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b); + +/** Multiply two (signed) numbers. */ +static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b); + +/** Replace a number by its remainder modulo m. M's sign is ignored. The result is a number between 0 and m-1, + even if r was negative. */ +static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m); + +/** Right-shift the passed number by bits bits. */ +static void secp256k1_num_shift(secp256k1_num *r, int bits); + +/** Check whether a number is zero. */ +static int secp256k1_num_is_zero(const secp256k1_num *a); + +/** Check whether a number is one. */ +static int secp256k1_num_is_one(const secp256k1_num *a); + +/** Check whether a number is strictly negative. */ +static int secp256k1_num_is_neg(const secp256k1_num *a); + +/** Change a number's sign. */ +static void secp256k1_num_negate(secp256k1_num *r); + +#endif + +#endif diff --git a/src/secp256k1/src/num_gmp.h b/src/secp256k1/src/num_gmp.h new file mode 100644 index 000000000..7dd813088 --- /dev/null +++ b/src/secp256k1/src/num_gmp.h @@ -0,0 +1,20 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_NUM_REPR_ +#define _SECP256K1_NUM_REPR_ + +#include + +#define NUM_LIMBS ((256+GMP_NUMB_BITS-1)/GMP_NUMB_BITS) + +typedef struct { + mp_limb_t data[2*NUM_LIMBS]; + int neg; + int limbs; +} secp256k1_num; + +#endif diff --git a/src/secp256k1/src/num_gmp_impl.h b/src/secp256k1/src/num_gmp_impl.h new file mode 100644 index 000000000..3a46495ee --- /dev/null +++ b/src/secp256k1/src/num_gmp_impl.h @@ -0,0 +1,288 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_NUM_REPR_IMPL_H_ +#define _SECP256K1_NUM_REPR_IMPL_H_ + +#include +#include +#include + +#include "util.h" +#include "num.h" + +#ifdef VERIFY +static void secp256k1_num_sanity(const secp256k1_num *a) { + VERIFY_CHECK(a->limbs == 1 || (a->limbs > 1 && a->data[a->limbs-1] != 0)); +} +#else +#define secp256k1_num_sanity(a) do { } while(0) +#endif + +static void secp256k1_num_copy(secp256k1_num *r, const secp256k1_num *a) { + *r = *a; +} + +static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num *a) { + unsigned char tmp[65]; + int len = 0; + int shift = 0; + if (a->limbs>1 || a->data[0] != 0) { + len = mpn_get_str(tmp, 256, (mp_limb_t*)a->data, a->limbs); + } + while (shift < len && tmp[shift] == 0) shift++; + VERIFY_CHECK(len-shift <= (int)rlen); + memset(r, 0, rlen - len + shift); + if (len > shift) { + memcpy(r + rlen - len + shift, tmp + shift, len - shift); + } + memset(tmp, 0, sizeof(tmp)); +} + +static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsigned int alen) { + int len; + VERIFY_CHECK(alen > 0); + VERIFY_CHECK(alen <= 64); + len = mpn_set_str(r->data, a, alen, 256); + if (len == 0) { + r->data[0] = 0; + len = 1; + } + VERIFY_CHECK(len <= NUM_LIMBS*2); + r->limbs = len; + r->neg = 0; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } +} + +static void secp256k1_num_add_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { + mp_limb_t c = mpn_add(r->data, a->data, a->limbs, b->data, b->limbs); + r->limbs = a->limbs; + if (c != 0) { + VERIFY_CHECK(r->limbs < 2*NUM_LIMBS); + r->data[r->limbs++] = c; + } +} + +static void secp256k1_num_sub_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { + mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs); + (void)c; + VERIFY_CHECK(c == 0); + r->limbs = a->limbs; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } +} + +static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m) { + secp256k1_num_sanity(r); + secp256k1_num_sanity(m); + + if (r->limbs >= m->limbs) { + mp_limb_t t[2*NUM_LIMBS]; + mpn_tdiv_qr(t, r->data, 0, r->data, r->limbs, m->data, m->limbs); + memset(t, 0, sizeof(t)); + r->limbs = m->limbs; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } + } + + if (r->neg && (r->limbs > 1 || r->data[0] != 0)) { + secp256k1_num_sub_abs(r, m, r); + r->neg = 0; + } +} + +static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m) { + int i; + mp_limb_t g[NUM_LIMBS+1]; + mp_limb_t u[NUM_LIMBS+1]; + mp_limb_t v[NUM_LIMBS+1]; + mp_size_t sn; + mp_size_t gn; + secp256k1_num_sanity(a); + secp256k1_num_sanity(m); + + /** mpn_gcdext computes: (G,S) = gcdext(U,V), where + * * G = gcd(U,V) + * * G = U*S + V*T + * * U has equal or more limbs than V, and V has no padding + * If we set U to be (a padded version of) a, and V = m: + * G = a*S + m*T + * G = a*S mod m + * Assuming G=1: + * S = 1/a mod m + */ + VERIFY_CHECK(m->limbs <= NUM_LIMBS); + VERIFY_CHECK(m->data[m->limbs-1] != 0); + for (i = 0; i < m->limbs; i++) { + u[i] = (i < a->limbs) ? a->data[i] : 0; + v[i] = m->data[i]; + } + sn = NUM_LIMBS+1; + gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs); + (void)gn; + VERIFY_CHECK(gn == 1); + VERIFY_CHECK(g[0] == 1); + r->neg = a->neg ^ m->neg; + if (sn < 0) { + mpn_sub(r->data, m->data, m->limbs, r->data, -sn); + r->limbs = m->limbs; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } + } else { + r->limbs = sn; + } + memset(g, 0, sizeof(g)); + memset(u, 0, sizeof(u)); + memset(v, 0, sizeof(v)); +} + +static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b) { + int ret; + mpz_t ga, gb; + secp256k1_num_sanity(a); + secp256k1_num_sanity(b); + VERIFY_CHECK(!b->neg && (b->limbs > 0) && (b->data[0] & 1)); + + mpz_inits(ga, gb, NULL); + + mpz_import(gb, b->limbs, -1, sizeof(mp_limb_t), 0, 0, b->data); + mpz_import(ga, a->limbs, -1, sizeof(mp_limb_t), 0, 0, a->data); + if (a->neg) { + mpz_neg(ga, ga); + } + + ret = mpz_jacobi(ga, gb); + + mpz_clears(ga, gb, NULL); + + return ret; +} + +static int secp256k1_num_is_one(const secp256k1_num *a) { + return (a->limbs == 1 && a->data[0] == 1); +} + +static int secp256k1_num_is_zero(const secp256k1_num *a) { + return (a->limbs == 1 && a->data[0] == 0); +} + +static int secp256k1_num_is_neg(const secp256k1_num *a) { + return (a->limbs > 1 || a->data[0] != 0) && a->neg; +} + +static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b) { + if (a->limbs > b->limbs) { + return 1; + } + if (a->limbs < b->limbs) { + return -1; + } + return mpn_cmp(a->data, b->data, a->limbs); +} + +static int secp256k1_num_eq(const secp256k1_num *a, const secp256k1_num *b) { + if (a->limbs > b->limbs) { + return 0; + } + if (a->limbs < b->limbs) { + return 0; + } + if ((a->neg && !secp256k1_num_is_zero(a)) != (b->neg && !secp256k1_num_is_zero(b))) { + return 0; + } + return mpn_cmp(a->data, b->data, a->limbs) == 0; +} + +static void secp256k1_num_subadd(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b, int bneg) { + if (!(b->neg ^ bneg ^ a->neg)) { /* a and b have the same sign */ + r->neg = a->neg; + if (a->limbs >= b->limbs) { + secp256k1_num_add_abs(r, a, b); + } else { + secp256k1_num_add_abs(r, b, a); + } + } else { + if (secp256k1_num_cmp(a, b) > 0) { + r->neg = a->neg; + secp256k1_num_sub_abs(r, a, b); + } else { + r->neg = b->neg ^ bneg; + secp256k1_num_sub_abs(r, b, a); + } + } +} + +static void secp256k1_num_add(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { + secp256k1_num_sanity(a); + secp256k1_num_sanity(b); + secp256k1_num_subadd(r, a, b, 0); +} + +static void secp256k1_num_sub(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { + secp256k1_num_sanity(a); + secp256k1_num_sanity(b); + secp256k1_num_subadd(r, a, b, 1); +} + +static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { + mp_limb_t tmp[2*NUM_LIMBS+1]; + secp256k1_num_sanity(a); + secp256k1_num_sanity(b); + + VERIFY_CHECK(a->limbs + b->limbs <= 2*NUM_LIMBS+1); + if ((a->limbs==1 && a->data[0]==0) || (b->limbs==1 && b->data[0]==0)) { + r->limbs = 1; + r->neg = 0; + r->data[0] = 0; + return; + } + if (a->limbs >= b->limbs) { + mpn_mul(tmp, a->data, a->limbs, b->data, b->limbs); + } else { + mpn_mul(tmp, b->data, b->limbs, a->data, a->limbs); + } + r->limbs = a->limbs + b->limbs; + if (r->limbs > 1 && tmp[r->limbs - 1]==0) { + r->limbs--; + } + VERIFY_CHECK(r->limbs <= 2*NUM_LIMBS); + mpn_copyi(r->data, tmp, r->limbs); + r->neg = a->neg ^ b->neg; + memset(tmp, 0, sizeof(tmp)); +} + +static void secp256k1_num_shift(secp256k1_num *r, int bits) { + if (bits % GMP_NUMB_BITS) { + /* Shift within limbs. */ + mpn_rshift(r->data, r->data, r->limbs, bits % GMP_NUMB_BITS); + } + if (bits >= GMP_NUMB_BITS) { + int i; + /* Shift full limbs. */ + for (i = 0; i < r->limbs; i++) { + int index = i + (bits / GMP_NUMB_BITS); + if (index < r->limbs && index < 2*NUM_LIMBS) { + r->data[i] = r->data[index]; + } else { + r->data[i] = 0; + } + } + } + while (r->limbs>1 && r->data[r->limbs-1]==0) { + r->limbs--; + } +} + +static void secp256k1_num_negate(secp256k1_num *r) { + r->neg ^= 1; +} + +#endif diff --git a/src/secp256k1/src/num_impl.h b/src/secp256k1/src/num_impl.h new file mode 100644 index 000000000..0b0e3a072 --- /dev/null +++ b/src/secp256k1/src/num_impl.h @@ -0,0 +1,24 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_NUM_IMPL_H_ +#define _SECP256K1_NUM_IMPL_H_ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include "num.h" + +#if defined(USE_NUM_GMP) +#include "num_gmp_impl.h" +#elif defined(USE_NUM_NONE) +/* Nothing. */ +#else +#error "Please select num implementation" +#endif + +#endif diff --git a/src/secp256k1/src/scalar.h b/src/secp256k1/src/scalar.h new file mode 100644 index 000000000..b590ccd6d --- /dev/null +++ b/src/secp256k1/src/scalar.h @@ -0,0 +1,104 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCALAR_ +#define _SECP256K1_SCALAR_ + +#include "num.h" + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#if defined(USE_SCALAR_4X64) +#include "scalar_4x64.h" +#elif defined(USE_SCALAR_8X32) +#include "scalar_8x32.h" +#else +#error "Please select scalar implementation" +#endif + +/** Clear a scalar to prevent the leak of sensitive data. */ +static void secp256k1_scalar_clear(secp256k1_scalar *r); + +/** Access bits from a scalar. All requested bits must belong to the same 32-bit limb. */ +static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count); + +/** Access bits from a scalar. Not constant time. */ +static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count); + +/** Set a scalar from a big endian byte array. */ +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *bin, int *overflow); + +/** Set a scalar to an unsigned integer. */ +static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v); + +/** Convert a scalar to a byte array. */ +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a); + +/** Add two scalars together (modulo the group order). Returns whether it overflowed. */ +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b); + +/** Conditionally add a power of two to a scalar. The result is not allowed to overflow. */ +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag); + +/** Multiply two scalars (modulo the group order). */ +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b); + +/** Shift a scalar right by some amount strictly between 0 and 16, returning + * the low bits that were shifted off */ +static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n); + +/** Compute the square of a scalar (modulo the group order). */ +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a); + +/** Compute the inverse of a scalar (modulo the group order). */ +static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *a); + +/** Compute the inverse of a scalar (modulo the group order), without constant-time guarantee. */ +static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *a); + +/** Compute the complement of a scalar (modulo the group order). */ +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a); + +/** Check whether a scalar equals zero. */ +static int secp256k1_scalar_is_zero(const secp256k1_scalar *a); + +/** Check whether a scalar equals one. */ +static int secp256k1_scalar_is_one(const secp256k1_scalar *a); + +/** Check whether a scalar, considered as an nonnegative integer, is even. */ +static int secp256k1_scalar_is_even(const secp256k1_scalar *a); + +/** Check whether a scalar is higher than the group order divided by 2. */ +static int secp256k1_scalar_is_high(const secp256k1_scalar *a); + +/** Conditionally negate a number, in constant time. + * Returns -1 if the number was negated, 1 otherwise */ +static int secp256k1_scalar_cond_negate(secp256k1_scalar *a, int flag); + +#ifndef USE_NUM_NONE +/** Convert a scalar to a number. */ +static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a); + +/** Get the order of the group as a number. */ +static void secp256k1_scalar_order_get_num(secp256k1_num *r); +#endif + +/** Compare two scalars. */ +static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b); + +#ifdef USE_ENDOMORPHISM +/** Find r1 and r2 such that r1+r2*2^128 = a. */ +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a); +/** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (see secp256k1_gej_mul_lambda). */ +static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a); +#endif + +/** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */ +static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift); + +#endif diff --git a/src/secp256k1/src/scalar_4x64.h b/src/secp256k1/src/scalar_4x64.h new file mode 100644 index 000000000..cff406038 --- /dev/null +++ b/src/secp256k1/src/scalar_4x64.h @@ -0,0 +1,19 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCALAR_REPR_ +#define _SECP256K1_SCALAR_REPR_ + +#include + +/** A scalar modulo the group order of the secp256k1 curve. */ +typedef struct { + uint64_t d[4]; +} secp256k1_scalar; + +#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{((uint64_t)(d1)) << 32 | (d0), ((uint64_t)(d3)) << 32 | (d2), ((uint64_t)(d5)) << 32 | (d4), ((uint64_t)(d7)) << 32 | (d6)}} + +#endif diff --git a/src/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h new file mode 100644 index 000000000..aa2703dd2 --- /dev/null +++ b/src/secp256k1/src/scalar_4x64_impl.h @@ -0,0 +1,949 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_ +#define _SECP256K1_SCALAR_REPR_IMPL_H_ + +/* Limbs of the secp256k1 order. */ +#define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL) +#define SECP256K1_N_1 ((uint64_t)0xBAAEDCE6AF48A03BULL) +#define SECP256K1_N_2 ((uint64_t)0xFFFFFFFFFFFFFFFEULL) +#define SECP256K1_N_3 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) + +/* Limbs of 2^256 minus the secp256k1 order. */ +#define SECP256K1_N_C_0 (~SECP256K1_N_0 + 1) +#define SECP256K1_N_C_1 (~SECP256K1_N_1) +#define SECP256K1_N_C_2 (1) + +/* Limbs of half the secp256k1 order. */ +#define SECP256K1_N_H_0 ((uint64_t)0xDFE92F46681B20A0ULL) +#define SECP256K1_N_H_1 ((uint64_t)0x5D576E7357A4501DULL) +#define SECP256K1_N_H_2 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) +#define SECP256K1_N_H_3 ((uint64_t)0x7FFFFFFFFFFFFFFFULL) + +SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { + r->d[0] = 0; + r->d[1] = 0; + r->d[2] = 0; + r->d[3] = 0; +} + +SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { + r->d[0] = v; + r->d[1] = 0; + r->d[2] = 0; + r->d[3] = 0; +} + +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6); + return (a->d[offset >> 6] >> (offset & 0x3F)) & ((((uint64_t)1) << count) - 1); +} + +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + VERIFY_CHECK(count < 32); + VERIFY_CHECK(offset + count <= 256); + if ((offset + count - 1) >> 6 == offset >> 6) { + return secp256k1_scalar_get_bits(a, offset, count); + } else { + VERIFY_CHECK((offset >> 6) + 1 < 4); + return ((a->d[offset >> 6] >> (offset & 0x3F)) | (a->d[(offset >> 6) + 1] << (64 - (offset & 0x3F)))) & ((((uint64_t)1) << count) - 1); + } +} + +SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { + int yes = 0; + int no = 0; + no |= (a->d[3] < SECP256K1_N_3); /* No need for a > check. */ + no |= (a->d[2] < SECP256K1_N_2); + yes |= (a->d[2] > SECP256K1_N_2) & ~no; + no |= (a->d[1] < SECP256K1_N_1); + yes |= (a->d[1] > SECP256K1_N_1) & ~no; + yes |= (a->d[0] >= SECP256K1_N_0) & ~no; + return yes; +} + +SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigned int overflow) { + uint128_t t; + VERIFY_CHECK(overflow <= 1); + t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0; + r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)r->d[1] + overflow * SECP256K1_N_C_1; + r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)r->d[2] + overflow * SECP256K1_N_C_2; + r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint64_t)r->d[3]; + r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; + return overflow; +} + +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + int overflow; + uint128_t t = (uint128_t)a->d[0] + b->d[0]; + r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)a->d[1] + b->d[1]; + r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)a->d[2] + b->d[2]; + r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)a->d[3] + b->d[3]; + r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + overflow = t + secp256k1_scalar_check_overflow(r); + VERIFY_CHECK(overflow == 0 || overflow == 1); + secp256k1_scalar_reduce(r, overflow); + return overflow; +} + +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { + uint128_t t; + VERIFY_CHECK(bit < 256); + bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */ + t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); + r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)r->d[1] + (((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F)); + r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)r->d[2] + (((uint64_t)((bit >> 6) == 2)) << (bit & 0x3F)); + r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)r->d[3] + (((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F)); + r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; +#ifdef VERIFY + VERIFY_CHECK((t >> 64) == 0); + VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); +#endif +} + +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { + int over; + r->d[0] = (uint64_t)b32[31] | (uint64_t)b32[30] << 8 | (uint64_t)b32[29] << 16 | (uint64_t)b32[28] << 24 | (uint64_t)b32[27] << 32 | (uint64_t)b32[26] << 40 | (uint64_t)b32[25] << 48 | (uint64_t)b32[24] << 56; + r->d[1] = (uint64_t)b32[23] | (uint64_t)b32[22] << 8 | (uint64_t)b32[21] << 16 | (uint64_t)b32[20] << 24 | (uint64_t)b32[19] << 32 | (uint64_t)b32[18] << 40 | (uint64_t)b32[17] << 48 | (uint64_t)b32[16] << 56; + r->d[2] = (uint64_t)b32[15] | (uint64_t)b32[14] << 8 | (uint64_t)b32[13] << 16 | (uint64_t)b32[12] << 24 | (uint64_t)b32[11] << 32 | (uint64_t)b32[10] << 40 | (uint64_t)b32[9] << 48 | (uint64_t)b32[8] << 56; + r->d[3] = (uint64_t)b32[7] | (uint64_t)b32[6] << 8 | (uint64_t)b32[5] << 16 | (uint64_t)b32[4] << 24 | (uint64_t)b32[3] << 32 | (uint64_t)b32[2] << 40 | (uint64_t)b32[1] << 48 | (uint64_t)b32[0] << 56; + over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r)); + if (overflow) { + *overflow = over; + } +} + +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { + bin[0] = a->d[3] >> 56; bin[1] = a->d[3] >> 48; bin[2] = a->d[3] >> 40; bin[3] = a->d[3] >> 32; bin[4] = a->d[3] >> 24; bin[5] = a->d[3] >> 16; bin[6] = a->d[3] >> 8; bin[7] = a->d[3]; + bin[8] = a->d[2] >> 56; bin[9] = a->d[2] >> 48; bin[10] = a->d[2] >> 40; bin[11] = a->d[2] >> 32; bin[12] = a->d[2] >> 24; bin[13] = a->d[2] >> 16; bin[14] = a->d[2] >> 8; bin[15] = a->d[2]; + bin[16] = a->d[1] >> 56; bin[17] = a->d[1] >> 48; bin[18] = a->d[1] >> 40; bin[19] = a->d[1] >> 32; bin[20] = a->d[1] >> 24; bin[21] = a->d[1] >> 16; bin[22] = a->d[1] >> 8; bin[23] = a->d[1]; + bin[24] = a->d[0] >> 56; bin[25] = a->d[0] >> 48; bin[26] = a->d[0] >> 40; bin[27] = a->d[0] >> 32; bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0]; +} + +SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { + return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0; +} + +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { + uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_scalar_is_zero(a) == 0); + uint128_t t = (uint128_t)(~a->d[0]) + SECP256K1_N_0 + 1; + r->d[0] = t & nonzero; t >>= 64; + t += (uint128_t)(~a->d[1]) + SECP256K1_N_1; + r->d[1] = t & nonzero; t >>= 64; + t += (uint128_t)(~a->d[2]) + SECP256K1_N_2; + r->d[2] = t & nonzero; t >>= 64; + t += (uint128_t)(~a->d[3]) + SECP256K1_N_3; + r->d[3] = t & nonzero; +} + +SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { + return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3]) == 0; +} + +static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { + int yes = 0; + int no = 0; + no |= (a->d[3] < SECP256K1_N_H_3); + yes |= (a->d[3] > SECP256K1_N_H_3) & ~no; + no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; /* No need for a > check. */ + no |= (a->d[1] < SECP256K1_N_H_1) & ~yes; + yes |= (a->d[1] > SECP256K1_N_H_1) & ~no; + yes |= (a->d[0] > SECP256K1_N_H_0) & ~no; + return yes; +} + +static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { + /* If we are flag = 0, mask = 00...00 and this is a no-op; + * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ + uint64_t mask = !flag - 1; + uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1; + uint128_t t = (uint128_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); + r->d[0] = t & nonzero; t >>= 64; + t += (uint128_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); + r->d[1] = t & nonzero; t >>= 64; + t += (uint128_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask); + r->d[2] = t & nonzero; t >>= 64; + t += (uint128_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask); + r->d[3] = t & nonzero; + return 2 * (mask == 0) - 1; +} + +/* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ + +/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd(a,b) { \ + uint64_t tl, th; \ + { \ + uint128_t t = (uint128_t)a * b; \ + th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = t; \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \ + c1 += th; /* overflow is handled on the next line */ \ + c2 += (c1 < th) ? 1 : 0; /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK((c1 >= th) || (c2 != 0)); \ +} + +/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */ +#define muladd_fast(a,b) { \ + uint64_t tl, th; \ + { \ + uint128_t t = (uint128_t)a * b; \ + th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = t; \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \ + c1 += th; /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK(c1 >= th); \ +} + +/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd2(a,b) { \ + uint64_t tl, th, th2, tl2; \ + { \ + uint128_t t = (uint128_t)a * b; \ + th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = t; \ + } \ + th2 = th + th; /* at most 0xFFFFFFFFFFFFFFFE (in case th was 0x7FFFFFFFFFFFFFFF) */ \ + c2 += (th2 < th) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((th2 >= th) || (c2 != 0)); \ + tl2 = tl + tl; /* at most 0xFFFFFFFFFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFFFFFFFFFF) */ \ + th2 += (tl2 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \ + c0 += tl2; /* overflow is handled on the next line */ \ + th2 += (c0 < tl2) ? 1 : 0; /* second overflow is handled on the next line */ \ + c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \ + c1 += th2; /* overflow is handled on the next line */ \ + c2 += (c1 < th2) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \ +} + +/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define sumadd(a) { \ + unsigned int over; \ + c0 += (a); /* overflow is handled on the next line */ \ + over = (c0 < (a)) ? 1 : 0; \ + c1 += over; /* overflow is handled on the next line */ \ + c2 += (c1 < over) ? 1 : 0; /* never overflows by contract */ \ +} + +/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */ +#define sumadd_fast(a) { \ + c0 += (a); /* overflow is handled on the next line */ \ + c1 += (c0 < (a)) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \ + VERIFY_CHECK(c2 == 0); \ +} + +/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. */ +#define extract(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = c2; \ + c2 = 0; \ +} + +/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. c2 is required to be zero. */ +#define extract_fast(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = 0; \ + VERIFY_CHECK(c2 == 0); \ +} + +static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) { +#ifdef USE_ASM_X86_64 + /* Reduce 512 bits into 385. */ + uint64_t m0, m1, m2, m3, m4, m5, m6; + uint64_t p0, p1, p2, p3, p4; + uint64_t c; + + __asm__ __volatile__( + /* Preload. */ + "movq 32(%%rsi), %%r11\n" + "movq 40(%%rsi), %%r12\n" + "movq 48(%%rsi), %%r13\n" + "movq 56(%%rsi), %%r14\n" + /* Initialize r8,r9,r10 */ + "movq 0(%%rsi), %%r8\n" + "movq $0, %%r9\n" + "movq $0, %%r10\n" + /* (r8,r9) += n0 * c0 */ + "movq %8, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* extract m0 */ + "movq %%r8, %q0\n" + "movq $0, %%r8\n" + /* (r9,r10) += l1 */ + "addq 8(%%rsi), %%r9\n" + "adcq $0, %%r10\n" + /* (r9,r10,r8) += n1 * c0 */ + "movq %8, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += n0 * c1 */ + "movq %9, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* extract m1 */ + "movq %%r9, %q1\n" + "movq $0, %%r9\n" + /* (r10,r8,r9) += l2 */ + "addq 16(%%rsi), %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += n2 * c0 */ + "movq %8, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += n1 * c1 */ + "movq %9, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += n0 */ + "addq %%r11, %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* extract m2 */ + "movq %%r10, %q2\n" + "movq $0, %%r10\n" + /* (r8,r9,r10) += l3 */ + "addq 24(%%rsi), %%r8\n" + "adcq $0, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += n3 * c0 */ + "movq %8, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += n2 * c1 */ + "movq %9, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += n1 */ + "addq %%r12, %%r8\n" + "adcq $0, %%r9\n" + "adcq $0, %%r10\n" + /* extract m3 */ + "movq %%r8, %q3\n" + "movq $0, %%r8\n" + /* (r9,r10,r8) += n3 * c1 */ + "movq %9, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += n2 */ + "addq %%r13, %%r9\n" + "adcq $0, %%r10\n" + "adcq $0, %%r8\n" + /* extract m4 */ + "movq %%r9, %q4\n" + /* (r10,r8) += n3 */ + "addq %%r14, %%r10\n" + "adcq $0, %%r8\n" + /* extract m5 */ + "movq %%r10, %q5\n" + /* extract m6 */ + "movq %%r8, %q6\n" + : "=g"(m0), "=g"(m1), "=g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6) + : "S"(l), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1) + : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc"); + + /* Reduce 385 bits into 258. */ + __asm__ __volatile__( + /* Preload */ + "movq %q9, %%r11\n" + "movq %q10, %%r12\n" + "movq %q11, %%r13\n" + /* Initialize (r8,r9,r10) */ + "movq %q5, %%r8\n" + "movq $0, %%r9\n" + "movq $0, %%r10\n" + /* (r8,r9) += m4 * c0 */ + "movq %12, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* extract p0 */ + "movq %%r8, %q0\n" + "movq $0, %%r8\n" + /* (r9,r10) += m1 */ + "addq %q6, %%r9\n" + "adcq $0, %%r10\n" + /* (r9,r10,r8) += m5 * c0 */ + "movq %12, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += m4 * c1 */ + "movq %13, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* extract p1 */ + "movq %%r9, %q1\n" + "movq $0, %%r9\n" + /* (r10,r8,r9) += m2 */ + "addq %q7, %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += m6 * c0 */ + "movq %12, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += m5 * c1 */ + "movq %13, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += m4 */ + "addq %%r11, %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* extract p2 */ + "movq %%r10, %q2\n" + /* (r8,r9) += m3 */ + "addq %q8, %%r8\n" + "adcq $0, %%r9\n" + /* (r8,r9) += m6 * c1 */ + "movq %13, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* (r8,r9) += m5 */ + "addq %%r12, %%r8\n" + "adcq $0, %%r9\n" + /* extract p3 */ + "movq %%r8, %q3\n" + /* (r9) += m6 */ + "addq %%r13, %%r9\n" + /* extract p4 */ + "movq %%r9, %q4\n" + : "=&g"(p0), "=&g"(p1), "=&g"(p2), "=g"(p3), "=g"(p4) + : "g"(m0), "g"(m1), "g"(m2), "g"(m3), "g"(m4), "g"(m5), "g"(m6), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1) + : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "cc"); + + /* Reduce 258 bits into 256. */ + __asm__ __volatile__( + /* Preload */ + "movq %q5, %%r10\n" + /* (rax,rdx) = p4 * c0 */ + "movq %7, %%rax\n" + "mulq %%r10\n" + /* (rax,rdx) += p0 */ + "addq %q1, %%rax\n" + "adcq $0, %%rdx\n" + /* extract r0 */ + "movq %%rax, 0(%q6)\n" + /* Move to (r8,r9) */ + "movq %%rdx, %%r8\n" + "movq $0, %%r9\n" + /* (r8,r9) += p1 */ + "addq %q2, %%r8\n" + "adcq $0, %%r9\n" + /* (r8,r9) += p4 * c1 */ + "movq %8, %%rax\n" + "mulq %%r10\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* Extract r1 */ + "movq %%r8, 8(%q6)\n" + "movq $0, %%r8\n" + /* (r9,r8) += p4 */ + "addq %%r10, %%r9\n" + "adcq $0, %%r8\n" + /* (r9,r8) += p2 */ + "addq %q3, %%r9\n" + "adcq $0, %%r8\n" + /* Extract r2 */ + "movq %%r9, 16(%q6)\n" + "movq $0, %%r9\n" + /* (r8,r9) += p3 */ + "addq %q4, %%r8\n" + "adcq $0, %%r9\n" + /* Extract r3 */ + "movq %%r8, 24(%q6)\n" + /* Extract c */ + "movq %%r9, %q0\n" + : "=g"(c) + : "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1) + : "rax", "rdx", "r8", "r9", "r10", "cc", "memory"); +#else + uint128_t c; + uint64_t c0, c1, c2; + uint64_t n0 = l[4], n1 = l[5], n2 = l[6], n3 = l[7]; + uint64_t m0, m1, m2, m3, m4, m5; + uint32_t m6; + uint64_t p0, p1, p2, p3; + uint32_t p4; + + /* Reduce 512 bits into 385. */ + /* m[0..6] = l[0..3] + n[0..3] * SECP256K1_N_C. */ + c0 = l[0]; c1 = 0; c2 = 0; + muladd_fast(n0, SECP256K1_N_C_0); + extract_fast(m0); + sumadd_fast(l[1]); + muladd(n1, SECP256K1_N_C_0); + muladd(n0, SECP256K1_N_C_1); + extract(m1); + sumadd(l[2]); + muladd(n2, SECP256K1_N_C_0); + muladd(n1, SECP256K1_N_C_1); + sumadd(n0); + extract(m2); + sumadd(l[3]); + muladd(n3, SECP256K1_N_C_0); + muladd(n2, SECP256K1_N_C_1); + sumadd(n1); + extract(m3); + muladd(n3, SECP256K1_N_C_1); + sumadd(n2); + extract(m4); + sumadd_fast(n3); + extract_fast(m5); + VERIFY_CHECK(c0 <= 1); + m6 = c0; + + /* Reduce 385 bits into 258. */ + /* p[0..4] = m[0..3] + m[4..6] * SECP256K1_N_C. */ + c0 = m0; c1 = 0; c2 = 0; + muladd_fast(m4, SECP256K1_N_C_0); + extract_fast(p0); + sumadd_fast(m1); + muladd(m5, SECP256K1_N_C_0); + muladd(m4, SECP256K1_N_C_1); + extract(p1); + sumadd(m2); + muladd(m6, SECP256K1_N_C_0); + muladd(m5, SECP256K1_N_C_1); + sumadd(m4); + extract(p2); + sumadd_fast(m3); + muladd_fast(m6, SECP256K1_N_C_1); + sumadd_fast(m5); + extract_fast(p3); + p4 = c0 + m6; + VERIFY_CHECK(p4 <= 2); + + /* Reduce 258 bits into 256. */ + /* r[0..3] = p[0..3] + p[4] * SECP256K1_N_C. */ + c = p0 + (uint128_t)SECP256K1_N_C_0 * p4; + r->d[0] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; + c += p1 + (uint128_t)SECP256K1_N_C_1 * p4; + r->d[1] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; + c += p2 + (uint128_t)p4; + r->d[2] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; + c += p3; + r->d[3] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; +#endif + + /* Final reduction of r. */ + secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); +} + +static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, const secp256k1_scalar *b) { +#ifdef USE_ASM_X86_64 + const uint64_t *pb = b->d; + __asm__ __volatile__( + /* Preload */ + "movq 0(%%rdi), %%r15\n" + "movq 8(%%rdi), %%rbx\n" + "movq 16(%%rdi), %%rcx\n" + "movq 0(%%rdx), %%r11\n" + "movq 8(%%rdx), %%r12\n" + "movq 16(%%rdx), %%r13\n" + "movq 24(%%rdx), %%r14\n" + /* (rax,rdx) = a0 * b0 */ + "movq %%r15, %%rax\n" + "mulq %%r11\n" + /* Extract l0 */ + "movq %%rax, 0(%%rsi)\n" + /* (r8,r9,r10) = (rdx) */ + "movq %%rdx, %%r8\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += a0 * b1 */ + "movq %%r15, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a1 * b0 */ + "movq %%rbx, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l1 */ + "movq %%r8, 8(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += a0 * b2 */ + "movq %%r15, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a1 * b1 */ + "movq %%rbx, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a2 * b0 */ + "movq %%rcx, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l2 */ + "movq %%r9, 16(%%rsi)\n" + "xorq %%r9, %%r9\n" + /* (r10,r8,r9) += a0 * b3 */ + "movq %%r15, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* Preload a3 */ + "movq 24(%%rdi), %%r15\n" + /* (r10,r8,r9) += a1 * b2 */ + "movq %%rbx, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += a2 * b1 */ + "movq %%rcx, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += a3 * b0 */ + "movq %%r15, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* Extract l3 */ + "movq %%r10, 24(%%rsi)\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += a1 * b3 */ + "movq %%rbx, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a2 * b2 */ + "movq %%rcx, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a3 * b1 */ + "movq %%r15, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l4 */ + "movq %%r8, 32(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += a2 * b3 */ + "movq %%rcx, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a3 * b2 */ + "movq %%r15, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l5 */ + "movq %%r9, 40(%%rsi)\n" + /* (r10,r8) += a3 * b3 */ + "movq %%r15, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + /* Extract l6 */ + "movq %%r10, 48(%%rsi)\n" + /* Extract l7 */ + "movq %%r8, 56(%%rsi)\n" + : "+d"(pb) + : "S"(l), "D"(a->d) + : "rax", "rbx", "rcx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "cc", "memory"); +#else + /* 160 bit accumulator. */ + uint64_t c0 = 0, c1 = 0; + uint32_t c2 = 0; + + /* l[0..7] = a[0..3] * b[0..3]. */ + muladd_fast(a->d[0], b->d[0]); + extract_fast(l[0]); + muladd(a->d[0], b->d[1]); + muladd(a->d[1], b->d[0]); + extract(l[1]); + muladd(a->d[0], b->d[2]); + muladd(a->d[1], b->d[1]); + muladd(a->d[2], b->d[0]); + extract(l[2]); + muladd(a->d[0], b->d[3]); + muladd(a->d[1], b->d[2]); + muladd(a->d[2], b->d[1]); + muladd(a->d[3], b->d[0]); + extract(l[3]); + muladd(a->d[1], b->d[3]); + muladd(a->d[2], b->d[2]); + muladd(a->d[3], b->d[1]); + extract(l[4]); + muladd(a->d[2], b->d[3]); + muladd(a->d[3], b->d[2]); + extract(l[5]); + muladd_fast(a->d[3], b->d[3]); + extract_fast(l[6]); + VERIFY_CHECK(c1 == 0); + l[7] = c0; +#endif +} + +static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar *a) { +#ifdef USE_ASM_X86_64 + __asm__ __volatile__( + /* Preload */ + "movq 0(%%rdi), %%r11\n" + "movq 8(%%rdi), %%r12\n" + "movq 16(%%rdi), %%r13\n" + "movq 24(%%rdi), %%r14\n" + /* (rax,rdx) = a0 * a0 */ + "movq %%r11, %%rax\n" + "mulq %%r11\n" + /* Extract l0 */ + "movq %%rax, 0(%%rsi)\n" + /* (r8,r9,r10) = (rdx,0) */ + "movq %%rdx, %%r8\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += 2 * a0 * a1 */ + "movq %%r11, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l1 */ + "movq %%r8, 8(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += 2 * a0 * a2 */ + "movq %%r11, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a1 * a1 */ + "movq %%r12, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l2 */ + "movq %%r9, 16(%%rsi)\n" + "xorq %%r9, %%r9\n" + /* (r10,r8,r9) += 2 * a0 * a3 */ + "movq %%r11, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += 2 * a1 * a2 */ + "movq %%r12, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* Extract l3 */ + "movq %%r10, 24(%%rsi)\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += 2 * a1 * a3 */ + "movq %%r12, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a2 * a2 */ + "movq %%r13, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l4 */ + "movq %%r8, 32(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += 2 * a2 * a3 */ + "movq %%r13, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l5 */ + "movq %%r9, 40(%%rsi)\n" + /* (r10,r8) += a3 * a3 */ + "movq %%r14, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + /* Extract l6 */ + "movq %%r10, 48(%%rsi)\n" + /* Extract l7 */ + "movq %%r8, 56(%%rsi)\n" + : + : "S"(l), "D"(a->d) + : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc", "memory"); +#else + /* 160 bit accumulator. */ + uint64_t c0 = 0, c1 = 0; + uint32_t c2 = 0; + + /* l[0..7] = a[0..3] * b[0..3]. */ + muladd_fast(a->d[0], a->d[0]); + extract_fast(l[0]); + muladd2(a->d[0], a->d[1]); + extract(l[1]); + muladd2(a->d[0], a->d[2]); + muladd(a->d[1], a->d[1]); + extract(l[2]); + muladd2(a->d[0], a->d[3]); + muladd2(a->d[1], a->d[2]); + extract(l[3]); + muladd2(a->d[1], a->d[3]); + muladd(a->d[2], a->d[2]); + extract(l[4]); + muladd2(a->d[2], a->d[3]); + extract(l[5]); + muladd_fast(a->d[3], a->d[3]); + extract_fast(l[6]); + VERIFY_CHECK(c1 == 0); + l[7] = c0; +#endif +} + +#undef sumadd +#undef sumadd_fast +#undef muladd +#undef muladd_fast +#undef muladd2 +#undef extract +#undef extract_fast + +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + uint64_t l[8]; + secp256k1_scalar_mul_512(l, a, b); + secp256k1_scalar_reduce_512(r, l); +} + +static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { + int ret; + VERIFY_CHECK(n > 0); + VERIFY_CHECK(n < 16); + ret = r->d[0] & ((1 << n) - 1); + r->d[0] = (r->d[0] >> n) + (r->d[1] << (64 - n)); + r->d[1] = (r->d[1] >> n) + (r->d[2] << (64 - n)); + r->d[2] = (r->d[2] >> n) + (r->d[3] << (64 - n)); + r->d[3] = (r->d[3] >> n); + return ret; +} + +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { + uint64_t l[8]; + secp256k1_scalar_sqr_512(l, a); + secp256k1_scalar_reduce_512(r, l); +} + +#ifdef USE_ENDOMORPHISM +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { + r1->d[0] = a->d[0]; + r1->d[1] = a->d[1]; + r1->d[2] = 0; + r1->d[3] = 0; + r2->d[0] = a->d[2]; + r2->d[1] = a->d[3]; + r2->d[2] = 0; + r2->d[3] = 0; +} +#endif + +SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { + return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0; +} + +SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift) { + uint64_t l[8]; + unsigned int shiftlimbs; + unsigned int shiftlow; + unsigned int shifthigh; + VERIFY_CHECK(shift >= 256); + secp256k1_scalar_mul_512(l, a, b); + shiftlimbs = shift >> 6; + shiftlow = shift & 0x3F; + shifthigh = 64 - shiftlow; + r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[1] = shift < 448 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0; + secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1); +} + +#endif diff --git a/src/secp256k1/src/scalar_8x32.h b/src/secp256k1/src/scalar_8x32.h new file mode 100644 index 000000000..1319664f6 --- /dev/null +++ b/src/secp256k1/src/scalar_8x32.h @@ -0,0 +1,19 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCALAR_REPR_ +#define _SECP256K1_SCALAR_REPR_ + +#include + +/** A scalar modulo the group order of the secp256k1 curve. */ +typedef struct { + uint32_t d[8]; +} secp256k1_scalar; + +#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}} + +#endif diff --git a/src/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h new file mode 100644 index 000000000..aae4f35c0 --- /dev/null +++ b/src/secp256k1/src/scalar_8x32_impl.h @@ -0,0 +1,721 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_ +#define _SECP256K1_SCALAR_REPR_IMPL_H_ + +/* Limbs of the secp256k1 order. */ +#define SECP256K1_N_0 ((uint32_t)0xD0364141UL) +#define SECP256K1_N_1 ((uint32_t)0xBFD25E8CUL) +#define SECP256K1_N_2 ((uint32_t)0xAF48A03BUL) +#define SECP256K1_N_3 ((uint32_t)0xBAAEDCE6UL) +#define SECP256K1_N_4 ((uint32_t)0xFFFFFFFEUL) +#define SECP256K1_N_5 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_6 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_7 ((uint32_t)0xFFFFFFFFUL) + +/* Limbs of 2^256 minus the secp256k1 order. */ +#define SECP256K1_N_C_0 (~SECP256K1_N_0 + 1) +#define SECP256K1_N_C_1 (~SECP256K1_N_1) +#define SECP256K1_N_C_2 (~SECP256K1_N_2) +#define SECP256K1_N_C_3 (~SECP256K1_N_3) +#define SECP256K1_N_C_4 (1) + +/* Limbs of half the secp256k1 order. */ +#define SECP256K1_N_H_0 ((uint32_t)0x681B20A0UL) +#define SECP256K1_N_H_1 ((uint32_t)0xDFE92F46UL) +#define SECP256K1_N_H_2 ((uint32_t)0x57A4501DUL) +#define SECP256K1_N_H_3 ((uint32_t)0x5D576E73UL) +#define SECP256K1_N_H_4 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_H_5 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_H_6 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_H_7 ((uint32_t)0x7FFFFFFFUL) + +SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { + r->d[0] = 0; + r->d[1] = 0; + r->d[2] = 0; + r->d[3] = 0; + r->d[4] = 0; + r->d[5] = 0; + r->d[6] = 0; + r->d[7] = 0; +} + +SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { + r->d[0] = v; + r->d[1] = 0; + r->d[2] = 0; + r->d[3] = 0; + r->d[4] = 0; + r->d[5] = 0; + r->d[6] = 0; + r->d[7] = 0; +} + +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5); + return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1); +} + +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + VERIFY_CHECK(count < 32); + VERIFY_CHECK(offset + count <= 256); + if ((offset + count - 1) >> 5 == offset >> 5) { + return secp256k1_scalar_get_bits(a, offset, count); + } else { + VERIFY_CHECK((offset >> 5) + 1 < 8); + return ((a->d[offset >> 5] >> (offset & 0x1F)) | (a->d[(offset >> 5) + 1] << (32 - (offset & 0x1F)))) & ((((uint32_t)1) << count) - 1); + } +} + +SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { + int yes = 0; + int no = 0; + no |= (a->d[7] < SECP256K1_N_7); /* No need for a > check. */ + no |= (a->d[6] < SECP256K1_N_6); /* No need for a > check. */ + no |= (a->d[5] < SECP256K1_N_5); /* No need for a > check. */ + no |= (a->d[4] < SECP256K1_N_4); + yes |= (a->d[4] > SECP256K1_N_4) & ~no; + no |= (a->d[3] < SECP256K1_N_3) & ~yes; + yes |= (a->d[3] > SECP256K1_N_3) & ~no; + no |= (a->d[2] < SECP256K1_N_2) & ~yes; + yes |= (a->d[2] > SECP256K1_N_2) & ~no; + no |= (a->d[1] < SECP256K1_N_1) & ~yes; + yes |= (a->d[1] > SECP256K1_N_1) & ~no; + yes |= (a->d[0] >= SECP256K1_N_0) & ~no; + return yes; +} + +SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, uint32_t overflow) { + uint64_t t; + VERIFY_CHECK(overflow <= 1); + t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0; + r->d[0] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[1] + overflow * SECP256K1_N_C_1; + r->d[1] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[2] + overflow * SECP256K1_N_C_2; + r->d[2] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[3] + overflow * SECP256K1_N_C_3; + r->d[3] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[4] + overflow * SECP256K1_N_C_4; + r->d[4] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[5]; + r->d[5] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[6]; + r->d[6] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[7]; + r->d[7] = t & 0xFFFFFFFFUL; + return overflow; +} + +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + int overflow; + uint64_t t = (uint64_t)a->d[0] + b->d[0]; + r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[1] + b->d[1]; + r->d[1] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[2] + b->d[2]; + r->d[2] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[3] + b->d[3]; + r->d[3] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[4] + b->d[4]; + r->d[4] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[5] + b->d[5]; + r->d[5] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[6] + b->d[6]; + r->d[6] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[7] + b->d[7]; + r->d[7] = t & 0xFFFFFFFFULL; t >>= 32; + overflow = t + secp256k1_scalar_check_overflow(r); + VERIFY_CHECK(overflow == 0 || overflow == 1); + secp256k1_scalar_reduce(r, overflow); + return overflow; +} + +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { + uint64_t t; + VERIFY_CHECK(bit < 256); + bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */ + t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F)); + r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F)); + r->d[1] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[2] + (((uint32_t)((bit >> 5) == 2)) << (bit & 0x1F)); + r->d[2] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[3] + (((uint32_t)((bit >> 5) == 3)) << (bit & 0x1F)); + r->d[3] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[4] + (((uint32_t)((bit >> 5) == 4)) << (bit & 0x1F)); + r->d[4] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[5] + (((uint32_t)((bit >> 5) == 5)) << (bit & 0x1F)); + r->d[5] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[6] + (((uint32_t)((bit >> 5) == 6)) << (bit & 0x1F)); + r->d[6] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[7] + (((uint32_t)((bit >> 5) == 7)) << (bit & 0x1F)); + r->d[7] = t & 0xFFFFFFFFULL; +#ifdef VERIFY + VERIFY_CHECK((t >> 32) == 0); + VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); +#endif +} + +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { + int over; + r->d[0] = (uint32_t)b32[31] | (uint32_t)b32[30] << 8 | (uint32_t)b32[29] << 16 | (uint32_t)b32[28] << 24; + r->d[1] = (uint32_t)b32[27] | (uint32_t)b32[26] << 8 | (uint32_t)b32[25] << 16 | (uint32_t)b32[24] << 24; + r->d[2] = (uint32_t)b32[23] | (uint32_t)b32[22] << 8 | (uint32_t)b32[21] << 16 | (uint32_t)b32[20] << 24; + r->d[3] = (uint32_t)b32[19] | (uint32_t)b32[18] << 8 | (uint32_t)b32[17] << 16 | (uint32_t)b32[16] << 24; + r->d[4] = (uint32_t)b32[15] | (uint32_t)b32[14] << 8 | (uint32_t)b32[13] << 16 | (uint32_t)b32[12] << 24; + r->d[5] = (uint32_t)b32[11] | (uint32_t)b32[10] << 8 | (uint32_t)b32[9] << 16 | (uint32_t)b32[8] << 24; + r->d[6] = (uint32_t)b32[7] | (uint32_t)b32[6] << 8 | (uint32_t)b32[5] << 16 | (uint32_t)b32[4] << 24; + r->d[7] = (uint32_t)b32[3] | (uint32_t)b32[2] << 8 | (uint32_t)b32[1] << 16 | (uint32_t)b32[0] << 24; + over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r)); + if (overflow) { + *overflow = over; + } +} + +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { + bin[0] = a->d[7] >> 24; bin[1] = a->d[7] >> 16; bin[2] = a->d[7] >> 8; bin[3] = a->d[7]; + bin[4] = a->d[6] >> 24; bin[5] = a->d[6] >> 16; bin[6] = a->d[6] >> 8; bin[7] = a->d[6]; + bin[8] = a->d[5] >> 24; bin[9] = a->d[5] >> 16; bin[10] = a->d[5] >> 8; bin[11] = a->d[5]; + bin[12] = a->d[4] >> 24; bin[13] = a->d[4] >> 16; bin[14] = a->d[4] >> 8; bin[15] = a->d[4]; + bin[16] = a->d[3] >> 24; bin[17] = a->d[3] >> 16; bin[18] = a->d[3] >> 8; bin[19] = a->d[3]; + bin[20] = a->d[2] >> 24; bin[21] = a->d[2] >> 16; bin[22] = a->d[2] >> 8; bin[23] = a->d[2]; + bin[24] = a->d[1] >> 24; bin[25] = a->d[1] >> 16; bin[26] = a->d[1] >> 8; bin[27] = a->d[1]; + bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0]; +} + +SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { + return (a->d[0] | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; +} + +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { + uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(a) == 0); + uint64_t t = (uint64_t)(~a->d[0]) + SECP256K1_N_0 + 1; + r->d[0] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[1]) + SECP256K1_N_1; + r->d[1] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[2]) + SECP256K1_N_2; + r->d[2] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[3]) + SECP256K1_N_3; + r->d[3] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[4]) + SECP256K1_N_4; + r->d[4] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[5]) + SECP256K1_N_5; + r->d[5] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[6]) + SECP256K1_N_6; + r->d[6] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[7]) + SECP256K1_N_7; + r->d[7] = t & nonzero; +} + +SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { + return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; +} + +static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { + int yes = 0; + int no = 0; + no |= (a->d[7] < SECP256K1_N_H_7); + yes |= (a->d[7] > SECP256K1_N_H_7) & ~no; + no |= (a->d[6] < SECP256K1_N_H_6) & ~yes; /* No need for a > check. */ + no |= (a->d[5] < SECP256K1_N_H_5) & ~yes; /* No need for a > check. */ + no |= (a->d[4] < SECP256K1_N_H_4) & ~yes; /* No need for a > check. */ + no |= (a->d[3] < SECP256K1_N_H_3) & ~yes; + yes |= (a->d[3] > SECP256K1_N_H_3) & ~no; + no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; + yes |= (a->d[2] > SECP256K1_N_H_2) & ~no; + no |= (a->d[1] < SECP256K1_N_H_1) & ~yes; + yes |= (a->d[1] > SECP256K1_N_H_1) & ~no; + yes |= (a->d[0] > SECP256K1_N_H_0) & ~no; + return yes; +} + +static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { + /* If we are flag = 0, mask = 00...00 and this is a no-op; + * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ + uint32_t mask = !flag - 1; + uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0); + uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); + r->d[0] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); + r->d[1] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask); + r->d[2] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask); + r->d[3] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[4] ^ mask) + (SECP256K1_N_4 & mask); + r->d[4] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[5] ^ mask) + (SECP256K1_N_5 & mask); + r->d[5] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[6] ^ mask) + (SECP256K1_N_6 & mask); + r->d[6] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[7] ^ mask) + (SECP256K1_N_7 & mask); + r->d[7] = t & nonzero; + return 2 * (mask == 0) - 1; +} + + +/* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ + +/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd(a,b) { \ + uint32_t tl, th; \ + { \ + uint64_t t = (uint64_t)a * b; \ + th = t >> 32; /* at most 0xFFFFFFFE */ \ + tl = t; \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \ + c1 += th; /* overflow is handled on the next line */ \ + c2 += (c1 < th) ? 1 : 0; /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK((c1 >= th) || (c2 != 0)); \ +} + +/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */ +#define muladd_fast(a,b) { \ + uint32_t tl, th; \ + { \ + uint64_t t = (uint64_t)a * b; \ + th = t >> 32; /* at most 0xFFFFFFFE */ \ + tl = t; \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \ + c1 += th; /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK(c1 >= th); \ +} + +/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd2(a,b) { \ + uint32_t tl, th, th2, tl2; \ + { \ + uint64_t t = (uint64_t)a * b; \ + th = t >> 32; /* at most 0xFFFFFFFE */ \ + tl = t; \ + } \ + th2 = th + th; /* at most 0xFFFFFFFE (in case th was 0x7FFFFFFF) */ \ + c2 += (th2 < th) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((th2 >= th) || (c2 != 0)); \ + tl2 = tl + tl; /* at most 0xFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFF) */ \ + th2 += (tl2 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \ + c0 += tl2; /* overflow is handled on the next line */ \ + th2 += (c0 < tl2) ? 1 : 0; /* second overflow is handled on the next line */ \ + c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \ + c1 += th2; /* overflow is handled on the next line */ \ + c2 += (c1 < th2) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \ +} + +/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define sumadd(a) { \ + unsigned int over; \ + c0 += (a); /* overflow is handled on the next line */ \ + over = (c0 < (a)) ? 1 : 0; \ + c1 += over; /* overflow is handled on the next line */ \ + c2 += (c1 < over) ? 1 : 0; /* never overflows by contract */ \ +} + +/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */ +#define sumadd_fast(a) { \ + c0 += (a); /* overflow is handled on the next line */ \ + c1 += (c0 < (a)) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \ + VERIFY_CHECK(c2 == 0); \ +} + +/** Extract the lowest 32 bits of (c0,c1,c2) into n, and left shift the number 32 bits. */ +#define extract(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = c2; \ + c2 = 0; \ +} + +/** Extract the lowest 32 bits of (c0,c1,c2) into n, and left shift the number 32 bits. c2 is required to be zero. */ +#define extract_fast(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = 0; \ + VERIFY_CHECK(c2 == 0); \ +} + +static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint32_t *l) { + uint64_t c; + uint32_t n0 = l[8], n1 = l[9], n2 = l[10], n3 = l[11], n4 = l[12], n5 = l[13], n6 = l[14], n7 = l[15]; + uint32_t m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12; + uint32_t p0, p1, p2, p3, p4, p5, p6, p7, p8; + + /* 96 bit accumulator. */ + uint32_t c0, c1, c2; + + /* Reduce 512 bits into 385. */ + /* m[0..12] = l[0..7] + n[0..7] * SECP256K1_N_C. */ + c0 = l[0]; c1 = 0; c2 = 0; + muladd_fast(n0, SECP256K1_N_C_0); + extract_fast(m0); + sumadd_fast(l[1]); + muladd(n1, SECP256K1_N_C_0); + muladd(n0, SECP256K1_N_C_1); + extract(m1); + sumadd(l[2]); + muladd(n2, SECP256K1_N_C_0); + muladd(n1, SECP256K1_N_C_1); + muladd(n0, SECP256K1_N_C_2); + extract(m2); + sumadd(l[3]); + muladd(n3, SECP256K1_N_C_0); + muladd(n2, SECP256K1_N_C_1); + muladd(n1, SECP256K1_N_C_2); + muladd(n0, SECP256K1_N_C_3); + extract(m3); + sumadd(l[4]); + muladd(n4, SECP256K1_N_C_0); + muladd(n3, SECP256K1_N_C_1); + muladd(n2, SECP256K1_N_C_2); + muladd(n1, SECP256K1_N_C_3); + sumadd(n0); + extract(m4); + sumadd(l[5]); + muladd(n5, SECP256K1_N_C_0); + muladd(n4, SECP256K1_N_C_1); + muladd(n3, SECP256K1_N_C_2); + muladd(n2, SECP256K1_N_C_3); + sumadd(n1); + extract(m5); + sumadd(l[6]); + muladd(n6, SECP256K1_N_C_0); + muladd(n5, SECP256K1_N_C_1); + muladd(n4, SECP256K1_N_C_2); + muladd(n3, SECP256K1_N_C_3); + sumadd(n2); + extract(m6); + sumadd(l[7]); + muladd(n7, SECP256K1_N_C_0); + muladd(n6, SECP256K1_N_C_1); + muladd(n5, SECP256K1_N_C_2); + muladd(n4, SECP256K1_N_C_3); + sumadd(n3); + extract(m7); + muladd(n7, SECP256K1_N_C_1); + muladd(n6, SECP256K1_N_C_2); + muladd(n5, SECP256K1_N_C_3); + sumadd(n4); + extract(m8); + muladd(n7, SECP256K1_N_C_2); + muladd(n6, SECP256K1_N_C_3); + sumadd(n5); + extract(m9); + muladd(n7, SECP256K1_N_C_3); + sumadd(n6); + extract(m10); + sumadd_fast(n7); + extract_fast(m11); + VERIFY_CHECK(c0 <= 1); + m12 = c0; + + /* Reduce 385 bits into 258. */ + /* p[0..8] = m[0..7] + m[8..12] * SECP256K1_N_C. */ + c0 = m0; c1 = 0; c2 = 0; + muladd_fast(m8, SECP256K1_N_C_0); + extract_fast(p0); + sumadd_fast(m1); + muladd(m9, SECP256K1_N_C_0); + muladd(m8, SECP256K1_N_C_1); + extract(p1); + sumadd(m2); + muladd(m10, SECP256K1_N_C_0); + muladd(m9, SECP256K1_N_C_1); + muladd(m8, SECP256K1_N_C_2); + extract(p2); + sumadd(m3); + muladd(m11, SECP256K1_N_C_0); + muladd(m10, SECP256K1_N_C_1); + muladd(m9, SECP256K1_N_C_2); + muladd(m8, SECP256K1_N_C_3); + extract(p3); + sumadd(m4); + muladd(m12, SECP256K1_N_C_0); + muladd(m11, SECP256K1_N_C_1); + muladd(m10, SECP256K1_N_C_2); + muladd(m9, SECP256K1_N_C_3); + sumadd(m8); + extract(p4); + sumadd(m5); + muladd(m12, SECP256K1_N_C_1); + muladd(m11, SECP256K1_N_C_2); + muladd(m10, SECP256K1_N_C_3); + sumadd(m9); + extract(p5); + sumadd(m6); + muladd(m12, SECP256K1_N_C_2); + muladd(m11, SECP256K1_N_C_3); + sumadd(m10); + extract(p6); + sumadd_fast(m7); + muladd_fast(m12, SECP256K1_N_C_3); + sumadd_fast(m11); + extract_fast(p7); + p8 = c0 + m12; + VERIFY_CHECK(p8 <= 2); + + /* Reduce 258 bits into 256. */ + /* r[0..7] = p[0..7] + p[8] * SECP256K1_N_C. */ + c = p0 + (uint64_t)SECP256K1_N_C_0 * p8; + r->d[0] = c & 0xFFFFFFFFUL; c >>= 32; + c += p1 + (uint64_t)SECP256K1_N_C_1 * p8; + r->d[1] = c & 0xFFFFFFFFUL; c >>= 32; + c += p2 + (uint64_t)SECP256K1_N_C_2 * p8; + r->d[2] = c & 0xFFFFFFFFUL; c >>= 32; + c += p3 + (uint64_t)SECP256K1_N_C_3 * p8; + r->d[3] = c & 0xFFFFFFFFUL; c >>= 32; + c += p4 + (uint64_t)p8; + r->d[4] = c & 0xFFFFFFFFUL; c >>= 32; + c += p5; + r->d[5] = c & 0xFFFFFFFFUL; c >>= 32; + c += p6; + r->d[6] = c & 0xFFFFFFFFUL; c >>= 32; + c += p7; + r->d[7] = c & 0xFFFFFFFFUL; c >>= 32; + + /* Final reduction of r. */ + secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); +} + +static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar *a, const secp256k1_scalar *b) { + /* 96 bit accumulator. */ + uint32_t c0 = 0, c1 = 0, c2 = 0; + + /* l[0..15] = a[0..7] * b[0..7]. */ + muladd_fast(a->d[0], b->d[0]); + extract_fast(l[0]); + muladd(a->d[0], b->d[1]); + muladd(a->d[1], b->d[0]); + extract(l[1]); + muladd(a->d[0], b->d[2]); + muladd(a->d[1], b->d[1]); + muladd(a->d[2], b->d[0]); + extract(l[2]); + muladd(a->d[0], b->d[3]); + muladd(a->d[1], b->d[2]); + muladd(a->d[2], b->d[1]); + muladd(a->d[3], b->d[0]); + extract(l[3]); + muladd(a->d[0], b->d[4]); + muladd(a->d[1], b->d[3]); + muladd(a->d[2], b->d[2]); + muladd(a->d[3], b->d[1]); + muladd(a->d[4], b->d[0]); + extract(l[4]); + muladd(a->d[0], b->d[5]); + muladd(a->d[1], b->d[4]); + muladd(a->d[2], b->d[3]); + muladd(a->d[3], b->d[2]); + muladd(a->d[4], b->d[1]); + muladd(a->d[5], b->d[0]); + extract(l[5]); + muladd(a->d[0], b->d[6]); + muladd(a->d[1], b->d[5]); + muladd(a->d[2], b->d[4]); + muladd(a->d[3], b->d[3]); + muladd(a->d[4], b->d[2]); + muladd(a->d[5], b->d[1]); + muladd(a->d[6], b->d[0]); + extract(l[6]); + muladd(a->d[0], b->d[7]); + muladd(a->d[1], b->d[6]); + muladd(a->d[2], b->d[5]); + muladd(a->d[3], b->d[4]); + muladd(a->d[4], b->d[3]); + muladd(a->d[5], b->d[2]); + muladd(a->d[6], b->d[1]); + muladd(a->d[7], b->d[0]); + extract(l[7]); + muladd(a->d[1], b->d[7]); + muladd(a->d[2], b->d[6]); + muladd(a->d[3], b->d[5]); + muladd(a->d[4], b->d[4]); + muladd(a->d[5], b->d[3]); + muladd(a->d[6], b->d[2]); + muladd(a->d[7], b->d[1]); + extract(l[8]); + muladd(a->d[2], b->d[7]); + muladd(a->d[3], b->d[6]); + muladd(a->d[4], b->d[5]); + muladd(a->d[5], b->d[4]); + muladd(a->d[6], b->d[3]); + muladd(a->d[7], b->d[2]); + extract(l[9]); + muladd(a->d[3], b->d[7]); + muladd(a->d[4], b->d[6]); + muladd(a->d[5], b->d[5]); + muladd(a->d[6], b->d[4]); + muladd(a->d[7], b->d[3]); + extract(l[10]); + muladd(a->d[4], b->d[7]); + muladd(a->d[5], b->d[6]); + muladd(a->d[6], b->d[5]); + muladd(a->d[7], b->d[4]); + extract(l[11]); + muladd(a->d[5], b->d[7]); + muladd(a->d[6], b->d[6]); + muladd(a->d[7], b->d[5]); + extract(l[12]); + muladd(a->d[6], b->d[7]); + muladd(a->d[7], b->d[6]); + extract(l[13]); + muladd_fast(a->d[7], b->d[7]); + extract_fast(l[14]); + VERIFY_CHECK(c1 == 0); + l[15] = c0; +} + +static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar *a) { + /* 96 bit accumulator. */ + uint32_t c0 = 0, c1 = 0, c2 = 0; + + /* l[0..15] = a[0..7]^2. */ + muladd_fast(a->d[0], a->d[0]); + extract_fast(l[0]); + muladd2(a->d[0], a->d[1]); + extract(l[1]); + muladd2(a->d[0], a->d[2]); + muladd(a->d[1], a->d[1]); + extract(l[2]); + muladd2(a->d[0], a->d[3]); + muladd2(a->d[1], a->d[2]); + extract(l[3]); + muladd2(a->d[0], a->d[4]); + muladd2(a->d[1], a->d[3]); + muladd(a->d[2], a->d[2]); + extract(l[4]); + muladd2(a->d[0], a->d[5]); + muladd2(a->d[1], a->d[4]); + muladd2(a->d[2], a->d[3]); + extract(l[5]); + muladd2(a->d[0], a->d[6]); + muladd2(a->d[1], a->d[5]); + muladd2(a->d[2], a->d[4]); + muladd(a->d[3], a->d[3]); + extract(l[6]); + muladd2(a->d[0], a->d[7]); + muladd2(a->d[1], a->d[6]); + muladd2(a->d[2], a->d[5]); + muladd2(a->d[3], a->d[4]); + extract(l[7]); + muladd2(a->d[1], a->d[7]); + muladd2(a->d[2], a->d[6]); + muladd2(a->d[3], a->d[5]); + muladd(a->d[4], a->d[4]); + extract(l[8]); + muladd2(a->d[2], a->d[7]); + muladd2(a->d[3], a->d[6]); + muladd2(a->d[4], a->d[5]); + extract(l[9]); + muladd2(a->d[3], a->d[7]); + muladd2(a->d[4], a->d[6]); + muladd(a->d[5], a->d[5]); + extract(l[10]); + muladd2(a->d[4], a->d[7]); + muladd2(a->d[5], a->d[6]); + extract(l[11]); + muladd2(a->d[5], a->d[7]); + muladd(a->d[6], a->d[6]); + extract(l[12]); + muladd2(a->d[6], a->d[7]); + extract(l[13]); + muladd_fast(a->d[7], a->d[7]); + extract_fast(l[14]); + VERIFY_CHECK(c1 == 0); + l[15] = c0; +} + +#undef sumadd +#undef sumadd_fast +#undef muladd +#undef muladd_fast +#undef muladd2 +#undef extract +#undef extract_fast + +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + uint32_t l[16]; + secp256k1_scalar_mul_512(l, a, b); + secp256k1_scalar_reduce_512(r, l); +} + +static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { + int ret; + VERIFY_CHECK(n > 0); + VERIFY_CHECK(n < 16); + ret = r->d[0] & ((1 << n) - 1); + r->d[0] = (r->d[0] >> n) + (r->d[1] << (32 - n)); + r->d[1] = (r->d[1] >> n) + (r->d[2] << (32 - n)); + r->d[2] = (r->d[2] >> n) + (r->d[3] << (32 - n)); + r->d[3] = (r->d[3] >> n) + (r->d[4] << (32 - n)); + r->d[4] = (r->d[4] >> n) + (r->d[5] << (32 - n)); + r->d[5] = (r->d[5] >> n) + (r->d[6] << (32 - n)); + r->d[6] = (r->d[6] >> n) + (r->d[7] << (32 - n)); + r->d[7] = (r->d[7] >> n); + return ret; +} + +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { + uint32_t l[16]; + secp256k1_scalar_sqr_512(l, a); + secp256k1_scalar_reduce_512(r, l); +} + +#ifdef USE_ENDOMORPHISM +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { + r1->d[0] = a->d[0]; + r1->d[1] = a->d[1]; + r1->d[2] = a->d[2]; + r1->d[3] = a->d[3]; + r1->d[4] = 0; + r1->d[5] = 0; + r1->d[6] = 0; + r1->d[7] = 0; + r2->d[0] = a->d[4]; + r2->d[1] = a->d[5]; + r2->d[2] = a->d[6]; + r2->d[3] = a->d[7]; + r2->d[4] = 0; + r2->d[5] = 0; + r2->d[6] = 0; + r2->d[7] = 0; +} +#endif + +SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { + return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0; +} + +SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift) { + uint32_t l[16]; + unsigned int shiftlimbs; + unsigned int shiftlow; + unsigned int shifthigh; + VERIFY_CHECK(shift >= 256); + secp256k1_scalar_mul_512(l, a, b); + shiftlimbs = shift >> 5; + shiftlow = shift & 0x1F; + shifthigh = 32 - shiftlow; + r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 480 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[1] = shift < 480 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[2] = shift < 448 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 416 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[3] = shift < 416 ? (l[3 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[4 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[4] = shift < 384 ? (l[4 + shiftlimbs] >> shiftlow | (shift < 352 && shiftlow ? (l[5 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[5] = shift < 352 ? (l[5 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[6 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[6] = shift < 320 ? (l[6 + shiftlimbs] >> shiftlow | (shift < 288 && shiftlow ? (l[7 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow) : 0; + secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1); +} + +#endif diff --git a/src/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h new file mode 100644 index 000000000..c5baf4df4 --- /dev/null +++ b/src/secp256k1/src/scalar_impl.h @@ -0,0 +1,335 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCALAR_IMPL_H_ +#define _SECP256K1_SCALAR_IMPL_H_ + +#include "group.h" +#include "scalar.h" + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#if defined(USE_SCALAR_4X64) +#include "scalar_4x64_impl.h" +#elif defined(USE_SCALAR_8X32) +#include "scalar_8x32_impl.h" +#else +#error "Please select scalar implementation" +#endif + +#ifndef USE_NUM_NONE +static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a) { + unsigned char c[32]; + secp256k1_scalar_get_b32(c, a); + secp256k1_num_set_bin(r, c, 32); +} + +/** secp256k1 curve order, see secp256k1_ecdsa_const_order_as_fe in ecdsa_impl.h */ +static void secp256k1_scalar_order_get_num(secp256k1_num *r) { + static const unsigned char order[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, + 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, + 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41 + }; + secp256k1_num_set_bin(r, order, 32); +} +#endif + +static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) { + secp256k1_scalar *t; + int i; + /* First compute x ^ (2^N - 1) for some values of N. */ + secp256k1_scalar x2, x3, x4, x6, x7, x8, x15, x30, x60, x120, x127; + + secp256k1_scalar_sqr(&x2, x); + secp256k1_scalar_mul(&x2, &x2, x); + + secp256k1_scalar_sqr(&x3, &x2); + secp256k1_scalar_mul(&x3, &x3, x); + + secp256k1_scalar_sqr(&x4, &x3); + secp256k1_scalar_mul(&x4, &x4, x); + + secp256k1_scalar_sqr(&x6, &x4); + secp256k1_scalar_sqr(&x6, &x6); + secp256k1_scalar_mul(&x6, &x6, &x2); + + secp256k1_scalar_sqr(&x7, &x6); + secp256k1_scalar_mul(&x7, &x7, x); + + secp256k1_scalar_sqr(&x8, &x7); + secp256k1_scalar_mul(&x8, &x8, x); + + secp256k1_scalar_sqr(&x15, &x8); + for (i = 0; i < 6; i++) { + secp256k1_scalar_sqr(&x15, &x15); + } + secp256k1_scalar_mul(&x15, &x15, &x7); + + secp256k1_scalar_sqr(&x30, &x15); + for (i = 0; i < 14; i++) { + secp256k1_scalar_sqr(&x30, &x30); + } + secp256k1_scalar_mul(&x30, &x30, &x15); + + secp256k1_scalar_sqr(&x60, &x30); + for (i = 0; i < 29; i++) { + secp256k1_scalar_sqr(&x60, &x60); + } + secp256k1_scalar_mul(&x60, &x60, &x30); + + secp256k1_scalar_sqr(&x120, &x60); + for (i = 0; i < 59; i++) { + secp256k1_scalar_sqr(&x120, &x120); + } + secp256k1_scalar_mul(&x120, &x120, &x60); + + secp256k1_scalar_sqr(&x127, &x120); + for (i = 0; i < 6; i++) { + secp256k1_scalar_sqr(&x127, &x127); + } + secp256k1_scalar_mul(&x127, &x127, &x7); + + /* Then accumulate the final result (t starts at x127). */ + t = &x127; + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 4; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 4; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 3; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x2); /* 11 */ + for (i = 0; i < 4; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 5; i++) { /* 00 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 4; i++) { /* 00 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x2); /* 11 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 5; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x4); /* 1111 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 3; i++) { /* 00 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 4; i++) { /* 000 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 10; i++) { /* 0000000 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 4; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 9; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x8); /* 11111111 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 3; i++) { /* 00 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 3; i++) { /* 00 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 5; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x4); /* 1111 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 5; i++) { /* 000 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x2); /* 11 */ + for (i = 0; i < 4; i++) { /* 00 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x2); /* 11 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 8; i++) { /* 000000 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x2); /* 11 */ + for (i = 0; i < 3; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x2); /* 11 */ + for (i = 0; i < 3; i++) { /* 00 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 6; i++) { /* 00000 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 8; i++) { /* 00 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(r, t, &x6); /* 111111 */ +} + +SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { + /* d[0] is present and is the lowest word for all representations */ + return !(a->d[0] & 1); +} + +static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { +#if defined(USE_SCALAR_INV_BUILTIN) + secp256k1_scalar_inverse(r, x); +#elif defined(USE_SCALAR_INV_NUM) + unsigned char b[32]; + secp256k1_num n, m; + secp256k1_scalar t = *x; + secp256k1_scalar_get_b32(b, &t); + secp256k1_num_set_bin(&n, b, 32); + secp256k1_scalar_order_get_num(&m); + secp256k1_num_mod_inverse(&n, &n, &m); + secp256k1_num_get_bin(b, 32, &n); + secp256k1_scalar_set_b32(r, b, NULL); + /* Verify that the inverse was computed correctly, without GMP code. */ + secp256k1_scalar_mul(&t, &t, r); + CHECK(secp256k1_scalar_is_one(&t)); +#else +#error "Please select scalar inverse implementation" +#endif +} + +#ifdef USE_ENDOMORPHISM +/** + * The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where + * lambda is {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a, + * 0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78,0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72} + * + * "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) gives an algorithm + * (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1 + * and k2 have a small size. + * It relies on constants a1, b1, a2, b2. These constants for the value of lambda above are: + * + * - a1 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} + * - b1 = -{0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3} + * - a2 = {0x01,0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8} + * - b2 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} + * + * The algorithm then computes c1 = round(b1 * k / n) and c2 = round(b2 * k / n), and gives + * k1 = k - (c1*a1 + c2*a2) and k2 = -(c1*b1 + c2*b2). Instead, we use modular arithmetic, and + * compute k1 as k - k2 * lambda, avoiding the need for constants a1 and a2. + * + * g1, g2 are precomputed constants used to replace division with a rounded multiplication + * when decomposing the scalar for an endomorphism-based point multiplication. + * + * The possibility of using precomputed estimates is mentioned in "Guide to Elliptic Curve + * Cryptography" (Hankerson, Menezes, Vanstone) in section 3.5. + * + * The derivation is described in the paper "Efficient Software Implementation of Public-Key + * Cryptography on Sensor Networks Using the MSP430X Microcontroller" (Gouvea, Oliveira, Lopez), + * Section 4.3 (here we use a somewhat higher-precision estimate): + * d = a1*b2 - b1*a2 + * g1 = round((2^272)*b2/d) + * g2 = round((2^272)*b1/d) + * + * (Note that 'd' is also equal to the curve order here because [a1,b1] and [a2,b2] are found + * as outputs of the Extended Euclidean Algorithm on inputs 'order' and 'lambda'). + * + * The function below splits a in r1 and r2, such that r1 + lambda * r2 == a (mod order). + */ + +static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { + secp256k1_scalar c1, c2; + static const secp256k1_scalar minus_lambda = SECP256K1_SCALAR_CONST( + 0xAC9C52B3UL, 0x3FA3CF1FUL, 0x5AD9E3FDUL, 0x77ED9BA4UL, + 0xA880B9FCUL, 0x8EC739C2UL, 0xE0CFC810UL, 0xB51283CFUL + ); + static const secp256k1_scalar minus_b1 = SECP256K1_SCALAR_CONST( + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, + 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C3UL + ); + static const secp256k1_scalar minus_b2 = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, + 0x8A280AC5UL, 0x0774346DUL, 0xD765CDA8UL, 0x3DB1562CUL + ); + static const secp256k1_scalar g1 = SECP256K1_SCALAR_CONST( + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00003086UL, + 0xD221A7D4UL, 0x6BCDE86CUL, 0x90E49284UL, 0xEB153DABUL + ); + static const secp256k1_scalar g2 = SECP256K1_SCALAR_CONST( + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x0000E443UL, + 0x7ED6010EUL, 0x88286F54UL, 0x7FA90ABFUL, 0xE4C42212UL + ); + VERIFY_CHECK(r1 != a); + VERIFY_CHECK(r2 != a); + /* these _var calls are constant time since the shift amount is constant */ + secp256k1_scalar_mul_shift_var(&c1, a, &g1, 272); + secp256k1_scalar_mul_shift_var(&c2, a, &g2, 272); + secp256k1_scalar_mul(&c1, &c1, &minus_b1); + secp256k1_scalar_mul(&c2, &c2, &minus_b2); + secp256k1_scalar_add(r2, &c1, &c2); + secp256k1_scalar_mul(r1, r2, &minus_lambda); + secp256k1_scalar_add(r1, r1, a); +} +#endif + +#endif diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c new file mode 100644 index 000000000..7973d60c3 --- /dev/null +++ b/src/secp256k1/src/secp256k1.c @@ -0,0 +1,561 @@ +/********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include "include/secp256k1.h" + +#include "util.h" +#include "num_impl.h" +#include "field_impl.h" +#include "scalar_impl.h" +#include "group_impl.h" +#include "ecmult_impl.h" +#include "ecmult_const_impl.h" +#include "ecmult_gen_impl.h" +#include "ecdsa_impl.h" +#include "eckey_impl.h" +#include "hash_impl.h" + +#define ARG_CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + secp256k1_callback_call(&ctx->illegal_callback, #cond); \ + return 0; \ + } \ +} while(0) + +static void default_illegal_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); + abort(); +} + +static const secp256k1_callback default_illegal_callback = { + default_illegal_callback_fn, + NULL +}; + +static void default_error_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); + abort(); +} + +static const secp256k1_callback default_error_callback = { + default_error_callback_fn, + NULL +}; + + +struct secp256k1_context_struct { + secp256k1_ecmult_context ecmult_ctx; + secp256k1_ecmult_gen_context ecmult_gen_ctx; + secp256k1_callback illegal_callback; + secp256k1_callback error_callback; +}; + +secp256k1_context* secp256k1_context_create(unsigned int flags) { + secp256k1_context* ret = (secp256k1_context*)checked_malloc(&default_error_callback, sizeof(secp256k1_context)); + ret->illegal_callback = default_illegal_callback; + ret->error_callback = default_error_callback; + + if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) { + secp256k1_callback_call(&ret->illegal_callback, + "Invalid flags"); + free(ret); + return NULL; + } + + secp256k1_ecmult_context_init(&ret->ecmult_ctx); + secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx); + + if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) { + secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->error_callback); + } + if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) { + secp256k1_ecmult_context_build(&ret->ecmult_ctx, &ret->error_callback); + } + + return ret; +} + +secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) { + secp256k1_context* ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, sizeof(secp256k1_context)); + ret->illegal_callback = ctx->illegal_callback; + ret->error_callback = ctx->error_callback; + secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx, &ctx->error_callback); + secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx, &ctx->error_callback); + return ret; +} + +void secp256k1_context_destroy(secp256k1_context* ctx) { + if (ctx != NULL) { + secp256k1_ecmult_context_clear(&ctx->ecmult_ctx); + secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); + + free(ctx); + } +} + +void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { + if (fun == NULL) { + fun = default_illegal_callback_fn; + } + ctx->illegal_callback.fn = fun; + ctx->illegal_callback.data = data; +} + +void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { + if (fun == NULL) { + fun = default_error_callback_fn; + } + ctx->error_callback.fn = fun; + ctx->error_callback.data = data; +} + +static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) { + if (sizeof(secp256k1_ge_storage) == 64) { + /* When the secp256k1_ge_storage type is exactly 64 byte, use its + * representation inside secp256k1_pubkey, as conversion is very fast. + * Note that secp256k1_pubkey_save must use the same representation. */ + secp256k1_ge_storage s; + memcpy(&s, &pubkey->data[0], 64); + secp256k1_ge_from_storage(ge, &s); + } else { + /* Otherwise, fall back to 32-byte big endian for X and Y. */ + secp256k1_fe x, y; + secp256k1_fe_set_b32(&x, pubkey->data); + secp256k1_fe_set_b32(&y, pubkey->data + 32); + secp256k1_ge_set_xy(ge, &x, &y); + } + ARG_CHECK(!secp256k1_fe_is_zero(&ge->x)); + return 1; +} + +static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) { + if (sizeof(secp256k1_ge_storage) == 64) { + secp256k1_ge_storage s; + secp256k1_ge_to_storage(&s, ge); + memcpy(&pubkey->data[0], &s, 64); + } else { + VERIFY_CHECK(!secp256k1_ge_is_infinity(ge)); + secp256k1_fe_normalize_var(&ge->x); + secp256k1_fe_normalize_var(&ge->y); + secp256k1_fe_get_b32(pubkey->data, &ge->x); + secp256k1_fe_get_b32(pubkey->data + 32, &ge->y); + } +} + +int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) { + secp256k1_ge Q; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(input != NULL); + if (!secp256k1_eckey_pubkey_parse(&Q, input, inputlen)) { + return 0; + } + secp256k1_pubkey_save(pubkey, &Q); + secp256k1_ge_clear(&Q); + return 1; +} + +int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_pubkey* pubkey, unsigned int flags) { + secp256k1_ge Q; + size_t len; + int ret = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(outputlen != NULL); + ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33 : 65)); + len = *outputlen; + *outputlen = 0; + ARG_CHECK(output != NULL); + memset(output, 0, len); + ARG_CHECK(pubkey != NULL); + ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION); + if (secp256k1_pubkey_load(ctx, &Q, pubkey)) { + ret = secp256k1_eckey_pubkey_serialize(&Q, output, &len, flags & SECP256K1_FLAGS_BIT_COMPRESSION); + if (ret) { + *outputlen = len; + } + } + return ret; +} + +static void secp256k1_ecdsa_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_ecdsa_signature* sig) { + (void)ctx; + if (sizeof(secp256k1_scalar) == 32) { + /* When the secp256k1_scalar type is exactly 32 byte, use its + * representation inside secp256k1_ecdsa_signature, as conversion is very fast. + * Note that secp256k1_ecdsa_signature_save must use the same representation. */ + memcpy(r, &sig->data[0], 32); + memcpy(s, &sig->data[32], 32); + } else { + secp256k1_scalar_set_b32(r, &sig->data[0], NULL); + secp256k1_scalar_set_b32(s, &sig->data[32], NULL); + } +} + +static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s) { + if (sizeof(secp256k1_scalar) == 32) { + memcpy(&sig->data[0], r, 32); + memcpy(&sig->data[32], s, 32); + } else { + secp256k1_scalar_get_b32(&sig->data[0], r); + secp256k1_scalar_get_b32(&sig->data[32], s); + } +} + +int secp256k1_ecdsa_signature_parse_der(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { + secp256k1_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(input != NULL); + + if (secp256k1_ecdsa_sig_parse(&r, &s, input, inputlen)) { + secp256k1_ecdsa_signature_save(sig, &r, &s); + return 1; + } else { + memset(sig, 0, sizeof(*sig)); + return 0; + } +} + +int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input64) { + secp256k1_scalar r, s; + int ret = 1; + int overflow = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(input64 != NULL); + + secp256k1_scalar_set_b32(&r, &input64[0], &overflow); + ret &= !overflow; + secp256k1_scalar_set_b32(&s, &input64[32], &overflow); + ret &= !overflow; + if (ret) { + secp256k1_ecdsa_signature_save(sig, &r, &s); + } else { + memset(sig, 0, sizeof(*sig)); + } + return ret; +} + +int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_ecdsa_signature* sig) { + secp256k1_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output != NULL); + ARG_CHECK(outputlen != NULL); + ARG_CHECK(sig != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); + return secp256k1_ecdsa_sig_serialize(output, outputlen, &r, &s); +} + +int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, const secp256k1_ecdsa_signature* sig) { + secp256k1_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output64 != NULL); + ARG_CHECK(sig != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); + secp256k1_scalar_get_b32(&output64[0], &r); + secp256k1_scalar_get_b32(&output64[32], &s); + return 1; +} + +int secp256k1_ecdsa_signature_normalize(const secp256k1_context* ctx, secp256k1_ecdsa_signature *sigout, const secp256k1_ecdsa_signature *sigin) { + secp256k1_scalar r, s; + int ret = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sigin != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, sigin); + ret = secp256k1_scalar_is_high(&s); + if (sigout != NULL) { + if (ret) { + secp256k1_scalar_negate(&s, &s); + } + secp256k1_ecdsa_signature_save(sigout, &r, &s); + } + + return ret; +} + +int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_signature *sig, const unsigned char *msg32, const secp256k1_pubkey *pubkey) { + secp256k1_ge q; + secp256k1_scalar r, s; + secp256k1_scalar m; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(pubkey != NULL); + + secp256k1_scalar_set_b32(&m, msg32, NULL); + secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); + return (!secp256k1_scalar_is_high(&s) && + secp256k1_pubkey_load(ctx, &q, pubkey) && + secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &r, &s, &q, &m)); +} + +static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + unsigned char keydata[112]; + int keylen = 64; + secp256k1_rfc6979_hmac_sha256_t rng; + unsigned int i; + /* We feed a byte array to the PRNG as input, consisting of: + * - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d. + * - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data. + * - optionally 16 extra bytes with the algorithm name. + * Because the arguments have distinct fixed lengths it is not possible for + * different argument mixtures to emulate each other and result in the same + * nonces. + */ + memcpy(keydata, key32, 32); + memcpy(keydata + 32, msg32, 32); + if (data != NULL) { + memcpy(keydata + 64, data, 32); + keylen = 96; + } + if (algo16 != NULL) { + memcpy(keydata + keylen, algo16, 16); + keylen += 16; + } + secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, keylen); + memset(keydata, 0, sizeof(keydata)); + for (i = 0; i <= counter; i++) { + secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + } + secp256k1_rfc6979_hmac_sha256_finalize(&rng); + return 1; +} + +const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; +const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979; + +int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { + secp256k1_scalar r, s; + secp256k1_scalar sec, non, msg; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(seckey != NULL); + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_default; + } + + secp256k1_scalar_set_b32(&sec, seckey, &overflow); + /* Fail if the secret key is invalid. */ + if (!overflow && !secp256k1_scalar_is_zero(&sec)) { + unsigned int count = 0; + secp256k1_scalar_set_b32(&msg, msg32, NULL); + while (1) { + unsigned char nonce32[32]; + ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); + if (!ret) { + break; + } + secp256k1_scalar_set_b32(&non, nonce32, &overflow); + memset(nonce32, 0, 32); + if (!overflow && !secp256k1_scalar_is_zero(&non)) { + if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL)) { + break; + } + } + count++; + } + secp256k1_scalar_clear(&msg); + secp256k1_scalar_clear(&non); + secp256k1_scalar_clear(&sec); + } + if (ret) { + secp256k1_ecdsa_signature_save(signature, &r, &s); + } else { + memset(signature, 0, sizeof(*signature)); + } + return ret; +} + +int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char *seckey) { + secp256k1_scalar sec; + int ret; + int overflow; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + + secp256k1_scalar_set_b32(&sec, seckey, &overflow); + ret = !overflow && !secp256k1_scalar_is_zero(&sec); + secp256k1_scalar_clear(&sec); + return ret; +} + +int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey) { + secp256k1_gej pj; + secp256k1_ge p; + secp256k1_scalar sec; + int overflow; + int ret = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(seckey != NULL); + + secp256k1_scalar_set_b32(&sec, seckey, &overflow); + ret = (!overflow) & (!secp256k1_scalar_is_zero(&sec)); + if (ret) { + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec); + secp256k1_ge_set_gej(&p, &pj); + secp256k1_pubkey_save(pubkey, &p); + } + secp256k1_scalar_clear(&sec); + return ret; +} + +int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) { + secp256k1_scalar term; + secp256k1_scalar sec; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak != NULL); + + secp256k1_scalar_set_b32(&term, tweak, &overflow); + secp256k1_scalar_set_b32(&sec, seckey, NULL); + + ret = !overflow && secp256k1_eckey_privkey_tweak_add(&sec, &term); + memset(seckey, 0, 32); + if (ret) { + secp256k1_scalar_get_b32(seckey, &sec); + } + + secp256k1_scalar_clear(&sec); + secp256k1_scalar_clear(&term); + return ret; +} + +int secp256k1_ec_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) { + secp256k1_ge p; + secp256k1_scalar term; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(tweak != NULL); + + secp256k1_scalar_set_b32(&term, tweak, &overflow); + ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + if (secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term)) { + secp256k1_pubkey_save(pubkey, &p); + } else { + ret = 0; + } + } + + return ret; +} + +int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) { + secp256k1_scalar factor; + secp256k1_scalar sec; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak != NULL); + + secp256k1_scalar_set_b32(&factor, tweak, &overflow); + secp256k1_scalar_set_b32(&sec, seckey, NULL); + ret = !overflow && secp256k1_eckey_privkey_tweak_mul(&sec, &factor); + memset(seckey, 0, 32); + if (ret) { + secp256k1_scalar_get_b32(seckey, &sec); + } + + secp256k1_scalar_clear(&sec); + secp256k1_scalar_clear(&factor); + return ret; +} + +int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) { + secp256k1_ge p; + secp256k1_scalar factor; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(tweak != NULL); + + secp256k1_scalar_set_b32(&factor, tweak, &overflow); + ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + if (secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor)) { + secp256k1_pubkey_save(pubkey, &p); + } else { + ret = 0; + } + } + + return ret; +} + +int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); + return 1; +} + +int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, const secp256k1_pubkey * const *pubnonces, size_t n) { + size_t i; + secp256k1_gej Qj; + secp256k1_ge Q; + + ARG_CHECK(pubnonce != NULL); + memset(pubnonce, 0, sizeof(*pubnonce)); + ARG_CHECK(n >= 1); + ARG_CHECK(pubnonces != NULL); + + secp256k1_gej_set_infinity(&Qj); + + for (i = 0; i < n; i++) { + secp256k1_pubkey_load(ctx, &Q, pubnonces[i]); + secp256k1_gej_add_ge(&Qj, &Qj, &Q); + } + if (secp256k1_gej_is_infinity(&Qj)) { + return 0; + } + secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_pubkey_save(pubnonce, &Q); + return 1; +} + +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORR +# include "modules/schnorr/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_RECOVERY +# include "modules/recovery/main_impl.h" +#endif diff --git a/src/secp256k1/src/testrand.h b/src/secp256k1/src/testrand.h new file mode 100644 index 000000000..f8efa93c7 --- /dev/null +++ b/src/secp256k1/src/testrand.h @@ -0,0 +1,38 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_TESTRAND_H_ +#define _SECP256K1_TESTRAND_H_ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +/* A non-cryptographic RNG used only for test infrastructure. */ + +/** Seed the pseudorandom number generator for testing. */ +SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16); + +/** Generate a pseudorandom number in the range [0..2**32-1]. */ +static uint32_t secp256k1_rand32(void); + +/** Generate a pseudorandom number in the range [0..2**bits-1]. Bits must be 1 or + * more. */ +static uint32_t secp256k1_rand_bits(int bits); + +/** Generate a pseudorandom number in the range [0..range-1]. */ +static uint32_t secp256k1_rand_int(uint32_t range); + +/** Generate a pseudorandom 32-byte array. */ +static void secp256k1_rand256(unsigned char *b32); + +/** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */ +static void secp256k1_rand256_test(unsigned char *b32); + +/** Generate pseudorandom bytes with long sequences of zero and one bits. */ +static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len); + +#endif diff --git a/src/secp256k1/src/testrand_impl.h b/src/secp256k1/src/testrand_impl.h new file mode 100644 index 000000000..15c7b9f12 --- /dev/null +++ b/src/secp256k1/src/testrand_impl.h @@ -0,0 +1,110 @@ +/********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_TESTRAND_IMPL_H_ +#define _SECP256K1_TESTRAND_IMPL_H_ + +#include +#include + +#include "testrand.h" +#include "hash.h" + +static secp256k1_rfc6979_hmac_sha256_t secp256k1_test_rng; +static uint32_t secp256k1_test_rng_precomputed[8]; +static int secp256k1_test_rng_precomputed_used = 8; +static uint64_t secp256k1_test_rng_integer; +static int secp256k1_test_rng_integer_bits_left = 0; + +SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16) { + secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, seed16, 16); +} + +SECP256K1_INLINE static uint32_t secp256k1_rand32(void) { + if (secp256k1_test_rng_precomputed_used == 8) { + secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, (unsigned char*)(&secp256k1_test_rng_precomputed[0]), sizeof(secp256k1_test_rng_precomputed)); + secp256k1_test_rng_precomputed_used = 0; + } + return secp256k1_test_rng_precomputed[secp256k1_test_rng_precomputed_used++]; +} + +static uint32_t secp256k1_rand_bits(int bits) { + uint32_t ret; + if (secp256k1_test_rng_integer_bits_left < bits) { + secp256k1_test_rng_integer |= (((uint64_t)secp256k1_rand32()) << secp256k1_test_rng_integer_bits_left); + secp256k1_test_rng_integer_bits_left += 32; + } + ret = secp256k1_test_rng_integer; + secp256k1_test_rng_integer >>= bits; + secp256k1_test_rng_integer_bits_left -= bits; + ret &= ((~((uint32_t)0)) >> (32 - bits)); + return ret; +} + +static uint32_t secp256k1_rand_int(uint32_t range) { + /* We want a uniform integer between 0 and range-1, inclusive. + * B is the smallest number such that range <= 2**B. + * two mechanisms implemented here: + * - generate B bits numbers until one below range is found, and return it + * - find the largest multiple M of range that is <= 2**(B+A), generate B+A + * bits numbers until one below M is found, and return it modulo range + * The second mechanism consumes A more bits of entropy in every iteration, + * but may need fewer iterations due to M being closer to 2**(B+A) then + * range is to 2**B. The array below (indexed by B) contains a 0 when the + * first mechanism is to be used, and the number A otherwise. + */ + static const int addbits[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0}; + uint32_t trange, mult; + int bits = 0; + if (range <= 1) { + return 0; + } + trange = range - 1; + while (trange > 0) { + trange >>= 1; + bits++; + } + if (addbits[bits]) { + bits = bits + addbits[bits]; + mult = ((~((uint32_t)0)) >> (32 - bits)) / range; + trange = range * mult; + } else { + trange = range; + mult = 1; + } + while(1) { + uint32_t x = secp256k1_rand_bits(bits); + if (x < trange) { + return (mult == 1) ? x : (x % range); + } + } +} + +static void secp256k1_rand256(unsigned char *b32) { + secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, b32, 32); +} + +static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len) { + size_t bits = 0; + memset(bytes, 0, len); + while (bits < len * 8) { + int now; + uint32_t val; + now = 1 + (secp256k1_rand_bits(6) * secp256k1_rand_bits(5) + 16) / 31; + val = secp256k1_rand_bits(1); + while (now > 0 && bits < len * 8) { + bytes[bits / 8] |= val << (bits % 8); + now--; + bits++; + } + } +} + +static void secp256k1_rand256_test(unsigned char *b32) { + secp256k1_rand_bytes_test(b32, 32); +} + +#endif diff --git a/src/secp256k1/src/tests.c b/src/secp256k1/src/tests.c new file mode 100644 index 000000000..b32cb9081 --- /dev/null +++ b/src/secp256k1/src/tests.c @@ -0,0 +1,4525 @@ +/********************************************************************** + * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include +#include + +#include + +#include "secp256k1.c" +#include "include/secp256k1.h" +#include "testrand_impl.h" + +#ifdef ENABLE_OPENSSL_TESTS +#include "openssl/bn.h" +#include "openssl/ec.h" +#include "openssl/ecdsa.h" +#include "openssl/obj_mac.h" +#endif + +#include "contrib/lax_der_parsing.c" +#include "contrib/lax_der_privatekey_parsing.c" + +#if !defined(VG_CHECK) +# if defined(VALGRIND) +# include +# define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y)) +# define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y)) +# else +# define VG_UNDEF(x,y) +# define VG_CHECK(x,y) +# endif +#endif + +static int count = 64; +static secp256k1_context *ctx = NULL; + +static void counting_illegal_callback_fn(const char* str, void* data) { + /* Dummy callback function that just counts. */ + int32_t *p; + (void)str; + p = data; + (*p)++; +} + +static void uncounting_illegal_callback_fn(const char* str, void* data) { + /* Dummy callback function that just counts (backwards). */ + int32_t *p; + (void)str; + p = data; + (*p)--; +} + +void random_field_element_test(secp256k1_fe *fe) { + do { + unsigned char b32[32]; + secp256k1_rand256_test(b32); + if (secp256k1_fe_set_b32(fe, b32)) { + break; + } + } while(1); +} + +void random_field_element_magnitude(secp256k1_fe *fe) { + secp256k1_fe zero; + int n = secp256k1_rand_int(9); + secp256k1_fe_normalize(fe); + if (n == 0) { + return; + } + secp256k1_fe_clear(&zero); + secp256k1_fe_negate(&zero, &zero, 0); + secp256k1_fe_mul_int(&zero, n - 1); + secp256k1_fe_add(fe, &zero); + VERIFY_CHECK(fe->magnitude == n); +} + +void random_group_element_test(secp256k1_ge *ge) { + secp256k1_fe fe; + do { + random_field_element_test(&fe); + if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_rand_bits(1))) { + secp256k1_fe_normalize(&ge->y); + break; + } + } while(1); +} + +void random_group_element_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) { + secp256k1_fe z2, z3; + do { + random_field_element_test(&gej->z); + if (!secp256k1_fe_is_zero(&gej->z)) { + break; + } + } while(1); + secp256k1_fe_sqr(&z2, &gej->z); + secp256k1_fe_mul(&z3, &z2, &gej->z); + secp256k1_fe_mul(&gej->x, &ge->x, &z2); + secp256k1_fe_mul(&gej->y, &ge->y, &z3); + gej->infinity = ge->infinity; +} + +void random_scalar_order_test(secp256k1_scalar *num) { + do { + unsigned char b32[32]; + int overflow = 0; + secp256k1_rand256_test(b32); + secp256k1_scalar_set_b32(num, b32, &overflow); + if (overflow || secp256k1_scalar_is_zero(num)) { + continue; + } + break; + } while(1); +} + +void random_scalar_order(secp256k1_scalar *num) { + do { + unsigned char b32[32]; + int overflow = 0; + secp256k1_rand256(b32); + secp256k1_scalar_set_b32(num, b32, &overflow); + if (overflow || secp256k1_scalar_is_zero(num)) { + continue; + } + break; + } while(1); +} + +void run_context_tests(void) { + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; + unsigned char ctmp[32]; + int32_t ecount; + int32_t ecount2; + secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + secp256k1_gej pubj; + secp256k1_ge pub; + secp256k1_scalar msg, key, nonce; + secp256k1_scalar sigr, sigs; + + ecount = 0; + ecount2 = 10; + secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount2); + secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, NULL); + CHECK(vrfy->error_callback.fn != sign->error_callback.fn); + + /*** clone and destroy all of them to make sure cloning was complete ***/ + { + secp256k1_context *ctx_tmp; + + ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_destroy(ctx_tmp); + } + + /* Verify that the error callback makes it across the clone. */ + CHECK(vrfy->error_callback.fn != sign->error_callback.fn); + /* And that it resets back to default. */ + secp256k1_context_set_error_callback(sign, NULL, NULL); + CHECK(vrfy->error_callback.fn == sign->error_callback.fn); + + /*** attempt to use them ***/ + random_scalar_order_test(&msg); + random_scalar_order_test(&key); + secp256k1_ecmult_gen(&both->ecmult_gen_ctx, &pubj, &key); + secp256k1_ge_set_gej(&pub, &pubj); + + /* Verify context-type checking illegal-argument errors. */ + memset(ctmp, 1, 32); + CHECK(secp256k1_ec_pubkey_create(vrfy, &pubkey, ctmp) == 0); + CHECK(ecount == 1); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(sign, &pubkey, ctmp) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ecdsa_sign(vrfy, &sig, ctmp, ctmp, NULL, NULL) == 0); + CHECK(ecount == 2); + VG_UNDEF(&sig, sizeof(sig)); + CHECK(secp256k1_ecdsa_sign(sign, &sig, ctmp, ctmp, NULL, NULL) == 1); + VG_CHECK(&sig, sizeof(sig)); + CHECK(ecount2 == 10); + CHECK(secp256k1_ecdsa_verify(sign, &sig, ctmp, &pubkey) == 0); + CHECK(ecount2 == 11); + CHECK(secp256k1_ecdsa_verify(vrfy, &sig, ctmp, &pubkey) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ec_pubkey_tweak_add(sign, &pubkey, ctmp) == 0); + CHECK(ecount2 == 12); + CHECK(secp256k1_ec_pubkey_tweak_add(vrfy, &pubkey, ctmp) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ec_pubkey_tweak_mul(sign, &pubkey, ctmp) == 0); + CHECK(ecount2 == 13); + CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_context_randomize(sign, NULL) == 1); + CHECK(ecount2 == 13); + secp256k1_context_set_illegal_callback(vrfy, NULL, NULL); + secp256k1_context_set_illegal_callback(sign, NULL, NULL); + + /* This shouldn't leak memory, due to already-set tests. */ + secp256k1_ecmult_gen_context_build(&sign->ecmult_gen_ctx, NULL); + secp256k1_ecmult_context_build(&vrfy->ecmult_ctx, NULL); + + /* obtain a working nonce */ + do { + random_scalar_order_test(&nonce); + } while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + + /* try signing */ + CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + + /* try verifying */ + CHECK(secp256k1_ecdsa_sig_verify(&vrfy->ecmult_ctx, &sigr, &sigs, &pub, &msg)); + CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sigr, &sigs, &pub, &msg)); + + /* cleanup */ + secp256k1_context_destroy(none); + secp256k1_context_destroy(sign); + secp256k1_context_destroy(vrfy); + secp256k1_context_destroy(both); + /* Defined as no-op. */ + secp256k1_context_destroy(NULL); +} + +/***** HASH TESTS *****/ + +void run_sha256_tests(void) { + static const char *inputs[8] = { + "", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "For this sample, this 63-byte string will be used as input data", + "This is exactly 64 bytes long, not counting the terminating byte" + }; + static const unsigned char outputs[8][32] = { + {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}, + {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}, + {0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55, 0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50}, + {0xf3, 0x0c, 0xeb, 0x2b, 0xb2, 0x82, 0x9e, 0x79, 0xe4, 0xca, 0x97, 0x53, 0xd3, 0x5a, 0x8e, 0xcc, 0x00, 0x26, 0x2d, 0x16, 0x4c, 0xc0, 0x77, 0x08, 0x02, 0x95, 0x38, 0x1c, 0xbd, 0x64, 0x3f, 0x0d}, + {0x68, 0x19, 0xd9, 0x15, 0xc7, 0x3f, 0x4d, 0x1e, 0x77, 0xe4, 0xe1, 0xb5, 0x2d, 0x1f, 0xa0, 0xf9, 0xcf, 0x9b, 0xea, 0xea, 0xd3, 0x93, 0x9f, 0x15, 0x87, 0x4b, 0xd9, 0x88, 0xe2, 0xa2, 0x36, 0x30}, + {0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}, + {0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42}, + {0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8} + }; + int i; + for (i = 0; i < 8; i++) { + unsigned char out[32]; + secp256k1_sha256_t hasher; + secp256k1_sha256_initialize(&hasher); + secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); + secp256k1_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + if (strlen(inputs[i]) > 0) { + int split = secp256k1_rand_int(strlen(inputs[i])); + secp256k1_sha256_initialize(&hasher); + secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); + secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); + secp256k1_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + } + } +} + +void run_hmac_sha256_tests(void) { + static const char *keys[6] = { + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + "\x4a\x65\x66\x65", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + }; + static const char *inputs[6] = { + "\x48\x69\x20\x54\x68\x65\x72\x65", + "\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20\x6e\x6f\x74\x68\x69\x6e\x67\x3f", + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd", + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd", + "\x54\x65\x73\x74\x20\x55\x73\x69\x6e\x67\x20\x4c\x61\x72\x67\x65\x72\x20\x54\x68\x61\x6e\x20\x42\x6c\x6f\x63\x6b\x2d\x53\x69\x7a\x65\x20\x4b\x65\x79\x20\x2d\x20\x48\x61\x73\x68\x20\x4b\x65\x79\x20\x46\x69\x72\x73\x74", + "\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x2e" + }; + static const unsigned char outputs[6][32] = { + {0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7}, + {0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43}, + {0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe}, + {0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07, 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b}, + {0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54}, + {0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2} + }; + int i; + for (i = 0; i < 6; i++) { + secp256k1_hmac_sha256_t hasher; + unsigned char out[32]; + secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); + secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); + secp256k1_hmac_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + if (strlen(inputs[i]) > 0) { + int split = secp256k1_rand_int(strlen(inputs[i])); + secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); + secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); + secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); + secp256k1_hmac_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + } + } +} + +void run_rfc6979_hmac_sha256_tests(void) { + static const unsigned char key1[65] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x4b, 0xf5, 0x12, 0x2f, 0x34, 0x45, 0x54, 0xc5, 0x3b, 0xde, 0x2e, 0xbb, 0x8c, 0xd2, 0xb7, 0xe3, 0xd1, 0x60, 0x0a, 0xd6, 0x31, 0xc3, 0x85, 0xa5, 0xd7, 0xcc, 0xe2, 0x3c, 0x77, 0x85, 0x45, 0x9a, 0}; + static const unsigned char out1[3][32] = { + {0x4f, 0xe2, 0x95, 0x25, 0xb2, 0x08, 0x68, 0x09, 0x15, 0x9a, 0xcd, 0xf0, 0x50, 0x6e, 0xfb, 0x86, 0xb0, 0xec, 0x93, 0x2c, 0x7b, 0xa4, 0x42, 0x56, 0xab, 0x32, 0x1e, 0x42, 0x1e, 0x67, 0xe9, 0xfb}, + {0x2b, 0xf0, 0xff, 0xf1, 0xd3, 0xc3, 0x78, 0xa2, 0x2d, 0xc5, 0xde, 0x1d, 0x85, 0x65, 0x22, 0x32, 0x5c, 0x65, 0xb5, 0x04, 0x49, 0x1a, 0x0c, 0xbd, 0x01, 0xcb, 0x8f, 0x3a, 0xa6, 0x7f, 0xfd, 0x4a}, + {0xf5, 0x28, 0xb4, 0x10, 0xcb, 0x54, 0x1f, 0x77, 0x00, 0x0d, 0x7a, 0xfb, 0x6c, 0x5b, 0x53, 0xc5, 0xc4, 0x71, 0xea, 0xb4, 0x3e, 0x46, 0x6d, 0x9a, 0xc5, 0x19, 0x0c, 0x39, 0xc8, 0x2f, 0xd8, 0x2e} + }; + + static const unsigned char key2[64] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}; + static const unsigned char out2[3][32] = { + {0x9c, 0x23, 0x6c, 0x16, 0x5b, 0x82, 0xae, 0x0c, 0xd5, 0x90, 0x65, 0x9e, 0x10, 0x0b, 0x6b, 0xab, 0x30, 0x36, 0xe7, 0xba, 0x8b, 0x06, 0x74, 0x9b, 0xaf, 0x69, 0x81, 0xe1, 0x6f, 0x1a, 0x2b, 0x95}, + {0xdf, 0x47, 0x10, 0x61, 0x62, 0x5b, 0xc0, 0xea, 0x14, 0xb6, 0x82, 0xfe, 0xee, 0x2c, 0x9c, 0x02, 0xf2, 0x35, 0xda, 0x04, 0x20, 0x4c, 0x1d, 0x62, 0xa1, 0x53, 0x6c, 0x6e, 0x17, 0xae, 0xd7, 0xa9}, + {0x75, 0x97, 0x88, 0x7c, 0xbd, 0x76, 0x32, 0x1f, 0x32, 0xe3, 0x04, 0x40, 0x67, 0x9a, 0x22, 0xcf, 0x7f, 0x8d, 0x9d, 0x2e, 0xac, 0x39, 0x0e, 0x58, 0x1f, 0xea, 0x09, 0x1c, 0xe2, 0x02, 0xba, 0x94} + }; + + secp256k1_rfc6979_hmac_sha256_t rng; + unsigned char out[32]; + int i; + + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 64); + for (i = 0; i < 3; i++) { + secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); + CHECK(memcmp(out, out1[i], 32) == 0); + } + secp256k1_rfc6979_hmac_sha256_finalize(&rng); + + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 65); + for (i = 0; i < 3; i++) { + secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); + CHECK(memcmp(out, out1[i], 32) != 0); + } + secp256k1_rfc6979_hmac_sha256_finalize(&rng); + + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 64); + for (i = 0; i < 3; i++) { + secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); + CHECK(memcmp(out, out2[i], 32) == 0); + } + secp256k1_rfc6979_hmac_sha256_finalize(&rng); +} + +/***** RANDOM TESTS *****/ + +void test_rand_bits(int rand32, int bits) { + /* (1-1/2^B)^rounds[B] < 1/10^9, so rounds is the number of iterations to + * get a false negative chance below once in a billion */ + static const unsigned int rounds[7] = {1, 30, 73, 156, 322, 653, 1316}; + /* We try multiplying the results with various odd numbers, which shouldn't + * influence the uniform distribution modulo a power of 2. */ + static const uint32_t mults[6] = {1, 3, 21, 289, 0x9999, 0x80402011}; + /* We only select up to 6 bits from the output to analyse */ + unsigned int usebits = bits > 6 ? 6 : bits; + unsigned int maxshift = bits - usebits; + /* For each of the maxshift+1 usebits-bit sequences inside a bits-bit + number, track all observed outcomes, one per bit in a uint64_t. */ + uint64_t x[6][27] = {{0}}; + unsigned int i, shift, m; + /* Multiply the output of all rand calls with the odd number m, which + should not change the uniformity of its distribution. */ + for (i = 0; i < rounds[usebits]; i++) { + uint32_t r = (rand32 ? secp256k1_rand32() : secp256k1_rand_bits(bits)); + CHECK((((uint64_t)r) >> bits) == 0); + for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) { + uint32_t rm = r * mults[m]; + for (shift = 0; shift <= maxshift; shift++) { + x[m][shift] |= (((uint64_t)1) << ((rm >> shift) & ((1 << usebits) - 1))); + } + } + } + for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) { + for (shift = 0; shift <= maxshift; shift++) { + /* Test that the lower usebits bits of x[shift] are 1 */ + CHECK(((~x[m][shift]) << (64 - (1 << usebits))) == 0); + } + } +} + +/* Subrange must be a whole divisor of range, and at most 64 */ +void test_rand_int(uint32_t range, uint32_t subrange) { + /* (1-1/subrange)^rounds < 1/10^9 */ + int rounds = (subrange * 2073) / 100; + int i; + uint64_t x = 0; + CHECK((range % subrange) == 0); + for (i = 0; i < rounds; i++) { + uint32_t r = secp256k1_rand_int(range); + CHECK(r < range); + r = r % subrange; + x |= (((uint64_t)1) << r); + } + /* Test that the lower subrange bits of x are 1. */ + CHECK(((~x) << (64 - subrange)) == 0); +} + +void run_rand_bits(void) { + size_t b; + test_rand_bits(1, 32); + for (b = 1; b <= 32; b++) { + test_rand_bits(0, b); + } +} + +void run_rand_int(void) { + static const uint32_t ms[] = {1, 3, 17, 1000, 13771, 999999, 33554432}; + static const uint32_t ss[] = {1, 3, 6, 9, 13, 31, 64}; + unsigned int m, s; + for (m = 0; m < sizeof(ms) / sizeof(ms[0]); m++) { + for (s = 0; s < sizeof(ss) / sizeof(ss[0]); s++) { + test_rand_int(ms[m] * ss[s], ss[s]); + } + } +} + +/***** NUM TESTS *****/ + +#ifndef USE_NUM_NONE +void random_num_negate(secp256k1_num *num) { + if (secp256k1_rand_bits(1)) { + secp256k1_num_negate(num); + } +} + +void random_num_order_test(secp256k1_num *num) { + secp256k1_scalar sc; + random_scalar_order_test(&sc); + secp256k1_scalar_get_num(num, &sc); +} + +void random_num_order(secp256k1_num *num) { + secp256k1_scalar sc; + random_scalar_order(&sc); + secp256k1_scalar_get_num(num, &sc); +} + +void test_num_negate(void) { + secp256k1_num n1; + secp256k1_num n2; + random_num_order_test(&n1); /* n1 = R */ + random_num_negate(&n1); + secp256k1_num_copy(&n2, &n1); /* n2 = R */ + secp256k1_num_sub(&n1, &n2, &n1); /* n1 = n2-n1 = 0 */ + CHECK(secp256k1_num_is_zero(&n1)); + secp256k1_num_copy(&n1, &n2); /* n1 = R */ + secp256k1_num_negate(&n1); /* n1 = -R */ + CHECK(!secp256k1_num_is_zero(&n1)); + secp256k1_num_add(&n1, &n2, &n1); /* n1 = n2+n1 = 0 */ + CHECK(secp256k1_num_is_zero(&n1)); + secp256k1_num_copy(&n1, &n2); /* n1 = R */ + secp256k1_num_negate(&n1); /* n1 = -R */ + CHECK(secp256k1_num_is_neg(&n1) != secp256k1_num_is_neg(&n2)); + secp256k1_num_negate(&n1); /* n1 = R */ + CHECK(secp256k1_num_eq(&n1, &n2)); +} + +void test_num_add_sub(void) { + int i; + secp256k1_scalar s; + secp256k1_num n1; + secp256k1_num n2; + secp256k1_num n1p2, n2p1, n1m2, n2m1; + random_num_order_test(&n1); /* n1 = R1 */ + if (secp256k1_rand_bits(1)) { + random_num_negate(&n1); + } + random_num_order_test(&n2); /* n2 = R2 */ + if (secp256k1_rand_bits(1)) { + random_num_negate(&n2); + } + secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = R1 + R2 */ + secp256k1_num_add(&n2p1, &n2, &n1); /* n2p1 = R2 + R1 */ + secp256k1_num_sub(&n1m2, &n1, &n2); /* n1m2 = R1 - R2 */ + secp256k1_num_sub(&n2m1, &n2, &n1); /* n2m1 = R2 - R1 */ + CHECK(secp256k1_num_eq(&n1p2, &n2p1)); + CHECK(!secp256k1_num_eq(&n1p2, &n1m2)); + secp256k1_num_negate(&n2m1); /* n2m1 = -R2 + R1 */ + CHECK(secp256k1_num_eq(&n2m1, &n1m2)); + CHECK(!secp256k1_num_eq(&n2m1, &n1)); + secp256k1_num_add(&n2m1, &n2m1, &n2); /* n2m1 = -R2 + R1 + R2 = R1 */ + CHECK(secp256k1_num_eq(&n2m1, &n1)); + CHECK(!secp256k1_num_eq(&n2p1, &n1)); + secp256k1_num_sub(&n2p1, &n2p1, &n2); /* n2p1 = R2 + R1 - R2 = R1 */ + CHECK(secp256k1_num_eq(&n2p1, &n1)); + + /* check is_one */ + secp256k1_scalar_set_int(&s, 1); + secp256k1_scalar_get_num(&n1, &s); + CHECK(secp256k1_num_is_one(&n1)); + /* check that 2^n + 1 is never 1 */ + secp256k1_scalar_get_num(&n2, &s); + for (i = 0; i < 250; ++i) { + secp256k1_num_add(&n1, &n1, &n1); /* n1 *= 2 */ + secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = n1 + 1 */ + CHECK(!secp256k1_num_is_one(&n1p2)); + } +} + +void test_num_mod(void) { + int i; + secp256k1_scalar s; + secp256k1_num order, n; + + /* check that 0 mod anything is 0 */ + random_scalar_order_test(&s); + secp256k1_scalar_get_num(&order, &s); + secp256k1_scalar_set_int(&s, 0); + secp256k1_scalar_get_num(&n, &s); + secp256k1_num_mod(&n, &order); + CHECK(secp256k1_num_is_zero(&n)); + + /* check that anything mod 1 is 0 */ + secp256k1_scalar_set_int(&s, 1); + secp256k1_scalar_get_num(&order, &s); + secp256k1_scalar_get_num(&n, &s); + secp256k1_num_mod(&n, &order); + CHECK(secp256k1_num_is_zero(&n)); + + /* check that increasing the number past 2^256 does not break this */ + random_scalar_order_test(&s); + secp256k1_scalar_get_num(&n, &s); + /* multiply by 2^8, which'll test this case with high probability */ + for (i = 0; i < 8; ++i) { + secp256k1_num_add(&n, &n, &n); + } + secp256k1_num_mod(&n, &order); + CHECK(secp256k1_num_is_zero(&n)); +} + +void test_num_jacobi(void) { + secp256k1_scalar sqr; + secp256k1_scalar small; + secp256k1_scalar five; /* five is not a quadratic residue */ + secp256k1_num order, n; + int i; + /* squares mod 5 are 1, 4 */ + const int jacobi5[10] = { 0, 1, -1, -1, 1, 0, 1, -1, -1, 1 }; + + /* check some small values with 5 as the order */ + secp256k1_scalar_set_int(&five, 5); + secp256k1_scalar_get_num(&order, &five); + for (i = 0; i < 10; ++i) { + secp256k1_scalar_set_int(&small, i); + secp256k1_scalar_get_num(&n, &small); + CHECK(secp256k1_num_jacobi(&n, &order) == jacobi5[i]); + } + + /** test large values with 5 as group order */ + secp256k1_scalar_get_num(&order, &five); + /* we first need a scalar which is not a multiple of 5 */ + do { + secp256k1_num fiven; + random_scalar_order_test(&sqr); + secp256k1_scalar_get_num(&fiven, &five); + secp256k1_scalar_get_num(&n, &sqr); + secp256k1_num_mod(&n, &fiven); + } while (secp256k1_num_is_zero(&n)); + /* next force it to be a residue. 2 is a nonresidue mod 5 so we can + * just multiply by two, i.e. add the number to itself */ + if (secp256k1_num_jacobi(&n, &order) == -1) { + secp256k1_num_add(&n, &n, &n); + } + + /* test residue */ + CHECK(secp256k1_num_jacobi(&n, &order) == 1); + /* test nonresidue */ + secp256k1_num_add(&n, &n, &n); + CHECK(secp256k1_num_jacobi(&n, &order) == -1); + + /** test with secp group order as order */ + secp256k1_scalar_order_get_num(&order); + random_scalar_order_test(&sqr); + secp256k1_scalar_sqr(&sqr, &sqr); + /* test residue */ + secp256k1_scalar_get_num(&n, &sqr); + CHECK(secp256k1_num_jacobi(&n, &order) == 1); + /* test nonresidue */ + secp256k1_scalar_mul(&sqr, &sqr, &five); + secp256k1_scalar_get_num(&n, &sqr); + CHECK(secp256k1_num_jacobi(&n, &order) == -1); + /* test multiple of the order*/ + CHECK(secp256k1_num_jacobi(&order, &order) == 0); + + /* check one less than the order */ + secp256k1_scalar_set_int(&small, 1); + secp256k1_scalar_get_num(&n, &small); + secp256k1_num_sub(&n, &order, &n); + CHECK(secp256k1_num_jacobi(&n, &order) == 1); /* sage confirms this is 1 */ +} + +void run_num_smalltests(void) { + int i; + for (i = 0; i < 100*count; i++) { + test_num_negate(); + test_num_add_sub(); + test_num_mod(); + test_num_jacobi(); + } +} +#endif + +/***** SCALAR TESTS *****/ + +void scalar_test(void) { + secp256k1_scalar s; + secp256k1_scalar s1; + secp256k1_scalar s2; +#ifndef USE_NUM_NONE + secp256k1_num snum, s1num, s2num; + secp256k1_num order, half_order; +#endif + unsigned char c[32]; + + /* Set 's' to a random scalar, with value 'snum'. */ + random_scalar_order_test(&s); + + /* Set 's1' to a random scalar, with value 's1num'. */ + random_scalar_order_test(&s1); + + /* Set 's2' to a random scalar, with value 'snum2', and byte array representation 'c'. */ + random_scalar_order_test(&s2); + secp256k1_scalar_get_b32(c, &s2); + +#ifndef USE_NUM_NONE + secp256k1_scalar_get_num(&snum, &s); + secp256k1_scalar_get_num(&s1num, &s1); + secp256k1_scalar_get_num(&s2num, &s2); + + secp256k1_scalar_order_get_num(&order); + half_order = order; + secp256k1_num_shift(&half_order, 1); +#endif + + { + int i; + /* Test that fetching groups of 4 bits from a scalar and recursing n(i)=16*n(i-1)+p(i) reconstructs it. */ + secp256k1_scalar n; + secp256k1_scalar_set_int(&n, 0); + for (i = 0; i < 256; i += 4) { + secp256k1_scalar t; + int j; + secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits(&s, 256 - 4 - i, 4)); + for (j = 0; j < 4; j++) { + secp256k1_scalar_add(&n, &n, &n); + } + secp256k1_scalar_add(&n, &n, &t); + } + CHECK(secp256k1_scalar_eq(&n, &s)); + } + + { + /* Test that fetching groups of randomly-sized bits from a scalar and recursing n(i)=b*n(i-1)+p(i) reconstructs it. */ + secp256k1_scalar n; + int i = 0; + secp256k1_scalar_set_int(&n, 0); + while (i < 256) { + secp256k1_scalar t; + int j; + int now = secp256k1_rand_int(15) + 1; + if (now + i > 256) { + now = 256 - i; + } + secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits_var(&s, 256 - now - i, now)); + for (j = 0; j < now; j++) { + secp256k1_scalar_add(&n, &n, &n); + } + secp256k1_scalar_add(&n, &n, &t); + i += now; + } + CHECK(secp256k1_scalar_eq(&n, &s)); + } + +#ifndef USE_NUM_NONE + { + /* Test that adding the scalars together is equal to adding their numbers together modulo the order. */ + secp256k1_num rnum; + secp256k1_num r2num; + secp256k1_scalar r; + secp256k1_num_add(&rnum, &snum, &s2num); + secp256k1_num_mod(&rnum, &order); + secp256k1_scalar_add(&r, &s, &s2); + secp256k1_scalar_get_num(&r2num, &r); + CHECK(secp256k1_num_eq(&rnum, &r2num)); + } + + { + /* Test that multiplying the scalars is equal to multiplying their numbers modulo the order. */ + secp256k1_scalar r; + secp256k1_num r2num; + secp256k1_num rnum; + secp256k1_num_mul(&rnum, &snum, &s2num); + secp256k1_num_mod(&rnum, &order); + secp256k1_scalar_mul(&r, &s, &s2); + secp256k1_scalar_get_num(&r2num, &r); + CHECK(secp256k1_num_eq(&rnum, &r2num)); + /* The result can only be zero if at least one of the factors was zero. */ + CHECK(secp256k1_scalar_is_zero(&r) == (secp256k1_scalar_is_zero(&s) || secp256k1_scalar_is_zero(&s2))); + /* The results can only be equal to one of the factors if that factor was zero, or the other factor was one. */ + CHECK(secp256k1_num_eq(&rnum, &snum) == (secp256k1_scalar_is_zero(&s) || secp256k1_scalar_is_one(&s2))); + CHECK(secp256k1_num_eq(&rnum, &s2num) == (secp256k1_scalar_is_zero(&s2) || secp256k1_scalar_is_one(&s))); + } + + { + secp256k1_scalar neg; + secp256k1_num negnum; + secp256k1_num negnum2; + /* Check that comparison with zero matches comparison with zero on the number. */ + CHECK(secp256k1_num_is_zero(&snum) == secp256k1_scalar_is_zero(&s)); + /* Check that comparison with the half order is equal to testing for high scalar. */ + CHECK(secp256k1_scalar_is_high(&s) == (secp256k1_num_cmp(&snum, &half_order) > 0)); + secp256k1_scalar_negate(&neg, &s); + secp256k1_num_sub(&negnum, &order, &snum); + secp256k1_num_mod(&negnum, &order); + /* Check that comparison with the half order is equal to testing for high scalar after negation. */ + CHECK(secp256k1_scalar_is_high(&neg) == (secp256k1_num_cmp(&negnum, &half_order) > 0)); + /* Negating should change the high property, unless the value was already zero. */ + CHECK((secp256k1_scalar_is_high(&s) == secp256k1_scalar_is_high(&neg)) == secp256k1_scalar_is_zero(&s)); + secp256k1_scalar_get_num(&negnum2, &neg); + /* Negating a scalar should be equal to (order - n) mod order on the number. */ + CHECK(secp256k1_num_eq(&negnum, &negnum2)); + secp256k1_scalar_add(&neg, &neg, &s); + /* Adding a number to its negation should result in zero. */ + CHECK(secp256k1_scalar_is_zero(&neg)); + secp256k1_scalar_negate(&neg, &neg); + /* Negating zero should still result in zero. */ + CHECK(secp256k1_scalar_is_zero(&neg)); + } + + { + /* Test secp256k1_scalar_mul_shift_var. */ + secp256k1_scalar r; + secp256k1_num one; + secp256k1_num rnum; + secp256k1_num rnum2; + unsigned char cone[1] = {0x01}; + unsigned int shift = 256 + secp256k1_rand_int(257); + secp256k1_scalar_mul_shift_var(&r, &s1, &s2, shift); + secp256k1_num_mul(&rnum, &s1num, &s2num); + secp256k1_num_shift(&rnum, shift - 1); + secp256k1_num_set_bin(&one, cone, 1); + secp256k1_num_add(&rnum, &rnum, &one); + secp256k1_num_shift(&rnum, 1); + secp256k1_scalar_get_num(&rnum2, &r); + CHECK(secp256k1_num_eq(&rnum, &rnum2)); + } + + { + /* test secp256k1_scalar_shr_int */ + secp256k1_scalar r; + int i; + random_scalar_order_test(&r); + for (i = 0; i < 100; ++i) { + int low; + int shift = 1 + secp256k1_rand_int(15); + int expected = r.d[0] % (1 << shift); + low = secp256k1_scalar_shr_int(&r, shift); + CHECK(expected == low); + } + } +#endif + + { + /* Test that scalar inverses are equal to the inverse of their number modulo the order. */ + if (!secp256k1_scalar_is_zero(&s)) { + secp256k1_scalar inv; +#ifndef USE_NUM_NONE + secp256k1_num invnum; + secp256k1_num invnum2; +#endif + secp256k1_scalar_inverse(&inv, &s); +#ifndef USE_NUM_NONE + secp256k1_num_mod_inverse(&invnum, &snum, &order); + secp256k1_scalar_get_num(&invnum2, &inv); + CHECK(secp256k1_num_eq(&invnum, &invnum2)); +#endif + secp256k1_scalar_mul(&inv, &inv, &s); + /* Multiplying a scalar with its inverse must result in one. */ + CHECK(secp256k1_scalar_is_one(&inv)); + secp256k1_scalar_inverse(&inv, &inv); + /* Inverting one must result in one. */ + CHECK(secp256k1_scalar_is_one(&inv)); +#ifndef USE_NUM_NONE + secp256k1_scalar_get_num(&invnum, &inv); + CHECK(secp256k1_num_is_one(&invnum)); +#endif + } + } + + { + /* Test commutativity of add. */ + secp256k1_scalar r1, r2; + secp256k1_scalar_add(&r1, &s1, &s2); + secp256k1_scalar_add(&r2, &s2, &s1); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + + { + secp256k1_scalar r1, r2; + secp256k1_scalar b; + int i; + /* Test add_bit. */ + int bit = secp256k1_rand_bits(8); + secp256k1_scalar_set_int(&b, 1); + CHECK(secp256k1_scalar_is_one(&b)); + for (i = 0; i < bit; i++) { + secp256k1_scalar_add(&b, &b, &b); + } + r1 = s1; + r2 = s1; + if (!secp256k1_scalar_add(&r1, &r1, &b)) { + /* No overflow happened. */ + secp256k1_scalar_cadd_bit(&r2, bit, 1); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + /* cadd is a noop when flag is zero */ + secp256k1_scalar_cadd_bit(&r2, bit, 0); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + } + + { + /* Test commutativity of mul. */ + secp256k1_scalar r1, r2; + secp256k1_scalar_mul(&r1, &s1, &s2); + secp256k1_scalar_mul(&r2, &s2, &s1); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + + { + /* Test associativity of add. */ + secp256k1_scalar r1, r2; + secp256k1_scalar_add(&r1, &s1, &s2); + secp256k1_scalar_add(&r1, &r1, &s); + secp256k1_scalar_add(&r2, &s2, &s); + secp256k1_scalar_add(&r2, &s1, &r2); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + + { + /* Test associativity of mul. */ + secp256k1_scalar r1, r2; + secp256k1_scalar_mul(&r1, &s1, &s2); + secp256k1_scalar_mul(&r1, &r1, &s); + secp256k1_scalar_mul(&r2, &s2, &s); + secp256k1_scalar_mul(&r2, &s1, &r2); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + + { + /* Test distributitivity of mul over add. */ + secp256k1_scalar r1, r2, t; + secp256k1_scalar_add(&r1, &s1, &s2); + secp256k1_scalar_mul(&r1, &r1, &s); + secp256k1_scalar_mul(&r2, &s1, &s); + secp256k1_scalar_mul(&t, &s2, &s); + secp256k1_scalar_add(&r2, &r2, &t); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + + { + /* Test square. */ + secp256k1_scalar r1, r2; + secp256k1_scalar_sqr(&r1, &s1); + secp256k1_scalar_mul(&r2, &s1, &s1); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + + { + /* Test multiplicative identity. */ + secp256k1_scalar r1, v1; + secp256k1_scalar_set_int(&v1,1); + secp256k1_scalar_mul(&r1, &s1, &v1); + CHECK(secp256k1_scalar_eq(&r1, &s1)); + } + + { + /* Test additive identity. */ + secp256k1_scalar r1, v0; + secp256k1_scalar_set_int(&v0,0); + secp256k1_scalar_add(&r1, &s1, &v0); + CHECK(secp256k1_scalar_eq(&r1, &s1)); + } + + { + /* Test zero product property. */ + secp256k1_scalar r1, v0; + secp256k1_scalar_set_int(&v0,0); + secp256k1_scalar_mul(&r1, &s1, &v0); + CHECK(secp256k1_scalar_eq(&r1, &v0)); + } + +} + +void run_scalar_tests(void) { + int i; + for (i = 0; i < 128 * count; i++) { + scalar_test(); + } + + { + /* (-1)+1 should be zero. */ + secp256k1_scalar s, o; + secp256k1_scalar_set_int(&s, 1); + CHECK(secp256k1_scalar_is_one(&s)); + secp256k1_scalar_negate(&o, &s); + secp256k1_scalar_add(&o, &o, &s); + CHECK(secp256k1_scalar_is_zero(&o)); + secp256k1_scalar_negate(&o, &o); + CHECK(secp256k1_scalar_is_zero(&o)); + } + +#ifndef USE_NUM_NONE + { + /* A scalar with value of the curve order should be 0. */ + secp256k1_num order; + secp256k1_scalar zero; + unsigned char bin[32]; + int overflow = 0; + secp256k1_scalar_order_get_num(&order); + secp256k1_num_get_bin(bin, 32, &order); + secp256k1_scalar_set_b32(&zero, bin, &overflow); + CHECK(overflow == 1); + CHECK(secp256k1_scalar_is_zero(&zero)); + } +#endif + + { + /* Does check_overflow check catch all ones? */ + static const secp256k1_scalar overflowed = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL + ); + CHECK(secp256k1_scalar_check_overflow(&overflowed)); + } + + { + /* Static test vectors. + * These were reduced from ~10^12 random vectors based on comparison-decision + * and edge-case coverage on 32-bit and 64-bit implementations. + * The responses were generated with Sage 5.9. + */ + secp256k1_scalar x; + secp256k1_scalar y; + secp256k1_scalar z; + secp256k1_scalar zz; + secp256k1_scalar one; + secp256k1_scalar r1; + secp256k1_scalar r2; +#if defined(USE_SCALAR_INV_NUM) + secp256k1_scalar zzv; +#endif + int overflow; + unsigned char chal[33][2][32] = { + {{0xff, 0xff, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff}}, + {{0xef, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x80, 0xff}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0x3f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x00}, + {0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x1e, 0xf8, 0xff, 0xff, 0xff, 0xfd, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xe0, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, + 0xf3, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x1c, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1f, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xfc, 0x9f, + 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0x0f, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0xf8, 0xff, 0x0f, 0xc0, 0xff, 0xff, + 0xff, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x07, 0x80, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0x00, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf0}, + {0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0x00, 0xf8, 0xff, 0x03, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0xc0, 0xff, 0x0f, 0xfc, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x00, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0x8f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x7f, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x0f, 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, 0xc0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0x7f}, + {0xff, 0xcf, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, + 0xbf, 0xff, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0x01, 0xfc, 0xff, 0x01, 0x00, 0xfe, 0xff}, + {0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7f, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf0, 0xff, 0xff, + 0xe0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xfc, 0xff, 0xff, 0x3f, 0xf0, 0xff, 0xff, 0x3f, + 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x0f, 0x7e, 0x00, 0x00}}, + {{0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x1f, 0x00, 0x00, 0xfe, 0x07, 0x00}, + {0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfb, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60}}, + {{0xff, 0x01, 0x00, 0xff, 0xff, 0xff, 0x0f, 0x00, + 0x80, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00}}, + {{0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0xff, 0xff, 0xcf, 0xff, 0x1f, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x7e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00}, + {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0x7f, 0x00, 0x80, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x80, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x1f, 0x00, 0xfe}}, + {{0xff, 0xff, 0xff, 0x3f, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0x03, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 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, 0x00, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}}, + {{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, 0x01}, + {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, 0x00}}, + {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xc0, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff}}, + {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {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, 0x02}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}, + {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, 0x01}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7e, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x07, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0x01, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x00, 0x00, 0xc0, 0xf1, 0x7f, 0x00}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00}, + {0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, + 0x00, 0x00, 0xfc, 0xff, 0xff, 0x01, 0xff, 0xff}}, + {{0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0x03, 0xe0, 0x01, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0xff, 0xf0, 0x07, 0x00, 0x3c, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x07, 0xe0, 0xff, 0x00, 0x00, 0x00}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x80, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x7f, 0xfe, 0xff, 0x1f, + 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0xfe, 0xff}}, + {{0xff, 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, + 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf0}, + {0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, + 0xf8, 0x07, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}}, + {{0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb, + 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}, + {0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb, + 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}} + }; + unsigned char res[33][2][32] = { + {{0x0c, 0x3b, 0x0a, 0xca, 0x8d, 0x1a, 0x2f, 0xb9, + 0x8a, 0x7b, 0x53, 0x5a, 0x1f, 0xc5, 0x22, 0xa1, + 0x07, 0x2a, 0x48, 0xea, 0x02, 0xeb, 0xb3, 0xd6, + 0x20, 0x1e, 0x86, 0xd0, 0x95, 0xf6, 0x92, 0x35}, + {0xdc, 0x90, 0x7a, 0x07, 0x2e, 0x1e, 0x44, 0x6d, + 0xf8, 0x15, 0x24, 0x5b, 0x5a, 0x96, 0x37, 0x9c, + 0x37, 0x7b, 0x0d, 0xac, 0x1b, 0x65, 0x58, 0x49, + 0x43, 0xb7, 0x31, 0xbb, 0xa7, 0xf4, 0x97, 0x15}}, + {{0xf1, 0xf7, 0x3a, 0x50, 0xe6, 0x10, 0xba, 0x22, + 0x43, 0x4d, 0x1f, 0x1f, 0x7c, 0x27, 0xca, 0x9c, + 0xb8, 0xb6, 0xa0, 0xfc, 0xd8, 0xc0, 0x05, 0x2f, + 0xf7, 0x08, 0xe1, 0x76, 0xdd, 0xd0, 0x80, 0xc8}, + {0xe3, 0x80, 0x80, 0xb8, 0xdb, 0xe3, 0xa9, 0x77, + 0x00, 0xb0, 0xf5, 0x2e, 0x27, 0xe2, 0x68, 0xc4, + 0x88, 0xe8, 0x04, 0xc1, 0x12, 0xbf, 0x78, 0x59, + 0xe6, 0xa9, 0x7c, 0xe1, 0x81, 0xdd, 0xb9, 0xd5}}, + {{0x96, 0xe2, 0xee, 0x01, 0xa6, 0x80, 0x31, 0xef, + 0x5c, 0xd0, 0x19, 0xb4, 0x7d, 0x5f, 0x79, 0xab, + 0xa1, 0x97, 0xd3, 0x7e, 0x33, 0xbb, 0x86, 0x55, + 0x60, 0x20, 0x10, 0x0d, 0x94, 0x2d, 0x11, 0x7c}, + {0xcc, 0xab, 0xe0, 0xe8, 0x98, 0x65, 0x12, 0x96, + 0x38, 0x5a, 0x1a, 0xf2, 0x85, 0x23, 0x59, 0x5f, + 0xf9, 0xf3, 0xc2, 0x81, 0x70, 0x92, 0x65, 0x12, + 0x9c, 0x65, 0x1e, 0x96, 0x00, 0xef, 0xe7, 0x63}}, + {{0xac, 0x1e, 0x62, 0xc2, 0x59, 0xfc, 0x4e, 0x5c, + 0x83, 0xb0, 0xd0, 0x6f, 0xce, 0x19, 0xf6, 0xbf, + 0xa4, 0xb0, 0xe0, 0x53, 0x66, 0x1f, 0xbf, 0xc9, + 0x33, 0x47, 0x37, 0xa9, 0x3d, 0x5d, 0xb0, 0x48}, + {0x86, 0xb9, 0x2a, 0x7f, 0x8e, 0xa8, 0x60, 0x42, + 0x26, 0x6d, 0x6e, 0x1c, 0xa2, 0xec, 0xe0, 0xe5, + 0x3e, 0x0a, 0x33, 0xbb, 0x61, 0x4c, 0x9f, 0x3c, + 0xd1, 0xdf, 0x49, 0x33, 0xcd, 0x72, 0x78, 0x18}}, + {{0xf7, 0xd3, 0xcd, 0x49, 0x5c, 0x13, 0x22, 0xfb, + 0x2e, 0xb2, 0x2f, 0x27, 0xf5, 0x8a, 0x5d, 0x74, + 0xc1, 0x58, 0xc5, 0xc2, 0x2d, 0x9f, 0x52, 0xc6, + 0x63, 0x9f, 0xba, 0x05, 0x76, 0x45, 0x7a, 0x63}, + {0x8a, 0xfa, 0x55, 0x4d, 0xdd, 0xa3, 0xb2, 0xc3, + 0x44, 0xfd, 0xec, 0x72, 0xde, 0xef, 0xc0, 0x99, + 0xf5, 0x9f, 0xe2, 0x52, 0xb4, 0x05, 0x32, 0x58, + 0x57, 0xc1, 0x8f, 0xea, 0xc3, 0x24, 0x5b, 0x94}}, + {{0x05, 0x83, 0xee, 0xdd, 0x64, 0xf0, 0x14, 0x3b, + 0xa0, 0x14, 0x4a, 0x3a, 0x41, 0x82, 0x7c, 0xa7, + 0x2c, 0xaa, 0xb1, 0x76, 0xbb, 0x59, 0x64, 0x5f, + 0x52, 0xad, 0x25, 0x29, 0x9d, 0x8f, 0x0b, 0xb0}, + {0x7e, 0xe3, 0x7c, 0xca, 0xcd, 0x4f, 0xb0, 0x6d, + 0x7a, 0xb2, 0x3e, 0xa0, 0x08, 0xb9, 0xa8, 0x2d, + 0xc2, 0xf4, 0x99, 0x66, 0xcc, 0xac, 0xd8, 0xb9, + 0x72, 0x2a, 0x4a, 0x3e, 0x0f, 0x7b, 0xbf, 0xf4}}, + {{0x8c, 0x9c, 0x78, 0x2b, 0x39, 0x61, 0x7e, 0xf7, + 0x65, 0x37, 0x66, 0x09, 0x38, 0xb9, 0x6f, 0x70, + 0x78, 0x87, 0xff, 0xcf, 0x93, 0xca, 0x85, 0x06, + 0x44, 0x84, 0xa7, 0xfe, 0xd3, 0xa4, 0xe3, 0x7e}, + {0xa2, 0x56, 0x49, 0x23, 0x54, 0xa5, 0x50, 0xe9, + 0x5f, 0xf0, 0x4d, 0xe7, 0xdc, 0x38, 0x32, 0x79, + 0x4f, 0x1c, 0xb7, 0xe4, 0xbb, 0xf8, 0xbb, 0x2e, + 0x40, 0x41, 0x4b, 0xcc, 0xe3, 0x1e, 0x16, 0x36}}, + {{0x0c, 0x1e, 0xd7, 0x09, 0x25, 0x40, 0x97, 0xcb, + 0x5c, 0x46, 0xa8, 0xda, 0xef, 0x25, 0xd5, 0xe5, + 0x92, 0x4d, 0xcf, 0xa3, 0xc4, 0x5d, 0x35, 0x4a, + 0xe4, 0x61, 0x92, 0xf3, 0xbf, 0x0e, 0xcd, 0xbe}, + {0xe4, 0xaf, 0x0a, 0xb3, 0x30, 0x8b, 0x9b, 0x48, + 0x49, 0x43, 0xc7, 0x64, 0x60, 0x4a, 0x2b, 0x9e, + 0x95, 0x5f, 0x56, 0xe8, 0x35, 0xdc, 0xeb, 0xdc, + 0xc7, 0xc4, 0xfe, 0x30, 0x40, 0xc7, 0xbf, 0xa4}}, + {{0xd4, 0xa0, 0xf5, 0x81, 0x49, 0x6b, 0xb6, 0x8b, + 0x0a, 0x69, 0xf9, 0xfe, 0xa8, 0x32, 0xe5, 0xe0, + 0xa5, 0xcd, 0x02, 0x53, 0xf9, 0x2c, 0xe3, 0x53, + 0x83, 0x36, 0xc6, 0x02, 0xb5, 0xeb, 0x64, 0xb8}, + {0x1d, 0x42, 0xb9, 0xf9, 0xe9, 0xe3, 0x93, 0x2c, + 0x4c, 0xee, 0x6c, 0x5a, 0x47, 0x9e, 0x62, 0x01, + 0x6b, 0x04, 0xfe, 0xa4, 0x30, 0x2b, 0x0d, 0x4f, + 0x71, 0x10, 0xd3, 0x55, 0xca, 0xf3, 0x5e, 0x80}}, + {{0x77, 0x05, 0xf6, 0x0c, 0x15, 0x9b, 0x45, 0xe7, + 0xb9, 0x11, 0xb8, 0xf5, 0xd6, 0xda, 0x73, 0x0c, + 0xda, 0x92, 0xea, 0xd0, 0x9d, 0xd0, 0x18, 0x92, + 0xce, 0x9a, 0xaa, 0xee, 0x0f, 0xef, 0xde, 0x30}, + {0xf1, 0xf1, 0xd6, 0x9b, 0x51, 0xd7, 0x77, 0x62, + 0x52, 0x10, 0xb8, 0x7a, 0x84, 0x9d, 0x15, 0x4e, + 0x07, 0xdc, 0x1e, 0x75, 0x0d, 0x0c, 0x3b, 0xdb, + 0x74, 0x58, 0x62, 0x02, 0x90, 0x54, 0x8b, 0x43}}, + {{0xa6, 0xfe, 0x0b, 0x87, 0x80, 0x43, 0x67, 0x25, + 0x57, 0x5d, 0xec, 0x40, 0x50, 0x08, 0xd5, 0x5d, + 0x43, 0xd7, 0xe0, 0xaa, 0xe0, 0x13, 0xb6, 0xb0, + 0xc0, 0xd4, 0xe5, 0x0d, 0x45, 0x83, 0xd6, 0x13}, + {0x40, 0x45, 0x0a, 0x92, 0x31, 0xea, 0x8c, 0x60, + 0x8c, 0x1f, 0xd8, 0x76, 0x45, 0xb9, 0x29, 0x00, + 0x26, 0x32, 0xd8, 0xa6, 0x96, 0x88, 0xe2, 0xc4, + 0x8b, 0xdb, 0x7f, 0x17, 0x87, 0xcc, 0xc8, 0xf2}}, + {{0xc2, 0x56, 0xe2, 0xb6, 0x1a, 0x81, 0xe7, 0x31, + 0x63, 0x2e, 0xbb, 0x0d, 0x2f, 0x81, 0x67, 0xd4, + 0x22, 0xe2, 0x38, 0x02, 0x25, 0x97, 0xc7, 0x88, + 0x6e, 0xdf, 0xbe, 0x2a, 0xa5, 0x73, 0x63, 0xaa}, + {0x50, 0x45, 0xe2, 0xc3, 0xbd, 0x89, 0xfc, 0x57, + 0xbd, 0x3c, 0xa3, 0x98, 0x7e, 0x7f, 0x36, 0x38, + 0x92, 0x39, 0x1f, 0x0f, 0x81, 0x1a, 0x06, 0x51, + 0x1f, 0x8d, 0x6a, 0xff, 0x47, 0x16, 0x06, 0x9c}}, + {{0x33, 0x95, 0xa2, 0x6f, 0x27, 0x5f, 0x9c, 0x9c, + 0x64, 0x45, 0xcb, 0xd1, 0x3c, 0xee, 0x5e, 0x5f, + 0x48, 0xa6, 0xaf, 0xe3, 0x79, 0xcf, 0xb1, 0xe2, + 0xbf, 0x55, 0x0e, 0xa2, 0x3b, 0x62, 0xf0, 0xe4}, + {0x14, 0xe8, 0x06, 0xe3, 0xbe, 0x7e, 0x67, 0x01, + 0xc5, 0x21, 0x67, 0xd8, 0x54, 0xb5, 0x7f, 0xa4, + 0xf9, 0x75, 0x70, 0x1c, 0xfd, 0x79, 0xdb, 0x86, + 0xad, 0x37, 0x85, 0x83, 0x56, 0x4e, 0xf0, 0xbf}}, + {{0xbc, 0xa6, 0xe0, 0x56, 0x4e, 0xef, 0xfa, 0xf5, + 0x1d, 0x5d, 0x3f, 0x2a, 0x5b, 0x19, 0xab, 0x51, + 0xc5, 0x8b, 0xdd, 0x98, 0x28, 0x35, 0x2f, 0xc3, + 0x81, 0x4f, 0x5c, 0xe5, 0x70, 0xb9, 0xeb, 0x62}, + {0xc4, 0x6d, 0x26, 0xb0, 0x17, 0x6b, 0xfe, 0x6c, + 0x12, 0xf8, 0xe7, 0xc1, 0xf5, 0x2f, 0xfa, 0x91, + 0x13, 0x27, 0xbd, 0x73, 0xcc, 0x33, 0x31, 0x1c, + 0x39, 0xe3, 0x27, 0x6a, 0x95, 0xcf, 0xc5, 0xfb}}, + {{0x30, 0xb2, 0x99, 0x84, 0xf0, 0x18, 0x2a, 0x6e, + 0x1e, 0x27, 0xed, 0xa2, 0x29, 0x99, 0x41, 0x56, + 0xe8, 0xd4, 0x0d, 0xef, 0x99, 0x9c, 0xf3, 0x58, + 0x29, 0x55, 0x1a, 0xc0, 0x68, 0xd6, 0x74, 0xa4}, + {0x07, 0x9c, 0xe7, 0xec, 0xf5, 0x36, 0x73, 0x41, + 0xa3, 0x1c, 0xe5, 0x93, 0x97, 0x6a, 0xfd, 0xf7, + 0x53, 0x18, 0xab, 0xaf, 0xeb, 0x85, 0xbd, 0x92, + 0x90, 0xab, 0x3c, 0xbf, 0x30, 0x82, 0xad, 0xf6}}, + {{0xc6, 0x87, 0x8a, 0x2a, 0xea, 0xc0, 0xa9, 0xec, + 0x6d, 0xd3, 0xdc, 0x32, 0x23, 0xce, 0x62, 0x19, + 0xa4, 0x7e, 0xa8, 0xdd, 0x1c, 0x33, 0xae, 0xd3, + 0x4f, 0x62, 0x9f, 0x52, 0xe7, 0x65, 0x46, 0xf4}, + {0x97, 0x51, 0x27, 0x67, 0x2d, 0xa2, 0x82, 0x87, + 0x98, 0xd3, 0xb6, 0x14, 0x7f, 0x51, 0xd3, 0x9a, + 0x0b, 0xd0, 0x76, 0x81, 0xb2, 0x4f, 0x58, 0x92, + 0xa4, 0x86, 0xa1, 0xa7, 0x09, 0x1d, 0xef, 0x9b}}, + {{0xb3, 0x0f, 0x2b, 0x69, 0x0d, 0x06, 0x90, 0x64, + 0xbd, 0x43, 0x4c, 0x10, 0xe8, 0x98, 0x1c, 0xa3, + 0xe1, 0x68, 0xe9, 0x79, 0x6c, 0x29, 0x51, 0x3f, + 0x41, 0xdc, 0xdf, 0x1f, 0xf3, 0x60, 0xbe, 0x33}, + {0xa1, 0x5f, 0xf7, 0x1d, 0xb4, 0x3e, 0x9b, 0x3c, + 0xe7, 0xbd, 0xb6, 0x06, 0xd5, 0x60, 0x06, 0x6d, + 0x50, 0xd2, 0xf4, 0x1a, 0x31, 0x08, 0xf2, 0xea, + 0x8e, 0xef, 0x5f, 0x7d, 0xb6, 0xd0, 0xc0, 0x27}}, + {{0x62, 0x9a, 0xd9, 0xbb, 0x38, 0x36, 0xce, 0xf7, + 0x5d, 0x2f, 0x13, 0xec, 0xc8, 0x2d, 0x02, 0x8a, + 0x2e, 0x72, 0xf0, 0xe5, 0x15, 0x9d, 0x72, 0xae, + 0xfc, 0xb3, 0x4f, 0x02, 0xea, 0xe1, 0x09, 0xfe}, + {0x00, 0x00, 0x00, 0x00, 0xfa, 0x0a, 0x3d, 0xbc, + 0xad, 0x16, 0x0c, 0xb6, 0xe7, 0x7c, 0x8b, 0x39, + 0x9a, 0x43, 0xbb, 0xe3, 0xc2, 0x55, 0x15, 0x14, + 0x75, 0xac, 0x90, 0x9b, 0x7f, 0x9a, 0x92, 0x00}}, + {{0x8b, 0xac, 0x70, 0x86, 0x29, 0x8f, 0x00, 0x23, + 0x7b, 0x45, 0x30, 0xaa, 0xb8, 0x4c, 0xc7, 0x8d, + 0x4e, 0x47, 0x85, 0xc6, 0x19, 0xe3, 0x96, 0xc2, + 0x9a, 0xa0, 0x12, 0xed, 0x6f, 0xd7, 0x76, 0x16}, + {0x45, 0xaf, 0x7e, 0x33, 0xc7, 0x7f, 0x10, 0x6c, + 0x7c, 0x9f, 0x29, 0xc1, 0xa8, 0x7e, 0x15, 0x84, + 0xe7, 0x7d, 0xc0, 0x6d, 0xab, 0x71, 0x5d, 0xd0, + 0x6b, 0x9f, 0x97, 0xab, 0xcb, 0x51, 0x0c, 0x9f}}, + {{0x9e, 0xc3, 0x92, 0xb4, 0x04, 0x9f, 0xc8, 0xbb, + 0xdd, 0x9e, 0xc6, 0x05, 0xfd, 0x65, 0xec, 0x94, + 0x7f, 0x2c, 0x16, 0xc4, 0x40, 0xac, 0x63, 0x7b, + 0x7d, 0xb8, 0x0c, 0xe4, 0x5b, 0xe3, 0xa7, 0x0e}, + {0x43, 0xf4, 0x44, 0xe8, 0xcc, 0xc8, 0xd4, 0x54, + 0x33, 0x37, 0x50, 0xf2, 0x87, 0x42, 0x2e, 0x00, + 0x49, 0x60, 0x62, 0x02, 0xfd, 0x1a, 0x7c, 0xdb, + 0x29, 0x6c, 0x6d, 0x54, 0x53, 0x08, 0xd1, 0xc8}}, + {{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, 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, 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, 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, 0x00, 0x00, 0x00, 0x01}}, + {{0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}, + {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}}, + {{0x28, 0x56, 0xac, 0x0e, 0x4f, 0x98, 0x09, 0xf0, + 0x49, 0xfa, 0x7f, 0x84, 0xac, 0x7e, 0x50, 0x5b, + 0x17, 0x43, 0x14, 0x89, 0x9c, 0x53, 0xa8, 0x94, + 0x30, 0xf2, 0x11, 0x4d, 0x92, 0x14, 0x27, 0xe8}, + {0x39, 0x7a, 0x84, 0x56, 0x79, 0x9d, 0xec, 0x26, + 0x2c, 0x53, 0xc1, 0x94, 0xc9, 0x8d, 0x9e, 0x9d, + 0x32, 0x1f, 0xdd, 0x84, 0x04, 0xe8, 0xe2, 0x0a, + 0x6b, 0xbe, 0xbb, 0x42, 0x40, 0x67, 0x30, 0x6c}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x73, 0x2f, 0xc9, 0xbe, 0xbd}, + {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}, + {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, 0x01}}, + {{0x1c, 0xc4, 0xf7, 0xda, 0x0f, 0x65, 0xca, 0x39, + 0x70, 0x52, 0x92, 0x8e, 0xc3, 0xc8, 0x15, 0xea, + 0x7f, 0x10, 0x9e, 0x77, 0x4b, 0x6e, 0x2d, 0xdf, + 0xe8, 0x30, 0x9d, 0xda, 0xe8, 0x9a, 0x65, 0xae}, + {0x02, 0xb0, 0x16, 0xb1, 0x1d, 0xc8, 0x57, 0x7b, + 0xa2, 0x3a, 0xa2, 0xa3, 0x38, 0x5c, 0x8f, 0xeb, + 0x66, 0x37, 0x91, 0xa8, 0x5f, 0xef, 0x04, 0xf6, + 0x59, 0x75, 0xe1, 0xee, 0x92, 0xf6, 0x0e, 0x30}}, + {{0x8d, 0x76, 0x14, 0xa4, 0x14, 0x06, 0x9f, 0x9a, + 0xdf, 0x4a, 0x85, 0xa7, 0x6b, 0xbf, 0x29, 0x6f, + 0xbc, 0x34, 0x87, 0x5d, 0xeb, 0xbb, 0x2e, 0xa9, + 0xc9, 0x1f, 0x58, 0xd6, 0x9a, 0x82, 0xa0, 0x56}, + {0xd4, 0xb9, 0xdb, 0x88, 0x1d, 0x04, 0xe9, 0x93, + 0x8d, 0x3f, 0x20, 0xd5, 0x86, 0xa8, 0x83, 0x07, + 0xdb, 0x09, 0xd8, 0x22, 0x1f, 0x7f, 0xf1, 0x71, + 0xc8, 0xe7, 0x5d, 0x47, 0xaf, 0x8b, 0x72, 0xe9}}, + {{0x83, 0xb9, 0x39, 0xb2, 0xa4, 0xdf, 0x46, 0x87, + 0xc2, 0xb8, 0xf1, 0xe6, 0x4c, 0xd1, 0xe2, 0xa9, + 0xe4, 0x70, 0x30, 0x34, 0xbc, 0x52, 0x7c, 0x55, + 0xa6, 0xec, 0x80, 0xa4, 0xe5, 0xd2, 0xdc, 0x73}, + {0x08, 0xf1, 0x03, 0xcf, 0x16, 0x73, 0xe8, 0x7d, + 0xb6, 0x7e, 0x9b, 0xc0, 0xb4, 0xc2, 0xa5, 0x86, + 0x02, 0x77, 0xd5, 0x27, 0x86, 0xa5, 0x15, 0xfb, + 0xae, 0x9b, 0x8c, 0xa9, 0xf9, 0xf8, 0xa8, 0x4a}}, + {{0x8b, 0x00, 0x49, 0xdb, 0xfa, 0xf0, 0x1b, 0xa2, + 0xed, 0x8a, 0x9a, 0x7a, 0x36, 0x78, 0x4a, 0xc7, + 0xf7, 0xad, 0x39, 0xd0, 0x6c, 0x65, 0x7a, 0x41, + 0xce, 0xd6, 0xd6, 0x4c, 0x20, 0x21, 0x6b, 0xc7}, + {0xc6, 0xca, 0x78, 0x1d, 0x32, 0x6c, 0x6c, 0x06, + 0x91, 0xf2, 0x1a, 0xe8, 0x43, 0x16, 0xea, 0x04, + 0x3c, 0x1f, 0x07, 0x85, 0xf7, 0x09, 0x22, 0x08, + 0xba, 0x13, 0xfd, 0x78, 0x1e, 0x3f, 0x6f, 0x62}}, + {{0x25, 0x9b, 0x7c, 0xb0, 0xac, 0x72, 0x6f, 0xb2, + 0xe3, 0x53, 0x84, 0x7a, 0x1a, 0x9a, 0x98, 0x9b, + 0x44, 0xd3, 0x59, 0xd0, 0x8e, 0x57, 0x41, 0x40, + 0x78, 0xa7, 0x30, 0x2f, 0x4c, 0x9c, 0xb9, 0x68}, + {0xb7, 0x75, 0x03, 0x63, 0x61, 0xc2, 0x48, 0x6e, + 0x12, 0x3d, 0xbf, 0x4b, 0x27, 0xdf, 0xb1, 0x7a, + 0xff, 0x4e, 0x31, 0x07, 0x83, 0xf4, 0x62, 0x5b, + 0x19, 0xa5, 0xac, 0xa0, 0x32, 0x58, 0x0d, 0xa7}}, + {{0x43, 0x4f, 0x10, 0xa4, 0xca, 0xdb, 0x38, 0x67, + 0xfa, 0xae, 0x96, 0xb5, 0x6d, 0x97, 0xff, 0x1f, + 0xb6, 0x83, 0x43, 0xd3, 0xa0, 0x2d, 0x70, 0x7a, + 0x64, 0x05, 0x4c, 0xa7, 0xc1, 0xa5, 0x21, 0x51}, + {0xe4, 0xf1, 0x23, 0x84, 0xe1, 0xb5, 0x9d, 0xf2, + 0xb8, 0x73, 0x8b, 0x45, 0x2b, 0x35, 0x46, 0x38, + 0x10, 0x2b, 0x50, 0xf8, 0x8b, 0x35, 0xcd, 0x34, + 0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}}, + {{0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34, + 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13, + 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46, + 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}, + {0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34, + 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13, + 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46, + 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}} + }; + secp256k1_scalar_set_int(&one, 1); + for (i = 0; i < 33; i++) { + secp256k1_scalar_set_b32(&x, chal[i][0], &overflow); + CHECK(!overflow); + secp256k1_scalar_set_b32(&y, chal[i][1], &overflow); + CHECK(!overflow); + secp256k1_scalar_set_b32(&r1, res[i][0], &overflow); + CHECK(!overflow); + secp256k1_scalar_set_b32(&r2, res[i][1], &overflow); + CHECK(!overflow); + secp256k1_scalar_mul(&z, &x, &y); + CHECK(!secp256k1_scalar_check_overflow(&z)); + CHECK(secp256k1_scalar_eq(&r1, &z)); + if (!secp256k1_scalar_is_zero(&y)) { + secp256k1_scalar_inverse(&zz, &y); + CHECK(!secp256k1_scalar_check_overflow(&zz)); +#if defined(USE_SCALAR_INV_NUM) + secp256k1_scalar_inverse_var(&zzv, &y); + CHECK(secp256k1_scalar_eq(&zzv, &zz)); +#endif + secp256k1_scalar_mul(&z, &z, &zz); + CHECK(!secp256k1_scalar_check_overflow(&z)); + CHECK(secp256k1_scalar_eq(&x, &z)); + secp256k1_scalar_mul(&zz, &zz, &y); + CHECK(!secp256k1_scalar_check_overflow(&zz)); + CHECK(secp256k1_scalar_eq(&one, &zz)); + } + secp256k1_scalar_mul(&z, &x, &x); + CHECK(!secp256k1_scalar_check_overflow(&z)); + secp256k1_scalar_sqr(&zz, &x); + CHECK(!secp256k1_scalar_check_overflow(&zz)); + CHECK(secp256k1_scalar_eq(&zz, &z)); + CHECK(secp256k1_scalar_eq(&r2, &zz)); + } + } +} + +/***** FIELD TESTS *****/ + +void random_fe(secp256k1_fe *x) { + unsigned char bin[32]; + do { + secp256k1_rand256(bin); + if (secp256k1_fe_set_b32(x, bin)) { + return; + } + } while(1); +} + +void random_fe_test(secp256k1_fe *x) { + unsigned char bin[32]; + do { + secp256k1_rand256_test(bin); + if (secp256k1_fe_set_b32(x, bin)) { + return; + } + } while(1); +} + +void random_fe_non_zero(secp256k1_fe *nz) { + int tries = 10; + while (--tries >= 0) { + random_fe(nz); + secp256k1_fe_normalize(nz); + if (!secp256k1_fe_is_zero(nz)) { + break; + } + } + /* Infinitesimal probability of spurious failure here */ + CHECK(tries >= 0); +} + +void random_fe_non_square(secp256k1_fe *ns) { + secp256k1_fe r; + random_fe_non_zero(ns); + if (secp256k1_fe_sqrt(&r, ns)) { + secp256k1_fe_negate(ns, ns, 1); + } +} + +int check_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe an = *a; + secp256k1_fe bn = *b; + secp256k1_fe_normalize_weak(&an); + secp256k1_fe_normalize_var(&bn); + return secp256k1_fe_equal_var(&an, &bn); +} + +int check_fe_inverse(const secp256k1_fe *a, const secp256k1_fe *ai) { + secp256k1_fe x; + secp256k1_fe one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_fe_mul(&x, a, ai); + return check_fe_equal(&x, &one); +} + +void run_field_convert(void) { + static const unsigned char b32[32] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, + 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40 + }; + static const secp256k1_fe_storage fes = SECP256K1_FE_STORAGE_CONST( + 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, + 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL + ); + static const secp256k1_fe fe = SECP256K1_FE_CONST( + 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, + 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL + ); + secp256k1_fe fe2; + unsigned char b322[32]; + secp256k1_fe_storage fes2; + /* Check conversions to fe. */ + CHECK(secp256k1_fe_set_b32(&fe2, b32)); + CHECK(secp256k1_fe_equal_var(&fe, &fe2)); + secp256k1_fe_from_storage(&fe2, &fes); + CHECK(secp256k1_fe_equal_var(&fe, &fe2)); + /* Check conversion from fe. */ + secp256k1_fe_get_b32(b322, &fe); + CHECK(memcmp(b322, b32, 32) == 0); + secp256k1_fe_to_storage(&fes2, &fe); + CHECK(memcmp(&fes2, &fes, sizeof(fes)) == 0); +} + +int fe_memcmp(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe t = *b; +#ifdef VERIFY + t.magnitude = a->magnitude; + t.normalized = a->normalized; +#endif + return memcmp(a, &t, sizeof(secp256k1_fe)); +} + +void run_field_misc(void) { + secp256k1_fe x; + secp256k1_fe y; + secp256k1_fe z; + secp256k1_fe q; + secp256k1_fe fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5); + int i, j; + for (i = 0; i < 5*count; i++) { + secp256k1_fe_storage xs, ys, zs; + random_fe(&x); + random_fe_non_zero(&y); + /* Test the fe equality and comparison operations. */ + CHECK(secp256k1_fe_cmp_var(&x, &x) == 0); + CHECK(secp256k1_fe_equal_var(&x, &x)); + z = x; + secp256k1_fe_add(&z,&y); + /* Test fe conditional move; z is not normalized here. */ + q = x; + secp256k1_fe_cmov(&x, &z, 0); + VERIFY_CHECK(!x.normalized && x.magnitude == z.magnitude); + secp256k1_fe_cmov(&x, &x, 1); + CHECK(fe_memcmp(&x, &z) != 0); + CHECK(fe_memcmp(&x, &q) == 0); + secp256k1_fe_cmov(&q, &z, 1); + VERIFY_CHECK(!q.normalized && q.magnitude == z.magnitude); + CHECK(fe_memcmp(&q, &z) == 0); + secp256k1_fe_normalize_var(&x); + secp256k1_fe_normalize_var(&z); + CHECK(!secp256k1_fe_equal_var(&x, &z)); + secp256k1_fe_normalize_var(&q); + secp256k1_fe_cmov(&q, &z, (i&1)); + VERIFY_CHECK(q.normalized && q.magnitude == 1); + for (j = 0; j < 6; j++) { + secp256k1_fe_negate(&z, &z, j+1); + secp256k1_fe_normalize_var(&q); + secp256k1_fe_cmov(&q, &z, (j&1)); + VERIFY_CHECK(!q.normalized && q.magnitude == (j+2)); + } + secp256k1_fe_normalize_var(&z); + /* Test storage conversion and conditional moves. */ + secp256k1_fe_to_storage(&xs, &x); + secp256k1_fe_to_storage(&ys, &y); + secp256k1_fe_to_storage(&zs, &z); + secp256k1_fe_storage_cmov(&zs, &xs, 0); + secp256k1_fe_storage_cmov(&zs, &zs, 1); + CHECK(memcmp(&xs, &zs, sizeof(xs)) != 0); + secp256k1_fe_storage_cmov(&ys, &xs, 1); + CHECK(memcmp(&xs, &ys, sizeof(xs)) == 0); + secp256k1_fe_from_storage(&x, &xs); + secp256k1_fe_from_storage(&y, &ys); + secp256k1_fe_from_storage(&z, &zs); + /* Test that mul_int, mul, and add agree. */ + secp256k1_fe_add(&y, &x); + secp256k1_fe_add(&y, &x); + z = x; + secp256k1_fe_mul_int(&z, 3); + CHECK(check_fe_equal(&y, &z)); + secp256k1_fe_add(&y, &x); + secp256k1_fe_add(&z, &x); + CHECK(check_fe_equal(&z, &y)); + z = x; + secp256k1_fe_mul_int(&z, 5); + secp256k1_fe_mul(&q, &x, &fe5); + CHECK(check_fe_equal(&z, &q)); + secp256k1_fe_negate(&x, &x, 1); + secp256k1_fe_add(&z, &x); + secp256k1_fe_add(&q, &x); + CHECK(check_fe_equal(&y, &z)); + CHECK(check_fe_equal(&q, &y)); + } +} + +void run_field_inv(void) { + secp256k1_fe x, xi, xii; + int i; + for (i = 0; i < 10*count; i++) { + random_fe_non_zero(&x); + secp256k1_fe_inv(&xi, &x); + CHECK(check_fe_inverse(&x, &xi)); + secp256k1_fe_inv(&xii, &xi); + CHECK(check_fe_equal(&x, &xii)); + } +} + +void run_field_inv_var(void) { + secp256k1_fe x, xi, xii; + int i; + for (i = 0; i < 10*count; i++) { + random_fe_non_zero(&x); + secp256k1_fe_inv_var(&xi, &x); + CHECK(check_fe_inverse(&x, &xi)); + secp256k1_fe_inv_var(&xii, &xi); + CHECK(check_fe_equal(&x, &xii)); + } +} + +void run_field_inv_all_var(void) { + secp256k1_fe x[16], xi[16], xii[16]; + int i; + /* Check it's safe to call for 0 elements */ + secp256k1_fe_inv_all_var(0, xi, x); + for (i = 0; i < count; i++) { + size_t j; + size_t len = secp256k1_rand_int(15) + 1; + for (j = 0; j < len; j++) { + random_fe_non_zero(&x[j]); + } + secp256k1_fe_inv_all_var(len, xi, x); + for (j = 0; j < len; j++) { + CHECK(check_fe_inverse(&x[j], &xi[j])); + } + secp256k1_fe_inv_all_var(len, xii, xi); + for (j = 0; j < len; j++) { + CHECK(check_fe_equal(&x[j], &xii[j])); + } + } +} + +void run_sqr(void) { + secp256k1_fe x, s; + + { + int i; + secp256k1_fe_set_int(&x, 1); + secp256k1_fe_negate(&x, &x, 1); + + for (i = 1; i <= 512; ++i) { + secp256k1_fe_mul_int(&x, 2); + secp256k1_fe_normalize(&x); + secp256k1_fe_sqr(&s, &x); + } + } +} + +void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) { + secp256k1_fe r1, r2; + int v = secp256k1_fe_sqrt(&r1, a); + CHECK((v == 0) == (k == NULL)); + + if (k != NULL) { + /* Check that the returned root is +/- the given known answer */ + secp256k1_fe_negate(&r2, &r1, 1); + secp256k1_fe_add(&r1, k); secp256k1_fe_add(&r2, k); + secp256k1_fe_normalize(&r1); secp256k1_fe_normalize(&r2); + CHECK(secp256k1_fe_is_zero(&r1) || secp256k1_fe_is_zero(&r2)); + } +} + +void run_sqrt(void) { + secp256k1_fe ns, x, s, t; + int i; + + /* Check sqrt(0) is 0 */ + secp256k1_fe_set_int(&x, 0); + secp256k1_fe_sqr(&s, &x); + test_sqrt(&s, &x); + + /* Check sqrt of small squares (and their negatives) */ + for (i = 1; i <= 100; i++) { + secp256k1_fe_set_int(&x, i); + secp256k1_fe_sqr(&s, &x); + test_sqrt(&s, &x); + secp256k1_fe_negate(&t, &s, 1); + test_sqrt(&t, NULL); + } + + /* Consistency checks for large random values */ + for (i = 0; i < 10; i++) { + int j; + random_fe_non_square(&ns); + for (j = 0; j < count; j++) { + random_fe(&x); + secp256k1_fe_sqr(&s, &x); + test_sqrt(&s, &x); + secp256k1_fe_negate(&t, &s, 1); + test_sqrt(&t, NULL); + secp256k1_fe_mul(&t, &s, &ns); + test_sqrt(&t, NULL); + } + } +} + +/***** GROUP TESTS *****/ + +void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { + CHECK(a->infinity == b->infinity); + if (a->infinity) { + return; + } + CHECK(secp256k1_fe_equal_var(&a->x, &b->x)); + CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); +} + +/* This compares jacobian points including their Z, not just their geometric meaning. */ +int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) { + secp256k1_gej a2; + secp256k1_gej b2; + int ret = 1; + ret &= a->infinity == b->infinity; + if (ret && !a->infinity) { + a2 = *a; + b2 = *b; + secp256k1_fe_normalize(&a2.x); + secp256k1_fe_normalize(&a2.y); + secp256k1_fe_normalize(&a2.z); + secp256k1_fe_normalize(&b2.x); + secp256k1_fe_normalize(&b2.y); + secp256k1_fe_normalize(&b2.z); + ret &= secp256k1_fe_cmp_var(&a2.x, &b2.x) == 0; + ret &= secp256k1_fe_cmp_var(&a2.y, &b2.y) == 0; + ret &= secp256k1_fe_cmp_var(&a2.z, &b2.z) == 0; + } + return ret; +} + +void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { + secp256k1_fe z2s; + secp256k1_fe u1, u2, s1, s2; + CHECK(a->infinity == b->infinity); + if (a->infinity) { + return; + } + /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */ + secp256k1_fe_sqr(&z2s, &b->z); + secp256k1_fe_mul(&u1, &a->x, &z2s); + u2 = b->x; secp256k1_fe_normalize_weak(&u2); + secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z); + s2 = b->y; secp256k1_fe_normalize_weak(&s2); + CHECK(secp256k1_fe_equal_var(&u1, &u2)); + CHECK(secp256k1_fe_equal_var(&s1, &s2)); +} + +void test_ge(void) { + int i, i1; +#ifdef USE_ENDOMORPHISM + int runs = 6; +#else + int runs = 4; +#endif + /* Points: (infinity, p1, p1, -p1, -p1, p2, p2, -p2, -p2, p3, p3, -p3, -p3, p4, p4, -p4, -p4). + * The second in each pair of identical points uses a random Z coordinate in the Jacobian form. + * All magnitudes are randomized. + * All 17*17 combinations of points are added to each other, using all applicable methods. + * + * When the endomorphism code is compiled in, p5 = lambda*p1 and p6 = lambda^2*p1 are added as well. + */ + secp256k1_ge *ge = (secp256k1_ge *)malloc(sizeof(secp256k1_ge) * (1 + 4 * runs)); + secp256k1_gej *gej = (secp256k1_gej *)malloc(sizeof(secp256k1_gej) * (1 + 4 * runs)); + secp256k1_fe *zinv = (secp256k1_fe *)malloc(sizeof(secp256k1_fe) * (1 + 4 * runs)); + secp256k1_fe zf; + secp256k1_fe zfi2, zfi3; + + secp256k1_gej_set_infinity(&gej[0]); + secp256k1_ge_clear(&ge[0]); + secp256k1_ge_set_gej_var(&ge[0], &gej[0]); + for (i = 0; i < runs; i++) { + int j; + secp256k1_ge g; + random_group_element_test(&g); +#ifdef USE_ENDOMORPHISM + if (i >= runs - 2) { + secp256k1_ge_mul_lambda(&g, &ge[1]); + } + if (i >= runs - 1) { + secp256k1_ge_mul_lambda(&g, &g); + } +#endif + ge[1 + 4 * i] = g; + ge[2 + 4 * i] = g; + secp256k1_ge_neg(&ge[3 + 4 * i], &g); + secp256k1_ge_neg(&ge[4 + 4 * i], &g); + secp256k1_gej_set_ge(&gej[1 + 4 * i], &ge[1 + 4 * i]); + random_group_element_jacobian_test(&gej[2 + 4 * i], &ge[2 + 4 * i]); + secp256k1_gej_set_ge(&gej[3 + 4 * i], &ge[3 + 4 * i]); + random_group_element_jacobian_test(&gej[4 + 4 * i], &ge[4 + 4 * i]); + for (j = 0; j < 4; j++) { + random_field_element_magnitude(&ge[1 + j + 4 * i].x); + random_field_element_magnitude(&ge[1 + j + 4 * i].y); + random_field_element_magnitude(&gej[1 + j + 4 * i].x); + random_field_element_magnitude(&gej[1 + j + 4 * i].y); + random_field_element_magnitude(&gej[1 + j + 4 * i].z); + } + } + + /* Compute z inverses. */ + { + secp256k1_fe *zs = malloc(sizeof(secp256k1_fe) * (1 + 4 * runs)); + for (i = 0; i < 4 * runs + 1; i++) { + if (i == 0) { + /* The point at infinity does not have a meaningful z inverse. Any should do. */ + do { + random_field_element_test(&zs[i]); + } while(secp256k1_fe_is_zero(&zs[i])); + } else { + zs[i] = gej[i].z; + } + } + secp256k1_fe_inv_all_var(4 * runs + 1, zinv, zs); + free(zs); + } + + /* Generate random zf, and zfi2 = 1/zf^2, zfi3 = 1/zf^3 */ + do { + random_field_element_test(&zf); + } while(secp256k1_fe_is_zero(&zf)); + random_field_element_magnitude(&zf); + secp256k1_fe_inv_var(&zfi3, &zf); + secp256k1_fe_sqr(&zfi2, &zfi3); + secp256k1_fe_mul(&zfi3, &zfi3, &zfi2); + + for (i1 = 0; i1 < 1 + 4 * runs; i1++) { + int i2; + for (i2 = 0; i2 < 1 + 4 * runs; i2++) { + /* Compute reference result using gej + gej (var). */ + secp256k1_gej refj, resj; + secp256k1_ge ref; + secp256k1_fe zr; + secp256k1_gej_add_var(&refj, &gej[i1], &gej[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr); + /* Check Z ratio. */ + if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&refj)) { + secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z); + CHECK(secp256k1_fe_equal_var(&zrz, &refj.z)); + } + secp256k1_ge_set_gej_var(&ref, &refj); + + /* Test gej + ge with Z ratio result (var). */ + secp256k1_gej_add_ge_var(&resj, &gej[i1], &ge[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr); + ge_equals_gej(&ref, &resj); + if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&resj)) { + secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z); + CHECK(secp256k1_fe_equal_var(&zrz, &resj.z)); + } + + /* Test gej + ge (var, with additional Z factor). */ + { + secp256k1_ge ge2_zfi = ge[i2]; /* the second term with x and y rescaled for z = 1/zf */ + secp256k1_fe_mul(&ge2_zfi.x, &ge2_zfi.x, &zfi2); + secp256k1_fe_mul(&ge2_zfi.y, &ge2_zfi.y, &zfi3); + random_field_element_magnitude(&ge2_zfi.x); + random_field_element_magnitude(&ge2_zfi.y); + secp256k1_gej_add_zinv_var(&resj, &gej[i1], &ge2_zfi, &zf); + ge_equals_gej(&ref, &resj); + } + + /* Test gej + ge (const). */ + if (i2 != 0) { + /* secp256k1_gej_add_ge does not support its second argument being infinity. */ + secp256k1_gej_add_ge(&resj, &gej[i1], &ge[i2]); + ge_equals_gej(&ref, &resj); + } + + /* Test doubling (var). */ + if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 == ((i2 + 3)%4)/2)) { + secp256k1_fe zr2; + /* Normal doubling with Z ratio result. */ + secp256k1_gej_double_var(&resj, &gej[i1], &zr2); + ge_equals_gej(&ref, &resj); + /* Check Z ratio. */ + secp256k1_fe_mul(&zr2, &zr2, &gej[i1].z); + CHECK(secp256k1_fe_equal_var(&zr2, &resj.z)); + /* Normal doubling. */ + secp256k1_gej_double_var(&resj, &gej[i2], NULL); + ge_equals_gej(&ref, &resj); + } + + /* Test adding opposites. */ + if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 != ((i2 + 3)%4)/2)) { + CHECK(secp256k1_ge_is_infinity(&ref)); + } + + /* Test adding infinity. */ + if (i1 == 0) { + CHECK(secp256k1_ge_is_infinity(&ge[i1])); + CHECK(secp256k1_gej_is_infinity(&gej[i1])); + ge_equals_gej(&ref, &gej[i2]); + } + if (i2 == 0) { + CHECK(secp256k1_ge_is_infinity(&ge[i2])); + CHECK(secp256k1_gej_is_infinity(&gej[i2])); + ge_equals_gej(&ref, &gej[i1]); + } + } + } + + /* Test adding all points together in random order equals infinity. */ + { + secp256k1_gej sum = SECP256K1_GEJ_CONST_INFINITY; + secp256k1_gej *gej_shuffled = (secp256k1_gej *)malloc((4 * runs + 1) * sizeof(secp256k1_gej)); + for (i = 0; i < 4 * runs + 1; i++) { + gej_shuffled[i] = gej[i]; + } + for (i = 0; i < 4 * runs + 1; i++) { + int swap = i + secp256k1_rand_int(4 * runs + 1 - i); + if (swap != i) { + secp256k1_gej t = gej_shuffled[i]; + gej_shuffled[i] = gej_shuffled[swap]; + gej_shuffled[swap] = t; + } + } + for (i = 0; i < 4 * runs + 1; i++) { + secp256k1_gej_add_var(&sum, &sum, &gej_shuffled[i], NULL); + } + CHECK(secp256k1_gej_is_infinity(&sum)); + free(gej_shuffled); + } + + /* Test batch gej -> ge conversion with and without known z ratios. */ + { + secp256k1_fe *zr = (secp256k1_fe *)malloc((4 * runs + 1) * sizeof(secp256k1_fe)); + secp256k1_ge *ge_set_table = (secp256k1_ge *)malloc((4 * runs + 1) * sizeof(secp256k1_ge)); + secp256k1_ge *ge_set_all = (secp256k1_ge *)malloc((4 * runs + 1) * sizeof(secp256k1_ge)); + for (i = 0; i < 4 * runs + 1; i++) { + /* Compute gej[i + 1].z / gez[i].z (with gej[n].z taken to be 1). */ + if (i < 4 * runs) { + secp256k1_fe_mul(&zr[i + 1], &zinv[i], &gej[i + 1].z); + } + } + secp256k1_ge_set_table_gej_var(4 * runs + 1, ge_set_table, gej, zr); + secp256k1_ge_set_all_gej_var(4 * runs + 1, ge_set_all, gej, &ctx->error_callback); + for (i = 0; i < 4 * runs + 1; i++) { + secp256k1_fe s; + random_fe_non_zero(&s); + secp256k1_gej_rescale(&gej[i], &s); + ge_equals_gej(&ge_set_table[i], &gej[i]); + ge_equals_gej(&ge_set_all[i], &gej[i]); + } + free(ge_set_table); + free(ge_set_all); + free(zr); + } + + free(ge); + free(gej); + free(zinv); +} + +void test_add_neg_y_diff_x(void) { + /* The point of this test is to check that we can add two points + * whose y-coordinates are negatives of each other but whose x + * coordinates differ. If the x-coordinates were the same, these + * points would be negatives of each other and their sum is + * infinity. This is cool because it "covers up" any degeneracy + * in the addition algorithm that would cause the xy coordinates + * of the sum to be wrong (since infinity has no xy coordinates). + * HOWEVER, if the x-coordinates are different, infinity is the + * wrong answer, and such degeneracies are exposed. This is the + * root of https://github.com/bitcoin-core/secp256k1/issues/257 + * which this test is a regression test for. + * + * These points were generated in sage as + * # secp256k1 params + * F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) + * C = EllipticCurve ([F (0), F (7)]) + * G = C.lift_x(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798) + * N = FiniteField(G.order()) + * + * # endomorphism values (lambda is 1^{1/3} in N, beta is 1^{1/3} in F) + * x = polygen(N) + * lam = (1 - x^3).roots()[1][0] + * + * # random "bad pair" + * P = C.random_element() + * Q = -int(lam) * P + * print " P: %x %x" % P.xy() + * print " Q: %x %x" % Q.xy() + * print "P + Q: %x %x" % (P + Q).xy() + */ + secp256k1_gej aj = SECP256K1_GEJ_CONST( + 0x8d24cd95, 0x0a355af1, 0x3c543505, 0x44238d30, + 0x0643d79f, 0x05a59614, 0x2f8ec030, 0xd58977cb, + 0x001e337a, 0x38093dcd, 0x6c0f386d, 0x0b1293a8, + 0x4d72c879, 0xd7681924, 0x44e6d2f3, 0x9190117d + ); + secp256k1_gej bj = SECP256K1_GEJ_CONST( + 0xc7b74206, 0x1f788cd9, 0xabd0937d, 0x164a0d86, + 0x95f6ff75, 0xf19a4ce9, 0xd013bd7b, 0xbf92d2a7, + 0xffe1cc85, 0xc7f6c232, 0x93f0c792, 0xf4ed6c57, + 0xb28d3786, 0x2897e6db, 0xbb192d0b, 0x6e6feab2 + ); + secp256k1_gej sumj = SECP256K1_GEJ_CONST( + 0x671a63c0, 0x3efdad4c, 0x389a7798, 0x24356027, + 0xb3d69010, 0x278625c3, 0x5c86d390, 0x184a8f7a, + 0x5f6409c2, 0x2ce01f2b, 0x511fd375, 0x25071d08, + 0xda651801, 0x70e95caf, 0x8f0d893c, 0xbed8fbbe + ); + secp256k1_ge b; + secp256k1_gej resj; + secp256k1_ge res; + secp256k1_ge_set_gej(&b, &bj); + + secp256k1_gej_add_var(&resj, &aj, &bj, NULL); + secp256k1_ge_set_gej(&res, &resj); + ge_equals_gej(&res, &sumj); + + secp256k1_gej_add_ge(&resj, &aj, &b); + secp256k1_ge_set_gej(&res, &resj); + ge_equals_gej(&res, &sumj); + + secp256k1_gej_add_ge_var(&resj, &aj, &b, NULL); + secp256k1_ge_set_gej(&res, &resj); + ge_equals_gej(&res, &sumj); +} + +void run_ge(void) { + int i; + for (i = 0; i < count * 32; i++) { + test_ge(); + } + test_add_neg_y_diff_x(); +} + +void test_ec_combine(void) { + secp256k1_scalar sum = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_pubkey data[6]; + const secp256k1_pubkey* d[6]; + secp256k1_pubkey sd; + secp256k1_pubkey sd2; + secp256k1_gej Qj; + secp256k1_ge Q; + int i; + for (i = 1; i <= 6; i++) { + secp256k1_scalar s; + random_scalar_order_test(&s); + secp256k1_scalar_add(&sum, &sum, &s); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &s); + secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_pubkey_save(&data[i - 1], &Q); + d[i - 1] = &data[i - 1]; + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sum); + secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_pubkey_save(&sd, &Q); + CHECK(secp256k1_ec_pubkey_combine(ctx, &sd2, d, i) == 1); + CHECK(memcmp(&sd, &sd2, sizeof(sd)) == 0); + } +} + +void run_ec_combine(void) { + int i; + for (i = 0; i < count * 8; i++) { + test_ec_combine(); + } +} + +void test_group_decompress(const secp256k1_fe* x) { + /* The input itself, normalized. */ + secp256k1_fe fex = *x; + secp256k1_fe fez; + /* Results of set_xquad_var, set_xo_var(..., 0), set_xo_var(..., 1). */ + secp256k1_ge ge_quad, ge_even, ge_odd; + secp256k1_gej gej_quad; + /* Return values of the above calls. */ + int res_quad, res_even, res_odd; + + secp256k1_fe_normalize_var(&fex); + + res_quad = secp256k1_ge_set_xquad(&ge_quad, &fex); + res_even = secp256k1_ge_set_xo_var(&ge_even, &fex, 0); + res_odd = secp256k1_ge_set_xo_var(&ge_odd, &fex, 1); + + CHECK(res_quad == res_even); + CHECK(res_quad == res_odd); + + if (res_quad) { + secp256k1_fe_normalize_var(&ge_quad.x); + secp256k1_fe_normalize_var(&ge_odd.x); + secp256k1_fe_normalize_var(&ge_even.x); + secp256k1_fe_normalize_var(&ge_quad.y); + secp256k1_fe_normalize_var(&ge_odd.y); + secp256k1_fe_normalize_var(&ge_even.y); + + /* No infinity allowed. */ + CHECK(!ge_quad.infinity); + CHECK(!ge_even.infinity); + CHECK(!ge_odd.infinity); + + /* Check that the x coordinates check out. */ + CHECK(secp256k1_fe_equal_var(&ge_quad.x, x)); + CHECK(secp256k1_fe_equal_var(&ge_even.x, x)); + CHECK(secp256k1_fe_equal_var(&ge_odd.x, x)); + + /* Check that the Y coordinate result in ge_quad is a square. */ + CHECK(secp256k1_fe_is_quad_var(&ge_quad.y)); + + /* Check odd/even Y in ge_odd, ge_even. */ + CHECK(secp256k1_fe_is_odd(&ge_odd.y)); + CHECK(!secp256k1_fe_is_odd(&ge_even.y)); + + /* Check secp256k1_gej_has_quad_y_var. */ + secp256k1_gej_set_ge(&gej_quad, &ge_quad); + CHECK(secp256k1_gej_has_quad_y_var(&gej_quad)); + do { + random_fe_test(&fez); + } while (secp256k1_fe_is_zero(&fez)); + secp256k1_gej_rescale(&gej_quad, &fez); + CHECK(secp256k1_gej_has_quad_y_var(&gej_quad)); + secp256k1_gej_neg(&gej_quad, &gej_quad); + CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad)); + do { + random_fe_test(&fez); + } while (secp256k1_fe_is_zero(&fez)); + secp256k1_gej_rescale(&gej_quad, &fez); + CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad)); + secp256k1_gej_neg(&gej_quad, &gej_quad); + CHECK(secp256k1_gej_has_quad_y_var(&gej_quad)); + } +} + +void run_group_decompress(void) { + int i; + for (i = 0; i < count * 4; i++) { + secp256k1_fe fe; + random_fe_test(&fe); + test_group_decompress(&fe); + } +} + +/***** ECMULT TESTS *****/ + +void run_ecmult_chain(void) { + /* random starting point A (on the curve) */ + secp256k1_gej a = SECP256K1_GEJ_CONST( + 0x8b30bbe9, 0xae2a9906, 0x96b22f67, 0x0709dff3, + 0x727fd8bc, 0x04d3362c, 0x6c7bf458, 0xe2846004, + 0xa357ae91, 0x5c4a6528, 0x1309edf2, 0x0504740f, + 0x0eb33439, 0x90216b4f, 0x81063cb6, 0x5f2f7e0f + ); + /* two random initial factors xn and gn */ + secp256k1_scalar xn = SECP256K1_SCALAR_CONST( + 0x84cc5452, 0xf7fde1ed, 0xb4d38a8c, 0xe9b1b84c, + 0xcef31f14, 0x6e569be9, 0x705d357a, 0x42985407 + ); + secp256k1_scalar gn = SECP256K1_SCALAR_CONST( + 0xa1e58d22, 0x553dcd42, 0xb2398062, 0x5d4c57a9, + 0x6e9323d4, 0x2b3152e5, 0xca2c3990, 0xedc7c9de + ); + /* two small multipliers to be applied to xn and gn in every iteration: */ + static const secp256k1_scalar xf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x1337); + static const secp256k1_scalar gf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x7113); + /* accumulators with the resulting coefficients to A and G */ + secp256k1_scalar ae = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_scalar ge = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + /* actual points */ + secp256k1_gej x; + secp256k1_gej x2; + int i; + + /* the point being computed */ + x = a; + for (i = 0; i < 200*count; i++) { + /* in each iteration, compute X = xn*X + gn*G; */ + secp256k1_ecmult(&ctx->ecmult_ctx, &x, &x, &xn, &gn); + /* also compute ae and ge: the actual accumulated factors for A and G */ + /* if X was (ae*A+ge*G), xn*X + gn*G results in (xn*ae*A + (xn*ge+gn)*G) */ + secp256k1_scalar_mul(&ae, &ae, &xn); + secp256k1_scalar_mul(&ge, &ge, &xn); + secp256k1_scalar_add(&ge, &ge, &gn); + /* modify xn and gn */ + secp256k1_scalar_mul(&xn, &xn, &xf); + secp256k1_scalar_mul(&gn, &gn, &gf); + + /* verify */ + if (i == 19999) { + /* expected result after 19999 iterations */ + secp256k1_gej rp = SECP256K1_GEJ_CONST( + 0xD6E96687, 0xF9B10D09, 0x2A6F3543, 0x9D86CEBE, + 0xA4535D0D, 0x409F5358, 0x6440BD74, 0xB933E830, + 0xB95CBCA2, 0xC77DA786, 0x539BE8FD, 0x53354D2D, + 0x3B4F566A, 0xE6580454, 0x07ED6015, 0xEE1B2A88 + ); + + secp256k1_gej_neg(&rp, &rp); + secp256k1_gej_add_var(&rp, &rp, &x, NULL); + CHECK(secp256k1_gej_is_infinity(&rp)); + } + } + /* redo the computation, but directly with the resulting ae and ge coefficients: */ + secp256k1_ecmult(&ctx->ecmult_ctx, &x2, &a, &ae, &ge); + secp256k1_gej_neg(&x2, &x2); + secp256k1_gej_add_var(&x2, &x2, &x, NULL); + CHECK(secp256k1_gej_is_infinity(&x2)); +} + +void test_point_times_order(const secp256k1_gej *point) { + /* X * (point + G) + (order-X) * (pointer + G) = 0 */ + secp256k1_scalar x; + secp256k1_scalar nx; + secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_gej res1, res2; + secp256k1_ge res3; + unsigned char pub[65]; + size_t psize = 65; + random_scalar_order_test(&x); + secp256k1_scalar_negate(&nx, &x); + secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &x, &x); /* calc res1 = x * point + x * G; */ + secp256k1_ecmult(&ctx->ecmult_ctx, &res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */ + secp256k1_gej_add_var(&res1, &res1, &res2, NULL); + CHECK(secp256k1_gej_is_infinity(&res1)); + CHECK(secp256k1_gej_is_valid_var(&res1) == 0); + secp256k1_ge_set_gej(&res3, &res1); + CHECK(secp256k1_ge_is_infinity(&res3)); + CHECK(secp256k1_ge_is_valid_var(&res3) == 0); + CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 0) == 0); + psize = 65; + CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 1) == 0); + /* check zero/one edge cases */ + secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &zero, &zero); + secp256k1_ge_set_gej(&res3, &res1); + CHECK(secp256k1_ge_is_infinity(&res3)); + secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &one, &zero); + secp256k1_ge_set_gej(&res3, &res1); + ge_equals_gej(&res3, point); + secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &zero, &one); + secp256k1_ge_set_gej(&res3, &res1); + ge_equals_ge(&res3, &secp256k1_ge_const_g); +} + +void run_point_times_order(void) { + int i; + secp256k1_fe x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2); + static const secp256k1_fe xr = SECP256K1_FE_CONST( + 0x7603CB59, 0xB0EF6C63, 0xFE608479, 0x2A0C378C, + 0xDB3233A8, 0x0F8A9A09, 0xA877DEAD, 0x31B38C45 + ); + for (i = 0; i < 500; i++) { + secp256k1_ge p; + if (secp256k1_ge_set_xo_var(&p, &x, 1)) { + secp256k1_gej j; + CHECK(secp256k1_ge_is_valid_var(&p)); + secp256k1_gej_set_ge(&j, &p); + CHECK(secp256k1_gej_is_valid_var(&j)); + test_point_times_order(&j); + } + secp256k1_fe_sqr(&x, &x); + } + secp256k1_fe_normalize_var(&x); + CHECK(secp256k1_fe_equal_var(&x, &xr)); +} + +void ecmult_const_random_mult(void) { + /* random starting point A (on the curve) */ + secp256k1_ge a = SECP256K1_GE_CONST( + 0x6d986544, 0x57ff52b8, 0xcf1b8126, 0x5b802a5b, + 0xa97f9263, 0xb1e88044, 0x93351325, 0x91bc450a, + 0x535c59f7, 0x325e5d2b, 0xc391fbe8, 0x3c12787c, + 0x337e4a98, 0xe82a9011, 0x0123ba37, 0xdd769c7d + ); + /* random initial factor xn */ + secp256k1_scalar xn = SECP256K1_SCALAR_CONST( + 0x649d4f77, 0xc4242df7, 0x7f2079c9, 0x14530327, + 0xa31b876a, 0xd2d8ce2a, 0x2236d5c6, 0xd7b2029b + ); + /* expected xn * A (from sage) */ + secp256k1_ge expected_b = SECP256K1_GE_CONST( + 0x23773684, 0x4d209dc7, 0x098a786f, 0x20d06fcd, + 0x070a38bf, 0xc11ac651, 0x03004319, 0x1e2a8786, + 0xed8c3b8e, 0xc06dd57b, 0xd06ea66e, 0x45492b0f, + 0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956 + ); + secp256k1_gej b; + secp256k1_ecmult_const(&b, &a, &xn); + + CHECK(secp256k1_ge_is_valid_var(&a)); + ge_equals_gej(&expected_b, &b); +} + +void ecmult_const_commutativity(void) { + secp256k1_scalar a; + secp256k1_scalar b; + secp256k1_gej res1; + secp256k1_gej res2; + secp256k1_ge mid1; + secp256k1_ge mid2; + random_scalar_order_test(&a); + random_scalar_order_test(&b); + + secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a); + secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b); + secp256k1_ge_set_gej(&mid1, &res1); + secp256k1_ge_set_gej(&mid2, &res2); + secp256k1_ecmult_const(&res1, &mid1, &b); + secp256k1_ecmult_const(&res2, &mid2, &a); + secp256k1_ge_set_gej(&mid1, &res1); + secp256k1_ge_set_gej(&mid2, &res2); + ge_equals_ge(&mid1, &mid2); +} + +void ecmult_const_mult_zero_one(void) { + secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_scalar negone; + secp256k1_gej res1; + secp256k1_ge res2; + secp256k1_ge point; + secp256k1_scalar_negate(&negone, &one); + + random_group_element_test(&point); + secp256k1_ecmult_const(&res1, &point, &zero); + secp256k1_ge_set_gej(&res2, &res1); + CHECK(secp256k1_ge_is_infinity(&res2)); + secp256k1_ecmult_const(&res1, &point, &one); + secp256k1_ge_set_gej(&res2, &res1); + ge_equals_ge(&res2, &point); + secp256k1_ecmult_const(&res1, &point, &negone); + secp256k1_gej_neg(&res1, &res1); + secp256k1_ge_set_gej(&res2, &res1); + ge_equals_ge(&res2, &point); +} + +void ecmult_const_chain_multiply(void) { + /* Check known result (randomly generated test problem from sage) */ + const secp256k1_scalar scalar = SECP256K1_SCALAR_CONST( + 0x4968d524, 0x2abf9b7a, 0x466abbcf, 0x34b11b6d, + 0xcd83d307, 0x827bed62, 0x05fad0ce, 0x18fae63b + ); + const secp256k1_gej expected_point = SECP256K1_GEJ_CONST( + 0x5494c15d, 0x32099706, 0xc2395f94, 0x348745fd, + 0x757ce30e, 0x4e8c90fb, 0xa2bad184, 0xf883c69f, + 0x5d195d20, 0xe191bf7f, 0x1be3e55f, 0x56a80196, + 0x6071ad01, 0xf1462f66, 0xc997fa94, 0xdb858435 + ); + secp256k1_gej point; + secp256k1_ge res; + int i; + + secp256k1_gej_set_ge(&point, &secp256k1_ge_const_g); + for (i = 0; i < 100; ++i) { + secp256k1_ge tmp; + secp256k1_ge_set_gej(&tmp, &point); + secp256k1_ecmult_const(&point, &tmp, &scalar); + } + secp256k1_ge_set_gej(&res, &point); + ge_equals_gej(&res, &expected_point); +} + +void run_ecmult_const_tests(void) { + ecmult_const_mult_zero_one(); + ecmult_const_random_mult(); + ecmult_const_commutativity(); + ecmult_const_chain_multiply(); +} + +void test_wnaf(const secp256k1_scalar *number, int w) { + secp256k1_scalar x, two, t; + int wnaf[256]; + int zeroes = -1; + int i; + int bits; + secp256k1_scalar_set_int(&x, 0); + secp256k1_scalar_set_int(&two, 2); + bits = secp256k1_ecmult_wnaf(wnaf, 256, number, w); + CHECK(bits <= 256); + for (i = bits-1; i >= 0; i--) { + int v = wnaf[i]; + secp256k1_scalar_mul(&x, &x, &two); + if (v) { + CHECK(zeroes == -1 || zeroes >= w-1); /* check that distance between non-zero elements is at least w-1 */ + zeroes=0; + CHECK((v & 1) == 1); /* check non-zero elements are odd */ + CHECK(v <= (1 << (w-1)) - 1); /* check range below */ + CHECK(v >= -(1 << (w-1)) - 1); /* check range above */ + } else { + CHECK(zeroes != -1); /* check that no unnecessary zero padding exists */ + zeroes++; + } + if (v >= 0) { + secp256k1_scalar_set_int(&t, v); + } else { + secp256k1_scalar_set_int(&t, -v); + secp256k1_scalar_negate(&t, &t); + } + secp256k1_scalar_add(&x, &x, &t); + } + CHECK(secp256k1_scalar_eq(&x, number)); /* check that wnaf represents number */ +} + +void test_constant_wnaf_negate(const secp256k1_scalar *number) { + secp256k1_scalar neg1 = *number; + secp256k1_scalar neg2 = *number; + int sign1 = 1; + int sign2 = 1; + + if (!secp256k1_scalar_get_bits(&neg1, 0, 1)) { + secp256k1_scalar_negate(&neg1, &neg1); + sign1 = -1; + } + sign2 = secp256k1_scalar_cond_negate(&neg2, secp256k1_scalar_is_even(&neg2)); + CHECK(sign1 == sign2); + CHECK(secp256k1_scalar_eq(&neg1, &neg2)); +} + +void test_constant_wnaf(const secp256k1_scalar *number, int w) { + secp256k1_scalar x, shift; + int wnaf[256] = {0}; + int i; + int skew; + secp256k1_scalar num = *number; + + secp256k1_scalar_set_int(&x, 0); + secp256k1_scalar_set_int(&shift, 1 << w); + /* With USE_ENDOMORPHISM on we only consider 128-bit numbers */ +#ifdef USE_ENDOMORPHISM + for (i = 0; i < 16; ++i) { + secp256k1_scalar_shr_int(&num, 8); + } +#endif + skew = secp256k1_wnaf_const(wnaf, num, w); + + for (i = WNAF_SIZE(w); i >= 0; --i) { + secp256k1_scalar t; + int v = wnaf[i]; + CHECK(v != 0); /* check nonzero */ + CHECK(v & 1); /* check parity */ + CHECK(v > -(1 << w)); /* check range above */ + CHECK(v < (1 << w)); /* check range below */ + + secp256k1_scalar_mul(&x, &x, &shift); + if (v >= 0) { + secp256k1_scalar_set_int(&t, v); + } else { + secp256k1_scalar_set_int(&t, -v); + secp256k1_scalar_negate(&t, &t); + } + secp256k1_scalar_add(&x, &x, &t); + } + /* Skew num because when encoding numbers as odd we use an offset */ + secp256k1_scalar_cadd_bit(&num, skew == 2, 1); + CHECK(secp256k1_scalar_eq(&x, &num)); +} + +void run_wnaf(void) { + int i; + secp256k1_scalar n = {{0}}; + + /* Sanity check: 1 and 2 are the smallest odd and even numbers and should + * have easier-to-diagnose failure modes */ + n.d[0] = 1; + test_constant_wnaf(&n, 4); + n.d[0] = 2; + test_constant_wnaf(&n, 4); + /* Random tests */ + for (i = 0; i < count; i++) { + random_scalar_order(&n); + test_wnaf(&n, 4+(i%10)); + test_constant_wnaf_negate(&n); + test_constant_wnaf(&n, 4 + (i % 10)); + } + secp256k1_scalar_set_int(&n, 0); + CHECK(secp256k1_scalar_cond_negate(&n, 1) == -1); + CHECK(secp256k1_scalar_is_zero(&n)); + CHECK(secp256k1_scalar_cond_negate(&n, 0) == 1); + CHECK(secp256k1_scalar_is_zero(&n)); +} + +void test_ecmult_constants(void) { + /* Test ecmult_gen() for [0..36) and [order-36..0). */ + secp256k1_scalar x; + secp256k1_gej r; + secp256k1_ge ng; + int i; + int j; + secp256k1_ge_neg(&ng, &secp256k1_ge_const_g); + for (i = 0; i < 36; i++ ) { + secp256k1_scalar_set_int(&x, i); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &r, &x); + for (j = 0; j < i; j++) { + if (j == i - 1) { + ge_equals_gej(&secp256k1_ge_const_g, &r); + } + secp256k1_gej_add_ge(&r, &r, &ng); + } + CHECK(secp256k1_gej_is_infinity(&r)); + } + for (i = 1; i <= 36; i++ ) { + secp256k1_scalar_set_int(&x, i); + secp256k1_scalar_negate(&x, &x); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &r, &x); + for (j = 0; j < i; j++) { + if (j == i - 1) { + ge_equals_gej(&ng, &r); + } + secp256k1_gej_add_ge(&r, &r, &secp256k1_ge_const_g); + } + CHECK(secp256k1_gej_is_infinity(&r)); + } +} + +void run_ecmult_constants(void) { + test_ecmult_constants(); +} + +void test_ecmult_gen_blind(void) { + /* Test ecmult_gen() blinding and confirm that the blinding changes, the affine points match, and the z's don't match. */ + secp256k1_scalar key; + secp256k1_scalar b; + unsigned char seed32[32]; + secp256k1_gej pgej; + secp256k1_gej pgej2; + secp256k1_gej i; + secp256k1_ge pge; + random_scalar_order_test(&key); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej, &key); + secp256k1_rand256(seed32); + b = ctx->ecmult_gen_ctx.blind; + i = ctx->ecmult_gen_ctx.initial; + secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); + CHECK(!secp256k1_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind)); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej2, &key); + CHECK(!gej_xyz_equals_gej(&pgej, &pgej2)); + CHECK(!gej_xyz_equals_gej(&i, &ctx->ecmult_gen_ctx.initial)); + secp256k1_ge_set_gej(&pge, &pgej); + ge_equals_gej(&pge, &pgej2); +} + +void test_ecmult_gen_blind_reset(void) { + /* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */ + secp256k1_scalar b; + secp256k1_gej initial; + secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0); + b = ctx->ecmult_gen_ctx.blind; + initial = ctx->ecmult_gen_ctx.initial; + secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0); + CHECK(secp256k1_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind)); + CHECK(gej_xyz_equals_gej(&initial, &ctx->ecmult_gen_ctx.initial)); +} + +void run_ecmult_gen_blind(void) { + int i; + test_ecmult_gen_blind_reset(); + for (i = 0; i < 10; i++) { + test_ecmult_gen_blind(); + } +} + +#ifdef USE_ENDOMORPHISM +/***** ENDOMORPHISH TESTS *****/ +void test_scalar_split(void) { + secp256k1_scalar full; + secp256k1_scalar s1, slam; + const unsigned char zero[32] = {0}; + unsigned char tmp[32]; + + random_scalar_order_test(&full); + secp256k1_scalar_split_lambda(&s1, &slam, &full); + + /* check that both are <= 128 bits in size */ + if (secp256k1_scalar_is_high(&s1)) { + secp256k1_scalar_negate(&s1, &s1); + } + if (secp256k1_scalar_is_high(&slam)) { + secp256k1_scalar_negate(&slam, &slam); + } + + secp256k1_scalar_get_b32(tmp, &s1); + CHECK(memcmp(zero, tmp, 16) == 0); + secp256k1_scalar_get_b32(tmp, &slam); + CHECK(memcmp(zero, tmp, 16) == 0); +} + +void run_endomorphism_tests(void) { + test_scalar_split(); +} +#endif + +void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) { + unsigned char pubkeyc[65]; + secp256k1_pubkey pubkey; + secp256k1_ge ge; + size_t pubkeyclen; + int32_t ecount; + ecount = 0; + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + for (pubkeyclen = 3; pubkeyclen <= 65; pubkeyclen++) { + /* Smaller sizes are tested exhaustively elsewhere. */ + int32_t i; + memcpy(&pubkeyc[1], input, 64); + VG_UNDEF(&pubkeyc[pubkeyclen], 65 - pubkeyclen); + for (i = 0; i < 256; i++) { + /* Try all type bytes. */ + int xpass; + int ypass; + int ysign; + pubkeyc[0] = i; + /* What sign does this point have? */ + ysign = (input[63] & 1) + 2; + /* For the current type (i) do we expect parsing to work? Handled all of compressed/uncompressed/hybrid. */ + xpass = xvalid && (pubkeyclen == 33) && ((i & 254) == 2); + /* Do we expect a parse and re-serialize as uncompressed to give a matching y? */ + ypass = xvalid && yvalid && ((i & 4) == ((pubkeyclen == 65) << 2)) && + ((i == 4) || ((i & 251) == ysign)) && ((pubkeyclen == 33) || (pubkeyclen == 65)); + if (xpass || ypass) { + /* These cases must parse. */ + unsigned char pubkeyo[65]; + size_t outl; + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + ecount = 0; + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + outl = 65; + VG_UNDEF(pubkeyo, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + VG_CHECK(pubkeyo, outl); + CHECK(outl == 33); + CHECK(memcmp(&pubkeyo[1], &pubkeyc[1], 32) == 0); + CHECK((pubkeyclen != 33) || (pubkeyo[0] == pubkeyc[0])); + if (ypass) { + /* This test isn't always done because we decode with alternative signs, so the y won't match. */ + CHECK(pubkeyo[0] == ysign); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + secp256k1_pubkey_save(&pubkey, &ge); + VG_CHECK(&pubkey, sizeof(pubkey)); + outl = 65; + VG_UNDEF(pubkeyo, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); + VG_CHECK(pubkeyo, outl); + CHECK(outl == 65); + CHECK(pubkeyo[0] == 4); + CHECK(memcmp(&pubkeyo[1], input, 64) == 0); + } + CHECK(ecount == 0); + } else { + /* These cases must fail to parse. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + } + } + } + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); +} + +void run_ec_pubkey_parse_test(void) { +#define SECP256K1_EC_PARSE_TEST_NVALID (12) + const unsigned char valid[SECP256K1_EC_PARSE_TEST_NVALID][64] = { + { + /* Point with leading and trailing zeros in x and y serialization. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x52, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x64, 0xef, 0xa1, 0x7b, 0x77, 0x61, 0xe1, 0xe4, 0x27, 0x06, 0x98, 0x9f, 0xb4, 0x83, + 0xb8, 0xd2, 0xd4, 0x9b, 0xf7, 0x8f, 0xae, 0x98, 0x03, 0xf0, 0x99, 0xb8, 0x34, 0xed, 0xeb, 0x00 + }, + { + /* Point with x equal to a 3rd root of unity.*/ + 0x7a, 0xe9, 0x6a, 0x2b, 0x65, 0x7c, 0x07, 0x10, 0x6e, 0x64, 0x47, 0x9e, 0xac, 0x34, 0x34, 0xe9, + 0x9c, 0xf0, 0x49, 0x75, 0x12, 0xf5, 0x89, 0x95, 0xc1, 0x39, 0x6c, 0x28, 0x71, 0x95, 0x01, 0xee, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Point with largest x. (1/2) */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2c, + 0x0e, 0x99, 0x4b, 0x14, 0xea, 0x72, 0xf8, 0xc3, 0xeb, 0x95, 0xc7, 0x1e, 0xf6, 0x92, 0x57, 0x5e, + 0x77, 0x50, 0x58, 0x33, 0x2d, 0x7e, 0x52, 0xd0, 0x99, 0x5c, 0xf8, 0x03, 0x88, 0x71, 0xb6, 0x7d, + }, + { + /* Point with largest x. (2/2) */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2c, + 0xf1, 0x66, 0xb4, 0xeb, 0x15, 0x8d, 0x07, 0x3c, 0x14, 0x6a, 0x38, 0xe1, 0x09, 0x6d, 0xa8, 0xa1, + 0x88, 0xaf, 0xa7, 0xcc, 0xd2, 0x81, 0xad, 0x2f, 0x66, 0xa3, 0x07, 0xfb, 0x77, 0x8e, 0x45, 0xb2, + }, + { + /* Point with smallest x. (1/2) */ + 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, 0x01, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Point with smallest x. (2/2) */ + 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, 0x01, + 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, + 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41, + }, + { + /* Point with largest y. (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with largest y. (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with largest y. (3/3) */ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with smallest y. (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 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, 0x01, + }, + { + /* Point with smallest y. (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 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, 0x01, + }, + { + /* Point with smallest y. (3/3) */ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 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, 0x01 + } + }; +#define SECP256K1_EC_PARSE_TEST_NXVALID (4) + const unsigned char onlyxvalid[SECP256K1_EC_PARSE_TEST_NXVALID][64] = { + { + /* Valid if y overflow ignored (y = 1 mod p). (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* Valid if y overflow ignored (y = 1 mod p). (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* Valid if y overflow ignored (y = 1 mod p). (3/3)*/ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* x on curve, y is from y^2 = x^3 + 8. */ + 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, 0x01, + 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, 0x03 + } + }; +#define SECP256K1_EC_PARSE_TEST_NINVALID (7) + const unsigned char invalid[SECP256K1_EC_PARSE_TEST_NINVALID][64] = { + { + /* x is third root of -8, y is -1 * (x^3+7); also on the curve for y^2 = x^3 + 9. */ + 0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, + 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, + 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, 0x01, + }, + { + /* Valid if x overflow ignored (x = 1 mod p). */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Valid if x overflow ignored (x = 1 mod p). */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, + 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41, + }, + { + /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + 0xf4, 0x84, 0x14, 0x5c, 0xb0, 0x14, 0x9b, 0x82, 0x5d, 0xff, 0x41, 0x2f, 0xa0, 0x52, 0xa8, 0x3f, + 0xcb, 0x72, 0xdb, 0x61, 0xd5, 0x6f, 0x37, 0x70, 0xce, 0x06, 0x6b, 0x73, 0x49, 0xa2, 0xaa, 0x28, + }, + { + /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + 0x0b, 0x7b, 0xeb, 0xa3, 0x4f, 0xeb, 0x64, 0x7d, 0xa2, 0x00, 0xbe, 0xd0, 0x5f, 0xad, 0x57, 0xc0, + 0x34, 0x8d, 0x24, 0x9e, 0x2a, 0x90, 0xc8, 0x8f, 0x31, 0xf9, 0x94, 0x8b, 0xb6, 0x5d, 0x52, 0x07, + }, + { + /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */ + 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, 0x00, + 0x8f, 0x53, 0x7e, 0xef, 0xdf, 0xc1, 0x60, 0x6a, 0x07, 0x27, 0xcd, 0x69, 0xb4, 0xa7, 0x33, 0x3d, + 0x38, 0xed, 0x44, 0xe3, 0x93, 0x2a, 0x71, 0x79, 0xee, 0xcb, 0x4b, 0x6f, 0xba, 0x93, 0x60, 0xdc, + }, + { + /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */ + 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, 0x00, + 0x70, 0xac, 0x81, 0x10, 0x20, 0x3e, 0x9f, 0x95, 0xf8, 0xd8, 0x32, 0x96, 0x4b, 0x58, 0xcc, 0xc2, + 0xc7, 0x12, 0xbb, 0x1c, 0x6c, 0xd5, 0x8e, 0x86, 0x11, 0x34, 0xb4, 0x8f, 0x45, 0x6c, 0x9b, 0x53 + } + }; + const unsigned char pubkeyc[66] = { + /* Serialization of G. */ + 0x04, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, + 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, + 0x98, 0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65, 0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08, + 0xA8, 0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19, 0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4, + 0xB8, 0x00 + }; + unsigned char sout[65]; + unsigned char shortkey[2]; + secp256k1_ge ge; + secp256k1_pubkey pubkey; + size_t len; + int32_t i; + int32_t ecount; + int32_t ecount2; + ecount = 0; + /* Nothing should be reading this far into pubkeyc. */ + VG_UNDEF(&pubkeyc[65], 1); + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + /* Zero length claimed, fail, zeroize, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(shortkey, 2); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 0) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* Length one claimed, fail, zeroize, no illegal arg error. */ + for (i = 0; i < 256 ; i++) { + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + shortkey[0] = i; + VG_UNDEF(&shortkey[1], 1); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 1) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + } + /* Length two claimed, fail, zeroize, no illegal arg error. */ + for (i = 0; i < 65536 ; i++) { + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + shortkey[0] = i & 255; + shortkey[1] = i >> 8; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 2) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + } + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + /* 33 bytes claimed on otherwise valid input starting with 0x04, fail, zeroize output, no illegal arg error. */ + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 33) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* NULL pubkey, illegal arg error. Pubkey isn't rewritten before this step, since it's NULL into the parser. */ + CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, pubkeyc, 65) == 0); + CHECK(ecount == 2); + /* NULL input string. Illegal arg and zeroize output. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, NULL, 65) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 1); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 2); + /* 64 bytes claimed on input starting with 0x04, fail, zeroize output, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 64) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* 66 bytes claimed, fail, zeroize output, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 66) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* Valid parse. */ + memset(&pubkey, 0, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 65) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + VG_UNDEF(&ge, sizeof(ge)); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1); + VG_CHECK(&ge.x, sizeof(ge.x)); + VG_CHECK(&ge.y, sizeof(ge.y)); + VG_CHECK(&ge.infinity, sizeof(ge.infinity)); + ge_equals_ge(&secp256k1_ge_const_g, &ge); + CHECK(ecount == 0); + /* secp256k1_ec_pubkey_serialize illegal args. */ + ecount = 0; + len = 65; + CHECK(secp256k1_ec_pubkey_serialize(ctx, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); + CHECK(ecount == 1); + CHECK(len == 0); + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); + CHECK(ecount == 2); + len = 65; + VG_UNDEF(sout, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED) == 0); + VG_CHECK(sout, 65); + CHECK(ecount == 3); + CHECK(len == 0); + len = 65; + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, ~0) == 0); + CHECK(ecount == 4); + CHECK(len == 0); + len = 65; + VG_UNDEF(sout, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); + VG_CHECK(sout, 65); + CHECK(ecount == 4); + CHECK(len == 65); + /* Multiple illegal args. Should still set arg error only once. */ + ecount = 0; + ecount2 = 11; + CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0); + CHECK(ecount == 1); + /* Does the illegal arg callback actually change the behavior? */ + secp256k1_context_set_illegal_callback(ctx, uncounting_illegal_callback_fn, &ecount2); + CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0); + CHECK(ecount == 1); + CHECK(ecount2 == 10); + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); + /* Try a bunch of prefabbed points with all possible encodings. */ + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NVALID; i++) { + ec_pubkey_parse_pointtest(valid[i], 1, 1); + } + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NXVALID; i++) { + ec_pubkey_parse_pointtest(onlyxvalid[i], 1, 0); + } + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NINVALID; i++) { + ec_pubkey_parse_pointtest(invalid[i], 0, 0); + } +} + +void run_eckey_edge_case_test(void) { + const unsigned char orderc[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 + }; + const unsigned char zeros[sizeof(secp256k1_pubkey)] = {0x00}; + unsigned char ctmp[33]; + unsigned char ctmp2[33]; + secp256k1_pubkey pubkey; + secp256k1_pubkey pubkey2; + secp256k1_pubkey pubkey_one; + secp256k1_pubkey pubkey_negone; + const secp256k1_pubkey *pubkeys[3]; + size_t len; + int32_t ecount; + /* Group order is too large, reject. */ + CHECK(secp256k1_ec_seckey_verify(ctx, orderc) == 0); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, orderc) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* Maximum value is too large, reject. */ + memset(ctmp, 255, 32); + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* Zero is too small, reject. */ + memset(ctmp, 0, 32); + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* One must be accepted. */ + ctmp[31] = 0x01; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + pubkey_one = pubkey; + /* Group order + 1 is too large, reject. */ + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x42; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* -1 must be accepted. */ + ctmp[31] = 0x40; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + pubkey_negone = pubkey; + /* Tweak of zero leaves the value changed. */ + memset(ctmp2, 0, 32); + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, ctmp2) == 1); + CHECK(memcmp(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40); + memcpy(&pubkey2, &pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Multiply tweak of zero zeroizes the output. */ + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, ctmp2) == 0); + CHECK(memcmp(zeros, ctmp, 32) == 0); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, ctmp2) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* Overflowing key tweak zeroizes. */ + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, orderc) == 0); + CHECK(memcmp(zeros, ctmp, 32) == 0); + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, orderc) == 0); + CHECK(memcmp(zeros, ctmp, 32) == 0); + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, orderc) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, orderc) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* Private key tweaks results in a key of zero. */ + ctmp2[31] = 1; + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 0); + CHECK(memcmp(zeros, ctmp2, 32) == 0); + ctmp2[31] = 1; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* Tweak computation wraps and results in a key of 1. */ + ctmp2[31] = 2; + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 1); + CHECK(memcmp(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1); + ctmp2[31] = 2; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + ctmp2[31] = 1; + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, ctmp2) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Tweak mul * 2 = 1+1. */ + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + ctmp2[31] = 2; + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Test argument errors. */ + ecount = 0; + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + CHECK(ecount == 0); + /* Zeroize pubkey on parse error. */ + memset(&pubkey, 0, 32); + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + memset(&pubkey2, 0, 32); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 0); + CHECK(ecount == 2); + CHECK(memcmp(&pubkey2, zeros, sizeof(pubkey2)) == 0); + /* Plain argument errors. */ + ecount = 0; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_ec_seckey_verify(ctx, NULL) == 0); + CHECK(ecount == 1); + ecount = 0; + memset(ctmp2, 0, 32); + ctmp2[31] = 4; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + memset(ctmp2, 0, 32); + ctmp2[31] = 4; + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + memset(ctmp2, 0, 32); + CHECK(secp256k1_ec_privkey_tweak_add(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + memset(ctmp2, 0, 32); + ctmp2[31] = 1; + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + CHECK(secp256k1_ec_pubkey_create(ctx, NULL, ctmp) == 0); + CHECK(ecount == 1); + memset(&pubkey, 1, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 2); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* secp256k1_ec_pubkey_combine tests. */ + ecount = 0; + pubkeys[0] = &pubkey_one; + VG_UNDEF(&pubkeys[0], sizeof(secp256k1_pubkey *)); + VG_UNDEF(&pubkeys[1], sizeof(secp256k1_pubkey *)); + VG_UNDEF(&pubkeys[2], sizeof(secp256k1_pubkey *)); + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 0) == 0); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_pubkey_combine(ctx, NULL, pubkeys, 1) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 2); + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, NULL, 1) == 0); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 3); + pubkeys[0] = &pubkey_negone; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 1) == 1); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(ecount == 3); + len = 33; + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1); + CHECK(memcmp(ctmp, ctmp2, 33) == 0); + /* Result is infinity. */ + pubkeys[0] = &pubkey_one; + pubkeys[1] = &pubkey_negone; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 0); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 3); + /* Passes through infinity but comes out one. */ + pubkeys[2] = &pubkey_one; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 3) == 1); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(ecount == 3); + len = 33; + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1); + CHECK(memcmp(ctmp, ctmp2, 33) == 0); + /* Adds to two. */ + pubkeys[1] = &pubkey_one; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 1); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(ecount == 3); + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); +} + +void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) { + secp256k1_scalar nonce; + do { + random_scalar_order_test(&nonce); + } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid)); +} + +void test_ecdsa_sign_verify(void) { + secp256k1_gej pubj; + secp256k1_ge pub; + secp256k1_scalar one; + secp256k1_scalar msg, key; + secp256k1_scalar sigr, sigs; + int recid; + int getrec; + random_scalar_order_test(&msg); + random_scalar_order_test(&key); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key); + secp256k1_ge_set_gej(&pub, &pubj); + getrec = secp256k1_rand_bits(1); + random_sign(&sigr, &sigs, &key, &msg, getrec?&recid:NULL); + if (getrec) { + CHECK(recid >= 0 && recid < 4); + } + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg)); + secp256k1_scalar_set_int(&one, 1); + secp256k1_scalar_add(&msg, &msg, &one); + CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg)); +} + +void run_ecdsa_sign_verify(void) { + int i; + for (i = 0; i < 10*count; i++) { + test_ecdsa_sign_verify(); + } +} + +/** Dummy nonce generation function that just uses a precomputed nonce, and fails if it is not accepted. Use only for testing. */ +static int precomputed_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + (void)msg32; + (void)key32; + (void)algo16; + memcpy(nonce32, data, 32); + return (counter == 0); +} + +static int nonce_function_test_fail(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + /* Dummy nonce generator that has a fatal error on the first counter value. */ + if (counter == 0) { + return 0; + } + return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 1); +} + +static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + /* Dummy nonce generator that produces unacceptable nonces for the first several counter values. */ + if (counter < 3) { + memset(nonce32, counter==0 ? 0 : 255, 32); + if (counter == 2) { + nonce32[31]--; + } + return 1; + } + if (counter < 5) { + static const unsigned char order[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, + 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, + 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41 + }; + memcpy(nonce32, order, 32); + if (counter == 4) { + nonce32[31]++; + } + return 1; + } + /* Retry rate of 6979 is negligible esp. as we only call this in deterministic tests. */ + /* If someone does fine a case where it retries for secp256k1, we'd like to know. */ + if (counter > 5) { + return 0; + } + return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 5); +} + +int is_empty_signature(const secp256k1_ecdsa_signature *sig) { + static const unsigned char res[sizeof(secp256k1_ecdsa_signature)] = {0}; + return memcmp(sig, res, sizeof(secp256k1_ecdsa_signature)) == 0; +} + +void test_ecdsa_end_to_end(void) { + unsigned char extra[32] = {0x00}; + unsigned char privkey[32]; + unsigned char message[32]; + unsigned char privkey2[32]; + secp256k1_ecdsa_signature signature[6]; + secp256k1_scalar r, s; + unsigned char sig[74]; + size_t siglen = 74; + unsigned char pubkeyc[65]; + size_t pubkeyclen = 65; + secp256k1_pubkey pubkey; + unsigned char seckey[300]; + size_t seckeylen = 300; + + /* Generate a random key and message. */ + { + secp256k1_scalar msg, key; + random_scalar_order_test(&msg); + random_scalar_order_test(&key); + secp256k1_scalar_get_b32(privkey, &key); + secp256k1_scalar_get_b32(message, &msg); + } + + /* Construct and verify corresponding public key. */ + CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + + /* Verify exporting and importing public key. */ + CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_rand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED)); + memset(&pubkey, 0, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); + + /* Verify private key import and export. */ + CHECK(ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_rand_bits(1) == 1)); + CHECK(ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1); + CHECK(memcmp(privkey, privkey2, 32) == 0); + + /* Optionally tweak the keys using addition. */ + if (secp256k1_rand_int(3) == 0) { + int ret1; + int ret2; + unsigned char rnd[32]; + secp256k1_pubkey pubkey2; + secp256k1_rand256_test(rnd); + ret1 = secp256k1_ec_privkey_tweak_add(ctx, privkey, rnd); + ret2 = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, rnd); + CHECK(ret1 == ret2); + if (ret1 == 0) { + return; + } + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + } + + /* Optionally tweak the keys using multiplication. */ + if (secp256k1_rand_int(3) == 0) { + int ret1; + int ret2; + unsigned char rnd[32]; + secp256k1_pubkey pubkey2; + secp256k1_rand256_test(rnd); + ret1 = secp256k1_ec_privkey_tweak_mul(ctx, privkey, rnd); + ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, rnd); + CHECK(ret1 == ret2); + if (ret1 == 0) { + return; + } + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + } + + /* Sign. */ + CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[4], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[1], message, privkey, NULL, extra) == 1); + extra[31] = 1; + CHECK(secp256k1_ecdsa_sign(ctx, &signature[2], message, privkey, NULL, extra) == 1); + extra[31] = 0; + extra[0] = 1; + CHECK(secp256k1_ecdsa_sign(ctx, &signature[3], message, privkey, NULL, extra) == 1); + CHECK(memcmp(&signature[0], &signature[4], sizeof(signature[0])) == 0); + CHECK(memcmp(&signature[0], &signature[1], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[0], &signature[2], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[0], &signature[3], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[1], &signature[2], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[1], &signature[3], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[2], &signature[3], sizeof(signature[0])) != 0); + /* Verify. */ + CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[1], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[2], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[3], message, &pubkey) == 1); + /* Test lower-S form, malleate, verify and fail, test again, malleate again */ + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[0])); + secp256k1_ecdsa_signature_load(ctx, &r, &s, &signature[0]); + secp256k1_scalar_negate(&s, &s); + secp256k1_ecdsa_signature_save(&signature[5], &r, &s); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 0); + CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5])); + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5])); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); + secp256k1_scalar_negate(&s, &s); + secp256k1_ecdsa_signature_save(&signature[5], &r, &s); + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); + CHECK(memcmp(&signature[5], &signature[0], 64) == 0); + + /* Serialize/parse DER and verify again */ + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); + memset(&signature[0], 0, sizeof(signature[0])); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1); + /* Serialize/destroy/parse DER and verify again. */ + siglen = 74; + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); + sig[secp256k1_rand_int(siglen)] += 1 + secp256k1_rand_int(255); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 0 || + secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 0); +} + +void test_random_pubkeys(void) { + secp256k1_ge elem; + secp256k1_ge elem2; + unsigned char in[65]; + /* Generate some randomly sized pubkeys. */ + size_t len = secp256k1_rand_bits(2) == 0 ? 65 : 33; + if (secp256k1_rand_bits(2) == 0) { + len = secp256k1_rand_bits(6); + } + if (len == 65) { + in[0] = secp256k1_rand_bits(1) ? 4 : (secp256k1_rand_bits(1) ? 6 : 7); + } else { + in[0] = secp256k1_rand_bits(1) ? 2 : 3; + } + if (secp256k1_rand_bits(3) == 0) { + in[0] = secp256k1_rand_bits(8); + } + if (len > 1) { + secp256k1_rand256(&in[1]); + } + if (len > 33) { + secp256k1_rand256(&in[33]); + } + if (secp256k1_eckey_pubkey_parse(&elem, in, len)) { + unsigned char out[65]; + unsigned char firstb; + int res; + size_t size = len; + firstb = in[0]; + /* If the pubkey can be parsed, it should round-trip... */ + CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, len == 33)); + CHECK(size == len); + CHECK(memcmp(&in[1], &out[1], len-1) == 0); + /* ... except for the type of hybrid inputs. */ + if ((in[0] != 6) && (in[0] != 7)) { + CHECK(in[0] == out[0]); + } + size = 65; + CHECK(secp256k1_eckey_pubkey_serialize(&elem, in, &size, 0)); + CHECK(size == 65); + CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size)); + ge_equals_ge(&elem,&elem2); + /* Check that the X9.62 hybrid type is checked. */ + in[0] = secp256k1_rand_bits(1) ? 6 : 7; + res = secp256k1_eckey_pubkey_parse(&elem2, in, size); + if (firstb == 2 || firstb == 3) { + if (in[0] == firstb + 4) { + CHECK(res); + } else { + CHECK(!res); + } + } + if (res) { + ge_equals_ge(&elem,&elem2); + CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, 0)); + CHECK(memcmp(&in[1], &out[1], 64) == 0); + } + } +} + +void run_random_pubkeys(void) { + int i; + for (i = 0; i < 10*count; i++) { + test_random_pubkeys(); + } +} + +void run_ecdsa_end_to_end(void) { + int i; + for (i = 0; i < 64*count; i++) { + test_ecdsa_end_to_end(); + } +} + +int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) { + static const unsigned char zeroes[32] = {0}; +#ifdef ENABLE_OPENSSL_TESTS + static const unsigned char max_scalar[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40 + }; +#endif + + int ret = 0; + + secp256k1_ecdsa_signature sig_der; + unsigned char roundtrip_der[2048]; + unsigned char compact_der[64]; + size_t len_der = 2048; + int parsed_der = 0, valid_der = 0, roundtrips_der = 0; + + secp256k1_ecdsa_signature sig_der_lax; + unsigned char roundtrip_der_lax[2048]; + unsigned char compact_der_lax[64]; + size_t len_der_lax = 2048; + int parsed_der_lax = 0, valid_der_lax = 0, roundtrips_der_lax = 0; + +#ifdef ENABLE_OPENSSL_TESTS + ECDSA_SIG *sig_openssl; + const unsigned char *sigptr; + unsigned char roundtrip_openssl[2048]; + int len_openssl = 2048; + int parsed_openssl, valid_openssl = 0, roundtrips_openssl = 0; +#endif + + parsed_der = secp256k1_ecdsa_signature_parse_der(ctx, &sig_der, sig, siglen); + if (parsed_der) { + ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der, &sig_der)) << 0; + valid_der = (memcmp(compact_der, zeroes, 32) != 0) && (memcmp(compact_der + 32, zeroes, 32) != 0); + } + if (valid_der) { + ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der, &len_der, &sig_der)) << 1; + roundtrips_der = (len_der == siglen) && memcmp(roundtrip_der, sig, siglen) == 0; + } + + parsed_der_lax = ecdsa_signature_parse_der_lax(ctx, &sig_der_lax, sig, siglen); + if (parsed_der_lax) { + ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der_lax, &sig_der_lax)) << 10; + valid_der_lax = (memcmp(compact_der_lax, zeroes, 32) != 0) && (memcmp(compact_der_lax + 32, zeroes, 32) != 0); + } + if (valid_der_lax) { + ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der_lax, &len_der_lax, &sig_der_lax)) << 11; + roundtrips_der_lax = (len_der_lax == siglen) && memcmp(roundtrip_der_lax, sig, siglen) == 0; + } + + if (certainly_der) { + ret |= (!parsed_der) << 2; + } + if (certainly_not_der) { + ret |= (parsed_der) << 17; + } + if (valid_der) { + ret |= (!roundtrips_der) << 3; + } + + if (valid_der) { + ret |= (!roundtrips_der_lax) << 12; + ret |= (len_der != len_der_lax) << 13; + ret |= (memcmp(roundtrip_der_lax, roundtrip_der, len_der) != 0) << 14; + } + ret |= (roundtrips_der != roundtrips_der_lax) << 15; + if (parsed_der) { + ret |= (!parsed_der_lax) << 16; + } + +#ifdef ENABLE_OPENSSL_TESTS + sig_openssl = ECDSA_SIG_new(); + sigptr = sig; + parsed_openssl = (d2i_ECDSA_SIG(&sig_openssl, &sigptr, siglen) != NULL); + if (parsed_openssl) { + valid_openssl = !BN_is_negative(sig_openssl->r) && !BN_is_negative(sig_openssl->s) && BN_num_bits(sig_openssl->r) > 0 && BN_num_bits(sig_openssl->r) <= 256 && BN_num_bits(sig_openssl->s) > 0 && BN_num_bits(sig_openssl->s) <= 256; + if (valid_openssl) { + unsigned char tmp[32] = {0}; + BN_bn2bin(sig_openssl->r, tmp + 32 - BN_num_bytes(sig_openssl->r)); + valid_openssl = memcmp(tmp, max_scalar, 32) < 0; + } + if (valid_openssl) { + unsigned char tmp[32] = {0}; + BN_bn2bin(sig_openssl->s, tmp + 32 - BN_num_bytes(sig_openssl->s)); + valid_openssl = memcmp(tmp, max_scalar, 32) < 0; + } + } + len_openssl = i2d_ECDSA_SIG(sig_openssl, NULL); + if (len_openssl <= 2048) { + unsigned char *ptr = roundtrip_openssl; + CHECK(i2d_ECDSA_SIG(sig_openssl, &ptr) == len_openssl); + roundtrips_openssl = valid_openssl && ((size_t)len_openssl == siglen) && (memcmp(roundtrip_openssl, sig, siglen) == 0); + } else { + len_openssl = 0; + } + ECDSA_SIG_free(sig_openssl); + + ret |= (parsed_der && !parsed_openssl) << 4; + ret |= (valid_der && !valid_openssl) << 5; + ret |= (roundtrips_openssl && !parsed_der) << 6; + ret |= (roundtrips_der != roundtrips_openssl) << 7; + if (roundtrips_openssl) { + ret |= (len_der != (size_t)len_openssl) << 8; + ret |= (memcmp(roundtrip_der, roundtrip_openssl, len_der) != 0) << 9; + } +#endif + return ret; +} + +static void assign_big_endian(unsigned char *ptr, size_t ptrlen, uint32_t val) { + size_t i; + for (i = 0; i < ptrlen; i++) { + int shift = ptrlen - 1 - i; + if (shift >= 4) { + ptr[i] = 0; + } else { + ptr[i] = (val >> shift) & 0xFF; + } + } +} + +static void damage_array(unsigned char *sig, size_t *len) { + int pos; + int action = secp256k1_rand_bits(3); + if (action < 1 && *len > 3) { + /* Delete a byte. */ + pos = secp256k1_rand_int(*len); + memmove(sig + pos, sig + pos + 1, *len - pos - 1); + (*len)--; + return; + } else if (action < 2 && *len < 2048) { + /* Insert a byte. */ + pos = secp256k1_rand_int(1 + *len); + memmove(sig + pos + 1, sig + pos, *len - pos); + sig[pos] = secp256k1_rand_bits(8); + (*len)++; + return; + } else if (action < 4) { + /* Modify a byte. */ + sig[secp256k1_rand_int(*len)] += 1 + secp256k1_rand_int(255); + return; + } else { /* action < 8 */ + /* Modify a bit. */ + sig[secp256k1_rand_int(*len)] ^= 1 << secp256k1_rand_bits(3); + return; + } +} + +static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly_der, int* certainly_not_der) { + int der; + int nlow[2], nlen[2], nlenlen[2], nhbit[2], nhbyte[2], nzlen[2]; + size_t tlen, elen, glen; + int indet; + int n; + + *len = 0; + der = secp256k1_rand_bits(2) == 0; + *certainly_der = der; + *certainly_not_der = 0; + indet = der ? 0 : secp256k1_rand_int(10) == 0; + + for (n = 0; n < 2; n++) { + /* We generate two classes of numbers: nlow==1 "low" ones (up to 32 bytes), nlow==0 "high" ones (32 bytes with 129 top bits set, or larger than 32 bytes) */ + nlow[n] = der ? 1 : (secp256k1_rand_bits(3) != 0); + /* The length of the number in bytes (the first byte of which will always be nonzero) */ + nlen[n] = nlow[n] ? secp256k1_rand_int(33) : 32 + secp256k1_rand_int(200) * secp256k1_rand_int(8) / 8; + CHECK(nlen[n] <= 232); + /* The top bit of the number. */ + nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : secp256k1_rand_bits(1)); + /* The top byte of the number (after the potential hardcoded 16 0xFF characters for "high" 32 bytes numbers) */ + nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + secp256k1_rand_bits(7) : 1 + secp256k1_rand_int(127)); + /* The number of zero bytes in front of the number (which is 0 or 1 in case of DER, otherwise we extend up to 300 bytes) */ + nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? secp256k1_rand_int(3) : secp256k1_rand_int(300 - nlen[n]) * secp256k1_rand_int(8) / 8); + if (nzlen[n] > ((nlen[n] == 0 || nhbit[n]) ? 1 : 0)) { + *certainly_not_der = 1; + } + CHECK(nlen[n] + nzlen[n] <= 300); + /* The length of the length descriptor for the number. 0 means short encoding, anything else is long encoding. */ + nlenlen[n] = nlen[n] + nzlen[n] < 128 ? 0 : (nlen[n] + nzlen[n] < 256 ? 1 : 2); + if (!der) { + /* nlenlen[n] max 127 bytes */ + int add = secp256k1_rand_int(127 - nlenlen[n]) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256; + nlenlen[n] += add; + if (add != 0) { + *certainly_not_der = 1; + } + } + CHECK(nlen[n] + nzlen[n] + nlenlen[n] <= 427); + } + + /* The total length of the data to go, so far */ + tlen = 2 + nlenlen[0] + nlen[0] + nzlen[0] + 2 + nlenlen[1] + nlen[1] + nzlen[1]; + CHECK(tlen <= 856); + + /* The length of the garbage inside the tuple. */ + elen = (der || indet) ? 0 : secp256k1_rand_int(980 - tlen) * secp256k1_rand_int(8) / 8; + if (elen != 0) { + *certainly_not_der = 1; + } + tlen += elen; + CHECK(tlen <= 980); + + /* The length of the garbage after the end of the tuple. */ + glen = der ? 0 : secp256k1_rand_int(990 - tlen) * secp256k1_rand_int(8) / 8; + if (glen != 0) { + *certainly_not_der = 1; + } + CHECK(tlen + glen <= 990); + + /* Write the tuple header. */ + sig[(*len)++] = 0x30; + if (indet) { + /* Indeterminate length */ + sig[(*len)++] = 0x80; + *certainly_not_der = 1; + } else { + int tlenlen = tlen < 128 ? 0 : (tlen < 256 ? 1 : 2); + if (!der) { + int add = secp256k1_rand_int(127 - tlenlen) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256; + tlenlen += add; + if (add != 0) { + *certainly_not_der = 1; + } + } + if (tlenlen == 0) { + /* Short length notation */ + sig[(*len)++] = tlen; + } else { + /* Long length notation */ + sig[(*len)++] = 128 + tlenlen; + assign_big_endian(sig + *len, tlenlen, tlen); + *len += tlenlen; + } + tlen += tlenlen; + } + tlen += 2; + CHECK(tlen + glen <= 1119); + + for (n = 0; n < 2; n++) { + /* Write the integer header. */ + sig[(*len)++] = 0x02; + if (nlenlen[n] == 0) { + /* Short length notation */ + sig[(*len)++] = nlen[n] + nzlen[n]; + } else { + /* Long length notation. */ + sig[(*len)++] = 128 + nlenlen[n]; + assign_big_endian(sig + *len, nlenlen[n], nlen[n] + nzlen[n]); + *len += nlenlen[n]; + } + /* Write zero padding */ + while (nzlen[n] > 0) { + sig[(*len)++] = 0x00; + nzlen[n]--; + } + if (nlen[n] == 32 && !nlow[n]) { + /* Special extra 16 0xFF bytes in "high" 32-byte numbers */ + int i; + for (i = 0; i < 16; i++) { + sig[(*len)++] = 0xFF; + } + nlen[n] -= 16; + } + /* Write first byte of number */ + if (nlen[n] > 0) { + sig[(*len)++] = nhbyte[n]; + nlen[n]--; + } + /* Generate remaining random bytes of number */ + secp256k1_rand_bytes_test(sig + *len, nlen[n]); + *len += nlen[n]; + nlen[n] = 0; + } + + /* Generate random garbage inside tuple. */ + secp256k1_rand_bytes_test(sig + *len, elen); + *len += elen; + + /* Generate end-of-contents bytes. */ + if (indet) { + sig[(*len)++] = 0; + sig[(*len)++] = 0; + tlen += 2; + } + CHECK(tlen + glen <= 1121); + + /* Generate random garbage outside tuple. */ + secp256k1_rand_bytes_test(sig + *len, glen); + *len += glen; + tlen += glen; + CHECK(tlen <= 1121); + CHECK(tlen == *len); +} + +void run_ecdsa_der_parse(void) { + int i,j; + for (i = 0; i < 200 * count; i++) { + unsigned char buffer[2048]; + size_t buflen = 0; + int certainly_der = 0; + int certainly_not_der = 0; + random_ber_signature(buffer, &buflen, &certainly_der, &certainly_not_der); + CHECK(buflen <= 2048); + for (j = 0; j < 16; j++) { + int ret = 0; + if (j > 0) { + damage_array(buffer, &buflen); + /* We don't know anything anymore about the DERness of the result */ + certainly_der = 0; + certainly_not_der = 0; + } + ret = test_ecdsa_der_parse(buffer, buflen, certainly_der, certainly_not_der); + if (ret != 0) { + size_t k; + fprintf(stderr, "Failure %x on ", ret); + for (k = 0; k < buflen; k++) { + fprintf(stderr, "%02x ", buffer[k]); + } + fprintf(stderr, "\n"); + } + CHECK(ret == 0); + } + } +} + +/* Tests several edge cases. */ +void test_ecdsa_edge_cases(void) { + int t; + secp256k1_ecdsa_signature sig; + + /* Test the case where ECDSA recomputes a point that is infinity. */ + { + secp256k1_gej keyj; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_negate(&ss, &ss); + secp256k1_scalar_inverse(&ss, &ss); + secp256k1_scalar_set_int(&sr, 1); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sr); + secp256k1_ge_set_gej(&key, &keyj); + msg = ss; + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } + + /* Verify signature with r of zero fails. */ + { + const unsigned char pubkey_mods_zero[33] = { + 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, + 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, + 0x41 + }; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_set_int(&msg, 0); + secp256k1_scalar_set_int(&sr, 0); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey_mods_zero, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } + + /* Verify signature with s of zero fails. */ + { + const unsigned char pubkey[33] = { + 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, + 0x01 + }; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 0); + secp256k1_scalar_set_int(&msg, 0); + secp256k1_scalar_set_int(&sr, 1); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } + + /* Verify signature with message 0 passes. */ + { + const unsigned char pubkey[33] = { + 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, + 0x02 + }; + const unsigned char pubkey2[33] = { + 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, + 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, + 0x43 + }; + secp256k1_ge key; + secp256k1_ge key2; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 2); + secp256k1_scalar_set_int(&msg, 0); + secp256k1_scalar_set_int(&sr, 2); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_negate(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_set_int(&ss, 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0); + } + + /* Verify signature with message 1 passes. */ + { + const unsigned char pubkey[33] = { + 0x02, 0x14, 0x4e, 0x5a, 0x58, 0xef, 0x5b, 0x22, + 0x6f, 0xd2, 0xe2, 0x07, 0x6a, 0x77, 0xcf, 0x05, + 0xb4, 0x1d, 0xe7, 0x4a, 0x30, 0x98, 0x27, 0x8c, + 0x93, 0xe6, 0xe6, 0x3c, 0x0b, 0xc4, 0x73, 0x76, + 0x25 + }; + const unsigned char pubkey2[33] = { + 0x02, 0x8a, 0xd5, 0x37, 0xed, 0x73, 0xd9, 0x40, + 0x1d, 0xa0, 0x33, 0xd2, 0xdc, 0xf0, 0xaf, 0xae, + 0x34, 0xcf, 0x5f, 0x96, 0x4c, 0x73, 0x28, 0x0f, + 0x92, 0xc0, 0xf6, 0x9d, 0xd9, 0xb2, 0x09, 0x10, + 0x62 + }; + const unsigned char csr[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xeb + }; + secp256k1_ge key; + secp256k1_ge key2; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_set_int(&msg, 1); + secp256k1_scalar_set_b32(&sr, csr, NULL); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_negate(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_set_int(&ss, 2); + secp256k1_scalar_inverse_var(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0); + } + + /* Verify signature with message -1 passes. */ + { + const unsigned char pubkey[33] = { + 0x03, 0xaf, 0x97, 0xff, 0x7d, 0x3a, 0xf6, 0xa0, + 0x02, 0x94, 0xbd, 0x9f, 0x4b, 0x2e, 0xd7, 0x52, + 0x28, 0xdb, 0x49, 0x2a, 0x65, 0xcb, 0x1e, 0x27, + 0x57, 0x9c, 0xba, 0x74, 0x20, 0xd5, 0x1d, 0x20, + 0xf1 + }; + const unsigned char csr[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xee + }; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_set_int(&msg, 1); + secp256k1_scalar_negate(&msg, &msg); + secp256k1_scalar_set_b32(&sr, csr, NULL); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + secp256k1_scalar_negate(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + secp256k1_scalar_set_int(&ss, 3); + secp256k1_scalar_inverse_var(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } + + /* Signature where s would be zero. */ + { + secp256k1_pubkey pubkey; + size_t siglen; + int32_t ecount; + unsigned char signature[72]; + static const unsigned char nonce[32] = { + 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, 0x01, + }; + static const unsigned char nonce2[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, + 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, + 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40 + }; + const unsigned char key[32] = { + 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, 0x01, + }; + unsigned char msg[32] = { + 0x86, 0x41, 0x99, 0x81, 0x06, 0x23, 0x44, 0x53, + 0xaa, 0x5f, 0x9d, 0x6a, 0x31, 0x78, 0xf4, 0xf7, + 0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62, + 0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9, + }; + ecount = 0; + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 0); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 0); + msg[31] = 0xaa; + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_ecdsa_sign(ctx, NULL, msg, key, precomputed_nonce_function, nonce2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, NULL, key, precomputed_nonce_function, nonce2) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, NULL, precomputed_nonce_function, nonce2) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, key) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, NULL, msg, &pubkey) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, NULL, &pubkey) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, NULL) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 1); + CHECK(ecount == 6); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 7); + /* That pubkeyload fails via an ARGCHECK is a little odd but makes sense because pubkeys are an opaque data type. */ + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 0); + CHECK(ecount == 8); + siglen = 72; + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, NULL, &siglen, &sig) == 0); + CHECK(ecount == 9); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, NULL, &sig) == 0); + CHECK(ecount == 10); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, NULL) == 0); + CHECK(ecount == 11); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 1); + CHECK(ecount == 11); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, NULL, signature, siglen) == 0); + CHECK(ecount == 12); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, NULL, siglen) == 0); + CHECK(ecount == 13); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, signature, siglen) == 1); + CHECK(ecount == 13); + siglen = 10; + /* Too little room for a signature does not fail via ARGCHECK. */ + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 0); + CHECK(ecount == 13); + ecount = 0; + CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, NULL) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, NULL, &sig) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, &sig) == 1); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, NULL, signature) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, NULL) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 1); + CHECK(ecount == 5); + memset(signature, 255, 64); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 0); + CHECK(ecount == 5); + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); + } + + /* Nonce function corner cases. */ + for (t = 0; t < 2; t++) { + static const unsigned char zero[32] = {0x00}; + int i; + unsigned char key[32]; + unsigned char msg[32]; + secp256k1_ecdsa_signature sig2; + secp256k1_scalar sr[512], ss; + const unsigned char *extra; + extra = t == 0 ? NULL : zero; + memset(msg, 0, 32); + msg[31] = 1; + /* High key results in signature failure. */ + memset(key, 0xFF, 32); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0); + CHECK(is_empty_signature(&sig)); + /* Zero key results in signature failure. */ + memset(key, 0, 32); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0); + CHECK(is_empty_signature(&sig)); + /* Nonce function failure results in signature failure. */ + key[31] = 1; + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_fail, extra) == 0); + CHECK(is_empty_signature(&sig)); + /* The retry loop successfully makes its way to the first good value. */ + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_retry, extra) == 1); + CHECK(!is_empty_signature(&sig)); + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, nonce_function_rfc6979, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); + /* The default nonce function is deterministic. */ + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); + /* The default nonce function changes output with different messages. */ + for(i = 0; i < 256; i++) { + int j; + msg[0] = i; + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2); + for (j = 0; j < i; j++) { + CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); + } + } + msg[0] = 0; + msg[31] = 2; + /* The default nonce function changes output with different keys. */ + for(i = 256; i < 512; i++) { + int j; + key[0] = i - 256; + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2); + for (j = 0; j < i; j++) { + CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); + } + } + key[0] = 0; + } + + { + /* Check that optional nonce arguments do not have equivalent effect. */ + const unsigned char zeros[32] = {0}; + unsigned char nonce[32]; + unsigned char nonce2[32]; + unsigned char nonce3[32]; + unsigned char nonce4[32]; + VG_UNDEF(nonce,32); + VG_UNDEF(nonce2,32); + VG_UNDEF(nonce3,32); + VG_UNDEF(nonce4,32); + CHECK(nonce_function_rfc6979(nonce, zeros, zeros, NULL, NULL, 0) == 1); + VG_CHECK(nonce,32); + CHECK(nonce_function_rfc6979(nonce2, zeros, zeros, zeros, NULL, 0) == 1); + VG_CHECK(nonce2,32); + CHECK(nonce_function_rfc6979(nonce3, zeros, zeros, NULL, (void *)zeros, 0) == 1); + VG_CHECK(nonce3,32); + CHECK(nonce_function_rfc6979(nonce4, zeros, zeros, zeros, (void *)zeros, 0) == 1); + VG_CHECK(nonce4,32); + CHECK(memcmp(nonce, nonce2, 32) != 0); + CHECK(memcmp(nonce, nonce3, 32) != 0); + CHECK(memcmp(nonce, nonce4, 32) != 0); + CHECK(memcmp(nonce2, nonce3, 32) != 0); + CHECK(memcmp(nonce2, nonce4, 32) != 0); + CHECK(memcmp(nonce3, nonce4, 32) != 0); + } + + + /* Privkey export where pubkey is the point at infinity. */ + { + unsigned char privkey[300]; + unsigned char seckey[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41, + }; + size_t outlen = 300; + CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 0)); + outlen = 300; + CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 1)); + } +} + +void run_ecdsa_edge_cases(void) { + test_ecdsa_edge_cases(); +} + +#ifdef ENABLE_OPENSSL_TESTS +EC_KEY *get_openssl_key(const unsigned char *key32) { + unsigned char privkey[300]; + size_t privkeylen; + const unsigned char* pbegin = privkey; + int compr = secp256k1_rand_bits(1); + EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1); + CHECK(ec_privkey_export_der(ctx, privkey, &privkeylen, key32, compr)); + CHECK(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen)); + CHECK(EC_KEY_check_key(ec_key)); + return ec_key; +} + +void test_ecdsa_openssl(void) { + secp256k1_gej qj; + secp256k1_ge q; + secp256k1_scalar sigr, sigs; + secp256k1_scalar one; + secp256k1_scalar msg2; + secp256k1_scalar key, msg; + EC_KEY *ec_key; + unsigned int sigsize = 80; + size_t secp_sigsize = 80; + unsigned char message[32]; + unsigned char signature[80]; + unsigned char key32[32]; + secp256k1_rand256_test(message); + secp256k1_scalar_set_b32(&msg, message, NULL); + random_scalar_order_test(&key); + secp256k1_scalar_get_b32(key32, &key); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &qj, &key); + secp256k1_ge_set_gej(&q, &qj); + ec_key = get_openssl_key(key32); + CHECK(ec_key != NULL); + CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key)); + CHECK(secp256k1_ecdsa_sig_parse(&sigr, &sigs, signature, sigsize)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg)); + secp256k1_scalar_set_int(&one, 1); + secp256k1_scalar_add(&msg2, &msg, &one); + CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg2)); + + random_sign(&sigr, &sigs, &key, &msg, NULL); + CHECK(secp256k1_ecdsa_sig_serialize(signature, &secp_sigsize, &sigr, &sigs)); + CHECK(ECDSA_verify(0, message, sizeof(message), signature, secp_sigsize, ec_key) == 1); + + EC_KEY_free(ec_key); +} + +void run_ecdsa_openssl(void) { + int i; + for (i = 0; i < 10*count; i++) { + test_ecdsa_openssl(); + } +} +#endif + +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_SCHNORR +# include "modules/schnorr/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_RECOVERY +# include "modules/recovery/tests_impl.h" +#endif + +int main(int argc, char **argv) { + unsigned char seed16[16] = {0}; + unsigned char run32[32] = {0}; + /* find iteration count */ + if (argc > 1) { + count = strtol(argv[1], NULL, 0); + } + + /* find random seed */ + if (argc > 2) { + int pos = 0; + const char* ch = argv[2]; + while (pos < 16 && ch[0] != 0 && ch[1] != 0) { + unsigned short sh; + if (sscanf(ch, "%2hx", &sh)) { + seed16[pos] = sh; + } else { + break; + } + ch += 2; + pos++; + } + } else { + FILE *frand = fopen("/dev/urandom", "r"); + if ((frand == NULL) || !fread(&seed16, sizeof(seed16), 1, frand)) { + uint64_t t = time(NULL) * (uint64_t)1337; + seed16[0] ^= t; + seed16[1] ^= t >> 8; + seed16[2] ^= t >> 16; + seed16[3] ^= t >> 24; + seed16[4] ^= t >> 32; + seed16[5] ^= t >> 40; + seed16[6] ^= t >> 48; + seed16[7] ^= t >> 56; + } + fclose(frand); + } + secp256k1_rand_seed(seed16); + + printf("test count = %i\n", count); + printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]); + + /* initialize */ + run_context_tests(); + ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + if (secp256k1_rand_bits(1)) { + secp256k1_rand256(run32); + CHECK(secp256k1_context_randomize(ctx, secp256k1_rand_bits(1) ? run32 : NULL)); + } + + run_rand_bits(); + run_rand_int(); + + run_sha256_tests(); + run_hmac_sha256_tests(); + run_rfc6979_hmac_sha256_tests(); + +#ifndef USE_NUM_NONE + /* num tests */ + run_num_smalltests(); +#endif + + /* scalar tests */ + run_scalar_tests(); + + /* field tests */ + run_field_inv(); + run_field_inv_var(); + run_field_inv_all_var(); + run_field_misc(); + run_field_convert(); + run_sqr(); + run_sqrt(); + + /* group tests */ + run_ge(); + run_group_decompress(); + + /* ecmult tests */ + run_wnaf(); + run_point_times_order(); + run_ecmult_chain(); + run_ecmult_constants(); + run_ecmult_gen_blind(); + run_ecmult_const_tests(); + run_ec_combine(); + + /* endomorphism tests */ +#ifdef USE_ENDOMORPHISM + run_endomorphism_tests(); +#endif + + /* EC point parser test */ + run_ec_pubkey_parse_test(); + + /* EC key edge cases */ + run_eckey_edge_case_test(); + +#ifdef ENABLE_MODULE_ECDH + /* ecdh tests */ + run_ecdh_tests(); +#endif + + /* ecdsa tests */ + run_random_pubkeys(); + run_ecdsa_der_parse(); + run_ecdsa_sign_verify(); + run_ecdsa_end_to_end(); + run_ecdsa_edge_cases(); +#ifdef ENABLE_OPENSSL_TESTS + run_ecdsa_openssl(); +#endif + +#ifdef ENABLE_MODULE_SCHNORR + /* Schnorr tests */ + run_schnorr_tests(); +#endif + +#ifdef ENABLE_MODULE_RECOVERY + /* ECDSA pubkey recovery tests */ + run_recovery_tests(); +#endif + + secp256k1_rand256(run32); + printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]); + + /* shutdown */ + secp256k1_context_destroy(ctx); + + printf("no problems found\n"); + return 0; +} diff --git a/src/secp256k1/src/util.h b/src/secp256k1/src/util.h new file mode 100644 index 000000000..4eef4ded4 --- /dev/null +++ b/src/secp256k1/src/util.h @@ -0,0 +1,110 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_UTIL_H_ +#define _SECP256K1_UTIL_H_ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include +#include +#include + +typedef struct { + void (*fn)(const char *text, void* data); + const void* data; +} secp256k1_callback; + +static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback * const cb, const char * const text) { + cb->fn(text, (void*)cb->data); +} + +#ifdef DETERMINISTIC +#define TEST_FAILURE(msg) do { \ + fprintf(stderr, "%s\n", msg); \ + abort(); \ +} while(0); +#else +#define TEST_FAILURE(msg) do { \ + fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, msg); \ + abort(); \ +} while(0) +#endif + +#ifdef HAVE_BUILTIN_EXPECT +#define EXPECT(x,c) __builtin_expect((x),(c)) +#else +#define EXPECT(x,c) (x) +#endif + +#ifdef DETERMINISTIC +#define CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + TEST_FAILURE("test condition failed"); \ + } \ +} while(0) +#else +#define CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + TEST_FAILURE("test condition failed: " #cond); \ + } \ +} while(0) +#endif + +/* Like assert(), but when VERIFY is defined, and side-effect safe. */ +#ifdef VERIFY +#define VERIFY_CHECK CHECK +#define VERIFY_SETUP(stmt) do { stmt; } while(0) +#else +#define VERIFY_CHECK(cond) do { (void)(cond); } while(0) +#define VERIFY_SETUP(stmt) +#endif + +static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) { + void *ret = malloc(size); + if (ret == NULL) { + secp256k1_callback_call(cb, "Out of memory"); + } + return ret; +} + +/* Macro for restrict, when available and not in a VERIFY build. */ +#if defined(SECP256K1_BUILD) && defined(VERIFY) +# define SECP256K1_RESTRICT +#else +# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if SECP256K1_GNUC_PREREQ(3,0) +# define SECP256K1_RESTRICT __restrict__ +# elif (defined(_MSC_VER) && _MSC_VER >= 1400) +# define SECP256K1_RESTRICT __restrict +# else +# define SECP256K1_RESTRICT +# endif +# else +# define SECP256K1_RESTRICT restrict +# endif +#endif + +#if defined(_WIN32) +# define I64FORMAT "I64d" +# define I64uFORMAT "I64u" +#else +# define I64FORMAT "lld" +# define I64uFORMAT "llu" +#endif + +#if defined(HAVE___INT128) +# if defined(__GNUC__) +# define SECP256K1_GNUC_EXT __extension__ +# else +# define SECP256K1_GNUC_EXT +# endif +SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t; +#endif + +#endif diff --git a/src/segwit_addr.c b/src/segwit_addr.c new file mode 100644 index 000000000..cb5d6d6bd --- /dev/null +++ b/src/segwit_addr.c @@ -0,0 +1,191 @@ +/* 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 + +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) { + 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; + 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/src/serialize.c b/src/serialize.c new file mode 100644 index 000000000..ba874629d --- /dev/null +++ b/src/serialize.c @@ -0,0 +1,356 @@ +/* Copyright 2012 exMULTI, Inc. + * Distributed under the MIT/X11 software license, see the accompanying + * file COPYING or http://www.opensource.org/licenses/mit-license.php. + */ + +#include +#include + +#include + +void ser_bytes(cstring* s, const void* p, size_t len) +{ + cstr_append_buf(s, p, len); +} + +void ser_u16(cstring* s, uint16_t v_) +{ + uint16_t v = htole16(v_); + cstr_append_buf(s, &v, sizeof(v)); +} + +void ser_u32(cstring* s, uint32_t v_) +{ + uint32_t v = htole32(v_); + cstr_append_buf(s, &v, sizeof(v)); +} + +void ser_s32(cstring* s, int32_t v_) +{ + ser_u32(s, (uint32_t)v_); +} + +void ser_u64(cstring* s, uint64_t v_) +{ + uint64_t v = htole64(v_); + cstr_append_buf(s, &v, sizeof(v)); +} + +void ser_s64(cstring* s, int64_t v_) +{ + ser_u64(s, (uint64_t)v_); +} + +void ser_u256(cstring* s, const unsigned char* v_) +{ + ser_bytes(s, v_, 32); +} + +void ser_varlen(cstring* s, uint32_t vlen) +{ + unsigned char c; + + if (vlen < 253) { + c = vlen; + ser_bytes(s, &c, 1); + } + + else if (vlen < 0x10000) { + c = 253; + ser_bytes(s, &c, 1); + ser_u16(s, (uint16_t)vlen); + } + + else { + c = 254; + ser_bytes(s, &c, 1); + ser_u32(s, vlen); + } + + /* u64 case intentionally not implemented */ +} + +void ser_str(cstring* s, const char* s_in, size_t maxlen) +{ + size_t slen = strnlen(s_in, maxlen); + + ser_varlen(s, slen); + ser_bytes(s, s_in, slen); +} + +void ser_varstr(cstring* s, cstring* s_in) +{ + if (!s_in || !s_in->len) { + ser_varlen(s, 0); + return; + } + + ser_varlen(s, s_in->len); + ser_bytes(s, s_in->str, s_in->len); +} + +int deser_skip(struct const_buffer* buf, size_t len) +{ + char* p; + if (buf->len < len) + return false; + + p = (char*)buf->p; + p += len; + buf->p = p; + buf->len -= len; + + return true; +} + +int deser_bytes(void* po, struct const_buffer* buf, size_t len) +{ + char* p; + if (buf->len < len) + return false; + + memcpy(po, buf->p, len); + p = (char*)buf->p; + p += len; + buf->p = p; + buf->len -= len; + + return true; +} + +int deser_u16(uint16_t* vo, struct const_buffer* buf) +{ + uint16_t v; + + if (!deser_bytes(&v, buf, sizeof(v))) + return false; + + *vo = le16toh(v); + return true; +} + +int deser_s32(int32_t* vo, struct const_buffer* buf) +{ + int32_t v; + + if (!deser_bytes(&v, buf, sizeof(v))) + return false; + + *vo = le32toh(v); + return true; +} + +int deser_u32(uint32_t* vo, struct const_buffer* buf) +{ + uint32_t v; + + if (!deser_bytes(&v, buf, sizeof(v))) + return false; + + *vo = le32toh(v); + return true; +} + +int deser_u64(uint64_t* vo, struct const_buffer* buf) +{ + uint64_t v; + + if (!deser_bytes(&v, buf, sizeof(v))) + return false; + + *vo = le64toh(v); + return true; +} + +int deser_u256(uint256 vo, struct const_buffer* buf) +{ + return deser_bytes(vo, buf, 32); +} + +int deser_varlen(uint32_t* lo, struct const_buffer* buf) +{ + uint32_t len; + + unsigned char c; + if (!deser_bytes(&c, buf, 1)) + return false; + + if (c == 253) { + uint16_t v16; + if (!deser_u16(&v16, buf)) + return false; + len = v16; + } else if (c == 254) { + uint32_t v32; + if (!deser_u32(&v32, buf)) + return false; + len = v32; + } else if (c == 255) { + uint64_t v64; + if (!deser_u64(&v64, buf)) + return false; + len = (uint32_t)v64; /* WARNING: truncate */ + } else + len = c; + + *lo = len; + return true; +} + +int deser_varlen_from_file(uint32_t* lo, FILE* file) +{ + uint32_t len; + struct const_buffer buf; + unsigned char c; + const unsigned char bufp[sizeof(uint64_t)]; + + if (fread(&c, 1, 1, file) != 1) + return false; + + buf.p = (void*)bufp; + buf.len = sizeof(uint64_t); + + if (c == 253) { + uint16_t v16; + if (fread((void*)buf.p, 1, sizeof(v16), file) != sizeof(v16)) + return false; + if (!deser_u16(&v16, &buf)) + return false; + len = v16; + } else if (c == 254) { + uint32_t v32; + if (fread((void*)buf.p, 1, sizeof(v32), file) != sizeof(v32)) + return false; + if (!deser_u32(&v32, &buf)) + return false; + len = v32; + } else if (c == 255) { + uint64_t v64; + if (fread((void*)buf.p, 1, sizeof(v64), file) != sizeof(v64)) + return false; + if (!deser_u64(&v64, &buf)) + return false; + len = (uint32_t)v64; /* WARNING: truncate */ + } else + len = c; + + *lo = len; + return true; +} + +int deser_varlen_file(uint32_t* lo, FILE* file, uint8_t* rawdata, size_t* buflen_inout) +{ + uint32_t len; + struct const_buffer buf; + unsigned char c; + const unsigned char bufp[sizeof(uint64_t)]; + + /* check min size of the buffer */ + if (*buflen_inout < sizeof(len)) + return false; + + if (fread(&c, 1, 1, file) != 1) + return false; + + rawdata[0] = c; + *buflen_inout = 1; + + buf.p = (void*)bufp; + buf.len = sizeof(uint64_t); + + if (c == 253) { + uint16_t v16; + if (fread((void*)buf.p, 1, sizeof(v16), file) != sizeof(v16)) + return false; + memcpy(rawdata + 1, buf.p, sizeof(v16)); + *buflen_inout += sizeof(v16); + if (!deser_u16(&v16, &buf)) + return false; + len = v16; + } else if (c == 254) { + uint32_t v32; + if (fread((void*)buf.p, 1, sizeof(v32), file) != sizeof(v32)) + return false; + memcpy(rawdata + 1, buf.p, sizeof(v32)); + *buflen_inout += sizeof(v32); + if (!deser_u32(&v32, &buf)) + return false; + len = v32; + } else if (c == 255) { + uint64_t v64; + if (fread((void*)buf.p, 1, sizeof(v64), file) != sizeof(v64)) + return false; + memcpy(rawdata + 1, buf.p, sizeof(uint32_t)); /* warning, truncate! */ + *buflen_inout += sizeof(uint32_t); + if (!deser_u64(&v64, &buf)) + return false; + len = (uint32_t)v64; /* WARNING: truncate */ + } else + len = c; + + *lo = len; + return true; +} + + +int deser_str(char* so, struct const_buffer* buf, size_t maxlen) +{ + uint32_t len; + uint32_t skip_len = 0; + if (!deser_varlen(&len, buf)) + return false; + + /* if input larger than buffer, truncate copy, skip remainder */ + if (len > maxlen) { + skip_len = len - maxlen; + len = maxlen; + } + + if (!deser_bytes(so, buf, len)) + return false; + if (!deser_skip(buf, skip_len)) + return false; + + /* add C string null */ + if (len < maxlen) + so[len] = 0; + else + so[maxlen - 1] = 0; + + return true; +} + +int deser_varstr(cstring** so, struct const_buffer* buf) +{ + uint32_t len; + cstring* s; + char* p; + + if (*so) { + cstr_free(*so, 1); + *so = NULL; + } + + if (!deser_varlen(&len, buf)) + return false; + + if (buf->len < len) + return false; + + s = cstr_new_sz(len); + cstr_append_buf(s, buf->p, len); + + p = (char*)buf->p; + p += len; + buf->p = p; + buf->len -= len; + + *so = s; + + return true; +} + +int deser_s64(int64_t* vo, struct const_buffer* buf) +{ + return deser_u64((uint64_t*)vo, buf); +} diff --git a/src/sha2.c b/src/sha2.c new file mode 100644 index 000000000..d9ce19603 --- /dev/null +++ b/src/sha2.c @@ -0,0 +1,1024 @@ +/** + * Copyright (c) 2000-2001 Aaron D. Gifford + * Copyright (c) 2013 Pavol Rusnak + * Copyright (c) 2015 Jonas Schnelli + * 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 + +/* + * 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 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 + +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: */ +static const 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: */ +static const 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: */ +static const 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-512 */ +static const sha2_word64 sha512_initial_hash_value[8] = { + 0x6a09e667f3bcc908ULL, + 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, + 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, + 0x5be0cd19137e2179ULL}; + + +/*** 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, (const 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; + sha2_word64* t; + + /* 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: */ + t = (sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH]; + *t = 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; +} + +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); +} + + +/*** 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, (const 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; + sha2_word64* t; + + 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): */ + 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); +} + +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)); +} + +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); +} + +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/src/tools/bitcoin-send-tx.c b/src/tools/bitcoin-send-tx.c new file mode 100644 index 000000000..025b685bc --- /dev/null +++ b/src/tools/bitcoin-send-tx.c @@ -0,0 +1,359 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2017 Jonas Schnelli + + 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 "libbtc-config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct option long_options[] = + { + {"testnet", no_argument, NULL, 't'}, + {"regtest", no_argument, NULL, 'r'}, + {"ips", no_argument, NULL, 'i'}, + {"debug", no_argument, NULL, 'd'}, + {"timeout", no_argument, NULL, 's'}, + {"maxnodes", no_argument, NULL, 'm'}, + {NULL, 0, NULL, 0}}; + +static void print_version() +{ + printf("Version: %s %s\n", PACKAGE_NAME, PACKAGE_VERSION); +} + +static void print_usage() +{ + print_version(); + printf("Usage: bitcoin-send-tx (-i|-ips ) (-m[--maxpeers] ) (-t[--testnet]) (-r[--regtest]) (-d[--debug]) (-s[--timeout] ) \n"); + printf("\nExamples: \n"); + printf("Send a TX to random peers on testnet:\n"); + printf("> bitcoin-send-tx --testnet \n\n"); + printf("Send a TX to specific peers on mainnet:\n"); + printf("> bitcoin-send-tx -i 127.0.0.1:8333,192.168.0.1:8333 \n\n"); +} + +static bool showError(const char* er) +{ + printf("Error: %s\n", er); + return 1; +} + +btc_bool broadcast_tx(const btc_chainparams* chain, const btc_tx* tx, const char* ips, int maxpeers, int timeout, btc_bool debug); + +int main(int argc, char* argv[]) +{ + int ret = 0; + int long_index = 0; + int opt = 0; + char* data = 0; + char* ips = 0; + int debug = 0; + int timeout = 15; + int maxnodes = 10; + const btc_chainparams* chain = &btc_chainparams_main; + + if (argc <= 1 || strlen(argv[argc - 1]) == 0 || argv[argc - 1][0] == '-') { + /* exit if no command was provided */ + print_usage(); + exit(EXIT_FAILURE); + } + data = argv[argc - 1]; + + /* get arguments */ + while ((opt = getopt_long_only(argc, argv, "i:trds:m:", long_options, &long_index)) != -1) { + switch (opt) { + case 't': + chain = &btc_chainparams_test; + break; + case 'r': + chain = &btc_chainparams_regtest; + break; + case 'd': + debug = 1; + break; + case 's': + timeout = (int)strtol(optarg, (char**)NULL, 10); + break; + case 'i': + ips = optarg; + break; + case 'm': + maxnodes = (int)strtol(optarg, (char**)NULL, 10); + break; + case 'v': + print_version(); + exit(EXIT_SUCCESS); + break; + default: + print_usage(); + exit(EXIT_FAILURE); + } + } + + if (data == NULL || strlen(data) == 0 || strlen(data) > BTC_MAX_P2P_MSG_SIZE) { + return showError("Transaction in invalid or to large.\n"); + } + uint8_t* data_bin = btc_malloc(strlen(data) / 2 + 1); + int outlen = 0; + utils_hex_to_bin(data, data_bin, strlen(data), &outlen); + + btc_tx* tx = btc_tx_new(); + if (btc_tx_deserialize(data_bin, outlen, tx, NULL, true)) { + broadcast_tx(chain, tx, ips, maxnodes, timeout, debug); + } else { + showError("Transaction is invalid\n"); + ret = 1; + } + btc_free(data_bin); + btc_tx_free(tx); + + return ret; +} + +struct broadcast_ctx { + const btc_tx* tx; + unsigned int timeout; + int debuglevel; + int connected_to_peers; + int max_peers_to_connect; + int max_peers_to_inv; + int inved_to_peers; + int getdata_from_peers; + int found_on_non_inved_peers; + uint64_t start_time; +}; + +static btc_bool broadcast_timer_cb(btc_node* node, uint64_t* now) +{ + struct broadcast_ctx* ctx = (struct broadcast_ctx*)node->nodegroup->ctx; + + if (node->time_started_con > 0) { + node->nodegroup->log_write_cb("timer node %d, delta: %" PRIu64 " secs (timeout is: %d)\n", node->nodeid, (*now - ctx->start_time), ctx->timeout); + } + if ((*now - ctx->start_time) > ctx->timeout) + btc_node_disconnect(node); + + if ((node->hints & (1 << 1)) == (1 << 1)) { + btc_node_disconnect(node); + } + + if ((node->hints & (1 << 2)) == (1 << 2)) { + btc_node_disconnect(node); + } + + /* return true = run internal timer logic (ping, disconnect-timeout, etc.) */ + return true; +} + +void broadcast_handshake_done(struct btc_node_* node) +{ + char ipaddr[256]; + struct sockaddr_in *ad = (struct sockaddr_in *) &node->addr; + evutil_inet_ntop(node->addr.sa_family, &ad->sin_addr, ipaddr, sizeof(ipaddr)); + + printf("Successfully connected to peer %d (%s)\n", node->nodeid, ipaddr); + struct broadcast_ctx* ctx = (struct broadcast_ctx*)node->nodegroup->ctx; + ctx->connected_to_peers++; + + if (ctx->inved_to_peers >= ctx->max_peers_to_inv) { + return; + } + + /* create a INV */ + cstring* inv_msg_cstr = cstr_new_sz(256); + btc_p2p_inv_msg inv_msg; + memset(&inv_msg, 0, sizeof(inv_msg)); + + uint256 hash; + btc_tx_hash(ctx->tx, hash); + btc_p2p_msg_inv_init(&inv_msg, BTC_INV_TYPE_TX, hash); + + /* serialize the inv count (1) */ + ser_varlen(inv_msg_cstr, 1); + btc_p2p_msg_inv_ser(&inv_msg, inv_msg_cstr); + + cstring* p2p_msg = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, BTC_MSG_INV, inv_msg_cstr->str, inv_msg_cstr->len); + cstr_free(inv_msg_cstr, true); + btc_node_send(node, p2p_msg); + cstr_free(p2p_msg, true); + + /* set hint bit 0 == inv sent */ + node->hints |= (1 << 0); + ctx->inved_to_peers++; +} + +btc_bool broadcast_should_connect_more(btc_node* node) +{ + struct broadcast_ctx* ctx = (struct broadcast_ctx*)node->nodegroup->ctx; + node->nodegroup->log_write_cb("check if more nodes are required (connected to already: %d)\n", ctx->connected_to_peers); + if (ctx->connected_to_peers >= ctx->max_peers_to_connect) { + return false; + } + return true; +} + +void broadcast_post_cmd(struct btc_node_* node, btc_p2p_msg_hdr* hdr, struct const_buffer* buf) +{ + struct broadcast_ctx* ctx = (struct broadcast_ctx*)node->nodegroup->ctx; + if (strcmp(hdr->command, BTC_MSG_INV) == 0) { + /* hash the tx */ + /* TODO: cache the hash */ + uint256 hash; + btc_tx_hash(ctx->tx, hash); + + // decompose + uint32_t vsize; + if (!deser_varlen(&vsize, buf)) { + btc_node_missbehave(node); + return; + }; + for (unsigned int i = 0; i < vsize; i++) { + btc_p2p_inv_msg inv_msg; + if (!btc_p2p_msg_inv_deser(&inv_msg, buf)) { + btc_node_missbehave(node); + return; + } + if (memcmp(hash, inv_msg.hash, sizeof(hash)) == 0) { + // txfound + /* set hint bit 2 == tx found on peer*/ + node->hints |= (1 << 2); + printf("node %d has the tx\n", node->nodeid); + ctx->found_on_non_inved_peers++; + printf("tx successfully seen on node %d\n", node->nodeid); + } + } + } else if (strcmp(hdr->command, BTC_MSG_GETDATA) == 0 && ((node->hints & (1 << 1)) != (1 << 1))) { + ctx->getdata_from_peers++; + //only allow a single object in getdata for the broadcaster + uint32_t vsize; + if (!deser_varlen(&vsize, buf) || vsize != 1) { + btc_node_missbehave(node); + return; + } + + btc_p2p_inv_msg inv_msg; + memset(&inv_msg, 0, sizeof(inv_msg)); + if (!btc_p2p_msg_inv_deser(&inv_msg, buf) || inv_msg.type != BTC_INV_TYPE_TX) { + btc_node_missbehave(node); + return; + }; + + /* send the tx */ + cstring* tx_ser = cstr_new_sz(1024); + btc_tx_serialize(tx_ser, ctx->tx, true); + cstring* p2p_msg = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, BTC_MSG_TX, tx_ser->str, tx_ser->len); + cstr_free(tx_ser, true); + btc_node_send(node, p2p_msg); + cstr_free(p2p_msg, true); + + /* set hint bit 1 == tx sent */ + node->hints |= (1 << 1); + + printf("tx successfully sent to node %d\n", node->nodeid); + } +} + +btc_bool broadcast_tx(const btc_chainparams* chain, const btc_tx* tx, const char* ips, int maxpeers, int timeout, btc_bool debug) +{ + struct broadcast_ctx ctx; + ctx.tx = tx; + ctx.debuglevel = debug; + ctx.timeout = timeout; + ctx.max_peers_to_inv = 2; + ctx.found_on_non_inved_peers = 0; + ctx.getdata_from_peers = 0; + ctx.inved_to_peers = 0; + ctx.connected_to_peers = 0; + ctx.max_peers_to_connect = maxpeers; + /* create a node group */ + btc_node_group* group = btc_node_group_new(chain); + group->desired_amount_connected_nodes = ctx.max_peers_to_connect; + group->ctx = &ctx; + + /* set the timeout callback */ + group->periodic_timer_cb = broadcast_timer_cb; + + /* set a individual log print function */ + if (debug) { + group->log_write_cb = net_write_log_printf; + } + group->postcmd_cb = broadcast_post_cmd; + group->handshake_done_cb = broadcast_handshake_done; + group->should_connect_to_more_nodes_cb = broadcast_should_connect_more; + + btc_node_group_add_peers_by_ip_or_seed(group, ips); + + uint256 txhash; + btc_tx_hash(tx, txhash); + char hexout[sizeof(txhash)*2+1]; + utils_bin_to_hex(txhash, sizeof(txhash), hexout); + hexout[sizeof(txhash)*2] = 0; + utils_reverse_hex(hexout, strlen(hexout)); + printf("Start broadcasting transaction: %s with timeout %d seconds\n", hexout, timeout); + /* connect to the next node */ + ctx.start_time = time(NULL); + printf("Trying to connect to nodes...\n"); + btc_node_group_connect_next_nodes(group); + + /* start the event loop */ + btc_node_group_event_loop(group); + + /* cleanup */ + btc_node_group_free(group); //will also free the nodes structures from the heap + + printf("\n\nResult:\n=============\n"); + printf("Max nodes to connect to: %d\n", ctx.max_peers_to_connect); + printf("Successfully connected to nodes: %d\n", ctx.connected_to_peers); + printf("Informed nodes: %d\n", ctx.inved_to_peers); + printf("Requested from nodes: %d\n", ctx.getdata_from_peers); + printf("Seen on other nodes: %d\n", ctx.found_on_non_inved_peers); + + if (ctx.getdata_from_peers == 0) + { + printf("\nError: The transaction was not requested by the informed nodes. This usually happens when the transaction has already been broadcasted\n"); + } + else if (ctx.found_on_non_inved_peers == 0) + { + printf("\nError: The transaction was not relayed back. Your transaction is very likely invalid (or was already broadcased and picked up by an invalid node)\n"); + } + return 1; +} diff --git a/src/tools/bitcoin-spv.c b/src/tools/bitcoin-spv.c new file mode 100644 index 000000000..ec82b0261 --- /dev/null +++ b/src/tools/bitcoin-spv.c @@ -0,0 +1,226 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2017 Jonas Schnelli + + 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 "libbtc-config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct option long_options[] = + { + {"testnet", no_argument, NULL, 't'}, + {"regtest", no_argument, NULL, 'r'}, + {"ips", no_argument, NULL, 'i'}, + {"debug", no_argument, NULL, 'd'}, + {"maxnodes", no_argument, NULL, 'm'}, + {"dbfile", no_argument, NULL, 'f'}, + {"continuous", no_argument, NULL, 'c'}, + {NULL, 0, NULL, 0}}; + +static void print_version() +{ + printf("Version: %s %s\n", PACKAGE_NAME, PACKAGE_VERSION); +} + +static void print_usage() +{ + print_version(); + printf("Usage: bitcoin-spv (-c|continuous) (-i|-ips ) (-m[--maxpeers] ) (-t[--testnet]) (-f ) (-r[--regtest]) (-d[--debug]) (-s[--timeout] ) \n"); + printf("Supported commands:\n"); + printf(" scan (scan blocks up to the tip, creates header.db file)\n"); + printf("\nExamples: \n"); + printf("Sync up to the chain tip and stores all headers in headers.db (quit once synced):\n"); + printf("> bitcoin-spv scan\n\n"); + printf("Sync up to the chain tip and give some debug output during that process:\n"); + printf("> bitcoin-spv -d scan\n\n"); + printf("Sync up, show debug info, don't store headers in file (only in memory), wait for new blocks:\n"); + printf("> bitcoin-spv -d -f 0 -c scan\n\n"); +} + +static bool showError(const char* er) +{ + printf("Error: %s\n", er); + return 1; +} + +btc_bool spv_header_message_processed(struct btc_spv_client_ *client, btc_node *node, btc_blockindex *newtip) { + UNUSED(client); + UNUSED(node); + if (newtip) { + printf("New headers tip height %d\n", newtip->height); + } + return true; +} + +static btc_bool quit_when_synced = true; +void spv_sync_completed(btc_spv_client* client) { + printf("Sync completed, at height %d\n", client->headers_db->getchaintip(client->headers_db_ctx)->height); + if (quit_when_synced) { + btc_node_group_shutdown(client->nodegroup); + } + else { + printf("Waiting for new blocks or relevant transactions...\n"); + } +} + +int main(int argc, char* argv[]) +{ + int ret = 0; + int long_index = 0; + int opt = 0; + char* data = 0; + char* ips = 0; + btc_bool debug = false; + int timeout = 15; + int maxnodes = 10; + char* dbfile = 0; + const btc_chainparams* chain = &btc_chainparams_main; + + if (argc <= 1 || strlen(argv[argc - 1]) == 0 || argv[argc - 1][0] == '-') { + /* exit if no command was provided */ + print_usage(); + exit(EXIT_FAILURE); + } + data = argv[argc - 1]; + + /* get arguments */ + while ((opt = getopt_long_only(argc, argv, "i:ctrds:m:f:", long_options, &long_index)) != -1) { + switch (opt) { + case 'c': + quit_when_synced = false; + break; + case 't': + chain = &btc_chainparams_test; + break; + case 'r': + chain = &btc_chainparams_regtest; + break; + case 'd': + debug = true; + break; + case 's': + timeout = (int)strtol(optarg, (char**)NULL, 10); + break; + case 'i': + ips = optarg; + break; + case 'm': + maxnodes = (int)strtol(optarg, (char**)NULL, 10); + break; + case 'f': + dbfile = optarg; + break; + case 'v': + print_version(); + exit(EXIT_SUCCESS); + break; + default: + print_usage(); + exit(EXIT_FAILURE); + } + } + + if (strcmp(data, "scan") == 0) { + btc_ecc_start(); + btc_wallet *wallet = btc_wallet_new(chain); + int error; + btc_bool created; + int res = btc_wallet_load(wallet, "wallet.db", &error, &created); + if (!res) { + fprintf(stdout, "Loading wallet failed\n"); + exit(EXIT_FAILURE); + } + if (created) { + // create a new key + + btc_hdnode node; + uint8_t seed[32]; + assert(btc_random_bytes(seed, sizeof(seed), true)); + btc_hdnode_from_seed(seed, sizeof(seed), &node); + btc_wallet_set_master_key_copy(wallet, &node); + } + else { + // ensure we have a key + // TODO + } + + btc_wallet_hdnode* node = btc_wallet_next_key(wallet); + size_t strsize = 128; + char str[strsize]; + btc_hdnode_get_p2pkh_address(node->hdnode, chain, str, strsize); + printf("Wallet addr: %s (child %d)\n", str, node->hdnode->child_num); + + vector *addrs = vector_new(1, free); + btc_wallet_get_addresses(wallet, addrs); + for (unsigned int i = 0; i < addrs->len; i++) { + char* addr= vector_idx(addrs, i); + printf("Addr: %s\n", addr); + } + vector_free(addrs, true); + btc_spv_client* client = btc_spv_client_new(chain, debug, (dbfile && (dbfile[0] == '0' || (strlen(dbfile) > 1 && dbfile[0] == 'n' && dbfile[0] == 'o'))) ? true : false); + client->header_message_processed = spv_header_message_processed; + client->sync_completed = spv_sync_completed; + client->sync_transaction = btc_wallet_check_transaction; + client->sync_transaction_ctx = wallet; + if (!btc_spv_client_load(client, (dbfile ? dbfile : "headers.db"))) { + printf("Could not load or create headers database...aborting\n"); + ret = EXIT_FAILURE; + } + else { + printf("Discover peers..."); + btc_spv_client_discover_peers(client, ips); + printf("done\n"); + printf("Connecting to the p2p network...\n"); + btc_spv_client_runloop(client); + btc_spv_client_free(client); + ret = EXIT_SUCCESS; + } + btc_ecc_stop(); + } + else { + printf("Invalid command (use -?)\n"); + ret = EXIT_FAILURE; + } + return ret; +} diff --git a/src/tools/bitcointool.c b/src/tools/bitcointool.c new file mode 100644 index 000000000..b79dd1281 --- /dev/null +++ b/src/tools/bitcointool.c @@ -0,0 +1,438 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Jonas Schnelli + + 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 "libbtc-config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +static struct option long_options[] = + { + {"privkey", required_argument, NULL, 'p'}, + {"pubkey", required_argument, NULL, 'k'}, + {"keypath", required_argument, NULL, 'm'}, + {"command", required_argument, NULL, 'c'}, + {"testnet", no_argument, NULL, 't'}, + {"regtest", no_argument, NULL, 'r'}, + {"version", no_argument, NULL, 'v'}, + {"txhex", no_argument, NULL, 'x'}, + {"scripthex", no_argument, NULL, 's'}, + {"inputindex", no_argument, NULL, 'i'}, + {"sighashtype", no_argument, NULL, 'h'}, + {"amount", no_argument, NULL, 'a'}, + {NULL, 0, NULL, 0}}; + +static void print_version() +{ + printf("Version: %s %s\n", PACKAGE_NAME, PACKAGE_VERSION); +} + +static void print_usage() +{ + print_version(); + printf("Usage: bitcointool (-m|-keypath ) (-k|-pubkey ) (-p|-privkey ) (-t[--testnet]) (-r[--regtest]) -c \n"); + printf("Available commands: pubfrompriv (requires -p WIF), addrfrompub (requires -k HEX), genkey, hdgenmaster, hdprintkey (requires -p), hdderive (requires -m and -p) \n"); + printf("\nExamples: \n"); + printf("Generate a testnet privatekey in WIF/HEX format:\n"); + printf("> bitcointool -c genkey --testnet\n\n"); + printf("> bitcointool -c pubfrompriv -p KzLzeMteBxy8aPPDCeroWdkYPctafGapqBAmWQwdvCkgKniH9zw6\n\n"); +} + +static bool showError(const char* er) +{ + printf("Error: %s\n", er); + btc_ecc_stop(); + return 1; +} + +int main(int argc, char* argv[]) +{ + int long_index = 0; + int opt = 0; + char* pkey = 0; + char* pubkey = 0; + char* cmd = 0; + char* keypath = 0; + char* txhex = 0; + char* scripthex = 0; + int inputindex = 0; + int sighashtype = 1; + uint64_t amount = 0; + const btc_chainparams* chain = &btc_chainparams_main; + + /* get arguments */ + while ((opt = getopt_long_only(argc, argv, "h:i:s:x:p:k:a:m:c:trv", long_options, &long_index)) != -1) { + switch (opt) { + case 'p': + pkey = optarg; + if (strlen(pkey) < 50) + return showError("Private key must be WIF encoded"); + break; + case 'c': + cmd = optarg; + break; + case 'm': + keypath = optarg; + break; + case 'k': + pubkey = optarg; + break; + case 't': + chain = &btc_chainparams_test; + break; + case 'r': + chain = &btc_chainparams_regtest; + break; + case 'v': + print_version(); + exit(EXIT_SUCCESS); + break; + case 'x': + txhex = optarg; + break; + case 's': + scripthex = optarg; + break; + case 'i': + inputindex = (int)strtol(optarg, (char**)NULL, 10); + break; + case 'h': + sighashtype = (int)strtol(optarg, (char**)NULL, 10); + break; + case 'a': + amount = (int)strtoll(optarg, (char**)NULL, 10); + break; + default: + print_usage(); + exit(EXIT_FAILURE); + } + } + + if (!cmd) { + /* exit if no command was provided */ + print_usage(); + exit(EXIT_FAILURE); + } + + /* start ECC context */ + btc_ecc_start(); + + const char *pkey_error = "Missing extended key (use -p)"; + + if (strcmp(cmd, "pubfrompriv") == 0) { + /* output compressed hex pubkey from hex privkey */ + + size_t sizeout = 128; + char pubkey_hex[sizeout]; + if (!pkey) + return showError(pkey_error); + if (!pubkey_from_privatekey(chain, pkey, pubkey_hex, &sizeout)) + return showError("Operation failed"); + + /* clean memory of private key */ + memset(pkey, 0, strlen(pkey)); + + /* give out hex pubkey */ + printf("pubkey: %s\n", pubkey_hex); + + /* give out p2pkh address */ + char address_p2pkh[sizeout]; + char address_p2sh_p2wpkh[sizeout]; + char address_p2wpkh[sizeout]; + addresses_from_pubkey(chain, pubkey_hex, address_p2pkh, address_p2sh_p2wpkh, address_p2wpkh); + printf("p2pkh address: %s\n", address_p2pkh); + printf("p2sh-p2wpkh address: %s\n", address_p2sh_p2wpkh); + + /* clean memory */ + memset(pubkey_hex, 0, strlen(pubkey_hex)); + memset(address_p2pkh, 0, strlen(address_p2pkh)); + memset(address_p2sh_p2wpkh, 0, strlen(address_p2sh_p2wpkh)); + } else if (strcmp(cmd, "addrfrompub") == 0 || strcmp(cmd, "p2pkhaddrfrompub") == 0) { + /* get p2pkh address from pubkey */ + + size_t sizeout = 128; + char address_p2pkh[sizeout]; + char address_p2sh_p2wpkh[sizeout]; + char address_p2wpkh[sizeout]; + if (!pubkey) + return showError("Missing public key (use -k)"); + if (!addresses_from_pubkey(chain, pubkey, address_p2pkh, address_p2sh_p2wpkh, address_p2wpkh)) + return showError("Operation failed, invalid pubkey"); + printf("p2pkh address: %s\n", address_p2pkh); + printf("p2sh-p2wpkh address: %s\n", address_p2sh_p2wpkh); + printf("p2wpkh (bc1 / bech32) address: %s\n", address_p2wpkh); + + memset(pubkey, 0, strlen(pubkey)); + memset(address_p2pkh, 0, strlen(address_p2pkh)); + memset(address_p2sh_p2wpkh, 0, strlen(address_p2sh_p2wpkh)); + } else if (strcmp(cmd, "genkey") == 0) { + size_t sizeout = 128; + char newprivkey_wif[sizeout]; + char newprivkey_hex[sizeout]; + + /* generate a new private key */ + gen_privatekey(chain, newprivkey_wif, sizeout, newprivkey_hex); + printf("privatekey WIF: %s\n", newprivkey_wif); + printf("privatekey HEX: %s\n", newprivkey_hex); + memset(newprivkey_wif, 0, strlen(newprivkey_wif)); + memset(newprivkey_hex, 0, strlen(newprivkey_hex)); + } else if (strcmp(cmd, "hdgenmaster") == 0) { + size_t sizeout = 128; + char masterkey[sizeout]; + + /* generate a new hd master key */ + hd_gen_master(chain, masterkey, sizeout); + printf("masterkey: %s\n", masterkey); + memset(masterkey, 0, strlen(masterkey)); + } else if (strcmp(cmd, "hdprintkey") == 0) { + if (!pkey) + return showError(pkey_error); + if (!hd_print_node(chain, pkey)) + return showError("Failed. Probably invalid extended key.\n"); + } else if (strcmp(cmd, "hdderive") == 0) { + if (!pkey) + return showError(pkey_error); + if (!keypath) + return showError("Missing keypath (use -m)"); + size_t sizeout = 128; + char newextkey[sizeout]; + + //check if we derive a range of keys + unsigned int maxlen = 1024; + int posanum = -1; + int posbnum = -1; + int end = -1; + uint64_t from; + uint64_t to; + + static char digits[] = "0123456789"; + for (unsigned int i = 0; i maxlen) { + break; + } + if (posanum > -1 && posbnum == -1) { + if (keypath[i] == '-') { + if (i-posanum >= 9) { + break; + } + posbnum = i+1; + char buf[9] = {0}; + memcpy (buf, &keypath[posanum], i-posanum); + from = strtoull(buf, NULL, 10); + } + else if (!strchr(digits, keypath[i])) { + posanum = -1; + break; + } + } + else if (posanum > -1 && posbnum > -1) { + if (keypath[i] == ']' || keypath[i] == ')') { + if (i-posbnum >= 9) { + break; + } + char buf[9] = {0}; + memcpy (buf, &keypath[posbnum], i-posbnum); + to = strtoull(buf, NULL, 10); + end = i+1; + break; + } + else if (!strchr(digits, keypath[i])) { + posbnum = -1; + posanum = -1; + break; + } + } + if (keypath[i] == '[' || keypath[i] == '(') { + posanum = i+1; + } + } + + if (end > -1 && from <= to) { + for (uint64_t i = from; i <= to; i++) { + char keypathnew[strlen(keypath)+16]; + memcpy(keypathnew, keypath, posanum-1); + char index[9] = {0}; + sprintf(index, "%lld", i); + memcpy(keypathnew+posanum-1, index, strlen(index)); + memcpy(keypathnew+posanum-1+strlen(index), &keypath[end], strlen(keypath)-end); + + + if (!hd_derive(chain, pkey, keypathnew, newextkey, sizeout)) + return showError("Deriving child key failed\n"); + else + hd_print_node(chain, newextkey); + } + } + else { + if (!hd_derive(chain, pkey, keypath, newextkey, sizeout)) + return showError("Deriving child key failed\n"); + else + hd_print_node(chain, newextkey); + } + } else if (strcmp(cmd, "sign") == 0) { + if(!txhex || !scripthex) { + return showError("Missing tx-hex or script-hex (use -x, -s)\n"); + } + + if (strlen(txhex) > 1024*100) { //don't accept tx larger then 100kb + return showError("tx too large (max 100kb)\n"); + } + + //deserialize transaction + btc_tx* tx = btc_tx_new(); + uint8_t* data_bin = btc_malloc(strlen(txhex) / 2 + 1); + int outlen = 0; + utils_hex_to_bin(txhex, data_bin, strlen(txhex), &outlen); + if (!btc_tx_deserialize(data_bin, outlen, tx, NULL, true)) { + free(data_bin); + btc_tx_free(tx); + return showError("Invalid tx hex"); + } + free(data_bin); + + if ((size_t)inputindex >= tx->vin->len) { + btc_tx_free(tx); + return showError("Inputindex out of range"); + } + + btc_tx_in *tx_in = vector_idx(tx->vin, inputindex); + + uint8_t script_data[strlen(scripthex) / 2 + 1]; + utils_hex_to_bin(scripthex, script_data, strlen(scripthex), &outlen); + cstring* script = cstr_new_buf(script_data, outlen); + + uint256 sighash; + memset(sighash, 0, sizeof(sighash)); + btc_tx_sighash(tx, script, inputindex, sighashtype, 0, SIGVERSION_BASE, sighash); + + char *hex = utils_uint8_to_hex(sighash, 32); + utils_reverse_hex(hex, 64); + + enum btc_tx_out_type type = btc_script_classify(script, NULL); + printf("script: %s\n", scripthex); + printf("script-type: %s\n", btc_tx_out_type_to_str(type)); + printf("inputindex: %d\n", inputindex); + printf("sighashtype: %d\n", sighashtype); + printf("hash: %s\n", hex); + + // sign + btc_bool sign = false; + btc_key key; + btc_privkey_init(&key); + if (btc_privkey_decode_wif(pkey, chain, &key)) { + sign = true; + } + else { + if (strlen(pkey) > 50) { + btc_tx_free(tx); + cstr_free(script, true); + return showError("Invalid wif privkey\n"); + } + printf("No private key provided, signing will not happen\n"); + } + if (sign) { + uint8_t sigcompact[64] = {0}; + int sigderlen = 74+1; //&hashtype + uint8_t sigder_plus_hashtype[75] = {0}; + enum btc_tx_sign_result res = btc_tx_sign_input(tx, script, amount, &key, inputindex, sighashtype, sigcompact, sigder_plus_hashtype, &sigderlen); + cstr_free(script, true); + + if (res != BTC_SIGN_OK) { + printf("!!!Sign error:%s\n", btc_tx_sign_result_to_str(res)); + } + + char sigcompacthex[64*2+1] = {0}; + utils_bin_to_hex((unsigned char *)sigcompact, 64, sigcompacthex); + + char sigderhex[74*2+2+1]; //74 der, 2 hashtype, 1 nullbyte + memset(sigderhex, 0, sizeof(sigderhex)); + utils_bin_to_hex((unsigned char *)sigder_plus_hashtype, sigderlen, sigderhex); + + printf("\nSignature created:\n"); + printf("signature compact: %s\n", sigcompacthex); + printf("signature DER (+hashtype): %s\n", sigderhex); + + cstring* signed_tx = cstr_new_sz(1024); + btc_tx_serialize(signed_tx, tx, true); + + char signed_tx_hex[signed_tx->len*2+1]; + utils_bin_to_hex((unsigned char *)signed_tx->str, signed_tx->len, signed_tx_hex); + printf("signed TX: %s\n", signed_tx_hex); + cstr_free(signed_tx, true); + } + btc_tx_free(tx); + } + else if (strcmp(cmd, "comp2der") == 0) { + if(!scripthex || strlen(scripthex) != 128) { + return showError("Missing signature or invalid length (use hex, 128 chars == 64 bytes)\n"); + } + + int outlen = 0; + uint8_t sig_comp[strlen(scripthex) / 2 + 1]; + printf("%s\n", scripthex); + utils_hex_to_bin(scripthex, sig_comp, strlen(scripthex), &outlen); + + unsigned char sigder[74]; + size_t sigderlen = 74; + + btc_ecc_compact_to_der_normalized(sig_comp, sigder, &sigderlen); + char hexbuf[sigderlen*2 + 1]; + utils_bin_to_hex(sigder, sigderlen, hexbuf); + printf("DER: %s\n", hexbuf); + } + else if (strcmp(cmd, "bip32maintotest") == 0) { + btc_hdnode node; + if (!btc_hdnode_deserialize(pkey, chain, &node)) + return false; + + char masterkeyhex[200]; + int strsize = 200; + btc_hdnode_serialize_private(&node, &btc_chainparams_test, masterkeyhex, strsize); + printf("%s\n", masterkeyhex); + + //022d0e577424abfbbb5e321d3e2c700122a0c004305f57725810988cee6c4c278d + } + + + btc_ecc_stop(); + + return 0; +} diff --git a/src/tx.c b/src/tx.c new file mode 100644 index 000000000..41a15d1cd --- /dev/null +++ b/src/tx.c @@ -0,0 +1,916 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Jonas Schnelli + + 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 + +#include +#include +#include +#include +#include +#include +#include + +void btc_tx_in_free(btc_tx_in* tx_in) +{ + if (!tx_in) + return; + + memset(&tx_in->prevout.hash, 0, sizeof(tx_in->prevout.hash)); + tx_in->prevout.n = 0; + + if (tx_in->script_sig) { + cstr_free(tx_in->script_sig, true); + tx_in->script_sig = NULL; + } + + if (tx_in->witness_stack) { + vector_free(tx_in->witness_stack, true); + tx_in->witness_stack = NULL; + } + + memset(tx_in, 0, sizeof(*tx_in)); + btc_free(tx_in); +} + +//callback for vector free function +void btc_tx_in_free_cb(void* data) +{ + if (!data) + return; + + btc_tx_in* tx_in = data; + btc_tx_in_free(tx_in); +} + +void btc_tx_in_witness_stack_free_cb(void* data) +{ + if (!data) + return; + + cstring* stack_item = data; + cstr_free(stack_item, true); +} + +btc_tx_in* btc_tx_in_new() +{ + btc_tx_in* tx_in; + tx_in = btc_calloc(1, sizeof(*tx_in)); + memset(&tx_in->prevout, 0, sizeof(tx_in->prevout)); + tx_in->sequence = UINT32_MAX; + + tx_in->witness_stack = vector_new(8, btc_tx_in_witness_stack_free_cb); + return tx_in; +} + + +void btc_tx_out_free(btc_tx_out* tx_out) +{ + if (!tx_out) + return; + tx_out->value = 0; + + if (tx_out->script_pubkey) { + cstr_free(tx_out->script_pubkey, true); + tx_out->script_pubkey = NULL; + } + + memset(tx_out, 0, sizeof(*tx_out)); + btc_free(tx_out); +} + + +void btc_tx_out_free_cb(void* data) +{ + if (!data) + return; + + btc_tx_out* tx_out = data; + btc_tx_out_free(tx_out); +} + + +btc_tx_out* btc_tx_out_new() +{ + btc_tx_out* tx_out; + tx_out = btc_calloc(1, sizeof(*tx_out)); + + return tx_out; +} + + +void btc_tx_free(btc_tx* tx) +{ + if (tx->vin) + vector_free(tx->vin, true); + + if (tx->vout) + vector_free(tx->vout, true); + + btc_free(tx); +} + + +btc_tx* btc_tx_new() +{ + btc_tx* tx; + tx = btc_calloc(1, sizeof(*tx)); + tx->vin = vector_new(8, btc_tx_in_free_cb); + tx->vout = vector_new(8, btc_tx_out_free_cb); + tx->version = 1; + tx->locktime = 0; + return tx; +} + + +btc_bool btc_tx_in_deserialize(btc_tx_in* tx_in, struct const_buffer* buf) +{ + deser_u256(tx_in->prevout.hash, buf); + if (!deser_u32(&tx_in->prevout.n, buf)) + return false; + if (!deser_varstr(&tx_in->script_sig, buf)) + return false; + if (!deser_u32(&tx_in->sequence, buf)) + return false; + return true; +} + +btc_bool btc_tx_out_deserialize(btc_tx_out* tx_out, struct const_buffer* buf) +{ + if (!deser_s64(&tx_out->value, buf)) + return false; + if (!deser_varstr(&tx_out->script_pubkey, buf)) + return false; + return true; +} + +int btc_tx_deserialize(const unsigned char* tx_serialized, size_t inlen, btc_tx* tx, size_t* consumed_length, btc_bool allow_witness) +{ + struct const_buffer buf = {tx_serialized, inlen}; + if (consumed_length) + *consumed_length = 0; + + //tx needs to be initialized + deser_s32(&tx->version, &buf); + + uint32_t vlen; + if (!deser_varlen(&vlen, &buf)) + return false; + + uint8_t flags = 0; + if (vlen == 0 && allow_witness) { + /* We read a dummy or an empty vin. */ + deser_bytes(&flags, &buf, 1); + if (flags != 0) { + // contains witness, deser the vin len + if (!deser_varlen(&vlen, &buf)) + return false; + } + } + + unsigned int i; + for (i = 0; i < vlen; i++) { + btc_tx_in* tx_in = btc_tx_in_new(); + + if (!btc_tx_in_deserialize(tx_in, &buf)) { + btc_tx_in_free(tx_in); + return false; + } else { + vector_add(tx->vin, tx_in); + } + } + + if (!deser_varlen(&vlen, &buf)) + return false; + for (i = 0; i < vlen; i++) { + btc_tx_out* tx_out = btc_tx_out_new(); + + if (!btc_tx_out_deserialize(tx_out, &buf)) { + btc_free(tx_out); + return false; + } else { + vector_add(tx->vout, tx_out); + } + } + + if ((flags & 1) && allow_witness) { + /* The witness flag is present, and we support witnesses. */ + flags ^= 1; + for (size_t i = 0; i < tx->vin->len; i++) { + btc_tx_in *tx_in = vector_idx(tx->vin, i); + uint32_t vlen; + if (!deser_varlen(&vlen, &buf)) return false; + for (size_t j = 0; j < vlen; j++) { + cstring* witness_item = cstr_new_sz(1024); + if (!deser_varstr(&witness_item, &buf)) { + cstr_free(witness_item, true); + return false; + } + vector_add(tx_in->witness_stack, witness_item); //vector is responsible for freeing the items memory + } + } + } + if (flags) { + /* Unknown flag in the serialization */ + return false; + } + + if (!deser_u32(&tx->locktime, &buf)) + return false; + + if (consumed_length) + *consumed_length = inlen - buf.len; + return true; +} + +void btc_tx_in_serialize(cstring* s, const btc_tx_in* tx_in) +{ + ser_u256(s, tx_in->prevout.hash); + ser_u32(s, tx_in->prevout.n); + ser_varstr(s, tx_in->script_sig); + ser_u32(s, tx_in->sequence); +} + +void btc_tx_out_serialize(cstring* s, const btc_tx_out* tx_out) +{ + ser_s64(s, tx_out->value); + ser_varstr(s, tx_out->script_pubkey); +} + +btc_bool btc_tx_has_witness(const btc_tx *tx) +{ + for (size_t i = 0; i < tx->vin->len; i++) { + btc_tx_in *tx_in = vector_idx(tx->vin, i); + if (tx_in->witness_stack != NULL && tx_in->witness_stack->len > 0) { + return true; + } + } + return false; +} + +void btc_tx_serialize(cstring* s, const btc_tx* tx, btc_bool allow_witness) +{ + ser_s32(s, tx->version); + uint8_t flags = 0; + // Consistency check + if (allow_witness) { + /* Check whether witnesses need to be serialized. */ + if (btc_tx_has_witness(tx)) { + flags |= 1; + } + } + if (flags) { + /* Use extended format in case witnesses are to be serialized. */ + uint8_t dummy = 0; + ser_bytes(s, &dummy, 1); + ser_bytes(s, &flags, 1); + } + + ser_varlen(s, tx->vin ? tx->vin->len : 0); + + unsigned int i; + if (tx->vin) { + for (i = 0; i < tx->vin->len; i++) { + btc_tx_in* tx_in; + + tx_in = vector_idx(tx->vin, i); + btc_tx_in_serialize(s, tx_in); + } + } + + ser_varlen(s, tx->vout ? tx->vout->len : 0); + + if (tx->vout) { + for (i = 0; i < tx->vout->len; i++) { + btc_tx_out* tx_out; + + tx_out = vector_idx(tx->vout, i); + btc_tx_out_serialize(s, tx_out); + } + } + + if (flags & 1) { + // serialize the witness stack + if (tx->vin) { + for (i = 0; i < tx->vin->len; i++) { + btc_tx_in* tx_in; + tx_in = vector_idx(tx->vin, i); + if (tx_in->witness_stack) { + ser_varlen(s, tx_in->witness_stack->len); + for (unsigned int j = 0; j < tx_in->witness_stack->len; j++) { + cstring *item = vector_idx(tx_in->witness_stack, j); + ser_varstr(s, item); + } + } + } + } + } + + ser_u32(s, tx->locktime); +} + +void btc_tx_hash(const btc_tx* tx, uint256 hashout) +{ + cstring* txser = cstr_new_sz(1024); + btc_tx_serialize(txser, tx, false); + + + sha256_Raw((const uint8_t*)txser->str, txser->len, hashout); + sha256_Raw(hashout, BTC_HASH_LENGTH, hashout); + cstr_free(txser, true); +} + + +void btc_tx_in_copy(btc_tx_in* dest, const btc_tx_in* src) +{ + memcpy(&dest->prevout, &src->prevout, sizeof(dest->prevout)); + dest->sequence = src->sequence; + + if (!src->script_sig) + dest->script_sig = NULL; + else { + dest->script_sig = cstr_new_sz(src->script_sig->len); + cstr_append_buf(dest->script_sig, + src->script_sig->str, + src->script_sig->len); + } + + if (!src->witness_stack) + dest->witness_stack = NULL; + else { + dest->witness_stack = vector_new(src->witness_stack->len, btc_tx_in_witness_stack_free_cb); + for (unsigned int i = 0; i < src->witness_stack->len; i++) { + cstring *witness_item = vector_idx(src->witness_stack, i); + cstring *item_cpy = cstr_new_cstr(witness_item); + vector_add(dest->witness_stack, item_cpy); + } + } +} + + +void btc_tx_out_copy(btc_tx_out* dest, const btc_tx_out* src) +{ + dest->value = src->value; + + if (!src->script_pubkey) + dest->script_pubkey = NULL; + else { + dest->script_pubkey = cstr_new_sz(src->script_pubkey->len); + cstr_append_buf(dest->script_pubkey, + src->script_pubkey->str, + src->script_pubkey->len); + } +} + + +void btc_tx_copy(btc_tx* dest, const btc_tx* src) +{ + dest->version = src->version; + dest->locktime = src->locktime; + + if (!src->vin) + dest->vin = NULL; + else { + unsigned int i; + + if (dest->vin) + vector_free(dest->vin, true); + + dest->vin = vector_new(src->vin->len, btc_tx_in_free_cb); + + for (i = 0; i < src->vin->len; i++) { + btc_tx_in *tx_in_old, *tx_in_new; + + tx_in_old = vector_idx(src->vin, i); + tx_in_new = btc_malloc(sizeof(*tx_in_new)); + btc_tx_in_copy(tx_in_new, tx_in_old); + vector_add(dest->vin, tx_in_new); + } + } + + if (!src->vout) + dest->vout = NULL; + else { + unsigned int i; + + if (dest->vout) + vector_free(dest->vout, true); + + dest->vout = vector_new(src->vout->len, + btc_tx_out_free_cb); + + for (i = 0; i < src->vout->len; i++) { + btc_tx_out *tx_out_old, *tx_out_new; + + tx_out_old = vector_idx(src->vout, i); + tx_out_new = btc_malloc(sizeof(*tx_out_new)); + btc_tx_out_copy(tx_out_new, tx_out_old); + vector_add(dest->vout, tx_out_new); + } + } +} + +void btc_tx_prevout_hash(const btc_tx* tx, uint256 hash) { + cstring* s = cstr_new_sz(512); + unsigned int i; + btc_tx_in* tx_in; + for (i = 0; i < tx->vin->len; i++) { + tx_in = vector_idx(tx->vin, i); + ser_u256(s, tx_in->prevout.hash); + ser_u32(s, tx_in->prevout.n); + } + + btc_hash((const uint8_t*)s->str, s->len, hash); + cstr_free(s, true); +} + + +void btc_tx_sequence_hash(const btc_tx* tx, uint256 hash) { + cstring* s = cstr_new_sz(512); + unsigned int i; + btc_tx_in* tx_in; + for (i = 0; i < tx->vin->len; i++) { + tx_in = vector_idx(tx->vin, i); + ser_u32(s, tx_in->sequence); + } + + btc_hash((const uint8_t*)s->str, s->len, hash); + cstr_free(s, true); +} + +void btc_tx_outputs_hash(const btc_tx* tx, uint256 hash) { + cstring* s = cstr_new_sz(512); + unsigned int i; + btc_tx_out* tx_out; + for (i = 0; i < tx->vout->len; i++) { + tx_out = vector_idx(tx->vout, i); + btc_tx_out_serialize(s, tx_out); + } + + btc_hash((const uint8_t*)s->str, s->len, hash); + cstr_free(s, true); +} + +btc_bool btc_tx_sighash(const btc_tx* tx_to, const cstring* fromPubKey, unsigned int in_num, int hashtype, const uint64_t amount, const enum btc_sig_version sigversion, uint256 hash) +{ + if (in_num >= tx_to->vin->len) + return false; + + btc_bool ret = true; + + btc_tx* tx_tmp = btc_tx_new(); + btc_tx_copy(tx_tmp, tx_to); + + cstring* s = NULL; + + // segwit + if (sigversion == SIGVERSION_WITNESS_V0) { + uint256 hash_prevouts; + btc_hash_clear(hash_prevouts); + uint256 hash_sequence; + btc_hash_clear(hash_sequence); + uint256 hash_outputs; + btc_hash_clear(hash_outputs); + + if (!(hashtype & SIGHASH_ANYONECANPAY)) { + btc_tx_prevout_hash(tx_tmp, hash_prevouts); + } + if (!(hashtype & SIGHASH_ANYONECANPAY)) { + btc_tx_outputs_hash(tx_tmp, hash_outputs); + } + if (!(hashtype & SIGHASH_ANYONECANPAY) && (hashtype & 0x1f) != SIGHASH_SINGLE && (hashtype & 0x1f) != SIGHASH_NONE) { + btc_tx_sequence_hash(tx_tmp, hash_sequence); + } + + if ((hashtype & 0x1f) != SIGHASH_SINGLE && (hashtype & 0x1f) != SIGHASH_NONE) { + btc_tx_outputs_hash(tx_tmp, hash_outputs); + } else if ((hashtype & 0x1f) == SIGHASH_SINGLE && in_num < tx_tmp->vout->len) { + cstring* s1 = cstr_new_sz(512); + btc_tx_out* tx_out = vector_idx(tx_tmp->vout, in_num); + btc_tx_out_serialize(s1, tx_out); + btc_hash((const uint8_t*)s1->str, s1->len, hash); + cstr_free(s1, true); + } + + s = cstr_new_sz(512); + ser_u32(s, tx_tmp->version); // Version + + // Input prevouts/nSequence (none/all, depending on flags) + ser_u256(s, hash_prevouts); + ser_u256(s, hash_sequence); + + // The input being signed (replacing the scriptSig with scriptCode + amount) + // The prevout may already be contained in hashPrevout, and the nSequence + // may already be contain in hashSequence. + btc_tx_in* tx_in = vector_idx(tx_tmp->vin, in_num); + ser_u256(s, tx_in->prevout.hash); + ser_u32(s, tx_in->prevout.n); + + ser_varstr(s, (cstring *)fromPubKey); // script code + + ser_u64(s, amount); + ser_u32(s, tx_in->sequence); + ser_u256(s, hash_outputs); // Outputs (none/one/all, depending on flags) + ser_u32(s, tx_tmp->locktime); // Locktime + ser_s32(s, hashtype); // Sighash type + } + else { + // standard (non witness) sighash (SIGVERSION_BASE) + cstring* new_script = cstr_new_sz(fromPubKey->len); + btc_script_copy_without_op_codeseperator(fromPubKey, new_script); + + unsigned int i; + btc_tx_in* tx_in; + for (i = 0; i < tx_tmp->vin->len; i++) { + tx_in = vector_idx(tx_tmp->vin, i); + cstr_resize(tx_in->script_sig, 0); + + if (i == in_num) + cstr_append_buf(tx_in->script_sig, + new_script->str, + new_script->len); + } + cstr_free(new_script, true); + /* Blank out some of the outputs */ + if ((hashtype & 0x1f) == SIGHASH_NONE) { + /* Wildcard payee */ + if (tx_tmp->vout) + vector_free(tx_tmp->vout, true); + + tx_tmp->vout = vector_new(1, btc_tx_out_free_cb); + + /* Let the others update at will */ + for (i = 0; i < tx_tmp->vin->len; i++) { + tx_in = vector_idx(tx_tmp->vin, i); + if (i != in_num) + tx_in->sequence = 0; + } + } + + else if ((hashtype & 0x1f) == SIGHASH_SINGLE) { + /* Only lock-in the txout payee at same index as txin */ + unsigned int n_out = in_num; + if (n_out >= tx_tmp->vout->len) { + //TODO: set error code + ret = false; + goto out; + } + + vector_resize(tx_tmp->vout, n_out + 1); + + for (i = 0; i < n_out; i++) { + btc_tx_out* tx_out; + + tx_out = vector_idx(tx_tmp->vout, i); + tx_out->value = -1; + if (tx_out->script_pubkey) { + cstr_free(tx_out->script_pubkey, true); + tx_out->script_pubkey = NULL; + } + } + + /* Let the others update at will */ + for (i = 0; i < tx_tmp->vin->len; i++) { + tx_in = vector_idx(tx_tmp->vin, i); + if (i != in_num) + tx_in->sequence = 0; + } + } + + /* Blank out other inputs completely; + not recommended for open transactions */ + if (hashtype & SIGHASH_ANYONECANPAY) { + if (in_num > 0) + vector_remove_range(tx_tmp->vin, 0, in_num); + vector_resize(tx_tmp->vin, 1); + } + + s = cstr_new_sz(512); + btc_tx_serialize(s, tx_tmp, false); + ser_s32(s, hashtype); + } + + //char str[10000]; + //memset(str, strlen(str), 0); + //utils_bin_to_hex((unsigned char *)s->str, s->len, str); + //printf("\n"); + //printf("%s\n", str); + + sha256_Raw((const uint8_t*)s->str, s->len, hash); + sha256_Raw(hash, BTC_HASH_LENGTH, hash); + + cstr_free(s, true); + +out: + btc_tx_free(tx_tmp); + + return ret; +} + +btc_bool btc_tx_add_data_out(btc_tx* tx, const int64_t amount, const uint8_t *data, const size_t datalen) +{ + if (datalen > 80) + return false; + + btc_tx_out* tx_out = btc_tx_out_new(); + + tx_out->script_pubkey = cstr_new_sz(1024); + btc_script_append_op(tx_out->script_pubkey , OP_RETURN); + btc_script_append_pushdata(tx_out->script_pubkey, (unsigned char*)data, datalen); + + tx_out->value = amount; + + vector_add(tx->vout, tx_out); + + return true; +} + +btc_bool btc_tx_add_puzzle_out(btc_tx* tx, const int64_t amount, const uint8_t *puzzle, const size_t puzzlelen) +{ + if (puzzlelen > BTC_HASH_LENGTH) + return false; + + btc_tx_out* tx_out = btc_tx_out_new(); + + tx_out->script_pubkey = cstr_new_sz(1024); + btc_script_append_op(tx_out->script_pubkey , OP_HASH256); + btc_script_append_pushdata(tx_out->script_pubkey, (unsigned char*)puzzle, puzzlelen); + btc_script_append_op(tx_out->script_pubkey , OP_EQUAL); + tx_out->value = amount; + + vector_add(tx->vout, tx_out); + + return true; +} + +btc_bool btc_tx_add_address_out(btc_tx* tx, const btc_chainparams* chain, int64_t amount, const char* address) +{ + uint8_t buf[strlen(address) * 2]; + int r = btc_base58_decode_check(address, buf, sizeof(buf)); + if (r > 0 && buf[0] == chain->b58prefix_pubkey_address) { + btc_tx_add_p2pkh_hash160_out(tx, amount, &buf[1]); + } else if (r > 0 && buf[0] == chain->b58prefix_script_address) { + btc_tx_add_p2sh_hash160_out(tx, amount, &buf[1]); + } + else { + // check for bech32 + int version = 0; + unsigned char programm[40] = {0}; + size_t programmlen = 0; + if(segwit_addr_decode(&version, programm, &programmlen, chain->bech32_hrp, address) == 1) { + if (programmlen == 20) { + btc_tx_out* tx_out = btc_tx_out_new(); + tx_out->script_pubkey = cstr_new_sz(1024); + + btc_script_build_p2wpkh(tx_out->script_pubkey, (const uint8_t *)programm); + + tx_out->value = amount; + vector_add(tx->vout, tx_out); + } + } + return false; + } + + return true; +} + + +btc_bool btc_tx_add_p2pkh_hash160_out(btc_tx* tx, int64_t amount, uint160 hash160) +{ + btc_tx_out* tx_out = btc_tx_out_new(); + + tx_out->script_pubkey = cstr_new_sz(1024); + btc_script_build_p2pkh(tx_out->script_pubkey, hash160); + + tx_out->value = amount; + + vector_add(tx->vout, tx_out); + + return true; +} + +btc_bool btc_tx_add_p2sh_hash160_out(btc_tx* tx, int64_t amount, uint160 hash160) +{ + btc_tx_out* tx_out = btc_tx_out_new(); + + tx_out->script_pubkey = cstr_new_sz(1024); + btc_script_build_p2sh(tx_out->script_pubkey, hash160); + + tx_out->value = amount; + + vector_add(tx->vout, tx_out); + + return true; +} + +btc_bool btc_tx_add_p2pkh_out(btc_tx* tx, int64_t amount, const btc_pubkey* pubkey) +{ + uint160 hash160; + btc_pubkey_get_hash160(pubkey, hash160); + return btc_tx_add_p2pkh_hash160_out(tx, amount, hash160); +} + +btc_bool btc_tx_outpoint_is_null(btc_tx_outpoint* tx) +{ + (void)(tx); + return true; +} + +btc_bool btc_tx_is_coinbase(btc_tx* tx) +{ + if (tx->vin->len == 1) { + btc_tx_in* vin = vector_idx(tx->vin, 0); + + if (btc_hash_is_empty(vin->prevout.hash) && vin->prevout.n == UINT32_MAX) + return true; + } + return false; +} + +const char* btc_tx_sign_result_to_str(const enum btc_tx_sign_result result) { + if (result == BTC_SIGN_OK) { + return "OK"; + } + else if (result == BTC_SIGN_INVALID_TX_OR_SCRIPT) { + return "INVALID_TX_OR_SCRIPT"; + } + else if (result == BTC_SIGN_INPUTINDEX_OUT_OF_RANGE) { + return "INPUTINDEX_OUT_OF_RANGE"; + } + else if (result == BTC_SIGN_INVALID_KEY) { + return "INVALID_KEY"; + } + else if (result == BTC_SIGN_NO_KEY_MATCH) { + return "NO_KEY_MATCH"; + } + else if (result == BTC_SIGN_UNKNOWN_SCRIPT_TYPE) { + return "SIGN_UNKNOWN_SCRIPT_TYPE"; + } + else if (result == BTC_SIGN_SIGHASH_FAILED) { + return "SIGHASH_FAILED"; + } + return "UNKOWN"; +} + +enum btc_tx_sign_result btc_tx_sign_input(btc_tx *tx_in_out, const cstring *script, uint64_t amount, const btc_key *privkey, int inputindex, int sighashtype, uint8_t *sigcompact_out, uint8_t *sigder_out, int *sigder_len_out) { + if (!tx_in_out || !script) { + return BTC_SIGN_INVALID_TX_OR_SCRIPT; + } + if ((size_t)inputindex >= tx_in_out->vin->len) { + return BTC_SIGN_INPUTINDEX_OUT_OF_RANGE; + } + if (!btc_privkey_is_valid(privkey)) { + return BTC_SIGN_INVALID_KEY; + } + // calculate pubkey + btc_pubkey pubkey; + btc_pubkey_init(&pubkey); + btc_pubkey_from_key(privkey, &pubkey); + if (!btc_pubkey_is_valid(&pubkey)) { + return BTC_SIGN_INVALID_KEY; + } + enum btc_tx_sign_result res = BTC_SIGN_OK; + + cstring *script_sign = cstr_new_cstr(script); //copy the script because we may modify it + btc_tx_in *tx_in = vector_idx(tx_in_out->vin, inputindex); + vector *script_pushes = vector_new(1, free); + + cstring *witness_set_scriptsig = NULL; //required in order to set the P2SH-P2WPKH scriptSig + enum btc_tx_out_type type = btc_script_classify(script, script_pushes); + enum btc_sig_version sig_version = SIGVERSION_BASE; + if (type == BTC_TX_SCRIPTHASH) { + // p2sh script, need the redeem script + // for now, pretend to be a p2sh-p2wpkh + type = BTC_TX_WITNESS_V0_PUBKEYHASH; + uint8_t *hash160 = btc_calloc(1, 20); + btc_pubkey_get_hash160(&pubkey, hash160); + vector_add(script_pushes, hash160); + + // set the script sig + witness_set_scriptsig = cstr_new_sz(22); + uint8_t version = 0; + ser_varlen(witness_set_scriptsig, 22); + ser_bytes(witness_set_scriptsig, &version, 1); + ser_varlen(witness_set_scriptsig, 20); + ser_bytes(witness_set_scriptsig, hash160, 20); + } + if (type == BTC_TX_PUBKEYHASH && script_pushes->len == 1) { + // check if given private key matches the script + uint160 hash160; + btc_pubkey_get_hash160(&pubkey, hash160); + uint160 *hash160_in_script = vector_idx(script_pushes, 0); + if (memcmp(hash160_in_script, hash160, sizeof(hash160)) != 0) { + res = BTC_SIGN_NO_KEY_MATCH; //sign anyways + } + } + else if (type == BTC_TX_WITNESS_V0_PUBKEYHASH && script_pushes->len == 1) { + uint160 *hash160_in_script = vector_idx(script_pushes, 0); + sig_version = SIGVERSION_WITNESS_V0; + + // check if given private key matches the script + uint160 hash160; + btc_pubkey_get_hash160(&pubkey, hash160); + if (memcmp(hash160_in_script, hash160, sizeof(hash160)) != 0) { + res = BTC_SIGN_NO_KEY_MATCH; //sign anyways + } + + cstr_resize(script_sign, 0); + btc_script_build_p2pkh(script_sign, *hash160_in_script); + } + else { + // unknown script, however, still try to create a signature (don't apply though) + res = BTC_SIGN_UNKNOWN_SCRIPT_TYPE; + } + vector_free(script_pushes, true); + + uint256 sighash; + memset(sighash, 0, sizeof(sighash)); + if(!btc_tx_sighash(tx_in_out, script_sign, inputindex, sighashtype, amount, sig_version, sighash)) { + cstr_free(witness_set_scriptsig, true); + cstr_free(script_sign, true); + return BTC_SIGN_SIGHASH_FAILED; + } + cstr_free(script_sign, true); + // sign compact + uint8_t sig[64]; + size_t siglen = 0; + btc_key_sign_hash_compact(privkey, sighash, sig, &siglen); + assert(siglen == sizeof(sig)); + if (sigcompact_out) { + memcpy(sigcompact_out, sig, siglen); + } + + // form normalized DER signature & hashtype + unsigned char sigder_plus_hashtype[74+1]; + size_t sigderlen = 75; + btc_ecc_compact_to_der_normalized(sig, sigder_plus_hashtype, &sigderlen); + assert(sigderlen <= 74 && sigderlen >= 70); + sigder_plus_hashtype[sigderlen] = sighashtype; + sigderlen+=1; //+hashtype + if (sigcompact_out) { + memcpy(sigder_out, sigder_plus_hashtype, sigderlen); + } + if (sigder_len_out) { + *sigder_len_out = sigderlen; + } + + // apply signature depending on script type + if (type == BTC_TX_PUBKEYHASH) { + // apply DER sig + ser_varlen(tx_in->script_sig, sigderlen); + ser_bytes(tx_in->script_sig, sigder_plus_hashtype, sigderlen); + + // apply pubkey + ser_varlen(tx_in->script_sig, pubkey.compressed ? BTC_ECKEY_COMPRESSED_LENGTH : BTC_ECKEY_UNCOMPRESSED_LENGTH); + ser_bytes(tx_in->script_sig, pubkey.pubkey, pubkey.compressed ? BTC_ECKEY_COMPRESSED_LENGTH : BTC_ECKEY_UNCOMPRESSED_LENGTH); + } + else if (type == BTC_TX_WITNESS_V0_PUBKEYHASH) { + // signal witness by emtpying script sig (may be already empty) + cstr_resize(tx_in->script_sig, 0); + if (witness_set_scriptsig) { + // apend the script sig in case of P2SH-P2WPKH + cstr_append_cstr(tx_in->script_sig, witness_set_scriptsig); + cstr_free(witness_set_scriptsig, true); + } + + // fill witness stack (DER sig, pubkey) + cstring* witness_item = cstr_new_buf(sigder_plus_hashtype, sigderlen); + vector_add(tx_in->witness_stack, witness_item); + + witness_item = cstr_new_buf(pubkey.pubkey, pubkey.compressed ? BTC_ECKEY_COMPRESSED_LENGTH : BTC_ECKEY_UNCOMPRESSED_LENGTH); + vector_add(tx_in->witness_stack, witness_item); + } + else { + // append nothing + res = BTC_SIGN_UNKNOWN_SCRIPT_TYPE; + } + + return res; +} diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 000000000..5f05cc86c --- /dev/null +++ b/src/utils.c @@ -0,0 +1,302 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Douglas J. Bakkum + Copyright (c) 2015 Jonas Schnelli + + 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 +#include +#include + +#include + +#ifdef WIN32 + +#ifdef _MSC_VER +#pragma warning(disable:4786) +#pragma warning(disable:4804) +#pragma warning(disable:4805) +#pragma warning(disable:4717) +#endif + +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif +#define _WIN32_WINNT 0x0501 + +#ifdef _WIN32_IE +#undef _WIN32_IE +#endif +#define _WIN32_IE 0x0501 + +#define WIN32_LEAN_AND_MEAN 1 +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include /* for _commit */ +#include + +#endif + +static uint8_t buffer_hex_to_uint8[TO_UINT8_HEX_BUF_LEN]; +static char buffer_uint8_to_hex[TO_UINT8_HEX_BUF_LEN]; + + +void utils_clear_buffers(void) +{ + memset(buffer_hex_to_uint8, 0, TO_UINT8_HEX_BUF_LEN); + memset(buffer_uint8_to_hex, 0, TO_UINT8_HEX_BUF_LEN); +} + +void utils_hex_to_bin(const char* str, unsigned char* out, int inLen, int* outLen) +{ + int bLen = inLen / 2; + uint8_t c; + int i; + memset(out, 0, bLen); + for (i = 0; i < bLen; i++) { + c = 0; + if (str[i * 2] >= '0' && str[i * 2] <= '9') { + *out = (str[i * 2] - '0') << 4; + } + if (str[i * 2] >= 'a' && str[i * 2] <= 'f') { + *out = (10 + str[i * 2] - 'a') << 4; + } + if (str[i * 2] >= 'A' && str[i * 2] <= 'F') { + *out = (10 + str[i * 2] - 'A') << 4; + } + if (str[i * 2 + 1] >= '0' && str[i * 2 + 1] <= '9') { + *out |= (str[i * 2 + 1] - '0'); + } + if (str[i * 2 + 1] >= 'a' && str[i * 2 + 1] <= 'f') { + *out |= (10 + str[i * 2 + 1] - 'a'); + } + if (str[i * 2 + 1] >= 'A' && str[i * 2 + 1] <= 'F') { + *out |= (10 + str[i * 2 + 1] - 'A'); + } + out++; + } + *outLen = i; +} + +uint8_t* utils_hex_to_uint8(const char* str) +{ + uint8_t c; + size_t i; + if (strlens(str) > TO_UINT8_HEX_BUF_LEN) { + return NULL; + } + memset(buffer_hex_to_uint8, 0, TO_UINT8_HEX_BUF_LEN); + for (i = 0; i < strlens(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'); + } + buffer_hex_to_uint8[i] = c; + } + return buffer_hex_to_uint8; +} + + +void utils_bin_to_hex(unsigned char* bin_in, size_t inlen, char* hex_out) +{ + static char digits[] = "0123456789abcdef"; + size_t i; + for (i = 0; i < inlen; i++) { + hex_out[i * 2] = digits[(bin_in[i] >> 4) & 0xF]; + hex_out[i * 2 + 1] = digits[bin_in[i] & 0xF]; + } + hex_out[inlen * 2] = '\0'; +} + + +char* utils_uint8_to_hex(const uint8_t* bin, size_t l) +{ + static char digits[] = "0123456789abcdef"; + size_t i; + if (l > (TO_UINT8_HEX_BUF_LEN / 2 - 1)) { + return NULL; + } + memset(buffer_uint8_to_hex, 0, TO_UINT8_HEX_BUF_LEN); + for (i = 0; i < l; i++) { + buffer_uint8_to_hex[i * 2] = digits[(bin[i] >> 4) & 0xF]; + buffer_uint8_to_hex[i * 2 + 1] = digits[bin[i] & 0xF]; + } + buffer_uint8_to_hex[l * 2] = '\0'; + return buffer_uint8_to_hex; +} + +void utils_reverse_hex(char* h, int len) +{ + char* copy = btc_malloc(len); + int i; + strncpy(copy, h, len); + for (i = 0; i < len; i += 2) { + h[i] = copy[len - i - 2]; + h[i + 1] = copy[len - i - 1]; + } + btc_free(copy); +} + +const signed char p_util_hexdigit[256] = + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -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, 9, -1, -1, -1, -1, -1, -1, + -1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + +signed char utils_hex_digit(char c) +{ + return p_util_hexdigit[(unsigned char)c]; +} + +void utils_uint256_sethex(char* psz, uint8_t* out) +{ + memset(out, 0, sizeof(uint256)); + + // skip leading spaces + while (isspace(*psz)) + psz++; + + // skip 0x + if (psz[0] == '0' && tolower(psz[1]) == 'x') + psz += 2; + + // hex string to uint + const char* pbegin = psz; + while (utils_hex_digit(*psz) != -1) + psz++; + psz--; + unsigned char* p1 = (unsigned char*)out; + unsigned char* pend = p1 + sizeof(uint256); + while (psz >= pbegin && p1 < pend) { + *p1 = utils_hex_digit(*psz--); + if (psz >= pbegin) { + *p1 |= ((unsigned char)utils_hex_digit(*psz--) << 4); + p1++; + } + } +} + +void* safe_malloc(size_t size) +{ + void* result; + + if ((result = malloc(size))) { /* assignment intentional */ + return (result); + } else { + printf("memory overflow: malloc failed in safe_malloc."); + printf(" Exiting Program.\n"); + exit(-1); + return (0); + } +} + +void btc_cheap_random_bytes(uint8_t* buf, uint32_t len) +{ + srand(time(NULL)); + for (uint32_t i = 0; i < len; i++) { + buf[i] = rand(); + } +} + +void btc_get_default_datadir(cstring *path_out) +{ + // Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin + // Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin + // Mac: ~/Library/Application Support/Bitcoin + // Unix: ~/.bitcoin +#ifdef WIN32 + // Windows + char* homedrive = getenv("HOMEDRIVE"); + char* homepath = getenv("HOMEDRIVE"); + cstr_append_buf(path_out, homedrive, strlen(homedrive)); + cstr_append_buf(path_out, homepath, strlen(homepath)); +#else + char* home = getenv("HOME"); + if (home == NULL || strlen(home) == 0) + cstr_append_c(path_out, '/'); + else + cstr_append_buf(path_out, home, strlen(home)); +#ifdef __APPLE__ + // Mac + char *osx_home = "/Library/Application Support/Bitcoin"; + cstr_append_buf(path_out, osx_home, strlen(osx_home)); +#else + // Unix + char *posix_home = "/.bitcoin"; + cstr_append_buf(path_out, posix_home, strlen(posix_home)); +#endif +#endif +} + +void btc_file_commit(FILE *file) +{ + fflush(file); // harmless if redundantly called +#ifdef WIN32 + HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file)); + FlushFileBuffers(hFile); +#else + #if defined(__linux__) || defined(__NetBSD__) + fdatasync(fileno(file)); + #elif defined(__APPLE__) && defined(F_FULLFSYNC) + fcntl(fileno(file), F_FULLFSYNC, 0); + #else + fsync(fileno(file)); + #endif +#endif +} diff --git a/src/vector.c b/src/vector.c new file mode 100644 index 000000000..3056dd4a5 --- /dev/null +++ b/src/vector.c @@ -0,0 +1,185 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Jonas Schnelli + + 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 + +vector* vector_new(size_t res, void (*free_f)(void*)) +{ + vector* vec = btc_calloc(1, sizeof(vector)); + if (!vec) + return NULL; + + vec->alloc = 8; + while (vec->alloc < res) + vec->alloc *= 2; + + vec->elem_free_f = free_f; + vec->data = btc_malloc(vec->alloc * sizeof(void*)); + if (!vec->data) { + btc_free(vec); + return NULL; + } + + return vec; +} + +static void vector_free_data(vector* vec) +{ + if (!vec->data) + return; + + if (vec->elem_free_f) { + unsigned int i; + for (i = 0; i < vec->len; i++) + if (vec->data[i]) { + vec->elem_free_f(vec->data[i]); + vec->data[i] = NULL; + } + } + + btc_free(vec->data); + vec->data = NULL; + vec->alloc = 0; + vec->len = 0; +} + +void vector_free(vector* vec, btc_bool free_array) +{ + if (!vec) + return; + + if (free_array) + vector_free_data(vec); + + memset(vec, 0, sizeof(*vec)); + btc_free(vec); +} + +static btc_bool vector_grow(vector* vec, size_t min_sz) +{ + size_t new_alloc = vec->alloc; + while (new_alloc < min_sz) + new_alloc *= 2; + + if (vec->alloc == new_alloc) + return true; + + void* new_data = btc_realloc(vec->data, new_alloc * sizeof(void*)); + if (!new_data) + return false; + + vec->data = new_data; + vec->alloc = new_alloc; + return true; +} + +ssize_t vector_find(vector* vec, void* data) +{ + if (vec && vec->len) { + size_t i; + for (i = 0; i < vec->len; i++) + if (vec->data[i] == data) + return (ssize_t)i; + } + + return -1; +} + +btc_bool vector_add(vector* vec, void* data) +{ + if (vec->len == vec->alloc) + if (!vector_grow(vec, vec->len + 1)) + return false; + + vec->data[vec->len] = data; + vec->len++; + return true; +} + +void vector_remove_range(vector* vec, size_t pos, size_t len) +{ + if (!vec || ((pos + len) > vec->len)) + return; + + if (vec->elem_free_f) { + unsigned int i, count; + for (i = pos, count = 0; count < len; i++, count++) + vec->elem_free_f(vec->data[i]); + } + + memmove(&vec->data[pos], &vec->data[pos + len], (vec->len - pos - len) * sizeof(void*)); + vec->len -= len; +} + +void vector_remove_idx(vector* vec, size_t pos) +{ + vector_remove_range(vec, pos, 1); +} + +btc_bool vector_remove(vector* vec, void* data) +{ + ssize_t idx = vector_find(vec, data); + if (idx < 0) + return false; + + vector_remove_idx(vec, idx); + return true; +} + +btc_bool vector_resize(vector* vec, size_t newsz) +{ + unsigned int i; + + /* same size */ + if (newsz == vec->len) + return true; + + /* truncate */ + else if (newsz < vec->len) { + size_t del_count = vec->len - newsz; + + for (i = (vec->len - del_count); i < vec->len; i++) { + if (vec->elem_free_f) + vec->elem_free_f(vec->data[i]); + vec->data[i] = NULL; + } + + vec->len = newsz; + return true; + } + + /* last possibility: grow */ + if (!vector_grow(vec, newsz)) + return false; + + /* set new elements to NULL */ + for (i = vec->len; i < newsz; i++) + vec->data[i] = NULL; + + return true; +} diff --git a/src/wallet.c b/src/wallet.c new file mode 100644 index 000000000..d6ee528c1 --- /dev/null +++ b/src/wallet.c @@ -0,0 +1,752 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2016 Jonas Schnelli + + 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define COINBASE_MATURITY 100 + +uint8_t WALLET_DB_REC_TYPE_MASTERKEY = 0; +uint8_t WALLET_DB_REC_TYPE_PUBKEYCACHE = 1; +uint8_t WALLET_DB_REC_TYPE_TX = 2; + +static const unsigned char file_hdr_magic[4] = {0xA8, 0xF0, 0x11, 0xC5}; /* header magic */ +static const uint32_t current_version = 1; + +static const char* hdkey_key = "hdkey"; +static const char* hdmasterkey_key = "mstkey"; +static const char* tx_key = "tx"; + + +/* ====================== */ +/* compare btree callback */ +/* ====================== */ +int btc_wallet_hdnode_compare(const void *l, const void *r) +{ + const btc_wallet_hdnode *lm = l; + const btc_wallet_hdnode *lr = r; + + uint8_t *pubkeyA = (uint8_t *)lm->pubkeyhash; + uint8_t *pubkeyB = (uint8_t *)lr->pubkeyhash; + + /* byte per byte compare */ + /* TODO: switch to memcmp */ + for (unsigned int i = 0; i < sizeof(uint160); i++) { + uint8_t iA = pubkeyA[i]; + uint8_t iB = pubkeyB[i]; + if (iA > iB) + return -1; + else if (iA < iB) + return 1; + } + + return 0; +} + +int btc_wtx_compare(const void *l, const void *r) +{ + const btc_wtx *lm = l; + const btc_wtx *lr = r; + + uint8_t *hashA = (uint8_t *)lm->tx_hash_cache; + uint8_t *hashB = (uint8_t *)lr->tx_hash_cache; + + /* byte per byte compare */ + for (unsigned int i = 0; i < sizeof(uint256); i++) { + uint8_t iA = hashA[i]; + uint8_t iB = hashB[i]; + if (iA > iB) + return -1; + else if (iA < iB) + return 1; + } + + return 0; +} + + +/* + ========================================================== + WALLET TRANSACTION (WTX) FUNCTIONS + ========================================================== +*/ + +btc_wtx* btc_wallet_wtx_new() +{ + btc_wtx* wtx; + wtx = btc_calloc(1, sizeof(*wtx)); + wtx->height = 0; + wtx->tx = btc_tx_new(); + + return wtx; +} + +btc_wtx* btc_wallet_wtx_copy(btc_wtx* wtx) +{ + btc_wtx* wtx_copy; + wtx_copy = btc_wallet_wtx_new(); + btc_tx_copy(wtx_copy->tx, wtx->tx); + + return wtx_copy; +} + +void btc_wallet_wtx_free(btc_wtx* wtx) +{ + btc_tx_free(wtx->tx); + btc_free(wtx); +} + +void btc_wallet_wtx_serialize(cstring* s, const btc_wtx* wtx) +{ + ser_u32(s, wtx->height); + ser_u256(s, wtx->tx_hash_cache); + btc_tx_serialize(s, wtx->tx, true); +} + +btc_bool btc_wallet_wtx_deserialize(btc_wtx* wtx, struct const_buffer* buf) +{ + deser_u32(&wtx->height, buf); + deser_u256(wtx->tx_hash_cache, buf); + return btc_tx_deserialize(buf->p, buf->len, wtx->tx, NULL, true); +} + +/* + ========================================================== + WALLET HDNODE (WALLET_HDNODE) FUNCTIONS + ========================================================== +*/ + +btc_wallet_hdnode* btc_wallet_hdnode_new() +{ + btc_wallet_hdnode* whdnode; + whdnode = btc_calloc(1, sizeof(*whdnode)); + whdnode->hdnode = btc_hdnode_new(); + + return whdnode; +} +void btc_wallet_hdnode_free(btc_wallet_hdnode* whdnode) +{ + btc_hdnode_free(whdnode->hdnode); + btc_free(whdnode); +} + +void btc_wallet_hdnode_serialize(cstring* s, const btc_chainparams *params, const btc_wallet_hdnode* whdnode) +{ + ser_bytes(s, whdnode->pubkeyhash, sizeof(uint160)); + char strbuf[196]; + btc_hdnode_serialize_private(whdnode->hdnode, params, strbuf, sizeof(strbuf)); + ser_str(s, strbuf, sizeof(strbuf)); +} + +btc_bool btc_wallet_hdnode_deserialize(btc_wallet_hdnode* whdnode, const btc_chainparams *params, struct const_buffer* buf) { + deser_bytes(&whdnode->pubkeyhash, buf, sizeof(uint160)); + char strbuf[196]; + if (!deser_str(strbuf, buf, sizeof(strbuf))) return false; + if (!btc_hdnode_deserialize(strbuf, params, whdnode->hdnode)) return false; + return true; +} + +/* + ========================================================== + WALLET OUTPUT (prev wtx + n) FUNCTIONS + ========================================================== + */ + +btc_output* btc_wallet_output_new() +{ + btc_output* output; + output = btc_calloc(1, sizeof(*output)); + output->i = 0; + output->wtx = btc_wallet_wtx_new(); + + return output; +} + +void btc_wallet_output_free(btc_output* output) +{ + btc_wallet_wtx_free(output->wtx); + btc_free(output); +} + +/* + ========================================================== + WALLET CORE FUNCTIONS + ========================================================== + */ +btc_wallet* btc_wallet_new(const btc_chainparams *params) +{ + btc_wallet* wallet; + wallet = btc_calloc(1, sizeof(*wallet)); + wallet->masterkey = NULL; + wallet->chain = params; + wallet->spends = vector_new(10, free); + + wallet->wtxes_rbtree = 0; + wallet->hdkeys_rbtree = 0; + return wallet; +} + +void btc_wallet_free(btc_wallet* wallet) +{ + if (!wallet) + return; + + if (wallet->dbfile) { + fclose(wallet->dbfile); + wallet->dbfile = NULL; + } + + if (wallet->spends) { + vector_free(wallet->spends, true); + wallet->spends = NULL; + } + + if (wallet->masterkey) + btc_free(wallet->masterkey); + + btc_btree_tdestroy(wallet->wtxes_rbtree, btc_free); + btc_btree_tdestroy(wallet->hdkeys_rbtree, btc_free); + + btc_free(wallet); +} + +//void btc_wallet_logdb_append_cb(void* ctx, logdb_bool load_phase, logdb_record* rec) +//{ +// btc_wallet* wallet = (btc_wallet*)ctx; +// if (load_phase) { +// if (wallet->masterkey == NULL && rec->mode == RECORD_TYPE_WRITE && rec->key->len > strlen(hdmasterkey_key) && memcmp(rec->key->str, hdmasterkey_key, strlen(hdmasterkey_key)) == 0) { +// wallet->masterkey = btc_hdnode_new(); +// btc_hdnode_deserialize(rec->value->str, wallet->chain, wallet->masterkey); +// } +// if (rec->key->len == strlen(hdkey_key) + sizeof(uint160) && memcmp(rec->key->str, hdkey_key, strlen(hdkey_key)) == 0) { +// btc_hdnode* hdnode = btc_hdnode_new(); +// btc_hdnode_deserialize(rec->value->str, wallet->chain, hdnode); + +// /* rip out the hash from the record key (avoid re-SHA256) */ +// cstring* keyhash160 = cstr_new_buf(rec->key->str + strlen(hdkey_key), sizeof(uint160)); + +// /* add hdnode to the rbtree */ +// RBTreeInsert(wallet->hdkeys_rbtree, keyhash160, hdnode); + +// if (hdnode->child_num + 1 > wallet->next_childindex) +// wallet->next_childindex = hdnode->child_num + 1; +// } + +// if (rec->key->len == strlen(tx_key) + SHA256_DIGEST_LENGTH && memcmp(rec->key->str, tx_key, strlen(tx_key)) == 0) { +// btc_wtx* wtx = btc_wallet_wtx_new(); +// struct const_buffer buf = {rec->value->str, rec->value->len}; + +// /* deserialize transaction */ +// btc_wallet_wtx_deserialize(wtx, &buf); + +// /* rip out the hash from the record key (avoid re-SHA256) */ +// cstring* wtxhash = cstr_new_buf(rec->key->str + strlen(tx_key), SHA256_DIGEST_LENGTH); + +// /* add wtx to the rbtree */ +// RBTreeInsert(wallet->wtxes_rbtree, wtxhash, wtx); + +// /* add to spends */ +// btc_wallet_add_to_spent(wallet, wtx); +// } +// } +//} + +btc_bool btc_wallet_load(btc_wallet* wallet, const char* file_path, int *error, btc_bool *created) +{ + (void)(error); + if (!wallet) + return false; + + struct stat buffer; + *created = true; + if (stat(file_path, &buffer) == 0) + *created = false; + + wallet->dbfile = fopen(file_path, *created ? "a+b" : "r+b"); + + if (*created) { + // write file-header-magic + if (fwrite(file_hdr_magic, 4, 1, wallet->dbfile ) != 1 ) return false; + + // write version + uint32_t v = htole32(current_version); + if (fwrite(&v, sizeof(v), 1, wallet->dbfile ) != 1) return false; + + // write genesis + if (fwrite(wallet->chain->genesisblockhash, sizeof(uint256), 1, wallet->dbfile ) != 1) return false; + + btc_file_commit(wallet->dbfile); + } + else { + // check file-header-magic, version and genesis + uint8_t buf[sizeof(file_hdr_magic)+sizeof(current_version)+sizeof(uint256)]; + if ( (uint32_t)buffer.st_size < (uint32_t)(sizeof(buf)) || + fread(buf, sizeof(buf), 1, wallet->dbfile ) != 1 || + memcmp(buf, file_hdr_magic, sizeof(file_hdr_magic)) + ) + { + fprintf(stderr, "Wallet file: error reading database file\n"); + return false; + } + if (le32toh(*(buf+sizeof(file_hdr_magic))) > current_version) { + fprintf(stderr, "Wallet file: unsupported file version\n"); + return false; + } + if (memcmp(buf+sizeof(file_hdr_magic)+sizeof(current_version), wallet->chain->genesisblockhash, sizeof(uint256)) != 0) { + fprintf(stderr, "Wallet file: different network\n"); + return false; + } + // read + + while (!feof(wallet->dbfile)) + { + uint8_t rectype; + if (fread(&rectype, 1, 1, wallet->dbfile ) != 1) { + // no more record, break + break; + } + + if (rectype == WALLET_DB_REC_TYPE_MASTERKEY) { + uint32_t len; + char strbuf[196]; + if (!deser_varlen_from_file(&len, wallet->dbfile)) return false; + if (len > sizeof(strbuf)) { return false; } + if (fread(strbuf, len, 1, wallet->dbfile ) != 1) return false; + size_t test = strlen(strbuf); + wallet->masterkey = btc_hdnode_new(); + printf("xpriv: %s\n", strbuf); + btc_hdnode_deserialize(strbuf, wallet->chain, wallet->masterkey ); + int i = 0; + } + + if (rectype == WALLET_DB_REC_TYPE_PUBKEYCACHE) { + uint32_t len; + + btc_wallet_hdnode *whdnode = btc_wallet_hdnode_new(); + if (fread(whdnode->pubkeyhash, sizeof(uint160), 1, wallet->dbfile ) != 1) { + btc_wallet_hdnode_free(whdnode); + return false; + } + + // read the varint for the stringlength + char strbuf[1024]; + if (!deser_varlen_from_file(&len, wallet->dbfile)) { + btc_wallet_hdnode_free(whdnode); + return false; + } + if (len > sizeof(strbuf)) { return false; } + if (fread(strbuf, len, 1, wallet->dbfile ) != 1) { + btc_wallet_hdnode_free(whdnode); + return false; + } + // deserialize the hdnode + if (!btc_hdnode_deserialize(strbuf, wallet->chain, whdnode->hdnode)) { + btc_wallet_hdnode_free(whdnode); + return false; + } + + // add the node to the binary tree + btc_wallet_hdnode* checknode = tsearch(whdnode, &wallet->hdkeys_rbtree, btc_wallet_hdnode_compare); + + } + } + } + + return true; +} + +btc_bool btc_wallet_flush(btc_wallet* wallet) +{ + btc_file_commit(wallet->dbfile); + return true; +} + +void btc_wallet_set_master_key_copy(btc_wallet* wallet, btc_hdnode* masterkey) +{ + if (!masterkey) + return; + + if (wallet->masterkey != NULL) { + //changing the master key should not be done,... + //anyways, we are going to accept that at this point + //consuming application needs to take care about that + btc_hdnode_free(wallet->masterkey); + wallet->masterkey = NULL; + } + wallet->masterkey = btc_hdnode_copy(masterkey); + + cstring* record = cstr_new_sz(256); + ser_bytes(record, &WALLET_DB_REC_TYPE_MASTERKEY, 1); + char strbuf[196]; + btc_hdnode_serialize_private(wallet->masterkey, wallet->chain, strbuf, sizeof(strbuf)); + printf("xpriv: %s\n", strbuf); + ser_str(record, strbuf, sizeof(strbuf)); + + if ( fwrite(record->str, record->len, 1, wallet->dbfile) != 1 ) { + fprintf(stderr, "Writing master private key record failed\n"); + } + cstr_free(record, true); + + btc_file_commit(wallet->dbfile); +} + +btc_wallet_hdnode* btc_wallet_next_key(btc_wallet* wallet) +{ + if (!wallet || !wallet->masterkey) + return NULL; + + //for now, only m/k is possible + btc_wallet_hdnode *whdnode = btc_wallet_hdnode_new(); + btc_hdnode_free(whdnode->hdnode); + whdnode->hdnode = btc_hdnode_copy(wallet->masterkey); + btc_hdnode_private_ckd(whdnode->hdnode, wallet->next_childindex); + btc_hdnode_get_hash160(whdnode->hdnode, whdnode->pubkeyhash); + + //add it to the binary tree + // tree manages memory + btc_wallet_hdnode* checknode = tsearch(whdnode, &wallet->hdkeys_rbtree, btc_wallet_hdnode_compare); + + //serialize and store node + cstring* record = cstr_new_sz(256); + ser_bytes(record, &WALLET_DB_REC_TYPE_PUBKEYCACHE, 1); + btc_wallet_hdnode_serialize(record, wallet->chain, whdnode); + + if (fwrite(record->str, record->len, 1, wallet->dbfile) != 1) { + fprintf(stderr, "Writing childkey failed\n"); + } + cstr_free(record, true); + + btc_file_commit(wallet->dbfile); + + //increase the in-memory counter (cache) + wallet->next_childindex++; + + return whdnode; +} + +void btc_wallet_get_addresses(btc_wallet* wallet, vector* addr_out) +{ + (void)(wallet); + (void)(addr_out); +// rb_red_blk_node* hdkey_rbtree_node; + +// if (!wallet) +// return; + +// while ((hdkey_rbtree_node = rbtree_enumerate_next(wallet->hdkeys_rbtree))) { +// cstring* key = hdkey_rbtree_node->key; +// uint8_t hash160[sizeof(uint160)+1]; +// hash160[0] = wallet->chain->b58prefix_pubkey_address; +// memcpy(hash160 + 1, key->str, sizeof(uint160)); + +// size_t addrsize = 98; +// char* addr = btc_calloc(1, addrsize); +// btc_base58_encode_check(hash160, sizeof(uint160)+1, addr, addrsize); +// vector_add(addr_out, addr); +// } +} + +btc_wallet_hdnode* btc_wallet_find_hdnode_byaddr(btc_wallet* wallet, const char* search_addr) +{ + if (!wallet || !search_addr) + return NULL; + + uint8_t hashdata[strlen(search_addr)]; + memset(hashdata, 0, sizeof(uint160)); + int outlen = btc_base58_decode_check(search_addr, hashdata, strlen(search_addr)); + if (outlen == 0) { + return NULL; + } + + btc_wallet_hdnode* whdnode_search; + whdnode_search = btc_calloc(1, sizeof(*whdnode_search)); + memcpy(whdnode_search->pubkeyhash, hashdata+1, sizeof(uint160)); + + btc_wallet_hdnode *needle = tfind(whdnode_search, &wallet->hdkeys_rbtree, btc_wallet_hdnode_compare); /* read */ + if (needle) { + needle = *(btc_wallet_hdnode **)needle; + } + btc_free(whdnode_search); + + return needle; +} + +btc_bool btc_wallet_add_wtx_move(btc_wallet* wallet, btc_wtx* wtx) +{ + if (!wallet || !wtx) + return false; + + cstring* record = cstr_new_sz(1024); + ser_bytes(record, &WALLET_DB_REC_TYPE_TX, 1); + btc_wallet_wtx_serialize(record, wtx); + + if (fwrite(record->str, record->len, 1, wallet->dbfile) ) { + fprintf(stderr, "Writing master private key record failed\n"); + } + cstr_free(record, true); + + //add to spends + btc_wallet_add_to_spent(wallet, wtx); + + //add it to the binary tree + btc_wtx* checkwtx = tsearch(wtx, &wallet->wtxes_rbtree, btc_wtx_compare); + if (checkwtx) { + // remove existing wtx + checkwtx = *(btc_wtx **)checkwtx; + tdelete(checkwtx, &wallet->wtxes_rbtree, btc_wtx_compare); + btc_wallet_wtx_free(checkwtx); + + // insert again + btc_wtx* checkwtx = tsearch(wtx, &wallet->wtxes_rbtree, btc_wtx_compare); + } + + + return true; +} + +btc_bool btc_wallet_have_key(btc_wallet* wallet, uint160 hash160) +{ + if (!wallet) + return false; + + btc_wallet_hdnode* whdnode_search; + whdnode_search = btc_calloc(1, sizeof(*whdnode_search)); + memcpy(whdnode_search->pubkeyhash, hash160, sizeof(uint160)); + + btc_wallet_hdnode *needle = tfind(whdnode_search, &wallet->hdkeys_rbtree, btc_wallet_hdnode_compare); /* read */ + if (needle) { + needle = *(btc_wallet_hdnode **)needle; + } + btc_free(whdnode_search); + + return (needle != NULL); +} + +int64_t btc_wallet_get_balance(btc_wallet* wallet) +{ + int64_t credit = 0; + + if (!wallet) + return false; + +// // enumerate over the rbtree, calculate balance +// while ((hdkey_rbtree_node = rbtree_enumerate_next(wallet->wtxes_rbtree))) { +// btc_wtx* wtx = hdkey_rbtree_node->info; +// credit += btc_wallet_wtx_get_credit(wallet, wtx); +// } + + return credit; +} + +int64_t btc_wallet_wtx_get_credit(btc_wallet* wallet, btc_wtx* wtx) +{ + int64_t credit = 0; + + if (btc_tx_is_coinbase(wtx->tx) && + (wallet->bestblockheight < COINBASE_MATURITY || wtx->height > wallet->bestblockheight - COINBASE_MATURITY)) + return credit; + + uint256 hash; + btc_tx_hash(wtx->tx, hash); + unsigned int i = 0; + if (wtx->tx->vout) { + for (i = 0; i < wtx->tx->vout->len; i++) { + btc_tx_out* tx_out; + tx_out = vector_idx(wtx->tx->vout, i); + + if (!btc_wallet_is_spent(wallet, hash, i)) { + if (btc_wallet_txout_is_mine(wallet, tx_out)) + credit += tx_out->value; + } + } + } + return credit; +} + +btc_bool btc_wallet_txout_is_mine(btc_wallet* wallet, btc_tx_out* tx_out) +{ + if (!wallet || !tx_out) return false; + + btc_bool ismine = false; + + vector* vec = vector_new(16, free); + enum btc_tx_out_type type2 = btc_script_classify(tx_out->script_pubkey, vec); + + //TODO: Multisig, etc. + if (type2 == BTC_TX_PUBKEYHASH) { + //TODO: find a better format for vector elements (not a pure pointer) + uint8_t* hash160 = vector_idx(vec, 0); + if (btc_wallet_have_key(wallet, hash160)) + ismine = true; + } + + vector_free(vec, true); + + return ismine; +} + +btc_bool btc_wallet_is_mine(btc_wallet* wallet, const btc_tx *tx) +{ + if (!wallet || !tx) return false; + if (tx->vout) { + for (unsigned int i = 0; i < tx->vout->len; i++) { + btc_tx_out* tx_out = vector_idx(tx->vout, i); + if (tx_out && btc_wallet_txout_is_mine(wallet, tx_out)) { + return true; + } + } + } + return false; +} + +int64_t btc_wallet_get_debit_txi(btc_wallet *wallet, const btc_tx_in *txin) { + if (!wallet || !txin) return 0; + + btc_wtx wtx; + memcpy(wtx.tx_hash_cache, txin->prevout.hash, sizeof(wtx.tx_hash_cache)); + + btc_wtx* checkwtx = tfind(&wtx, &wallet->wtxes_rbtree, btc_wtx_compare); + if (checkwtx) { + // remove existing wtx + checkwtx = *(btc_wtx **)checkwtx; + //todo get debig + } + + return 0; +} + +int64_t btc_wallet_get_debit_tx(btc_wallet *wallet, const btc_tx *tx) { + int64_t debit = 0; + if (tx->vin) { + for (unsigned int i = 0; i < tx->vin->len; i++) { + btc_tx_in* tx_in= vector_idx(tx->vin, i); + if (tx_in) { + debit += btc_wallet_get_debit_txi(wallet, tx_in); + } + } + } + return debit; +} + +btc_bool btc_wallet_is_from_me(btc_wallet *wallet, const btc_tx *tx) +{ + return (btc_wallet_get_debit_tx(wallet, tx) > 0); +} + +void btc_wallet_add_to_spent(btc_wallet* wallet, btc_wtx* wtx) { + if (!wallet || !wtx) + return; + + if (btc_tx_is_coinbase(wtx->tx)) + return; + + unsigned int i = 0; + if (wtx->tx->vin) { + for (i = 0; i < wtx->tx->vin->len; i++) { + btc_tx_in* tx_in = vector_idx(wtx->tx->vin, i); + + //add to spends + btc_tx_outpoint* outpoint = btc_calloc(1, sizeof(btc_tx_outpoint)); + memcpy(outpoint, &tx_in->prevout, sizeof(btc_tx_outpoint)); + vector_add(wallet->spends, outpoint); + } + } +} + +btc_bool btc_wallet_is_spent(btc_wallet* wallet, uint256 hash, uint32_t n) +{ + if (!wallet) + return false; + + unsigned int i = 0; + for (i = wallet->spends->len; i > 0; i--) { + btc_tx_outpoint* outpoint = vector_idx(wallet->spends, i - 1); + if (memcmp(outpoint->hash, hash, BTC_HASH_LENGTH) == 0 && n == outpoint->n) + return true; + } + return false; +} + +btc_bool btc_wallet_get_unspent(btc_wallet* wallet, vector* unspents) +{ + (void)(wallet); + (void)(unspents); + return true; +// rb_red_blk_node* hdkey_rbtree_node; + +// if (!wallet) +// return false; + +// while ((hdkey_rbtree_node = rbtree_enumerate_next(wallet->wtxes_rbtree))) { +// btc_wtx* wtx = hdkey_rbtree_node->info; +// cstring* key = hdkey_rbtree_node->key; +// uint8_t* hash = (uint8_t*)key->str; + +// unsigned int i = 0; +// if (wtx->tx->vout) { +// for (i = 0; i < wtx->tx->vout->len; i++) { +// btc_tx_out* tx_out; +// tx_out = vector_idx(wtx->tx->vout, i); + +// if (!btc_wallet_is_spent(wallet, hash, i)) { +// if (btc_wallet_txout_is_mine(wallet, tx_out)) { +// btc_output* output = btc_wallet_output_new(); +// btc_wallet_wtx_free(output->wtx); +// output->wtx = btc_wallet_wtx_copy(wtx); +// output->i = i; +// vector_add(unspents, output); +// } +// } +// } +// } +// } + +// return true; +} + +void btc_wallet_check_transaction(void *ctx, btc_tx *tx, unsigned int pos, btc_blockindex *pindex) { + (void)(pos); + (void)(pindex); + btc_wallet *wallet = (btc_wallet *)ctx; + if (btc_wallet_is_mine(wallet, tx) || btc_wallet_is_from_me(wallet, tx)) { + int i = 0; + printf("\nFound relevant transaction!\n"); + } +} diff --git a/test/aes_tests.c b/test/aes_tests.c new file mode 100644 index 000000000..118b93897 --- /dev/null +++ b/test/aes_tests.c @@ -0,0 +1,602 @@ +/********************************************************************** + * Copyright (c) 2015 Jonas Schnelli * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include +#include "utest.h" + +struct nist_aes_test_vector +{ + char key[65]; + char iv[33]; + char in[33]; + char out[33]; +}; + +static const struct nist_aes_test_vector nist_aes_test_vectors_encrypt[] = +{ + {"8000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "e35a6dcb19b201a01ebcfa8aa22b5759"}, + {"c000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "b29169cdcf2d83e838125a12ee6aa400"}, + {"e000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "d8f3a72fc3cdf74dfaf6c3e6b97b2fa6"}, + {"f000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "1c777679d50037c79491a94da76a9a35"}, + {"f800000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "9cf4893ecafa0a0247a898e040691559"}, + {"fc00000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "8fbb413703735326310a269bd3aa94b2"}, + {"fe00000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "60e32246bed2b0e859e55c1cc6b26502"}, + {"ff00000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "ec52a212f80a09df6317021bc2a9819e"}, + {"ff80000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "f23e5b600eb70dbccf6c0b1d9a68182c"}, + {"ffc0000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "a3f599d63a82a968c33fe26590745970"}, + {"ffe0000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "d1ccb9b1337002cbac42c520b5d67722"}, + {"fff0000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "cc111f6c37cf40a1159d00fb59fb0488"}, + {"fff8000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "dc43b51ab609052372989a26e9cdd714"}, + {"fffc000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "4dcede8da9e2578f39703d4433dc6459"}, + {"fffe000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "1a4c1c263bbccfafc11782894685e3a8"}, + {"ffff000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "937ad84880db50613423d6d527a2823d"}, + {"ffff800000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "610b71dfc688e150d8152c5b35ebc14d"}, + {"ffffc00000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "27ef2495dabf323885aab39c80f18d8b"}, + {"ffffe00000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "633cafea395bc03adae3a1e2068e4b4e"}, + {"fffff00000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "6e1b482b53761cf631819b749a6f3724"}, + {"fffff80000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "976e6f851ab52c771998dbb2d71c75a9"}, + {"fffffc0000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "85f2ba84f8c307cf525e124c3e22e6cc"}, + {"fffffe0000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "6bcca98bf6a835fa64955f72de4115fe"}, + {"ffffff0000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "2c75e2d36eebd65411f14fd0eb1d2a06"}, + {"ffffff8000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "bd49295006250ffca5100b6007a0eade"}, + {"ffffffc000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "a190527d0ef7c70f459cd3940df316ec"}, + {"ffffffe000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "bbd1097a62433f79449fa97d4ee80dbf"}, + {"fffffff000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "07058e408f5b99b0e0f061a1761b5b3b"}, + {"fffffff800000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "5fd1f13fa0f31e37fabde328f894eac2"}, + {"fffffffc00000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "fc4af7c948df26e2ef3e01c1ee5b8f6f"}, + {"fffffffe00000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "829fd7208fb92d44a074a677ee9861ac"}, + {"ffffffff00000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "ad9fc613a703251b54c64a0e76431711"}, + {"ffffffff80000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "33ac9eccc4cc75e2711618f80b1548e8"}, + {"ffffffffc0000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "2025c74b8ad8f4cda17ee2049c4c902d"}, + {"ffffffffe0000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "f85ca05fe528f1ce9b790166e8d551e7"}, + {"fffffffff0000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "6f6238d8966048d4967154e0dad5a6c9"}, + {"fffffffff8000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "f2b21b4e7640a9b3346de8b82fb41e49"}, + {"fffffffffc000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "f836f251ad1d11d49dc344628b1884e1"}, + {"fffffffffe000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "077e9470ae7abea5a9769d49182628c3"}, + {"ffffffffff000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "e0dcc2d27fc9865633f85223cf0d611f"}, + {"ffffffffff800000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "be66cfea2fecd6bf0ec7b4352c99bcaa"}, + {"ffffffffffc00000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "df31144f87a2ef523facdcf21a427804"}, + {"ffffffffffe00000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "b5bb0f5629fb6aae5e1839a3c3625d63"}, + {"fffffffffff00000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "3c9db3335306fe1ec612bdbfae6b6028"}, + {"fffffffffff80000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "3dd5c34634a79d3cfcc8339760e6f5f4"}, + {"fffffffffffc0000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "82bda118a3ed7af314fa2ccc5c07b761"}, + {"fffffffffffe0000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "2937a64f7d4f46fe6fea3b349ec78e38"}, + {"ffffffffffff0000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "225f068c28476605735ad671bb8f39f3"}, + {"ffffffffffff8000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "ae682c5ecd71898e08942ac9aa89875c"}, + {"ffffffffffffc000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "5e031cb9d676c3022d7f26227e85c38f"}, + {"ffffffffffffe000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "a78463fb064db5d52bb64bfef64f2dda"}, + {"fffffffffffff000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "8aa9b75e784593876c53a00eae5af52b"}, + {"fffffffffffff800000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "3f84566df23da48af692722fe980573a"}, + {"fffffffffffffc00000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "31690b5ed41c7eb42a1e83270a7ff0e6"}, + {"fffffffffffffe00000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "77dd7702646d55f08365e477d3590eda"}, + {"ffffffffffffff00000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "4c022ac62b3cb78d739cc67b3e20bb7e"}, + {"ffffffffffffff80000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "092fa137ce18b5dfe7906f550bb13370"}, + {"ffffffffffffffc0000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "3e0cdadf2e68353c0027672c97144dd3"}, + {"ffffffffffffffe0000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "d8c4b200b383fc1f2b2ea677618a1d27"}, + {"fffffffffffffff0000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "11825f99b0e9bb3477c1c0713b015aac"}, + {"fffffffffffffff8000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "f8b9fffb5c187f7ddc7ab10f4fb77576"}, + {"fffffffffffffffc000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "ffb4e87a32b37d6f2c8328d3b5377802"}, + {"fffffffffffffffe000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "d276c13a5d220f4da9224e74896391ce"}, + {"ffffffffffffffff000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "94efe7a0e2e031e2536da01df799c927"}, + {"ffffffffffffffff800000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "8f8fd822680a85974e53a5a8eb9d38de"}, + {"ffffffffffffffffc00000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "e0f0a91b2e45f8cc37b7805a3042588d"}, + {"ffffffffffffffffe00000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "597a6252255e46d6364dbeeda31e279c"}, + {"fffffffffffffffff00000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "f51a0f694442b8f05571797fec7ee8bf"}, + {"fffffffffffffffff80000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "9ff071b165b5198a93dddeebc54d09b5"}, + {"fffffffffffffffffc0000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "c20a19fd5758b0c4bc1a5df89cf73877"}, + {"fffffffffffffffffe0000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "97120166307119ca2280e9315668e96f"}, + {"ffffffffffffffffff0000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "4b3b9f1e099c2a09dc091e90e4f18f0a"}, + {"ffffffffffffffffff8000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "eb040b891d4b37f6851f7ec219cd3f6d"}, + {"ffffffffffffffffffc000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "9f0fdec08b7fd79aa39535bea42db92a"}, + {"ffffffffffffffffffe000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "2e70f168fc74bf911df240bcd2cef236"}, + {"fffffffffffffffffff000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "462ccd7f5fd1108dbc152f3cacad328b"}, + {"fffffffffffffffffff800000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "a4af534a7d0b643a01868785d86dfb95"}, + {"fffffffffffffffffffc00000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "ab980296197e1a5022326c31da4bf6f3"}, + {"fffffffffffffffffffe00000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "f97d57b3333b6281b07d486db2d4e20c"}, + {"ffffffffffffffffffff00000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "f33fa36720231afe4c759ade6bd62eb6"}, + {"ffffffffffffffffffff80000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "fdcfac0c02ca538343c68117e0a15938"}, + {"ffffffffffffffffffffc0000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "ad4916f5ee5772be764fc027b8a6e539"}, + {"ffffffffffffffffffffe0000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "2e16873e1678610d7e14c02d002ea845"}, + {"fffffffffffffffffffff0000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "4e6e627c1acc51340053a8236d579576"}, + {"fffffffffffffffffffff8000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "ab0c8410aeeead92feec1eb430d652cb"}, + {"fffffffffffffffffffffc000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "e86f7e23e835e114977f60e1a592202e"}, + {"fffffffffffffffffffffe000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "e68ad5055a367041fade09d9a70a794b"}, + {"ffffffffffffffffffffff000000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "0791823a3c666bb6162825e78606a7fe"}, + {"ffffffffffffffffffffff800000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "dcca366a9bf47b7b868b77e25c18a364"}, + {"ffffffffffffffffffffffc00000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "684c9efc237e4a442965f84bce20247a"}, + {"ffffffffffffffffffffffe00000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "a858411ffbe63fdb9c8aa1bfaed67b52"}, + {"fffffffffffffffffffffff00000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "04bc3da2179c3015498b0e03910db5b8"}, + {"fffffffffffffffffffffff80000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "40071eeab3f935dbc25d00841460260f"}, + {"fffffffffffffffffffffffc0000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "0ebd7c30ed2016e08ba806ddb008bcc8"}, + {"fffffffffffffffffffffffe0000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "15c6becf0f4cec7129cbd22d1a79b1b8"}, + {"ffffffffffffffffffffffff0000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "0aeede5b91f721700e9e62edbf60b781"}, + {"ffffffffffffffffffffffff8000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "266581af0dcfbed1585e0a242c64b8df"}, + {"ffffffffffffffffffffffffc000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "6693dc911662ae473216ba22189a511a"}, + {"ffffffffffffffffffffffffe000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "7606fa36d86473e6fb3a1bb0e2c0adf5"}, + {"fffffffffffffffffffffffff000000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "112078e9e11fbb78e26ffb8899e96b9a"}, + {"fffffffffffffffffffffffff800000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "40b264e921e9e4a82694589ef3798262"}, + {"fffffffffffffffffffffffffc00000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "8d4595cb4fa7026715f55bd68e2882f9"}, + {"fffffffffffffffffffffffffe00000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "b588a302bdbc09197df1edae68926ed9"}, + {"ffffffffffffffffffffffffff00000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "33f7502390b8a4a221cfecd0666624ba"}, + {"ffffffffffffffffffffffffff80000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "3d20253adbce3be2373767c4d822c566"}, + {"ffffffffffffffffffffffffffc0000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "a42734a3929bf84cf0116c9856a3c18c"}, + {"ffffffffffffffffffffffffffe0000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "e3abc4939457422bb957da3c56938c6d"}, + {"fffffffffffffffffffffffffff0000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "972bdd2e7c525130fadc8f76fc6f4b3f"}, + {"fffffffffffffffffffffffffff8000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "84a83d7b94c699cbcb8a7d9b61f64093"}, + {"fffffffffffffffffffffffffffc000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "ce61d63514aded03d43e6ebfc3a9001f"}, + {"fffffffffffffffffffffffffffe000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "6c839dd58eeae6b8a36af48ed63d2dc9"}, + {"ffffffffffffffffffffffffffff000000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "cd5ece55b8da3bf622c4100df5de46f9"}, + {"ffffffffffffffffffffffffffff800000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "3b6f46f40e0ac5fc0a9c1105f800f48d"}, + {"ffffffffffffffffffffffffffffc00000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "ba26d47da3aeb028de4fb5b3a854a24b"}, + {"ffffffffffffffffffffffffffffe00000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "87f53bf620d3677268445212904389d5"}, + {"fffffffffffffffffffffffffffff00000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "10617d28b5e0f4605492b182a5d7f9f6"}, + {"fffffffffffffffffffffffffffff80000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "9aaec4fabbf6fae2a71feff02e372b39"}, + {"fffffffffffffffffffffffffffffc0000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "3a90c62d88b5c42809abf782488ed130"}, + {"fffffffffffffffffffffffffffffe0000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "f1f1c5a40899e15772857ccb65c7a09a"}, + {"ffffffffffffffffffffffffffffff0000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "190843d29b25a3897c692ce1dd81ee52"}, + {"ffffffffffffffffffffffffffffff8000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "a866bc65b6941d86e8420a7ffb0964db"}, + {"ffffffffffffffffffffffffffffffc000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "8193c6ff85225ced4255e92f6e078a14"}, + {"ffffffffffffffffffffffffffffffe000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "9661cb2424d7d4a380d547f9e7ec1cb9"}, + {"fffffffffffffffffffffffffffffff000000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "86f93d9ec08453a071e2e2877877a9c8"}, + {"fffffffffffffffffffffffffffffff800000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "27eefa80ce6a4a9d598e3fec365434d2"}, + {"fffffffffffffffffffffffffffffffc00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "d62068444578e3ab39ce7ec95dd045dc"}, + {"fffffffffffffffffffffffffffffffe00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "b5f71d4dd9a71fe5d8bc8ba7e6ea3048"}, + {"ffffffffffffffffffffffffffffffff00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "6825a347ac479d4f9d95c5cb8d3fd7e9"}, + {"ffffffffffffffffffffffffffffffff80000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "e3714e94a5778955cc0346358e94783a"}, + {"ffffffffffffffffffffffffffffffffc0000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "d836b44bb29e0c7d89fa4b2d4b677d2a"}, + {"ffffffffffffffffffffffffffffffffe0000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "5d454b75021d76d4b84f873a8f877b92"}, + {"fffffffffffffffffffffffffffffffff0000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "c3498f7eced2095314fc28115885b33f"}, + {"fffffffffffffffffffffffffffffffff8000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "6e668856539ad8e405bd123fe6c88530"}, + {"fffffffffffffffffffffffffffffffffc000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "8680db7f3a87b8605543cfdbe6754076"}, + {"fffffffffffffffffffffffffffffffffe000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "6c5d03b13069c3658b3179be91b0800c"}, + {"ffffffffffffffffffffffffffffffffff000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "ef1b384ac4d93eda00c92add0995ea5f"}, + {"ffffffffffffffffffffffffffffffffff800000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "bf8115805471741bd5ad20a03944790f"}, + {"ffffffffffffffffffffffffffffffffffc00000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "c64c24b6894b038b3c0d09b1df068b0b"}, + {"ffffffffffffffffffffffffffffffffffe00000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "3967a10cffe27d0178545fbf6a40544b"}, + {"fffffffffffffffffffffffffffffffffff00000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "7c85e9c95de1a9ec5a5363a8a053472d"}, + {"fffffffffffffffffffffffffffffffffff80000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "a9eec03c8abec7ba68315c2c8c2316e0"}, + {"fffffffffffffffffffffffffffffffffffc0000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "cac8e414c2f388227ae14986fc983524"}, + {"fffffffffffffffffffffffffffffffffffe0000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "5d942b7f4622ce056c3ce3ce5f1dd9d6"}, + {"ffffffffffffffffffffffffffffffffffff0000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "d240d648ce21a3020282c3f1b528a0b6"}, + {"ffffffffffffffffffffffffffffffffffff8000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "45d089c36d5c5a4efc689e3b0de10dd5"}, + {"ffffffffffffffffffffffffffffffffffffc000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "b4da5df4becb5462e03a0ed00d295629"}, + {"ffffffffffffffffffffffffffffffffffffe000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "dcf4e129136c1a4b7a0f38935cc34b2b"}, + {"fffffffffffffffffffffffffffffffffffff000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "d9a4c7618b0ce48a3d5aee1a1c0114c4"}, + {"fffffffffffffffffffffffffffffffffffff800000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "ca352df025c65c7b0bf306fbee0f36ba"}, + {"fffffffffffffffffffffffffffffffffffffc00000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "238aca23fd3409f38af63378ed2f5473"}, + {"fffffffffffffffffffffffffffffffffffffe00000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "59836a0e06a79691b36667d5380d8188"}, + {"ffffffffffffffffffffffffffffffffffffff00000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "33905080f7acf1cdae0a91fc3e85aee4"}, + {"ffffffffffffffffffffffffffffffffffffff80000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "72c9e4646dbc3d6320fc6689d93e8833"}, + {"ffffffffffffffffffffffffffffffffffffffc0000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "ba77413dea5925b7f5417ea47ff19f59"}, + {"ffffffffffffffffffffffffffffffffffffffe0000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "6cae8129f843d86dc786a0fb1a184970"}, + {"fffffffffffffffffffffffffffffffffffffff0000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "fcfefb534100796eebbd990206754e19"}, + {"fffffffffffffffffffffffffffffffffffffff8000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "8c791d5fdddf470da04f3e6dc4a5b5b5"}, + {"fffffffffffffffffffffffffffffffffffffffc000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "c93bbdc07a4611ae4bb266ea5034a387"}, + {"fffffffffffffffffffffffffffffffffffffffe000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "c102e38e489aa74762f3efc5bb23205a"}, + {"ffffffffffffffffffffffffffffffffffffffff000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "93201481665cbafc1fcc220bc545fb3d"}, + {"ffffffffffffffffffffffffffffffffffffffff800000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "4960757ec6ce68cf195e454cfd0f32ca"}, + {"ffffffffffffffffffffffffffffffffffffffffc00000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "feec7ce6a6cbd07c043416737f1bbb33"}, + {"ffffffffffffffffffffffffffffffffffffffffe00000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "11c5413904487a805d70a8edd9c35527"}, + {"fffffffffffffffffffffffffffffffffffffffff00000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "347846b2b2e36f1f0324c86f7f1b98e2"}, + {"fffffffffffffffffffffffffffffffffffffffff80000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "332eee1a0cbd19ca2d69b426894044f0"}, + {"fffffffffffffffffffffffffffffffffffffffffc0000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "866b5b3977ba6efa5128efbda9ff03cd"}, + {"fffffffffffffffffffffffffffffffffffffffffe0000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "cc1445ee94c0f08cdee5c344ecd1e233"}, + {"ffffffffffffffffffffffffffffffffffffffffff0000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "be288319029363c2622feba4b05dfdfe"}, + {"ffffffffffffffffffffffffffffffffffffffffff8000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "cfd1875523f3cd21c395651e6ee15e56"}, + {"ffffffffffffffffffffffffffffffffffffffffffc000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "cb5a408657837c53bf16f9d8465dce19"}, + {"ffffffffffffffffffffffffffffffffffffffffffe000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "ca0bf42cb107f55ccff2fc09ee08ca15"}, + {"fffffffffffffffffffffffffffffffffffffffffff000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "fdd9bbb4a7dc2e4a23536a5880a2db67"}, + {"fffffffffffffffffffffffffffffffffffffffffff800000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "ede447b362c484993dec9442a3b46aef"}, + {"fffffffffffffffffffffffffffffffffffffffffffc00000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "10dffb05904bff7c4781df780ad26837"}, + {"fffffffffffffffffffffffffffffffffffffffffffe00000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "c33bc13e8de88ac25232aa7496398783"}, + {"ffffffffffffffffffffffffffffffffffffffffffff00000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "ca359c70803a3b2a3d542e8781dea975"}, + {"ffffffffffffffffffffffffffffffffffffffffffff80000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "bcc65b526f88d05b89ce8a52021fdb06"}, + {"ffffffffffffffffffffffffffffffffffffffffffffc0000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "db91a38855c8c4643851fbfb358b0109"}, + {"ffffffffffffffffffffffffffffffffffffffffffffe0000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "ca6e8893a114ae8e27d5ab03a5499610"}, + {"fffffffffffffffffffffffffffffffffffffffffffff0000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "6629d2b8df97da728cdd8b1e7f945077"}, + {"fffffffffffffffffffffffffffffffffffffffffffff8000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "4570a5a18cfc0dd582f1d88d5c9a1720"}, + {"fffffffffffffffffffffffffffffffffffffffffffffc000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "72bc65aa8e89562e3f274d45af1cd10b"}, + {"fffffffffffffffffffffffffffffffffffffffffffffe000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "98551da1a6503276ae1c77625f9ea615"}, + {"ffffffffffffffffffffffffffffffffffffffffffffff000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "0ddfe51ced7e3f4ae927daa3fe452cee"}, + {"ffffffffffffffffffffffffffffffffffffffffffffff800000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "db826251e4ce384b80218b0e1da1dd4c"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffc00000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "2cacf728b88abbad7011ed0e64a1680c"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffe00000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "330d8ee7c5677e099ac74c9994ee4cfb"}, + {"fffffffffffffffffffffffffffffffffffffffffffffff00000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "edf61ae362e882ddc0167474a7a77f3a"}, + {"fffffffffffffffffffffffffffffffffffffffffffffff80000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "6168b00ba7859e0970ecfd757efecf7c"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffc0000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "d1415447866230d28bb1ea18a4cdfd02"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffe0000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "516183392f7a8763afec68a060264141"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "77565c8d73cfd4130b4aa14d8911710f"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffff8000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "37232a4ed21ccc27c19c9610078cabac"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffc000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "804f32ea71828c7d329077e712231666"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffe000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "d64424f23cb97215e9c2c6f28d29eab7"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "023e82b533f68c75c238cebdb2ee89a2"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffff800000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "193a3d24157a51f1ee0893f6777417e7"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffc00000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "84ecacfcd400084d078612b1945f2ef5"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffe00000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "1dcd8bb173259eb33a5242b0de31a455"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "35e9eddbc375e792c19992c19165012b"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "8a772231c01dfdd7c98e4cfddcc0807a"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffc0000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "6eda7ff6b8319180ff0d6e65629d01c3"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffe0000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "c267ef0e2d01a993944dd397101413cb"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "e9f80e9d845bcc0f62926af72eabca39"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffff8000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "6702990727aa0878637b45dcd3a3b074"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffc000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "2e2e647d5360e09230a5d738ca33471e"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffe000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "1f56413c7add6f43d1d56e4f02190330"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "69cd0606e15af729d6bca143016d9842"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffff800000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "a085d7c1a500873a20099c4caa3c3f5b"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffc00000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "4fc0d230f8891415b87b83f95f2e09d1"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffe00000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "4327d08c523d8eba697a4336507d1f42"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "7a15aab82701efa5ae36ab1d6b76290f"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "5bf0051893a18bb30e139a58fed0fa54"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffc0000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "97e8adf65638fd9cdf3bc22c17fe4dbd"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffe0000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "1ee6ee326583a0586491c96418d1a35d"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "26b549c2ec756f82ecc48008e529956b"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffff8000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "70377b6da669b072129e057cc28e9ca5"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffc000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "9c94b8b0cb8bcc919072262b3fa05ad9"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffe000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "2fbb83dfd0d7abcb05cd28cad2dfb523"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "96877803de77744bb970d0a91f4debae"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffff800000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "7379f3370cf6e5ce12ae5969c8eea312"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffc00000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "02dc99fa3d4f98ce80985e7233889313"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffe00000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "1e38e759075ba5cab6457da51844295a"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "70bed8dbf615868a1f9d9b05d3e7a267"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "234b148b8cb1d8c32b287e896903d150"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "294b033df4da853f4be3e243f7e513f4"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "3f58c950f0367160adec45f2441e7411"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "37f655536a704e5ace182d742a820cf4"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffff8000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "ea7bd6bb63418731aeac790fe42d61e8"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffc000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "e74a4c999b4c064e48bb1e413f51e5ea"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffe000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "ba9ebefdb4ccf30f296cecb3bc1943e8"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "3194367a4898c502c13bb7478640a72d"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff800000", "00000000000000000000000000000000", "00000000000000000000000000000000", "da797713263d6f33a5478a65ef60d412"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00000", "00000000000000000000000000000000", "00000000000000000000000000000000", "d1ac39bb1ef86b9c1344f214679aa376"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00000", "00000000000000000000000000000000", "00000000000000000000000000000000", "2fdea9e650532be5bc0e7325337fd363"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000", "00000000000000000000000000000000", "00000000000000000000000000000000", "d3a204dbd9c2af158b6ca67a5156ce4a"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000", "00000000000000000000000000000000", "00000000000000000000000000000000", "3a0a0e75a8da36735aee6684d965a778"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0000", "00000000000000000000000000000000", "00000000000000000000000000000000", "52fc3e620492ea99641ea168da5b6d52"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0000", "00000000000000000000000000000000", "00000000000000000000000000000000", "d2e0c7f15b4772467d2cfc873000b2ca"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000", "00000000000000000000000000000000", "00000000000000000000000000000000", "563531135e0c4d70a38f8bdb190ba04e"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8000", "00000000000000000000000000000000", "00000000000000000000000000000000", "a8a39a0f5663f4c0fe5f2d3cafff421a"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc000", "00000000000000000000000000000000", "00000000000000000000000000000000", "d94b5e90db354c1e42f61fabe167b2c0"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe000", "00000000000000000000000000000000", "00000000000000000000000000000000", "50e6d3c9b6698a7cd276f96b1473f35a"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000", "00000000000000000000000000000000", "00000000000000000000000000000000", "9338f08e0ebee96905d8f2e825208f43"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff800", "00000000000000000000000000000000", "00000000000000000000000000000000", "8b378c86672aa54a3a266ba19d2580ca"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00", "00000000000000000000000000000000", "00000000000000000000000000000000", "cca7c3086f5f9511b31233da7cab9160"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00", "00000000000000000000000000000000", "00000000000000000000000000000000", "5b40ff4ec9be536ba23035fa4f06064c"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", "00000000000000000000000000000000", "00000000000000000000000000000000", "60eb5af8416b257149372194e8b88749"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80", "00000000000000000000000000000000", "00000000000000000000000000000000", "2f005a8aed8a361c92e440c15520cbd1"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0", "00000000000000000000000000000000", "00000000000000000000000000000000", "7b03627611678a997717578807a800e2"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0", "00000000000000000000000000000000", "00000000000000000000000000000000", "cf78618f74f6f3696e0a4779b90b5a77"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", "00000000000000000000000000000000", "00000000000000000000000000000000", "03720371a04962eaea0a852e69972858"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8", "00000000000000000000000000000000", "00000000000000000000000000000000", "1f8a8133aa8ccf70e2bd3285831ca6b7"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc", "00000000000000000000000000000000", "00000000000000000000000000000000", "27936bd27fb1468fc8b48bc483321725"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", "00000000000000000000000000000000", "00000000000000000000000000000000", "b07d4f3e2cd2ef2eb545980754dfea0f"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "00000000000000000000000000000000", "00000000000000000000000000000000", "4bf85f1b5d54adbc307b0a048389adcb"} +}; + +static const struct nist_aes_test_vector nist_aes_test_vectors_decrypt[] = +{ + {"8000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "e35a6dcb19b201a01ebcfa8aa22b5759", "00000000000000000000000000000000"}, + {"c000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "b29169cdcf2d83e838125a12ee6aa400", "00000000000000000000000000000000"}, + {"e000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "d8f3a72fc3cdf74dfaf6c3e6b97b2fa6", "00000000000000000000000000000000"}, + {"f000000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "1c777679d50037c79491a94da76a9a35", "00000000000000000000000000000000"}, + {"f800000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "9cf4893ecafa0a0247a898e040691559", "00000000000000000000000000000000"}, + {"fc00000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "8fbb413703735326310a269bd3aa94b2", "00000000000000000000000000000000"}, + {"fe00000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "60e32246bed2b0e859e55c1cc6b26502", "00000000000000000000000000000000"}, + {"ff00000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "ec52a212f80a09df6317021bc2a9819e", "00000000000000000000000000000000"}, + {"ff80000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "f23e5b600eb70dbccf6c0b1d9a68182c", "00000000000000000000000000000000"}, + {"ffc0000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "a3f599d63a82a968c33fe26590745970", "00000000000000000000000000000000"}, + {"ffe0000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "d1ccb9b1337002cbac42c520b5d67722", "00000000000000000000000000000000"}, + {"fff0000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "cc111f6c37cf40a1159d00fb59fb0488", "00000000000000000000000000000000"}, + {"fff8000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "dc43b51ab609052372989a26e9cdd714", "00000000000000000000000000000000"}, + {"fffc000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "4dcede8da9e2578f39703d4433dc6459", "00000000000000000000000000000000"}, + {"fffe000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "1a4c1c263bbccfafc11782894685e3a8", "00000000000000000000000000000000"}, + {"ffff000000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "937ad84880db50613423d6d527a2823d", "00000000000000000000000000000000"}, + {"ffff800000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "610b71dfc688e150d8152c5b35ebc14d", "00000000000000000000000000000000"}, + {"ffffc00000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "27ef2495dabf323885aab39c80f18d8b", "00000000000000000000000000000000"}, + {"ffffe00000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "633cafea395bc03adae3a1e2068e4b4e", "00000000000000000000000000000000"}, + {"fffff00000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "6e1b482b53761cf631819b749a6f3724", "00000000000000000000000000000000"}, + {"fffff80000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "976e6f851ab52c771998dbb2d71c75a9", "00000000000000000000000000000000"}, + {"fffffc0000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "85f2ba84f8c307cf525e124c3e22e6cc", "00000000000000000000000000000000"}, + {"fffffe0000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "6bcca98bf6a835fa64955f72de4115fe", "00000000000000000000000000000000"}, + {"ffffff0000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "2c75e2d36eebd65411f14fd0eb1d2a06", "00000000000000000000000000000000"}, + {"ffffff8000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "bd49295006250ffca5100b6007a0eade", "00000000000000000000000000000000"}, + {"ffffffc000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "a190527d0ef7c70f459cd3940df316ec", "00000000000000000000000000000000"}, + {"ffffffe000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "bbd1097a62433f79449fa97d4ee80dbf", "00000000000000000000000000000000"}, + {"fffffff000000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "07058e408f5b99b0e0f061a1761b5b3b", "00000000000000000000000000000000"}, + {"fffffff800000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "5fd1f13fa0f31e37fabde328f894eac2", "00000000000000000000000000000000"}, + {"fffffffc00000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "fc4af7c948df26e2ef3e01c1ee5b8f6f", "00000000000000000000000000000000"}, + {"fffffffe00000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "829fd7208fb92d44a074a677ee9861ac", "00000000000000000000000000000000"}, + {"ffffffff00000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "ad9fc613a703251b54c64a0e76431711", "00000000000000000000000000000000"}, + {"ffffffff80000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "33ac9eccc4cc75e2711618f80b1548e8", "00000000000000000000000000000000"}, + {"ffffffffc0000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "2025c74b8ad8f4cda17ee2049c4c902d", "00000000000000000000000000000000"}, + {"ffffffffe0000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "f85ca05fe528f1ce9b790166e8d551e7", "00000000000000000000000000000000"}, + {"fffffffff0000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "6f6238d8966048d4967154e0dad5a6c9", "00000000000000000000000000000000"}, + {"fffffffff8000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "f2b21b4e7640a9b3346de8b82fb41e49", "00000000000000000000000000000000"}, + {"fffffffffc000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "f836f251ad1d11d49dc344628b1884e1", "00000000000000000000000000000000"}, + {"fffffffffe000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "077e9470ae7abea5a9769d49182628c3", "00000000000000000000000000000000"}, + {"ffffffffff000000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "e0dcc2d27fc9865633f85223cf0d611f", "00000000000000000000000000000000"}, + {"ffffffffff800000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "be66cfea2fecd6bf0ec7b4352c99bcaa", "00000000000000000000000000000000"}, + {"ffffffffffc00000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "df31144f87a2ef523facdcf21a427804", "00000000000000000000000000000000"}, + {"ffffffffffe00000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "b5bb0f5629fb6aae5e1839a3c3625d63", "00000000000000000000000000000000"}, + {"fffffffffff00000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "3c9db3335306fe1ec612bdbfae6b6028", "00000000000000000000000000000000"}, + {"fffffffffff80000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "3dd5c34634a79d3cfcc8339760e6f5f4", "00000000000000000000000000000000"}, + {"fffffffffffc0000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "82bda118a3ed7af314fa2ccc5c07b761", "00000000000000000000000000000000"}, + {"fffffffffffe0000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "2937a64f7d4f46fe6fea3b349ec78e38", "00000000000000000000000000000000"}, + {"ffffffffffff0000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "225f068c28476605735ad671bb8f39f3", "00000000000000000000000000000000"}, + {"ffffffffffff8000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "ae682c5ecd71898e08942ac9aa89875c", "00000000000000000000000000000000"}, + {"ffffffffffffc000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "5e031cb9d676c3022d7f26227e85c38f", "00000000000000000000000000000000"}, + {"ffffffffffffe000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "a78463fb064db5d52bb64bfef64f2dda", "00000000000000000000000000000000"}, + {"fffffffffffff000000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "8aa9b75e784593876c53a00eae5af52b", "00000000000000000000000000000000"}, + {"fffffffffffff800000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "3f84566df23da48af692722fe980573a", "00000000000000000000000000000000"}, + {"fffffffffffffc00000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "31690b5ed41c7eb42a1e83270a7ff0e6", "00000000000000000000000000000000"}, + {"fffffffffffffe00000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "77dd7702646d55f08365e477d3590eda", "00000000000000000000000000000000"}, + {"ffffffffffffff00000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "4c022ac62b3cb78d739cc67b3e20bb7e", "00000000000000000000000000000000"}, + {"ffffffffffffff80000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "092fa137ce18b5dfe7906f550bb13370", "00000000000000000000000000000000"}, + {"ffffffffffffffc0000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "3e0cdadf2e68353c0027672c97144dd3", "00000000000000000000000000000000"}, + {"ffffffffffffffe0000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "d8c4b200b383fc1f2b2ea677618a1d27", "00000000000000000000000000000000"}, + {"fffffffffffffff0000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "11825f99b0e9bb3477c1c0713b015aac", "00000000000000000000000000000000"}, + {"fffffffffffffff8000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "f8b9fffb5c187f7ddc7ab10f4fb77576", "00000000000000000000000000000000"}, + {"fffffffffffffffc000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "ffb4e87a32b37d6f2c8328d3b5377802", "00000000000000000000000000000000"}, + {"fffffffffffffffe000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "d276c13a5d220f4da9224e74896391ce", "00000000000000000000000000000000"}, + {"ffffffffffffffff000000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "94efe7a0e2e031e2536da01df799c927", "00000000000000000000000000000000"}, + {"ffffffffffffffff800000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "8f8fd822680a85974e53a5a8eb9d38de", "00000000000000000000000000000000"}, + {"ffffffffffffffffc00000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "e0f0a91b2e45f8cc37b7805a3042588d", "00000000000000000000000000000000"}, + {"ffffffffffffffffe00000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "597a6252255e46d6364dbeeda31e279c", "00000000000000000000000000000000"}, + {"fffffffffffffffff00000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "f51a0f694442b8f05571797fec7ee8bf", "00000000000000000000000000000000"}, + {"fffffffffffffffff80000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "9ff071b165b5198a93dddeebc54d09b5", "00000000000000000000000000000000"}, + {"fffffffffffffffffc0000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "c20a19fd5758b0c4bc1a5df89cf73877", "00000000000000000000000000000000"}, + {"fffffffffffffffffe0000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "97120166307119ca2280e9315668e96f", "00000000000000000000000000000000"}, + {"ffffffffffffffffff0000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "4b3b9f1e099c2a09dc091e90e4f18f0a", "00000000000000000000000000000000"}, + {"ffffffffffffffffff8000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "eb040b891d4b37f6851f7ec219cd3f6d", "00000000000000000000000000000000"}, + {"ffffffffffffffffffc000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "9f0fdec08b7fd79aa39535bea42db92a", "00000000000000000000000000000000"}, + {"ffffffffffffffffffe000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "2e70f168fc74bf911df240bcd2cef236", "00000000000000000000000000000000"}, + {"fffffffffffffffffff000000000000000000000000000000000000000000000", "00000000000000000000000000000000", "462ccd7f5fd1108dbc152f3cacad328b", "00000000000000000000000000000000"}, + {"fffffffffffffffffff800000000000000000000000000000000000000000000", "00000000000000000000000000000000", "a4af534a7d0b643a01868785d86dfb95", "00000000000000000000000000000000"}, + {"fffffffffffffffffffc00000000000000000000000000000000000000000000", "00000000000000000000000000000000", "ab980296197e1a5022326c31da4bf6f3", "00000000000000000000000000000000"}, + {"fffffffffffffffffffe00000000000000000000000000000000000000000000", "00000000000000000000000000000000", "f97d57b3333b6281b07d486db2d4e20c", "00000000000000000000000000000000"}, + {"ffffffffffffffffffff00000000000000000000000000000000000000000000", "00000000000000000000000000000000", "f33fa36720231afe4c759ade6bd62eb6", "00000000000000000000000000000000"}, + {"ffffffffffffffffffff80000000000000000000000000000000000000000000", "00000000000000000000000000000000", "fdcfac0c02ca538343c68117e0a15938", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffc0000000000000000000000000000000000000000000", "00000000000000000000000000000000", "ad4916f5ee5772be764fc027b8a6e539", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffe0000000000000000000000000000000000000000000", "00000000000000000000000000000000", "2e16873e1678610d7e14c02d002ea845", "00000000000000000000000000000000"}, + {"fffffffffffffffffffff0000000000000000000000000000000000000000000", "00000000000000000000000000000000", "4e6e627c1acc51340053a8236d579576", "00000000000000000000000000000000"}, + {"fffffffffffffffffffff8000000000000000000000000000000000000000000", "00000000000000000000000000000000", "ab0c8410aeeead92feec1eb430d652cb", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffc000000000000000000000000000000000000000000", "00000000000000000000000000000000", "e86f7e23e835e114977f60e1a592202e", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffe000000000000000000000000000000000000000000", "00000000000000000000000000000000", "e68ad5055a367041fade09d9a70a794b", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffff000000000000000000000000000000000000000000", "00000000000000000000000000000000", "0791823a3c666bb6162825e78606a7fe", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffff800000000000000000000000000000000000000000", "00000000000000000000000000000000", "dcca366a9bf47b7b868b77e25c18a364", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffc00000000000000000000000000000000000000000", "00000000000000000000000000000000", "684c9efc237e4a442965f84bce20247a", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffe00000000000000000000000000000000000000000", "00000000000000000000000000000000", "a858411ffbe63fdb9c8aa1bfaed67b52", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffff00000000000000000000000000000000000000000", "00000000000000000000000000000000", "04bc3da2179c3015498b0e03910db5b8", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffff80000000000000000000000000000000000000000", "00000000000000000000000000000000", "40071eeab3f935dbc25d00841460260f", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffc0000000000000000000000000000000000000000", "00000000000000000000000000000000", "0ebd7c30ed2016e08ba806ddb008bcc8", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffe0000000000000000000000000000000000000000", "00000000000000000000000000000000", "15c6becf0f4cec7129cbd22d1a79b1b8", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffff0000000000000000000000000000000000000000", "00000000000000000000000000000000", "0aeede5b91f721700e9e62edbf60b781", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffff8000000000000000000000000000000000000000", "00000000000000000000000000000000", "266581af0dcfbed1585e0a242c64b8df", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffc000000000000000000000000000000000000000", "00000000000000000000000000000000", "6693dc911662ae473216ba22189a511a", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffe000000000000000000000000000000000000000", "00000000000000000000000000000000", "7606fa36d86473e6fb3a1bb0e2c0adf5", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffff000000000000000000000000000000000000000", "00000000000000000000000000000000", "112078e9e11fbb78e26ffb8899e96b9a", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffff800000000000000000000000000000000000000", "00000000000000000000000000000000", "40b264e921e9e4a82694589ef3798262", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffc00000000000000000000000000000000000000", "00000000000000000000000000000000", "8d4595cb4fa7026715f55bd68e2882f9", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffe00000000000000000000000000000000000000", "00000000000000000000000000000000", "b588a302bdbc09197df1edae68926ed9", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffff00000000000000000000000000000000000000", "00000000000000000000000000000000", "33f7502390b8a4a221cfecd0666624ba", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffff80000000000000000000000000000000000000", "00000000000000000000000000000000", "3d20253adbce3be2373767c4d822c566", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffc0000000000000000000000000000000000000", "00000000000000000000000000000000", "a42734a3929bf84cf0116c9856a3c18c", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffe0000000000000000000000000000000000000", "00000000000000000000000000000000", "e3abc4939457422bb957da3c56938c6d", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffff0000000000000000000000000000000000000", "00000000000000000000000000000000", "972bdd2e7c525130fadc8f76fc6f4b3f", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffff8000000000000000000000000000000000000", "00000000000000000000000000000000", "84a83d7b94c699cbcb8a7d9b61f64093", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffc000000000000000000000000000000000000", "00000000000000000000000000000000", "ce61d63514aded03d43e6ebfc3a9001f", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffe000000000000000000000000000000000000", "00000000000000000000000000000000", "6c839dd58eeae6b8a36af48ed63d2dc9", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffff000000000000000000000000000000000000", "00000000000000000000000000000000", "cd5ece55b8da3bf622c4100df5de46f9", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffff800000000000000000000000000000000000", "00000000000000000000000000000000", "3b6f46f40e0ac5fc0a9c1105f800f48d", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffc00000000000000000000000000000000000", "00000000000000000000000000000000", "ba26d47da3aeb028de4fb5b3a854a24b", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffe00000000000000000000000000000000000", "00000000000000000000000000000000", "87f53bf620d3677268445212904389d5", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffff00000000000000000000000000000000000", "00000000000000000000000000000000", "10617d28b5e0f4605492b182a5d7f9f6", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffff80000000000000000000000000000000000", "00000000000000000000000000000000", "9aaec4fabbf6fae2a71feff02e372b39", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffc0000000000000000000000000000000000", "00000000000000000000000000000000", "3a90c62d88b5c42809abf782488ed130", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffe0000000000000000000000000000000000", "00000000000000000000000000000000", "f1f1c5a40899e15772857ccb65c7a09a", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffff0000000000000000000000000000000000", "00000000000000000000000000000000", "190843d29b25a3897c692ce1dd81ee52", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffff8000000000000000000000000000000000", "00000000000000000000000000000000", "a866bc65b6941d86e8420a7ffb0964db", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffc000000000000000000000000000000000", "00000000000000000000000000000000", "8193c6ff85225ced4255e92f6e078a14", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffe000000000000000000000000000000000", "00000000000000000000000000000000", "9661cb2424d7d4a380d547f9e7ec1cb9", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffff000000000000000000000000000000000", "00000000000000000000000000000000", "86f93d9ec08453a071e2e2877877a9c8", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffff800000000000000000000000000000000", "00000000000000000000000000000000", "27eefa80ce6a4a9d598e3fec365434d2", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffc00000000000000000000000000000000", "00000000000000000000000000000000", "d62068444578e3ab39ce7ec95dd045dc", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffe00000000000000000000000000000000", "00000000000000000000000000000000", "b5f71d4dd9a71fe5d8bc8ba7e6ea3048", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffff00000000000000000000000000000000", "00000000000000000000000000000000", "6825a347ac479d4f9d95c5cb8d3fd7e9", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffff80000000000000000000000000000000", "00000000000000000000000000000000", "e3714e94a5778955cc0346358e94783a", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffc0000000000000000000000000000000", "00000000000000000000000000000000", "d836b44bb29e0c7d89fa4b2d4b677d2a", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffe0000000000000000000000000000000", "00000000000000000000000000000000", "5d454b75021d76d4b84f873a8f877b92", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffff0000000000000000000000000000000", "00000000000000000000000000000000", "c3498f7eced2095314fc28115885b33f", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffff8000000000000000000000000000000", "00000000000000000000000000000000", "6e668856539ad8e405bd123fe6c88530", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffc000000000000000000000000000000", "00000000000000000000000000000000", "8680db7f3a87b8605543cfdbe6754076", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffe000000000000000000000000000000", "00000000000000000000000000000000", "6c5d03b13069c3658b3179be91b0800c", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffff000000000000000000000000000000", "00000000000000000000000000000000", "ef1b384ac4d93eda00c92add0995ea5f", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffff800000000000000000000000000000", "00000000000000000000000000000000", "bf8115805471741bd5ad20a03944790f", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffc00000000000000000000000000000", "00000000000000000000000000000000", "c64c24b6894b038b3c0d09b1df068b0b", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffe00000000000000000000000000000", "00000000000000000000000000000000", "3967a10cffe27d0178545fbf6a40544b", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffff00000000000000000000000000000", "00000000000000000000000000000000", "7c85e9c95de1a9ec5a5363a8a053472d", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffff80000000000000000000000000000", "00000000000000000000000000000000", "a9eec03c8abec7ba68315c2c8c2316e0", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffc0000000000000000000000000000", "00000000000000000000000000000000", "cac8e414c2f388227ae14986fc983524", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffe0000000000000000000000000000", "00000000000000000000000000000000", "5d942b7f4622ce056c3ce3ce5f1dd9d6", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffff0000000000000000000000000000", "00000000000000000000000000000000", "d240d648ce21a3020282c3f1b528a0b6", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffff8000000000000000000000000000", "00000000000000000000000000000000", "45d089c36d5c5a4efc689e3b0de10dd5", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffc000000000000000000000000000", "00000000000000000000000000000000", "b4da5df4becb5462e03a0ed00d295629", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffe000000000000000000000000000", "00000000000000000000000000000000", "dcf4e129136c1a4b7a0f38935cc34b2b", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffff000000000000000000000000000", "00000000000000000000000000000000", "d9a4c7618b0ce48a3d5aee1a1c0114c4", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffff800000000000000000000000000", "00000000000000000000000000000000", "ca352df025c65c7b0bf306fbee0f36ba", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffc00000000000000000000000000", "00000000000000000000000000000000", "238aca23fd3409f38af63378ed2f5473", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffe00000000000000000000000000", "00000000000000000000000000000000", "59836a0e06a79691b36667d5380d8188", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffff00000000000000000000000000", "00000000000000000000000000000000", "33905080f7acf1cdae0a91fc3e85aee4", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffff80000000000000000000000000", "00000000000000000000000000000000", "72c9e4646dbc3d6320fc6689d93e8833", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffc0000000000000000000000000", "00000000000000000000000000000000", "ba77413dea5925b7f5417ea47ff19f59", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffe0000000000000000000000000", "00000000000000000000000000000000", "6cae8129f843d86dc786a0fb1a184970", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffff0000000000000000000000000", "00000000000000000000000000000000", "fcfefb534100796eebbd990206754e19", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffff8000000000000000000000000", "00000000000000000000000000000000", "8c791d5fdddf470da04f3e6dc4a5b5b5", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffc000000000000000000000000", "00000000000000000000000000000000", "c93bbdc07a4611ae4bb266ea5034a387", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffe000000000000000000000000", "00000000000000000000000000000000", "c102e38e489aa74762f3efc5bb23205a", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffff000000000000000000000000", "00000000000000000000000000000000", "93201481665cbafc1fcc220bc545fb3d", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffff800000000000000000000000", "00000000000000000000000000000000", "4960757ec6ce68cf195e454cfd0f32ca", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffc00000000000000000000000", "00000000000000000000000000000000", "feec7ce6a6cbd07c043416737f1bbb33", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffe00000000000000000000000", "00000000000000000000000000000000", "11c5413904487a805d70a8edd9c35527", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffff00000000000000000000000", "00000000000000000000000000000000", "347846b2b2e36f1f0324c86f7f1b98e2", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffff80000000000000000000000", "00000000000000000000000000000000", "332eee1a0cbd19ca2d69b426894044f0", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffc0000000000000000000000", "00000000000000000000000000000000", "866b5b3977ba6efa5128efbda9ff03cd", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffe0000000000000000000000", "00000000000000000000000000000000", "cc1445ee94c0f08cdee5c344ecd1e233", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffff0000000000000000000000", "00000000000000000000000000000000", "be288319029363c2622feba4b05dfdfe", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffff8000000000000000000000", "00000000000000000000000000000000", "cfd1875523f3cd21c395651e6ee15e56", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffc000000000000000000000", "00000000000000000000000000000000", "cb5a408657837c53bf16f9d8465dce19", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffe000000000000000000000", "00000000000000000000000000000000", "ca0bf42cb107f55ccff2fc09ee08ca15", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffff000000000000000000000", "00000000000000000000000000000000", "fdd9bbb4a7dc2e4a23536a5880a2db67", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffff800000000000000000000", "00000000000000000000000000000000", "ede447b362c484993dec9442a3b46aef", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffc00000000000000000000", "00000000000000000000000000000000", "10dffb05904bff7c4781df780ad26837", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffe00000000000000000000", "00000000000000000000000000000000", "c33bc13e8de88ac25232aa7496398783", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffff00000000000000000000", "00000000000000000000000000000000", "ca359c70803a3b2a3d542e8781dea975", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffff80000000000000000000", "00000000000000000000000000000000", "bcc65b526f88d05b89ce8a52021fdb06", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffc0000000000000000000", "00000000000000000000000000000000", "db91a38855c8c4643851fbfb358b0109", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffe0000000000000000000", "00000000000000000000000000000000", "ca6e8893a114ae8e27d5ab03a5499610", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffff0000000000000000000", "00000000000000000000000000000000", "6629d2b8df97da728cdd8b1e7f945077", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffff8000000000000000000", "00000000000000000000000000000000", "4570a5a18cfc0dd582f1d88d5c9a1720", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffc000000000000000000", "00000000000000000000000000000000", "72bc65aa8e89562e3f274d45af1cd10b", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffe000000000000000000", "00000000000000000000000000000000", "98551da1a6503276ae1c77625f9ea615", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffff000000000000000000", "00000000000000000000000000000000", "0ddfe51ced7e3f4ae927daa3fe452cee", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffff800000000000000000", "00000000000000000000000000000000", "db826251e4ce384b80218b0e1da1dd4c", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffc00000000000000000", "00000000000000000000000000000000", "2cacf728b88abbad7011ed0e64a1680c", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffe00000000000000000", "00000000000000000000000000000000", "330d8ee7c5677e099ac74c9994ee4cfb", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffff00000000000000000", "00000000000000000000000000000000", "edf61ae362e882ddc0167474a7a77f3a", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffff80000000000000000", "00000000000000000000000000000000", "6168b00ba7859e0970ecfd757efecf7c", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffc0000000000000000", "00000000000000000000000000000000", "d1415447866230d28bb1ea18a4cdfd02", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffe0000000000000000", "00000000000000000000000000000000", "516183392f7a8763afec68a060264141", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000", "00000000000000000000000000000000", "77565c8d73cfd4130b4aa14d8911710f", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffff8000000000000000", "00000000000000000000000000000000", "37232a4ed21ccc27c19c9610078cabac", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffc000000000000000", "00000000000000000000000000000000", "804f32ea71828c7d329077e712231666", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffe000000000000000", "00000000000000000000000000000000", "d64424f23cb97215e9c2c6f28d29eab7", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000", "00000000000000000000000000000000", "023e82b533f68c75c238cebdb2ee89a2", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffff800000000000000", "00000000000000000000000000000000", "193a3d24157a51f1ee0893f6777417e7", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffc00000000000000", "00000000000000000000000000000000", "84ecacfcd400084d078612b1945f2ef5", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffe00000000000000", "00000000000000000000000000000000", "1dcd8bb173259eb33a5242b0de31a455", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000", "00000000000000000000000000000000", "35e9eddbc375e792c19992c19165012b", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000", "00000000000000000000000000000000", "8a772231c01dfdd7c98e4cfddcc0807a", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffc0000000000000", "00000000000000000000000000000000", "6eda7ff6b8319180ff0d6e65629d01c3", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffe0000000000000", "00000000000000000000000000000000", "c267ef0e2d01a993944dd397101413cb", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000", "00000000000000000000000000000000", "e9f80e9d845bcc0f62926af72eabca39", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffff8000000000000", "00000000000000000000000000000000", "6702990727aa0878637b45dcd3a3b074", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffc000000000000", "00000000000000000000000000000000", "2e2e647d5360e09230a5d738ca33471e", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffe000000000000", "00000000000000000000000000000000", "1f56413c7add6f43d1d56e4f02190330", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000", "00000000000000000000000000000000", "69cd0606e15af729d6bca143016d9842", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffff800000000000", "00000000000000000000000000000000", "a085d7c1a500873a20099c4caa3c3f5b", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffc00000000000", "00000000000000000000000000000000", "4fc0d230f8891415b87b83f95f2e09d1", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffe00000000000", "00000000000000000000000000000000", "4327d08c523d8eba697a4336507d1f42", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000", "00000000000000000000000000000000", "7a15aab82701efa5ae36ab1d6b76290f", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000", "00000000000000000000000000000000", "5bf0051893a18bb30e139a58fed0fa54", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffc0000000000", "00000000000000000000000000000000", "97e8adf65638fd9cdf3bc22c17fe4dbd", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffe0000000000", "00000000000000000000000000000000", "1ee6ee326583a0586491c96418d1a35d", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000", "00000000000000000000000000000000", "26b549c2ec756f82ecc48008e529956b", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffff8000000000", "00000000000000000000000000000000", "70377b6da669b072129e057cc28e9ca5", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffc000000000", "00000000000000000000000000000000", "9c94b8b0cb8bcc919072262b3fa05ad9", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffe000000000", "00000000000000000000000000000000", "2fbb83dfd0d7abcb05cd28cad2dfb523", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000", "00000000000000000000000000000000", "96877803de77744bb970d0a91f4debae", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffff800000000", "00000000000000000000000000000000", "7379f3370cf6e5ce12ae5969c8eea312", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffc00000000", "00000000000000000000000000000000", "02dc99fa3d4f98ce80985e7233889313", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffe00000000", "00000000000000000000000000000000", "1e38e759075ba5cab6457da51844295a", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000", "00000000000000000000000000000000", "70bed8dbf615868a1f9d9b05d3e7a267", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000", "00000000000000000000000000000000", "234b148b8cb1d8c32b287e896903d150", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0000000", "00000000000000000000000000000000", "294b033df4da853f4be3e243f7e513f4", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0000000", "00000000000000000000000000000000", "3f58c950f0367160adec45f2441e7411", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000", "00000000000000000000000000000000", "37f655536a704e5ace182d742a820cf4", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffff8000000", "00000000000000000000000000000000", "ea7bd6bb63418731aeac790fe42d61e8", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffc000000", "00000000000000000000000000000000", "e74a4c999b4c064e48bb1e413f51e5ea", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffe000000", "00000000000000000000000000000000", "ba9ebefdb4ccf30f296cecb3bc1943e8", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000", "00000000000000000000000000000000", "3194367a4898c502c13bb7478640a72d", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff800000", "00000000000000000000000000000000", "da797713263d6f33a5478a65ef60d412", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00000", "00000000000000000000000000000000", "d1ac39bb1ef86b9c1344f214679aa376", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00000", "00000000000000000000000000000000", "2fdea9e650532be5bc0e7325337fd363", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000", "00000000000000000000000000000000", "d3a204dbd9c2af158b6ca67a5156ce4a", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000", "00000000000000000000000000000000", "3a0a0e75a8da36735aee6684d965a778", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0000", "00000000000000000000000000000000", "52fc3e620492ea99641ea168da5b6d52", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0000", "00000000000000000000000000000000", "d2e0c7f15b4772467d2cfc873000b2ca", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000", "00000000000000000000000000000000", "563531135e0c4d70a38f8bdb190ba04e", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8000", "00000000000000000000000000000000", "a8a39a0f5663f4c0fe5f2d3cafff421a", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc000", "00000000000000000000000000000000", "d94b5e90db354c1e42f61fabe167b2c0", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe000", "00000000000000000000000000000000", "50e6d3c9b6698a7cd276f96b1473f35a", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000", "00000000000000000000000000000000", "9338f08e0ebee96905d8f2e825208f43", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff800", "00000000000000000000000000000000", "8b378c86672aa54a3a266ba19d2580ca", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00", "00000000000000000000000000000000", "cca7c3086f5f9511b31233da7cab9160", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00", "00000000000000000000000000000000", "5b40ff4ec9be536ba23035fa4f06064c", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00", "00000000000000000000000000000000", "60eb5af8416b257149372194e8b88749", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80", "00000000000000000000000000000000", "2f005a8aed8a361c92e440c15520cbd1", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0", "00000000000000000000000000000000", "7b03627611678a997717578807a800e2", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0", "00000000000000000000000000000000", "cf78618f74f6f3696e0a4779b90b5a77", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", "00000000000000000000000000000000", "03720371a04962eaea0a852e69972858", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8", "00000000000000000000000000000000", "1f8a8133aa8ccf70e2bd3285831ca6b7", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc", "00000000000000000000000000000000", "27936bd27fb1468fc8b48bc483321725", "00000000000000000000000000000000"}, + {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", "00000000000000000000000000000000", "b07d4f3e2cd2ef2eb545980754dfea0f", "00000000000000000000000000000000"}, + {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "00000000000000000000000000000000", "4bf85f1b5d54adbc307b0a048389adcb", "00000000000000000000000000000000"}, +}; + +void test_aes() +{ + /* TODO: add more NIST test vectors (non CBC / 128) */ + uint8_t key_bin[128], iv_bin[128], plaintext_bin[65], ciphertext_bin[64], plaintext_bin_check[64]; + + unsigned int i; + for (i = 0; i < (sizeof(nist_aes_test_vectors_encrypt) / sizeof(nist_aes_test_vectors_encrypt[0])); i++) { + + struct nist_aes_test_vector tv = nist_aes_test_vectors_encrypt[i]; + + int outlen_key; + utils_hex_to_bin(tv.key, key_bin, strlen(tv.key), &outlen_key); + + int outlen_iv; + utils_hex_to_bin(tv.iv, iv_bin, strlen(tv.iv), &outlen_iv); + + int outlen_plaintext; + utils_hex_to_bin(tv.in, plaintext_bin, strlen(tv.in), &outlen_plaintext); + + int outlen_cipthertext; + utils_hex_to_bin(tv.out, ciphertext_bin, strlen(tv.out), &outlen_cipthertext); + + aes256_cbc_encrypt(key_bin, iv_bin, plaintext_bin, outlen_plaintext, 1, ciphertext_bin); + aes256_cbc_decrypt(key_bin, iv_bin, ciphertext_bin, outlen_plaintext, 1, plaintext_bin_check); + u_assert_mem_eq(plaintext_bin_check, plaintext_bin, outlen_plaintext); + + char hexout[128]; + utils_bin_to_hex(ciphertext_bin, outlen_cipthertext, hexout); + + u_assert_str_eq(tv.out, hexout); + } + + for (i = 0; i < (sizeof(nist_aes_test_vectors_decrypt) / sizeof(nist_aes_test_vectors_decrypt[0])); i++) { + + struct nist_aes_test_vector tv = nist_aes_test_vectors_decrypt[i]; + + int outlen_key; + utils_hex_to_bin(tv.key, key_bin, strlen(tv.key), &outlen_key); + + int outlen_iv; + utils_hex_to_bin(tv.iv, iv_bin, strlen(tv.iv), &outlen_iv); + + int outlen_plaintext; + utils_hex_to_bin(tv.in, plaintext_bin, strlen(tv.in), &outlen_plaintext); + + int outlen_cipthertext; + utils_hex_to_bin(tv.out, ciphertext_bin, strlen(tv.out), &outlen_cipthertext); + + aes256_cbc_decrypt(key_bin, iv_bin, plaintext_bin, outlen_plaintext, 1, ciphertext_bin); + aes256_cbc_encrypt(key_bin, iv_bin, ciphertext_bin, outlen_plaintext, 1, plaintext_bin_check); + u_assert_mem_eq(plaintext_bin_check, plaintext_bin, outlen_plaintext); + + char hexout[128]; + utils_bin_to_hex(ciphertext_bin, outlen_cipthertext, hexout); + + u_assert_str_eq(tv.out, hexout); + } +} diff --git a/test/base58check_tests.c b/test/base58check_tests.c new file mode 100644 index 000000000..57d4da999 --- /dev/null +++ b/test/base58check_tests.c @@ -0,0 +1,174 @@ +/********************************************************************** + * Copyright (c) 2015 Jonas Schnelli / Douglas J. Bakkum * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include +#include +#include + +#include +#include + +/* test vectors from bitcoin core */ +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, +}; + +static const char* base58_invalid_vector[] = { + "dc", + "3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G", + "ec", + "055ece0cadddc415b1980f001785947120acdb36fc055ece0cadddc415b1980f001785947120acdb36fc055ece0cadddc415b1980f001785947120acdb36fc055ece0cadddc415b1980f001785947120acdb36fc055ece0cadddc415b1980f001785947120acdb36fc055ece0cadddc415b1980f001785947120acdb36fc055ece0cadddc415b1980f001785947120acdb36fc055ece0cadddc415b1980f001785947120acdb36fc", + "dc", + "", + "dc", + "9ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G", + 0, + 0}; + +void test_base58check() +{ + const char** raw = base58_vector; + const char** str = base58_vector + 1; + uint8_t rawn[96]; + char strn[53]; + while (*raw && *str) { + size_t len = strlen(*raw) / 2; + + memcpy(rawn, utils_hex_to_uint8(*raw), len); + int r = btc_base58_encode_check(rawn, len, strn, sizeof(strn)); + assert(r == (int)strlen(*str) + 1); + assert(strcmp(strn, *str) == 0); + + r = btc_base58_decode_check(strn, rawn, sizeof(rawn)); + assert(r == (int)len + 4); + + raw += 2; + str += 2; + } + + const char** i_cmd = base58_invalid_vector; + const char** i_raw = base58_invalid_vector + 1; + uint8_t i_rawn[2048]; + while (*i_raw && *i_cmd) { + size_t len = strlen(*i_raw) / 2; + + memcpy(i_rawn, utils_hex_to_uint8(*i_raw), len); + + unsigned char outbuf[1024]; + + int r = 0; + if (strncmp(*i_cmd, "ec", 2) == 0) + r = btc_base58_encode_check(i_rawn, len, strn, sizeof(strn)); + else + r = btc_base58_decode_check(*i_raw, outbuf, sizeof(outbuf)); + + assert(r == 0); + i_raw += 2; + i_cmd += 2; + } +} diff --git a/test/bip32_tests.c b/test/bip32_tests.c new file mode 100644 index 000000000..016c3c252 --- /dev/null +++ b/test/bip32_tests.c @@ -0,0 +1,249 @@ +/********************************************************************** + * Copyright (c) 2015 Jonas Schnelli * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include + +#include "utest.h" +#include + +void test_bip32() +{ + btc_hdnode node, node2, node3, node4; + char str[112]; + int r; + uint8_t private_key_master[32]; + uint8_t chain_code_master[32]; + + /* init m */ + btc_hdnode_from_seed(utils_hex_to_uint8("000102030405060708090a0b0c0d0e0f"), 16, &node); + + /* [Chain m] */ + memcpy(private_key_master, + utils_hex_to_uint8("e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35"), + 32); + memcpy(chain_code_master, + utils_hex_to_uint8("873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508"), + 32); + u_assert_int_eq(node.fingerprint, 0x00000000); + u_assert_mem_eq(node.chain_code, chain_code_master, 32); + u_assert_mem_eq(node.private_key, private_key_master, 32); + u_assert_mem_eq(node.public_key, + utils_hex_to_uint8("0339a36013301597daef41fbe593a02cc513d0b55527ec2df1050e2e8ff49c85c2"), + 33); + btc_hdnode_serialize_private(&node, &btc_chainparams_main, str, sizeof(str)); + u_assert_str_eq(str, + "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"); + r = btc_hdnode_deserialize(str, &btc_chainparams_main, &node2); + u_assert_int_eq(r, true); + u_assert_mem_eq(&node, &node2, sizeof(btc_hdnode)); + + btc_hdnode_get_p2pkh_address(&node, &btc_chainparams_main, str, sizeof(str)); + u_assert_str_eq(str, "15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma"); + + btc_hdnode_serialize_public(&node, &btc_chainparams_main, str, sizeof(str)); + u_assert_str_eq(str, + "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"); + r = btc_hdnode_deserialize(str, &btc_chainparams_main, &node2); + u_assert_int_eq(r, true); + memcpy(&node3, &node, sizeof(btc_hdnode)); + memset(&node3.private_key, 0, 32); + u_assert_mem_eq(&node2, &node3, sizeof(btc_hdnode)); + + + /* [Chain m/0'] */ + char path0[] = "m/0'"; + btc_hd_generate_key(&node, path0, private_key_master, chain_code_master, false); + u_assert_int_eq(node.fingerprint, 0x3442193e); + u_assert_mem_eq(node.chain_code, + utils_hex_to_uint8("47fdacbd0f1097043b78c63c20c34ef4ed9a111d980047ad16282c7ae6236141"), + 32); + u_assert_mem_eq(node.private_key, + utils_hex_to_uint8("edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea"), + 32); + u_assert_mem_eq(node.public_key, + utils_hex_to_uint8("035a784662a4a20a65bf6aab9ae98a6c068a81c52e4b032c0fb5400c706cfccc56"), + 33); + btc_hdnode_serialize_private(&node, &btc_chainparams_main, str, sizeof(str)); + u_assert_str_eq(str, + "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7"); + r = btc_hdnode_deserialize(str, &btc_chainparams_main, &node2); + u_assert_int_eq(r, true); + u_assert_mem_eq(&node, &node2, sizeof(btc_hdnode)); + + btc_hdnode_get_p2pkh_address(&node, &btc_chainparams_main, str, sizeof(str)); + u_assert_str_eq(str, "19Q2WoS5hSS6T8GjhK8KZLMgmWaq4neXrh"); + + btc_hdnode_serialize_public(&node, &btc_chainparams_main, str, sizeof(str)); + u_assert_str_eq(str, + "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"); + r = btc_hdnode_deserialize(str, &btc_chainparams_main, &node2); + u_assert_int_eq(r, true); + memcpy(&node3, &node, sizeof(btc_hdnode)); + memset(&node3.private_key, 0, 32); + u_assert_mem_eq(&node2, &node3, sizeof(btc_hdnode)); + + + /* [Chain m/0'/1] */ + char path1[] = "m/0'/1"; + btc_hd_generate_key(&node, path1, private_key_master, chain_code_master, false); + u_assert_int_eq(node.fingerprint, 0x5c1bd648); + u_assert_mem_eq(node.chain_code, + utils_hex_to_uint8("2a7857631386ba23dacac34180dd1983734e444fdbf774041578e9b6adb37c19"), + 32); + u_assert_mem_eq(node.private_key, + utils_hex_to_uint8("3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368"), + 32); + u_assert_mem_eq(node.public_key, + utils_hex_to_uint8("03501e454bf00751f24b1b489aa925215d66af2234e3891c3b21a52bedb3cd711c"), + 33); + btc_hdnode_serialize_private(&node, &btc_chainparams_main, str, sizeof(str)); + u_assert_str_eq(str, + "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs"); + r = btc_hdnode_deserialize(str, &btc_chainparams_main, &node2); + u_assert_int_eq(r, true); + u_assert_mem_eq(&node, &node2, sizeof(btc_hdnode)); + btc_hdnode_get_p2pkh_address(&node, &btc_chainparams_main, str, sizeof(str)); + u_assert_str_eq(str, "1JQheacLPdM5ySCkrZkV66G2ApAXe1mqLj"); + btc_hdnode_serialize_public(&node, &btc_chainparams_main, str, sizeof(str)); + u_assert_str_eq(str, + "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"); + r = btc_hdnode_deserialize(str, &btc_chainparams_main, &node2); + u_assert_int_eq(r, true); + memcpy(&node3, &node, sizeof(btc_hdnode)); + memset(&node3.private_key, 0, 32); + u_assert_mem_eq(&node2, &node3, sizeof(btc_hdnode)); + + /* [Chain m/0'/1/2'] */ + char path2[] = "m/0'/1/2'"; + btc_hd_generate_key(&node, path2, private_key_master, chain_code_master, false); + u_assert_int_eq(node.fingerprint, 0xbef5a2f9); + u_assert_mem_eq(node.chain_code, + utils_hex_to_uint8("04466b9cc8e161e966409ca52986c584f07e9dc81f735db683c3ff6ec7b1503f"), + 32); + u_assert_mem_eq(node.private_key, + utils_hex_to_uint8("cbce0d719ecf7431d88e6a89fa1483e02e35092af60c042b1df2ff59fa424dca"), + 32); + u_assert_mem_eq(node.public_key, + utils_hex_to_uint8("0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2"), + 33); + btc_hdnode_serialize_private(&node, &btc_chainparams_main, str, sizeof(str)); + u_assert_str_eq(str, + "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM"); + r = btc_hdnode_deserialize(str, &btc_chainparams_main, &node2); + u_assert_int_eq(r, true); + u_assert_mem_eq(&node, &node2, sizeof(btc_hdnode)); + btc_hdnode_get_p2pkh_address(&node, &btc_chainparams_main, str, sizeof(str)); + u_assert_str_eq(str, "1NjxqbA9aZWnh17q1UW3rB4EPu79wDXj7x"); + btc_hdnode_serialize_public(&node, &btc_chainparams_main, str, sizeof(str)); + u_assert_str_eq(str, + "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"); + r = btc_hdnode_deserialize(str, &btc_chainparams_main, &node2); + u_assert_int_eq(r, true); + memcpy(&node3, &node, sizeof(btc_hdnode)); + memset(&node3.private_key, 0, 32); + u_assert_mem_eq(&node2, &node3, sizeof(btc_hdnode)); + + /* [Chain m/0'/1/2'/2] */ + char path3[] = "m/0'/1/2'/2"; + btc_hd_generate_key(&node, path3, private_key_master, chain_code_master, false); + u_assert_int_eq(node.fingerprint, 0xee7ab90c); + u_assert_mem_eq(node.chain_code, + utils_hex_to_uint8("cfb71883f01676f587d023cc53a35bc7f88f724b1f8c2892ac1275ac822a3edd"), + 32); + u_assert_mem_eq(node.private_key, + utils_hex_to_uint8("0f479245fb19a38a1954c5c7c0ebab2f9bdfd96a17563ef28a6a4b1a2a764ef4"), + 32); + u_assert_mem_eq(node.public_key, + utils_hex_to_uint8("02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29"), + 33); + btc_hdnode_serialize_private(&node, &btc_chainparams_main, str, sizeof(str)); + u_assert_str_eq(str, + "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334"); + r = btc_hdnode_deserialize(str, &btc_chainparams_main, &node2); + u_assert_int_eq(r, true); + u_assert_mem_eq(&node, &node2, sizeof(btc_hdnode)); + btc_hdnode_get_p2pkh_address(&node, &btc_chainparams_main, str, sizeof(str)); + u_assert_str_eq(str, "1LjmJcdPnDHhNTUgrWyhLGnRDKxQjoxAgt"); + btc_hdnode_serialize_public(&node, &btc_chainparams_main, str, sizeof(str)); + u_assert_str_eq(str, + "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"); + r = btc_hdnode_deserialize(str, &btc_chainparams_main, &node2); + u_assert_int_eq(r, true); + memcpy(&node3, &node, sizeof(btc_hdnode)); + memset(&node3.private_key, 0, 32); + u_assert_mem_eq(&node2, &node3, sizeof(btc_hdnode)); + + /* [Chain m/0'/1/2'/2/1000000000] */ + char path4[] = "m/0'/1/2'/2/1000000000"; + btc_hd_generate_key(&node, path4, private_key_master, chain_code_master, false); + u_assert_int_eq(node.fingerprint, 0xd880d7d8); + u_assert_mem_eq(node.chain_code, + utils_hex_to_uint8("c783e67b921d2beb8f6b389cc646d7263b4145701dadd2161548a8b078e65e9e"), + 32); + u_assert_mem_eq(node.private_key, + utils_hex_to_uint8("471b76e389e528d6de6d816857e012c5455051cad6660850e58372a6c3e6e7c8"), + 32); + u_assert_mem_eq(node.public_key, + utils_hex_to_uint8("022a471424da5e657499d1ff51cb43c47481a03b1e77f951fe64cec9f5a48f7011"), + 33); + btc_hdnode_serialize_private(&node, &btc_chainparams_main, str, sizeof(str)); + u_assert_str_eq(str, "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76"); + r = btc_hdnode_deserialize(str, &btc_chainparams_main, &node2); + u_assert_int_eq(r, true); + u_assert_mem_eq(&node, &node2, sizeof(btc_hdnode)); + btc_hdnode_get_p2pkh_address(&node, &btc_chainparams_main, str, sizeof(str)); + u_assert_str_eq(str, "1LZiqrop2HGR4qrH1ULZPyBpU6AUP49Uam"); + btc_hdnode_serialize_public(&node, &btc_chainparams_main, str, sizeof(str)); + u_assert_str_eq(str, + "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy"); + r = btc_hdnode_deserialize(str, &btc_chainparams_main, &node2); + u_assert_int_eq(r, true); + memcpy(&node3, &node, sizeof(btc_hdnode)); + memset(&node3.private_key, 0, 32); + u_assert_mem_eq(&node2, &node3, sizeof(btc_hdnode)); + + + char str_pub_ckd[] = "xpub6LTiQPFh8tFrK56BQXuYcyam39cTXsBvudjQ7NM4EyRABPKapbm9dNe7aYQ6VNDzYHmhZYde5Pv8a6vTeQcfG3g1s7S8g1otXsK8d4qGyLs"; + + r = btc_hdnode_deserialize(str_pub_ckd, &btc_chainparams_main, &node4); + r = btc_hdnode_public_ckd(&node4, 123); + u_assert_int_eq(r, true); + btc_hdnode_serialize_public(&node4, &btc_chainparams_main, str, sizeof(str)); + u_assert_str_eq(str, "xpub6Mf5jT2qB3v8YP8frMBbgQ9L79UF6zXzdYbUSAwzezhEQep8w3GfBrbFGquW7T4PQXvmRh8DFEJFbm6qgsJXmT4FjNgrJL2m6YuKJRbsgUa"); + + + r = btc_hdnode_public_ckd(&node4, 0x80000000 + 1); //try deriving a hardened key (= must fail) + u_assert_int_eq(r, false); + + + char str_pub_ckd_tn[] = "tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK"; + + r = btc_hdnode_deserialize(str_pub_ckd_tn, &btc_chainparams_test, &node4); + r = btc_hdnode_public_ckd(&node4, 123); + u_assert_int_eq(r, true); + btc_hdnode_get_p2pkh_address(&node4, &btc_chainparams_test, str, sizeof(str)); + u_assert_str_eq(str, "mp4VkLBrnetj5LkhyNqtgkBzJwRBqhTbaa"); + size_t size = sizeof(str); + size_t sizeSmall = 55; + r = btc_hdnode_get_pub_hex(&node4, str, &sizeSmall); + u_assert_int_eq(r, false); + r = btc_hdnode_get_pub_hex(&node4, str, &size); + u_assert_int_eq(size, 66); + u_assert_int_eq(r, true); + u_assert_str_eq(str, "0391a9964e79f39cebf9b59eb2151b500bd462e589682d6ceebe8e15970bfebf8b"); + btc_hdnode_serialize_public(&node4, &btc_chainparams_test, str, sizeof(str)); + u_assert_str_eq(str, "tpubD8MQJFN9LVzG8pktwoQ7ApWWKLfUUhonQkeXe8gqi9tFMtMdC34g6Ntj5K6V1hdzR3to2z7dGnQbXaoZSsFkVky7TFWZjmC9Ez4Gog6ujaD"); + + btc_hdnode *nodeheap; + nodeheap = btc_hdnode_new(); + btc_hdnode *nodeheap_copy = btc_hdnode_copy(nodeheap); + + u_assert_int_eq(memcmp(nodeheap->private_key, nodeheap_copy->private_key, 32), 0); + u_assert_int_eq(memcmp(nodeheap->public_key, nodeheap_copy->public_key, 33), 0) + + btc_hdnode_free(nodeheap); + btc_hdnode_free(nodeheap_copy); +} diff --git a/test/block_tests.c b/test/block_tests.c new file mode 100644 index 000000000..7d43ffc6e --- /dev/null +++ b/test/block_tests.c @@ -0,0 +1,153 @@ +/********************************************************************** + * Copyright (c) 2015 Jonas Schnelli * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "utest.h" + +struct blockheadertest { + char hexheader[160]; + char hexhash[64]; + int32_t version; + uint32_t timestamp; + uint32_t bits; + uint32_t nonce; +}; + +static const struct blockheadertest block_header_tests[] = + { + {"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c", "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", 1, 1231006505, 486604799, 2083236893}, + {"04000000db716ecedcc0eabee8f8a333aeaca8d020c10b7d6c851baf1f97442d68397d6e376353ed67b819ae38f8e821a8f3bc51f28e57973e11ceff0191353a07b68285fac6ca56ffff7f2002000000", "0eba32fd89d25ff24ae4eb9c9f7dccd5032cbbaa5fedfd06c9d5b75e5edb7f2f", 4, 1456129786, 545259519, 2} + }; + +void test_block_header() +{ + int outlen; + char hexbuf[161]; + unsigned int i; + for (i = 0; i < (sizeof(block_header_tests) / sizeof(block_header_tests[0])); i++) { + cstring* serialized = cstr_new_sz(80); + const struct blockheadertest* test = &block_header_tests[i]; + uint8_t header_data[80]; + uint256 hash_data; + + utils_hex_to_bin(test->hexheader, header_data, 160, &outlen); + utils_hex_to_bin(test->hexhash, hash_data, sizeof(hash_data), &outlen); + + btc_block_header* header = btc_block_header_new(); + struct const_buffer buf = {header_data, 80}; + btc_block_header_deserialize(header, &buf); + + // Check the copies are the same + btc_block_header* header_copy = btc_block_header_new(); + btc_block_header_copy(header_copy, header); + assert(memcmp(header_copy, header, sizeof(*header_copy)) == 0); + + // Check the serialized form matches + btc_block_header_serialize(serialized, header); + utils_bin_to_hex((unsigned char*) serialized->str, serialized->len, hexbuf); + assert(memcmp(hexbuf, test->hexheader, 160) == 0); + + // Check the block hash + uint256 blockhash; + btc_block_header_hash(header, blockhash); + + utils_bin_to_hex(blockhash, BTC_HASH_LENGTH, hexbuf); + utils_reverse_hex(hexbuf, BTC_HASH_LENGTH*2); + assert(memcmp(hexbuf, test->hexhash, BTC_HASH_LENGTH*2) == 0); + + // Check version, ts, bits, nonce + assert(header->version == test->version); + assert(header->timestamp == test->timestamp); + assert(header->bits == test->bits); + assert(header->nonce == test->nonce); + + btc_block_header_free(header); + btc_block_header_free(header_copy); + cstr_free(serialized, true); + } + + + /* blockheader */ + btc_block_header bheader, bheaderprev, bheadercheck; + bheader.version = 536870912; + bheader.timestamp = 1472802860; + bheader.nonce = 2945279651; + bheader.bits = 402979592; + char *prevblock_hex_o = "00000000000000000098ad436f0c305b4d577e40e2687783822a2fe6637dc8e5"; + char *prevblock_hex = btc_malloc(strlen(prevblock_hex_o)+1); + memcpy(prevblock_hex, prevblock_hex_o, strlen(prevblock_hex_o)); + utils_reverse_hex(prevblock_hex, 64); + outlen = 0; + utils_hex_to_bin(prevblock_hex, bheader.prev_block, 64, &outlen); + btc_free(prevblock_hex); + + char *merkleroot_hex_o = "d4690e152bb72a3dc2a2a90f3f1e8afc3b48a26a070f2b099b46a439c69eb776"; + char *merkleroot_hex = btc_malloc(strlen(merkleroot_hex_o)+1); + memcpy(merkleroot_hex, merkleroot_hex_o, strlen(merkleroot_hex_o)); + utils_reverse_hex(merkleroot_hex, 64); + outlen = 0; + utils_hex_to_bin(merkleroot_hex, bheader.merkle_root, 64, &outlen); + btc_free(merkleroot_hex); + + bheaderprev.version = 536870912; + bheaderprev.timestamp = 1472802636; + bheaderprev.nonce = 3627526227; + bheaderprev.bits = 402979592; + + prevblock_hex_o = "000000000000000001beee80fe573d34a51b48f30248a8933dc71b67db9f542d"; + prevblock_hex = btc_malloc(strlen(prevblock_hex_o)+1); + memcpy(prevblock_hex, prevblock_hex_o, strlen(prevblock_hex_o)); + utils_reverse_hex(prevblock_hex, 64); + outlen = 0; + utils_hex_to_bin(prevblock_hex, bheaderprev.prev_block, 64, &outlen); + btc_free(prevblock_hex); + + merkleroot_hex_o = "3696737d03075235b3874ed2ec6e93555e3259f818f53f3c241a2ae74f18ab07"; + merkleroot_hex = btc_malloc(strlen(merkleroot_hex_o)+1); + memcpy(merkleroot_hex, merkleroot_hex_o, strlen(merkleroot_hex_o)); + utils_reverse_hex(merkleroot_hex, 64); + outlen = 0; + utils_hex_to_bin(merkleroot_hex, bheaderprev.merkle_root, 64, &outlen); + btc_free(merkleroot_hex); + + /* compare blockheaderhex */ + cstring *blockheader_ser = cstr_new_sz(256); + btc_block_header_serialize(blockheader_ser, &bheader); + char *blockheader_h427928 = "00000020e5c87d63e62f2a82837768e2407e574d5b300c6f43ad9800000000000000000076b79ec639a4469b092b0f076aa2483bfc8a1e3f0fa9a2c23d2ab72b150e69d42c30c95708fb0418a3668daf"; + char *blockheader_hash_h427928 = "00000000000000000127d7e285f5d9ad281d236353d73a176a56f7dab499b5b6"; + + char headercheck[1024]; + utils_bin_to_hex((unsigned char *)blockheader_ser->str, blockheader_ser->len, headercheck); + u_assert_str_eq(headercheck, blockheader_h427928); + + uint256 checkhash; + btc_block_header_hash(&bheader, (uint8_t *)&checkhash); + char hashhex[sizeof(checkhash)*2]; + utils_bin_to_hex(checkhash, sizeof(checkhash), hashhex); + utils_reverse_hex(hashhex, strlen(hashhex)); + u_assert_str_eq(blockheader_hash_h427928, hashhex); + + struct const_buffer buf; + buf.p = blockheader_ser->str; + buf.len = blockheader_ser->len; + btc_block_header_deserialize(&bheadercheck, &buf); + u_assert_mem_eq(&bheader, &bheadercheck, sizeof(bheadercheck)); + cstr_free(blockheader_ser, true); + + + btc_block_header_hash(&bheaderprev, (uint8_t *)&checkhash); + u_assert_mem_eq(&checkhash, &bheader.prev_block, sizeof(checkhash)); +} diff --git a/test/buffer_tests.c b/test/buffer_tests.c new file mode 100644 index 000000000..1b26a6587 --- /dev/null +++ b/test/buffer_tests.c @@ -0,0 +1,26 @@ +/********************************************************************** + * Copyright (c) 2015 Jonas Schnelli * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include +#include +#include "limits.h" + +#include + +void test_buffer() +{ + struct const_buffer buf0 = {"data", 4}; + struct const_buffer buf0a= {"data1", 5}; + struct const_buffer buf1 = {"data", 4}; + struct buffer* buf2; + + assert(buffer_equal(&buf0, &buf1) == 1); + assert(buffer_equal(&buf0, &buf0a) == 0); + + buf2 = buffer_copy(&buf0.p, buf0.len); + buffer_free(buf2); +} diff --git a/test/cstr_tests.c b/test/cstr_tests.c new file mode 100644 index 000000000..4648e8def --- /dev/null +++ b/test/cstr_tests.c @@ -0,0 +1,94 @@ +/********************************************************************** + * Copyright (c) Copyright 2015 BitPay, Inc. * + * Copyright (c) Copyright 2015 Jonas Schnelli * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include +#include +#include + +#include + +void test_cstr() +{ + cstring* s1 = cstr_new("foo"); + cstring* s2 = cstr_new("foo"); + cstring* s3 = cstr_new("bar"); + cstring* s4 = cstr_new("bar1"); + + cstring* s = cstr_new("foo"); + assert(s != NULL); + assert(s->len == 3); + assert(strcmp(s->str, "foo") == 0); + + cstr_free(s, true); + + s = cstr_new_sz(200); + assert(s != NULL); + assert(s->alloc > 200); + assert(s->len == 0); + + cstr_free(s, true); + + s = cstr_new_buf("foo", 2); + assert(s != NULL); + assert(s->len == 2); + assert(strcmp(s->str, "fo") == 0); + + cstr_free(s, true); + + s = cstr_new(NULL); + assert(s != NULL); + cstr_append_buf(s, "f", 1); + cstr_append_buf(s, "o", 1); + cstr_append_buf(s, "o", 1); + assert(s->len == 3); + assert(strcmp(s->str, "foo") == 0); + + cstr_free(s, true); + + s = cstr_new("foo"); + assert(s != NULL); + + cstr_resize(s, 2); + cstr_resize(s, 2); + cstr_alloc_minsize(s, 2); + cstr_alloc_minsize(s, 1); + + assert(s->len == 2); + assert(strcmp(s->str, "fo") == 0); + + cstr_resize(s, 4); + assert(s->len == 4); + assert(s->alloc > 4); + memcpy(s->str, "food", 4); + assert(strcmp(s->str, "food") == 0); + + cstr_free(s, true); + + assert(cstr_compare(s1, s2) == 0); + assert(cstr_compare(s1, s3) == 1); + assert(cstr_compare(s3, s1) == -1); + assert(cstr_compare(s3, s4) == -1); + assert(cstr_compare(s4, s3) == 1); + + assert(cstr_equal(s1, s2) == true); + assert(cstr_equal(s1, s3) == false); + assert(cstr_equal(s1, NULL) == false); + assert(cstr_equal(s2, s3) == false); + assert(cstr_equal(s3, s3) == true); + assert(cstr_equal(s3, s4) == false); + cstr_erase(s4, 0, 3); + cstr_erase(s4, 110, 3); + cstr_erase(s4, s4->len, 0); + cstr_erase(s4, 0, 100); + assert(strcmp(s4->str, "1") == 0); + + cstr_free(s1, true); + cstr_free(s2, true); + cstr_free(s3, true); + cstr_free(s4, true); +} diff --git a/test/ecc_tests.c b/test/ecc_tests.c new file mode 100644 index 000000000..cfe9f5283 --- /dev/null +++ b/test/ecc_tests.c @@ -0,0 +1,64 @@ +/********************************************************************** + * Copyright (c) 2015 Jonas Schnelli * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "utest.h" +#include + +void test_ecc() +{ + unsigned char r_buf[32]; + memset(r_buf, 0, 32); + btc_random_init(); + + while (btc_ecc_verify_privatekey(r_buf) == 0) { + u_assert_int_eq(btc_random_bytes(r_buf, 32, 0), true); + } + + memset(r_buf, 0xFF, 32); + u_assert_int_eq(btc_ecc_verify_privatekey(r_buf), 0); //secp256k1 overflow + + uint8_t pub_key33[33], pub_key33_invalid[33], pub_key65[65], pub_key65_invalid[65]; + + memcpy(pub_key33, utils_hex_to_uint8("02fcba7ecf41bc7e1be4ee122d9d22e3333671eb0a3a87b5cdf099d59874e1940f"), 33); + memcpy(pub_key33_invalid, utils_hex_to_uint8("999999999941bc7e1be4ee122d9d22e3333671eb0a3a87b5cdf099d59874e1940f"), 33); + memcpy(pub_key65, utils_hex_to_uint8("044054fd18aeb277aeedea01d3f3986ff4e5be18092a04339dcf4e524e2c0a09746c7083ed2097011b1223a17a644e81f59aa3de22dac119fd980b36a8ff29a244"), 65); + memcpy(pub_key65_invalid, utils_hex_to_uint8("044054fd18aeb277aeedea01d3f3986ff4e5be18092a04339dcf4e524e2c0a09746c7083ed2097011b1223a17a644e81f59aa3de22dac119fd980b39999f29a244"), 65); + + + u_assert_int_eq(btc_ecc_verify_pubkey(pub_key33, 1), 1); + u_assert_int_eq(btc_ecc_verify_pubkey(pub_key65, 0), 1); + + u_assert_int_eq(btc_ecc_verify_pubkey(pub_key33_invalid, 1), 0); + u_assert_int_eq(btc_ecc_verify_pubkey(pub_key65_invalid, 0), 0); + + btc_key key; + btc_privkey_init(&key); + assert(btc_privkey_is_valid(&key) == 0); + btc_privkey_gen(&key); + + uint8_t* hash = utils_hex_to_uint8((const char*)"26db47a48a10b9b0b697b793f5c0231aa35fe192c9d063d7b03a55e3c302850a"); + unsigned char sig[74]; + size_t outlen = 74; + btc_key_sign_hash(&key, hash, sig, &outlen); + + uint8_t sigcomp[64]; + unsigned char sigder[74]; + size_t sigderlen = 74; + u_assert_int_eq(btc_ecc_der_to_compact(sig, outlen, sigcomp), true); + u_assert_int_eq(btc_ecc_compact_to_der_normalized(sigcomp, sigder, &sigderlen), true); + u_assert_int_eq(outlen, sigderlen); + u_assert_int_eq(memcmp(sig,sigder,sigderlen), 0); +} diff --git a/test/eckey_tests.c b/test/eckey_tests.c new file mode 100644 index 000000000..0cd750094 --- /dev/null +++ b/test/eckey_tests.c @@ -0,0 +1,107 @@ +/* + + The MIT License (MIT) + + Copyright (c) 2015 Jonas Schnelli + + 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 + +#include "utest.h" +#include + +void test_eckey() +{ + btc_key key; + btc_privkey_init(&key); + assert(btc_privkey_is_valid(&key) == 0); + btc_privkey_gen(&key); + assert(btc_privkey_is_valid(&key) == 1); + + btc_pubkey pubkey; + btc_pubkey_init(&pubkey); + assert(btc_pubkey_is_valid(&pubkey) == 0); + btc_pubkey_from_key(&key, &pubkey); + assert(btc_pubkey_is_valid(&pubkey) == 1); + + assert(btc_privkey_verify_pubkey(&key, &pubkey) == 1); + + unsigned int i; + for (i = 33; i < BTC_ECKEY_UNCOMPRESSED_LENGTH; i++) + assert(pubkey.pubkey[i] == 0); + + uint8_t* hash = utils_hex_to_uint8((const char*)"26db47a48a10b9b0b697b793f5c0231aa35fe192c9d063d7b03a55e3c302850a"); + unsigned char sig[74]; + size_t outlen = 74; + btc_key_sign_hash(&key, hash, sig, &outlen); + + unsigned char sigcmp[64]; + size_t outlencmp = 64; + btc_key_sign_hash_compact(&key, hash, sigcmp, &outlencmp); + + unsigned char sigcmp_rec[64]; + size_t outlencmp_rec = 64; + int recid; + btc_pubkey pubkey_rec; + btc_pubkey_init(&pubkey_rec); + btc_key_sign_hash_compact_recoverable(&key, hash, sigcmp_rec, &outlencmp_rec, &recid); + btc_key_sign_recover_pubkey(sigcmp_rec, hash, recid, &pubkey_rec); + u_assert_int_eq(btc_pubkey_verify_sig(&pubkey, hash, sig, outlen), true); + u_assert_int_eq(btc_pubkey_verify_sig(&pubkey, hash, sig, outlen), true); + int test = sizeof(pubkey.pubkey); + u_assert_mem_eq(pubkey.pubkey, pubkey_rec.pubkey, sizeof(pubkey.pubkey)); + + + size_t size = 66; + char str[size]; + int r = btc_pubkey_get_hex(&pubkey, str, &size); + u_assert_int_eq(r, true); + u_assert_int_eq(size, 66); + + size = 50; + r = btc_pubkey_get_hex(&pubkey, str, &size); + u_assert_int_eq(r, false); + btc_privkey_cleanse(&key); + btc_pubkey_cleanse(&pubkey); + + btc_key key_wif; + btc_privkey_init(&key_wif); + assert(btc_privkey_is_valid(&key_wif) == 0); + btc_privkey_gen(&key_wif); + assert(btc_privkey_is_valid(&key_wif) == 1); + char wifstr[100]; + size_t wiflen = 100; + btc_privkey_encode_wif(&key_wif, &btc_chainparams_main, wifstr, &wiflen); + + char wif_decode_buf[100]; + wiflen = 100; + btc_key key_wif_decode; + btc_privkey_decode_wif(wifstr, &btc_chainparams_main, &key_wif_decode); + + u_assert_mem_eq(key_wif_decode.privkey, key_wif.privkey, sizeof(key_wif_decode.privkey)); +} diff --git a/test/hash_tests.c b/test/hash_tests.c new file mode 100644 index 000000000..3df118c8d --- /dev/null +++ b/test/hash_tests.c @@ -0,0 +1,28 @@ +/********************************************************************** + * Copyright (c) 2015 Jonas Schnelli * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include +#include +#include + +#include + +#include +#include + +void test_bitcoin_hash() +{ + const char data[] = "cea946542b91ca50e2afecba73cf546ce1383d82668ecb6265f79ffaa07daa49abb43e21a19c6b2b15c8882b4bc01085a8a5b00168139dcb8f4b2bbe22929ce196d43532898d98a3b0ea4d63112ba25e724bb50711e3cf55954cf30b4503b73d785253104c2df8c19b5b63e92bd6b1ff2573751ec9c508085f3f206c719aa4643776bf425344348cbf63f1450389"; + + const char expected[] = "52aa8dd6c598d91d580cc446624909e52a076064ffab67a1751f5758c9f76d26"; + uint256* digest_expected; + digest_expected = (uint256*)utils_hex_to_uint8(expected); + + uint256 hashout; + btc_hash((const unsigned char *)data, strlen(data), hashout); + assert(memcmp(hashout, digest_expected, sizeof(hashout)) == 0); +} diff --git a/test/memory_tests.c b/test/memory_tests.c new file mode 100644 index 000000000..81cf95c30 --- /dev/null +++ b/test/memory_tests.c @@ -0,0 +1,62 @@ +/********************************************************************** +* Copyright (c) 2015 Jonas Schnelli * +* Distributed under the MIT software license, see the accompanying * +* file COPYING or http://www.opensource.org/licenses/mit-license.php.* +**********************************************************************/ + +#include + +#include "utest.h" + +#include +#include +#include +#include + +void* test_memory_malloc(size_t size) +{ + (void)(size); + + return NULL; +} + +void* test_memory_calloc(size_t count, size_t size) +{ + (void)(count); + (void)(size); + + return NULL; +} + +void* test_memory_realloc(void *ptr, size_t size) +{ + (void)(ptr); + (void)(size); + + return NULL; +} + +void test_memory_free(void *ptr) +{ + free(ptr); +} + + +void test_memory() +{ + btc_mem_mapper mymapper = {test_memory_malloc, test_memory_calloc, test_memory_realloc, test_memory_free}; + btc_mem_set_mapper(mymapper); + + void *ptr = btc_malloc(32); + u_assert_int_eq((ptr == NULL), 1); + ptr = btc_calloc(32, 1); + u_assert_int_eq((ptr == NULL), 1); + + void *buf = malloc(100); + void *obuf = buf; + ptr = btc_realloc(buf, 1000); + u_assert_int_eq((ptr == NULL), 1); + free(obuf); + // switch back to the default memory callback mapper + btc_mem_set_mapper_default(); +} diff --git a/test/net_tests.c b/test/net_tests.c new file mode 100644 index 000000000..2719f5a0c --- /dev/null +++ b/test/net_tests.c @@ -0,0 +1,201 @@ +#include "utest.h" +#include +#include +#include +#include +#include + +static btc_bool timer_cb(btc_node *node, uint64_t *now) +{ + if (node->time_started_con + 300 < *now) + btc_node_disconnect(node); + + /* return true = run internal timer logic (ping, disconnect-timeout, etc.) */ + return true; +} + +static int default_write_log(const char *format, ...) +{ + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + return 1; +} + +btc_bool parse_cmd(struct btc_node_ *node, btc_p2p_msg_hdr *hdr, struct const_buffer *buf) +{ + (void)(node); + (void)(hdr); + (void)(buf); + return true; +} + +void postcmd(struct btc_node_ *node, btc_p2p_msg_hdr *hdr, struct const_buffer *buf) +{ + if (strcmp(hdr->command, "block") == 0) + { + btc_block_header header; + if (!btc_block_header_deserialize(&header, buf)) return; + + uint32_t vsize; + if (!deser_varlen(&vsize, buf)) return; + + for (unsigned int i = 0; i < vsize; i++) + { + btc_tx *tx = btc_tx_new(); //needs to be on the heep + btc_tx_deserialize(buf->p, buf->len, tx, NULL, true); + + btc_tx_free(tx); + } + + btc_node_disconnect(node); + } + + if (strcmp(hdr->command, "inv") == 0) + { + // directly create a getdata message + cstring *p2p_msg = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, "getdata", buf->p, buf->len); + + uint32_t vsize; + uint8_t hash[36]; + uint32_t type; + if (!deser_varlen(&vsize, buf)) return; + + for (unsigned int i = 0; i < vsize; i++) + { + if (!deser_u32(&type, buf)) return; + if (!deser_u256(hash, buf)) return; + + } + + /* send message */ + btc_node_send(node, p2p_msg); + + /* cleanup */ + cstr_free(p2p_msg, true); + } + + if (strcmp(hdr->command, "headers") == 0) + { + /* send getblock command */ + + /* request some headers (from the genesis block) */ + vector *blocklocators = vector_new(1, NULL); + uint256 from_hash; + utils_uint256_sethex("000000000000000001e67f0781f5e31a62863e6d7a1a1f786c7f666a9954a648", from_hash); // height 428694 + uint256 stop_hash; + utils_uint256_sethex("00000000000000000378be785f464ef19243baba187cb3791ac92a69ca46bb46", stop_hash); // height 428695 + + vector_add(blocklocators, from_hash); + + cstring *getheader_msg = cstr_new_sz(256); + btc_p2p_msg_getheaders(blocklocators, stop_hash, getheader_msg); + + /* create p2p message */ + cstring *p2p_msg = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, "getblocks", getheader_msg->str, getheader_msg->len); + cstr_free(getheader_msg, true); + + /* send message */ + btc_node_send(node, p2p_msg); + + /* cleanup */ + vector_free(blocklocators, true); + cstr_free(p2p_msg, true); + } +} + +void node_connection_state_changed(struct btc_node_ *node) +{ + (void)(node); +} + +void handshake_done(struct btc_node_ *node) +{ + /* make sure only one node is used for header sync */ + for(size_t i =0;i< node->nodegroup->nodes->len; i++) + { + btc_node *check_node = vector_idx(node->nodegroup->nodes, i); + if ((check_node->state & NODE_HEADERSYNC) == NODE_HEADERSYNC) + return; + } + + // request some headers (from the genesis block) + vector *blocklocators = vector_new(1, NULL); + vector_add(blocklocators, (void *)node->nodegroup->chainparams->genesisblockhash); + + cstring *getheader_msg = cstr_new_sz(256); + btc_p2p_msg_getheaders(blocklocators, NULL, getheader_msg); + + /* create p2p message */ + cstring *p2p_msg = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, "getheaders", getheader_msg->str, getheader_msg->len); + cstr_free(getheader_msg, true); + + /* send message */ + node->state |= NODE_HEADERSYNC; + btc_node_send(node, p2p_msg); + + /* cleanup */ + vector_free(blocklocators, true); + cstr_free(p2p_msg, true); +} + +void test_net_basics_plus_download_block() +{ + + vector *ips = vector_new(10, free); + const btc_dns_seed seed = btc_chainparams_main.dnsseeds[0]; + + btc_get_peers_from_dns(seed.domain, ips, btc_chainparams_main.default_port, AF_INET); + for (unsigned int i = 0; ilen; i++) + { + char *ip = (char *)vector_idx(ips, i); + printf("dns seed ip %d: %s\n", i, ip); + } + vector_free(ips, true); + + /* create a invalid node */ + btc_node *node_wrong = btc_node_new(); + u_assert_int_eq(btc_node_set_ipport(node_wrong, "0.0.0.1:1"), true); + + /* create a invalid node to will run directly into a timeout */ + btc_node *node_timeout_direct = btc_node_new(); + u_assert_int_eq(btc_node_set_ipport(node_timeout_direct, "127.0.0.1:1234"), true); + + /* create a invalid node to will run indirectly into a timeout */ + btc_node *node_timeout_indirect = btc_node_new(); + u_assert_int_eq(btc_node_set_ipport(node_timeout_indirect, "8.8.8.8:8333"), true); + + /* create a node */ + btc_node *node = btc_node_new(); + u_assert_int_eq(btc_node_set_ipport(node, "138.201.55.219:8333"), true); + + /* create a node group */ + btc_node_group* group = btc_node_group_new(NULL); + group->desired_amount_connected_nodes = 1; + + /* add the node to the group */ + btc_node_group_add_node(group, node_wrong); + btc_node_group_add_node(group, node_timeout_direct); + btc_node_group_add_node(group, node_timeout_indirect); + btc_node_group_add_node(group, node); + + /* set the timeout callback */ + group->periodic_timer_cb = timer_cb; + + /* set a individual log print function */ + group->log_write_cb = net_write_log_printf; + group->parse_cmd_cb = parse_cmd; + group->postcmd_cb = postcmd; + group->node_connection_state_changed_cb = node_connection_state_changed; + group->handshake_done_cb = handshake_done; + + /* connect to the next node */ + btc_node_group_connect_next_nodes(group); + + /* start the event loop */ + btc_node_group_event_loop(group); + + /* cleanup */ + btc_node_group_free(group); //will also free the nodes structures from the heap +} diff --git a/test/netspv_tests.c b/test/netspv_tests.c new file mode 100644 index 000000000..4870699bc --- /dev/null +++ b/test/netspv_tests.c @@ -0,0 +1,40 @@ +#include "utest.h" +#include +#include +#include +#include +#include +#include + +#include + +void test_spv_sync_completed(btc_spv_client* client) { + printf("Sync completed, at height %d\n", client->headers_db->getchaintip(client->headers_db_ctx)->height); + btc_node_group_shutdown(client->nodegroup); +} + +btc_bool test_spv_header_message_processed(struct btc_spv_client_ *client, btc_node *node, btc_blockindex *newtip) { + UNUSED(client); + UNUSED(node); + if (newtip) { + printf("New headers tip height %d\n", newtip->height); + } + return true; +} + +void test_netspv() +{ + unlink("headers.db"); + btc_spv_client* client = btc_spv_client_new(&btc_chainparams_main, true, false); + client->header_message_processed = test_spv_header_message_processed; + client->sync_completed = test_spv_sync_completed; + + btc_spv_client_load(client, "headers.db"); + + printf("Discover peers..."); + btc_spv_client_discover_peers(client, NULL); + printf("done\n"); + printf("Start interacting with the p2p network...\n"); + btc_spv_client_runloop(client); + btc_spv_client_free(client); +} diff --git a/test/protocol_tests.c b/test/protocol_tests.c new file mode 100644 index 000000000..79666ea8a --- /dev/null +++ b/test/protocol_tests.c @@ -0,0 +1,133 @@ +/********************************************************************** + * Copyright (c) 2016 Jonas Schnelli * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include +#include "utest.h" + +#include + +void test_protocol() +{ + /* get new string buffer */ + cstring *version_msg_cstr = cstr_new_sz(256); + cstring *inv_msg_cstr = cstr_new_sz(256); + + struct sockaddr_in test_sa, test_sa_check; + memset(&test_sa, 0, sizeof(test_sa)); + memset(&test_sa_check, 0, sizeof(test_sa_check)); + test_sa.sin_family = AF_INET; + struct sockaddr_in6 test_sa6, test_sa6_check; + test_sa6.sin6_family = AF_INET6; + test_sa6.sin6_port = htons(1024); + evutil_inet_pton(AF_INET, "10.0.0.1", &test_sa.sin_addr); // store IP in antelope + + char i6buf[1024]; + memset(&i6buf, 0, 1024); + + evutil_inet_pton(AF_INET6, "::1", &test_sa6.sin6_addr); + btc_p2p_address ipv6Test; + btc_p2p_address_init(&ipv6Test); + btc_addr_to_p2paddr((struct sockaddr *)&test_sa6, &ipv6Test); + btc_p2paddr_to_addr(&ipv6Test, (struct sockaddr *)&test_sa6_check); + memset(&i6buf, 0, 1024); + u_assert_int_eq(test_sa6.sin6_port, test_sa6_check.sin6_port); + + /* copy socket_addr to p2p addr */ + btc_p2p_address fromAddr; + btc_p2p_address_init(&fromAddr); + btc_p2p_address toAddr; + btc_p2p_address_init(&toAddr); + btc_addr_to_p2paddr((struct sockaddr *)&test_sa, &toAddr); + btc_p2paddr_to_addr(&toAddr, (struct sockaddr *)&test_sa_check); + u_assert_int_eq(test_sa.sin_port, test_sa_check.sin_port); + evutil_inet_ntop(AF_INET, &test_sa_check.sin_addr, i6buf, 1024); + u_assert_str_eq(i6buf, "10.0.0.1"); + + /* create a inv message struct */ + btc_p2p_inv_msg inv_msg, inv_msg_check; + memset(&inv_msg, 0, sizeof(inv_msg)); + + uint256 hash = {0}; + + btc_p2p_msg_inv_init(&inv_msg, 1, hash); + btc_p2p_msg_inv_ser(&inv_msg, inv_msg_cstr); + + struct const_buffer buf_inv = {inv_msg_cstr->str, inv_msg_cstr->len}; + u_assert_int_eq(btc_p2p_msg_inv_deser(&inv_msg_check, &buf_inv), true); + u_assert_int_eq(inv_msg_check.type, 1); + u_assert_mem_eq(inv_msg_check.hash, inv_msg.hash, sizeof(inv_msg.hash)); + cstr_free(inv_msg_cstr, true); + + /* create a version message struct */ + btc_p2p_version_msg version_msg; + memset(&version_msg, 0, sizeof(version_msg)); + + /* create a serialized version message */ + btc_p2p_msg_version_init(&version_msg, &fromAddr, &toAddr, "client", false); + btc_p2p_msg_version_ser(&version_msg, version_msg_cstr); + + /* create p2p message */ + cstring *p2p_msg = btc_p2p_message_new((unsigned const char *)&btc_chainparams_main.netmagic, BTC_MSG_VERSION, version_msg_cstr->str, version_msg_cstr->len); + + struct const_buffer buf = {p2p_msg->str, p2p_msg->len}; + btc_p2p_msg_hdr hdr; + btc_p2p_deser_msghdr(&hdr, &buf); + + u_assert_mem_eq(hdr.netmagic, &btc_chainparams_main.netmagic, 4); + u_assert_str_eq(hdr.command, BTC_MSG_VERSION); + u_assert_int_eq(hdr.data_len, version_msg_cstr->len); + u_assert_int_eq(buf.len, hdr.data_len); + u_assert_int_eq(buf.len, hdr.data_len); + u_assert_mem_eq(buf.p, version_msg_cstr->str, hdr.data_len); + + btc_p2p_version_msg v_msg_check; + u_assert_int_eq(btc_p2p_msg_version_deser(&v_msg_check, &buf), true); + + u_assert_int_eq(v_msg_check.version, BTC_PROTOCOL_VERSION); + u_assert_str_eq(v_msg_check.useragent, "client"); + u_assert_int_eq(v_msg_check.start_height, 0); + + cstr_free(p2p_msg, true); + cstr_free(version_msg_cstr, true); + + /* getheaders */ + uint256 genesis_hash = {0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0xd6, 0x68, 0x9c, 0x08, 0x5a, 0xe1, 0x65, 0x83, 0x1e, 0x93, 0x4f, 0xf7, 0x63, 0xae, 0x46, 0xa2, 0xa6, 0xc1, 0x72, 0xb3, 0xf1, 0xb6, 0x0a, 0x8c, 0xe2, 0x6f}; + vector *blocklocators = vector_new(1, NULL); + vector_add(blocklocators, genesis_hash); + cstring *getheader_msg = cstr_new_sz(256); + btc_p2p_msg_getheaders(blocklocators, NULL, getheader_msg); + p2p_msg = btc_p2p_message_new((unsigned const char *)&btc_chainparams_main.netmagic, BTC_MSG_GETHEADERS, getheader_msg->str, getheader_msg->len); + + + buf.p = p2p_msg->str; + buf.len = p2p_msg->len; + btc_p2p_deser_msghdr(&hdr, &buf); + u_assert_str_eq(hdr.command, BTC_MSG_GETHEADERS); + u_assert_int_eq(hdr.data_len, getheader_msg->len); + + + uint256 hashstop_check; + vector *blocklocators_check = vector_new(1, free); + btc_p2p_deser_msg_getheaders(blocklocators_check, hashstop_check, &buf); + u_assert_mem_eq(NULLHASH, hashstop_check, sizeof(hashstop_check)); + uint8_t *hash_loc_0 = vector_idx(blocklocators_check, 0); + u_assert_mem_eq(genesis_hash, hash_loc_0, sizeof(genesis_hash)); + + + /* cleanup */ + cstr_free(getheader_msg, true); + vector_free(blocklocators, true); + vector_free(blocklocators_check, true); + cstr_free(p2p_msg, true); +} + diff --git a/test/random_tests.c b/test/random_tests.c new file mode 100644 index 000000000..ace27b26c --- /dev/null +++ b/test/random_tests.c @@ -0,0 +1,49 @@ +/********************************************************************** +* Copyright (c) 2015 Jonas Schnelli * +* Distributed under the MIT software license, see the accompanying * +* file COPYING or http://www.opensource.org/licenses/mit-license.php.* +**********************************************************************/ + +#include + +#include "utest.h" + +#include +#include +#include +#include + +void test_random_init_cb(void) +{ + +} + + +btc_bool test_random_bytes_cb(uint8_t* buf, uint32_t len, const uint8_t update_seed) { + + (void)(update_seed); + for (uint32_t i = 0; i < len; i++) { + buf[i] = 0; + } + return false; +} + +void test_random() +{ + unsigned char r_buf[32]; + memset(r_buf, 0, 32); + btc_random_init(); + u_assert_int_eq(btc_random_bytes(r_buf, 32, 0), true); + + btc_rnd_mapper mymapper = {test_random_init_cb, test_random_bytes_cb}; + btc_rnd_set_mapper(mymapper); + + u_assert_int_eq(btc_random_bytes(r_buf, 32, 0), false); + + for (uint8_t i = 0; i < 32; i++) { + u_assert_int_eq(r_buf[i], 0); + } + + // switch back to the default random callback mapper + btc_rnd_set_mapper_default(); +} diff --git a/test/serialize_tests.c b/test/serialize_tests.c new file mode 100644 index 000000000..0dd50d88d --- /dev/null +++ b/test/serialize_tests.c @@ -0,0 +1,89 @@ +/********************************************************************** + * Copyright (c) 2015 Jonas Schnelli * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include + +void test_serialize() +{ + cstring* s3 = cstr_new("foo"); + cstring* s2 = cstr_new_sz(200); + struct const_buffer buf2; + uint16_t num0; + uint32_t num1; + int32_t num1a; + uint64_t num2; + int64_t num2a; + uint32_t num3; + char strbuf[255]; + cstring* deser_test; + struct const_buffer buf3; + uint16_t u16; + uint32_t u32; + uint64_t u64; + int32_t i32; + uint256 hash = {0x00,0x01,0x02,0x03,0x00,0x01,0x02,0x03,0x00,0x01,0x02,0x03,0x00,0x01,0x02,0x03,0x00,0x01,0x02,0x03,0x00,0x01,0x02,0x03,0x00,0x01,0x02,0x03,0x00,0x01,0x02,0x03}; + uint256 hashc; + + ser_u16(s2, 0xAAFF); + ser_u32(s2, 0xFFFFFFFF); + ser_s32(s2, 0xFFFFFFFF); + ser_u64(s2, 0x99FF99FFDDBBAAFF); + ser_s64(s2, 0x99FF99FFDDBBAAFF); + ser_varlen(s2, 10); + ser_varlen(s2, 1000); + ser_varlen(s2, 100000000); + ser_str(s2, "test", 4); + ser_varstr(s2, s3); + ser_u256(s2, hash); + cstr_free(s3, true); + + buf2.p = s2->str; buf2.len = s2->len; + deser_u16(&num0, &buf2); + assert(num0 == 43775); /* 0xAAFF */ + deser_u32(&num1, &buf2); + assert(num1 == 4294967295); /* 0xFFFFFFFF */ + deser_s32(&num1a, &buf2); + assert(num1a == -1); /* 0xFFFFFFFF signed */ + + deser_u64(&num2, &buf2); + assert(num2 == 0x99FF99FFDDBBAAFF); /* 0x99FF99FFDDBBAAFF */ + deser_s64(&num2a, &buf2); + assert(num2a == (int64_t)0x99FF99FFDDBBAAFF); /* 0x99FF99FFDDBBAAFF */ + + deser_varlen(&num3, &buf2); + assert(num3 == 10); + deser_varlen(&num3, &buf2); + assert(num3 == 1000); + deser_varlen(&num3, &buf2); + assert(num3 == 100000000); + + deser_str(strbuf, &buf2, 255); + assert(strncmp(strbuf, "test", 4) == 0); + deser_test = cstr_new_sz(0); + deser_varstr(&deser_test, &buf2); + assert(strncmp(deser_test->str, "foo", 3) == 0); + + deser_u256(hashc, &buf2); + assert(memcmp(hash, hashc, 32) == 0); + cstr_free(deser_test, true); + + cstr_free(s2, true); + + buf3.p = NULL, buf3.len = 0; + + assert(deser_u16(&u16, &buf3) == false); + assert(deser_u32(&u32, &buf3) == false); + assert(deser_u64(&u64, &buf3) == false); + assert(deser_s32(&i32, &buf3) == false); +} + diff --git a/test/sha2_tests.c b/test/sha2_tests.c new file mode 100644 index 000000000..9ba6d5216 --- /dev/null +++ b/test/sha2_tests.c @@ -0,0 +1,506 @@ +/********************************************************************** + * Copyright (c) 2015 Jonas Schnelli * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include +#include +#include + +#include +#include + +struct sha256_test_v_short { + int len; + char msg[512 / 8 * 2]; + const char digest_hex[SHA256_DIGEST_LENGTH * 2 + 1]; +}; + +static const struct sha256_test_v_short nist_sha256_test_vectors_short[] = + { + {8, "d3", "28969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c1"}, + {16, "11af", "5ca7133fa735326081558ac312c620eeca9970d1e70a4b95533d956f072d1f98"}, + {24, "b4190e", "dff2e73091f6c05e528896c4c831b9448653dc2ff043528f6769437bc7b975c2"}, + {32, "74ba2521", "b16aa56be3880d18cd41e68384cf1ec8c17680c45a02b1575dc1518923ae8b0e"}, + {40, "c299209682", "f0887fe961c9cd3beab957e8222494abb969b1ce4c6557976df8b0f6d20e9166"}, + {48, "e1dc724d5621", "eca0a060b489636225b4fa64d267dabbe44273067ac679f20820bddc6b6a90ac"}, + {56, "06e076f5a442d5", "3fd877e27450e6bbd5d74bb82f9870c64c66e109418baa8e6bbcff355e287926"}, + {64, "5738c929c4f4ccb6", "963bb88f27f512777aab6c8b1a02c70ec0ad651d428f870036e1917120fb48bf"}, + {72, "3334c58075d3f4139e", "078da3d77ed43bd3037a433fd0341855023793f9afd08b4b08ea1e5597ceef20"}, + {80, "74cb9381d89f5aa73368", "73d6fad1caaa75b43b21733561fd3958bdc555194a037c2addec19dc2d7a52bd"}, + {88, "76ed24a0f40a41221ebfcf", "044cef802901932e46dc46b2545e6c99c0fc323a0ed99b081bda4216857f38ac"}, + {96, "9baf69cba317f422fe26a9a0", "fe56287cd657e4afc50dba7a3a54c2a6324b886becdcd1fae473b769e551a09b"}, + {104, "68511cdb2dbbf3530d7fb61cbc", "af53430466715e99a602fc9f5945719b04dd24267e6a98471f7a7869bd3b4313"}, + {112, "af397a8b8dd73ab702ce8e53aa9f", "d189498a3463b18e846b8ab1b41583b0b7efc789dad8a7fb885bbf8fb5b45c5c"}, + {120, "294af4802e5e925eb1c6cc9c724f09", "dcbaf335360de853b9cddfdafb90fa75567d0d3d58af8db9d764113aef570125"}, + {128, "0a27847cdc98bd6f62220b046edd762b", "80c25ec1600587e7f28b18b1b18e3cdc89928e39cab3bc25e4d4a4c139bcedc4"}, + {136, "1b503fb9a73b16ada3fcf1042623ae7610", "d5c30315f72ed05fe519a1bf75ab5fd0ffec5ac1acb0daf66b6b769598594509"}, + {144, "59eb45bbbeb054b0b97334d53580ce03f699", "32c38c54189f2357e96bd77eb00c2b9c341ebebacc2945f97804f59a93238288"}, + {152, "58e5a3259cb0b6d12c83f723379e35fd298b60", "9b5b37816de8fcdf3ec10b745428708df8f391c550ea6746b2cafe019c2b6ace"}, + {160, "c1ef39cee58e78f6fcdc12e058b7f902acd1a93b", "6dd52b0d8b48cc8146cebd0216fbf5f6ef7eeafc0ff2ff9d1422d6345555a142"}, + {168, "9cab7d7dcaec98cb3ac6c64dd5d4470d0b103a810c", "44d34809fc60d1fcafa7f37b794d1d3a765dd0d23194ebbe340f013f0c39b613"}, + {176, "ea157c02ebaf1b22de221b53f2353936d2359d1e1c97", "9df5c16a3f580406f07d96149303d8c408869b32053b726cf3defd241e484957"}, + {184, "da999bc1f9c7acff32828a73e672d0a492f6ee895c6867", "672b54e43f41ee77584bdf8bf854d97b6252c918f7ea2d26bc4097ea53a88f10"}, + {192, "47991301156d1d977c0338efbcad41004133aefbca6bcf7e", "feeb4b2b59fec8fdb1e55194a493d8c871757b5723675e93d3ac034b380b7fc9"}, + {200, "2e7ea84da4bc4d7cfb463e3f2c8647057afff3fbececa1d200", "76e3acbc718836f2df8ad2d0d2d76f0cfa5fea0986be918f10bcee730df441b9"}, + {208, "47c770eb4549b6eff6381d62e9beb464cd98d341cc1c09981a7a", "6733809c73e53666c735b3bd3daf87ebc77c72756150a616a194108d71231272"}, + {216, "ac4c26d8b43b8579d8f61c9807026e83e9b586e1159bd43b851937", "0e6e3c143c3a5f7f38505ed6adc9b48c18edf6dedf11635f6e8f9ac73c39fe9e"}, + {224, "0777fc1e1ca47304c2e265692838109e26aab9e5c4ae4e8600df4b1f", "ffb4fc03e054f8ecbc31470fc023bedcd4a406b9dd56c71da1b660dcc4842c65"}, + {232, "1a57251c431d4e6c2e06d65246a296915071a531425ecf255989422a66", "c644612cd326b38b1c6813b1daded34448805aef317c35f548dfb4a0d74b8106"}, + {240, "9b245fdad9baeb890d9c0d0eff816efb4ca138610bc7d78cb1a801ed3273", "c0e29eeeb0d3a7707947e623cdc7d1899adc70dd7861205ea5e5813954fb7957"}, + {248, "95a765809caf30ada90ad6d61c2b4b30250df0a7ce23b7753c9187f4319ce2", "a4139b74b102cf1e2fce229a6cd84c87501f50afa4c80feacf7d8cf5ed94f042"}, + {256, "09fc1accc230a205e4a208e64a8f204291f581a12756392da4b8c0cf5ef02b95", "4f44c1c7fbebb6f9601829f3897bfd650c56fa07844be76489076356ac1886a4"}, + {264, "0546f7b8682b5b95fd32385faf25854cb3f7b40cc8fa229fbd52b16934aab388a7", "b31ad3cd02b10db282b3576c059b746fb24ca6f09fef69402dc90ece7421cbb7"}, + {272, "b12db4a1025529b3b7b1e45c6dbc7baa8897a0576e66f64bf3f8236113a6276ee77d", "1c38bf6bbfd32292d67d1d651fd9d5b623b6ec1e854406223f51d0df46968712"}, + {280, "e68cb6d8c1866c0a71e7313f83dc11a5809cf5cfbeed1a587ce9c2c92e022abc1644bb", "c2684c0dbb85c232b6da4fb5147dd0624429ec7e657991edd95eda37a587269e"}, + {288, "4e3d8ac36d61d9e51480831155b253b37969fe7ef49db3b39926f3a00b69a36774366000", "bf9d5e5b5393053f055b380baed7e792ae85ad37c0ada5fd4519542ccc461cf3"}, + {296, "03b264be51e4b941864f9b70b4c958f5355aac294b4b87cb037f11f85f07eb57b3f0b89550", "d1f8bd684001ac5a4b67bbf79f87de524d2da99ac014dec3e4187728f4557471"}, + {304, "d0fefd96787c65ffa7f910d6d0ada63d64d5c4679960e7f06aeb8c70dfef954f8e39efdb629b", "49ba38db85c2796f85ffd57dd5ec337007414528ae33935b102d16a6b91ba6c1"}, + {312, "b7c79d7e5f1eeccdfedf0e7bf43e730d447e607d8d1489823d09e11201a0b1258039e7bd4875b1", "725e6f8d888ebaf908b7692259ab8839c3248edd22ca115bb13e025808654700"}, + {320, "64cd363ecce05fdfda2486d011a3db95b5206a19d3054046819dd0d36783955d7e5bf8ba18bf738a", "32caef024f84e97c30b4a7b9d04b678b3d8a6eb2259dff5b7f7c011f090845f8"}, + {328, "6ac6c63d618eaf00d91c5e2807e83c093912b8e202f78e139703498a79c6067f54497c6127a23910a6", "4bb33e7c6916e08a9b3ed6bcef790aaaee0dcf2e7a01afb056182dea2dad7d63"}, + {336, "d26826db9baeaa892691b68900b96163208e806a1da077429e454fa011840951a031327e605ab82ecce2", "3ac7ac6bed82fdc8cd15b746f0ee7489158192c238f371c1883c9fe90b3e2831"}, + {344, "3f7a059b65d6cb0249204aac10b9f1a4ac9e5868adebbe935a9eb5b9019e1c938bfc4e5c5378997a3947f2", "bfce809534eefe871273964d32f091fe756c71a7f512ef5f2300bcd57f699e74"}, + {352, "60ffcb23d6b88e485b920af81d1083f6291d06ac8ca3a965b85914bc2add40544a027fca936bbde8f359051c", "1d26f3e04f89b4eaa9dbed9231bb051eef2e8311ad26fe53d0bf0b821eaf7567"}, + {360, "9ecd07b684bb9e0e6692e320cec4510ca79fcdb3a2212c26d90df65db33e692d073cc174840db797504e482eef", "0ffeb644a49e787ccc6970fe29705a4f4c2bfcfe7d19741c158333ff6982cc9c"}, + {368, "9d64de7161895884e7fa3d6e9eb996e7ebe511b01fe19cd4a6b3322e80aaf52bf6447ed1854e71001f4d54f8931d", "d048ee1524014adf9a56e60a388277de194c694cc787fc5a1b554ea9f07abfdf"}, + {376, "c4ad3c5e78d917ecb0cbbcd1c481fc2aaf232f7e289779f40e504cc309662ee96fecbd20647ef00e46199fbc482f46", "50dbf40066f8d270484ee2ef6632282dfa300a85a8530eceeb0e04275e1c1efd"}, + {384, "4eef5107459bddf8f24fc7656fd4896da8711db50400c0164847f692b886ce8d7f4d67395090b3534efd7b0d298da34b", "7c5d14ed83dab875ac25ce7feed6ef837d58e79dc601fb3c1fca48d4464e8b83"}, + {392, "047d2758e7c2c9623f9bdb93b6597c5e84a0cd34e610014bcb25b49ed05c7e356e98c7a672c3dddcaeb84317ef614d342f", "7d53eccd03da37bf58c1962a8f0f708a5c5c447f6a7e9e26137c169d5bdd82e4"}, + {400, "3d83df37172c81afd0de115139fbf4390c22e098c5af4c5ab4852406510bc0e6cf741769f44430c5270fdae0cb849d71cbab", "99dc772e91ea02d9e421d552d61901016b9fd4ad2df4a8212c1ec5ba13893ab2"}, + {408, "33fd9bc17e2b271fa04c6b93c0bdeae98654a7682d31d9b4dab7e6f32cd58f2f148a68fbe7a88c5ab1d88edccddeb30ab21e5e", "cefdae1a3d75e792e8698d5e71f177cc761314e9ad5df9602c6e60ae65c4c267"}, + {416, "77a879cfa11d7fcac7a8282cc38a43dcf37643cc909837213bd6fd95d956b219a1406cbe73c52cd56c600e55b75bc37ea69641bc", "c99d64fa4dadd4bc8a389531c68b4590c6df0b9099c4d583bc00889fb7b98008"}, + {424, "45a3e6b86527f20b4537f5af96cfc5ad8777a2dde6cf7511886c5590ece24fc61b226739d207dabfe32ba6efd9ff4cd5db1bd5ead3", "4d12a849047c6acd4b2eee6be35fa9051b02d21d50d419543008c1d82c427072"}, + {432, "25362a4b9d74bde6128c4fdc672305900947bc3ada9d9d316ebcf1667ad4363189937251f149c72e064a48608d940b7574b17fefc0df", "f8e4ccab6c979229f6066cc0cb0cfa81bb21447c16c68773be7e558e9f9d798d"}, + {440, "3ebfb06db8c38d5ba037f1363e118550aad94606e26835a01af05078533cc25f2f39573c04b632f62f68c294ab31f2a3e2a1a0d8c2be51", "6595a2ef537a69ba8583dfbf7f5bec0ab1f93ce4c8ee1916eff44a93af5749c4"}, + {448, "2d52447d1244d2ebc28650e7b05654bad35b3a68eedc7f8515306b496d75f3e73385dd1b002625024b81a02f2fd6dffb6e6d561cb7d0bd7a", "cfb88d6faf2de3a69d36195acec2e255e2af2b7d933997f348e09f6ce5758360"}, + {456, "4cace422e4a015a75492b3b3bbfbdf3758eaff4fe504b46a26c90dacc119fa9050f603d2b58b398cad6d6d9fa922a154d9e0bc4389968274b0", "4d54b2d284a6794581224e08f675541c8feab6eefa3ac1cfe5da4e03e62f72e4"}, + {464, "8620b86fbcaace4ff3c2921b8466ddd7bacae07eefef693cf17762dcabb89a84010fc9a0fb76ce1c26593ad637a61253f224d1b14a05addccabe", "dba490256c9720c54c612a5bd1ef573cd51dc12b3e7bd8c6db2eabe0aacb846b"}, + {472, "d1be3f13febafefc14414d9fb7f693db16dc1ae270c5b647d80da8583587c1ad8cb8cb01824324411ca5ace3ca22e179a4ff4986f3f21190f3d7f3", "02804978eba6e1de65afdbc6a6091ed6b1ecee51e8bff40646a251de6678b7ef"}, + {480, "f499cc3f6e3cf7c312ffdfba61b1260c37129c1afb391047193367b7b2edeb579253e51d62ba6d911e7b818ccae1553f6146ea780f78e2219f629309", "0b66c8b4fefebc8dc7da0bbedc1114f228aa63c37d5c30e91ab500f3eadfcec5"}, + {488, "6dd6efd6f6caa63b729aa8186e308bc1bda06307c05a2c0ae5a3684e6e460811748690dc2b58775967cfcc645fd82064b1279fdca771803db9dca0ff53", "c464a7bf6d180de4f744bb2fe5dc27a3f681334ffd54a9814650e60260a478e3"}, + {496, "6511a2242ddb273178e19a82c57c85cb05a6887ff2014cf1a31cb9ba5df1695aadb25c22b3c5ed51c10d047d256b8e3442842ae4e6c525f8d7a5a944af2a", "d6859c0b5a0b66376a24f56b2ab104286ed0078634ba19112ace0d6d60a9c1ae"}, + {504, "e2f76e97606a872e317439f1a03fcd92e632e5bd4e7cbc4e97f1afc19a16fde92d77cbe546416b51640cddb92af996534dfd81edb17c4424cf1ac4d75aceeb", "18041bd4665083001fba8c5411d2d748e8abbfdcdfd9218cb02b68a78e7d4c23"}, + {512, "5a86b737eaea8ee976a0a24da63e7ed7eefad18a101c1211e2b3650c5187c2a8a650547208251f6d4237e661c7bf4c77f335390394c37fa1a9f9be836ac28509", "42e61e174fbb3897d6dd6cef3dd2802fe67b331953b06114a65c772859dfc1aa"}}; + +struct sha256_test_v_long { + int len; + char msg[51200 / 8 * 2]; + const char digest_hex[SHA256_DIGEST_LENGTH * 2 + 1]; +}; + +static const struct sha256_test_v_long nist_sha256_test_vectors_long[] = + { + {3680, "5f664be0c0f3d2fc9a1a7ed6b515ef9c52ad1c7fb3acf2c2de943e109f91cc12ccadd041cc4386f95ab616cf8762ba25fed322fc8c351809e00c600a8f26e25a5bcd0bc3b44170947f65b4f417b8ac769187c2ee4561978289cced04c036c37f942ec10f7fd4d7f6908e22ed6cfd0fb89330c2fde417b956643aaca53baab8a8ff38bdcd35e60547159b26618e1b29128a35ebd2733fc4adf6bf6796076b09fd2554c6a4df5e40ae97f389f986f843ad00000515f9c001aec9c4e47e2c60fea78de8a33c8423d1539dfe125c5b7ea4b17cf8d86e7f84b88264afec06b370dfcebf5e1d3e2c1f005faf248b321593964587852b830c7231504fe947d6a385f399441cfc52df3914fa55cdba25bd215f91a80fc8ffa872b34113dbbd9504868331a38c081fa659574b186169db590f48be67fe75885b6c877d37ec16ebde5ad7be6414084e88670f7b7f485efcf44599f44cbbfbc62e48f62b438319823aeb3767101ec6868e4c85b113ea623193ab9a5ae0ac226328ee4674bf0a90ff1f20eb542e110870bfee01165ab03c2240299319aa3ab1045247bf7f34e8410d96e13aae465597b42336cad2de00b67602a7cb5832cd7253b239ab752a85f452a6166e9de0523bf9c20c2a0c274396d5", "044d823532092c22a4b48181cfb2c796e1f5b98bcd713a21f70b5afcceef1d73"}, + + {50408, "9ad432e59a7f71adefb66e0c10e1873b5ab91c65624f8ac38a505d06d288c1f5f1a63a57a53f951347151f96a298147505ad5a5397af6f06ebb3a1f5d4117dc47b208934ae4036447b1e109dfe33382c778e14119fd445b83d85d945f480c2365fca8743608b3a89b459aae8cbb9d9aad7e3b16524c6f222a74c6fbed9df7a91c62c9d4e60278b2a1a4f5541b233e1354e359918cb8e608c5292ca282c358c1ed7cf311b591c0f6fd4877a6e5ba83716040b33f23e33753d65de524b948be025bb3aad74f173b0a00b897f386d20c39520ede9ba25bd1b7f09b96fefbae85eee99f5771fd0335404e6dece6791a46df9cb63223a2735399866aa89db4554eec09a89f9e49f64e5e48e0dcdc36e3a1d8c2cf64738eda2b7d1a33908d8ded878e5e67d998d060e4a882a9ee613adedbb946c2dbe7d1f0c7c72e9ee54ae2d7ae4a3a459c1e0ac3a6b38e31a8021f5c22f5ab291f0d1647b72c35f52d525d9441a43fca6d8a73af0303ce10802b3efc3612627a945fb64f8800c2eecf4048b3e020c17ea46a8573681db4bf0d69242f73a40f2fd26c5c88a8e947d441715ea6f85481db072acac16465f495a63869766a0ef3d15f9f5383a85a475e3a81e9fdf893d367dc67ae197670e05cf115796197c7c2d7a27545b0f4b843e500de85196f73588dba9dc9dc1cc31a4d648cce617b72fecb319aada11c97cff13b03ba99db8763e518398889d5e0f51f870ae30683750a24836bf5c48e7d4e0b5f7df4ffbb2487e68bd774b3203f232bcf1c51b15e62776c1e55a8abd8ed30abd4c9beab8cff570a6bd418e89a4206faa34d95025abfc91a790450c77a4c2a5b3163822ddf6c43e96ecbef8a82ae2314a9fb276a06d161b829e46897e12e9d820bc7fa1700ffc0dbdb2b532997b80a0259b17368f16be3bd87726aadbc190cc8ba8350c7c01e608a578f0e4648142e3c291d238f98d3c193383ac169598ffa97c41250e06b6ca54d5a435b50f227023a9e7a923e6bad8de1a29a275b47e7d967bef164d1815f01cd5a04d4da4485187630765a05e85dab216d4ce71415d54bb111acf71b9069f862ed200552ada2e387757ce566ad689bcaee9fab0421cca41c52a1923f27120ba67a41575aac04f5d6d41abee11952e256ad1ecdac2a328502087bc0bca3ebce1087d56542be2fc1fce2bc60f5caa1114d2f46d98c6dab60fa99a80d04956b82399c4899bb5287da6217fe56251fd7ab26fba449258a9bba7e8c92d1a779f5fa7a3e377f1507a1919eea4d18efb77b127c88c3b6f7ff88140657d8a935d02f896ae41e8ff05c01aa0be02523c5ffefd9a65d018d744af4e00a91f60e10267ca174046a46ddbe2c66517012f14877ba833cff0a474adb66b123b1577ac6eb71e53e35a72e2dbc8668d840932bd7ad7f81c8d52a7ebc5f5209ca3c9979daad83c721ee51b060c5a41438a8221e040f8367a2760e9e79154b4c76aa1885bbdb46c9b794f68827681a1adb3d4c524e2c8a9782680310e1bbc71ba1707118faf32f6f67d001efe2123ccf38667e632672e9b3b111c48086a139d9e3262fce1893921acb161082116290b3e8ba44cb1d71152ee709bf77e8643819a431a0ff852b337e59ed8ed945c7ca6b64bf1be4a3a5b17b7cc650418783265d7d397137d12877ec8cace94fffb02e5824db705a599f332beabe2377d47ca907c6940cf17d19d3f7ebfacc608fca510cb195fe969fbc1eb2c987a5a56fbf14cb28e7f0d6f98ddc12e05d84b5a664c6eb8384f323f69ad8a291895334a9d91dfa1c9bb932d6e2f4e0122bceb9b41df487231f1a8ceea9f56dcb59b8c0233919270a25d2af85c7b2c1fa0be6e749545e6208cac13bf867f986ef6f42b25c8d9ad48a1cb9a7869a9a4af07489b8c6b6890ebd2e73ab9453599076308d85c615178504f6eab569da1fedaddc13b8cca2f8efb8a0ce66530a99ecd853f5d4f08e13bb133ae253a004b82c7ac91161bbb8227773c82df6a4ec4f2ebe30281a5c4713d92d6f4cfcb9b8f789ffb1ff4e24549a58771b1ed72a86cdc8706b70b079ee9c71cbea672b27556278953d59d88706c4e55af01d822448aa3ca74c8c41c9c312176752ed6979686d8ae3b1ad8b644d46b0681da67242c0790dbb79b748dc93193ca83f2c3200709d3353b566f14ca6743c56ca4642068c9ebe2579ae3012ad2653d6e5c01f8cfc56047dbf22849090e20b8fac795bdfebafc09da2bd821c9fadef9c0d257c5f6a4c70ca454ccfe09b24807b2abc2a4f8c10a76cab81c95ad92472600be8f30858d4fab1de523dad33904db1cb8b57d5dc55f51aea87804de83e8ebb7876fe08367414dcf0df4866e8d9c5cc15735ef36b041c30f63b11665b309716c95c07ef81ce519403509a9e29458b128ee09a28a69f9f474519274490cf2e0a75049b1ed938338fac328ec38388003dae7fa3f61d8ce0b65dae2c69275eb5ff120d42268b463d185211af7775f5b795da8d06ec4e50a306a6668b348d53b16d06d27787467cd0d67b5a671a7f3323c3b9b53d6b978f38d0c5dede474162b2ece9f0c5c169408142ae99603d1db4d73fb264a204b79d347d22739011e1f03cf731e487658235d0d5524b154fcfff44726b37ff37fd0f089452c14b14cd80b204652a66d41fc142071cdbe0d30476fe043a9b8f85f659379ebd4469c08298a4acfa4edead9087577054e86d5759b0565da70bed7f220033f4f88966b59faca74967ae494292dc737990ed155d4e300fe7470593740ea8a04f6aecec6483311c7243d55143854548bb67566345407a6d5981050c052a96ef06ab0b454dbbca86b005606110f666299e3eb0f1bfeef400fcebb6d1b2f47f82a32f411be1c7dd787b22bbf34b4493a89a8d892b2d88415d79ed676f0dfaa70dbd6e4acab135fe544c3264a2531e724848da4b8a0edac6f5391ca34e66bbc1e2adee64fc4c7481cc9baae6e8b8e2667b21bb7498e425094ab2eff6fa6da634940d364c0b14021c23f1f2af20ed1f04d3ad97a0d23e159cd08fdddefd834893b443dc5c81986d320cd7b049f57042c1c444f53cc08d1ad629287cd7b2382153a5fa2712fa5a2457e9c54a33d0e2ec21dfa06ab4de41a369b705335dd2fcbef8fb98cd0bdfc9b5e24d3356f94db5899988285eb5960c5dac0cbea7edba517ff8279824a3ac67908599ba3d06b64899bd5045479b824d88318cad2113e2d6e2d5ac80d476dad442a661c282e8b54c9af1ba9fcbf32d75e18ec969554cd6ed96161cdb42f1f5705ab937d4bf1bd5120bdb49804238e215c818456bab152115f83ddb1ff6a186cc47528e79581c70397aee6faf40f96acdca62833ca8f93bd097b179b76602095876f6d818c4771143568faf755ea101de56f20554c565a1bde3157b4a279ff7a5881aa74baa9852903d438b6ae1cc51f80c4b3e3c86d6dd3e68de5230a1e7cc23e9326e7a710c9ed07dae760870d7d58b48d2b05c73e948c2978081136b56115428d2a03d9e507054b63501c6825007089b2cee5d03099eeb0d809a6afa8741d6a57feefda8e051cd755bc13dacc1510071be5a86bab43a382973009fc5d7e7fc0daead432758cd8b19a716d646a86e037b0b77920175950a79bc563a53e46e64cfc36da670063e1e318b8518f671987205a8e7e78dda4a028ce10db33b196f815a62928039954e075b9d8e7e22b97aecaffb0dffa63ec380c16599a2d20345d23c10ce78ea7257d6d631b58e51ec7fc3e8866c52f12f8c35b5de7c81bf2e9be7e33273e8e929f5fd500c7cc20a8731a83def8589d5292e71d8a038c858f7dc32fe6c2568dc18a2fb477256a1c3261afa1e7aebfce8c804c5b85f50ef45fb8133dc02557129eae9413b07d5b60225a64a18dd0234a268b9b1d360577f0ca6257b0ab9868a690d237f99317c774e226e18ab7a5ab978a7b7c69857befff384236908e62b1d0ffc0bf6e083ad5e1d88dcd644d76803f1e1896495a9e9dab112159e650cc5b18533ed57bf72fad2e6e57d038368bc9ca4c2a92c49db7aa7bbdc767b9db1e8e06f5152126483f78e30b4b930d5c2cafbe7b7817e2360e3df7a4fc091216a071234b0d4a79e3af5e891633beeba6a15aa512cbceac0deb7fa82e88e7f8e9992df6beedf97cb0ca86a7f9d5f9dafc31f1067beb5f290a969815c432a8733c53e907b77fd53698d719c51bf9eae346269c6a1da071621656afc7ccc3f58bf714cedf9c8987af811d3e6be4693c0d6cc6855860b2ac5d1775ec44b004754903250405d6d4b6ef55e51e22bcec9561575ad158ace8ba24f7397816d6bad1b446ceb201ce280bfffa77e0710b499ee5ed29abf2690b40bf9ceb7bc4a8b0b0d5a956015ceb4c2ee65a1baee13949fea3177d39afffe3e934f0d21cd78cadbbb21407189d940ac6ac5b19adf9aeb45da3be9ca316d7385a8dd93884d6ec789a557027204c33287b5ae7b80741d35265ecc8cf12b057d23ed24163db492fdaf4c6a3ff40f22f6ff7f6e542e4410eeabc851f5eae03e8793b090f9c48b9bd9b710b97d7a116f0a7df8b3cfd6b82c8460a79a9919e99f3f4f93c2b2bf3adfe83ba2e32f76a40de98de1ed632c58b6a2cf8cd50b00bfade0c21727c5805ad5a5977375ea6c4f861099ab99a2819e45a652d8bfa021cac12895bb4ec6ba64139e74f2c022dd7c7e1c4bb637029901602b952bb91d0fa39f8334e0962abfdf203f3eb1706d4ca34c68fea25407b52a8c9ef0f63fc62cc29f7d1a379c76233472046f3ff51e3c5c87833cf06f267862216d10b8d2300bb02762d020c01d66fc9f8a80eedcda2f2095f78110e6f35550d5325ef40eef2ef4edf0d11cbf94fdafef3e1e4e861597781e32558459d2de6efe7b46285457f8f94993a7bbd97179c707ab81ef8f54f7cb86d044eb4659762533a460d6310f1c35d0c7ce6eac475dca7f3f6642572cd2a3563db9962afbaf0beb4a398e2378eb530a09afb5b66b0c22ac8635d78be1ba8802f73e15764dfb9babd92aa0aa29f8a95bd5e6117661178815fc7b2f8c2811f213794cf9c6a4ee4cebddcebe43a6b6d14cb8ec026ade0233422ea0bae6647b7a0e5050a38ab4f9a831c490577e53c843632f3c2912265eecb77940ea093b49786a0903b330e2a035f42a19dcb8c58f7825a550d5face7ffcfc88c66d82f11e85bcffb0a967a2646ec97ac5ee91808ef81ac7c499835b07ec87c9bb95e23a6d1a5dc0f1e68d98c8cb28432edd86f9494b98e2f1f45a406943cfb89b03858bb7bee2e9420b112a4fc386ffaf5a07b440db46938366de13269b5ad1ef270b5980ebd2d52b7790db6bf06c1cd1c4a226083faa65d3818d37b24bafa21280e2185b19b41118cc9b20afca4e3730add4e2f1d11ab67ca4e642bedd44a5cf91886c98c0fd29847a8e9e8dc9b3bb46861e6fa0483e21d96187b89ee8905950e98cbadc8a148b08f1f9a9787713358dedfd2095fd8b149447d00dc4c6493950e95d8798dd90b210c35ad6024b13226135dfaa4579682b17c86dc6d32ea5c24a2189575024083b367f20a8bdbe09fe7b0e646131447bc1ee53af584c6a5c9097228eae8505d192d485e9960d688e4635c7f9e9dbd72c75927a13468301c400e25cdbf1c9eb83359568243263a306862c032ea8c7aa00b27ebc3816399d72af9630ffc5715da3bfd3a65ee27326193ac840612267558f053d9a9c5bb295ff093d6f789e2dd4a97e29c0f83a9e3a2cd084f04feb4d322dea3985ae6b9073bf8a4248c4e051d90b1d02289ebf5787b7e40c932967dbf863de1d1decea55cf3acf4f5d73307fe35ef8f77da0c5317740e1a9b9ac3cb5f0d75d32b3e63c74f10734af2de2132a7c0bbe6410ad00ae916e65f6d446be4db3eee424f818f660919b470c2abfecc40b97c9e29221e6415e86cd7e63677115ca210f5e4af39ccb196d92c0e46b41ef3a9997fd629dda7c3730949af7ad09a0abf44b693d1493f700f49477eb52970e6177c51f127f71c1d3d257e70185cc70c20f04b04eda6086e0d6c89b902470a418b8cdc2125530b48d0293fd01605e08b4a7e7dde0e3a6fd217aab96835f4332d8d31e80f29d9bc6fb47b52777eb22caec75414c939ecbbc5b66ba132541a34d2a6d33c623e7176b86f857f0e584bf49e1ddcd86f78a4366e711707c069a055575ddaa1c36903834b8bae903daab78082d77c9175d24a26f6d016b4b97b6edee43bafdfdab4772951905d4bab7ee018837a9e068650c7d4845bd070c6936c17a3c7b8be4e26b5b1f204fc7a01dbad04c990a90048f80188419bae028fb88248ba895e06c8c7a6635571f2e3e6ca068b7ba1054763d4e18a54171634bbf298b85109097eefa03086a35ea74f0351d3f7c13319a380ec4f21e65771ccf34996b091d022ef6cb83c6403548385007bfc8ec4d04fdc474634961fe42893dec66478a1650f21e618b3439edaee4f844d6a99acff0eb95fec76312645a1512570ea58aa503adc06c67b6c9c78507337d1035fa149bf0371e6ff3a240246ce6f501198d41a09e874cc7e2724b611bac20eb02aca34c882243ab5f940a47ed1656cbf7f464ae60cd732a2bb5e1d99eccd0c5a404f4a92fe21f282b6a3b2b024afcedd5629683811d7fed172733450d1ffd4e7ea5913853f0f164db874b4468df47e5465a4fc67c01d3af2928b839f30016d41701016090c97acfe48dc33a7d5dc820af4e08fdbdf51eded64cd93ecd37adf4e1a9bdb872f61be7cae03b63bc411e4e94b05a8fb361b20aa3062eba0801333f83022ea656e1453b13210c56a2138acd8b23ad0318f21da103e72142400747025f9cfcc0d925874841c2ce89cb6fce0be70a78ee5b00e2309d52494df1b449ebfbec808e563d728ddb37ea83949028a85ce756a7d6288037d3ea0f538982cc6adc7352657a83677a4402f8ca9a3f5b11414ccec626d378352c20fbe9941d3eed75c3faeca2b2069c10b661d548c7b5e538ad39dfc99c5aa71a7997869dce22125c50e29a6b23b071d5c4ce1a3cb3c982a77b304b3aed781c23565aa0f3200647f49c91f52062f589e7b0962fc2ae267812593aaf073180e2db69cdcf50bd6c1cd32981638efa5642dafc428c86f12d340da9c1519b12d5b9b706597822f0b3ff7c6a498bf344534b342a5b9706376e54fdff6cf9830c170f2ace9611e6548e6e54e152c4f9fb6cf167ad59f5aceb6a4967cc860d3b87a531cb24fc5317635bf8011135b50f6a13d40a07c62f0787a19fef83a4e3411000effcac048232b79d1ae59c5ab2a02ad8717fbc1889928694a6d9d76232102fca9853c64745d4abd25586c53a6468b83b485d5cd9bbca82b41ccb1a1660455162a954f62d0459ba8c16793e6d40a59cacc7174c823c3be6906047de6a044d0f59b164de3e444e8e3afc116a6bcdf332bd8c221d9a61533cb9ffb496b58493c4203f27c0e39c3f715f7503dbae62ee24edf622428ae1acef8169b5d58167b60a46b10250c562891e79ffa504ada5d2fdae938c5dec23a599973cb00d6634206c4da588f04c3dc7e01b1a9968021d6df78ff2c4c236bdd9a55bc727b0dc506f44958b2041f0948860a3444588242ffbdcf2726001e2f6b5bd5fb7a1624c62ff3dcee06ca85afd371ab31b3de78c54290886b0e2bf8994c62c037ca1943ee25cb25a23c2a5d3de4068bafde708b33061f4ad3cc13d82ee877bf794acc94c45044cb7e3c6ccf3ce50e53b6ad56e212b233be664900e778a8647ac8e2773cd01926778aeed805333d52aa4f08d7a7edb0948b2c6b3c4dfef2f0982c7a61669ae638d0cd3bb624aa54973980d73dff49670a5a2d1b0e31482fe2c2adfad338ab20437f4f094d572992a8a75302ce14b03f5dd37242bdbbdfc8039f544a15da8a300f2b1842e6c4395f4c9dd071d30ea9a0549d02c692154a231bd828536f75bf7c647d31ccc99361234ac3fe0c9315bdf2b961e591d56411aaf21431fb2931d36e0a1da1913eed2a466bc0e5bc584f729d52c62489ced3bdc44ffc782b8a354d6dc8b270778dfa1b30773d8d6768e75309e875c698c487d5d8fb3704ccdbaab5e068e4a668fde1bc4936e1fff60c03e59f4215d3a501abe150bf6edec465b79431b05d4c4bd7cb95fa6f5542528cccb2c52a4f5497cb65699361490cfd6d8570c769c26a0764df2fa9ec405e61306941e466cb50586bddf609a96f985d3e3cd40a5bbe0686e94611c0734b5c0d40021a65bf30cfcf293d0f1a618989ce1f0345624df72aafb127c3a5cd1e433d03c1c6aefd27d9e44caa3d2e4f3ee83757024d370815dd6a03abcec2c2601bd9c2cccc29e857777f1e4e07ad3d37bc7f2f6273f155c1289f26f9b97d19b9ecc8c54bb43d4769b088e551f5fff11c0d90ef4b3ff8faa31136633b0c409cd3bff454670751e4048de7eadb8f8c3394e451dfe43ab5bf62a3180296507211539b44b7474bcf85d1148575125ebdcd4748aa4656eb8e6ea6e32b4b340c7a41e489a035150b1ef3774f48cd21e9f885de41836ec8dbeccd19db58853dc8c2f42c90f018f6cca6f69f46193c2eb8a62501d7c49d639038a6619288fad90cb1f1d3b81ca61418cf55f100e108625430735713561c4f94d8bf2610a1f02e61af0282090d28977601da1485867ae444fc3889fc1f33b36f36e0115e8cb0674e24ede18ca9e5a76fa44bb1ddf2dadd10743b3e9a0829b7a7b8d3c9833282aa5c787b9748d9276a8a20716f110b707441ff461ff6f94885c6c85ff7877aad1f1114744d4586340b4fdd14f727bb83d25e041fd417dbd64254cd4b43734b7bf0f85ea0aa8c9656b04644fcf02ae85d1eefed8f0406941c19d72f60544e8f324296bfc75724f3d282f8bbf0031f7c44817d215e57c90e6230d95566d3", "90df9cc3a3b904415331eba9cd52750c2c5cb73cb91b42caca7eee3788fc2b30"}}; + + +struct sha512_test_v_short { + int len; + char msg[1024]; + const char digest_hex[SHA512_DIGEST_LENGTH * 2 + 1]; +}; + +static const struct sha512_test_v_short nist_sha512_test_vectors_short[] = + { + {8, "21", "3831a6a6155e509dee59a7f451eb35324d8f8f2df6e3708894740f98fdee23889f4de5adb0c5010dfb555cda77c8ab5dc902094c52de3278f35a75ebc25f093a"}, + {16, "9083", "55586ebba48768aeb323655ab6f4298fc9f670964fc2e5f2731e34dfa4b0c09e6e1e12e3d7286b3145c61c2047fb1a2a1297f36da64160b31fa4c8c2cddd2fb4"}, + {24, "0a55db", "7952585e5330cb247d72bae696fc8a6b0f7d0804577e347d99bc1b11e52f384985a428449382306a89261ae143c2f3fb613804ab20b42dc097e5bf4a96ef919b"}, + {32, "23be86d5", "76d42c8eadea35a69990c63a762f330614a4699977f058adb988f406fb0be8f2ea3dce3a2bbd1d827b70b9b299ae6f9e5058ee97b50bd4922d6d37ddc761f8eb"}, + {40, "eb0ca946c1", "d39ecedfe6e705a821aee4f58bfc489c3d9433eb4ac1b03a97e321a2586b40dd0522f40fa5aef36afff591a78c916bfc6d1ca515c4983dd8695b1ec7951d723e"}, + {48, "38667f39277b", "85708b8ff05d974d6af0801c152b95f5fa5c06af9a35230c5bea2752f031f9bd84bd844717b3add308a70dc777f90813c20b47b16385664eefc88449f04f2131"}, + {56, "b39f71aaa8a108", "258b8efa05b4a06b1e63c7a3f925c5ef11fa03e3d47d631bf4d474983783d8c0b09449009e842fc9fa15de586c67cf8955a17d790b20f41dadf67ee8cdcdfce6"}, + {64, "6f8d58b7cab1888c", "a3941def2803c8dfc08f20c06ba7e9a332ae0c67e47ae57365c243ef40059b11be22c91da6a80c2cff0742a8f4bcd941bdee0b861ec872b215433ce8dcf3c031"}, + {72, "162b0cf9b3750f9438", "ade217305dc34392aa4b8e57f64f5a3afdd27f1fa969a9a2608353f82b95cfb4ae84598d01575a578a1068a59b34b5045ff6d5299c5cb7ee17180701b2d1d695"}, + {80, "bad7c618f45be207975e", "5886828959d1f82254068be0bd14b6a88f59f534061fb20376a0541052dd3635edf3c6f0ca3d08775e13525df9333a2113c0b2af76515887529910b6c793c8a5"}, + {88, "6213e10a4420e0d9b77037", "9982dc2a04dff165567f276fd463efef2b369fa2fbca8cee31ce0de8a79a2eb0b53e437f7d9d1f41c71d725cabb949b513075bad1740c9eefbf6a5c6633400c7"}, + {96, "6332c3c2a0a625a61df71858", "9d60375d9858d9f2416fb86fa0a2189ee4213e8710314fd1ebed0fd158b043e6e7c9a76d62c6ba1e1d411a730902309ec676dd491433c6ef66c8f116233d6ce7"}, + {104, "f47be3a2b019d1beededf5b80c", "b94292625caa28c7be24a0997eb7328062a76d9b529c0f1d568f850df6d569b5e84df07e9e246be232033ffac3adf2d18f92ab9dacfc0ecf08aff7145f0b833b"}, + {112, "b1715f782ff02c6b88937f054116", "ee1a56ee78182ec41d2c3ab33d4c41871d437c5c1ca060ee9e219cb83689b4e5a4174dfdab5d1d1096a31a7c8d3abda75c1b5e6da97e1814901c505b0bc07f25"}, + {120, "9bcd5262868cd9c8a96c9e82987f03", "2e07662a001b9755ae922c8e8a95756db5341dc0f2e62ae1cf827038f33ce055f63ad5c00b65391428434ddc01e5535e7fecbf53db66d93099b8e0b7e44e4b25"}, + {128, "cd67bd4054aaa3baa0db178ce232fd5a", "0d8521f8f2f3900332d1a1a55c60ba81d04d28dfe8c504b6328ae787925fe0188f2ba91c3a9f0c1653c4bf0ada356455ea36fd31f8e73e3951cad4ebba8c6e04"}, + {136, "6ba004fd176791efb381b862e298c67b08", "112e19144a9c51a223a002b977459920e38afd4ca610bd1c532349e9fa7c0d503215c01ad70e1b2ac5133cf2d10c9e8c1a4c9405f291da2dc45f706761c5e8fe"}, + {144, "c6a170936568651020edfe15df8012acda8d", "c36c100cdb6c8c45b072f18256d63a66c9843acb4d07de62e0600711d4fbe64c8cf314ec3457c90308147cb7ac7e4d073ba10f0ced78ea724a474b32dae71231"}, + {152, "61be0c9f5cf62745c7da47c104597194db245c", "b379249a3ca5f14c29456710114ba6f6136b34c3fc9f6fb91b59d491af782d6b237eb71aaffdd38079461cf690a46d9a4ddd602d19808ab6235d1d8aa01e8200"}, + {160, "e07056d4f7277bc548099577720a581eec94141d", "59f1856303ff165e2ab5683dddeb6e8ad81f15bb578579b999eb5746680f22cfec6dba741e591ca4d9e53904837701b374be74bbc0847a92179ac2b67496d807"}, + {168, "67ebda0a3573a9a58751d4169e10c7e8663febb3a8", "13963f81cfabfca71de4739fd24a10ce3897bba1d716907fc0a28490c192a7fc3ccb8db1f91af7a2d250d6617f0dfd1519d221d618a02e3e3fa9041cf35ed1ea"}, + {176, "63e09db99eb4cd6238677859a567df313c8520d845b4", "9083e5348b08eb9810b2d15781d8265845410de54fe61750d4b93853690649adc6e72490bc2b7c365e2390573d9414becc0939719e0cb78eca6b2c80c2fda920"}, + {184, "f3e06b4bd79e380a65cb679a98ccd732563cc5ebe892e2", "6b315f106b07c59eedc5ab1df813b3c0b903060e7217cc010e9070278512a885008dac8b2472a521e77835a7f4deadc1d591aa23b624b69948a99bb60121c54e"}, + {192, "16b17074d3e3d97557f9ed77d920b4b1bff4e845b345a922", "6884134582a760046433abcbd53db8ff1a89995862f305b887020f6da6c7b903a314721e972bf438483f452a8b09596298a576c903c91df4a414c7bd20fd1d07"}, + {200, "3edf93251349d22806bed25345fd5c190aac96d6cdb2d758b8", "299e0daf6605e5b0c30e1ec8bb98e7a3bd7b33b388bdb457452dab509594406c8e7b841e6f4e75c8d6fbd614d5eb9e56c359bfafb4285754787ab72b46dd33f0"}, + {208, "b2d5a14f01e6b778888c562a059ec819ad89992d16a09f7a54b4", "ab2e7d745d8ad393439af2a3fbc9cdc25510d4a04e78b526e12b1c0be3b22966872ebe652e2f46ed5c5acecd2f233a9175dd295ebeb3a0706fc66fa1b137042b"}, + {216, "844b66f12ba0c5f9e92731f571539d1eef332e1549a49dbfa4c6de", "c3f9c5781925774783ae9d839772d7513dfcea8c5af8da262c196f9fe80135b2b0c8c6ca0a1604e0a3460247620de20b299f2db7871982d27c2176ae5fa7ad65"}, + {224, "6b6cc692d39860b1f30203653e25d09c01e6a8043c1a9cb8b249a41e", "2e5263d9a4f21b210e0e161ed39df44102864325788647261a6e70ea4b1ee0abb57b57499bc82158d82336dd53f1ef4464c6a08126e138b2cc0892f765f6af85"}, + {232, "ab1fc9ee845eeb205ec13725daf1fb1f5d50629b14ea9a2235a9350a88", "72d188a9df5f3b00057bca22c92c0f8228422d974302d22d4b322e7a6c8fc3b2b50ec74c6842781f29f7075c3d4bd065878648846c39bb3e4e2692c0f053f7ed"}, + {240, "594ed82acfc03c0e359cc560b8e4b85f6ee77ee59a70023c2b3d5b3285b2", "5ef322cb4014ecbb713a13659612a222225984d31c187debc4459ba7901f03dac775400acfe3510b306b79894fb0e8437b412150c9193ee5a2164306ebb78301"}, + {248, "f2c66efbf2a76c5b041860ea576103cd8c6b25e50eca9ff6a2fa88083fe9ac", "7978f93ef7ed02c4a24abecba124d14dd214e1492ff1e168304c0eab89637da0f7a569c43dc4562bdb9404a018b6314fe0eebaccfb25ba76506aa7e9dcd956a7"}, + {256, "8ccb08d2a1a282aa8cc99902ecaf0f67a9f21cffe28005cb27fcf129e963f99d", "4551def2f9127386eea8d4dae1ea8d8e49b2add0509f27ccbce7d9e950ac7db01d5bca579c271b9f2d806730d88f58252fd0c2587851c3ac8a0e72b4e1dc0da6"}, + {264, "9f8c49320af9370cd3db20e9b50d3eaa59a6232d7a86fb7d472f124508d7968b05", "81b002f15c4d48be8517f7ed89df302fb1435c9435efefed58f3eb8ea11910623f1eb9028a66e02121a7f08a7c604226f2324f483e91548dbbd2c441ab704ce5"}, + {272, "4ab9aa069475e54b25e5688a52dd4acd134169c858105f01a0a1b134c72d4af51f8e", "48ba5a63aba7e7bd8e420475331125a947928c67fdb00f65c4080d9a0b99c0672424e76a1ba6bd76dfe492c730f6f9adccaee7bb11571aadb31f6bb628cfa933"}, + {280, "f0c1d3407de92ef7421e42df5c9ab31d2ec0a750a9522869cbe4cabd66908d5823ec04", "9e75c5bca2c2af1d7739787f46e1d981c4f98e493d0724b5252c2fbae3c526719f1d27e6ccd0d705240281e8fbf3db75b9b3205c1413436d3b5d140004b8cca1"}, + {288, "ae8c9f8fb41b519b6d943833fe1c32d1c4292fb1ddf1dbe2eb227d9e14d31ed74ebaef12", "042f9fd0a4ed3d9fec3655ae11011c6f2bc7e457e8812b6d8be2cd45fc6c432a94558c88f22c01439618865e8e49e509c448b342ca914b120344aaf7bcbdca18"}, + {296, "da39fb86237f00303844e61fc6cfe779e42af53349839590bcd2f0e4cbbc279ec0b7e885d1", "ecb43de8c233a731b38e30c5696f8876761b7ea72efe283fd07bedf20029f47c6d2a4427823e100fb087abaf22d7eff42a951c97c3dd05f48a20163fa4367cba"}, + {304, "3e7271d2070ef095394620c4b016576c150f34bea60784613a0f660d7fa5ae56872b88c58398", "8154d0da634ab2266061acc123acb407650ffe9164a22de3fe29bf05393b2aece92cf4db00ea5b4341c31ddb7de151683c8a71b5a44d5c3175790feac67d18ee"}, + {312, "311fb67f6a0784bb01a2d5a3f3092c407a9d3322319dff9a79f894291c5fac37319fb408402e18", "1870fe913abb0a4b4f53b6581ae18322cd05328514556607f3f4d7b6a2ac8e9185d94d947d8b9c88e0efa66d89b59f7439c75fdadd1816f7412306ab2b59d664"}, + {320, "7651ab491b8fa86f969d42977d09df5f8bee3e5899180b52c968b0db057a6f02a886ad617a84915a", "f35e50e2e02b8781345f8ceb2198f068ba103476f715cfb487a452882c9f0de0c720b2a088a39d06a8a6b64ce4d6470dfeadc4f65ae06672c057e29f14c4daf9"}, + {328, "dbe5db685ed7cb848c094524c1723519d49dc66ef9fe6d57e6862a6435750bfa0a70f104f5d396e61a", "2fa6e5b2c443a68050f093e7fb713bd6b18f6274c061ed61d79bf0688a61dba1940bcc30998276860943ab038902896d0fbf59b88b07c80de927037097150c40"}, + {336, "9fa83e96b2a6df23fb372895015678e0b2c9cd18a8542c3eaa2c435a76ae4dc9bd5136d970daff933acf", "3a2c0ec88a3e5347cf0ea9c078838300ef7356f9a6c342063277c106b880a00ed2be205c13064097bd372fde38007bc306561eb4e74bba2bb20bd354aa690ca6"}, + {344, "8a5a45e398bac1d9b896b5a2b4e3566b91d80ad20c977ea7450ff2efb521d82f65019ee762e0c85c6cc841", "3c704620f4066d79c1ff67752980f39ef3d9c1023fa5a213a5265376b14a15166ffe069b51df7710d8907fef9406bf375d502ce086ac82aff17229aaa7a5a334"}, + {352, "49cfffdaf4d031e33b1d28a447450545f6c4293b38d5afbcb9883976c014f080576ec691ac1bff70b742efab", "8bcc4f1ea2b7862ef1591bfa73916665de8faf65439ddf5cc1be43cebfd5f60f205e835a2b186b675b041258c5cff42669316ce25b46a2f4d4218e102f0f5d6f"}, + {360, "2ff845d85efbc4fa5637e9448d950496f19d8d57da99b7bd3df7474822f0a790586736416714e364c6e1fae04e", "236f6f4ed6e858c02d51787e60c578f731f694f8e52b5df4ecd5b04dff14c78e56bad1028d6f626c29d85aeee151a2a2846d3eed5cfafa9854a69fea8af6d04a"}, + {368, "cfca05fd893c0f005f5ff796f4da19ba27a1e729956b8b715e67ce4b2d2a382a72ec7814f2f507b1825209a20fcc", "d80969284a4565add4dad6ab9b3bdf53446142f84aaf92d4b23dd22ee7241e6c81489ac8b246edcb6df9bd7b23d91a0c517f546feba4ed5790a2be6e165c1709"}, + {376, "cfc425759a9c36bb9f4b32eed7767af6566f68ded0adeae25c7a70ca78ec09774d16c8bc357f6d6f7bd441bf62d942", "b587a785cdf455cc9c544e756c1e306300aa3c59f8725012e68ab4d54020b6d227a164d9f83c905e86f8cebeef708a69f976d6e7b18b9bf78e9b98cc4a5cd1b6"}, + {384, "097c9db919515242c99d973acb1dc4ed482768f974eb83b465f9f6c82503372006e4490835e2ec8f92301130bfb790b2", "ff5a376f938e73014caef7fe3962944a7230d020b7087869ebe7ec70302721cd06fcdc981c893a425d05e2f99fe198e4db50a088aee2bf1263212110efed422c"}, + {392, "77e73d387e7bc80419ebf5482b61d5255caf819fb59251ff6a384e75f601ea026d83ef950ed0b67518fb99dee0d8aaef1f", "c4c89cd882ec945cc888fb9a0127d35e585ecc14a75e4b5b3d8330538d22da28cf6af1ebec96dc247f109cd2aaab9756e6946a3d80db8363a4da3e6ddbb510a1"}, + {400, "317e5d9ac73ed0633fa18ebebbca7909ec3a5ef790478f9c38cacec44f196d895835b425774483043341381e7af2d383e51a", "b10bb04491b9c0c334709b407cda1d503efb6b63ee944f2d366b6855e6e63e5b80115be4be7ff63edecdfb5923792e68123976d79212b3884dec2179d1fcf382"}, + {408, "209461f20666a346fedf4a530f41a6fa280c43665767be923bc1d80bbcb8c9f8f93ad75782ea2689c8c5d211d2053b993145a0", "67b7a328d9444056a52ca2f695c5d3f3baafb625a14fb32eee8ff26a40ccb296bec1771a826b55f7ddb6170d4caf7795b612448e66a0f19356fe505927149b47"}, + {416, "5d61aa45c446f3bf93604b0511313b4e2f306d6b046fbd94797b926746836f2e1dbdc56124060c6ca9c911b1122192d112420827", "d3931bde2bde8271ed18ca0b9148b12f6f16161e637e376fc961f65bc33bcacf2f6addf26a3eaa81b196653cc37e8a739ec5b3df870d8c38c8f28691c22a39bb"}, + {424, "9288c795bb0b86c0419d9c5637dcc37b39bfa18d441e3fbfca75bc0306e5432e8e7b3a5627b5bc7fdc424a77520abdff566e7f2bb8", "e363d0e95d8cd18c384016ebeed6d99c4fa2768e2bd58fca019c5108b9cde1cb46f3f884028a55ce282ec310a10037faa1b16b4a6a669957f0b00f350bbd63d0"}, + {432, "780427dc164b2f69b8c7d569266f461e2d30c88c4cd6057fb030a6cf636f24e3c0d0db742a7b6193fdaa15eec50dfb4fae6ec7653c91", "2964b009fb1bf996de12e030b9d6e0608ae8b9dbf2acfb9beb76fc5361cc104ee85c2a46fb7b4cee90848312da302de49afe61c546477e2b25d223d5e3d33560"}, + {440, "ec2a92e47f692b53c1355475c71ceff0b0952a8b3541b2938270247d44e7c5cc04e17236b353da028674eab4047d89ec5dad868cfd91ce", "c83aca6147bfcbbc72c377efa8d53654ba0830c5a6a89e1d2a19b713e68fb534640deb833ca512247166dd273b5897e57d526f88eef58f6ff97baee0b4ee5644"}, + {448, "c99e31ad4e23ac68e15e605d0b02437f8147c44f5445a55b68a10905276cce8676481c33e8cd3efe322bb13fe0107bb546ccbec7b8b38d10", "52992d45a88221d972958e9f2854adaa9a21d2bf7051e1f1019ae78004da50c5b55c144a02afffe539d753949a2b056534f5b4c21f248a05baa52a6c38c7f5dd"}, + {456, "9aa3e8ad92777dfeb121a646ce2e918d1e12b30754bc09470d6da4af6cc9642b012f041ff046569d4fd8d0dccfe448e59feefc908d9ad5af6f", "994d1cda4de40aff4713237cf9f78f7033af83369ac9c64e504091ea2f1caff6c5152d6a0c5608f82886c0093b3d7fbadd49dfd1f9e0f85accf23bc7dad48904"}, + {464, "5842512c37312511a3d8ae41f5801df60cd682d58b4a997342b6e717e94006c214813e6c63e75591f957a7ec301779838bec8ae3ed7febad0805", "9763c43331ad0eb279d704c5f6e97e02da8724115026827f889e9fcda21f60fd230894ab35abb719890f3afa51afd31bc6852183b9c51059910af460abd2474d"}, + {472, "ca14e2ea2f37c78f78ef280f58707ec549a31a94361073e37701bfe503e4c01ee1f2e123e00e81a188f08fa050825709128a9b66bb8ae6ea47e41d", "4600e022a02258739f67fdd367cc1e662631fb087918768352062b9b3c8de8dbca0e9ec751b91f284694fbddb8d325c0637bccb21dd2efa92e48dbab2e5e9c26"}, + {480, "647629c779b24c1e76f41744aba17159487532a0156a7d8264db50d645e9595ff81e0c96a850f2aa56c844c613a4b892727a9bfc3d3e20386766f805", "5bc842fc2d3b7eb31d2d3044df3ec32af114feaa7cfc27ebc8630f46ab6f0c543f59b812e776e5303861d17da3f1f16097641f3b808d4d5cb3e483946409746c"}, + {488, "1c5dc0d1dd2e4c717635ff3e9b67caf957aec0f8f63c1b1e221e800a4c14848f4ea06e644e5d3e1de592ef5a8007fa3f07171b24bd07578d68963e5cb1", "cbf1ea86fa5b3dbf67be82fac41e84cccd0d296c757169b37837d273ccc015eecd102b9ce1cff68fdc7f05d22f2b774734f62ded54c8ee0bf57a5a82010d74f5"}, + {496, "8a555e75477d065b3af7e615475f37c0a667f73a4c7af5e4a69f28a68d9f4434776a8f90eab7f1d137eb4b22643c0a0d6a16fcfaa1bd62f2783546a9695f", "c088e4a3d7da2f6f99a8f3f717361108872b8ffef921b383c24b8061d4e7c27fc56f4f20dc8f952a14043c5650b5a9e777c49c41cfeb3f2de97ee2e16b2c3924"}, + {504, "ebb3e2ad7803508ba46e81e220b1cff33ea8381504110e9f8092ef085afef84db0d436931d085d0e1b06bd218cf571c79338da31a83b4cb1ec6c06d6b98768", "f33428d8fc67aa2cc1adcb2822f37f29cbd72abff68190483e415824f0bcecd447cb4f05a9c47031b9c50e0411c552f31cd04c30cea2bc64bcf825a5f8a66028"}, + {512, "c1ca70ae1279ba0b918157558b4920d6b7fba8a06be515170f202fafd36fb7f79d69fad745dba6150568db1e2b728504113eeac34f527fc82f2200b462ecbf5d", "046e46623912b3932b8d662ab42583423843206301b58bf20ab6d76fd47f1cbbcf421df536ecd7e56db5354e7e0f98822d2129c197f6f0f222b8ec5231f3967d"}, + {520, "d3ddddf805b1678a02e39200f6440047acbb062e4a2f046a3ca7f1dd6eb03a18be00cd1eb158706a64af5834c68cf7f105b415194605222c99a2cbf72c50cb14bf", "bae7c5d590bf25a493d8f48b8b4638ccb10541c67996e47287b984322009d27d1348f3ef2999f5ee0d38e112cd5a807a57830cdc318a1181e6c4653cdb8cf122"}, + {528, "8e8ef8aa336b3b98894c3126c71878910618838c00ac8590173c91749972ff3d42a61137029ad74501684f75e1b8d1d74336aa908c44082ae9eb162e901867f54905", "41672931558a93762522b1d55389ecf1b8c0feb8b88f4587fbd417ca809055b0cb630d8bea133ab7f6cf1f21c6b35e2e25c0d19583258808e6c23e1a75336103"}, + {536, "52761e1dac0eaea898e0b07cd24f4b2e6bb7bc200ea4b0528842f17b87154559a2ea94459a0e480ae0bdf9f757dd4a335aed0e510138b024a04ed1d591b4323234dbd5", "b826fe80494e19c51b42f2582b2d080ba6b90512f35f2db67dd7fd5ee532eaa16498afba08b4996cbcfdf8d1a2df6b1da939e8265115a48aefa42f38205db436"}, + {544, "3804ebc43cbea80c2bd7e4fda5c5515500cd2d2b846a1378dbf218d5c377138606eb3cb8ac88f9076f6ff4436f90717427c9df1ba052acbbe4585e98b6e8e0bf800f1946", "17dd6d87bc6773051e52047fd444996afa8124b0483fe121877f98553448772bd0e7751fc655e9cc2d29830211015d310f191474ca6adc0477a187c03b8fe252"}, + {552, "2249d698c4d807a8e7b4de21c485738959a0d67e5d2ca6f77983dfccb5dbf47931261e1f1537f3cbca253afb6bf4fe5e7672e1dcc860b3d6c8d243afe2d9758b375e955692", "6af44563fc468d51182f6c3be58d45932af1d985c6f283976c91a9ff421f383fe21dc7322f397ccead583e26b3e3fda067976a7f34665df25a2ced7b4b09cdec"}, + {560, "32a9c17033658c54f22c7135ddfc879de94d79593ef2dc7d3041bfa872738389864eeda27801794ccc4ff1fcb5ef3fc48833801d6fe959e3627f8ea1536ad00fa9c7d7d9f043", "6a47699dd3ada2f11bc4ea42072b06cc20857bf164497df1285400c250f5848b6f71957dbdc845f5daeab913036661f69387893fc2d61c25fa59b9d85b19f401"}, + {568, "3d65f69a590a5baaabcd274fe3ef9e88920ffc7adf05c16d7b0f4d18d72bac1e94c3b3d83b8f4c552eb80e9fde3911403f8b000579816f02e1716fd627946031d0af0793e7f3e1", "ffb2d9450943c24b5933c24812459b75d3d9f380344c9bc06fa3e17ee448eca2f98ff79f7e2235ccd9f9a8176f68a2254bbc9b834d6ac8d2bfdbc1597c432c9f"}, + {576, "76ff8b20a18cf104f6cdb65e2ba8f66ecf844af7e85e8ef2da19e8848a16052ec405a644dafb5ca08ec48f97327ac52c0e56218402c72a9a6dc1cf344d58a716a78d7d7529680bae", "f8858144c6d709dd0689a526a548a43f17494950ba2ac20544799e8ea27201d78bce5b921e29a7b4029278e68341ef2a0ca4ba3894566b3c8f8950e3e545a689"}, + {584, "ca88dddfc876a12f45f19562bc9ca250f43267ab251a7f345c3c022e20144e135604078762ef5c8a8f038cf1b1d6a91709b59dd068396a9e971ab628f74886e765384a23607c1a1e6e", "4f3d9eeef349ca51a7e419af1686f42795abde58a85335ce68d496e81e4436a80a61dc143a4300008c23a3e71f4ba98743195a3694a8d02fee11bd314569abc0"}, + {592, "0a78b16b4026f7ec063db4e7b77c42a298e524e268093c5038853e217dcd65f66428650165fca06a1b4c9cf1537fb5d463630ff3bd71cf32c3538b1fdda3fed5c9f601203319b7e1869a", "6095c3df5b9db7ce524d76123f77421ce888b86a477ae8c6db1d0be8d326d22c852915ab03c0c81a5b7ac71e2c14e74bda17a78d2b10585fa214f6546eb710a0"}, + {600, "20f10ef9a0e6128675340171cd248df30b586557620b615ca39a00db534315a9012dbdbfd6a994986eb829dbe6cdaf3a37d4f59ac27298742c8f777b6b12677f21eb289129579868705f27", "b4ead3f860eabbd36c770d66c7356f8107acd1485c7c94178c2eaabd50266d7645d009972586ef83ed43ed92882137df5117b88f35231b894ec1741ae7501145"}, + {608, "995c8f747ea418f7d63aba2260b34ac3c7dceebb78438ca4b1f982b7db9798ec1a7f32622264cb024c0d9e60e955a6e1d677c923518851990a459b767d0f13cd803460f61870db3391b44693", "a00a601edeaca83041dc452d438a8de549594e25d843c2cf60a0e009fb92d87abe28a72690ab657c8d35b43cd02d22ec0755de229d1f922fa6ca18a6d6c2aaae"}, + {616, "0feb23c7e4a19bcbd70bd300d76ec9045d696f8c9687f49ec4154400e231d2f0862495150cf250b6f12f172a7d130f8fa5d175bf2f25e280172ccdfb327951701165302728a619aa2f242631c9", "eeb6dee30c119fb1e1eb5c15ff2b32d8b9c7464a4e4cc6815cd251a6bae29b49961dd5c2fa9c44a9b142ca062c7072cbf3db04299b767789040196bf0c06aa76"}, + {624, "ac59a110623f1a64666f160ed32926676cb5be25dd9d962f441951b0efcb5d6a67ac1a4eae473e49c6257860728853ff415c5e8ec76a8a462ecfd343eeac22dad820722c597332fbfd94ebbd32c6", "f65ea942ae0a47e73b02b1442e5b26083db79307f64dd34a039c476faf18d5c514bb77a2c412a6074a7afc326ea66c74e5705fe2abbabf274333325a15b61fd9"}, + {632, "9e3e1077e1333a1fb1aa633ccf2f746588ad426489ea08dff5511438b5f4c0b110d1a4d47b540a12b21ea2aa070578ccfa5c22fe0b743ec0cc621c6b3a03b75f4d3eea5dce89e03269afcd9603d0db", "4b5c5df80c344c12388c723856cd06965b2190af652480476747dc2195ea3716f87c1762359583a5f31522f83f7833bec30f1f47d14540417dd463f5d258cd4a"}, + {640, "e881e3284c79d8f5237e699e4fbca84090c664bb53229f58cb0842b0436710c9b329d98191b8f030e9c1df89b03858c1569c6ff49a7c07c4a23a8a434b0fde13be4f94cb44ee629d5b44d336090d3de6", "147d8071c7871ef9256cff32aa63ea031404fa5ee4ec09c56afdd5da919b0cc84a9d35d142c417715203316011cc620cd6855bb117063a5e52867facc680d5f4"}, + {648, "e58521098911503de84311387d375c25929e6e55076eb6934fd8f2b1bb7b9667fbd76d5ee204828769a341b1f716da5bdfece6c62a9f4d4f988267fce1f5615540dbe375324eef607c910d976b45a5ea5f", "f97ba056fa41f43b8e1987072a09e828c71c5ff6ad4e37f9ab6b89e2a078933dd23052fa72c6615b613904259e9ff9b55ef7b923b89bc8752f6babddd256e117"}, + {656, "3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c9f133e5f8527f1b184830e07c3458c83a8ca9f9d9c6998760e610668ba0f22e22b656a737e978b246a17840b7dc4091da85f", "c8a466199acbcbc93f2ce042968508c046901631e3118a2d0bf39a9b42b4197a379b3a86cdeca9df2de1a3eb71b79ae9bf2d6575eadf1878029c4093133f54d3"}, + {664, "9af608d031ccf309d7273c607a8e5e36840d449b55db5b13f03aeb9af49fa7e7cf1383ee2ed9c5a8b7515f16fb1c7c84a681590bf90f56597b844db5ebee223d78109b72350772f7c72ea996603e1e84f2ba5f", "f0ded9495b4f64cac585be8a737cfa14247a4a81cdf7f01ebcb134ace71f5a83df2cd72e7773fea1e82beae17e13857372792c8231e2ab9fbeb633e399d5f0ae"}, + {672, "d0df1bdf1df6203241722fb9c9c1cf7405017497ae154538ccf9224ad752e6ce1d4ae948639aca70cfe86b2b06543cb9914ebd3085aa3e2963f6e9b93d0b03a31ae26fcb9ca974eee016c091a6fcac37b21cc1d7", "c2da3ea3c8a3fd88a5bc5dea2bc076f861abedefae5a5fbd941ddfd1c41cc3312eb2dc826c2c0f65414fe72ebee447d2f9b1a6a56302660d1f86632ee80a175f"}, + {680, "8cbc9480553acef7bcdba9716ea8d66b4131780917de2b0b048045fcb32b5cac054808e1fce6e94ad851ecb47fe6cb802225d3551e08ea122093d0078dada564212eacf1d6394e0007cc62a1d595ab14ca08a284bc", "63b39b88ceb848188b37316e04560e75a5340ab8d417932d231c997e892b41daa69d9fe3e9a14dd19ccfbbfa01488c208e7b946cfaf16ca2b1bf7c8d8da4e6b2"}, + {688, "38f184448f3cf82a54cafc556aff336f23f9149e612134b3fc00c8a56455653d88640b12f69062b8432c4335ad8f7ab4ff66cb7eb54f332561a36f024d92c3e26276f4fd48619628cff88e4b8e85cf14ca4767ed990d", "9a49265fc641c59f1a91872cdae490d3da73c0c60fd59648e1d17dba1a647a5b95629392bb4ff5163d1a3cb45427c1437a3b2e1d9f030c0a8bcc5ed22da9e2ed"}, + {696, "70900618b1e9e9db62296fb6c6590c9f10b0a632765c489c887f1ab7c07791765a62e38465e1be281b1d396c6e080b7ee3e6fa56a30b9799d0e629be153ee76f81bc6a3295aa61489bfa87d53a8ad24248a6ede0dfcfe9", "1c8c3357ff1f8d6ac4defb3af462a73e09159e3a20c6506edd8cd3052df941c81f68c5fbb893912619e28640977fe8eaae8e9d5d4e7d5f132552cefab4540bac"}, + {704, "4e6ddae0d805afcd10a055bce584c848d050fb29fe8f1c64b18e1abfe46b65782e6ff536e89d8d40928b41ed7371365c8080a9647f7532ce6c6d4ac21cfb0c8020783851ec9a7dbc3948f8fca7adf8b2a78c04d898d31ff6", "5c2f996c779b91b3c4639311f54fabbdde7e2212b53dbae4828c8399588fc00d3b2ae60918aaaf6bb48bc757e52b2bcea84f5d15bf4ec25d5519fb54f6f26e1b"}, + {712, "696825f6d6ea8173ec47d0959a401c4ddf69f8f08ddd678a4d2ff976e3a4372bb39f4159845cb63585e1d4108d32e12fa7c5c9d7ce3508a7f53aca2b4bd951adbcd8984ebb7536563f5884c90bc5023b3316f7e4dc6958f743", "3ce940ca96b00011375daa95c65f66907d69b3eb3b8d779e6fc971afcc05e990bc4c541f434590f6b18b68c080d0f24475a3e764e9cb85343301314ee2fb661e"}, + {720, "79ecdfd47a29a74220a52819ce4589747f2b30b364d0852cce52f91e4f0f48e61c72fa76b60d3002cae89dfc5519d3430b95c098fa4678516b5e355109ea9b3745aa41d6f8206ee64ae720f8d44653b001057f2eba7f63cd42f9", "ba3d0fe04470f4cf8f08c46d82ae3afd1caea8c13bebbe026b5c1777aa59860af2e3da7751844e0be24072af48bc8a6fd77678aaee04e08f63395f5c8a465763"}, + {728, "9263fe75e8f6c7d5d642e2ca6a6eea4f44e9a0f249513ed79c9409ffca5526ca4491aebb1382057cc7c36722b0b6c3b15123cde312214f25353abfe30bca170568a8e1ba5408917403a01834080ab607c56a10d0265082498fe0b6", "7736d7a7fc1eb05857ce7d88abfffa87f58c670bfdfc0a8031f60f379e4b6ad94ac8f13ffe28c697809b5cfac7f13be01e7496a85237c4025539051fb2e32fb6"}, + {736, "78c17bfe0e02eb526d1a44a1ac127be082181452b625394bd6dc093a2cb432e6ee59c2f8b5503aba30dae41e1a1c6702697c99b2c94e94af48b00caf53b2e0e4e1bbee81ee282c7b2b35f58cf421a07e828d57a6622626af25835399", "b56b6e343166328523e0d1693e5174da643ae83cf69c85a7b3c3bee247b77b84702069d9e6b4cab03bf17fe612009bf4239683ca78ca7e876aca7d07603ba714"}, + {744, "298bb304a920f960447d8fd38b061bf8fe4ac1f871d8a0feb4549feb72ca694a5a41b6867d94cd5af77d468ad2f315d127b6c41a862800f3985e573e037740298e2c5c6186a9fb83609be2d49f8b4c31f96a2e49b56dbf09571b38587f", "34e3878627904ffbbbd85266cc973c34f931e3cab5d4c31f841c553dd69f84838206067df4f9f3b9102001be19267151e673f5c2d4c2f8438a6999a0a325487d"}, + {752, "a3cf714bf112647e727e8cfd46499acd35a640dd393ddd263cd85cf6225f59890a0686dad1c54eb8d809b81c08a98dba131bbdd6fce8ff59d95db824d8831ea480529da739227a6e0f62b603b38c35cdc2581f614a31879b8be54aeefaa0", "6f230ae4903ddbef0ba384c2e3506eab318bfd1a46ea76099f65a3fd529c91bc2865b9fd943e346de64626b8529f9db1377bf2c5e0129c66b50c6a5cfb364b3a"}, + {760, "0a427ae55ef3a7e6044a08cf6128cbaaabfd776c4e9374708f2ece246fd73603d2f54ac3e01d16cfac2bdaf713920d66e8f0a3d54ee68cff64267d5528cdf2f295f474d10f81173e0143488ac53fc503c444ed23dec63a080ce90c2443dba8", "f6bbe5d0cf13ddf41c1436748a5d1ccae2948547b452c2171c7c8e8b66c6ae4de3c0e8b2962bcb60d3de3608479f80e455c9024d9716c38f6f1206861ab1eaac"}, + {768, "2cbbb87511f4948efec3a61b511ededb1dda8b6ecfc0210c11e43a77ee32dc2e374afae4268e3d30427804868232a966b56006d3214037076bf6a265b72135af0fb2ef7909fea2dea412f7717446b276ff153753662b4d4148c02347e3259169", "76897b87a8a1cf835c434f6d391c9e5227351af9d3e20a3389c796b98b424281a59068d9c8d567ec2bebc435b0126b059e2d86394a9854d6611e1c922f385496"}, + {776, "2b23324c9992f60a7fc010159a03cb9a2b290df4fa6a82359b9af602f0a403a5ef33ed5da5b2caf87b77e6a4b93b650348ce2a7dbc08f8da9203d710b587ba5947c65e899f4a759f8e2b049ae7850a8e3e2962f6ef93ea4c631de5d78e729ec5bc", "3beea0b373ed09cf1c919c51d86d642c9125e0ee81698dc4cbadf02e9e6925efb562fd9b87301a6377ca192be79c4118deabc450b54639000c2e312945451fb5"}, + {784, "4022f930c7033b00d986c65ff6bbbdf9ebd0e58c52844ff658df3893c3202dc533f873d4a7f5a5f944419fb5528c9b6788479a1e891306acae7995fc06db70a59baa95bef7da79f5e793f2db7f2a55825e4fdb4a34884af881ded1089fd5334502a2", "0358775bbb733ccc49e78f544aeee512370d480d0e13c7e8d5c444c423e592146b45fdb91a1b694d35e36b60e4bc8397fca8bb9790e619339778b9cd1abe3fe9"}, + {792, "1cb77ba43ce77e236b9fc925f589b1c070780a84f99e8f50c1ff846ac92599cfe91612c8178325bee642a34f4dffdba2aa2ebcf7064339829b26f27993e1106c139c70d578cc05f0e1a777cceddb10a2c67fd9675e4a009df8037d6eeb38f5fba233df", "6502f46551a3fab3a96428fb97801d7a4aa2f17fef6603238df84e17c74309ed3d9489c8b16a9384ee634a3f86d0b3ba9a4dbc9c51ec8bd4bf8d61de6d3d87d7"}, + {800, "52167de2d6c502d99fa10c27b2ab6203bdebc2cafbbfdef15872a43dd610c2362f796ad9bcb5528d95870058fa454453f1e6065b315d410a3f2650e5d71e69d78d9767dfb4accc057fd2069266b0f180cb319e30ded7535bbe52d24be151de4bb598fc5c", "25cb3ed3983a91b4cf37a65193916c5e3e211b63e943e2f7b50a85d349a463b941aad33eff16561bdfdc92fda06a4e1d94b162de48f06d3c626940b31020925f"}, + {808, "cede6697d422ddaa78e2d55ae080b8b9e9356c69bc558201a2d4b0b3190a812c27b34bbcee3a62b781378b1bf636b372bcbae1fa2f816a046a0a649a5c555c641fea4ccd841cc761f38f777972f8c91b0324e71c333ce787f04741439bf087ef5e895011c0", "0be42a25d77ac6ad995c6be48e783380bad25a61732f87cefb0cce1a769cd69081f494a1a12d657664ef2b4d9c41f2ee83f6e9a84327d8756af9f985595e7d3b"}, + {816, "56d18d3e2e496440d0a5c9e1bcb464faf5bc70a8b562124f5fc9e9deb5fee6544b945e833b8b5d131b773ecb2cdd780cd4e1bb9e4f1e3cb0a1d64d19cf4b30e44e6c2d0cbcb4e284ce50db7a8a8062ddb63f981d9026c532bf8eeddf8af5a43848a32262178c", "982dc61c91a93770582eee8025aa55da8e9edb966bf5cf70d4a6534c0d53a2789a8c4fb65b7fed478cda02ed1e0d198d85c5c735b2417c5fab5d34e969fc8e7e"}, + {824, "25a7320dfaec5af65da4d0f8688e29e8e95532ecc16679ea8aff0f407d898db6922855b0e8901aa9681aa3dca617cb440764cdc7293fbeaf7f585b593c2b0531738e0ade7c8626b9995f4a84d9fc9b593d6bbee01abc53c5be14bf6956fd2fd81000dafc7c7686", "749c928c3d5510925bfe98659025b0ed7c01acd4d59a9bf1c54863a088091771dc9d407bdbf83b0f44b0902e10349ba79c84d0981d5e8c4f5c733a117fed0790"}, + {832, "3d7177b28ffd916e7e0634895833ba0bd9e0653df2cc4202c811536a005aec853a505e75db55d3c7107579041099e382a1feac80dde65d72368e909ab85f56d88e68d7c3c80c38f85bf8c2b36959409cc34ba8e3ad94fe8ee1927612d672d92141a329c4dd8a88a9", "14a331508cd7d94fcce56a66bf65f20870a281c8442f8dbd4c2371454a2b66f8d0994a0b67692e771efc6a5e0b887acae7d6f4ec7338e1aa89f2abc7034c4e4c"}, + {840, "c033e4a512297caecdbead892b11a9f7007af9a74bcab89e0bd4ffdd542ca03ea12e17a06c42bd43fc5f3f757fce4f6f5831997abac3f95676e1ebdb11ca43e11aa31e5ebabe18ce8d1bbfd8b02f482e1ce581b532e307e6960eb97441506c2ed299e1282523f41527", "95ac9b7d22aa458921874c4b4331e7d64761853217c3f83c601abcbccd7e2eaa6ca6ce9a22ebcfe5046d52f8a09097f043ab8bc59243fd770090bb432c3155e9"}, + {848, "69fff0f1a3dbfb36e32f025819fa99ea9a0edaef73145bf7fcd05d8bb0a646cb3b5d5256d524856acfd2e44d6b72e4ebf1ff23c0ff6c56f821e782d5a15f7052a1445b06668eeb4af700679ee7ae26496fbd4640c06aa149964dfd6011df835ac13b73c8ff21151e8440", "45d4daa652558d1c12beb0f5662c712f325b4c802fc6eb9ee039c949d002bb786f1a732712be941f9c5c79b3e5c43064d63a38578e5a54ee526acb735b9ad45f"}, + {856, "b2c439c97ab7c63736b3796324d68eeb7a471ed142bd9622684167d61234fff82f93f907537a909bc2e75a4bcbc133cf57197662c1af746ae8b81e5b83de05d9b589851de25d3c99c004c1dfb12d93bf50d450af49c428716f5b90ef088e3b6a6b2c46d3ce67b379599018", "c48ec83be5fa669e6ec8db90aca9676cfe2ec0d5e8e7a2431687bb953c0a300be3db4075cca3bac4dfa4d971baf0fa1aff46639db4b238856ff36d1dfcd520f1"}, + {864, "c016f522f26b7470e922b9a287e6d45f6c28813b68c1457e36d9ba266708272f9cbc5411f8db9d8bd5a9449fb6eb0cde7d4d03e5df019f2814a90ceed377c59d7d92623899bcb0268033073559d4d8de488686cbe3d67796e6df6ad4276d0b52cc62c49ebb58d7c95287aa6c", "7402f1a99b47e102b3b73140c6771b07ee6c33b3715e9c4027c441bee40511b735d95e508baea78da26fded9b7038e9a53defa58448aba40dc1e62d7ec592107"}, + {872, "a766b2a7ef916721f4677b67dbc65ef9b4d1bda1ad4e53fc854b0236440822152a111939e5ab2ba207719472b63fd4f4a54f4bde44a205d334a2d72cfe05abf804f41841b86d36920be6b0b529331ac163a985556c84511ec986439f83e1d7311f57d848cfa02df9ea0cf6b99a", "ddd60f93a3babc78299cf763e7919d45ac6f479700e1adb05ab137acdf89c1521ecb9dfeacd091e58ca57a1db964a9c3cd1fa39192cc1e9f734caa1c5fa62975"}, + {880, "10f2be77a4055771a67007cd8630e3230e38288499cb160380290174d66da57455b6baaa9785c84c8a663de41ed3bd544055b9170cec43cb3eb120eceaba1fe36e3eaa3fa4f99b425cd2519f09bc0282bada52d14ce625b1ded3b24d86b1dad342d2b7be322b775b04fc6b86afb4", "a872fa33d463b3343cec57c20c66979c33e1ad067bfc703454696aab5dd0003bc194318f4a8ebbc74503feb7211a472dadee991efe3e38f21a1310f8a76eac80"}, + {888, "324533e685f1852e358eea8ea8b81c288b3f3beb1f2bc2b8d3fdbac318382e3d7120de30c9c237aa0a34831deb1e5e060a7969cd3a9742ec1e64b354f7eb290cba1c681c66cc7ea994fdf5614f604d1a2718aab581c1c94931b1387e4b7dc73635bf3a7301174075fa70a9227d85d3", "3b26c5170729d0814153becb95f1b65cd42f9a6d0649d914e4f69d938b5e9dc041cd0f5c8da0b484d7c7bc7b1bdefb08fe8b1bfedc81109345bc9e9a399feedf"}, + {896, "518985977ee21d2bf622a20567124fcbf11c72df805365835ab3c041f4a9cd8a0ad63c9dee1018aa21a9fa3720f47dc48006f1aa3dba544950f87e627f369bc2793ede21223274492cceb77be7eea50e5a509059929a16d33a9f54796cde5770c74bd3ecc25318503f1a41976407aff2", "c00926a374cde55b8fbd77f50da1363da19744d3f464e07ce31794c5a61b6f9c85689fa1cfe136553527fd876be91673c2cac2dd157b2defea360851b6d92cf4"}, + {904, "9159767275ba6f79cbb3d58c0108339d8c6a41138991ab7aa58b14793b545b04bda61dd255127b12cc501d5aaad476e09fa14aec21626e8d57b7d08c36cdb79eea314bdd77e65779a0b54eab08c48ceb976adf631f4246a33f7ef896887ea8b5dfa2087a225c8c180f8970696101fc283b", "3cd3380a90868de17dee4bd4d7f90d7512696f0a92b2d089240d61a9d20cd3af094c78bf466c2d404dd2f662ec5f4a299be2adeadf627b98e50e1c072b769d62"}, + {912, "fe2d8ae200e6657fdc7494af5a12b2ae940348f1f983f0ba98febbe99c80d115126d57dbf37296765ebb5990256696588b3851d54c8fbe7ade98a6faf7c20b5e4f730f54a7f912ca0ac31bbb53d17949ef69aa0de40c7bab12a871a9b90f68813ca87af4256422a268f4a1d8ec3aa1a947fd", "8025a8608df0f6a01c34cdec012d4cb25852e1b100b68172fc4e86ac8b7126b64859cb9e767a7e59060989cedbd925afc475ca7369bd43f85ae590e224e036dd"}, + {920, "dc28484ebfd293d62ac759d5754bdf502423e4d419fa79020805134b2ce3dff738c7556c91d810adbad8dd210f041296b73c2185d4646c97fc0a5b69ed49ac8c7ced0bd1cfd7e3c3cca47374d189247da6811a40b0ab097067ed4ad40ade2e4791e39204e398b3204971445822a1be0dd93af8", "615115d2e8b62e345adaa4bdb95395a3b4fe27d71c4a111b86c1841463c5f03d6b20d164a39948ab08ae060720d05c10f6022e5c8caf2fa3bca2e04d9c539ded"}, + {928, "5af8c0f26db4e99b47ec2e4a01a786e77899e46d464ac337f175027b61aef3149848af849d76ac39b9b0910fe6594817859e55974fa167518ed72d088dae6b414d744d477974fb719c626da792f981233de24b7579d8acca510a266d73c0ee8ee1424343eaf6ffcc59c86c1becce5894072c6c11", "09da284d5b6556508be54c8ab6c97bbd472995c6bbd585917ecdb54ea9167208daaa070a7b2b7d8e93ce1315f0d1ef8d69667429c44dc5ee1499de57b229a398"}, + {936, "49cd0ba0df5bb3f43f68464e3e83e9cbd5d5ee077ffa5591e30f939cb30c93f7d454fb3fbf8bb05327a89c08dc4baf1eef50237317a405775357f1e0d1f31d9f0f0d98124019d47bf18363b1ecfbfe155c10cbc83300e01bc9ce0347c596b35f411e6d8229ad2855e42022b0373ade98663c6d6e9c", "30cbf0679a97c871574d2fc05d7aa760c6bc8a864b7d246c39b9e812f9b7ff7b4ef5197dd5b69493306688b8564de1ad47d75505c913ba6a78788f8caf5788bd"}, + {944, "a8a37dfc083ad2f47fff468738bf8b728eb7f1907e427fa15cb4424bc685e55ed7b2825c9c60b839ccc2fe5fb33e36f570cb8661609e630bda05ee641d938428867d90e00744a4aad494c93c5f6d1327878078590cdce1e647c9820818f467641fcd508e2f2ebfd0ff3d4f272393478f3b9e6f806b43", "8e1c91729be8eb40226f6c58a029380ef7edb9dc166a5c3cdbcefe90bd30d85cb7c4b248e66abf0a3a4c842281299bef6db88858d9e5ab5244f70b7969e1c072"}, + {952, "36af17595494ef793c42f48410246df07d05936a918afe74cd005e537c586b2843701f5df8952242b74586f83339b48f4ba3a66bdeb457ecdf61784eac6765cd9b8c570dd628dbba6ae5836b9ac3dbcd795f9efdb8742a35bca232abf36eb3b6698b2933965802277ba953a6edcacaf330c1e4e8c7d45f", "158bfc348a30b4fabbe355a7d44bdc2122a4c850444c03f289003ce01bfc1ebf3ecc0febb6a8ff523d25db7681b05bdce048d11943ab476c1967cf6556c4a120"}, + {960, "42d66edc5f22e0c13c25504c5101a5d172d2db7209e461efa323c0bfaed27e5f808042ea9c3838ea31f9b76de465225ccfbd0c09ca0d9f07e9a43e3e46c7693e00a7e1d483900ddb0a629d5563456dbbf299ac91f92c3d3c17b05d180e6c87c6c93194c39d90273fcf4a482c56084f95e34c04311fa80438", "061afb119a3c60876e04c10f12ad0f4b977593dc5a2d21096a57e7d3f7d4d44fdef934b2c17d7530674e4f4a1c176dbdcc54811a22e1b8712e4192fc2d4bf8e8"}, + {968, "f91bb2e1a9c4cd96bf250426b3a6afd9b87ac51e93254d2dae3b16ec686ba80fb0bd7a84d218660e9007593075bc4f4c66567f0c7a5fd2010c999a8a0efa81f89ff5bfefe0fb910f0442e6d4a7c55bbb618c69a79a2ddd82a0938927f6fe3a80f04beaeb7c7636e3435d12dcf1c6bb6ed0a4edb69c9657fa93", "6e692c8c694ee0a3565f37a299e0006b85ab4a821b20e76798220229f656efc6a20211a4e7e4ed77facde0d70e4d5d95bc8ed1d7a56d8df1446d562f044b344c"}, + {976, "d1eb961ca6a8f67c49b61e4d3ceaa2a1de6f0ea927b132bf987abdaa725b0e1e274e46830e99a2f75af608964df0dff9a99024fc6839bac5acd10202f921ac71a27fcda681aa3109ebf5f21ee3a849098ea3a551e844fae4b48b5c5bb97ccc802bc5520d68a14cb7e5fc056b67d889d876efb82d0e9a9a2499f1", "39b2c76ec207120de4b320c7fe069e602c9c38f257596da7369395e87eb64b3acff988c1839ac269d5012c093f9edd4b7cabf13bdea7d42e969ab108269c6ab0"}, + {984, "adf2263200f376886ba7b6f5e4411d5f07f7d9d101590c73ace114bafbcb0fdc99269e87cd2cead2a1cfe5744394d333aba408a07e21f30233b65b907472e9e3c7d6e7aa6d2c47a08a1be7bb877913a6b5604c723384478911c339e3b5fe527c7e288705a89c95d970b443347897e79f6c522bafe62b11ef8f3135", "3c23d2d8cf4db6ac6a42e27208180f37668bef5ee0a3f879483c8e604e7f42583f202037b8d242c04a87345b8be6dc8b121d6484b9edad0d73c894c1288f5cae"}, + {992, "18e75b47d898ac629c48e80dbfb75dae1e1700b771165eccdb18d628bfc4063dd6c3839a7ec4cd1255c4821b078cd174647b320bb685541d517c579f6b8e3cdd2e109a610c7a921653b204ad018d0340d9938735b60262662016767e1d8824a64954086229c0e3b5bd9ad88c54c1dc5aa4e768ff1a9470ee6f6e998f", "01c756b7c20b5f95fd2b079ab6a50f28b946fb16266b07c6060945dc4fe9e0d279c5b1505b9ec7d8f8f3c9ebf0c5ee9365aec08cf278d65b64daeccc19d3cbf4"}, + {1000, "c2963342cfaa88ccd102a258e6d629f6b0d367dd55116502ca4451ea523623bc4175819a0648df3168e8ea8f10ed27354807d76e02ee1fdf1c9c655ee2b9fd08d557058dabdf8dcf964bfcacc996ae173971e26ea038d407c824260d06c2848a04a488c4c456dbcde2939e561ab908c4097b508638d6cda556465c9cc5", "a4d2f59393a5fea612c3c745f4bb9f41aaf3a3ce1679aa8afc1a62baa4ed452819418c8ae1a1e658757976692390fc43d4decf7d855cd8b498b6dc60cae05a90"}, + {1008, "85360c3d4257d9878e2f5c16d3cd7d0747df3d231e1a8f63fddc69b3b1101af72153de4c8154b090c9815f2466e0e4f02f3af3a89a7fd04e306664f93e5490d4ce7fc169d553c520ae15dd02c7c613c39b4acd00e0c9a3c501566e52cecea11f7303dd1da61abf3f2532fd396047b1887255f4b256c0afcf58f3ae48c947", "e8352ddcac59e377ea0f9c32bbb43dfd1b6c829fad1954240c41b7c45b0b09db11064b64e2442a96f6530aac2c4abf3beb1eae77f2bce4efe88fee1a70cf5423"}, + {1016, "c13e6ca3abb893aa5f82c4a8ef754460628af6b75af02168f45b72f8f09e45ed127c203bc7bb80ff0c7bd96f8cc6d8110868eb2cfc01037d8058992a6cf2effcbfe498c842e53a2e68a793867968ba18efc4a78b21cdf6a11e5de821dcabab14921ddb33625d48a13baffad6fe8272dbdf4433bd0f7b813c981269c388f001", "6e56f77f6883d0bd4face8b8d557f144661989f66d51b1fe4b8fc7124d66d9d20218616fea1bcf86c08d63bf8f2f21845a3e519083b937e70aa7c358310b5a7c"}, + {1024, "fd2203e467574e834ab07c9097ae164532f24be1eb5d88f1af7748ceff0d2c67a21f4e4097f9d3bb4e9fbf97186e0db6db0100230a52b453d421f8ab9c9a6043aa3295ea20d2f06a2f37470d8a99075f1b8a8336f6228cf08b5942fc1fb4299c7d2480e8e82bce175540bdfad7752bc95b577f229515394f3ae5cec870a4b2f8", "a21b1077d52b27ac545af63b32746c6e3c51cb0cb9f281eb9f3580a6d4996d5c9917d2a6e484627a9d5a06fa1b25327a9d710e027387fc3e07d7c4d14c6086cc"}, +}; + +struct sha512_test_v_long { + int len; + char msg[102400 / 8 * 2]; + const char digest_hex[SHA512_DIGEST_LENGTH * 2 + 1]; +}; + +static const struct sha512_test_v_long nist_sha512_test_vectors_long[] = + { + {50920, "96bb7a62306a40df8c1d0ef9f11301ea036d7d15e8cd713caa23dcf3dcc4905481bd36f5296692175d3a08203de55f4c689fc69f1cb9141e9f75543edd1b819d52498ef02a8ba93ca72bc14ac44b465518303005fce142a1f0f190803b993fc0d20a8c3b7b000fb7329b415dcc6b3d6ddac9c32fd06e822d673e979f3f655127c9a537be64ee4ceec63091439e6dccfc77128805e0875d2aca05718531a83f38ffc597622d7de64b2b92b8e2827a7b6ab8b2867073555a00e2ed27185989925d3b10b50d1dd46735286abe24bfbad31f6252c556d3000117779fc042fe31d1fd472e98a87d1c57148760acef9f545b8340994ea146afdad751c244e96ac7847fe9c8481c957c3c4f0e1b892d68709bfe19302837158a6ea937ffbcf7e374334dea86ce4fad1da05086445dc563381cf9b4be5b0288ba44f3f2fe2f53b26067ce110f312b0d270a7eb682319fd8d265dadaecf0e8e667e41e4b66a5e51fb2a76a280c7997fdc10341687e0ca30f66ff0b5362eed379b8d79307e0269571937c89f524af7ac413120162e0f6b94f1d70f2e7c75daa87d6a4b9f113bb4bf22a6d934200dabeab46bf266d4ff7c9e21e42f95ec4465559e9d3f7d0a86befe8a002f0d547024afa829218517318bb0e92fc877f00b0bb3718edb76b463f699c1cc30976a22f06f9ee1440d6f560771ca127031324a3c6688b79608b963da156c73944efb96adaefb3cc04c47dd8e554724ad7e2d7275d366bff5af83f6f805ec8eb0a0733baae26f842cde2b286eefd2eed6ab4c24568e7e0070c7aeaddecfb4861c485b9286ae4e6ff04f93d747860fc9924518c04d0c4111ae0d93f8ece766f24d832f2bbf672a58a0fd1c5aa6cc605d46d81de6d7b1527bf3ddce58a0f1764bbb0d6877b3a185c6b5832f32eb3757129ad0b60865222497f8b4d85d9952650aeb2391f701f1d342b45e46f0a33b6671d4cb8b9593d32a0e133f2c6844aeb5a86482263a38bcb545140aee046d6d00f3ab25092ee258f546d9b93519115aeabcad95afa1b6768e465b05aefe8830d9207489b924bf07f8cab2cfacd0bddb66a02ccaa8ee09c3d0ef0fdae43fa22b3180c7460627a884b70244eeee3f78c4cc0b78bd8c4fb1192f8798e7385839a0bc8d29f69a983d33b295f6a363b5f09b8d56f7dac4673adafca88cd705c8cd55dcbe0327c106cbb96dfe4e69b7c4a3c42d0b50af0bc505adbada5216f711cbaf149be93623f3f27a6b93c2ce54fc10d32da0e9a6acd9bff5fc959f2366b3b310e69f52ce3dd04feb1e0eea2dc5bcb64cf1a0495e3225b8383452ba98ff3f122fd530c64c692c12a007c82b24749702962b91e64246398d08f49a4ac40b1477507308ba2d5088092dbb481c3f0c0b84433dee56df2375acdcbff4a64114c44127228fb50d6e4481e89b0723c9d69ac9d8ab2df191846aa627f8da839cc6df1e28662e3d592d122b65499dd8717ec531daf5d96d05c398f77f21b439437bb54cb8d07cb99d175144282974a0b26f0b6aae90692fb88b812f46dd2a5db1cdf78b6cd3e3b045a7829aa5cd14230911ddb2d82d55900626a3ac138d955784180628c8f30bc7ef78366d62a704c5e221ccc8fc0f37549b3f80fc79b59dbd16e471c331b04d56f6e3ed5af349bf1fd9f9591b6ec886e3c420999ecde7ac0506ddbad95b9e30f3f88507d1bc17bb875d12f308c4dbbca43d946e11948638b5b05e61d99b1f5f1560d6266031b38292f8093b3f82db513c53e57ee37223dc45cfd0d74264a61031cc51b995088f9cc91746921e1d29ed02a3ae3c82cb42ff3ba1efabb26ce50cdfa78241de851e62a0474588331859d8ad9959278e24662a1dd3055fa8083e9d856ed24fab5be28caf14a08e0cf8edac83c170e053f20fe552dfbc5371cb255ab99edc4399e16e734bebc2240a3357e12ba88fc772d8a2a981246f37ce2a2bbce2c40ace18aa34af1d5934eac95c2b1f0bbaf07d793cb0ef1f4db87d0ba9d44ca75ae83fa63ab7a889c96332a8d7c9aeba755d52c582cd3e83b80283c8ce91826defff18d10779f817d8f7ac573ad628ae7420e7e66f5a1054ffe7ec640cf5e6acefaa0a0794fe065de44ca822f9b3056e13e5bd5a46e9fd1981c3279be973f1fad68353e867a65bb297fcc6ba98e2dd6fe11643afadef6d37fa4ec5aee89e2cce2115b6c1f42570bc5062887cad08192a682d0b4508fcd936a5c5373b8ed70f9d7bdb8342ceddede1aa185de78a85312425b474c8ec74d9ac20e10cb050a102ef334f49d95c421ba901a8b799c5dcbdf386273099dcf9e6ff080cb6abb29ebf49e3db8af420f492a8f38e35f1f381380f260f9f363efe79b5a7b2b59c49228d240a2ac731b167db37fc23598e781507dd61c8412c96e51a46ac6d89f068df051412977f00920e6dfc881282dde80ad5f4e60ba6fb7960314872b7b446b626bf70a9bc12ff277ab35d23d6525eb7c50acc1f2431116ad25721870bc51da58c04f01bf3436c061f63d06bd9488f5bf61ef979bc800ccfce147875e42cd3ab818de8f5f760f5927ec80cacb5c5fe68f09ad3723f145c3cb5d1a3bbdb6c075ca9a2e1c412fc2a711b785872d65b1a5356f700b5265e7e162c1739c55bf3272d66fc6112e085590667fd4a6ac58861af9bdbf7af0cdee100836da12ed062c1924be2ed4eea8d2fe706bf68d10dde62d221823ecc4d0633706e4d8054f32b552fcb0efcf49b940d875a472a6219bdac6faaa23c997174d3ea4f2f4dd41ecd605a56d906907e0a806be52d058a73b69cdc79b477a3149b40c2a88b7028cdc961a681c9909efc7116f939b990a69649c2ad21317655a0fa08be0d0a8ddf8a9fd798de59219cb1683fd3baa542630bf7ac563391cf3da111aa20eef4fd44cfc130b5cf104006175079700a58913c4f40b86c135dd8c78f62939fb103450527ce1b61c687726798aa32528b5c139edaa57563630e299fd67d639f059e0bad0d26e63177271f3dd006190fc0182007389671b0852b480320b288835f2da788fa5c2fb93357ccf547d49bec4b257d01d3b42bf80c2daabdc8b270f1204aaf4579ee664d9dc1f22a5a96298c8efc511b465f028e6a9dc80c68edbb6cfb7d994ef65e188318de354992eb4064fe1562b01b27a40822e4369b7bd4d66b332eec221a1bb4de2704ecdf8b147f1a3af9186c9c7e7ed9b7a96cd76c08405079e71e5b3fa7d9d36afeaf58add243f0a82fe8ad74f3f197bb45d14cc3e887c1322ea646e1a2e5f736f3f35165752dacd8226a0f2f08aab680521a581df62b41fe7e2a91aa6d67be2dbd3f366cad9a834d6902ee152d18bab9568ea5d4c19947315e11b7f497dd8cb18319840dcc29386a7c49e6d1e1ca18c8bbd4a282db50357d36d2264a92c607651de8d6d3514820d1c4b565efc71d5520fa52da9293feb12491026936eebfa2aac6339b57ed75c0f5eacc07c93da0f474baafba9e9be33eda0518fd241c08e31514903df5f130bd5946f428e8c5e37b164531df0153ac33000b8c6eacab505d1691855b57fd176a7e71d465e8e0535d98528f94654bb832390ce31a3b0d145531c5696fd871985cc7f3d33b242d8f107d4b2f8734e4a5b0d791a39c49b1c37ff918d2d801ef1208e8357715350de53837978823eacee3338e2254617359fc31cf1448406ed632f331cf468095f2044949d03007016b0f3eaf475c1622361d2f4630402579c769a04719b809b17a4aa8368d9d8d13396836cd794106e106a4acd10540f3ad2324949abd421d322746f9901847429acabcb06b20a9d03a2c315f020bc137837a0254af127b3772598791b918c3a4028f4b3ffad5dcfe8817319a5bac476d974c7144e6c1d9e50cb16b2543f7794de507b24a1f2170de75682403306f5a12531b0ff9f433d4a26b9f8008b34cfe9cacc470432a6bfc1c6c9f970e42dd6fa241561cf839f0f1fc19a464d07971ba1cd43603dfbf4de524e81df93fe57f0ea9ec9e46a43a81c86e81406801191e424af5ecfb54402fb2847273c90caabc9da5af541ba2785ebe565cf4281f14ab1d938c49b5655f89eab7962194f9052eb3021407ea6765f05a5fe740138efe90a2a2f1dcc0675ff5043acdb7db89874de56bb52a5157a5df02f7cab4c8d5397777e5e136bafed3f9758a73a70b3293728b2f0d4bdf179a836eaa61b2a68647b813e8b4c7e3806dffe523326fa288cc653ae886ecf21bc675e3d466da3b16bbeafd07f70108905070a99184724ff0a47e7b04ac7e28d8bc3f1922249bf50b0878a9d0228268a35e145951e46f520e9e36a22ff88fe1d2ee476500455872d7bff990ddc1cca23dd9236ae0ccb767371c1666b6f582bb9ecf175deb23c0230144d6489d4f3033c4445654dac7dade1ec0a62f362e072490e1377a6f4a43842c29b7377b355dabdb3205bd8c405a450a0e5e722a0c8dab5dc71030f94363249cf0e4f4041ec558e724b9fb91d0a63a9d67b7c60f0b76ce59e34a1815899f72e81d07f4d465d7f97c9efb9567f35f0d5d6f3a9151c552fc19c83d9640a758fda21098b058a535dc100343219b22e55bbe876f6a9ea4b2b321e87342170740334f6e0fccfd474f9f25e4191697d9c9a42542cec842341681e6b67391e533c5a234a7e5815ee685a132c3f5eada928c554613c120e8fdeef6fcc4c71c47a759c91630b2a3e9ed8880db355224ffe79e0d859cff0b0f5cbc70b895e627bafc8d2658aaef7b2ad6c8cc638ac63b64438f2b5820c0fd01eb0f8dceac496acb8dc0387078f49d8e3cb6d28066bac4a430c04d5251cf6d8d3338bc836a795bd5e5b37de22d7a71a079e331a64bb8273c39e1d1f89262d2edaff87b9b72ee51869ea765423ae9adfe38ce68399c46f998b95457bf8533d3cfbbaf496b3821023a133c9d0513ba9903d3e8f4deeadfa24649a84d1b8cbad68000dda4773ca9e48cede373bf6a75c93de5b365fab9fac7c1655e30912b5051caf9f42b33f2f15eeb793c97b58193b518e8ce1a118c10b09696d690c4e39cebfd21933c45fd9ff7c25f98679bfbacf3214799afb7c3ca134258b1fc0b4818fb92f22b6611aefe35ce0b8761d75b29f9f3ac968552137f66311560b0e8cb2d0718f63d272b99a4af5b079a150c12833fec62554974ddb90fff67737de1df71a51b9838fe08401bbaf5de410f8ea4414b8813464a94950f9719c95ab19b076f3c0772bf591c34dbef2aea0cafe3930c936339fa2735dbdb920cb596ea58d57e6268f030d6ebea5db266c56d74bf611dadfa40d16ded04a56734b6a876cfcc378eccab2de5fbd329bb35fad40c66912d01a9b27c7d0ec215ad4e372015545e23378f0e1704d071b85024f4e0c56d9583251e295bd32f7674daa5d16e147afdb9e33c937cc1ee589227904e043e5900e88eb3ffe00ed3a47b55c7f00312c83d741851c5df9bc9fa4f881450cee5ad45a5b507b0a99e7fde71c5412d8f9eb0afda5d7b3faff0d7d939183dc7a139cee6431e75e628f0a886f09f9dd453f6c8976518f54b7e7fbc67f75e58fd1bd952655951aafaeea3d220805b3aaf00d974b69cd17c83cb86dc48f2a1127b9f12cc3550c503895b26714da97ea3f816a5497ffa2d5d7307a4abdec3a6d6cdcb9490f8b20f2bfc0f072a70c4706659f5f8bb45f5733483c367cfabd2d6325df1cd4502058660dd7ac4520c69d6fe4f2f224ebb37497e507f3eac32b89591c6d23b6cf3c3c15ea81ecc8ca32228e84232d078420826b743ab97c605ed8b9172cd4d5d40555671d66bae3ec755dc90dda181cc7d00816be7c901a187da1eadfc4391aa6a62ac5702f1d7ecdbad68946beba4cfbeb8e008b7681ac34b16d543cde5a6d8f454495a9841e81b6271637f8781b7d6a989c91a3cf931afc21c35ff5223db7d50b2940910cc3d4efe4a439ebb043985a00bb31cd30cf4cb8f62b73d437ecdec11f632ff0701660c01a08f9e70d3b86144b7248d3413b2bb0572df89fc66fcc9ba97ac98e581f0b71f1cbddb4370a2de0a04a3e7ba9e29d2c6d52561f76cc67abd3f475326ae5be4990744f19d7b8770527ca7b8e11c98b735f21f51cf00d9938c35b9da651706291208bb6e0954e4bcd0a7a67d320fadece56233e5edb3a498ca136a8b0b3c8dd92c8997acf18d3907e6ee26b147f7c7c857ade97ace0595fed960efe1939f61991b12502af094f30617d8bed17d5574fe0f2dc69cfa774c2a4ca6a07a88a01fcd902b7b8470fca12be5ffc57a5cb933e26e7a51d90d7925cf964d22a274ff170b1e4d70361d34d1edd3cbd0f86093930a180bf19b518bc14338cced25c2fce5c607f0e4bc3fcdf3c053b577f8236510f97e6b4c70614f9d29c6ce76411d3a1a72ffae3f9363389548084510d61fae1c251400c8e4d70517e7a29a4490ce2723b667edf738220524e94403323eafff33117b74dd550d7cc0116ee8ee9160547ff4d3288226f6a42128a978628e6ea8e4431730106d8ef7341b8e12bacf6e42adb2b3f696ec5ba6189aab0d0841e66bbe3e69baf88ad604d27a82a06fb762622b74acc07c04bb7b8993bb49c9e571981f67f58e0c397d3629b2df2a43c5c73377bf002ec7eca0a4e2b87ca6fe05cabe86544d11b1f5ef0bb8690618fd97175721066099f120b5a2b28d41bd3b1f4c5f8187d2fe804c95e5fce1a9e4e387dd1da5cf408a8e2d35058766bcf4f79e60fbaf77299cfdaa2c6565d10d269c348327848e1279058ed94dcff940d6ca1fb3035eb6b385909afcfa919bd2468e0993e52bc7790ddda20cdbfa996fdb08ffbd171daaf330df9b9225fec68bdd4f9399d73a1fc681ad233a30a5ebbc8a5acae9977ae87b37412876680bd58c43575f1f8e0ddb9dacca7efc0c4054996d360db314e4d3be014bde3441573d66211bc87f7a25af60b7dc11cc9f586898ec1144c40fea113e17860936425f82abff236c341c2fefb26b4888269a5c9c3d9f72ec76f909056df2565606db8339c025f4b6f7f48b30f51fa64e846ddb53f9efd1815660b044e01a5321208d60c7454e16351583a607bb4d6bd1708a43444065c38fecc77e441707e3171dc886bf9dcffe63375a2ed8879d0fbd858032e1b399bf84949dd1878533bc84492d53874c3413cdb7d87417bc57086f1de01890d5e42bfc08744873bd3616155d1c65b2d302fcd1119f2469fc33fc62a41a62e609ed9f4292bb41bd2187a636a4262bd6c4c52019ff1eae33b98c4244d29fa055c20e9014de035bb84490e364c8cb144793e31414cac7700966f8706204006f64b0df94df44cd04f9a8fa342c358bbd99b2f54f3dff3a186f96e11d56d2bd1ea738c9240e5178cc05c11c3ee974e89651c474481216d715bacbde9fafa9563c71ec63b42eaea72f412f8f5a48f1522ce42ad8851dac3ee68f78597db8f24c57792e27cbbc96d88d4046bc2cc74568efe568aa8cdd19c219522eea4e2f680fee01709dd134b47d8487a93b0cc0eb8d6db9f052d5bd0a110cb741f9776f65216ecf763e7b238206a39bb97490d25e4014f67479e659d7ac5f03641f8fe564216827817210158a2448d10a015f781811741f478835201ce48edb17b50e4dff70589e44e14667373702ec1d69bf3e938219890be658ac4459fab2af6268f591aebeb812f464a503bf6021660636727b1253e8144ca75ae88d411ecd902678c52d18f98e34116b8a3dcf35667f5bc01932e1a0f303d7b873fef063e4d6cd43f48be5d70918d3073522ce8cb12da5b4087411484ab43041612f674677aed3e3ca4ba3d5362b00249f2eec8bb8a99aaac34681426dc667824a7f342b0870c0d490dcd17877e34f20228287d6ff6ba130c43aa023fec2d3f79a9ed58619d52a92f2b00d3550ca16a659ee4ee2f7fc5fd295b10c6150220c1ddbeed9ec2e3467bb5a75a5905347dd13bfc2903434d43d0cc25a049f047c866188efafc1a8270e9a529e391df20528f4ce900a4f287bcf3bb4864711ae3ac97f1c21c5ab3a1585cc658a4642bf5a70c600e6fb98556b6d0bf6d6427dafd55ba32025ba0d369873ddfdda4b830de05af3f13812a44e1bbce9f3ca75477bd4939a1f5c0b6c30284f2b95fec773701f3e2b09f3bdf77515255255c35de3a4c127a07445284cb93d7e51c8782878886f90d7d5aa7c166cd04cd177616af6bd238e72b971af23244097ccffd70d26b969f966ceeccb6597e579e3e3153ad527641e6d7941ee9423fa1219c68be3e28596ee64600b2a7978bd5316236f2c23661b7e1d1e6684f41a9273b497172b506f6ed65d23b627d691d06ec4b2cfed561bb213fe233000e78ad23329fbf961e4e95a57bda44e31e175c7138c0bc7ccd19ab0868d224ec0c2f701e6d66fb316049601c9124c63d74e96f9e7e8a8e7694a759f3c469603633ae1da05666cc4c653c7ddc0d7a677966267f15247149f31153ee6abb6f90e6693cda2f5466dbee1472146d59a2cf9edb18b35f943d96fc2c6492f5b5ab5b029822cf55cf30cf1f55324e55db64a7b4bd05340334b61c98cd246c1d1ae66a94a7a926992f8a51e710c3521efd8a97c4f33629896ea484cfdcd9a56952e864a37e160483dd3d094f2d6e494f26da46d465f3bb7aa9ce75a941cc6462c579f23805b4939c3f119e5e957b5b71bd1e5deffb84125c4cfd982fe445d28edb61bc5a24cafb6bbecdb91d2e32af0b2c1c831a9d3055bac1f99568ae8b1777fd676911c39f6479c33b0192e1da6ea5da9d615f3340ad196f8a135d85e85aa59155a165ca7cf54cb4211fc797bdbfc82f689fc5a5fc4103be78ba1453a2c39f01f10e5f21a9d66efa48bac43621cbfa9347e454dbac3aff168a3397fe027cedb3045606b06e3067fe787b8fa74fbac66e00d815bd98bf96df8926ee6f50aa171155216360132bbd27780932d38fb3b1285c240f3408f94e813e3a1f8fd478a581ae187c17dfeefadc120eb5a129de452923704b26430fb2646e183445d6", "3fb5d3d8d7154294799650b12df25c71f508c4b0bcd4da2ad6e57babc98439a1fe21d4ef57c7c0befedca85d517fb9c5d5a705ffd90b1a5b9f1717001c8ef547"}, + + {102400, "a1ed9fbb03c366c30f7513bc64f45ad979ad888031c6bba8afa553866bb3a468855fede15a658e26565075b8093dda437ce32cc6c5d04bf5d9f5f7dca26589c4515ae05af6799f0e4d5796badb3b7d843a26e805b21077ab09754d5b9b10c45bade75f70fe8701439f915c090575ab635d7ea4831f0fa891e62c3e4d7f3bbff53f0c53699a181b8df206b0efad74cdaa8af3488a355347701922b0f8756fe15ab2d3a28ef4b357b4efbf7bb2fcbe491f6b8ebc601b66ba10495f8ca6a6339251ac44352731e01c7f3dc3a39b19dd898ba856e84dfad06b391fecbb9d390f3aa4d566f47c7c27d3b7841a12f22c59f3b5e954b59bfa17c0b342d02425578b4119d741c7d4fb11e2246ecdaeff5fb8f167d58e099042c523455c13ae882830107957dd9779d625b28ea1e36109d884ea67140ece76fb61fbb912be430cd3850d8b00434ab136ebabbdc564115abf44467e4fdcea934c74b0d50ed7cafb8113a119777acac543ec35798359a8383d816c742efe47305e85aa62f8692a9b596034e9678afdfd24afb98983c90dec7ac2c611587ecb94591c502777794d3584f62fc5767ccda002bd9db66cbc28be9d8fbb1d7663600964c20cee34111a10295df8734c5721f8049c4bc8e63ae1f5ce70b35f2fb6edd5a7fd457dd7387976711bf9bb9223e04b53d629879b4c20db37ee16a02c7e59414b58649d07f752ad84ba9967f0e8f4e216f3a1ba30f9cdb6fd904da814c38e957858cf166c558dfe89c23f3d0daf440576791a2b504ad0cf4bdfbe3f908e73195587efb0af5a13b1a8b95507927fb8fb9bf2fca0a145116e4762d22d48e6f0150b6c2c33780eca0e0b29428b2661380eace5aee2cbf479db19a1f139e3d3edd0c18fef666e7a9b5dd7996e92725cac84d1db9ab9775fee5dea24842d0a5d5293a0799e123aa56ee5379241e31e78fca6345b27ec4d8d593de274f1cf648d07a6d0b1a3ff84972cef519b2348d1bd11bcfaedbd45f486a3c42818a2e89a6af55178bf64f5f359bbc34d3c7c873334d10e4e19c48a1552b237e598fd3f53fc02dcc12c4bbc2ff205a954fdb469ede425e35668a48457fa70e1407d6c9e384c178ed27fbe1be16af1e98e6733b6a7d6f5853a61c6fb6385c409624d56cbf0611db0d44027dcb1ca66ca2201613608102a3a238d90b7e0fb95f67293238f2444fa8aeef8edc546194e953853a7b0b99caa4b39726b7f7764cdf199d43ab27cfb9864492e789f495f9093fae66bee62825f00a39ac01cd0c95342ff9a05fc9f90dd860c6a303161a414098e4116b6aac830a08a8df55792310f31cb6ceb35360ab33760347d4537f1c2421ced11d13978047515d174f665a5e90626d35424e87201c16d15c7a1724d8285cd70c307b899c5c56df0a3c1f32cc9083756a8925ecfaf6a5a94760ebbc13c19c854931fcf345ad9b972ec82e1ce9780277d50474029a47b503af254ba54d8473620ebe32550abf922ddb6ffda933bb61dd0b20b3589ca3b768da33b160e3e573f5d321963f5a06cd0bb680184849df242d837a6e5f608f4f517f28b78f756910a92cf8a302b217cea936c5087a8a67cbd1c47dff97846ecf460450b8718093cc0472cfe35fb166f98ee29b48c083c9bb7244b7f19176c6d9cee0584ec783da28805b03d1a6c678e045307f53baa48995879a94fecdc63bd144b9bbf4e1fdb098b52c30e8687fc21534a6eda3b98b3bcc7a2cb141bce112485ff6d815616ccbaf1b9cd3a2153bd70b05bc62d35da634d2d2717994df55fec1790e595ac64f6fde1bf368a94d893c2410f77b4d0764293b191f7a52b5a355bf1886ac2f711431a83ee67c3871e64612eede938b57637d87c67d2ff5d047cbb3c6f63cfdf269a5800cdc6b0a12e1a93a07e85808be12962b53110708afb1a521fcb3a850eaae20080e4bc188b0f9ba1bf48b156fbc0027b857818c05a48f969c32656ac29a5055a2abcb2c2edc9d1d3b2d5d680ad1aa96914c254b777f2ff4750071f0cdb20eaae27dc0e776d65a270a2ad5dc748f70674899a2b1c86011636edf7fd6cc92179449fcc39ffb6eaf8c2b656acf3756001e60d8505b9327e257cc27d58959eb39a63b9159c226e60ba0f175a2dccdb5b8205c70d4a5420701462f821985000db35559d3e9ea83ecfd0a0ec41471923f3711be0b963b6fbdfcb30b76b256398a3326074cfa658cd4021bd5e9161a4f42db66e7f11b6a769d4312e26e468960d1279cd66511efbc4ba97ad95d4e533f7133946cd9eacef125530a46e13c7b30730f3e49a4b6d59ca4619bab8913a8fd3ace3edf2e7ae55a06dafd9b680ab80300686ec3945fb3a88eb902aef51c88031009aaa157522a2b821971627b47dc72d9b1b2f6ac73066a5b1e246649bf7ceb91847c45ece719e047bcea3e936a34ea9f89bf3565a74a4caa0f8563cf72f4012fbd384f67c04112c823dc8238e87de4a23ec8124852fbe9fc1baa2a2edd89fe5b12432050742c3d83ecccdfe458f3eb826f821fdd1c97acb1b1071bc065ab3d9432416b2f5927cafb864f9a1e225389c09a51a09c5aaa1f7b6e30db2c91d4497b8b97726d05e0359f7eb9534edb0929ed2ddb66fe93afbca9b19bcadbf8a1ac618cd9f891f0d217f034be9e1ef9815658b873b58c5e24fedd19cc7d56e07fc0f6c47d4026b079ec9e56a3dce6f44899a3b8bf2ebe20867076052765160fdb41abb0f5fb93bb342dea432d923f51eb6e4ebd12351c71609c15125104a1dd5088e0d0d88d7177bd46748890409098d63eca24016b1fc72fec3abfcdfe72bf5c1146a29968487c61e0bda5908a834f95a5a68c212340a860db476be295114c7a753db4bd3e714fde67361892b27fdca61d5453e610278b8003dbb5537af60b181f4675b85294586f546e501b6aeed694105429d4942ce729e0581a8512a951d199e1741f571a3ca132d6fa9f1678a3cc29366c5131d951baeb5d09fbeea3d7235faf2e56be8b53107d0056923785facab27ba9f06ba541af9f4b022c816df189eaf002f2eb603249bd6b2299509f122c66844136c4293d9476b2a19b5d604771c6649088802150995e87bd19043ca04d9ff0e0a8bdcdabf5fc1456cce5433f776c7d656bff47449bead6a495a4d71bbad93206aadb1b2340b9f0a045bb5f4007679ae031cb6a74ddece86793b506eb00acd801d18e8a2a011ad7fc7a424cffae225d9f5e76d367cbdf2d7497d744a4ab755380914aa336c3a92ae9ef0c74d4d837260166844aa3d22c266a267e08cf07ed25018eb1febfe4ef79f7189c6f56121094a4ce76189fad7e53a6a40bdbc0c25edce31e36e55bf15835929b54a509e84919f81abec5e1aa2045b8b51326205754dbc3b46c0f61757dfe4acbd7be46d73b3679cfd0eae054cc7d2ebe2680743369a21205a3c586fdbb248e4e9803c34b717ab8525ee03229dd5a6743a87322e307e06c7680b022d6aa58db88082dd5c186473246bb6e4db5cd7df0ca3b66c2e2a9f7218b7547cbbcc60bc0fcca8514e5e43c561168bda975374869d631d3cabeea56dfb91404f7fc98addd3131b1f71515bab2470976cbf4855a20ec3e52a0d423900583cf702e328cbf6eb9e02cf2cb9552c55bf0222b904223b470b36bebcef03311701a01d4db3cd113fb586e9e95dd850dc4cf484ee4f825a3083378120bdaa0a2028632827303535b79fcff60f068d20a15f941bc6f01d05b17311faa173d7935bf969acd868ae6b3ba6047e067c1ba38c400a6eaab19c47b222ebb2a8db31d3b1bcda31c823debab3104d0735872ce286367f050058a7251bd9ee2f9bbb61d208b8de3d5f296d2a0726d31b06ef65e3758a1b6931aee5a9d4e042fbe4dc0e984a369b5a054104c31f30be41e07b70b043850521a67bffdac57f0e9ee906e12e5d7e3c0f22354b8ee37636022bf5f551d66c66b5c6879cc0d7fe7a9e1400819b2bd8e7e41ecbe9923c3f62e450239bcc188a65aef8996564f0a4b085cc9498e79a8cc56261cc87d710d56a71b5cd0b2bef262b93a67b02cdf9bad5da7888cb1b94e1fd1053ffcc66497e7731c3bded764587dfec37f31a03db88142682a5c43d0020b7775d2e6146cd83b1abe2bae8b301f6aa4213ca550f7c5693f051b32b58c5921d1de51fed7f862c3f677b8ba4ec0bbbb41ba2c85df8c66c7ac04d7aa771cd7c548c559b191a5ac049edf4f9ca284b1e24024bb4d7c6a011f21edec1e192ff29874c136a8d1e3389f9c6b7cc0270a967227c79576e82f18f23936c5281c243e0dce38954f093f8cd75792accf3cb0dddd813917ac833a32c34a65ff32e0a81e87bdb1d21ea8291d5e58eb7c046415fc96c4efce38de19d314de01f6d9070a18a8dbc399825f2e5e9728dc572a2da877306b5225b6694c7e698c8148850ff8c0e3a0c448346ebde5044ffbba8b09f6d23cfd16ba9fb5509923ae6a70b16bc28bca955a6a8f8756354826c032b1897f921ee294097f32b4b7e5ec23ec089b15edb031ec6cfe1995d3b545a04c381ca14b48c4607ebf61f75f32ae5436d52e517b56ff00ec2a95eb24ee35326379341a426d1ae2a6eae386f37c6d61cdb196039901652e548f9cd4bd557ded151f70392bde4eb0fe8c07e21925b1d33d2852badb520ccb32879ec1018d8846dd75518c7c2ee852021d7f9744e1143ee1a3e4d5c6cb4e6e12bd0c5e95e8ccb629254892a7c1602c3e099b24eb20fcfb77aedce2dfdfa29d519a660bff19e3e194a9d5da23585ec62efaeb099057e49f5bb3ab707af1b1cf8baa5c378173462f8c7d89c193362ca6414bffb3b9085390fa5cc0fd4cb3f48b2d573f8fe1977c168d0ac4f76c0d6253118749c1e9b4d286f004cde7b998d336c34b807373f8ee2d22fc17da122098431c2749a286dfe9e7c94612ce4612e678c9d1df60dd0a14d9caac02e81a1226fccdc68fd4350bf219e29b402f76b4a6c7cd949cf6716da8b300a516a00874a6e6a2cf7ce568ab83b3d86ec679cfe08c8a2b0e69a2c575f23f4161b3a051aa80a737cca1448641273c174b264bb64900568e9995d46dc589d5298c7a579a465ca4f9288d70326f55193bbae003ce30baa354e0c229cedee82b156fcb4426ba8376636da1f6e18885e1923874307c4a14070a5e7f016d14858781a636e49b89ad7203268f57182f421bc74e635044f794e83b7d1d09cd290aa11aaa4db76d26235e64dd960f4ab6023e47572df1ccbbc5cd54c73c81636ebfde3ce6603b2032ad61e4ed669dfdcf5eafaefd448358291f3ce2c75e36c4683db565051efe391174432fe06171a5ddb0064aab37838ba219ad61e7e26874a80cbd2f70ea6f2c55306882512728e7639ed8c6eb8780ebc93d955eb369b4d8a0a56bf8a4530c8e706a48a8ba182216f3737d8038b4f9dd01038b35b4749a74d470285d29d964b3f57a69ef75c50bc8fff68b230d305cf3dc040583656387ddd625a8c97bfdf65146f952e32eae3481fb60781be38a38b4dca78ad440e71b88081e33da05313fdb076f9a105f543ab67879dad766430b8465768184d14fb3e7fcd27feb7003bfb5993585f352279cfaf98b19e1dfcb440718e99021813def9226dad38a26e5d4658ee3cd08d1b8c9a3f11cbbb7eab380a169892d46eb123d0b089fd542a4684c8f5b02c5cd48884f65e1b746e6017c2fe7d9cdbf41796d1aa734ba0b81730b5687701b16bd1106aca56de321f8ae85d04edc3fdccdb6bf071b1d91dce31d3fa0e280852654d5c45fe6d819034c5c70e04b0357fc282d8890cb35bfcfd40d85aa24eee97b210141d79ec2c1316d95cdfe60c19e940d384a263c1fac6ac0be6de0d32da08bae2dffa251b09452d8e4ed7924a97c4ad9718465e22dd02455ba68c351cf52ee58b65e5e9413dade1ac45fef1b1d99771963b7ae5202e382ff8c06e035367909cd24fe5ada7f3d39bfaeb5de98b04eaf4989648e00112f0d2aadb8c5f2157b64581450359965140c141e5fb631e43469d65d1b7370eb3b396399fec32cced294a5eee46d6547f7bbd49dee148b4bc31d6c493cfd28f3908e36cb698629d53701132f3b60a29a60cf5da7c157e939735077f849999cccc78210cc598d9dcae1304c4fb5bde5fee7cd3bc67a1ef03fdda965c4d1c750c928ab8e177f27dd1299b89deaf3e3a3d7e52bdb6488c814e16a7ec2496614c99b6c610b371b038c4e98f0a46b766070a7f161d92c7df1ebb0924719e066e08b95eb4914a5edaf1fc1977eec5badb2b0f18515a168ba1ad91ffd98d94464d8fb5b3dda46ee47690c2dfdc9d2361a69094728adc0b3dda16191f4fa9ccfe06cbd5dcc8afe6ab8efc5e63447f2853ce1ce0b4490b388493419b920d2b10d59fa26001fd1c7b5c291f18ce3afc9c385bb93d07164f6709d3165e7f9b7d267322fea04c0551f59f50e03748437c46ba564ef1937a105e74a27dac0f8205d68196c6dbe367b81c1b0a2705f8e967ef7fc6c3457ffcb6e66c085ecb69492deaa704e25aeeabb7b7795fdcc807b3255f2fb30081f425a9c7990ea104b7785c288c733965965ab8906057e8c99d291e5e7325eced197b51c9a4bb2e9f1e98f95ad9ebb54302fb226d79fb3150e0d4bab4f32571d1178817b43518ede4c8306e4635753d3e5c165d176c52a0a5fb3b622856ba767415d4614ff32bc61bddc822b54917ba9cc933d156e0641d0f14e77c8444ede41f3ce5986387fea28b84e87d6ebddb12a673dbe6f17e3a91d7545e728e67c5a11ab44525b89899677de619e73b38c92ea4829504b2eddbe246e22aaa0f644a96ada47c6e16cf02ff392be2c8e262e8f6de1eea935fd54ffaa2e7d28ecee684ab203410dd45d44350077acc882ce440529b6d61fbc1e09fbf338adf8495937cc9ba8e8bd90c4e64442ffb5e8fe166d92b259a82a4a0b4d21b43f4d8f62a1339d6c4d775c935e66bc2f8d82046c98fbc67c2cbd5f6c4f9f0f5184c454b560fc3bb863a5417864362b1ac369a13ab08f0f0bb29e35af4580234fbbbafebe12f236148ddb22ac80e50fb9140555f51787dac58db3336fa780fc234699d3e931a60af52e8166ac2ee3e87ef1bd89381886c85e0094df39c031f860b7d97ac3479828ceb84093f3e8c333d10f2ab1504e0c4629dddbafaa39e3b68c81f259d8bf392e25dd91211028f37053beb574fa2278d2ad57d01b2d6f36950b279d07961319698ee0eb948d8a052c7b72e63a72206cfc7d111aa82ffaab32612b01fa87eda9996e74b864c86678d6bcde457874e249320d9c23ed4e46b21d230ef9b92aa97a0c490ba0286d48befd9c535bc56ec2ae01d34b7440f4fddba3d545cca9fad10b50a3080b45c8cb581fae748187cc5bfbfa62c1a449a06a8864dc61f36384eecdf5010c82437748c4ab47a46f661a18c37a30710c6dfd1758debcd6167c356d4277e79b8db8056b952f0c856db6d483850fc0ec353457aecd800b34ae4aa8e6f937cb178609df8e3a19717a15108816c129a895b7234c7b46e72be013553bb662e3200313bf822b3408fb04fdf9a15d08663c0ffac148276572b37afe228a860fd88b00bf5f79ed036c2db870e8bcd0bb340fad8884e71d99c11667b738f1c060a67082d150433e48b16e07164436fc6a219810e8e485d86440e928e71f2de005cb54fc02386a894477506366b2ac3a859d79bc8466b0d245709040f64b8b7f5fb5cceeba8e5c68a73c696feaba8935ae260912e391f4b5cdee90527d2496f8df042cdd72b88556e17f1d8f0ab26a583459eab6aeecdddd6df98dbfe450dce71425193ab34d91de739dd1435f30ac2cc887830a1eddb8c3965fdcebb446c9c49f96f6a904b3fe59ee37492f40bbeb2ddb5d56afebfb3202d7500288758cea0bc1e8698aef922773b1c9d99567ca83d5dd39f9fa6ebbb615c19892f89079ba373b77d662cc5ea9965ed407383cc322bf5ebbd18c4f95d176b58802deadc3b6d16cf3c1c33380014c45c4666a286c3434c04171d7e720009053bcd68d15c16c64c6bab02ead8caaf017495bbdc2fc24e0b2695f5fcdd0b00d0c8592967119476bd95b2607a30b134c43a16ba58519915d9591fea67c2e8c474090ab7d3821e441254397d0ac51e69b4b8b1aa3f73af5d5fa69d42e7a9fe1d9a06c95c3e371af9f3b128a2c32177187af54fd5b81e6cf14414f746a31bb5d3eac67f5ed0b9f25d07b26717cdcb2507bef9d681ecd9389831ac153ec49f75ad0b511206b08f0c38f762de244f4b91ff27cd30f7022c7b19ce75df7271bea674a6af6c9c0741d2526ac67611712a22c75d78437f239f9d3dc2773e29d3ffb0f062e97368fc58aa7309e815255def3f290902f96077bb06ccb6ba18ad12eafce9e80511b1b85bfe627ccfa4a9382252ebd37438e425071f8e514757445507f027df0e2dc163d235e86a830ce52d4bc2d662d5ea51560c4e4a3c25e137c4dff571f009aede2445b7cd7c0d332161f3f7b25f2df6f03150fcca1e5ca0ce89f97491c3007e51233decd9597403a5ffa1594771844409df5d92d4a0f57a50c9ddd34dfffa846289423cd3a9c063b82dde505c41e3bce487bb76316af75907af147c6e4c00a8587eda0f8516f93aa4133144bb765146c852f012a9236a24396025d5bc5419d27d298fcdb5462872afdb229d2ab9d7caff6886cd037356c32f079848febc4dea17b3e8de2ce155f222aa39c372b27c30cff0050e0904c41d31caf63bfe2fa4d86f436daab29086a245abff1e5b0848608112f33f817bbb1c86d1c61882532784cd02a79a0ffbc56a5f03fb16ac6443425cf8dac7348344a77845904653d0ddd778181d140ac91932baddb6142f6d76bfaac7410eeac266a64d4edd2d394fcfb7baac57816ca28be29c5fb67eaacce8bdb1aab17c6ae029024e133335fb78030dd9e6de4afd3021624eb185bee628a125bbc7b1797e8695a1c3bd1dc663f283c21eef39d58518e59a18fcab3aab2aaae00e46c96dec5cb36cf4732048376657bcd1eff08ccc05df734168ae5cc07a0ad5f25081c07d098a4b285ec623407b85e53a0d8cd6999d16d3131c188befbfc9ebb10d62daf9362227a9a696bf46da1724a172941ab68892a4d441702efea1f00c92a4f323288a84e6bd721885112a14604d4690c2e96f5bcccdfe3fafb6ca861fdc3dbc04d2aeb772adead5db6814858387b00935fbfa7a35467c0c75dfdf930bd80246e3be49c3b1c138542a1440717497d886dbb4d0f6c586e25fe8418b20bace191829b504b18d40811ddbde55e01bc5e78f1cdb9ad766d759c070a374331305aabb3f7f8788ed74f0b9548bfcdb605905ac603aff25ff7f09b875cf42d7fec7deb58be47950b8a3aaafffe6dc682b9a59660f97a8e977c719ce5f8b9e11635adc9077ac8212d816da8743b69e9264d10c4491bb3c2bb8f7b28b96a030eb2a07cdd36a9e4bd53415a6ca87c2e95ef34645cf4e6e64f1a957fb7682d69f6c3c16d907cc837ca1b4e736ff35d366d6c0412d8daf77c845322f1d178cf4939c7fcf27b30423bd7e40d6b3aeb4b1bc01b40aec081aa00f2e3bc63ff61ac4b684dc7ae05f7c46b475c02845606c2494e7b5e8a9c8f8afe2b5ac658a9c960cad2b3b5e2b949bb40c8d1c26139bc5f49691ac258d53b26de8e06d5426906695239a85c431d8c9346bcf3c1846ea27e869068207bf33aea2cab967db3a5af427bed7a0f41ab66e907a41094605d2facab64e1dd767f056162f488042ee83a68a26ec76360db3f28ee0ed69f779dda660247267dcaf101190c094a1d06b92e68504e0eed23259bef745db4575ca9293735c794760bd1d46da25a5b3ced90f1be100bcef0fb22f3892531286061f7929ca056ba4a9b99f5fba05839c846082ac66c1876337b5bdc929b09a12f3a01bd12fc8516800cc1cc3f90837463a267403dcf0493190628cd982047bd38477fff1684d327aad1e1eda5fd7c89738566d870b340b4163e223d167f8bdb000c9aef33e3b16c2f8d62c0cb31a3e79c516f3a0bb36d47bf75d0a179e336990b1c1ae3d793b0528291ccfc1bf78a1d32b8e90b6b39eacc796faca15ef5e875ddd848939e1f40894871a8d61499afa8cb0e8cb31bc139b0d86e1ea3224211dfecd3dc64d3d0f26ee5bf5f1541a28508e9d492c7a9e3daa35103bf2d50323355bc912eee35733681eedd88002fac9acc03adb3cf721c5e0277c306b68560dd65c182b8862f509d40c85e9c4d4b025150acec682110c5346cb12e7dc52e38609e904b11c32e03875a16b50443006e59354a3328730298ee2091a89cdfb7337d5ead3cc33bbe06950c3e636887fc2b12e86ff46d1bd3e1fbecadb3dc6cbcdc84247cea35464bd446f5b40c3192aad30ef892b2aea1e14ade2f49e2c502abbe058e83d5f07973e70d952bf1e7e978f0bdd436f075abd73e15471ab7df280032720b56827d4bc2c96968eac703f3030ea019d1205a70123631e274a5935356e47a197962444394f5daff94fe0e55c5773617f5e4b5b51ebda4800c3e8a0b1c4e5e374117ede776f6e2b7aef97f782ce5107d29902fd1794efd8e35d51bb5ccdacef361f5c2ade547012f8d5bcfd0c5b2afb7c0c5116bae749d8b761bd0e9f5041ccc309e6b1d7c50c6c5d4a787f61c7a74367ff612da2a9914f66175322e0174f82051746fac88cea429094f306e9d96fe979b959ca37a56e46d7c73c7e88e87c1ae290a18e1a6fb19b79fb54190c5b2bf59c846276e0a289c4f2b99faa008c709b44be22f336370a8000c9c4413213826db7a6a4b7086789d19f35a52fafcbd40d12e7eeb382ac9cf80d446a05c3cb1d5bb268461814bd1775c6827694fc6c5079345430566895100b88b66fed2749a3c67512711e6d6cdbb94fe9396151398be6914d0e624fbb0dc15965fa81c656bdb7e7ec4c537b3c7ca422b2171f15f82e5c1319b0619fe73c23689a344a09b91335f23e003ea6f5a33f28253755af72e0e3a1023fdabfdf44389d9c44cf563c4c487d4fb467575ef7914789c28b896f4a84234ee356196bcf09e1b5539816a510f871689157f44021a26828df490ab714468246c35c1455829c1a2b892eb2bd094eb4d1bf95e763c87a7448b7189a11e532a4320874186407fb32470d18904cdd512fd265a9968f95225132717fa146654e725ad9268d5f062e0f5108de1a1a340acab3ab1c6b8c2fa1e92e3607871f3da4d4055ffbdc0f263b9b91a109b7eeb77f6ebbba75cc2140ff22832e36b561153cb37dc27a6b3c102cbc4e0120ce910dba0133ba3c23186d44e67b809791d7941cf508292ca3ad6c095cd24fabc9ccdfc36c63d3fad73760791c5c55af8448634e84efbc97ec2ce1d86263b4330f65d5a098932b355047c1a6ac6fd408f77b2ada467aa545af7f17a3b64a583f0824965b6c0bed78f60f37d17dfc2629503990c625f009be526fb77140cf62571cd3cbfccf123f4831596b04794b729af94a3d1c089b13883fc4694be839fb03b3381b89abf2492f69eb054687a3e1e45876dae4d6c1e82ddc46d43896d24acc351d2f0ce7f134b4068eaca08f4e9b8ed7850f2479abb33593bda14032e078390a48ae8c6b582860700a08187a92c720dc3e83e6d8a19a26cbf0776ba4acacd39a8141121f6f4cb90f27c2b92eb88d22d16adf31dbeac58aeba8ffc2d47e0f204e9290a5eb7dc9494cad82889407161d1dd1ca0e6ad05de85dade14caa9ec9aa8c42424db7ccc7988d63ef8f94c98a99283bed836d998ac988c7c4110f5301f9bd5800126ba26d2c3b12b2d51744111c5a70ef9bcc8e73b4d4be501ae9e6df934a9d71fdef48e38fbf82736203c2d1301b377a5b6ff74131a9592e6e229f8c0299d93e152b0652497f7bd93f4289f55cd35a33cd3f1c1bc86f610615a0c630ce14d30e630723e2e0e5c58c73bae1a329ea9fc4f822442a028e9f7f184da3f27d22558aed6ce9bade582735065514031dc8cfd5e401b996666ed8427e0f7efb992a255abd409e03cb3f6b7c01f9693fc2d5b20d9ac5c1867d78d7f74fd09e73aa960c25db6d8be42d0457086b90277ca07a0f152154a522cd12634594774c8136cdd2934dd9f8868e0eb4824c0197e53d1daf948198ad94e0a543d454ecd04dc7373f4d1d6e2c1075c54991ac34019f23285b33c37820013e9a404d97177200e43c1bfb531271ab6b91e0de9411add5da01d99aeedb48946d57225865e07ac216442d45f5af0d7ff7da3f100b80e2ade812f1700aab6b72f746b19cc72f2fbae3b73ed10d2c49b3a1082fd01a69e94fd7c16d5e20cfd2c664ceb4c2c4ecda11d6fd164aa2716d70f18378c6c8b40ae42f78140b362fc5b63a56f57165ffc3ee747e7d56bd66c1dd70b4e2991d498d94769ead2057b38b6a03483a52b150327a47a33b9d65f38d23a50135f22110ba86369a014488436e0b460b4c0db0c76fddd6d217c8a200186918d33878ddf2d9e3f6d6d820d3c7b4c18c07f3496a4dc13ea974db7f7c75abd85293b4d458d531d23fb9f95b3f27a6b35ca4f6aee8c872c549f24d69fc3a8e98daa772ad9aa30b7c98ab2e9ed44b8c0a3e4a1fe53122c89c3db2362f293709d0387937acac42af0989143d919b1baeedba6134964d410ce80d1e5d790c5564a8f56fce79959c65a09a5defdb9b8053855951fe69450f85d4429d8ceeab7ae64998f3febb5d97756954ec0c25dd60c5faa282450420727d8563968936108fd8dba96c8e1a0d1d268d3e2a5c1667a54a731e5dd112e6543a26f8731dfa437d8285b1424740ac15c234e17fa65743352b18534869399f9c05dd899b10e24a2a2c7037dcf1d242668f85c354b48f79fab012cbacd721543226d29f762a952f801ec4c3a4547bd8fad6a96e0f4c670fda20890ef2e1730dfee52fc16c33bcfa669fa8dd0137e174b8dec86a1a37870fbfc5a4a28050d7d0e78a1978e5f2feb1c3f9440e5b63ac2188f1083ddb3d968090e58c11c0ebf4a7d85cba4b4930045e8172c1dd1ba185e452559471bc253d6b35c969e3187c7399b6a43ac200b57508875347d3a7b714c7fe53928e23b923d795b9629ef2c9fbae6aabc1657249fab8bde4fd76686d00d175332b1a7abff1cc9afc9fccb59c35efdcb676bd08b43b750b6c0c51c68df10a9d3d869f28004e532bdc49f4c9bbc963f410815128bddf4759359ce92add917b5fb9cca49544e372309f889f96ee5e139b000ba93b2e8f368f85d4c8fa27852ba4ee24b229535733928e835484ff9c05b7cd3c4eaacdf24b95a5dc75a03178225225b7504cf4539e37f1639bfbb42d4331c03bc7dc63b18d53dddd7882c4106952a6ac0666f17fba08104ffc63d7b6d5f221319c38b77305b274ff5a0aa7f5078db92c5cdf10828fed327000242ee2c1e13845562893e1b998b469a29ea4d004eaa65fdb1f1a0525cfa1ee2ea6825611e54ca07c12bda2b3eee344d8a881496950b46c0a8ed6af8594a3f00f519abdcde8a6699660fe5ffb9d4ab7848f07073da92c7c71950e29b626819e298e40bdfbd18fc92d791ec0978c31eb2fbbfeb388dc56b6999a881ac06b832107c33afea5884de8c8c5e56c91a2df0760942ef453d17a4309070d2bac4df0a12e5a5129d2f428edefac1b0cf1c99e34a0825e73a570e04a4942650481b3124528b94de68bff6a002a968747bde8b49a76ed58d886a1d0f4e2b5584c47842f367b4af6dcd790594b02ebf2c6ffe66a606a3de2cafe4c91695bc6aeab06aa909cb27314b4be903ff3fe132431bead08af04dac5f116596cd03cdf2ecbc70c7d9e529e6e1648e56223a777e52f0324d6aecd2cc9f6d5b0a9510e67a25191923d64e532cda87e780b01837dfd68d5331c864c9cb5814439901658c6d0e86d241a17f397f915673181b51c8e33853cc2215e0990533969dd6844a263803662aa5adf0234ba030bf80e68fa13502e40b92e5f8d7169c74e827b0675a87ce3780c46e39c73d81b73b6f842a3721d0aea008bb05fa8c0d2fb110f8257fc8b98b732264c48bb1a04a651886aa1155fc24180807b089b200376736de0d3c774fd280542418f754966acb306097c62e1fd4d1f55e50eb45002c98edd496e7200b9d26be1ebf7072deb8ec2ba46bac36a6417c65118fb5a1a76fc4ca6e5b263f775be4d4d720ada8e395368eb4ae59fc19fa65ebd3c56f44408159412db260321d8f294ccfd505634f8038ce33c845daf5503cde178a8ec975f1e4d675452ba458b7826a7b450e3e7d1a716e8452067fc2e34fd05f578a9db241e61ee77bff12d3558ed26c092ea6e6b46ed438d402470d443d471db4e93d8fe1eb7ef6df40e9f7f98d090499ed19270e8fb3c3b6cfcd2ec373c6c51b21255962537b25d797b641042b62f76fd021b8595271a782d57ec21191c407f2d8e1c933bc97e70d79e44925d89497036e3d1545659276b099d8418f05b338e466ff39e68559dcd95e106aaf230275fd1de7b853279a93d8a36637cc4e38ea6861da35fb5c3559e3bab74020893116a565ae3c03270e915388b51f39e9b99ee7401f47d29fbef0852635442a79a4eb94ebfcfac5d242f1c9a021625856b9b8f9881ada1cde6b23561736f12d72d2875417408f1bb7ec379380479bc813bdeb17a069872a76ae84df0428d18a134e5c6b5e356385466ec559afa435d9af3a87aa3f97b99c270d777873876ff0c97ced33473802931c5f3d8494a3cb2d97c42159ac01fbd23e1c9dcafbdf16d213e2bc5458c506b59812029cc5e2c6345bcf4a8e7c54c87d4a304a4ef39c70be71144c371968ca7d484bb71ab9cdb18e69c055c136ec99edca0d1f6d014c08066f960f63ef9fd84abb40cd76f6e1178c504bf58a52560ac43be77fad9b6a474a6dcc986361e6babe5fb5b849f3b952be9dd68c52551d75611e740da92883b91b0a4c59ae16b9ec38a40efa0c36a30da5b0d49ca1b59f7464f0272bb83f04d7c8b379d5ac6495d75a36b11526365aa2d217eaa9010a7882405f756c83557a1e03f7f99ef6d217169366309c20893cbcb4516d33e8ca2529739ae34262f260063d56200815e59a3464e121f19395c5a5dcebf0bfd15b21c48f50e5400f9c332ad54ca1c37225bb9b4f05f9b7f7f28218ac5609bf5353fb0df4001fd7c1c98ff67c49e333a408d7b5d2632c41b615fe6fb31e1cb4d73b1d403236f78c21f0b2f392dc68eb24059b3e6f773e316676972571a29e32e5771515ca43e0efb8a8689ca982975c6ab2627fa6c0a409719af8d4789222bbf6ae5ef93ce57044fe670d6c30cb12f9e075ba03f8be023c70097fe7384b3eb2933767550a6a2a5e5b931decb92450663df62e65d5edbd4cea38a8f8216c46a933b8cad3a360738e68e31698b31cd403db8a2c1fdede49ad38af1061d443ef12608905dfa856f0479ead73fabf13226531c83f9c73ee4bffe3e322ceb1807c80924e84e389bc052c7578d27d2da5a00ce926d55625cc1897846b7c9959908376517fe489b81e46af85cbbeba8f52e16d5a3c89f774c6541692ae6a5c2cf298662673913cb3ec1943382c751d74996af91d5fc9dad17b62ef97329871bc353fc279e007671da4118a04f1a2204de7b152ab37118adc69e9a4ea8e739477c6ce2dd43bd3a355e4b3d684d1c25d9bdc38ec7c290d71e6104cb93518781ef025d80abdfd727bed1c64db3043524feed5863908cbfa4a9eecf0aeef77328bb5e0f1ebaf9b605b53b9c8ea8fbcee51b7620dcae986745f677e99f872112f6529769043219c29cc1a4b44970ba4d32d7610540496ef183ac0339d28757ccb25db5527a3ac863b48b15f6c532c91cd1dab5eed98897c326739ba7eb1621092683c1b4c7fa8c0114ba954a4c17b1a18acd7ac2ed949a47f6f5461b315b0831186dc276349bf00485f72d982447f9462758b96bc595ffe4bbd70c7ded7f93ac51c3c080094579d4cfeae4c896e929726e2279d0a9b24f013cc4f5b568a94be3992cc4ba8e1fb1d9ba3ac2c2ea26c98c29d4c2d9e013110842620aace702b63cb750d40c0a521f7b0e90cf6e682562fe1e159c6eb4e1cd6095595248b5b25e2075d8fb5ec7054b23929314b5580f7b2f168e10776b440b71fd52d57219e0cbf8996c3e980b61be370fec987d010b9d87d8e725dc4e6354a342f59c135ab5832aecb3a7a21f8eff214d4263b0ac424f6e2ec7e485a5672f5e2be9ae11c158102036563d644bb39647143e7e34a1db194cded6535bb877250a81d7145696f1fa403ffc08c6d6f90c132c88f0f328ff8389b1bd7d44cebcbd0f0c66d4c821aac7f4ce4e11b10a87e8eb5cc7c1d389d6168d6f246729315e7fd5943ff851a9a901a3adf45f0b2d86b2396da3fabe0b8759c1e0b21bf32784f3c5e10987d878162fb4a295fabe881df36428c6a29bf73bd58bcb10a088f956a245ba6d8a44d41ada9176d9ebb0637531d452d5c15295191054fae6fed2effd13bee913087f06dd89a1f16a39cb06b5f7f1b67b60ca2d4a948533db3db850a1ce9934a209705586c44cdaedecf5b806ca231b5e85ed07f5e9843f97662166695c3c64c396ff0b3d14fafb0d0d18c29034d248263ba26b4395bbe6c381f7777e4411411db5146f2cff131a70a31b6c7abc66067c87d1a05c2290ef079421cc080e7e92597197c8780fff00beb6e6feedeb471d087362ef67186d240aa987ad2e43ed211ecf705f4ccc2775a04f61c01047dd5571063ea08cfdb94b75c71161186ac5b415d9887ccebdf140bd7474fa0c5a91765f484bfbf55bdc2deff7a732ef0b6e14e596c566266ac62bbf3007f308acc9477c427247c7b93e9221403166dbae5009370e10677d5b0ffc4b8802f42dc3ee916dfb9cce2da04742b2aa974603dcd35ab34a52c5fb19327c0c864d45a229691cdd7bafd64d975f044b3dc11a901c5fd1005171c9c72b9973a731d02e9066a0b072cb95a84f26eea19402972aa9f75c34c72b57bb0a19aaa9c79174f71f00fd15d4f2348c5cd55ce2340002bd77f4324cafe1eae3eb6ccfe512af1fe77681e712acf876c99c2d118cd43fe81d229b49e1617a148893ab6ff13092ba47be71c671a2e641a936b5756a1bc83390d17409bb84febbf4295ef193ca422e5f1e5601f85dc37f7252f5f043b2a2c95fac08dba1c176c96dd60dbf9488c86177bfba02708697176d1a76ebde40d594d2dcde255cc0e9253cc24140bb112b3dd7c92430a0c46bf1e2b4bfcc046e6a7a30897e50b5285fb7a91481dcd20e73a9c7631df352c046f5194859fd7de46865c3da71c571a2e067fbf556fb9f26a98c8eb52cb34c22300b59ffcae41149d73cd1f83eeb5bd5751d7c8c4705ec02d4d075e8d9d85791311bec009ceb8846c0e7a30b6d293a6a25c17202dc627f49fc5cc424acca3bb5520d18745679a9822a4d813a87e9d508f93b267e9d7b20a42918c3902ef2c0379ac9268381f53da61d58b2ad1392f558f773e02913b699bb64ecb955e6b6aebf12375e54a4c90c59a1ef808d998c62012952e82ac57cb135b4c0f09a5c7fccf4c0400710475cde44bffa3102a13ee4ac97be85aa3b362fbb227cae8819b6e37faeca6adef3167b0e7e620e33b412430148a000d1fe4adcf4b5083c47a4c1bb07e4bed0e72e5fab60e70d5f49596f46a744e1a1c695228089754ce2fe850a1c3568057f53839f35e200e46c6b19bdb7479367b0b28824e3216a31e7d645f7ceb14485c049773ee23bd3cf7cc27b655c883e1c75bc60bacc659d9d95f66bf298228028daf194a47a1468b7d97607cdfd134be7380da44b04fc157932867f62443122d51774613ac514c582c9ae455e648fc5af40ccdc3e5490daae07b00aaf98853474bdfa66668ae4f41a9592be8058a5b15ed62291fd82c6f5235c9a93405dc7bdec15aa2c91932bfd65854bf99ca0fd19db423749ef56486dbf796ca27f5a9ec62767ad3a24a692e64de0017e18053e040ecc328f7c9abe4a6ca54fbfd359b3560cfb2b18858cc1b9b9f0dbd65e4f117bdfbc3ce80c14cf9511296b73a420ad7583184b4f1e0d5f7e90fb0288d4461d8536597cde078d2455954de7455b79352b7407356656f0", "26263445024bbdbd0518b331a7ab88e7bdc8d8344a3480d1c19ad0e7c7cb22447cf88e53d2536fd215e25c5158dbc52ef56585f7ab5b771387811a9f9afbdb7f"}}; + +struct sha_hmac_test_v { + int count; + int klen; + int tlen; + char key[300]; + char msg[500]; + const char digest_hex[SHA512_DIGEST_LENGTH * 2 + 1]; +}; + +static const struct sha_hmac_test_v sha_hmac_test_vectors[] = + { + {30, 40, 32, "9779d9120642797f1747025d5b22b7ac607cab08e1758f2f3a46c8be1e25c53b8c6a8f58ffefa176", "b1689c2591eaf3c9e66070f8a77954ffb81749f1b00346f9dfe0b2ee905dcc288baf4a92de3f4001dd9f44c468c3d07d6c6ee82faceafc97c2fc0fc0601719d2dcd0aa2aec92d1b0ae933c65eb06a03c9c935c2bad0459810241347ab87e9f11adb30415424c6c7f5f22a003b8ab8de54f6ded0e3ab9245fa79568451dfa258e", "769f00d3e6a6cc1fb426a14a4f76c6462e6149726e0dee0ec0cf97a16605ac8b"}, + {31, 40, 32, "09675f2dcc4783b599f18fb765583668a0fd8ae4096f6fcdc60d4f35b4130fbefcd542ffe7459d2a", "0cf2198c31376f5c8915660137725f2bbc180a986e5a7bda27fa81593a4a339bab92cbc39fb2b8581108ee48c794812d845a72ce8008c9e915d9e330bbb90e9136aa53ba0e6693dd4046d6b03362dfb9edfa04c887153cc5de677aab8c7839d517035879679c29727e96c5426324a2575fbe678d6cc7fef5eb6cebd595cfddef", "6b142d4dfe217f1881aa0e6483b271dd5d43f70b85605953a0fef272ddde46ca"}, + {32, 40, 32, "cfd4a44910c9e567507abb6cede4fe601a7a2765c9755aa2cf6ba4814223811a26a8a1ef499cebd9", "3fb301cb4092f9623aa5ffd690d22d65d56e5a1c330b9c4a0d910c34e391c90a76d5401a2d3caa44b8c5d5aef3e928b90d2ee233e9f9a2cec4a32cd019d06a0dc1fcb1125f5746a4fbd32169ed7bf0e4fd065fa7c8ac97c366380484495f5c5b6850dd1c9d8cd6694cf8686e46308ed0ed1f5bdf98cd831339771db63de5a7de", "20153bf8ea2953c48251ebcc4161f8b6e28499e5c76c24014cff4a9e2f62d25c"}, + {33, 40, 32, "5448998f9d8f98534addf0c8ba631c496bf8a8006cbb46ad15fa1fa2f55367120c19348c3afa90c3", "1c4396f7b7f9228e832a13692002ba2aff439dcb7fddbfd456c022d133ee8903a2d482562fdaa493ce3916d77a0c51441dab26f6b0340238a36a71f87fc3e179cabca9482b704971ce69f3f20ab64b70413d6c2908532b2a888a9fc224cae1365da410b6f2e298904b63b4a41726321835a4774dd063c211cfc8b5166c2d11a2", "7e8cba9dd9f06ebdd7f92e0f1a67c7f4df52693c212bdd84f67370b351533c6c"}, + {34, 40, 32, "9da0c114682f82c1d1e9b54430580b9c569489ca16b92ee10498d55d7cad5db5e652063439311e04", "4953408be3ddde42521eb625a37af0d2cf9ed184f5b627e5e7e0e824e8e11648b418e5c4c1b0204bc519c9e578b800439bdd254f39f641082d03a28de44ac677644c7b6c8df743f29f1dfd80fd25c2db31010ea02f60201cde24a364d4168da261d848aed01c10dee9149c1ebb29004398f0d29c605a8bca032b31d241ad3371", "cdeacfcebf46cc9d7e4d4175e5d8d267c23a64cde83e867e5001ecf26fbd30d2"}, + {35, 40, 32, "aaafd08fd89bebe239ab65bb190b86d49c5d39faa50b1109f7dc8b179bc693f0810449c36a68041a", "44131187c07a8e3979254b0c1d1cfa8081f0beb8890633744932af3f6987c7eace6e153876f639dba46b1e9f3e2a7fe673b3a954a00082cb7516ca9a54d9a1f1f924499960192ee1e3b623dca4a9efc92a6608d34f769efb5912db5267f06a6b0f5d3610458c74347e2ee32916425213ef2f649d5c1090ea3d4f6bcf6b752a3f", "0c19ab5d4ee7b64396eff7b2ca9efa5ca7369c1a1ed14952445d2fb5ece9473a"}, + {36, 40, 32, "b06f7ca7a5dd8baf2ca940811edad87a33da666dc427bcf4d54a8e03520dd5c399e9729d39be1494", "32b45fbcbaf262bbe347360bd6076c43dc26ba9573fcabaea14595de886ccc793b09157dd0a85d74b6ccab9c49335446a45c6e7cb64786e6997c96ef1e4e3123ad6101db4c6a731dfd36b1be4deed1c92a994b25f5e2b171d81b9a335a83e03230c40b2056c00c7c5f8d2fb70abe4b9615e53bd756569217072d8bf362923f6e", "a9c9d3993fe7ec4c2033ccf3b73b3407cd999d67455b43a75d6ba97efda3be63"}, + {37, 40, 32, "2dff35c2fe5039123d4c5d9feb7d5167e3e959b31841abec1e5b18b0ece2ef25e04d1f8d030d9b1b", "14890f3b2ee63746c8249909013571a403eb54273760090db5959b06ff59acfaee6d0c4aece58b5964d10b4b771dd90cf1b63d947bee4f6a12220d67b79aabbd68b02a3850352cc33b10072d4c28182df2855aa418b236239c659dad036155be6b9c908bc09dc38c3329b538e81ed710ef9fd3de7671673f3da5745f4a785204", "468d8498d46afe74a0ffb541b847bac724faeabd48c41322bf534b284c4e9fe0"}, + {38, 40, 32, "9794cf76aeef22963fa40a09a86bf0e2ba9f54f30f43bff09d44f9d28cfd7b7a45002797cc1437c9", "3e8a9030eae1bb6084cffdb577623c4cf94b7aee3d3ca994ea94c12acd3e1194cad6d2ef190e0219af517073f9a613e5d0d69f23aad15a2f0d4e2c204ab2f621673325bc5d3d875984145d014bbcb1682c16ea2bdf4b9d56ce6da629ca5c781cfce7b1201e34f228eb62ede8d36cbfdcf451818d46721910153b56cfb5053d8c", "29973999c4ec891154b83ebe5b0201cf29205d68e7be2c1d59bbc81658d6668e"}, + {39, 40, 32, "c1d60814376aae39c4111246353485958f95558fa38ffc14e4a0981d76249b9f8763c4b3e2ce4ef5", "97d29ac5ede94c0a5071e0095e6102123d1726132f9dc102672ab87b1cec18abdb04096c21d3fdb129742d250389460fe63b5f79c77c2f912a8f7d4f39cbd758139c872366cac35a40fe248322825adf57481d92832e66057f80e08964be993de6a0fe31e45806cb3c17ad6ae4d2a44a374647a88c3acf260d04c970c74ec720", "50db0ecb5b31524a6914264930abccae0da07f01a2bbb9408207156f8e8a340c"}, + {40, 40, 32, "ca5f3eb9308604f9fcc2af1c6a3175cd8a75045593b473bd7ae37933c345ddb0982e2dd7180db31f", "8734e49e3e629deb352c77f58ff4dcce2af3b1182e7d896ae68619f6cf66ed69efd95913684ab1484d51bc06b47a67d70d48b7f9b27901bdbf8c5d2d238158f1f7e0e9740ffca742cf7938b5400c0dd063824c6bc6040e905499cb2671ec12cc47507e085a01e5a163acd2495b32367fd6aa5ab492a518ad50b54b28e23084c2", "a5772a3da86365b46638f1e97037fc0d8351d2e19ed929f85448ebf4e8379a8e"}, + {41, 40, 32, "808d7aa9aba6a40d1bc43e9b932ec8e9273b892ffc0a769e4f7255f3b83c224bb090b23952ae9616", "61c5be972faa61f67bcb332542c0b8a7c74ef67cdb95d6f65c8acec8fca8bd6043e31677d8de41e6fc5d3ebb57fd8c8cf723490b96329adb1b014da2648cbd6043e9f6ffc67e1a2bbc72046374612a50c854c8565af03b6a1eedaa2319caec1368bfa65783f4b46dc3f0cb4622545c9c43c9bb86b237804a6c382e72a2cc1222", "5f1b8de0e3b07da6f9ce1a494be5712e54ac16080bb4f6d5373620d86d5ea5c7"}, + {42, 40, 32, "d8b994bb8df02d7803ca2e09d601b918d6b5bde90b611bebf70e078d1ac7b152bc4c2528e60b70f6", "b31d11cb4f5c572ccf3405c65cbd218ee8abdc08b6c82e5d1da2baaf8980f7a9c29b915a718b0d43e000adae01b29342b29b28d53f63bf81281c76fa252f5d1e6896dbce224c4dfd4802ef0697140043d6bb21db5b84ffdbd001318937be64f52c76b5d06a875e8191a4957627cab1b8dc758fc3121334949cb9b303c6155153", "8e44d685fa79395b4761cab89688e37509e69ad007a2794c8c0b4152b67036ea"}, + {43, 40, 32, "a89bbaa86a339951ddcd37799e21b5d1688e4abedbc72daf7cc9b5adfe10be34c00a504196cc7bac", "3ad17308cd259688d5b52c32d01a3b868bfaa4758bdaa5ceac34a1f908ca24e71a39224924d17f00cda4d4d50fdd716b50549e71cf5f271c42ea17d5becac32fd64e0a1b0717dc5f542af9442d44fb8f956e97b384d020458aca4cb0b6413b2ab637b5e73f9fb48cb06f22e6f2f6e3dca27016a272d89830ccfdcaf3b9d895c2", "905d55da5d290d023f6940fcb904c50e70181c95000eb1e6a33aa01077692736"}, + {44, 40, 32, "a9560fd61746d7f986b691f070c920256a535c21a64ab5a2bd771aeeab7119681bcc4761e68ee230", "46eb5059055d3345c1ea84a4ebd2d7cc53361707eccd70e7cfd86bda83585bfe7c7ef937e1634b7e93f9ca7c6a42c357c2bffecc362c9e7eab6a488d91bd876b65376feb7a74819bfa88cf542736610fe763d6fa80c94ecca0f08855a05a485909fefc9e58f99e44fe7fdc55ab17779dcc08e9bc530e4a79b65274593a996671", "9045dd3fa6e8f2ef7c57b03932d244186caa1bc1d4b694c47e1f2901d9eba193"}, + {75, 45, 32, "b763263dc4fc62b227cd3f6b4e9e358c21ca036ce396ab9259c1bedd2f5cd90297dc703c336eca3e358a4d6dc5", "53cb09d0a788e4466d01588df6945d8728d9363f76cd012a10308dad562b6be093364892e8397a8d86f1d81a2096cfc8a1bbb26a1a75525ffebfcf16911dadd09e802aa8686acfd1e4524620254a6bca18dfa56e71417756e5a452fa9ae5aec5dc71591c11630e9defec49a4ecf85a14f60eb854657899972ea5bf6159cb9547", "737301dea93db6bcbadd7bf796693961317ca680b380416f12f466f06526b36b"}, + {76, 45, 32, "9fe42dfac92a4a136fa7c9f6e331b5d3a61aa73035b53a8d2517be43721b31b215a96b9bd43798cb5e8febfa97", "f9660fb784c14b5fbec280526a69c2294fba12aea163789bbe9f52a51b5aebb97d964f866c0d5e3be41820924fcf580db0725c7f210823cf7f45a0f964b14e5555070d1c3ddb2c281a80c7fbf72953031a4e771d7e521d578462cafae5a02ac8eb81f082e173ddadc8c41d964bbfda94f5180c8da28a8ebb33be77b0866fa798", "7786c155d10c741b63ec650b7b1aa3bfd71ac71881ad06ae98fb082f17e0caa0"}, + {77, 45, 32, "98fff7b5f77326c24471bb9c317490be1febad28e2e825afc41c3b97cc03c963405ce3ec68dcb7b19523b76e62", "64a78a4d6fb8ff3813df8dc022faaf4415e4df2949e16467683c6c47242e5a6b2c02610e5877528d2766b2266ca41000442a956c4b73dd6b10260570c6f506673cc541f50f0f5b021e864a753efab03e2f7c689acfc35f928ecea6c522cbc5687c38518bfa48c19ede887d33ffc23806be21803a3c9793e5ca7c75cfa1783f77", "c02c6022ee0de099e3027850be95a29ce800118ed3a97757dd8ab9e60f69a005"}, + {78, 45, 32, "8d649e5ccbb8bb0032cdddbbe44ed0b5bbbde78a30c0f8437bbca985fca5ea08da15c34bea9b5086d2550ae16e", "a7734a0739d51af0ac2c4039dfafa86f36fc06c2355d0f654d4ae938f52fe0a5fd6f5ac71fa80dd2d8396faf76016ee6716a62c1fea640afe23910e684b8a14c47d07b98168915b441cc48668724043074c14275edc239dc09b4d5fa2255652b2c9e94c046019a608ff0b3a83b9ed015e6098d24273864b769c120bbf68f9408", "13e0834e4dd72a2ef7872249bf895da4432329c6e8ade8665d702ba33bb677b0"}, + {79, 45, 32, "57958d7e4c73fa606ef405d77ea4977ac96b8813fc1210483a037e7b6c502ceed8f7b22bf6655aa37e38d495c6", "0b9a58cd96351a135c559d17e82ede3434a0caf0befef5dfdf138ec5586793fb2ebe4114b9e2cfbff7a25bef261b253a9136fb7faa72f4cc59e4617f947c01ab308974bdf67ff25ffaf83d9c28fad44520786a94441b96100e42ccb0a8478c43b604d90f7695edb90c602b651753551d886dff77b4804472a835b7a2bc509c8d", "cd251e66c421bad1b37cfebfa3c04ef30b8be4e5526b10fc48fd5bc5d6f04bb4"}, + {80, 45, 32, "6d32ba0c063774bf8d0621b208d72095f684faa33ca6f3dc62fbdf95ff0c3733720c6c34d3027b6f2a2bc29cde", "e5804b099ee4b351843adb9c9e3c231773256e6a2070d697a9e29e258dca677f9d88a7970d4c58cecc20ed1811298a5b37297419ca49c74fe216679dafc938a656cb92bafb78efb31f24e71c2d5b5f994f6dfd82862adfd2faeb8c408fd22aabb852f2bb90f1e2c6274cb1f0195c089766f9efee7d9c86e79a69f557526da555", "9d283d8e8e473a16162d186e96355b1885370e83954dbd08622dbe64f0aac695"}, + {81, 45, 32, "6b97478fdafd3a85d0d9b339971a70c2fd24d542abd3e20eb2bd630f67b86668719df258204bf66201ee80acaf", "8b1d4523b6e457f856e5f09875d389eb6587223e53477ba01f49878c6c731ec9f365f28f1cb9c4ebcf89d8648732a6dfa958d2c0152b5e52fae81f69eea26d463e421fba82cdb78f75e5d92304930256a54376a6ea107a995642c45c6f1530a914bdb4ed11a696abf100dc1b147b0518014ff639fc80373ddc605fac1755cdbb", "6ab8f69868b4c87fdec9a031045b34b66660212f687a83d561bc4f9caad59fff"}, + {82, 45, 32, "89c77d79de98df18f0cf29a9316d6dc46b61eb7af7f1e2de2f5ca6c525bef3c996338194193fd85b9c6e66a811", "ff8662e9af3a38d3efc0143138fa619a57d569f61e29b3895ae08f2d055befdebc11787c7379d9cd672b5cc25442bafbe804348c78c5df02f30840a114e818f0dbb681783de43ac81b2140bc71c69effd07185cf0eef9f003c60a144d89520a944bda563774103ccf3ece8a9f64fb3aff564854646719b8c1d2fdb9db92cac12", "4746e6f151caf29b3534b2f493f7cc1308fa119116d251481572a1b53a8a1b3a"}, + {83, 45, 32, "08cce7d7f3ccea0212cf0299f27f3d3f393a97d3dd71caf1954e67bc8d9a26db5edd7ac23dc7693372ce9b040d", "33ab861f089bac0e5c886f66adc568ae7ba331655a371de7475e269138ff2725f7904c702fdcc62ac703c31d70c29d8a7af451c8ec59342ed397e133da7e76d41b90003635c1338d9f7b5f3c3ce59f3e2f6554c4f064d11f9f5158e199e8463f4ab48aba42d25bff8af92b0b38b7d69241fd20a28fde5e84539473e39dc4fe2f", "2c723282159ceabc5b367b95cd807f249f1dff7f9ebf5ba179a43081454e1b05"}, + {84, 45, 32, "1a2e86f6ab2db235e5d7f00cf438680fe5b442dcb1f8c3ae7730b92f097a1a8eaa9be8d216f2576ec3aa321567", "5a2240f64fc704ce9f8ed33d019e4155cb46747a659e3421fe6b42d67f44eb84bdf3dcf1f31e38886f27e85b8b503368df238e1bb511b515bd59fa2c032bddb31d0ddefba97f8f19f7daedea027ef055a52c61d00bb1ec2668c57677e632b180e339ed1c5931310b9d718af34d70a3a4832b96a04fc702db65785ebf12a18c73", "22de07c3055a8935b52bb2c85a9a6b7ffd4038b5db4069c07e9e86ee1b171d25"}, + {85, 45, 32, "3270b4e48d575f0312659a6202adbc4e877d69298de4090ed47278b4433fff95802e844fbd73fd4ad5532b9b97", "f407f815a33cd450c0b72a378f00762788f91bc44f09f93de67a41d2222088935b3c1b6a689f935bca13a90b28f64b7ffc28ef278b28271b1a7975a45f4b61fe3657ca5c950b7a2dc2e7fd9ec327b26017a222aba3f29183efd5d33a92d36136eb21acf412c6b14d0efccef849d9d451412e5d587fb060fdcd55029ba401afc2", "dd1a8105ab753d83d90ab39adbc748940fefda05bedea7eeebdbdf54b02d9ae1"}, + {86, 45, 32, "c704d5793539ef3909bdaa7c29e9c0a0c441814c37bcd062325f6e2e16107be4a2aa3949cf4d14b0f8f8df283e", "dbb84fef130f929805b0876cb4646a046330bc33ab1cf1e9ca3869573ee1a1549341ab007915dba719b3c4e8a94b62163e6d99dee2cbde2ae74135467b125b417c7544978d50c80c694399db77e878109f59a8335df3a326135a0d50a4bde6fc3e5c03fb7747bf919c68ee8f45c312bc2dfdd279411ba7a5f78dd9bfe16baa4a", "441c7fdaa40e50bf1eba073509769b1c0942f3a16e1e183435819d3b5f8538cd"}, + {87, 45, 32, "5b2cced47045bca47512fe226c1f415ef127a209bf885b8a76f5a24f9c6bce61e166bc3ca75471ddc14a001c7b", "1de00288a6e93930070183de9d9ed0ce86f6cc0f64b7bedb5df8af24676fd06fc2e516e5c5e827a7dec07963d5a4b825502d696f9c0ace8baaf6092058e78304f2888f51f9ea4bbb2376c720a2276a61a9f691712d9578abe95f5e69a490e4d2b6b1b7f3c9576e12dd0db63e8f8fac2b9a398a3d9ebe86e3201df726d2d1ba82", "15c62ce7a3bfd5b3b3856d6f47cb19bb7030dc469e35a27807511f81ea83091c"}, + {88, 45, 32, "0d4dd35f90f0a10d7d8030e9919446f3d5e2532472bcef0cc5db84bab65c48dc46086f2768d89ef912b8a23d93", "2937aa2ff7c942bf7dcfa670154e988c28177391969db4995804ba1a647acacfd0ca56f63b2e7fbc6965d8f62d066d118c14044c1fd2a224b9d951104a67216f03fa6dbfbb1e5f0f9283b6b7d452c74620c1c2bcc9e637fa7cc8d97623bc81330aef76f1403feba1414fc91bd1daaf132b4737495b7e7c01e9fbd9b3b720f303", "d5596bcc39af2782df1cd9fc8c37a8f96789275422f511280971d8429a8cb661"}, + {89, 45, 32, "5ef946b64ff80e4df8ee98a357f07c825c3acc434d0f994069c0b88ccc0ac5e192a469d93f19d9615fd49f6b69", "dfa3b06eb1e30b47ad9f0bf0f441fcd94856ca8b1f4cb88cf6795582e860ad9c7f30bc2eca8e289bb0942f78831addeed934836097fb664e4e91b47acb5fbc49e9a15d6baa25bfbe864f42700361b46586f9c7d869dcc2444df17685b291743ac5fe7d6f78303a79d8d82d209c9fe804f9ae7d39be7435359ca385ecc57c3d39", "223dfaf583140a769c805c33f1f30bfb2f0926b088f55439dfeb4f5a9ceeedf1"}, + {120, 64, 32, "992868504d2564c4fb47bcbd4ae482d8fb0e8e56d7b81864e61986a0e25682daeb5b50177c095edc9e971da95c3210c376e723365ac33d1b4f391817f4c35124", "ed4f269a8851eb3154771516b27228155200778049b2dc1963f3ac32ba46ea1387cfbb9c39151a2cc406cdc13c3c9860a27eb0b7fe8a7201ad11552afd041e33f70e53d97c62f17194b66117028fa9071cc0e04bd92de4972cd54f719010a694e414d4977abed7ca6b90ba612df6c3d467cded85032598a48546804f9cf2ecfe", "2f8321f416b9bb249f113b13fc12d70e1668dc332839c10daa5717896cb70ddf"}, + {121, 64, 32, "ceab398e4107483ede64ce107c9270e6022778b61f6a258d3b7045d4ad8506d32ece0a738d2cb948a562dbce8d7b66f30e6694d65ae439cffaa454af09abe449", "6dde9ae867e2feb367008a975d7853ed8f89690f3c87a1107f2e98aa7736f477a527ed64956f0d64c1b23361b261de78688ea865fcff113c84817e5b377e829cd2d25bcf3adbc06762cfda736f5390d01a49079d56e969f03313e6c703e3f942bb87ed0f9c4d9f25120085b5dc75ef5d6d618da0926d3293568dd7d8238de3d0", "2d3a760595f3fb19293cc6d23651222a9f5a4f02284457a9c1ed4c43ac993ca5"}, + {122, 64, 32, "6a6155dc4d59c6bf46caa3de09666326da308c51a23e6ec342bd12b227376e8a1f11da906b58c8c515bdaf0d84dd48904dc6fd614cb79f5ef4285757e30adf72", "107bdfb55c601e74f6505015a5cb87bc0eb0b2e7cb04594fbeef8e0fa5072007eed21183cc854a188a128ecf2062ad8604dffa924236fea9cf5b6e001acd5bb0e51ba95e53a7c21b42aa8b89da78983f66069c6f63a923c6d7208394e5d50f2d9d608f8f194ded45c51f318bfe94afb2df2b7fc657e42e6f7f47b3152ba7a547", "6dc2b05619ad5458ee3de70b0c1649b3788e1a5312e8924b5486905506970881"}, + {123, 64, 32, "ce97ded47e101a6d0aa1041138093586046524f54345ec9e860550c9415bfc002d2c0d7beaa4d4dce985d71d89bf19c680429c637d1023350c963c28b93c7e05", "f62796faaa333dddae596f98cd4de3931ed90710287446604a158b575b4901fd8d841e8697b4df85131c555c246060f75ddcbbbade3a38b7c0444d25b4f6d00de6d8ff47288bc3a54ca1366ed1b2620ec3ab4c0bdc6a313bef880f3587766705cbcc4124a4dd72a7228f1ab61c6a704017eec2ed692ab7549f8ad86f1bf14e4b", "837ecd647e03fe8df9a92c32dcbc87d0734851ffbc17376e03218cce9cbe974f"}, + {124, 64, 32, "554e344537a09659920c19b40f2850b07235c3c7209993a6de905c82db1e5faff148e16f2883ce087c6da219e0bb892d8272c591515b5163bdb0c4ecbd1c7730", "44e9a1f1437791963c1a3e0aaaae24affc3b405844d16a5233b6e5a145c4358b390c305bc4bf585f864f68333dd12d4139a69789105a109e92cc0cf1ff8fe2527891dab4b4fa8731f457574e39f8687fb4969dee7e3af27889590cf8d74415c9e9c0c6867bf0c5146e7c32e306ec7c7055557a0ff738b7e700a70d3e33a975f7", "9cd24a0efa26c107738f5335526b57d8c93e54fef8c1babbbbb2d42f3a1d03c6"}, + {125, 64, 32, "76d8e0342011d2bca953b26ee200e56685b721d50ed4dda7cd3a05633a50f153884998e67da901528004fb7df4090e1ec4c0b11f3f10bd4727842215044fd9ef", "0ebaefd2153de2c70537ceb27e5ee70105ae85bd4da38462b4abebed11dbcd36ade16d808f3aa54ffda5897a3fd74780a670521fcd2ebf231f60ef7d999e6e94d1b81be038ec89b49c5ca65bf1bf9a675056f2464021fe16355477ba5605652e8327401797bb569fea456c7f1b7da85d0c48af592de60ae3fe6dcecfcf767cab", "1cbd4f923d683ca38aca6cd0ad81151062fd642b155b2a950eb551ca8216b0ca"}, + {126, 64, 32, "731ec9f365f28f1cb9c4ebcf89d8648732a6dfa958d2c0152b5e52fae81f69eea26d463e421fba82cdb78f75e5d92304930256a54376a6ea107a995642c45c6f", "d98557504a21fc3a434c780c328ec239cf8d7c26f58d6ad7b23329c79a8e1e176058aceba778aa1215cc14e5a92600714f94d4d8b2e5b7f45268453ed6f787eea3342264ad13cec78d990aecd5e30f79a069024a6d846d132d2ef0479a093439cba4218205f951a2d53ac4ea5bcdd599e9956c45cd73767c6a0c92ac8ecd0d40", "4f2501d2a88cb13046a6549f90e4ea924773408bb684025b5126a8fc21f48670"}, + {127, 64, 32, "cc38826523a9097e0f7d075a3a039a70ca1e2b5590a6443e820ba1c16c3b89dbe2c65f37794074ad37e81f0a4786100ff19ae1bccab2eece281c6786d9bda3ac", "6e09febed308baa41a8b6e0f7fab61808c9c8471ea32eef178a4888e9a910a77d44026e2972c02ac5ac0ec3fed5f4ab90aa7cf4b2ef7f5dea62ea7fdedb63def35c2ae2344d301d2818105df4f78420299c12f25ae43a60e5089943f07c5f51abc15004982069e5db75721b54cff33a261700cc8151ee9c89c3bb91c92c51942", "83b1403389173568588e5b6b8cf9da180408c79f91d054ac5cd99de0b728ff66"}, + {128, 64, 32, "62c1d149567f05a0b76c4fd32d1f365d170cb165cfb38f922f1716225472eb36a127327007f8f5c08479ca7beac4b0aee26f3bb130bbf1ff390ef344c2a4e0b8", "7af390cc4edde0f3d496137d0cacd0876b54c909dc5ce36705619742cb42989418d4b6fcdbd80256512a338f843b48b711c06f582dac2607ea5ca038b7126a5726a54e14f37778fe41a6d7532687c6166a50ec638c14600006f51134d29566dc2dcd21bb9ba289122b74c870fc7992cc006a07d1007cdb79e192b4dd25b1d34c", "2f1a4c2bde7c8bdd7d8a9b6315b19ac654266120c652fc24ab19e00ac11c5461"}, + {129, 64, 32, "af81e327525f3a9104b7282959a0f6600fad7efae7709bb8b33cde34b12f830c1770a342efb6abe3250a0ce7dfcd34590cfcbeb840b3e59cbff03f9cd89aa870", "75ed3ae9085bbf2d034b864d7f87057c2d0b12c7395feb0375237903b3ebd60e724e0c8fbe3a200f518a4f61fedb971c509b794f6e62fe6f4186f894d9ea8ae50d16ea51628d66812f5aa50afeed30e634253025f5ae7ae0428dc86f64f949db8e6d5d96befb996ae4e312b04664d8c223d2c0b396e9673dbe6173fa1cc21cd7", "579d35cef5b6f8468c8285829861e93587c8dee5791208406a7f4bfafb70abfd"}, + {130, 64, 32, "17a5baecf916634433dcf133ddc2dcdfcf4a680e088928985138c01d1d09eef3b437cc6290614f14079814c72bb75c45eff255968bb29b7421a1feffa00086b2", "7809e59ad48aeb2c6f03de775b1371b7f86926ae0b87098e10c69e19d29b18073818cba862b6e4caf45158ddb2741a554ed791507d2649795004e92cc25065db8ea774b0432a457399816daf062025108dc8b210d75124d284a8434ec314c7af20bdc7f99e6e74ef069a07347e9df8b05d4571353e91026354b896c9fd6da64c", "810d7bda3421589a7dd60597447edf2b987f1e7283f3c65890248712c80969c1"}, + {131, 64, 32, "e09ad7d2ff8d559a26e0454bcbfff844e8d2415b07872bc59c93e73698f308483bb8f3212ac29050c1cc46f9aaa92732afcc67accc0e139689acffbe878f01fa", "4745100cec0406cffa146350ee12213330d192123af4a1bafdbc5c98801eaf6ecb19724a0346a7b9d6b1fc381ae798ebb0501392afbfc6b8be48462dc2522bb7baec1605e665f2e42f1679b6c383fa1f00a35a01937b5aabe1f2174da6e0d7afdb680223de886fb9cdeee1b1320dd236e6716f492f4fe3fb2c61d8df73f03bbf", "055ee0ade716231bcaa0a7d18161004127a37e7aa12773433a376073474d3d58"}, + {132, 64, 32, "fd013d615c6ca959030a520e148808a07e27d38a215634d53486ae8be43a856f3e5dc6eb4fd9874a8a6570276a9e7b25585af7e1ce39d325bd7d195f2c1bb951", "91ea78334108ce6261ddee5d98045bb307a6e8f3d0ee65c1d9bc7d28cd9edf3264fc9cb6e592d072e9238559616cd42eda584d5200729adb619f5ee5740d632dda67f5dce34b89a054fda301685df6f31416cca78f19a8a7124a2a22dd7834847a934b4a451940152cd20ffdb4bd07273c4a2b9a86c9d94e7323a9860ec89860", "eb5aaa4ee702ff7b5324bc72c98fe87df6d9cc342b053ebce6cbf27fdea0eabf"}, + {133, 64, 32, "62e3a735edcd87fca0dd1d2797cc0e574160da9ac23f60e39501a5b77688d1287f947a0791922556f5b50afc434818bc83433968931cd752c9df9f04d8818531", "ec638734d336b8da6dfaf3da9e18c7131494fcc0709cd3a9a6618e9ba62533153c958e44345a7531c3eb503a22a5d8bf7c1d1e1d0ab5cfe07d6db7349cfc859d2e20cee81a325462cdfd8747dcd04c7dead2fe82cd96b2a4ecefc070eb067f6c8ba94f09cbe6ddd354d9a2eb13c2adb7285aa3d8ff68045cbc8faf35dd6aa9ea", "26db47a48a10b9b0b697b793f5c0231aa35fe192c9d063d7b03a55e3c302850a"}, + {134, 64, 32, "abc9ccdfbd92b6919a5d6c6b5a765a39662ed90080d3549204dfaa5f6d70d48e1af8c84d53369d658765ef11d7b38510d9f431f99598f8cfd4da73d59b3b75a3", "ac4756b851fc8866b9adfac2d02599148e0db7757a62b1e06d26cf8c99556b79c91a5649ea437752cbf3b5f121961821ce1a2a4c635da461e3e14626cac707d04dfb6ed1e4ac40f106ff5ba03304e28a38e99a6daf6d9427c5980d1440a99296c05168f5441e2a6af13ab4760f55407855e0cf7f667ccb5d9bb2eafd03e455f6", "0e445d77789a6947da70848dc4da5dc9c125869bb6945b04304bde93829a75d9"}, + {165, 70, 32, "c09e29071c405d5e820d345a46dbbf1e0f8202e92de3ed3e2d298e43aa4f846866e3b748990946d488c2c1ae5a6e99d32790d47d53d205481a497c936bf9ba29fa9c2821919f", "ea7240529980076d3b028a083ebc4e24efdaa06c9c84d76bf5b2d9fdb842e1038e487f5b30a5e010cddb4fcdb01ffc981eb0fcbc7d689207bc90ad36eef9b1ae38487a6dee929f3ff929f3357cb55253b7869a892b28f7e5fe386406a2776ed4b21d3b6e1c70cc6485947f27e9a5d8bd820380b9eced8e6b865206541be39fdc", "49ae1c4a7a570fde47f7517ab18898b1b991d03cfcf8c45bb3615b5f755da682"}, + {166, 70, 32, "bce50cdfff843885d4f364d69f93bf58a2322c707b82e878eec96d11e5db97bbb54606a3a3ccc3bba716261070a6f759a70ed3cb785fd1354fe56648df11863669b70c803b7a", "93b7ef0e470ddfac6aef93c0dcd37b8f1c4baf5eadd978e3bf0512fa0baeb099ff9ec1061b6172479b5674db5606ffa7e6b5173309370e1647054aafd5904816bad5e1523032cccd4d786505e241ac83a484911189666f287553d6a8164e8dcb0c85d75c4e29f624c97ceea64a2c8b0c9ddfa560f70fa3ff91183e4b968f88a1", "37f9f32918308210849dfebf8dd456804babd6845af07218f9d9be9df9743d55"}, + {167, 70, 32, "0cb35a02ddc8c7fb7c93aeab77b9318118b0fd449524209d879a1cd69d5439e192741f9c5c64a353a774e28681c58ced576783ba20bea51ed82ae50e30e6a147843130900dac", "21063443bf02ffe9f813dc6688920d036041a2a3a63a9956fc254a2c05ae03472537ef3489c93c7c68517c7588094c5e033434ab4b0ecf9e6c032c17911f73adcac6ccfd0ca57c427ae85127e2ad41d98bb94e5f2e6aad2e42ed26f87cb1bec6971c9446517c0966b6402321a06834997f3ab66756377a2f064d0277cf4e2bb9", "5c258ba6241f65c2ee5356bb47332236baea227857e29506165861a4c7379c51"}, + {168, 70, 32, "cddf76f985d6797c9fe3830c210567c5094fb979343fd5a1804c239a2ebe9a0e8ac283b0cdbe802c42e2cc5da800c4c1d89da72ba7489ab80e2aef0488dfa69ebc8434b95c11", "9724c0d5c989e5adafcd7527fee269ea14c0aec3ddb62596f3fdee9b0993e6c689466e877c0f6fb4aba29bc40343f53d3edb936fc04ba263bf00ac0fa7c816cbbde4ed09025ee2405a9d9229ed360b2ece058c20db7d8d28e43cff000fe2d5627a24c3c1231c463805e3e4c08462b5a50b65223bf4f1edcda8d872d6078a2c73", "3c5a9ac2a0fa2f58825233ff676bedf93d8845a409a42a05a9ae5218cea14680"}, + {169, 70, 32, "731bdc9fb219f3667c9a135ecf34c7f52cf638c39c554f1ef1691ae84e5a71ace915d9e91043a8ae6a7b6a6780b684f77b0417072f7e279d597cfdf02508c97bf4928c505be5", "12353bca6b0f3d545ec4b470c69272f72bb5589793e6ca769a226018c5acde83145567a1d6fbede5c150ec3142dc58f81246d4a00acf242a381fe51432447b7eaaf84c8d43222c0da3a0175aca442680a21cbca1d7f70097e82491db7f7d75a5fea552555a8de0122c3d9eb105d1c4d802c17963a1664706d3bacc345360b240", "f15a210fca2cefc4d92bf14ff572d021463bcc28f60d034e87222dc6076eaffe"}, + {170, 70, 32, "85806ff2a642f729d28ded0734aef4f6a3f0bb32771e77729b4391cae4b49bd0a15089fe74071e576099a44d22a0e0e3c5d1450f717f68628460b4eae3945f5893e39c5e8347", "df073817d8687293257d7ed1816803afe292d779f34e14b0c5ba6e0ac1e6c3b9e239f4f02110f4a430a71e906a3dcc7b0b7325bd9cf63600b25d4544d8556126cafb3e61e4894095d935d647a8560929ccc9559cb393b77472c707fbb7ab8838ff16be71091c7fee8aed4d0022fbe3428f5b0e1f216ebe946dc05d3746305f79", "6c63bed6c6082bfb085cf2426ef3d0dea97acd717a57ff0aa624d0b803f2ea14"}, + {171, 70, 32, "f13794e5ea5e27507a7bad638f8eb8b86ca5ad73b5a17424c63c74ef494bbfea084189c6fff5dfb2b6a5967cce3a81f9d9cde7a86f6b33927e15ee74e10beb20344bc121e754", "cd3f17355a1e254b9821276141a850f0b71cb3cf4824a803b01c71d8dfc31d31fd33ad1cac1776a98d18c6fd0598caa241a3af21772208d36f5270f4437570f963c8a323dbb41755d948f72369e7672b843eb0a849799d448ab7252e8abb496d05e44074715fd2f6849b02fbf6fdef3488d6fc8b45922fff0832d7af3efc7234", "d08563dad7c32c02b305b87fad504918fd566c433e98a1367a3dbbadb26e9b64"}, + {172, 70, 32, "e3d0c3abdef069e6e4fa35015797bd8a9d64bc9b75f20b028b12cca04a4fe80ff1bbbd88e9ef1003564d499fec88df4503671188eec5d7d089dd18b812c41db43a3746f77b97", "934dc1ef76993aa82061cf67aaac7714f12e25aa8f6f54840a2ae3d84af32481511d300126db7dc612a5b2ac0fdeb9c47eb316541846781e270c8ee5f6731c2e86c94e4482594c7e75d70ec43bfe7250b6778cb2c2fd3d176abf07ca5c051ffb9a17c4c0735bd059b2bd8db81553c94100412dce73dbcaf63a0af58f63f15571", "5717fc337916d66b4e292e69d507b1c81663d8140536670f3e70e33b04c83ac3"}, + {173, 70, 32, "51bbdf37124cee0cd5830e9d8f4b0ecfa44c8b1bb86a6433c18f6ee961ab694d74f93316e5833c44c5e83a039e5d1ed104f246e36e17f4c5445eff423982c883dba9707b68e6", "c84394086457d8fa900a57f18ea50a93be16f06fc28b5532de40541da5959bb6d2646ebe7491ef644ee39cb87d1219625b213094a4ed163dd707ef80dfbf9564f38195cdbb657babb4015071d58260c973fb418562fc10d95d67fec8a77f0bddf342121b82f906368b0d7b04df1c682ecd4c2b2b43dfcd6f370888df45fd8689", "3e0212e7982f43fc303d5e8457d2ab630aa257302ac489c74976cc5678823931"}, + {174, 70, 32, "e95751c99e14bed0dd9ba102f48e5e440519c53208e03ab7133613dad99042db7239347f5a47f9a8bbcda428ef52f5d7408235e4f3246268864c8c4135d27f1dc302a2d57695", "36bda8d33b3bc10f367caf71c5ed387fe5f1493c1d3bd2aaf97ad78cba3cc5704c0c02ed78dec72a5bae329f17639720c8f91817badf7511d99e257c68bca5aef6e0102a8e36f01f2f1553327be0227db32aafd8e31d8d575a1ca4145da7842e1d7ffa11e60be1f898fb3bb15b2b81a08fca370702bbc285663b7edc02c50cf7", "d965907e6d0f926a7ea719464b1034a5879c865a00d4df0342b2d4f4bde0976c"}, + {175, 70, 32, "9dd10a4c713776700f7e7e0a710a014b923bf228234daf5e807c8eb3e26cb97fd6c93d6cee2a5d7ab63c2c46e91c5b8be5044fe95d2a76e54ee5dc323412f92f7db6ceb03ee5", "3722eaa433830abdbcaa9177e373bab05fcb8fd82fc3afa581e34f08d3c07f5f58d0aeec9d7e71866c7a808ef15301251b470a9c455a612c16a586e8a5f1f3efe184a2e6313bd0a657d901319a9f44eb241db807a9474f3f49cbd2c8b8a225859ce5cd7b36e3af8545701a482780086a42f4a1ffa2b30144e3fd3b9052fc9e87", "9c22961d48d0651bd592fd369129e44822ee22d35c142dcb6b60a725bf177c85"}, + {176, 70, 32, "36bbb59925c6432139c7cd1bbc2b1b05c4010e09645f797e230131b2ad3468e7c9f2369b8b4f790dcb14dffcd6a941b262383341c80fd90d6d46fc8a81a25c47edba482c8658", "03074e714d5eefdf5b714381d80e694ef37c2647b374d8a38a6dac2a2e1d11dfa43c6de19d8b0e93061563fbdbb46c683cd86f58c284ed981399d4adb457f6731f21ba04168011db366bac3acfc66dc8f3281b7fcde159c5343cd9d98001cd719d3e9ea25e47e1ff13fc87055d4a53b741f592857c94067216dd23763a227e21", "a6109ba372c4564f4ed8c875619ff5bb64d503225197ee9259dd50264eb1f4ea"}, + {177, 70, 32, "ffa63ebba8239b6896bbec6af1c7b87b9c69257a0d146c0d5c4e8b8a99b43a18633f1f11b6c745ab05c5cbd8895dd96ad89cd87bb9fee30c373378ecf42274dcc02f3ef06ab9", "739f460034249e805aff665d6248a594250695835aa24cfa5d9c9b962f7d374abd0d163f65c51cdeb687f72b778d4854eba00389548a180fb6cd5390dd9580b6a1ecd4f8692d88b3eebbc77c42f2cab5105e425e252bf62e2fddade2c5424ed6a8a446d249422a268b029df9c96075de1baa19a8d56f2d8051357234ef6ae7d2", "c580c8e0f6a1f36403322f7b0ae3d06dd2dfd16ebc6dddd205704e97dc2998e2"}, + {178, 70, 32, "30be326c2ffff6d031affdab0a27d5a8cbfc4ba9dec626ad522615f77307e56d9e23f73e53c9f2c78cdeb5b84d2390727db5b3b4f4dae677d5fa7b161eec81b27d743bd56609", "082e7b4cde8914bf07c288441be643e408f6cb5ca932f67e9b975bd54ca706885468708009afaecd4d9ee846ab6c0d70a364c5a24131a766f558ad219e06e4f7e80c68e9d8289040a586662fca865ab459c037bf92465596b4281178133e7a806b214dcd747b24e0b681ea459fbd9276d31108fcc3f968d781106f20d3d62fed", "a51f5988a8f0f3992f549ea7f8c370a06d5ae8d65880067997536385d632b206"}, + {179, 70, 32, "19fb88775a517bfedeb2cde7c9455ca58d40d150b0a47ffbd0288e42e4725822c48d130eec98b13e7cbb044b846026f97f9f18531df9a9fe464a99c75bf9ff7ebf72e80796d6", "892525a0f02aae7f2264cb024632f11e8adbdbecb7d0c7080832e2373c94014cea02914c1542d1d000593fab43524fcd1f3a63670f6ff8509f1b1da881fb2abbde65ae27ea89a942bbf7fcb65b611d6e1ca20fb62b00929d68ae979e7595f6800d55637b98869f9cfc43eb6bb5e9c2ca281cc720340bfdb70bf5366340edce65", "974752b18d0dcbf29cc6104295e041259622cb7733cff63dbcf6808b15a5ad45"}, + {210, 74, 32, "81574323c973540719d192833ddb51f13a52dcbae294aebea51be5f6aa47f3571f5d97facdcf0c7befbe809f44bdc73963d8514e4fd559774bb96087ef8eda6e7c64275d6d96c42b4e4e", "b9e944e0b42d0ff454f7f8aa24f00e9ee039058ce4094111e39731b6dc3ade2a4acec4cf9c5be078e4f10a72d3d685c1e5e4d5abd92cd07b64dff87f266f0853ddf1cd61d9c637a9b07ab0be32ecac119faf827218b17ad4541a27519477f76ed918089f54b63d0e1e5a92982979ac187764b5e989e066a61b1065340e9cd203", "514bd18495f6de0e237054b8e3ba1a74c3fada4279ad6b8550f3a14712c528df"}, + {211, 74, 32, "44f71c2317cde52151c84260d1d3c04a28cc15ce5b3802b2e5357e2bfcaf10ab15d77dfaaad1a3883bada502939948234c559dcd95e7e158338fa12ac6fd21874ec2ffabed051416ef77", "2ac0bb0524c22b902de34ce64e6172d1b2074e159f517ab1abd152622cd10669f03aed8e2eb51c65bd0f38d084e288c532724e512fd558ddd257d2b1d41c5eb6040767803ddbb18b95a035c5d8492d4d35936b7b3630ee20f625b70f8e71d9dcd0efd0e3387d138c1f5eedce32dd88f223334b9a9eab65017f04aa8442179f62", "ca0053d51f6cf6f9998ff1e0db00b90e82c7b18cb5377acc8ebe9afe20da1c3d"}, + {212, 74, 32, "7edeeb6b63c3b9c836c4843ba46bfebd8ca9a6e205c7ed68a29f9710f50c65ac519ff17ad494d9b0a5041f587b5cd05e5f0de4e8b28566e5715fd5e9b8d6c9388580d921bf39bd8d775c", "f5aff283b3aaa4c71b13c590771d8bd3358d76988ecd1eae653c2f9d72c9b2dc9fc08e44b2e34ec52dbd245872332e342b5cf945e99344da0bca069ee221b2c913b7b9973cbf50fadad7758b6a962cc7ce640f78f38f0571b19b527ef2d9d09b173b7b64976633cde909be13a56d0df3e64ec019f2eaecdb1d571b27ea1994ba", "5131ce486de164491b4bbc84e7e461a874a2cfdd769355584a063e306960acac"}, + {213, 74, 32, "6e1b663e808a6986f29956b7b9708066696f9dfe0d7bcdb55696d8bef9b3b7c052c857884d2499fb86039d4eaf604079330ae3e818fa6f742ae49593560c5bcb545bd46d89b22e7f2b7e", "c0bb12a5da628363a71f1f5c9ce715ce8995e607148d772b669f6532242f9830a1931bd952bd2a44821a8def46b92504b4b0c5da50bc43bfc727cef5e0ef81faaf24390c0c92a4ed43a09be40d78b204bf680db0c288755f439eaa9d2b3efb5352361547ef2919e65479f142d86ae35714856692523b359442cba333ef662ec1", "665344e5618e0c1fb8758d049409a484fa69b89b009746067ea036bfa0ee8a37"}, + {214, 74, 32, "208f91ccc87965d365cc325d3262b64277f6112b0b9371a4174cee721c2eb32638735ff2a5f8abbc82f24c71d6dc1b9cd2b473375666dac0b789e490c0495569f6a4864e20da0a97071e", "854b32866273c6eb110e380b8f3bfd169cc87a6f6149c75e5667b305637b0895465c10c134745773c31ab3be071c8215fb9a33ba231b087870da199564619d03765965d6b8a1a9fbb79d0726a3d1c90cb0ae67d3bbab4cc63198dd4e2d2fb81de0ed39ad362043e9b6403d2aab825a6481ab1ea271221eaf614a0716050ee14d", "42680195f431e71b592899686af630e15996dc718cc29030163d677688a33021"}, + {215, 74, 32, "915794a6c6540f1ce9958c2784cefcc13772198cabd4fa17c88de45c281d648dcbd59a100cf4d8c8d3106c960db7b91f59578dd0045bae203897b61570e6210a2f11a5aff2f3c25163db", "99494422460ec858a24394f603b1d9b940a24ad9c6a3d1e9e88781fe77afcd139389f7acc057cbba3d328cbf914e2f32667fc7259afc412594645162d4feac10ce45780cf9a400c3237ead50077132e421dc066bc19e176c5f21bd312e98ec29f384af8a187dd13afc2fddf08ea34a971ac0eff36311bd86f1c8acb5ac03f627", "2ca1bb808448eb29085286594de21e254fb3416f9ab01e99ea33ca83c1d14dc3"}, + {216, 74, 32, "b1a95aa80bac5acb7a18332fc03067600610f376d99e77a272be96063ac5a0ca8d316e6cbe978e575cdca1b8b4a8008d9718a6fe5eb34af12aa0cbd97116d1ceb613b2e3975192b40d76", "d8efcb416f237c7e05bed9212c543011c39e6a5f25d7e2cba065788a29bce1464d8041676be9fb91216cc76d049806ad943e534a6fd45b10c41bee5d0b005626f3c0e73a9c50d7cb07fc502acb4ec4d2093181a8a1568581a6d793e5101b8613b1f9e6446b20b9349fb69bdfe83f11880ac11b00252508252fe18ea9a0d41a15", "988d4a6fa87f8138d754c5de9d176c45eaccf8eb8ca1799d87c8f04a966b6f4c"}, + {217, 74, 32, "9e4ba7d72b76edee6a6f290ed318bedb0ad88c8411f9c449bd4ffb3a661b7e41e32ee662b552ec4283e57ee6c7c712bec6773ae2c578789b7afa5425c1b6adb3901a4db42da6c0559e96", "1a0223261ab437a4ac1701b4780776c43f0f8949b3e7a1618c3b4ab6d8ae2aa6921f38a2772b28d415f32905251fd3bd1a235bacfac00a486dceedb8143acdf11b4b611f1229c346f89f21299920b56b1b08f7f4d32511965d7693f0eb326893dd0c096492b6f0427ea450e87d1203146748c3e9e51d9e9183baa42806a0e3d5", "ee6492a669e22bcf19bbdfc45495cd0efa9c2f2ef5d42831e3f13a545cbcd6a1"}, + {218, 74, 32, "8fa12bc017bfeb6c894020e420c5f76f9080e8733b998ef3a7d0b6563063b66afa3200a82a21f6ba56be003a3924dcbdac1f3610d29079c19213e4e14ae0e009c1ef919b5e60ab4a9819", "faa6ce40d931f3c0cb4538a82a22f0d4f3221f027b99d3d85dffb729b751e57496b4fcadae5c72404fac2c54949e4c4cde664b948052479abcf59e1aef84bb9f088030473e9505c603c350ad33bb06ed928c1196757ea3e5bf3ec97e0f3c43f638529394f2a65459cfd1cd3d7041c6bcf8db9a91c1e58ec24e2461dc81412580", "9611e838fb1d816a0ff9cd269217d93258c34df9e26b74476fe4da0f7dee2335"}, + {219, 74, 32, "c18bc28d496beedb25ca42d1b217bc81891d4c2bbb35380e5bb9bf7e3dbbfd37fef70ef14407763447d6c06e915766430277f124165061236b9fcf057d785199b4381e49a2bcf3ef85d0", "28b18b862ce9541ed6daf81199f9a331133b0ea3e48ff486c1acc6d5c40e9f8f063b7a15704ba3d3cea76b222511206d47e53c93a49edd8d639b7551b224c3f65aa802189648607e259ab1fa9ea665910435b7dc9a4c28aef8f32cf85f3a23e94a7e8a5945e9736702383261aac15ae571b4e8466da1bd31a83a5291745ba7af", "0bb4127d89d9073ea425c303adc3f9db39e40adac23ea61fba8b6e251d79390f"}, + {220, 74, 32, "dfd4faa6b9ebfff6eb33d4b536f3f18785fc33e82ddf3908735d0fd94f1f09666fa8f2667f876611a8d17d3256ceaa7e3ff3e224a11000a5cacb68e6de4dea84d53bea67c3e8be9a5cc9", "80f20152d12b0a5993a2b17d1f55cfc0c078961ed00cd1c21db36d7a92c339691399eafca830621fdef232b06acd5d33108a5fc8c35a6d5b0eb2ff1bb2598c2d91c094a1ca91e4a5268a16f8b38c57a2aeef6de3a619f869df4ff7c5f5ca8f20c10e082a807719543215653f41ba45746350c855c170f85459315f62a13ecaaa", "109ebb4cb2ad746762b6652fc63b99019857ae89acfe9807648c3cfa151fed42"}, + {221, 74, 32, "c96c04a3bb0816fc47e05913a715fbac9a3ad09db75b48e8013d9f27bbe8532d7e63dbea88bf968f575602f377552e35987872a4e3155ddb8e5cef30aedd08504d4b2123bd7f3af62bbf", "b11389c7dc20ffd0c4a5f887f2576bdc302c7d2af7089a012799c528fa7f2ce23bb10071b31c83d9e58d63e6fbd04670ff1aa6de4ea4dfe94a9986a35032fdb7ea1f44f2452a1202e517257e97ced627a7bcf06e5476c236819f73daad0d96722527fe527891d4d42c0ce658af97428890da04e1efc56c6f337534d7fb57209b", "b53db6bf0c8317586ae6c1a1e2857f241bf55dddd1b423578c6949d4bf014611"}, + {222, 74, 32, "9319838432ca096960e2196a06398134ea06e4e8799ba470c54f0512cabb9045f529b6c4e749b6e27626c11df4595bf5b47c04ffcbe218351485f49077405ad96a3f17bcb7b3e21e80ca", "57e1d3ff5fc4785f9370df2e5abf454579752ea934d2a9bab568d5aeb22ba43e4bc7df9f31366bb40d91ca822026e4e426cc088081732ef993ff7f676c571704a5b809278b50a3778108f4589fa18caa9f0283b3fad0bd594e406b950329d5242e5e5880b53aaa0eb57c66992055c4ffabc0a72ae712de42add2a321c0ca6808", "4a34bd4dfeef7fa1dc739280f16a3fe1281a51311c10a920ab43d406d4ae3370"}, + {223, 74, 32, "2914da23e86a603cda1eede153be2431c2947cdaeed6a1ea801d18e2c218220ca682e40f0a51c4c13a31163cb730f83437bb7a88ecc903160956f0d483137d1d145ce948866ad57f2eca", "6b8db9acdfd24150808a92368596557181d445e5a04e91112db2812b58035d72378d8bc00a1ef75ec373b81dc6f1f0a2ed96f302cf2eac8f42ca3df11e6ee678440a28b0dfab2a36eaf35bcbf3c759a71e47120f6c03292a3d6b9b111488a2259bead9a5e7e2a180fcf1c467947f59271cd0e8360035ce8b287fe2b3c3b95822", "4de7bab7fe9a0a9bf7b51a7cdf7d929f2b1c6ff4575fd527baba1efdf4254890"}, + {224, 74, 32, "4b7ab133efe99e02fc89a28409ee187d579e774f4cba6fc223e13504e3511bef8d4f638b9aca55d4a43b8fbd64cf9d74dcc8c9e8d52034898c70264ea911a3fd70813fa73b083371289b", "138efc832c64513d11b9873c6fd4d8a65dbf367092a826ddd587d141b401580b798c69025ad510cff05fcfbceb6cf0bb03201aaa32e423d5200925bddfadd418d8e30e18050eb4f0618eb9959d9f78c1157d4b3e02cd5961f138afd57459939917d9144c95d8e6a94c8f6d4eef3418c17b1ef0b46c2a7188305d9811dccb3d99", "4f1ee7cb36c58803a8721d4ac8c4cf8cae5d8832392eed2a96dc59694252801b"}, + {60, 100, 64, "57c2eb677b5093b9e829ea4babb50bde55d0ad59fec34a618973802b2ad9b78e26b2045dda784df3ff90ae0f2cc51ce39cf54867320ac6f3ba2c6f0d72360480c96614ae66581f266c35fb79fd28774afd113fa5187eff9206d7cbe90dd8bf67c844e202", "2423dff48b312be864cb3490641f793d2b9fb68a7763b8e298c86f42245e4540eb01ae4d2d4500370b1886f23ca2cf9701704cad5bd21ba87b811daf7a854ea24a56565ced425b35e40e1acbebe03603e35dcf4a100e57218408a1d8dbcc3b99296cfea931efe3ebd8f719a6d9a15487b9ad67eafedf15559ca42445b0f9b42e", "33c511e9bc2307c62758df61125a980ee64cefebd90931cb91c13742d4714c06de4003faf3c41c06aefc638ad47b21906e6b104816b72de6269e045a1f4429d4"}, + {61, 100, 64, "7c98912c74421362e112a2f98fed9babe0057fc778b4453239aaf5ac724b725553539770a5bc8666b8e13d0e9ce36b2b934c8137c7f20b5f391f41cefaeed92e9df8206cec3049bcda0c05deb9e6549fada19aa2618ff560f892ce6e4782aeff41cf53a9", "74e8936d83bf3f16b8d03fb73384ed8f46bd32343f5df8358107e2fdda293afa103a2bffbd4030e75d96cc7ca6ec7c97188fea88d4eb63b7b14e8b8c8dee4f8de12e1cc6981d4e6e223fecc7c491924632c7aef45fd8ef1494bcfb06c074616b0f4cce8abd5d83f32d550661357b18e5bcede841882c869251db9a331ac456dd", "4cc28818486bb9b1b52e333dde71f73acc227488453fd907c6b51d349d67af1df29a9f225532ce04f50395fed565e98d78978626df93462d3f012f7373347298"}, + {62, 100, 64, "662ca8f53b97edd9bbd43b1f9e4ea49f2ac14417faee257aff93608bc49a85abf6913def235a2e76c2241ffa749a5da489595d25c6a8a2026563e12f5e3964e0e518ac9c34e45a938a6f503174a613f34b08737afe5d6fde11a45344e64d23b33ca83c23", "0c057a2b56cb7e651c6339e4c91a1a72d51af2a646de9dfd77e9e42c18b8a2b576f526b9fcedd90dfa442090a6e784bb614311793bb5fb39b8418842d586294746f1ea3c02320d6801ecf2ba44b13b60172d2d9693a158bc66947aacd7c5a14a0463905d6e80649db8c4770cac5e858a7f400da4568cfaae08498311265b50e5", "c0d6e13c5746369d49bef107cfc9a465627691320b8203233359e6a49659025ac96a6db6c4d460224f6aa1cb7a6b8df311e066f6109bd466cd9aee3058dbc5f0"}, + {63, 100, 64, "0cc5bca2025bd6030fe0818e0a61ecc730b2e5526da942c0d7897fa97bc1a8fb5dd77991ba9fc50890b014ce6118907b334f2265db6ad86e7b918a214ab3bdfe9378c711017834ca19aa6908081f87779ff0921c9c75d32e2bb77a28ac28881cb792ec4a", "c532714f570982993d4b22c7d07a1e79ff5a75c94eee75dc1fa222b630cad753664b30f3c99826b5cfe17c67dd875b9d0bd2390028e6ffe9fef36a2fd6adb13d3ffc69670cf4a67e9c0764a15e7925579315dbdb561f07b7da892394f4693e51d9abe65228034a1b2b26a01d5a3ac5cf208b2301e27fd86e3ecc159090e8c3b8", "c34bf0931b2dd2e41956dc86996e1427379d0c89739b1c33fa3be5b0770673a20c5335c6d22c766826009938fe1f4d478b882b59a3b19fdf25bf18f043fbb3f7"}, + {64, 100, 64, "7d407fda74d3a127b2ed14c727d0e81a04f6789d20eeef629b670abdc18b1f41318e5eea3e86579c957dbccc20c4687d2b8ba16fc6af9a936ad33cc1dfb226ad5cb3f318f1bfbb43224fdca9d5c9faed6e0c44123849f9ea07162bd11bbdc49b48dac6ca", "eabd8db90e6d67a41f096e4369f77cd6ba23da4fcfa459120d9c9ef9725fbe9bcad80bce26292d6a8a927450e6946cab4756b2764f47073fe305a32a237ecb389f55a6c9c7874d60a44e21a7c64561b37ecdfc884db0a3e09b052328ac54f2ccd1fa07b4dbceef0fd5041e4ff3528374c5525f8eb028567d9f64c7fcf62a59de", "771bf59b658cb17576761d078cf6b1474db746a2201d30ddf289fa708366a27d6a53959bb7eb2b963622b326edaae3dce086dc364c93c874e50089b69c5cf52d"}, + {65, 100, 64, "c367aeb5c02b727883ffe2a4ceebf911b01454beb328fb5d57fc7f11bf744576aba421e2a63426ea8109bd28ff21f53cd2bf1a11c6c989623d6ec27cdb0bbf458250857d819ff84408b4f3dce08b98b1587ee59683af8852a0a5f55bda3ab5e132b4010e", "1a7331c8ff1b748e3cee96952190fdbbe4ee2f79e5753bbb368255ee5b19c05a4ed9f1b2c72ff1e9b9cb0348205087befa501e7793770faf0606e9c901836a9bc8afa00d7db94ee29eb191d5cf3fc3e8da95a0f9f4a2a7964289c3129b512bd890de8700a9205420f28a8965b6c67be28ba7fe278e5fcd16f0f22cf2b2eacbb9", "4459066109cb11e6870fa9c6bfd251adfa304c0a2928ca915049704972edc560cc7c0bc38249e9101aae2f7d4da62eaff83fb07134efc277de72b9e4ab360425"}, + {66, 100, 64, "52d3e26c59df9bf3f5c01e311fd6611b895dbf6e8e918ff16916fbfaa6981033d7af119e880511d775bac09afa078684ca22ce1ee462a517c3a483d1d5ed68202f512b4e7f130f62420d98a137529d5613139dcf76bf57a81e6e944c5b8048b8c281d982", "2485736977ef55a55abeba3b8e857ee2fa5beb144324e46f9e12625be26b25ede28ca30bf92e45d1e6e8d234daf52be5d0383a781d7d25c64802c7901b366065fac08bc574c3718618603d778a7dd044d6c5b59903f0578aec4571334b5dc79b172914df1037438c9830e14cc4a6d3c5b30c44be1e06e28331e44a8b9968c059", "b1c34ea9d837b4e0b0771792384fb5f5b9bb5af7226d461b5ca81ce8079c6472c5c44624a640f01960c8a94f6aaca5324c0da2cbfdbcb077cbdca7f6c6a38e75"}, + {67, 100, 64, "ce1e3b693ce203166bf045472fdd1457c8f6591a0ad41912bb30f6e63df8f90f6ca18ed5cac0d07adad407b5c9666f6253553c77e56bda3aff3379b1dd0fc95a5685021d04da287fa5e28d18c11697478ee7c3241052eab684b5c467ffe1aab45370a029", "e2542c06864dd3a0499493e144a97fe04006b68c83a5dd4ceac3cde238e48895ae17728fdc7bbe84b6022694ea75df7371b8ccc76450f2d112222c504f7d1fa20f5b712d33e436fda234abae9c5e278d4bb14efa9b3a88114c89b28946b813db2caa91a73391245435b38cf8016d3f77f678a6eed06b8852c181c754c49d4a88", "d5e6ef77772459874a73fc4f7665cd3ade20468bea1ecdac41142ff32350b8cb15828612050046299f08ccc486acef0d0c04e0f8feb29045ef7e3a3db093d512"}, + {68, 100, 64, "3699d9cd078a20ec0c96eb01aa60df6cd5dcb554260eea8e2e15b7c00b6943c638611854aaf8d3dd18d020b49a77e67275eabf973557ab74fd2705481c3cb6a9e077a825af7e7e2a53bc822396a9dee40f4b10483bfd9818d06ff32f4deecddcd6e57388", "9186eaa3b8e785dd2a747297bdbdd4f5532a47b7008c21686ff7f8d881d464cd383205f6d45dc8203bb267ac9eb12f415a5406be1c9fac73497941909dba08dd12856aac03d83e0d916147404694fe70f8fa929ef0cc2edb4cc07abaa2236405e62820af8e806d0af32a1b3afb8dcaeaf5c4f43dc4392e074075aa3ed93601ab", "d8bf5ff4392938534a7962c64985f163ce7c95e6c05f93cf704106f9bda7c9ae963f5ea87f73626f67ed3146e8611ca62ef2eeb4f9a13847dc6e7ffbe3d851a4"}, + {69, 100, 64, "b0c0a896096bc42bd0c5ea646779a4f1ce541f9cbc04df29ef20b180c069e10efa50ae68ecb8fb31bdfc473f0034dff988b452037ed6261eb0fac9492ccaca2c0ec349b796f1ad077ef995898a5d106160fc100d9ad81c451a1c46269d5e5d90932163cd", "debcf190ea6ab2358636af5cfe4b3a9bdc1bce160bf350aa3cd3956b897e255158cd3e2e83481ce3b6f778d418764f992d48e4f7fb6d080e6b3799d3f35949c17241a0cc5ba84597166779e6a38ce45681ad944cce7c432baf9cd8caf2b33125f2c12052bbb0b3b76f2cb97be9b4813a9ff1e5fdcd478769d0ab5b36cfb466e3", "2180018c7e9c3287c3d2928fdf36dda80be4fa21d3a879c0f617eb0e43c58836b0cd714a8081652f8dca9a01925a4f3ec5dbe07b5160be7b1ac58ea623952293"}, + {70, 100, 64, "1ce7e20abbdcd1154d4b536714ff534a01b8e88c78da34d653638c39291fd80ad01f3df02067fa3bfae7907789ad2641c8582b5a45d03dfa24344a676614f5c56ce13b30b6a15608f1e7e18c31033eab7b76351686a9dd9ac2dec0ad9a663a47f61422f3", "46ae8403ebb4c8723652b9848fdaaa537a50e3191bd94442f9702bc602db98b5cfdd8f142aaebee7cda8608f6d436156f743c3491a30404605073155722fae3be3aef74d2b9d128331d9b6cdf1fc68aac38ce4f6e072be0322ad49ec0b47b82609888358f86b0d6de94e83e722ed077666910ec9768506a4d7ca3d33d60bfe9e", "d032bfb5a538197385eb70673cf8f93e31fdf9c22c0e90008a454ba4d69bdc2232475a41723c8a5e3b29c6de929a7a1e87b64beecda29683d0d925f00ce23b35"}, + {71, 100, 64, "d7148e81b94a9a902b5980e751a5a59ef4a2397ad4df251240443e30e598bf7ae445f65227603dfaf4e42cfcc23e0dc94c0f90a0e52dc1b10beb36833e9a8d93134f163e84e7cce08a498a3eeeeb7b215b98d344b970bc70b63093e6a5b355fd8cb9540c", "251cff72773e93021e816407edbdf5c1b0dd9a0d633f41e7a25e932d61ae3ca5ddc78642d2c62da3eff06fdd8799627a89458ac2b20cab390143dc686c58dde0d1feaa7d2f8a50e8169d005f5c0462b912dc2ba4b6faf232aa8a4094e5f5e625e90993aaf554a5d77bd04016d4c69d8533eca53dd8d0bfda867ae638364dfe7a", "9f783389d7905291a0446004816233918acfbbc1d4443f4dfdff55f3c151a7a1ad20d0a18d0aafc4bde38e3bbd9c7f672f8b1d14649e8f41c47a0fe1ca051d8e"}, + {72, 100, 64, "c821be1cce09579ea899899d24f8329994c2c839cf0084e27857c688837fb5c4f4f72527eaf7bfcfdda75b37248eb153ba4d31dd418d2fea473643c0c9e1f0ebf591838e349d3ef868f1b67772777a71f8cff5b0654696fe31062ef2628a99095355a0f8", "98b0c5e030490c0de1cb08d49ab64560693160acedab1a450ec2ab52eb6459d114344823fa2f94cba48f9d73a3efa22f47b19206139d1eaf6fca13989dc2e72deee1915636fe9e417d4e8263f7842cb9373ddd549f9c39141b319fb40f20b6068d7f4880ccff54f8d5cf5eac80bd0a859f9fe99d79f193fe7abff6ad28c6ede7", "8af5f3e56ba1a151975f4fc6a784aa050572f7b163a93f24f016395ab4688f39172bf20f1bc246d73b971d022b3d49d1b31f40b0a121b9c3a66e09096d4815f4"}, + {73, 100, 64, "8ad2ff9cc9e5979ab79e2122f2b6c0d75f0f19da6bedb79a9762aeee330a7f6169f93ccc7ef2ed2b55d931a9356b29fdcb2d91f973a23060b3c173f908a655e1e6888125faebbb90b2177cc2ffc8dc825a27b55605f906509317952aaa1ed996086716cf", "18aa61677eb2e25b7f5738c929c4f4ccb69749a1038b1a6644545722f7cb8a06164badf3915b3f3cfb8d97ac83a677cb27fee45d242a352cb1d96b07ecfcc00b152a8321fa4222c8b25289158eb7aaf74d865dc08f2b6be18d50e5f50601bb027d0d89fba1afb4890d6db60a3141b6db90f75cd22dd6e30f3f8270f52c21a273", "3aed2fb463393706efbbb98fd426075af837a8eab622b95da9aeb0393188665336f0d46bd20773fbea36aa289bd702d6ed4d6080449b680c92b0355fcbf13ead"}, + {74, 100, 64, "bceaf34d50c1f202539233630b16dd048ea23f093c9f713b8d3a385b0d5c2bb6a4dd14f91bf59947dcf31c89f931df0570476c33ae7f34cb51897623327062b8a3cd7f0af53b4aae3e0a209e58385dd32d9cc6163265241332c332af4de4b99b4022fa29", "f3bfa5c1f1055281a35b48f86fa3ae454c03eac56ff064cf268b8da20431219b3e4da9ac55714309f5a6a5241e0060dc817562f12deebfbc6a9fb11de594ddb40e8dd754bf0ce9b41eac1068c4b448101fec09d014b01200e94265246365931e2b2739a276fecbebe51690acaaeaee4aed12e8486e5be5036b1db39fc4c9cb41", "bb714844b6be93ccec0acb8780996b2a4778c42a8a76a49eff87ced3a258815d76685dce4c8ae37c244229f17e0503de089a043368cd300d13f842f28c111fbb"}, + {135, 125, 64, "13fb1ed6389f32d1de3139cb04bcdd53525c9889b85379d3535a25d290351c95938a3d0cdaf38dbf1d5234bf7965c8ddce9ace1b66247e60d74ec7702a0f931a3cdf4cb465ca9fc458c380004a3a6e7957f1f813210b8038ba663fcdc42a8965d6a252b5224bf249552b2575bf64568db4091d58323006c3c34994d3a5", "88ad812fd34e55c809e817199604b4a7f7feae42cdc4c9e930db08e845a3d74313db8a57926706bf0551be758a0fe239f004d237c849d9e4bfac18292bf9c0c3e37985ea54b94f30d18c32ad2b53a059827cddb95a49b4bef1d369ead14eeeb4a18e592e40ca96e515a15908a05a57cd5570b611ab4ec23f7057e1725f29c9de", "a481e713cdc81ca5afa0efcb16e35cd20d01aa449958fd2eaede2e25a5ba540beafba2fab4adfef2e146b4c1b2a1832e93dd373d63fa90bb61490f6568191f65"}, + {136, 125, 64, "fd5070362296c40d65b105d5ab4653fe34e0200516933f3eeae03ed0c5d9f6016a8560b4bd86ab2f7bf98b22299ed3e54a394602d538aaf3e6951f2db4feaf5dc33426f15bb124da388d709083a28f5701ef96c28b3a3c75bef9332ef373b90771236af5e25d589504345d28a19ab0dbc1c9b74d1ee21c4bd8d423de6a", "8d2e68d7e9846cfa30d931a38efb59bcced53a14164b3163d2653888eeb0bb1448e1a80c65bcc6eb633447e72ed4a075f75d980fe2b19f35ffef62b27ce09c2019922faedb427321057fce19448d85962a08d1baddc936d1110e108e33d46f97e7882445b5df1ca4ff03edc237efaf264f1c0d9e705d9b3eee076ba57c56db82", "b6cad1ca5ba505498a8f66a9422bf539426a8a55334fab9c6b9e08e3a5179d157d1efa0f91d5c5e26ffa43f5c1cb7ca5f906ce4f0efcf4e871820b8353e890e4"}, + {137, 125, 64, "0f67caceedf8cce39a7223d32ae1b6badae2c2ab01bf75f543dbb8a408514c4b2cd81801f9eac1aa52257c7830f120b1536380b23161f734330744ce204a98bbd9dbeede484e9b03937c26689526597c8edb98e6191b72c95fbc76468b8d48437e3af46bc36f8176c540caab3fc989a3f511b54fa2350e3d31c2f6162f", "3173a712ed715b321a849279be6ba237fc90dec0e48b0e1290e81cb86c2a10eed50f3e05e616be098e3f1da2e6125238c2e2f45a8753aa613c1ae250e304c6ff093a6b799cc34ca2fd4af81d5622076c2e8752593a27649576e12ba075ccf3e8f57b9635b77fec448e2e89b2b5a3a81d65066285a70e24f868c35f6ecb8981f2", "e913fccc25f84a1390ef0b0f86050fe9e61146c1b4ef0b4b60d187baa36b61458bbda925b96e99cf8a4330291690417fe194cb9bc2b6232d43e046d13f038ed3"}, + {138, 125, 64, "5c8589b3845970145e12b34713455eb6b5ceb132242024e42fd9a886fc9a30d3aa15703b3467e4dc99a915ae3ac118fd837e571dcde5945983c52a2c849296b4c96f3763488d52f818b459add51f6db2468d21db3d958196bf3a531f65bf9cf702bd66928672c14f235c08aeae0665be472397d43cd9f3822b5fa9c767", "7f2544a478961dd012ac705e12e74587e2df6b2ee1406a0bfe13b908853f31eb384fc236a275654ba8cf51d461ea726228851754ef97ebfbd69326fcfcea04f594d177633c4618c38b4d64f7e98025eca4c62e7a40634b8b0e317880002c51d0bb34caf2ee0f207ee2ae108f53b1466b7f2d18667cac7403ce75175d390e00c5", "be73d57ab3a7c5bb305451922fa9b11d0ae938bec886fac5645a8b72de93770d96465291da2bdd5d11692f2cbfae69adb36ae714f1e5cf43b9d2841ddeba4ca6"}, + {139, 125, 64, "7198b12a22014154578f5236b5a0d4cbe29aab3bf289bea2220a4a13c9677ddd8b03400cd0f954337400a069c192c9929a4d04e0f89928999b8b081af909ff1c7b2fcc36e8f2a0a32103764610f6a3ebdba4aed05dce6164d603204ee1c37ab1a7e4feae5335502bc6627cd38b17895e0d6852130771918b3d393db76a", "9b2e0306e73662c94377e5a99fa9b63f034ba91c8b95645eb0afc381c8207b77d089fdfa6a939d212226f331f5dc81b614b597d3e50c74d74bc9ae1027d9d4e41fdb511d9e1c93851bc66db39f54ba248149448e7422e470c589eaeeddcbbedc0d8cc8198bba8e1eb7bf1cd6a3fba9b1d37177f441c0fb53a4563ec1f2e08387", "165e1cc47a7433270f1673e1cee581001708195a3471c9ec71333ce87299e72abc5dd490d43676d10c1375125d4e7fc673adb15342ddb7e72eb24ff36f54f82c"}, + {140, 125, 64, "b5ffe36117589646ac097327e4147dc9fb13f7346fd97a6fb756448b32bbd3e25edfb3a14ae194844e109fe1f9070ae84b1cea2924fc4957fd8f794bd622a74b6fc4b38dbbf040f7926d0729a67370bdb80f63cd0cc85bb61a83bd1c86a4692f52768e2c53cdc226e1ea5206d39ed6d1abb309290d87d81776fab9072a", "1e6b0799e857a1efb3cb0aaadf74c78c31d5e1c72547dd1d863eed463bcf6892646f78cfa6fe136dc2042ce06d3a2a465c4c994a9edd1f482ecbb2b2c9b509b2fdbb501083852057ce87ae33e483431e6d4fec3b09d87282e7678c1e9423541310d8f82427f6b2f4feddfa6bed57fa5b8c6642641141bd15d999e353442031ff", "5702e9898e96cf220c6778cc1d07469f13ef0c2ec0e335ddd1791ff265ce865d200e4e6238b52eaa9be880adfc9076202625bf83bc07d861401a17d4a51d84a8"}, + {141, 125, 64, "b8100034c20a0b6e423c9f6c541fe9fca08fde8ce7177191db6f0929344332fe0036926e3a2720ea9fb3909cbdfb114d4da73b85c22b43f42248721015d6d5003cc235b9c35349673ab12b0ea0a70971c1a81d33c310df3cfbad795e057e7b3813bad05b8514f1acba3e580a26ac3830a59a6bdc0f50ab310da506592b", "29aaac0418f6bb3890902888219720b59878f226d06c7e8bcb42e9c0015e96f4f802520a15cccf3fb280540e7108b251cfb97aa8fcd86d1eea5d340aa3f65234e14f5639d89155315729978e0fca914732b513374138c3c01f74cab36964cd740a1b1f59094d3554a6115ad2a6e5a3e2ebf3269a479367b692101383faaff1fc", "9c87ca3b8ee3849224833b477333d4fb1bea3d8167fda445dc677d0d70b9ba85d0c4fd79909703481fbfe99caba7299da8c514a7a0799d59ab6f9e3f1f63a372"}, + {142, 125, 64, "d62dd5837abfe25749b0371803cc47ff4b386e840b4c7ad115a06a76066a765e70074f0238d7a7dc3c4ef41f394871a5ed9d662978f6aab608df665fb51d1b31aa41e766867d04db02b791c5d3dc959fd27741675a827509f17b861c2bbb3fcccc0425172d59ff3de1129671972fbad542ed85a57897e4b2189f521330", "ed3dc5fa63bedb28c12a423320ca6dce3afe8f72712ebbf61304495fdcd87bf9bc6c61a7dbdaf977dbca9b795de894d2c696120c43dd40b00aaab117e337027de7c7bb57889677e6d210450df1414d60f28db77dcea1c89fa4a94e7046c33f1ff7b49db373db9c9f30630796e4bce0a0474b476e1a609cea6869e8130c667908", "1e5b3b965cf268d5f9529d0a256e6512b41bf2726d762e9447e40af239cf3673fd91257edc6739cfcf9e6893bd9955e4166e4fe2eff2265c1534abaf5b11544d"}, + {143, 125, 64, "ad9e1d5774ee7e882b2dd772c7867eaadc56299b7583f67b430fae7efbed4a49f913b6a929d0d6852760c711a5be67450eb9178e684abfc37f25135a408e15dc636edb964da6939234a3c4c58432d78a8196d54f2ed9728e6e5f4b006ac16c0d32d81586a717be96981e58f62b8dd6617f16ec488fd716c65ae6ddd641", "e76411d3a1a72ffae3f9363389548084510d61fae1c251400c8e4d70517e7a29a4490ce2723b667edf738220524e94403323eafff33117b74dd550d7cc0116ee8ee9160547ff4d3288226f6a42128a978628e6ea8e4431730106d8ef7341b8e12bacf6e42adb2b3f696ec5ba6189aab0d0841e66bbe3e69baf88ad604d27a82a", "313a41518da2a8194451b01a4365b1d99d9c46498c24160b51a4b494f669dd2d0bf0922dbfecc703255f7ab74fff2d7bee9ff2a4823d26874f7532594b96847d"}, + {144, 125, 64, "054221b2a3507d491e5f0da4292931f63d105152316217100adbdb72146b5f88323abd5072ea9d22e41cab4bad3549f9576280576bd93df84262ba7918163a626267f94e6161634cf8308484bbe1c01e486dc45fdaf3bc151b45c6363aa6a7c43ed2bef39a3f368e01a37f977bb6fe2eb93903b3a537fc2f3e8be9f0a3", "56958d7871c6b901f42910b8d7a17c3172fd25454b77e5b52d81fd0f7ac206d6c15b2add936e93f493e124c6cd5f670249a0c7b9dfeb00084cd9d3f6865bfe9f4dfe6b93036ea879bd3997f89ad667d754e6c26214b948108b143d643e327e112108ba6168ceded79abad114e70f62f7bb567f0893eba71710bca120494e6f72", "6d3c6a9a076d3a3506d7beed3845521f50b2df2c5f3bce0707d66e20bcf09445ff13e0e445190e7f2c43fc73ae2bf68858a721a67feb8083dfaf498c8b86e192"}, + {145, 125, 64, "42d6852473735ecc21b107e3e0a5d3c5ad2cbccf7e2d9dc31d1ea26e35cafc88ad51d9db367093a82002274672c7ea0c3965777120acec72411e56343baf69eb85c975fa0293955cd5732a4276d287fd051fee1fdf16bcdd7042e0b848c0915d704741c9fe65ccb0e70bf620154c1462b9620921e3f274cd5091284282", "2679ac7911bf024295d61b25aaa0ddba9328bbfe6ee3e5b10a36bbfcf8398857e5bb6daa27869bb295e3c5a79c61d61c8fd3df263f9853c0cc1f766ebaa9132147516d5bfc4a799383694adbb8e3cdc00257b672e40fba25cf83ffb63b1ed192f64596d4bb9604ad066d910927ad2b6f95bd2a2986d083a6bc6a3e1ca2202a71", "cbc45d2f971d684010caef1c2d6124f56be8dfdcea7050c417b0a26f6058f6401542f8cd4cc9f81a28f4a4eecdb8376d8fd5cb15ca6b2bcafe79e1e209f55c16"}, + {146, 125, 64, "0748bc683d617a4e668f36907eee655e454d6c19e43f6309d3701952fa36582417686a335f73db6768aa81d446debaecf52ff5f3f72174b43df350734b2cbd2298768fd833affd7eac3ea5cc32a3d174f952f99cdfc289924ec1e3bb640aa8cd5119343e013e67fdfcf1ab5f8a65325c1a6080fbe4492a0bce83dd148c", "2b0b018d11c1ebeecc2a1b5bd17e3be5b87f577987ac3eb733b82b00643aa4d179a6a350cc7cf42537bfde8bd7a905a70f9d8f18d05d86cf187d7d21b918771a5cc10415c5bcad89596f9226dd13522180af2bcc1c476369b950e640536830efdd446d0285eadfc33a2081536b24eafa129d73bcf2d29c2d1c1aac86b89398f7", "ee313f4f6c8ad4764f81873d4baa3e9f9b7f6481904a01fb1c827eff0314c1305cdfb0595a4cb8a6f979d9b7ab337e38eabe823742b89c2a1ce88c5260896ac7"}, + {147, 125, 64, "ad8db0f165d0ed6e9495e6e53ea1e0dee4437cc156db2e83c999f084298738b8b1ca2706b82503edcebee76d0725b92597925db99f6e2876471598390ddb428c5d4d0b1361b99b271af00fc0b04aee9806eb5f8d924599476cde9a1ca4531c30d99ec5e107949e62a1b1c6a5e018687f5ad6ea07d667673f5f7b60f697", "b6d8212d828dfaf27a03b79f0cc73ecd76ebeeb521058c4f317a80bb5afd41dff5520e525358df7851469bef2c358b2a97df0f5c0ba68f985fd8b5369831d97802a1bd6e80507b1620e0bbc8f2f229d11beb275f25f8be9d994fdb1ed0b8b87f064c9848b07db7140f5781f20606020a29979e84160302a508695a3ba99bc43c", "9210b074bb645c3a36ce46f9921de1d6cd8c9f37829c251d1d999c193dc30467d44c830084914cf19f4ba761a0e774c103f092b51ea25beb1b8277e99fde26a3"}, + {148, 125, 64, "484babc2861503d442448c3c43d7569a380eadd9eed2eeb4c651997867e9a80bb0471f2df0d0e5fe5a3fd2c0b39009df4e1e882e3a08fd74bad8db27f567ae77effbac8fb8b38c17e4259bfd3a450c75b1898f3e984a2627146e34d3cf44d7b9efaf786e4587a127c73c0e7a41bc06644797ec906e6111d6bc59cc035c", "b04bb381f91b8b64478391d6ab6ae306e796020418bf917899e85a9423ef924739625eb4c39496e2f9f0c8b5828e801ddd04c68d017fe9af40127b56714d9db44e127dcd1ba41c2b890155d3d9721b79446002f09b6900e42bb375cbe3806a19b90316b34973a7a7bf5d3f1af83e3c82e451bc152fa66080207451ddc1b081df", "0d73f53c10c029069a2d1d5733bc6be8a1e94de821573daa290fbee3f897f44297cfbd515cc5ddb0df7bf44ef58c446ec085c32c8d6ef779a5518e63328de957"}, + {149, 125, 64, "c4e631adcca6a4735c905c369c7cd44d132200b362f29a0a3240b7e06ba49d32a6a1d82ee6848b3d828f05416657941b7c6b9e716436edae6b274b4abb0f4f4bcfca760c2a21753d49efce2bd683a2411e46c6cfc59d190bb811145664aea2c026a832cd02450b7a97f6e07b52c7a5c7e3faa156edefc3290248398cce", "e8ab6a06dbcd52a245152d3851ceac0551d5c3780da0a44f5a7fedfeef222050755c5550dd262b6af6e704ce3ff37215fa51ec2781c1c65cddfd60e195409d5ec40596d56e1190ce14b32cb1864bde73f909a07459f7e8a8e13ad7f6e895b3ddfe2e975d37956915c7020da9cfded866778548293d4bf27c8dbdbb0391294b17", "8d9725605aea94c3ef125b307f7acd5a906d10b4908fcd21f678937cc4605b0800af50480ef6ff1439cca60cd1986f04a1ddea0abed6c8dcb9b485a923288c03"}, + {210, 128, 64, "e9e4480d1c4a621e0c4e1505992556347a7ab34fd2b289910474766cc969116f8040d96dc5f66cdc4454fa7bcfb9f838af19195038467ab8a16e1cbc12e598e6fd250e21b2145f1e2e859cf73400be12a0c69749f7100847429875351d5a76970b9ccf700c2ca3ad72e9e4c0f0840e8cf488158136989b0891f867211350134a", "b82eefb2081bd14dab0e9e345248a34ade73f3291886b91ea3e8cc742fd884f6ee0ccdaf4c9879f4db12dba58cf491af2541a1d5ef6cc8b1af750ef5d8559ef7ff9cd56d8f599974be3aecd8c0f4c08f3ae50d86f9f822a1e4ca39fd2f0b4d78d22630733a24d8d63ecdf9555411daf205a761c39ef46ff6292e74129bc13a7f", "90093bdcc45da7338bd2efe92e30933b14f75582739c747f7572b3270b104f33af0c939e3c8ae53b2066fc8c97ccf38785cd2ec3d79e6946499d36121e44a3e7"}, + {211, 128, 64, "d3fbd6fe4e356ac1c8c120d432d7204d9d579b2a5a5d0c8b6016bd1eefd38dda735cf2f0ab873afe0a0916865e8b58a0af01fceb6a3765c9bfaceacc47a4916bea791afa003240d9b6563bebb3038949fc3aee38157dba596a9c4a20edccd187fff95904945d04b8925298e97b643ab24cab7af9a55890a2298de5022872d697", "b967c7d9c0a941f02e87723cf282eada4347b28193d3e0bfbeda6985886a37e646cc7b1cdbab45cce677528b3a0c24a08f8f580b779935c79398814d067298592a6bbff08248b5a2f0b48b0d28e4b6a2657763ac5ba00a8d6c86464b1eebe44ccd0c395e9dc9b9fbb306c6caa551c6682ec57869272e889ab26e6189b91f4248", "bc9a83d782e50ba5a801146f8da39095d92387d759eb4ad52bbd9e99d9f68f4a0f6f6470c653c45979c2e19543804ced592ee9c53eb68a5b1b7746ed403ebe67"}, + {212, 128, 64, "19d4cb1d72c73e2577a23006f31466ff777b9582fdfb25e8cbcd34649adade35f889bc20ebd5aa1ed7a2ce52a151d63d1592803585796013b3d5de2df2bd7e84876b643e554e1756ba5a8592b4a347b5482a27f624f6dfb28367245e51c8e3bf8f23cb5dfa590b35e7715dae723143ced7eb90ae209a2b2b012e10df00239750", "fd13a5e109ee583bda183ab64e4d27855bfaec17449f14991378febc435c33b8bde5f79106d11e98b6a821362c9f71e580bd0b7fb93c4dbb403208f49571d62d41abae530cdab5c16fde570a4c6897f2dd18a3bdebe2acad40b6f4c65e6029d471adf1af83cfc6beef0204ba187040b45a52dc5a4159d876f94cebb706f2d3b4", "b201720661830a671c94421958f73c8b666fd8a323629548a29afa163cee2ec24a01201d901ccf5b0adb1d20fcf0c5ea1c7483fa95ffa0a9590b970385d5779e"}, + {213, 128, 64, "69d9440047b29b8e1dea08482a506d9afad24fffe9ef7f18e36ff9ff6d510cd9e905bbaa15db646ed6bc9f65341869aea51f82178e341334079e94aedf81eddedf0ddb9a53f6964fc724b1500fab416e8afd41c9a75f35e6a7990e01a5f24ea4d45b6c7809eb7a5c798b05b4c3f33d0331d555bd3a572d564cc72f9fc98a7752", "18ec13250ee9c74c0fc4dd564b3d24a825802d5ae402a53bacace115ae3bbb329be79d1e5e42dbaf0a6446431145fe49b86a8703c7c41f8985d54f12e314c16ff89351d8addf66ebba2783f2d1a11965182aa0b0dd2de53586c5a695c6265c2b173958da648611090557bdebf11a1e042f089fe98e049f4796c60d26be38356f", "921264559658c2a0f948d13620312047326ba3ab84d1795c9e438fa76daa37ea5f16024306be804aedf8f91b586987254bc0ca8d64a79325c46b2f0b7371e3dc"}, + {214, 128, 64, "9ecc24e4faa8fd520aa9a49cab88fee7fd39425e13ca502eef8d45d5ad794c9dfeceb763d8f84e9d6cb6e69c597b360e1f15e7c6d68ceac0204d0e5f5c87d2fa1cd67797d91f5af6e6bb81d2a3d77463f31a4e27f08913e2dda844e45be2b18ae02b8f0766e4ca6460ff9dc6f2635ff06192a008c989749e0ee80fea14529255", "b85c46b5d55b896d67b87ac3313a97c7509984211ed80b0357d4615c7a1eaa4f7206c0e376f830fc2e0c868a17d8cb0028894b08b6329c749563db7880fe3917ba46b6dcf6392dca752091956e647613b2a3d3ed9003069af6c6188eda1f43aed844b1081dc587c1831c224efd85a0e73610a33975f4515cc426a004512ad0fb", "9088a7ca211f69835b3786789afd93f3704de4a34116ec5cd5ed0a43a3bd611ca08619718d9bf287502bfe07b6d79b3b2ba982f99442752aad29ec23856bfa47"}, + {215, 128, 64, "aa42b41c544fa928b2f3c7f12c41e5c56c910860ca257cb3080c24e440470e951a2b4a694206fdc41a05b1d3ac55efcde2891078f93c50ee33f724a1cc55ce9d30642e0d6b4fdb01e13a726e3f6e2e76b1b6b9ea5608420ef168d09ce10ad60b53b70710b6716b666f5ab3cbced2ca4b41e0acc0c8d37b9aa929d0dc65af4f67", "2b1f5c46d4b819bfa1ede55a14077644b642aa3963d177a6e823200bd065afa47a489f486f04d991f39de23dda6452d49dc2888bad319c69078b95a80987dc5e8480f15d12795d57aa5fe846718d0b0ad396a854d33ef9c49fc9c74e6879dce27052ba4c65208d59edbb5f3b828a8b2e8046745c7c0076fed8661dc594429578", "16d83f28f335f8d876b2fc85512159147f4cdcbb5c3ace09367d8f1b557bc977cc6cd31db4f93b144302f2712a05fd964f21f5fff11d28b703b9de3a01f87764"}, + {216, 128, 64, "b04cada1712ceb8b03c37c11034d7f6723c5d185cdfad3d80ae56e37a33a5418863d88046ad72048b6e94aee9fe08deb918a519ad128a26960c431d322c49b8e3fc0ee05ca916a08a1aa84c294ac31ecc93460415ef7c8325112e5da9d9b3d34a67ce88cd7814f338aaf347728d8f3d2916c0762be92cf99a57792365ce6c274", "1bfa498a685e81f725583a0f4fc5722fde8c01199b23139a3255db6a884286534ea76e95d75f918a262a41864cae1d01f1bb3ff830d3b790a8ea38fdcf6a12a28a7a6079fb8083b69ae4cfa7881883df20d5ff93cea7314424ab519e2a97cea1f6fc88fe7dc83fc4a90f4b3bac0b8e109361a8b31ea569fecf218c1741d2a297", "175e9a5606934304d65f5a2357d074b3511b597afe0167704aa457447a7015a02700f9c00aad116217b27daa9898c6c1e134e7624a7488c3515694b98a2f6ec4"}, + {217, 128, 64, "95b203c6488fc5b5215aa58c6e34148dc277cd1552925b139f14dcbe55060488737e654dad71edd10fc9b069e2b7e7f8d34b391d52423aab391f325aae7d1fbc4aa3fd727b59449f26fab39d91cb4cef818ba0779f4b4ce92080c480a5574ff06048539b79eed307b016369043164a5a1260888a01569ab69e601a99043c9d0c", "2ce3453903e4f074dfe57499a1506187f8287e79849e0e373cdf538e0d3151fdc33ed4b12dafb4b47cfd5861ed84791ba8da283ee75e13565a14048fcbb0aa6dfef09cbddb2f9bccce3817d66f58f5c15eb7900b71e7fe0212be9433e261ac24a3a2a546548c2c259d3bbae26ef25ee3e467bdc96c6157a22a850c609c6dde8b", "2302ffdac9cf3b7e284d80fc470ed42cac01d218fa1b851a4dc3edc80c2f3c8f239280da93ebcc249886bfc08c7f0bf22defb7e447dc8bdbb94093cb357cc5ea"}, + {218, 128, 64, "f84d1361c51c3e50e245848383fcd37b2f7b0fd916010a7fa41bb1f256228302cd0548ae2148ff42774d18c2d6d3e38b36bc4938da13bac3e04d66ec17cfb0df10b1df1178c2176ba4cc89aa6e19e606403519116ef635e3c9baac7471f0c349eada42537290701492493e03f4d6c332746fe82e79b2652686e9ec500c8ca389", "2bac5a6bd9dc5ee714606e2262bbd3d3ef73c9d578688321676370fa40f2bd673b741be63370c25fbe2bb5579e79486658d3e0eb22aafbfe02fb70a63524f74ccef6eb709f0b4f9b5c591095fe0889d766814c4343c82013350b4610337b01042a5a5571e6550e83361504444b119e0f62a69547a369fa4848bc7b9e019fe276", "5f3422f586e6dbae45ddc87f8d04b0c88152f90fabfc6dfbb0ccd7edae37de528460a7bf16c4c0521355d5f28c88ffeb55986f8b919feb756693b076c1690d5b"}, + {219, 128, 64, "befb1ce10b50a8dd71468834cc5c1174bcc1885f4a67e49ece59d6b3104e0730ad7ea126bcb410e1b2a50ad28380cccd0ac6a775ab5cbcf437df04ef0f3793b88d6f1dc69fc3b963b5fbe5a5def8ca9f2d8dc2d8629018fdc6300fd25788256e257598a8fca52acd43f1219424ed9353eebde072b72a802045f5ff462f6a45b9", "1283748593d539417ff5701cac703c3dfcae39608382bd14ec005e26188fb45d093f6067ff5c4c14e04335c2dd74671953e9c8f8efa618ae1692776e848528fd33a294ae7ee792908602e5e6d56606d7419f256713e26aa669e98027d9fe54b457551a40599e921d39db8970da6fa2e18e785697375f3a63adae803b6021c1eb", "6d4aa62658419fc842553c70118d90da3cb2a37539dae4b086b4a7f0303dd9c5f5a82d1a7700fbc1d5309a7f668bda06ac53f6f77ae26878bb9225651b1523a2"}, + {220, 128, 64, "21251ddba377e48fa35ad148389c486a84e623f3dc49f9af281aa0af8d00f0f74a4bca77e087593d765198e87b6a15608d0af4c49a7736a445d53c718b408631a618c177319c01938ebb4b06852656392daa926e10bd6af68a57c6a47203d583fc3509c4dede63fab23ef08a9cf9945c2c6e06d786441c0dc04549328b706453", "41da7852d48d59fc2ad0fffb9d64b9ae213f3266d5d4a2c7d89445725eb50de1033294915f135467daee1a4dc1aeb81c9a93fabeb57adc94045ffa152c2048b8dc8303145e7be8466ca7a394441c8a50ff648bfe1ec663b966c811d2eef38bbb76d6af23fa4e7c63870482194e369712f7bbcc6e3741a0fea5da73f1c9b73db0", "41a4c83777750d4fea58645cea32ff4456c44953b466a5980d2b8da234603547a6259188f8693649dcef85e85110026c006ab968297567ce823965a1df6701fe"}, + {221, 128, 64, "5d307655cf8f7c1b3b573bd75e2374942ee3e56b6b2578ec7793bbc067bc908d5a17261a094427b4a09633d0cdcf8ef1162a15cc6f9f77aa0c62a10f74ad7a99d7bfd12aa125934a4f3842c681e7a29d51b6b61de407ea4a3e98927f5b4e93587b3160cebdb729a4ef454f03a5f31a618890aea7f1e63b92b73e755945274491", "f91bc92f97c28b011e7bb1dce84cf9154942094ab908b49635b87906e2f14c51f42a9ac3ce46877b6a687ad6fc08db2bd2471bb97f7ff5dd381ff4897eb636f1fe4d6f87b5fa302a57b26a9af25f2e30ce32b6cc993ba90ec0379bc920a9d3b4de2c526393071176ad0289111278788c06aee36b4e63579095a875af10f2ae03", "9f5c4fd863f070b85d29b933b1379e7023335b74aac37186315e959473bf2b3c0f1f893e1feace27dffe35be6c607a22b02d695e41948b3b6b2bbf58ae7ae84b"}, + {222, 128, 64, "ffe01cbd0ef36a85e32adf18931c4761709fb382228b27bbf9c1938d816c041f57871ce03ca0c06e68db10b720399c5e8b1ad460c201c1f72698f3bef6f4bb1621199ac958c1f8ee6859190dc74d4e836c856827e430722da3c0a04b9835821b049f7dc18bde7ccd8cade363aedfc599bbe75620b29ea3271741807c8eb9c2f4", "a32d2fba17f4b0f08a9ee7edeab34b1b8f7b12ad6e65fe248fa97a18c12de5358ca62e8467ffa1eb2bfe00f8c825d6da36d608b0afbbad071c651f9dcd33526b6c7665e334d277775ee8bc5adc31d08a4a2d4b0e22be957c2fcefcbf443803172de6fd61e637db990ba3439d90a1e234b2c8024e2d355f8eb02e36058e04a041", "c1437541647fb134322fe4809de516ff2a9982c16132077dac91e0e06f14cfa943fc8539a22c91faa3fa8fe623dafc954ebee5c17136281e7f8a3038f58bd80a"}, + {223, 128, 64, "d65a384d328a1c8908a53151d8fb1e029c6fc44958c2728bf314588445a73f2e71e777e475a710c7ffae4d61837255888a232c854debe27682750af176ac6eea5cc501d7e47f151110a9ce7e44e5d76d9cad53c1819317527fcd169051f01c6a3efcc06ea9999431e3a09ef143dd0c79791423451f4179e7912464a9fffdb274", "0f280564119a83a8482f57b7c20b247171a985d8dcc55b17157966c4eba613626095952a5ede370ba589f1ef08743940d9f41baaa2bf8c23150afc2946ee2a4b18103cebf5810f42c3e3cca513cebc069b725dbde67db5894a3fe6d11b0b03301ee12231404bb25788850f614be054cb9f68719811c57d4f9b5f4d44d0c64518", "9645b0d953f9f91de98ca15845b7edc24434d3a247c1eccc99b71e9a3c3ffc79e94ac59ac7bb6ebfd10cc7645dd9c8449ce36bd1b4d1eae96de857cb04a76c0e"}, + {224, 128, 64, "69a9f4e2dc0ec5a720cb369e9a7ef804a4eb5254dffc1567ca06d2e0944e4ac72fcc2674a62fe9afb021221585cbe6bef09c7d1ca6465c26d60a53b6013608300ceca4659424ccb781f4d37dde102ea9e88d28a864ead78936504e62301914ef2890d57d4df75806bbcfb19e4c53b80db146b9bec2ee6dd8136129aac8ff564c", "b9c8680ebb44ac60adfb20716c23b7bd9ba54908f51e888de129355847e094f1a3a01d3a580d749a46569b5b9ebb6751f54c30bd98f3cd7020b4bf344634ad67f87811e9acf03039f4b44fda520d24fc4e378b58c7657a5c870637881a47c818dfd9ace35ff4c883de9ca4b63023d704ceefc0a2297d77973ea6031d6b21ce4a", "73eefeacc31d31fa658517504322a759664bc1a94c3f31ffcf333f678d236c743066f05f92c99b30141a13dd65d0fc9881145af6acc9bbc446e0194d68b64977"}, + {285, 139, 64, "95af10920dc788269e70b8560b73135cf7f6f5b04a502c7bd61cb74f3b8ccd160701224922d865636a860d949ae755b970d3858c0ff37418a2d24b7142378ba11ab352e5c876da1a076642728b73916b2d24f8024876572363e7036510cec7f413ed28cec749ed33be3adf56a8bece597612d478bf84de85628367946df887f73dd92d6de7faa896d7276d", "61d91f317a902ea0944e11e92e6657a589e17abc027fcd869ff8b030e8870662f8a9e91ed3239cecfa42c0343d66cbebd1c2b771a25df7baea5cafad038424c97afb720e644e7d1bf5b829944ea2cec69766e68e4e580976de071c2274c0c5eb0e5421c9d51bba76ac39b3d009204680035771d9ad79eb02a3805d58e243cf0e", "6e989ec9cbf010ad6691a672ff4ca90a00275f9ba4c81cd147cc506e1dbc8bc93b1d96a375e493503c0ac697f7c45e4fadf138242df7e06e677de245afa97780"}, + {286, 139, 64, "27e6c9f270b9855c9658ad0e3d6c9a111a624f66fa64a49a0688a49b454733ca6230f451b0dd69b76b275cb241967e3c101b4fe8f2023d77772210a63157854b763239a061eec9df1aa6380f57c6911d23c0cd2edf00f63486218dbf35612a17ea5262878bd3edfb2b3f08ce8ae419dddab792e0c94517fabbede38e574d685546fa35ad37741d34275996", "df24279bf8277ad1091972b82594d84677e54fe5d65786d19ab5b2c1ae0a3cc9e7abb67f9477145d575e196633200f0ce557bb5278b8902e1496233117a7df69660bfa87068aa73de61e8eeaffb179799f275086029f47c323f6569bd18dea15054ddafa73e89c3a5f61b98cb2ce7e554d5df4cb9d95135a70de33470744c393", "e6f6061275a89345f5463cfa198d528e14047d478f69ad7a73432f18f88bc68a1b8aba2c3b025c93b25deb8f403763a55024408a97a903e95f0cb6178e7be389"}, + {287, 139, 64, "59aa9d7f583f6ab90b472935aa6dea95e2fbe402cbf70c6e1992e61c96c49b63d0304daf0e4da7c889c7b857d92301a6aea3cca7c069c03809deb3a53155bf6e4aec984bbdb31c6e84112c089a63bb0eb0e5243d22d6c15c29d7b9c1529519162fa7275d4cbaf33264eb2e50d5743f57528b94cdd8873662e345a178e1cad2e2e729a1eca3a7519c921e66", "b9a8865c3a6ba8f2c13f35730b39fc3c92405c06bb6e116851b84d9d32d20a88484d9ff5bb03922265b4ae7e87f155b0ba3917db28638321fb3b3c661670505603aec6a92d0776a550971ee52d68b15a8293f28f39a84231e050b6ce59316dddd31221fff940fb846830ac316765b940d29416a95807f7a0e73fe35f63dd0a25", "d78285ab97dffed5f16d00a7f277eee9e9bbbc5eb14fab10c189739965fb3dd1c196fbe3b01363260bf688955278884812286dcf81c25f1eb17cd2503ffc7acc"}, + {288, 139, 64, "51f9ab865146187fe650e49d45421fff28c45c3bd8c465458b762d93f199067e0afd14ec3a42022c9fe2f321a272bca3cc245022dc917b8c16b5d471dd3bed6684fbcca762c29f002451abed67a8860087848683b126795f4056963c46a8b4ea68febafff04e57c21da5f348bd6ce5ddfeebe6a6820bc584b1605d3a5366c5d35e0bc63e0c6e923c31e7b2", "b96ac1ed835f1e58f5327338fd604fabd399bb65e6d9cdf716d57a512398ac86656e94d0be0142d4cec27327658aaa103e818290ea40429f0a32b2b9c1402d9969adf845853ed24af79fcc4974025bb23409acd0eee6370603c19758fa59992c2cef9352c060f743da9127a6100f8b191ef7e22dda14d5b26a48d236b42d17c8", "d6aa880ea45e0ab267e47374598086784a7db2169043073614c4a1917e90e8dd2818f63bf8a899d0bc615e60abc57d45e20638dec691b4750a36079a330e5270"}, + {289, 139, 64, "9cb3288f3b04f0442f2ca8cdc41b0f39ddf93f898868e312d509a422e941e4e64e3daf8b8d33eea4ffebdecce07fc18ca55fd47f8f9780b38155d4530fa53383d7804a8c14054539700643811ac607651901f01ce02d2b6e2200275ee732490be084e2d8f7015ecb2b84be339b7a488ee0e97ca9a0b24b096013848a9a6f8f4610525db85fb09f22d76d36", "96a83010f9d4f0405826e8cc941190e07c33d933362db680e1b1db3a78ddc47cf9c7fa3fc75992cf4d5ff680e5dee89cf8a7c3a1662d04a928940a2a340a1adfa05aa6060bbecfcc39f52806fd96bd215ca4545cef62f2348969a1201af7717fd38abdcf8baeaf1f621306c7a4e21756f05112cc9976870a4c582986f34cd143", "cb700e68aec9448b67ab8e15d491aa070242b4430d6c70db6b736ad66756065f417c0b201395e203c57bd7809272ce34d4dfe1972b7c5277a28d71c7f52c32fd"}, + {290, 139, 64, "cf44b9d057cc04899fdc5a32e48c043fd99862e3f761dc3115351c8138d07a15ac23b8fc5454f0373e05ca1b7ad9f2f62d34caf5e1435c451f3d927940e8a92c805ee3e754117c45fe0de0545e7d1b3f0b71912aa2deef5e5ee661a6e95a06f8727ea158000c91fa067b03a7378066619bd61f4ae33b7ec2fabbf1d0dc3078c3ab0a5919004c159f7fd79a", "ff24c8943c8e6d3db40c7ac16776f756c44803ee07a3c95bc594afb7c599d0031261ad0e4ed41f98495391b8d3416b7bcec2d1ce87c28e9e463a4b3d23ae05081cfbbe47654f7254ff794c008c631a3262dcffd1de9b67e4fa8140f8221f68c24478610627084cb8fd0515603be4ebc3a81ff3bfb4363d770cf4f7b06bf3e07b", "2c537d0edfa86126672ca6f0081e8c13fd161510d56c0bb6ef015ec35cdcbadf4fe68594fe70820ebfd99cfb83a1fd18febfde2743bf408479a52c3334e39141"}, + {291, 139, 64, "0f55624e40771d01c2643c2bef1c97d5fd0eaa1ede76953064e96874a92e9e02ae50e75c42f12b5b26e1cb696ef02af12a006c14465e7d9eaf525538b7f47bdfbb42c89403706e55e97f394d3e111448e97cce69d11d1e1ffeefe555fb5bb4e97e528e604a9aefd855650c3d26285dc082aa5985475c819c98e89f333a0c500a3ea9c027e117b5cab0bccf", "0f565c68deda3bc803d93246a1fc18ede3cf16d1e217adfcc965faab37eb39bbe48f895e883eee12f8839cd492587390dc3cc6dd688560e7fbf8c9aced97c56cd3ba1e5a5c61a39879c97162c13d718a132f22247d8799825c3bc663c520f8672400a3c623ec6242ced3385af4541bc1d0d1b30ee8c55fb536577936862fdb94", "db88ffd6256ef15c09d67244d84d4ba61730ee6eaa565cfcc4fe587e6a950cbf69a7ca19ef489b68f8dec772550795198462e87ae414ad604591d765b6a2ad0a"}, + {292, 139, 64, "a50b14fc2b1852542a497dddb86709c49b3285f26af9d93fef69cce2d0a3c92c6e91e2770e79155937d2ce1d5a57ae73b95b8b66815cb88f39da868860690aa4520621dd6ca7b20e701633632bfe6f0d5546863ab89f354495595728437bac3b1912da188ec9b1dd9fbab3977184d4fa389e7e5657ebd8c6c98e48abbfff37588a5e140fbc089b2d8a6957", "f4d6aedd9a34e0a1822362714d4e81794b53b266417678c16a97887bbb612cc96bc5e532b3a654e5d3d65a5155427ff09569906381138cc49e3fc2384c5d33c34abd3d617c487b52ec6ee7b5105f41584b7eb5cfb512b8c31f3f338d5236e30398a8ff927e801c8ed7d14fc5040d915a737967d166ddc266f68023a357530431", "0d99228df5e7ec538be55d8852a0c4ad0ca61befb94f988d2d3cb68c006c0fed69b867e1a4f2a50348890fc1ec82c46ba72fb8d585376037f94c9fd18b67a839"}, + {293, 139, 64, "bd619ca4cf382df22b99f1310a6498633bbf0100220a578e011681727691b90645c57aeb5883a0a10459cb548e0b04f9ee41a39ad27e6feee651082d53cf82228540538232196f7c982bb19106197da69d0fa45858b1878f4a52805627677dea063bee1065e4e2ac6e756c9079754c92d190cbe1bb8de799b480b094fb41f2844f1c143efaca40590ea0c5", "acf723e38ad26db1560747fa39674eb6d8546af98625a677b7cc3f47b8b5fae79ef2bb817d96546cda5e9bf66297bf61dc3bdc2b5c5ecc93b9c8415842e410c4add9d0e950f6a42b945355fea6b5a4f16fb3deecc717b0b5e5873db91a656e0ac0f389a46dbb06f46c2e9e9b6d8ba46f7b0298c22f1afae823505cf3aa00bbc1", "3c13c0897926d1d45c67f68a4e1c1bdbee8f601affa0edf8ebc6b567d920962fb9f14a4fc92276ee1a266258ea7f71e09241225053edbeb7f31130b36022dc13"}, + {294, 139, 64, "107ed9ca1f16fbdcbdfa5211b1a9ec8d9e03bbcb1f0a468715e99fdb403695a80d742a37afdc4820715daf6b4be132f6b3d22316b5dc0c8146f59f6cd69bf0f0245de2b2569ddfc34994cdc526973d503698e594f7ef503f6f5bd4a1c043c50dfd42e8833ce32a8deca9926769537562ce5de98a0bca7b87372125c127b67ac83f2a24f28835904603a3e8", "204058177a61aa45bd666bd0f3870645fd6b9330cb91a89ad3f072cfbbda04655926ee79de8e123c4e56b3af342fcfaa935aaf231f10bcadad22943fe9dd5d3747305a9e3c11bbaead1cba91a87de36c5211b39c20c865404a4e09f77dead6ebd1a6c10efab04fa3c200a701b73beb9320d7c82436814c5991bbf87fe1ca1787", "1bc503398a25223fb9e93ea65228d2727b201f0a3fb544a300dc804340b6ab3676862b6320bce35adabef387ec628da38277f7de6929c44810c47f2a7acbeb03"}, + {295, 139, 64, "8aa3ae798494805441b45a59bce230f9b2bbb960b15f2456727807636879983799241f48ad4fabbd44e7048b8d35e2de15605cbadc34a3e2ae21f0f9b087bbe73a312e7ee41fd95ee488a715971f118b5d96919eaa605a095abc468a45ef104414d0c362538a72fdc79e2a3f012725c933624053436daf921e4ff05f4f39fd15d00cc63b1f1ade63953175", "20d04970ba4d2cfcb4c4e1cfa3fc6406011e8a31e869e4ac1b28e62d46e1489987d0ad1c2c938378bf272a9d4013587bb1e3bc14d8d8e1d540de562681be0c40c195ff3e7b8518777faa520c3a501dbd38630001e72681559e2849d4dd758408d70987002d8ab5a2fd36a3431b1a7a759e849d209fbc8cd53def095ee46c799a", "45560765e5e4644476206c7af9a2744de1768b44692a1e38567390eab59b951e6c311576b8c33b8e8769149c9bed6b5e1698ee209a8b464e032f4bdef057065c"}, + {296, 139, 64, "be0a902d7d0a1a31c76982a5a4612e27ce13c887656f94cae453017554f77e08bf888ec8e8131fc139a5180cfdb1314ecfb10781521070f723480b9b0c481c7b7b18978332bf7b8b3f6561952fb5554f7f85e4e053b976e06a64dfa8523130cdd802d3e7c3d6d797c2f088c8a2364334c4d7882acf30518fa2f1a2248d7b6206c08d697b0320daeba88fb3", "6e3662888bd3f3d6d980684854d93883dcd2da3637a8e6aa5618779bd9ced347d5204ec4d4fc6b961d1f458136882d9ca82d95a702ec2d9e20c44b8ead4590a8e745c994a2d5130890744398bf8284d063f74280d6544757ddda24b32dfad3b82e0e9aa0fe463251b9e52935f8ad85469797aa68bcc87efc14c1cab260d6e49e", "4a87dba3c394b7f9c0d55041043e9637bc5713a9664daf4077a37fc55ebfadc5fd04a28a9bd13caeda0a7db4ea7a01eeb1410d35a821b1cf4e8c66475549f43d"}, + {297, 139, 64, "6dfc8966adf3c592d0d2895f5ba20d3cce6d7eac6ef6e99d47a75bf672cb476f94fd27a5a7e0666efd117e69815a5eda41290eb5294095f911ad1b3ffbfd4b9395adfb8206e10f74e6589a3d8ea047ee9386f8f18dd1ac551d30a6662e70cc817af24d26505d864f959027000adb9120cc6e83872111f65871164591938c91e04bb664b910bc94a5129f6b", "97449ca6c272484156c84d60b7afc1cc59546a46cba1df1bf56beaf89eed31003175151cc05ddb92493d09da385f13ad2e73375e0184a66d042be45a880371b7a25ca9812f34e9b01663f30dcd1594441f7d843a2cc88da0b150efc9891304b87463207e18dfbbc345a1d2a27db98abab4da17815454dcdc8442d3edaa05302c", "2ffef9fe1a0a7ecf39d730564020b8f0ccadca49e4c1780e193e1901a19787db8aec9d7af3b9b7d5a96c2d948f81d89b0b0aa23e4fa350c3d8983556e1be2f4c"}, + {298, 139, 64, "1f2855e133cefd5e9e295a3c63fcb3f9185b5fdcf56b7ddc2b69e5bf76ed5e7ff67011f13b0c3da89f842d18d88467f7cd2a27e9a9c40b5b2edc10af4d72bd9af3889ecb25e4f4ce4f11ab2fd9a78ce2fcccb4e2d4fb4519b6045b80c3544287bd77e6b71adb8a9657d7bdcb8feb8a824c4af0129d9592dd69eaae78021d530dfd45cffd427b67c95fde4c", "b55e84a2c74e837420120c9babb9813dff4d545833587664f4a71334d64e7c1ee8ed655b8b3150b0849d494e4f8ad4f8b66c2463a3588de233c33c430b8d26f3ef3e3e69918febc2a62cb9a93fb84f7a5711a1a7a8d6665ac427cd5c60ac6b35f3d9789580703cf2af47c473234bd90d08c533ecebdce914cf5b2c487db5352a", "61a87e67cdb1cc9b3aedc912b28f086c0a23cb5be98a51d60cdf1ab3e0d288fb443881a10205778c6f599d79dfedd4af27f1417131d9263d995748df45342d2d"}, + {299, 139, 64, "f37bfaeac36a4ec9d379ac509b49fe50f85a995a89d8c22f59b87178bf0455b78373177e423de3df142d25236bf890be3fcd6583682df2154bfd599eb8da92c313acb3d7b27e6f4e878ddd75ff9e7b61299573251b441d499281c477d87bad76eb4e555ddbd4fb0074be5eaf1de4c82000da4ba96bc44bb2766b3d6be790adba5280867885e88edc23eb30", "a781be58853dcea37c1a30ca5db6e16b9ebdaab800ffea2670c695652b667d952615d0b7adfde2614a902db6e81c9796389ff31254dcc923a3ae5a9bfc9ddf5b0eaf12c7ff80ef775395bc2f10ee47121fda6f12f610e5ab74fa34d10c54ff2726f68a71c2ee7d4c5fd2e41d1b5579471b1726a12dc2c627ac522cefa5b4665f", "66dadec2dd4e47418e8116d5ce4c2a9e85fb82ea0a96257b661d5ee9f4b8568a0021602f698f20b5c3c77d2533e1c6760eca0abaff7f1cb0834cc5064b19b102"}, + {360, 142, 64, "01b95a887927ce31b1242391bbd00965eb77a903d4b8399b72e6cebda9ae721beefa779145160b626b110cc554671da0d8dcf993a9ab073888e02fa9b803ed43b3f6a3aa1d20340df6ccceac13cb0797cf612cb8fe5fd513228cbd4de249d16bb77587dde98f71bbba1a124ee046f0d239ccea7abb1accb5aab021b00dca491c623fcb3191a9ecf31fc680b4a41e", "632afa8e79b14b2a3604f5855d2bf182d3c56d6853f21fe46271da5286065f38b31f751306b63c57b679beb14729c78f0040f7e2a0d615224dc5a693cd0cbec8f87117656d6b6029853ed72b85681a63183c3a6dfccd128afb0dd7e81d36f0231c69070b189560a88c9b697b81b0930701026190cf9ebe23559194d6de4d9a51", "210ad45ca2fd1f105c0a18f993774f933ece57ace4da619689e1cb8b491a189cc6e4ee1954a32201072e70f934837c0fb6e239b4fdfbd26ebf11b9a919eafd09"}, + {361, 142, 64, "61096f4fe5340488916de293be38cc3ae0c877670c713637b760d74fc18ac773b2e27d5543cf16aa20dd3d83ecb34edb8545bb6c8a4aaec81bf1f0a4e0cf09774d1ca944242046b33be807677f3de18c39d700af90cd68d34f50dcc1e999fe9fbb20b9c4900fdccb6af607e680c0cb7583e60dd825e2ab81dce7634de3cff0148355757f90841f19366f06a9f623", "67e704046f98cb5aa97da95b19147391f05788f811366b0ece44b12af2b11e0e05780bbfcbd90a950e0acd8e9d2a44e7957606eedfbff212fa1c163cfbdcd062d2be3259ce65abea6406e4292c64e9022cfe89155986ffc45b96d289919ff98d552243778122f68231d9b6d3cbaaa9093d57d9158674da4c781bacbabce2e2ba", "9a2d147e50827157f3866e868c1cca9f081579c92f25da8cebc9ed249928c82bead39d480ecbb5b5d0e0755029aebf3e0206984f3ea83f4d6372f4453390e070"}, + {362, 142, 64, "c5c06993d43f27e86bff96ca7511176974bb63e618bfc4b610e0854820a3a6e77453d5e134479ae95868d2babeed5efd79691c6d6d0816391915faa9b3c0cb057a1fd5b34872e69f66abbbe0a52eb998aad5de1b8a37f654972a12657986368e802c5250384773d23ed23b83535b8f01af068f3a97d4cbd13225b3c3997c504a2d8332012d4faa4988e439eceffc", "b53127b89772ea1ca6dd27277da80ed972e82f1232a73d4ba537118418c5f17d9a311329a61e5d6003456fd4e90ee3466561d3fafeb99c68997be2349a87d5604c0cb2c183a08caf80904c011474f73909072ffbbd36fdc41077cdd8805cba7c93680c667621ff72e366c7964703d01825834afeb546e5c7d2d3d958136e2a39", "e3a4d32f262c6cb0e99195c7439ad2731185c58811f40ecd32af214a21c20869aef5297cd951fec2a145e15f982266c46f7a60c9fb0bd0c6b16f5ee40fb44708"}, + {363, 142, 64, "5860501208a4c922ad7550dbd931a19ac1434750e63d5f34f528a0b5eb1798b37c0338eeb6d293bfe2b9e306abc4cd6382b3e6a94008758f0d5e7ba981fcf0970aaa507d8ec456b3518c07bd18c4f37d8f7db8a7e82ac776c5f86b9d58620781c8ff9fa5d79f9965c397c5e869599c50b048c53325cade4fe39e7879b67063d780aa2d4fdb8ee53fff82246fe7aa", "c35b26bd02499cdb6b06bfa4b18979f0a472ba7c559dbd277bf78c611590c6e051f2a094adb22ade5c44d4fdeb1330c924d1f9a3330c55ac07035735fbb7c877b64527844f72ee7eb58817074f61dff8dfc1ca56ace9e782e06855af2f350699b9fbc37532b47023407992ab24980ee79de8337d0959fb11cecf8eb8f83108af", "8c385547a8eba518e777c3593c5b7ce0bd7c859af6d67b6238d20a58b8d0d74d80d18ab358ef1c1218b928a026ae8c4e3b73bb5bc0914de905d499c75e6f3d9f"}, + {364, 142, 64, "fe4c83e8496a69b7a251228396a5d2b4849edcee0ab1f8dabd6d872a1da324d7c8c97cadeda05f0a041517e3bc65f807358538a870c1011704a3c5cf1216d2b57acb269e4fdc841289b0c750fa1e779184d59a9188fbcc4ca11492059326ec8d7e1a29c25866ff5699e9dbd2381676dad755a9b23ba68201fe8897d588199ae83b7e2e22ee85f95e9d89fb715e97", "c24fab7f7998c69063c2d1103e60a6c4cb03206add01d09faf75f1007a879e9047ee435a02b35257d1373791a4778d890c8f92d6507dd810be283eec3fa11fa82ea8c9aa6a723164aaa9e57a11b54127033ae6dd36e1682b0c5c47e420a4217e1e8525b8d95dcb7f9721c213afa02a66570c04c5b7b6e7b94219f430451a0cd8", "d725750a042de65607af5ef523e3c86d08be52427b7036ad514b9596c901e96d76b5e58f68907044282e695b3b875c09ad49ecd9950fe312a59dad691471c572"}, + {365, 142, 64, "41f4749cded6e44c11b8118c38cd71cb95a26f9eff01bbbdd716e44e3ed02867858a8bcee5eb2603710ac28048d6a53f0fb6ac7d9f6c9abefa3fb01184597e95706ef83c789ecccfd19df3325e1186ea243bd4dcfedab157914c115583f7d5fee8e7e46efdb87eb819b7cd2be044bdd4ba7b0e438413a89285852ea4a371d5abd63e77edde02e3c731a178f23838", "5c74212dfc2a80d30c39d680327d2488838c35d6503c1a8c4366d7eaabe95c7115f1b7481c7987de820eb4d17fd65d0f58d2123b346044522c04f98ea167c48ad2a0f5a8adb30db0e65775b947fd6f4d470d4cc8dd73e001965a332ce63779ffbb0a441458e1f98f619d800032f8408b75c74b46f47dd5e2abf1eb8e22616218", "7e983cd601ff5837e7d170f3092e914e076c21b31761eb7b9ec211e3506758d8d1395ea914c0350afdd6827c0283ea4af188cf30c1fdf075e41363fbdbb29eed"}, + {366, 142, 64, "fe27bbc87755aacc37f667f8ca37f8888fc9dc530fe4f8f38e8cd426e01307747edff012d96da707ee96338d1b11feba313a865fca115431dd8632268ff499224ceb69d31732dcd91e0cbd2b92bbd5b6b543a74735705daab81a0114b8a8f0be91d38cd3d8ad328cefe16c99d63c67c4446ca7d1f708f9a848d1a9b60238f6907420c3d9c5e48f67889ca7a1909c", "99841c3e4a41b53c30267dc056e7e9b8f9994494dfbba363ea761c38ec2433d3bd10957d8b7c093472e9a3084c923ac5cb3a1dd2c5270259ce6f3fa80c723dd847a829ac409decbb44395ed20045b694972b4663f2fd658458b9ac7d3ecc65c260d4409110aa481bcea016e41a07446c86f5250f0f45b32aaddec97f293993db", "562b5ef3d5cec882a2f54f8169612dba2b033325ce5ed924024e7806c745de9e7612dbcfcbb95ea3fdb93de9c6460a866bd412b45eaba5139939fe43d20f9315"}, + {367, 142, 64, "29f8eb9fc8ab58fef681f9faaf934e992d42046f0ccd2fc9ab23d42bd5f5aafda110218196eaa408137a1b66ee4db5a35cd7e4f31107a9e8a81e11e744c000d9784b2d2264696ed721e1362b60b35b2b4d631dacba95658179da4af109cad9687653166c7a503ed3e85d4f334aeaca9bc98fb8804e9febfae70086316c3ac01162cde4461fc89c642f977065f71d", "3ac2ffbc5b6b2334809232c0f8151ed379a8634d70d3f5a1963a7637c421ad0f082f34a8f872702046a4c69c95ad0cea8b683e6528aa731956810f28c1b9396de8a5905e751c1937c9c17c55dc8771df447575ac93a7c161e6967cdabb9930cc03ab7ba8796e07c23170bbb274ad33facb566eea5ad1c7c16f0127155bc77875", "38ca18d60f180fd2a40e342272190d9b84ba37bbccf59b29bcbdb08762a90e1f8b28349ca634a6f955cc08c96835ee70a2267444fde88b45b8e313b0daf6e12f"}, + {368, 142, 64, "345479ae901adbac7223f5f9edc419bb64665cba4e3684b7371e28ff07f3124087f0e89a21630cf9e8a6c0a3d8518e0d5eaee7f31b6d0aa7e59927aa0ecbc479e99e61a98b625736cf1506199d8f2f186bfc9fe2038f0e5b87754635b30888c063462b035581860b2f571083c4e5c6859338cdb09004597b2899cdc87f1224bdfcd08fcf07275f1f1156260ad5bd", "e4b38e556aa285688979a55eeacd7d953f1ee0ab8109444c7cc068488eb83ae9aca1f783a59b944caba75d6e0f5bdc5b4cdbfc6147046e7ed5ea4c757e85fc2181a7580a17310b36fc873e422c4175b1ea24b3830750e50961ba7df9aadd5ebe6badf81148cdb4cd850192ffc9e6103d22e14f3a4a557197291945fb9a292665", "24d2dd3d082e6556dbe27381640837a23e5d4a4d6822066cd09217a677068e5b8901c1eca7da77a9595be271abfa76f9d40656cfbae050ff6d8ddedb0f4c82ed"}, + {369, 142, 64, "2aa1d94ec83ce7c3c75c6bc847759b085234fd44b407d8f80ddfe93c243556e87e4be8fb30b4743ef1169a24732fb2f5f416042b10c3371dd9d20dda29844d58370700ce69f7df5e69240df77b96027a0ecec71b904f690b875da854de05ef047c5d898d1c0d116c580e2a0906b271dec8e5b0dcdfb2550a40092270eabf253376d6eb01f0fff1afe55d5b21bd8c", "acf624e86580af11d0d23c19df6969fe2ec2cdc737bfd00bc54dc0b2ab4421ffb58f44cfdf8c1b1bc5b54bc45b818390de850c6f0adfa2048ed48360bdb8c511860eec5ba6f1bcc51cb34cd8ddc35c23cad4e882df3bfea0ad99ccbb0abbfda707be461622773b16bd1268dbcff89dbfdaf789871d9d8ae80ae4c44afa1571cb", "b6e82d35182ec417bb33d9230a55690f8720d32191cb5cd46bfd591421911727a0f8ff64ba6e16f25aa10669a85bf2ba74d84a754ed947335b7a17af0297accc"}, + {370, 142, 64, "cea946542b91ca50e2afecba73cf546ce1383d82668ecb6265f79ffaa07daa49abb43e21a19c6b2b15c8882b4bc01085a8a5b00168139dcb8f4b2bbe22929ce196d43532898d98a3b0ea4d63112ba25e724bb50711e3cf55954cf30b4503b73d785253104c2df8c19b5b63e92bd6b1ff2573751ec9c508085f3f206c719aa4643776bf425344348cbf63f1450389", "f3ac4422cc724378100d7515ddfbf3fe340002b7976c43acd69c2acf26c3b18173eb4eb6f73622540c6a73dd3eac5c4ea58cc34772428c6bc7370c0accc8c1feff4640d2cb416e2a5d06f35eb366ec69f5b9e0020923f6086216652318182ba93ec702be701a90c0abe9dee261b00b16cd9042318596e9494e401b62333d594a", "d336f2002c558eb518c773608387bd500704156043b76104eca2309afa67d69ad9b00e6b83417e088d3f93435922d4e8242e9631f962cd9fc258f3505305d636"}, + {371, 142, 64, "ef71b7b3ca0f904dc50447ae548096b2b3603b312a5e59d490851b270ee99aef259401bdf2c3efc3b1531ce78176401666aa30db94ec4a30eb281494bef5205dd87f3350c1c4a56f3d040b12167214391b30b121697a7915e9224b871a3c355f111a9493be7b7df870ff5c589bdedbc4dada062b3072ac2c93590829ab26a09dd74d6eaf714e3e07532c57e09921", "50ec304fa342839457d7eb28791b671ba5c425f711c3a351cc76149d481f0547179540fff239f054ff2c078454bfdd92b72b199aa783d562a1e6fd319cf9f8e4d6948b3ed2bcfa80a1d270396209a060051eada0544347f3335c1872266d5e6c1553d9b54cb3e740c631eef0abe2faac1703a7b21deb422d0c3e2b09f0647d06", "39d94c4e1c8456bed8637e592e4231854df3a6ffce98463e4a85c477d9fd34d27035cdfccfcfd385d91e4e38e8c75d9ff941de80742e985baa9c94dbec5a6837"}, + {372, 142, 64, "e5606f31ca4d0f5d62730f443f6db0edd8224f1881eaf27f9af3215d06e2f72ddfbd78b467082541422ece34e323a8bd45489fe6db8fedd4c9dfec4954ba286e971db9d078a7d0a8dbfe8f5f166f1e51a4d4fbd21dbb916e65c40d75244b6db87747d98de672371995abfacebe983a325e8f0ae22fb706d7d76a2be95fdeec91e60581f397b1831cd8fcb688c4e7", "082e7b4604dbd3608df7932475e4279bb288688ef998cceb8e16d9695a18e06f3ecce733a7b9e71f62473878b2824941a01b945d93afd1f5204c6a19233230aa0fd64c77822d78a61d266f569279a182fe9f2c287a2108abec16817724e7ebe32456915bbebfeebe659d20053d4f9926741d1837d576d7d79a7b06ca82c279e3", "d675982ccc457324e24a8ac6db3710b38e5f18c5057730cb7ea2a37b4ba44c41dde0874e43836cc95e97ff0b3ac10410497f9664177b0e576be8c508ab1c7857"}, + {373, 142, 64, "8a0349d4d1ed8c4af533e9e83468b5859bb68237798038171346684499c9dc2b5970730533eb2ca04d1680630820f58d32ecf0bd7db7cab72ffc27651c94831cd1220e2113aeba6c889092abb3904d8a264b2332f2d9df0f63ac36d7eabb57c85be0c331587f5f330d69c7c91f00e606de9bc49ec22c9ea815203ca2ed867fb65d743a3beca6427f4669c9c432b7", "035f55033df01f670015a828eff154a245e8ca7474b0b3330cabbe5fdd74e89560b8fa075347532aa46ae7ae907888b30ca4653a6419d0d9224944b43181a6a842c1cbc96fcc3b0f1e7b344c2956f2613c652eb27e44e5d773765a9521fb5e0c7125cf31d9a75f7f38ef96ea01b61b159cd52fc4095a7a94c7db0aeaf40a9929", "3780ef695742f09a160c8dd7d35e2758b08284e8150934d222db31df2767d40d7c815c526ecee5f787030c8dc5f050c419ec6ea7563650dcce1480892d3088e6"}, + {374, 142, 64, "f78343071f61ee7d9f791bd53132e6d557928bcfe4b214bebf6f3592e46374c7ab148c3c4d6a1443a4675cf4321298c865b440631947b6b05f2c2a337d1cbb9b3661de974b4604eb41cc77c3659e85470e47e16f22a34619db935d59cbf5e1101ed401c020db069eff1035e9d1bff77bd8b3379e05ac0c20bc0e98aad7d7304dedd3bc5ed4136184649b5e0f7e5b", "d63b50b54e1536e35d5f3c6e29f1e49a78ca43fa22b31232c71f0300bd56517e4cd29ba11ee9f206f1ad31ee8f118c87004d6c6dfe837b70a9a2fa987c8b5b6680720c5dbf8791c1fcd6d59fa16cc20df9bc0fb39f41598a376476e45b9f06add8e34af01b373a9ce6a3d189484cacb6cbe0d3d5ef34d709d72c1dee43dc79da", "086f674d778db491e73b6fbc5126233c6b6e1f066963356d49ea386d9c0868ad25bf6edad0371cde87cea94a18c6dba47535dfce2e40d2246ab17980495d656c"}}; + +void test_sha_256() +{ + SHA256_CTX context; + uint8_t buf[SHA256_DIGEST_LENGTH]; + uint8_t* digest_out; /* use non thread save buffer (optimized for embedded systems) */ + int oLen; + unsigned char msg_buf[20480]; + + unsigned int i; + for (i = 0; i < (sizeof(nist_sha256_test_vectors_short) / sizeof(nist_sha256_test_vectors_short[0])); i++) { + utils_hex_to_bin((char*)nist_sha256_test_vectors_short[i].msg, msg_buf, nist_sha256_test_vectors_short[i].len / 8 * 2, &oLen); + sha256_Raw(msg_buf, oLen, buf); + digest_out = utils_hex_to_uint8((const char*)nist_sha256_test_vectors_short[i].digest_hex); + assert(memcmp(buf, digest_out, SHA256_DIGEST_LENGTH) == 0); + } + + for (i = 0; i < (sizeof(nist_sha256_test_vectors_long) / sizeof(nist_sha256_test_vectors_long[0])); i++) { + utils_hex_to_bin((char*)nist_sha256_test_vectors_long[i].msg, msg_buf, nist_sha256_test_vectors_long[i].len / 8 * 2, &oLen); + + sha256_Init(&context); + if (oLen == 3680 / 8) { + int j; + for (j = 0; j < oLen; j += oLen / 10) { + sha256_Update(&context, msg_buf + j, oLen / 10); + } + } else { + sha256_Update(&context, msg_buf, oLen); + } + sha256_Final(buf, &context); + digest_out = utils_hex_to_uint8((const char*)nist_sha256_test_vectors_long[i].digest_hex); + assert(memcmp(buf, digest_out, SHA256_DIGEST_LENGTH) == 0); + } +} + +void test_sha_512() +{ + SHA512_CTX context; + uint8_t buf[SHA512_DIGEST_LENGTH]; + uint8_t* digest_out; /* use non thread save buffer (optimized for embedded systems) */ + int oLen; + unsigned char msg_buf[20480]; + + unsigned int i; + for (i = 0; i < (sizeof(nist_sha512_test_vectors_short) / sizeof(nist_sha512_test_vectors_short[0])); i++) { + utils_hex_to_bin((char*)nist_sha512_test_vectors_short[i].msg, msg_buf, nist_sha512_test_vectors_short[i].len / 8 * 2, &oLen); + sha512_Raw(msg_buf, oLen, buf); + digest_out = utils_hex_to_uint8((const char*)nist_sha512_test_vectors_short[i].digest_hex); + assert(memcmp(buf, digest_out, SHA512_DIGEST_LENGTH) == 0); + } + + for (i = 0; i < (sizeof(nist_sha512_test_vectors_long) / sizeof(nist_sha512_test_vectors_long[0])); i++) { + utils_hex_to_bin((char*)nist_sha512_test_vectors_long[i].msg, msg_buf, nist_sha512_test_vectors_long[i].len / 8 * 2, &oLen); + + sha512_Init(&context); + + if (oLen == 12800) { + int j; + for (j = 0; j < oLen; j += oLen / 1280) { + sha512_Update(&context, msg_buf + j, oLen / 1280); + } + } else { + sha512_Update(&context, msg_buf, oLen); + } + sha512_Final(buf, &context); + + digest_out = utils_hex_to_uint8((const char*)nist_sha512_test_vectors_long[i].digest_hex); + assert(memcmp(buf, digest_out, SHA512_DIGEST_LENGTH) == 0); + } +} + +void test_sha_hmac() +{ + uint8_t buf[SHA512_DIGEST_LENGTH]; + uint8_t* digest_out; + int oLenMsg; + int oLenKey; + unsigned char msg_buf[550]; + unsigned char key_buf[200]; + + unsigned int i; + for (i = 0; i < (sizeof(sha_hmac_test_vectors) / sizeof(sha_hmac_test_vectors[0])); i++) { + int msglen = strlen(sha_hmac_test_vectors[i].msg); + utils_hex_to_bin((char*)sha_hmac_test_vectors[i].msg, msg_buf, msglen, &oLenMsg); + utils_hex_to_bin((char*)sha_hmac_test_vectors[i].key, key_buf, sha_hmac_test_vectors[i].klen * 2, &oLenKey); + + if (sha_hmac_test_vectors[i].tlen == 32) + hmac_sha256(key_buf, sha_hmac_test_vectors[i].klen, msg_buf, oLenMsg, buf); + else + hmac_sha512(key_buf, sha_hmac_test_vectors[i].klen, msg_buf, oLenMsg, buf); + + digest_out = utils_hex_to_uint8((const char*)sha_hmac_test_vectors[i].digest_hex); + assert(memcmp(buf, digest_out, sha_hmac_test_vectors[i].tlen) == 0); + } +} diff --git a/test/tool_tests.c b/test/tool_tests.c new file mode 100644 index 000000000..49581c662 --- /dev/null +++ b/test/tool_tests.c @@ -0,0 +1,66 @@ +/********************************************************************** + * Copyright (c) 2016 Jonas Schnelli * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include +#include + +#include + +#include "utest.h" + +void test_tool() +{ + char addr[100]; + char addr_p2sh_p2wpkh[100]; + char addr_p2wpkh[100]; + u_assert_int_eq(addresses_from_pubkey(&btc_chainparams_main, "02fcba7ecf41bc7e1be4ee122d9d22e3333671eb0a3a87b5cdf099d59874e1940f", addr, addr_p2sh_p2wpkh, addr_p2wpkh), true); + u_assert_str_eq(addr, "1Nro9WkpaKm9axmcfPVp79dAJU1Gx7VmMZ"); + u_assert_str_eq(addr_p2sh_p2wpkh, "3Jb8Sd36aKa4G5SeVwwFderVskb3tCbmY6"); + u_assert_str_eq(addr_p2wpkh, "bc1qalzchqutx9f3wjln69nhkusnx5aymn8a7dl97t"); + + size_t pubkeylen = 100; + char pubkey[pubkeylen]; + u_assert_int_eq(pubkey_from_privatekey(&btc_chainparams_main, "KxDQjJwvLdNNGhsipGgmceWaPjRndZuaQB9B2tgdHsw5sQ8Rtqje", pubkey, &pubkeylen), true); + u_assert_str_eq(pubkey, "02fcba7ecf41bc7e1be4ee122d9d22e3333671eb0a3a87b5cdf099d59874e1940f"); + + size_t privkeywiflen = 100; + char privkeywif[privkeywiflen]; + char privkeyhex[100]; + u_assert_int_eq(gen_privatekey(&btc_chainparams_main, privkeywif, privkeywiflen, NULL), true); + u_assert_int_eq(gen_privatekey(&btc_chainparams_main, privkeywif, privkeywiflen, privkeyhex), true); + + uint8_t privkey_data[strlen(privkeywif)]; + size_t outlen = btc_base58_decode_check(privkeywif, privkey_data, sizeof(privkey_data)); + u_assert_int_eq(privkey_data[0] == btc_chainparams_main.b58prefix_secret_address, true); + + char privkey_hex_or_null[65]; + utils_bin_to_hex(privkey_data+1, BTC_ECKEY_PKEY_LENGTH, privkey_hex_or_null); + u_assert_str_eq(privkeyhex,privkey_hex_or_null); + + size_t masterkeysize = 200; + char masterkey[masterkeysize]; + u_assert_int_eq(hd_gen_master(&btc_chainparams_main, masterkey, masterkeysize), true); + u_assert_int_eq(hd_print_node(&btc_chainparams_main, masterkey), true); + + size_t extoutsize = 200; + char extout[extoutsize]; + const char *privkey = "xprv9s21ZrQH143K2JF8RafpqtKiTbsbaxEeUaMnNHsm5o6wCW3z8ySyH4UxFVSfZ8n7ESu7fgir8imbZKLYVBxFPND1pniTZ81vKfd45EHKX73"; + + u_assert_int_eq(hd_derive(&btc_chainparams_main, privkey, "m/1", extout, extoutsize), true); + u_assert_str_eq(extout, "xprv9tzRNW1ZnrURGVu66TgodMCdZfYms8dVapp4q24RswKY7hChXwrdnbyEFpfz26yVJh5h4zgBWiJ2nD8Qj3oGjjVNtyTFZFUrWQiYwwAfYdg"); + + u_assert_int_eq(hd_derive(&btc_chainparams_main, privkey, "m/1'", extout, extoutsize), true); + u_assert_str_eq(extout, "xprv9tzRNW1i8X1PSWBU8w1T7f8xCejSahmGsBLXi2XUqJPF7gLpn99mnuUK9jUKUP9hZbi5bbMCcHKi7MceLJ2ya3ArinuB3rDgcUnSzks1iWk"); + + u_assert_int_eq(hd_derive(&btc_chainparams_main, "xpub661MyMwAqRbcEnKbXcCqD2GT1di5zQxVqoHPAgHNe8dv5JP8gWmDproS6kFHJnLZd23tWevhdn4urGJ6b264DfTGKr8zjmYDjyDTi9U7iyT", "m/1", extout, extoutsize), true); + + u_assert_int_eq(hd_derive(&btc_chainparams_main, privkey, "m/", extout, extoutsize), true); + u_assert_str_eq(extout, privkey); + + u_assert_int_eq(hd_derive(&btc_chainparams_main, privkey, "m", extout, extoutsize), false); + u_assert_int_eq(hd_derive(&btc_chainparams_main, privkey, "n/1", extout, extoutsize), false); +} diff --git a/test/tx_tests.c b/test/tx_tests.c new file mode 100644 index 000000000..5970d66c6 --- /dev/null +++ b/test/tx_tests.c @@ -0,0 +1,1365 @@ +/********************************************************************** + * Copyright (c) 2015 Jonas Schnelli * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include "utest.h" +#include + +#include +#include + +struct txtest_sighash { + char sighash_sertx[10048]; // serialized transaction during sighash (debug) + char sertx[10048]; // serialized transaction + char script[1024]; // scriptPubKey + int i; // input index + uint64_t amount; // amount (SegWit) + char sighash[32 * 2 + 1]; // the expected sighash + int witness; // bool; used witness transaction digest algorithm (SIGVERSION_WITNESS_V0) +}; + +struct txtest_input { + char hash[32 * 2 + 1]; + uint32_t n; + char hexscript[2048]; +}; + +struct txtest { + int num_ins; + struct txtest_input inputs[10]; + char hextx[2048]; + char txtype[32]; +}; + +/* this are the tx_valid test vectors from Bitcoin Core 0.15, run through Bitcoin Core's SignatureHash function */ +static const struct txtest_sighash txvalid_sighash[] = { + { "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba2600000000087514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52aeffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac0000000001000000", "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52ae", 0, 0, "c21469f396d266507fd339292bd8ff0a6d4b29538b914265387a4d17e4839d25", 0}, + { "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba2600000000087514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52aeffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac0000000001000000", "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a0048304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2bab01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52ae", 0, 0, "c21469f396d266507fd339292bd8ff0a6d4b29538b914265387a4d17e4839d25", 0}, + { "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba2600000000087514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52aeffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac0000000001000000", "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a01ff47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52ae", 0, 0, "c21469f396d266507fd339292bd8ff0a6d4b29538b914265387a4d17e4839d25", 0}, + { "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba2600000000087514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52aeffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac0000000001000000", "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000495147304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52ae", 0, 0, "c21469f396d266507fd339292bd8ff0a6d4b29538b914265387a4d17e4839d25", 0}, + { "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba2600000000087514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52aeffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac0000000001000000", "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000494f47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52ae", 0, 0, "c21469f396d266507fd339292bd8ff0a6d4b29538b914265387a4d17e4839d25", 0}, + { "01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000001976a914dc44b1164188067c3a32d4780f5996fa14a4f2d988ac000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac0000000001000000", "01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000", "76a914dc44b1164188067c3a32d4780f5996fa14a4f2d988ac", 0, 0, "fa97d64d2b3b3cb86ee6776b211c658cede54d6488b4fa0c8591b491b4fd5638", 0}, + { "01000000010001000000000000000000000000000000000000000000000000000000000000000000001a76a9145b6462475454710f3c22f5fdf0b40704c92f25c388ad51ffffffff01000000000000000001510000000001000000", "01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "76a9145b6462475454710f3c22f5fdf0b40704c92f25c388ad51", 0, 0, "d173b431d7786bf0b8c92f3aae4d27d3e6b16f64b05a84644570a60ad0a19b58", 0}, + { "01000000010001000000000000000000000000000000000000000000000000000000000000000000006276a9145b6462475454710f3c22f5fdf0b40704c92f25c388ad51473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01ffffffff01000000000000000001510000000001000000", "01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "76a9145b6462475454710f3c22f5fdf0b40704c92f25c388ad51473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01", 0, 0, "0657f30ac19bd609d59212b82589373d2954f421acbc8d00618992b3af0ffd74", 0}, + { "01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000001976a914bef80ecf3a44500fda1bc92176e442891662aed288acffffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b70100000000ffffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac0000000001000000", "01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000", "76a914bef80ecf3a44500fda1bc92176e442891662aed288ac", 0, 0, "dcd0f937ba3b2b8d3542d2eaa7aeecaa039f4c5ec32d450497fccd5484b76008", 0}, + { "01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b40000000000ffffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000001976a914bef80ecf3a44500fda1bc92176e442891662aed288acffffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac0000000001000000", "01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000", "76a914bef80ecf3a44500fda1bc92176e442891662aed288ac", 1, 0, "8182430dba1b422cd25fdeb6bf6c0375ebe52093fed2cd1cab5d53be43b45bfe", 0}, + { "01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff01000000000000000001510000000001000000", "01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", "51", 0, 0, "b384078aea34dcc7c902801a5f143f8c1879cd47c6b334c89bcc125afb83d2bc", 0}, + { "010000000200020000000000000000000000000000000000000000000000000000000000000000000000ffffffff0001000000000000000000000000000000000000000000000000000000000000000000001976a914e52b482f2faa8ecbf0db344f93c84ac908557f3388acffffffff01000000000000000001510000000001000000", "01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", "76a914e52b482f2faa8ecbf0db344f93c84ac908557f3388ac", 1, 0, "f4232faa0bcb82b2b0c148caccdd46a83bd42a94c692a53c4b46dcbe618fd7dd", 0}, + { "010000000390d31c6107013d754529d8818eff285fe40a3e7635f6930fec5d12eb02107a43010000001976a914383fb81cb0a3fc724b5e08cf8bbd404336d711f688acffffffff3ff04a68e22bdd52e7c8cb848156d2d158bd5515b3c50adabc87d0ca2cd3482d0100000000ffffffff46a8dc8970eb96622f27a516adcf40e0fcec5731e7556e174f2a271aef6861c70100000000ffffffff028036be26000000001976a914ddfb29efad43a667465ac59ff14dc6442a1adfca88ac3d5cba01000000001976a914b64dde7a505a13ca986c40e86e984a8dc81368b688ac0000000001000000", "010000000390d31c6107013d754529d8818eff285fe40a3e7635f6930fec5d12eb02107a43010000006b483045022100f40815ae3c81a0dd851cc8d376d6fd226c88416671346a9033468cca2cdcc6c202204f764623903e6c4bed1b734b75d82c40f1725e4471a55ad4f51218f86130ac038321033d710ab45bb54ac99618ad23b3c1da661631aa25f23bfe9d22b41876f1d46e4effffffff3ff04a68e22bdd52e7c8cb848156d2d158bd5515b3c50adabc87d0ca2cd3482d010000006a4730440220598d263c107004008e9e26baa1e770be30fd31ee55ded1898f7c00da05a75977022045536bead322ca246779698b9c3df3003377090f41afeca7fb2ce9e328ec4af2832102b738b531def73020bd637f32935924cc88549c8206976226d968edd3a42fc2d7ffffffff46a8dc8970eb96622f27a516adcf40e0fcec5731e7556e174f2a271aef6861c7010000006b483045022100c5b90a777a9fdc90c208dbef7290d1fc1be651f47151ee4ccff646872a454cf90220640cfbc4550446968fbbe9d12528f3adf7d87b31541569c59e790db8a220482583210391332546e22bbe8fe3af54addfad6f8b83d05fa4f5e047593d4c07ae938795beffffffff028036be26000000001976a914ddfb29efad43a667465ac59ff14dc6442a1adfca88ac3d5cba01000000001976a914b64dde7a505a13ca986c40e86e984a8dc81368b688ac00000000", "76a914383fb81cb0a3fc724b5e08cf8bbd404336d711f688ac", 0, 0, "e20e77e4773a5f39e01cd69d276dc20e231d88ec9fc337456bbbe59f83cdf230", 0}, + { "010000000390d31c6107013d754529d8818eff285fe40a3e7635f6930fec5d12eb02107a430100000000ffffffff3ff04a68e22bdd52e7c8cb848156d2d158bd5515b3c50adabc87d0ca2cd3482d010000001976a914275ec2a233e5b23d43fa19e7bf9beb0cb399611788acffffffff46a8dc8970eb96622f27a516adcf40e0fcec5731e7556e174f2a271aef6861c70100000000ffffffff028036be26000000001976a914ddfb29efad43a667465ac59ff14dc6442a1adfca88ac3d5cba01000000001976a914b64dde7a505a13ca986c40e86e984a8dc81368b688ac0000000001000000", "010000000390d31c6107013d754529d8818eff285fe40a3e7635f6930fec5d12eb02107a43010000006b483045022100f40815ae3c81a0dd851cc8d376d6fd226c88416671346a9033468cca2cdcc6c202204f764623903e6c4bed1b734b75d82c40f1725e4471a55ad4f51218f86130ac038321033d710ab45bb54ac99618ad23b3c1da661631aa25f23bfe9d22b41876f1d46e4effffffff3ff04a68e22bdd52e7c8cb848156d2d158bd5515b3c50adabc87d0ca2cd3482d010000006a4730440220598d263c107004008e9e26baa1e770be30fd31ee55ded1898f7c00da05a75977022045536bead322ca246779698b9c3df3003377090f41afeca7fb2ce9e328ec4af2832102b738b531def73020bd637f32935924cc88549c8206976226d968edd3a42fc2d7ffffffff46a8dc8970eb96622f27a516adcf40e0fcec5731e7556e174f2a271aef6861c7010000006b483045022100c5b90a777a9fdc90c208dbef7290d1fc1be651f47151ee4ccff646872a454cf90220640cfbc4550446968fbbe9d12528f3adf7d87b31541569c59e790db8a220482583210391332546e22bbe8fe3af54addfad6f8b83d05fa4f5e047593d4c07ae938795beffffffff028036be26000000001976a914ddfb29efad43a667465ac59ff14dc6442a1adfca88ac3d5cba01000000001976a914b64dde7a505a13ca986c40e86e984a8dc81368b688ac00000000", "76a914275ec2a233e5b23d43fa19e7bf9beb0cb399611788ac", 1, 0, "ef6469919a352b43d24bf82427c28a431bd8fbb3cced5a911434a9e7365874d5", 0}, + { "010000000390d31c6107013d754529d8818eff285fe40a3e7635f6930fec5d12eb02107a430100000000ffffffff3ff04a68e22bdd52e7c8cb848156d2d158bd5515b3c50adabc87d0ca2cd3482d0100000000ffffffff46a8dc8970eb96622f27a516adcf40e0fcec5731e7556e174f2a271aef6861c7010000001976a91434fea2c5a75414fd945273ae2d029ce1f28dafcf88acffffffff028036be26000000001976a914ddfb29efad43a667465ac59ff14dc6442a1adfca88ac3d5cba01000000001976a914b64dde7a505a13ca986c40e86e984a8dc81368b688ac0000000001000000", "010000000390d31c6107013d754529d8818eff285fe40a3e7635f6930fec5d12eb02107a43010000006b483045022100f40815ae3c81a0dd851cc8d376d6fd226c88416671346a9033468cca2cdcc6c202204f764623903e6c4bed1b734b75d82c40f1725e4471a55ad4f51218f86130ac038321033d710ab45bb54ac99618ad23b3c1da661631aa25f23bfe9d22b41876f1d46e4effffffff3ff04a68e22bdd52e7c8cb848156d2d158bd5515b3c50adabc87d0ca2cd3482d010000006a4730440220598d263c107004008e9e26baa1e770be30fd31ee55ded1898f7c00da05a75977022045536bead322ca246779698b9c3df3003377090f41afeca7fb2ce9e328ec4af2832102b738b531def73020bd637f32935924cc88549c8206976226d968edd3a42fc2d7ffffffff46a8dc8970eb96622f27a516adcf40e0fcec5731e7556e174f2a271aef6861c7010000006b483045022100c5b90a777a9fdc90c208dbef7290d1fc1be651f47151ee4ccff646872a454cf90220640cfbc4550446968fbbe9d12528f3adf7d87b31541569c59e790db8a220482583210391332546e22bbe8fe3af54addfad6f8b83d05fa4f5e047593d4c07ae938795beffffffff028036be26000000001976a914ddfb29efad43a667465ac59ff14dc6442a1adfca88ac3d5cba01000000001976a914b64dde7a505a13ca986c40e86e984a8dc81368b688ac00000000", "76a91434fea2c5a75414fd945273ae2d029ce1f28dafcf88ac", 2, 0, "3147850f099c747971e26460122086b516bc3f2de474519a51323984e909e31b", 0}, + { "010000000100010000000000000000000000000000000000000000000000000000000000000000000017a9147a052c840ba73af26755de42cf01cc9e0a49fef087ffffffff01000000000000000001510000000001000000", "010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", "a9147a052c840ba73af26755de42cf01cc9e0a49fef087", 0, 0, "ffaa609cad18ced17c1e8cecc479b7a955879e601fa9a1e3e19d88e7c9855cc4", 0}, + { "010000000100010000000000000000000000000000000000000000000000000000000000000000000017a9148febbed40483661de6958d957412f82deed8e2f787ffffffff01000000000000000001510000000001000000", "01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000", "a9148febbed40483661de6958d957412f82deed8e2f787", 0, 0, "3c269ecef9a86532ea00a1d62a9075d18bdaa2b7c12c6abe7e859f220b897c40", 0}, + { "010000000100010000000000000000000000000000000000000000000000000000000000000000000017a91432afac281462b822adbec5094b8d4d337dd5bd6a87ffffffff010040075af075070001510000000001000000", "01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000", "a91432afac281462b822adbec5094b8d4d337dd5bd6a87", 0, 0, "d4e366729d81ed5bffa99a4df94dd5e095044f80c89955231e16d2dc1e58a284", 0}, + { "010000000100010000000000000000000000000000000000000000000000000000000000000000000017a914b558cbf4930954aa6a344363a15668d7477ae71687ffffffff020040075af07507000151000000000000000001510000000001000000", "01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510000000000000000015100000000", "a914b558cbf4930954aa6a344363a15668d7477ae71687", 0, 0, "5d32a6c90084090c2ed7d0ba08eaa912d0019d54efc7f00b801158341324bf75", 0}, + { "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0151ffffffff01000000000000000001510000000001000000", "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025151ffffffff010000000000000000015100000000", "51", 0, 0, "020b0855f1da9bd6e8530aa3d7b38bf14d231604716397d5ebc86789de637577", 0}, + { "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0151ffffffff01000000000000000001510000000001000000", "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6451515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", "51", 0, 0, "020b0855f1da9bd6e8530aa3d7b38bf14d231604716397d5ebc86789de637577", 0}, + { "01000000020001000000000000000000000000000000000000000000000000000000000000000000002321035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcacffffffff00020000000000000000000000000000000000000000000000000000000000000000000000ffffffff01010000000000000001510000000001000000", "010000000200010000000000000000000000000000000000000000000000000000000000000000000049483045022100d180fd2eb9140aeb4210c9204d3f358766eb53842b2a9473db687fa24b12a3cc022079781799cd4f038b85135bbe49ec2b57f306b2bb17101b17f71f000fcab2b6fb01ffffffff0002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", "21035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac", 0, 0, "cc2562dd136abb3494d151d8483a7984aa6d61f4fa1e7086f8e62e5d9c639bf6", 0}, + { "010000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0002000000000000000000000000000000000000000000000000000000000000000000002321035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcacffffffff01010000000000000001510000000001000000", "010000000200010000000000000000000000000000000000000000000000000000000000000000000049483045022100d180fd2eb9140aeb4210c9204d3f358766eb53842b2a9473db687fa24b12a3cc022079781799cd4f038b85135bbe49ec2b57f306b2bb17101b17f71f000fcab2b6fb01ffffffff0002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", "21035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac", 1, 0, "3622359ca6c0cf7d95226467c403e9eecdb896603b137fa093f78e4ecb5b7b00", 0}, + { "01000000020001000000000000000000000000000000000000000000000000000000000000000000002321035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac0100000000020000000000000000000000000000000000000000000000000000000000000000000000ffffffff01010000000000000001510000000001000000", "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", "21035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac", 0, 0, "8634e5a9ec43f3b8ae46ad3cef55c61d14c709abf83d03d278dc3fb02a39ad64", 0}, + { "010000000200010000000000000000000000000000000000000000000000000000000000000000000000010000000002000000000000000000000000000000000000000000000000000000000000000000002321035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcacffffffff01010000000000000001510000000001000000", "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", "21035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efcac", 1, 0, "355be40d833aa6bb0bf73e44bb1e66e8468d501b5010b344cec2b0fa0342c66e", 0}, + { "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000001976a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88acffffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e8040100000000ffffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee0100000000ffffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac0000000001000000", "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000", "76a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88ac", 0, 0, "0387d5e3b6ccad57c9a05b8945d2e76c3a57a01d79cbded56983e36671a51efb", 0}, + { "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf630000000000ffffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000001976a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88acffffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee0100000000ffffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac0000000001000000", "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000", "76a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88ac", 1, 0, "3c4ec475118e74f02fe89562b4b6a2e6fe8d51b6c3534b87dcbb4f52730c38b3", 0}, + { "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf630000000000ffffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e8040100000000ffffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000001976a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88acffffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac0000000001000000", "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000", "76a914dcf72c4fd02f5a987cf9b02f2fabfcac3341a87d88ac", 2, 0, "7c88e71dd479bfee1fe6e5b19cde850c33a52da61a08b686c72a6e78012ac33b", 0}, + { "0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c500000000ca4cae606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e2074607576a914bfd7436b6265aa9de506f8a994f881ff08cc287288acffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac0000000001000000", "0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c5000000008b483045022100bf0bbae9bde51ad2b222e87fbf67530fbafc25c903519a1e5dcc52a32ff5844e022028c4d9ad49b006dd59974372a54291d5764be541574bb0c4dc208ec51f80b7190141049dd4aad62741dc27d5f267f7b70682eee22e7e9c1923b9c0957bdae0b96374569b460eb8d5b40d972e8c7c0ad441de3d94c4a29864b212d56050acb980b72b2bffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac00000000", "4cae606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e2074607576a914bfd7436b6265aa9de506f8a994f881ff08cc287288ac", 0, 0, "d1e6ea4ecf6cf7cfdeda9ae912ec519a79fcf2fea96ace34a10e0b77264e2ea4", 0}, + { "01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab30000000017a914b1ce99298d5f07364b57b1e5c9cc00be0b04a95487ffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac0000000001000000", "01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe0000483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa0148304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f4014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", "a914b1ce99298d5f07364b57b1e5c9cc00be0b04a95487", 0, 0, "5ca48999d397072753891d3ccb8770f88bed457b66206570ed3817e7955bc962", 0}, + { "0100000001f709fa82596e4f908ee331cb5e0ed46ab331d7dcfaf697fe95891e73dac4ebcb00000000b52102085c6600657566acc2d6382a47bc3f324008d2aa10940dd7705a48aa2a5a5e33ac7c2103f5d0fb955f95dd6be6115ce85661db412ec6a08abcbfce7da0ba8297c6cc0ec4ac7c5379a820d68df9e32a147cffa36193c6f7c43a1c8c69cda530e1c6db354bfabdcfefaf3c875379a820f531f3041d3136701ea09067c53e7159c8f9b2746a56c3d82966c54bbc553226879a5479827701200122a59a5379827701200122a59a6353798277537982778779679a68ffffffff01c075790000000000232103611f9a45c18f28f06f19076ad571c344c82ce8fcfe34464cf8085217a2d294a6ac0000000001000000", "0100000001f709fa82596e4f908ee331cb5e0ed46ab331d7dcfaf697fe95891e73dac4ebcb000000008c20ca42095840735e89283fec298e62ac2ddea9b5f34a8cbb7097ad965b87568100201b1b01dc829177da4a14551d2fc96a9db00c6501edfa12f22cd9cefd335c227f483045022100a9df60536df5733dd0de6bc921fab0b3eee6426501b43a228afa2c90072eb5ca02201c78b74266fac7d1db5deff080d8a403743203f109fbcabf6d5a760bf87386d20100ffffffff01c075790000000000232103611f9a45c18f28f06f19076ad571c344c82ce8fcfe34464cf8085217a2d294a6ac00000000", "2102085c6600657566acc2d6382a47bc3f324008d2aa10940dd7705a48aa2a5a5e33ac7c2103f5d0fb955f95dd6be6115ce85661db412ec6a08abcbfce7da0ba8297c6cc0ec4ac7c5379a820d68df9e32a147cffa36193c6f7c43a1c8c69cda530e1c6db354bfabdcfefaf3c875379a820f531f3041d3136701ea09067c53e7159c8f9b2746a56c3d82966c54bbc553226879a5479827701200122a59a5379827701200122a59a6353798277537982778779679a68", 0, 0, "6388c00bf863571ee96a0d119937fdb058d34f9e27cf70269f67ec7664d19347", 0}, + { "01000000012c651178faca83be0b81c8c1375c4b0ad38d53c8fe1b1c4255f5e795c2579222000000000300ac91ffffffff010100000000000000232102c2410f8891ae918cab4ffc4bb4a3b0881be67c7a1e7faa8b5acf9ab8932ec30cac0000000001000000", "01000000012c651178faca83be0b81c8c1375c4b0ad38d53c8fe1b1c4255f5e795c25792220000000049483045022100d6044562284ac76c985018fc4a90127847708c9edb280996c507b28babdc4b2a02203d74eca3f1a4d1eea7ff77b528fde6d5dc324ec2dbfdb964ba885f643b9704cd01ffffffff010100000000000000232102c2410f8891ae918cab4ffc4bb4a3b0881be67c7a1e7faa8b5acf9ab8932ec30cac00000000", "00ac91", 0, 0, "b27e976e5b9fe49e036506f4530ad0d46bbb35ea626be591972ca61a322daee4", 0}, + { "0100000001f725ea148d92096a79b1709611e06e94c63c4ef61cbae2d9b906388efd3ca99c000000002421028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02ac91ffffffff0101000000000000002321028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02ac0000000001000000", "0100000001f725ea148d92096a79b1709611e06e94c63c4ef61cbae2d9b906388efd3ca99c000000000100ffffffff0101000000000000002321028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02ac00000000", "21028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02ac91", 0, 0, "12c120e38f8a55fb4345be84efbc9d99c54d06702372d426c5e9b53a3d8df3b4", 0}, + { "0100000001be599efaa4148474053c2fa031c7262398913f1dc1d9ec201fd44078ed004e44000000002651002102136b04758b0b6e363e7a6fbe83aaf527a153db2b060d36cc29f7f8309ba6e45852aeffffffff010100000000000000232103ac4bba7e7ca3e873eea49e08132ad30c7f03640b6539e9b59903cf14fd016bbbac0000000001000000", "0100000001be599efaa4148474053c2fa031c7262398913f1dc1d9ec201fd44078ed004e44000000004900473044022022b29706cb2ed9ef0cb3c97b72677ca2dfd7b4160f7b4beb3ba806aa856c401502202d1e52582412eba2ed474f1f437a427640306fd3838725fab173ade7fe4eae4a01ffffffff010100000000000000232103ac4bba7e7ca3e873eea49e08132ad30c7f03640b6539e9b59903cf14fd016bbbac00000000", "51002102136b04758b0b6e363e7a6fbe83aaf527a153db2b060d36cc29f7f8309ba6e45852ae", 0, 0, "9dedb5ccf676e65436ef680208e9cb6e47b1d747f05a036f836d200b252d308e", 0}, + { "010000000112b66d5e8c7d224059e946749508efea9d66bf8d0c83630f080cf30be8bb6ae10000000026512103905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9f0052aeffffffff010100000000000000232103905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9fac0000000001000000", "010000000112b66d5e8c7d224059e946749508efea9d66bf8d0c83630f080cf30be8bb6ae100000000490047304402206ffe3f14caf38ad5c1544428e99da76ffa5455675ec8d9780fac215ca17953520220779502985e194d84baa36b9bd40a0dbd981163fa191eb884ae83fc5bd1c86b1101ffffffff010100000000000000232103905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9fac00000000", "512103905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9f0052ae", 0, 0, "630463341c94f250d8bb345984da8e390208a3f989b25382a9a962b58678e788", 0}, + { "0100000001b0ef70cc644e0d37407e387e73bfad598d852a5aa6d691d72b2913cebff4bceb00000000485221033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af041942103a88b326f8767f4f192ce252afe33c94d25ab1d24f27f159b3cb3aa691ffe142352ae91ffffffff0101000000000000002321033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194ac0000000001000000", "0100000001b0ef70cc644e0d37407e387e73bfad598d852a5aa6d691d72b2913cebff4bceb000000004a00473044022068cd4851fc7f9a892ab910df7a24e616f293bcb5c5fbdfbc304a194b26b60fba022078e6da13d8cb881a22939b952c24f88b97afd06b4c47a47d7f804c9a352a6d6d0100ffffffff0101000000000000002321033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194ac00000000", "5221033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af041942103a88b326f8767f4f192ce252afe33c94d25ab1d24f27f159b3cb3aa691ffe142352ae91", 0, 0, "519417300901d4221c197d60ca7952530e3dd11e8b11c611deca30d71bdcf811", 0}, + { "0100000001c188aa82f268fcf08ba18950f263654a3ea6931dabc8bf3ed1d4d42aaed74cba00000000485221037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe12102edc823cd634f2c4033d94f5755207cb6b60c4b1f1f056ad7471c47de5f2e4d5052ae91ffffffff0101000000000000002321037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1ac0000000001000000", "0100000001c188aa82f268fcf08ba18950f263654a3ea6931dabc8bf3ed1d4d42aaed74cba000000004b0000483045022100940378576e069aca261a6b26fb38344e4497ca6751bb10905c76bb689f4222b002204833806b014c26fd801727b792b1260003c55710f87c5adbd7a9cb57446dbc9801ffffffff0101000000000000002321037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1ac00000000", "5221037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe12102edc823cd634f2c4033d94f5755207cb6b60c4b1f1f056ad7471c47de5f2e4d5052ae91", 0, 0, "66f6496afcc050eb10b2d0d45f605ed2083fd5e60380408fcbcbe1927fda81ac", 0}, + { "01000000012432b60dc72cebc1a27ce0969c0989c895bdd9e62e8234839117f8fc32d17fbc000000002321038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041acffffffff010000000000000000016a0000000001000000", "01000000012432b60dc72cebc1a27ce0969c0989c895bdd9e62e8234839117f8fc32d17fbc000000004a493046022100a576b52051962c25e642c0fd3d77ee6c92487048e5d90818bcf5b51abaccd7900221008204f8fb121be4ec3b24483b1f92d89b1b0548513a134e345c5442e86e8617a501ffffffff010000000000000000016a00000000", "ab21038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac", 0, 0, "2820037610ca45e1d691606b928cdb864b05e0f5214b3b474068a43be6846fd7", 0}, + { "01000000014710b0e7cf9f8930de259bdc4b84aa5dfb9437b665a3e3a21ff26e0bf994e183000000002321038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041acffffffff010000000000000000016a0000000001000000", "01000000014710b0e7cf9f8930de259bdc4b84aa5dfb9437b665a3e3a21ff26e0bf994e183000000004a493046022100a166121a61b4eeb19d8f922b978ff6ab58ead8a5a5552bf9be73dc9c156873ea02210092ad9bc43ee647da4f6652c320800debcf08ec20a094a0aaf085f63ecb37a17201ffffffff010000000000000000016a00000000", "abab21038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac", 0, 0, "e03b1bb5cff4e465c1e446ce0ff172307b976a1dcfef1005c3b5d62870c6ce6c", 0}, + { "01000000015ebaa001d8e4ec7a88703a3bcf69d98c874bca6299cca0f191512bf2a7826832000000002321038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041acffffffff010000000000000000016a0000000001000000", "01000000015ebaa001d8e4ec7a88703a3bcf69d98c874bca6299cca0f191512bf2a7826832000000004948304502203bf754d1c6732fbf87c5dcd81258aefd30f2060d7bd8ac4a5696f7927091dad1022100f5bcb726c4cf5ed0ed34cc13dadeedf628ae1045b7cb34421bc60b89f4cecae701ffffffff010000000000000000016a00000000", "21038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041abac", 0, 0, "a6b4f388729dbb317ba3418bb99db80e75e38f3b60bacc0a202f1d5397b4baf1", 0}, + { "010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004721038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ad21038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ad51ffffffff010000000000000000016a0000000001000000", "010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a900000000924830450221009c0a27f886a1d8cb87f6f595fbc3163d28f7a81ec3c4b252ee7f3ac77fd13ffa02203caa8dfa09713c8c4d7ef575c75ed97812072405d932bd11e6a1593a98b679370148304502201e3861ef39a526406bad1e20ecad06be7375ad40ddb582c9be42d26c3a0d7b240221009d0a3985e96522e59635d19cc4448547477396ce0ef17a58e7d74c3ef464292301ffffffff010000000000000000016a00000000", "21038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041adab21038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041adab51", 0, 0, "8596bf48192c07b08069259f2a30eb73a17aa2286642aa84ea9e00a61281f93d", 0}, + { "010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a900000000266368210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71ad51ffffffff010000000000000000016a0000000001000000", "010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a48304502207a6974a77c591fa13dff60cabbb85a0de9e025c09c65a4b2285e47ce8e22f761022100f0efaac9ff8ac36b10721e0aae1fb975c90500b50c56e8a0cc52b0403f0425dd0100ffffffff010000000000000000016a00000000", "63ab68210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71adab51", 0, 0, "1a3285b12207936ff9043c78e96771193f9cc80a8dc028cca27b610413084852", 0}, + { "010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a900000000266368210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71ad51ffffffff010000000000000000016a0000000001000000", "010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a483045022100fa4a74ba9fd59c59f46c3960cf90cbe0d2b743c471d24a3d5d6db6002af5eebb02204d70ec490fd0f7055a7c45f86514336e3a7f03503dacecabb247fc23f15c83510151ffffffff010000000000000000016a00000000", "63ab68210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71adab51", 0, 0, "1a3285b12207936ff9043c78e96771193f9cc80a8dc028cca27b610413084852", 0}, + { "0100000001e0be9e32f1f89c3d916c4f21e55cdcd096741b895cc76ac353e6023a05f4f7cc000000001976a914ee5a6aa40facefb2655ac23c0c28c57c65c41f9b88acffffffff010000000000000000016a0000000001000000", "0100000001e0be9e32f1f89c3d916c4f21e55cdcd096741b895cc76ac353e6023a05f4f7cc00000000d86149304602210086e5f736a2c3622ebb62bd9d93d8e5d76508b98be922b97160edc3dcca6d8c47022100b23c312ac232a4473f19d2aeb95ab7bdf2b65518911a0d72d50e38b5dd31dc820121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac4730440220508fa761865c8abd81244a168392876ee1d94e8ed83897066b5e2df2400dad24022043f5ee7538e87e9c6aef7ef55133d3e51da7cc522830a9c4d736977a76ef755c0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "76a914ee5a6aa40facefb2655ac23c0c28c57c65c41f9b88ac", 0, 0, "7c16006be7e0a534fdbee124da43446aff225d6ac62513e0da8e7756b87ec467", 0}, + { "01000000013c6f30f99a5161e75a2ce4bca488300ca0c6112bde67f0807fe983feeff0c910010000001976a914ee5a6aa40facefb2655ac23c0c28c57c65c41f9b88acffffffff010000000000000000016a0000000001000000", "01000000013c6f30f99a5161e75a2ce4bca488300ca0c6112bde67f0807fe983feeff0c91001000000e608646561646265656675ab61493046022100ce18d384221a731c993939015e3d1bcebafb16e8c0b5b5d14097ec8177ae6f28022100bcab227af90bab33c3fe0a9abfee03ba976ee25dc6ce542526e9b2e56e14b7f10121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac493046022100c3b93edcc0fd6250eb32f2dd8a0bba1754b0f6c3be8ed4100ed582f3db73eba2022100bf75b5bd2eff4d6bf2bda2e34a40fcc07d4aa3cf862ceaa77b47b81eff829f9a01ab21038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "76a914ee5a6aa40facefb2655ac23c0c28c57c65c41f9b88ac", 0, 0, "f1a86fd8723956f88142d57b5aa2bed3107a539f9faa88046418b3192d88ccd4", 0}, + { "01000000016f3dbe2ca96fa217e94b1017860be49f20820dea5c91bdcb103b0049d5eb5660000000001976a914ee5a6aa40facefb2655ac23c0c28c57c65c41f9b88acffffffff010000000000000000016a0000000001000000", "01000000016f3dbe2ca96fa217e94b1017860be49f20820dea5c91bdcb103b0049d5eb566000000000fd1d0147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac47304402203757e937ba807e4a5da8534c17f9d121176056406a6465054bdd260457515c1a02200f02eccf1bec0f3a0d65df37889143c2e88ab7acec61a7b6f5aa264139141a2b0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "76a914ee5a6aa40facefb2655ac23c0c28c57c65c41f9b88ac", 0, 0, "75ed6124bc473c381bc23522e4891bdfc71ecc17daabe3b716b182feeae8ba39", 0}, + { "01000000012139c555ccb81ee5b1e87477840991ef7b386bc3ab946b6b682a04a621006b5a010000001976a914ee5a6aa40facefb2655ac23c0c28c57c65c41f9b88acffffffff010000000000000000016a0000000001000000", "01000000012139c555ccb81ee5b1e87477840991ef7b386bc3ab946b6b682a04a621006b5a01000000fdb40148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f2204148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390175ac4830450220646b72c35beeec51f4d5bc1cbae01863825750d7f490864af354e6ea4f625e9c022100f04b98432df3a9641719dbced53393022e7249fb59db993af1118539830aab870148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a580039017521038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "76a914ee5a6aa40facefb2655ac23c0c28c57c65c41f9b88ac", 0, 0, "82bd02352411f56497d22a0c4c39543aa90790aea66a6ae9e8273f98b62c9125", 0}, + { "0100000002f9cbafc519425637ba4227f8d0a0b7160b4e65168193d5af39747891de98b5b5000000001976a914f6f365c40f0739b61de827a44751e5e99032ed8f88acffffffff42e7988254800876b69f24676b3e0205b77be476512ca4d970707dd5c60598ab0000000000ffffffff01a08601000000000017a914d8dacdadb7462ae15cd906f1878706d0da8660e6870000000001000000", "0100000002f9cbafc519425637ba4227f8d0a0b7160b4e65168193d5af39747891de98b5b5000000006b4830450221008dd619c563e527c47d9bd53534a770b102e40faa87f61433580e04e271ef2f960220029886434e18122b53d5decd25f1f4acb2480659fea20aabd856987ba3c3907e0121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffff42e7988254800876b69f24676b3e0205b77be476512ca4d970707dd5c60598ab00000000fd260100483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a53034930460221008431bdfa72bc67f9d41fe72e94c88fb8f359ffa30b33c72c121c5a877d922e1002210089ef5fc22dd8bfc6bf9ffdb01a9862d27687d424d1fefbab9e9c7176844a187a014c9052483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c7153aeffffffff01a08601000000000017a914d8dacdadb7462ae15cd906f1878706d0da8660e68700000000", "76a914f6f365c40f0739b61de827a44751e5e99032ed8f88ac", 0, 0, "542f9a298626b650f7e7f5111b2d3bb831c3efc58de294ea65e0331ef1245944", 0}, + { "0100000002f9cbafc519425637ba4227f8d0a0b7160b4e65168193d5af39747891de98b5b50000000000ffffffff42e7988254800876b69f24676b3e0205b77be476512ca4d970707dd5c60598ab0000000017a914d8dacdadb7462ae15cd906f1878706d0da8660e687ffffffff01a08601000000000017a914d8dacdadb7462ae15cd906f1878706d0da8660e6870000000001000000", "0100000002f9cbafc519425637ba4227f8d0a0b7160b4e65168193d5af39747891de98b5b5000000006b4830450221008dd619c563e527c47d9bd53534a770b102e40faa87f61433580e04e271ef2f960220029886434e18122b53d5decd25f1f4acb2480659fea20aabd856987ba3c3907e0121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffff42e7988254800876b69f24676b3e0205b77be476512ca4d970707dd5c60598ab00000000fd260100483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a53034930460221008431bdfa72bc67f9d41fe72e94c88fb8f359ffa30b33c72c121c5a877d922e1002210089ef5fc22dd8bfc6bf9ffdb01a9862d27687d424d1fefbab9e9c7176844a187a014c9052483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c7153aeffffffff01a08601000000000017a914d8dacdadb7462ae15cd906f1878706d0da8660e68700000000", "a914d8dacdadb7462ae15cd906f1878706d0da8660e687", 1, 0, "1b43cb521a15b4e26e2ea8ba6a6eae30806a63a2eaaf77f6856b60289e8b8cb2", 0}, + { "0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000001976a914f6f365c40f0739b61de827a44751e5e99032ed8f88acffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce0100000000ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac0000000001000000", "0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000", "76a914f6f365c40f0739b61de827a44751e5e99032ed8f88ac", 0, 0, "cb4f4adc3da0a54f5892c1e40ec0bac834d37102f733a55c72d2de3a548f7665", 0}, + { "0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce0000000000ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009052483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c7153aeffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac0000000001000000", "0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000", "52483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c7153ae", 1, 0, "51af5bd4718c186561b35016ddccbaee302f9b814ccdfb7780f1b0f6748deeb1", 0}, + { "01000000010001000000000000000000000000000000000000000000000000000000000000000000000300b15100000000010000000000000000000000000001000000", "010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "00b151", 0, 0, "9521b84cdd30997504fd5fb7d6d7af65fe9614be1e7e0b89e8522145dcea70fc", 0}, + { "01000000010001000000000000000000000000000000000000000000000000000000000000000000000704ff64cd1db1510000000001000000000000000000ff64cd1d01000000", "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "04ff64cd1db151", 0, 0, "dd8bdcd78c05914a57c6033d335ba6ca1df2f4cc8b5172dd4cf0b432be1bd24c", 0}, + { "01000000010001000000000000000000000000000000000000000000000000000000000000000000000300b1510000000001000000000000000000ff64cd1d01000000", "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "00b151", 0, 0, "05751dd868560a451b6b402d84993393347104de1a077dff19ca24ecd7d7eedd", 0}, + { "010000000100010000000000000000000000000000000000000000000000000000000000000000000007040065cd1db15100000000010000000000000000000065cd1d01000000", "01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "040065cd1db151", 0, 0, "5cc399a83be43c43474229b3f89f34510d4ce8d55eb3313a9c6b44ee774f3068", 0}, + { "01000000010001000000000000000000000000000000000000000000000000000000000000000000000805ffffffff00b1510000000001000000000000000000ffffffff01000000", "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "05ffffffff00b151", 0, 0, "c2d81b118c2ebd4a3a4727c7ba801f15fac4a84bdeb6bc1c8cd907d8713b4044", 0}, + { "010000000100010000000000000000000000000000000000000000000000000000000000000000000007040065cd1db1510000000001000000000000000000ffffffff01000000", "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "040065cd1db151", 0, 0, "4e3e0bffe85f5eadd14444510dded1f6ff373b9cdf3166ed01dccbb217f0c120", 0}, + { "01000000010001000000000000000000000000000000000000000000000000000000000000000000000300b151feffffff010000000000000000000000000001000000", "010000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "00b151", 0, 0, "55d7b5a152aa91b3b559b3964bf909ef838bd824cdcd4231d19b703240b092d8", 0}, + { "01000000010001000000000000000000000000000000000000000000000000000000000000000000000804ff64cd1d8bb15100000000010000000000000000000065cd1d01000000", "01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "04ff64cd1d8bb151", 0, 0, "22fb197022c0d0e4d8a937261b087becbac1c4436fba1b360e4f7e00beade9b5", 0}, + { "01000000010001000000000000000000000000000000000000000000000000000000000000000000000d04ffffff7f04ffffff7f93b1510000000001000000000000000000feffffff01000000", "0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "04ffffff7f04ffffff7f93b151", 0, 0, "7e7e7e67a115af7894aa0ba899a47d641b9cc217339bb72498a7c26be6fc803a", 0}, + { "010000000100010000000000000000000000000000000000000000000000000000000000000000000008050000000000b15100000000010000000000000000000000000001000000", "010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "050000000000b151", 0, 0, "0351e800af82b27f6e1fd2eed93b09f328ed5af4ffdf61ad9c3c6100ec00d330", 0}, + { "0100000001000100000000000000000000000000000000000000000000000000000000000000000000015100000000010000000000000000000100000001000000", "01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1000000000100000000000000000001000000", "51", 0, 0, "c08f4c420d047a687241fc169a1cfdb4787ed1be282ec64908d5431292601eac", 0}, + { "010000000100010000000000000000000000000000000000000000000000000000000000000000000017a914c5b93064159b3b2d6ab506a41b1f50463771b9888700000000010000000000000000000100000001000000", "0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000001000000", "a914c5b93064159b3b2d6ab506a41b1f50463771b98887", 0, 0, "53b2ee008a6442fef371f32274e5e4bd3078b92d31436cd816645af7acdf7880", 0}, + { "010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000001976a9144b3bd7eba3bc0284fd3007be7f3be275e94f582688acffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac0000000001000000", "010000000132211bdd0d568506804eef0d8cc3db68c3d766ab9306cdfcc0a9c89616c8dbb1000000006c493045022100c7bb0faea0522e74ff220c20c022d2cb6033f8d167fb89e75a50e237a35fd6d202203064713491b1f8ad5f79e623d0219ad32510bfaa1009ab30cbee77b59317d6e30001210237af13eb2d84e4545af287b919c2282019c9691cc509e78e196a9d8274ed1be0ffffffff0100000000000000001976a914f1b3ed2eda9a2ebe5a9374f692877cdf87c0f95b88ac00000000", "76a9144b3bd7eba3bc0284fd3007be7f3be275e94f582688ac", 0, 0, "b81d5bb751e20792b4d3dd61a3d38f0b84a249d978a874cf4d55c71984dfaea6", 0}, + { "02000000010001000000000000000000000000000000000000000000000000000000000000000000000300b25100000000010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "00b251", 0, 0, "6b077d438b7793cc4d1d2486a34152d07d5061332332979a1e3f30ba89d9a058", 0}, + { "02000000010001000000000000000000000000000000000000000000000000000000000000000000000603ffff00b251ffff0000010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "03ffff00b251", 0, 0, "8ee809453c60181e6c7355a1484e4427046ebe4fa2a24ca1bcd73a2603a3b556", 0}, + { "02000000010001000000000000000000000000000000000000000000000000000000000000000000000603ffff00b251ffffbf7f010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "03ffff00b251", 0, 0, "651e985fe8ace5cf67dcdbe65d936a337b70f7356f9238be1801f5794822c9e9", 0}, + { "02000000010001000000000000000000000000000000000000000000000000000000000000000000000300b251ffffbf7f010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "00b251", 0, 0, "d7695df7e237a42441630f433e6e28dcb261bc42226cceb94e7b75e5f1f7d3f3", 0}, + { "02000000010001000000000000000000000000000000000000000000000000000000000000000000000603000040b25100004000010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "03000040b251", 0, 0, "d7816b5928a222a38915ab76d25947e3041b1aa38f94611ff81e0061869ba6e7", 0}, + { "02000000010001000000000000000000000000000000000000000000000000000000000000000000000603ffff40b251ffff4000010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff40000100000000000000000000000000", "03ffff40b251", 0, 0, "2fec97e97ffb45f622e0e1b2ce2d368ef04ac39d34b6623b3a5259d35326706d", 0}, + { "02000000010001000000000000000000000000000000000000000000000000000000000000000000000603ffff40b251ffffff7f010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "03ffff40b251", 0, 0, "26a649ca2b9aa2d0492db558a011a541d79609ac0be7d2072cd7f980654c0937", 0}, + { "02000000010001000000000000000000000000000000000000000000000000000000000000000000000603000040b251ffffff7f010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "03000040b251", 0, 0, "1d4b6d93ef9acfa62bcaec312758f7b084c26916187e87d2e6c17f36fe7d2fce", 0}, + { "020000000100010000000000000000000000000000000000000000000000000000000000000000000008050000008000b25100000080010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "050000008000b251", 0, 0, "b28cbdbec32dad2702bd294f95bf1e78ebce5547bde739581402681b15e3b345", 0}, + { "02000000010001000000000000000000000000000000000000000000000000000000000000000000000805ffffffff00b25100000080010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000", "05ffffffff00b251", 0, 0, "b3edb073db12dfd66a5b3fc7b5ca77d38c453b3a3e9b3dcc876abeb0c2401d52", 0}, + { "020000000100010000000000000000000000000000000000000000000000000000000000000000000008050000008000b251feffffff010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "050000008000b251", 0, 0, "d2b179286ee2476e1d818653fe854cff642795d3145536189d2c8b0281146430", 0}, + { "02000000010001000000000000000000000000000000000000000000000000000000000000000000000805ffffffff00b251feffffff010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "05ffffffff00b251", 0, 0, "9cb1f1b00514f17897da4102c204d5f15efb49a28ad2e88b23c33b8612e1324a", 0}, + { "020000000100010000000000000000000000000000000000000000000000000000000000000000000008050000008000b251ffffffff010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "050000008000b251", 0, 0, "9e0283aca3d968911bff6b765cd04b0808bc10c5714e4a263efeb2c53870e70b", 0}, + { "02000000010001000000000000000000000000000000000000000000000000000000000000000000000805ffffffff00b251ffffffff010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "05ffffffff00b251", 0, 0, "51ed42f2942a4d080099a41ab999c5197ec956b9c175854df8556b7ff30e1d3e", 0}, + { "020000000100010000000000000000000000000000000000000000000000000000000000000000000008050000008000b251ffffbf7f010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "050000008000b251", 0, 0, "d8a4a39155ad2672212bd685a9662bb5edc7ead5f78c2a6bfa77919e54af114d", 0}, + { "020000000100010000000000000000000000000000000000000000000000000000000000000000000008050000008000b251ffffff7f010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "050000008000b251", 0, 0, "7ce267a3adfabdb52658645280bcb76b3c739e2041a21f938acd16b53132f9cb", 0}, + { "020000000100010000000000000000000000000000000000000000000000000000000000000000000008050000008000b251ffffffff010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "050000008000b251", 0, 0, "9e0283aca3d968911bff6b765cd04b0808bc10c5714e4a263efeb2c53870e70b", 0}, + { "02000000010001000000000000000000000000000000000000000000000000000000000000000000000805ffffffff00b251ffffbf7f010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "05ffffffff00b251", 0, 0, "2129be03c4ee5418480f634e78d11c24e45600fbb95939191ab448aa8d68bb0d", 0}, + { "02000000010001000000000000000000000000000000000000000000000000000000000000000000000805ffffffff00b251ffffff7f010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "05ffffffff00b251", 0, 0, "5ed98bd48b85874c8a9494c9200652c58ba1416256116b20597a4d373ae978f8", 0}, + { "02000000010001000000000000000000000000000000000000000000000000000000000000000000000805ffffffff00b251ffffffff010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "05ffffffff00b251", 0, 0, "51ed42f2942a4d080099a41ab999c5197ec956b9c175854df8556b7ff30e1d3e", 0}, + { "020000000100010000000000000000000000000000000000000000000000000000000000000000000008050000008001b251ffffbf7f010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffbf7f0100000000000000000000000000", "050000008001b251", 0, 0, "56ef179ac6d5cba99c9e29df1fdf0f1abfff9cfc17fd11003a509c4dde7e0856", 0}, + { "020000000100010000000000000000000000000000000000000000000000000000000000000000000008050000008001b251ffffff7f010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffff7f0100000000000000000000000000", "050000008001b251", 0, 0, "8d143c8c0e37169b19c192203a4fdefed960875cc2efd9f11cef926d42a0911a", 0}, + { "020000000100010000000000000000000000000000000000000000000000000000000000000000000008050000008001b251ffffffff010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "050000008001b251", 0, 0, "dadcedb44965f11466d232912932c370d7e02ed3e76db2ef6f0b22edeb1681cc", 0}, + { "020000000100010000000000000000000000000000000000000000000000000000000000000000000008050000000000b25100000000010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "050000000000b251", 0, 0, "c6812f7cab7a7e0e791d05a6526e43ba873fac30b4d587c15f6cc1ae4878c9e5", 0}, + { "02000000010001000000000000000000000000000000000000000000000000000000000000000000000703ffff3f8bb25100004000010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "03ffff3f8bb251", 0, 0, "d95e733825c5f1104a5730e72f403b109cb49b9fb0541ed58a4dc0ebf16c5146", 0}, + { "020000000100010000000000000000000000000000000000000000000000000000000000000000000007030000408cb251ffff0000010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000ffff00000100000000000000000000000000", "030000408cb251", 0, 0, "4a6cf74076204e618507d50d7f111a2feae171011a26736ce7e4423429ac07ff", 0}, + { "02000000010001000000000000000000000000000000000000000000000000000000000000000000000b04ffffff7f03000001b25100000000010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "04ffffff7f03000001b251", 0, 0, "f1b6a4bfe5d78daa4542e35bf90782f06d92e27d7be3cafbb0bbc13a5eb67d85", 0}, + { "02000000010001000000000000000000000000000000000000000000000000000000000000000000000c04ffffff7f0300004193b25100004000010000000000000000000000000001000000", "020000000100010000000000000000000000000000000000000000000000000000000000000000000000000040000100000000000000000000000000", "04ffffff7f0300004193b251", 0, 0, "d5dc4b1dd96c5acf547a16f0aa8bf95c068f26c653de8111c111fe45900a3cd6", 0}, + { "0200000001000100000000000000000000000000000000000000000000000000000000000000000000015101000000010000000000000000000000000001000000", "02000000010001000000000000000000000000000000000000000000000000000000000000000000000251b2010000000100000000000000000000000000", "51", 0, 0, "fc402c5ce4bd16c7e3c1bff7c44ddad843527e5f8866b2a89418c6a8282e970f", 0}, + { "020000000100010000000000000000000000000000000000000000000000000000000000000000000017a9147c17aff532f22beb54069942f9bf567a66133eaf8701000000010000000000000000000000000001000000", "0200000001000100000000000000000000000000000000000000000000000000000000000000000000030251b2010000000100000000000000000000000000", "a9147c17aff532f22beb54069942f9bf567a66133eaf87", 0, 0, "1b927f5991e23fa6504eee83b749f9788ed40b7eb0f8833e87f60631e472eb9e", 0}, + { "010000007495d50732e62d65f11068892370d8b68a2cbd2e0c80be8c67e099a1ef0d7bee3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e706650440001000000000000000000000000000000000000000000000000000000000000000000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fe803000000000000ffffffff0000000001000000", "0100000000010100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff01e8030000000000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac02483045022100cfb07164b36ba64c1b1e8c7720a56ad64d96f6ef332d3d37f9cb3c96477dc44502200a464cd7a9cf94cd70f66ce4f4f0625ef650052c7afcfe29d7d7e01830ff91ed012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 0, 1000, "fa6153bdac89f1cfbe5f64b1d7097ee011f81342b6b3772648d16eeda4362654", 1}, + { "010000007495d50732e62d65f11068892370d8b68a2cbd2e0c80be8c67e099a1ef0d7bee3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044000100000000000000000000000000000000000000000000000000000000000000000000220020ff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3dbe803000000000000ffffffff0000000001000000", "0100000000010100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff01e8030000000000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac02483045022100aa5d8aa40a90f23ce2c3d11bc845ca4a12acd99cbea37de6b9f6d86edebba8cb022022dedc2aa0a255f74d04c0b76ece2d7c691f9dd11a64a8ac49f62a99c3a05f9d01232103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ac00000000", "0020ff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3db", 0, 1000, "b3b24add62af002c288c50df90c9e1871a5c54f3b247278887728bd9ecf22419", 1}, + { "010000007495d50732e62d65f11068892370d8b68a2cbd2e0c80be8c67e099a1ef0d7bee3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e7066504400010000000000000000000000000000000000000000000000000000000000000000000017a914fe9c7dacc9fcfbf7e3b7d5ad06aa2b28c5a7b7e387e803000000000000ffffffff0000000001000000", "01000000000101000100000000000000000000000000000000000000000000000000000000000000000000171600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fffffffff01e8030000000000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac02483045022100cfb07164b36ba64c1b1e8c7720a56ad64d96f6ef332d3d37f9cb3c96477dc44502200a464cd7a9cf94cd70f66ce4f4f0625ef650052c7afcfe29d7d7e01830ff91ed012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000", "a914fe9c7dacc9fcfbf7e3b7d5ad06aa2b28c5a7b7e387", 0, 1000, "85ba2a27852d86bdc2e36403759d8c2fe0c6eb3eb253861d300941c7fe03ca83", 1}, + { "010000007495d50732e62d65f11068892370d8b68a2cbd2e0c80be8c67e099a1ef0d7bee3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e7066504400010000000000000000000000000000000000000000000000000000000000000000000017a9142135ab4f0981830311e35600eebc7376dce3a91487e803000000000000ffffffff0000000001000000", "0100000000010100010000000000000000000000000000000000000000000000000000000000000000000023220020ff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3dbffffffff01e8030000000000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac02483045022100aa5d8aa40a90f23ce2c3d11bc845ca4a12acd99cbea37de6b9f6d86edebba8cb022022dedc2aa0a255f74d04c0b76ece2d7c691f9dd11a64a8ac49f62a99c3a05f9d01232103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ac00000000", "a9142135ab4f0981830311e35600eebc7376dce3a91487", 0, 1000, "418e514d1a3710a18590cd45d821792663943b0172aaaa33241f180ee7284405", 1}, + { "010000000e186640d1ce42f53f6ccf3c9d0427da056178e500ba6a26ff4b57bee73e329603bae88710f05ebf15c1c34f7ea4c1ad55ee8c5d7d6ee2b6f9ecd26cf663ca0800010000000000000000000000000000000000000000000000000000000000000200000001511c0c000000000000ffffffff0000000001000000", "0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff05540b0000000000000151d0070000000000000151840300000000000001513c0f00000000000001512c010000000000000151000248304502210092f4777a0f17bf5aeb8ae768dec5f2c14feabf9d1fe2c89c78dfed0f13fdb86902206da90a86042e252bcd1e80a168c719e4a1ddcc3cebea24b9812c5453c79107e9832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71000000000000", "51", 0, 3100, "1d27752811bb71ce44897df3f0c30c763c358633be796cc1581f695227448ab1", 1}, + { "010000000e186640d1ce42f53f6ccf3c9d0427da056178e500ba6a26ff4b57bee73e329603bae88710f05ebf15c1c34f7ea4c1ad55ee8c5d7d6ee2b6f9ecd26cf663ca080001000000000000000000000000000000000000000000000000000000000000010000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fd007000000000000ffffffff0000000001000000", "0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff05540b0000000000000151d0070000000000000151840300000000000001513c0f00000000000001512c010000000000000151000248304502210092f4777a0f17bf5aeb8ae768dec5f2c14feabf9d1fe2c89c78dfed0f13fdb86902206da90a86042e252bcd1e80a168c719e4a1ddcc3cebea24b9812c5453c79107e9832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71000000000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1, 2000, "3db35e83ec3444037cf7105c3fa400f9dfa43c778a6a12ea7de8bed73d490577", 1}, + { "010000000e186640d1ce42f53f6ccf3c9d0427da056178e500ba6a26ff4b57bee73e329603bae88710f05ebf15c1c34f7ea4c1ad55ee8c5d7d6ee2b6f9ecd26cf663ca0800010000000000000000000000000000000000000000000000000000000000000000000001514c04000000000000ffffffff0000000001000000", "0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff05540b0000000000000151d0070000000000000151840300000000000001513c0f00000000000001512c010000000000000151000248304502210092f4777a0f17bf5aeb8ae768dec5f2c14feabf9d1fe2c89c78dfed0f13fdb86902206da90a86042e252bcd1e80a168c719e4a1ddcc3cebea24b9812c5453c79107e9832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71000000000000", "51", 2, 1100, "88243fca671fc3651d4e18017ab5b4685f3c2d7fd693cf00fac2a620b4e98beb", 1}, + { "010000000e186640d1ce42f53f6ccf3c9d0427da056178e500ba6a26ff4b57bee73e329603bae88710f05ebf15c1c34f7ea4c1ad55ee8c5d7d6ee2b6f9ecd26cf663ca0800010000000000000000000000000000000000000000000000000000000000000300000001510410000000000000ffffffff0000000001000000", "0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff05540b0000000000000151d0070000000000000151840300000000000001513c0f00000000000001512c010000000000000151000248304502210092f4777a0f17bf5aeb8ae768dec5f2c14feabf9d1fe2c89c78dfed0f13fdb86902206da90a86042e252bcd1e80a168c719e4a1ddcc3cebea24b9812c5453c79107e9832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71000000000000", "51", 3, 4100, "8ff90af8ceb022a084374aa2ff68908195603479edd5a3fbb5451393cccedc39", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000000000000151e803000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b0000000000000151000248304502210092f4777a0f17bf5aeb8ae768dec5f2c14feabf9d1fe2c89c78dfed0f13fdb86902206da90a86042e252bcd1e80a168c719e4a1ddcc3cebea24b9812c5453c79107e9832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 0, 1000, "64db9f88d32107a925741be9d11c52eacf113ac54ca9ee34651415830dfabbcb", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000010000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fd007000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b0000000000000151000248304502210092f4777a0f17bf5aeb8ae768dec5f2c14feabf9d1fe2c89c78dfed0f13fdb86902206da90a86042e252bcd1e80a168c719e4a1ddcc3cebea24b9812c5453c79107e9832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1, 2000, "5487d90163ba4c05f3e5b63aa1f0473adf739f9d1f28734e99a80a9e0b9329d1", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000020000000151b80b000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b0000000000000151000248304502210092f4777a0f17bf5aeb8ae768dec5f2c14feabf9d1fe2c89c78dfed0f13fdb86902206da90a86042e252bcd1e80a168c719e4a1ddcc3cebea24b9812c5453c79107e9832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 2, 3000, "511e72d552487d66a764efadfd32bf9549beacfa559d57e9c80776730134a7e5", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000000000000151e803000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff0484030000000000000151d0070000000000000151540b0000000000000151c800000000000000015100024730440220699e6b0cfe015b64ca3283e6551440a34f901ba62dd4c72fe1cb815afb2e6761022021cc5e84db498b1479de14efda49093219441adc6c543e5534979605e273d80b032103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 0, 1000, "a0ac55ae4093ab01853472425b2695763fb1613f8243350c4ff0faef5371b1f0", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000010000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fd007000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff0484030000000000000151d0070000000000000151540b0000000000000151c800000000000000015100024730440220699e6b0cfe015b64ca3283e6551440a34f901ba62dd4c72fe1cb815afb2e6761022021cc5e84db498b1479de14efda49093219441adc6c543e5534979605e273d80b032103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1, 2000, "d1c720dc79814699f3e47adcc4620863056a2b4abbc245471c91ac3a590c8d21", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000020000000151b80b000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff0484030000000000000151d0070000000000000151540b0000000000000151c800000000000000015100024730440220699e6b0cfe015b64ca3283e6551440a34f901ba62dd4c72fe1cb815afb2e6761022021cc5e84db498b1479de14efda49093219441adc6c543e5534979605e273d80b032103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 2, 3000, "e8acecd5fb8fdfa4a64d9c55e51549e3909b2c782014fec9ff36b52cd01296b0", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000000000000151e803000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b000000000000015100024730440220699e6b0cfe015b64ca3283e6551440a34f901ba62dd4c72fe1cb815afb2e6761022021cc5e84db498b1479de14efda49093219441adc6c543e5534979605e273d80b032103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 0, 1000, "64db9f88d32107a925741be9d11c52eacf113ac54ca9ee34651415830dfabbcb", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000010000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fd007000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b000000000000015100024730440220699e6b0cfe015b64ca3283e6551440a34f901ba62dd4c72fe1cb815afb2e6761022021cc5e84db498b1479de14efda49093219441adc6c543e5534979605e273d80b032103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1, 2000, "5487d90163ba4c05f3e5b63aa1f0473adf739f9d1f28734e99a80a9e0b9329d1", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000020000000151b80b000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b000000000000015100024730440220699e6b0cfe015b64ca3283e6551440a34f901ba62dd4c72fe1cb815afb2e6761022021cc5e84db498b1479de14efda49093219441adc6c543e5534979605e273d80b032103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 2, 3000, "511e72d552487d66a764efadfd32bf9549beacfa559d57e9c80776730134a7e5", 1}, + { "010000008e02751544b73592f8800af5cbe898fdc9bdba198b2f3de46ccde46727706f1e03bae88710f05ebf15c1c34f7ea4c1ad55ee8c5d7d6ee2b6f9ecd26cf663ca0800010000000000000000000000000000000000000000000000000000000000000200000001511c0c000000000000ffffffff0000000001000000", "0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff04b60300000000000001519e070000000000000151860b00000000000001009600000000000000015100000248304502210091b32274295c2a3fa02f5bce92fb2789e3fc6ea947fbe1a76e52ea3f4ef2381a022079ad72aefa3837a2e0c033a8652a59731da05fa4a813f4fc48e87c075037256b822103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 0, 3100, "d14441cb5ac7700c65b7660059e50c6c9655467ba90ac20174a449526469e157", 1}, + { "010000008e02751544b73592f8800af5cbe898fdc9bdba198b2f3de46ccde46727706f1e03bae88710f05ebf15c1c34f7ea4c1ad55ee8c5d7d6ee2b6f9ecd26cf663ca0800010000000000000000000000000000000000000000000000000000000000000000000001514c04000000000000ffffffff0000000001000000", "0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff04b60300000000000001519e070000000000000151860b00000000000001009600000000000000015100000248304502210091b32274295c2a3fa02f5bce92fb2789e3fc6ea947fbe1a76e52ea3f4ef2381a022079ad72aefa3837a2e0c033a8652a59731da05fa4a813f4fc48e87c075037256b822103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 1, 1100, "f6a9df6916d7a376c680553692d4fd9f3931758aa0ba9d0f3a442c830ce21837", 1}, + { "010000008e02751544b73592f8800af5cbe898fdc9bdba198b2f3de46ccde46727706f1e03bae88710f05ebf15c1c34f7ea4c1ad55ee8c5d7d6ee2b6f9ecd26cf663ca080001000000000000000000000000000000000000000000000000000000000000010000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fd007000000000000ffffffff0000000001000000", "0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff04b60300000000000001519e070000000000000151860b00000000000001009600000000000000015100000248304502210091b32274295c2a3fa02f5bce92fb2789e3fc6ea947fbe1a76e52ea3f4ef2381a022079ad72aefa3837a2e0c033a8652a59731da05fa4a813f4fc48e87c075037256b822103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 2, 2000, "d333eecf9028701327e5c9615937462318edd118d3fc058b95b4d15e71d1ebbb", 1}, + { "010000008e02751544b73592f8800af5cbe898fdc9bdba198b2f3de46ccde46727706f1e03bae88710f05ebf15c1c34f7ea4c1ad55ee8c5d7d6ee2b6f9ecd26cf663ca0800010000000000000000000000000000000000000000000000000000000000000300000001510410000000000000ffffffff0000000001000000", "0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff04b60300000000000001519e070000000000000151860b00000000000001009600000000000000015100000248304502210091b32274295c2a3fa02f5bce92fb2789e3fc6ea947fbe1a76e52ea3f4ef2381a022079ad72aefa3837a2e0c033a8652a59731da05fa4a813f4fc48e87c075037256b822103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 3, 4100, "25acf3e4c6c41b9dd160adffc781cc28ae6759f74a8beaf713210e7f08e296df", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000000000000151e803000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b0000000000000151000248304502210091b32274295c2a3fa02f5bce92fb2789e3fc6ea947fbe1a76e52ea3f4ef2381a022079ad72aefa3837a2e0c033a8652a59731da05fa4a813f4fc48e87c075037256b822103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 0, 1000, "64db9f88d32107a925741be9d11c52eacf113ac54ca9ee34651415830dfabbcb", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000010000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fd007000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b0000000000000151000248304502210091b32274295c2a3fa02f5bce92fb2789e3fc6ea947fbe1a76e52ea3f4ef2381a022079ad72aefa3837a2e0c033a8652a59731da05fa4a813f4fc48e87c075037256b822103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1, 2000, "5487d90163ba4c05f3e5b63aa1f0473adf739f9d1f28734e99a80a9e0b9329d1", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000020000000151b80b000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b0000000000000151000248304502210091b32274295c2a3fa02f5bce92fb2789e3fc6ea947fbe1a76e52ea3f4ef2381a022079ad72aefa3837a2e0c033a8652a59731da05fa4a813f4fc48e87c075037256b822103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 2, 3000, "511e72d552487d66a764efadfd32bf9549beacfa559d57e9c80776730134a7e5", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000000000000151e803000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff04b60300000000000001519e070000000000000151860b0000000000000100960000000000000001510002473044022022fceb54f62f8feea77faac7083c3b56c4676a78f93745adc8a35800bc36adfa022026927df9abcf0a8777829bcfcce3ff0a385fa54c3f9df577405e3ef24ee56479022103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 0, 1000, "1662226f119e2aff44bf34e2386effd820df2cecccd85cd82120eb45dc83e7f3", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000010000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fd007000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff04b60300000000000001519e070000000000000151860b0000000000000100960000000000000001510002473044022022fceb54f62f8feea77faac7083c3b56c4676a78f93745adc8a35800bc36adfa022026927df9abcf0a8777829bcfcce3ff0a385fa54c3f9df577405e3ef24ee56479022103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1, 2000, "84bd4f937b63d04bb874f6809b63020bf488c1f4e1abb442fbaf19d16c454de3", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000020000000151b80b000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff04b60300000000000001519e070000000000000151860b0000000000000100960000000000000001510002473044022022fceb54f62f8feea77faac7083c3b56c4676a78f93745adc8a35800bc36adfa022026927df9abcf0a8777829bcfcce3ff0a385fa54c3f9df577405e3ef24ee56479022103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 2, 3000, "0382df8917ac89086a063faa1a29089ce75e7f73b76c03edfd80a94b81191c59", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000000000000151e803000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b00000000000001510002473044022022fceb54f62f8feea77faac7083c3b56c4676a78f93745adc8a35800bc36adfa022026927df9abcf0a8777829bcfcce3ff0a385fa54c3f9df577405e3ef24ee56479022103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 0, 1000, "64db9f88d32107a925741be9d11c52eacf113ac54ca9ee34651415830dfabbcb", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000010000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fd007000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b00000000000001510002473044022022fceb54f62f8feea77faac7083c3b56c4676a78f93745adc8a35800bc36adfa022026927df9abcf0a8777829bcfcce3ff0a385fa54c3f9df577405e3ef24ee56479022103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1, 2000, "5487d90163ba4c05f3e5b63aa1f0473adf739f9d1f28734e99a80a9e0b9329d1", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000020000000151b80b000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b00000000000001510002473044022022fceb54f62f8feea77faac7083c3b56c4676a78f93745adc8a35800bc36adfa022026927df9abcf0a8777829bcfcce3ff0a385fa54c3f9df577405e3ef24ee56479022103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 2, 3000, "511e72d552487d66a764efadfd32bf9549beacfa559d57e9c80776730134a7e5", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e9488429d66cf637c769bb3a29d2f834aa7f37c53dea9a8471cd3066c4a4dcd360c7290a0001000000000000000000000000000000000000000000000000000000000000000000000151e803000000000000020000000000000001000000", "01000000000103000100000000000000000000000000000000000000000000000000000000000000000000000200000000010000000000000000000000000000000000000000000000000000000000000100000000ffffffff000100000000000000000000000000000000000000000000000000000000000002000000000200000003e8030000000000000151d0070000000000000151b80b00000000000001510002473044022022fceb54f62f8feea77faac7083c3b56c4676a78f93745adc8a35800bc36adfa022026927df9abcf0a8777829bcfcce3ff0a385fa54c3f9df577405e3ef24ee56479022103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 0, 1000, "13d0733df87d3991adc04eac0c1075cbe368efdbc2705332f0fc8cb3da9e9453", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e9488429d66cf637c769bb3a29d2f834aa7f37c53dea9a8471cd3066c4a4dcd360c7290a0001000000000000000000000000000000000000000000000000000000000000010000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fd007000000000000ffffffff0000000001000000", "01000000000103000100000000000000000000000000000000000000000000000000000000000000000000000200000000010000000000000000000000000000000000000000000000000000000000000100000000ffffffff000100000000000000000000000000000000000000000000000000000000000002000000000200000003e8030000000000000151d0070000000000000151b80b00000000000001510002473044022022fceb54f62f8feea77faac7083c3b56c4676a78f93745adc8a35800bc36adfa022026927df9abcf0a8777829bcfcce3ff0a385fa54c3f9df577405e3ef24ee56479022103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1, 2000, "5bb0fbb7deb357774834052371e25da193e3cb080067dc89007f57342730de07", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e9488429d66cf637c769bb3a29d2f834aa7f37c53dea9a8471cd3066c4a4dcd360c7290a0001000000000000000000000000000000000000000000000000000000000000020000000151b80b000000000000020000000000000001000000", "01000000000103000100000000000000000000000000000000000000000000000000000000000000000000000200000000010000000000000000000000000000000000000000000000000000000000000100000000ffffffff000100000000000000000000000000000000000000000000000000000000000002000000000200000003e8030000000000000151d0070000000000000151b80b00000000000001510002473044022022fceb54f62f8feea77faac7083c3b56c4676a78f93745adc8a35800bc36adfa022026927df9abcf0a8777829bcfcce3ff0a385fa54c3f9df577405e3ef24ee56479022103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 2, 3000, "d93aabe917329ffad69ba0eb71cdf6c899eb0e020eb2629d49af49e7a7d706a9", 1}, + { "010000008e02751544b73592f8800af5cbe898fdc9bdba198b2f3de46ccde46727706f1e03bae88710f05ebf15c1c34f7ea4c1ad55ee8c5d7d6ee2b6f9ecd26cf663ca0800010000000000000000000000000000000000000000000000000000000000000200000001511c0c000000000000ffffffff0000000001000000", "0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff03e8030000000000000151d0070000000000000151b80b0000000000000151000002483045022100a3cec69b52cba2d2de623eeef89e0ba1606184ea55476c0f8189fda231bc9cbb022003181ad597f7c380a7d1c740286b1d022b8b04ded028b833282e055e03b8efef812103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 0, 3100, "caed95ecc8f84e2e518721cb89df965a23d6cbd2c478e06f6b598f45d361685b", 1}, + { "010000008e02751544b73592f8800af5cbe898fdc9bdba198b2f3de46ccde46727706f1e03bae88710f05ebf15c1c34f7ea4c1ad55ee8c5d7d6ee2b6f9ecd26cf663ca0800010000000000000000000000000000000000000000000000000000000000000000000001514c04000000000000ffffffff0000000001000000", "0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff03e8030000000000000151d0070000000000000151b80b0000000000000151000002483045022100a3cec69b52cba2d2de623eeef89e0ba1606184ea55476c0f8189fda231bc9cbb022003181ad597f7c380a7d1c740286b1d022b8b04ded028b833282e055e03b8efef812103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 1, 1100, "bc997cbb05bab26e787c749ed2803f9cc8f4fb38d8bfae7681d1545aba9ec8e4", 1}, + { "010000008e02751544b73592f8800af5cbe898fdc9bdba198b2f3de46ccde46727706f1e03bae88710f05ebf15c1c34f7ea4c1ad55ee8c5d7d6ee2b6f9ecd26cf663ca080001000000000000000000000000000000000000000000000000000000000000010000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fd007000000000000ffffffff0000000001000000", "0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff03e8030000000000000151d0070000000000000151b80b0000000000000151000002483045022100a3cec69b52cba2d2de623eeef89e0ba1606184ea55476c0f8189fda231bc9cbb022003181ad597f7c380a7d1c740286b1d022b8b04ded028b833282e055e03b8efef812103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 2, 2000, "e2ccf717f0c4ca0cca28740466b35d36581c82a9c1869b4a0e24c19cfb4c97ce", 1}, + { "010000008e02751544b73592f8800af5cbe898fdc9bdba198b2f3de46ccde46727706f1e03bae88710f05ebf15c1c34f7ea4c1ad55ee8c5d7d6ee2b6f9ecd26cf663ca0800010000000000000000000000000000000000000000000000000000000000000300000001510410000000000000ffffffff0000000001000000", "0100000000010400010000000000000000000000000000000000000000000000000000000000000200000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000300000000ffffffff03e8030000000000000151d0070000000000000151b80b0000000000000151000002483045022100a3cec69b52cba2d2de623eeef89e0ba1606184ea55476c0f8189fda231bc9cbb022003181ad597f7c380a7d1c740286b1d022b8b04ded028b833282e055e03b8efef812103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 3, 4100, "cd0edb19abe92874abc0571c10029feaeebce21fdfd7d7406783de6580de8d00", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000000000000151e803000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b00000000000001510002483045022100a3cec69b52cba2d2de623eeef89e0ba1606184ea55476c0f8189fda231bc9cbb022003181ad597f7c380a7d1c740286b1d022b8b04ded028b833282e055e03b8efef812103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 0, 1000, "64db9f88d32107a925741be9d11c52eacf113ac54ca9ee34651415830dfabbcb", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000010000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fd007000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b00000000000001510002483045022100a3cec69b52cba2d2de623eeef89e0ba1606184ea55476c0f8189fda231bc9cbb022003181ad597f7c380a7d1c740286b1d022b8b04ded028b833282e055e03b8efef812103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1, 2000, "5487d90163ba4c05f3e5b63aa1f0473adf739f9d1f28734e99a80a9e0b9329d1", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000020000000151b80b000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b00000000000001510002483045022100a3cec69b52cba2d2de623eeef89e0ba1606184ea55476c0f8189fda231bc9cbb022003181ad597f7c380a7d1c740286b1d022b8b04ded028b833282e055e03b8efef812103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 2, 3000, "511e72d552487d66a764efadfd32bf9549beacfa559d57e9c80776730134a7e5", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000000000000151e803000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b00000000000001510002483045022100a3cec69b52cba2d2de623ffffffffff1606184ea55476c0f8189fda231bc9cbb022003181ad597f7c380a7d1c740286b1d022b8b04ded028b833282e055e03b8efef812103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 0, 1000, "64db9f88d32107a925741be9d11c52eacf113ac54ca9ee34651415830dfabbcb", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000010000001660144c9c3dfac4207d5d8cb89df5722cb3d712385e3fd007000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b00000000000001510002483045022100a3cec69b52cba2d2de623ffffffffff1606184ea55476c0f8189fda231bc9cbb022003181ad597f7c380a7d1c740286b1d022b8b04ded028b833282e055e03b8efef812103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "60144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1, 2000, "aa1eb4d257e447bd63a7b684a2e12019b95482dbd4a064b7df3d6b20149729f6", 1}, + { "0100000067ad88be284d8327089d02444717906c1d6dd220e9ceae917d97a9f6e948842982a7d5bb59fc957ff7f737ca0b8be713c705d6173783ad5edb067819bed70be80001000000000000000000000000000000000000000000000000000000000000020000000151b80b000000000000ffffffff0000000001000000", "0100000000010300010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000200000000ffffffff03e8030000000000000151d0070000000000000151b80b00000000000001510002483045022100a3cec69b52cba2d2de623ffffffffff1606184ea55476c0f8189fda231bc9cbb022003181ad597f7c380a7d1c740286b1d022b8b04ded028b833282e055e03b8efef812103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "51", 2, 3000, "511e72d552487d66a764efadfd32bf9549beacfa559d57e9c80776730134a7e5", 1}, + { "010000007495d50732e62d65f11068892370d8b68a2cbd2e0c80be8c67e099a1ef0d7bee3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e7066504400010000000000000000000000000000000000000000000000000000000000000000000022002033198a9bfef674ebddb9ffaa52928017b8472791e54c609cb95f278ac6b1e349e803000000000000ffffffff0000000001000000", "0100000000010100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff010000000000000000015102fd08020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002755100000000", "002033198a9bfef674ebddb9ffaa52928017b8472791e54c609cb95f278ac6b1e349", 0, 1000, "58d3a7be8abbcee7ee66069c23d9fd537cc27106a363119377771dbd617d6f3e", 1}, + { "01000000e0f98ad94ad3210a543e7af8dd9f61cefc035dc6bf378ae3827315fa425281ebc0cbc41638b87e0f44ba232e0c48d8e6afadd74e1f762aae84e8cfa0ce5049830001000000000000000000000000000000000000000000000000000000000000000000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fe803000000000000ffffffff0000000001000000", "0100000000010c00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff0001000000000000000000000000000000000000000000000000000000000000020000006a473044022026c2e65b33fcd03b2a3b0f25030f0244bd23cc45ae4dec0f48ae62255b1998a00220463aa3982b718d593a6b9e0044513fd67a5009c2fdccc59992cffc2b167889f4012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000030000006a4730440220008bd8382911218dcb4c9f2e75bf5c5c3635f2f2df49b36994fde85b0be21a1a02205a539ef10fb4c778b522c1be852352ea06c67ab74200977c722b0bc68972575a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000040000006b483045022100d9436c32ff065127d71e1a20e319e4fe0a103ba0272743dbd8580be4659ab5d302203fd62571ee1fe790b182d078ecfd092a509eac112bea558d122974ef9cc012c7012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000050000006a47304402200e2c149b114ec546015c13b2b464bbcb0cdc5872e6775787527af6cbc4830b6c02207e9396c6979fb15a9a2b96ca08a633866eaf20dc0ff3c03e512c1d5a1654f148012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000060000006b483045022100b20e70d897dc15420bccb5e0d3e208d27bdd676af109abbd3f88dbdb7721e6d6022005836e663173fbdfe069f54cde3c2decd3d0ea84378092a5d9d85ec8642e8a41012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff00010000000000000000000000000000000000000000000000000000000000000700000000ffffffff00010000000000000000000000000000000000000000000000000000000000000800000000ffffffff00010000000000000000000000000000000000000000000000000000000000000900000000ffffffff00010000000000000000000000000000000000000000000000000000000000000a00000000ffffffff00010000000000000000000000000000000000000000000000000000000000000b0000006a47304402206639c6e05e3b9d2675a7f3876286bdf7584fe2bbd15e0ce52dd4e02c0092cdc60220757d60b0a61fc95ada79d23746744c72bac1545a75ff6c2c7cdb6ae04e7e9592012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0ce8030000000000000151e9030000000000000151ea030000000000000151eb030000000000000151ec030000000000000151ed030000000000000151ee030000000000000151ef030000000000000151f0030000000000000151f1030000000000000151f2030000000000000151f30300000000000001510248304502210082219a54f61bf126bfc3fa068c6e33831222d1d7138c6faa9d33ca87fd4202d6022063f9902519624254d7c2c8ea7ba2d66ae975e4e229ae38043973ec707d5d4a83012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022017fb58502475848c1b09f162cb1688d0920ff7f142bed0ef904da2ccc88b168f02201798afa61850c65e77889cbcd648a5703b487895517c88f85cdd18b021ee246a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000000247304402202830b7926e488da75782c81a54cd281720890d1af064629ebf2e31bf9f5435f30220089afaa8b455bbeb7d9b9c3fe1ed37d07685ade8455c76472cda424d93e4074a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022026326fcdae9207b596c2b05921dbac11d81040c4d40378513670f19d9f4af893022034ecd7a282c0163b89aaa62c22ec202cef4736c58cd251649bad0d8139bcbf55012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71024730440220214978daeb2f38cd426ee6e2f44131a33d6b191af1c216247f1dd7d74c16d84a02205fdc05529b0bc0c430b4d5987264d9d075351c4f4484c16e91662e90a72aab24012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402204a6e9f199dc9672cf2ff8094aaa784363be1eb62b679f7ff2df361124f1dca3302205eeb11f70fab5355c9c8ad1a0700ea355d315e334822fa182227e9815308ee8f012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 0, 1000, "f79eaa7c339cacac6282debba686a90faee99a8f43614000e0a0353519d302ca", 1}, + { "01000000e0f98ad94ad3210a543e7af8dd9f61cefc035dc6bf378ae3827315fa425281ebc0cbc41638b87e0f44ba232e0c48d8e6afadd74e1f762aae84e8cfa0ce5049830001000000000000000000000000000000000000000000000000000000000000010000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fe903000000000000ffffffff0000000001000000", "0100000000010c00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff0001000000000000000000000000000000000000000000000000000000000000020000006a473044022026c2e65b33fcd03b2a3b0f25030f0244bd23cc45ae4dec0f48ae62255b1998a00220463aa3982b718d593a6b9e0044513fd67a5009c2fdccc59992cffc2b167889f4012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000030000006a4730440220008bd8382911218dcb4c9f2e75bf5c5c3635f2f2df49b36994fde85b0be21a1a02205a539ef10fb4c778b522c1be852352ea06c67ab74200977c722b0bc68972575a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000040000006b483045022100d9436c32ff065127d71e1a20e319e4fe0a103ba0272743dbd8580be4659ab5d302203fd62571ee1fe790b182d078ecfd092a509eac112bea558d122974ef9cc012c7012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000050000006a47304402200e2c149b114ec546015c13b2b464bbcb0cdc5872e6775787527af6cbc4830b6c02207e9396c6979fb15a9a2b96ca08a633866eaf20dc0ff3c03e512c1d5a1654f148012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000060000006b483045022100b20e70d897dc15420bccb5e0d3e208d27bdd676af109abbd3f88dbdb7721e6d6022005836e663173fbdfe069f54cde3c2decd3d0ea84378092a5d9d85ec8642e8a41012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff00010000000000000000000000000000000000000000000000000000000000000700000000ffffffff00010000000000000000000000000000000000000000000000000000000000000800000000ffffffff00010000000000000000000000000000000000000000000000000000000000000900000000ffffffff00010000000000000000000000000000000000000000000000000000000000000a00000000ffffffff00010000000000000000000000000000000000000000000000000000000000000b0000006a47304402206639c6e05e3b9d2675a7f3876286bdf7584fe2bbd15e0ce52dd4e02c0092cdc60220757d60b0a61fc95ada79d23746744c72bac1545a75ff6c2c7cdb6ae04e7e9592012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0ce8030000000000000151e9030000000000000151ea030000000000000151eb030000000000000151ec030000000000000151ed030000000000000151ee030000000000000151ef030000000000000151f0030000000000000151f1030000000000000151f2030000000000000151f30300000000000001510248304502210082219a54f61bf126bfc3fa068c6e33831222d1d7138c6faa9d33ca87fd4202d6022063f9902519624254d7c2c8ea7ba2d66ae975e4e229ae38043973ec707d5d4a83012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022017fb58502475848c1b09f162cb1688d0920ff7f142bed0ef904da2ccc88b168f02201798afa61850c65e77889cbcd648a5703b487895517c88f85cdd18b021ee246a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000000247304402202830b7926e488da75782c81a54cd281720890d1af064629ebf2e31bf9f5435f30220089afaa8b455bbeb7d9b9c3fe1ed37d07685ade8455c76472cda424d93e4074a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022026326fcdae9207b596c2b05921dbac11d81040c4d40378513670f19d9f4af893022034ecd7a282c0163b89aaa62c22ec202cef4736c58cd251649bad0d8139bcbf55012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71024730440220214978daeb2f38cd426ee6e2f44131a33d6b191af1c216247f1dd7d74c16d84a02205fdc05529b0bc0c430b4d5987264d9d075351c4f4484c16e91662e90a72aab24012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402204a6e9f199dc9672cf2ff8094aaa784363be1eb62b679f7ff2df361124f1dca3302205eeb11f70fab5355c9c8ad1a0700ea355d315e334822fa182227e9815308ee8f012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1, 1001, "815613b832ca9ee834633974fed624de30121f9df90cda0d9c25410bcb353a86", 1}, + { "01000000e0f98ad94ad3210a543e7af8dd9f61cefc035dc6bf378ae3827315fa425281ebc0cbc41638b87e0f44ba232e0c48d8e6afadd74e1f762aae84e8cfa0ce5049830001000000000000000000000000000000000000000000000000000000000000020000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88acea03000000000000ffffffff0000000001000000", "0100000000010c00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff0001000000000000000000000000000000000000000000000000000000000000020000006a473044022026c2e65b33fcd03b2a3b0f25030f0244bd23cc45ae4dec0f48ae62255b1998a00220463aa3982b718d593a6b9e0044513fd67a5009c2fdccc59992cffc2b167889f4012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000030000006a4730440220008bd8382911218dcb4c9f2e75bf5c5c3635f2f2df49b36994fde85b0be21a1a02205a539ef10fb4c778b522c1be852352ea06c67ab74200977c722b0bc68972575a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000040000006b483045022100d9436c32ff065127d71e1a20e319e4fe0a103ba0272743dbd8580be4659ab5d302203fd62571ee1fe790b182d078ecfd092a509eac112bea558d122974ef9cc012c7012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000050000006a47304402200e2c149b114ec546015c13b2b464bbcb0cdc5872e6775787527af6cbc4830b6c02207e9396c6979fb15a9a2b96ca08a633866eaf20dc0ff3c03e512c1d5a1654f148012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000060000006b483045022100b20e70d897dc15420bccb5e0d3e208d27bdd676af109abbd3f88dbdb7721e6d6022005836e663173fbdfe069f54cde3c2decd3d0ea84378092a5d9d85ec8642e8a41012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff00010000000000000000000000000000000000000000000000000000000000000700000000ffffffff00010000000000000000000000000000000000000000000000000000000000000800000000ffffffff00010000000000000000000000000000000000000000000000000000000000000900000000ffffffff00010000000000000000000000000000000000000000000000000000000000000a00000000ffffffff00010000000000000000000000000000000000000000000000000000000000000b0000006a47304402206639c6e05e3b9d2675a7f3876286bdf7584fe2bbd15e0ce52dd4e02c0092cdc60220757d60b0a61fc95ada79d23746744c72bac1545a75ff6c2c7cdb6ae04e7e9592012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0ce8030000000000000151e9030000000000000151ea030000000000000151eb030000000000000151ec030000000000000151ed030000000000000151ee030000000000000151ef030000000000000151f0030000000000000151f1030000000000000151f2030000000000000151f30300000000000001510248304502210082219a54f61bf126bfc3fa068c6e33831222d1d7138c6faa9d33ca87fd4202d6022063f9902519624254d7c2c8ea7ba2d66ae975e4e229ae38043973ec707d5d4a83012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022017fb58502475848c1b09f162cb1688d0920ff7f142bed0ef904da2ccc88b168f02201798afa61850c65e77889cbcd648a5703b487895517c88f85cdd18b021ee246a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000000247304402202830b7926e488da75782c81a54cd281720890d1af064629ebf2e31bf9f5435f30220089afaa8b455bbeb7d9b9c3fe1ed37d07685ade8455c76472cda424d93e4074a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022026326fcdae9207b596c2b05921dbac11d81040c4d40378513670f19d9f4af893022034ecd7a282c0163b89aaa62c22ec202cef4736c58cd251649bad0d8139bcbf55012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71024730440220214978daeb2f38cd426ee6e2f44131a33d6b191af1c216247f1dd7d74c16d84a02205fdc05529b0bc0c430b4d5987264d9d075351c4f4484c16e91662e90a72aab24012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402204a6e9f199dc9672cf2ff8094aaa784363be1eb62b679f7ff2df361124f1dca3302205eeb11f70fab5355c9c8ad1a0700ea355d315e334822fa182227e9815308ee8f012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "76a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac", 2, 1002, "fb992261e24602e73c7c64bc8d2796eaecbfcdf4636bd893f5cfd5731ba98502", 1}, + { "01000000e0f98ad94ad3210a543e7af8dd9f61cefc035dc6bf378ae3827315fa425281ebc0cbc41638b87e0f44ba232e0c48d8e6afadd74e1f762aae84e8cfa0ce5049830001000000000000000000000000000000000000000000000000000000000000030000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88aceb03000000000000ffffffff0000000001000000", "0100000000010c00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff0001000000000000000000000000000000000000000000000000000000000000020000006a473044022026c2e65b33fcd03b2a3b0f25030f0244bd23cc45ae4dec0f48ae62255b1998a00220463aa3982b718d593a6b9e0044513fd67a5009c2fdccc59992cffc2b167889f4012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000030000006a4730440220008bd8382911218dcb4c9f2e75bf5c5c3635f2f2df49b36994fde85b0be21a1a02205a539ef10fb4c778b522c1be852352ea06c67ab74200977c722b0bc68972575a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000040000006b483045022100d9436c32ff065127d71e1a20e319e4fe0a103ba0272743dbd8580be4659ab5d302203fd62571ee1fe790b182d078ecfd092a509eac112bea558d122974ef9cc012c7012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000050000006a47304402200e2c149b114ec546015c13b2b464bbcb0cdc5872e6775787527af6cbc4830b6c02207e9396c6979fb15a9a2b96ca08a633866eaf20dc0ff3c03e512c1d5a1654f148012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000060000006b483045022100b20e70d897dc15420bccb5e0d3e208d27bdd676af109abbd3f88dbdb7721e6d6022005836e663173fbdfe069f54cde3c2decd3d0ea84378092a5d9d85ec8642e8a41012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff00010000000000000000000000000000000000000000000000000000000000000700000000ffffffff00010000000000000000000000000000000000000000000000000000000000000800000000ffffffff00010000000000000000000000000000000000000000000000000000000000000900000000ffffffff00010000000000000000000000000000000000000000000000000000000000000a00000000ffffffff00010000000000000000000000000000000000000000000000000000000000000b0000006a47304402206639c6e05e3b9d2675a7f3876286bdf7584fe2bbd15e0ce52dd4e02c0092cdc60220757d60b0a61fc95ada79d23746744c72bac1545a75ff6c2c7cdb6ae04e7e9592012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0ce8030000000000000151e9030000000000000151ea030000000000000151eb030000000000000151ec030000000000000151ed030000000000000151ee030000000000000151ef030000000000000151f0030000000000000151f1030000000000000151f2030000000000000151f30300000000000001510248304502210082219a54f61bf126bfc3fa068c6e33831222d1d7138c6faa9d33ca87fd4202d6022063f9902519624254d7c2c8ea7ba2d66ae975e4e229ae38043973ec707d5d4a83012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022017fb58502475848c1b09f162cb1688d0920ff7f142bed0ef904da2ccc88b168f02201798afa61850c65e77889cbcd648a5703b487895517c88f85cdd18b021ee246a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000000247304402202830b7926e488da75782c81a54cd281720890d1af064629ebf2e31bf9f5435f30220089afaa8b455bbeb7d9b9c3fe1ed37d07685ade8455c76472cda424d93e4074a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022026326fcdae9207b596c2b05921dbac11d81040c4d40378513670f19d9f4af893022034ecd7a282c0163b89aaa62c22ec202cef4736c58cd251649bad0d8139bcbf55012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71024730440220214978daeb2f38cd426ee6e2f44131a33d6b191af1c216247f1dd7d74c16d84a02205fdc05529b0bc0c430b4d5987264d9d075351c4f4484c16e91662e90a72aab24012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402204a6e9f199dc9672cf2ff8094aaa784363be1eb62b679f7ff2df361124f1dca3302205eeb11f70fab5355c9c8ad1a0700ea355d315e334822fa182227e9815308ee8f012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "76a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac", 3, 1003, "c860cc1c9d72a0f92cd37a4cbb7c88964be8434d67a8cfa15b16b8b29326b1bf", 1}, + { "01000000e0f98ad94ad3210a543e7af8dd9f61cefc035dc6bf378ae3827315fa425281ebc0cbc41638b87e0f44ba232e0c48d8e6afadd74e1f762aae84e8cfa0ce5049830001000000000000000000000000000000000000000000000000000000000000040000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88acec03000000000000ffffffff0000000001000000", "0100000000010c00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff0001000000000000000000000000000000000000000000000000000000000000020000006a473044022026c2e65b33fcd03b2a3b0f25030f0244bd23cc45ae4dec0f48ae62255b1998a00220463aa3982b718d593a6b9e0044513fd67a5009c2fdccc59992cffc2b167889f4012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000030000006a4730440220008bd8382911218dcb4c9f2e75bf5c5c3635f2f2df49b36994fde85b0be21a1a02205a539ef10fb4c778b522c1be852352ea06c67ab74200977c722b0bc68972575a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000040000006b483045022100d9436c32ff065127d71e1a20e319e4fe0a103ba0272743dbd8580be4659ab5d302203fd62571ee1fe790b182d078ecfd092a509eac112bea558d122974ef9cc012c7012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000050000006a47304402200e2c149b114ec546015c13b2b464bbcb0cdc5872e6775787527af6cbc4830b6c02207e9396c6979fb15a9a2b96ca08a633866eaf20dc0ff3c03e512c1d5a1654f148012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000060000006b483045022100b20e70d897dc15420bccb5e0d3e208d27bdd676af109abbd3f88dbdb7721e6d6022005836e663173fbdfe069f54cde3c2decd3d0ea84378092a5d9d85ec8642e8a41012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff00010000000000000000000000000000000000000000000000000000000000000700000000ffffffff00010000000000000000000000000000000000000000000000000000000000000800000000ffffffff00010000000000000000000000000000000000000000000000000000000000000900000000ffffffff00010000000000000000000000000000000000000000000000000000000000000a00000000ffffffff00010000000000000000000000000000000000000000000000000000000000000b0000006a47304402206639c6e05e3b9d2675a7f3876286bdf7584fe2bbd15e0ce52dd4e02c0092cdc60220757d60b0a61fc95ada79d23746744c72bac1545a75ff6c2c7cdb6ae04e7e9592012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0ce8030000000000000151e9030000000000000151ea030000000000000151eb030000000000000151ec030000000000000151ed030000000000000151ee030000000000000151ef030000000000000151f0030000000000000151f1030000000000000151f2030000000000000151f30300000000000001510248304502210082219a54f61bf126bfc3fa068c6e33831222d1d7138c6faa9d33ca87fd4202d6022063f9902519624254d7c2c8ea7ba2d66ae975e4e229ae38043973ec707d5d4a83012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022017fb58502475848c1b09f162cb1688d0920ff7f142bed0ef904da2ccc88b168f02201798afa61850c65e77889cbcd648a5703b487895517c88f85cdd18b021ee246a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000000247304402202830b7926e488da75782c81a54cd281720890d1af064629ebf2e31bf9f5435f30220089afaa8b455bbeb7d9b9c3fe1ed37d07685ade8455c76472cda424d93e4074a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022026326fcdae9207b596c2b05921dbac11d81040c4d40378513670f19d9f4af893022034ecd7a282c0163b89aaa62c22ec202cef4736c58cd251649bad0d8139bcbf55012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71024730440220214978daeb2f38cd426ee6e2f44131a33d6b191af1c216247f1dd7d74c16d84a02205fdc05529b0bc0c430b4d5987264d9d075351c4f4484c16e91662e90a72aab24012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402204a6e9f199dc9672cf2ff8094aaa784363be1eb62b679f7ff2df361124f1dca3302205eeb11f70fab5355c9c8ad1a0700ea355d315e334822fa182227e9815308ee8f012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "76a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac", 4, 1004, "1fc97f377e9105fd031b031ea6570916c0d7e4de21da3e4530957f67eabe1738", 1}, + { "01000000e0f98ad94ad3210a543e7af8dd9f61cefc035dc6bf378ae3827315fa425281ebc0cbc41638b87e0f44ba232e0c48d8e6afadd74e1f762aae84e8cfa0ce5049830001000000000000000000000000000000000000000000000000000000000000050000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88aced03000000000000ffffffff0000000001000000", "0100000000010c00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff0001000000000000000000000000000000000000000000000000000000000000020000006a473044022026c2e65b33fcd03b2a3b0f25030f0244bd23cc45ae4dec0f48ae62255b1998a00220463aa3982b718d593a6b9e0044513fd67a5009c2fdccc59992cffc2b167889f4012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000030000006a4730440220008bd8382911218dcb4c9f2e75bf5c5c3635f2f2df49b36994fde85b0be21a1a02205a539ef10fb4c778b522c1be852352ea06c67ab74200977c722b0bc68972575a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000040000006b483045022100d9436c32ff065127d71e1a20e319e4fe0a103ba0272743dbd8580be4659ab5d302203fd62571ee1fe790b182d078ecfd092a509eac112bea558d122974ef9cc012c7012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000050000006a47304402200e2c149b114ec546015c13b2b464bbcb0cdc5872e6775787527af6cbc4830b6c02207e9396c6979fb15a9a2b96ca08a633866eaf20dc0ff3c03e512c1d5a1654f148012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000060000006b483045022100b20e70d897dc15420bccb5e0d3e208d27bdd676af109abbd3f88dbdb7721e6d6022005836e663173fbdfe069f54cde3c2decd3d0ea84378092a5d9d85ec8642e8a41012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff00010000000000000000000000000000000000000000000000000000000000000700000000ffffffff00010000000000000000000000000000000000000000000000000000000000000800000000ffffffff00010000000000000000000000000000000000000000000000000000000000000900000000ffffffff00010000000000000000000000000000000000000000000000000000000000000a00000000ffffffff00010000000000000000000000000000000000000000000000000000000000000b0000006a47304402206639c6e05e3b9d2675a7f3876286bdf7584fe2bbd15e0ce52dd4e02c0092cdc60220757d60b0a61fc95ada79d23746744c72bac1545a75ff6c2c7cdb6ae04e7e9592012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0ce8030000000000000151e9030000000000000151ea030000000000000151eb030000000000000151ec030000000000000151ed030000000000000151ee030000000000000151ef030000000000000151f0030000000000000151f1030000000000000151f2030000000000000151f30300000000000001510248304502210082219a54f61bf126bfc3fa068c6e33831222d1d7138c6faa9d33ca87fd4202d6022063f9902519624254d7c2c8ea7ba2d66ae975e4e229ae38043973ec707d5d4a83012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022017fb58502475848c1b09f162cb1688d0920ff7f142bed0ef904da2ccc88b168f02201798afa61850c65e77889cbcd648a5703b487895517c88f85cdd18b021ee246a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000000247304402202830b7926e488da75782c81a54cd281720890d1af064629ebf2e31bf9f5435f30220089afaa8b455bbeb7d9b9c3fe1ed37d07685ade8455c76472cda424d93e4074a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022026326fcdae9207b596c2b05921dbac11d81040c4d40378513670f19d9f4af893022034ecd7a282c0163b89aaa62c22ec202cef4736c58cd251649bad0d8139bcbf55012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71024730440220214978daeb2f38cd426ee6e2f44131a33d6b191af1c216247f1dd7d74c16d84a02205fdc05529b0bc0c430b4d5987264d9d075351c4f4484c16e91662e90a72aab24012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402204a6e9f199dc9672cf2ff8094aaa784363be1eb62b679f7ff2df361124f1dca3302205eeb11f70fab5355c9c8ad1a0700ea355d315e334822fa182227e9815308ee8f012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "76a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac", 5, 1005, "7eeb16881410e2412ac103b8e44df673df25fab04d64da2e8eb7cf4f937f9860", 1}, + { "01000000e0f98ad94ad3210a543e7af8dd9f61cefc035dc6bf378ae3827315fa425281ebc0cbc41638b87e0f44ba232e0c48d8e6afadd74e1f762aae84e8cfa0ce5049830001000000000000000000000000000000000000000000000000000000000000060000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88acee03000000000000ffffffff0000000001000000", "0100000000010c00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff0001000000000000000000000000000000000000000000000000000000000000020000006a473044022026c2e65b33fcd03b2a3b0f25030f0244bd23cc45ae4dec0f48ae62255b1998a00220463aa3982b718d593a6b9e0044513fd67a5009c2fdccc59992cffc2b167889f4012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000030000006a4730440220008bd8382911218dcb4c9f2e75bf5c5c3635f2f2df49b36994fde85b0be21a1a02205a539ef10fb4c778b522c1be852352ea06c67ab74200977c722b0bc68972575a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000040000006b483045022100d9436c32ff065127d71e1a20e319e4fe0a103ba0272743dbd8580be4659ab5d302203fd62571ee1fe790b182d078ecfd092a509eac112bea558d122974ef9cc012c7012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000050000006a47304402200e2c149b114ec546015c13b2b464bbcb0cdc5872e6775787527af6cbc4830b6c02207e9396c6979fb15a9a2b96ca08a633866eaf20dc0ff3c03e512c1d5a1654f148012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000060000006b483045022100b20e70d897dc15420bccb5e0d3e208d27bdd676af109abbd3f88dbdb7721e6d6022005836e663173fbdfe069f54cde3c2decd3d0ea84378092a5d9d85ec8642e8a41012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff00010000000000000000000000000000000000000000000000000000000000000700000000ffffffff00010000000000000000000000000000000000000000000000000000000000000800000000ffffffff00010000000000000000000000000000000000000000000000000000000000000900000000ffffffff00010000000000000000000000000000000000000000000000000000000000000a00000000ffffffff00010000000000000000000000000000000000000000000000000000000000000b0000006a47304402206639c6e05e3b9d2675a7f3876286bdf7584fe2bbd15e0ce52dd4e02c0092cdc60220757d60b0a61fc95ada79d23746744c72bac1545a75ff6c2c7cdb6ae04e7e9592012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0ce8030000000000000151e9030000000000000151ea030000000000000151eb030000000000000151ec030000000000000151ed030000000000000151ee030000000000000151ef030000000000000151f0030000000000000151f1030000000000000151f2030000000000000151f30300000000000001510248304502210082219a54f61bf126bfc3fa068c6e33831222d1d7138c6faa9d33ca87fd4202d6022063f9902519624254d7c2c8ea7ba2d66ae975e4e229ae38043973ec707d5d4a83012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022017fb58502475848c1b09f162cb1688d0920ff7f142bed0ef904da2ccc88b168f02201798afa61850c65e77889cbcd648a5703b487895517c88f85cdd18b021ee246a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000000247304402202830b7926e488da75782c81a54cd281720890d1af064629ebf2e31bf9f5435f30220089afaa8b455bbeb7d9b9c3fe1ed37d07685ade8455c76472cda424d93e4074a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022026326fcdae9207b596c2b05921dbac11d81040c4d40378513670f19d9f4af893022034ecd7a282c0163b89aaa62c22ec202cef4736c58cd251649bad0d8139bcbf55012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71024730440220214978daeb2f38cd426ee6e2f44131a33d6b191af1c216247f1dd7d74c16d84a02205fdc05529b0bc0c430b4d5987264d9d075351c4f4484c16e91662e90a72aab24012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402204a6e9f199dc9672cf2ff8094aaa784363be1eb62b679f7ff2df361124f1dca3302205eeb11f70fab5355c9c8ad1a0700ea355d315e334822fa182227e9815308ee8f012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "76a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac", 6, 1006, "29257738985d6819763287f06039feed5c31ebb9851eb8205a4977f88d1e6755", 1}, + { "01000000e0f98ad94ad3210a543e7af8dd9f61cefc035dc6bf378ae3827315fa425281ebc0cbc41638b87e0f44ba232e0c48d8e6afadd74e1f762aae84e8cfa0ce5049830001000000000000000000000000000000000000000000000000000000000000070000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fef03000000000000ffffffff0000000001000000", "0100000000010c00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff0001000000000000000000000000000000000000000000000000000000000000020000006a473044022026c2e65b33fcd03b2a3b0f25030f0244bd23cc45ae4dec0f48ae62255b1998a00220463aa3982b718d593a6b9e0044513fd67a5009c2fdccc59992cffc2b167889f4012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000030000006a4730440220008bd8382911218dcb4c9f2e75bf5c5c3635f2f2df49b36994fde85b0be21a1a02205a539ef10fb4c778b522c1be852352ea06c67ab74200977c722b0bc68972575a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000040000006b483045022100d9436c32ff065127d71e1a20e319e4fe0a103ba0272743dbd8580be4659ab5d302203fd62571ee1fe790b182d078ecfd092a509eac112bea558d122974ef9cc012c7012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000050000006a47304402200e2c149b114ec546015c13b2b464bbcb0cdc5872e6775787527af6cbc4830b6c02207e9396c6979fb15a9a2b96ca08a633866eaf20dc0ff3c03e512c1d5a1654f148012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000060000006b483045022100b20e70d897dc15420bccb5e0d3e208d27bdd676af109abbd3f88dbdb7721e6d6022005836e663173fbdfe069f54cde3c2decd3d0ea84378092a5d9d85ec8642e8a41012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff00010000000000000000000000000000000000000000000000000000000000000700000000ffffffff00010000000000000000000000000000000000000000000000000000000000000800000000ffffffff00010000000000000000000000000000000000000000000000000000000000000900000000ffffffff00010000000000000000000000000000000000000000000000000000000000000a00000000ffffffff00010000000000000000000000000000000000000000000000000000000000000b0000006a47304402206639c6e05e3b9d2675a7f3876286bdf7584fe2bbd15e0ce52dd4e02c0092cdc60220757d60b0a61fc95ada79d23746744c72bac1545a75ff6c2c7cdb6ae04e7e9592012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0ce8030000000000000151e9030000000000000151ea030000000000000151eb030000000000000151ec030000000000000151ed030000000000000151ee030000000000000151ef030000000000000151f0030000000000000151f1030000000000000151f2030000000000000151f30300000000000001510248304502210082219a54f61bf126bfc3fa068c6e33831222d1d7138c6faa9d33ca87fd4202d6022063f9902519624254d7c2c8ea7ba2d66ae975e4e229ae38043973ec707d5d4a83012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022017fb58502475848c1b09f162cb1688d0920ff7f142bed0ef904da2ccc88b168f02201798afa61850c65e77889cbcd648a5703b487895517c88f85cdd18b021ee246a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000000247304402202830b7926e488da75782c81a54cd281720890d1af064629ebf2e31bf9f5435f30220089afaa8b455bbeb7d9b9c3fe1ed37d07685ade8455c76472cda424d93e4074a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022026326fcdae9207b596c2b05921dbac11d81040c4d40378513670f19d9f4af893022034ecd7a282c0163b89aaa62c22ec202cef4736c58cd251649bad0d8139bcbf55012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71024730440220214978daeb2f38cd426ee6e2f44131a33d6b191af1c216247f1dd7d74c16d84a02205fdc05529b0bc0c430b4d5987264d9d075351c4f4484c16e91662e90a72aab24012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402204a6e9f199dc9672cf2ff8094aaa784363be1eb62b679f7ff2df361124f1dca3302205eeb11f70fab5355c9c8ad1a0700ea355d315e334822fa182227e9815308ee8f012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 7, 1007, "d24edb1bf2186a169ab021dc2b5dc781a72be5ec1006bda95b3c2c1bf06dc71d", 1}, + { "01000000e0f98ad94ad3210a543e7af8dd9f61cefc035dc6bf378ae3827315fa425281ebc0cbc41638b87e0f44ba232e0c48d8e6afadd74e1f762aae84e8cfa0ce5049830001000000000000000000000000000000000000000000000000000000000000080000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3ff003000000000000ffffffff0000000001000000", "0100000000010c00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff0001000000000000000000000000000000000000000000000000000000000000020000006a473044022026c2e65b33fcd03b2a3b0f25030f0244bd23cc45ae4dec0f48ae62255b1998a00220463aa3982b718d593a6b9e0044513fd67a5009c2fdccc59992cffc2b167889f4012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000030000006a4730440220008bd8382911218dcb4c9f2e75bf5c5c3635f2f2df49b36994fde85b0be21a1a02205a539ef10fb4c778b522c1be852352ea06c67ab74200977c722b0bc68972575a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000040000006b483045022100d9436c32ff065127d71e1a20e319e4fe0a103ba0272743dbd8580be4659ab5d302203fd62571ee1fe790b182d078ecfd092a509eac112bea558d122974ef9cc012c7012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000050000006a47304402200e2c149b114ec546015c13b2b464bbcb0cdc5872e6775787527af6cbc4830b6c02207e9396c6979fb15a9a2b96ca08a633866eaf20dc0ff3c03e512c1d5a1654f148012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000060000006b483045022100b20e70d897dc15420bccb5e0d3e208d27bdd676af109abbd3f88dbdb7721e6d6022005836e663173fbdfe069f54cde3c2decd3d0ea84378092a5d9d85ec8642e8a41012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff00010000000000000000000000000000000000000000000000000000000000000700000000ffffffff00010000000000000000000000000000000000000000000000000000000000000800000000ffffffff00010000000000000000000000000000000000000000000000000000000000000900000000ffffffff00010000000000000000000000000000000000000000000000000000000000000a00000000ffffffff00010000000000000000000000000000000000000000000000000000000000000b0000006a47304402206639c6e05e3b9d2675a7f3876286bdf7584fe2bbd15e0ce52dd4e02c0092cdc60220757d60b0a61fc95ada79d23746744c72bac1545a75ff6c2c7cdb6ae04e7e9592012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0ce8030000000000000151e9030000000000000151ea030000000000000151eb030000000000000151ec030000000000000151ed030000000000000151ee030000000000000151ef030000000000000151f0030000000000000151f1030000000000000151f2030000000000000151f30300000000000001510248304502210082219a54f61bf126bfc3fa068c6e33831222d1d7138c6faa9d33ca87fd4202d6022063f9902519624254d7c2c8ea7ba2d66ae975e4e229ae38043973ec707d5d4a83012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022017fb58502475848c1b09f162cb1688d0920ff7f142bed0ef904da2ccc88b168f02201798afa61850c65e77889cbcd648a5703b487895517c88f85cdd18b021ee246a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000000247304402202830b7926e488da75782c81a54cd281720890d1af064629ebf2e31bf9f5435f30220089afaa8b455bbeb7d9b9c3fe1ed37d07685ade8455c76472cda424d93e4074a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022026326fcdae9207b596c2b05921dbac11d81040c4d40378513670f19d9f4af893022034ecd7a282c0163b89aaa62c22ec202cef4736c58cd251649bad0d8139bcbf55012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71024730440220214978daeb2f38cd426ee6e2f44131a33d6b191af1c216247f1dd7d74c16d84a02205fdc05529b0bc0c430b4d5987264d9d075351c4f4484c16e91662e90a72aab24012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402204a6e9f199dc9672cf2ff8094aaa784363be1eb62b679f7ff2df361124f1dca3302205eeb11f70fab5355c9c8ad1a0700ea355d315e334822fa182227e9815308ee8f012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 8, 1008, "1b067ef11ec9bc35bc925b9790974ccdec6276101eb337b6321eda2c72eed8cb", 1}, + { "01000000e0f98ad94ad3210a543e7af8dd9f61cefc035dc6bf378ae3827315fa425281ebc0cbc41638b87e0f44ba232e0c48d8e6afadd74e1f762aae84e8cfa0ce5049830001000000000000000000000000000000000000000000000000000000000000090000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3ff103000000000000ffffffff0000000001000000", "0100000000010c00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff0001000000000000000000000000000000000000000000000000000000000000020000006a473044022026c2e65b33fcd03b2a3b0f25030f0244bd23cc45ae4dec0f48ae62255b1998a00220463aa3982b718d593a6b9e0044513fd67a5009c2fdccc59992cffc2b167889f4012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000030000006a4730440220008bd8382911218dcb4c9f2e75bf5c5c3635f2f2df49b36994fde85b0be21a1a02205a539ef10fb4c778b522c1be852352ea06c67ab74200977c722b0bc68972575a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000040000006b483045022100d9436c32ff065127d71e1a20e319e4fe0a103ba0272743dbd8580be4659ab5d302203fd62571ee1fe790b182d078ecfd092a509eac112bea558d122974ef9cc012c7012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000050000006a47304402200e2c149b114ec546015c13b2b464bbcb0cdc5872e6775787527af6cbc4830b6c02207e9396c6979fb15a9a2b96ca08a633866eaf20dc0ff3c03e512c1d5a1654f148012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000060000006b483045022100b20e70d897dc15420bccb5e0d3e208d27bdd676af109abbd3f88dbdb7721e6d6022005836e663173fbdfe069f54cde3c2decd3d0ea84378092a5d9d85ec8642e8a41012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff00010000000000000000000000000000000000000000000000000000000000000700000000ffffffff00010000000000000000000000000000000000000000000000000000000000000800000000ffffffff00010000000000000000000000000000000000000000000000000000000000000900000000ffffffff00010000000000000000000000000000000000000000000000000000000000000a00000000ffffffff00010000000000000000000000000000000000000000000000000000000000000b0000006a47304402206639c6e05e3b9d2675a7f3876286bdf7584fe2bbd15e0ce52dd4e02c0092cdc60220757d60b0a61fc95ada79d23746744c72bac1545a75ff6c2c7cdb6ae04e7e9592012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0ce8030000000000000151e9030000000000000151ea030000000000000151eb030000000000000151ec030000000000000151ed030000000000000151ee030000000000000151ef030000000000000151f0030000000000000151f1030000000000000151f2030000000000000151f30300000000000001510248304502210082219a54f61bf126bfc3fa068c6e33831222d1d7138c6faa9d33ca87fd4202d6022063f9902519624254d7c2c8ea7ba2d66ae975e4e229ae38043973ec707d5d4a83012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022017fb58502475848c1b09f162cb1688d0920ff7f142bed0ef904da2ccc88b168f02201798afa61850c65e77889cbcd648a5703b487895517c88f85cdd18b021ee246a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000000247304402202830b7926e488da75782c81a54cd281720890d1af064629ebf2e31bf9f5435f30220089afaa8b455bbeb7d9b9c3fe1ed37d07685ade8455c76472cda424d93e4074a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022026326fcdae9207b596c2b05921dbac11d81040c4d40378513670f19d9f4af893022034ecd7a282c0163b89aaa62c22ec202cef4736c58cd251649bad0d8139bcbf55012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71024730440220214978daeb2f38cd426ee6e2f44131a33d6b191af1c216247f1dd7d74c16d84a02205fdc05529b0bc0c430b4d5987264d9d075351c4f4484c16e91662e90a72aab24012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402204a6e9f199dc9672cf2ff8094aaa784363be1eb62b679f7ff2df361124f1dca3302205eeb11f70fab5355c9c8ad1a0700ea355d315e334822fa182227e9815308ee8f012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 9, 1009, "4fa849a1e73000617192f5bce3f328d1848e9029d5a598a1f2b07157a7132120", 1}, + { "01000000e0f98ad94ad3210a543e7af8dd9f61cefc035dc6bf378ae3827315fa425281ebc0cbc41638b87e0f44ba232e0c48d8e6afadd74e1f762aae84e8cfa0ce50498300010000000000000000000000000000000000000000000000000000000000000a0000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3ff203000000000000ffffffff0000000001000000", "0100000000010c00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff0001000000000000000000000000000000000000000000000000000000000000020000006a473044022026c2e65b33fcd03b2a3b0f25030f0244bd23cc45ae4dec0f48ae62255b1998a00220463aa3982b718d593a6b9e0044513fd67a5009c2fdccc59992cffc2b167889f4012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000030000006a4730440220008bd8382911218dcb4c9f2e75bf5c5c3635f2f2df49b36994fde85b0be21a1a02205a539ef10fb4c778b522c1be852352ea06c67ab74200977c722b0bc68972575a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000040000006b483045022100d9436c32ff065127d71e1a20e319e4fe0a103ba0272743dbd8580be4659ab5d302203fd62571ee1fe790b182d078ecfd092a509eac112bea558d122974ef9cc012c7012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000050000006a47304402200e2c149b114ec546015c13b2b464bbcb0cdc5872e6775787527af6cbc4830b6c02207e9396c6979fb15a9a2b96ca08a633866eaf20dc0ff3c03e512c1d5a1654f148012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000060000006b483045022100b20e70d897dc15420bccb5e0d3e208d27bdd676af109abbd3f88dbdb7721e6d6022005836e663173fbdfe069f54cde3c2decd3d0ea84378092a5d9d85ec8642e8a41012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff00010000000000000000000000000000000000000000000000000000000000000700000000ffffffff00010000000000000000000000000000000000000000000000000000000000000800000000ffffffff00010000000000000000000000000000000000000000000000000000000000000900000000ffffffff00010000000000000000000000000000000000000000000000000000000000000a00000000ffffffff00010000000000000000000000000000000000000000000000000000000000000b0000006a47304402206639c6e05e3b9d2675a7f3876286bdf7584fe2bbd15e0ce52dd4e02c0092cdc60220757d60b0a61fc95ada79d23746744c72bac1545a75ff6c2c7cdb6ae04e7e9592012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0ce8030000000000000151e9030000000000000151ea030000000000000151eb030000000000000151ec030000000000000151ed030000000000000151ee030000000000000151ef030000000000000151f0030000000000000151f1030000000000000151f2030000000000000151f30300000000000001510248304502210082219a54f61bf126bfc3fa068c6e33831222d1d7138c6faa9d33ca87fd4202d6022063f9902519624254d7c2c8ea7ba2d66ae975e4e229ae38043973ec707d5d4a83012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022017fb58502475848c1b09f162cb1688d0920ff7f142bed0ef904da2ccc88b168f02201798afa61850c65e77889cbcd648a5703b487895517c88f85cdd18b021ee246a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000000247304402202830b7926e488da75782c81a54cd281720890d1af064629ebf2e31bf9f5435f30220089afaa8b455bbeb7d9b9c3fe1ed37d07685ade8455c76472cda424d93e4074a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022026326fcdae9207b596c2b05921dbac11d81040c4d40378513670f19d9f4af893022034ecd7a282c0163b89aaa62c22ec202cef4736c58cd251649bad0d8139bcbf55012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71024730440220214978daeb2f38cd426ee6e2f44131a33d6b191af1c216247f1dd7d74c16d84a02205fdc05529b0bc0c430b4d5987264d9d075351c4f4484c16e91662e90a72aab24012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402204a6e9f199dc9672cf2ff8094aaa784363be1eb62b679f7ff2df361124f1dca3302205eeb11f70fab5355c9c8ad1a0700ea355d315e334822fa182227e9815308ee8f012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 10, 1010, "022da6ce7b51de3964e59e4e9a6e66a1e87a6d7a32d4cc100e793deb39bb6611", 1}, + { "01000000e0f98ad94ad3210a543e7af8dd9f61cefc035dc6bf378ae3827315fa425281ebc0cbc41638b87e0f44ba232e0c48d8e6afadd74e1f762aae84e8cfa0ce50498300010000000000000000000000000000000000000000000000000000000000000b0000001976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88acf303000000000000ffffffff0000000001000000", "0100000000010c00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff0001000000000000000000000000000000000000000000000000000000000000020000006a473044022026c2e65b33fcd03b2a3b0f25030f0244bd23cc45ae4dec0f48ae62255b1998a00220463aa3982b718d593a6b9e0044513fd67a5009c2fdccc59992cffc2b167889f4012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000030000006a4730440220008bd8382911218dcb4c9f2e75bf5c5c3635f2f2df49b36994fde85b0be21a1a02205a539ef10fb4c778b522c1be852352ea06c67ab74200977c722b0bc68972575a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000040000006b483045022100d9436c32ff065127d71e1a20e319e4fe0a103ba0272743dbd8580be4659ab5d302203fd62571ee1fe790b182d078ecfd092a509eac112bea558d122974ef9cc012c7012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000050000006a47304402200e2c149b114ec546015c13b2b464bbcb0cdc5872e6775787527af6cbc4830b6c02207e9396c6979fb15a9a2b96ca08a633866eaf20dc0ff3c03e512c1d5a1654f148012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0001000000000000000000000000000000000000000000000000000000000000060000006b483045022100b20e70d897dc15420bccb5e0d3e208d27bdd676af109abbd3f88dbdb7721e6d6022005836e663173fbdfe069f54cde3c2decd3d0ea84378092a5d9d85ec8642e8a41012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff00010000000000000000000000000000000000000000000000000000000000000700000000ffffffff00010000000000000000000000000000000000000000000000000000000000000800000000ffffffff00010000000000000000000000000000000000000000000000000000000000000900000000ffffffff00010000000000000000000000000000000000000000000000000000000000000a00000000ffffffff00010000000000000000000000000000000000000000000000000000000000000b0000006a47304402206639c6e05e3b9d2675a7f3876286bdf7584fe2bbd15e0ce52dd4e02c0092cdc60220757d60b0a61fc95ada79d23746744c72bac1545a75ff6c2c7cdb6ae04e7e9592012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ffffffff0ce8030000000000000151e9030000000000000151ea030000000000000151eb030000000000000151ec030000000000000151ed030000000000000151ee030000000000000151ef030000000000000151f0030000000000000151f1030000000000000151f2030000000000000151f30300000000000001510248304502210082219a54f61bf126bfc3fa068c6e33831222d1d7138c6faa9d33ca87fd4202d6022063f9902519624254d7c2c8ea7ba2d66ae975e4e229ae38043973ec707d5d4a83012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022017fb58502475848c1b09f162cb1688d0920ff7f142bed0ef904da2ccc88b168f02201798afa61850c65e77889cbcd648a5703b487895517c88f85cdd18b021ee246a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000000247304402202830b7926e488da75782c81a54cd281720890d1af064629ebf2e31bf9f5435f30220089afaa8b455bbeb7d9b9c3fe1ed37d07685ade8455c76472cda424d93e4074a012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7102473044022026326fcdae9207b596c2b05921dbac11d81040c4d40378513670f19d9f4af893022034ecd7a282c0163b89aaa62c22ec202cef4736c58cd251649bad0d8139bcbf55012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71024730440220214978daeb2f38cd426ee6e2f44131a33d6b191af1c216247f1dd7d74c16d84a02205fdc05529b0bc0c430b4d5987264d9d075351c4f4484c16e91662e90a72aab24012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402204a6e9f199dc9672cf2ff8094aaa784363be1eb62b679f7ff2df361124f1dca3302205eeb11f70fab5355c9c8ad1a0700ea355d315e334822fa182227e9815308ee8f012103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710000000000", "76a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac", 11, 1011, "a3712ef6f6dd8a8fb324e81b4cd593055acb39ef96e7daa4d7c883aa07ac0cfa", 1}, + { "01000000010001000000000000000000000000000000000000000000000000000000000000000000001660144c9c3dfac4207d5d8cb89df5722cb3d712385e3fffffffff01e80300000000000001510000000001000000", "010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff01e803000000000000015100000000", "60144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 0, 1000, "181a02887447e1f618df3d607299a66d0416a4d5d333e7fa7baa89d941cc2769", 0}, + { "0100000071dbcb97997570a86397faebd5d73c333193297feb8626e48b518526ce9db527752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632ad0001000000000000000000000000000000000000000000000000000000000000000000000151e803000000000000ffffffff0000000001000000", "0100000000010200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff01d00700000000000001510003483045022100e078de4e96a0e05dcdc0a414124dd8475782b5f3f0ed3f607919e9a5eeeb22bf02201de309b3a3109adb3de8074b3610d4cf454c49b61247a2779a0bcbf31c889333032103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc711976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac00000000", "51", 0, 1000, "a022bcfdbc9dab2a073e0acf192039e788b30de49024720381e977d31b0ee031", 1}, + { "0100000071dbcb97997570a86397faebd5d73c333193297feb8626e48b518526ce9db527752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632ad0001000000000000000000000000000000000000000000000000000000000000010000002200204d6c2a32c87821d68fc016fca70797abdb80df6cd84651d40a9300c6bad79e62e803000000000000ffffffff0000000001000000", "0100000000010200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff01d00700000000000001510003483045022100e078de4e96a0e05dcdc0a414124dd8475782b5f3f0ed3f607919e9a5eeeb22bf02201de309b3a3109adb3de8074b3610d4cf454c49b61247a2779a0bcbf31c889333032103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc711976a9144c9c3dfac4207d5d8cb89df5722cb3d712385e3f88ac00000000", "00204d6c2a32c87821d68fc016fca70797abdb80df6cd84651d40a9300c6bad79e62", 1, 1000, "d078b5978f8d96476e32875a2c611d29e01ae917ba621c9c6eb2e2811531af90", 1}, + { "010000000100010000000000000000000000000000000000000000000000000000000000000000000003600101ffffffff01e80300000000000001510000000001000000", "010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff01e803000000000000015100000000", "600101", 0, 1000, "113b7af2ef783b71ac109cb62388a66333b5ae4b293e141f95b3f670767cce45", 0}, + { "01000000010001000000000000000000000000000000000000000000000000000000000000000000002b6029ff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3dbff0000000000000000ffffffff01e80300000000000001510000000001000000", "010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff01e803000000000000015100000000", "6029ff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3dbff0000000000000000", 0, 1000, "ed759a8f58294c7db3f8bb9565d375045d520ff56bb50678084649dfc9311f9f", 0}, + { "0100000001000100000000000000000000000000000000000000000000000000000000000000000000050110020001ffffffff01e80300000000000001510000000001000000", "010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff01e803000000000000015100000000", "0110020001", 0, 1000, "b94fe19666c3c32c06e5cf0bb276b4f5d021da3d8e51926c95b69a2db0c3f9c7", 0}, + { "010000000100010000000000000000000000000000000000000000000000000000000000000000000005604c020001ffffffff01e80300000000000001510000000001000000", "010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff01e803000000000000015100000000", "604c020001", 0, 1000, "90d8dee6903b8072df9cb77a18985b302c928b582d28e81d5482c66145301062", 0}, + { "0100000071dbcb97997570a86397faebd5d73c333193297feb8626e48b518526ce9db527752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632ad0001000000000000000000000000000000000000000000000000000000000000000000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fe803000000000000ffffffff0000000001000000", "0100000000010200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff02e8030000000000000151e90300000000000001510247304402206d59682663faab5e4cb733c562e22cdae59294895929ec38d7c016621ff90da0022063ef0af5f970afe8a45ea836e3509b8847ed39463253106ac17d19c437d3d56b832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710248304502210085001a820bfcbc9f9de0298af714493f8a37b3b354bfd21a7097c3e009f2018c022050a8b4dbc8155d4d04da2f5cdd575dcf8dd0108de8bec759bd897ea01ecb3af7832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 0, 1000, "1447e4e80fb49e2ce28bf8b2b64814ed40a72583eeb27b2fcd4afa8694c66d9b", 1}, + { "0100000071dbcb97997570a86397faebd5d73c333193297feb8626e48b518526ce9db527752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632ad0001000000000000000000000000000000000000000000000000000000000000010000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fe903000000000000ffffffff0000000001000000", "0100000000010200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff02e8030000000000000151e90300000000000001510247304402206d59682663faab5e4cb733c562e22cdae59294895929ec38d7c016621ff90da0022063ef0af5f970afe8a45ea836e3509b8847ed39463253106ac17d19c437d3d56b832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710248304502210085001a820bfcbc9f9de0298af714493f8a37b3b354bfd21a7097c3e009f2018c022050a8b4dbc8155d4d04da2f5cdd575dcf8dd0108de8bec759bd897ea01ecb3af7832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1, 1001, "f1d29240a18ecf01c547a4279e08863268fe7bbf76a420777aee6de5391696ad", 1}, + { "010000000dbf707e65dfbbcd7cbc59af9ebb710ad71d5e889b36f1e3d25538c7757b6848752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632ad0001000000000000000000000000000000000000000000000000000000000000010000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fe903000000000000ffffffff0000000001000000", "0100000000010200010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff02e9030000000000000151e80300000000000001510248304502210085001a820bfcbc9f9de0298af714493f8a37b3b354bfd21a7097c3e009f2018c022050a8b4dbc8155d4d04da2f5cdd575dcf8dd0108de8bec759bd897ea01ecb3af7832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402206d59682663faab5e4cb733c562e22cdae59294895929ec38d7c016621ff90da0022063ef0af5f970afe8a45ea836e3509b8847ed39463253106ac17d19c437d3d56b832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 0, 1001, "4b9654c559e6038288eb37c71bd5d5037c20eafeeab88c9b07c0620f88de2e8a", 1}, + { "010000000dbf707e65dfbbcd7cbc59af9ebb710ad71d5e889b36f1e3d25538c7757b6848752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632ad0001000000000000000000000000000000000000000000000000000000000000000000001600144c9c3dfac4207d5d8cb89df5722cb3d712385e3fe803000000000000ffffffff0000000001000000", "0100000000010200010000000000000000000000000000000000000000000000000000000000000100000000ffffffff00010000000000000000000000000000000000000000000000000000000000000000000000ffffffff02e9030000000000000151e80300000000000001510248304502210085001a820bfcbc9f9de0298af714493f8a37b3b354bfd21a7097c3e009f2018c022050a8b4dbc8155d4d04da2f5cdd575dcf8dd0108de8bec759bd897ea01ecb3af7832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc710247304402206d59682663faab5e4cb733c562e22cdae59294895929ec38d7c016621ff90da0022063ef0af5f970afe8a45ea836e3509b8847ed39463253106ac17d19c437d3d56b832103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc7100000000", "00144c9c3dfac4207d5d8cb89df5722cb3d712385e3f", 1, 1000, "c8d2788f5a0addd3f81df9a4c1ecf67329e09e5e951309a78486e439669ccb13", 1}, + { "0100000002000100000000000000000000000000000000000000000000000000000000000000000000232103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71acffffffff00010000000000000000000000000000000000000000000000000000000000000100000000ffffffff02e8030000000000000151e90300000000000001510000000001000000", "01000000020001000000000000000000000000000000000000000000000000000000000000000000004847304402202a0b4b1294d70540235ae033d78e64b4897ec859c7b6f1b2b1d8a02e1d46006702201445e756d2254b0f1dfda9ab8e1e1bc26df9668077403204f32d16a49a36eb6983ffffffff00010000000000000000000000000000000000000000000000000000000000000100000049483045022100acb96cfdbda6dc94b489fd06f2d720983b5f350e31ba906cdbd800773e80b21c02200d74ea5bdf114212b4bbe9ed82c36d2e369e302dff57cb60d01c428f0bd3daab83ffffffff02e8030000000000000151e903000000000000015100000000", "2103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ac", 0, 1000, "01a08aa0be7f65ed023ea5b75dccc07190f3ad690c9c381de2fe76be7e54a626", 0}, + { "010000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff000100000000000000000000000000000000000000000000000000000000000001000000232103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71acffffffff02e8030000000000000151e90300000000000001510000000001000000", "01000000020001000000000000000000000000000000000000000000000000000000000000000000004847304402202a0b4b1294d70540235ae033d78e64b4897ec859c7b6f1b2b1d8a02e1d46006702201445e756d2254b0f1dfda9ab8e1e1bc26df9668077403204f32d16a49a36eb6983ffffffff00010000000000000000000000000000000000000000000000000000000000000100000049483045022100acb96cfdbda6dc94b489fd06f2d720983b5f350e31ba906cdbd800773e80b21c02200d74ea5bdf114212b4bbe9ed82c36d2e369e302dff57cb60d01c428f0bd3daab83ffffffff02e8030000000000000151e903000000000000015100000000", "2103596d3451025c19dbbdeb932d6bf8bfb4ad499b95b6f88db8899efac102e5fc71ac", 1, 1001, "19a29d34cfa3a3f7b6e2b4aa3148c361ed3303802f576d6a9619b1447a3ec94d", 0}, + { "01000000ef546acf4a020de3898d1b8956176bb507e6211b5ed3619cd08b6ea7e2a09d41752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632adfe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e000000002321036d5c20fa14fb2f635474c1dc4ef5909d4568e5569b79fc94d3448486e14685f8ac902f500900000000ffffffff0000000001000000", "01000000000102fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e000000004847304402200af4e47c9b9629dbecc21f73af989bdaa911f7e6f6c2e9394588a3aa68f81e9902204f3fcf6ade7e5abb1295b6774c8e0abd94ae62217367096bc02ee5e435b67da201ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f8145e5acadf23f751864167f32e0963f788ac000347304402200de66acf4527789bfda55fc5459e214fa6083f936b430a762c629656216805ac0220396f550692cd347171cbc1ef1f51e15282e837bb2b30860dc77c8f78bc8501e503473044022027dc95ad6b740fe5129e7e62a75dd00f291a2aeb1200b84b09d9e3789406b6c002201a9ecd315dd6a0e632ab20bbb98948bc0c6fb204f2c286963bb48517a7058e27034721026dccc749adc2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880aeadab210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac00000000", "21036d5c20fa14fb2f635474c1dc4ef5909d4568e5569b79fc94d3448486e14685f8ac", 0, 156250000, "ff478a5f7e83f21fa83c53683d3434e9e75b48c432b0f351c4bd7cb19b33717d", 1}, + { "01000000ef546acf4a020de3898d1b8956176bb507e6211b5ed3619cd08b6ea7e2a09d41752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632ad0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f8000000002200205d1b56b63d714eebe542309525f484b7e9d6f686b3781b6f61ef925d66d6f6a00011102401000000ffffffff0000000001000000", "01000000000102fe3dc9208094f3ffd12645477b3dc56f60ec4fa8e6f5d67c565d1c6b9216b36e000000004847304402200af4e47c9b9629dbecc21f73af989bdaa911f7e6f6c2e9394588a3aa68f81e9902204f3fcf6ade7e5abb1295b6774c8e0abd94ae62217367096bc02ee5e435b67da201ffffffff0815cf020f013ed6cf91d29f4202e8a58726b1ac6c79da47c23d1bee0a6925f80000000000ffffffff0100f2052a010000001976a914a30741f8145e5acadf23f751864167f32e0963f788ac000347304402200de66acf4527789bfda55fc5459e214fa6083f936b430a762c629656216805ac0220396f550692cd347171cbc1ef1f51e15282e837bb2b30860dc77c8f78bc8501e503473044022027dc95ad6b740fe5129e7e62a75dd00f291a2aeb1200b84b09d9e3789406b6c002201a9ecd315dd6a0e632ab20bbb98948bc0c6fb204f2c286963bb48517a7058e27034721026dccc749adc2a9d0d89497ac511f760f45c47dc5ed9cf352a58ac706453880aeadab210255a9626aebf5e29c0e6538428ba0d1dcf6ca98ffdf086aa8ced5e0d0215ea465ac00000000", "00205d1b56b63d714eebe542309525f484b7e9d6f686b3781b6f61ef925d66d6f6a0", 1, 4900000000, "2e91ec69ff86a50adfe5a9d3f150b72f919005e32c193be04a02e03dfa82f7f2", 1}, + { "01000000e08b54f3f059d43954e867282174e84f4d58f4a47ddab0576645277c2c857189752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632ade9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc00100000000220020ba468eea561b26301e4cf69fa34bde4ad60c81e70f059f045ca9a79931004a4dffffff0000000000ffffffff0000000001000000", "01000000000102e9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc0010000000000ffffffff80e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b0000000000ffffffff0280969800000000001976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac80969800000000001976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac02483045022100f6a10b8604e6dc910194b79ccfc93e1bc0ec7c03453caaa8987f7d6c3413566002206216229ede9b4d6ec2d325be245c5b508ff0339bf1794078e20bfe0babc7ffe683270063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac024730440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d13986da504502b8c3be59617e043552f506c46ff83275163ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac00000000", "0020ba468eea561b26301e4cf69fa34bde4ad60c81e70f059f045ca9a79931004a4d", 0, 16777215, "542910875137129694fca0e14909e2c3c96fa10d05ff9a33a78daf7b7cac75eb", 1}, + { "01000000e08b54f3f059d43954e867282174e84f4d58f4a47ddab0576645277c2c857189752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632ad80e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b00000000220020d9bbfbe56af7c4b7f960a70d7ea107156913d9e5a26b0a71429df5e097ca6537ffffff0000000000ffffffff0000000001000000", "01000000000102e9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc0010000000000ffffffff80e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b0000000000ffffffff0280969800000000001976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac80969800000000001976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac02483045022100f6a10b8604e6dc910194b79ccfc93e1bc0ec7c03453caaa8987f7d6c3413566002206216229ede9b4d6ec2d325be245c5b508ff0339bf1794078e20bfe0babc7ffe683270063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac024730440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d13986da504502b8c3be59617e043552f506c46ff83275163ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac00000000", "0020d9bbfbe56af7c4b7f960a70d7ea107156913d9e5a26b0a71429df5e097ca6537", 1, 16777215, "f14f4a27aae2e318926fa4fd8326f89932623c6bb4a409c0d46bb3ca2da03409", 1}, + { "01000000fd779c3e82f678209763aae112a9cfd96dd993287745210b556d21b7ce0df897752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632ad80e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b00000000220020d9bbfbe56af7c4b7f960a70d7ea107156913d9e5a26b0a71429df5e097ca6537ffffff0000000000ffffffff0000000001000000", "0100000000010280e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b0000000000ffffffffe9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc0010000000000ffffffff0280969800000000001976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac80969800000000001976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac024730440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d13986da504502b8c3be59617e043552f506c46ff83275163ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac02483045022100f6a10b8604e6dc910194b79ccfc93e1bc0ec7c03453caaa8987f7d6c3413566002206216229ede9b4d6ec2d325be245c5b508ff0339bf1794078e20bfe0babc7ffe683270063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac00000000", "0020d9bbfbe56af7c4b7f960a70d7ea107156913d9e5a26b0a71429df5e097ca6537", 0, 16777215, "8db8ee3b94be67a071807601d38691a7cc7239bc1bf5d976870b5e48492cc0dc", 1}, + { "01000000fd779c3e82f678209763aae112a9cfd96dd993287745210b556d21b7ce0df897752adad0a7b9ceca853768aebb6965eca126a62965f698a0c1bc43d83db632ade9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc00100000000220020ba468eea561b26301e4cf69fa34bde4ad60c81e70f059f045ca9a79931004a4dffffff0000000000ffffffff0000000001000000", "0100000000010280e68831516392fcd100d186b3c2c7b95c80b53c77e77c35ba03a66b429a2a1b0000000000ffffffffe9b542c5176808107ff1df906f46bb1f2583b16112b95ee5380665ba7fcfc0010000000000ffffffff0280969800000000001976a9146648a8cd4531e1ec47f35916de8e259237294d1e88ac80969800000000001976a914de4b231626ef508c9a74a8517e6783c0546d6b2888ac024730440220032521802a76ad7bf74d0e2c218b72cf0cbc867066e2e53db905ba37f130397e02207709e2188ed7f08f4c952d9d13986da504502b8c3be59617e043552f506c46ff83275163ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac02483045022100f6a10b8604e6dc910194b79ccfc93e1bc0ec7c03453caaa8987f7d6c3413566002206216229ede9b4d6ec2d325be245c5b508ff0339bf1794078e20bfe0babc7ffe683270063ab68210392972e2eb617b2388771abe27235fd5ac44af8e61693261550447a4c3e39da98ac00000000", "0020ba468eea561b26301e4cf69fa34bde4ad60c81e70f059f045ca9a79931004a4d", 1, 16777215, "0c2a2777e9fdd7b9ccd3b5abb681b8e53e9e38799dd700d8a64b37a65c213dbb", 1}, + { "0100000074afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa03bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e7066504436641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000017a9149993a429037b5d912407a71c252019287b8d27a587b168de3a00000000ffffffff0000000001000000", "0100000000010136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000023220020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac080047304402206ac44d672dac41f9b00e28f4df20c52eeb087207e8d758d76d92c6fab3b73e2b0220367750dbbe19290069cba53d096f44530e4f98acaa594810388cf7409a1870ce01473044022068c7946a43232757cbdf9176f009a928e1cd9a1a8c212f15c1e11ac9f2925d9002205b75f937ff2f9f3c1246e547e54f62e027f64eefa2695578cc6432cdabce271502473044022059ebf56d98010a932cf8ecfec54c48e6139ed6adb0728c09cbe1e4fa0915302e022007cd986c8fa870ff5d2b3a89139c9fe7e499259875357e20fcbb15571c76795403483045022100fbefd94bd0a488d50b79102b5dad4ab6ced30c4069f1eaa69a4b5a763414067e02203156c6a5c9cf88f91265f5a942e96213afae16d83321c8b31bb342142a14d16381483045022100a5263ea0553ba89221984bd7f0b13613db16e7a70c549a86de0cc0444141a407022005c360ef0ae5a5d4f9f2f87a56c1546cc8268cab08c73501d6b3be2e1e1a8a08824730440220525406a1482936d5a21888260dc165497a90a15669636d8edca6b9fe490d309c022032af0c646a34a44d1f4576bf6a4a74b67940f8faa84c7df9abe12a01a11e2b4783cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae00000000", "a9149993a429037b5d912407a71c252019287b8d27a587", 0, 987654321, "656651a8affc36f0949454b98ad907efe11a1ef37b076fe8fa6d38d32bd59921", 1}, + { "010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f1581b000017a9140c746489e2d83cdbb5b90b432773342ba809c13487ffffffff010100000000000000000000000001000000", "010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f1581b0000b64830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0121037a3fb04bcdb09eba90f69961ba1692a3528e45e67c85b200df820212d7594d334aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01ffffffff0101000000000000000000000000", "a9140c746489e2d83cdbb5b90b432773342ba809c13487", 0, 200000, "7807ff331d93240d9f48629f6b5ab45a7dd9f4e5bd5d038be14893f590893bd2", 0}, + { "01000000b67c76d200c6ce72962d919dc107884b9d5d0e26f2aea7474b46a1904c53359f3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e7066504469c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d00002200209e1be07558ea5cc8e02ed1d80c0911048afad949affa36d5c3951e3159dbea19400d030000000000ffffffff0000000001000000", "0100000000010169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff01010000000000000000034830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012102a9781d66b61fb5a7ef00ac5ad5bc6ffc78be7b44a566e3c87870e1079368df4c4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0100000000", "00209e1be07558ea5cc8e02ed1d80c0911048afad949affa36d5c3951e3159dbea19", 0, 200000, "eb9db740ca641347aca552f086bb0c3d3a61541a35bbf1bddd1e46ef8de3bdcf", 1}, + { "01000000019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a662896581b000017a9145748407f5ca5cdca53ba30b79040260770c9ee1b87ffffffff010100000000000000000000000001000000", "01000000019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a662896581b0000fd6f01004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c03959601522102cd74a2809ffeeed0092bc124fd79836706e41f048db3f6ae9df8708cefb83a1c2102e615999372426e46fd107b76eaf007156a507584aa2cc21de9eee3bdbd26d36c4c9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175ffffffff0101000000000000000000000000", "a9145748407f5ca5cdca53ba30b79040260770c9ee1b87", 0, 200000, "373cffc5f4b7707e1c8b463b18c9c95aae192677ad3618b9f958aa269e749b2b", 0}, +{ "0100000039283953eb1e26994dde57b7f9362a79a8c523e2f8deba943c27e826a005f1e63bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e706650449275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a6628964c1d00002200209b66c15b4e0b4eb49fa877982cafded24859fe5b0e2dbfbe4f0df1de7743fd52400d030000000000ffffffff0000000001000000", "010000000001019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a6628964c1d000000ffffffff0101000000000000000007004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960101022102966f109c54e85d3aee8321301136cedeb9fc710fdef58a9de8a73942f8e567c021034ffc99dd9a79dd3cb31e2ab3e0b09e0e67db41ac068c625cd1f491576016c84e9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c039596017500000000", "00209b66c15b4e0b4eb49fa877982cafded24859fe5b0e2dbfbe4f0df1de7743fd52", 0, 200000, "77753c03a5aa29406c9beb35d845caf94e79c997d5e7f2557a89de0a7223e39d", 1}, +}; + +static const struct txtest txvalid[] = + { + {1, {{"60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"}}, "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"}, + + {1, {{"60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"}}, "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a0048304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2bab01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"}, + + {1, {{"60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"}}, "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a01ff47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"}, + + {1, {{"60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"}}, "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000495147304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"}, + + {1, {{"60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"}}, "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000494f47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"}, + + {1, {{"406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602", 0, "DUP HASH160 0x14 0xdc44b1164188067c3a32d4780f5996fa14a4f2d9 EQUALVERIFY CHECKSIG"}}, "01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000", "P2SH"}, + + {1, {{"0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1"}}, "01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"}, + + {1, {{"0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"}}, "01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"}, + + {2, {{"b464e85df2a238416f8bdae11d120add610380ea07f4ef19c5f9dfd472f96c3d", 0, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"}, {"b7978cc96e59a8b13e0865d3f95657561a7f725be952438637475920bac9eb21", 1, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"}}, "01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000", "P2SH"}, + + {2, {{"0000000000000000000000000000000000000000000000000000000000000200", 0, "1"}, {"0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0xe52b482f2faa8ecbf0db344f93c84ac908557f33 EQUALVERIFY CHECKSIG"}}, "01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", "P2SH"}, + + {1, {{"0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"}}, "010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", "NONE"}, + + {1, {{"0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x8febbed40483661de6958d957412f82deed8e2f7 EQUAL"}}, "01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000", "P2SH"}, + + {1, {{"0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"}}, "01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000", "P2SH"}, + + {1, {{"0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL"}}, "01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510000000000000000015100000000", "P2SH"}, + + {1, {{"0000000000000000000000000000000000000000000000000000000000000000", -1, "1"}}, "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025151ffffffff010000000000000000015100000000", "P2SH"}, + + {1, {{"0000000000000000000000000000000000000000000000000000000000000000", -1, "1"}}, "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6451515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", "P2SH"}, + + {2, {{"0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"}, {"0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"}}, "010000000200010000000000000000000000000000000000000000000000000000000000000000000049483045022100d180fd2eb9140aeb4210c9204d3f358766eb53842b2a9473db687fa24b12a3cc022079781799cd4f038b85135bbe49ec2b57f306b2bb17101b17f71f000fcab2b6fb01ffffffff0002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", "P2SH"}, + + {2, {{"0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"}, {"0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"}}, "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", "P2SH"}, + + {3, {{"63cfa5a09dc540bf63e53713b82d9ea3692ca97cd608c384f2aa88e51a0aac70", 0, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"}, {"04e8d0fcf3846c6734477b98f0f3d4badfb78f020ee097a0be5fe347645b817d", 1, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"}, {"ee1377aff5d0579909e11782e1d2f5f7b84d26537be7f5516dd4e43373091f3f", 1, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"}}, "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000", "P2SH"}, + + {1, {{"c5510a5dd97a25f43175af1fe649b707b1df8e1a41489bac33a23087027a2f48", 0, "0x4c 0xae 0x606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e207460 DROP DUP HASH160 0x14 0xbfd7436b6265aa9de506f8a994f881ff08cc2872 EQUALVERIFY CHECKSIG"}}, "0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c5000000008b483045022100bf0bbae9bde51ad2b222e87fbf67530fbafc25c903519a1e5dcc52a32ff5844e022028c4d9ad49b006dd59974372a54291d5764be541574bb0c4dc208ec51f80b7190141049dd4aad62741dc27d5f267f7b70682eee22e7e9c1923b9c0957bdae0b96374569b460eb8d5b40d972e8c7c0ad441de3d94c4a29864b212d56050acb980b72b2bffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac00000000", "P2SH"}, + + {1, {{"b3da01dd4aae683c7aee4d5d8b52a540a508e1115f77cd7fa9a291243f501223", 0, "HASH160 0x14 0xb1ce99298d5f07364b57b1e5c9cc00be0b04a954 EQUAL"}}, "01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe0000483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa0148304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f4014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", "P2SH"}, + + {1, {{"cbebc4da731e8995fe97f6fadcd731b36ad40e5ecb31e38e904f6e5982fa09f7", 0, "0x2102085c6600657566acc2d6382a47bc3f324008d2aa10940dd7705a48aa2a5a5e33ac7c2103f5d0fb955f95dd6be6115ce85661db412ec6a08abcbfce7da0ba8297c6cc0ec4ac7c5379a820d68df9e32a147cffa36193c6f7c43a1c8c69cda530e1c6db354bfabdcfefaf3c875379a820f531f3041d3136701ea09067c53e7159c8f9b2746a56c3d82966c54bbc553226879a5479827701200122a59a5379827701200122a59a6353798277537982778779679a68"}}, "0100000001f709fa82596e4f908ee331cb5e0ed46ab331d7dcfaf697fe95891e73dac4ebcb000000008c20ca42095840735e89283fec298e62ac2ddea9b5f34a8cbb7097ad965b87568100201b1b01dc829177da4a14551d2fc96a9db00c6501edfa12f22cd9cefd335c227f483045022100a9df60536df5733dd0de6bc921fab0b3eee6426501b43a228afa2c90072eb5ca02201c78b74266fac7d1db5deff080d8a403743203f109fbcabf6d5a760bf87386d20100ffffffff01c075790000000000232103611f9a45c18f28f06f19076ad571c344c82ce8fcfe34464cf8085217a2d294a6ac00000000", "P2SH"}, + + {1, {{"229257c295e7f555421c1bfec8538dd30a4b5c37c1c8810bbe83cafa7811652c", 0, "0x00 CHECKSIG NOT"}}, "01000000012c651178faca83be0b81c8c1375c4b0ad38d53c8fe1b1c4255f5e795c25792220000000049483045022100d6044562284ac76c985018fc4a90127847708c9edb280996c507b28babdc4b2a02203d74eca3f1a4d1eea7ff77b528fde6d5dc324ec2dbfdb964ba885f643b9704cd01ffffffff010100000000000000232102c2410f8891ae918cab4ffc4bb4a3b0881be67c7a1e7faa8b5acf9ab8932ec30cac00000000", "P2SH"}, + + {1, {{"9ca93cfd8e3806b9d9e2ba1cf64e3cc6946ee0119670b1796a09928d14ea25f7", 0, "0x21 0x028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02 CHECKSIG NOT"}}, "0100000001f725ea148d92096a79b1709611e06e94c63c4ef61cbae2d9b906388efd3ca99c000000000100ffffffff0101000000000000002321028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02ac00000000", "P2SH"}, + + {1, {{"444e00ed7840d41f20ecd9c11d3f91982326c731a02f3c05748414a4fa9e59be", 0, "1 0x00 0x21 0x02136b04758b0b6e363e7a6fbe83aaf527a153db2b060d36cc29f7f8309ba6e458 2 CHECKMULTISIG"}}, "0100000001be599efaa4148474053c2fa031c7262398913f1dc1d9ec201fd44078ed004e44000000004900473044022022b29706cb2ed9ef0cb3c97b72677ca2dfd7b4160f7b4beb3ba806aa856c401502202d1e52582412eba2ed474f1f437a427640306fd3838725fab173ade7fe4eae4a01ffffffff010100000000000000232103ac4bba7e7ca3e873eea49e08132ad30c7f03640b6539e9b59903cf14fd016bbbac00000000", "P2SH"}, + + {1, {{"e16abbe80bf30c080f63830c8dbf669deaef08957446e95940227d8c5e6db612", 0, "1 0x21 0x03905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9f 0x00 2 CHECKMULTISIG"}}, "010000000112b66d5e8c7d224059e946749508efea9d66bf8d0c83630f080cf30be8bb6ae100000000490047304402206ffe3f14caf38ad5c1544428e99da76ffa5455675ec8d9780fac215ca17953520220779502985e194d84baa36b9bd40a0dbd981163fa191eb884ae83fc5bd1c86b1101ffffffff010100000000000000232103905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9fac00000000", "P2SH"}, + + {1, {{"ebbcf4bfce13292bd791d6a65a2a858d59adbf737e387e40370d4e64cc70efb0", 0, "2 0x21 0x033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194 0x21 0x03a88b326f8767f4f192ce252afe33c94d25ab1d24f27f159b3cb3aa691ffe1423 2 CHECKMULTISIG NOT"}}, "0100000001b0ef70cc644e0d37407e387e73bfad598d852a5aa6d691d72b2913cebff4bceb000000004a00473044022068cd4851fc7f9a892ab910df7a24e616f293bcb5c5fbdfbc304a194b26b60fba022078e6da13d8cb881a22939b952c24f88b97afd06b4c47a47d7f804c9a352a6d6d0100ffffffff0101000000000000002321033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194ac00000000", "P2SH"}, + + {1, {{"ba4cd7ae2ad4d4d13ebfc8ab1d93a63e4a6563f25089a18bf0fc68f282aa88c1", 0, "2 0x21 0x037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1 0x21 0x02edc823cd634f2c4033d94f5755207cb6b60c4b1f1f056ad7471c47de5f2e4d50 2 CHECKMULTISIG NOT"}}, "0100000001c188aa82f268fcf08ba18950f263654a3ea6931dabc8bf3ed1d4d42aaed74cba000000004b0000483045022100940378576e069aca261a6b26fb38344e4497ca6751bb10905c76bb689f4222b002204833806b014c26fd801727b792b1260003c55710f87c5adbd7a9cb57446dbc9801ffffffff0101000000000000002321037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1ac00000000", "P2SH"}, + + {1, {{"bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224", 0, "CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG"}}, "01000000012432b60dc72cebc1a27ce0969c0989c895bdd9e62e8234839117f8fc32d17fbc000000004a493046022100a576b52051962c25e642c0fd3d77ee6c92487048e5d90818bcf5b51abaccd7900221008204f8fb121be4ec3b24483b1f92d89b1b0548513a134e345c5442e86e8617a501ffffffff010000000000000000016a00000000", "P2SH"}, + {1, {{"83e194f90b6ef21fa2e3a365b63794fb5daa844bdc9b25de30899fcfe7b01047", 0, "CODESEPARATOR CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG"}}, "01000000014710b0e7cf9f8930de259bdc4b84aa5dfb9437b665a3e3a21ff26e0bf994e183000000004a493046022100a166121a61b4eeb19d8f922b978ff6ab58ead8a5a5552bf9be73dc9c156873ea02210092ad9bc43ee647da4f6652c320800debcf08ec20a094a0aaf085f63ecb37a17201ffffffff010000000000000000016a00000000", "P2SH"}, + + {1, {{"326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e", 0, "0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CODESEPARATOR CHECKSIG"}}, "01000000015ebaa001d8e4ec7a88703a3bcf69d98c874bca6299cca0f191512bf2a7826832000000004948304502203bf754d1c6732fbf87c5dcd81258aefd30f2060d7bd8ac4a5696f7927091dad1022100f5bcb726c4cf5ed0ed34cc13dadeedf628ae1045b7cb34421bc60b89f4cecae701ffffffff010000000000000000016a00000000", "P2SH"}, + + {1, {{"a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 1"}}, "010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a900000000924830450221009c0a27f886a1d8cb87f6f595fbc3163d28f7a81ec3c4b252ee7f3ac77fd13ffa02203caa8dfa09713c8c4d7ef575c75ed97812072405d932bd11e6a1593a98b679370148304502201e3861ef39a526406bad1e20ecad06be7375ad40ddb582c9be42d26c3a0d7b240221009d0a3985e96522e59635d19cc4448547477396ce0ef17a58e7d74c3ef464292301ffffffff010000000000000000016a00000000", "P2SH"}, + + {1, {{"a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"}}, "010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a48304502207a6974a77c591fa13dff60cabbb85a0de9e025c09c65a4b2285e47ce8e22f761022100f0efaac9ff8ac36b10721e0aae1fb975c90500b50c56e8a0cc52b0403f0425dd0100ffffffff010000000000000000016a00000000", "P2SH"}, + + {1, {{"a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"}}, "010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a483045022100fa4a74ba9fd59c59f46c3960cf90cbe0d2b743c471d24a3d5d6db6002af5eebb02204d70ec490fd0f7055a7c45f86514336e3a7f03503dacecabb247fc23f15c83510151ffffffff010000000000000000016a00000000", "P2SH"}, + + {1, {{"ccf7f4053a02e653c36ac75c891b7496d0dc5ce5214f6c913d9cf8f1329ebee0", 0, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"}}, "0100000001e0be9e32f1f89c3d916c4f21e55cdcd096741b895cc76ac353e6023a05f4f7cc00000000d86149304602210086e5f736a2c3622ebb62bd9d93d8e5d76508b98be922b97160edc3dcca6d8c47022100b23c312ac232a4473f19d2aeb95ab7bdf2b65518911a0d72d50e38b5dd31dc820121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac4730440220508fa761865c8abd81244a168392876ee1d94e8ed83897066b5e2df2400dad24022043f5ee7538e87e9c6aef7ef55133d3e51da7cc522830a9c4d736977a76ef755c0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"}, + + {1, {{"10c9f0effe83e97f80f067de2b11c6a00c3088a4bce42c5ae761519af9306f3c", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"}}, "01000000013c6f30f99a5161e75a2ce4bca488300ca0c6112bde67f0807fe983feeff0c91001000000e608646561646265656675ab61493046022100ce18d384221a731c993939015e3d1bcebafb16e8c0b5b5d14097ec8177ae6f28022100bcab227af90bab33c3fe0a9abfee03ba976ee25dc6ce542526e9b2e56e14b7f10121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac493046022100c3b93edcc0fd6250eb32f2dd8a0bba1754b0f6c3be8ed4100ed582f3db73eba2022100bf75b5bd2eff4d6bf2bda2e34a40fcc07d4aa3cf862ceaa77b47b81eff829f9a01ab21038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"}, + + {1, {{"6056ebd549003b10cbbd915cea0d82209fe40b8617104be917a26fa92cbe3d6f", 0, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"}}, "01000000016f3dbe2ca96fa217e94b1017860be49f20820dea5c91bdcb103b0049d5eb566000000000fd1d0147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac47304402203757e937ba807e4a5da8534c17f9d121176056406a6465054bdd260457515c1a02200f02eccf1bec0f3a0d65df37889143c2e88ab7acec61a7b6f5aa264139141a2b0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"}, + + {1, {{"5a6b0021a6042a686b6b94abc36b387bef9109847774e8b1e51eb8cc55c53921", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"}}, "01000000012139c555ccb81ee5b1e87477840991ef7b386bc3ab946b6b682a04a621006b5a01000000fdb40148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f2204148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390175ac4830450220646b72c35beeec51f4d5bc1cbae01863825750d7f490864af354e6ea4f625e9c022100f04b98432df3a9641719dbced53393022e7249fb59db993af1118539830aab870148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a580039017521038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"}, + + {2, {{"b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"}, {"ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742", 0, "HASH160 0x14 0xd8dacdadb7462ae15cd906f1878706d0da8660e6 EQUAL"}}, "0100000002f9cbafc519425637ba4227f8d0a0b7160b4e65168193d5af39747891de98b5b5000000006b4830450221008dd619c563e527c47d9bd53534a770b102e40faa87f61433580e04e271ef2f960220029886434e18122b53d5decd25f1f4acb2480659fea20aabd856987ba3c3907e0121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffff42e7988254800876b69f24676b3e0205b77be476512ca4d970707dd5c60598ab00000000fd260100483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a53034930460221008431bdfa72bc67f9d41fe72e94c88fb8f359ffa30b33c72c121c5a877d922e1002210089ef5fc22dd8bfc6bf9ffdb01a9862d27687d424d1fefbab9e9c7176844a187a014c9052483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c7153aeffffffff01a08601000000000017a914d8dacdadb7462ae15cd906f1878706d0da8660e68700000000", "P2SH"}, + + {2, {{"ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"}, {"ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 1, "2 0x48 0x3045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 3 CHECKMULTISIG"}}, "0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000", "P2SH"}, + +}; + + +struct sighashtest { + char txhex[1024]; + char script[1024]; + int inputindex; + int hashtype; + char hashhex[32 * 2 + 1]; +}; + +/* sighash tests from bitcoin core 0.11 + added some standard transactions on the top +*/ +static const struct sighashtest sighash_tests[] = + { + /*{"raw_transaction, script, input_index, hashType, signature_hash (result)"},*/ + {"907c2bc503ade11cc3b04eb2918b6f547b0630ab569273824748c87ea14b0696526c66ba740200000004ab65ababfd1f9bdd4ef073c7afc4ae00da8a66f429c917a0081ad1e1dabce28d373eab81d8628de802000000096aab5253ab52000052ad042b5f25efb33beec9f3364e8a9139e8439d9d7e26529c3c30b6c3fd89f8684cfd68ea0200000009ab53526500636a52ab599ac2fe02a526ed040000000008535300516352515164370e010000000003006300ab2ec229", "", 2, 1864164639, "31af167a6cf3f9d5f6875caa4d31704ceb0eba078d132b78dab52c3b8997317e"}, + {"a0aa3126041621a6dea5b800141aa696daf28408959dfb2df96095db9fa425ad3f427f2f6103000000015360290e9c6063fa26912c2e7fb6a0ad80f1c5fea1771d42f12976092e7a85a4229fdb6e890000000001abc109f6e47688ac0e4682988785744602b8c87228fcef0695085edf19088af1a9db126e93000000000665516aac536affffffff8fe53e0806e12dfd05d67ac68f4768fdbe23fc48ace22a5aa8ba04c96d58e2750300000009ac51abac63ab5153650524aa680455ce7b000000000000499e50030000000008636a00ac526563ac5051ee030000000003abacabd2b6fe000000000003516563910fb6b5", "65", 0, -1391424484, "48d6a1bd2cd9eec54eb866fc71209418a950402b5d7e52363bfb75c98e141175"}, + {"6e7e9d4b04ce17afa1e8546b627bb8d89a6a7fefd9d892ec8a192d79c2ceafc01694a6a7e7030000000953ac6a51006353636a33bced1544f797f08ceed02f108da22cd24c9e7809a446c61eb3895914508ac91f07053a01000000055163ab516affffffff11dc54eee8f9e4ff0bcf6b1a1a35b1cd10d63389571375501af7444073bcec3c02000000046aab53514a821f0ce3956e235f71e4c69d91abe1e93fb703bd33039ac567249ed339bf0ba0883ef300000000090063ab65000065ac654bec3cc504bcf499020000000005ab6a52abac64eb060100000000076a6a5351650053bbbc130100000000056a6aab53abd6e1380100000000026a51c4e509b8", "acab655151", 0, 479279909, "2a3d95b09237b72034b23f2d2bb29fa32a58ab5c6aa72f6aafdfa178ab1dd01c"}, + {"73107cbd025c22ebc8c3e0a47b2a760739216a528de8d4dab5d45cbeb3051cebae73b01ca10200000007ab6353656a636affffffffe26816dffc670841e6a6c8c61c586da401df1261a330a6c6b3dd9f9a0789bc9e000000000800ac6552ac6aac51ffffffff0174a8f0010000000004ac52515100000000", "5163ac63635151ac", 1, 1190874345, "06e328de263a87b09beabe222a21627a6ea5c7f560030da31610c4611f4a46bc"}, + {"e93bbf6902be872933cb987fc26ba0f914fcfc2f6ce555258554dd9939d12032a8536c8802030000000453ac5353eabb6451e074e6fef9de211347d6a45900ea5aaf2636ef7967f565dce66fa451805c5cd10000000003525253ffffffff047dc3e6020000000007516565ac656aabec9eea010000000001633e46e600000000000015080a030000000001ab00000000", "5300ac6a53ab6a", 1, -886562767, "f03aa4fc5f97e826323d0daa03343ebf8a34ed67a1ce18631f8b88e5c992e798"}, + {"50818f4c01b464538b1e7e7f5ae4ed96ad23c68c830e78da9a845bc19b5c3b0b20bb82e5e9030000000763526a63655352ffffffff023b3f9c040000000008630051516a6a5163a83caf01000000000553ab65510000000000", "6aac", 0, 946795545, "746306f322de2b4b58ffe7faae83f6a72433c22f88062cdde881d4dd8a5a4e2d"}, + {"a93e93440250f97012d466a6cc24839f572def241c814fe6ae94442cf58ea33eb0fdd9bcc1030000000600636a0065acffffffff5dee3a6e7e5ad6310dea3e5b3ddda1a56bf8de7d3b75889fc024b5e233ec10f80300000007ac53635253ab53ffffffff0160468b04000000000800526a5300ac526a00000000", "ac00636a53", 1, 1773442520, "5c9d3a2ce9365bb72cfabbaa4579c843bb8abf200944612cf8ae4b56a908bcbd"}, + {"ce7d371f0476dda8b811d4bf3b64d5f86204725deeaa3937861869d5b2766ea7d17c57e40b0100000003535265ffffffff7e7e9188f76c34a46d0bbe856bde5cb32f089a07a70ea96e15e92abb37e479a10100000006ab6552ab655225bcab06d1c2896709f364b1e372814d842c9c671356a1aa5ca4e060462c65ae55acc02d0000000006abac0063ac5281b33e332f96beebdbc6a379ebe6aea36af115c067461eb99d22ba1afbf59462b59ae0bd0200000004ab635365be15c23801724a1704000000000965006a65ac00000052ca555572", "53ab530051ab", 1, 2030598449, "c336b2f7d3702fbbdeffc014d106c69e3413c7c71e436ba7562d8a7a2871f181"}, + {"d3b7421e011f4de0f1cea9ba7458bf3486bee722519efab711a963fa8c100970cf7488b7bb0200000003525352dcd61b300148be5d05000000000000000000", "535251536aac536a", 0, -1960128125, "29aa6d2d752d3310eba20442770ad345b7f6a35f96161ede5f07b33e92053e2a"}, + {"04bac8c5033460235919a9c63c42b2db884c7c8f2ed8fcd69ff683a0a2cccd9796346a04050200000003655351fcad3a2c5a7cbadeb4ec7acc9836c3f5c3e776e5c566220f7f965cf194f8ef98efb5e3530200000007526a006552526526a2f55ba5f69699ece76692552b399ba908301907c5763d28a15b08581b23179cb01eac03000000075363ab6a516351073942c2025aa98a05000000000765006aabac65abd7ffa6030000000004516a655200000000", "53ac6365ac526a", 1, 764174870, "bf5fdc314ded2372a0ad078568d76c5064bf2affbde0764c335009e56634481b"}, + {"c363a70c01ab174230bbe4afe0c3efa2d7f2feaf179431359adedccf30d1f69efe0c86ed390200000002ab51558648fe0231318b04000000000151662170000000000008ac5300006a63acac00000000", "", 0, 2146479410, "191ab180b0d753763671717d051f138d4866b7cb0d1d4811472e64de595d2c70"}, + {"8d437a7304d8772210a923fd81187c425fc28c17a5052571501db05c7e89b11448b36618cd02000000026a6340fec14ad2c9298fde1477f1e8325e5747b61b7e2ff2a549f3d132689560ab6c45dd43c3010000000963ac00ac000051516a447ed907a7efffebeb103988bf5f947fc688aab2c6a7914f48238cf92c337fad4a79348102000000085352ac526a5152517436edf2d80e3ef06725227c970a816b25d0b58d2cd3c187a7af2cea66d6b27ba69bf33a0300000007000063ab526553f3f0d6140386815d030000000003ab6300de138f00000000000900525153515265abac1f87040300000000036aac6500000000", "51", 3, -315779667, "b6632ac53578a741ae8c36d8b69e79f39b89913a2c781cdf1bf47a8c29d997a5"}, + {"fd878840031e82fdbe1ad1d745d1185622b0060ac56638290ec4f66b1beef4450817114a2c0000000009516a63ab53650051abffffffff37b7a10322b5418bfd64fb09cd8a27ddf57731aeb1f1f920ffde7cb2dfb6cdb70300000008536a5365ac53515369ecc034f1594690dbe189094dc816d6d57ea75917de764cbf8eccce4632cbabe7e116cd0100000003515352ffffffff035777fc000000000003515200abe9140300000000050063005165bed6d10200000000076300536363ab65195e9110", "635265", 0, 1729787658, "6e3735d37a4b28c45919543aabcb732e7a3e1874db5315abb7cc6b143d62ff10"}, + {"f40a750702af06efff3ea68e5d56e42bc41cdb8b6065c98f1221fe04a325a898cb61f3d7ee030000000363acacffffffffb5788174aef79788716f96af779d7959147a0c2e0e5bfb6c2dba2df5b4b97894030000000965510065535163ac6affffffff0445e6fd0200000000096aac536365526a526aa6546b000000000008acab656a6552535141a0fd010000000000c897ea030000000008526500ab526a6a631b39dba3", "00abab5163ac", 1, -1778064747, "d76d0fc0abfa72d646df888bce08db957e627f72962647016eeae5a8412354cf"}, + {"a63bc673049c75211aa2c09ecc38e360eaa571435fedd2af1116b5c1fa3d0629c269ecccbf0000000008ac65ab516352ac52ffffffffbf1a76fdda7f451a5f0baff0f9ccd0fe9136444c094bb8c544b1af0fa2774b06010000000463535253ffffffff13d6b7c3ddceef255d680d87181e100864eeb11a5bb6a3528cb0d70d7ee2bbbc02000000056a0052abab951241809623313b198bb520645c15ec96bfcc74a2b0f3db7ad61d455cc32db04afc5cc702000000016309c9ae25014d9473020000000004abab6aac3bb1e803", "", 3, -232881718, "6e48f3da3a4ac07eb4043a232df9f84e110485d7c7669dd114f679c27d15b97e"}, + {"4c565efe04e7d32bac03ae358d63140c1cfe95de15e30c5b84f31bb0b65bb542d637f49e0f010000000551abab536348ae32b31c7d3132030a510a1b1aacf7b7c3f19ce8dc49944ef93e5fa5fe2d356b4a73a00100000009abac635163ac00ab514c8bc57b6b844e04555c0a4f4fb426df139475cd2396ae418bc7015820e852f711519bc202000000086a00510000abac52488ff4aec72cbcfcc98759c58e20a8d2d9725aa4a80f83964e69bc4e793a4ff25cd75dc701000000086a52ac6aac5351532ec6b10802463e0200000000000553005265523e08680100000000002f39a6b0", "", 3, 70712784, "c6076b6a45e6fcfba14d3df47a34f6aadbacfba107e95621d8d7c9c0e40518ed"}, + {"1233d5e703403b3b8b4dae84510ddfc126b4838dcb47d3b23df815c0b3a07b55bf3098110e010000000163c5c55528041f480f40cf68a8762d6ed3efe2bd402795d5233e5d94bf5ddee71665144898030000000965525165655151656affffffff6381667e78bb74d0880625993bec0ea3bd41396f2bcccc3cc097b240e5e92d6a01000000096363acac6a63536365ffffffff04610ad60200000000065251ab65ab52e90d680200000000046351516ae30e98010000000008abab52520063656a671856010000000004ac6aac514c84e383", "6aabab636300", 1, -114996813, "aeb8c5a62e8a0b572c28f2029db32854c0b614dbecef0eaa726abebb42eebb8d"}, + {"0c69702103b25ceaed43122cc2672de84a3b9aa49872f2a5bb458e19a52f8cc75973abb9f102000000055365656aacffffffff3ffb1cf0f76d9e3397de0942038c856b0ebbea355dc9d8f2b06036e19044b0450100000000ffffffff4b7793f4169617c54b734f2cd905ed65f1ce3d396ecd15b6c426a677186ca0620200000008655263526551006a181a25b703240cce0100000000046352ab53dee22903000000000865526a6a516a51005e121602000000000852ab52ababac655200000000", "6a516aab63", 1, -2040012771, "a6e6cb69f409ec14e10dd476f39167c29e586e99bfac93a37ed2c230fcc1dbbe"}, + {"fd22692802db8ae6ab095aeae3867305a954278f7c076c542f0344b2591789e7e33e4d29f4020000000151ffffffffb9409129cfed9d3226f3b6bab7a2c83f99f48d039100eeb5796f00903b0e5e5e0100000006656552ac63abd226abac0403e649000000000007abab51ac5100ac8035f10000000000095165006a63526a52510d42db030000000007635365ac6a63ab24ef5901000000000453ab6a0000000000", "536a52516aac6a", 1, 309309168, "7ca0f75e6530ec9f80d031fc3513ca4ecd67f20cb38b4dacc6a1d825c3cdbfdb"}, + {"a43f85f701ffa54a3cc57177510f3ea28ecb6db0d4431fc79171cad708a6054f6e5b4f89170000000008ac6a006a536551652bebeaa2013e779c05000000000665ac5363635100000000", "ac", 0, 2028978692, "58294f0d7f2e68fe1fd30c01764fe1619bcc7961d68968944a0e263af6550437"}, + {"c2b0b99001acfecf7da736de0ffaef8134a9676811602a6299ba5a2563a23bb09e8cbedf9300000000026300ffffffff042997c50300000000045252536a272437030000000007655353ab6363ac663752030000000002ab6a6d5c900000000000066a6a5265abab00000000", "52ac525163515251", 0, -894181723, "8b300032a1915a4ac05cea2f7d44c26f2a08d109a71602636f15866563eaafdc"}, + {"82f9f10304c17a9d954cf3380db817814a8c738d2c811f0412284b2c791ec75515f38c4f8c020000000265ab5729ca7db1b79abee66c8a757221f29280d0681355cb522149525f36da760548dbd7080a0100000001510b477bd9ce9ad5bb81c0306273a3a7d051e053f04ecf3a1dbeda543e20601a5755c0cfae030000000451ac656affffffff71141a04134f6c292c2e0d415e6705dfd8dcee892b0d0807828d5aeb7d11f5ef0300000001520b6c6dc802a6f3dd0000000000056aab515163bfb6800300000000015300000000", "", 3, -635779440, "d55ed1e6c53510f2608716c12132a11fb5e662ec67421a513c074537eeccc34b"}, + {"8edcf5a1014b604e53f0d12fe143cf4284f86dc79a634a9f17d7e9f8725f7beb95e8ffcd2403000000046aabac52ffffffff01c402b5040000000005ab6a63525100000000", "6351525251acabab6a", 0, 1520147826, "2765bbdcd3ebb8b1a316c04656b28d637f80bffbe9b040661481d3dc83eea6d6"}, + {"2074bad5011847f14df5ea7b4afd80cd56b02b99634893c6e3d5aaad41ca7c8ee8e5098df003000000026a6affffffff018ad59700000000000900ac656a526551635300000000", "65635265", 0, -1804671183, "663c999a52288c9999bff36c9da2f8b78d5c61b8347538f76c164ccba9868d0a"}, + {"7100b11302e554d4ef249ee416e7510a485e43b2ba4b8812d8fe5529fe33ea75f36d392c4403000000020000ffffffff3d01a37e075e9a7715a657ae1bdf1e44b46e236ad16fd2f4c74eb9bf370368810000000007636553ac536365ffffffff01db696a0400000000065200ac656aac00000000", "63005151", 0, -1210499507, "b9c3aee8515a4a3b439de1ffc9c156824bda12cb75bfe5bc863164e8fd31bd7a"}, + {"02c1017802091d1cb08fec512db7b012fe4220d57a5f15f9e7676358b012786e1209bcff950100000004acab6352ffffffff799bc282724a970a6fea1828984d0aeb0f16b67776fa213cbdc4838a2f1961a3010000000951516a536552ab6aabffffffff016c7b4b03000000000865abac5253ac5352b70195ad", "65655200516a", 0, -241626954, "be567cb47170b34ff81c66c1142cb9d27f9b6898a384d6dfc4fce16b75b6cb14"}, + {"cb3178520136cd294568b83bb2520f78fecc507898f4a2db2674560d72fd69b9858f75b3b502000000066aac00515100ffffffff03ab005a01000000000563526363006e3836030000000001abfbda3200000000000665ab0065006500000000", "ab516a0063006a5300", 0, 1182109299, "2149e79c3f4513da4e4378608e497dcfdfc7f27c21a826868f728abd2b8a637a"}, + {"18a4b0c004702cf0e39686ac98aab78ad788308f1d484b1ddfe70dc1997148ba0e28515c310300000000ffffffff05275a52a23c59da91129093364e275da5616c4070d8a05b96df5a2080ef259500000000096aac51656a6aac53ab66e64966b3b36a07dd2bb40242dd4a3743d3026e7e1e0d9e9e18f11d068464b989661321030000000265ac383339c4fae63379cafb63b0bab2eca70e1f5fc7d857eb5c88ccd6c0465093924bba8b2a000000000300636ab5e0545402bc2c4c010000000000cd41c002000000000000000000", "abac635253656a00", 3, 2052372230, "32db877b6b1ca556c9e859442329406f0f8246706522369839979a9f7a235a32"}, + {"1d9c5df20139904c582285e1ea63dec934251c0f9cf5c47e86abfb2b394ebc57417a81f67c010000000353515222ba722504800d3402000000000353656a3c0b4a0200000000000fb8d20500000000076300ab005200516462f30400000000015200000000", "ab65", 0, -210854112, "edf73e2396694e58f6b619f68595b0c1cdcb56a9b3147845b6d6afdb5a80b736"}, + {"4504cb1904c7a4acf375ddae431a74de72d5436efc73312cf8e9921f431267ea6852f9714a01000000066a656a656553a2fbd587c098b3a1c5bd1d6480f730a0d6d9b537966e20efc0e352d971576d0f87df0d6d01000000016321aeec3c4dcc819f1290edb463a737118f39ab5765800547522708c425306ebfca3f396603000000055300ac656a1d09281d05bfac57b5eb17eb3fa81ffcedfbcd3a917f1be0985c944d473d2c34d245eb350300000007656a51525152ac263078d9032f470f0500000000066aac00000052e12da60200000000003488410200000000076365006300ab539981e432", "52536a52526a", 1, -31909119, "f0a2deee7fd8a3a9fad6927e763ded11c940ee47e9e6d410f94fda5001f82e0c"}, + {"14bc7c3e03322ec0f1311f4327e93059c996275302554473104f3f7b46ca179bfac9ef753503000000016affffffff9d405eaeffa1ca54d9a05441a296e5cc3a3e32bb8307afaf167f7b57190b07e00300000008abab51ab5263abab45533aa242c61bca90dd15d46079a0ab0841d85df67b29ba87f2393cd764a6997c372b55030000000452005263ffffffff0250f40e02000000000651516a0063630e95ab0000000000046a5151ac00000000", "6a65005151", 0, -1460947095, "aa418d096929394c9147be8818d8c9dafe6d105945ab9cd7ec682df537b5dd79"}, + {"2b3bd0dd04a1832f893bf49a776cd567ec4b43945934f4786b615d6cb850dfc0349b33301a000000000565ac000051cf80c670f6ddafab63411adb4d91a69c11d9ac588898cbfb4cb16061821cc104325c895103000000025163ffffffffa9e2d7506d2d7d53b882bd377bbcc941f7a0f23fd15d2edbef3cd9df8a4c39d10200000009ac63006a52526a5265ffffffff44c099cdf10b10ce87d4b38658d002fd6ea17ae4a970053c05401d86d6e75f99000000000963ab53526a5252ab63ffffffff035af69c01000000000100ba9b8b0400000000004cead10500000000026a520b77d667", "ab52abac526553", 3, -1955078165, "eb9ceecc3b401224cb79a44d23aa8f428e29f1405daf69b4e01910b848ef1523"}, + {"35df11f004a48ba439aba878fe9df20cc935b4a761c262b1b707e6f2b33e2bb7565cd68b130000000000ffffffffb2a2f99abf64163bb57ca900500b863f40c02632dfd9ea2590854c5fb4811da90200000006ac006363636affffffffaf9d89b2a8d2670ca37c8f7c140600b81259f2e037cb4590578ec6e37af8bf200000000005abac6a655270a4751eb551f058a93301ffeda2e252b6614a1fdd0e283e1d9fe53c96c5bbaafaac57b8030000000153ffffffff020d9f3b02000000000100ed7008030000000004abac000000000000", "abac", 3, 593793071, "88fdee1c2d4aeead71d62396e28dc4d00e5a23498eea66844b9f5d26d1f21042"}, + {"a08ff466049fb7619e25502ec22fedfb229eaa1fe275aa0b5a23154b318441bf547989d0510000000005ab5363636affffffff2b0e335cb5383886751cdbd993dc0720817745a6b1c9b8ab3d15547fc9aafd03000000000965656a536a52656a532b53d10584c290d3ac1ab74ab0a19201a4a039cb59dc58719821c024f6bf2eb26322b33f010000000965ac6aac0053ab6353ffffffff048decba6ebbd2db81e416e39dde1f821ba69329725e702bcdea20c5cc0ecc6402000000086363ab5351ac6551466e377b0468c0fa00000000000651ab53ac6a513461c6010000000008636a636365535100eeb3dc010000000006526a52ac516a43f362010000000005000063536500000000", "0063516a", 1, -1158911348, "f6a1ecb50bd7c2594ebecea5a1aa23c905087553e40486dade793c2f127fdfae"}, + {"5ac2f17d03bc902e2bac2469907ec7d01a62b5729340bc58c343b7145b66e6b97d434b30fa000000000163ffffffff44028aa674192caa0d0b4ebfeb969c284cb16b80c312d096efd80c6c6b094cca000000000763acabac516a52ffffffff10c809106e04b10f9b43085855521270fb48ab579266e7474657c6c625062d2d030000000351636595a0a97004a1b69603000000000465ab005352ad68010000000008636a5263acac5100da7105010000000002acab90325200000000000000000000", "6a6aab516a63526353", 2, 1518400956, "f7efb74b1dcc49d316b49c632301bc46f98d333c427e55338be60c7ef0d953be"}, + {"aeb2e11902dc3770c218b97f0b1960d6ee70459ecb6a95eff3f05295dc1ef4a0884f10ba460300000005516352526393e9b1b3e6ae834102d699ddd3845a1e159aa7cf7635edb5c02003f7830fee3788b795f20100000009ab006a526553ac006ad8809c570469290e0400000000050000abab00b10fd5040000000008ab655263abac53ab630b180300000000009d9993040000000002516300000000", "5351ababac6a65", 0, 1084852870, "f2286001af0b0170cbdad92693d0a5ebaa8262a4a9d66e002f6d79a8c94026d1"}, + {"9860ca9a0294ff4812534def8c3a3e3db35b817e1a2ddb7f0bf673f70eab71bb79e90a2f3100000000086a636551acac5165ffffffffed4d6d3cd9ff9b2d490e0c089739121161a1445844c3e204296816ab06e0a83702000000035100ac88d0db5201c3b59a050000000005ac6a0051ab00000000", "535263ab006a526aab", 1, -962088116, "30df2473e1403e2b8e637e576825f785528d998af127d501556e5f7f5ed89a2a"}, + {"4ddaa680026ec4d8060640304b86823f1ac760c260cef81d85bd847952863d629a3002b54b0200000008526365636a656aab65457861fc6c24bdc760c8b2e906b6656edaf9ed22b5f50e1fb29ec076ceadd9e8ebcb6b000000000152ffffffff033ff04f00000000000551526a00657a1d900300000000002153af040000000003006a6300000000", "ab526a53acabab", 0, 1055317633, "7f21b62267ed52462e371a917eb3542569a4049b9dfca2de3c75872b39510b26"}, + {"01e76dcd02ad54cbc8c71d68eaf3fa7c883b65d74217b30ba81f1f5144ef80b706c0dc82ca000000000352ab6a078ec18bcd0514825feced2e8b8ea1ccb34429fae41c70cc0b73a2799e85603613c6870002000000086363ab6365536a53ffffffff043acea90000000000016ad20e1803000000000100fa00830200000000056352515351e864ee00000000000865535253ab6a6551d0c46672", "6a6365abacab", 0, -1420559003, "8af0b4cbdbc011be848edf4dbd2cde96f0578d662cfebc42252495387114224a"}, + {"fa00b26402670b97906203434aa967ce1559d9bd097d56dbe760469e6032e7ab61accb54160100000006635163630052fffffffffe0d3f4f0f808fd9cfb162e9f0c004601acf725cd7ea5683bbdc9a9a433ef15a0200000005ab52536563d09c7bef049040f305000000000153a7c7b9020000000004ac63ab52847a2503000000000553ab00655390ed80010000000005006553ab52860671d4", "536565ab52", 0, 799022412, "40ed8e7bbbd893e15f3cce210ae02c97669818de5946ca37eefc7541116e2c78"}, + {"cb5c06dc01b022ee6105ba410f0eb12b9ce5b5aa185b28532492d839a10cef33d06134b91b010000000153ffffffff02cec0530400000000005e1e4504000000000865656551acacac6a00000000", "ab53", 0, -1514251329, "136beb95459fe6b126cd6cefd54eb5d971524b0e883e41a292a78f78015cb8d5"}, + {"f10a0356031cd569d652dbca8e7a4d36c8da33cdff428d003338602b7764fe2c96c505175b010000000465ac516affffffffbb54563c71136fa944ee20452d78dc87073ac2365ba07e638dce29a5d179da600000000003635152ffffffff9a411d8e2d421b1e6085540ee2809901e590940bbb41532fa38bd7a16b68cc350100000007535251635365636195df1603b61c45010000000002ab65bf6a310400000000026352fcbba10200000000016aa30b7ff0", "5351", 0, 1552495929, "9eb8adf2caecb4bf9ac59d7f46bd20e83258472db2f569ee91aba4cf5ee78e29"}, + {"c3325c9b012f659466626ca8f3c61dfd36f34670abc054476b7516a1839ec43cd0870aa0c0000000000753525265005351e7e3f04b0112650500000000000363ac6300000000", "acac", 0, -68961433, "5ca70e727d91b1a42b78488af2ed551642c32d3de4712a51679f60f1456a8647"}, + {"2333e54c044370a8af16b9750ac949b151522ea6029bacc9a34261599549581c7b4e5ece470000000007510052006563abffffffff80630fc0155c750ce20d0ca4a3d0c8e8d83b014a5b40f0b0be0dd4c63ac28126020000000465000000ffffffff1b5f1433d38cdc494093bb1d62d84b10abbdae57e3d04e82e600857ab3b1dc990300000003515100b76564be13e4890a908ea7508afdad92ec1b200a9a67939fadce6eb7a29eb4550a0a28cb0300000001acffffffff02926c930300000000016373800201000000000153d27ee740", "ab6365ab516a53", 3, 598653797, "2be27a686eb7940dd32c44ff3a97c1b28feb7ab9c5c0b1593b2d762361cfc2db"}, + {"b500ca48011ec57c2e5252e5da6432089130603245ffbafb0e4c5ffe6090feb629207eeb0e010000000652ab6a636aab8302c9d2042b44f40500000000015278c05a050000000004ac5251524be080020000000007636aac63ac5252c93a9a04000000000965ab6553636aab5352d91f9ddb", "52005100", 0, -2024394677, "49c8a6940a461cc7225637f1e512cdd174c99f96ec05935a59637ededc77124c"}, + {"f52ff64b02ee91adb01f3936cc42e41e1672778962b68cf013293d649536b519bc3271dd2c00000000020065afee11313784849a7c15f44a61cd5fd51ccfcdae707e5896d131b082dc9322a19e12858501000000036aac654e8ca882022deb7c020000000006006a515352abd3defc0000000000016300000000", "63520063", 0, 1130989496, "7f208df9a5507e98c62cebc5c1e2445eb632e95527594929b9577b53363e96f6"}, + {"ab7d6f36027a7adc36a5cf7528fe4fb5d94b2c96803a4b38a83a675d7806dda62b380df86a0000000003000000ffffffff5bc00131e29e22057c04be854794b4877dda42e416a7a24706b802ff9da521b20000000007ac6a0065ac52ac957cf45501b9f06501000000000500ac6363ab25f1110b", "00526500536a635253", 0, 911316637, "5fa09d43c8aef6f6fa01c383a69a5a61a609cd06e37dce35a39dc9eae3ddfe6c"}, + {"f940888f023dce6360263c850372eb145b864228fdbbb4c1186174fa83aab890ff38f8c9a90300000000ffffffff01e80ccdb081e7bbae1c776531adcbfb77f2e5a7d0e5d0d0e2e6c8758470e85f00000000020053ffffffff03b49088050000000004656a52ab428bd604000000000951630065ab63ac636a0cbacf0400000000070063ac5265ac53d6e16604", "ac63", 0, 39900215, "713ddeeefcfe04929e7b6593c792a4efbae88d2b5280d1f0835d2214eddcbad6"}, + {"530ecd0b01ec302d97ef6f1b5a6420b9a239714013e20d39aa3789d191ef623fc215aa8b940200000005ac5351ab6a3823ab8202572eaa04000000000752ab6a51526563fd8a270100000000036a006581a798f0", "525153656a0063", 0, 1784562684, "fe42f73a8742676e640698222b1bd6b9c338ff1ccd766d3d88d7d3c6c6ac987e"}, + {"5d781d9303acfcce964f50865ddfddab527ea971aee91234c88e184979985c00b4de15204b0100000003ab6352a009c8ab01f93c8ef2447386c434b4498538f061845862c3f9d5751ad0fce52af442b3a902000000045165ababb909c66b5a3e7c81b3c45396b944be13b8aacfc0204f3f3c105a66fa8fa6402f1b5efddb01000000096a65ac636aacab656ac3c677c402b79fa4050000000004006aab5133e35802000000000751ab635163ab0078c2e025", "6aac51636a6a005265", 0, -882306874, "551ce975d58647f10adefb3e529d9bf9cda34751627ec45e690f135ef0034b95"}, + {"25ee54ef0187387564bb86e0af96baec54289ca8d15e81a507a2ed6668dc92683111dfb7a50100000004005263634cecf17d0429aa4d000000000007636a6aabab5263daa75601000000000251ab4df70a01000000000151980a890400000000065253ac6a006377fd24e3", "65ab", 0, 797877378, "069f38fd5d47abff46f04ee3ae27db03275e9aa4737fa0d2f5394779f9654845"}, + {"a9c57b1a018551bcbc781b256642532bbc09967f1cbe30a227d352a19365d219d3f11649a3030000000451655352b140942203182894030000000006ab00ac6aab654add350400000000003d379505000000000553abacac00e1739d36", "5363", 0, -1069721025, "6da32416deb45a0d720a1dbe6d357886eabc44029dd5db74d50feaffbe763245"}, + {"05c4fb94040f5119dc0b10aa9df054871ed23c98c890f1e931a98ffb0683dac45e98619fdc0200000007acab6a525263513e7495651c9794c4d60da835d303eb4ee6e871f8292f6ad0b32e85ef08c9dc7aa4e03c9c010000000500ab52acacfffffffffee953259cf14ced323fe8d567e4c57ba331021a1ef5ac2fa90f7789340d7c550100000007ac6aacac6a6a53ffffffff08d9dc820d00f18998af247319f9de5c0bbd52a475ea587f16101af3afab7c210100000003535363569bca7c0468e34f00000000000863536353ac51ac6584e319010000000006650052ab6a533debea030000000003ac0053ee7070020000000006ac52005253ac00000000", "6351005253", 2, 1386916157, "76c4013c40bfa1481badd9d342b6d4b8118de5ab497995fafbf73144469e5ff0"}, + {"c95ab19104b63986d7303f4363ca8f5d2fa87c21e3c5d462b99f1ebcb7c402fc012f5034780000000009006aac63ac65655265ffffffffbe91afa68af40a8700fd579c86d4b706c24e47f7379dad6133de389f815ef7f501000000046aac00abffffffff1520db0d81be4c631878494668d258369f30b8f2b7a71e257764e9a27f24b48701000000076a515100535300b0a989e1164db9499845bac01d07a3a7d6d2c2a76e4c04abe68f808b6e2ef5068ce6540e0100000009ac53636a63ab65656affffffff0309aac6050000000005ab6563656a6067e8020000000003ac536aec91c8030000000009655251ab65ac6a53acc7a45bc5", "63526a65abac", 1, 512079270, "fb7eca81d816354b6aedec8cafc721d5b107336657acafd0d246049556f9e04b"}, + {"ca66ae10049533c2b39f1449791bd6d3f039efe0a121ab7339d39ef05d6dcb200ec3fb2b3b020000000465006a53ffffffff534b8f97f15cc7fb4f4cea9bf798472dc93135cd5b809e4ca7fe4617a61895980100000000ddd83c1dc96f640929dd5e6f1151dab1aa669128591f153310d3993e562cc7725b6ae3d903000000046a52536582f8ccddb8086d8550f09128029e1782c3f2624419abdeaf74ecb24889cc45ac1a64492a0100000002516a4867b41502ee6ccf03000000000752acacab52ab6a4b7ba80000000000075151ab0052536300000000", "6553", 2, -62969257, "8085e904164ab9a8c20f58f0d387f6adb3df85532e11662c03b53c3df8c943cb"}, + {"ba646d0b0453999f0c70cb0430d4cab0e2120457bb9128ed002b6e9500e9c7f8d7baa20abe0200000001652a4e42935b21db02b56bf6f08ef4be5adb13c38bc6a0c3187ed7f6197607ba6a2c47bc8a03000000040052516affffffffa55c3cbfc19b1667594ac8681ba5d159514b623d08ed4697f56ce8fcd9ca5b0b00000000096a6a5263ac655263ab66728c2720fdeabdfdf8d9fb2bfe88b295d3b87590e26a1e456bad5991964165f888c03a0200000006630051ac00acffffffff0176fafe0100000000070063acac65515200000000", "63", 1, 2002322280, "9db4e320208185ee70edb4764ee195deca00ba46412d5527d9700c1cf1c3d057"}, + {"2ddb8f84039f983b45f64a7a79b74ff939e3b598b38f436def7edd57282d0803c7ef34968d02000000026a537eb00c4187de96e6e397c05f11915270bcc383959877868ba93bac417d9f6ed9f627a7930300000004516551abffffffffacc12f1bb67be3ae9f1d43e55fda8b885340a0df1175392a8bbd9f959ad3605003000000025163ffffffff02ff0f4700000000000070bd99040000000003ac53abf8440b42", "", 2, -393923011, "0133f1a161363b71dfb3a90065c7128c56bd0028b558b610142df79e055ab5c7"}, + {"b21fc15403b4bdaa994204444b59323a7b8714dd471bd7f975a4e4b7b48787e720cbd1f5f00000000000ffffffff311533001cb85c98c1d58de0a5fbf27684a69af850d52e22197b0dc941bc6ca9030000000765ab6363ab5351a8ae2c2c7141ece9a4ff75c43b7ea9d94ec79b7e28f63e015ac584d984a526a73fe1e04e0100000007526352536a5365ffffffff02a0a9ea030000000002ab52cfc4f300000000000465525253e8e0f342", "000000", 1, 1305253970, "d1df1f4bba2484cff8a816012bb6ec91c693e8ca69fe85255e0031711081c46a"}, + {"d1704d6601acf710b19fa753e307cfcee2735eada0d982b5df768573df690f460281aad12d0000000007656300005100acffffffff0232205505000000000351ab632ca1bc0300000000016300000000", "ac65ab65ab51", 0, 165179664, "40b4f03c68288bdc996011b0f0ddb4b48dc3be6762db7388bdc826113266cd6c"}, + {"d2f6c096025cc909952c2400bd83ac3d532bfa8a1f8f3e73c69b1fd7b8913379793f3ce92202000000076a00ab6a53516ade5332d81d58b22ed47b2a249ab3a2cb3a6ce9a6b5a6810e18e3e1283c1a1b3bd73e3ab00300000002acabffffffff01a9b2d40500000000056352abab00dc4b7f69", "ab0065", 0, -78019184, "2ef025e907f0fa454a2b48a4f3b81346ba2b252769b5c35d742d0c8985e0bf5e"}, + {"3e6db1a1019444dba461247224ad5933c997256d15c5d37ade3d700506a0ba0a57824930d7010000000852ab6500ab00ac00ffffffff03389242020000000001aba8465a0200000000086a6a636a5100ab52394e6003000000000953ac51526351000053d21d9800", "abababacab53ab65", 0, 1643661850, "1f8a3aca573a609f4aea0c69522a82fcb4e15835449da24a05886ddc601f4f6a"}, + {"f821a042036ad43634d29913b77c0fc87b4af593ac86e9a816a9d83fd18dfcfc84e1e1d57102000000076a63ac52006351ffffffffbcdaf490fc75086109e2f832c8985716b3a624a422cf9412fe6227c10585d21203000000095252abab5352ac526affffffff2efed01a4b73ad46c7f7bc7fa3bc480f8e32d741252f389eaca889a2e9d2007e000000000353ac53ffffffff032ac8b3020000000009636300000063516300d3d9f2040000000006510065ac656aafa5de0000000000066352ab5300ac9042b57d", "525365", 1, 667065611, "0d17a92c8d5041ba09b506ddf9fd48993be389d000aad54f9cc2a44fcc70426b"}, + {"58e3f0f704a186ef55d3919061459910df5406a9121f375e7502f3be872a449c3f2bb058380100000000f0e858da3ac57b6c973f889ad879ffb2bd645e91b774006dfa366c74e2794aafc8bbc871010000000751ac65516a515131a68f120fd88ca08687ceb4800e1e3fbfea7533d34c84fef70cc5a96b648d580369526d000000000600ac00515363f6191d5b3e460fa541a30a6e83345dedfa3ed31ad8574d46d7bbecd3c9074e6ba5287c24020000000151e3e19d6604162602010000000004005100ac71e17101000000000065b5e90300000000040053ab53f6b7d101000000000200ac00000000", "6563ab", 1, -669018604, "8221d5dfb75fc301a80e919e158e0b1d1e86ffb08870a326c89408d9bc17346b"}, + {"efec1cce044a676c1a3d973f810edb5a9706eb4cf888a240f2b5fb08636bd2db482327cf500000000005ab51656a52ffffffff46ef019d7c03d9456e5134eb0a7b5408d274bd8e33e83df44fab94101f7c5b650200000009ac5100006353630051407aadf6f5aaffbd318fdbbc9cae4bd883e67d524df06bb006ce2f7c7e2725744afb76960100000005536aab53acec0d64eae09e2fa1a7c4960354230d51146cf6dc45ee8a51f489e20508a785cbe6ca86fc000000000651536a516300ffffffff014ef598020000000006636aac655265a6ae1b75", "53516a5363526563ab", 2, -1823982010, "13e8b5ab4e5b2ceeff0045c625e19898bda2d39fd7af682e2d1521303cfe1154"}, + {"3c436c2501442a5b700cbc0622ee5143b34b1b8021ea7bbc29e4154ab1f5bdfb3dff9d640501000000086aab5251ac5252acffffffff0170b9a20300000000066aab6351525114b13791", "63acabab52ab51ac65", 0, -2140612788, "87ddf1f9acb6640448e955bd1968f738b4b3e073983af7b83394ab7557f5cd61"}, + {"d62f183e037e0d52dcf73f9b31f70554bce4f693d36d17552d0e217041e01f15ad3840c838000000000963acac6a6a6a63ab63ffffffffabdfb395b6b4e63e02a763830f536fc09a35ff8a0cf604021c3c751fe4c88f4d0300000006ab63ab65ac53aa4d30de95a2327bccf9039fb1ad976f84e0b4a0936d82e67eafebc108993f1e57d8ae39000000000165ffffffff04364ad30500000000036a005179fd84010000000007ab636aac6363519b9023030000000008510065006563ac6acd2a4a02000000000000000000", "52", 1, 595020383, "da8405db28726dc4e0f82b61b2bfd82b1baa436b4e59300305cc3b090b157504"}, + {"44c200a5021238de8de7d80e7cce905606001524e21c8d8627e279335554ca886454d692e6000000000500acac52abbb8d1dc876abb1f514e96b21c6e83f429c66accd961860dc3aed5071e153e556e6cf076d02000000056553526a51870a928d0360a580040000000004516a535290e1e302000000000851ab6a00510065acdd7fc5040000000007515363ab65636abb1ec182", "6363", 0, -785766894, "ed53cc766cf7cb8071cec9752460763b504b2183442328c5a9761eb005c69501"}, + {"d682d52d034e9b062544e5f8c60f860c18f029df8b47716cabb6c1b4a4b310a0705e754556020000000400656a0016eeb88eef6924fed207fba7ddd321ff3d84f09902ff958c815a2bf2bb692eb52032c4d803000000076365ac516a520099788831f8c8eb2552389839cfb81a9dc55ecd25367acad4e03cfbb06530f8cccf82802701000000085253655300656a53ffffffff02d543200500000000056a510052ac03978b05000000000700ac51525363acfdc4f784", "", 2, -696035135, "e1a256854099907050cfee7778f2018082e735a1f1a3d91437584850a74c87bb"}, + {"e8c0dec5026575ddf31343c20aeeca8770afb33d4e562aa8ee52eeda6b88806fdfd4fe0a97030000000953acabab65ab516552ffffffffdde122c2c3e9708874286465f8105f43019e837746686f442666629088a970e0010000000153ffffffff01f98eee0100000000025251fe87379a", "63", 1, 633826334, "abe441209165d25bc6d8368f2e7e7dc21019056719fef1ace45542aa2ef282e2"}, + {"b288c331011c17569293c1e6448e33a64205fc9dc6e35bc756a1ac8b97d18e912ea88dc0770200000007635300ac6aacabfc3c890903a3ccf8040000000004656500ac9c65c9040000000009ab6a6aabab65abac63ac5f7702000000000365005200000000", "526a63", 0, 1574937329, "0dd1bd5c25533bf5f268aa316ce40f97452cca2061f0b126a59094ca5b65f7a0"}, + {"fc0a092003cb275fa9a25a72cf85d69c19e4590bfde36c2b91cd2c9c56385f51cc545530210000000004ab530063ffffffff729b006eb6d14d6e5e32b1c376acf1c62830a5d9246da38dbdb4db9f51fd1c74020000000463636500ffffffff0ae695c6d12ab7dcb8d3d4b547b03f178c7268765d1de9af8523d244e3836b12030000000151ffffffff0115c1e20100000000066a6aabac6a6a1ff59aec", "ab0053ac", 0, 931831026, "73fe22099c826c34a74edf45591f5d7b3a888c8178cd08facdfd96a9a681261c"}, + {"0fcae7e004a71a4a7c8f66e9450c0c1785268679f5f1a2ee0fb3e72413d70a9049ecff75de020000000452005251ffffffff99c8363c4b95e7ec13b8c017d7bb6e80f7c04b1187d6072961e1c2479b1dc0320200000000ffffffff7cf03b3d66ab53ed740a70c5c392b84f780fff5472aee82971ac3bfeeb09b2df0200000006ab5265636a0058e4fe9257d7c7c7e82ff187757c6eadc14cceb6664dba2de03a018095fd3006682a5b9600000000056353536a636de26b2303ff76de010000000001acdc0a2e020000000001ab0a53ed020000000007530063ab51510088417307", "ac6aacab5165535253", 2, -902160694, "eea96a48ee572aea33d75d0587ce954fcfb425531a7da39df26ef9a6635201be"}, + {"612701500414271138e30a46b7a5d95c70c78cc45bf8e40491dac23a6a1b65a51af04e6b94020000000451655153ffffffffeb72dc0e49b2fad3075c19e1e6e4b387f1365dca43d510f6a02136318ddecb7f0200000003536352e115ffc4f9bae25ef5baf534a890d18106fb07055c4d7ec9553ba89ed1ac2101724e507303000000080063006563acabac2ff07f69a080cf61a9d19f868239e6a4817c0eeb6a4f33fe254045d8af2bca289a8695de0300000000430736c404d317840500000000086a00abac5351ab65306e0503000000000963ab0051536aabab6a6c8aca01000000000565516351ab5dcf960100000000016a00000000", "ab", 2, -604581431, "5ec805e74ee934aa815ca5f763425785ae390282d46b5f6ea076b6ad6255a842"}, + {"6b68ba00023bb4f446365ea04d68d48539aae66f5b04e31e6b38b594d2723ab82d44512460000000000200acffffffff5dfc6febb484fff69c9eeb7c7eb972e91b6d949295571b8235b1da8955f3137b020000000851ac6352516a535325828c8a03365da801000000000800636aabac6551ab0f594d03000000000963ac536365ac63636a45329e010000000005abac53526a00000000", "005151", 0, 1317038910, "42f5ba6f5fe1e00e652a08c46715871dc4b40d89d9799fd7c0ea758f86eab6a7"}, + {"aff5850c0168a67296cc790c1b04a9ed9ad1ba0469263a9432fcb53676d1bb4e0eea8ea1410100000005ac65526a537d5fcb1d01d9c26d0200000000065265ab5153acc0617ca1", "51ab650063", 0, 1712981774, "8449d5247071325e5f8edcc93cb9666c0fecabb130ce0e5bef050575488477eb"}, + {"e6d6b9d8042c27aec99af8c12b6c1f7a80453e2252c02515e1f391da185df0874e133696b50300000006ac5165650065ffffffff6a4b60a5bfe7af72b198eaa3cde2e02aa5fa36bdf5f24ebce79f6ecb51f3b554000000000652656aababac2ec4c5a6cebf86866b1fcc4c5bd5f4b19785a8eea2cdfe58851febf87feacf6f355324a80100000001537100145149ac1e287cef62f6f5343579189fad849dd33f25c25bfca841cb696f10c5a34503000000046a636a63df9d7c4c018d96e20100000000015100000000", "53ab", 1, -1924777542, "f98f95d0c5ec3ac3e699d81f6c440d2e7843eab15393eb023bc5a62835d6dcea"}, + {"046ac25e030a344116489cc48025659a363da60bc36b3a8784df137a93b9afeab91a04c1ed020000000951ab0000526a65ac51ffffffff6c094a03869fde55b9a8c4942a9906683f0a96e2d3e5a03c73614ea3223b2c29020000000500ab636a6affffffff3da7aa5ecef9071600866267674b54af1740c5aeb88a290c459caa257a2683cb0000000004ab6565ab7e2a1b900301b916030000000005abac63656308f4ed03000000000852ab53ac63ac51ac73d620020000000003ab00008deb1285", "6a", 2, 1299505108, "f79e6b776e2592bad45ca328c54abf14050c241d8f822d982c36ea890fd45757"}, + {"bd515acd0130b0ac47c2d87f8d65953ec7d657af8d96af584fc13323d0c182a2e5f9a96573000000000652ac51acac65ffffffff0467aade000000000003655363dc577d050000000006515252ab5300137f60030000000007535163530065004cdc860500000000036a5265241bf53e", "acab", 0, 621090621, "771d4d87f1591a13d77e51858c16d78f1956712fe09a46ff1abcabbc1e7af711"}, + {"ff1ae37103397245ac0fa1c115b079fa20930757f5b6623db3579cb7663313c2dc4a3ffdb300000000076353656a000053ffffffff83c59e38e5ad91216ee1a312d15b4267bae2dd2e57d1a3fd5c2f0f809eeb5d46010000000800abab6a6a53ab51ffffffff9d5e706c032c1e0ca75915f8c6686f64ec995ebcd2539508b7dd8abc3e4d7d2a01000000006b2bdcda02a8fe070500000000045253000019e31d04000000000700ab63acab526a00000000", "53656aab6a525251", 0, 881938872, "726bb88cdf3af2f7603a31f33d2612562306d08972a4412a55dbbc0e3363721c"}, + {"ff5400dd02fec5beb9a396e1cbedc82bedae09ed44bae60ba9bef2ff375a6858212478844b03000000025253ffffffff01e46c203577a79d1172db715e9cc6316b9cfc59b5e5e4d9199fef201c6f9f0f000000000900ab6552656a5165acffffffff02e8ce62040000000002515312ce3e00000000000251513f119316", "", 0, 1541581667, "1e0da47eedbbb381b0e0debbb76e128d042e02e65b11125e17fd127305fc65cd"}, + {"28e3daa603c03626ad91ffd0ff927a126e28d29db5012588b829a06a652ea4a8a5732407030200000004ab6552acffffffff8e643146d3d0568fc2ad854fd7864d43f6f16b84e395db82b739f6f5c84d97b40000000004515165526b01c2dc1469db0198bd884e95d8f29056c48d7e74ff9fd37a9dec53e44b8769a6c99c030200000009ab006a516a53630065eea8738901002398000000000007ac5363516a51abeaef12f5", "52ab52515253ab", 2, 1687390463, "55591346aec652980885a558cc5fc2e3f8d21cbd09f314a798e5a7ead5113ea6"}, + {"b54bf5ac043b62e97817abb892892269231b9b220ba08bc8dbc570937cd1ea7cdc13d9676c010000000451ab5365a10adb7b35189e1e8c00b86250f769319668189b7993d6bdac012800f1749150415b2deb0200000003655300ffffffff60b9f4fb9a7e17069fd00416d421f804e2ef2f2c67de4ca04e0241b9f9c1cc5d0200000003ab6aacfffffffff048168461cce1d40601b42fbc5c4f904ace0d35654b7cc1937ccf53fe78505a0100000008526563525265abacffffffff01dbf4e6040000000007acac656553636500000000", "63", 2, 882302077, "f5b38b0f06e246e47ce622e5ee27d5512c509f8ac0e39651b3389815eff2ab93"}, + {"ebf628b30360bab3fa4f47ce9e0dcbe9ceaf6675350e638baff0c2c197b2419f8e4fb17e16000000000452516365ac4d909a79be207c6e5fb44fbe348acc42fc7fe7ef1d0baa0e4771a3c4a6efdd7e2c118b0100000003acacacffffffffa6166e9101f03975721a3067f1636cc390d72617be72e5c3c4f73057004ee0ee010000000863636a6a516a5252c1b1e82102d8d54500000000000153324c900400000000015308384913", "0063516a51", 1, -1658428367, "eb2d8dea38e9175d4d33df41f4087c6fea038a71572e3bad1ea166353bf22184"}, + {"d6a8500303f1507b1221a91adb6462fb62d741b3052e5e7684ea7cd061a5fc0b0e93549fa50100000004acab65acfffffffffdec79bf7e139c428c7cfd4b35435ae94336367c7b5e1f8e9826fcb0ebaaaea30300000000ffffffffd115fdc00713d52c35ea92805414bd57d1e59d0e6d3b79a77ee18a3228278ada020000000453005151ffffffff040231510300000000085100ac6a6a000063c6041c0400000000080000536a6563acac138a0b04000000000263abd25fbe03000000000900656a00656aac510000000000", "ac526aac6a00", 1, -2007972591, "13d12a51598b34851e7066cd93ab8c5212d60c6ed2dae09d91672c10ccd7f87c"}, + {"658cb1c1049564e728291a56fa79987a4ed3146775fce078bd2e875d1a5ca83baf6166a82302000000056a656351ab2170e7d0826cbdb45fda0457ca7689745fd70541e2137bb4f52e7b432dcfe2112807bd720300000007006a0052536351ffffffff8715ca2977696abf86d433d5c920ef26974f50e9f4a20c584fecbb68e530af5101000000009e49d864155bf1d3c757186d29f3388fd89c7f55cc4d9158b4cf74ca27a35a1dd93f945502000000096a535353ac656351510d29fa870230b809040000000006ab6a6a526a633b41da050000000004ab6a6a65ed63bf62", "52acabac", 2, -1774073281, "53ab197fa7e27b8a3f99ff48305e67081eb90e95d89d7e92d80cee25a03a6689"}, + {"e92492cc01aec4e62df67ea3bc645e2e3f603645b3c5b353e4ae967b562d23d6e043badecd0100000003acab65ffffffff02c7e5ea040000000002ab52e1e584010000000005536365515195d16047", "6551", 0, -424930556, "93c34627f526d73f4bea044392d1a99776b4409f7d3d835f23b03c358f5a61c2"}, + {"02e242db04be2d8ced9179957e98cee395d4767966f71448dd084426844cbc6d15f2182e85030000000200650c8ffce3db9de9c3f9cdb9104c7cb26647a7531ad1ebf7591c259a9c9985503be50f8de30000000007ac6a51636a6353ffffffffa2e33e7ff06fd6469987ddf8a626853dbf30c01719efb259ae768f051f803cd30300000000fffffffffd69d8aead941683ca0b1ee235d09eade960e0b1df3cd99f850afc0af1b73e070300000001ab60bb602a011659670100000000076363526300acac00000000", "6353ab515251", 3, 1451100552, "bbc9069b8615f3a52ac8a77359098dcc6c1ba88c8372d5d5fe080b99eb781e55"}, + {"b28d5f5e015a7f24d5f9e7b04a83cd07277d452e898f78b50aae45393dfb87f94a26ef57720200000008ababac630053ac52ffffffff046475ed040000000008ab5100526363ac65c9834a04000000000251abae26b30100000000040000ac65ceefb900000000000000000000", "ac6551ac6a536553", 0, -1756558188, "5848d93491044d7f21884eef7a244fe7d38886f8ae60df49ce0dfb2a342cd51a"}, + {"efb8b09801f647553b91922a5874f8e4bb2ed8ddb3536ed2d2ed0698fac5e0e3a298012391030000000952ac005263ac52006affffffff04cdfa0f050000000007ac53ab51abac65b68d1b02000000000553ab65ac00d057d50000000000016a9e1fda010000000007ac63ac536552ac00000000", "6aac", 0, 1947322973, "603a9b61cd30fcea43ef0a5c18b88ca372690b971b379ee9e01909c336280511"}, + {"68a59fb901c21946797e7d07a4a3ea86978ce43df0479860d7116ac514ba955460bae78fff0000000001abffffffff03979be80100000000036553639300bc040000000008006552006a656565cfa78d0000000000076552acab63ab5100000000", "ab65ab", 0, 995583673, "3b320dd47f2702452a49a1288bdc74a19a4b849b132b6cad9a1d945d87dfbb23"}, + {"67761f2a014a16f3940dcb14a22ba5dc057fcffdcd2cf6150b01d516be00ef55ef7eb07a830100000004636a6a51ffffffff01af67bd050000000008526553526300510000000000", "6a00", 0, 1570943676, "079fa62e9d9d7654da8b74b065da3154f3e63c315f25751b4d896733a1d67807"}, + {"e20fe96302496eb436eee98cd5a32e1c49f2a379ceb71ada8a48c5382df7c8cd88bdc47ced03000000016556aa0e180660925a841b457aed0aae47fca2a92fa1d7afeda647abf67198a3902a7c80dd00000000085152ac636a535265bd18335e01803c810100000000046500ac52f371025e", "6363ab", 1, -651254218, "2921a0e5e3ba83c57ba57c25569380c17986bf34c366ec216d4188d5ba8b0b47"}, + {"4e1bd9fa011fe7aa14eee8e78f27c9fde5127f99f53d86bc67bdab23ca8901054ee8a8b6eb0300000009ac535153006a6a0063ffffffff044233670500000000000a667205000000000652ab636a51abe5bf35030000000003535351d579e505000000000700630065ab51ac3419ac30", "52abac52", 0, -1807563680, "4aae6648f856994bed252d319932d78db55da50d32b9008216d5366b44bfdf8a"}, + {"ec02fbee03120d02fde12574649660c441b40d330439183430c6feb404064d4f507e704f3c0100000000ffffffffe108d99c7a4e5f75cc35c05debb615d52fac6e3240a6964a29c1704d98017fb60200000002ab63fffffffff726ec890038977adfc9dadbeaf5e486d5fcb65dc23acff0dd90b61b8e2773410000000002ac65e9dace55010f881b010000000005ac00ab650000000000", "51ac525152ac6552", 2, -1564046020, "3f988922d8cd11c7adff1a83ce9499019e5ab5f424752d8d361cf1762e04269b"}, + {"23dbdcc1039c99bf11938d8e3ccec53b60c6c1d10c8eb6c31197d62c6c4e2af17f52115c3a0300000008636352000063ababffffffff17823880e1df93e63ad98c29bfac12e36efd60254346cac9d3f8ada020afc0620300000003ab63631c26f002ac66e86cd22a25e3ed3cb39d982f47c5118f03253054842daadc88a6c41a2e1500000000096a00ab636a53635163195314de015570fd0100000000096a5263acab5200005300000000", "ababac6a6553", 1, 11586329, "bd36a50e0e0a4ecbf2709e68daef41eddc1c0c9769efaee57910e99c0a1d1343"}, + {"33b03bf00222c7ca35c2f8870bbdef2a543b70677e413ce50494ac9b22ea673287b6aa55c50000000005ab00006a52ee4d97b527eb0b427e4514ea4a76c81e68c34900a23838d3e57d0edb5410e62eeb8c92b6000000000553ac6aacac42e59e170326245c000000000009656553536aab516aabb1a10603000000000852ab52ab6a516500cc89c802000000000763ac6a63ac516300000000", "", 0, 557416556, "41bead1b073e1e9fee065dd612a617ca0689e8f9d3fed9d0acfa97398ebb404c"}, + {"813eda1103ac8159850b4524ef65e4644e0fc30efe57a5db0c0365a30446d518d9b9aa8fdd0000000003656565c2f1e89448b374b8f12055557927d5b33339c52228f7108228149920e0b77ef0bcd69da60000000006abac00ab63ab82cdb7978d28630c5e1dc630f332c4245581f787936f0b1e84d38d33892141974c75b4750300000004ac53ab65ffffffff0137edfb02000000000000000000", "0063", 1, -1948560575, "71dfcd2eb7f2e6473aed47b16a6d5fcbd0af22813d892e9765023151e07771ec"}, + {"9e45d9aa0248c16dbd7f435e8c54ae1ad086de50c7b25795a704f3d8e45e1886386c653fbf01000000025352fb4a1acefdd27747b60d1fb79b96d14fb88770c75e0da941b7803a513e6d4c908c6445c7010000000163ffffffff014069a8010000000001520a794fb3", "51ac005363", 1, -719113284, "0d31a221c69bd322ef7193dd7359ddfefec9e0a1521d4a8740326d46e44a5d6a"}, + {"36e42018044652286b19a90e5dd4f8d9f361d0760d080c5c5add1970296ff0f1de630233c8010000000200ac39260c7606017d2246ee14ddb7611586178067e6a4be38e788e33f39a3a95a55a13a6775010000000352ac638bea784f7c2354ed02ea0b93f0240cdfb91796fa77649beee6f7027caa70778b091deee700000000066a65ac656363ffffffff4d9d77ab676d711267ef65363f2d192e1bd55d3cd37f2280a34c72e8b4c559d700000000056a006aab00001764e1020d30220100000000085252516aacab0053472097040000000009635353ab6a636a5100a56407a1", "006a536551ab53ab", 0, 827296034, "daec2af5622bbe220c762da77bab14dc75e7d28aa1ade9b7f100798f7f0fd97a"}, + {"5e06159a02762b5f3a5edcdfc91fd88c3bff08b202e69eb5ba74743e9f4291c4059ab008200000000001ac348f5446bb069ef977f89dbe925795d59fb5d98562679bafd61f5f5f3150c3559582992d0000000008ab5165515353abac762fc67703847ec6010000000000e200cf040000000002abaca64b86010000000008520000515363acabb82b491b", "ab53525352ab6a", 0, -61819505, "75a7db0df41485a28bf6a77a37ca15fa8eccc95b5d6014a731fd8adb9ada0f12"}, + {"a1948872013b543d6d902ccdeead231c585195214ccf5d39f136023855958436a43266911501000000086aac006a6a6a51514951c9b2038a538a04000000000452526563c0f345050000000007526a5252ac526af9be8e03000000000752acac51ab006306198db2", "ab6353", 0, -326384076, "ced7ef84aad4097e1eb96310e0d1c8e512cfcb392a01d9010713459b23bc0cf4"}, + {"c3efabba03cb656f154d1e159aa4a1a4bf9423a50454ebcef07bc3c42a35fb8ad84014864d0000000000d1cc73d260980775650caa272e9103dc6408bdacaddada6b9c67c88ceba6abaa9caa2f7d020000000553536a5265ffffffff9f946e8176d9b11ff854b76efcca0a4c236d29b69fb645ba29d406480427438e01000000066a0065005300ffffffff040419c0010000000003ab6a63cdb5b6010000000009006300ab5352656a63f9fe5e050000000004acac5352611b980100000000086a00acac00006a512d7f0c40", "0053", 0, -59089911, "c503001c16fbff82a99a18d88fe18720af63656fccd8511bca1c3d0d69bd7fc0"}, + {"efb55c2e04b21a0c25e0e29f6586be9ef09f2008389e5257ebf2f5251051cdc6a79fce2dac020000000351006affffffffaba73e5b6e6c62048ba5676d18c33ccbcb59866470bb7911ccafb2238cfd493802000000026563ffffffffe62d7cb8658a6eca8a8babeb0f1f4fa535b62f5fc0ec70eb0111174e72bbec5e0300000009abababac516365526affffffffbf568789e681032d3e3be761642f25e46c20322fa80346c1146cb47ac999cf1b0300000000b3dbd55902528828010000000001ab0aac7b0100000000015300000000", "acac52", 3, 1638140535, "e84444d91580da41c8a7dcf6d32229bb106f1be0c811b2292967ead5a96ce9d4"}, + {"91d3b21903629209b877b3e1aef09cd59aca6a5a0db9b83e6b3472aceec3bc2109e64ab85a0200000003530065ffffffffca5f92de2f1b7d8478b8261eaf32e5656b9eabbc58dcb2345912e9079a33c4cd010000000700ab65ab00536ad530611da41bbd51a389788c46678a265fe85737b8d317a83a8ff7a839debd18892ae5c80300000007ab6aac65ab51008b86c501038b8a9a05000000000263525b3f7a040000000007ab535353ab00abd4e3ff04000000000665ac51ab65630b7b656f", "6551525151516a00", 2, 499657927, "ef4bd7622eb7b2bbbbdc48663c1bc90e01d5bde90ff4cb946596f781eb420a0c"}, + {"5d5c41ad0317aa7e40a513f5141ad5fc6e17d3916eebee4ddb400ddab596175b41a111ead20100000005536a5265acffffffff900ecb5e355c5c9f278c2c6ea15ac1558b041738e4bffe5ae06a9346d66d5b2b00000000080000ab636a65ab6affffffff99f4e08305fa5bd8e38fb9ca18b73f7a33c61ff7b3c68e696b30a04fea87f3ca000000000163d3d1760d019fc13a00000000000000000000", "ab53acabab6aac6a52", 2, 1007461922, "4012f5ff2f1238a0eb84854074670b4703238ebc15bfcdcd47ffa8498105fcd9"}, + {"ceecfa6c02b7e3345445b82226b15b7a097563fa7d15f3b0c979232b138124b62c0be007890200000009abac51536a63525253ffffffffbae481ccb4f15d94db5ec0d8854c24c1cc8642bd0c6300ede98a91ca13a4539a0200000001ac50b0813d023110f5020000000006acabac526563e2b0d0040000000009656aac0063516a536300000000", "0063526500", 0, -1862053821, "e1600e6df8a6160a79ac32aa40bb4644daa88b5f76c0d7d13bf003327223f70c"}, + {"ae62d5fd0380c4083a26642159f51af24bf55dc69008e6b7769442b6a69a603edd980a33000000000005ab5100ab53ffffffff49d048324d899d4b8ed5e739d604f5806a1104fede4cb9f92cc825a7fa7b4bfe0200000005536a000053ffffffff42e5cea5673c650881d0b4005fa4550fd86de5f21509c4564a379a0b7252ac0e0000000007530000526a53525f26a68a03bfacc3010000000000e2496f000000000009ab5253acac52636563b11cc600000000000700510065526a6a00000000", "abab", 1, -1600104856, "05cf0ec9c61f1a15f651a0b3c5c221aa543553ce6c804593f43bb5c50bb91ffb"}, + {"f06f64af04fdcb830464b5efdb3d5ee25869b0744005375481d7b9d7136a0eb8828ad1f0240200000003516563fffffffffd3ba192dabe9c4eb634a1e3079fca4f072ee5ceb4b57deb6ade5527053a92c5000000000165ffffffff39f43401a36ba13a5c6dd7f1190e793933ae32ee3bf3e7bfb967be51e681af760300000009650000536552636a528e34f50b21183952cad945a83d4d56294b55258183e1627d6e8fb3beb8457ec36cadb0630000000005abab530052334a7128014bbfd10100000000085352ab006a63656afc424a7c", "53650051635253ac00", 2, 313255000, "d309da5afd91b7afa257cfd62df3ca9df036b6a9f4b38f5697d1daa1f587312b"}, + {"6dfd2f98046b08e7e2ef5fff153e00545faf7076699012993c7a30cb1a50ec528281a9022f030000000152ffffffff1f535e4851920b968e6c437d84d6ecf586984ebddb7d5db6ae035bd02ba222a8010000000651006a53ab51605072acb3e17939fa0737bc3ee43bc393b4acd58451fc4ffeeedc06df9fc649828822d5010000000253525a4955221715f27788d302382112cf60719be9ae159c51f394519bd5f7e70a4f9816c7020200000009526a6a51636aab656a36d3a5ff0445548e0100000000086a6a00516a52655167030b050000000004ac6a63525cfda8030000000000e158200000000000010000000000", "535263ac6a65515153", 3, 585774166, "72b7da10704c3ca7d1deb60c31b718ee12c70dc9dfb9ae3461edce50789fe2ba"}, + {"187eafed01389a45e75e9dda526d3acbbd41e6414936b3356473d1f9793d161603efdb45670100000002ab00ffffffff04371c8202000000000563630063523b3bde02000000000753516563006300e9e765010000000005516aac656a373f9805000000000665525352acab08d46763", "ab", 0, 122457992, "393aa6c758e0eed15fa4af6d9e2d7c63f49057246dbb92b4268ec24fc87301ca"}, + {"7d50b977035d50411d814d296da9f7965ddc56f3250961ca5ba805cadd0454e7c521e31b0300000000003d0416c2cf115a397bacf615339f0e54f6c35ffec95aa009284d38390bdde1595cc7aa7c0100000005ab52ac5365ffffffff4232c6e796544d5ac848c9dc8d25cfa74e32e847a5fc74c74d8f38ca51188562030000000653ac51006a51ffffffff016bd8bb00000000000465ab5253163526f3", "51ab526a00005353", 1, -1311316785, "60b7544319b42e4159976c35c32c2644f0adf42eff13be1dc2f726fc0b6bb492"}, + {"2a45cd1001bf642a2315d4a427eddcc1e2b0209b1c6abd2db81a800c5f1af32812de42032702000000050051525200ffffffff032177db050000000005530051abac49186f000000000004ab6aab00645c0000000000000765655263acabac00000000", "6a65", 0, -1774715722, "6a9ac3f7da4c7735fbc91f728b52ecbd602233208f96ac5592656074a5db118a"}, + {"479358c202427f3c8d19e2ea3def6d6d3ef2281b4a93cd76214f0c7d8f040aa042fe19f71f0300000001abffffffffa2709be556cf6ecaa5ef530df9e4d056d0ed57ce96de55a5b1f369fa40d4e74a020000000700006a51635365c426be3f02af578505000000000363ab63fd8f590500000000065153abac53632dfb14b3", "520063ab51", 1, -763226778, "cfe147982afacde044ce66008cbc5b1e9f0fd9b8ed52b59fc7c0fecf95a39b0e"}, + {"76179a8e03bec40747ad65ab0f8a21bc0d125b5c3c17ad5565556d5cb03ade7c83b4f32d98030000000151ffffffff99b900504e0c02b97a65e24f3ad8435dfa54e3c368f4e654803b756d011d24150200000003ac5353617a04ac61bb6cf697cfa4726657ba35ed0031432da8c0ffb252a190278830f9bd54f0320100000006656551005153c8e8fc8803677c77020000000007ac6553535253ac70f442030000000001535be0f20200000000026300bf46cb3a", "6aab52", 1, -58495673, "35e94b3776a6729d20aa2f3ddeeb06d3aad1c14cc4cde52fd21a4efc212ea16c"}, + {"75ae53c2042f7546223ce5d5f9e00a968ddc68d52e8932ef2013fa40ce4e8c6ed0b6195cde01000000056563ac630079da0452c20697382e3dba6f4fc300da5f52e95a9dca379bb792907db872ba751b8024ee0300000009655151536500005163ffffffffe091b6d43f51ff00eff0ccfbc99b72d3aff208e0f44b44dfa5e1c7322cfc0c5f01000000075200005363ab63ffffffff7e96c3b83443260ac5cfd18258574fbc4225c630d3950df812bf51dceaeb0f9103000000065365655165639a6bf70b01b3e14305000000000563530063ac00000000", "6300ab00ac", 2, 982422189, "ee4ea49d2aae0dbba05f0b9785172da54408eb1ec67d36759ff7ed25bfc28766"}, + {"1cdfa01e01e1b8078e9c2b0ca5082249bd18fdb8b629ead659adedf9a0dd5a04031871ba120200000008525351536565ab6affffffff011e28430200000000076a5363636aac52b2febd4a", "abacac63656300", 0, 387396350, "299dcaac2bdaa627eba0dfd74767ee6c6f27c9200b49da8ff6270b1041669e7e"}, + {"cc28c1810113dfa6f0fcd9c7d9c9a30fb6f1d774356abeb527a8651f24f4e6b25cf763c4e00300000003ab636affffffff02dfc6050000000000080053636351ab0052afd56903000000000453ab5265f6c90d99", "006551abacacac", 0, 1299280838, "a4c0773204ab418a939e23f493bd4b3e817375d133d307609e9782f2cc38dbcf"}, + {"ca816e7802cd43d66b9374cd9bf99a8da09402d69c688d8dcc5283ace8f147e1672b757e020200000005516aabab5240fb06c95c922342279fcd88ba6cd915933e320d7becac03192e0941e0345b79223e89570300000004005151ac353ecb5d0264dfbd010000000005ac6aacababd5d70001000000000752ac53ac6a5151ec257f71", "63ac", 1, 774695685, "cc180c4f797c16a639962e7aec58ec4b209853d842010e4d090895b22e7a7863"}, + {"b42b955303942fedd7dc77bbd9040aa0de858afa100f399d63c7f167b7986d6c2377f66a7403000000066aac00525100ffffffff0577d04b64880425a3174055f94191031ad6b4ca6f34f6da9be7c3411d8b51fc000000000300526a6391e1cf0f22e45ef1c44298523b516b3e1249df153590f592fcb5c5fc432dc66f3b57cb03000000046a6aac65ffffffff0393a6c9000000000004516a65aca674ac0400000000046a525352c82c370000000000030053538e577f89", "", 1, -1237094944, "566953eb806d40a9fb684d46c1bf8c69dea86273424d562bd407b9461c8509af"}, + {"92c9fe210201e781b72554a0ed5e22507fb02434ddbaa69aff6e74ea8bad656071f1923f3f02000000056a63ac6a514470cef985ba83dcb8eee2044807bedbf0d983ae21286421506ae276142359c8c6a34d68020000000863ac63525265006aa796dd0102ca3f9d05000000000800abab52ab535353cd5c83010000000007ac00525252005322ac75ee", "5165", 0, 97879971, "6e6307cef4f3a9b386f751a6f40acebab12a0e7e17171d2989293cbec7fd45c2"}, + {"ccca1d5b01e40fe2c6b3ee24c660252134601dab785b8f55bd6201ffaf2fddc7b3e2192325030000000365535100496d4703b4b66603000000000665535253ac633013240000000000015212d2a502000000000951abac636353636a5337b82426", "0052", 0, -1691630172, "577bf2b3520b40aef44899a20d37833f1cded6b167e4d648fc5abe203e43b649"}, + {"bc1a7a3c01691e2d0c4266136f12e391422f93655c71831d90935fbda7e840e50770c61da20000000008635253abac516353ffffffff031f32aa020000000003636563786dbc0200000000003e950f00000000000563516a655184b8a1de", "51536a", 0, -1627072905, "730bc25699b46703d7718fd5f5c34c4b5f00f594a9968ddc247fa7d5175124ed"}, + {"076d209e02d904a6c40713c7225d23e7c25d4133c3c3477828f98c7d6dbd68744023dbb66b030000000753ab00536565acffffffff10975f1b8db8861ca94c8cc7c7cff086ddcd83e10b5fffd4fc8f2bdb03f9463c0100000000ffffffff029dff76010000000006526365530051a3be6004000000000000000000", "515253ac65acacac", 1, -1207502445, "66c488603b2bc53f0d22994a1f0f66fb2958203102eba30fe1d37b27a55de7a5"}, + {"690fd1f80476db1f9eebe91317f2f130a60cbc1f4feadd9d6474d438e9cb7f91e4994600af0300000004ab536a63a15ce9fa6622d0c4171d895b42bff884dc6e8a7452f827fdc68a29c3c88e6fdee364eaf50000000002ab52ffffffff022dc39d3c0956b24d7f410b1e387859e7a72955f45d6ffb1e884d77888d18fe0300000005ac6a63656afffffffff10b06bce1800f5c49153d24748fdefb0bf514c12863247d1042d56018c3e25c03000000086a63ac6365536a52ffffffff031f162f0500000000060000655265abffbcd40500000000045151ac001a9c8c05000000000652ac53656a6300000000", "ac51ab63acac", 0, -67986012, "051c0df7ac688c2c930808dabde1f50300aea115f2bb3334f4753d5169b51e46"}, + {"49ac2af00216c0307a29e83aa5de19770e6b20845de329290bd69cf0e0db7aed61ae41b39002000000035163ac8b2558ef84635bfc59635150e90b61fc753d34acfd10d97531043053e229cd720133cd95000000000463516a51ffffffff02458471040000000008abab636a51ac0065545aa80000000000096a6553516a5263ac6a00000000", "51526300ab5363", 1, 1449668540, "ddfd902bba312a06197810da96a0ddccb595f96670b28ded7dba88d8cd0469b8"}, + {"fa4d868b024b010bd5dce46576c2fb489aa60bb797dac3c72a4836f49812c5c564c258414f03000000007a9b3a585e05027bdd89edbadf3c85ac61f8c3a04c773fa746517ae600ff1a9d6b6c02fb0200000004515163abffffffff01b17d020500000000046a65520000000000", "536565ab65635363", 0, -1718953372, "96c2b32f0a00a5925db7ba72d0b5d39922f30ea0f7443b22bc1b734808513c47"}, + {"cac6382d0462375e83b67c7a86c922b569a7473bfced67f17afd96c3cd2d896cf113febf9e0300000003006a53ffffffffaa4913b7eae6821487dd3ca43a514e94dcbbf350f8cc4cafff9c1a88720711b800000000096a6a525300acac6353ffffffff184fc4109c34ea27014cc2c1536ef7ed1821951797a7141ddacdd6e429fae6ff01000000055251655200ffffffff9e7b79b4e6836e290d7b489ead931cba65d1030ccc06f20bd4ca46a40195b33c030000000008f6bc8304a09a2704000000000563655353511dbc73050000000000cf34c500000000000091f76e0000000000085200ab00005100abd07208cb", "0063656a", 2, -1488731031, "bf078519fa87b79f40abc38f1831731422722c59f88d86775535f209cb41b9b1"}, + {"1711146502c1a0b82eaa7893976fefe0fb758c3f0e560447cef6e1bde11e42de91a125f71c030000000015bd8c04703b4030496c7461482481f290c623be3e76ad23d57a955807c9e851aaaa20270300000000d04abaf20326dcb7030000000001632225350400000000075263ac00520063dddad9020000000000af23d148", "52520053510063", 0, 1852122830, "e33d5ee08c0f3c130a44d7ce29606450271b676f4a80c52ab9ffab00cecf67f8"}, + {"8d5b124d0231fbfc640c706ddb1d57bb49a18ba8ca0e1101e32c7e6e65a0d4c7971d93ea360100000008acabac0000abac65ffffffff8fe0fd7696597b845c079c3e7b87d4a44110c445a330d70342a5501955e17dd70100000004ab525363ef22e8a90346629f030000000009516a00ac63acac51657bd57b05000000000200acfd4288050000000009acab5352ab00ab636300000000", "53ac526553ab65", 0, 1253152975, "8b57a7c3170c6c02dd14ae1d392ce3d828197b20e9145c89c1cfd5de050e1562"}, + {"38146dc502c7430e92b6708e9e107b61cd38e5e773d9395e5c8ad8986e7e4c03ee1c1e1e760100000000c8962ce2ac1bb3b1285c0b9ba07f4d2e5ce87c738c42ac0548cd8cec1100e6928cd6b0b6010000000763ab636aab52527cccefbd04e5f6f8020000000006006aabacac65ab2c4a00000000000351635209a6f40100000000026aacce57dc040000000008ab5353ab516a516a00000000", "ab", 0, -1205978252, "3cb5b030e7da0b60ccce5b4a7f3793e6ca56f03e3799fe2d6c3cc22d6d841dcb"}, + {"22d81c740469695a6a83a9a4824f77ecff8804d020df23713990afce2b72591ed7de98500502000000065352526a6a6affffffff90dc85e118379b1005d7bbc7d2b8b0bab104dad7eaa49ff5bead892f17d8c3ba010000000665656300ab51ffffffff965193879e1d5628b52005d8560a35a2ba57a7f19201a4045b7cbab85133311d0200000003ac005348af21a13f9b4e0ad90ed20bf84e4740c8a9d7129632590349afc03799414b76fd6e826200000000025353ffffffff04a0d40d04000000000060702700000000000652655151516ad31f1502000000000365ac0069a1ac0500000000095100655300ab53525100000000", "51636a52ac", 0, -1644680765, "add7f5da27262f13da6a1e2cc2feafdc809bd66a67fb8ae2a6f5e6be95373b6f"}, + {"a27dcbc801e3475174a183586082e0914c314bc9d79d1570f29b54591e5e0dff07fbb45a7f0000000004ac53ab51ffffffff027347f5020000000005535351ab63d0e5c9030000000009ac65ab6a63515200ab7cd632ed", "ac63636553", 0, -686435306, "883a6ea3b2cc53fe8a803c229106366ca14d25ffbab9fef8367340f65b201da6"}, + {"b123ed2204410d4e8aaaa8cdb95234ca86dad9ff77fb4ae0fd4c06ebed36794f0215ede0040100000002ac63ffffffff3b58b81b19b90d8f402701389b238c3a84ff9ba9aeea298bbf15b41a6766d27a01000000056a6553ab00151824d401786153b819831fb15926ff1944ea7b03d884935a8bde01ed069d5fd80220310200000000ffffffffa9c9d246f1eb8b7b382a9032b55567e9a93f86c77f4e32c092aa1738f7f756c30100000002ab65ffffffff011a2b48000000000000ed44d1fb", "630051ab63", 2, -1118263883, "b5dab912bcabedff5f63f6dd395fc2cf030d83eb4dd28214baba68a45b4bfff0"}, + {"1339051503e196f730955c5a39acd6ed28dec89b4dadc3f7c79b203b344511270e5747fa9900000000045151636affffffff378c6090e08a3895cedf1d25453bbe955a274657172491fd2887ed5c9aceca7b0100000000ffffffffcf7cc3c36ddf9d4749edfa9cefed496d2f86e870deb814bfcd3b5637a5496461030000000451006300ffffffff04dcf3fa010000000008526a63005263acabb41d84040000000004abac5153800eff020000000005656a535365106c5e00000000000000000000", "abac5300", 2, 2013719928, "7fc74de39ce6ca46ca25d760d3cec7bb21fd14f7efe1c443b5aa294f2cb5f546"}, + {"0728c606014c1fd6005ccf878196ba71a54e86cc8c53d6db500c3cc0ac369a26fac6fcbc210000000005ab53ac5365ba9668290182d7870100000000066a000053655100000000", "65", 0, 1789961588, "ab6baa6da3b2bc853868d166f8996ad31d63ef981179f9104f49968fd61c8427"}, + {"a1134397034bf4067b6c81c581e2b73fb63835a08819ba24e4e92df73074bf773c94577df7000000000465525251ffffffff8b6608feaa3c1f35f49c6330a769716fa01c5c6f6e0cdc2eb10dfc99bbc21e77010000000952656aac005352655180a0bda4bc72002c2ea8262e26e03391536ec36867258cab968a6fd6ec7523b64fa1d8c001000000056a53ac6353ffffffff04dbeeed05000000000553650052abcd5d0e01000000000463abab51104b2e0500000000066aac53ac5165283ca7010000000004535252ab00000000", "ab515151516552ab", 1, -324598676, "91178482112f94d1c8e929de443e4b9c893e18682998d393ca9ca77950412586"}, + {"bcdafbae04aa18eb75855aeb1f5124f30044741351b33794254a80070940cb10552fa4fa8e0300000001acd0423fe6e3f3f88ae606f2e8cfab7a5ef87caa2a8f0401765ff9a47d718afcfb40c0099b0000000008ac6565ab53ac6aac645308009d680202d600e492b31ee0ab77c7c5883ebad5065f1ce87e4dfe6453e54023a0010000000151ffffffffb9d818b14245899e1d440152827c95268a676f14c3389fc47f5a11a7b38b1bde03000000026300ffffffff03cda22102000000000751ac535263005100a4d20400000000045200536ac8bef405000000000700ab51ab6563ac00000000", "6553516a526aab", 1, -2111409753, "5e1849e7368cf4f042718586d9bd831d61479b775bab97aba9f450042bd9876a"}, + {"ed3bb93802ddbd08cb030ef60a2247f715a0226de390c9c1a81d52e83f8674879065b5f87d0300000003ab6552ffffffff04d2c5e60a21fb6da8de20bf206db43b720e2a24ce26779bca25584c3f765d1e0200000008ab656a6aacab00ab6e946ded025a811d04000000000951abac6352ac00ab5143cfa3030000000005635200636a00000000", "5352ac650065535300", 1, -668727133, "e9995065e1fddef72a796eef5274de62012249660dc9d233a4f24e02a2979c87"}, + {"59f4629d030fa5d115c33e8d55a79ea3cba8c209821f979ed0e285299a9c72a73c5bba00150200000002636affffffffd8aca2176df3f7a96d0dc4ee3d24e6cecde1582323eec2ebef9a11f8162f17ac0000000007ab6565acab6553ffffffffeebc10af4f99c7a21cbc1d1074bd9f0ee032482a71800f44f26ee67491208e0403000000065352ac656351ffffffff0434e955040000000004ab515152caf2b305000000000365ac007b1473030000000003ab530033da970500000000060051536a5253bb08ab51", "", 2, 396340944, "0e9c47973ef2c292b2252c623f465bbb92046fe0b893eebf4e1c9e02cb01c397"}, + {"286e3eb7043902bae5173ac3b39b44c5950bc363f474386a50b98c7bdab26f98dc83449c4a020000000752ac6a00510051ffffffff4339cd6a07f5a5a2cb5815e5845da70300f5c7833788363bf7fe67595d3225520100000000fffffffff9c2dd8b06ad910365ffdee1a966f124378a2b8021065c8764f6138bb1e951380200000005ab5153ac6affffffff0370202aba7a68df85436ea7c945139513384ef391fa33d16020420b8ad40e9a000000000900ab5165526353abacffffffff020c1907000000000004abac526a1b490b040000000000df1528f7", "5353ab", 3, -1407529517, "32154c09174a9906183abf26538c39e78468344ca0848bbd0785e24a3565d932"}, + {"2e245cf80179e2e95cd1b34995c2aff49fe4519cd7cee93ad7587f7f7e8105fc2dff206cd30200000009006a63516a6553ab52350435a201d5ed2d02000000000352ab6558552c89", "00ab53", 0, -233917810, "4605ae5fd3d50f9c45d37db7118a81a9ef6eb475d2333f59df5d3e216f150d49"}, + {"33a98004029d262f951881b20a8d746c8c707ea802cd2c8b02a33b7e907c58699f97e42be80100000007ac53536552abacdee04cc01d205fd8a3687fdf265b064d42ab38046d76c736aad8865ca210824b7c622ecf02000000070065006a536a6affffffff01431c5d010000000000270d48ee", "", 1, 921554116, "ff9d7394002f3f196ea25472ea6c46f753bd879a7244795157bb7235c9322902"}, + {"aac18f2b02b144ed481557c53f2146ae523f24fcde40f3445ab0193b6b276c315dc2894d2300000000075165650000636a233526947dbffc76aec7db1e1baa6868ad4799c76e14794dcbaaec9e713a83967f6a65170200000005abac6551ab27d518be01b652a30000000000015300000000", "52ac5353", 1, 1559377136, "59fc2959bb7bb24576cc8a237961ed95bbb900679d94da6567734c4390cb6ef5"}, + {"5ab79881033555b65fe58c928883f70ce7057426fbdd5c67d7260da0fe8b1b9e6a2674cb850300000009ac516aac6aac006a6affffffffa5be9223b43c2b1a4d120b5c5b6ec0484f637952a3252181d0f8e813e76e11580200000000e4b5ceb8118cb77215bbeedc9a076a4d087bb9cd1473ea32368b71daeeeacc451ec209010000000005acac5153aced7dc34e02bc5d11030000000005ac5363006a54185803000000000552ab00636a00000000", "5100", 1, 1927062711, "e9f53d531c12cce1c50abed4ac521a372b4449b6a12f9327c80020df6bff66c0"}, + {"6c2c8fac0124b0b7d4b610c3c5b91dee32b7c927ac71abdf2d008990ca1ac40de0dfd530660300000006ababac5253656bd7eada01d847ec000000000004ac52006af4232ec8", "6a6a6a0051", 0, -340809707, "fb51eb9d7e47d32ff2086205214f90c7c139e08c257a64829ae4d2b301071c6a"}, + {"6e3880af031735a0059c0bb5180574a7dcc88e522c8b56746d130f8d45a52184045f96793e0100000008acabac6a526a6553fffffffffe05f14cdef7d12a9169ec0fd37524b5fcd3295f73f48ca35a36e671da4a2f560000000008006a526a6351ab63ffffffffdfbd869ac9e472640a84caf28bdd82e8c6797f42d03b99817a705a24fde2736600000000010090a090a503db956b04000000000952ac53ab6a536a63ab358390010000000009656a5200525153ac65353ee204000000000763530052526aaba6ad83fb", "535151ab6300", 2, 222014018, "57a34ddeb1bf36d28c7294dda0432e9228a9c9e5cc5c692db98b6ed2e218d825"}, + {"8df1cd19027db4240718dcaf70cdee33b26ea3dece49ae6917331a028c85c5a1fb7ee3e475020000000865ab6a00510063636157988bc84d8d55a8ba93cdea001b9bf9d0fa65b5db42be6084b5b1e1556f3602f65d4d0100000005ac00ab0052206c852902b2fb54030000000008ac5252536aacac5378c4a5050000000007acabac535163532784439e", "acab6a", 0, 1105620132, "edb7c74223d1f10f9b3b9c1db8064bc487321ff7bb346f287c6bc2fad83682de"}, + {"0e803682024f79337b25c98f276d412bc27e56a300aa422c42994004790cee213008ff1b8303000000080051ac65ac655165f421a331892b19a44c9f88413d057fea03c3c4a6c7de4911fe6fe79cf2e9b3b10184b1910200000005525163630096cb1c670398277204000000000253acf7d5d502000000000963536a6a636a5363ab381092020000000002ac6a911ccf32", "6565", 1, -1492094009, "f0672638a0e568a919e9d8a9cbd7c0189a3e132940beeb52f111a89dcc2daa2c"}, + {"7d71669d03022f9dd90edac323cde9e56354c6804c6b8e687e9ae699f46805aafb8bcaa636000000000253abffffffff698a5fdd3d7f2b8b000c68333e4dd58fa8045b3e2f689b889beeb3156cecdb490300000009525353abab0051acabc53f0aa821cdd69b473ec6e6cf45cf9b38996e1c8f52c27878a01ec8bb02e8cb31ad24e500000000055353ab0052ffffffff0447a23401000000000565ab53ab5133aaa0030000000006515163656563057d110300000000056a6aacac52cf13b5000000000003526a5100000000", "6a6a51", 1, -1349253507, "722efdd69a7d51d3d77bed0ac5544502da67e475ea5857cd5af6bdf640a69945"}, + {"9ff618e60136f8e6bb7eabaaac7d6e2535f5fba95854be6d2726f986eaa9537cb283c701ff02000000026a65ffffffff012d1c0905000000000865ab00ac6a516a652f9ad240", "51515253635351ac", 0, 1571304387, "659cd3203095d4a8672646add7d77831a1926fc5b66128801979939383695a79"}, + {"9fbd43ac025e1462ecd10b1a9182a8e0c542f6d1089322a41822ab94361e214ed7e1dfdd8a020000000263519d0437581538e8e0b6aea765beff5b4f3a4a202fca6e5d19b34c141078c6688f71ba5b8e0100000003ac6552ffffffff02077774050000000009655153655263acab6a0ae4e10100000000035152524c97136b", "635152ab", 0, 1969622955, "d82d4ccd9b67810f26a378ad9592eb7a30935cbbd27e859b00981aefd0a72e08"}, + {"0117c92004314b84ed228fc11e2999e657f953b6de3b233331b5f0d0cf40d5cc149b93c7b30300000005515263516a083e8af1bd540e54bf5b309d36ba80ed361d77bbf4a1805c7aa73667ad9df4f97e2da410020000000600ab6351ab524d04f2179455e794b2fcb3d214670001c885f0802e4b5e015ed13a917514a7618f5f332203000000086a536aab51000063ecf029e65a4a009a5d67796c9f1eb358b0d4bd2620c8ad7330fb98f5a802ab92d0038b1002000000036a6551a184a88804b04490000000000009ab6a5152535165526a33d1ab020000000001518e92320000000000002913df04000000000952abac6353525353ac8b19bfdf", "000051ab0000", 0, 489433059, "8eebac87e60da524bbccaf285a44043e2c9232868dda6c6271a53c153e7f3a55"}, + {"e7f5482903f98f0299e0984b361efb2fddcd9979869102281e705d3001a9d283fe9f3f3a1e02000000025365ffffffffcc5c7fe82feebad32a22715fc30bc584efc9cd9cadd57e5bc4b6a265547e676e0000000001ab579d21235bc2281e08bf5e7f8f64d3afb552839b9aa5c77cf762ba2366fffd7ebb74e49400000000055263ab63633df82cf40100982e05000000000453ac535300000000", "acacab", 2, -1362931214, "046de666545330e50d53083eb78c9336416902f9b96c77cc8d8e543da6dfc7e4"}, + {"09adb2e90175ca0e816326ae2dce7750c1b27941b16f6278023dbc294632ab97977852a09d030000000465ab006affffffff027739cf0100000000075151ab63ac65ab8a5bb601000000000653ac5151520011313cdc", "ac", 0, -76831756, "478ee06501b4965b40bdba6cbaad9b779b38555a970912bb791b86b7191c54bc"}, + {"f973867602e30f857855cd0364b5bbb894c049f44abbfd661d7ae5dbfeaafca89fac8959c20100000005ab52536a51ffffffffbeceb68a4715f99ba50e131884d8d20f4a179313691150adf0ebf29d05f8770303000000066352ab00ac63ffffffff021fddb90000000000036a656322a177000000000008526500ac5100acac84839083", "52acab53ac", 0, 1407879325, "db0329439490efc64b7104d6d009b03fbc6fac597cf54fd786fbbb5fd73b92b4"}, + {"fd22ebaa03bd588ad16795bea7d4aa7f7d48df163d75ea3afebe7017ce2f350f6a0c1cb0bb00000000086aabac5153526363ffffffff488e0bb22e26a565d77ba07178d17d8f85702630ee665ec35d152fa05af3bda10200000004515163abffffffffeb21035849e85ad84b2805e1069a91bb36c425dc9c212d9bae50a95b6bfde1200300000001ab5df262fd02b69848040000000008ab6363636a6363ace23bf2010000000007655263635253534348c1da", "006353526563516a00", 0, -1491036196, "92364ba3c7a85d4e88885b8cb9b520dd81fc29e9d2b750d0790690e9c1246673"}, + {"130b462d01dd49fac019dc4442d0fb54eaa6b1c2d1ad0197590b7df26969a67abd7f3fbb4f0100000008ac65abac53ab6563ffffffff0345f825000000000004ac53acac9d5816020000000002ababeff8e90500000000086aab006552ac6a53a892dc55", "ab0065ac530052", 0, 944483412, "1f4209fd4ce7f13d175fdd522474ae9b34776fe11a5f17a27d0796c77a2a7a9d"}, + {"f8e50c2604609be2a95f6d0f31553081f4e1a49a0a30777fe51eb1c596c1a9a92c053cf28c0300000009656a51ac5252630052fffffffff792ed0132ae2bd2f11d4a2aab9d0c4fbdf9a66d9ae2dc4108afccdc14d2b1700100000007ab6a6563ac636a7bfb2fa116122b539dd6a2ab089f88f3bc5923e5050c8262c112ff9ce0a3cd51c6e3e84f02000000066551ac5352650d5e687ddf4cc9a497087cabecf74d236aa4fc3081c3f67b6d323cba795e10e7a171b725000000000852635351ab635100ffffffff02df5409020000000008ac6a53acab5151004156990200000000045163655200000000", "ac53abac65005300", 0, -173065000, "b596f206d7eba22b7e2d1b7a4f4cf69c7c541b6c84dcc943f84e19a99a923310"}, + {"18020dd1017f149eec65b2ec23300d8df0a7dd64fc8558b36907723c03cd1ba672bbb0f51d0300000005ab65ab6a63ffffffff037cd7ae000000000009ab516a65005352ac65f1e4360400000000056353530053f118f0040000000009536363ab006500abac00000000", "63ab51acab52ac", 0, -550412404, "e19b796c14a0373674968e342f2741d8b51092a5f8409e9bff7dcd52e56fcbcb"}, + {"b04154610363fdade55ceb6942d5e5a723323863b48a0cb04fdcf56210717955763f56b08d0300000009ac526a525151635151ffffffff93a176e76151a9eabdd7af00ef2af72f9e7af5ecb0aa4d45d00618f394cdd03c030000000074d818b332ebe05dc24c44d776cf9d275c61f471cc01efce12fd5a16464157f1842c65cb00000000066a0000ac6352d3c4134f01d8a1c0030000000005520000005200000000", "5200656a656351", 2, -9757957, "6e3e5ba77f760b6b5b5557b13043f1262418f3dd2ce7f0298b012811fc8ad5bc"}, + {"9794b3ce033df7b1e32db62d2f0906b589eacdacf5743963dc2255b6b9a6cba211fadd0d41020000000600ab00650065ffffffffaae00687a6a4131152bbcaafedfaed461c86754b0bde39e2bef720e6d1860a0302000000070065516aac6552ffffffff50e4ef784d6230df7486e972e8918d919f005025bc2d9aacba130f58bed7056703000000075265ab52656a52ffffffff02c6f1a9000000000006005251006363cf450c040000000008abab63510053abac00000000", "ac0063ababab515353", 1, 2063905082, "fad092fc98f17c2c20e10ba9a8eb44cc2bcc964b006f4da45cb9ceb249c69698"}, + {"94533db7015e70e8df715066efa69dbb9c3a42ff733367c18c22ff070392f988f3b93920820000000006535363636300ce4dac3e03169af80300000000080065ac6a53ac65ac39c050020000000006abacab6aacac708a02050000000005ac5251520000000000", "6553", 0, -360458507, "5418cf059b5f15774836edd93571e0eed3855ba67b2b08c99dccab69dc87d3e9"}, + {"c8597ada04f59836f06c224a2640b79f3a8a7b41ef3efa2602592ddda38e7597da6c639fee0300000009005251635351acabacffffffff4c518f347ee694884b9d4072c9e916b1a1f0a7fc74a1c90c63fdf8e5a185b6ae02000000007113af55afb41af7518ea6146786c7c726641c68c8829a52925e8d4afd07d8945f68e7230300000008ab00ab65ab650063ffffffffc28e46d7598312c420e11dfaae12add68b4d85adb182ae5b28f8340185394b63000000000165ffffffff04dbabb7010000000000ee2f6000000000000852ab6500ab6a51acb62a27000000000009ac53515300ac006a6345fb7505000000000752516a0051636a00000000", "", 3, 15199787, "0d66003aff5bf78cf492ecbc8fd40c92891acd58d0a271be9062e035897f317e"}, + {"1a28c4f702c8efaad96d879b38ec65c5283b5c084b819ad7db1c086e85e32446c7818dc7a90300000008656351536a525165fa78cef86c982f1aac9c5eb8b707aee8366f74574c8f42ef240599c955ef4401cf578be30200000002ab518893292204c430eb0100000000016503138a0300000000040053abac60e0eb010000000005525200ab63567c2d030000000004abab52006cf81e85", "ab51525152", 1, 2118315905, "4e4c9a781f626b59b1d3ad8f2c488eb6dee8bb19b9bc138bf0dc33e7799210d4"}, + {"c6c7a87003f772bcae9f3a0ac5e499000b68703e1804b9ddc3e73099663564d53ddc4e1c6e01000000076a536a6aac63636e3102122f4c30056ef8711a6bf11f641ddfa6984c25ac38c3b3e286e74e839198a80a34010000000165867195cd425821dfa2f279cb1390029834c06f018b1e6af73823c867bf3a0524d1d6923b0300000005acab53ab65ffffffff02fa4c49010000000008ab656a0052650053e001100400000000008836d972", "ac526351acab", 1, 978122815, "a869c18a0edf563d6e5eddd5d5ae8686f41d07f394f95c9feb8b7e52761531ca"}, + {"0ea580ac04c9495ab6af3b8d59108bb4194fcb9af90b3511c83f7bb046d87aedbf8423218e02000000085152acac006363ab9063d7dc25704e0caa5edde1c6f2dd137ded379ff597e055b2977b9c559b07a7134fcef2000000000200aca89e50181f86e9854ae3b453f239e2847cf67300fff802707c8e3867ae421df69274449402000000056365abababffffffff47a4760c881a4d7e51c69b69977707bd2fb3bcdc300f0efc61f5840e1ac72cee0000000000ffffffff0460179a020000000004ab53ab52a5250c0500000000096565acac6365ab52ab6c281e02000000000952635100ac006563654e55070400000000046552526500000000", "ab526563acac53ab", 2, 1426964167, "b1c50d58b753e8f6c7513752158e9802cf0a729ebe432b99acc0fe5d9b4e9980"}, + {"c33028b301d5093e1e8397270d75a0b009b2a6509a01861061ab022ca122a6ba935b8513320200000000ffffffff013bcf5a0500000000015200000000", "", 0, -513413204, "6b1459536f51482f5dbf42d7e561896557461e1e3b6bf67871e2b51faae2832c"}, + {"43b2727901a7dd06dd2abf690a1ccedc0b0739cb551200796669d9a25f24f71d8d101379f50300000000ffffffff0418e031040000000000863d770000000000085352ac526563ac5174929e040000000004ac65ac00ec31ac0100000000066a51ababab5300000000", "65", 0, -492874289, "154ff7a9f0875edcfb9f8657a0b98dd9600fabee3c43eb88af37cf99286d516c"}, + {"4763ed4401c3e6ab204bed280528e84d5288f9cac5fb8a2e7bd699c7b98d4df4ac0c40e55303000000066a6aacab5165ffffffff015b57f80400000000046a63535100000000", "ac51abab53", 0, -592611747, "849033a2321b5755e56ef4527ae6f51e30e3bca50149d5707368479723d744f8"}, + {"d24f647b02f71708a880e6819a1dc929c1a50b16447e158f8ff62f9ccd644e0ca3c592593702000000050053536a00ffffffff67868cd5414b6ca792030b18d649de5450a456407242b296d936bcf3db79e07b02000000005af6319c016022f50100000000036a516300000000", "6aab526353516a6a", 0, 1350782301, "8556fe52d1d0782361dc28baaf8774b13f3ce5ed486ae0f124b665111e08e3e3"}, + {"fe6ddf3a02657e42a7496ef170b4a8caf245b925b91c7840fd28e4a22c03cb459cb498b8d603000000065263656a650071ce6bf8d905106f9f1faf6488164f3decac65bf3c5afe1dcee20e6bc3cb6d052561985a030000000163295b117601343dbb0000000000026563dba521df", "", 1, -1696179931, "d9684685c99ce48f398fb467a91a1a59629a850c429046fb3071f1fa9a5fe816"}, + {"c61523ef0129bb3952533cbf22ed797fa2088f307837dd0be1849f20decf709cf98c6f032f03000000026563c0f1d378044338310400000000066363516a5165a14fcb0400000000095163536a6a00ab53657271d60200000000001d953f0500000000010000000000", "53516353005153", 0, 1141615707, "7e975a72db5adaa3c48d525d9c28ac11cf116d0f8b16ce08f735ad75a80aec66"}, + {"ba3dac6c0182562b0a26d475fe1e36315f0913b6869bdad0ecf21f1339a5fcbccd32056c840200000000ffffffff04300351050000000000220ed405000000000851abac636565ac53dbbd19020000000007636363ac6a52acbb005a0500000000016abd0c78a8", "63006a635151005352", 0, 1359658828, "47bc8ab070273e1f4a0789c37b45569a6e16f3f3092d1ce94dddc3c34a28f9f4"}, + {"ac27e7f5025fc877d1d99f7fc18dd4cadbafa50e34e1676748cc89c202f93abf36ed46362101000000036300abffffffff958cd5381962b765e14d87fc9524d751e4752dd66471f973ed38b9d562e525620100000003006500ffffffff02b67120050000000004ac51516adc330c0300000000015200000000", "656352", 1, 15049991, "f3374253d64ac264055bdbcc32e27426416bd595b7c7915936c70f839e504010"}, + {"edb30140029182b80c8c3255b888f7c7f061c4174d1db45879dca98c9aab8c8fed647a6ffc03000000086a53510052ab6300ffffffff82f65f261db62d517362c886c429c8fbbea250bcaad93356be6f86ba573e9d930100000000ffffffff04daaf150400000000016a86d1300100000000096a6353535252ac5165d4ddaf000000000002abab5f1c6201000000000000000000", "ab6a6a00ac", 0, -2058017816, "8d7794703dad18e2e40d83f3e65269834bb293e2d2b8525932d6921884b8f368"}, + {"7e50207303146d1f7ad62843ae8017737a698498d4b9118c7a89bb02e8370307fa4fada41d000000000753006300005152b7afefc85674b1104ba33ef2bf37c6ed26316badbc0b4aa6cb8b00722da4f82ff3555a6c020000000900ac656363ac51ac52ffffffff93fab89973bd322c5d7ad7e2b929315453e5f7ada3072a36d8e33ca8bebee6e0020000000300acab930da52b04384b04000000000004650052ac435e380200000000076a6a515263ab6aa9494705000000000600ab6a525252af8ba90100000000096565acab526353536a279b17ad", "acac005263536aac63", 1, -34754133, "4e6357da0057fb7ff79da2cc0f20c5df27ff8b2f8af4c1709e6530459f7972b0"}, + {"c05764f40244fb4ebe4c54f2c5298c7c798aa90e62c29709acca0b4c2c6ec08430b26167440100000008acab6a6565005253ffffffffc02c2418f398318e7f34a3cf669d034eef2111ea95b9f0978b01493293293a870100000000e563e2e00238ee8d040000000002acab03fb060200000000076500ac656a516aa37f5534", "52ab6a0065", 1, -2033176648, "83deef4a698b62a79d4877dd9afebc3011a5275dbe06e89567e9ef84e8a4ee19"}, + {"5a59e0b9040654a3596d6dab8146462363cd6549898c26e2476b1f6ae42915f73fd9aedfda00000000036363abffffffff9ac9e9ca90be0187be2214251ff08ba118e6bf5e2fd1ba55229d24e50a510d53010000000165ffffffff41d42d799ac4104644969937522873c0834cc2fcdab7cdbecd84d213c0e96fd60000000000ffffffffd838db2c1a4f30e2eaa7876ef778470f8729fcf258ad228b388df2488709f8410300000000fdf2ace002ceb6d903000000000265654c1310040000000003ac00657e91c0ec", "536a63ac", 0, 82144555, "98ccde2dc14d14f5d8b1eeea5364bd18fc84560fec2fcea8de4d88b49c00695e"}, + {"156ebc8202065d0b114984ee98c097600c75c859bfee13af75dc93f57c313a877efb09f230010000000463536a51ffffffff81114e8a697be3ead948b43b5005770dd87ffb1d5ccd4089fa6c8b33d3029e9c03000000066a5251656351ffffffff01a87f140000000000050000ac51ac00000000", "00", 0, -362221092, "a903c84d8c5e71134d1ab6dc1e21ac307c4c1a32c90c90f556f257b8a0ec1bf5"}, + {"15e37793023c7cbf46e073428908fce0331e49550f2a42b92468827852693f0532a01c29f70200000007005353636351acffffffff38426d9cec036f00eb56ec1dcd193647e56a7577278417b8a86a78ac53199bc403000000056353006a53ffffffff04a25ce103000000000900ab5365656a526a63c8eff7030000000004526353537ab6db0200000000016a11a3fa02000000000651acacab526500000000", "53ac6aab6a6551", 0, 1117532791, "83c68b3c5a89260ce16ce8b4dbf02e1f573c532d9a72f5ea57ab419fa2630214"}, + {"f7a09f10027250fc1b70398fb5c6bffd2be9718d3da727e841a73596fdd63810c9e4520a6a010000000963ac516a636a65acac1d2e2c57ab28d311edc4f858c1663972eebc3bbc93ed774801227fda65020a7ec1965f780200000005ac5252516a8299fddc01dcbf7200000000000463ac6551960fda03", "65acab51", 1, 2017321737, "9c5fa02abfd34d0f9dec32bf3edb1089fca70016debdb41f4f54affcb13a2a2a"}, + {"6d97a9a5029220e04f4ccc342d8394c751282c328bf1c132167fc05551d4ca4da4795f6d4e02000000076a0052ab525165ffffffff9516a205e555fa2a16b73e6db6c223a9e759a7e09c9a149a8f376c0a7233fa1b0100000007acab51ab63ac6affffffff04868aed04000000000652ac65ac536a396edf01000000000044386c0000000000076aab5363655200894d48010000000001ab8ebefc23", "6351526aac51", 1, 1943666485, "f0bd4ca8e97203b9b4e86bc24bdc8a1a726db5e99b91000a14519dc83fc55c29"}, + {"8e3fddfb028d9e566dfdda251cd874cd3ce72e9dde837f95343e90bd2a93fe21c5daeb5eed01000000045151525140517dc818181f1e7564b8b1013fd68a2f9a56bd89469686367a0e72c06be435cf99db750000000003635251ffffffff01c051780300000000096552ababac6a65acab099766eb", "5163ab6a52ababab51", 1, 1296295812, "5509eba029cc11d7dd2808b8c9eb47a19022b8d8b7778893459bbc19ab7ea820"}, + {"a603f37b02a35e5f25aae73d0adc0b4b479e68a734cf722723fd4e0267a26644c36faefdab0200000000ffffffff43374ad26838bf733f8302585b0f9c22e5b8179888030de9bdda180160d770650200000001004c7309ce01379099040000000005526552536500000000", "abababab005153", 0, 1409936559, "4ca73da4fcd5f1b10da07998706ffe16408aa5dff7cec40b52081a6514e3827e"}, + {"9eeedaa8034471a3a0e3165620d1743237986f060c4434f095c226114dcb4b4ec78274729f03000000086a5365510052ac6afb505af3736e347e3f299a58b1b968fce0d78f7457f4eab69240cbc40872fd61b5bf8b120200000002ac52df8247cf979b95a4c97ecb8edf26b3833f967020cd2fb25146a70e60f82c9ee4b14e88b103000000008459e2fa0125cbcd05000000000000000000", "52ab5352006353516a", 0, -1832576682, "fb018ae54206fdd20c83ae5873ec82b8e320a27ed0d0662db09cda8a071f9852"}, + {"05921d7c048cf26f76c1219d0237c226454c2a713c18bf152acc83c8b0647a94b13477c07f0300000003ac526afffffffff2f494453afa0cabffd1ba0a626c56f90681087a5c1bd81d6adeb89184b27b7402000000036a6352ffffffff0ad10e2d3ce355481d1b215030820da411d3f571c3f15e8daf22fe15342fed04000000000095f29f7b93ff814a9836f54dc6852ec414e9c4e16a506636715f569151559100ccfec1d100000000055263656a53ffffffff04f4ffef010000000008ac6a6aabacabab6a0e6689040000000006ab536a5352abe364d005000000000965536363655251ab53807e00010000000004526aab63f18003e3", "6363ac51", 3, -375891099, "001b0b176f0451dfe2d9787b42097ceb62c70d324e925ead4c58b09eebdf7f67"}, + {"b9b44d9f04b9f15e787d7704e6797d51bc46382190c36d8845ec68dfd63ee64cf7a467b21e00000000096aac00530052ab636aba1bcb110a80c5cbe073f12c739e3b20836aa217a4507648d133a8eedd3f02cb55c132b203000000076a000063526352b1c288e3a9ff1f2da603f230b32ef7c0d402bdcf652545e2322ac01d725d75f5024048ad0100000000ffffffffffd882d963be559569c94febc0ef241801d09dc69527c9490210f098ed8203c700000000056a006300ab9109298d01719d9a0300000000066a52ab006365d7894c5b", "ac6351650063636a", 3, -622355349, "ac87b1b93a6baab6b2c6624f10e8ebf6849b0378ef9660a3329073e8f5553c8d"}, + {"ff60473b02574f46d3e49814c484081d1adb9b15367ba8487291fc6714fd6e3383d5b335f001000000026a6ae0b82da3dc77e5030db23d77b58c3c20fa0b70aa7d341a0f95f3f72912165d751afd57230300000008ac536563516a6363ffffffff04f86c0200000000000553acab636ab13111000000000003510065f0d3f305000000000951ab516a65516aabab730a3a010000000002515200000000", "ac6a", 1, 1895032314, "0767e09bba8cd66d55915677a1c781acd5054f530d5cf6de2d34320d6c467d80"}, + {"f218026204f4f4fc3d3bd0eada07c57b88570d544a0436ae9f8b753792c0c239810bb30fbc0200000002536affffffff8a468928d6ec4cc10aa0f73047697970e99fa64ae8a3b4dca7551deb0b639149010000000851ab520052650051ffffffffa98dc5df357289c9f6873d0f5afcb5b030d629e8f23aa082cf06ec9a95f3b0cf0000000000ffffffffea2c2850c5107705fd380d6f29b03f533482fd036db88739122aac9eff04e0aa010000000365536a03bd37db034ac4c4020000000007515152655200ac33b27705000000000151efb71e0000000000007b65425b", "515151", 3, -1772252043, "de35c84a58f2458c33f564b9e58bc57c3e028d629f961ad1b3c10ee020166e5a"}, + {"48e7d42103b260b27577b70530d1ac2fed2551e9dd607cbcf66dca34bb8c03862cf8f5fd5401000000075151526aacab00ffffffff1e3d3b841552f7c6a83ee379d9d66636836673ce0b0eda95af8f2d2523c91813030000000665acac006365ffffffff388b3c386cd8c9ef67c83f3eaddc79f1ff910342602c9152ffe8003bce51b28b0100000008636363006a636a52ffffffff04b8f67703000000000852005353ac6552520cef720200000000085151ab6352ab00ab5096d6030000000005516a005100662582020000000001ac6c137280", "6a65", 1, 1513618429, "e2fa3e1976aed82c0987ab30d4542da2cb1cffc2f73be13480132da8c8558d5c"}, + {"91ebc4cf01bc1e068d958d72ee6e954b196f1d85b3faf75a521b88a78021c543a06e056279000000000265ab7c12df0503832121030000000000cc41a6010000000005ab5263516540a951050000000006ab63ab65acac00000000", "526a0065636a6a6aac", 0, -614046478, "7de4ba875b2e584a7b658818c112e51ee5e86226f5a80e5f6b15528c86400573"}, + {"3cd4474201be7a6c25403bf00ca62e2aa8f8f4f700154e1bb4d18c66f7bb7f9b975649f0dc0100000006535151535153ffffffff01febbeb000000000006005151006aac00000000", "", 0, -1674687131, "6b77ca70cc452cc89acb83b69857cda98efbfc221688fe816ef4cb4faf152f86"}, + {"92fc95f00307a6b3e2572e228011b9c9ed41e58ddbaefe3b139343dbfb3b34182e9fcdc3f50200000002acab847bf1935fde8bcfe41c7dd99683289292770e7f163ad09deff0e0665ed473cd2b56b0f40300000006516551ab6351294dab312dd87b9327ce2e95eb44b712cfae0e50fda15b07816c8282e8365b643390eaab01000000026aacffffffff016e0b6b040000000001ac00000000", "650065acac005300", 2, -1885164012, "bd7d26bb3a98fc8c90c972500618bf894cb1b4fe37bf5481ff60eef439d3b970"}, + {"4db591ab018adcef5f4f3f2060e41f7829ce3a07ea41d681e8cb70a0e37685561e4767ac3b0000000005000052acabd280e63601ae6ef20000000000036a636326c908f7", "ac6a51526300630052", 0, 862877446, "355ccaf30697c9c5b966e619a554d3323d7494c3ea280a9b0dfb73f953f5c1cb"}, + {"503fd5ef029e1beb7b242d10032ac2768f9a1aca0b0faffe51cec24770664ec707ef7ede4f01000000045253ac53375e350cc77741b8e96eb1ce2d3ca91858c052e5f5830a0193200ae2a45b413dda31541f0000000003516553ffffffff0175a5ba0500000000015200000000", "6aab65510053ab65", 1, 1603081205, "353ca9619ccb0210ae18b24d0e57efa7abf8e58fa6f7102738e51e8e72c9f0c4"}, + {"c80abebd042cfec3f5c1958ee6970d2b4586e0abec8305e1d99eb9ee69ecc6c2cbd76374380000000007ac53006300ac510acee933b44817db79320df8094af039fd82111c7726da3b33269d3820123694d849ee5001000000056a65ab526562699bea8530dc916f5d61f0babea709dac578774e8a4dcd9c640ec3aceb6cb2443f24f302000000020063ea780e9e57d1e4245c1e5df19b4582f1bf704049c5654f426d783069bcc039f2d8fa659f030000000851ab53635200006a8d00de0b03654e8500000000000463ab635178ebbb0400000000055100636aab239f1d030000000006ab006300536500000000", "6565ac515100", 3, 1460851377, "b35bb1b72d02fab866ed6bbbea9726ab32d968d33a776686df3ac16aa445871e"}, + {"0337b2d5043eb6949a76d6632b8bb393efc7fe26130d7409ef248576708e2d7f9d0ced9d3102000000075352636a5163007034384dfa200f52160690fea6ce6c82a475c0ef1caf5c9e5a39f8f9ddc1c8297a5aa0eb02000000026a51ffffffff38e536298799631550f793357795d432fb2d4231f4effa183c4e2f61a816bcf0030000000463ac5300706f1cd3454344e521fde05b59b96e875c8295294da5d81d6cc7efcfe8128f150aa54d6503000000008f4a98c704c1561600000000000072cfa6000000000000e43def01000000000100cf31cc0500000000066365526a6500cbaa8e2e", "", 3, 2029506437, "7615b4a7b3be865633a31e346bc3db0bcc410502c8358a65b8127089d81b01f8"}, + {"59f6cffd034733f4616a20fe19ea6aaf6abddb30b408a3a6bd86cd343ab6fe90dc58300cc90200000000ffffffffc835430a04c3882066abe7deeb0fa1fdaef035d3233460c67d9eabdb05e95e5a02000000080065ac535353ab00ffffffff4b9a043e89ad1b4a129c8777b0e8d87a014a0ab6a3d03e131c27337bbdcb43b402000000066a5100abac6ad9e9bf62014bb118010000000001526cbe484f", "ab526352ab65", 0, 2103515652, "4f2ccf981598639bec57f885b4c3d8ea8db445ea6e61cfd45789c69374862e5e"}, + {"cbc79b10020b15d605680a24ee11d8098ad94ae5203cb6b0589e432832e20c27b72a926af20300000006ab65516a53acbb854f3146e55c508ece25fa3d99dbfde641a58ed88c051a8a51f3dacdffb1afb827814b02000000026352c43e6ef30302410a020000000000ff4bd90100000000065100ab63000008aa8e0400000000095265526565ac5365abc52c8a77", "53526aac0051", 0, 202662340, "984efe0d8d12e43827b9e4b27e97b3777ece930fd1f589d616c6f9b71dab710e"}, + {"7c07419202fa756d29288c57b5c2b83f3c847a807f4a9a651a3f6cd6c46034ae0aa3a7446b0200000004ab6a6365ffffffff9da83cf4219bb96c76f2d77d5df31c1411a421171d9b59ec02e5c1218f29935403000000008c13879002f8b1ac0400000000086a63536a636553653c584f02000000000000000000", "abac53ab656363", 1, -1038419525, "4a74f365a161bc6c9bddd249cbd70f5dadbe3de70ef4bd745dcb6ee1cd299fbd"}, + {"351cbb57021346e076d2a2889d491e9bfa28c54388c91b46ee8695874ad9aa576f1241874d0200000008ab6563525300516affffffffe13e61b8880b8cd52be4a59e00f9723a4722ea58013ec579f5b3693b9e115b1100000000096363abac5252635351ffffffff027fee02040000000008ab6a5200ab006a65b85f130200000000086a52630053ab52ab00000000", "ab6aab65", 1, 586415826, "08bbb746a596991ab7f53a76e19acad087f19cf3e1db54054aab403c43682d09"}, + {"a8252ea903f1e8ff953adb16c1d1455a5036222c6ea98207fc21818f0ece2e1fac310f9a0100000000095163ac635363ac0000be6619e9fffcde50a0413078821283ce3340b3993ad00b59950bae7a9f931a9b0a3a035f010000000463005300b8b0583fbd6049a1715e7adacf770162811989f2be20af33f5f60f26eba653dc26b024a00000000006525351636552ffffffff046d2acc030000000002636a9a2d430500000000080065005165ab53abecf63204000000000052b9ed050000000008acacac53ab65656500000000", "65ab53635253636a51", 2, 1442639059, "8ca11838775822f9a5beee57bdb352f4ee548f122de4a5ca61c21b01a1d50325"}, + {"2f1a425c0471a5239068c4f38f9df135b1d24bf52d730d4461144b97ea637504495aec360801000000055300515365c71801dd1f49f376dd134a9f523e0b4ae611a4bb122d8b26de66d95203f181d09037974300000000025152ffffffff9bdcea7bc72b6e5262e242c94851e3a5bf8f314b3e5de0e389fc9e5b3eadac030000000009525265655151005153ffffffffdbb53ce99b5a2320a4e6e2d13b01e88ed885a0957d222e508e9ec8e4f83496cb0200000007635200abac63ac04c96237020cc5490100000000080000516a51ac6553074a360200000000025152225520ca", "6551ab65ac65516a", 1, -489869549, "9bc5bb772c553831fb40abe466074e59a469154679c7dee042b8ea3001c20393"}, + {"ef3acfd4024defb48def411b8f8ba2dc408dc9ee97a4e8bde4d6cb8e10280f29c98a6e8e9103000000035100513d5389e3d67e075469dfd9f204a7d16175653a149bd7851619610d7ca6eece85a516b2df0300000005516aac6552ca678bdf02f477f003000000000057e45b0300000000055252525252af35c20a", "5165ac53ab", 1, -1900839569, "78eb6b24365ac1edc386aa4ffd15772f601059581c8776c34f92f8a7763c9ccf"}, + {"ff4468dc0108475fc8d4959a9562879ce4ab4867a419664bf6e065f17ae25043e6016c70480100000000ffffffff02133c6f0400000000000bd0a8020000000004006a520035afa4f6", "51ac65ab", 0, -537664660, "f6da59b9deac63e83728850ac791de61f5dfcaeed384ebcbb20e44afcd8c8910"}, + {"4e8594d803b1d0a26911a2bcdd46d7cbc987b7095a763885b1a97ca9cbb747d32c5ab9aa91030000000353ac53a0cc4b215e07f1d648b6eeb5cdbe9fa32b07400aa773b9696f582cebfd9930ade067b2b200000000060065abab6500fc99833216b8e27a02defd9be47fafae4e4a97f52a9d2a210d08148d2a4e5d02730bcd460100000004516351ac37ce3ae1033baa55040000000006006a636a63acc63c990400000000025265eb1919030000000005656a6a516a00000000", "", 1, -75217178, "04c5ee48514cd033b82a28e336c4d051074f477ef2675ce0ce4bafe565ee9049"}, + {"a88830a7023f13ed19ab14fd757358eb6af10d6520f9a54923a6d613ac4f2c11e249cda8aa030000000851630065abababacffffffff8f5fe0bc04a33504c4b47e3991d25118947a0261a9fa520356731eeabd561dd3020000000363ababffffffff038404bd010000000008ab5153516aab6a63d33a5601000000000263004642dc020000000009655152acac636352004be6f3af", "5253536565006aab6a", 0, 1174417836, "2e42ead953c9f4f81b72c27557e6dc7d48c37ff2f5c46c1dbe9778fb0d79f5b2"}, + {"44e1a2b4010762af23d2027864c784e34ef322b6e24c70308a28c8f2157d90d17b99cd94a401000000085163656565006300ffffffff0198233d020000000002000000000000", "52525153656365", 0, 1119696980, "d9096de94d70c6337da6202e6e588166f31bff5d51bb5adc9468594559d65695"}, + {"44ca65b901259245abd50a745037b17eb51d9ce1f41aa7056b4888285f48c6f26cb97b7a25020000000552636363abffffffff047820350400000000040053acab14f3e603000000000652635100ab630ce66c03000000000001bdc704000000000765650065ac51ac3e886381", "51", 0, -263340864, "ed5622ac642d11f90e68c0feea6a2fe36d880ecae6b8c0d89c4ea4b3d162bd90"}, + {"cfa147d2017fe84122122b4dda2f0d6318e59e60a7207a2d00737b5d89694d480a2c26324b0000000006006351526552ffffffff0456b5b804000000000800516aab525363ab166633000000000004655363ab254c0e02000000000952ab6a6a00ab525151097c1b020000000009656a52ac6300530065ad0d6e50", "6a535165ac6a536500", 0, -574683184, "f926d4036eac7f019a2b0b65356c4ee2fe50e089dd7a70f1843a9f7bc6997b35"}, + {"91c5d5f6022fea6f230cc4ae446ce040d8313071c5ac1749c82982cc1988c94cb1738aa48503000000016a19e204f30cb45dd29e68ff4ae160da037e5fc93538e21a11b92d9dd51cf0b5efacba4dd70000000005656a6aac51ffffffff03db126905000000000953006a53ab6563636a36a273030000000006656a52656552b03ede00000000000352516500000000", "530052526a00", 1, 1437328441, "255c125b60ee85f4718b2972174c83588ee214958c3627f51f13b5fb56c8c317"}, + {"03f20dc202c886907b607e278731ebc5d7373c348c8c66cac167560f19b341b782dfb634cb03000000076a51ac6aab63abea3e8de7adb9f599c9caba95aa3fa852e947fc88ed97ee50e0a0ec0d14d164f44c0115c10100000004ab5153516fdd679e0414edbd000000000005ac636a53512021f2040000000007006a0051536a52c73db2050000000005525265ac5369046e000000000003ab006a1ef7bd1e", "52656a", 0, 1360223035, "5a0a05e32ce4cd0558aabd5d79cd5fcbffa95c07137506e875a9afcba4bef5a2"}, + {"d9611140036881b61e01627078512bc3378386e1d4761f959d480fdb9d9710bebddba2079d020000000763536aab5153ab819271b41e228f5b04daa1d4e72c8e1955230accd790640b81783cfc165116a9f535a74c000000000163ffffffffa2e7bb9a28e810624c251ff5ba6b0f07a356ac082048cf9f39ec036bba3d431a02000000076a000000ac65acffffffff01678a820000000000085363515153ac635100000000", "535353", 2, -82213851, "52b9e0778206af68998cbc4ebdaad5a9469e04d0a0a6cef251abfdbb74e2f031"}, + {"98b3a0bf034233afdcf0df9d46ac65be84ef839e58ee9fa59f32daaa7d684b6bdac30081c60200000007636351acabababffffffffc71cf82ded4d1593e5825618dc1d5752ae30560ecfaa07f192731d68ea768d0f0100000006650052636563f3a2888deb5ddd161430177ce298242c1a86844619bc60ca2590d98243b5385bc52a5b8f00000000095365acacab520052ac50d4722801c3b8a60300000000035165517e563b65", "51", 1, -168940690, "b6b684e2d2ecec8a8dce4ed3fc1147f8b2e45732444222aa8f52d860c2a27a9d"}, + {"97be4f7702dc20b087a1fdd533c7de762a3f2867a8f439bddf0dcec9a374dfd0276f9c55cc0300000000cdfb1dbe6582499569127bda6ca4aaff02c132dc73e15dcd91d73da77e92a32a13d1a0ba0200000002ab51ffffffff048cfbe202000000000900516351515363ac535128ce0100000000076aac5365ab6aabc84e8302000000000863536a53ab6a6552f051230500000000066aac535153510848d813", "ac51", 0, 229541474, "e5da9a416ea883be1f8b8b2d178463633f19de3fa82ae25d44ffb531e35bdbc8"}, + {"085b6e04040b5bff81e29b646f0ed4a45e05890a8d32780c49d09643e69cdccb5bd81357670100000001abffffffffa5c981fe758307648e783217e3b4349e31a557602225e237f62b636ec26df1a80300000004650052ab4792e1da2930cc90822a8d2a0a91ea343317bce5356b6aa8aae6c3956076aa33a5351a9c0300000004abac5265e27ddbcd472a2f13325cc6be40049d53f3e266ac082172f17f6df817db1936d9ff48c02b000000000152ffffffff021aa7670500000000085353635163ab51ac14d584000000000001aca4d136cc", "6a525300536352536a", 0, -1398925877, "41ecca1e8152ec55074f4c39f8f2a7204dda48e9ec1e7f99d5e7e4044d159d43"}, + {"eec32fff03c6a18b12cd7b60b7bdc2dd74a08977e53fdd756000af221228fe736bd9c42d870100000007005353ac515265ffffffff037929791a188e9980e8b9cc154ad1b0d05fb322932501698195ab5b219488fc02000000070063510065ab6a0bfc176aa7e84f771ea3d45a6b9c24887ceea715a0ff10ede63db8f089e97d927075b4f1000000000551abab63abffffffff02eb933c000000000000262c420000000000036563632549c2b6", "6352", 2, 1480445874, "ff8a4016dfdd918f53a45d3a1f62b12c407cd147d68ca5c92b7520e12c353ff5"}, + {"98ea7eac0313d9fb03573fb2b8e718180c70ce647bebcf49b97a8403837a2556cb8c9377f30000000004ac53ac65ffffffff8caac77a5e52f0d8213ef6ce998bedbb50cfdf108954771031c0e0cd2a78423900000000010066e99a44937ebb37015be3693761078ad5c73aa73ec623ac7300b45375cc8eef36087eb80000000007515352acac5100ffffffff0114a51b02000000000000000000", "6aacab", 0, 243527074, "bad77967f98941af4dd52a8517d5ad1e32307c0d511e15461e86465e1b8b5273"}, + {"3ab70f4604e8fc7f9de395ec3e4c3de0d560212e84a63f8d75333b604237aa52a10da17196000000000763526a6553ac63a25de6fd66563d71471716fe59087be0dde98e969e2b359282cf11f82f14b00f1c0ac70f02000000050052516aacdffed6bb6889a13e46956f4b8af20752f10185838fd4654e3191bf49579c961f5597c36c0100000005ac636363abc3a1785bae5b8a1b4be5d0cbfadc240b4f7acaa7dfed6a66e852835df5eb9ac3c553766801000000036a65630733b7530218569602000000000952006a6a6a51acab52777f06030000000007ac0063530052abc08267c9", "000000536aac0000", 1, 1919096509, "df1c87cf3ba70e754d19618a39fdbd2970def0c1bfc4576260cba5f025b87532"}, + {"bdb6b4d704af0b7234ced671c04ba57421aba7ead0a117d925d7ebd6ca078ec6e7b93eea6600000000026565ffffffff3270f5ad8f46495d69b9d71d4ab0238cbf86cc4908927fbb70a71fa3043108e6010000000700516a65655152ffffffff6085a0fdc03ae8567d0562c584e8bfe13a1bd1094c518690ebcb2b7c6ce5f04502000000095251530052536a53aba576a37f2c516aad9911f687fe83d0ae7983686b6269b4dd54701cb5ce9ec91f0e6828390300000000ffffffff04cc76cc020000000002656a01ffb702000000000253ab534610040000000009acab006565516a00521f55f5040000000000389dfee9", "6a525165", 0, 1336204763, "71c294523c48fd7747eebefbf3ca06e25db7b36bff6d95b41c522fecb264a919"}, + {"54258edd017d22b274fbf0317555aaf11318affef5a5f0ae45a43d9ca4aa652c6e85f8a040010000000953ac65ab5251656500ffffffff03321d450000000000085265526a51526a529ede8b030000000003635151ce6065020000000001534c56ec1b", "acac", 0, 2094130012, "110d90fea9470dfe6c5048f45c3af5e8cc0cb77dd58fd13d338268e1c24b1ccc"}, + {"ce0d322e04f0ffc7774218b251530a7b64ebefca55c90db3d0624c0ff4b3f03f918e8cf6f60300000003656500ffffffff9cce943872da8d8af29022d0b6321af5fefc004a281d07b598b95f6dcc07b1830200000007abab515351acab8d926410e69d76b7e584aad1470a97b14b9c879c8b43f9a9238e52a2c2fefc2001c56af8010000000400ab5253cd2cd1fe192ce3a93b5478af82fa250c27064df82ba416dfb0debf4f0eb307a746b6928901000000096500abacac6a0063514214524502947efc0200000000035251652c40340100000000096a6aab52000052656a5231c54c", "51", 2, -2090320538, "0322ca570446869ec7ec6ad66d9838cff95405002d474c0d3c17708c7ee039c6"}, + {"47ac54940313430712ebb32004679d3a512242c2b33d549bf5bbc8420ec1fd0850ed50eb6d0300000009536aac6a65acacab51ffffffffb843e44266ce2462f92e6bff54316661048c8c17ecb092cb493b39bfca9117850000000001519ab348c05e74ebc3f67423724a3371dd99e3bceb4f098f8860148f48ad70000313c4c223000000000653006565656512c2d8dc033f3c97010000000002636aa993aa010000000006526365ab526ab7cf560300000000076a0065ac6a526500000000", "005352535300ab6a", 2, 59531991, "8b5b3d00d9c658f062fe6c5298e54b1fe4ed3a3eab2a87af4f3119edc47b1691"}, + {"233cd90b043916fc41eb870c64543f0111fb31f3c486dc72457689dea58f75c16ae59e9eb2000000000500536a6a6affffffff9ae30de76be7cd57fb81220fce78d74a13b2dbcad4d023f3cadb3c9a0e45a3ce000000000965ac6353ac5165515130834512dfb293f87cb1879d8d1b20ebad9d7d3d5c3e399a291ce86a3b4d30e4e32368a9020000000453005165ffffffff26d84ae93eb58c81158c9b3c3cbc24a84614d731094f38d0eea8686dec02824d0300000005636a65abacf02c784001a0bd5d03000000000900655351ab65ac516a416ef503", "", 1, -295106477, "b79f31c289e95d9dadec48ebf88e27c1d920661e50d090e422957f90ff94cb6e"}, + {"9200e26b03ff36bc4bf908143de5f97d4d02358db642bd5a8541e6ff709c420d1482d471b70000000008abab65536a636553ffffffff61ba6d15f5453b5079fb494af4c48de713a0c3e7f6454d7450074a2a80cb6d880300000007ac6a00ab5165515dfb7574fbce822892c2acb5d978188b1d65f969e4fe874b08db4c791d176113272a5cc10100000000ffffffff0420958d000000000009ac63516a0063516353dd885505000000000465ac00007b79e901000000000066d8bf010000000005525252006a00000000", "ac5152", 0, 2089531339, "89ec7fab7cfe7d8d7d96956613c49dc48bf295269cfb4ea44f7333d88c170e62"}, + {"45f335ba01ce2073a8b0273884eb5b48f56df474fc3dff310d9706a8ac7202cf5ac188272103000000025363ffffffff049d859502000000000365ab6a8e98b1030000000002ac51f3a80603000000000752535151ac00000306e30300000000020051b58b2b3a", "", 0, 1899564574, "78e01310a228f645c23a2ad0acbb8d91cedff4ecdf7ca997662c6031eb702b11"}, + {"d8f652a6043b4faeada05e14b81756cd6920cfcf332e97f4086961d49232ad6ffb6bc6c097000000000453526563ffffffff1ea4d60e5e91193fbbc1a476c8785a79a4c11ec5e5d6c9950c668ceacfe07a15020000000352ab51fffffffffe029a374595c4edd382875a8dd3f20b9820abb3e93f877b622598d11d0b09e503000000095351000052ac515152ffffffff9d65fea491b979699ceb13caf2479cd42a354bd674ded3925e760758e85a756803000000046365acabffffffff0169001d00000000000651636a65656300000000", "ab0063630000ac", 3, 1050965951, "4cc85cbc2863ee7dbce15490d8ca2c5ded61998257b9eeaff968fe38e9f009ae"}, + {"718662be026e1dcf672869ac658fd0c87d6835cfbb34bd854c44e577d5708a7faecda96e260300000004526a636a489493073353b678549adc7640281b9cbcb225037f84007c57e55b874366bb7b0fa03bdc00000000095165ababac65ac00008ab7f2a802eaa53d000000000007acac516aac526ae92f380100000000056aac00536500000000", "ab00", 1, 43296088, "2d642ceee910abff0af2116af75b2e117ffb7469b2f19ad8fef08f558416d8f7"}, + {"94083c840288d40a6983faca876d452f7c52a07de9268ad892e70a81e150d602a773c175ad03000000007ec3637d7e1103e2e7e0c61896cbbf8d7e205b2ecc93dd0d6d7527d39cdbf6d335789f660300000000ffffffff019e1f7b03000000000800ac0051acac0053539cb363", "", 1, -183614058, "a17b66d6bb427f42653d08207a22b02353dd19ccf2c7de6a9a3a2bdb7c49c9e7"}, + {"30e0d4d20493d0cd0e640b757c9c47a823120e012b3b64c9c1890f9a087ae4f2001ca22a61010000000152f8f05468303b8fcfaad1fb60534a08fe90daa79bff51675472528ebe1438b6f60e7f60c10100000009526aab6551ac510053ffffffffaaab73957ea2133e32329795221ed44548a0d3a54d1cf9c96827e7cffd1706df0200000009ab00526a005265526affffffffd19a6fe54352015bf170119742821696f64083b5f14fb5c7d1b5a721a3d7786801000000085265abababac53abffffffff020f39bd030000000004ab6aac52049f6c050000000004ab52516aba5b4c60", "6a6365516a6a655253", 0, -624256405, "8e221a6c4bf81ca0d8a0464562674dcd14a76a32a4b7baf99450dd9195d411e6"}, + {"f9c69d940276ec00f65f9fe08120fc89385d7350388508fd80f4a6ba2b5d4597a9e21c884f010000000663ab63ababab15473ae6d82c744c07fc876ecd53bd0f3018b2dbedad77d757d5bdf3811b23d294e8c0170000000001abafababe00157ede2050000000006ac6a5263635300000000", "ab53", 1, 606547088, "714d8b14699835b26b2f94c58b6ea4c53da3f7adf0c62ea9966b1e1758272c47"}, + {"5c0ac112032d6885b7a9071d3c5f493aa16c610a4a57228b2491258c38de8302014276e8be030000000300ab6a17468315215262ad5c7393bb5e0c5a6429fd1911f78f6f72dafbbbb78f3149a5073e24740300000003ac5100ffffffff33c7a14a062bdea1be3c9c8e973f54ade53fe4a69dcb5ab019df5f3345050be00100000008ac63655163526aab428defc0033ec36203000000000765516365536a00ae55b2000000000002ab53f4c0080400000000095265516a536563536a00000000", "6a005151006a", 2, 272749594, "91082410630337a5d89ff19145097090f25d4a20bdd657b4b953927b2f62c73b"}, + {"e3683329026720010b08d4bec0faa244f159ae10aa582252dd0f3f80046a4e145207d54d31000000000852acac52656aacac3aaf2a5017438ad6adfa3f9d05f53ebed9ceb1b10d809d507bcf75e0604254a8259fc29c020000000653526552ab51f926e52c04b44918030000000000f7679c0100000000090000525152005365539e3f48050000000009516500ab635363ab008396c905000000000253650591024f", "6a6365", 0, 908746924, "458aec3b5089a585b6bad9f99fd37a2b443dc5a2eefac2b7e8c5b06705efc9db"}, + {"48c4afb204204209e1df6805f0697edaa42c0450bbbd767941fe125b9bc40614d63d757e2203000000066a5363005152dc8b6a605a6d1088e631af3c94b8164e36e61445e2c60130292d81dabd30d15f54b355a802000000036a6353ffffffff1d05dcec4f3dedcfd02c042ce5d230587ee92cb22b52b1e59863f3717df2362f0300000005536552ac52ffffffffd4d71c4f0a7d53ba47bb0289ca79b1e33d4c569c1e951dd611fc9c9c1ca8bc6c030000000865536a65ab51abacffffffff042f9aa905000000000753655153656351ab93d8010000000002655337440e0300000000005d4c690000000000015278587acb", "ab006565526a51", 0, 1502064227, "bbed77ff0f808aa8abd946ba9e7ec1ddb003a969fa223dee0af779643cb841a9"}, + {"00b20fd104dd59705b84d67441019fa26c4c3dec5fd3b50eca1aa549e750ef9ddb774dcabe000000000651ac656aac65ffffffff52d4246f2db568fc9eea143e4d260c698a319f0d0670f84c9c83341204fde48b0200000000ffffffffb8aeabb85d3bcbc67b132f1fd815b451ea12dcf7fc169c1bc2e2cf433eb6777a03000000086a51ac6aab6563acd510d209f413da2cf036a31b0def1e4dcd8115abf2e511afbcccb5ddf41d9702f28c52900100000006ac52ab6a0065ffffffff039c8276000000000008ab53655200656a52401561010000000003acab0082b7160100000000035100ab00000000", "535265", 1, -947367579, "3212c6d6dd8d9d3b2ac959dec11f4638ccde9be6ed5d36955769294e23343da0"}, + {"455131860220abbaa72015519090a666faf137a0febce7edd49da1eada41feab1505a0028b02000000036365ab453ead4225724eb69beb590f2ec56a7693a608871e0ab0c34f5e96157f90e0a96148f3c502000000085251ab51535163acffffffff022d1249040000000009abac00acac6565630088b310040000000000e3920e59", "5152ab6a52ac5152", 0, 294375737, "c40fd7dfa72321ac79516502500478d09a35cc22cc264d652c7d18b14400b739"}, + {"624d28cb02c8747915e9af2b13c79b417eb34d2fa2a73547897770ace08c6dd9de528848d3030000000651ab63abab533c69d3f9b75b6ef8ed2df50c2210fd0bf4e889c42477d58682f711cbaece1a626194bb85030000000765acab53ac5353ffffffff018cc280040000000009abacabac52636352ac6859409e", "ac51ac", 1, 1005144875, "919144aada50db8675b7f9a6849c9d263b86450570293a03c245bd1e3095e292"}, + {"8f28471d02f7d41b2e70e9b4c804f2d90d23fb24d53426fa746bcdcfffea864925bdeabe3e0200000001acffffffff76d1d35d04db0e64d65810c808fe40168f8d1f2143902a1cc551034fd193be0e0000000001acffffffff048a5565000000000005005151516afafb610400000000045263ac53648bb30500000000086363516a6a5165513245de01000000000000000000", "6a0053510053", 1, -1525137460, "305fc8ff5dc04ebd9b6448b03c9a3d945a11567206c8d5214666b30ec6d0d6cc"}, + {"10ec50d7046b8b40e4222a3c6449490ebe41513aad2eca7848284a08f3069f3352c2a9954f0000000009526aac656352acac53ffffffff0d979f236155aa972472d43ee6f8ce22a2d052c740f10b59211454ff22cb7fd00200000007acacacab63ab53ffffffffbbf97ebde8969b35725b2e240092a986a2cbfd58de48c4475fe077bdd493a20c010000000663ab5365ababffffffff4600722d33b8dba300d3ad037bcfc6038b1db8abfe8008a15a1de2da2264007302000000035351ac6dbdafaf020d0ccf04000000000663ab6a51ab6ae06e5e0200000000036aabab00000000", "", 0, -1658960232, "2420dd722e229eccafae8508e7b8d75c6920bfdb3b5bac7cb8e23419480637c2"}, + {"fef98b7101bf99277b08a6eff17d08f3fcb862e20e13138a77d66fba55d54f26304143e5360100000006515365abab00ffffffff04265965030000000004655252ace2c775010000000001002b23b4040000000007516a5153ab53ac456a7a00000000000753ab525251acacba521291", "526aacacab00abab53", 0, -1614097109, "4370d05c07e231d6515c7e454a4e401000b99329d22ed7def323976fa1d2eeb5"}, + {"34a2b8830253661b373b519546552a2c3bff7414ea0060df183b1052683d78d8f54e842442000000000152ffffffffd961a8e34cf374151058dfcddc86509b33832bc57267c63489f69ff01199697c0300000002abacba856cfb01b17c2f050000000008515365ac53ab000000000000", "5263ab656a", 1, -2104480987, "2f9993e0a84a6ca560d6d1cc2b63ffe7fd71236d9cfe7d809491cef62bbfad84"}, + {"43559290038f32fda86580dd8a4bc4422db88dd22a626b8bd4f10f1c9dd325c8dc49bf479f01000000026351ffffffff401339530e1ed3ffe996578a17c3ec9d6fccb0723dd63e7b3f39e2c44b976b7b0300000006ab6a65656a51ffffffff6fb9ba041c96b886482009f56c09c22e7b0d33091f2ac5418d05708951816ce7000000000551ac525100ffffffff020921e40500000000035365533986f40500000000016a00000000", "52ac51", 0, 1769771809, "02040283ef2291d8e1f79bb71bdabe7c1546c40d7ed615c375643000a8b9600d"}, + {"6878a6bd02e7e1c8082d5e3ee1b746cfebfac9e8b97e61caa9e0759d8a8ecb3743e36a30de0100000002ab532a911b0f12b73e0071f5d50b6bdaf783f4b9a6ce90ec0cad9eecca27d5abae188241ddec0200000001651c7758d803f7457b0500000000036551515f4e90000000000001007022080200000000035365acc86b6946", "6351ab", 0, -1929374995, "f24be499c58295f3a07f5f1c6e5084496ae160450bd61fdb2934e615289448f1"}, + {"35b6fc06047ebad04783a5167ab5fc9878a00c4eb5e7d70ef297c33d5abd5137a2dea9912402000000036aacacffffffff21dc291763419a584bdb3ed4f6f8c60b218aaa5b99784e4ba8acfec04993e50c03000000046a00ac6affffffff69e04d77e4b662a82db71a68dd72ef0af48ca5bebdcb40f5edf0caf591bb41020200000000b5db78a16d93f5f24d7d932f93a29bb4b784febd0cbb1943f90216dc80bba15a0567684b000000000853ab52ab5100006a1be2208a02f6bdc103000000000265ab8550ea04000000000365636a00000000", "", 0, -1114114836, "1c8655969b241e717b841526f87e6bd68b2329905ba3fc9e9f72526c0b3ea20c"}, + {"bebb90c302bf91fd4501d33555a5fc5f2e1be281d9b7743680979b65c3c919108cc2f517510100000003abab00ffffffff969c30053f1276550532d0aa33cfe80ca63758cd215b740448a9c08a84826f3303000000056565ab5153ffffffff04bf6f2a04000000000565ab5265ab903e760100000000026a6a7103fa020000000006526553525365b05b2c000000000006ab000000535300000000", "51510053ab63635153", 1, 1081291172, "94338cd47a4639be30a71e21a7103cee4c99ef7297e0edd56aaf57a068b004de"}, + {"af48319f031b4eeb4319714a285f44244f283cbff30dcb9275b06f2348ccd0d7f015b54f8500000000066363ac65ac6affffffff2560a9817ebbc738ad01d0c9b9cf657b8f9179b1a7f073eb0b67517409d108180200000005ac6365ab52ffffffff0bdd67cd4ecae96249a2e2a96db1490ee645f042fd9d5579de945e22b799f4d003000000086552ab515153ab00cf187c8202e51abf0300000000066552006a00abadf37d000000000004ac6a535100000000", "63ab65", 1, -1855554446, "60caf46a7625f303c04706cec515a44b68ec319ee92273acb566cca4f66861c1"}, + {"f35befbc03faf8c25cc4bc0b92f6239f477e663b44b83065c9cb7cf231243032cf367ce3130000000005ab65526a517c4c334149a9c9edc39e29276a4b3ffbbab337de7908ea6f88af331228bd90086a6900ba020000000151279d19950d2fe81979b72ce3a33c6d82ebb92f9a2e164b6471ac857f3bbd3c0ea213b542010000000953ab51635363520065052657c20300a9ba04000000000452636a6a0516ea020000000008535253656365ababcfdd3f01000000000865ac516aac00530000000000", "", 2, -99793521, "c834a5485e68dc13edb6c79948784712122440d7fa5bbaa5cd2fc3d4dac8185d"}, + {"d3da18520216601acf885414538ce2fb4d910997eeb91582cac42eb6982c9381589587794f0300000000fffffffff1b1c9880356852e10cf41c02e928748dd8fae2e988be4e1c4cb32d0bfaea6f7000000000465ab6aabffffffff02fb0d69050000000002ababeda8580500000000085163526565ac52522b913c95", "ac", 1, -1247973017, "99b32b5679d91e0f9cdd6737afeb07459806e5acd7630c6a3b9ab5d550d0c003"}, + {"8218eb740229c695c252e3630fc6257c42624f974bc856b7af8208df643a6c520ef681bfd00000000002510066f30f270a09b2b420e274c14d07430008e7886ec621ba45665057120afce58befca96010300000004525153ab84c380a9015d96100000000000076a5300acac526500000000", "ac005263", 0, -1855679695, "5071f8acf96aea41c7518bd1b5b6bbe16258b529df0c03f9e374b83c66b742c6"}, + {"1123e7010240310013c74e5def60d8e14dd67aedff5a57d07a24abc84d933483431b8cf8ea0300000003530051fc6775ff1a23c627a2e605dd2560e84e27f4208300071e90f4589e762ad9c9fe8d0da95e020000000465655200ffffffff04251598030000000004ab65ab639d28d90400000000096563636aacac525153474df801000000000851525165ac51006a75e23b040000000000e5bd3a4a", "6363636565", 0, -467124448, "9cb0dd04e9fe287b112e94a1647590d27e8b164ca13c4fe70c610fd13f82c2fd"}, + {"fd92fe1003083c5179f97e77bf7d71975788138147adbdb283306802e261c0aee080fa22630200000000860c643ba9a1816b9badf36077b4554d11720e284e395a1121bc45279e148b2064c65e49020000000651ab6a53636a2c713088d20f4bc4001264d972cce05b9fe004dc33376ad24d0d013e417b91a5f1b6734e000000000100ffffffff02e3064c0500000000066552006a5165b86e8705000000000665ab65ab53522052eadb", "00ab53525265", 0, 776203277, "47207b48777727532f62e09afcd4104ea6687e723c7657c30504fa2081331cc8"}, + {"d1b6a703038f14d41fcc5cc45455faa135a5322be4bf0f5cbcd526578fc270a236cacb853f0200000001abffffffff135aeff902fa38f202ccf5bd34437ff89c9dc57a028b62447a0a38579383e8ef0000000000ffffffffadf398d2c818d0b90bc474f540c3618a4a643482eeab73d36101987e2ec0335900000000004bd3323504e69fc10000000000055151535251790ada02000000000563ab6aab521337a704000000000963ac63abacac52656a1e9862010000000007656500ac51ab6a8f4ee672", "ab5251656565ac63", 2, 82008394, "b8f3d255549909c07588ecba10a02e55a2d6f2206d831af9da1a7dae64cfbc8b"}, + {"81dadaa7011556683db3fe95262f4fdb20391b7e75b7ffcee51b176af64d83c06f85545d620200000005ab5151ab52ffffffff044805ef0300000000065353516352639702c802000000000900516351515252ab5270db08040000000009ac516aab526553abac4aabc90500000000096365ab0052636a525100000000", "6565ab6a5152", 0, -2126294159, "ad01ec9d6dbae325ec3a8e1fd98e2d03b1188378210efef093dd8b0b0ef3f19d"}, + {"3b937e05032b8895d2f4945cb7e3679be2fbd15311e2414f4184706dbfc0558cf7de7b4d000000000001638b91a12668a3c3ce349788c961c26aa893c862f1e630f18d80e7843686b6e1e6fc396310000000000852635353ab65ac51eeb09dd1c9605391258ee6f74b9ae17b5e8c2ef010dc721c5433dcdc6e93a1593e3b6d1700000000085365ac6553526351ffffffff0308b18e04000000000253acb6dd00040000000008536aac5153ac516ab0a88201000000000500ac006500804e3ff2", "", 0, 416167343, "595a3c02254564634e8085283ec4ea7c23808da97ce9c5da7aecd7b553e7fd7f"}, + {"a48f27ca047997470da74c8ee086ddad82f36d9c22e790bd6f8603ee6e27ad4d3174ea875403000000095153ac636aab6aacabffffffffefc936294e468d2c9a99e09909ba599978a8c0891ad47dc00ba424761627cef202000000056a51630053ffffffff304cae7ed2d3dbb4f2fbd679da442aed06221ffda9aee460a28ceec5a9399f4e0200000000f5bddf82c9c25fc29c5729274c1ff0b43934303e5f595ce86316fc66ad263b96ca46ab8d0100000003536500d7cf226b0146b00c04000000000200ac5c2014ce", "515100636563", 0, 1991799059, "9c051a7092fe17fa62b1720bc2c4cb2ffc1527d9fb0b006d2e142bb8fe07bf3c"}, + {"180cd53101c5074cf0b7f089d139e837fe49932791f73fa2342bd823c6df6a2f72fe6dba1303000000076a6a63ac53acabffffffff03853bc1020000000007ac526a6a6a6a003c4a8903000000000453515163a0fbbd030000000005ab656a5253253d64cf", "ac65", 0, -1548453970, "4d8efb3b99b9064d2f6be33b194a903ffabb9d0e7baa97a48fcec038072aac06"}, + {"c21ec8b60376c47e057f2c71caa90269888d0ffd5c46a471649144a920d0b409e56f190b700000000008acac6a526a536365ffffffff5d315d9da8bf643a9ba11299450b1f87272e6030fdb0c8adc04e6c1bfc87de9a0000000000ea43a9a142e5830c96b0ce827663af36b23b0277244658f8f606e95384574b91750b8e940000000007516a63ac0063acffffffff023c61be0400000000055165ab5263313cc8020000000006006a53526551ed8c3d56", "6a", 1, 1160627414, "a638cc17fd91f4b1e77877e8d82448c84b2a4e100df1373f779de7ad32695112"}, + {"128cd90f04b66a4cbc78bf48748f6eec0f08d5193ee8d0a6f2e8d3e5f138ed12c2c87d01a301000000085200ab6aac00ab00ffffffff09fc88bb1851e3dfb3d30179c38e15aeb1b39929c7c74f6acd071994ed4806490300000000e7fc5ea12ec56f56c0d758ecf4bb88aa95f3b08176b336db3b9bec2f6e27336dce28adbe030000000400530051fffffffffd6ff1adcf1fbe0d883451ee46904f1b7e8820243d395559b2d4ee8190a6e891000000000080fb1ae702f85b400000000000035200ab8d9651010000000006ab6a52536aab00000000", "ab", 1, 1667598199, "c10ccc9db8a92d7d4b133a2980782dab9d9d1d633d0dde9f9612ada57771fd89"}, + {"da9695a403493d3511c10e1fe1286f954db0366b7667c91ef18ae4578056c1bf752114ac5901000000035351519788d91dd1f9c62dc005d80ea54eb13f7131ca5aace3d5d29f9b58ccc5fbc9a27e779950010000000453ac6a00ffffffffe2556ff29ebe83eb42a32c7a8d93bc598043578f491b5935805a33608538845a030000000252ab65d21b3b018f26c4030000000006acab51535352e1cbcb10", "006565ab52", 2, -1550927794, "0ca673a1ee66f9625ceb9ab278ebef772c113c188112b02824570c17fdf48194"}, + {"b240517501334021240427adb0b413433641555424f6d24647211e3e6bfbb22a8045cbda2f000000000071bac8630112717802000000000000000000", "6a5165abac52656551", 0, 1790414254, "2c8be597620d95abd88f9c1cf4967c1ae3ca2309f3afec8928058c9598660e9e"}, + {"96bac43903044a199b4b3efeeec5d196ee23fb05495541fa2cd6fb6405a9432d1723363660010000000151ffffffffe6ce2b66ce1488918a3e880bebb0e750123f007c7bcbac8fcd67ce75cb6fbae80300000000ffffffff9c0955aa07f506455834895c0c56be5a095398f47c62a3d431fe125b161d666a0200000005520000abac7ffdbc540216f2f004000000000165a26dce010000000001ab00000000", "5151ab656a656a6a63", 0, -707123065, "26b22e18d5d9081fde9631594a4f7c49069ed2e429f3d08caf9d834f685ccab2"}, + {"b8fd394001ed255f49ad491fecc990b7f38688e9c837ccbc7714ddbbf5404f42524e68c18f0000000007ab6353535363ab081e15ee02706f7d050000000008515200535351526364c7ec040000000005636a53acac9206cbe1", "655352ac", 0, -1251578838, "8e0697d8cd8a9ccea837fd798cc6c5ed29f6fbd1892ee9bcb6c944772778af19"}, + {"e42a76740264677829e30ed610864160c7f97232c16528fe5610fc08814b21c34eefcea69d010000000653006a6a0052ffffffff647046cf44f217d040e6a8ff3f295312ab4dd5a0df231c66968ad1c6d8f4428000000000025352ffffffff0199a7f900000000000000000000", "655263006a005163", 1, 1122505713, "7cda43f1ff9191c646c56a4e29b1a8c6cb3f7b331da6883ef2f0480a515d0861"}, + {"0f034f32027a8e094119443aa9cfe11737c6d7dda9a52b839bc073dcc0235b847b28e0fab60200000006ac53ac536a63eee63447dfdad80476994b68706e916df1bd9d7cb4f3a4f6b14369de84564bea2e8688bd030000000565636a65acf8434663020b35fe01000000000800abab655163acabb3d6a103000000000353acab345eeda0", "526a51ac63ab51", 1, 66020215, "4435e62ff6531ac73529aac9cf878a7219e0b6e6cac79af8487c5355d1ad6d43"}, + {"a2dfa4690214c1ab25331815a5128f143219de51a47abdc7ce2d367e683eeb93960a31af9f010000000363636affffffff8be0628abb1861b078fcc19c236bc4cc726fa49068b88ad170adb2a97862e7460200000004ac655363ffffffff0441f11103000000000153dbab0c000000000009ab53ac5365526aab63abbb95050000000004ab52516a29a029040000000003ac526a00000000", "6a52ac63", 1, -1302210567, "913060c7454e6c80f5ba3835454b54db2188e37dc4ce72a16b37d11a430b3d23"}, + {"9dbc591f04521670af83fb3bb591c5d4da99206f5d38e020289f7db95414390dddbbeb56680100000004ac5100acffffffffb6a40b5e29d5e459f8e72d39f800089529f0889006cad3d734011991da8ef09d0100000009526a5100acab536a515fc427436df97cc51dc8497642ffc868857ee245314d28b356bd70adba671bd6071301fc0000000000ffffffff487efde2f620566a9b017b2e6e6d42525e4070f73a602f85c6dfd58304518db30000000005516353006a8d8090180244904a0200000000046a65656ab1e9c203000000000451ab63aba06a5449", "", 0, -1414953913, "bae189eb3d64aedbc28a6c28f6c0ccbd58472caaf0cf45a5aabae3e031dd1fea"}, + {"1345fb2c04bb21a35ae33a3f9f295bece34650308a9d8984a989dfe4c977790b0c21ff9a7f0000000006ac52ac6a0053ffffffff7baee9e8717d81d375a43b691e91579be53875350dfe23ba0058ea950029fcb7020000000753ab53ab63ab52ffffffff684b6b3828dfb4c8a92043b49b8cb15dd3a7c98b978da1d314dce5b9570dadd202000000086353ab6a5200ac63d1a8647bf667ceb2eae7ec75569ca249fbfd5d1b582acfbd7e1fcf5886121fca699c011d0100000003ac006affffffff049b1eb00300000000001e46dc0100000000080065ab6a6a630065ca95b40300000000030051520c8499010000000006ab6aac526a6500000000", "53526aac636300", 2, 1809978100, "cfeaa36790bc398783d4ca45e6354e1ea52ee74e005df7f9ebd10a680e9607bf"}, + {"7d75dc8f011e5f9f7313ba6aedef8dbe10d0a471aca88bbfc0c4a448ce424a2c5580cda1560300000003ab5152ffffffff01997f8e0200000000096552ac6a65656563530d93bbcc", "00656a6563", 0, 1414485913, "ec91eda1149f75bffb97612569a78855498c5d5386d473752a2c81454f297fa7"}, + {"1459179504b69f01c066e8ade5e124c748ae5652566b34ed673eea38568c483a5a4c4836ca0100000008ac5352006563656affffffff5d4e037880ab1975ce95ea378d2874dcd49d5e01e1cdbfae3343a01f383fa35800000000095251ac52ac6aac6500ffffffff7de3ae7d97373b7f2aeb4c55137b5e947b2d5fb325e892530cb589bc4f92abd503000000086563ac53ab520052ffffffffb4db36a32d6e543ef49f4bafde46053cb85b2a6c4f0e19fa0860d9083901a1190300000003ab51531bbcfe5504a6dbda040000000008536a5365abac6500d660c80300000000096565abab6a53536a6a54e84e010000000003acac52df2ccf0500000000025351220c857e", "", 2, 1879181631, "3aad18a209fab8db44954eb55fd3cc7689b5ec9c77373a4d5f4dae8f7ae58d14"}, + {"d98b777f04b1b3f4de16b07a05c31d79965579d0edda05600c118908d7cf642c9cd670093f020000000953005351ac65ab5363a268caad6733b7d1718008997f249e1375eb3ab9fe68ab0fe170d8e745ea24f54ce67f9b00000000066500516a5151ffffffff7ef8040dfcc86a0651f5907e8bfd1017c940f51cf8d57e3d3fe78d57e40b1e610200000003535263ffffffff39846cfed4babc098ff465256ba3820c30d710581316afcb67cd31c623b703360300000001acffffffff03d405120100000000056300006a5201a73d050000000004ab636a6a294c8c000000000006ac65536553ac00000000", "63525351abac", 1, 2018694761, "86970af23c89b72a4f9d6281e46b9ef5220816bed71ebf1ae20df53f38fe16ff"}, + {"cabb1b06045a895e6dcfc0c1e971e94130c46feace286759f69a16d298c8b0f6fd0afef8f20300000004ac006352ffffffffa299f5edac903072bfb7d29b663c1dd1345c2a33546a508ba5cf17aab911234602000000056a65515365ffffffff89a20dc2ee0524b361231092a070ace03343b162e7162479c96b757739c8394a0300000002abab92ec524daf73fabee63f95c1b79fa8b84e92d0e8bac57295e1d0adc55dc7af5534ebea410200000001534d70e79b04674f6f00000000000600abacab53517d60cc0200000000035265ab96c51d040000000004ac6300ac62a787050000000008006a516563ab63639e2e7ff7", "6551ac6351ac", 3, 1942663262, "d0c4a780e4e0bc22e2f231e23f01c9d536b09f6e5be51c123d218e906ec518be"}, + {"8b96d7a30132f6005b5bd33ea82aa325e2bcb441f46f63b5fca159ac7094499f380f6b7e2e00000000076aacabac6300acffffffff0158056700000000000465005100c319e6d0", "52006a", 0, -1100733473, "fb4bd26a91b5cf225dd3f170eb09bad0eac314bc1e74503cc2a3f376833f183e"}, + {"112191b7013cfbe18a175eaf09af7a43cbac2c396f3695bbe050e1e5f4250603056d60910e02000000001c8a5bba03738a22010000000005525352656a77a149010000000002510003b52302000000000351ac52722be8e6", "65ac6565", 0, -1847972737, "8e795aeef18f510d117dfa2b9f4a2bd2e2847a343205276cedd2ba14548fd63f"}, + {"ce6e1a9e04b4c746318424705ea69517e5e0343357d131ad55d071562d0b6ebfedafd6cb840100000003656553ffffffff67bd2fa78e2f52d9f8900c58b84c27ef9d7679f67a0a6f78645ce61b883fb8de000000000100d699a56b9861d99be2838e8504884af4d30b909b1911639dd0c5ad47c557a0773155d4d303000000046a5151abffffffff9fdb84b77c326921a8266854f7bbd5a71305b54385e747fe41af8a397e78b7fa010000000863acac6a51ab00ac0d2e9b9d049b8173010000000007ac53526a650063ba9b7e010000000008526a00525263acac0ab3fd030000000000ea8a0303000000000200aca61a97b9", "", 1, -1276952681, "b6ed4a3721be3c3c7305a5128c9d418efa58e419580cec0d83f133a93e3a22c5"}, + {"a7721d94021652d90c79aaf5022d98219337d50f836382403ed313adb1116ba507ac28b0b0010000000551ac6300ab89e6d64a7aa81fb9595368f04d1b36d7020e7adf5807535c80d015f994cce29554fe869b01000000065353ab636500ffffffff024944c90100000000046300635369df9f01000000000000000000", "656a536551ab", 0, -1740151687, "935892c6f02948f3b08bcd463b6acb769b02c1912be4450126768b055e8f183a"}, + {"2f7353dd02e395b0a4d16da0f7472db618857cd3de5b9e2789232952a9b154d249102245fd030000000151617fd88f103280b85b0a198198e438e7cab1a4c92ba58409709997cc7a65a619eb9eec3c0200000003636aabffffffff0397481c0200000000045300636a0dc97803000000000009d389030000000003ac6a53134007bb", "0000536552526a", 0, -1912746174, "30c4cd4bd6b291f7e9489cc4b4440a083f93a7664ea1f93e77a9597dab8ded9c"}, + {"7d95473604fd5267d0e1bb8c9b8be06d7e83ff18ad597e7a568a0aa033fa5b4e1e2b6f1007020000000465006a6affffffffaee008503bfc5708bd557c7e78d2eab4878216a9f19daa87555f175490c40aaf000000000263abffffffffabd74f0cff6e7ceb9acc2ee25e65af1abcebb50c08306e6c78fa8171c37613dd010000000552acacababffffffff54a3069393f7930fa1b331cdff0cb945ec21c11d4605d8eedba1d3e094c6ae1f01000000026300ffffffff0182edeb050000000009526353ab5153530065a247e8cd", "51516aab00", 2, -426210430, "2707ca714af09494bb4cf0794abe33c6cba5f29891d619e76070269d1fa8e690"}, + {"221d4718023d9ca9fe1af178dbfce02b2b369bf823ea3f43f00891b7fef98e215c06b94fdd000000000951005153ab000051acffffffffb1c7ad1c64b7441bf5e70cd0f6eb4ec96821d67fc4997d9e6dfdceadecd36dde01000000070051536a635153ffffffff04e883cd00000000000851ab536553ab0052bbb2f70400000000002f1b2e03000000000165259fcb00000000000010dbde99", "ab", 1, 665721280, "4abce77432a86dfe608e7c1646c18b5253a373392ff962e288e3ab96bba1ba1d"}, + {"6f66c0b3013e6ae6aabae9382a4326df31c981eac169b6bc4f746edaa7fc1f8c796ef4e374000000000665ab6aabac6affffffff0191c8d6030000000002525300000000", "6a5352516a635352ab", 0, -1299629906, "48411efeb133c6b7fec4e7bdbe613f827093cb06ea0dbcc2ffcfde3a9ac4356c"}, + {"89e7928c04363cb520eff4465251fd8e41550cbd0d2cdf18c456a0be3d634382abcfd4a2130200000006ac516a6a656355042a796061ed72db52ae47d1607b1ceef6ca6aea3b7eea48e7e02429f382b378c4e51901000000085351ab6352ab5252ffffffff53631cbda79b40183000d6ede011c778f70147dc6fa1aed3395d4ce9f7a8e69701000000096a6553ab52516a52abad0de418d80afe059aab5da73237e0beb60af4ac490c3394c12d66665d1bac13bdf29aa8000000000153f2b59ab6027a33eb040000000007005351ac5100ac88b941030000000003ab0052e1e8a143", "63656a", 0, 1258533326, "b575a04b0bb56e38bbf26e1a396a76b99fb09db01527651673a073a75f0a7a34"}, + {"ca356e2004bea08ec2dd2df203dc275765dc3f6073f55c46513a588a7abcc4cbde2ff011c7020000000553525100003aefec4860ef5d6c1c6be93e13bd2d2a40c6fb7361694136a7620b020ecbaca9413bcd2a030000000965ac00536352535100ace4289e00e97caaea741f2b89c1143060011a1f93090dc230bee3f05e34fbd8d8b6c399010000000365526affffffff48fc444238bda7a757cb6a98cb89fb44338829d3e24e46a60a36d4e24ba05d9002000000026a53ffffffff03d70b440200000000056a6a526aac853c97010000000002515335552202000000000351635300000000", "0052", 3, -528192467, "fc93cc056c70d5e033933d730965f36ad81ef64f1762e57f0bc5506c5b507e24"}, + {"82d4fa65017958d53e562fac073df233ab154bd0cf6e5a18f57f4badea8200b217975e31030200000004636aab51ac0891a204227cc9050000000006635200655365bfef8802000000000865650051635252acfc2d09050000000006ab65ac51516380195e030000000007ac52525352510063d50572", "53", 0, -713567171, "e095003ca82af89738c1863f0f5488ec56a96fb81ea7df334f9344fcb1d0cf40"}, + {"75f6949503e0e47dd70426ef32002d6cdb564a45abedc1575425a18a8828bf385fa8e808e600000000036aabab82f9fd14e9647d7a1b5284e6c55169c8bd228a7ea335987cef0195841e83da45ec28aa2e0300000002516350dc6fe239d150efdb1b51aa288fe85f9b9f741c72956c11d9dcd176889963d699abd63f0000000001ab429a63f502777d20010000000007abac52ac516a53d081d9020000000003acac630c3cc3a8", "535152516551510000", 1, 973814968, "c6ec1b7cb5c16a1bfd8a3790db227d2acc836300534564252b57bd66acf95092"}, + {"24f24cd90132b2162f938f1c22d3ca5e7daa83515883f31a61a5177aebf99d7db6bdfc398c010000000163ffffffff01d5562d0100000000016300000000", "5265ac5165ac5252ab", 0, 1055129103, "5eeb03e03806cd7bfd44bbba69c30f84c2c5120df9e68cd8facc605fcfbc9693"}, + {"5ff2cac201423064a4d87a96b88f1669b33adddc6fa9acdc840c0d8a243671e0e6de49a5b00300000005ac6353655353b91db50180db5a03000000000663535151006a047a3aff", "52ab51ab5365005163", 0, -1336626596, "b8db8d57fe40ab3a99cf2f8ed57da7a65050fcc1d34d4280e25faf10108d3110"}, + {"10011f150220ad76a50ccc7bb1a015eda0ff987e64cd447f84b0afb8dc3060bdae5b36a6900200000000ffffffff1e92dd814dfafa830187bc8e5b9258de2445ec07b02c420ee5181d0b203bb334000000000565ab536a65ffffffff0124e65401000000000800ab636553ab53ac00000000", "53abab0051", 0, 440222748, "c6675bf229737e005b5c8ffa6f81d9e2c4396840921b6151316f67c4315a4270"}, + {"8b95ec900456648d820a9b8df1d8f816db647df8a8dc9f6e7151ebf6079d90ee3f6861352a02000000085200ab00ac535151ffffffff039b10b845f961225ac0bcaac4f5fe1991029a051aa3d06a3811b5762977a67403000000035252abffffffff8559d65f40d5e261f45aec8aad3d2c56c6114b22b26f7ee54a06f0881be3a7f5010000000765635252536363ffffffff38f8b003b50f6412feb2322b06b270197f81ad69c36af02ca5008b94eee5f650020000000165ffffffff01ae2b00010000000001638eb153a2", "0053ab5300ac53", 2, 1266056769, "205f3653f0142b35ce3ef39625442efebae98cde8cbf0516b97b51073bb0479f"}, + {"babbb7ea01ab5d584727cb44393b17cf66521606dc81e25d85273be0d57bad43e8f6b6d43501000000036a656aba83a68803fb0f4a000000000005536353ab633fcfe4020000000009ac00acab6351006a65182a0c03000000000453ac5363bee74f44", "536a6a6a6365ac51ab", 0, -799187625, "3275e98dca37243b977525a07b5d8e369d6c3bdc08cb948029a635547d0d1a4e"}, + {"e86a24bc03e4fae784cdf81b24d120348cb5e52d937cd9055402fdba7e43281e482e77a1c100000000046363006affffffffa5447e9bdcdab22bd20d88b19795d4c8fb263fbbf7ce8f4f9a85f865953a6325020000000663ac53535253ffffffff9f8b693bc84e0101fc73748e0513a8cecdc264270d8a4ee1a1b6717607ee1eaa00000000026a513417bf980158d82c020000000009005253005351acac5200000000", "6353516365536a6a", 2, -563792735, "508129278ef07b43112ac32faf00170ad38a500eed97615a860fd58baaad174b"}, + {"53bd749603798ed78798ef0f1861b498fc61dcee2ee0f2b37cddb115b118e73bc6a5a47a0201000000096a63656a6aab6a000007ff674a0d74f8b4be9d2e8e654840e99d533263adbdd0cf083fa1d5dd38e44d2d163d900100000007abab5251ac6a51c8b6b63f744a9b9273ccfdd47ceb05d3be6400c1ed0f7283d32b34a7f4f0889cccf06be30000000009516a52636551ab516a9ac1fe63030c677e05000000000027bc610000000000086565636a635100526e2dc60200000000015300000000", "6552536a515351ab", 1, -1617066878, "fe516df92299e995b8e6489be824c6839543071ec5e9286060b2600935bf1f20"}, + {"691bf9fc028ca3099020b79184e70039cf53b3c7b3fe695d661fd62d7b433e65feda2150610000000003ac63abffffffff2c814c15b142bc944192bddccb90a392cd05b968b599c1d8cd99a55a28a243fd0100000009ab5300526a5200abac98516a5803dfd3540500000000046552ac522838120100000000040053ab6a4409a903000000000665636a5300658759621b", "65ac5165ab", 0, -359941441, "d582c442e0ecc400c7ba33a56c93ad9c8cfd45af820350a13623594b793486f0"}, + {"536bc5e60232eb60954587667d6bcdd19a49048d67a027383cc0c2a29a48b960dc38c5a0370300000005ac636300abffffffff8f1cfc102f39b1c9348a2195d496e602c77d9f57e0769dabde7eaaedf9c69e250100000006acabab6a6351ffffffff0432f56f0400000000046a5365517fd54b0400000000035265539484e4050000000003536a5376dc25020000000008ac536aab6aab536ab978e686", "ac0051006a006a006a", 0, -273074082, "f151f1ec305f698d9fdce18ea292b145a58d931f1518cf2a4c83484d9a429638"}, + {"74606eba01c2f98b86c29ba5a32dc7a7807c2abe6ed8d89435b3da875d87c12ae05329e6070200000003510052ffffffff02a1e2c4020000000006516563526a63c68bae04000000000952ab6363ab00006363fe19ae4f", "63ababacac5365", 0, 112323400, "d1b1d79001b4a0324962607b739972d6f39c1493c4500ce814fd3bd72d32a5a0"}, + {"2ed805e20399e52b5bcc9dc075dad5cf19049ff5d7f3de1a77aee9288e59c5f4986751483f020000000165ffffffff967531a5726e7a653a9db75bd3d5208fa3e2c5e6cd5970c4d3aba84eb644c72c0300000000ffffffffd79030d20c65e5f8d3c55b5692e5bdaa2ae78cfa1935a0282efb97515feac43f030000000400006365261ab88c02bdf66a000000000003ab6351d6ad8b000000000005525152abac00000000", "630053ab5265", 0, 2072814938, "1d25d16d84d5793be1ad5cda2de9c9cf70e04a66c3dae618f1a7ca4026198e7f"}, + {"fab796ee03f737f07669160d1f1c8bf0800041157e3ac7961fea33a293f976d79ce49c02ab0200000003ac5252eb097ea1a6d1a7ae9dace338505ba559e579a1ee98a2e9ad96f30696d6337adcda5a85f403000000096500abab656a6a656396d5d41a9b11f571d91e4242ddc0cf2420eca796ad4882ef1251e84e42b930398ec69dd80100000005526551ac6a8e5d0de804f763bb0400000000015288271a010000000001acf2bf2905000000000300ab51c9641500000000000952655363636365ac5100000000", "00ac536552", 0, -1854521113, "f3bbab70b759fe6cfae1bf349ce10716dbc64f6e9b32916904be4386eb461f1f"}, + {"f2b539a401e4e8402869d5e1502dbc3156dbce93583f516a4947b333260d5af1a34810c6a00200000003525363ffffffff01d305e2000000000005acab535200a265fe77", "", 0, -1435650456, "41617b27321a830c712638dbb156dae23d4ef181c7a06728ccbf3153ec53d7dd"}, + {"9f10b1d8033aee81ac04d84ceee0c03416a784d1017a2af8f8a34d2f56b767aea28ff88c8f02000000025352ffffffff748cb29843bea8e9c44ed5ff258df1faf55fbb9146870b8d76454786c4549de100000000016a5ba089417305424d05112c0ca445bc7107339083e7da15e430050d578f034ec0c589223b0200000007abac53ac6565abffffffff025a4ecd010000000006636563ab65ab40d2700000000000056a6553526333fa296c", "", 0, -395044364, "20fd0eee5b5716d6cbc0ddf852614b686e7a1534693570809f6719b6fcb0a626"}, + {"ab81755f02b325cbd2377acd416374806aa51482f9cc5c3b72991e64f459a25d0ddb52e66703000000036a00ab8727056d48c00cc6e6222be6608c721bc2b1e69d0ffbadd51d131f05ec54bcd83003aac5000000000003f2cdb60454630e020000000007526aac63000000e9e25c040000000003516a0088c97e0000000000076a535265655263771b5805000000000851ab00ac6565515100000000", "5151ab00ac", 0, -230931127, "ba0a2c987fcdd74b6915f6462f62c3f126a0750aa70048f7aa20f70726e6a20b"}, + {"7a17e0ef0378dab4c601240639139335da3b7d684600fa682f59b7346ef39386fe9abd69350000000004ac5252ab807f26fb3249326813e18260a603b9ad66f41f05eaa8146f66bcca452162a502aac4aa8b02000000026a534ea460faa7e3d7854ec6c70d7e797025697b547ec500b2c09c873b4d5517767d3f3720660300000000ffffffff01b12e7a02000000000900ab006aab65656a63991c03e2", "6aab6a", 1, -1577994103, "62cd3413d9d819fb7355336365cf8a2a997f7436cc050a7143972044343b3281"}, + {"ff2ecc09041b4cf5abb7b760e910b775268abee2792c7f21cc5301dd3fecc1b4233ee70a2c0200000009acac5300006a51526affffffffeb39c195a5426afff38379fc85369771e4933587218ef4968f3f05c51d6b7c92000000000165453a5f039b8dbef7c1ffdc70ac383b481f72f99f52b0b3a5903c825c45cfa5d2c0642cd50200000001654b5038e6c49daea8c0a9ac8611cfe904fc206dad03a41fb4e5b1d6d85b1ecad73ecd4c0102000000096a51000053ab656565bdb5548302cc719200000000000452655265214a3603000000000300ab6a00000000", "52516a006a63", 1, -2113289251, "37ed6fae36fcb3360c69cac8b359daa62230fc1419b2cf992a32d8f3e079dcff"}, + {"70a8577804e553e462a859375957db68cfdf724d68caeacf08995e80d7fa93db7ebc04519d02000000045352ab53619f4f2a428109c5fcf9fee634a2ab92f4a09dc01a5015e8ecb3fc0d9279c4a77fb27e900000000006ab6a51006a6affffffff3ed1a0a0d03f25c5e8d279bb5d931b7eb7e99c8203306a6c310db113419a69ad010000000565516300abffffffff6bf668d4ff5005ef73a1b0c51f32e8235e67ab31fe019bf131e1382050b39a630000000004536a6563ffffffff02faf0bb00000000000163cf2b4b05000000000752ac635363acac15ab369f", "ac", 0, -1175809030, "1c9d6816c20865849078f9777544b5ddf37c8620fe7bd1618e4b72fb72dddca1"}, + {"a3604e5304caa5a6ba3c257c20b45dcd468f2c732a8ca59016e77b6476ac741ce8b16ca8360200000004acac6553ffffffff695e7006495517e0b79bd4770f955040610e74d35f01e41c9932ab8ccfa3b55d0300000007ac5253515365acffffffff6153120efc5d73cd959d72566fc829a4eb00b3ef1a5bd3559677fb5aae116e38000000000400abab52c29e7abd06ff98372a3a06227386609adc7665a602e511cadcb06377cc6ac0b8f63d4fdb03000000055100acabacffffffff04209073050000000009ab5163ac525253ab6514462e05000000000952abacab636300656a20672c0400000000025153b276990000000000056565ab6a5300000000", "5351", 0, 1460890590, "249c4513a49076c6618aabf736dfd5ae2172be4311844a62cf313950b4ba94be"}, + {"c6a72ed403313b7d027f6864e705ec6b5fa52eb99169f8ea7cd884f5cdb830a150cebade870100000009ac63ab516565ab6a51ffffffff398d5838735ff43c390ca418593dbe43f3445ba69394a6d665b5dc3b4769b5d700000000075265acab515365ffffffff7ee5616a1ee105fd18189806a477300e2a9cf836bf8035464e8192a0d785eea3030000000700ac6a51516a52ffffffff018075fd0000000000015100000000", "005251acac5252", 2, -656067295, "2cc1c7514fdc512fd45ca7ba4f7be8a9fe6d3318328bc1a61ae6e7675047e654"}, + {"93c12cc30270fc4370c960665b8f774e07942a627c83e58e860e38bd6b0aa2cb7a2c1e060901000000036300abffffffff4d9b618035f9175f564837f733a2b108c0f462f28818093372eec070d9f0a5440300000001acffffffff039c2137020000000001525500990100000000055265ab636a07980e0300000000005ba0e9d1", "656a5100", 1, 18954182, "6beca0e0388f824ca33bf3589087a3c8ad0857f9fe7b7609ae3704bef0eb83e2"}, + {"97bddc63015f1767619d56598ad0eb5c7e9f880b24a928fea1e040e95429c930c1dc653bdb0100000008ac53acac00005152aaa94eb90235ed10040000000000287bdd0400000000016a8077673a", "acac6a536352655252", 0, -813649781, "5990b139451847343c9bb89cdba0e6daee6850b60e5b7ea505b04efba15f5d92"}, + {"cc3c9dd303637839fb727270261d8e9ddb8a21b7f6cbdcf07015ba1e5cf01dc3c3a327745d0300000000d2d7804fe20a9fca9659a0e49f258800304580499e8753046276062f69dbbde85d17cd2201000000096352536a520000acabffffffffbc75dfa9b5f81f3552e4143e08f485dfb97ae6187330e6cd6752de6c21bdfd21030000000600ab53650063ffffffff0313d0140400000000096565515253526aacac167f0a040000000008acab00535263536a9a52f8030000000006abab5151ab63f75b66f2", "6a635353636a65ac65", 1, 377286607, "dbc7935d718328d23d73f8a6dc4f53a267b8d4d9816d0091f33823bd1f0233e9"}, + {"236f91b702b8ffea3b890700b6f91af713480769dda5a085ae219c8737ebae90ff25915a3203000000056300ac6300811a6a10230f12c9faa28dae5be2ebe93f37c06a79e76214feba49bb017fb25305ff84eb020000000100ffffffff041e351703000000000351ac004ff53e050000000003ab53636c1460010000000000cb55f701000000000651520051ab0000000000", "acac636a6aac5300", 0, 406448919, "793a3d3c37f6494fab79ff10c16702de002f63e34be25dd8561f424b0ea938c4"}, + {"22e10d2003ab4ea9849a2801921113583b7c35c3710ff49a6003489395789a7cfb1e6051900100000006526a65535151ffffffff82f21e249ec60db33831d33b9ead0d56f6496db64337dcb7f1c3327c47729c4a020000000253abffffffff138f098f0e6a4cf51dc3e7a3b749f487d1ebde71b73b731d1d02ad1180ac7b8c02000000036563acda215011027a9484020000000007635165530000ac4bf6cb0400000000066aacabab65ab3ce3f32c", "ab0052ab", 2, 1136359457, "b5bd080bbcb8cd652f440484311d7a3cb6a973cd48f03c5c00fd6beb52dfc061"}, + {"c47d5ad60485cb2f7a825587b95ea665a593769191382852f3514a486d7a7a11d220b62c54000000000663655253acab8c3cf32b0285b040e50dcf6987ddf7c385b3665048ad2f9317b9e0c5ba0405d8fde4129b00000000095251ab00ac65635300ffffffff549fe963ee410d6435bb2ed3042a7c294d0c7382a83edefba8582a2064af3265000000000152fffffffff7737a85e0e94c2d19cd1cde47328ece04b3e33cd60f24a8a345da7f2a96a6d0000000000865ab6a0051656aab28ff30d5049613ea020000000005ac51000063f06df1050000000008ac63516aabac5153afef5901000000000700656500655253688bc00000000000086aab5352526a53521ff1d5ff", "51ac52", 2, -1296011911, "0c1fd44476ff28bf603ad4f306e8b6c7f0135a441dc3194a6f227cb54598642a"}, + {"0b43f122032f182366541e7ee18562eb5f39bc7a8e5e0d3c398f7e306e551cdef773941918030000000863006351ac51acabffffffffae586660c8ff43355b685dfa8676a370799865fbc4b641c5a962f0849a13d8250100000005abab63acabffffffff0b2b6b800d8e77807cf130de6286b237717957658443674df047a2ab18e413860100000008ab6aac655200ab63ffffffff04f1dbca03000000000800635253ab656a52a6eefd0300000000036365655d8ca90200000000005a0d530400000000015300000000", "65ac65acac", 0, 351448685, "86f26e23822afd1bdfc9fff92840fc1e60089f12f54439e3ab9e5167d0361dcf"}, + {"4b0ecc0c03ba35700d2a30a71f28e432ff6ac7e357533b49f4e97cf28f1071119ad6b97f3e0300000008acab516363ac63acffffffffcd6a2019d99b5c2d639ddca0b1aa5ea7c1326a071255ea226960bd88f45ca57d00000000085253655363005353ffffffffba257635191c9f216de3277be548cb5a2313114cb1a4c563b03b4ef6c0f4f7040300000001abda542edf0495cdc40100000000026353c049e903000000000752516a53ab65512b0f9304000000000963ab516aac65516552fa9ece050000000009acab6500005152530000000000", "65ab51525352510052", 1, -1355414590, "3cd85f84aae6d702436f3f9b8980adcc1f8f202e957759540a27da0a32fc6c87"}, + {"adaac0a803f66811346271c733036d6e0d45e15a9b602092e2e04ad93564f196e7f020b088000000000600526a636a00700ec3f9db07a3a6ce910bf318c7ec87a876e1f2a3366cc69f20cde09203b99c1cb9d15800000000050000ac636a4d0de554ebe95c6cc14faf5ff6361d1deba9474b8b0fd3b93c011cd96aec783abb3f36830200000005ab65005251ffffffff0464eb10050000000007520000ab6a65ab1beaa80300000000005a2f31050000000006526aab65ac52ba7db10000000000045251ab6a0cfb46e7", "ab0051ac52636a", 1, -184733716, "961ff413850336d3987c550404fc1d923266ca36cc9ffee7113edb3a9fea7f30"}, + {"af1c4ab301ec462f76ee69ba419b1b2557b7ded639f3442a3522d4f9170b2d6859765c3df402000000016affffffff01a5ca6c000000000008ab52536aab00005300000000", "6a6351", 0, 110304602, "e88ed2eea9143f2517b15c03db00767eb01a5ce12193b99b964a35700607e5f4"}, + {"0bfd34210451c92cdfa02125a62ba365448e11ff1db3fb8bc84f1c7e5615da40233a8cd368010000000252ac9a070cd88dec5cf9aed1eab10d19529720e12c52d3a21b92c6fdb589d056908e43ea910e0200000009ac516a52656a6a5165ffffffffc3edcca8d2f61f34a5296c405c5f6bc58276416c720c956ff277f1fb81541ddd00000000030063abffffffff811247905cdfc973d179c03014c01e37d44e78f087233444dfdce1d1389d97c302000000065163000063ab1724a26e02ca37c902000000000851ab53525352ac529012a90100000000085200525253535353fa32575b", "5352ac6351", 1, -1087700448, "b8f1e1f35e3e1368bd17008c756e59cced216b3c699bcd7bebdb5b6c8eec4697"}, + {"2c84c0640487a4a695751d3e4be48019dbaea85a6e854f796881697383ea455347d2b2769001000000055265526500ffffffff6aac176d8aa00778d496a7231eeb7d3334f20c512d3db1683276402100d98de5030000000700536a5263526ac1ee9ceb171c0c984ebaf12c234fd1487fbf3b3d73aa0756907f26837efba78d1bed33200300000001ab4d9e8ec0bed837cb929bbed76ee848959cec59de44bd7667b7631a744f880d5c71a20cfd0100000007005363515300abffffffff023753fb0000000000036565532d3873050000000009005152ab6a63acab5200000000", "ab650053ab", 0, -877941183, "c49af297dffe2d80deddf10ceea84b99f8554bd2d55bbdc34e449728c31f0835"}, + {"1f7e4b1b045d3efa6cd7a11d7873a8bab886c19bd11fcb6712f0948f2db3a7be76ff76c8f100000000095265ab6a0065ac5363ffffffffdaafcfa6029336c997680a541725190f09a6f6da21e54560eca4b5b8ae987da1000000000952ac52acac52515165ffffffff825a38d3b1e5bb4d10f33653ab3ab6882c7abdaec74460257d1528ce7be3f98e0100000007526a006a656a63c14adc8f04953a5d3d3f89237f38b857dd357713896d36215f7e8b77b11d98ea3cdc93df02000000015212484f6104bfafae0300000000025263a2b0120000000000056563ab00516c4d2605000000000653ac6500655301cc93030000000002acab14643b1f", "63acac53ab", 0, 333824258, "18da6ceb011cd36f15ad7dd6c55ef07e6f6ed48881ce3bb31416d3c290d9a0e9"}, + {"467a3e7602e6d1a7a531106791845ec3908a29b833598e41f610ef83d02a7da3a1900bf2960000000005ab6a636353ffffffff031db6dac6f0bafafe723b9199420217ad2c94221b6880654f2b35114f44b1df010000000965ab52636a63ac6352ffffffff02b3b95c0100000000026300703216030000000001ab3261c0aa", "6a", 0, 2110869267, "3078b1d1a7713c6d101c64afe35adfae0977a5ab4c7e07a0b170b041258adbf2"}, + {"8713bc4f01b411149d575ebae575f5dd7e456198d61d238695df459dd9b86c4e3b2734b62e0300000004abac6363ffffffff03b58049050000000002ac653c714c04000000000953656a005151526a527b5a9e03000000000652ac5100525300000000", "52", 0, -647281251, "0e0bed1bf2ff255aef6e5c587f879ae0be6222ab33bd75ee365ec6fbb8acbe38"}, + {"f2ba8a8701b9c401efe3dd0695d655e20532b90ac0142768cee4a3bb0a89646758f544aa8102000000036a52527899f4e4040c6f0b030000000008636565ab530051ab52b60c000000000009515200ab630053ac53a49c5f040000000008ab53ab516300ab63fa27340300000000015100000000", "ac63abab5251", 0, -1328936437, "ab61497afd39e61fe06bc5677326919716f9b20083c9f3417dcea905090e0411"}, + {"b5a7df6102107beded33ae7f1dec0531d4829dff7477260925aa2cba54119b7a07d92d5a1d02000000046a516a52803b625c334c1d2107a326538a3db92c6c6ae3f7c3516cd90a09b619ec6f58d10e77bd6703000000056563006a63ffffffff0117484b03000000000853acab52526a65abc1b548a1", "ac006a525100", 0, 2074359913, "680336db57347d8183b8898cd27a83f1ba5884155aeae5ce20b4840b75e12871"}, + {"278cb16204b9dadf400266106392c4aa9df01ba03af988c8139dae4c1818ac009f13fc5f1a00000000065200ac656a52ffffffffd006bbebd8cbd7bdead24cddc9badfcc6bc0c2e63c037e5c29aa858f5d0f3e7d01000000046a0051acffffffffbc62a5f57e58da0b67956003ae81ac97cb4cbd1d694c914fc41515c008c4d8fd020000000165e329c844bcc16164be64b64a81cbf4ffd41ed2934e0daa0040ccb8365bab0b2a9e401c180300000003ab52abffffffff02588460030000000000a25a12030000000005535100005300000000", "6553ab6a5300acab51", 3, 989407546, "1c29f110576f4a3b257f67454d99dfc0dee62ef5517ca702848ce4bd2ea1a1d7"}, + {"49eb2178020a04fca08612c34959fd41447319c190fb7ffed9f71c235aa77bec28703aa1820200000003ac6353abaff326071f07ec6b77fb651af06e8e8bd171068ec96b52ed584de1d71437fed186aecf0300000001acffffffff03da3dbe02000000000652ac63ac6aab8f3b680400000000096a536a65636a53516a5175470100000000016500000000", "6a536365", 0, 1283691249, "c670219a93234929f662ecb9aa148a85a2d281e83f4e53d10509461cdea47979"}, + {"0f96cea9019b4b3233c0485d5b1bad770c246fe8d4a58fb24c3b7dfdb3b0fd90ea4e8e947f0300000006006a5163515303571e1e01906956030000000005ab635353abadc0fbbe", "acac", 0, -1491469027, "716a8180e417228f769dcb49e0491e3fda63badf3d5ea0ceeac7970d483dd7e2"}, + {"9a7d858604577171f5fe3f3fd3e5e039c4b0a06717a5381e9977d80e9f53e025e0f16d2877020000000752636565536353ffffffff5862bd028e8276e63f044be1dddcbb8d0c3fa097678308abf2b0f45104a93dbd0100000001531200667ba8fdd3b28e98a35da73d3ddfe51e210303d8eb580f923de988ee632d77793892030000000752526363526563ffffffffe9744eb44db2658f120847c77f47786d268c302120d269e6004455aa3ea5f5e20200000009ab6300636aab656551ffffffff03c61a3c020000000009ab516a6aab6aab53ab737f1a05000000000853acabab655365ab92a4a00400000000016367edf6c8", "535352ab", 3, 659348595, "d36ee79fc80db2e63e05cdc50357d186181b40ae20e3720878284228a13ee8b3"}, + {"148e68480196eb52529af8e83e14127cbfdbd4a174e60a86ac2d86eac9665f46f4447cf7aa01000000045200ac538f8f871401cf240c0300000000065252ab52656a5266cf61", "", 0, -344314825, "eacc47c5a53734d6ae3aedbc6a7c0a75a1565310851b29ef0342dc4745ceb607"}, + {"e2bc29d4013660631ba14ecf75c60ec5e9bed7237524d8c10f66d0675daa66d1492cb834530200000004ac510065e42d0c9e04f2b26c01000000000951525152acac65ababa35b7504000000000953ac6aac00650053ab94688c0400000000056365526553a1bced0300000000016a00000000", "65ab0063655353", 0, -888431789, "59a34b3ed3a1cce0b104de8f7d733f2d386ffc7445efae67680cd90bc915f7e0"}, + {"0c8a70d70494dca6ab05b2bc941b5b431c43a292bd8f2f02eab5e240a408ca73a676044a4103000000056a51ab006affffffff84496004e54836c035821f14439149f22e1db834f315b24588ba2f031511926c0100000000ffffffffbbc5e70ed1c3060ba1bfe99c1656a3158a7307c3ce8eb362ec32c668596d2bd30000000009636563635351abab00b039344c6fc4f9bec24322e45407af271b2d3dfec5f259ee2fc7227bc5285e22b3be85b40100000009ac00ab53abac6a5352e5ddfcff02d50231020000000005006a51536ab086d9020000000006ababac51ac6a00000000", "abab636565acac6a", 3, 241546088, "643a7b4c8d832e14d5c10762e74ec84f2c3f7ed96c03053157f1bed226614911"}, + {"f98f79cf0274b745e1d6f36da7cbe205a79132a7ad462bdc434cfb1dcd62a6977c3d2a5dbc010000000553516a5365ffffffff4f89f485b53cdad7fb80cc1b7e314b9735b9383bc92c1248bb0e5c6173a55c0d010000000353655293f9b014045ad96d02000000000963ac526a53ac636365f4c27904000000000952536563635152526a2788f0030000000002516aff5add01000000000863530051655351abd04716ba", "ab6552536a53", 1, -2128899945, "56d29f5e300ddfed2cd8dcce5d79826e193981d0b70dc7487772c8a0b3b8d7b1"}, + {"6c7913f902aa3f5f939dd1615114ce961beda7c1e0dd195be36a2f0d9d047c28ac62738c3a020000000453abac00ffffffff477bf2c5b5c6733881447ac1ecaff3a6f80d7016eee3513f382ad7f554015b970100000007ab6563acab5152ffffffff04e58fe1040000000009ab00526aabab526553e59790010000000002ab525a834b03000000000035fdaf0200000000086551ac65515200ab00000000", "63ac53", 1, 1285478169, "1536da582a0b6de017862445e91ba14181bd6bf953f4de2f46b040d351a747c9"}, + {"4624aa9204584f06a8a325c84e3b108cafb97a387af62dc9eab9afd85ae5e2c71e593a3b690200000003636a005eb2b44eabbaeca6257c442fea00107c80e32e8715a1293cc164a42e62ce14fea146220c020000000090b9ee38106e3310037bfc519fd209bdbd21c588522a0e96df5fba4e979392bc993bfe9f01000000086363636a635353ab6f1907d218ef6f3c729d9200e23c1dbff2df58b8b1282c6717b26cf760ee4c880d23f4d100000000086a516a536a525163ffffffff01d6f162050000000000ebbab208", "525365ab0053", 1, -1515409325, "6cf9cd409b7185b1f118171f0a34217af5b612ea54195ea186505b667c19337f"}, + {"16562fc503f1cf9113987040c408bfd4523f1512da699a2ca6ba122dc65677a4c9bf7763830000000003636552ffffffff1ec1fab5ff099d1c8e6b068156f4e39b5543286bab53c6d61e2582d1e07c96cf02000000045163656affffffffd0ef40003524d54c08cb4d13a5ee61c84fbb28cde9eca7a6d11ba3a9335d8c620100000007635153536a6300fbb84fc2012003a601000000000363ab6a00000000", "63636a006a6aab", 0, -1310262675, "1efbf3d37a92bc03d9eb950b792f307e95504f7c4998f668aa250707ebb752ac"}, + {"531665d701f86bacbdb881c317ef60d9cd1baeffb2475e57d3b282cd9225e2a3bf9cbe0ded01000000086300ac515263acabffffffff0453a8500100000000086353acab516a6565e5e9200500000000026a52a44caa00000000000453ac000065e41b0500000000076500ac0065526ab4476f4d", "006563006aab00636a", 0, 1770013777, "0898b26dd3ca08632a5131fa48eb55b44386d0c5070c24d6e329673d5e3693b8"}, + {"0f1227a20140655a3da36e413b9b5d108a866f6f147eb4940f032f5a89854eae6d7c3a91600100000009525363515153515253e37a79480161ab61020000000001ab00000000", "ab65005200", 0, -1996383599, "979782dc3f36d908d37d7e4046a38d306b4b08ddc60a5eba355fe3d6da1b29a9"}, + {"063ff6eb01aff98d0d2a6db224475010edb634c2f3b46257084676adeb84165a4ff8558d7601000000066353006a5165deb3262c042d109c0000000000076363ab52ac005200b9c4050000000007516300ac510063cfffc800000000000200639e815501000000000700526a52ac6365ac7b07b8", "656552abac6500", 0, -1559847112, "674a4bcb04247f8dc98780f1792cac86b8aee41a800fc1e6f5032f6e1dccde65"}, + {"3320f6730132f830c4681d0cae542188e4177cad5d526fae84565c60ceb5c0118e844f90bd030000000163ffffffff0257ec5a040000000005525251ac6538344d000000000002515200000000", "5352656a53ac516a65", 0, 788050308, "3afacaca0ef6be9d39e71d7b1b118994f99e4ea5973c9107ca687d28d8eba485"}, + {"c13aa4b702eedd7cde09d0416e649a890d40e675aa9b5b6d6912686e20e9b9e10dbd40abb1000000000863ab6353515351ac11d24dc4cc22ded7cdbc13edd3f87bd4b226eda3e4408853a57bcd1becf2df2a1671fd1600000000045165516affffffff01baea300100000000076aab52ab53005300000000", "0065", 0, -1195908377, "241a23e7b1982d5f78917ed97a8678087acbbffe7f624b81df78a5fe5e41e754"}, + {"d9a6f20e019dd1b5fae897fb472843903f9c3c2293a0ffb59cff2b413bae6eceab574aaf9d030000000663ab006a515102f54939032df5100100000000056a51ab65530ec28f010000000004ac5100007e874905000000000651005265ac6a00000000", "abacab63acacabab", 0, 271463254, "1326a46f4c21e7619f30a992719a905aa1632aaf481a57e1cbd7d7c22139b41e"}, + {"157c81bf0490432b3fcb3f9a5b79e5f91f67f05efb89fa1c8740a3fe7e9bdc18d7cb6acd2203000000026351ffffffff912e48e72bbcf8a540b693cf8b028e532a950e6e63a28801f6eaad1afcc52ad00000000000b1a4b170a2b9e60e0cad88a0085137309f6807d25d5afb5c1e1d32aa10ba1cdf7df596dd0000000009525165656a51ab65ab3674fba32a76fe09b273618d5f14124465933f4190ba4e0fd09d838daafc6223b31642ac00000000086a53536551ac6565ffffffff01fe9fb6030000000008ab51656a5165636a00000000", "ab00ab6a6551", 3, -64357617, "1ddaab7f973551d71f16bd70c4c4edbf7225e64e784a6da0ee7f7a9fe4f12a0b"}, + {"a2692fff03b2387f5bacd5640c86ba7df574a0ee9ed7f66f22c73cccaef3907eae791cbd230200000004536363abffffffff4d9fe7e5b375de88ba48925d9b2005447a69ea2e00495a96eafb2f144ad475b40000000008000053000052636537259bee3cedd3dcc07c8f423739690c590dc195274a7d398fa196af37f3e9b4a1413f810000000006ac63acac52abffffffff04c65fe60200000000075151536365ab657236fc020000000009005263ab00656a6a5195b8b6030000000007ac5165636aac6a7d7b66010000000002acab00000000", "51", 2, -826546582, "925037c7dc7625f3f12dc83904755a37016560de8e1cdd153c88270a7201cf15"}, + {"2c5b003201b88654ac2d02ff6762446cb5a4af77586f05e65ee5d54680cea13291efcf930d0100000005ab536a006a37423d2504100367000000000004536a515335149800000000000152166aeb03000000000452510063226c8e03000000000000000000", "635251", 0, 1060344799, "7e058ca5dd07640e4aae7dea731cfb7d7fef1bfd0d6d7b6ce109d041f4ca2a31"}, + {"f981b9e104acb93b9a7e2375080f3ea0e7a94ce54cd8fb25c57992fa8042bdf4378572859f0100000002630008604febba7e4837da77084d5d1b81965e0ea0deb6d61278b6be8627b0d9a2ecd7aeb06a0300000005ac5353536a42af3ef15ce7a2cd60482fc0d191c4236e66b4b48c9018d7dbe4db820f5925aad0e8b52a0300000008ab0063510052516301863715efc8608bf69c0343f18fb81a8b0c720898a3563eca8fe630736c0440a179129d03000000086aac6a52ac6a63ac44fec4c00408320a03000000000062c21c030000000007ac6a655263006553835f0100000000015303cd60000000000005535263536558b596e0", "00", 0, -2140385880, "49870a961263354c9baf108c6979b28261f99b374e97605baa532d9fa3848797"}, + {"e7416df901269b7af14a13d9d0507709b3cd751f586ce9d5da8d16a121e1bd481f5a086e1103000000056aab005200ffffffff01aa269c040000000006acac6a6a5263ee718de6", "ab525363", 0, 1309186551, "eea7d2212bda2d408fff146f9ae5e85e6b640a93b9362622bb9d5e6e36798389"}, + {"402a815902193073625ab13d876190d1bbb72aecb0ea733c3330f2a4c2fe6146f322d8843a0300000008656aab0000535363fffffffff9dccdec5d8509d9297d26dfcb1e789cf02236c77dc4b90ebccbf94d1b5821150300000001510bf1f96a03c5c145000000000002ac6ae11b1c0100000000055163516a5239c8a600000000000365636300000000", "63536aacab", 0, -1811424955, "0090803a20102a778ab967a74532faee13e03b702083b090b1497bc2267ee2fe"}, + {"c4b702e502f1a54f235224f0e6de961d2e53b506ab45b9a40805d1dacd35148f0acf24ca5e00000000085200ac65ac53acabf34ba6099135658460de9d9b433b84a8562032723635baf21ca1db561dce1c13a06f4407000000000851ac006a63516aabffffffff02a853a603000000000163d17a67030000000005ab63006a5200000000", "ac5363515153", 1, 480734903, "5c46f7ac3d6460af0da28468fcc5b3c87f2b9093d0f837954b7c8174b4d7b6e7"}, + {"9b83f78704f492b9b353a3faad8d93f688e885030c274856e4037818848b99e490afef27770200000000ffffffff36b60675a5888c0ef4d9e11744ecd90d9fe9e6d8abb4cff5666c898fdce98d9e00000000056aab656352596370fca7a7c139752971e169a1af3e67d7656fc4fc7fd3b98408e607c2f2c836c9f27c030000000653ac51ab6300a0761de7e158947f401b3595b7dc0fe7b75fa9c833d13f1af57b9206e4012de0c41b8124030000000953656a53ab53510052242e5f5601bf83b301000000000465516a6300000000", "63515200ac656365", 3, -150879312, "9cf05990421ea853782e4a2c67118e03434629e7d52ab3f1d55c37cf7d72cdc4"}, + {"f492a9da04f80b679708c01224f68203d5ea2668b1f442ebba16b1aa4301d2fe5b4e2568f3010000000953005351525263ab65ffffffff93b34c3f37d4a66df255b514419105b56d7d60c24bf395415eda3d3d8aa5cd0101000000020065ffffffff9dba34dabdc4f1643b372b6b77fdf2b482b33ed425914bb4b1a61e4fad33cf390000000002ab52ffffffffbbf3dc82f397ef3ee902c5146c8a80d9a1344fa6e38b7abce0f157be7adaefae0000000009515351005365006a51ffffffff021359ba010000000000403fea0200000000095200ac6353abac635300000000", "00ac51acacac", 0, -2115078404, "fd44fc98639ca32c927929196fc3f3594578f4c4bd248156a25c04a65bf3a9f3"}, + {"2f73e0b304f154d3a00fde2fdd40e791295e28d6cb76af9c0fd8547acf3771a02e3a92ba37030000000852ac6351ab6565639aa95467b065cec61b6e7dc4d6192b5536a7c569315fb43f470078b31ed22a55dab8265f02000000080065636a6aab6a53ffffffff9e3addbff52b2aaf9fe49c67017395198a9b71f0aa668c5cb354d06c295a691a0100000000ffffffff45c2b4019abaf05c5e484df982a4a07459204d1343a6ee5badade358141f8f990300000007ac516a6aacac6308655cd601f3bc2f0000000000015200000000", "", 0, -2082053939, "9a95e692e1f78efd3e46bb98f178a1e3a0ef60bd0301d9f064c0e5703dc879c2"}, + {"5a60b9b503553f3c099f775db56af3456330f1e44e67355c4ab290d22764b9144a7b5f959003000000030052acbd63e0564decc8659aa53868be48c1bfcda0a8c9857b0db32a217bc8b46d9e7323fe9649020000000553ac6551abd0ecf806211db989bead96c09c7f3ec5f73c1411d3329d47d12f9e46678f09bac0dc383e0200000000ffffffff01494bb202000000000500516551ac00000000", "ac", 0, 1169947809, "62a36c6e8da037202fa8aeae03e533665376d5a4e0a854fc4624a75ec52e4eb1"}, + {"7e98d353045569c52347ca0ff2fdba608829e744f61eb779ffdb5830aae0e6d6857ab2690e03000000075365acab656352ffffffffa890dd37818776d12da8dca53d02d243ef23b4535c67016f4c58103eed85360f030000000093dbacdc25ca65d2951e047d6102c4a7da5e37f3d5e3c8b87c29b489360725dcd117ee2003000000056a6300ac53c7e99fa1dc2b8b51733034e6555f6d6de47dbbf1026effac7db80cb2080678687380dc1e02000000075352005263516affffffff04423272040000000008ab6353ab65510051e0f53b0500000000086300516552635152f74a5f04000000000853acab0053ab52ab0e8e5f00000000000951ac5363516a6aabab00000000", "6a5163ab52", 3, 890006103, "476868cecd1763c91dade98f17defa42d31049547df45acffa1cc5ae5c3d75d6"}, + {"e3649aa40405e6ffe377dbb1bbbb672a40d8424c430fa6512c6165273a2b9b6afa9949ec430200000007630052ab655153a365f62f2792fa90c784efe3f0981134d72aac0b1e1578097132c7f0406671457c332b84020000000353ab6ad780f40cf51be22bb4ff755434779c7f1def4999e4f289d2bd23d142f36b66fbe5cfbb4b01000000076a5252abac52ab1430ffdc67127c9c0fc97dcd4b578dab64f4fb9550d2b59d599773962077a563e8b6732c02000000016affffffff04cb2687000000000002ab636e320904000000000252acf70e9401000000000100dc3393050000000006ab0063536aacbc231765", "65520053", 3, -2016196547, "f64f805f0ff7f237359fa6b0e58085f3c766d1859003332223444fd29144112a"}, + {"1d033569040700441686672832b531ab55db89b50dc1f9fc00fb72218b652da9dcfbc83be901000000066551ac526a632b390f9ad068e5fdee6563e88e2a8e4e09763c861072713dc069893dc6bbc9db3f00e26502000000096a5363526565525252ffffffff8a36bdd0aaf38f6707592d203e14476ca9f259021e487135c7e8324244057ed90300000000ed3fb2a3dfd4d46b5f3603fe0148653911988457bd0ed7f742b07c452f5476c228ff9f600200000007526aac00525152ffffffff04b88e48030000000000c753d602000000000853510000006553518fda2603000000000853ac52acac5263534839f1030000000006ac006aacac5300000000", "516553635300ab0052", 1, 2075958316, "c2cefaec2293134acbcf6d2a8bf2b3eb42e4ec04ee8f8bf30ff23e65680677c1"}, + {"4c4be7540344050e3044f0f1d628039a334a7c1f7b4573469cfea46101d6888bb6161fe9710200000000ffffffffac85a4fdad641d8e28523f78cf5b0f4dc74e6c5d903c10b358dd13a5a1fd8a06000000000163e0ae75d05616b72467b691dc207fe2e65ea35e2eadb7e06ea442b2adb9715f212c0924f10200000000ffffffff0194ddfe02000000000265ac00000000", "00006500", 1, -479922562, "d66924d49f03a6960d3ca479f3415d638c45889ce9ab05e25b65ac260b51d634"}, + {"202c18eb012bc0a987e69e205aea63f0f0c089f96dd8f0e9fcde199f2f37892b1d4e6da90302000000055352ac6565ffffffff0257e5450100000000025300ad257203000000000000000000", "520052ac6a005265", 0, 168054797, "502967a6f999f7ee25610a443caf8653dda288e6d644a77537bcc115a8a29894"}, + {"32fa0b0804e6ea101e137665a041cc2350b794e59bf42d9b09088b01cde806ec1bbea077df0200000008515153650000006506a11c55904258fa418e57b88b12724b81153260d3f4c9f080439789a391ab147aabb0fa0000000007000052ac51ab510986f2a15c0d5e05d20dc876dd2dafa435276d53da7b47c393f20900e55f163b97ce0b800000000008ab526a520065636a8087df7d4d9c985fb42308fb09dce704650719140aa6050e8955fa5d2ea46b464a333f870000000009636300636a6565006affffffff01994a0d040000000002536500000000", "516563530065", 2, -163068286, "f58637277d2bc42e18358dc55f7e87e7043f5e33f4ce1fc974e715ef0d3d1c2a"}, + {"ae23424d040cd884ebfb9a815d8f17176980ab8015285e03fdde899449f4ae71e04275e9a80100000007ab006553530053ffffffff018e06db6af519dadc5280c07791c0fd33251500955e43fe4ac747a4df5c54df020000000251ac330e977c0fec6149a1768e0d312fdb53ed9953a3737d7b5d06aad4d86e9970346a4feeb5030000000951ab51ac6563ab526a67cabc431ee3d8111224d5ecdbb7d717aa8fe82ce4a63842c9bd1aa848f111910e5ae1eb0100000004ac515300bfb7e0d7048acddc030000000009636a5253636a655363a3428e040000000001525b99c6050000000004655265ab717e6e020000000000d99011eb", "ac6a6a516565", 1, -716251549, "b098eb9aff1bbd375c70a0cbb9497882ab51f3abfebbf4e1f8d74c0739dc7717"}, + {"030f44fc01b4a9267335a95677bd190c1c12655e64df74addc53b753641259af1a54146baa020000000152e004b56c04ba11780300000000026a53f125f001000000000251acd2cc7c03000000000763536563655363c9b9e50500000000015200000000", "ac", 0, -1351818298, "19dd32190ed2a37be22f0224a9b55b91e37290577c6c346d36d32774db0219a3"}, + {"c05f448f02817740b30652c5681a3b128322f9dc97d166bd4402d39c37c0b14506d8adb5890300000003536353ffffffffa188b430357055ba291c648f951cd2f9b28a2e76353bef391b71a889ba68d5fc02000000056565526a6affffffff02745f73010000000001ab3ec34c0400000000036aac5200000000", "516551510053", 0, -267877178, "3a1c6742d4c374f061b1ebe330b1e169a113a19792a1fdde979b53e094cc4a3c"}, + {"163ba45703dd8c2c5a1c1f8b806afdc710a2a8fc40c0138e2d83e329e0e02a9b6c837ff6b8000000000700655151ab6a522b48b8f134eb1a7e6f5a6fa319ce9d11b36327ba427b7d65ead3b4a6a69f85cda8bbcd22030000000563656552acffffffffdbcf4955232bd11eef0cc6954f3f6279675b2956b9bcc24f08c360894027a60201000000066500006500abffffffff04d0ce9d0200000000008380650000000000015233f360040000000003006aabedcf0801000000000000000000", "000065006500ac", 0, 216965323, "9afe3f4978df6a86e9a8ebd62ef6a9d48a2203f02629349f1864ef2b8b92fd55"}, + {"07f7f5530453a12ad0c7eb8fbc3f140c7ab6818144d67d2d8752600ca5d9a9358e2dff87d4000000000663526aab526a9e599c379d455e2da36d0cde88d931a863a3e97e01e93b9edb65856f3d958dc08b92b720000000000165bbc8d66dae3b1b170a6e2457f5b161465cb8706e0e6ffc6af55deb918365f14c5f40d4890100000000a7bd77c069ee4b48638e2363fcf2a86b02bea022047bd9fcb16d2b94ad068308d19b31cb00000000066aab5300ab529672aa8f01dbd8a205000000000663536353006a02e99901", "ac006351006a63ab63", 1, 119789359, "6629a1e75c6ae8f4f9d5f734246b6a71682a5ea57246040ef0584f6b97916175"}, + {"fe647f950311bf8f3a4d90afd7517df306e04a344d2b2a2fea368935faf11fa6882505890d0000000005ab5100516affffffff43c140947d9778718919c49c0535667fc6cc727f5876851cb8f7b6460710c7f60100000000ffffffffce4aa5d90d7ab93cbec2e9626a435afcf2a68dd693c15b0e1ece81a9fcbe025e0300000000ffffffff02f34806020000000002515262e54403000000000965635151ac655363636de5ce24", "6a005100ac516351", 2, 989643518, "818a7ceaf963f52b5c48a7f01681ac6653c26b63a9f491856f090d9d60f2ffe3"}, + {"a1050f8604d0f9d2feefcdb5051ae0052f38e21bf39daf583fd0c3900faa3eab5d431c0bbe030000000653536a005151683d27e5c6e0da8f22125823f32d5d98477d8098ef36263b9694d61d4d85d3f2ac02b7570200000007000052005165abffffffff0cad981542bcb54a87d9400aa63e514c7c6fab7158c2b1fb37821ea755eb162a0200000000b94feb5100e5ef3bf8ed8d43356c8a8d5ac6c7e80d7ff6040f4f0aa19abbe783f4f461240200000007636500000052655686fd70042be3ad02000000000465ab636a15680b000000000004acac53511277c705000000000452635252d27a0102000000000000000000", "6a6aacab65655251", 1, -982144648, "dfcf484111801989eb6df8dc2bafb944d7365ffeb36a575a08f3270d3ef24c9f"}, + {"cef7316804c3e77fe67fc6207a1ea6ae6eb06b3bf1b3a4010a45ae5c7ad677bb8a4ebd16d90200000009ac536a5152ac5263005301ab8a0da2b3e0654d31a30264f9356ba1851c820a403be2948d35cafc7f9fe67a06960300000006526a63636a53ffffffffbada0d85465199fa4232c6e4222df790470c5b7afd54704595a48eedd7a4916b030000000865ab63ac006a006ab28dba4ad55e58b5375053f78b8cdf4879f723ea4068aed3dd4138766cb4d80aab0aff3d0300000003ac6a00ffffffff010f5dd6010000000006ab006aab51ab00000000", "", 1, 889284257, "d0f32a6db43378af84b063a6706d614e2d647031cf066997c48c04de3b493a94"}, + {"7b3ff28004ba3c7590ed6e36f45453ebb3f16636fe716acb2418bb2963df596a50ed954d2e03000000065251515265abffffffff706ee16e32e22179400c9841013971645dabf63a3a6d2d5feb42f83aa468983e030000000653ac51ac5152ffffffffa03a16e5e5de65dfa848b9a64ee8bf8656cc1f96b06a15d35bd5f3d32629876e020000000043c1a3965448b3b46f0f0689f1368f3b2981208a368ec5c30defb35595ef9cf95ffd10e902000000036aac65253a5bbe042e907204000000000800006565656352634203b4020000000002656336b3b7010000000001ab7a063f0100000000026500a233cb76", "006551636a53ac5251", 1, -1144216171, "68c7bd717b399b1ee33a6562a916825a2fed3019cdf4920418bb72ffd7403c8c"}, + {"d5c1b16f0248c60a3ddccf7ebd1b3f260360bbdf2230577d1c236891a1993725e262e1b6cb000000000363636affffffff0a32362cfe68d25b243a015fc9aa172ea9c6b087c9e231474bb01824fd6bd8bc0300000005ab52ab516affffffff0420d9a70200000000045152656a45765d0000000000055252536a5277bad100000000000252ab3f3f3803000000000463acac5200000000", "52636a52ab65", 1, 1305123906, "978dc178ecd03d403b048213d904653979d11c51730381c96c4208e3ea24243a"}, + {"1be8ee5604a9937ebecffc832155d9ba7860d0ca451eaced58ca3688945a31d93420c27c460100000006abac5300535288b65458af2f17cbbf7c5fbcdcfb334ffd84c1510d5500dc7d25a43c36679b702e850f7c0200000003005300ffffffff7c237281cb859653eb5bb0a66dbb7aeb2ac11d99ba9ed0f12c766a8ae2a2157203000000086aabac526365acabfffffffff09d3d6639849f442a6a52ad10a5d0e4cb1f4a6b22a98a8f442f60280c9e5be80200000007ab00ab6565ab52ffffffff0398fe83030000000005526aababacbdd6ec010000000005535252ab6a82c1e6040000000001652b71c40c", "6563526353656351", 2, -853634888, "0d936cceda2f56c7bb87d90a7b508f6208577014ff280910a710580357df25f3"}, + {"9e0f99c504fbca858c209c6d9371ddd78985be1ab52845db0720af9ae5e2664d352f5037d4010000000552ac53636affffffff0e0ce866bc3f5b0a49748f597c18fa47a2483b8a94cef1d7295d9a5d36d31ae7030000000663515263ac635bb5d1698325164cdd3f7f3f7831635a3588f26d47cc30bf0fefd56cd87dc4e84f162ab702000000036a6365ffffffff85c2b1a61de4bcbd1d5332d5f59f338dd5e8accbc466fd860f96eef1f54c28ec030000000165ffffffff04f5cabd010000000007000052ac526563c18f1502000000000465510051dc9157050000000008655363ac525253ac506bb600000000000865656a53ab63006a00000000", "006a6a0052", 0, 1186324483, "2f9b7348600336512686e7271c53015d1cb096ab1a5e0bce49acd35bceb42bc8"}, + {"11ce51f90164b4b54b9278f0337d95c50d16f6828fcb641df9c7a041a2b274aa70b1250f2b0000000008ab6a6a65006551524c9fe7f604af44be050000000005525365006521f79a0300000000015306bb4e04000000000265ac99611a05000000000765acab656500006dc866d0", "", 0, -1710478768, "cfa4b7573559b3b199478880c8013fa713ca81ca8754a3fd68a6d7ee6147dc5a"}, + {"86bc233e02ba3c647e356558e7252481a7769491fb46e883dd547a4ce9898fc9a1ca1b77790000000006ab5351abab51f0c1d09c37696d5c7c257788f5dff5583f4700687bcb7d4acfb48521dc953659e325fa390300000003acac5280f29523027225af03000000000963abac0065ab65acab7e59d90400000000016549dac846", "53006aac52acac", 0, 711159875, "880330ccde00991503ea598a6dfd81135c6cda9d317820352781417f89134d85"}, + {"beac155d03a853bf18cd5c490bb2a245b3b2a501a3ce5967945b0bf388fec2ba9f04c03d68030000000012fe96283aec4d3aafed8f888b0f1534bd903f9cd1af86a7e64006a2fa0d2d30711af770010000000163ffffffffd963a19d19a292104b9021c535d3e302925543fb3b5ed39fb2124ee23a9db00302000000056500ac63acffffffff01ad67f503000000000300ac5189f78db2", "53536a636500", 2, 748992863, "bde3dd0575164d7ece3b5783ce0783ffddb7df98f178fe6468683230314f285a"}, + {"81dab34a039c9e225ba8ef421ec8e0e9d46b5172e892058a9ade579fe0eb239f7d9c97d45b0300000009ac65655351ab526363ffffffff10c0faaf7f597fc8b00bbc67c3fd4c6b70ca6b22718d15946bf6b032e62dae570000000005536a00ab6a02cddec3acf985bbe62c96fccf17012a87026ed63fc6756fa39e286eb4c2dd79b59d37400300000002516affffffff04f18b8d03000000000753abab5152636564411c02000000000400ab6300e965750300000000001bd2cf02000000000565ab526aab00000000", "006551ab", 0, -1488174485, "a3d65a8cd0c1eea8558d01396b929520a2221c29d9f25f29035b8abae874447f"}, + {"489ebbf10478e260ba88c0168bd7509a651b36aaee983e400c7063da39c93bf28100011f280100000004abab63ab2fc856f05f59b257a4445253e0d91b6dffe32302d520ac8e7f6f2467f7f6b4b65f2f59e903000000096353abacab6351656affffffff0122d9480db6c45a2c6fd68b7bc57246edffbf6330c39ccd36aa3aa45ec108fc030000000265ab9a7e78a69aadd6b030b12602dff0739bbc346b466c7c0129b34f50ae1f61e634e11e9f3d0000000006516a53525100ffffffff011271070000000000086563ab6353536352c4dd0e2c", "", 0, -293358504, "4eba3055bc2b58765593ec6e11775cea4b6493d8f785e28d01e2d5470ea71575"}, + {"6911195d04f449e8eade3bc49fd09b6fb4b7b7ec86529918b8593a9f6c34c2f2d301ec378b000000000263ab49162266af054643505b572c24ff6f8e4c920e601b23b3c42095881857d00caf56b28acd030000000565525200ac3ac4d24cb59ee8cfec0950312dcdcc14d1b360ab343e834004a5628d629642422f3c5acc02000000035100accf99b663e3c74787aba1272129a34130668a877cc6516bfb7574af9fa6d07f9b4197303400000000085351ab5152635252ffffffff042b3c95000000000000ff92330200000000046a5252ab884a2402000000000853530065520063000d78be03000000000953abab52ab53ac65aba72cb34b", "6a", 2, -637739405, "6b80d74eb0e7ee59d14f06f30ba7d72a48d3a8ff2d68d3b99e770dec23e9284f"}, + {"746347cf03faa548f4c0b9d2bd96504d2e780292730f690bf0475b188493fb67ca58dcca4f0000000002005336e3521bfb94c254058e852a32fc4cf50d99f9cc7215f7c632b251922104f638aa0b9d080100000008656aac5351635251ffffffff4da22a678bb5bb3ad1a29f97f6f7e5b5de11bb80bcf2f7bb96b67b9f1ac44d09030000000365ababffffffff036f02b30000000000076353ab6aac63ac50b72a050000000002acaba8abf804000000000663006a6a6353797eb999", "acac5100", 1, -1484493812, "164c32a263f357e385bd744619b91c3f9e3ce6c256d6a827d6defcbdff38fa75"}, + {"e17149010239dd33f847bf1f57896db60e955117d8cf013e7553fae6baa9acd3d0f1412ad90200000006516500516500cb7b32a8a67d58dddfb6ceb5897e75ef1c1ff812d8cd73875856487826dec4a4e2d2422a0100000004ac525365196dbb69039229270400000000070000535351636a8b7596020000000006ab51ac52655131e99d040000000003516551ee437f5c", "ac656a53", 1, 1102662601, "8858bb47a042243f369f27d9ab4a9cd6216adeac1c1ac413ed0890e46f23d3f3"}, + {"144971940223597a2d1dec49c7d4ec557e4f4bd207428618bafa3c96c411752d494249e1fb0100000004526a5151ffffffff340a545b1080d4f7e2225ff1c9831f283a7d4ca4d3d0a29d12e07d86d6826f7f0200000003006553ffffffff03c36965000000000000dfa9af00000000000451636aac7f7d140300000000016300000000", "", 1, -108117779, "c84fcaf9d779df736a26cc3cabd04d0e61150d4d5472dd5358d6626e610be57f"}, + {"b11b6752044e650b9c4744fb9c930819227d2ac4040d8c91a133080e090b042a142e93906e0000000003650053ffffffff6b9ce7e29550d3c1676b702e5e1537567354b002c8b7bb3d3535e63ad03b50ea01000000055100516300fffffffffcf7b252fea3ad5a108af3640a9bc2cd724a7a3ce22a760fba95496e88e2f2e801000000036a00ac7c58df5efba193d33d9549547f6ca839f93e14fa0e111f780c28c60cc938f785b363941b000000000863ab51516552ac5265e51fcd0308e9830400000000036a00abab72190300000000016a63d0710000000000050051ab6a6300000000", "53005165ac51ab65", 0, 229563932, "e562579d1a2b10d1c5e45c06513456002a6bec157d7eb42511d30b118103c052"}, + {"2aee6b9a02172a8288e02fac654520c9dd9ab93cf514d73163701f4788b4caeeb9297d2e250300000004ab6363008fb36695528d7482710ea2926412f877a3b20acae31e9d3091406bfa6b62ebf9d9d2a6470100000009535165536a63520065ffffffff03f7b560050000000003acab6a9a8338050000000000206ce90000000000056552516a5100000000", "5252", 1, -1102319963, "fa4676c374ae3a417124b4c970d1ed3319dc3ac91fb36efca1aa9ed981a8aa1b"}, + {"9554595203ad5d687f34474685425c1919e3d2cd05cf2dac89d5f33cd3963e5bb43f8706480100000000ffffffff9de2539c2fe3000d59afbd376cb46cefa8bd01dbc43938ff6089b63d68acdc2b02000000096553655251536a6500fffffffff9695e4016cd4dfeb5f7dadf00968e6a409ef048f81922cec231efed4ac78f5d010000000763abab6a5365006caaf0070162cc640200000000045163ab5100000000", "", 0, -1105256289, "e8e10ed162b1a43bfd23bd06b74a6c2f138b8dc1ab094ffb2fa11d5b22869bee"}, + {"04f51f2a0484cba53d63de1cb0efdcb222999cdf2dd9d19b3542a896ca96e23a643dfc45f00200000007acac53510063002b091fd0bfc0cfb386edf7b9e694f1927d7a3cf4e1d2ce937c1e01610313729ef6419ae7030000000165a3372a913c59b8b3da458335dc1714805c0db98992fd0d93f16a7f28c55dc747fe66a5b503000000095351ab65ab52536351ffffffff5650b318b3e236802a4e41ed9bc0a19c32b7aa3f9b2cda1178f84499963a0cde000000000165ffffffff0383954f04000000000553ac536363a8fc90030000000000a2e315000000000005acab00ab5100000000", "0053", 2, -1424653648, "a5bc0356f56b2b41a2314ec05bee7b91ef57f1074bcd2efc4da442222269d1a3"}, + {"5e4fab42024a27f0544fe11abc781f46596f75086730be9d16ce948b04cc36f86db7ad50fd01000000026a00613330f4916285b5305cc2d3de6f0293946aa6362fc087727e5203e558c676b314ef8dd401000000001af590d202ba496f040000000001009e3c9604000000000351ac51943d64d3", "51acabab5100ab52", 1, -129301207, "556c3f90aa81f9b4df5b92a23399fe6432cf8fecf7bba66fd8fdb0246440036c"}, + {"a115284704b88b45a5f060af429a3a8eab10b26b7c15ed421258f5320fa22f4882817d6c2b0300000003005300ffffffff4162f4d738e973e5d26991452769b2e1be4b2b5b7e8cbeab79b9cf9df2882c040000000006636aac63ac5194abc8aa22f8ddc8a7ab102a58e39671683d1891799d19bd1308d24ea6d365e571172f1e030000000700515352515153ffffffff4da7ad75ce6d8541acbb0226e9818a1784e9c97c54b7d1ff82f791df1c6578f60000000000ffffffff01b1f265040000000009ab0051ac656a516a5300000000", "51abab6352535265", 0, -1269106800, "0ef7b6e87c782fa33fe109aab157a2d9cddc4472864f629510a1c92fa1fe7fc1"}, + {"f3f771ae02939752bfe309d6c652c0d271b7cab14107e98032f269d92b2a8c8853ab057da8010000000563ab6a6365670c305c38f458e30a7c0ab45ee9abd9a8dc03bae1860f965ffced879cb2e5d0bb156821020000000153ffffffff025dc619050000000002ac51ec0d250100000000076a5200636a6363333aecd8", "650053ac515100ab", 1, 1812404608, "a7aa34bf8a5644f03c6dd8801f9b15ba2e07e07256dbf1e02dad59f0d3e17ea9"}, + {"fd3e267203ae7d6d3975e738ca84f12540229bb237dd228d5f688e9d5ba53fce4302b0334d01000000026353ffffffff602a3ab75af7aa951d93093e345ef0037a2863f3f580a9b1a575fffe68e677450300000000239e476d1e8f81e8b6313880d8a49b27c1b00af467f29756e76f675f084a5676539636ab030000000765ab6351acac52d9217747044d773204000000000752ac51526353acc33e45050000000005516500005115d889040000000004ab5163510cbbbd0200000000016500000000", "65ac526aac6a53ab52", 2, -886179388, "bc46f3f83058ddf5bebd9e1f2c117a673847c4dc5e31cfb24bac91adf30877cf"}, + {"f380ae23033646af5dfc186f6599098015139e961919aea28502ea2d69474413d94a555ea2000000000853635265abacac5314da394b99b07733341ddba9e86022637be3b76492992fb0f58f23c915098979250a96620300000003ab6300ffffffff4bb6d1c0a0d84eac7f770d3ad0fdc5369ae42a21bbe4c06e0b5060d5990776220300000000ffffffff0486fd70020000000007ac6500635252acf3fd72010000000005656a6a6551212de90500000000096365006a63635153000fa33100000000000600535151656300000000", "ab52", 2, -740890152, "f804fc4d81f039009ed1f2cccb5c91da797543f235ac71b214c20e763a6d86d7"}, + {"5c45d09801bb4d8e7679d857b86b97697472d514f8b76d862460e7421e8617b15a2df217c6010000000863acacab6565006affffffff01156dbc03000000000952ac63516551ac6aac00000000", "6aabac", 0, 1310125891, "270445ab77258ced2e5e22a6d0d8c36ac7c30fff9beefa4b3e981867b03fa0ad"}, + {"4ecc6bde030ca0f83c0ed3d4b777f94c0c88708c6c933fe1df6874f296d425cac95355c23d0000000006ac6a51536a52f286a0969d6170e20f2a8000193807f5bc556770e9d82341ef8e17b0035eace89c76edd50200000007ac65525100656affffffff5bade6e462fac1927f078d69d3a981f5b4c1e59311a38efcb9a910aa436afaa80000000007ac6a006352ab52ffffffff0331e58902000000000763ac53636352abb8b3ca000000000001637a1d26040000000009535263ac6a5352ab655ae34a39", "6a65ab", 2, 2142728517, "4a3415eb1677ae4e0c939644a4cfd5dc6299780b55cd0dc735967057b6b1526a"}, + {"a59484b501eb50114be0fc79e72ab9bc9f4a5f7acdf274a56d6b68684eb68cf8b07ec5d1c2000000000765abab00ab00639e09aa940141e3530200000000046500ac6500000000", "00516565ab", 0, -1561622405, "d60bbadd2cc0674100baa08d0e0493ee4248f0304b3eb778da942041f503a896"}, + {"53dc1a88046531c7b57a35f4d9adf101d068bf8d63fbbedaf4741dba8bc5e92c8725def571030000000453655251fcdf116a226b3ec240739c4c7493800e4edfe67275234e371a227721eac43d3d9ecaf1b50300000003ac0052ffffffff2c9279ffeea4718d167e9499bd067600715c14484e373ef93ae4a31d2f5671ab0000000009516553ac636a6a65001977752eeba95a8f16b88c571a459c2f2a204e23d48cc7090e4f4cc35846ca7fc0a455ce00000000055165ac0063188143f80205972902000000000765ac63ac516353c7b6a50000000000036a510000000000", "655351536a", 0, 103806788, "b276584d3514e5b4e058167c41dc02915b9d97f6795936a51f40e894ed8508bc"}, + {"53f8959f01ddb36afdcd20167edcbb75a63d18654fdcf10bc0004c761ab450fe236d79cb2702000000065151650063653435003a033a5e34050000000009ac52516a630000516ab86db3030000000002006344ac090500000000046363ab00f3644537", "5263abab63ac656353", 0, -218513553, "f1f2a489682e42a6fc20025dfc89584d17f150b2d7ae3ddedd2bf43d5e24f37f"}, + {"5a06cb4602dcfc85f49b8d14513f33c48f67146f2ee44959bbca092788e6823b2719f3160b0200000001ab3c013f2518035b9ea635f9a1c74ec1a3fb7496a160f46aae2e09bfc5cd5111a0f20969e003000000015158c89ab7049f20d6010000000008ac6a52abac53515349765e00000000000300ab638292630100000000045351ab0086da09010000000006656a6365525300000000", "526a63", 1, 1502936586, "bdfaff8a4e775379c5dc26e024968efa805f923de53fa8272dd53ec582afa0c5"}, + {"ca9d84fa0129011e1bf27d7cb71819650b59fb292b053d625c6f02b0339249b498ff7fd4b601000000025352ffffffff032173a0040000000008525253abab5152639473bb030000000009005153526a53535151d085bd0000000000086a5365ab5165655300000000", "005152ac51", 0, 580353445, "c629d93b02037f40aa110e46d903edb34107f64806aa0c418d435926feef68b8"}, + {"e3cdbfb4014d90ae6a4401e85f7ac717adc2c035858bf6ff48979dd399d155bce1f150daea0300000002ac51a67a0d39017f6c71040000000005535200535200000000", "", 0, -1899950911, "c1c7df8206e661d593f6455db1d61a364a249407f88e99ecad05346e495b38d7"}, + {"b2b6b9ab0283d9d73eeae3d847f41439cd88279c166aa805e44f8243adeb3b09e584efb1df00000000026300ffffffff7dfe653bd67ca094f8dab51007c6adaced09de2af745e175b9714ca1f5c68d050000000003ac6500aa8e596903fd3f3204000000000553ac6a6a533a2e210500000000075253acabab526392d0ee020000000008520065635200ab5200000000", "65acacac65005365", 0, 28298553, "39c2aaa2496212b3ab120ab7d7f37c5e852bfe38d20f5226413a2268663eeae8"}, + {"f30c5c3d01a6edb9e10fafaf7e85db14e7fec558b9dca4a80b05d7c3a2944d282c5018f4680200000003005263ffffffff04aac3530300000000026551bc2419010000000009005163acab6a5100658e7085050000000000c5e4ec050000000007656a6a635365ab2d8e8882", "abac53ab005251ac52", 0, -490287546, "877e347ec7487497769e2581142276d1a8d813b652e4483cf9cc993d16354417"}, + {"4314339e01de40faabcb1b970245a7f19eedbc17c507dac86cf986c2973715035cf95736ae0200000007abababababab65bde67b900151510b04000000000853ac00655200535300000000", "52", 0, 399070095, "47585dc25469d04ff3a60939d0a03779e3e81a411bf0ca18b91bb925ebd30718"}, + {"2d4cf4e9031b3e175b2ff18cd933151379d9cfac4713d8bd0e63b70bd4a92277aa7af901ab000000000565515353abffffffff557666c7f3be9cdecdad44c3df206eb63a2da4ed1f159d21193882a9f0340081020000000963ab53ab5252ac63abffffffff8a8c897bdb87e93886aad5ded9d82a13101d5476554386373646ca5e23612e450300000009006a526552abab6a635ac03fc00198bb02040000000009525100526a6563636a1d052834", "ab52ac00acac6a", 0, -1469882480, "09ed6563a454814ab7e3b4c28d56d8751162b77df1825b37ba66c6147750b2a3"}, + {"f063171b03e1830fdc1d685a30a377537363ccafdc68b42bf2e3acb908dac61ee24b37595c020000000765ac5100ab6aacf447bc8e037b89d6cadd62d960cc442d5ced901d188867b5122b42a862929ce45e7b628d010000000253aba009a1ba42b00f1490b0b857052820976c675f335491cda838fb7934d5eea0257684a2a202000000001e83cf2401a7f777030000000008ab6553526a53526a00000000", "", 2, 1984790332, "c19caada8e71535e29a86fa29cfd9b74a0c7412003fc722a121005e461e01636"}, + {"cf7bdc250249e22cbe23baf6b648328d31773ea0e771b3b76a48b4748d7fbd390e88a004d30000000003ac536a4ab8cce0e097136c90b2037f231b7fde2063017facd40ed4e5896da7ad00e9c71dd70ae600000000096a0063516352525365ffffffff01b71e3e00000000000300536a00000000", "", 1, 546970113, "6a815ba155270af102322c882f26d22da11c5330a751f520807936b320b9af5d"}, + {"ac7a125a0269d35f5dbdab9948c48674616e7507413cd10e1acebeaf85b369cd8c88301b7c030000000963656aac6a530053abffffffffed94c39a582e1a46ce4c6bffda2ccdb16cda485f3a0d94b06206066da12aecfe010000000752abab63536363ef71dcfb02ee07fa0400000000016a6908c802000000000751656a6551abac688c2c2d", "6a6351526551", 0, 858400684, "552ff97d7924f51cda6d1b94be53483153ef725cc0a3a107adbef220c753f9a6"}, + {"3a1f454a03a4591e46cf1f7605a3a130b631bf4dfd81bd2443dc4fac1e0a224e74112884fe0000000005516aac6a53a87e78b55548601ffc941f91d75eab263aa79cd498c88c37fdf275a64feff89fc1710efe03000000016a39d7ef6f2a52c00378b4f8f8301853b61c54792c0f1c4e2cd18a08cb97a7668caa008d970200000002656affffffff017642b20100000000096a63535253abac6a6528271998", "51", 2, 1459585400, "e9a7f21fc2d38be7be47095fbc8f1bf8923660aa4d71df6d797ae0ba5ca4d5b0"}, + {"f59366cc0114c2a18e6bd1347ed9470f2522284e9e835dd5c5f7ef243639ebea95d9b232b6020000000153474b62eb045c00170500000000096352ab516352ab5200038a520400000000086aab5253656a63005b968904000000000963536353ac0053635387106002000000000000000000", "ab52526300ab51", 0, 1834116153, "cdf51f6e3a9dc2be5a59ea4c00f5aac1e1426a5202c325e6cf2567d07d8d8de4"}, + {"6269e0fa0173e76e89657ca495913f1b86af5b8f1c1586bcd6c960aede9bc759718dfd5044000000000352ac530e2c7bd90219849b000000000007ab00ab6a53006319f281000000000007ab00515165ac5200000000", "6a", 0, -2039568300, "62094f98234a05bf1b9c7078c5275ed085656856fb5bdfd1b48090e86b53dd85"}, + {"eb2bc00604815b9ced1c604960d54beea4a3a74b5c0035d4a8b6bfec5d0c9108f143c0e99a0000000000ffffffff22645b6e8da5f11d90e5130fd0a0df8cf79829b2647957471d881c2372c527d8010000000263acffffffff1179dbaf17404109f706ae27ad7ba61e860346f63f0c81cb235d2b05d14f2c1003000000025300264cb23aaffdc4d6fa8ec0bb94eff3a2e50a83418a8e9473a16aaa4ef8b855625ed77ef40100000003ac51acf8414ad404dd328901000000000652526500006ab6261c000000000002526a72a4c9020000000006ac526500656586d2e7000000000006656aac00ac5279cd8908", "51", 1, -399279379, "d37532e7b2b8e7db5c7c534197600397ebcc15a750e3af07a3e2d2e4f84b024f"}, + {"dc9fe6a8038b84209bbdae5d848e8c040433237f415437592907aa798bf30d9dbbddf0ff85010000000153ffffffff23269a7ea29fcf788db483b8d4c4b35669e582608644259e950ce152b0fa6e050000000003acababffffffff65de94857897ae9ea3aa0b938ba6e5adf374d48469922d2b36dbb83d3b8c8261010000000452ac5200ffffffff02856e9b0300000000026a51980c8e02000000000365ab63d2648db4", "00ab0051ac526565", 2, 1562581941, "5cef9d8e18a2d5a70448f17b465d411a19dab78f0ddf1672ffd518b188f52433"}, + {"eba8b0de04ac276293c272d0d3636e81400b1aaa60db5f11561480592f99e6f6fa13ad387002000000070053acab536563bebb23d66fd17d98271b182019864a90e60a54f5a615e40b643a54f8408fa8512cfac927030000000963ac6a6aabac65ababffffffff890a72192bc01255058314f376bab1dc72b5fea104c154a15d6faee75dfa5dba020000000100592b3559b0085387ac7575c05b29b1f35d9a2c26a0c27903cc0f43e7e6e37d5a60d8305a030000000252abffffffff0126518f05000000000000000000", "005300635252635351", 1, 664344756, "26dc2cba4bd5334e5c0b3a520b44cc1640c6b923d10e576062f1197171724097"}, + {"91bd040802c92f6fe97411b159df2cd60fb9571764b001f31657f2d616964637605875c2a901000000055263006a65ffffffff3651df372645f50cf4e32fdf6e61c766e912e16335db2b40c5d52fe89eefe7cd00000000040065ab65ffffffff03ca8625030000000009ab51ac63530052ab52c6bf14020000000006ab00ab52005167d270000000000007ab53525351636a00000000", "5151ab63005252ac", 1, 1983087664, "3e5aa0200248d8d86ede3b315ca1b857018b89184a4bd023bd88ab12e499f6e1"}, + {"185cda1a01ecf7a8a8c28466725b60431545fc7a3367ab68e34d486e8ea85ee3128e0d8384000000000465ac63abec88b7bb031c56eb04000000000965636a51005252006a7c78d5040000000007acac63abac51ac3024a40500000000086300526a51abac51464c0e8c", "0065535265515352", 0, 1594558917, "b5280b9610c0625a65b36a8c2402a95019a7bbb9dd3de77f7c3cb1d82c3263ba"}, + {"a9531f07034091668b65fea8b1a79700d586ac9e2f42ca0455a26abe41f9e1805d009a0f5702000000096365516365ac5263ab3619bac643a9e28ee47855118cf80c3a74531cdf198835d206d0fe41804e325a4f9f105e03000000016a58e3ab0d46375d98994daf0fa7c600d2bb4669e726fca0e3a3f21ea0d9e777396740328f0100000008636a5363ab526a538d3ea7700304cb66030000000007515163ab52ab510184030500000000085353636565ac0051d9cff402000000000751ab52ab5352abf0e36254", "ab5353ac5365acab", 2, 1633101834, "04c9ef72f33668ca449c0415becf62cc0b8e0c75f9c8813852d42a58acf107c8"}, + {"6b5ecc7903fe0ba37ea551df92a59e12bad0a3065846ba69179a8f4a741a2b4fcf679aac810200000004535263529a3d343293b99ab425e7ef8529549d84f480bcd92472bab972ea380a302128ae14dfcd0200000000025163ffffffff24636e4545cab9bf87009119b7fc3ec4d5ee9e206b90f35d1df8a563b6cd097a010000000852abac53005153abc64467860406e832020000000009526300006a53ac6352ac1395010000000002ac53b117f300000000000863655351acab00651edf02030000000008ab51ac6353535252628ef71d", "ab63ab6a52ac526563", 2, -1559697626, "8f07ece7d65e509f1e0780584ef8d271c1c61a13b10335d5faafc7afc8b5b8ec"}, + {"92c9fb780138abc472e589d5b59489303f234acc838ca66ffcdf0164517a8679bb622a4267020000000153468e373d04de03fa020000000009ac006a5265ab5163006af649050000000007515153006a00658ceb59030000000001ac36afa0020000000009ab53006351ab51000000000000", "6a", 0, 2059357502, "e2358dfb51831ee81d7b0bc602a65287d6cd2dbfacf55106e2bf597e22a4b573"}, + {"6f62138301436f33a00b84a26a0457ccbfc0f82403288b9cbae39986b34357cb2ff9b889b302000000045253655335a7ff6701bac9960400000000086552ab656352635200000000", "6aac51", 0, 1444414211, "502a2435fd02898d2ff3ab08a3c19078414b32ec9b73d64a944834efc9dae10c"}, + {"9981143a040a88c2484ac3abe053849e72d04862120f424f373753161997dd40505dcb4783030000000700536365536565a2e10da3f4b1c1ad049d97b33f0ae0ea48c5d7c30cc8810e144ad93be97789706a5ead180100000003636a00ffffffffbdcbac84c4bcc87f03d0ad83fbe13b369d7e42ddb3aecf40870a37e814ad8bb5010000000963536a5100636a53abffffffff883609905a80e34202101544f69b58a0b4576fb7391e12a769f890eef90ffb72020000000651656352526affffffff04243660000000000004ab5352534a9ce001000000000863656363ab6a53652df19d030000000003ac65acedc51700000000000000000000", "ac6300acac", 2, 293672388, "7ba99b289c04718a7283f150d831175ed6303081e191a0608ea81f78926c5bdf"}, + {"a2bb630b01989bc5d643f2da4fb9b55c0cdf846ba06d1dbe372893024dbbe5b9b8a1900af802000000055265ac63aca7a68d2f04916c74010000000003abac007077f0040000000001007d4127010000000005ac516aac000f31e8030000000000571079c9", "65ab0051ac", 0, -1103627693, "92d53b4390262e6b288e8a32e0cfc36cd5adfdfabfe96c7bfd4a19d65e233761"}, + {"49f7d0b6037bba276e910ad3cd74966c7b3bc197ffbcfefd6108d6587006947e97789835ea0300000008526a52006a650053ffffffff8d7b6c07cd10f4c4010eac7946f61aff7fb5f3920bdf3467e939e58a1d4100ab03000000076aac63ac535351ffffffff8f48c3ba2d52ad67fbcdc90d8778f3c8a3894e3c35b9730562d7176b81af23c80100000003ab5265ffffffff0301e3ef0300000000046a525353e899ac0500000000075153ab6a65abac259bea0400000000007b739972", "53516aacac6aac", 1, 955403557, "5d366a7f4346ae18aeb7c9fc4dab5af71173184aa20ed22fcb4ea8511ad25449"}, + {"58a4fed801fbd8d92db9dfcb2e26b6ff10b120204243fee954d7dcb3b4b9b53380e7bb8fb60100000003006351ffffffff02a0795b050000000006536351ac6aac2718d00200000000075151acabac515354d21ba1", "005363515351", 0, -1322430665, "bbee941bbad950424bf40e3623457db47f60ed29deaa43c99dec702317cb3326"}, + {"32765a0b02e455793d9ce530e9f6a44bcbc612e893a875b5da61d822dc56d8245166c398b403000000085353abac6300006a6bdee2a78d0d0b6a5ea666eed70b9bfea99d1d612ba3878f615c4da10d4a521cba27155002000000035363abffffffff043cd42401000000000551656a53653685320100000000030000511881bc0500000000065165abab636a20169f010000000007acab656aac63acdb0706a8", "65ac53ab53", 0, 1936499176, "5c5a9c3a5de7dc7a82bc171c9d3505913b8bcc450bc8b2d11772c1a1d781210b"}, + {"17fad0d303da0d764fedf9f2887a91ea625331b28704940f41e39adf3903d8e75683ef6d46020000000151ffffffffff376eea4e880bcf0f03d33999104aafed2b3daf4907950bb06496af6b51720a020000000900636a63525253525196521684f3b08497bad2c660b00b43a6a517edc58217876eb5e478aa3b5fda0f29ee1bea00000000046aacab6affffffff03dde8e2050000000007ac5365ac51516a14772e000000000005630000abacbbb360010000000006ab5251ab656a50f180f0", "0053", 0, -1043701251, "a3bdf8771c8990971bff9b4e7d59b7829b067ed0b8d3ac1ec203429811384668"}, + {"236c32850300045e292c84ede2b9ab5733ba08315a2bb09ab234c4b4e8894808edbdac0d3b020000000653635363abacffffffffd3f696bb31fdd18a72f3fc2bb9ae54b416a253fc37c1a0f0180b52d35bad49440100000004650053abffffffffa85c75a2406d82a93b12e555b66641c1896a4e83ae41ef1038218311e38ace060200000006abab006a51ac104b5e6701e2842c04000000000800630051ac0000ab00000000", "ab63ac6a516a", 1, -1709887524, "8c29ea8ef60c5a927fccdba8ea385db6b6b84d98e891db45f5d4ee3148d3f5a7"}, + {"b78d5fd601345f3100af494cdf447e7d4076179f940035b0ebe8962587d4d0c9c6c9fc34ee0300000003516a6affffffff03dc5c890100000000085353ac53ac6a52534ac941040000000007ac63656a51ab51d4266b0100000000036aacac70731f2d", "005351ab0053", 0, -1789071265, "d5f1c1cb35956a5711d67bfb4cedbc67e77c089b912d688ad440ff735adb390d"}, + {"5a2257df03554550b774e677f348939b37f8e765a212e566ce6b60b4ea8fed4c9504b7f7d1000000000653655265ab5258b67bb931df15b041177cf9599b0604160b79e30f3d7a594e7826bae2c29700f6d8f8f40300000005515300ac6a159cf8808a41f504eb5c2e0e8a9279f3801a5b5d7bc6a70515fbf1c5edc875bb4c9ffac500000000050063510052ffffffff0422a90105000000000965006a650000516a006417d2020000000006526363ab00524d969d0100000000035153acc4f077040000000005ac5200636500000000", "6a52", 1, -1482463464, "37b794b05d0687c9b93d5917ab068f6b2f0e38406ff04e7154d104fc1fb14cdc"}, + {"e0032ad601269154b3fa72d3888a3151da0aed32fb2e1a15b3ae7bee57c3ddcffff76a1321010000000100110d93ae03f5bd080100000000075263516a6551002871e60100000000046a005252eaa753040000000004ab6aab526e325c71", "630052", 0, -1857873018, "ea117348e94de86381bb8ad1c7f93b8c623f0272104341701bb54e6cb433596c"}, + {"014b2a5304d46764817aca180dca50f5ab25f2e0d5749f21bb74a2f8bf6b8b7b3fa8189cb7030000000965ac5165ab6a51ac6360ecd91e8abc7e700a4c36c1a708a494c94bb20cbe695c408543146566ab22be43beae9103000000045163ab00ffffffffffa48066012829629a9ec06ccd4905a05df0e2b745b966f6a269c9c8e13451fc00000000026565ffffffffc40ccadc21e65fe8a4b1e072f4994738ccaf4881ae6fede2a2844d7da4d199ab02000000065152ab536aabffffffff01b6e054030000000004515352ab3e063432", "", 0, 1056459916, "a7aff48f3b8aeb7a4bfe2e6017c80a84168487a69b69e46681e0d0d8e63a84b6"}, + {"c4ef04c103c5dde65410fced19bf6a569549ecf01ceb0db4867db11f2a3a3eef0320c9e8e001000000085100536a53516aabffffffff2a0354fa5bd96f1e28835ffe30f52e19bd7d5150c687d255021a6bec03cf4cfd03000000056a006300514900c5b01d3d4ae1b97370ff1155b9dd0510e198d266c356d6168109c54c11b4c283dca00300000002ababffffffff02e19e3003000000000451655351fa5c0003000000000163ef1fc64b", "51636a51ab630065", 1, -1754709177, "0a281172d306b6a32e166e6fb2a2cc52c505c5d60ea448e9ba7029aa0a2211e1"}, + {"29083fe00398bd2bb76ceb178f22c51b49b5c029336a51357442ed1bac35b67e1ae6fdf13100000000066a6500acab51ffffffffe4ca45c9dc84fd2c9c47c7281575c2ba4bf33b0b45c7eca8a2a483f9e3ebe4b3010000000200abffffffffdf47ad2b8c263fafb1e3908158b18146357c3a6e0832f718cd464518a219d18303000000096352ac656351ac0052daddfb3b0231c36f00000000000400526a5275c7e0020000000001ab00000000", "acab536aac52", 2, 300802386, "82ebc07b16cff0077e9c1a279373185b3494e39d08fd3194aae6a4a019377509"}, + {"1201ab5d04f89f07c0077abd009762e59db4bb0d86048383ba9e1dad2c9c2ad96ef660e6d00200000007ab6a65ac5200652466fa5143ab13d55886b6cdc3d0f226f47ec1c3020c1c6e32602cd3428aceab544ef43e00000000086a6a6a526a6a5263ffffffffd5be0b0be13ab75001243749c839d779716f46687e2e9978bd6c9e2fe457ee48020000000365abab1e1bac0f72005cf638f71a3df2e3bbc0fa35bf00f32d9c7dc9c39a5e8909f7d53170c8ae0200000008ab6a51516363516affffffff02f0a6210500000000036300ac867356010000000009acab65ac6353536a659356d367", "ac53535252", 0, 917543338, "418acc156c2bc76a5d7baa58db29f1b4cf6c266c9222ed167ef5b4d47f0e0f41"}, + {"344fa11e01c19c4dd232c77742f0dd0aeb3695f18f76da627628741d0ee362b0ea1fb3a2180200000007635151005100529bab25af01937c1f0500000000055153ab53656e7630af", "6351005163ac51", 0, -629732125, "228ca52a0a376fe0527a61cfa8da6d7baf87486bba92d49dfd3899cac8a1034f"}, + {"b2fda1950191358a2b855f5626a0ebc830ab625bea7480f09f9cd3b388102e35c0f303124c030000000565ac65ab53ffffffff03f9c5ec04000000000765ab51516551650e2b9f0500000000045365525284e8f6040000000001ac00000000", "ac51655253", 0, 1433027632, "d2fa7e13c34cecda5105156bd2424c9b84ee0a07162642b0706f83243ff811a8"}, + {"a4a6bbd201aa5d882957ac94f2c74d4747ae32d69fdc765add4acc2b68abd1bdb8ee333d6e0300000008516a6552515152abffffffff02c353cb040000000007ac6351ab51536588bd320500000000066552525253ac00000000", "", 0, 1702060459, "499da7d74032388f820645191ac3c8d20f9dba8e8ded7fa3a5401ea2942392a1"}, + {"584e8d6c035a6b2f9dac2791b980a485994bf38e876d9dda9b77ad156eee02fa39e19224a60300000003ab636529db326cc8686a339b79ab6b6e82794a18e0aabc19d9ad13f31dee9d7aad8eff38288588020000000452530052ffffffff09a41f07755c16cea1c7e193c765807d18cadddca6ec1c2ed7f5dcdca99e90e80000000001acffffffff01cba62305000000000451ac63acccdf1f67", "ab536a6363", 2, -27393461, "1125645b49202dca2df2d76dae51877387903a096a9d3f66b5ac80e042c95788"}, + {"83a583d204d926f2ee587a83dd526cf1e25a44bb668e45370798f91a2907d184f7cddcbbc7030000000700ab6565536a539f71d3776300dffdfa0cdd1c3784c9a1f773e34041ca400193612341a9c42df64e3f550e01000000050052515251ffffffff52dab2034ab0648553a1bb8fc4e924b2c89ed97c18dfc8a63e248b454035564b01000000015139ab54708c7d4d2c2886290f08a5221cf69592a810fd1979d7b63d35c271961e710424fd0300000005ac65ac5251ffffffff01168f7c030000000000a85e5fb0", "6a536353656a00", 0, 179595345, "5350a31ac954a0b49931239d0ecafbf34d035a537fd0c545816b8fdc355e9961"}, + {"ffd35d51042f290108fcb6ea49a560ba0a6560f9181da7453a55dfdbdfe672dc800b39e7320200000006630065516a65f2166db2e3827f44457e86dddfd27a8af3a19074e216348daa0204717d61825f198ec0030100000006ab51abab00abffffffffdf41807adb7dff7db9f14d95fd6dc4e65f8402c002d009a3f1ddedf6f4895fc8030000000500ab006a65a5a848345052f860620abd5fcd074195548ce3bd0839fa9ad8642ed80627bf43a0d47dbd010000000765ab006a656a53b38cdd6502a186da05000000000765ab00ab006a53527c0e0100000000085365ab51acacac52534bd1b1", "6a635253ac0000", 0, 1095082149, "3c05473a816621a3613f0e903faa1a1e44891dd40862b029e41fc520776350fa"}, + {"6c9a4b98013c8f1cae1b1df9f0f2de518d0c50206a0ab871603ac682155504c0e0ce946f460100000000ffffffff04e9266305000000000753535100ac6aacded39e04000000000365ac6ab93ccd010000000002515397bf3d050000000003ab636300000000", "63520052ac656353", 0, -352633155, "936eff8cdfd771be24124da87c7b24feb48da7cbc2c25fb5ba13d1a23255d902"}, + {"e01dc7f0021dc07928906b2946ca3e9ac95f14ad4026887101e2d722c26982c27dc2b59fdb0000000005ac5200516ab5a31ffadcbe74957a5a3f97d7f1475cc6423fc6dbc4f96471bd44c70cc736e7dec0d1ea020000000951636a526a52abac53ffffffff04bc2edd05000000000252ab528c7b02000000000952ac51526500525353324820040000000002005380c713000000000009630065ab00ac525252451bbb48", "53ab65ac", 0, -552384418, "69c0b30f4c630a6c878fde6ea6b74dae94f4eb3bcfbde2dc3649e1a9ada00757"}, + {"009046a1023f266d0113556d604931374d7932b4d6a7952d08fbd9c9b87cbd83f4f4c178b4030000000452ac526346e73b438c4516c60edd5488023131f07acb5f9ea1540b3e84de92f4e3c432289781ea4900000000046500655357dfd6da02baef910100000000026a007d101703000000000800516500abacac5100000000", "6aab6553ac", 0, -802456605, "f8757fbb4448ca34e0cd41b997685b37238d331e70316659a9cc9087d116169d"}, + {"df76ec0801a3fcf3d18862c5f686b878266dd5083f16cf655facab888b4cb3123b3ce5db7e01000000010010e7ac6a0233c83803000000000365ac51faf14a040000000004ac51655100000000", "6353acab", 0, 15705861, "e7d873aa079a19ec712b269a37d2670f60d8cb334c4f97e2e3fd10eeb8ee5f5e"}, + {"828fd3e0031084051ccef9cfdd97fae4d9cc50c0dae36bd22a3ff332881f17e9756c3e288e0200000004ab535363961a2ccccaf0218ec6a16ba0c1d8b5e93cfd025c95b6e72bc629ec0a3f47da7a4c396dad01000000025353ffffffff19ad28747fb32b4caf7b5dbd9b2da5a264bedb6c86d3a4805cd294ae53a86ac40200000009ab53535351ab6551abffffffff04a41650030000000005656aab6aab8331a304000000000700516365ac516a0d2a47010000000007abac516353abacdebc19040000000006ab5300636a6300000000", "51ab52ab53ac52", 0, 1866105980, "311094b4d73e31aefc77e97859ef07ca2f07a7b7e4d7def80c69d3f5d58527e5"}, + {"c4b80f850323022205b3e1582f1ed097911a81be593471a8dce93d5c3a7bded92ef6c7c1260100000002006affffffff70294d62f37c3da7c5eae5d67dce6e1b28fedd7316d03f4f48e1829f78a88ae801000000096a5200530000516351f6b7b544f7c39189d3a2106ca58ce4130605328ce7795204be592a90acd81bef517d6f170200000000ffffffff012ab8080000000000075100006365006335454c1e", "53ac6a536aacac", 0, -1124103895, "06277201504e6bf8b8c94136fad81b6e3dadacb9d4a2c21a8e10017bfa929e0e"}, + {"8ab69ed50351b47b6e04ac05e12320984a63801716739ed7a940b3429c9c9fed44d3398ad40300000006536a516a52638171ef3a46a2adb8025a4884b453889bc457d63499971307a7e834b0e76eec69c943038a0300000000ffffffff566bb96f94904ed8d43d9d44a4a6301073cef2c011bf5a12a89bedbaa03e4724030000000265acb606affd01edea38050000000008515252516aacac6300000000", "65000000006365ac53", 0, -1338942849, "7912573937824058103cb921a59a7f910a854bf2682f4116a393a2045045a8c3"}, + {"2484991e047f1cf3cfe38eab071f915fe86ebd45d111463b315217bf9481daf0e0d10902a402000000006e71a424eb1347ffa638363604c0d5eccbc90447ff371e000bf52fc743ec832851bb564a0100000001abffffffffef7d014fad3ae7927948edbbb3afe247c1bcbe7c4c8f5d6cf97c799696412612020000000851536a5353006a001dfee0d7a0dd46ada63b925709e141863f7338f34f7aebde85d39268ae21b77c3068c01d0000000008535151ab00636563ffffffff018478070200000000095200635365ac52ab5341b08cd3", "", 3, 265623923, "24cb420a53b4f8bb477f7cbb293caabfd2fc47cc400ce37dbbab07f92d3a9575"}, + {"54839ef9026f65db30fc9cfcb71f5f84d7bb3c48731ab9d63351a1b3c7bc1e7da22bbd508e0300000000442ad138f170e446d427d1f64040016032f36d8325c3b2f7a4078766bdd8fb106e52e8d20000000003656500ffffffff02219aa101000000000851ababac52ab00659646bd02000000000552acacabac24c394a5", "ac", 0, 906807497, "69264faadcd1a581f7000570a239a0a26b82f2ad40374c5b9c1f58730514de96"}, + {"5036d7080434eb4eef93efda86b9131b0b4c6a0c421e1e5feb099a28ff9dd8477728639f77030000000951516aab535152ab5391429be9cce85d9f3d358c5605cf8c3666f034af42740e94d495e28b9aaa1001ba0c87580300000008006552ab00ab006affffffffd838978e10c0c78f1cd0a0830d6815f38cdcc631408649c32a25170099669daa0000000002acab8984227e804ad268b5b367285edcdf102d382d027789250a2c0641892b480c21bf84e3fb0100000000b518041e023d8653010000000001004040fb0100000000080051ac5200636a6300000000", "52ac", 0, 366357656, "bd0e88829afa6bdc1e192bb8b2d9d14db69298a4d81d464cbd34df0302c634c6"}, + {"9ad5ccf503fa4facf6a27b538bc910cce83c118d6dfd82f3fb1b8ae364a1aff4dcefabd38f03000000096365655263ac655300807c48130c5937190a996105a69a8eba585e0bd32fadfc57d24029cbed6446d30ebc1f100100000004000053650f0ccfca1356768df7f9210cbf078a53c72e0712736d9a7a238e0115faac0ca383f219d0010000000600ab536552002799982b0221b8280000000000000c41320000000000086552ac6365636a6595f233a3", "6a5152", 2, 553208588, "f99c29a79f1d73d2a69c59abbb5798e987639e36d4c44125d8dc78a94ddcfb13"}, + {"669538a204047214ce058aed6a07ca5ad4866c821c41ac1642c7d63ed0054f84677077a84f030000000853abacab6a655353ffffffff70c2a071c115282924e3cb678b13800c1d29b6a028b3c989a598c491bc7c76c5030000000752ac52ac5163ac80420e8a6e43d39af0163271580df6b936237f15de998e9589ec39fe717553d415ac02a4030000000463635153184ad8a5a4e69a8969f71288c331aff3c2b7d1b677d2ebafad47234840454b624bf7ac1d03000000056a63abab63df38c24a02fbc63a040000000002ab535ec3dc050000000002536500000000", "635153", 3, -190399351, "9615541884dfb1feeb08073a6a6aa73ef694bc5076e52187fdf4138a369f94d9"}, + {"a7f139e502af5894be88158853b7cbea49ba08417fbbca876ca6614b5a41432be34499987b000000000765635165abac63ffffffff8b8d70e96c7f54eb70da0229b548ced438e1ca2ba5ddd648a027f72277ee1efc0100000001abffffffff044f2c4204000000000165e93f550100000000050000526a6a94550304000000000365536aadc21c0300000000016300000000", "6aacac6363ab5265ac", 1, 2143189425, "6e3f97955490d93d6a107c18d7fe402f1cada79993bb0ff0d096357261b3a724"}, + {"3b94438f0366f9f53579a9989b86a95d134256ce271da63ca7cd16f7dd5e4bffa17d35133f010000000100ffffffff1aaad0c721e06ec00d07e61a84fb6dc840b9a968002ce7e142f943f06fd143a10100000008535151ac51ab0053b68b8e9c672daf66041332163e04db3f6048534bd718e1940b3fc3811c4eef5b7a56888b01000000001d58e38c012e38e700000000000852ab53ac6365536a00000000", "ab655352", 1, -935223304, "b3b336de141d4f071313a2207b2a0c7cf54a070dd8d234a511b7f1d13e23b0c4"}, + {"e5dca8a20456de0a67e185fa6ea94085ceae478d2c15c73cb931a500db3a1b6735dd1649ec0200000005ab536aabab32d11bbdcb81361202681df06a6b824b12b5cb40bb1a672cf9af8f2a836e4d95b7839327030000000951005365ab65abacabb345085932939eef0c724adef8a57f9e1bf5813852d957c039b6a12d9c2f201ea520fb030000000009ac5352005165acac6a5efc6072f1a421dc7dc714fc6368f6d763a5d76d0278b95fc0503b9268ccfadb48213a2500000000026a53ffffffff039ee1c4020000000009ac5353ab6353535163184018000000000005655265526a9a4a8a050000000001ac00000000", "65ab53ab6a00ab6553", 2, 1902561212, "7928ae8e86c0b0cad1b2c120ea313087437974382ee6d46443ca5ac3f5878b88"}, + {"972128b904e7b673517e96e98d80c0c8ceceae76e2f5c126d63da77ffd7893fb53308bb2da0300000006ac6552ab52acffffffff4cac767c797d297c079a93d06dc8569f016b4bf7a7d79b605c526e1d36a40e2202000000095365ab636aac6a6a6a69928d2eddc836133a690cfb72ec2d3115bf50fb3b0d10708fa5d2ebb09b4810c426a1db01000000060052526300001e8e89585da7e77b2dd2e30625887f0660accdf29e53a614d23cf698e6fc8ab03310e87700000000076a520051acac6555231ddb0330ec2d03000000000200abfaf457040000000004ab6a6352bdc42400000000000153d6dd2f04", "", 0, 209234698, "4a92fec1eb03f5bd754ee9bfd70707dc4420cc13737374f4675f48529be518e4"}, + {"1fb4085b022c6cfb848f8af7ba3ba8d21bd23ffa9f0bfd181cb68bcaaf2074e66d4974a31602000000090000006a6a6500acab6c12c07d9f3dbd2d93295c3a49e3757119767097e7fd5371f7d1ba9ba32f1a67a5a426f00000000000ffffffff018fd2fc04000000000363ac5100000000", "65ab006a6aab526a", 0, 1431502299, "8b7dd0ff12ca0d8f4dbf9abf0abba00e897c2f6fd3b92c79f5f6a534e0b33b32"}, + {"5374f0c603d727f63006078bd6c3dce48bd5d0a4b6ea00a47e5832292d86af258ea0825c260000000009655353636352526a6af2221067297d42a9f8933dfe07f61a574048ff9d3a44a3535cd8eb7de79fb7c45b6f47320200000003ac006affffffff153d917c447d367e75693c5591e0abf4c94bbdd88a98ab8ad7f75bfe69a08c470200000005ac65516365ffffffff037b5b7b000000000001515dc4d904000000000004bb26010000000004536a6aac00000000", "516552516352ac", 2, 328538756, "8bb7a0129eaf4b8fc23e911c531b9b7637a21ab11a246352c6c053ff6e93fcb6"}, + {"c441132102cc82101b6f31c1025066ab089f28108c95f18fa67db179610247086350c163bd010000000651525263ab00ffffffff9b8d56b1f16746f075249b215bdb3516cbbe190fef6292c75b1ad8a8988897c3000000000751ab6553abab00ffffffff02f9078b000000000009ab0053ac51ac00ab51c0422105000000000651006563525200000000", "ac51", 0, -197051790, "55acd8293ed0be6792150a3d7ced6c5ccd153ca7daf09cee035c1b0dac92bb96"}, + {"ab82ad3b04545bd86b3bb937eb1af304d3ef1a6d1343ed809b4346cafb79b7297c09e1648202000000086351ac5200535353ffffffff95d32795bbaaf5977a81c2128a9ec0b3c7551b9b1c3d952876fcb423b2dfb9e80000000005515363acac47a7d050ec1a603627ce6cd606b3af314fa7964abcc579d92e19c7aba00cf6c3090d6d4601000000056a516551633e794768bfe39277ebc0db18b5afb5f0c8117dde9b4dfd5697e9027210eca76a9be20d63000000000700520063ab6aacffffffff01ec2ddc050000000008ac52ac65ac65ac5100000000", "536300abab", 1, -2070209841, "b362da5634f20be7267de78b545d81773d711b82fe9310f23cd0414a8280801d"}, + {"8bff9d170419fa6d556c65fa227a185fe066efc1decf8a1c490bc5cbb9f742d68da2ab7f320100000007ab000053525365a7a43a80ab9593b9e8b6130a7849603b14b5c9397a190008d89d362250c3a2257504eb810200000007acabacac00ab51ee141be418f003e75b127fd3883dbf4e8c3f6cd05ca4afcaac52edd25dd3027ae70a62a00000000008ac52526a5200536affffffffb8058f4e1d7f220a1d1fa17e96d81dfb9a304a2de4e004250c9a576963a586ae0300000005abacac5363b9bc856c039c01d804000000000951656aac53005365acb0724e00000000000565abab63acea7c7a0000000000036a00ac00000000", "6565", 1, -1349282084, "2b822737c2affeefae13451d7c9db22ff98e06490005aba57013f6b9bbc97250"}, + {"0e1633b4041c50f656e882a53fde964e7f0c853b0ada0964fc89ae124a2b7ffc5bc97ea6230100000006ac6aacacabacffffffff2e35f4dfcad2d53ea1c8ada8041d13ea6c65880860d96a14835b025f76b1fbd9000000000351515121270867ef6bf63a91adbaf790a43465c61a096acc5a776b8e5215d4e5cd1492e611f761000000000600ac6aab5265ffffffff63b5fc39bcac83ca80ac36124abafc5caee608f9f63a12479b68473bd4bae769000000000965ac52acac5263acabffffffff0163153e020000000008ab005165ab65515300000000", "6a6aac00", 0, -968477862, "20732d5073805419f275c53784e78db45e53332ee618a9fcf60a3417a6e2ca69"}, + {"2b052c24022369e956a8d318e38780ef73b487ba6a8f674a56bdb80a9a63634c6110fb5154010000000251acffffffff48fe138fb7fdaa014d67044bc05940f4127e70c113c6744fbd13f8d51d45143e01000000005710db3804e01aa9030000000008acac6a516a5152abfd55aa01000000000751ab510000ac636d6026010000000000b97da9000000000000fddf3b53", "006552", 0, 595461670, "685d67d84755906d67a007a7d4fa311519467b9bdc6a351913246a41e082a29f"}, + {"073bc856015245f03b2ea2da62ccedc44ecb99e4250c7042f596bcb23b294c9dc92cfceb6b02000000095163abab52abab636afe292fb303b7c3f001000000000352636af3c49502000000000400ac6a535851850100000000066aac6553ab6500000000", "ab6aab53006aab52", 0, 247114317, "123916c6485cf23bfea95654a8815fbf04ce4d21a3b7f862805c241472906658"}, + {"7888b71403f6d522e414d4ca2e12786247acf3e78f1918f6d727d081a79813d129ee8befce0100000009ab516a6353ab6365abffffffff4a882791bf6400fda7a8209fb2c83c6eef51831bdf0f5dacde648859090797ec030000000153ffffffffbb08957d59fa15303b681bad19ccf670d7d913697a2f4f51584bf85fcf91f1f30200000008526565ac52ac63acffffffff0227c0e8050000000001ac361dc801000000000800515165ab00ab0000000000", "656a", 2, 1869281295, "f43378a0b7822ad672773944884e866d7a46579ee34f9afc17b20afc1f6cf197"}, + {"cc4dda57047bd0ca6806243a6a4b108f7ced43d8042a1acaa28083c9160911cf47eab910c40200000007526a0000ab6a63e4154e581fcf52567836c9a455e8b41b162a78c85906ccc1c2b2b300b4c69caaaa2ba0230300000008ab5152ac5100ab65ffffffff69696b523ed4bd41ecd4d65b4af73c9cf77edf0e066138712a8e60a04614ea1c0300000004ab6a000016c9045c7df7836e05ac4b2e397e2dd72a5708f4a8bf6d2bc36adc5af3cacefcf074b8b403000000065352ac5252acffffffff01d7e380050000000000cf4e699a", "525163656351", 1, -776533694, "ff18c5bffd086e00917c2234f880034d24e7ea2d1e1933a28973d134ca9e35d2"}, + {"b7877f82019c832707a60cf14fba44cfa254d787501fdd676bd58c744f6e951dbba0b3b77f0200000009ac515263ac53525300a5a36e500148f89c0500000000085265ac6a6a65acab00000000", "6563", 0, -1785108415, "cb6e4322955af12eb29613c70e1a00ddbb559c887ba844df0bcdebed736dffbd"}, + {"aeb14046045a28cc59f244c2347134d3434faaf980961019a084f7547218785a2bd03916f3000000000165f852e6104304955bda5fa0b75826ee176211acc4a78209816bbb4419feff984377b2352200000000003a94a5032df1e0d60390715b4b188c330e4bb7b995f07cdef11ced9d17ee0f60bb7ffc8e0100000002516513e343a5c1dc1c80cd4561e9dddad22391a2dbf9c8d2b6048e519343ca1925a9c6f0800a020000000665516365ac513180144a0290db27000000000006ab655151ab5138b187010000000007ab5363abac516a9e5cd98a", "53ac", 0, 478591320, "e8d89a302ae626898d4775d103867a8d9e81f4fd387af07212adab99946311ef"}, + {"c9270fe004c7911b791a00999d108ce42f9f1b19ec59143f7b7b04a67400888808487bd59103000000066a0052ac6565b905e76687be2dd7723b22c5e8269bc0f2000a332a289cfc40bc0d617cfe3214a61a85a30300000007ac63ac00635251560871209f21eb0268f175b8b4a06edd0b04162a974cf8b5dada43e499a1f22380d35ede0300000000792213fc58b6342cc8100079f9f5f046fb89f2d92cf0a2cb6d07304d32d9da858757037c0000000008abab51636565516affffffff02c72a8b03000000000452acac530dfb9f05000000000096f94307", "5253ab536351", 3, 543688436, "0278adbcc476d135493ae9bdcd7b3c2002df17f2d81c17d631c50c73e546c264"}, + {"57a5a04c0278c8c8e243d2df4bb716f81d41ac41e2df153e7096f5682380c4f441888d9d260300000004ab63ab6afdbe4203525dff42a7b1e628fe22bccaa5edbb34d8ab02faff198e085580ea5fcdb0c61b0000000002ac6affffffff03375e6c05000000000663ab516a6a513cb6260400000000007ca328020000000006516a636a52ab94701cc7", "0053ac5152", 0, -550925626, "b7ca991ab2e20d0158168df2d3dd842a57ab4a3b67cca8f45b07c4b7d1d11126"}, + {"072b75a504ad2550c2e9a02614bc9b2a2f50b5b553af7b87c0ef07c64ddc8d8934c96d216401000000036aabaca1387242a5bcd21099b016ad6045bed7dce603472757d9822cc5f602caa4ae20414d378b02000000026a63e4ac816734acdc969538d6f70b8ab43a2589f55e0177a4dc471bdd0eb61d59f0f46f6bb801000000065351526aab52d9f2977be76a492c3a7617b7a16dc29a3b0a7618f328c2f7d4fd9bafe760dc427a5066ef000000000465635165ffffffff02c5793600000000000165296820050000000002ac6300000000", "53006a6aac0052ab", 2, 66084636, "437e89bb6f70fd2ed2feef33350b6f6483b891305e574da03e580b3efd81ae13"}, + {"7e27c42d0279c1a05eeb9b9faedcc9be0cab6303bde351a19e5cbb26dd0d594b9d74f40d2b020000000200518c8689a08a01e862d5c4dcb294a2331912ff11c13785be7dce3092f154a005624970f84e0200000000500cf5a601e74c1f0000000000076aab52636a6a5200000000", "6500006a5351", 0, 449533391, "535ba819d74770d4d613ee19369001576f98837e18e1777b8246238ff2381dd0"}, + {"11414de403d7f6c0135a9df01cb108c1359b8d4e105be50a3dcba5e6be595c8817217490b20000000003005263ffffffff0c6becb9c3ad301c8dcd92f5cbc07c8bed7973573806d1489316fc77a829da03030000000700005253535352ffffffff2346d74ff9e12e5111aa8779a2025981850d4bf788a48de72baa2e321e4bc9ca00000000056352acab63cc585b64045e0385050000000009ab5253ab516aacac00efa9cf0300000000065200635151acbe80330400000000070063635100ab000be159050000000007525300655300ac00000000", "51656a0051ab", 0, 683137826, "d4737f3b58f3e5081b35f36f91acde89dda00a6a09d447e516b523e7a99264d5"}, + {"1c6b5f29033fc139338658237a42456123727c8430019ca25bd71c6168a9e35a2bf54538d80100000008536aac52ac6a6a52ffffffff3fb36be74036ff0c940a0247c451d923c65f826793d0ac2bb3f01ecbec8033290100000007ab000051ab6363ffffffff5d9eca0cf711685105bd060bf7a67321eaef95367acffab36ce8dedddd632ee2000000000652ac6a63ac517167319e032d26de040000000003516363dc38fb010000000000b37b00000000000006ab520051ac534baba51f", "636300ababac6563", 0, -2049129935, "3282a2ec6b8c87c9303e6060c17b421687db1bd35fbfa0345b48f2490e15b6cc"}, + {"978b9dad0214cfc7ce392d74d9dcc507350dc34007d72e4125861c63071ebf2cc0a6fd4856020000000651ac6a6aab52ffffffff47f20734e3370e733f87a6edab95a7a268ae44db7a8974e255614836b22938720200000008635265ac51516553ffffffff0137b2560100000000035252ac2f3363e9", "006aab6352", 1, 2014249801, "55611a5fb1483bce4c14c33ed15198130e788b72cd8929b2ceef4dd68b1806bf"}, + {"442f1c8703ab39876153c241ab3d69f432ba6db4732bea5002be45c8ca10c3a2356fe0e9590300000001accb2b679cab7c58a660cb6d4b3452c21cd7251a1b77a52c300f655f5baeb6fa27ff5b79880300000003005252e5ccf55712bc8ed6179f6726f8a78f3018a7a0391594b7e286ef5ee99efdcde302a102cc0200000009006352526351536a63ffffffff04443f63030000000006536a63ab63651405fb020000000009ac535351525300ab6a9f172b000000000004ab535263ad5c50050000000008656a65ab630000ac00000000", "65636aab006552", 2, 2125838294, "b3ff10f21e71ebc8b25fe058c4074c42f08617e0dcc03f9e75d20539d3242644"}, + {"2b3470dd028083910117f86614cdcfb459ee56d876572510be4df24c72e8f58c70d5f5948b03000000066aab65635265da2c3aac9d42c9baafd4b655c2f3efc181784d8cba5418e053482132ee798408ba43ccf90300000000ffffffff047dda4703000000000765516a52ac53009384a603000000000651636a63ab6a8cf57a03000000000352ab6a8cf6a405000000000952636a6a6565525100661e09cb", "ac520063ac6a6a52", 1, 1405647183, "9b360c3310d55c845ef537125662b9fe56840c72136891274e9fedfef56f9bb5"}, + {"d74282b501be95d3c19a5d9da3d49c8a88a7049c573f3788f2c42fc6fa594f59715560b9b00000000009655353525265ac52ac9772121f028f8303030000000003510065af5f47040000000007ac516a6551630000000000", "acab53006363ac", 0, -1113209770, "2f482b97178f17286f693796a756f4d7bd2dfcdbecd4142528eec1c7a3e5101a"}, + {"3a5644a9010f199f253f858d65782d3caec0ac64c3262b56893022b9796086275c9d4d097b02000000009d168f7603a67b30050000000007ac51536a0053acd9d88a050000000007655363535263ab3cf1f403000000000352ac6a00000000", "005363536565acac6a", 0, -1383947195, "6390ab0963cf611e0cea35a71dc958b494b084e6fd71d22217fdc5524787ade6"}, + {"67b3cc43049d13007485a8133b90d94648bcf30e83ba174f5486ab42c9107c69c5530c5e1f0000000003005100ffffffff9870ebb65c14263282ea8d41e4f4f40df16b565c2cf86f1d22a9494cad03a67f01000000016a5a121bee5e359da548e808ae1ad6dfccae7c67cbb8898d811638a1f455a671e822f228ef030000000151c1fcc9f9825f27c0dde27ea709da62a80a2ff9f6b1b86a5874c50d6c37d39ae31fb6c8a0030000000163553b8786020ca74a00000000000665635153ab5275c0760000000000020052e659b05d", "636aab6a6a", 0, -342795451, "f77c3322c97b1681c17b1eba461fa27b07e04c1534e8aaf735a49cab72c7c2e2"}, + {"bda1ff6804a3c228b7a12799a4c20917301dd501c67847d35da497533a606701ad31bf9d5e0300000001ac16a6c5d03cf516cd7364e4cbbf5aeccd62f8fd03cb6675883a0636a7daeb650423cb1291010000000500656553ac4a63c30b6a835606909c9efbae1b2597e9db020c5ecfc0642da6dc583fba4e84167539a8020000000865525353515200acffffffff990807720a5803c305b7da08a9f24b92abe343c42ac9e917a84e1f335aad785d00000000026a52ffffffff04981f20030000000001ab8c762200000000000253ab690b9605000000000151ce88b301000000000753526a6a51006500000000", "000052ac52530000", 1, -1809193140, "5299b0fb7fc16f40a5d6b337e71fcd1eb04d2600aefd22c06fe9c71fe0b0ba54"}, + {"2ead28ff0243b3ab285e5d1067f0ec8724224402b21b9cef9be962a8b0d153d401be99bbee0000000004ac635153ffffffff6985987b7c1360c9fa8406dd6e0a61141709f0d5195f946da55ed83be4e3895301000000020053ffffffff016503d20500000000085251ac6a65656a6a00000000", "51abab", 1, 1723793403, "67483ee62516be17a2431a163e96fd88a08ff2ce8634a52e42c1bc04e30f3f8a"}, + {"db4904e6026b6dd8d898f278c6428a176410d1ffbde75a4fa37cda12263108ccd4ca6137440100000007656a0000515263ffffffff1db7d5005c1c40da0ed17b74cf6b2a6ee2c33c9e0bacda76c0da2017dcac2fc70200000004abab6a53ffffffff0454cf2103000000000153463aef000000000009ab6a630065ab52636387e0ed050000000000e8d16f05000000000352ac63e4521b22", "", 1, 1027042424, "48315a95e49277ab6a2d561ee4626820b7bab919eea372b6bf4e9931ab221d04"}, + {"dca31ad10461ead74751e83d9a81dcee08db778d3d79ad9a6d079cfdb93919ac1b0b61871102000000086500525365ab51ac7f7e9aed78e1ef8d213d40a1c50145403d196019985c837ffe83836222fe3e5955e177e70100000006525152525300ffffffff5e98482883cc08a6fe946f674cca479822f0576a43bf4113de9cbf414ca628060100000006ac53516a5253ffffffff07490b0b898198ec16c23b75d606e14fa16aa3107ef9818594f72d5776805ec502000000036a0052ffffffff01932a2803000000000865ab6551ac6a516a2687aa06", "635300ac", 2, -1880362326, "74d6a2fa7866fd8b74b2e34693e2d6fd690410384b7afdcd6461b1ae71d265ce"}, + {"e14e1a9f0442ab44dfc5f6d945ad1ff8a376bc966aad5515421e96ddbe49e529614995cafc03000000055165515165fffffffff97582b8290e5a5cfeb2b0f018882dbe1b43f60b7f45e4dd21dbd3a8b0cfca3b0200000000daa267726fe075db282d694b9fee7d6216d17a8c1f00b2229085495c5dc5b260c8f8cd5d000000000363ac6affffffffaab083d22d0465471c896a438c6ac3abf4d383ae79420617a8e0ba8b9baa872b010000000963526563ac5363ababd948b5ce022113440200000000076a636552006a53229017040000000000e6f62ac8", "526353636a65", 3, -485265025, "1bc8ad76f9b7c366c5d052dc479d6a8a2015566d3a42e93ab12f727692c89d65"}, + {"720d4693025ca3d347360e219e9bc746ef8f7bc88e8795162e5e2f0b0fc99dc17116fc937100000000046353520045cb1fd79824a100d30b6946eab9b219daea2b0cdca6c86367c0c36af98f19ac64f3575002000000008a1c881003ed16f3050000000008536a63630000abac45e0e704000000000151f6551a05000000000963536565515363abab00000000", "6553ab6a6a510000ab", 1, 1249091393, "a575fa4f59a8e90cd07de012c78fe8f981183bb170b9c50fcc292b8c164cbc3b"}, + {"69df842a04c1410bfca10896467ce664cfa31c681a5dac10106b34d4b9d4d6d0dc1eac01c1000000000551536a5165269835ca4ad7268667b16d0a2df154ec81e304290d5ed69e0069b43f8c89e673328005e200000000076a5153006aacabffffffffc9314bd80b176488f3d634360fcba90c3a659e74a52e100ac91d3897072e3509010000000765abac51636363ffffffff0e0768b13f10f0fbd2fa3f68e4b4841809b3b5ba0e53987c3aaffcf09eee12bf0300000008ac535263526a53ac514f4c2402da8fab0400000000001ef15201000000000451526a52d0ec9aca", "525365ac52", 1, 313967049, "a72a760b361af41832d2c667c7488dc9702091918d11e344afc234a4aea3ec44"}, + {"adf2340d03af5c589cb5d28c06635ac07dd0757b884d4777ba85a6a7c410408ad5efa8b19001000000045100ab00ffffffff808dc0231c96e6667c04786865727013922bcb7db20739b686f0c17f5ba70e8f0300000000fd2332a654b580881a5e2bfec8313f5aa878ae94312f37441bf2d226e7fc953dcf0c77ab000000000163aa73dc580412f8c2050000000005636aacac63da02d502000000000153e74b52020000000001536b293d030000000009636552ababacab526500000000", "000052ab52ababab", 0, -568651175, "2c45d021db545df7167ac03c9ee56473f2398d9b2b739cf3ff3e074501d324f8"}, + {"e4fec9f10378a95199c1dd23c6228732c9de0d7997bf1c83918a5cfd36012476c0c3cba24002000000085165536500ac0000ad08ab93fb49d77d12a7ccdbb596bc5110876451b53a79fdce43104ff1c316ad63501de801000000046a6352ab76af9908463444aeecd32516a04dd5803e02680ed7f16307242a794024d93287595250f4000000000089807279041a82e603000000000200521429100200000000055253636a63f20b940400000000004049ed04000000000500ab5265ab43dfaf7d", "6563526aac", 2, -1923470368, "32f3c012eca9a823bebb9b282240aec40ca65df9f38da43b1dcfa0cac0c0df7e"}, + {"4000d3600100b7a3ff5b41ec8d6ccdc8b2775ad034765bad505192f05d1f55d2bc39d0cbe10100000007ab5165ac6a5163ffffffff034949150100000000026a6a92c9f6000000000008ab6553ab6aab635200e697040000000007636a5353525365237ae7d2", "52000063", 0, -880046683, "c76146f68f43037289aaeb2bacf47408cddc0fb326b350eb4f5ef6f0f8564793"}, + {"eabc0aa701fe489c0e4e6222d72b52f083166b49d63ad1410fb98caed027b6a71c02ab830c03000000075253ab63530065ffffffff01a5dc0b05000000000253533e820177", "", 0, 954499283, "1d849b92eedb9bf26bd4ced52ce9cb0595164295b0526842ab1096001fcd31b1"}, + {"d48d55d304aad0139783b44789a771539d052db565379f668def5084daba0dfd348f7dcf6b00000000006826f59e5ffba0dd0ccbac89c1e2d69a346531d7f995dea2ca6d7e6d9225d81aec257c6003000000096a655200ac656552acffffffffa188ffbd5365cae844c8e0dea6213c4d1b2407274ae287b769ab0bf293e049eb0300000005ac6a6aab51ad1c407c5b116ca8f65ed496b476183f85f072c5f8a0193a4273e2015b1cc288bf03e9e2030000000252abffffffff04076f44040000000006655353abab53be6500050000000003ac65ac3c15040500000000095100ab536353516a52ed3aba04000000000900ac53ab53636aabac00000000", "5253526563acac", 2, -1506108646, "bbee17c8582514744bab5df50012c94b0db4aff5984d2e13a8d09421674404e2"}, + {"9746f45b039bfe723258fdb6be77eb85917af808211eb9d43b15475ee0b01253d33fc3bfc502000000065163006a655312b12562dc9c54e11299210266428632a7d0ee31d04dfc7375dcad2da6e9c11947ced0e000000000009074095a5ac4df057554566dd04740c61490e1d3826000ad9d8f777a93373c8dddc4918a00000000025351ffffffff01287564030000000004636a00ab00000000", "52", 2, -1380411075, "84af1623366c4db68d81f452b86346832344734492b9c23fbb89015e516c60b2"}, + {"8731b64903d735ba16da64af537eaf487b57d73977f390baac57c7b567cb2770dfa2ef65870100000001635aedd990c42645482340eacb0bfa4a0a9e888057389c728b5b6a8691cdeb1a6a67b45e140200000008ac53526a52516551ffffffff45c4f567c47b8d999916fd49642cbc5d10d43c304b99e32d044d35091679cb860100000003006a51ffffffff0176d6c200000000000000000000", "ab6a65ab53", 2, -1221546710, "ccfdba36d9445f4451fb7cbf0752cc89c23d4fc6fff0f3930d20e116f9db0b95"}, + {"f5cfc52f016209ab1385e890c2865a74e93076595d1ca77cbe8fbf2022a2f2061a90fb0f3e010000000253acffffffff027de73f0200000000085252ac510052acac49cd6a020000000000e6c2cb56", "516552535300ab63", 0, -1195302704, "5532717402a2da01a1da912d824964024185ca7e8d4ad1748659dc393a14182b"}, + {"df0a32ae01c4672fd1abd0b2623aae0a1a8256028df57e532f9a472d1a9ceb194267b6ee190200000009536a6a51516a525251b545f9e803469a2302000000000465526500810631040000000000441f5b050000000006530051006aaceb183c76", "536a635252ac6a", 0, 1601138113, "9a0435996cc58bdba09643927fe48c1fc908d491a050abbef8daec87f323c58f"}, + {"d102d10c028b9c721abb259fe70bc68962f6cae384dabd77477c59cbeb1fb26266e091ba3e0100000002516affffffffe8d7305a74f43e30c772109849f4cd6fb867c7216e6d92e27605e69a0818899700000000026a65ecf82d58027db4620500000000026552c28ed3010000000001ab00000000", "0051ab515365", 1, -131815460, "1d1757a782cb5860302128bcbe9398243124a2f82d671a113f74f8e582c7a182"}, + {"cef930ed01c36fcb1d62ceef931bef57098f27a77a4299904cc0cbb44504802d535fb11557010000000153ffffffff02c8657403000000000863ac655253520063d593380400000000046aab536a00000000", "656a0051ab6365ab53", 0, -351313308, "e69dba3efb5c02af2ab1087d0a990678784671f4744d01ca097d71aec14dd8e9"}, + {"b1c0b71804dff30812b92eefb533ac77c4b9fdb9ab2f77120a76128d7da43ad70c20bbfb990200000002536392693e6001bc59411aebf15a3dc62a6566ec71a302141b0c730a3ecc8de5d76538b30f55010000000665535252ac514b740c6271fb9fe69fdf82bf98b459a7faa8a3b62f3af34943ad55df4881e0d93d3ce0ac0200000000c4158866eb9fb73da252102d1e64a3ce611b52e873533be43e6883137d0aaa0f63966f060000000001abffffffff04a605b604000000000851006a656a630052f49a0300000000000252515a94e1050000000009abac65ab0052abab00fd8dd002000000000651535163526a2566852d", "ac5363", 0, -1718831517, "b0dc030661783dd9939e4bf1a6dfcba809da2017e1b315a6312e5942d714cf05"}, + {"6a270ee404ebc8d137cfd4bb6b92aa3702213a3139a579c1fc6f56fbc7edd9574ef17b13f30100000009ab00ab656565ababacffffffffaa65b1ab6c6d87260d9e27a472edceb7dd212483e72d90f08857abf1dbfd46d10100000000fffffffff93c4c9c84c4dbbe8a912b99a2830cfe3401aebc919041de063d660e585fc9f002000000096aabacab52ac6a53acfa6dcef3f28355a8d98eee53839455445eeee83eecd2c854e784efa53cee699dbfecaebd0100000003ab6a51ffffffff04f7d71b050000000009ac6a536aac6a6365513c37650500000000065265abab6a53fa742002000000000039ed82030000000009516aac635165ab51ab2fdabd17", "ab535252526563", 1, -1326210506, "1dec0d5eb921bf5b2df39c8576e19c38d0c17254a4a0b78ac4b5422bcc426258"}, + {"3657e4260304ccdc19936e47bdf058d36167ee3d4eb145c52b224eff04c9eb5d1b4e434dfc0000000001ab58aefe57707c66328d3cceef2e6f56ab6b7465e587410c5f73555a513ace2b232793a74400000000036a006522e69d3a785b61ad41a635d59b3a06b2780a92173f85f8ed428491d0aaa436619baa9c4501000000046351abab2609629902eb7793050000000000a1b967040000000003525353a34d6192", "516a", 0, -1761874713, "0a2ff41f6d155d8d0e37cd9438f3b270df9f9214cda8e95c76d5a239ca189df2"}, + {"a0eb6dc402994e493c787b45d1f946d267b09c596c5edde043e620ce3d59e95b2b5b93d43002000000096a5252526aac63ab6555694287a279e29ee491c177a801cd685b8744a2eab83824255a3bcd08fc0e3ea13fb8820000000009abab6365ab52ab0063ffffffff029e424a040000000008acab53ab516a636a23830f0400000000016adf49c1f9", "ac0065ac6500005252", 1, 669294500, "e05e3d383631a7ed1b78210c13c2eb26564e5577db7ddfcea2583c7c014091d4"}, + {"6e67c0d3027701ef71082204c85ed63c700ef1400c65efb62ce3580d187fb348376a23e9710200000001655b91369d3155ba916a0bc6fe4f5d94cad461d899bb8aaac3699a755838bfc229d6828920010000000765536353526a52ffffffff04c0c792000000000005650052535372f79e000000000001527fc0ee010000000005ac5300ab65d1b3e902000000000251aba942b278", "6a5151", 0, 1741407676, "e657e2c8ec4ebc769ddd3198a83267b47d4f2a419fc737e813812acefad92ff7"}, + {"8f53639901f1d643e01fc631f632b7a16e831d846a0184cdcda289b8fa7767f0c292eb221a00000000046a53abacffffffff037a2daa01000000000553ac6a6a51eac349020000000005ac526552638421b3040000000007006a005100ac63048a1492", "ac65", 0, 1033685559, "da86c260d42a692358f46893d6f91563985d86eeb9ea9e21cd38c2d8ffcfcc4d"}, + {"491f99cb01bdfba1aa235e5538dac081fae9ce55f9622de483afe7e65105c2b0db75d360d200000000045251636340b60f0f041421330300000000096351ac000051636553ce2822040000000005516a00ac5180c8e40300000000025100caa8570400000000020000cfdc8da6", "6a5100516aab655365", 0, -953727341, "397c68803b7ce953666830b0221a5e2bcf897aa2ded8e36a6b76c497dcb1a2e1"}, + {"b3cad3a7041c2c17d90a2cd994f6c37307753fa3635e9ef05ab8b1ff121ca11239a0902e700300000009ab635300006aac5163ffffffffcec91722c7468156dce4664f3c783afef147f0e6f80739c83b5f09d5a09a57040200000004516a6552ffffffff969d1c6daf8ef53a70b7cdf1b4102fb3240055a8eaeaed2489617cd84cfd56cf020000000352ab53ffffffff46598b6579494a77b593681c33422a99559b9993d77ca2fa97833508b0c169f80200000009655300655365516351ffffffff04d7ddf800000000000853536a65ac6351ab09f3420300000000056aab65abac33589d04000000000952656a65655151acac944d6f0400000000006a8004ba", "005165", 1, 1035865506, "fe1dc9e8554deecf8f50c417c670b839cc9d650722ebaaf36572418756075d58"}, + {"e1cfd73b0125add9e9d699f5a45dca458355af175a7bd4486ebef28f1928d87864384d02df02000000036a0051ffffffff0357df030100000000036a5365777e2d04000000000763ab6a00005265f434a601000000000351655100000000", "ab53ab", 0, -1936500914, "950f4b4f72ccdf8a6a0f381265d6c8842fdb7e8b3df3e9742905f643b2432b69"}, + {"cf781855040a755f5ba85eef93837236b34a5d3daeb2dbbdcf58bb811828d806ed05754ab8010000000351ac53ffffffffda1e264727cf55c67f06ebcc56dfe7fa12ac2a994fecd0180ce09ee15c480f7d00000000096351516a51acac00ab53dd49ff9f334befd6d6f87f1a832cddfd826a90b78fd8cf19a52cb8287788af94e939d6020000000700525251ac526310d54a7e8900ed633f0f6f0841145aae7ee0cbbb1e2a0cae724ee4558dbabfdc58ba6855010000000552536a53abfd1b101102c51f910500000000096300656a525252656a300bee010000000009ac52005263635151abe19235c9", "53005365", 2, 1422854188, "d5981bd4467817c1330da72ddb8760d6c2556cd809264b2d85e6d274609fc3a3"}, + {"fea256ce01272d125e577c0a09570a71366898280dda279b021000db1325f27edda41a53460100000002ab53c752c21c013c2b3a01000000000000000000", "65", 0, 1145543262, "076b9f844f6ae429de228a2c337c704df1652c292b6c6494882190638dad9efd"}}; + + +struct txoptest { + char scripthex[1024]; + int opcodes; + int type; +}; + + +const struct txoptest txoptests[] = + { + {"76a914aab76ba4877d696590d94ea3e02948b55294815188ac", 5, BTC_TX_PUBKEYHASH}, + + {"522102004525da5546e7603eefad5ef971e82f7dad2272b34e6b3036ab1fe3d299c22f21037d7f2227e6c646707d1c61ecceb821794124363a2cf2c1d2a6f28cf01e5d6abe52ae", 5, BTC_TX_MULTISIG}, + + {"a9146262b64aec1f4a4c1d21b32e9c2811dd2171fd7587", 3, BTC_TX_SCRIPTHASH}, + + {"4104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac", 2, BTC_TX_PUBKEY} + +}; + + +void test_tx_serialization() +{ + unsigned int i; + for (i = 0; i < (sizeof(txvalid) / sizeof(txvalid[0])); i++) { + const struct txtest* one_test = &txvalid[i]; + uint8_t tx_data[sizeof(one_test->hextx) / 2]; + int outlen; + utils_hex_to_bin(one_test->hextx, tx_data, strlen(one_test->hextx), &outlen); + + btc_tx* tx = btc_tx_new(); + btc_tx_deserialize(tx_data, outlen, tx, NULL, true); + + btc_tx* tx_copy = btc_tx_new(); + btc_tx_copy(tx_copy, tx); + + + assert(tx->vin->len == (size_t)one_test->num_ins); + size_t victx; + for (victx = 0; victx < tx->vin->len; victx++) { + /* hex prevout hash */ + btc_tx_in* tx_in = vector_idx(tx->vin, victx); + char* hex_txin = utils_uint8_to_hex(tx_in->prevout.hash, 32); + utils_reverse_hex(hex_txin, strlen(hex_txin)); + assert(strcmp(one_test->inputs[victx].hash, hex_txin) == 0); + } + + cstring* str = cstr_new_sz(strlen(one_test->hextx) + 100); + btc_tx_serialize(str, tx, true); + + cstring* str2 = cstr_new_sz(strlen(one_test->hextx) + 100); + btc_tx_serialize(str2, tx_copy, true); + + assert(memcmp(str->str, str2->str, str->len) == 0); + + char hexbuf[sizeof(one_test->hextx) + 1]; + utils_bin_to_hex((unsigned char*)str->str, str->len, hexbuf); + cstr_free(str, true); + cstr_free(str2, true); + + assert(memcmp(one_test->hextx, hexbuf, strlen(hexbuf)) == 0); + btc_tx_free(tx); + btc_tx_free(tx_copy); + } + + int tstd = 1; +} + +void test_tx_sighash_ext() +{ + //extended sighash tests + int arrylen = (sizeof(txvalid_sighash) / sizeof(txvalid_sighash[0])); + for (unsigned int i = 0; i < (sizeof(txvalid_sighash) / sizeof(txvalid_sighash[0])); i++) { + int outlen_sighash = 0; + uint8_t tx_data_sighash[sizeof(txvalid_sighash[i].sertx) / 2]; + utils_hex_to_bin(txvalid_sighash[i].sertx, tx_data_sighash, strlen(txvalid_sighash[i].sertx), &outlen_sighash); + btc_tx* tx_sighash = btc_tx_new(); + btc_tx_deserialize(tx_data_sighash, outlen_sighash, tx_sighash, NULL, true); + + uint8_t script_data[strlen(txvalid_sighash[i].script)]; + utils_hex_to_bin(txvalid_sighash[i].script, script_data, strlen(txvalid_sighash[i].script), &outlen_sighash); + cstring *str = cstr_new_buf(script_data, outlen_sighash); + uint256 hash; + btc_tx_sighash(tx_sighash, str, txvalid_sighash[i].i, SIGHASH_ALL, txvalid_sighash[i].amount, txvalid_sighash[i].witness ? SIGVERSION_WITNESS_V0 : SIGVERSION_BASE, hash); + + btc_tx_free(tx_sighash); + cstr_free(str, true); + + char sighash_hex[65]; + utils_bin_to_hex(hash, sizeof(hash), sighash_hex); + utils_reverse_hex(sighash_hex, strlen(sighash_hex)); + + assert(memcmp(txvalid_sighash[i].sighash, sighash_hex, 64) == 0); + } +} + +void test_tx_sighash() +{ + unsigned int i; + + int fails, success; + fails = 0; + success = 0; + for (i = 0; i < (sizeof(sighash_tests) / sizeof(sighash_tests[0])); i++) { + const struct sighashtest* test = &sighash_tests[i]; + uint8_t tx_data[sizeof(test->txhex) / 2]; + int outlen; + utils_hex_to_bin(test->txhex, tx_data, strlen(test->txhex), &outlen); + + btc_tx* tx = btc_tx_new(); + btc_tx_deserialize(tx_data, outlen, tx, NULL, true); + + uint8_t script_data[strlen(test->script) / 2]; + utils_hex_to_bin(test->script, script_data, strlen(test->script), &outlen); + cstring* script = cstr_new_buf(script_data, outlen); + uint256 sighash; + memset(sighash, 0, sizeof(sighash)); + btc_tx_sighash(tx, script, test->inputindex, test->hashtype, 0, SIGVERSION_BASE, sighash); + + vector* vec = vector_new(10, btc_script_op_free_cb); + btc_script_get_ops(script, vec); + enum btc_tx_out_type type = btc_script_classify_ops(vec); + vector_free(vec, true); + + enum btc_tx_out_type type2 = btc_script_classify(script, NULL); + assert(type == type2); + + cstr_free(script, true); + + char hexbuf[sizeof(sighash)*2]; + utils_bin_to_hex(sighash, sizeof(sighash), hexbuf); + utils_reverse_hex(hexbuf, sizeof(hexbuf)); + + assert(strcmp(hexbuf, test->hashhex) == 0); + + btc_tx_free(tx); + } +} + + +void test_tx_negative_version() +{ + char txhex[] = "ffffffff0100000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100e1f505000000000000000000"; + int32_t versionGoal = -1; + + uint8_t tx_data[sizeof(txhex) / 2]; + int outlen; + utils_hex_to_bin(txhex, tx_data, strlen(txhex), &outlen); + + btc_tx* tx = btc_tx_new(); + btc_tx_deserialize(tx_data, outlen, tx, NULL, true); + u_assert_int_eq(versionGoal, tx->version); + + btc_tx_free(tx); +} + + +struct script_test { + char script[32]; +}; + +const struct script_test script_tests[] = + { + {"0x4c01"}, + {"0x4d0200ff"}, + {"0x4e03000000ffff"}}; + +void test_script_parse() +{ + unsigned int i; + for (i = 0; i < (sizeof(txoptests) / sizeof(txoptests[0])); i++) { + const struct txoptest* test = &txoptests[i]; + uint8_t script_data[sizeof(test->scripthex) / 2]; + int outlen; + utils_hex_to_bin(test->scripthex, script_data, strlen(test->scripthex), &outlen); + + cstring* script = cstr_new_buf(script_data, outlen); + vector* vec = vector_new(10, btc_script_op_free_cb); + btc_script_get_ops(script, vec); + enum btc_tx_out_type type = btc_script_classify_ops(vec); + + assert((int)type == test->type); + assert(vec->len == (size_t)test->opcodes); + + vector_free(vec, true); + cstr_free(script, true); + } + + for (i = 0; i < (sizeof(script_tests) / sizeof(script_tests[0])); i++) { + const struct script_test* test = &script_tests[i]; + uint8_t script_data[sizeof(test->script) / 2]; + int outlen; + utils_hex_to_bin(test->script, script_data, strlen(test->script), &outlen); + + cstring* script = cstr_new_buf(script_data, outlen); + vector* vec = vector_new(10, btc_script_op_free_cb); + btc_script_get_ops(script, vec); + enum btc_tx_out_type type = btc_script_classify_ops(vec); + + cstring* new_script = cstr_new_sz(script->len); + btc_script_copy_without_op_codeseperator(script, new_script); + cstr_free(new_script, true); + cstr_free(script, true); + vector_free(vec, true); + } + + vector* pubkeys = vector_new(3, free); + for (i = 0; i < 3; i++) { + btc_key key; + btc_privkey_init(&key); + btc_privkey_gen(&key); + + btc_pubkey* pubkey = btc_malloc(sizeof(btc_pubkey)); + btc_pubkey_init(pubkey); + btc_pubkey_from_key(&key, pubkey); + assert(btc_pubkey_is_valid(pubkey) == 1); + + vector_add(pubkeys, pubkey); + } + + cstring* new_script = cstr_new_sz(1024); + btc_script_build_multisig(new_script, 2, pubkeys); + + u_assert_int_eq(new_script->str[0], 0x52); //2 + u_assert_int_eq(new_script->str[new_script->len - 2], 0x53); //3 + u_assert_int_eq(((char)new_script->str[new_script->len - 1] == (char)OP_CHECKMULTISIG), 1); + cstr_free(new_script, true); + + btc_pubkey* pubkey = pubkeys->data[0]; + cstring* p2pkh = cstr_new_sz(1024); + btc_script_build_p2pkh(p2pkh, pubkey->pubkey); + u_assert_int_eq(p2pkh->str[0], (char)OP_DUP); //2 + u_assert_int_eq(p2pkh->str[1], (char)OP_HASH160); //2 + u_assert_int_eq(((char)p2pkh->str[p2pkh->len - 1] == (char)OP_CHECKSIG), 1); + cstr_free(p2pkh, true); + + + uint8_t pubkeydat[33] = {0x02,0xd0,0x03,0xdf,0xea,0xf0,0x76,0x2e,0xd1,0xcd,0xbb,0x1d,0x54,0x2b,0x0a,0x26,0x17,0x49,0xe3,0xff,0x81,0x09,0x64,0xef,0x90,0x64,0xd7,0x97,0xd5,0x78,0xa1,0x21,0x94}; + + btc_pubkey pubkeytx; + btc_pubkey_init(&pubkeytx); + memcpy(&pubkeytx.pubkey, pubkeydat, 33); + pubkeytx.compressed = true; + + btc_tx* tx = btc_tx_new(); + btc_tx_add_p2pkh_out(tx, 1000000000, &pubkeytx); + + cstring* txser = cstr_new_sz(1024); + btc_tx_serialize(txser, tx, false); + + char hexbuf[txser->len * 2 + 1]; + utils_bin_to_hex((unsigned char*)txser->str, txser->len, hexbuf); + + u_assert_str_eq(hexbuf, "01000000000100ca9a3b000000001976a91457b78cc8347175aee968eaa91846e840ef36ff9288ac00000000"); + cstr_free(txser, true); + + uint256 txhash; + btc_tx_hash(tx, txhash); + char txhashhex[sizeof(txhash)*2]; + utils_bin_to_hex((unsigned char*)txhash, sizeof(txhash), txhashhex); + utils_reverse_hex(txhashhex, sizeof(txhashhex)); + + u_assert_str_eq(txhashhex, "41a86af25423391b1d9d78df1143e3a237f20db27511d8b72e25f2dec7a81d80"); + + + btc_tx_add_address_out(tx, &btc_chainparams_regtest, 12345678, "n1e4M744gKSL269jozPwc8edjxxdwn6THc"); + + + txser = cstr_new_sz(1024); + btc_tx_serialize(txser, tx, false); + char hexbuf2[txser->len * 2 + 1]; + utils_bin_to_hex((unsigned char*)txser->str, txser->len, hexbuf2); + u_assert_str_eq(hexbuf2, "01000000000200ca9a3b000000001976a91457b78cc8347175aee968eaa91846e840ef36ff9288ac4e61bc00000000001976a914dcba7ad8b58f35ea9a7ffa2102dcfb2612b6ba9088ac00000000"); + + btc_tx_hash(tx, txhash); + utils_bin_to_hex((unsigned char*)txhash, 32, txhashhex); + utils_reverse_hex(txhashhex, 64); + + u_assert_str_eq(txhashhex, "6a56c7415dc6e3695b4b6b27bdfec5124ed70e0a615d5aa0d8cf0b5e8b72fd76"); + + cstr_free(txser, true); + + + btc_tx_add_address_out(tx, &btc_chainparams_regtest, 876543210, "2NFoJeWNrABZQ3YCWdbX9wGEnRge7kDeGzQ"); + txser = cstr_new_sz(1024); + btc_tx_serialize(txser, tx, false); + char hexbuf3[txser->len * 2 + 1]; + utils_bin_to_hex((unsigned char*)txser->str, txser->len, hexbuf3); + u_assert_str_eq(hexbuf3, "01000000000300ca9a3b000000001976a91457b78cc8347175aee968eaa91846e840ef36ff9288ac4e61bc00000000001976a914dcba7ad8b58f35ea9a7ffa2102dcfb2612b6ba9088aceafc3e340000000017a914f763f798ede75a6ebf4e061b9e68ddb6df0442928700000000"); + + cstr_free(txser, true); + + btc_tx_add_address_out(tx, &btc_chainparams_regtest, 100000000, "bcrt1qfupfj4yx83dz8vhcpcahhxyg4sfqr8pvx8l6l2"); + txser = cstr_new_sz(1024); + btc_tx_serialize(txser, tx, false); + char hexbuf4[txser->len * 2 + 1]; + utils_bin_to_hex((unsigned char*)txser->str, txser->len, hexbuf4); + u_assert_str_eq(hexbuf4, "01000000000400ca9a3b000000001976a91457b78cc8347175aee968eaa91846e840ef36ff9288ac4e61bc00000000001976a914dcba7ad8b58f35ea9a7ffa2102dcfb2612b6ba9088aceafc3e340000000017a914f763f798ede75a6ebf4e061b9e68ddb6df0442928700e1f505000000001600144f029954863c5a23b2f80e3b7b9888ac12019c2c00000000"); + cstr_free(txser, true); + + vector_free(pubkeys, true); + btc_tx_free(tx); + + // op_return test + size_t masterkeysize = 200; + char masterkey[masterkeysize]; + u_assert_int_eq(hd_gen_master(&btc_chainparams_main, masterkey, masterkeysize), true); + + btc_hdnode node; + u_assert_int_eq(btc_hdnode_deserialize(masterkey, &btc_chainparams_main, &node), true); + + uint256 rev_code; + uint256 sig_hash; + btc_hash(node.private_key, BTC_ECKEY_PKEY_LENGTH, rev_code); + + uint8_t sigdata[38] = {0x42, 0x49, 0x50, 0x00, 0x00, 0x00, 0x00 }; + btc_hash(rev_code, BTC_HASH_LENGTH, &sigdata[7]); + + btc_hash(sigdata, sizeof(sigdata), sig_hash); + + btc_key key; + btc_privkey_init(&key); + + memcpy(key.privkey, node.private_key, BTC_ECKEY_PKEY_LENGTH); + unsigned char sigcmp[64]; + size_t outlencmp = 64; + btc_key_sign_hash_compact(&key, sig_hash, sigcmp, &outlencmp); + + btc_pubkey pubkeytx_rev; + btc_pubkey_init(&pubkeytx_rev); + btc_pubkey_from_key(&key, &pubkeytx_rev); + + tx = btc_tx_new(); + btc_tx_add_data_out(tx, 100000, sigcmp, outlencmp); //0.001 BTC + btc_tx_add_p2pkh_out(tx, 10000, &pubkeytx_rev); + + txser = cstr_new_sz(1024); + btc_tx_serialize(txser, tx, false); + char hexbuf5[txser->len * 2 + 1]; + utils_bin_to_hex((unsigned char*)txser->str, txser->len, hexbuf5); + // TODO: test + cstr_free(txser, true); + + btc_tx_free(tx); +} + +void test_script_op_codeseperator() +{ + char scripthex[] = "ab00270025512102e485fdaa062387c0bbb5ab711a093b6635299ec155b7b852fce6b992d5adbfec51ae"; + char scripthexGoal[] = "00270025512102e485fdaa062387c0bbb5ab711a093b6635299ec155b7b852fce6b992d5adbfec51ae"; + uint8_t script_data[sizeof(scripthex) / 2]; + int outlen; + utils_hex_to_bin(scripthex, script_data, strlen(scripthex), &outlen); + + cstring* script = cstr_new_buf(script_data, outlen); + + cstring* new_script = cstr_new_sz(script->len); + btc_script_copy_without_op_codeseperator(script, new_script); + + char hexbuf[new_script->len * 2 + 1]; + utils_bin_to_hex((unsigned char*)new_script->str, new_script->len, hexbuf); + assert(strcmp(hexbuf, scripthexGoal) == 0); + cstr_free(new_script, true); + cstr_free(script, true); +} + +void test_invalid_tx_deser() +{ + char txstr[] = "asadasdadad"; + uint8_t tx_data[sizeof(txstr) / 2+1]; + int outlen; + utils_hex_to_bin(txstr, tx_data, strlen(txstr), &outlen); + + btc_tx* tx = btc_tx_new(); + u_assert_int_eq(btc_tx_deserialize(tx_data, outlen, tx, NULL, true), false); + btc_tx_free(tx); + + char failed_output[] = "02000000000101bb3ee7f13f00b58a65f3789ff9917ae2eb2f360957ca86d4ec8068deae16f94c0000000017160014d7d7d2e56512a14b41f2b412eb33f9a2c464e407ffffffff01c0878b3b0000000017a914b1"; + uint8_t tx_data_fo[sizeof(failed_output) / 2+1]; + utils_hex_to_bin(failed_output, tx_data_fo, strlen(failed_output), &outlen); + + btc_tx* tx_o = btc_tx_new(); + u_assert_int_eq(btc_tx_deserialize(tx_data, outlen, tx_o, NULL, true), false); + btc_tx_free(tx_o); + +} + +void test_tx_sign_p2sh_p2wpkh() { + const char *tx_hex = "0200000001bb3ee7f13f00b58a65f3789ff9917ae2eb2f360957ca86d4ec8068deae16f94c0000000000ffffffff01c0878b3b0000000017a914b1c1b08a898e07095e72a50cdf889bcdb1530a358700000000"; + const char *script_hex = "a9148824655b15edc6291e08b814744b2dc521d6c41687"; + const char *pkey_wif = "cRMBVuEydsdQdYCe8gFgu6HV8rFywrY6thdpumxzrrHC56BgBpEp"; + const char *expected_sigder = "30440220685849941f583fe4a54b77fbe7963a2f7fdb9fefc661f9e43d9c6c213f6a4c9c02207da98e43af69d2c616c489eb22657e62a1360eeb5a86d8a31bd8a33dd9de21f101"; + const char *expected_sigcomp = "685849941f583fe4a54b77fbe7963a2f7fdb9fefc661f9e43d9c6c213f6a4c9c7da98e43af69d2c616c489eb22657e62a1360eeb5a86d8a31bd8a33dd9de21f1"; + const char *expected_tx_signed = "02000000000101bb3ee7f13f00b58a65f3789ff9917ae2eb2f360957ca86d4ec8068deae16f94c0000000017160014d7d7d2e56512a14b41f2b412eb33f9a2c464e407ffffffff01c0878b3b0000000017a914b1c1b08a898e07095e72a50cdf889bcdb1530a3587024730440220685849941f583fe4a54b77fbe7963a2f7fdb9fefc661f9e43d9c6c213f6a4c9c02207da98e43af69d2c616c489eb22657e62a1360eeb5a86d8a31bd8a33dd9de21f10121022d0e577424abfbbb5e321d3e2c700122a0c004305f57725810988cee6c4c278d00000000"; + uint64_t amount = 1000000000; + int sighashtype = SIGHASH_ALL; + int inputindex = 0; + + int outlen; + uint8_t tx_data[strlen(tx_hex) / 2]; + utils_hex_to_bin(tx_hex, tx_data, strlen(tx_hex), &outlen); + uint8_t script_data[strlen(script_hex) / 2]; + utils_hex_to_bin(script_hex, script_data, strlen(script_hex), &outlen); + cstring *script = cstr_new_buf(script_data, outlen); + uint8_t expected_sigder_data[strlen(expected_sigder) / 2]; + utils_hex_to_bin(expected_sigder, expected_sigder_data, strlen(expected_sigder), &outlen); + uint8_t expected_sigcomp_data[strlen(expected_sigcomp) / 2]; + utils_hex_to_bin(expected_sigcomp, expected_sigcomp_data, strlen(expected_sigcomp), &outlen); + uint8_t expected_tx_signed_data[strlen(expected_tx_signed) / 2]; + utils_hex_to_bin(expected_tx_signed, expected_tx_signed_data, strlen(expected_tx_signed), &outlen); + + btc_key pkey; + btc_privkey_init(&pkey); + btc_privkey_decode_wif(pkey_wif, &btc_chainparams_regtest, &pkey); + + btc_tx* tx = btc_tx_new(); + btc_tx_deserialize(tx_data, outlen, tx, NULL, true); + + + uint8_t sigcomp[64] = {0}; + uint8_t sigder[76] = {0}; + int sigder_len = 0; + enum btc_tx_sign_result res = btc_tx_sign_input(tx, script, amount, &pkey, inputindex, sighashtype, sigcomp, sigder, &sigder_len); + u_assert_mem_eq(sigcomp, expected_sigcomp_data, 64); + u_assert_mem_eq(sigder, expected_sigder_data, sigder_len); + + cstring* tx_ser = cstr_new_sz(1024); + btc_tx_serialize(tx_ser, tx, true); + + char hexbuf[tx_ser->len*2+1]; + utils_bin_to_hex((unsigned char*)tx_ser->str, tx_ser->len, hexbuf); + u_assert_str_eq(hexbuf, expected_tx_signed); + + btc_tx_free(tx); + cstr_free(tx_ser, true); + cstr_free(script, true); +} + +void test_tx_sign_p2pkh(btc_tx *tx) { + const char *tx_hex = "02000000027409797c31feecc4e69b51c58b477b72c53355743a6f6124f9d78221672df3700100000000ffffffff6e1709c1e2bdd85aed24dccfd48293993617f249d4d4381296a9c914be3e85e60100000000ffffffff01c07fdc0b0000000017a914ba277fd56b69177464fcb6a27a530f03740345ed8700000000"; + const char *script_hex = "76a9149b47fd7adc7a671ed059c9dcbf2eee2e882ea56b88ac"; + const char *pkey_wif = "cRpSdivawavdAPgEYGXusWt64cJG9zLcgDPsEvnhHWtizVtmGk5b"; + const char *expected_sigder = "304402205d44c682a69da1ca10e1149548bf7e7b53f0ce8f2d2bd2ea74026cba57cd4fe702200e0f9d87aafa1c88697238aaf1059b7718a97ff681efe474097221d456eb7ea201"; + const char *expected_sigcomp = "685849941f583fe4a54b77fbe7963a2f7fdb9fefc661f9e43d9c6c213f6a4c9c7da98e43af69d2c616c489eb22657e62a1360eeb5a86d8a31bd8a33dd9de21f1"; + const char *expected_tx_signed = "02000000027409797c31feecc4e69b51c58b477b72c53355743a6f6124f9d78221672df370010000006a47304402205d44c682a69da1ca10e1149548bf7e7b53f0ce8f2d2bd2ea74026cba57cd4fe702200e0f9d87aafa1c88697238aaf1059b7718a97ff681efe474097221d456eb7ea2012102c5b9d2d528f13b7b745736f6fd198614a09200c3c5cb0554327e110b4a8efcf1ffffffff6e1709c1e2bdd85aed24dccfd48293993617f249d4d4381296a9c914be3e85e60100000000ffffffff01c07fdc0b0000000017a914ba277fd56b69177464fcb6a27a530f03740345ed8700000000"; + uint64_t amount = 100000000; + int sighashtype = SIGHASH_ALL; + int inputindex = 0; + + int outlen; + uint8_t tx_data[strlen(tx_hex) / 2]; + utils_hex_to_bin(tx_hex, tx_data, strlen(tx_hex), &outlen); + uint8_t script_data[strlen(script_hex) / 2]; + utils_hex_to_bin(script_hex, script_data, strlen(script_hex), &outlen); + cstring *script = cstr_new_buf(script_data, outlen); + uint8_t expected_sigder_data[strlen(expected_sigder) / 2]; + utils_hex_to_bin(expected_sigder, expected_sigder_data, strlen(expected_sigder), &outlen); + uint8_t expected_tx_signed_data[strlen(expected_tx_signed) / 2]; + utils_hex_to_bin(expected_tx_signed, expected_tx_signed_data, strlen(expected_tx_signed), &outlen); + + btc_key pkey; + btc_privkey_init(&pkey); + btc_privkey_decode_wif(pkey_wif, &btc_chainparams_regtest, &pkey); + + btc_tx_deserialize(tx_data, outlen, tx, NULL, true); + + + uint8_t sigcomp[64] = {0}; + uint8_t sigder[76] = {0}; + int sigder_len = 0; + enum btc_tx_sign_result res = btc_tx_sign_input(tx, script, amount, &pkey, inputindex, sighashtype, sigcomp, sigder, &sigder_len); + u_assert_mem_eq(sigder, expected_sigder_data, sigder_len); + + cstring* tx_ser = cstr_new_sz(1024); + btc_tx_serialize(tx_ser, tx, true); + + char hexbuf[tx_ser->len*2+1]; + utils_bin_to_hex((unsigned char*)tx_ser->str, tx_ser->len, hexbuf); + u_assert_str_eq(hexbuf, expected_tx_signed); + + cstr_free(tx_ser, true); + cstr_free(script, true); +} +void test_tx_sign_p2pkh_i2(btc_tx *tx) { + const char *tx_hex = "02000000027409797c31feecc4e69b51c58b477b72c53355743a6f6124f9d78221672df3700100000000ffffffff6e1709c1e2bdd85aed24dccfd48293993617f249d4d4381296a9c914be3e85e60100000000ffffffff01c07fdc0b0000000017a914ba277fd56b69177464fcb6a27a530f03740345ed8700000000"; + const char *script_hex_wrong = "76a9149b47fd7adc7a671ed059c9dcbf2eee2e882ea56b88ac"; + const char *script_hex_correct = "76a91481edb497b5ba6eb9e67b7ed50fb220395f76f95088ac"; + const char *pkey_wif = "cS8Xxe3MNoeWp5SckUfVw3WuaCNZ9eeQ4awjwkkARQ4xmXS5B1VW"; + const char *expected_sigder = "304502210084181199e59f30ab947fa751662b20899a3c89a45f13b5aff8096eae56a68aa502204ea5d1b96c15099315be0a3583628a09d18530a9f937a88e74fa8c24a49449a401"; + const char *expected_tx_signed = "02000000027409797c31feecc4e69b51c58b477b72c53355743a6f6124f9d78221672df370010000006a47304402205d44c682a69da1ca10e1149548bf7e7b53f0ce8f2d2bd2ea74026cba57cd4fe702200e0f9d87aafa1c88697238aaf1059b7718a97ff681efe474097221d456eb7ea2012102c5b9d2d528f13b7b745736f6fd198614a09200c3c5cb0554327e110b4a8efcf1ffffffff6e1709c1e2bdd85aed24dccfd48293993617f249d4d4381296a9c914be3e85e6010000006b48304502210084181199e59f30ab947fa751662b20899a3c89a45f13b5aff8096eae56a68aa502204ea5d1b96c15099315be0a3583628a09d18530a9f937a88e74fa8c24a49449a401210228f47e13841624ec8669f71176558927105207c138a65772331b7fc19c117b64ffffffff01c07fdc0b0000000017a914ba277fd56b69177464fcb6a27a530f03740345ed8700000000"; + uint64_t amount = 100000000; + int sighashtype = SIGHASH_ALL; + int inputindex = 1; + + int outlen; + uint8_t tx_data[strlen(tx_hex) / 2]; + utils_hex_to_bin(tx_hex, tx_data, strlen(tx_hex), &outlen); + uint8_t script_data[strlen(script_hex_correct) / 2]; + utils_hex_to_bin(script_hex_correct, script_data, strlen(script_hex_correct), &outlen); + cstring *script = cstr_new_buf(script_data, outlen); + uint8_t script_data_wrong[strlen(script_hex_wrong) / 2]; + utils_hex_to_bin(script_hex_wrong, script_data_wrong, strlen(script_hex_wrong), &outlen); + cstring *script_wrong = cstr_new_buf(script_data_wrong, outlen); + uint8_t expected_sigder_data[strlen(expected_sigder) / 2]; + utils_hex_to_bin(expected_sigder, expected_sigder_data, strlen(expected_sigder), &outlen); + uint8_t expected_tx_signed_data[strlen(expected_tx_signed) / 2]; + utils_hex_to_bin(expected_tx_signed, expected_tx_signed_data, strlen(expected_tx_signed), &outlen); + + btc_key pkey; + btc_privkey_init(&pkey); + btc_privkey_decode_wif(pkey_wif, &btc_chainparams_regtest, &pkey); + + uint8_t sigcomp[64] = {0}; + uint8_t sigder[76] = {0}; + int sigder_len = 0; + enum btc_tx_sign_result res = btc_tx_sign_input(tx, script_wrong, amount, &pkey, inputindex, sighashtype, sigcomp, sigder, &sigder_len); + u_assert_int_eq(res, BTC_SIGN_NO_KEY_MATCH); + btc_tx_in *in = vector_idx(tx->vin, 1); + cstr_resize(in->script_sig, 0); + res = btc_tx_sign_input(tx, script, amount, &pkey, inputindex, sighashtype, sigcomp, sigder, &sigder_len); + u_assert_int_eq(res, BTC_SIGN_OK); + //u_assert_mem_eq(sigcomp, expected_sigcomp_data, 64); + u_assert_mem_eq(sigder, expected_sigder_data, sigder_len); + + cstring* tx_ser = cstr_new_sz(1024); + btc_tx_serialize(tx_ser, tx, true); + + char hexbuf[tx_ser->len*2+1]; + utils_bin_to_hex((unsigned char*)tx_ser->str, tx_ser->len, hexbuf); + u_assert_str_eq(hexbuf, expected_tx_signed); + + cstr_free(tx_ser, true); + cstr_free(script, true); +} + +void test_tx_sign() { + test_tx_sign_p2sh_p2wpkh(); + btc_tx* tx = btc_tx_new(); + test_tx_sign_p2pkh(tx); + test_tx_sign_p2pkh_i2(tx); + btc_tx_free(tx); +} + diff --git a/test/unittester.c b/test/unittester.c new file mode 100644 index 000000000..dd2bb1f2a --- /dev/null +++ b/test/unittester.c @@ -0,0 +1,133 @@ +/********************************************************************** + * Copyright (c) 2015 Jonas Schnelli * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#if defined HAVE_CONFIG_H +#include "libbtc-config.h" +#endif + +#include +#include +#include +#include + +#include "utest.h" + +#ifdef HAVE_BUILTIN_EXPECT +#define EXPECT(x, c) __builtin_expect((x), (c)) +#else +#define EXPECT(x, c) (x) +#endif + +#define TEST_FAILURE(msg) \ + do { \ + fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, msg); \ + abort(); \ + } while (0) + +#define CHECK(cond) \ + do { \ + if (EXPECT(!(cond), 0)) { \ + TEST_FAILURE("test condition failed: " #cond); \ + } \ + } while (0) + +extern void test_sha_256(); +extern void test_sha_512(); +extern void test_sha_hmac(); +extern void test_cstr(); +extern void test_buffer(); +extern void test_utils(); +extern void test_serialize(); +extern void test_memory(); +extern void test_random(); +extern void test_bitcoin_hash(); +extern void test_base58check(); +extern void test_block_header(); +extern void test_bip32(); +extern void test_ecc(); +extern void test_vector(); +extern void test_aes(); +extern void test_tx_serialization(); +extern void test_tx_sighash(); +extern void test_tx_sighash_ext(); +extern void test_tx_negative_version(); +extern void test_script_parse(); +extern void test_script_op_codeseperator(); +extern void test_invalid_tx_deser(); +extern void test_tx_sign(); +extern void test_eckey(); + +#ifdef WITH_WALLET +extern void test_wallet(); +#endif + +#ifdef WITH_TOOLS +extern void test_tool(); +#endif + +#ifdef WITH_NET +extern void test_net_basics_plus_download_block(); +extern void test_protocol(); +extern void test_netspv(); +#endif + +extern void btc_ecc_start(); +extern void btc_ecc_stop(); + +int U_TESTS_RUN = 0; +int U_TESTS_FAIL = 0; + +int main() +{ + btc_ecc_start(); + + u_run_test(test_sha_256); + u_run_test(test_sha_512); + u_run_test(test_sha_hmac); + u_run_test(test_utils); + u_run_test(test_cstr); + u_run_test(test_buffer); + u_run_test(test_serialize); + + u_run_test(test_memory); + u_run_test(test_random); + u_run_test(test_bitcoin_hash); + u_run_test(test_base58check); + u_run_test(test_aes); + + u_run_test(test_bip32); + u_run_test(test_ecc); + u_run_test(test_vector); + u_run_test(test_tx_serialization); + u_run_test(test_invalid_tx_deser); + u_run_test(test_tx_sign); + u_run_test(test_tx_sighash); + u_run_test(test_tx_sighash_ext); + u_run_test(test_tx_negative_version); + u_run_test(test_block_header); + u_run_test(test_script_parse); + u_run_test(test_script_op_codeseperator); + + u_run_test(test_eckey); + +#ifdef WITH_WALLET + //u_run_test(test_wallet); +#endif + +#ifdef WITH_TOOLS + u_run_test(test_tool); +#endif + +#ifdef WITH_NET + u_run_test(test_netspv); + + u_run_test(test_protocol); + u_run_test(test_net_basics_plus_download_block); +#endif + + btc_ecc_stop(); + return U_TESTS_FAIL; +} diff --git a/test/utest.h b/test/utest.h new file mode 100644 index 000000000..e10dcec9f --- /dev/null +++ b/test/utest.h @@ -0,0 +1,229 @@ +/* + + Copyright (c) 2015 Douglas J. Bakkum + + 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. + +*/ + + +/* + +// +// Macros for light weight unit testing based on +// minunit.h from http://www.jera.com/techinfo/jtns/jtn002.html +// +// Example code: +// + +#include "utest.h" + + int U_TESTS_RUN = 0; + int U_TESTS_FAIL = 0; + + static void test_str(void) { + char * str = "hello"; + u_assert_str_eq(str, "hello"); + u_assert_str_eq(str, "hellooo"); + return; + } + + static void test_int(void) { + int i = 7; + u_assert_int_eq(i, 7); + u_assert_int_eq(i, 8); + return; + } + + static void test_mem(void) { + char * str = "hello"; + u_assert_mem_eq(str, "hello", 5); + u_assert_mem_eq(str, "hellooo", 5); + u_assert_mem_eq(str, "helooo", 5); + return; + } + + + int main(void) + { + u_run_test(test_str); + u_run_test(test_mem); + u_run_test(test_int); + if (!U_TESTS_FAIL) { + printf("\nALL TESTS PASSED\n\n"); + } + return U_TESTS_FAIL; + } +*/ + + +#ifndef _UTEST_H_ +#define _UTEST_H_ +#include +#include +#include + +#define u_run_test(TEST) \ + do { \ + int f_ = U_TESTS_FAIL; \ + TEST(); \ + U_TESTS_RUN++; \ + if (f_ == U_TESTS_FAIL) { \ + printf("PASSED - %s()\n", #TEST); \ + }; \ + } while (0) + +#define u_assert_int_eq(R, E) \ + { \ + int r_ = (R); \ + int e_ = (E); \ + do { \ + if (r_ != e_) { \ + printf("FAILED - %s() - Line %d\n", __func__, __LINE__); \ + printf("\tExpect: \t%d\n", e_); \ + printf("\tReceive:\t%d\n", r_); \ + U_TESTS_FAIL++; \ + return; \ + }; \ + } while (0); \ + } + +#define u_assert_uint32_eq(R, E) \ + { \ + uint64_t r_ = (R); \ + uint64_t e_ = (E); \ + do { \ + if (r_ != e_) { \ + printf("FAILED - %s() - Line %d\n", __func__, __LINE__); \ + printf("\tExpect: \t%" PRIu64 "\n", e_); \ + printf("\tReceive:\t%" PRIu64 "\n", r_); \ + U_TESTS_FAIL++; \ + return; \ + }; \ + } while (0); \ + } + +#define u_assert_str_eq(R, E) \ + { \ + const char* r_ = (R); \ + const char* e_ = (E); \ + do { \ + if (strcmp(r_, e_)) { \ + printf("FAILED - %s() - Line %d\n", __func__, __LINE__); \ + printf("\tExpect: \t%s\n", e_); \ + printf("\tReceive:\t%s\n", r_); \ + U_TESTS_FAIL++; \ + return; \ + }; \ + } while (0); \ + } + +#define u_assert_str_not_eq(R, E) \ + { \ + const char* r_ = (R); \ + const char* e_ = (E); \ + do { \ + if (!strcmp(r_, e_)) { \ + printf("FAILED - %s() - Line %d\n", __func__, __LINE__); \ + printf("\tNot expect:\t%s\n", e_); \ + printf("\tReceive:\t%s\n", r_); \ + U_TESTS_FAIL++; \ + return; \ + }; \ + } while (0); \ + } + +#define u_assert_str_has(R, E) \ + { \ + const char* r_ = (R); \ + const char* e_ = (E); \ + do { \ + if (!strstr(r_, e_)) { \ + printf("FAILED - %s() - Line %d\n", __func__, __LINE__); \ + printf("\tExpect: \t%s\n", e_); \ + printf("\tReceive:\t%s\n", r_); \ + U_TESTS_FAIL++; \ + return; \ + }; \ + } while (0); \ + } + +#define u_assert_str_has_not(R, E) \ + { \ + const char* r_ = (R); \ + const char* e_ = (E); \ + do { \ + if (strstr(r_, e_)) { \ + printf("FAILED - %s() - Line %d\n", __func__, __LINE__); \ + printf("\tNot expect:\t%s\n", e_); \ + printf("\tReceive:\t%s\n", r_); \ + U_TESTS_FAIL++; \ + return; \ + }; \ + } while (0); \ + } + +#define u_assert_mem_eq(R, E, L) \ + { \ + const void* r_ = (R); \ + const void* e_ = (E); \ + size_t l_ = (L); \ + do { \ + if (memcmp(r_, e_, l_)) { \ + printf("FAILED - %s() - Line %d\n", __func__, __LINE__); \ + printf("\tExpect: \t%s\n", utils_uint8_to_hex(e_, l_)); \ + printf("\tReceive:\t%s\n", utils_uint8_to_hex(r_, l_)); \ + U_TESTS_FAIL++; \ + return; \ + }; \ + } while (0); \ + } + +#define u_assert_is_null(R) \ + { \ + const void* r_ = (R); \ + do { \ + if (r_) { \ + printf("FAILED - %s() - Line %d\n", __func__, __LINE__); \ + printf("\tExpect: \tNULL\n"); \ + printf("\tReceive:\t%p\n", r_); \ + U_TESTS_FAIL++; \ + return; \ + }; \ + } while (0); \ + } + +#define u_assert_not_null(R) \ + { \ + const void* r_ = (R); \ + do { \ + if (!r_) { \ + printf("FAILED - %s() - Line %d\n", __func__, __LINE__); \ + printf("\tExpect: \tnot NULL\n"); \ + printf("\tReceive:\tNULL\n", r_); \ + U_TESTS_FAIL++; \ + return; \ + }; \ + } while (0); \ + } + +extern int U_TESTS_RUN; +extern int U_TESTS_FAIL; + +#endif diff --git a/test/utils_tests.c b/test/utils_tests.c new file mode 100644 index 000000000..2457ca863 --- /dev/null +++ b/test/utils_tests.c @@ -0,0 +1,56 @@ +/********************************************************************** + * Copyright (c) 2015 Jonas Schnelli * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include +#include +#include + +#include + +#include "utest.h" + +/* test a buffer overflow protection */ +static const char hash_buffer_exc[] = "28969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c128969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c1"; + +static const char hex2[] = "AA969cdfFFffFF3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c1"; + +void test_utils() +{ + + int outlen = 0; + unsigned char data[] = {0x00, 0xFF, 0x00, 0xAA, 0x00, 0xFF, 0x00, 0xAA}; + char hash[] = "28969cdfa74a12c82f3bad960b0b000aca2ac329deea5c2328ebc6f2ba9802c1"; + char hex[sizeof(data) * 2 + 1]; + unsigned char data2[sizeof(data)]; + uint8_t* hash_bin = utils_hex_to_uint8(hash); + char* new_data = utils_uint8_to_hex(hash_bin, BTC_HASH_LENGTH); + unsigned char data3[BTC_HASH_LENGTH*2]; + assert(strncmp(new_data, hash, BTC_HASH_LENGTH*2) == 0); + + utils_clear_buffers(); + + utils_bin_to_hex(data, sizeof(data), hex); + assert(strcmp(hex, "00ff00aa00ff00aa") == 0); + + utils_hex_to_bin(hex, data2, strlen(hex), &outlen); + assert(outlen == 8); + assert(memcmp(data, data2, outlen) == 0); + hash_bin = utils_hex_to_uint8(hash_buffer_exc); + + /* test upper and lowercase A / F */ + utils_hex_to_bin(hex2, data3, strlen(hex2), &outlen); + hash_bin = utils_hex_to_uint8(hex2); + utils_clear_buffers(); + + uint256 hash_rev; + uint256 hash_check = {0x6f,0xe2,0x8c,0x0a,0xb6,0xf1,0xb3,0x72,0xc1,0xa6,0xa2,0x46,0xae,0x63,0xf7,0x4f,0x93,0x1e,0x83,0x65,0xe1,0x5a,0x08,0x9c,0x68,0xd6,0x19,0x00,0x00,0x00,0x00,0x00}; + utils_uint256_sethex("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", hash_rev); + u_assert_mem_eq(hash_rev, hash_check, 32); + + utils_uint256_sethex("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943", hash_rev); + utils_uint256_sethex("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206", hash_rev); +} diff --git a/test/vector_tests.c b/test/vector_tests.c new file mode 100644 index 000000000..afbc77da1 --- /dev/null +++ b/test/vector_tests.c @@ -0,0 +1,109 @@ +/********************************************************************** + * Copyright (c) 2015 Jonas Schnelli * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include +#include +#include + +#include +#include + +struct teststruct { + void* dummy1; + void* dummy2; +}; + +void free_dummy(void* data) +{ + btc_free(((struct teststruct*)data)->dummy1); + btc_free(((struct teststruct*)data)->dummy2); + btc_free((struct teststruct*)data); +} + +void test_vector() +{ + btc_bool res; + char str0[] = "string"; + char str1[] = "rumba"; + + vector* vec = vector_new(10, NULL); + assert(vec != NULL); + assert(vec->len == 0); + assert(vec->alloc > 0); + + res = vector_add(vec, str0); + assert(res == true); + assert(vec->len == 1); + + res = vector_add(vec, str1); + assert(res == true); + assert(vec->len == 2); + + assert(vector_find(vec, str0) == 0); + assert(vector_find(vec, "test") == -1); + assert(vector_find(vec, str1) == 1); + + assert(strcmp(vector_idx(vec, 0), "string") == 0); + assert(strcmp(vector_idx(vec, 1), "rumba") == 0); + + vector_remove_idx(vec, 0); + assert(res == true); + assert(strcmp(vector_idx(vec, 0), "rumba") == 0); + + vector_free(vec, true); + + vec = vector_new(10, free); + res = vector_add(vec, strdup("TEST0")); + assert(res == true); + res = vector_add(vec, strdup("TEST1")); + assert(res == true); + + char* a_str = strdup("TEST2"); + res = vector_add(vec, a_str); + assert(res == true); + assert(vec->len == 3); + res = vector_remove(vec, a_str); + assert(res == true); + assert(vec->len == 2); + vector_free(vec, true); + + + /* test resize */ + vec = vector_new(1, free); + res = vector_resize(vec, 30); + assert(res == true); + res = vector_resize(vec, 30); + assert(res == true); + char str[80]; + int i; + for (i = 0; i < 20; i++) { + sprintf(str, "TEST%d", i); + res = vector_add(vec, strdup(str)); + assert(res == true); + assert(vec->len == (size_t)i + 1); + } + + res = vector_resize(vec, 5); + assert(res == true); + assert(strcmp(vector_idx(vec, 0), "TEST0") == 0); + assert(strcmp(vector_idx(vec, 4), "TEST4") == 0); + assert(vector_idx(vec, 5) == NULL); + + vector_remove_range(vec, 0, 4); + assert(strcmp(vector_idx(vec, 0), "TEST4") == 0); + vector_free(vec, true); + + + /* test custom free callback handler */ + struct teststruct* some_data = btc_calloc(1, sizeof(struct teststruct)); + some_data->dummy1 = btc_calloc(1, 10); + some_data->dummy2 = btc_calloc(1, 10); + + vec = vector_new(1, free_dummy); + vector_add(vec, some_data); + vector_free(vec, true); +} diff --git a/test/wallet_tests.c b/test/wallet_tests.c new file mode 100644 index 000000000..8d0a45418 --- /dev/null +++ b/test/wallet_tests.c @@ -0,0 +1,168 @@ +/********************************************************************** + * Copyright (c) 2015 Jonas Schnelli * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include + +#include "utest.h" +#include +#include + +static const char *wallettmpfile = "/tmp/dummy"; + +void test_wallet() +{ + unlink(wallettmpfile); + btc_wallet *wallet = btc_wallet_new(&btc_chainparams_main); + int error; + btc_bool created; + u_assert_int_eq(btc_wallet_load(wallet, wallettmpfile, &error, &created), true); + + char *xpriv = "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7"; + + btc_hdnode node; + btc_wallet_hdnode *node2, *node3; + btc_bool suc = btc_hdnode_deserialize(xpriv, &btc_chainparams_main, &node); + u_assert_int_eq(suc, 1); + btc_wallet_set_master_key_copy(wallet, &node); + + node2 = btc_wallet_next_key(wallet); + + btc_wallet_free(wallet); + + wallet = btc_wallet_new(&btc_chainparams_main); + u_assert_int_eq(btc_wallet_load(wallet, wallettmpfile, &error, &created), true); + node3 = btc_wallet_next_key(wallet); + + //should not be equal because we autoincrementing child index + u_assert_int_eq(memcmp(node2->hdnode->private_key, node3->hdnode->private_key, sizeof(node2->hdnode->private_key)) != 0, 1); + btc_wallet_hdnode_free(node3); + + //force to regenerate child 0 + wallet->next_childindex = 0; + node3 = btc_wallet_next_key(wallet); + btc_wallet_hdnode_free(node3); + wallet->next_childindex = 0; + node3 = btc_wallet_next_key(wallet); + + //now it should be equal + u_assert_int_eq(memcmp(node2->hdnode->private_key, node3->hdnode->private_key, sizeof(node2->hdnode->private_key)), 0); + + uint160 hash160; + + vector *addrs = vector_new(1, free); + btc_wallet_get_addresses(wallet, addrs); + u_assert_int_eq(addrs->len, 4); + u_assert_int_eq(strcmp(addrs->data[3],"1JQheacLPdM5ySCkrZkV66G2ApAXe1mqLj"), 0) + u_assert_int_eq(strcmp(addrs->data[0],"1LZaBnH11M2yN5ZNiK67yUbaspfX6XKmRr"), 0) + + vector_free(addrs, true); + btc_wallet_flush(wallet); + btc_wallet_free(wallet); + btc_wallet_hdnode_free(node2); + btc_wallet_hdnode_free(node3); + + wallet = btc_wallet_new(&btc_chainparams_main); + u_assert_int_eq(btc_wallet_load(wallet, wallettmpfile, &error, &created), true); + addrs = vector_new(1, free); + btc_wallet_get_addresses(wallet, addrs); + + u_assert_int_eq(addrs->len, 4); + u_assert_int_eq(strcmp(addrs->data[3],"1JQheacLPdM5ySCkrZkV66G2ApAXe1mqLj"), 0) + u_assert_int_eq(strcmp(addrs->data[0],"1LZaBnH11M2yN5ZNiK67yUbaspfX6XKmRr"), 0) + + // get a hdnode and compare + btc_wallet_hdnode *checknode = btc_wallet_find_hdnode_byaddr(wallet, addrs->data[0]); + + hash160[0] = wallet->chain->b58prefix_pubkey_address; + btc_hdnode_get_hash160(checknode->hdnode, hash160+1); + + size_t addrsize = 98; + char addr[addrsize]; + btc_base58_encode_check(hash160, sizeof(uint160)+1, addr, addrsize); + u_assert_int_eq(strcmp(addr, addrs->data[0]), 0); + vector_free(addrs, true); + + // add some txes + static const char *hextx_coinbase = "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6403c4210637e4b883e5bda9e7a59ee4bb99e9b1bc468ae3c311fe570bbbaadade4d0c6ae4fd009f2045e7808d8c569b1eb63ecdb802000000f09f909f0f4d696e6564206279206368656e626f000000000000000000000000000000000000000000000000c036008601bb734c95000000001976a914bef5a2f9a56a94aab12459f72ad9cf8cf19c7bbe88aca7525e3a"; + + static const char *hextx_ntx = "0100000001f48eef277d1338def6e6656b9226a82cb63b0591d15844e896fb875d95990edb000000006b483045022100ed3681313a3a52c1beb2f94f4cbba80d341652676463516cfd3e7fcfb00fdb8902201ff1acfba71bbb4436a990eac8f2ec3944a917859e2b02c9c113445147f23b9c0121021b8f3b66d044fabca1295e6ed16558909ebea941404ff376dcaec106cefe3526feffffff02e5b32400000000001976a91444d6af9359434935f1e9a0f43643eae59bf64d1388ace417541a030000001976a914d69367208e54bfdfa8ed1c77e4d8f6730b9777e388acb8210600"; + + // form coinbase tx + uint8_t tx_data[strlen(hextx_coinbase) / 2]; + int outlen ; + utils_hex_to_bin(hextx_coinbase, tx_data, strlen(hextx_coinbase), &outlen); + btc_wtx* wtx = btc_wallet_wtx_new(); + btc_tx_deserialize(tx_data, outlen, wtx->tx, NULL, true); + + // add coinbase tx + wtx->height = 0; + btc_wallet_add_wtx_move(wallet, wtx); + + uint64_t amount = btc_wallet_wtx_get_credit(wallet, wtx); + u_assert_uint32_eq(amount, 0); + wallet->bestblockheight = 200; + amount = btc_wallet_wtx_get_credit(wallet, wtx); + + u_assert_uint32_eq(amount, 2504815547); + btc_wallet_wtx_free(wtx); + + // form normal tx + uint8_t tx_data_n[strlen(hextx_ntx) / 2]; + utils_hex_to_bin(hextx_ntx, tx_data_n, strlen(hextx_ntx), &outlen); + wtx = btc_wallet_wtx_new(); + btc_tx_deserialize(tx_data_n, outlen, wtx->tx, NULL, true); + + // add normal tx + wtx->height = 0; + btc_wallet_add_wtx_move(wallet, wtx); + + amount = btc_wallet_wtx_get_credit(wallet, wtx); + btc_wallet_wtx_free(wtx); + + u_assert_uint32_eq(amount, 13326620644); + + btc_wallet_flush(wallet); + btc_wallet_free(wallet); + + wallet = btc_wallet_new(&btc_chainparams_main); + u_assert_int_eq(btc_wallet_load(wallet, wallettmpfile, &error, &created), true); + + amount = btc_wallet_get_balance(wallet); + + vector *unspents = vector_new(10, (void (*)(void*))btc_wallet_output_free); + btc_wallet_get_unspent(wallet, unspents); + + amount = btc_wallet_get_balance(wallet); + + unsigned int i; + unsigned int found = 0; + for (i = 0; i < unspents->len; i++) + { + btc_output *output = unspents->data[i]; + uint256 hash; + btc_tx_hash(output->wtx->tx, hash); + char str[65]; + utils_bin_to_hex(hash, sizeof(hash), str); + utils_reverse_hex(str, 64); + if (strcmp(str, "963b8b8e2d2025b64fd8144557604e98d2fa67a5386f8a06597d810f27ab60d7") == 0) + found++; + if (strcmp(str, "b99c4c532643a376c440b3cc612ec2fd96c15d1f50a6c40b112e4fd0c880d661") == 0) + found++; + } + vector_free(unspents, true); + u_assert_int_eq(found, 2); + + amount = btc_wallet_get_balance(wallet); + u_assert_uint32_eq(amount, 13326620644); + wallet->bestblockheight = 200; + amount = btc_wallet_get_balance(wallet); + u_assert_uint32_eq(amount, 13326620644+2504815547); + + btc_wallet_free(wallet); +} diff --git a/tooltests.py b/tooltests.py new file mode 100755 index 000000000..e38ebe537 --- /dev/null +++ b/tooltests.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# Copyright (c) 2016 Jonas Schnelli +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +import sys, os +from subprocess import call + +valgrind = True; +commands = [] +commands.append(["-v", 0]) +commands.append(["-foobar", 1]) +commands.append(["-c genkey", 0]) +commands.append(["-c genkey --testnet", 0]) +commands.append(["-c genkey --regtest", 0]) +commands.append(["", 1]) +commands.append(["-c hdprintkey", 1]) +commands.append(["-c hdprintkey -p xpub6MR9tbm8V5pGFTQ9hTATxd4kPgdKKqU75ED8s3rddrSknLHgZy1H4Wh596jgoYNH7WNcKEVM1wfKD2pTSdj5Hm7CMJwwyRjHYPQCT2LJXwm", 0]) +commands.append(["-c hdprintkey -p tprv8ZgxMBicQKsPegfnEE6sgR64tuPn72fX965MeazaJC72Sfi5JfqLrCnQmA9vTJTCxfDpiq2jWBSLc8L2Uy497ij5iT4KDvXYZRWxCNWPugm", 1]) +commands.append(["-c hdprintkey -p tprv8ZgxMBicQKsPegfnEE6sgR64tuPn72fX965MeazaJC72Sfi5JfqLrCnQmA9vTJTCxfDpiq2jWBSLc8L2Uy497ij5iT4KDvXYZRWxCNWPugm --testnet", 0]) +commands.append(["-c pubfrompriv -p L15mEfW7s13utgsTrziK52z6HC1jEZbp3R9ma7qPfwCphhtJFmjp", 0]) #successfull WIF to pub +commands.append(["-c pubfrompriv", 1]) #missing required argument +commands.append(["-c pubfrompriv -p L15mEfW7s13utgsTrziK52z6HC1jEZbp3R9", 1]) #invalid WIF key +commands.append(["-c addrfrompub -p 02b905509e4c9bd9b2fc87c95a6e6897f70ee9fd8bd2f1d9dc9a270b62ec11f47e", 1]) +commands.append(["-c addrfrompub -k 02b905509e4c9bd9b2fc87c95a6e6897f70ee9fd8bd2f1d9dc9a270b62ec11f47e", 0]) +commands.append(["-c hdgenmaster", 0]) +commands.append(["-c hdderive -p xpub6MR9tbm8V5pGFTQ9hTATxd4kPgdKKqU75ED8s3rddrSknLHgZy1H4Wh596jgoYNH7WNcKEVM1wfKD2pTSdj5Hm7CMJwwyRjHYPQCT2LJXwm -m m/100h/10h/100/10", 1]) #hardened keypath with pubkey +commands.append(["-c hdderive -p xprv9s21ZrQH143K3jC7xiaZ4EWrJdwJgtrEBmbVBpnoLNo91RCkdzkviG2GjgmN7xaDSDgPihJWu7JRGVcLUSoJdW8fHhGSpjQGUMoU2e8KjBY -m m/100h/10h/100/10", 0]) +commands.append(["-c hdderive -p xprv9s21ZrQH143K3jC7xiaZ4EWrJdwJgtrEBmbVBpnoLNo91RCkdzkviG2GjgmN7xaDSDgPihJWu7JRGVcLUSoJdW8fHhGSpjQGUMoU2e8KjBY -m n/100h/10h/100/10", 1]) #wrong keypath prefix +commands.append(["-c hdderive -p xpub6MR9tbm8V5pGFTQ9hTATxd4kPgdKKqU75ED8s3rddrSknLHgZy1H4Wh596jgoYNH7WNcKEVM1wfKD2pTSdj5Hm7CMJwwyRjHYPQCT2LJXwm -m m/100/10/100/10", 0]) +commands.append(["-c hdderive", 1]) #missing key +commands.append(["-c hdderive -p xpub6MR9tbm8V5pGFTQ9hTATxd4kPgdKKqU75ED8s3rddrSknLHgZy1H4Wh596jgoYNH7WNcKEVM1wfKD2pTSdj5Hm7CMJwwyRjHYPQCT2LJXwm", 1]) #missing keypath + +commands2 = [] +commands2.append(["0200000001554fb2f97f8fe299bf01004c70ec1930bc3c51fe162d1f81b18089e4f7cae470000000006a47304402207f5af3a9724be2946741e15b89bd2c989c9c20a0dfb519cb14b4efdaad945dc502206507ec7a3ba91be7794312961294c7a09a7bc693d918ab5a93712ff8576995fc012103caef57fae78ec425f5ff99d805fddd2417f3bfa7c7b0ec3b6b860cf6cc0e1d99ffffffff0100c63e05000000001976a91415e7469e21938db38e943abd7a2c1073c00e0edd88ac00000000", 0]) +commands2.append(["-v", 1]) +commands2.append(["?", 1]) +commands2.append(["-t -s 10 -d 0200000001554fb2f9", 1]) +commands2.append(["-t -s 5 -i 127.0.0.1:18444 0200000001554fb2f97f8fe299bf01004c70ec1930bc3c51fe162d1f81b18089e4f7cae470000000006a47304402207f5af3a9724be2946741e15b89bd2c989c9c20a0dfb519cb14b4efdaad945dc502206507ec7a3ba91be7794312961294c7a09a7bc693d918ab5a93712ff8576995fc012103caef57fae78ec425f5ff99d805fddd2417f3bfa7c7b0ec3b6b860cf6cc0e1d99ffffffff0100c63e05000000001976a91415e7469e21938db38e943abd7a2c1073c00e0edd88ac00000000", 0]) + + +baseCommand = "./bitcointool" +baseCommand2 = "./bitcoin-send-tx" +if valgrind == True: + baseCommand = "valgrind --leak-check=full "+baseCommand + baseCommand2 = "valgrind --leak-check=full "+baseCommand2 + +errored = False +for cmd in commands: + retcode = call(baseCommand+" "+cmd[0], shell=True) + if retcode != cmd[1]: + print("ERROR during "+cmd[0]) + sys.exit(os.EX_DATAERR) + +errored = False +for cmd in commands2: + retcode = call(baseCommand2+" "+cmd[0], shell=True) + if retcode != cmd[1]: + print("ERROR during "+cmd[0]) + sys.exit(os.EX_DATAERR) + +sys.exit(os.EX_OK) From c084ef9b79e4c0b0d0d7f794717a783f86d1bcd7 Mon Sep 17 00:00:00 2001 From: Douglas Roark Date: Tue, 13 Feb 2018 23:07:52 -0800 Subject: [PATCH 4/4] Enable libbtc compilation Also do a bit of random cleanup of Autotools files. --- configure.ac | 35 +++++++++++++++++++++----------- cppForSwig/Makefile.am | 8 +++++--- cppForSwig/cryptopp/configure.ac | 10 +++++++++ 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/configure.ac b/configure.ac index 2ae8b97cd..fec8646b0 100644 --- a/configure.ac +++ b/configure.ac @@ -178,17 +178,28 @@ if test "x$want_tests" = "xyes"; then AC_CONFIG_FILES(cppForSwig/gtest/Makefile) fi +dnl ac_configure_args can only be set once and affects all subdirs. +dnl Place all params here. +dnl FCGI - No customs +dnl Crypto++ - No customs +dnl libchacha20poly1305 - No customs +dnl libsecp256k1 (libbtc) - --disable-shared --with-pic --with-bignum=no --enable-experimental --enable-module-ecdh +ac_configure_args="${orig_config_args} --disable-shared --with-pic --with-bignum=no --enable-experimental --enable-module-ecdh" +AC_CONFIG_SUBDIRS([cppForSwig/fcgi cppForSwig/cryptopp cppForSwig/libbtc]) + AC_OUTPUT -echo " CC = $CC" -echo " CFLAGS = $CFLAGS" -echo " CPP = $CPP" -echo " CPPFLAGS = $CPPFLAGS" -echo " CXX = $CXX" -echo " CXXFLAGS = $CXXFLAGS" -echo " LDFLAGS = $LDFLAGS" -echo " LD = $LD" -echo " with tests = $want_tests" -echo " with benchmarks = $want_benchmarks" -echo " debug symbols = $want_debug" -echo " with GUI = $with_gui" +echo " Armory Autotools flags" +echo " CC = $CC" +echo " CFLAGS = $CFLAGS" +echo " CPP = $CPP" +echo " CPPFLAGS = $CPPFLAGS" +echo " CXX = $CXX" +echo " CXXFLAGS = $CXXFLAGS" +echo " LDFLAGS = $LDFLAGS" +echo " LD = $LD" +echo " ac_configure_args = $ac_configure_args" +echo " with tests = $want_tests" +echo " with benchmarks = $want_benchmarks" +echo " debug symbols = $want_debug" +echo " with GUI = $with_gui" diff --git a/cppForSwig/Makefile.am b/cppForSwig/Makefile.am index dffd46d37..2d6092acd 100644 --- a/cppForSwig/Makefile.am +++ b/cppForSwig/Makefile.am @@ -16,8 +16,8 @@ noinst_PROGRAMS += chacha20poly1305/chacha20poly1305bench BENCHMARKS += chacha20poly1305/chacha20poly1305bench endif -DIST_SUBDIRS = lmdb fcgi cryptopp -SUBDIRS = lmdb fcgi cryptopp $(MAYBE_BUILD) +DIST_SUBDIRS = lmdb fcgi cryptopp libbtc +SUBDIRS = lmdb fcgi cryptopp libbtc $(MAYBE_BUILD) SWIG_FLAGS = -c++ -python -threads AM_CXXFLAGS = $(CXXFLAGS) -std=c++11 @@ -90,12 +90,14 @@ libCppBlockUtils_la_SOURCES = $(CPPBLOCKUTILS_SOURCE_FILES) \ libCppBlockUtils_la_CPPFLAGS = $(AM_CPPFLAGS) $(INCLUDE_FILES) libCppBlockUtils_la_CXXFLAGS = $(AM_CXXFLAGS) -Ilmdb \ -Icryptopp \ + -Ilibbtc/src/secp256k1/include \ $(AX_SWIG_PYTHON_CPPFLAGS) \ $(EXTRA_PYTHON_INCLUDES) \ -D__STDC_LIMIT_MACROS libCppBlockUtils_la_LIBADD = -Llmdb -llmdb \ ./cryptopp/libcryptopp.la \ - -lpthread + ./libbtc/src/secp256k1/libsecp256k1.la \ + -lpthread libCppBlockUtils_la_LDFLAGS = $(LDFLAGS) # ChaCha20Poly1305 library diff --git a/cppForSwig/cryptopp/configure.ac b/cppForSwig/cryptopp/configure.ac index 8e944943d..84e9d512a 100644 --- a/cppForSwig/cryptopp/configure.ac +++ b/cppForSwig/cryptopp/configure.ac @@ -129,3 +129,13 @@ AM_CONDITIONAL([IS_X86], [test x$HOST_MACHINE = xx86]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT + +echo " Crypto++ flags" +echo " CC = $CC" +echo " CFLAGS = $CFLAGS" +echo " CPP = $CPP" +echo " CPPFLAGS = $CPPFLAGS" +echo " CXX = $CXX" +echo " CXXFLAGS = $CXXFLAGS" +echo " LDFLAGS = $LDFLAGS" +echo " LD = $LD"