From b01dd94bf2c22dec963e09cec866d15033fa5518 Mon Sep 17 00:00:00 2001 From: Tom St Denis Date: Fri, 28 Feb 2003 16:04:58 +0000 Subject: [PATCH] added libtommath-0.05 --- bn.c | 322 ++++++++++++++++++++++++++++++++++++++-------------- bn.h | 15 ++- bn.pdf | Bin 149256 -> 151874 bytes bn.tex | 126 +++++++++++--------- changes.txt | 13 +++ demo.c | 107 +++++++++++------ makefile | 7 +- 7 files changed, 412 insertions(+), 178 deletions(-) diff --git a/bn.c b/bn.c index 429e1c8..4a0f4f9 100644 --- a/bn.c +++ b/bn.c @@ -26,7 +26,7 @@ static const char *s_rmap = #ifdef DEBUG static char *_funcs[1000]; -static int _ifuncs; +int _ifuncs; #define REGFUNC(name) { if (_ifuncs == 999) { printf("TROUBLE\n"); exit(0); } _funcs[_ifuncs++] = name; } #define DECFUNC() --_ifuncs; @@ -75,13 +75,18 @@ error: /* init a new bigint */ int mp_init(mp_int *a) { + REGFUNC("mp_init"); a->dp = calloc(sizeof(mp_digit), 16); if (a->dp == NULL) { + DECFUNC(); return MP_MEM; } a->used = 0; a->alloc = 16; a->sign = MP_ZPOS; + + VERIFY(a); + DECFUNC(); return MP_OKAY; } @@ -125,6 +130,7 @@ static int mp_grow(mp_int *a, int size) tmp = calloc(sizeof(mp_digit), size); if (tmp == NULL) { + DECFUNC(); return MP_MEM; } for (i = 0; i < a->used; i++) { @@ -191,7 +197,7 @@ void mp_set(mp_int *a, mp_digit b) /* set a 32-bit const */ int mp_set_int(mp_int *a, unsigned long b) { - int x; + int x, res; REGFUNC("mp_set_int"); VERIFY(a); @@ -199,9 +205,20 @@ int mp_set_int(mp_int *a, unsigned long b) /* set four bits at a time, simplest solution to the what if DIGIT_BIT==7 case */ for (x = 0; x < 8; x++) { - mp_mul_2d(a, 4, a); + + /* shift the number up four bits */ + if ((res = mp_mul_2d(a, 4, a)) != MP_OKAY) { + DECFUNC(); + return res; + } + + /* OR in the top four bits of the source */ a->dp[0] |= (b>>28)&15; + + /* shift the source up to the next four bits */ b <<= 4; + + /* ensure that digits are not clamped off */ a->used += 32/DIGIT_BIT + 1; } @@ -213,16 +230,22 @@ int mp_set_int(mp_int *a, unsigned long b) /* init a mp_init and grow it to a given size */ int mp_init_size(mp_int *a, int size) { - int res; REGFUNC("mp_init_size"); - if ((res = mp_init(a)) != MP_OKAY) { + /* pad up so there are at least 16 zero digits */ + size += 32 - (size & 15); + + a->dp = calloc(sizeof(mp_digit), size); + if (a->dp == NULL) { DECFUNC(); - return res; + return MP_MEM; } - res = mp_grow(a, size); + a->used = 0; + a->alloc = size; + a->sign = MP_ZPOS; + DECFUNC(); - return res; + return MP_OKAY; } /* copy, b = a */ @@ -246,9 +269,12 @@ int mp_copy(mp_int *a, mp_int *b) return res; } + /* zero b and copy the parameters over */ mp_zero(b); b->used = a->used; b->sign = a->sign; + + /* copy all the digits */ for (n = 0; n < a->used; n++) { b->dp[n] = a->dp[n]; } @@ -482,7 +508,7 @@ int mp_mod_2d(mp_int *a, int b, mp_int *c) return res; } - /* zero digits above */ + /* zero digits above the last digit of the modulus */ for (x = (b/DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) { c->dp[x] = 0; } @@ -505,9 +531,11 @@ int mp_div_2d(mp_int *a, int b, mp_int *c, mp_int *d) VERIFY(c); if (d != NULL) { VERIFY(d); } + /* if the shift count is <= 0 then we do no work */ if (b <= 0) { res = mp_copy(a, c); if (d != NULL) { mp_zero(d); } + DECFUNC(); return res; } @@ -516,6 +544,7 @@ int mp_div_2d(mp_int *a, int b, mp_int *c, mp_int *d) return res; } + /* get the remainder */ if (d != NULL) { if ((res = mp_mod_2d(a, b, &t)) != MP_OKAY) { mp_clear(&t); @@ -539,8 +568,13 @@ int mp_div_2d(mp_int *a, int b, mp_int *c, mp_int *d) if (D != 0) { r = 0; for (x = c->used - 1; x >= 0; x--) { + /* get the lower bits of this word in a temp */ rr = c->dp[x] & ((mp_digit)((1U<dp[x] = (c->dp[x] >> D) | (r << (DIGIT_BIT-D)); + + /* set the carry to the carry bits of the current word found above */ r = rr; } } @@ -587,8 +621,13 @@ int mp_mul_2d(mp_int *a, int b, mp_int *c) if (d != 0) { r = 0; for (x = 0; x < c->used; x++) { + /* get the higher bits of the current word */ rr = (c->dp[x] >> (DIGIT_BIT - d)) & ((mp_digit)((1U<dp[x] = ((c->dp[x] << d) | r) & MP_MASK; + + /* set the carry to the carry bits of the current word */ r = rr; } } @@ -694,16 +733,26 @@ static int s_mp_add(mp_int *a, mp_int *b, mp_int *c) /* add digits from lower part */ u = 0; for (i = 0; i < min; i++) { + /* T[i] = A[i] + B[i] + U */ t.dp[i] = a->dp[i] + b->dp[i] + u; + + /* U = carry bit of T[i] */ u = (t.dp[i] >> DIGIT_BIT) & 1; + + /* take away carry bit from T[i] */ t.dp[i] &= MP_MASK; } - /* now copy higher words if any */ + /* now copy higher words if any, that is in A+B if A or B has more digits add those in */ if (min != max) { for (; i < max; i++) { + /* T[i] = X[i] + U */ t.dp[i] = x->dp[i] + u; + + /* U = carry bit of T[i] */ u = (t.dp[i] >> DIGIT_BIT) & 1; + + /* take away carry bit from T[i] */ t.dp[i] &= MP_MASK; } } @@ -744,16 +793,26 @@ static int s_mp_sub(mp_int *a, mp_int *b, mp_int *c) /* sub digits from lower part */ u = 0; for (i = 0; i < min; i++) { + /* T[i] = A[i] - B[i] - U */ t.dp[i] = a->dp[i] - (b->dp[i] + u); + + /* U = carry bit of T[i] */ u = (t.dp[i] >> DIGIT_BIT) & 1; + + /* Clear carry from T[i] */ t.dp[i] &= MP_MASK; } - /* now copy higher words if any */ + /* now copy higher words if any, e.g. if A has more digits than B */ if (min != max) { for (; i < max; i++) { + /* T[i] = A[i] - U */ t.dp[i] = a->dp[i] - u; + + /* U = carry bit of T[i] */ u = (t.dp[i] >> DIGIT_BIT) & 1; + + /* Clear carry from T[i] */ t.dp[i] &= MP_MASK; } } @@ -768,14 +827,20 @@ static int s_mp_sub(mp_int *a, mp_int *b, mp_int *c) /* low level multiplication */ #define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1) -/* fast multiplier */ -/* multiplies |a| * |b| and only computes upto digs digits of result */ +/* Fast (comba) multiplier + * + * This is the fast column-array [comba] multiplier. It is designed to compute + * the columns of the product first then handle the carries afterwards. This + * has the effect of making the nested loops that compute the columns very + * simple and schedulable on super-scalar processors. + * + */ static int fast_s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs) { mp_int t; int res, pa, pb, ix, iy; mp_word W[512], *_W; - mp_digit tmpx, *tmpt, *tmpy; + mp_digit tmpx, *tmpy; REGFUNC("fast_s_mp_mul_digs"); VERIFY(a); @@ -788,22 +853,44 @@ static int fast_s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs) } t.used = digs; - /* clear temp buf */ + /* clear temp buf (the columns) */ memset(W, 0, digs*sizeof(mp_word)); + /* calculate the columns */ pa = a->used; for (ix = 0; ix < pa; ix++) { + + /* this multiplier has been modified to allow you to control how many digits + * of output are produced. So at most we want to make upto "digs" digits + * of output + */ pb = MIN(b->used, digs - ix); + + /* setup some pointer aliases to simplify the inner loop */ tmpx = a->dp[ix]; - tmpt = &(t.dp[ix]); tmpy = b->dp; _W = &(W[ix]); + + /* this adds products to distinct columns (at ix+iy) of W + * note that each step through the loop is not dependent on + * the previous which means the compiler can easily unroll + * the loop without scheduling problems + */ for (iy = 0; iy < pb; iy++) { *_W++ += ((mp_word)tmpx) * ((mp_word)*tmpy++); } } - /* now convert the array W downto what we need */ + /* At this point W[] contains the sums of each column. To get the + * correct result we must take the extra bits from each column and + * carry them down + * + * Note that while this adds extra code to the multiplier it saves time + * since the carry propagation is removed from the above nested loop. + * This has the effect of reducing the work from N*(N+N*c)==N^2 + c*N^2 to + * N^2 + N*c where c is the cost of the shifting. On very small numbers + * this is slower but on most cryptographic size numbers it is faster. + */ for (ix = 1; ix < digs; ix++) { W[ix] = W[ix] + (W[ix-1] >> ((mp_word)DIGIT_BIT)); t.dp[ix-1] = W[ix-1] & ((mp_word)MP_MASK); @@ -831,10 +918,15 @@ static int s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs) VERIFY(b); VERIFY(c); - /* can we use the fast multiplier? */ + /* can we use the fast multiplier? + * + * The fast multiplier can be used if the output will have less than + * 512 digits and the number of digits won't affect carry propagation + */ if ((digs < 512) && digs < (1<<( (CHAR_BIT*sizeof(mp_word)) - (2*DIGIT_BIT)))) { + res = fast_s_mp_mul_digs(a,b,c,digs); DECFUNC(); - return fast_s_mp_mul_digs(a,b,c,digs); + return res; } if ((res = mp_init_size(&t, digs)) != MP_OKAY) { @@ -843,16 +935,29 @@ static int s_mp_mul_digs(mp_int *a, mp_int *b, mp_int *c, int digs) } t.used = digs; + /* compute the digits of the product directly */ pa = a->used; for (ix = 0; ix < pa; ix++) { + /* set the carry to zero */ u = 0; + + /* limit ourselves to making digs digits of output */ pb = MIN(b->used, digs - ix); + + /* setup some aliases */ tmpx = a->dp[ix]; tmpt = &(t.dp[ix]); tmpy = b->dp; + + /* compute the columns of the output and propagate the carry */ for (iy = 0; iy < pb; iy++) { + /* compute the column as a mp_word */ r = ((mp_word)*tmpt) + ((mp_word)tmpx) * ((mp_word)*tmpy++) + ((mp_word)u); + + /* the new column is the lower part of the result */ *tmpt++ = (mp_digit)(r & ((mp_word)MP_MASK)); + + /* get the carry word from the result */ u = (mp_digit)(r >> ((mp_word)DIGIT_BIT)); } if (ix+iyused + b->used + 1; + /* like the other comba method we compute the columns first */ pa = a->used; pb = b->used; memset(&W[digs], 0, (pa + pb + 1 - digs) * sizeof(mp_word)); for (ix = 0; ix < pa; ix++) { + /* pointer aliases */ tmpx = a->dp[ix]; - tmpt = &(t.dp[digs]); tmpy = b->dp + (digs - ix); _W = &(W[digs]); + + /* compute column products for digits above the minimum */ for (iy = digs - ix; iy < pb; iy++) { *_W++ += ((mp_word)tmpx) * ((mp_word)*tmpy++); } @@ -931,8 +1046,9 @@ static int s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs) /* can we use the fast multiplier? */ if (((a->used + b->used + 1) < 512) && MAX(a->used, b->used) < (1<<( (CHAR_BIT*sizeof(mp_word)) - (2*DIGIT_BIT)))) { + res = fast_s_mp_mul_high_digs(a,b,c,digs); DECFUNC(); - return fast_s_mp_mul_high_digs(a,b,c,digs); + return res; } if ((res = mp_init_size(&t, a->used + b->used + 1)) != MP_OKAY) { @@ -962,12 +1078,25 @@ static int s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs) return MP_OKAY; } -/* fast squaring */ +/* fast squaring + * + * This is the comba method where the columns of the product are computed first + * then the carries are computed. This has the effect of making a very simple + * inner loop that is executed the most + * + * W2 represents the outer products and W the inner. + * + * A further optimizations is made because the inner products are of the form + * "A * B * 2". The *2 part does not need to be computed until the end which is + * good because 64-bit shifts are slow! + * + * + */ static int fast_s_mp_sqr(mp_int *a, mp_int *b) { mp_int t; int res, ix, iy, pa; - mp_word W[512], *_W; + mp_word W2[512], W[512], *_W; mp_digit tmpx, *tmpy; REGFUNC("fast_s_mp_sqr"); @@ -981,19 +1110,33 @@ static int fast_s_mp_sqr(mp_int *a, mp_int *b) } t.used = pa + pa + 1; - /* zero temp buffer */ + /* zero temp buffer (columns) */ memset(W, 0, (pa+pa+1)*sizeof(mp_word)); + memset(W2, 0, (pa+pa+1)*sizeof(mp_word)); for (ix = 0; ix < pa; ix++) { - W[ix+ix] += ((mp_word)a->dp[ix]) * ((mp_word)a->dp[ix]); + /* compute the outer product */ + W2[ix+ix] += ((mp_word)a->dp[ix]) * ((mp_word)a->dp[ix]); + + /* pointer aliasing! */ tmpx = a->dp[ix]; tmpy = &(a->dp[ix+1]); _W = &(W[ix+ix+1]); + + /* inner products */ for (iy = ix + 1; iy < pa; iy++) { - *_W++ += ((mp_word)tmpx) * ((mp_word)*tmpy++) << ((mp_word)1); + *_W++ += ((mp_word)tmpx) * ((mp_word)*tmpy++); } } + + /* double first value, since the inner products are half of what they should be */ + W[0] += W[0] + W2[0]; + + /* now compute digits */ for (ix = 1; ix < (pa+pa+1); ix++) { + /* double/add next digit */ + W[ix] += W[ix] + W2[ix]; + W[ix] = W[ix] + (W[ix-1] >> ((mp_word)DIGIT_BIT)); t.dp[ix-1] = W[ix-1] & ((mp_word)MP_MASK); } @@ -1020,8 +1163,9 @@ static int s_mp_sqr(mp_int *a, mp_int *b) /* can we use the fast multiplier? */ if (((a->used * 2 + 1) < 512) && a->used < (1<<( (CHAR_BIT*sizeof(mp_word)) - (2*DIGIT_BIT) - 1))) { + res = fast_s_mp_sqr(a,b); DECFUNC(); - return fast_s_mp_sqr(a,b); + return res; } pa = a->used; @@ -1210,8 +1354,8 @@ static int mp_karatsuba_mul(mp_int *a, mp_int *b, mp_int *c) mp_clamp(&y1); /* now calc the products x0y0 and x1y1 */ - if (mp_mul(&x0, &y0, &x0y0) != MP_OKAY) goto X1Y1; /* x0y0 = x0*y0 */ - if (mp_mul(&x1, &y1, &x1y1) != MP_OKAY) goto X1Y1; /* x1y1 = x1*y1 */ + if (mp_mul(&x0, &y0, &x0y0) != MP_OKAY) goto X1Y1; /* x0y0 = x0*y0 */ + if (mp_mul(&x1, &y1, &x1y1) != MP_OKAY) goto X1Y1; /* x1y1 = x1*y1 */ /* now calc x1-x0 and y1-y0 */ if (mp_sub(&x1, &x0, &t1) != MP_OKAY) goto X1Y1; /* t1 = x1 - x0 */ @@ -1225,8 +1369,8 @@ static int mp_karatsuba_mul(mp_int *a, mp_int *b, mp_int *c) if (mp_sub(&t2, &t1, &t1) != MP_OKAY) goto X1Y1; /* t1 = x0y0 + x1y1 - (x1-x0)*(y1-y0) */ /* shift by B */ - if (mp_lshd(&t1, B) != MP_OKAY) goto X1Y1; /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))<sign == MP_NEG) { + return MP_VAL; + } + + /* if the modulus is odd we can use a faster routine instead */ if (mp_iseven(b) == 0) { res = fast_mp_invmod(a,b,c); DECFUNC(); @@ -2331,14 +2481,8 @@ top: } /* a is now the inverse */ - neg = a->sign; - if (C.sign == MP_NEG) { - res = mp_add(b, &C, c); - } else { - mp_exch(&C, c); - res = MP_OKAY; - } - c->sign = neg; + mp_exch(&C, c); + res = MP_OKAY; __D: mp_clear(&D); __C: mp_clear(&C); @@ -2441,7 +2585,7 @@ int mp_exptmod(mp_int *G, mp_int *X, mp_int *P, mp_int *Y) { mp_int M[64], res, mu; mp_digit buf; - int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, z, winsize, tab[64]; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; REGFUNC("mp_exptmod"); VERIFY(G); @@ -2476,38 +2620,44 @@ int mp_exptmod(mp_int *G, mp_int *X, mp_int *P, mp_int *Y) goto __MU; } - /* create M table */ + /* create M table + * + * The M table contains powers of the input base, e.g. M[x] = G^x mod P + * + * This table is not made in the straight forward manner of a for loop with only + * multiplications. Since squaring is faster than multiplication we use as many + * squarings as possible. As a result about half of the steps to make the M + * table are squarings. + * + * The first half of the table is not computed though accept for M[0] and M[1] + */ mp_set(&M[0], 1); if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) { goto __MU; } - memset(tab, 0, sizeof(tab)); - tab[0] = tab[1] = 1; + /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */ + if ((err = mp_copy(&M[1], &M[1<<(winsize-1)])) != MP_OKAY) { + goto __MU; + } - for (x = 2; x < (1 << winsize); x++) { - if (tab[x] == 0) { - if ((err = mp_mul(&M[x-1], &M[1], &M[x])) != MP_OKAY) { - goto __MU; - } - if ((err = mp_reduce(&M[x], P, &mu)) != MP_OKAY) { - goto __MU; - } - tab[x] = 1; - - y = x+x; - z = x; - while (y < (1 << winsize)) { - tab[y] = 1; - if ((err = mp_sqr(&M[z], &M[y])) != MP_OKAY) { - goto __MU; - } - if ((err = mp_reduce(&M[y], P, &mu)) != MP_OKAY) { - goto __MU; - } - z = y; - y = y + y; - } + for (x = 0; x < (winsize-1); x++) { + if ((err = mp_sqr(&M[1<<(winsize-1)], &M[1<<(winsize-1)])) != MP_OKAY) { + goto __MU; + } + if ((err = mp_reduce(&M[1<<(winsize-1)], P, &mu)) != MP_OKAY) { + goto __MU; + } + } + + + /* create upper table */ + for (x = (1<<(winsize-1))+1; x < (1 << winsize); x++) { + if ((err = mp_mul(&M[x-1], &M[1], &M[x])) != MP_OKAY) { + goto __MU; + } + if ((err = mp_reduce(&M[x], P, &mu)) != MP_OKAY) { + goto __MU; } } /* init result */ @@ -2588,8 +2738,7 @@ int mp_exptmod(mp_int *G, mp_int *X, mp_int *P, mp_int *Y) /* if bits remain then square/multiply */ if (mode == 2 && bitcpy > 0) { - bitbuf >>= (winsize - bitcpy); - /* square first */ + /* square then multiply if the bit is set */ for (x = 0; x < bitcpy; x++) { if ((err = mp_sqr(&res, &res)) != MP_OKAY) { goto __RES; @@ -2597,14 +2746,17 @@ int mp_exptmod(mp_int *G, mp_int *X, mp_int *P, mp_int *Y) if ((err = mp_reduce(&res, P, &mu)) != MP_OKAY) { goto __RES; } - } - /* then multiply */ - if ((err = mp_mul(&res, &M[bitbuf], &res)) != MP_OKAY) { - goto __MU; - } - if ((err = mp_reduce(&res, P, &mu)) != MP_OKAY) { - goto __MU; + bitbuf <<= 1; + if (bitbuf & (1< 64) { return MP_VAL; @@ -2759,8 +2912,9 @@ int mp_read_radix(mp_int *a, unsigned char *str, int radix) mp_zero(a); while (*str) { + ch = (radix < 36) ? toupper(*str) : *str; for (y = 0; y < 64; y++) { - if (*str == (unsigned char)s_rmap[y]) { + if (ch == s_rmap[y]) { break; } } @@ -2782,7 +2936,7 @@ int mp_read_radix(mp_int *a, unsigned char *str, int radix) } /* stores a bignum as a ASCII string in a given radix (2..64) */ -int mp_toradix(mp_int *a, unsigned char *str, int radix) +int mp_toradix(mp_int *a, char *str, int radix) { int res, digs; mp_int t; @@ -2809,11 +2963,11 @@ int mp_toradix(mp_int *a, unsigned char *str, int radix) mp_clear(&t); return res; } - *str++ = (unsigned char)s_rmap[d]; + *str++ = s_rmap[d]; ++digs; } reverse(_s, digs); - *str++ = (unsigned char)'\0'; + *str++ = '\0'; mp_clear(&t); return MP_OKAY; } diff --git a/bn.h b/bn.h index b0131ce..a87de8a 100644 --- a/bn.h +++ b/bn.h @@ -37,8 +37,15 @@ typedef unsigned short mp_digit; typedef unsigned long mp_word; #else +#ifndef CRYPT + #ifdef _MSC_VER + typedef __int64 ulong64; + #else + typedef unsigned long long ulong64; + #endif +#endif typedef unsigned long mp_digit; - typedef unsigned long long mp_word; + typedef ulong64 mp_word; #define DIGIT_BIT 28U #endif @@ -63,6 +70,8 @@ #define MP_VAL -3 /* invalid input */ #define MP_RANGE MP_VAL +typedef int mp_err; + #define KARATSUBA_MUL_CUTOFF 80 /* Min. number of digits before Karatsuba multiplication is used. */ #define KARATSUBA_SQR_CUTOFF 80 /* Min. number of digits before Karatsuba squaring is used. */ @@ -239,8 +248,8 @@ int mp_signed_bin_size(mp_int *a); int mp_read_signed_bin(mp_int *a, unsigned char *b, int c); int mp_to_signed_bin(mp_int *a, unsigned char *b); -int mp_read_radix(mp_int *a, unsigned char *str, int radix); -int mp_toradix(mp_int *a, unsigned char *str, int radix); +int mp_read_radix(mp_int *a, char *str, int radix); +int mp_toradix(mp_int *a, char *str, int radix); int mp_radix_size(mp_int *a, int radix); #define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len)) diff --git a/bn.pdf b/bn.pdf index 4834ba1299137649be6a14058df548f1329a55ab..34156bc0c92944ab498bcb06de953a9597d46d4f 100644 GIT binary patch delta 39120 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 LBG41bm+1cwaQ$3J delta 36506 zcmV)UK(N2Uq6vtO36Q9NwdyrKh{ihz?9`yNyWz0EKo!(Chom|s~8VI&BuVrJ&L@TR9VVhWuWpy{JUG6lupU z`tO~YT}q@$Ukbm7tJ&SToH;YICl|A$God}sSr*6M#meJSvP7p|5+#fa5G}v@k_FtC zLC8VipTIib8u(oVp-i-Y7G%nA%S8hsQ^8M}uW`G72_*OLgYOp~kIqsrW0{s{Ao4<< zGMQ$i`gFT3K(Sv2BK1i_zFyx4p@6%vvWrisZhjG@(yun>IUc*VJF6D$EgDmmu-Kwd z_;t~=HOlRosw~`MWxvfeY}RDf?c4^j26JuUG&Gf!8`Qcqi@b3MO7@G9?rDZ$0~eWA^(_RoLkYd&*9TXFZ2xk}?hsb!X76 z-+ny~ve^GJqKr(KN;~H<1sF83ps?%J7$QtfC{oVSR1Gq8hiM?_W#Vt!1>Le4*i!b^ zn1NVO2Bezgnj4j_LK<7GPT4hgzE+Uq4;c2Z{3Pt!P(4DTZr)&(mP)vYB-5GL! z>lA`IA44vf7D*p+2-Gw-^g1uCplY3@TG{WW*dS2E_j@bK%jFoFPzcF*l)B95ClKN> zoPrxV7A#HP1W>0c-0K?Q!(+{KXAC|1GvH9Y$Dc;<2+ahn`tZoEDZpCU&T-RH8>CI@ z1D1A*N}W2MYdmHN0%kcY72`1iW^%&RXhDQ1Jd8zJjP5!P+2PWw2D~9?tGE`cQzQ99xGwLWsC_PA)DwU+2&}lMbMETP&^ExN{pssI_f;2ixEd zfod9K=gR{Xu2XVn0DVidq(`$PVNz=d1i<8}^9@wT&@?tTm!>q$wBR4Ua**)% zqm*;SGNqg9dC9I1CMME8-rSTJ>}_S17~%Y!rUu(9RCaJ$*N8VBM+3-&2P&p3E6jVT zZP+*9WqGhmCpLkR@_#2naSfeRMN?Px{_0B{Iqt{}xgXUkPb6IMR1AY6l5Z+irz-5} zdR(a-W^D%jt~>I|N?q-q7hSQDq}tf+4Q*}qEni_V(i3e=V}(ta4`_^kblhcau`cp@ zx*|d23q@)5U0fUNvT4#yXjs`+QCIfguJ+P&@BO{q%jv~u*S)~);oXx1*14-$cw_kX zeYm@awVpRQJR@|Z!Jne;?$mq3xjjq0u4wEZn4*?zE~*|Sn;L0;3xszmpm$;K;fuKA zvz5q}mj>HVyQa6Y%VR@-uERDAo!I){x-C1t#eS+xvQ@$ejS`@1#ObZ^7P@x2!k)6n ze3dYcBUpAv`h0cc@)5m+5KLt8fDcFSEQ_{rP8^WtvILdTbe#j13>UZG2-~_SDT^>yh(Big4cD#WB@?JcCDnZh{_kXY5!& zQxDfI485zeaDl9=u0v0_IP?+w`Xp>u=C&wzBWPX(G)(btwdw)8ePs-2=W=TvieVIL z5AW`@JM|p0i|XdyU7Op_hk^4ix`PT{Nc3L*Di9qI`2Ox(G{yFC;MNBl^8Ei`HukiK z*=E|!Vbj(byvm>sN)>z^=T+Bi{sSs>|1`5aA%X`4Er8Adv%)Bz1OzwvOEj}&E%^il zf=8H#ox~&686msKJo^~3mLRqagv8` zZWdo|f0~Q=Qp$fYiz4DwoEly|-hDl+k9ZnJ?d%&*=XeK1d-JPyzBjo>W`FZslnygF zP-inx$Ns+R#6Om9aeYW+&y{j@|W(=qX^0=$I z-RJdUDT92m)L9nT3I;}qz#c$|15a*kQQ@yg{#h4CJb`}}J-FQsj7uJ#VR+gsh@uSe z9MNy=35J_+v5buZuC#&VQ&}gV0!zihfXz@gxHQ-?`}^%o!i<>9xlUq`JetQU3XN9t z^>OyU*{3gJzL|;nPcsqfES=xOScEdm=Es?aZHfDJnEg8YcS~yNX)Sxiz9;AI38Yh? z8R?cGU*Ug3tKb_M0hHFD*2vOEhDs`@M^QWDvW1RtNTmVV=zOphISEW8VUi^SUpX#R zLiRi~1zEdT+ot%ofWvrQQHr9#51y&&9IPA3G`K~{(89KH+iLf9zw4%~^13BKU%bM- zBiroh!Z-X2S=-7U=|Y?CW??Z2?5UF^3mRJ5<&}Tqb6%rp`-#A9oP1K1@ zz;%Cgk2Ui5tT6mMH-AqZMe?;&heAh#>)2A*uA8DfvArrUK!YpQi9{X6YXb3Q5@(f< zKVOEcQgIl|d6Z^h6vr=$R!3^tqcsXvr9~(}9KQ#J`fVY>IPd;3x=*Db7y1Ydooeyi z+hmL8$wH-&cM_&)N*i?uhDg9J64LB1c7q1yegKOlQIkeNE`Qow23yVh3U_s7-+O3g zONWoPsrmfayTM=~F`YadO7y7v;C>lDA^JH(xWS}Y4n{-tF&ZoNA zo$}4sRdM=S7k}hHWn2sgMfpnUN23kMO;U1|((iKxdvB|Y`q~~@KZkcy4mfk7f%5pL zIA1{?eLfeqnt$Z;Y+Jol-e*`Up0d;h-@C7vHDA|Gq+bQ0`7rbV^9=fRQ(bE2DLumv zCYTP<++V_%Hg+yCrSBD@*Rf&hu_2TtCHwWO#u)|4f)fXh2~BL=PAWe%T;X`fW6CuI z01HdYBG{Hlf=V*N6x?NN{vJ!0^5_==(PC8*2q|*MpMP406Jr$I^bv+Xf1tWdCC+Qp zvl*am!d>~gK@^$@(r;AKqBP8|;!h=@BtWmD;{@oxu%bCy%O0_DNdvT#h^S?VVo`;- z6ii2<%Hr1%%+Y#UFr9{p)T%a9gq#0DgG)>kl7@;s@LYf;JUp<6X_a zT`VI7%QL$nQ@2Q=iAKTlzcj`G=t==k9EuHZ_1>yMxFCxU37>!y#zz4k}kng`*7av>4V*w!0w9xe>Q?y zo<$S+kR_p63m)K+_AJ|+F4V3L`9z;3R47v4@BDLI4^${)--+KBhllo8Q(W(V;CjJ(<=O3lQl&^q z{5nm5#DDR2r1Y;$unIY&*e%OF?__&g_8>Y+BIC&U0iUre48YpwOkA%I1q3TLU-%k^ zGw7YTc@142^#7G(K{wO7R?>eByZ#sgODiahYWslF!+!mT`~KSpnBm_E);*VkM>kh7Cu-Em7;V|AfdvisqnS)S06VV zD@v01F1bF~y5=FuAISvz0nZj^kHGeho<+O(#9bpmg_}puU%1mwJW?qw!`P(Pfn^GQ zB*9cE_?(Ph1}q(|WslgzqcWh+NVg0L>eQIm#}CQaj>TT~@5aiZne|oG3?LUH^s63T^?yuZ+n2KyM;ZYGF)}xop(z3>e_CB{+cp$^_pdPeBo8&qPl*DC0V}W$ zE3mD@^49jjv7K0$Wv8;dto`-7_mY&Q=)*}Z3>^>za43qrJiH{&xg_=aYVzuhOs6SJ zV>P|HnF^&?65DCQ6DFjYUaj6onh7?Wi%7taFg(idW*@KKPJX(Yh$)9ZF%{M@mBdx8 ze`P-TGK?Pf|w{Oq#7VDWXacK}u{v*t~D zu1yW>eMYW?{1s*)Kt^bUW~tU5e^N}4t~Rb+72V+Qp9WK%29qX6R;)e1U6>3yT3`d@ z1+3=gj*9Yij@4+?d@mNem7DcK)YgzlSPHY96O!Ls%OYVGh{C*ESH8Ze=h6T@f<;I$o5l@#lxOKNmN84A_9*mNGuBIwf1wP*+#dS5 z5fF?5&RH6SCQ)FZejVD^^J0q0v`ve~_~mb6T=Fo_h!P=tNi&b8a$rWtt(XzgG~c1# zc1^3sKb>e1iV!Wr{|B^)t?pg%CM|~g9#L~8L9Jq49{QKV{3(*uUO%&e~tSr*i=e>_Cw^V?le5=bx| zr3>EFU>6id!O{+NVc8GWf(RHj4pwh#7_5aTJRQKg>ed(3do5*KU>cF2d>DE|&a$a7 zKI$Wlfpq2rUmt9q0`L&7hH#UVh6fhLpqa=HoA=rR$x{gUFhX?!IQ)>Dl-TUvTfT$z zcHw2F5tllIJJ&Gge^H@kyz0mZqc&hM=>)8b=5#8LK%daBW)bFZFRE{ zsU)Ld3$_NaN$_t1<5|bnuWp*zSd9bD+ZqO^fiD}-9uwpD>jh|yNyfn+Yz^X93gQbf z(1B%-UH}D2{j3))y)c*RMdLIA+PkU2L_Y?Y#ro3`VR!FUU{u6^dY*vCRqeeBS9S8o z$8ciw@Mwe&e{5G^jU`Vw9qEz)&a{aKB|tL;!R*s|Jh-QUQH^alL1`W^oAb<%h?N?N z`A^3BnctTo=Ensi-B2{x6(*=Q=_ufWtwC@Se2A)92iH&imT_&y0q1QEgEPLn0-#~T;1BAb`M;n4e>*M#p1N&#mVy7548+qggbf`4 zfId>vZ03*ArHNjnmkya5UEu5JM;uPHM_Z{)j47LUlO5jN)8UVX#yhC$r3|o_tuzFj=SW~EL2C(*B ztC|=le@Qc3e>bCxJY>Rsk>k3Qu=v_j%wRXd2K5z~bFvb|9jX zk}eJtn8lUltILB78RE8$RDgG^3hVRNcMpe4OIW`g zCO?O9h~tZfE7+RXjJ1YKE6KE0Rf7oY=c|_YeR1X55;7;@2^YMdH6zx{UX|srkuPoAyC6xzVAye%4Qp!r)e=|5gfPg~k|IC)8!z!3l?mPG9KXFuT7$>t7${ zXb6|m3qIQT$`}O-qU~=pOqtFtxP^mTVhaATXc}hPzfC&2dy^znzmwocJCiC@6az3c zGnb($0x5r5OLN?~5x(nJsC?qY9xU-BamZm^wXW>TsZ^BHdJojhNMdCk63MYv|33Wy z_|R}D+2-buN~uai0*&TJpwVA$ZfsCB7+4AM8!xEzifp5k{2N zW{oSSb+Qq+f+s}EZbqyUd2V4S?Vghf1GC6O=i4yYbiI7R-JjAlJyoBH%=jR2J)+%u z7kV3nTkUHG3yTR;*&I$a8Yh(ZL%@AZJ;dXX`k+rCfuGCbbkKCcoa!9j!VM<(>aKqb zNN*7Le$|wRJvX##9v6TFO@ixt;L8H-ZH;z-!-_2r+-+!c9ZokT5~wk0QZKvllA$yu+i9?&{$^Y%3xok0;X>rFqJ6?JFA|1> z`Sp4pzUXwFrHdef7;9XiYa)zMx2As-xEGntfiS9?La1~qtTlavuV)MewmA>dplT9n z?m*=P(iiALd)WDU4zy9#6k2VxNcDNJ=eQ#ELb<>dBUGVnU;)_C%oDfh3b=uI0)B&p zJ;xK!Gr|)v@EK1)%QK#Uk;D@y%RE7zWgR?65UDl~M^wZ-f#BbbaK$(`NDqITO1<9I zf|08;P8VEOCe@!#1k=p*j0Dsq3Akq@kXoU%{yzzP6$#iENx){Q$h4V<1$xTP(m<3! zm^<_a$1Nf~pFKE;kLN%cbxopFT0wlP1}MKIdocM-V1uq{u#i1?H3jyi>_I{lKMUTV zY7#Ey4%X%qa3_+7%%9I4Y;=G3a8Z|(F<8w^0KaWl%LExQK^B+*dXNb=E1aVSl|FIn zBjzJz%LGKk(Q8XhKDt5=|#0>@#~_dRotR+?l&w2 zaG5QQ@Wu>GX?0+WFBX58uEIb}XbXa}*%E%xp*;Es5W`p5HswA3l$(lsO15|94fWTp zRRPBsEt4M`mK!5qY~Q2RdPPAJv=dtchHZH6ka@9*cGw8{YIr}Z+&7Z19g;5u@4^Fr zw&bgYlWYoVBtkI`JW(eSJr+mAIrzu^%9|j!An$;etKhY$pH{xOiAxoggxHt|fW|dnJ(gt4hhsD1 zrM8E<+~0x)I(SA=RZo0LvDIza)bQr8TJYv*rEd7z+_Kv=cfqCc*kEedcT?02L9Doo zH`PAg1f2tG4ikUKn#n!hbv}~^qWtK~tcv~qfLk_IXqpmSI$$ku=Reil+|Ci+bhD0k z&$t3w;+v!zJ5fug1U76F#EL5D3+^5IKBKDjW=*?GCs+8G$OE8l72YR|3pog?IwE@= zXg3wjur$TSTCTuzAr8;`cM~UAa)c1w0ro%k9?RL4Pnm!2pmRm*;AJFIyiupl!GRz9 z@rH-;ih0?ZN6q;pU$o}n0*8wl`4cx_xxc5i zulcrBWRym8#I~P{iX1oD6V)gR?jPTd*i!~|ojG9Z&>XM@^TF0B;(+2F6;%g(>p#j} z(ICH^_^W^6>%8po+$nLw_%!R&_Gv~38IAnHjD+lEvpZC6vNZ0pofT=D@y(Pj$#l$R z2cHC1m)xFsb|;+Ade6}z=QxcvA=Y$|MJ+p(uS>(Eb^`cmG!1hvreOwR+uW*o(y*Sg zvuRkAp>iAsjMY>*&I$>#bAXJxCP8AVW+Bq=gM5E|7M2R{X962^O@qZ$O-+Hl9#3n) zB7}2tkk_=qClY5HPeBZdzJtTi82ml4P>4qHlK3w;IhY@tnJyBI{WV{1NlhK@T3?7a z=v1w;9gTBy!9Tmmrhw;DDh&n-C|$RSM^O=u+p)9;ou*a6>2po4SdI(@Da|Z=d#E@B z*>Qg(`CIrs4u~cPUc@LAl~d)dow^_%>OZ9RBnmb5BnlnAHyk*GZr ziDqEPvhSuws%_}Yve!HI$!PhnBe8Ht8;YHzF+lWX3@0%3&79!?5WCu3WLZBPiEAl- zG}?y&91Uhfqo$1pjbS$CFfa7c>R~Vw1#f@CWy1>Fpcijqm_mWNOGT#4ATX+n8%pnt zw9lR-O_$pPx+6!`C`ZvRS}5O!02l}KGC2-|@;v$erimt5u@vqz97xv4`wVXj{`r}5 zJ_tpQAza4BS8cLldrMXf+h&J*mG=z(hOj=z_+(Yy;iY<3s1A|^dXf7WoW%7!6Qh5q zG!vjkmBYKQeK~jo&+uF zXta{O7_DF)j%AZsqLrSqv(ZYFL740E^K__UAl{qY zeWteU6m0)N49NA8)Fcnb1I2wI16Q7uK?ju-Q=3pKTCBQ41Qk$8{`nHiC`$7uemfk zESYnOcu-MwUvd0+dIai)(*B#+@_#O)|DqZ!&}6Rr-1m0+W23J|H>EnS1Biy zoaxZEr|c~MMw#%bCnkZgW7p@I%__(|^ejN5u1TQEIw9o%Cx2wbSslX-=V0TE0Sn=! zp9OK$HHla&CA4(|$i4IM7pGX~7%rN500&*ufIW=W&*qpaM-l4?yTO05Xs7$1@&LPW zb_Jx8a_RQCZ;vx^qa5%s5c`_q-=X3`cd?d>*R)mf3OUB4R9-GCzPvls4PV{#G^0O8 zH;wK0+mPh3-l!BsqFzcPdl;hdVT8i&BSCQ~{pL_%u|j%I+j5LpQFRT^$BY;Nv}GQY z+Wb-M?zfRS-fG*n^b=T?_@&R7ib6aGCNH>J=O^& z6P&_6^Wf@u;jl*9v$2ndX45~oXu_dJD10al2`+|U$8exg1?hiN+Z-JB+_KcJ*oPx3 zI_>Cce9UIpczC9%2nDn{o~{f|Qo>Qwar*lLS2;2B{7uCfs_yzjtu8#r#g|MxC zOJwZ&j!urY;oG|vc#d)q%|he*qWch|Y2s%Rq?ZD>I>dR-QLzggnaEQ1ZZeH~@IS&p zZ~A3!WOH)Qj%AmNgoyijLAdt@Laxgp}yX(zWg>_ zXCjOBdV5$alZr$|>qI6(MRvU{ehz+kxBX_Lg1>A+9m!z32~}`{dDStYLqfU7|9u7Y z=EC%U$Lf6M(QXq)Nl@YhcK-JYoAOHm|4Ten09|FlaHU=Tbai3!VSs)8(DH6%(3a;i z=Sw@LGzZ?>pGrP_u6D4$&D*CbKR;zsPm5lI!nRQs^vQKf+iFm1XOC zrG?Rno1Ir5RzHobLeDFlG5Z>wF&9&%sYsO`FGMlHFggkzY816Wy@TSTv=XOFi6aAU zl=`zs?0LN?ab%^i=8nKUhzh>=bN&Snma=LYfloeg(sgBeUZ@x`&{iyp+}@{ zr>UKi8J}g{@f_{tA>=XCm)A+t4XRC6R%#ZkNdj)sAQ?)uU$_B0tWvl7)h4u26sUV# zM20BgZTW(W(!$1>TgSj3t-N3r#Uk=McMC>FM38<)K8p1t=iwj+B`;{IrzK;5V?}Je zqB*Pb_r(Pf;C;MbI!*w{G8&jVMT6sykC_iWC>aqU z<(>11@d#E+1^|CE9be`lD@NaEzy_Vd$LL~(q3 zI=z3G<3Vfv2N9+L;%WSUhZur2HoC)eZbk_YhEv*I zG&4%WMbbOwI8gq}ePMu@D2t^ppv{wB-M-<=psy-;gc0M2WJo|*riC)MF}iQs)-`@? zt%gv_SY=9exPub_f{hkHn;RC9Hl;4g1b@Sy1k=rIcE{!#6!R$K@&R_B4rz%O4T$v) z%Kr+A#PJ=LkaDwIWS|6pU$F#Auzjd;PSP9uOpUWq&^Y_187I`%`l4%OHmfo)*%9DM z-rD*``N5rsX~Fx@arm2)6ZYk`cXK}ZSdC3~%L|N*qvMQyGg1*`4s}jEqIku)Q=aMd zNl&iLO;7II?HC>tLW6z5gix(Dc4VBHEOyutRA0QNrn`>7C$YhQt4mHG?^xB5k-M81 zf!DAnCPo7GDaY*{jCUPt`>@e$C1kp-YGem@jLCE6UCC_`cSWzTk%A{pRbS5~kNdLo z2v4%$ib^-fHm`a0BLrVj){WTzi3wCu&=fc+CfA`q&&}1pg!tJ53?EO`9v4r10^cnI zTI5_f9**ug}65 zV!uL0{pswVk=6$P{tx~g*{Yb3RV|b1gK;kLy|CD6k=f#yVfFBtd+h~ z84NUW;k3nN5lFa;Xk(kl2|Po#eC}qwM1$V`X@awMVxhq?`+QSVIc+OkS zBlvNEzXFuheD+m7HE*zvxaAKBy?+41?!wn=!$@?FaoNevwL|KGd|&%SipTK%jK81g z24_dzCt?Hqfb05Gux1SB){L0fQ&CKP5 zNl`uExuSH7JAQY;IGyffpOL|$Wcs8=r5!ht>#TcAj7FmzK8dr`?pXE=eF6)#N;$H3 z_{xtZf!^FcuwXYnu$nUfjb2n#zM5B*J${&`byq4WYj3!vl2^V3ZJX4=q_K zb%T1heYjxdgKN$q$F{o&GRmS^g=a>rBak+R$4SOcR?3_Df89Gc5R(IMrjza=43pDG zB9rTV4wGgKI+Gu87XdhvK_V!Bt(;A7<3sO8&=G5wb zclF!V&%g53!xdkBf5n*!e)S%;CO@D|?r;jX*CBNK z-J5>?3g>oTo75~+#8B;IpP7q)v*MYUv<8oWB)nygOPbbqPuDVZzh6t=ZEzxo;|1w^ z#kA0^q@S#v(Mn;M;{JqINMF=>3$Uc~8W^a;`fvg!tzLuQxK~B-w%|+Rt?+3r8HnZ7 zaZVy1=oE&$ zYR8LGXu+4HP~lsoknw>AkWVVtPzqKs9c(KpBx_|USjgU9M~@3xltK%zB!wDSFifDU zGca;A_oQ7FLzcf_iBDAy7VxRNF+T(cy9GA?WB`XTrl*P!)9 zNi<+giYPN`WtkD~gi%smscl#*WaPy*2h2(kQ>!*7nR}(pfnvu1ri7Fiv)P-M?Fe|o z^A=mpq6URyvYiN%wQ?1c5NoYX3$7%>3YX%FK|OfFMe&ukD83eONqrSKjh8SeY%(~n zry^Ey&Ad8IL4PrS=-fgmRI8vTYvrJG$hkpW>|$DgrKnfHmZ;}o7ntkPt(z)F%UV=eVYjzu@jMJVd60b7z=nQiVcayB0y>BK7y zq@X;{TnMxV9@8w+$yzzo8d9kWmpY3kU@6uWuqD`k85jlIxpH;Uf-Xh7Lbp^GAJh3@ z(z6j`+@}Ox2Eb}{4;0{uaGTmL{3I+LMq6I zK>MgZA@0x@GbLKxHOQYskqIC(lY-%<@h6mcZBe=B^>< z6I?|;Rq7fvXdwvKs%yy1z4|7WhJ>U&BrP3(AFX}!2R>8BWJrp(Q@kOpy zooi;TSY+g&l`5kNSdw53YJp1&O%TL-ovBSr88Lu8+?Eoh@FAnt&xi)WBvzWMF}OZGxc(s6iHg z1<`^s38F$dKSIqZg^o`%!rIfr^;r>;39dg|5f&~Ux>fU;Su0EMDv6{8;o<6aJGmp@7x4x~Y*_D{BJkW>^nXFX751W(%?;iW=E0ij2&E%)XYG zm-$-gvMO4DCRJ2G7gc1S@Ru506<_aNZf|{Ist|#J#9GNBSu4vzLMs>kLi5{#EXkrq z2KBxbCtxDh6dGiKKIdy+zU$QlG|8d@y2v6U4LZKhrHEK_!u;x6zY1`a!lOVUXd9d$ zArIO3$n9VIaf8ax-S`N{^&@_NQ1D?I{e{zO!tY)V@Lzi0^BBK)m^DTFU|aTbKfd&1 z+zp5CUSNBijKk*RW;jIaJG9fkd%`EVBkuLEnXKaN8QNG*wP<*AU~wu5XN#-M80Xb$jqQtjKQjN57+I=CsQi2CYFa(wF^q z8#l-)@Ha*acjDc+IgZDFX>+E6?N_FY2gaY$!S`=*g4477<_d;$9;@leA_t6VNd85{o=bG`HbtHC{QMI9}LnN`rQV-BJ`vR*k^xtTnwg{ znI9$t$UFAmrsH}vOG7;#^5GbVF(&;nhD*$oiMD9% zKV=^#OQc_1|C5QL*C4^d8DSee2Nup}{N_ja27e!_AT{7CHdfE*22L8emaf^T8A(5&x`2`%oljT>`>aK6@ptwip}qk z9*%MM;ds9LTS#%!D2BTqX965*d_`$*YrS@q1cnl&1y9AN9suvV5~&rae5Qbpc1*Z82+T<+^{o zz7HAfqp3T8T3qpxMVV|m#SWJtx@S8Mm?XBtW;(F6T;k;m%tF6F_gil6rXb+}&Fq;L z3&1(+y8lLR;MaUvWw1C-77FPJ7C;>h9_{9yHTa(i;>hq#bPZ)oHZ5>8Ja zB+cXLm2mw)>*AKKMe~oS;o?O3Uru?8mj3o3j->d1NYyD92cx)UR?q@C9e>>}nN)VAp!l19OBDBk3Tw#?mTBvtJX`kpg~z;pl0oAC zeSpVS$DN%i?ss;c%zy)ulhgbS-2n^UNjFUn62^8}8&uO-9Zr1yycAFO!!cee6&79K zl$R}kWvFM8Xj~U?F~!&&YgyH&tg5E0`i9h#TkDtPhe`HpjOjb70tU)muv!ZVH|ATY zS9B~HK-0TDW?S6Kw0n#ref&dp(Fa^o!+pPvV|U9HZnLEWrz9^#I;k-DR-&4s^zT;X9SxWFm|9pIynW15 z-pNi{1S`};LkNr$1QACFN6$t=f2W#nt|qw&|0C}zJ9rpq+!LzVhr2U5Tl zX$fl~N(S8Q8J}KTSnfRhA8K)x^Rpv;G#pf%fTQhDX@)FMot%K-~t)E<- zWv<^ibq6(Xc=n|Jf>bSM=4X#jXce%))r`G+tMtX5Ocl|)hR&k^A(X?oX9`Ur4o82= z_AP)v32``#yk1D912}@-9)HU!bMXyw?^qY+iv!$zkaMxKKF{nXLCQczm*1@(H~<$T z{PNeCNDQfFD5!LkCHN&tAK&gq;;&~47)9>mti}c8SU52P>77VRu?9zOM>|V8Ikdr1 zQOl-+sJ&i@+S@eYsF$iTb%XPKk$|X1F5)kZX#@Hr> zvHMj%lt$)4G0!G>G+GzCe6VB;=_te}9CDHV()zTCdY8CKdL$o(6t^mHIMxX9otm4@ zlh|eEcFoPiDpiA860RGZbt@g+zC6hh7XZH0IJC@E+E{a@bv84CdEvz$lO%tcm`E1u zfHG%P*T&ZUDP=k^)KQi0ss!=GSqeRGykN-hQ|QC)b%SRk8CT1FR{_qa>M}a0NZ81v zx%KZFRwTd;WolfBd1P-)iLg)0AJAUBIu4^v@KDhJR8FPjCN;$bi+zSBL z6ex`4=RWahM=zZ5w$Mu`Q__EmIZQH}Tqtm9?*E@$r1z2w^`|8l=^(kFb-mf6i5aYIi^?05Tu|Oa{37_#uF?TC9e>>&btYWoj}K}Z0q|qpqy0i0mkN&i_VpQNB4Z$Eqgd++oz{(9Rv@Zl zNiB&p25NXw6p9-+!QG5ZtVwU4u*pc|K+zsZK%C)2`-Kj4BZodUydsU2H@r_1rqVb~ zyjiSDtSjM~hicpL6M=tC_$Bq&?YT-zJ;dTG;!Q3gg_MoU8Z|>u_IODWXKq}Dy^6RN z^3V4q3_M|0Fr!Sgt3&>Q&FYm4q;x3E3wF2l?=$x;D$}tFLGs6$N>Uzh6sZip_W7CM z2o)D$4;8-vguLks+t6iiy;Cb#Ro|3%PQHI|$D>gH#Su4bq9=dv84?|*^MS&uK3~D- z1Kk{yxX_yf5bW;w_t>=EoJ+Q`&h$<3018#19&?mZ#>HnM#wJ7S^KV4U*v#B3BqlZ? z>_5$heeKWU$FD!ltl$RBuIB>CT~;Rv(#i*8Sa&SrP;zIlXI0V{{pN1<9I$@Zz((e! zF$*1rX6%rApHF`+H$67dMo0Zc$+|gmS%pj=>G(<=J`+Q@>hyyh0t`2_$D>X#_KCZsb9Ir9yF!a(rILarPstTB3QDl=# ztg8&Gzr}h*#$EJ}sRiV~q38Px;PCYHu_6}d==oAK<^F#g39?rD8G1O%FWMO;b0F)y z7)x-J(dhu6P-U$N=?h1yK~czncb=9(*8NQrQE>SQ9(Gi6yA1B7gng+u8TN=$>kudD zq8C|bHW4>jtnPS7=e*Ajcb@)s0@k!~Zt`oV$i<2_R4O(B%|Q2+^QIaKTNJ@zs+WJh z$QoR>PxODNymDQc#GIrXkd@M?<#%05@umF)@`WdLU*yvoSG^Ui?K1->M*#{>M?h@*0f6ojiyU!HP|_}v&y&|P5~{qqW+AwhM%z5>i=g7f6) zuP(r54nHv}6fVefEBJ#vQcW>`0%ne;6tz%MZ=q5nK7*<^W713P^BM;=8S9w&Ogn^ zHwm*LKn)^*K{x(4MkQljlj0Vyiti?qJ6;7w^ZBeW%VL+_jZnAP+cp;l-NM=sh(HhB z>TG{zo&&2_pI`|dP!9ELEVi(VJ~U5JfQeoBw&xEwqNM6(t&P5umAj@Z4}&CTbV)$< zX-OdEGl$7>5D{Mj>&S51s}JsQMtwpK3W2^*vzH|{OXy4)nzr0g@(;P^6K4%+e+tC; zYN8E7##T( z!$QVrmjiv_SP&W<7q7t)>`NKV`DdD6w@esR5{OdnnyRE672oOMHwI}sjO(NinS6%g z*keHR8QlBuyNTc`u0D41-*2iMvGW&v?W8~^7E$)x_fCGb)nGaL;7R3JoN+msyM!c}51A4W_ z3z;av@1|Dr;Z(}{g=GA-fWV3|=mX2l4Ayz@gFC4w885y60Y374HnUiaX+{t?Gzu?F zWo~D5Xfhx&HZd@h(b5+JGBcAgNGg9+XIN9&x<){v0i=i^in0|E0zwMC7^?K%JBDNf zA=MB%BBLT82q@CKG!bbcy{jPTC`GA?QP80cAXQM16PYu2<~l#`{dJzR_x`covcB~` z-?yJ7e!{|9Mhi#r0QD$jx(relsS47KS=Xsh5{saW5NJtNF0Ss3<7X}peGb=Mq!=?GPC@D#QM3oo*$8Dh9UhZ|D#d= zkTE1YG3eh03W@4R2WfyQ1qaf|KU?j=KeCyEIJ_U}XVs97A>y%GWG^BJ$ROoq5%PcV zcwaqyAc(WT)3M%wCx++??(!fR_j3|v`*w4{tsL|WZS1B080@ZQfx(mMHbGQ>5J3E8 z-o?njFtbH8d?4VAkVPPnOe6FCbLINeS?9=D3Jy>90#FKy0ER}x1VItZQYZxlAOs2E z$v7|&00WtU;j&~3ow)^IHs&JWNufc1OjSV{fK!=+q2PY-yOgpL0Jr}igha>zaIe2X zrb_r5WbP;a1(653YON%8H&E75zx9lU^JXTVwdQ?yWGHK`Px5p1;ms zGCZ`s5=OZ6;{7ORDo*TEGSoGv$s`H1n`R_D|N6T=C7&`{*e&FezIO2YsPLol0m57E zG?kbfQ?_A$6$U@5U`R}VHM0U=WyyG@(Vi@OpNwv+FBA7s2hHwn7IIlOQ%X27wd{Ky zDO8k(R0a-k8eb<}Vq@vWo8j$tGGX23zq({cCET;CYCb>hJ$5zfzOKS=H8167qh{C# zdjc&@!}JLoDaW)DvHY$Ee5O(4@wel5iz>GZdpX!Q8r%?BZ9i9!&Ph;r` z$x?Ql?5otbs8`{CTv}>|y*=4nX7PJhewSQdVzA@1U|)En+17GL6Z825Fa zOufB*Q1|6`9f|a9b-~cvlF|8A%RAvj_(t`d;l4pg;5~=lEz_d{j=>xyx96`4G)+Gs z(_iNh*R=fWV4-7tQh3X7i#>9ojW&UEsV3tmS-HzcpIza9d#usitrf8LGV%a5r)%Fp zj4Ey4;uly{hoZolsSLBs5RFe!Gnb8;DeV1PpQ5X88u=DT?m^h7TstMOkvLfUSfY4A z0`cyh&!LpcO!4@=r;m2Yubbpt4R~RRH7+vPqOLpkaJOr>57ox@GZcpoom%mzcXAkV ziX&}1pf`(u)3xKp5^`%);^qQZYwl*H4-^W$R}?a|HEIF%A!4aJa*r=4q7te-VpJM$Q>KZw0 zV9w}|0~aHn7zKnSdKEQgC%9<5u1?YyKRq*bMfr7qGg`U!_JREo38f!@2|sS%RHt_z zI^>qGH4t^ybt~IyLilmO_s;fCUf*f5cQ7qtV!Okod!p0@kA7LcI#)eqY;C{y?hze` ze7qUo%KBc21+!AlqpM zn+kY;DF*+M%Po!#{kkcF+cdVrhNxAgz*?<^|EC2qDoG1VXVZTK-+iEp2s= z+{ZxZez`UHLqAX9Muk8p5uel~W51-KqYA7e{BGkq#!GSgI) zxbWqg+-_UlTRF3KSs{rC0Uwq>)^RiHanL@PLWvo5E&Mf8f3isq9O0tDKWWWR~9c!8ef;Nkj%`Zg!jc(tj$|H-T%3~51Z#~m*7RJg4Au|@VM9K|OeiLq|+ccG8Y znoTaIuV*t_rd`f2SidoFQjtgC-W_9q)mnS>2FCZA(H7FQ-`s178g9@g8_x+E5$pq% z?IA~2A3jjeioKo3WzG;i3ey)?FKXf;_dT~QLgegIx4FaV`ih{s^vl`LF=AINq!A+C zwy14xg^sg?Ci0?+^sOxE2o|*cQkIX3Tyc!3h-tNL;qLqCV@;)?J6)y<*8-)|34pfLwj<@k$Cmc}ZrUhQZnq^l@G%0EsK_<6m| zt!Kv#+kT~L3akO@+p7_jb9rC3uqb!cBVq7sDQgq!vw%=^*X;v0A&VbP)~1F=W(elm zXCtK-`o8jiPV3J(?*F-+RQh6nvS6lh_E4IR&Y6^a3%zLggk%^ONw2@>#QW#l4VZZs zlSR60_^3h6t7FU?a^J#y3#~3C%mfZ>Iy2T~MCc&$BhE z+RV(&RJJhBvhg&7o~$$m6Z{W=td)Z0qW`&}GK5|ASv8(!Mk^V=${w!i1(lq%xm z87cK_8X-;s7I?jXHz~_$x!svjJrE*P*R3QB2A}BY&4nU{uP-aR{eFH-axl{Ln?EMt zQg~W_SFJ&AYsgXvmwpOF!c{6YEDxP>FnaS_VZz9b9iF0Lpe5Cn;f|E8pGd94&--WY zeNVq`ix^GVWC3}v-txS&5$js%9p7Tv=D8Y2wG^G$!W&(GJf1XA+g&!NX5BipxZvmP z>Q=(feFv-dX>*4(>l=SQshOlyvA#UO3Blkl7(zGue${vOQ77DUn03pa|J|%&K}{PL zcTdsRy~L(Yj7?}tX8qZHv{Aw2!^d86Ey{LoL*ejA_gUG*?Lb-g6N9|zob1-%1m*&j z^#CgNodDl|1rP91T0Y!#W`>Fd{fdSkeMJnrDd%YyZJhbZ;lT05jt{b*nT zwCr#S=;d;*%f7|c`=asU`17XIgAuv9x}%KTd=eWu9_p0buj&Tq4{dmYQXzIKuU4Xt zP+S0ZwaW@0c}MWt7UyB>2j6HX1T*r!``HP4?orR>aodVT!ZUgbPSqUlVs*dHC>b7^ zO4_nG(GT*gc`e5`1sNMuomj0eD1294%=e^$Z(PDMvj_2ie4zg=@E=hCO9U}AI)#Lx z5upD9T5FFZlYiiV22xl?NmN&p1>tB0QdmYwR9BO8;b@cH;fIs3&5?8AB!@1Ep_E3t zbATZR7`miW2g#wkyIVS>K}rw-l@>%=LSfJIy#M#n{k|Xf{1UD?r}W%?}2#ckl#o$aDUcBnpso0mC3RR#1Stm8S#P1zE$! z${C>JY6Ag#`tbtfoSgyB|9Zm%@Eq&`hIxZ+d2xY2fGxzv6JQOthd^=p{&MsTYUc_N z{a4u5%kAHfyumOJq$vOg(j+GUY0=gd>g<09um#)U@@cptwZKRx|2ItiXK^JjXJ-v7 zm%qyY-KGC}Zsh`T_WPd3ikjjJsLiW~@G5r7p8X61*A zoD3uh0|I~m2-Ftr3jq5f9rN)*T|JSn0FW&S0@%62aR1s)ArSzd8*)!vZU2h@DqHvbTiA1Pt`2O@h4{sVuJBKChE zQpMp9M79d@2O@Qx|3IXW%WniCg`j^RQpoiWM6S*44@By^|A9zd*dO@Uru~7)etQ0a z$i;j8fk;>0e<0G8&u>KDUVOfPAkvlJABc42|2O{k!2*F?eFJ!q1I8nO97LpJae$~W zf6)J)s0W3(dx4)RAZM4KUle~iB7a3~ykIae)bsC~40&k(&2|vv5eI{P!8W)nORhGO z5sqoCQ57!~i)Je^AESco+Y&UI`sTaw!j}_KolD16-5;+v8s1c8k`nA-?lAcLr16M* z6R16<^gYx)A${>~$J=rz)4zkp@HA81Z`+OONB99@SL?$0p)jiE-1>h+MT$}JaL)0_ zL4g*Bg6{5vkBlh&Cf?2cSrHvdeM=MY=Vr>iPGIGVuYgCe27w#FxFVX-0o-kK2dZh1_D}YfWq_p-Sag6;XUhTxWMNqaI2_LLFQ1Oxs%F z8wX2cjZ6B;q9s}fRptAZ7=OucpPJ_h;yZf*=?|HKY>y5I>Nv7ES?*N?RU=nkFGVW; zs%Z|+p!Y~my>)Vp-gd;(4~-vV1s^x&jIx#ua~g;!vF6uAonJEVXHg zqevX*)Ynw0m`tRBytGDMsVHCJynmr~8XyvS*?Ly}EM8HB=K2#uogVwe=A<7!e}uiN zG#jU@G`awdsh$~&p+Q{iE)USIX!yNsQ&j`|4Co=y<=PwRH4EaMF@*Y15N z5lx5wCYF3bR`Mv~1@)GD9zWilq22M)2lHWbN@|w*wg=yfSQmnoMQ!)9MjMFWp{A$R zH8;*mHhcV$X7*D1ac!?H!t#O(*{TeV1EhmA0yhcf+YW#5`Gtqc;N>efLQjRrewA;2 z%ym}Il|ITO&eshd!?q~4p?;UWFY?JK9+(CQF6)Bo%`AS0)%NpbBD`2={oR31ykzh% z1s+@?>_oZ6N)rMEU0-&?LZ^;n33y?x?xezz!Su|6fnK|uZuH5EJ$*J0KL%^0!UPX- zt|_<2-K2kBBu9{^6L>_(j9BG-q8wG0aG~MaCgV9MjO=(_FllZ(SJM%?qs-|Z5ushE zxOQ178OFL_9k0Y+e=o4)cgS8{6FDNTQTl_3xz+M0=E+NY2hsh5;w`T7GqAiw0wLXC z#qnMon}CCfP`u7;T$R9dHpiie0yX)q?J5TOH@bf(YDLj7N6%QAEeawM>&ZPInQhI; zI^kVbdZIW|+IEV|MCs>VCAymHQ}C+-bUz|VF%*o}@ZeBP?5#?<;YQ68pA{l|l7vWoZMQrn+%(TjoHfN&a1Eb@(_`b$ z0k?PTX@)_vC3;@UdT+mH4TUB z?XhL@)4ccL8Lp{(Bhg2h4R{=gqm)z6DPDh*8GK9lW#!oU$#VDi3=Ff3nu1Ve*`_sY zDt|_h$Oyi?%y}Rfd504fY-h6LhDPWv;}7XSsZ7wOW`C*hd<|Q<;^TZJ=H>Lj@_yT- zM&rFpOhfayM0r2GdYLz$ga>CjQ{ZRQQFSxwMZJJ5n-D#^o*U?KONaxHS$fl!1jK*q z>Dy9`xY6cArB+Im)R);`5nN54PL(bmSWqGd;?G{aG+1!Pvxg41;%rxoBu}Rkg;M0g zNGCOMbPY#j^sww4F5=7T$C`#LA(iZ>?DU5Gzk;C@2lNl$h$>3*Fe_^sl)28iT8a@Q76^64t6!IwAoUZvDX2|g#r?kuR{X?N~Mmu4QtoD zC2QwY+*ez92(O`Em6VUAcB8KoqZxgG8@iht%KiIUzK0UO&PP4)ww$+Zhf5mRURx zO6$z-sS)PsnU@`(qD6Z#ZLSiec&QbPsk8ItL4)&tQNp9th*Fs4XT?e=;5saLY@G%r z%2*$zb%D-C>dmtk!XJO$G`XS0m_nXWoF?>h1d zCLK)E3c$II6@F4IeJDt#$;Nv`&=j^&L1zf45dPJw7$g=DB7)zy@Ddy0HD}^fd+78^ zWiWp6^G8CMKpFT~fyFpB_Fef;1q&Jabu>)%1<@G^;v2(IJluaXs7F(s2$3L$v0ktT zLZA8Bc${#t00!W6Fej_yQ))7PmpgB^HnDP~(2Co?M=*-6#lDQbXp0a4$9pb*Bn~h8tX)eF?a84a} z)}<)$zeIBIIwpU1MP;#9`tr?_7>xd0Nt~2SdJ)#86jvpB-sFE{7i?g*J@?*08>HQ8 z?CFhnSyYm?qDVCp^a)Df3N5ysqqLl%8p^dJdqdM)(RndA_AsA|zNJxBvLiz6Npav; z-|DEY<}U5kwC8IK!OLHD1Nj;!1Z}qaaJ8yC`z01sJR$A7~S(GX@wx=g%1(yS?iaH6h)3nH~DQ1T$PSbE^5K z2QN<`PIB9+)1vce3H1eTIoEgK7WIDetuBA;uD|DbPAwZB>CO(QJAZ7vG&>x}U{9Iu z4O_x}5uB1{Xs_V$wH(*C#_Lcq199jm&Y3~1&*y)lNnMWR?$g2@t(W?(e#bCZtCt+; zHX<3Rl*^51KBmT&_bVYfA$skx;=_~mF(!dGRI%it#4nWHy-yX&Vccy&=}|PgXm%(~ z(rk;jYsN#xR#RW7WGzGI%-EAKe)yDMkq*68NGnL7?!#kbxcC+&VNsWHV#pUbkU-ri zsOW$4iW%g>;|$V6`+i??4TdhIKnw}Tw&Q8yz)=XU{xthM3=8Nkm6ib$jZ zi=|0AW707-eiEGQez)*BD1iubVl%vH>3GwwkF37{ZC3V?RAS9rOqI0b4;k;R5vnm24}&K{QBdFYHSqi|l5_g@7#Qxkti@IUO^ zkho!RxR>T>8GBcGW_=5)Vr!Z%FWP;Tc89=n?pb=U;b>F+S>|0^PU72!G1RjtQ*K`D z%oAzLt=M}LqU850xeP0)y@v*KW7m3 zn4GWjHy9#02zzfLTtn+zO67lHn6P{vU+yS5kp`C;pzS_ZIWgD9@V(&5iEQ3>XWmZR z2W`>}7UU3i-XAd0xbT&^IJ()p;{U`w{Jy_>a~>H>oSccyBNXpQOLR-B;R0+ui~a;5 zLMan-#@ZXB)|evf5TzcTmG>s_7WyE)Jh$(sxgaem{(_)Rq)0W<$hvec@~GB*9oq+5>@i3x zt21^56|{4cU*SSq&R~D8&OMC475S0)Ld(LD35_I4n{~}E-q%WoaUB1?xFr0LpFRgy za!RNfzdUE^v@}jb)X^*i5fdh+znZJn*H7+i8)@qpr1ef>Dt%{iyGB%yA5>5(X>PUG zVRZR;MoM=?Q#^5+lTOD)9l?7h(($qWzzmW^Aj=#HOpt`sTMK^#z|kos6c!);`eHy! zb-IUAjNB3kYk@y6sZNK} zm?EhR7T}aOO4xt9n2xV#=4+e0US6SG;o_3@_?eLeKTr5ToF6wg@3?)c<(3STo`5N9 z5!|`IV=}zS{qn(noZDR|8Y9UBb*L!mbI7PJvGkkK^W19}`T0HkW#>|I@-VU-uGpic zIm2W}`>eI>k8#@AX#G`@>we$&i&6=)h*_9g$I%`tj~;(@W3Bmd87(zCh*4j7%|V%~ z2K}-bpi}#VF@U|GR0))C@J77`d`fwJ&kIEVj5myU#e*|LBy%v=TS6-5^lbCxs2RyY zb(-DDFjWWlL*5Y=X0G-5^mb+@YOLW_}KX<{wnGl`L zX%eSt>Vki5RepR>%sn;vLL4HNZdZzgz%xHu`A}q&?}94#Md#a!=NOIR7^ChJd}Nh) zCtq>^<#-CIn)>S{WhEMs@7Eb~MpMnr_=Z)O$d%niGI?h*7MNej#kb01>BVkF^@s`7 z&!{o=_^S&nODav+?S!**9+~@+B8(l5j9BTU7`uN91WzL9wulB*uyTTbQI+PWpz?&; zY+}!|d*}u+V-uh0?He#`nTYF+^$R^mJGG4-;A1BZ=vJR|CqR$zp1q;HMBY zQ60^!;`fa^Oo(zhsk(-N+KABran^0FBBs+9F^ndQmDJ=7PurgMNKMo~^vPQHUT1#@ z8DYY7yTwzywHs6(2&w(T?;ghG-ajU{MY8#x*Z#C6hDz#Gr@DOQ^yg-*Zjm`$bbS#= zw_YrlaS3(%m#Sjz<2v8Ifu6xS+STJoPsC7byUC?Sdn#_nPyMe)#byG(@oC zoEBVVf*=&(sR4FFF|~q`Ln#A;ALD^duxTH4GqNWtdVvy=g4V!qJYE)%vBWx}#_kY` z{CjJ+x5o-hrXgAv@{SKwUl}HY>m#g4KUeJM$@O;RnI5%=XQNjs#t)U;1RsBOs5706 zk2o~&u-u`U;LB;4h$MkVR&3{1!Xq9$-tFAJao5$HoBO zCC0Vl@BwD>-|0h&xPWmH%qy87f zyI)47sf=hCSOnN3+2Y_Pmk|fi$`cd0iHZbZTTzP0g z5n(6bFyNFh$(Z1tBrzhyAbB-vwRVaxfkG*_#%r&KCR@}G6P*Cq)Jr~Ox7*Qp4aGAVRyPY*CxAx+yGun6S_vK;fvYjOGrRz(7{EFM7V$AEbhl6o*B>L^;eK@ z)KY}%tYVZ^A6p9s+KSm5=eY_i+n?qPy%q|0=305g`QAT>!z*H9gnCBt8KH!2m(SJP zE4;DH)af@Gwhk9l?Qe@^@vm)*MT8iGYdzb0g$a~mZJ)$Cyy`NxSI@=9qqhJi78NMx zD&|6nu16k;B@};$qg`UA$9MOn$V5D`*Q1O(jsb^BBs%Y2(qDGS984A0hxr>#i2YED z;4nZ@!clDv&t!Pguvvuq?u$Ijd$d;Y5J*!sQ8#~Cb6J-Q>$^u;r&AQuk@8LI2 zoNFr6WE0@)l{Tlj%M`||@Mk2Avj*746?munvZs6AgF%0Z8itpFU6`}-9&tKMl`A5? z3J{K5MUu@8aa=v{plUgqn)bs6iG=o?D9WJ$0knM0CnE-aqg|;)Ti<+T)k7QYYCPvC zI}Oag5Q|ew5wGHudCep-WfCULw@COUv@LH8@?3{~{*-!iRfuof|8>p{h2r2rT7GTZ z!!Deh-8g@W=_4oc$NN_9LdG(U68kw86FajX2?eFHMwewq5mI$eLga|6quDYl4htbw zdPbnaQ`)5!pVQ3rHV$(ErFYty3I=wEwDyg)Lm}@>w-(j%X?sh#7*kOivkT1|_7Jlj zsDV~@=J)B|9=0P99@!;Pn~3%js^`1iDjj}?7=nK$4EqwK3QJ-bOX~|&sR#NS!!5iR zjyCAcYRAG40B_-zwiIYencL5uSZ@yLh?w21e6{S$)RF}+ zci6EZR3aD%?;T1QkRte~W4)wz=s=+lfJc9g!4GwcMSCVY+r1msJKbF+ z`9!LcUYn31+Ii_4zzPJkA#|Gtj#k#x`@lUT=x$?0xqh^{onH4NSa<<1`Q+|s4R6?A zAH_1D&PSeFtKm-{?Cj_A^26N7aK!|-%`2D2P&r>R(ge#{En(bkFyDl%oP<*(>*;^; z^`H2)5zLV>dYn`k(_=djMD4MdI8Sk;N6Fee#1xk;LL1}4g1P328W}jGA=qy(mqmTd z+zSubnd%=8=?^*N_6QqEBXXLW)JKKnXPiYwbf>jfmFI_whi%S0Tpt@y7hGAFE~RNZ zbel=O&K`gmS9(|ZmIcH$NH%|&9x#$=KBkfuCt8rSb#(V7*!zbokmTE>vtOs593RP3 z`fyGcd(|x&0)Os|c4h)?Z`$5BbGHS3^b<_E5}Kt0C%lWakPts8oQG*b&F4;k`{k|0 zgu@keLM0+fh&_kUb*c|9Edh0t@0%t_Kzz;o-F#0=B87X=RmD+a9fW_*LV-=PotfE@ zKbbW_lJ(?Vt@f=^oUg&)-cCgjE@5e#k_9I-u|3aY{4?2w8~Wa@pEOq(-m9p$e1mH@ zdy9z(@>c&=p&B=#kt)>Ytr0xm4${VFhH6R47DZ|LG=oNMG?+Hla3f|J$>GqBDs@?n z8-k-ut~c+$wg#Jb;hr8 zaG>&HZo%vsL%r#f&M)^q@2T{Qp{G)*aNsK?M4AcHTV4k|T02EaFJOoG3OQ+E>pRO# zk8gyPM6SH+!+Z&@#;M_akizj6sKIqo@hhV2xY6C~m~rlHtv-KNQF;DX^~Cs>`78Jh zKMp53=1{g>S}Um!7flQg?#C=BmoTu$dJcTfo0{An?TQ4-nV6N~D{%LO57JM<`_Jr} z#0#97$>S1V(Bb^#Z&4x&Ly5`8+Bb+4z}9}aUJ7qBN?lEPv4f+rn*18wr-?SS7o9?E zx?aWQ*hV3Wm*am%8`CDhf?A8T*izM_&)%AI3cj}bfbM#V8?M#8#@-{F)cb40CjOo=WId%g+HZH8-g5_FOgQLRhFXWu2#$18QR?u-m z8reu-`CB81oO4ikiVa+QP(CWm&`}T&jHa^!$~$|`75Z7wCu?p7`hoJOHDuSifsZx= zvbZH(<;8z2!UrUff<}Ia-0B`{kLm2k0st zG3_c7nBK4@2WtFC>TM9jJ0Kr8E&4?ny_DTjV-XT%_sg<1ztUSs`o&PVSDhShCBgOS z<+i83gx2-uajpFq`f;3hl$zCLwml)!nh}~TCGUTm!20Y2m2N8Ec>PW|D@QcWvs4MW z=47#ph0|@X#EWWlvOLP9R_qWv8|K~wdA)K503okKtLOO4b62x|_dLDEvJJ~AXlnVd zEuSP9y+ZVxI-Jy#zd^4laa$br(3?MQ2 zh#AI=j5TYPl6|sdDP##_i>z5gWM8r;vhN}LJzdxHyXv{_KcDBX`*qLx&%BT0_A%DF zXt)2QJfTPryeWVmZ}J9!w`h-myMJH+d#D4Ih&}?}3yOF0|HIV3#Wm0_F8UDHU-G|( z^xx7DSC|Xt{}dox-Owl~63|1~Ly_=*mzqKU_NE85hoN2noz+4?Twr#}a7Py?0Qx%w z^U#2KLG2A;C_5*>0pj8T{VNWI+yC1Her|tR5YfG@r*3-p=HK`ESI!UugMXv$V%+{w z{Z;%Ii~eT(bdWGFzzQS`0*T@a@y~z$-TzlFb+{eE9tOuRgrpPzK_Vd-D*R^PNfPi8 z1z>P{s22eB!W$M5h9gk;BLIFTet-i4N%iYGC8PimH~gI-?0?1o4uJs?ZzvM+Pe4)( z5OF}Dk^cmwBmoiSe@Gexh<|AOCUHPS>o?)$b$^pIAfopVf$`@If0G0ta`zv?uZjrd zH{l)G{w5hf#O@yw#g9b<`Um3sJN|)qS*Je`?;Q3A;)PxQK)kZ+ZxqEFg#Ur~Mu5Z?&-2jUxf{DJs6p#DJo>!JTZybaIaD28u@`3wL1TB)cYynlRz#Ki$2F-Z_0 zBOwV$OUU^B-*qN%m^&J(r3OfXKp<%u$-km@Xe1H}NB#93<2Uv{>;S{>Hx%jxwWInn zg0PbdamKz2%lB7*-B&;=K&awa6{BDNVX*!}@K`LNOKz8ryTEjr`B7oYW!mqg-#H(h zuz5t*`QGW#*bH=!d4Dl{_TAIwdy4maHuIenJZLX2xV)7)k?7BFY5&aAI{BVgUQ;+Bq;z*`? zgZ-VKP*mTX*hbW$FCD$6$c#UGKyICxMa76)Cmkk!naw6v3V%<0{Ta)feWTo}2m`xx zA{H&ne~9QB2XbD_X`-$D1AY?L<7iV;DIQLIU+)cJRV-=W<2P8Bx4RWuqd$A%OaxC# z8a6@SW+U)9l+QNWP;wtrDk%RlJtgowsV#)I*lJ-i{@N1zxiv4%Dj0q#JEQaXu%h{% zSn%%WH#$LHS%0{fZHX$$;-0F>1CH6h>E(YN6pZ(LdBnw6%QmdERy_ z467re1^uNGoUOL?g%e*S9&{RLT}GNVXlQeXg$(n>ao>ime9avz`tcQ9m4F<`r*g?p z=T7JbdcevaAPr_K;B$jCH(%prmFRV6MUk11=80@vk$<`V@=WCw{=w?q&=81ub6QG^ zmdksXP(Kk1%tv@=h_@v%V64@K#&cG^4Z;QAx({YXsV34-3beEWtqwZpkbn2yArCZk0 zj4U~d`F|r2)H?60g}ZiZ?)g6RA9Q5C2VP2qFn90@y*p+ov^Un#=`oGsajh1AaTDCL zcs;5S^$yqcIQDDlPd~8{gkB$a|2B=lBdL6w1Az~m9@B<2f`eB!WTpmpi3+>n#vR=6rUk0eGskBg_=L!7Bfz(vH>v3 z=VAM=SLdT~SzUH_4No@?(o0=KmE?X@WnI&KIA4N{Dnr>A#EmO>6@0I-4ZJ-*dT!lt zFn^V1!PinYgrMVE!dVZZ4r@g2Tnh_Tlm8NUB{aCo{mKzYpChrSH3*2)L;JRxOwRMZ zAnDjGRUhLQW@TVrc{$cS!;t!cdWW|;zxZ5eB7m~cOttHJnkx@f1Ak3$q9vT!4az|u0&LZ!o@Ou4n%>|zXWj;i zS{D2H}eX$}<4WBP)6MCEgM>Oy+&_4S=aYEMa#S4;fRQ_#)iuX(%OXsZ9%L`)LF zAbfq5yFsV%2T^>K@vVySjX|;!b(Th_K`R+1&o0XCKJsHhyBY>3;%fU#Y30vJyotS-#FLubYn~Tq@ehFa$bCgEP(+ z!#W(lsRi*H#2S`|OY&I%S7C_kyQ4D-Cz=jxrqy9Dp0&<7y{Aik=eZJX7RaJ~Ui<<9VL7secA@-`ma@ zJEDr=!+wn9t&)p4&`B|yX&GbQqK~Qee`NUyR()=)bsv#1lw`@#MEcf?)z6n#%z5w{ z3u>L8Yj?rBgHb=|?3$TD8`)8Ty1Ae}7gg3F(NB&=lCs^ng$N5Rl5>l?0DUy!rGWkg zS`*^1_UxZSa}3jTl&&#Tl7ICmI#UvJ)j)YyBQ4HVs)or05~)im<7Bb!sqG4jVEuUM zW*OYF@#hjc=0O0RIJ*R8 z?Te^OH$NjjEGRMcz&(0BhKs(2W3Y4yd1gybnvRc%`{-=0WEO2?=Uk4Q68BohNinTp!?4 z5v^l(9es_hA@f_g{(nPR$>Nn>x8epOiq~yT%O|h-R4*eS`Idje+1}3X%B_tyn3O#Q zBYXx^W8Y{j`1s!NTW$N2eUBiKE2H7O2d=d1c*v7$K@2Nx`Pf0# zKk{}Vt>c~idCiLhLi|1o=zrY^C2NrAVW#`N{t`iICSkZD0GIfbwyd2MV9o81a0AldEQ5pR&_4$%4E`ofgSm1lXy~P zW*krDtA9k%tA7MnPWN-$IZ2oc`xk7tBuC67NPAoF=w>HCbnCzD)Vm%Q?bl5bxE}`T zX&1nN&bElbC2RFRunGV_)TwJJ;FY>P9TjdD>!VZ7IuK7UnK9Z7zQ$-BDulr}~*4QKFq z?ps7rE`MIQat+gg*ztIiSR8xg$;`CbUYr?=aIDtQi*uLOsj&U1!q2*gwr^I!HW5U! z1&dtWV8Sdz zNl)71>VHR)aim$%mJv892juPj}S8{J}APiEHT;Om8Nh z`%$~>yMOFdaqB?T`}9NsMYdJOK0V)0 z-95i~W1^n#Kr)E!Ywh9E!)g+RP@=DC4i*-r$H@wIIoFqP`eusGCV^(yZ{@yqKUjC< z*_LK^o^>x*Hu#-A61{0SZ{aQ1Fz$n`*qFWLfkF-~OIH>6>%u>4nYb4)BNQtGttK_r6WOlPB)66&;b{BTr*Qdy+g z&-(6^M)1*7N%F)bVQ}v=8ylVn9FOe_EDGkBo~m;1iRhNzNjTHJy|Zh6)4>_b4D^H( z=_eHqNObw=?4Lbu_C`-Xe4|w29~CqQ^87UK7C#-Nld3j>ZgA5qyIg~!-rOwy?0;}J zmoh6wG#}836?0UlxcBKrC)nlz$tT4_^I^%g)6tDe8hyWOoD?gREX;@5&iy78ElhS$ z7f$C|a$Rf-7aX}tWtDuGTE>Kvl5@?=C6b$?OTrMg9OqXNZ?e7%>Rlizu=}`+X(d}o zZq`BqtW1=1WF@Sd#hDCTq2L1k#DiuN@im3-1m+C%|7gJEYjr14P0@9Nw z9%C!?tb_f|M`32{3Q9~Ib0YQT440Qm8s-8)_3_5?!sQ01p(aBYhgvSbo_`jIu;#rN z$ai0fnZH7zWOErUgPOx;xH9_1tvWq(^jst4=TcGR*jt)RPWS+3kFUjlZ1Qf+s}ke+-iiib5c zGS(%Si8X~QE9!bX#Maj~=dj<}%DaKNS zy@f<=A;Qoo-Mn4lcqkLA*PJO7LikT4Aa!|X58y5DMBBu;OP z8G(_KGSx_Fc$BH7c7o2-7kqG0!LFu`Z&J3HKcz4U2_p|x(iEv1RuY}7Ef*81m+8i5 z1vzVY5HHmBfF0vM(yK@35P>XVZU7#o~AnH-7JSUW9 zpGo;4T>0|V`>he`G|f`7BsMoQKGH;G3I8qT*2s#=VKd?Ec*?&0$6nn$0pFW8oK|h5 z&70rppGejBJW%{566u)E*W%6fvutnnWf1kL$+*hQ#`JSGFY=JZ2Xdp5FR{WN^$$3L z8Mm{}!t30fq<>Z%&qw##l;&iz3)HXJl+kSGz*Q<8K+3f(_uteEEUJcl3vT&j+zI{TWX5WNtX;wo1gtTW3BGU54 z7jErZxHYf`1(lFj)T+SVd|^IryxurrhS1ij+m5L9Wq&G6!kDu>{`U4sUimeHcWGh4 zIL@AswToY5-ZKJu`N?pOvGP&ZMLh+l2s#w|x9KDG6K*rI9ZTjH@|lgDjRhNnPdY{< z-hxT;=&CNW9~r1N?=^2#X?u_`v2RKq%5HtNRcU=jk>F)Wl&He^*&w>m$c0L>M~z^+=jStnKbiKl({sYPvFdpwod8lJWe+8Se%IEYei zJF(Vx-(Bc9xsxcIsT69+aiSX9O0}t|=;FxOlv28>IbARfMd>n;a;Xd>mxf#tIi*A; zoVCq4Gpz6Uhu`~q*Lt7#d7t4H1QK`0u(ZZcWlQw(MYeh+0dp_J=QKzxOXy~LxXZ)?wgO68G@9#)WuSRRHT{C~eV_+T4ew;sqAg@BKS^K9|@(jACQEJ-(GK z3N+F&Q2A80j&MIwWv(3ddeKSiVte0dvtPOE6;?(*D9G&%*g+^(@fX(y8O0}QY4`_Yq-yIRK_VCsA?#!Dq z(69H;l!AesZ-QK^TZcsF-)Wc*YpbM`Y}ixhG#HkaG&tq2wHLmdB;6DpefeLtHiblR zU!qL)*Q~u6PlCVEp4S#D@vo@9zRqLKln816qv@(9oLl=0<6N&N$0{?+jO<3X`I*?9 z+Vx1JnPqT2>fXUBpQ?mSsb?17c4ca-q%p%k$E{z^oM=DUtn#v))130&DWNs}z*J68 z{qc#G1o~H2X&L@BZ_sgS;h$t;kK$;{zN4YOWoepc=P#JM#jv?1 zyQuFC9#3pX#*Y<3Sx4H6~Yk9ykXQ>toF@nwVlox`6FC7w<^Tcf|c z#nEcBWplgm!t9)ycRFF3>u(nNkKA{&l(zKW{Z#Jmv!TnW&wHo&FT>yals_|XZ5UP- zYKR&qN63!aI+e;ZtQ!@ zGI}11Og|)T9ICJ@_q^4y=J@3f$GT&)LhU6|op9q^N10g_2+b^pvoBp)6uDzxhrXWc zy(5W}bmtqqJbm}_=66wA4P6vzfl0BP3O2S2zBt=wU8U{=xT$`V6y zrE{L>`nG|^?A`Od(5gz?vGa%;A--aHR(xi^OX~cEQF+y`Y(u`UGx>Nci+};E@4n8n z3%$Qo=~SL)L@3{UVP!PoAAQ#s<&$@nWeobAMI4VR*j&Kl~1S3aeh8lwe^N z$a*JNqIZl@4b2Z5zv+$MIA!NT-}>tI(A#Amw`_GBd+GzzzB5S=I@Gr}{cT1}b7bbV zm2ZObCVnXKsC8+zIal&t`-#uTpzVuOXhGd*m&Q1Kg* z5=fF*jG`fcSd8Qd35CZ9g5>8xlEw1?$0=fxv4tT`{hvgZzyVSWkg#%ZCxM%cqDcn3 z8qgfX%RzK8KaZqn{47B*c~90S@=F)+Y#4CEDIAkE5eI3tc&n!sQIhN1DX1C}KjULMT?j7z`}5*mkv zuA?xHP#%Peym1`Sw1mN-GEl+*tWR_w88RcBei8rzr=MULo~n>x@t8qw!DEmH5&{Q9QS_)ajFT?OQe#(d zbaoU)ayYFd1$b*qB2UGsCINwa5+GTmq(5{tI)6aYEab7k@b(CahUDkb42cVlq-g>d zCP@*1m&eLb_zyIr9g{3My47QasSq&U9Yt}x!ZcDQUWA4uh0{;d$k7yaQUCvYDghd; z4qk*ogU2sq2$ID|!Y~96Aj6=A!kS|_IL-n``Da;<#fxwZC&AT2>VNyy?OMltfgULpIPen@hNhVgWv z7_xILMj_Y3m_Y`ICXeSK55VY00;bq;XI0Us5ehZT%6pawT+|pw0)!?e_8tzx{{V4c B96$g7 diff --git a/bn.tex b/bn.tex index f10cee4..9808a73 100644 --- a/bn.tex +++ b/bn.tex @@ -1,7 +1,7 @@ \documentclass{article} \begin{document} -\title{LibTomMath v0.04 \\ A Free Multiple Precision Integer Library} +\title{LibTomMath v0.05 \\ A Free Multiple Precision Integer Library} \author{Tom St Denis \\ tomstdenis@iahu.ca} \maketitle \newpage @@ -91,6 +91,8 @@ variables as destinations. For example: mp_div_2(&x, &x); /* x = x / 2 */ \end{verbatim} +\section{Quick Overview} + \subsection{Basic Functionality} Essentially all LibTomMath functions return one of three values to indicate if the function worked as desired. A function will return \textbf{MP\_OKAY} if the function was successful. A function will return \textbf{MP\_MEM} if @@ -335,59 +337,69 @@ The class of digit manipulation functions such as \textbf{mp\_rshd}, \textbf{mp\ very simple functions to analyze. \subsubsection{mp\_rshd(mp\_int *a, int b)} -If the shift count ``b'' is less than or equal to zero the function returns without doing any work. If the -the shift count is larger than the number of digits in ``a'' then ``a'' is simply zeroed without shifting digits. +Shifts $a$ by given number of digits to the right and is equivalent to dividing by $\beta^b$. The work is performed +in-place which means the input and output are the same. If the shift count $b$ is less than or equal to zero +the function returns without doing any work. If the the shift count is larger than the number of digits in $a$ +then $a$ is simply zeroed without shifting digits. This function requires no additional memory and $O(N)$ time. \subsubsection{mp\_lshd(mp\_int *a, int b)} -If the shift count ``b'' is less than or equal to zero the function returns success without doing any work. +Shifts $a$ by a given number of digits to the left and is equivalent to multiplying by $\beta^b$. The work +is performed in-place which means the input and output are the same. If the shift count $b$ is less than or equal +to zero the function returns success without doing any work. This function requires $O(b)$ additional digits of memory and $O(N)$ time. \subsubsection{mp\_div\_2d(mp\_int *a, int b, mp\_int *c, mp\_int *d)} -If the shift count ``b'' is less than or equal to zero the function places ``a'' in ``c'' and returns success. +Shifts $a$ by a given number of \textbf{bits} to the right and is equivalent to dividing by $2^b$. The shifted number is stored +in the $c$ parameter. The remainder of $a/2^b$ is optionally stored in $d$ (if it is not passed as NULL). +If the shift count $b$ is less than or equal to zero the function places $a$ in $c$ and returns success. This function requires $O(2 \cdot N)$ additional digits of memory and $O(2 \cdot N)$ time. \subsubsection{mp\_mul\_2d(mp\_int *a, int b, mp\_int *c)} -If the shift count ``b'' is less than or equal to zero the function places ``a'' in ``c'' and returns success. +Shifts $a$ by a given number of bits to the left and is equivalent to multiplying by $2^b$. The shifted number +is placed in the $c$ parameter. If the shift count $b$ is less than or equal to zero the function places $a$ +in $c$ and returns success. This function requires $O(N)$ additional digits of memory and $O(2 \cdot N)$ time. \subsubsection{mp\_mod\_2d(mp\_int *a, int b, mp\_int *c)} -If the shift count ``b'' is less than or equal to zero the function places ``a'' in ``c'' and returns success. +Performs the action of reducing $a$ modulo $2^b$ and stores the result in $c$. If the shift count $b$ is less than +or equal to zero the function places $a$ in $c$ and returns success. This function requires $O(N)$ additional digits of memory and $O(2 \cdot N)$ time. \subsection{Basic Arithmetic} \subsubsection{mp\_cmp(mp\_int *a, mp\_int *b)} -Performs a \textbf{signed} comparison between ``a'' and ``b'' returning -\textbf{MP\_GT} is ``a'' is larger than ``b''. +Performs a \textbf{signed} comparison between $a$ and $b$ returning \textbf{MP\_GT} is $a$ is larger than $b$. This function requires no additional memory and $O(N)$ time. \subsubsection{mp\_cmp\_mag(mp\_int *a, mp\_int *b)} -Performs a \textbf{unsigned} comparison between ``a'' and ``b'' returning -\textbf{MP\_GT} is ``a'' is larger than ``b''. Note that this comparison is unsigned which means it will report, for -example, $-5 > 3$. By comparison mp\_cmp will report $-5 < 3$. +Performs a \textbf{unsigned} comparison between $a$ and $b$ returning \textbf{MP\_GT} is $a$ is larger than $b$. Note +that this comparison is unsigned which means it will report, for example, $-5 > 3$. By comparison mp\_cmp will +report $-5 < 3$. This function requires no additional memory and $O(N)$ time. \subsubsection{mp\_add(mp\_int *a, mp\_int *b, mp\_int *c)} -Handles the sign of the numbers correctly which means it will subtract as required, e.g. $a + -b$ turns into $a - b$. +Computes $c = a + b$ using signed arithmetic. Handles the sign of the numbers which means it will subtract as +required, e.g. $a + -b$ turns into $a - b$. This function requires no additional memory and $O(N)$ time. \subsubsection{mp\_sub(mp\_int *a, mp\_int *b, mp\_int *c)} -Handles the sign of the numbers correctly which means it will add as required, e.g. $a - -b$ turns into $a + b$. +Computes $c = a - b$ using signed arithmetic. Handles the sign of the numbers which means it will add as +required, e.g. $a - -b$ turns into $a + b$. This function requires no additional memory and $O(N)$ time. \subsubsection{mp\_mul(mp\_int *a, mp\_int *b, mp\_int *c)} -Handles the sign of the numbers correctly which means it will correct the sign of the product as required, -e.g. $a \cdot -b$ turns into $-ab$. +Computes $c = a \cdot b$ using signed arithmetic. Handles the sign of the numbers correctly which means it will +correct the sign of the product as required, e.g. $a \cdot -b$ turns into $-ab$. For relatively small inputs, that is less than 80 digits a standard baseline or comba-baseline multiplier is used. It requires no additional memory and $O(N^2)$ time. The comba-baseline multiplier is only used if it can safely be used @@ -397,33 +409,41 @@ than 80 for the inputs than a Karatsuba multiplier is used which requires approx $O(N^{lg(3)})$ time. \subsubsection{mp\_sqr(mp\_int *a, mp\_int *b)} +Computes $b = a^2$. For relatively small inputs, that is less than 80 digits a modified squaring or comba-squaring algorithm is used. It requires no additional memory and $O((N^2 + N)/2)$ time. The comba-squaring method is used only if it can be safely used without losing carry digits. After 80 digits a Karatsuba squaring algorithm is used whcih requires approximately $O(4 \cdot N)$ memory and $O(N^{lg(3)})$ time. \subsubsection{mp\_div(mp\_int *a, mp\_int *b, mp\_int *c, mp\_int *d)} -The quotient is placed in ``c'' and the remainder in ``d''. Either (or both) of ``c'' and ``d'' can be set to NULL -if the value is not desired. +Computes $c = \lfloor a/b \rfloor$ and $d \equiv a \mbox{ (mod }b\mbox{)}$. The division is signed which means the sign +of the output is not always positive. The sign of the remainder equals the sign of $a$ while the sign of the +quotient equals the product of the ratios $(a/\vert a \vert) \cdot (b/\vert b \vert)$. Both $c$ and $d$ can be +optionally passed as NULL if the value is not desired. For example, if you want only the quotient of $x/y$ then +mp\_div(\&x, \&y, \&z, NULL) is acceptable. -This function requires $O(4 \cdot N)$ memory and $O(N^2 + N)$ time. +This function requires $O(4 \cdot N)$ memory and $O(3 \cdot N^2)$ time. + +\subsubsection{mp\_mod(mp\_int *a, mp\_int *b, mp\_int *c)} +Computes $c \equiv a \mbox{ (mod }b\mbox{)}$ but with the added condition that $0 \le c < b$. That is a normal +division is performed and if the remainder is negative $b$ is added to it. Since adding $b$ modulo $b$ is equivalent +to adding zero ($0 \equiv b \mbox{ (mod }b\mbox{)}$) the result is accurate. The results are undefined +when $b \le 0$, in theory the routine will still give a properly congruent answer but it will not always be positive. + +This function requires $O(4 \cdot N)$ memory and $O(3 \cdot N^2)$ time. \subsection{Modular Arithmetic} \subsubsection{mp\_addmod, mp\_submod, mp\_mulmod, mp\_sqrmod} These functions take the time of their host function plus the time it takes to perform a division. For example, -mp\_addmod takes $O(N + (N^2 + N))$ time. Note that if you are performing many modular operations in a row with +mp\_addmod takes $O(N + 3 \cdot N^2)$ time. Note that if you are performing many modular operations in a row with the same modulus you should consider Barrett reductions. -NOTE: This section will be expanded upon in future releases of the library. +Also note that these functions use mp\_mod which means the result are guaranteed to be positive. \subsubsection{mp\_invmod(mp\_int *a, mp\_int *b, mp\_int *c)} -This function is technically only defined for moduli who are positive and inputs that are positive. That is it will find -$c = 1/a \mbox{ (mod }b\mbox{)}$ for any $a > 0$ and $b > 0$. The function will work for negative values of $a$ since -it merely computes $c = -1 \cdot (1/{\vert a \vert}) \mbox{ (mod }b\mbox{)}$. In general the input is only -\textbf{guaranteed} to lead to a correct output if $-b < a < b$ and $(a, b) = 1$. - -NOTE: This function will be revised to accept a wider range of inputs in future releases. +This function will find $c = 1/a \mbox{ (mod }b\mbox{)}$ for any value of $a$ such that $(a, b) = 1$ and $b > 0$. When +$b$ is odd a ``fast'' variant is used which finds the inverse twice as fast. \section{Timing Analysis} \subsection{Observed Timings} @@ -440,34 +460,34 @@ were observed. \begin{tabular}{c|c|c|c} \hline \textbf{Operation} & \textbf{Size (bits)} & \textbf{Time with MPI (cycles)} & \textbf{Time with LibTomMath (cycles)} \\ \hline -Inversion & 128 & 264,083 & 172,381 \\ -Inversion & 256 & 549,370 & 381,237 \\ -Inversion & 512 & 1,675,975 & 1,212,341 \\ -Inversion & 1024 & 5,237,957 & 3,114,144 \\ -Inversion & 2048 & 17,871,944 & 8,137,896 \\ -Inversion & 4096 & 66,610,468 & 22,469,360 \\ +Inversion & 128 & 264,083 & 159,194 \\ +Inversion & 256 & 549,370 & 355,914 \\ +Inversion & 512 & 1,675,975 & 842,538 \\ +Inversion & 1024 & 5,237,957 & 2,170,804 \\ +Inversion & 2048 & 17,871,944 & 6,250,876 \\ +Inversion & 4096 & 66,610,468 & 18,161,612 \\ \hline -Multiply & 128 & 1,426 & 847 \\ -Multiply & 256 & 2,551 & 1,848 \\ -Multiply & 512 & 7,913 & 3,505 \\ -Multiply & 1024 & 28,496 & 9,097 \\ -Multiply & 2048 & 109,897 & 29,497 \\ -Multiply & 4096 & 469,970 & 112,651 \\ +Multiply & 128 & 1,426 & 828 \\ +Multiply & 256 & 2,551 & 1,393 \\ +Multiply & 512 & 7,913 & 2,926 \\ +Multiply & 1024 & 28,496 & 8,620 \\ +Multiply & 2048 & 109,897 & 28,967 \\ +Multiply & 4096 & 469,970 & 106,855 \\ \hline -Square & 128 & 1,319 & 883 \\ -Square & 256 & 1,776 & 1,895 \\ -Square & 512 & 5,399 & 3,543 \\ -Square & 1024 & 18,991 & 8,692 \\ -Square & 2048 & 72,126 & 26,792 \\ -Square & 4096 & 306,269 & 103,263 \\ +Square & 128 & 1,319 & 869 \\ +Square & 256 & 1,776 & 1,362 \\ +Square & 512 & 5,399 & 2,571 \\ +Square & 1024 & 18,991 & 6,332 \\ +Square & 2048 & 72,126 & 18,426 \\ +Square & 4096 & 306,269 & 76,305 \\ \hline -Exptmod & 512 & 32,021,586 & 7,096,687 \\ -Exptmod & 768 & 97,595,492 & 14,849,813 \\ -Exptmod & 1024 & 223,302,532 & 27,826,489 \\ -Exptmod & 2048 & 1,682,223,369 & 142,026,274 \\ -Exptmod & 2560 & 3,268,615,571 & 292,597,205 \\ -Exptmod & 3072 & 5,597,240,141 & 452,731,243 \\ -Exptmod & 4096 & 13,347,270,891 & 941,433,401 +Exptmod & 512 & 32,021,586 & 5,709,468 \\ +Exptmod & 768 & 97,595,492 & 12,473,526 \\ +Exptmod & 1024 & 223,302,532 & 23,593,075 \\ +Exptmod & 2048 & 1,682,223,369 & 121,992,481 \\ +Exptmod & 2560 & 3,268,615,571 & 258,155,605 \\ +Exptmod & 3072 & 5,597,240,141 & 399,800,504 \\ +Exptmod & 4096 & 13,347,270,891 & 826,013,375 \end{tabular} \end{center} @@ -475,7 +495,7 @@ Exptmod & 4096 & 13,347,270,891 & 941,433,401 Note that the figures do fluctuate but their magnitudes are relatively intact. The purpose of the chart is not to get an exact timing but to compare the two libraries. For example, in all of the tests the exact time for a 512-bit -squaring operation was not the same. The observed times were all approximately 3,500 cycles, more importantly they +squaring operation was not the same. The observed times were all approximately 2,500 cycles, more importantly they were always faster than the timings observed with MPI by about the same magnitude. \subsection{Digit Size} diff --git a/changes.txt b/changes.txt index bf89d99..7900121 100644 --- a/changes.txt +++ b/changes.txt @@ -1,3 +1,16 @@ +Dec 30th, 2002 +v0.05 -- Builds with MSVC out of the box + -- Fixed a bug in mp_invmod w.r.t. even moduli + -- Made mp_toradix and mp_read_radix use char instead of unsigned char arrays + -- Fixed up exptmod to use fewer multiplications + -- Fixed up mp_init_size to use only one heap operation + -- Note there is a slight "off-by-one" bug in the library somewhere + without the padding (see the source for comment) the library + crashes in libtomcrypt. Anyways a reasonable workaround is to pad the + numbers which will always correct it since as the numbers grow the padding + will still be beyond the end of the number + -- Added more to the manual + Dec 29th, 2002 v0.04 -- Fixed a memory leak in mp_to_unsigned_bin -- optimized invmod code diff --git a/demo.c b/demo.c index ed697c9..5e29d1f 100644 --- a/demo.c +++ b/demo.c @@ -7,18 +7,30 @@ #include #include #include "mpi.h" + #ifdef _MSC_VER + typedef __int64 ulong64; + #else + typedef unsigned long long ulong64; + #endif + #else #include "bn.h" #endif #ifdef TIMER_X86 #define TIMER -extern unsigned long long rdtsc(void); +extern ulong64 rdtsc(void); extern void reset(void); #else -unsigned long long _tt; +ulong64 _tt; void reset(void) { _tt = clock(); } -unsigned long long rdtsc(void) { return clock() - _tt; } +ulong64 rdtsc(void) { return clock() - _tt; } +#endif + +#ifndef DEBUG +int _ifuncs; +#else +extern int _ifuncs; #endif void ndraw(mp_int *a, char *name) @@ -70,7 +82,7 @@ int main(void) #ifdef TIMER int n; - unsigned long long tt; + ulong64 tt; #endif mp_init(&a); @@ -96,48 +108,55 @@ int main(void) #ifdef TIMER mp_read_radix(&a, "340282366920938463463374607431768211455", 10); - mp_read_radix(&b, "234892374891378913789237289378973232333", 10); + mp_read_radix(&b, "340282366920938463463574607431768211455", 10); + while (a.used * DIGIT_BIT < 8192) { + reset(); + for (rr = 0; rr < 1000000; rr++) { + mp_add(&a, &b, &c); + } + tt = rdtsc(); + printf("Adding %d-bit took %llu cycles\n", mp_count_bits(&a), tt / ((ulong64)1000000)); + mp_sqr(&a, &a); + mp_sqr(&b, &b); + } + + mp_read_radix(&a, "340282366920938463463374607431768211455", 10); + mp_read_radix(&b, "340282366920938463463574607431768211455", 10); + while (a.used * DIGIT_BIT < 8192) { + reset(); + for (rr = 0; rr < 1000000; rr++) { + mp_sub(&a, &b, &c); + } + tt = rdtsc(); + printf("Subtracting %d-bit took %llu cycles\n", mp_count_bits(&a), tt / ((ulong64)1000000)); + mp_sqr(&a, &a); + mp_sqr(&b, &b); + } + + + mp_read_radix(&a, "340282366920938463463374607431768211455", 10); while (a.used * DIGIT_BIT < 8192) { reset(); - for (rr = 0; rr < 1000; rr++) { - mp_invmod(&b, &a, &c); + for (rr = 0; rr < 10000; rr++) { + mp_sqr(&a, &b); } tt = rdtsc(); - mp_mulmod(&b, &c, &a, &d); - if (mp_cmp_d(&d, 1) != MP_EQ) { - printf("Failed to invert\n"); - return 0; - } - printf("Inverting mod %d-bit took %llu cycles\n", mp_count_bits(&a), tt / ((unsigned long long)1000)); - mp_sqr(&a, &a); - mp_sqr(&b, &b); + printf("Squaring %d-bit took %llu cycles\n", mp_count_bits(&a), tt / ((ulong64)10000)); + mp_copy(&b, &a); } mp_read_radix(&a, "340282366920938463463374607431768211455", 10); while (a.used * DIGIT_BIT < 8192) { reset(); - for (rr = 0; rr < 1000000; rr++) { + for (rr = 0; rr < 10000; rr++) { mp_mul(&a, &a, &b); } tt = rdtsc(); - printf("Multiplying %d-bit took %llu cycles\n", mp_count_bits(&a), tt / ((unsigned long long)1000000)); + printf("Multiplying %d-bit took %llu cycles\n", mp_count_bits(&a), tt / ((ulong64)10000)); mp_copy(&b, &a); } - - - - - mp_read_radix(&a, "340282366920938463463374607431768211455", 10); - while (a.used * DIGIT_BIT < 8192) { - reset(); - for (rr = 0; rr < 1000000; rr++) { - mp_sqr(&a, &b); - } - tt = rdtsc(); - printf("Squaring %d-bit took %llu cycles\n", mp_count_bits(&a), tt / ((unsigned long long)1000000)); - mp_copy(&b, &a); - } - + + { char *primes[] = { "17933601194860113372237070562165128350027320072176844226673287945873370751245439587792371960615073855669274087805055507977323024886880985062002853331424203", @@ -160,7 +179,7 @@ int main(void) mp_mod(&b, &c, &b); mp_set(&c, 3); reset(); - for (rr = 0; rr < 50; rr++) { + for (rr = 0; rr < 35; rr++) { mp_exptmod(&c, &b, &a, &d); } tt = rdtsc(); @@ -173,15 +192,33 @@ int main(void) draw(&d); exit(0); } - printf("Exponentiating %d-bit took %llu cycles\n", mp_count_bits(&a), tt / ((unsigned long long)50)); + printf("Exponentiating %d-bit took %llu cycles\n", mp_count_bits(&a), tt / ((ulong64)35)); } } + mp_read_radix(&a, "340282366920938463463374607431768211455", 10); + mp_read_radix(&b, "234892374891378913789237289378973232333", 10); + while (a.used * DIGIT_BIT < 8192) { + reset(); + for (rr = 0; rr < 100; rr++) { + mp_invmod(&b, &a, &c); + } + tt = rdtsc(); + mp_mulmod(&b, &c, &a, &d); + if (mp_cmp_d(&d, 1) != MP_EQ) { + printf("Failed to invert\n"); + return 0; + } + printf("Inverting mod %d-bit took %llu cycles\n", mp_count_bits(&a), tt / ((ulong64)100)); + mp_sqr(&a, &a); + mp_sqr(&b, &b); + } + #endif inv_n = expt_n = lcm_n = gcd_n = add_n = sub_n = mul_n = div_n = sqr_n = mul2d_n = div2d_n = 0; for (;;) { - printf("%7lu/%7lu/%7lu/%7lu/%7lu/%7lu/%7lu/%7lu/%7lu/%7lu/%7lu\r", add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, gcd_n, lcm_n, expt_n, inv_n); + printf("%7lu/%7lu/%7lu/%7lu/%7lu/%7lu/%7lu/%7lu/%7lu/%7lu/%7lu/%5d\r", add_n, sub_n, mul_n, div_n, sqr_n, mul2d_n, div2d_n, gcd_n, lcm_n, expt_n, inv_n, _ifuncs); fgets(cmd, 4095, stdin); cmd[strlen(cmd)-1] = 0; printf("%s ]\r",cmd); fflush(stdout); diff --git a/makefile b/makefile index 52e0735..58b57ad 100644 --- a/makefile +++ b/makefile @@ -1,12 +1,13 @@ CC = gcc -CFLAGS += -DDEBUG -Wall -W -Os +CFLAGS += -DDEBUG -Wall -W -O3 -fomit-frame-pointer -funroll-loops -VERSION=0.04 +VERSION=0.05 default: test -test: bn.o demo.o +test: bn.o demo.o $(CC) bn.o demo.o -o demo + cd mtest ; gcc -O3 -fomit-frame-pointer -funroll-loops mtest.c -o mtest.exe -s docdvi: bn.tex latex bn