summaryrefslogtreecommitdiff
path: root/keyexchange/isakmpd-20041012/math_2n.c
diff options
context:
space:
mode:
authorOthmar Gsenger <otti@anytun.org>2008-05-25 09:50:42 +0000
committerOthmar Gsenger <otti@anytun.org>2008-05-25 09:50:42 +0000
commit71da41451212389bea25d67bc5da696b6d194bff (patch)
treea3b20decbd8bc9e47640af5fa4b39f731477955a /keyexchange/isakmpd-20041012/math_2n.c
parentimproved presentation again (diff)
moved keyexchange to http://anytun.org/svn/keyexchange
Diffstat (limited to 'keyexchange/isakmpd-20041012/math_2n.c')
-rw-r--r--keyexchange/isakmpd-20041012/math_2n.c1107
1 files changed, 0 insertions, 1107 deletions
diff --git a/keyexchange/isakmpd-20041012/math_2n.c b/keyexchange/isakmpd-20041012/math_2n.c
deleted file mode 100644
index f8828ef..0000000
--- a/keyexchange/isakmpd-20041012/math_2n.c
+++ /dev/null
@@ -1,1107 +0,0 @@
-/* $OpenBSD: math_2n.c,v 1.16 2004/06/14 09:55:41 ho Exp $ */
-/* $EOM: math_2n.c,v 1.15 1999/04/20 09:23:30 niklas Exp $ */
-
-/*
- * Copyright (c) 1998 Niels Provos. All rights reserved.
- * Copyright (c) 1999 Niklas Hallqvist. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
- */
-
-/*
- * This code was written under funding by Ericsson Radio Systems.
- */
-
-/*
- * B2N is a module for doing arithmetic on the Field GF(2**n) which is
- * isomorph to ring of polynomials GF(2)[x]/p(x) where p(x) is an
- * irreduciable polynomial over GF(2)[x] with grade n.
- *
- * First we need functions which operate on GF(2)[x], operation
- * on GF(2)[x]/p(x) can be done as for Z_p then.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "sysdep.h"
-
-#include "math_2n.h"
-#include "util.h"
-
-static u_int8_t hex2int(char);
-
-static char int2hex[] = "0123456789abcdef";
-CHUNK_TYPE b2n_mask[CHUNK_BITS] = {
- 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
-#if CHUNK_BITS > 8
- 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
-#if CHUNK_BITS > 16
- 0x00010000, 0x00020000, 0x00040000, 0x00080000,
- 0x00100000, 0x00200000, 0x00400000, 0x00800000,
- 0x01000000, 0x02000000, 0x04000000, 0x08000000,
- 0x10000000, 0x20000000, 0x40000000, 0x80000000,
-#endif
-#endif
-};
-
-/* Convert a hex character to its integer value. */
-static u_int8_t
-hex2int(char c)
-{
- if (c <= '9')
- return c - '0';
- if (c <= 'f')
- return 10 + c - 'a';
-
- return 0;
-}
-
-int
-b2n_random(b2n_ptr n, u_int32_t bits)
-{
- if (b2n_resize(n, (CHUNK_MASK + bits) >> CHUNK_SHIFTS))
- return -1;
-
- getrandom((u_int8_t *) n->limp, CHUNK_BYTES * n->chunks);
-
- /* Get the number of significant bits right */
- if (bits & CHUNK_MASK) {
- CHUNK_TYPE m =
- (((1 << ((bits & CHUNK_MASK) - 1)) - 1) << 1) | 1;
- n->limp[n->chunks - 1] &= m;
- }
- n->dirty = 1;
- return 0;
-}
-
-/* b2n management functions */
-
-void
-b2n_init(b2n_ptr n)
-{
- n->chunks = 0;
- n->limp = 0;
-}
-
-void
-b2n_clear(b2n_ptr n)
-{
- if (n->limp)
- free(n->limp);
-}
-
-int
-b2n_resize(b2n_ptr n, unsigned int chunks)
-{
- size_t old = n->chunks;
- size_t size;
- CHUNK_TYPE *new;
-
- if (chunks == 0)
- chunks = 1;
-
- if (chunks == old)
- return 0;
-
- size = CHUNK_BYTES * chunks;
-
- new = realloc(n->limp, size);
- if (!new)
- return -1;
-
- n->limp = new;
- n->chunks = chunks;
- n->bits = chunks << CHUNK_SHIFTS;
- n->dirty = 1;
-
- if (chunks > old)
- memset(n->limp + old, 0, size - CHUNK_BYTES * old);
-
- return 0;
-}
-
-/* Simple assignment functions. */
-
-int
-b2n_set(b2n_ptr d, b2n_ptr s)
-{
- if (d == s)
- return 0;
-
- b2n_sigbit(s);
- if (b2n_resize(d, (CHUNK_MASK + s->bits) >> CHUNK_SHIFTS))
- return -1;
- memcpy(d->limp, s->limp, CHUNK_BYTES * d->chunks);
- d->bits = s->bits;
- d->dirty = s->dirty;
- return 0;
-}
-
-int
-b2n_set_null(b2n_ptr n)
-{
- if (b2n_resize(n, 1))
- return -1;
- n->limp[0] = n->bits = n->dirty = 0;
- return 0;
-}
-
-int
-b2n_set_ui(b2n_ptr n, unsigned int val)
-{
-#if CHUNK_BITS < 32
- int i, chunks;
-
- chunks = (CHUNK_BYTES - 1 + sizeof(val)) / CHUNK_BYTES;
-
- if (b2n_resize(n, chunks))
- return -1;
-
- for (i = 0; i < chunks; i++) {
- n->limp[i] = val & CHUNK_BMASK;
- val >>= CHUNK_BITS;
- }
-#else
- if (b2n_resize(n, 1))
- return -1;
- n->limp[0] = val;
-#endif
- n->dirty = 1;
- return 0;
-}
-
-/* XXX This one only takes hex at the moment. */
-int
-b2n_set_str(b2n_ptr n, char *str)
-{
- int i, j, w, len, chunks;
- CHUNK_TYPE tmp;
-
- if (strncasecmp(str, "0x", 2))
- return -1;
-
- /* Make the hex string even lengthed */
- len = strlen(str) - 2;
- if (len & 1) {
- len++;
- str++;
- } else
- str += 2;
-
- len /= 2;
-
- chunks = (CHUNK_BYTES - 1 + len) / CHUNK_BYTES;
- if (b2n_resize(n, chunks))
- return -1;
- memset(n->limp, 0, CHUNK_BYTES * n->chunks);
-
- for (w = 0, i = 0; i < chunks; i++) {
- tmp = 0;
- for (j = (i == 0 ?
- ((len - 1) % CHUNK_BYTES) + 1 : CHUNK_BYTES);
- j > 0; j--) {
- tmp <<= 8;
- tmp |= (hex2int(str[w]) << 4) | hex2int(str[w + 1]);
- w += 2;
- }
- n->limp[chunks - 1 - i] = tmp;
- }
-
- n->dirty = 1;
- return 0;
-}
-
-/* Output function, mainly for debugging purposes. */
-void
-b2n_print(b2n_ptr n)
-{
- int i, j, w, flag = 0;
- int left;
- char buffer[2 * CHUNK_BYTES];
- CHUNK_TYPE tmp;
-
- left = ((((7 + b2n_sigbit(n)) >> 3) - 1) % CHUNK_BYTES) + 1;
- printf("0x");
- for (i = 0; i < n->chunks; i++) {
- tmp = n->limp[n->chunks - 1 - i];
- memset(buffer, '0', sizeof(buffer));
- for (w = 0, j = (i == 0 ? left : CHUNK_BYTES); j > 0; j--) {
- buffer[w++] = int2hex[(tmp >> 4) & 0xf];
- buffer[w++] = int2hex[tmp & 0xf];
- tmp >>= 8;
- }
-
- for (j = (i == 0 ? left - 1 : CHUNK_BYTES - 1); j >= 0; j--)
- if (flag || (i == n->chunks - 1 && j == 0) ||
- buffer[2 * j] != '0' || buffer[2 * j + 1] != '0') {
- putchar(buffer[2 * j]);
- putchar(buffer[2 * j + 1]);
- flag = 1;
- }
- }
- printf("\n");
-}
-
-int
-b2n_snprint(char *buf, size_t sz, b2n_ptr n)
-{
- int i, j, w, flag = 0;
- size_t k;
- int left;
- char buffer[2 * CHUNK_BYTES];
- CHUNK_TYPE tmp;
-
- left = ((((7 + b2n_sigbit(n)) >> 3) - 1) % CHUNK_BYTES) + 1;
-
- k = strlcpy(buf, "0x", sz);
- for (i = 0; i < n->chunks && k < sz - 1; i++) {
- tmp = n->limp[n->chunks - 1 - i];
- memset(buffer, '0', sizeof(buffer));
- for (w = 0, j = (i == 0 ? left : CHUNK_BYTES); j > 0; j--) {
- buffer[w++] = int2hex[(tmp >> 4) & 0xf];
- buffer[w++] = int2hex[tmp & 0xf];
- tmp >>= 8;
- }
-
- for (j = (i == 0 ? left - 1 : CHUNK_BYTES - 1); j >= 0
- && k < sz - 3; j--)
- if (flag || (i == n->chunks - 1 && j == 0) ||
- buffer[2 * j] != '0' || buffer[2 * j + 1] != '0') {
- buf[k++] = buffer[2 * j];
- buf[k++] = buffer[2 * j + 1];
- flag = 1;
- }
- }
-
- buf[k++] = 0;
- return k;
-}
-
-/* Arithmetic functions. */
-
-u_int32_t
-b2n_sigbit(b2n_ptr n)
-{
- int i, j;
-
- if (!n->dirty)
- return n->bits;
-
- for (i = n->chunks - 1; i > 0; i--)
- if (n->limp[i])
- break;
-
- if (!n->limp[i])
- return 0;
-
- for (j = CHUNK_MASK; j > 0; j--)
- if (n->limp[i] & b2n_mask[j])
- break;
-
- n->bits = (i << CHUNK_SHIFTS) + j + 1;
- n->dirty = 0;
- return n->bits;
-}
-
-/* Addition on GF(2)[x] is nice, its just an XOR. */
-int
-b2n_add(b2n_ptr d, b2n_ptr a, b2n_ptr b)
-{
- int i;
- b2n_ptr bmin, bmax;
-
- if (!b2n_cmp_null(a))
- return b2n_set(d, b);
-
- if (!b2n_cmp_null(b))
- return b2n_set(d, a);
-
- bmin = B2N_MIN(a, b);
- bmax = B2N_MAX(a, b);
-
- if (b2n_resize(d, bmax->chunks))
- return -1;
-
- for (i = 0; i < bmin->chunks; i++)
- d->limp[i] = bmax->limp[i] ^ bmin->limp[i];
-
- /*
- * If d is not bmax, we have to copy the rest of the bytes, and also
- * need to adjust to number of relevant bits.
- */
- if (d != bmax) {
- for (; i < bmax->chunks; i++)
- d->limp[i] = bmax->limp[i];
-
- d->bits = bmax->bits;
- }
- /*
- * Help to converse memory. When the result of the addition is zero
- * truncate the used amount of memory.
- */
- if (d != bmax && !b2n_cmp_null(d))
- return b2n_set_null(d);
- else
- d->dirty = 1;
- return 0;
-}
-
-/* Compare two polynomials. */
-int
-b2n_cmp(b2n_ptr n, b2n_ptr m)
-{
- int sn, sm;
- int i;
-
- sn = b2n_sigbit(n);
- sm = b2n_sigbit(m);
-
- if (sn > sm)
- return 1;
- if (sn < sm)
- return -1;
-
- for (i = n->chunks - 1; i >= 0; i--)
- if (n->limp[i] > m->limp[i])
- return 1;
- else if (n->limp[i] < m->limp[i])
- return -1;
-
- return 0;
-}
-
-int
-b2n_cmp_null(b2n_ptr a)
-{
- int i = 0;
-
- do {
- if (a->limp[i])
- return 1;
- }
- while (++i < a->chunks);
-
- return 0;
-}
-
-/* Left shift, needed for polynomial multiplication. */
-int
-b2n_lshift(b2n_ptr d, b2n_ptr n, unsigned int s)
-{
- int i, maj, min, chunks;
- u_int16_t bits = b2n_sigbit(n), add;
- CHUNK_TYPE *p, *op;
-
- if (!s)
- return b2n_set(d, n);
-
- maj = s >> CHUNK_SHIFTS;
- min = s & CHUNK_MASK;
-
- add = (!(bits & CHUNK_MASK) ||
- ((bits & CHUNK_MASK) + min) > CHUNK_MASK) ? 1 : 0;
- chunks = n->chunks;
- if (b2n_resize(d, chunks + maj + add))
- return -1;
- memmove(d->limp + maj, n->limp, CHUNK_BYTES * chunks);
-
- if (maj)
- memset(d->limp, 0, CHUNK_BYTES * maj);
- if (add)
- d->limp[d->chunks - 1] = 0;
-
- /* If !min there are no bit shifts, we are done */
- if (!min)
- return 0;
-
- op = p = &d->limp[d->chunks - 1];
- for (i = d->chunks - 2; i >= maj; i--) {
- op--;
- *p = (*p << min) | (*op >> (CHUNK_BITS - min));
- p--;
- }
- *p <<= min;
-
- d->dirty = 0;
- d->bits = bits + (maj << CHUNK_SHIFTS) + min;
- return 0;
-}
-
-/* Right shift, needed for polynomial division. */
-int
-b2n_rshift(b2n_ptr d, b2n_ptr n, unsigned int s)
-{
- int maj, min, size = n->chunks, newsize;
- b2n_ptr tmp;
-
- if (!s)
- return b2n_set(d, n);
-
- maj = s >> CHUNK_SHIFTS;
-
- newsize = size - maj;
-
- if (size < maj)
- return b2n_set_null(d);
-
- min = (CHUNK_BITS - (s & CHUNK_MASK)) & CHUNK_MASK;
- if (min) {
- if ((b2n_sigbit(n) & CHUNK_MASK) > (u_int32_t) min)
- newsize++;
-
- if (b2n_lshift(d, n, min))
- return -1;
- tmp = d;
- } else
- tmp = n;
-
- memmove(d->limp, tmp->limp + maj + (min ? 1 : 0),
- CHUNK_BYTES * newsize);
- if (b2n_resize(d, newsize))
- return -1;
-
- d->bits = tmp->bits - ((maj + (min ? 1 : 0)) << CHUNK_SHIFTS);
- return 0;
-}
-
-/* Normal polynomial multiplication. */
-int
-b2n_mul(b2n_ptr d, b2n_ptr n, b2n_ptr m)
-{
- int i, j;
- b2n_t tmp, tmp2;
-
- if (!b2n_cmp_null(m) || !b2n_cmp_null(n))
- return b2n_set_null(d);
-
- if (b2n_sigbit(m) == 1)
- return b2n_set(d, n);
-
- if (b2n_sigbit(n) == 1)
- return b2n_set(d, m);
-
- b2n_init(tmp);
- b2n_init(tmp2);
-
- if (b2n_set(tmp, B2N_MAX(n, m)))
- goto fail;
- if (b2n_set(tmp2, B2N_MIN(n, m)))
- goto fail;
-
- if (b2n_set_null(d))
- goto fail;
-
- for (i = 0; i < tmp2->chunks; i++)
- if (tmp2->limp[i])
- for (j = 0; j < CHUNK_BITS; j++) {
- if (tmp2->limp[i] & b2n_mask[j])
- if (b2n_add(d, d, tmp))
- goto fail;
-
- if (b2n_lshift(tmp, tmp, 1))
- goto fail;
- }
- else if (b2n_lshift(tmp, tmp, CHUNK_BITS))
- goto fail;
-
- b2n_clear(tmp);
- b2n_clear(tmp2);
- return 0;
-
-fail:
- b2n_clear(tmp);
- b2n_clear(tmp2);
- return -1;
-}
-
-/*
- * Squaring in this polynomial ring is more efficient than normal
- * multiplication.
- */
-int
-b2n_square(b2n_ptr d, b2n_ptr n)
-{
- int i, j, maj, min, bits, chunk;
- b2n_t t;
-
- maj = b2n_sigbit(n);
- min = maj & CHUNK_MASK;
- maj = (maj + CHUNK_MASK) >> CHUNK_SHIFTS;
-
- b2n_init(t);
- if (b2n_resize(t,
- 2 * maj + ((CHUNK_MASK + 2 * min) >> CHUNK_SHIFTS))) {
- b2n_clear(t);
- return -1;
- }
- chunk = 0;
- bits = 0;
-
- for (i = 0; i < maj; i++)
- if (n->limp[i])
- for (j = 0; j < CHUNK_BITS; j++) {
- if (n->limp[i] & b2n_mask[j])
- t->limp[chunk] ^= b2n_mask[bits];
-
- bits += 2;
- if (bits >= CHUNK_BITS) {
- chunk++;
- bits &= CHUNK_MASK;
- }
- }
- else
- chunk += 2;
-
- t->dirty = 1;
- B2N_SWAP(d, t);
- b2n_clear(t);
- return 0;
-}
-
-/*
- * Normal polynomial division.
- * These functions are far from optimal in speed.
- */
-int
-b2n_div_q(b2n_ptr d, b2n_ptr n, b2n_ptr m)
-{
- b2n_t r;
- int rv;
-
- b2n_init(r);
- rv = b2n_div(d, r, n, m);
- b2n_clear(r);
- return rv;
-}
-
-int
-b2n_div_r(b2n_ptr r, b2n_ptr n, b2n_ptr m)
-{
- b2n_t q;
- int rv;
-
- b2n_init(q);
- rv = b2n_div(q, r, n, m);
- b2n_clear(q);
- return rv;
-}
-
-int
-b2n_div(b2n_ptr q, b2n_ptr r, b2n_ptr n, b2n_ptr m)
-{
- int i, j, len, bits;
- u_int32_t sm, sn;
- b2n_t nenn, div, shift, mask;
-
- /* If Teiler > Zaehler, the result is 0 */
- if ((sm = b2n_sigbit(m)) > (sn = b2n_sigbit(n))) {
- if (b2n_set_null(q))
- return -1;
- return b2n_set(r, n);
- }
- if (sm == 0)
- /* Division by Zero */
- return -1;
- else if (sm == 1) {
- /* Division by the One-Element */
- if (b2n_set(q, n))
- return -1;
- return b2n_set_null(r);
- }
- b2n_init(nenn);
- b2n_init(div);
- b2n_init(shift);
- b2n_init(mask);
-
- if (b2n_set(nenn, n))
- goto fail;
- if (b2n_set(div, m))
- goto fail;
- if (b2n_set(shift, m))
- goto fail;
- if (b2n_set_ui(mask, 1))
- goto fail;
-
- if (b2n_resize(q, (sn - sm + CHUNK_MASK) >> CHUNK_SHIFTS))
- goto fail;
- memset(q->limp, 0, CHUNK_BYTES * q->chunks);
-
- if (b2n_lshift(shift, shift, sn - sm))
- goto fail;
- if (b2n_lshift(mask, mask, sn - sm))
- goto fail;
-
- /* Number of significant octets */
- len = (sn - 1) >> CHUNK_SHIFTS;
- /* The first iteration is done over the relevant bits */
- bits = (CHUNK_MASK + sn) & CHUNK_MASK;
- for (i = len; i >= 0 && b2n_sigbit(nenn) >= sm; i--)
- for (j = (i == len ? bits : CHUNK_MASK); j >= 0
- && b2n_sigbit(nenn) >= sm; j--) {
- if (nenn->limp[i] & b2n_mask[j]) {
- if (b2n_sub(nenn, nenn, shift))
- goto fail;
- if (b2n_add(q, q, mask))
- goto fail;
- }
- if (b2n_rshift(shift, shift, 1))
- goto fail;
- if (b2n_rshift(mask, mask, 1))
- goto fail;
- }
-
- B2N_SWAP(r, nenn);
-
- b2n_clear(nenn);
- b2n_clear(div);
- b2n_clear(shift);
- b2n_clear(mask);
- return 0;
-
-fail:
- b2n_clear(nenn);
- b2n_clear(div);
- b2n_clear(shift);
- b2n_clear(mask);
- return -1;
-}
-
-/* Functions for Operation on GF(2**n) ~= GF(2)[x]/p(x). */
-int
-b2n_mod(b2n_ptr m, b2n_ptr n, b2n_ptr p)
-{
- int bits, size;
-
- if (b2n_div_r(m, n, p))
- return -1;
-
- bits = b2n_sigbit(m);
- size = ((CHUNK_MASK + bits) >> CHUNK_SHIFTS);
- if (size == 0)
- size = 1;
- if (m->chunks > size)
- if (b2n_resize(m, size))
- return -1;
-
- m->bits = bits;
- m->dirty = 0;
- return 0;
-}
-
-int
-b2n_gcd(b2n_ptr e, b2n_ptr go, b2n_ptr ho)
-{
- b2n_t g, h;
-
- b2n_init(g);
- b2n_init(h);
- if (b2n_set(g, go))
- goto fail;
- if (b2n_set(h, ho))
- goto fail;
-
- while (b2n_cmp_null(h)) {
- if (b2n_mod(g, g, h))
- goto fail;
- B2N_SWAP(g, h);
- }
-
- B2N_SWAP(e, g);
-
- b2n_clear(g);
- b2n_clear(h);
- return 0;
-
-fail:
- b2n_clear(g);
- b2n_clear(h);
- return -1;
-}
-
-int
-b2n_mul_inv(b2n_ptr ga, b2n_ptr be, b2n_ptr p)
-{
- b2n_t a;
-
- b2n_init(a);
- if (b2n_set_ui(a, 1))
- goto fail;
-
- if (b2n_div_mod(ga, a, be, p))
- goto fail;
-
- b2n_clear(a);
- return 0;
-
-fail:
- b2n_clear(a);
- return -1;
-}
-
-int
-b2n_div_mod(b2n_ptr ga, b2n_ptr a, b2n_ptr be, b2n_ptr p)
-{
- b2n_t s0, s1, s2, q, r0, r1;
-
- /* There is no multiplicative inverse to Null. */
- if (!b2n_cmp_null(be))
- return b2n_set_null(ga);
-
- b2n_init(s0);
- b2n_init(s1);
- b2n_init(s2);
- b2n_init(r0);
- b2n_init(r1);
- b2n_init(q);
-
- if (b2n_set(r0, p))
- goto fail;
- if (b2n_set(r1, be))
- goto fail;
-
- if (b2n_set_null(s0))
- goto fail;
- if (b2n_set(s1, a))
- goto fail;
-
- while (b2n_cmp_null(r1)) {
- if (b2n_div(q, r0, r0, r1))
- goto fail;
- B2N_SWAP(r0, r1);
-
- if (b2n_mul(s2, q, s1))
- goto fail;
- if (b2n_mod(s2, s2, p))
- goto fail;
- if (b2n_sub(s2, s0, s2))
- goto fail;
-
- B2N_SWAP(s0, s1);
- B2N_SWAP(s1, s2);
- }
- B2N_SWAP(ga, s0);
-
- b2n_clear(s0);
- b2n_clear(s1);
- b2n_clear(s2);
- b2n_clear(r0);
- b2n_clear(r1);
- b2n_clear(q);
- return 0;
-
-fail:
- b2n_clear(s0);
- b2n_clear(s1);
- b2n_clear(s2);
- b2n_clear(r0);
- b2n_clear(r1);
- b2n_clear(q);
- return -1;
-}
-
-/*
- * The trace tells us if there do exist any square roots
- * for 'a' in GF(2)[x]/p(x). The number of square roots is
- * 2 - 2*Trace.
- * If z is a square root, z + 1 is the other.
- */
-int
-b2n_trace(b2n_ptr ho, b2n_ptr a, b2n_ptr p)
-{
- int i, m = b2n_sigbit(p) - 1;
- b2n_t h;
-
- b2n_init(h);
- if (b2n_set(h, a))
- goto fail;
-
- for (i = 0; i < m - 1; i++) {
- if (b2n_square(h, h))
- goto fail;
- if (b2n_mod(h, h, p))
- goto fail;
-
- if (b2n_add(h, h, a))
- goto fail;
- }
- B2N_SWAP(ho, h);
-
- b2n_clear(h);
- return 0;
-
-fail:
- b2n_clear(h);
- return -1;
-}
-
-/*
- * The halftrace yields the square root if the degree of the
- * irreduceable polynomial is odd.
- */
-int
-b2n_halftrace(b2n_ptr ho, b2n_ptr a, b2n_ptr p)
-{
- int i, m = b2n_sigbit(p) - 1;
- b2n_t h;
-
- b2n_init(h);
- if (b2n_set(h, a))
- goto fail;
-
- for (i = 0; i < (m - 1) / 2; i++) {
- if (b2n_square(h, h))
- goto fail;
- if (b2n_mod(h, h, p))
- goto fail;
- if (b2n_square(h, h))
- goto fail;
- if (b2n_mod(h, h, p))
- goto fail;
-
- if (b2n_add(h, h, a))
- goto fail;
- }
-
- B2N_SWAP(ho, h);
-
- b2n_clear(h);
- return 0;
-
-fail:
- b2n_clear(h);
- return -1;
-}
-
-/*
- * Solving the equation: y**2 + y = b in GF(2**m) where ip is the
- * irreduceable polynomial. If m is odd, use the half trace.
- */
-int
-b2n_sqrt(b2n_ptr zo, b2n_ptr b, b2n_ptr ip)
-{
- int i, m = b2n_sigbit(ip) - 1;
- b2n_t w, p, temp, z;
-
- if (!b2n_cmp_null(b))
- return b2n_set_null(z);
-
- if (m & 1)
- return b2n_halftrace(zo, b, ip);
-
- b2n_init(z);
- b2n_init(w);
- b2n_init(p);
- b2n_init(temp);
-
- do {
- if (b2n_random(p, m))
- goto fail;
- if (b2n_set_null(z))
- goto fail;
- if (b2n_set(w, p))
- goto fail;
-
- for (i = 1; i < m; i++) {
- if (b2n_square(z, z)) /* z**2 */
- goto fail;
- if (b2n_mod(z, z, ip))
- goto fail;
-
- if (b2n_square(w, w)) /* w**2 */
- goto fail;
- if (b2n_mod(w, w, ip))
- goto fail;
-
- if (b2n_mul(temp, w, b)) /* w**2 * b */
- goto fail;
- if (b2n_mod(temp, temp, ip))
- goto fail;
- if (b2n_add(z, z, temp)) /* z**2 + w**2 + b */
- goto fail;
-
- if (b2n_add(w, w, p)) /* w**2 + p */
- goto fail;
- }
- }
- while (!b2n_cmp_null(w));
-
- B2N_SWAP(zo, z);
-
- b2n_clear(w);
- b2n_clear(p);
- b2n_clear(temp);
- b2n_clear(z);
- return 0;
-
-fail:
- b2n_clear(w);
- b2n_clear(p);
- b2n_clear(temp);
- b2n_clear(z);
- return -1;
-}
-
-/* Exponentiation modulo a polynomial. */
-int
-b2n_exp_mod(b2n_ptr d, b2n_ptr b0, u_int32_t e, b2n_ptr p)
-{
- b2n_t u, b;
-
- b2n_init(u);
- b2n_init(b);
- if (b2n_set_ui(u, 1))
- goto fail;
- if (b2n_mod(b, b0, p))
- goto fail;
-
- while (e) {
- if (e & 1) {
- if (b2n_mul(u, u, b))
- goto fail;
- if (b2n_mod(u, u, p))
- goto fail;
- }
- if (b2n_square(b, b))
- goto fail;
- if (b2n_mod(b, b, p))
- goto fail;
- e >>= 1;
- }
-
- B2N_SWAP(d, u);
-
- b2n_clear(u);
- b2n_clear(b);
- return 0;
-
-fail:
- b2n_clear(u);
- b2n_clear(b);
- return -1;
-}
-
-/*
- * Low-level function to speed up scalar multiplication with
- * elliptic curves.
- * Multiplies a normal number by 3.
- */
-
-/* Normal addition behaves as Z_{2**n} and not F_{2**n}. */
-int
-b2n_nadd(b2n_ptr d0, b2n_ptr a0, b2n_ptr b0)
-{
- int i, carry;
- b2n_ptr a, b;
- b2n_t d;
-
- if (!b2n_cmp_null(a0))
- return b2n_set(d0, b0);
-
- if (!b2n_cmp_null(b0))
- return b2n_set(d0, a0);
-
- b2n_init(d);
- a = B2N_MAX(a0, b0);
- b = B2N_MIN(a0, b0);
-
- if (b2n_resize(d, a->chunks + 1)) {
- b2n_clear(d);
- return -1;
- }
- for (carry = i = 0; i < b->chunks; i++) {
- d->limp[i] = a->limp[i] + b->limp[i] + carry;
- carry = (d->limp[i] < a->limp[i] ? 1 : 0);
- }
-
- for (; i < a->chunks && carry; i++) {
- d->limp[i] = a->limp[i] + carry;
- carry = (d->limp[i] < a->limp[i] ? 1 : 0);
- }
-
- if (i < a->chunks)
- memcpy(d->limp + i, a->limp + i,
- CHUNK_BYTES * (a->chunks - i));
-
- d->dirty = 1;
- B2N_SWAP(d0, d);
-
- b2n_clear(d);
- return 0;
-}
-
-/* Very special sub, a > b. */
-int
-b2n_nsub(b2n_ptr d0, b2n_ptr a, b2n_ptr b)
-{
- int i, carry;
- b2n_t d;
-
- if (b2n_cmp(a, b) <= 0)
- return b2n_set_null(d0);
-
- b2n_init(d);
- if (b2n_resize(d, a->chunks)) {
- b2n_clear(d);
- return -1;
- }
- for (carry = i = 0; i < b->chunks; i++) {
- d->limp[i] = a->limp[i] - b->limp[i] - carry;
- carry = (d->limp[i] > a->limp[i] ? 1 : 0);
- }
-
- for (; i < a->chunks && carry; i++) {
- d->limp[i] = a->limp[i] - carry;
- carry = (d->limp[i] > a->limp[i] ? 1 : 0);
- }
-
- if (i < a->chunks)
- memcpy(d->limp + i, a->limp + i,
- CHUNK_BYTES * (a->chunks - i));
-
- d->dirty = 1;
-
- B2N_SWAP(d0, d);
-
- b2n_clear(d);
- return 0;
-}
-
-int
-b2n_3mul(b2n_ptr d0, b2n_ptr e)
-{
- b2n_t d;
-
- b2n_init(d);
- if (b2n_lshift(d, e, 1))
- goto fail;
-
- if (b2n_nadd(d0, d, e))
- goto fail;
-
- b2n_clear(d);
- return 0;
-
-fail:
- b2n_clear(d);
- return -1;
-}