diff --git a/src/bn.c b/src/bn.c new file mode 100644 index 0000000..e0e7d95 --- /dev/null +++ b/src/bn.c @@ -0,0 +1,246 @@ +/* + * bn.c -- 256-bit and 512-bit bignum calculation + * + * Copyright (C) 2011 Free Software Initiative of Japan + * Author: NIIBE Yutaka + * + * This file is a part of Gnuk, a GnuPG USB Token implementation. + * + * Gnuk 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. + * + * Gnuk 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 . + * + */ + +#include +#include "bn.h" + +int +bn256_add (bn256 *X, const bn256 *A, const bn256 *B) +{ + int i; + uint32_t carry = 0; + uint32_t *px; + const uint32_t *pa, *pb; + + px = X->words; + pa = A->words; + pb = B->words; + + for (i = 0; i < BN256_WORDS; i++) + { + *px = *pa + carry; + carry = (*px < carry); + *px += *pb; + carry += (*px < *pb); + px++; + pa++; + pb++; + } + + return carry; +} + +int +bn256_sub (bn256 *X, const bn256 *A, const bn256 *B) +{ + int i; + uint32_t borrow = 0; + uint32_t *px; + const uint32_t *pa, *pb; + + px = X->words; + pa = A->words; + pb = B->words; + + for (i = 0; i < BN256_WORDS; i++) + { + uint32_t borrow0 = (*pa < borrow); + + *px = *pa - borrow; + borrow = (*px < *pb) + borrow0; + *px -= *pb; + px++; + pa++; + pb++; + } + + return borrow; +} + +void +bn256_mul (bn512 *X, const bn256 *A, const bn256 *B) +{ + int i, j, k; + int i_beg, i_end; + uint32_t r0, r1, r2; + + r0 = r1 = r2 = 0; + for (k = 0; k <= (BN256_WORDS - 1)*2; k++) + { + if (k < BN256_WORDS) + { + i_beg = 0; + i_end = k; + } + else + { + i_beg = k - BN256_WORDS + 1; + i_end = BN256_WORDS - 1; + } + + for (i = i_beg; i <= i_end; i++) + { + uint64_t uv; + uint32_t u, v; + uint32_t carry; + + j = k - i; + + uv = ((uint64_t )A->words[i])*((uint64_t )B->words[j]); + v = uv; + u = (uv >> 32); + r0 += v; + carry = (r0 < v); + r1 += carry; + carry = (r1 < carry); + r1 += u; + carry += (r1 < u); + r2 += carry; + } + + X->words[k] = r0; + r0 = r1; + r1 = r2; + r2 = 0; + } + + X->words[k] = r0; +} + +void +bn256_sqr (bn512 *X, const bn256 *A) +{ + int i, j, k; + int i_beg, i_end; + uint32_t r0, r1, r2; + + r0 = r1 = r2 = 0; + for (k = 0; k <= (BN256_WORDS - 1)*2; k++) + { + if (k < BN256_WORDS) + { + i_beg = 0; + i_end = k/2; + } + else + { + i_beg = k - BN256_WORDS + 1; + i_end = k/2; + } + + for (i = i_beg; i <= i_end; i++) + { + uint64_t uv; + uint32_t u, v; + uint32_t carry; + + j = k - i; + + uv = ((uint64_t )A->words[i])*((uint64_t )A->words[j]); + if (i < j) + { + if ((uv >> 63) != 0) + r2++; + uv <<= 1; + } + v = uv; + u = (uv >> 32); + r0 += v; + carry = (r0 < v); + r1 += carry; + carry = (r1 < carry); + r1 += u; + carry += (r1 < u); + r2 += carry; + } + + X->words[k] = r0; + r0 = r1; + r1 = r2; + r2 = 0; + } + + X->words[k] = r0; +} + +int +bn256_shift (bn256 *X, const bn256 *A, int shift) +{ + int i; + uint32_t carry = 0, next_carry; + + if (shift > 0) + { + for (i = 0; i < BN256_WORDS; i++) + { + next_carry = A->words[i] >> (32 - shift); + X->words[i] = (A->words[i] << shift) | carry; + carry = next_carry; + } + } + else + { + shift = -shift; + + for (i = BN256_WORDS - 1; i >= 0; i--) + { + next_carry = A->words[i] & ((1 << shift) - 1); + X->words[i] = (A->words[i] >> shift) | (carry << (32 - shift)); + carry = next_carry; + } + } + + return carry; +} + +int +bn256_is_zero (const bn256 *X) +{ + int i; + + for (i = 0; i < BN256_WORDS; i++) + if (X->words[i] != 0) + return 0; + + return 1; +} + +int +bn256_is_even (const bn256 *X) +{ + return !(X->words[0] & 1); +} + +int +bn256_is_ge (const bn256 *A, const bn256 *B) +{ + int i; + + for (i = BN256_WORDS - 1; i >= 0; i--) + if (A->words[i] > B->words[i]) + return 1; + else if (A->words[i] < B->words[i]) + return 0; + + return 1; +} diff --git a/src/bn.h b/src/bn.h new file mode 100644 index 0000000..ac0adad --- /dev/null +++ b/src/bn.h @@ -0,0 +1,18 @@ +#define BN256_WORDS 8 +typedef struct bn256 { + uint32_t words[ BN256_WORDS ]; /* Little endian */ +} bn256; + +#define BN512_WORDS 16 +typedef struct bn512 { + uint32_t words[ BN512_WORDS ]; /* Little endian */ +} bn512; + +int bn256_add (bn256 *X, const bn256 *A, const bn256 *B); +int bn256_sub (bn256 *X, const bn256 *A, const bn256 *B); +void bn256_mul (bn512 *X, const bn256 *A, const bn256 *B); +void bn256_sqr (bn512 *X, const bn256 *A); +int bn256_shift (bn256 *X, const bn256 *A, int shift); +int bn256_is_zero (const bn256 *X); +int bn256_is_even (const bn256 *X); +int bn256_is_ge (const bn256 *A, const bn256 *B);