1564 lines
30 KiB
C
1564 lines
30 KiB
C
/* $Id: bigd.c $ */
|
|
|
|
/***** BEGIN LICENSE BLOCK *****
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* Copyright (c) 2001-16 David Ireland, D.I. Management Services Pty Limited
|
|
* <http://www.di-mgt.com.au/bigdigits.html>. All rights reserved.
|
|
*
|
|
***** END LICENSE BLOCK *****/
|
|
/*
|
|
* Last updated:
|
|
* $Date: 2016-03-31 09:51:00 $
|
|
* $Revision: 2.6.1 $
|
|
* $Author: dai $
|
|
*/
|
|
|
|
/* BIGD "bd" wrapper functions around BigDigits "mp" functions */
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include <assert.h>
|
|
#include "bigd.h"
|
|
#include "bigdigits.h"
|
|
|
|
/* Required for opaque pointers */
|
|
#define T BIGD
|
|
struct T
|
|
{
|
|
DIGIT_T *digits; /* Ptr to array of digits, least sig. first */
|
|
size_t ndigits; /* No of non-zero significant digits */
|
|
size_t maxdigits; /* Max size allocated */
|
|
/*int is_signed;*/ /* (for future use) */
|
|
};
|
|
|
|
#define OCTETS_PER_DIGIT (sizeof(bdigit_t))
|
|
|
|
/*
|
|
All these functions MUST make sure that there are always
|
|
enough digits before doing anything, and SHOULD reset <ndigits>
|
|
afterwards to reflect the final significant size.
|
|
-- <maxdigits> is the size allocated (at least one).
|
|
-- <ndigits> may be zero.
|
|
-- <ndigits> may be too long if MS digits compute to zero so
|
|
consider it an upper bound on significant digits, not gospel.
|
|
|
|
It is an error to pass a NULL BIGD parameter except to bdFree.
|
|
*/
|
|
|
|
#ifdef _DEBUG
|
|
static int debug = 0; /* <= change this to > 0 for console debugging */
|
|
#else
|
|
static int debug = 0; /* <= ALWAYS ZERO */
|
|
#endif
|
|
|
|
/* Useful definitions */
|
|
#ifndef FALSE
|
|
#define FALSE 0
|
|
#endif
|
|
#ifndef TRUE
|
|
#define TRUE 1
|
|
#endif
|
|
#ifndef max
|
|
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
|
#endif
|
|
#ifndef min
|
|
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
|
#endif
|
|
|
|
|
|
T bdNew(void)
|
|
{
|
|
struct T *p;
|
|
p = calloc(1, (long)sizeof(*p));
|
|
if (!p)
|
|
{
|
|
mpFail("bdNew: Failed to calloc memory.");
|
|
}
|
|
copyright_notice();
|
|
/* set up with single zero digit */
|
|
p->digits = mpAlloc(1);
|
|
p->digits[0] = 0;
|
|
p->ndigits = 0;
|
|
p->maxdigits = 1;
|
|
//p->sign = 0;
|
|
return p;
|
|
}
|
|
|
|
void bdFree(T *p)
|
|
/* Zeroise and free memory. Set ptr to NULL. */
|
|
{
|
|
T bd = *p;
|
|
if (*p)
|
|
{
|
|
/* Zeroise them all, just in case */
|
|
if (bd->digits)
|
|
{
|
|
mpSetZero(bd->digits, bd->maxdigits);
|
|
free(bd->digits);
|
|
}
|
|
bd->maxdigits = 0;
|
|
bd->ndigits = 0;
|
|
free(*p);
|
|
}
|
|
*p = NULL;
|
|
}
|
|
|
|
static int bd_resize(T b, size_t newsize)
|
|
{
|
|
/*
|
|
Internal fn to re-size a BIGD structure before a calc.
|
|
Use carefully!
|
|
1. If growing, it allocs more digits and increases maxdigits
|
|
2. If shrinking, it decreases ndigits and zeroises the excess.
|
|
3. It does not increase b->ndigits; that's up to you later.
|
|
4. It does not release excess digits; use bdFree.
|
|
|
|
In other words, it's like middle-aged spread:
|
|
you go from a 32" waist to a 38 but can never go backwards.
|
|
|
|
Be careful doing the following:-
|
|
n = new_size_we_expect;
|
|
bd_resize(b, n);
|
|
mpFunctionOfSorts(b->digits, n);
|
|
b->ndigits = mpSizeof(b->digits, b->ndigits); // NO!
|
|
|
|
b->ndigits may be set too short
|
|
|
|
Better:
|
|
n = new_size_we_expect;
|
|
bd_resize(b, n);
|
|
mpFunctionOfSorts(b->digits, n);
|
|
b->ndigits = mpSizeof(b->digits, n); // Yes.
|
|
|
|
*/
|
|
|
|
size_t i;
|
|
|
|
/* Check just in case NULL */
|
|
assert(b);
|
|
assert(b->digits);
|
|
|
|
/* If we are shrinking, clear high digits */
|
|
if (newsize < b->ndigits)
|
|
{
|
|
for (i = newsize; i < b->ndigits; i++)
|
|
b->digits[i] = 0;
|
|
b->ndigits = newsize;
|
|
return 0;
|
|
}
|
|
|
|
/* We need more room */
|
|
if (b->maxdigits < newsize)
|
|
{
|
|
DIGIT_T *newp, *oldp;
|
|
size_t oldsize = b->maxdigits;
|
|
/* Increase size of digit array */
|
|
//b->digits = (DIGIT_T *)realloc(b->digits, newsize * sizeof(DIGIT_T));
|
|
/* -- [v2.2] changed [2008-03-30] to avoid realloc */
|
|
newp = (DIGIT_T *)malloc(newsize * sizeof(DIGIT_T));
|
|
oldp = b->digits;
|
|
|
|
/* Check for failure */
|
|
if (!newp)
|
|
{
|
|
mpSetZero(oldp, oldsize);
|
|
free(oldp);
|
|
mpFail("bd_resize: Failed to realloc memory.");
|
|
}
|
|
|
|
memcpy(newp, oldp, oldsize * sizeof(DIGIT_T));
|
|
mpSetZero(oldp, oldsize);
|
|
free(oldp);
|
|
b->digits = newp;
|
|
|
|
b->maxdigits = newsize; /* Remember new allocated size */
|
|
}
|
|
|
|
/* Make sure new digits are zero */
|
|
for (i = b->ndigits; i < newsize; i++)
|
|
b->digits[i] = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* New in [v2.6]: A more compact way to allocate and free BIGD variables */
|
|
|
|
void bdNewVars(BIGD *pb1, ...)
|
|
{
|
|
BIGD *pbd;
|
|
va_list ap;
|
|
|
|
va_start(ap, pb1);
|
|
while ((pbd = va_arg(ap, BIGD*))) {
|
|
*pbd = bdNew();
|
|
}
|
|
va_end(ap);
|
|
/* Deal with the first argument */
|
|
*pb1 = bdNew();
|
|
}
|
|
|
|
void bdFreeVars(BIGD *pb1, ...)
|
|
{
|
|
BIGD *pbd;
|
|
va_list ap;
|
|
|
|
/* NB the stdarg macros do not permit programmers to code a function with no fixed arguments
|
|
* So this skips the first argument */
|
|
va_start(ap, pb1);
|
|
while ((pbd = va_arg(ap, BIGD*))) {
|
|
bdFree(pbd);
|
|
}
|
|
va_end(ap);
|
|
/* Deal with the first argument */
|
|
bdFree(pb1);
|
|
}
|
|
|
|
size_t bdConvFromOctets(T b, const unsigned char *c, size_t nbytes)
|
|
/* Converts nbytes octets into big digit b, resizing if necessary */
|
|
{
|
|
size_t ndigits, n;
|
|
|
|
assert(b);
|
|
ndigits = (nbytes + OCTETS_PER_DIGIT - 1) / OCTETS_PER_DIGIT;
|
|
|
|
bd_resize(b, ndigits);
|
|
|
|
n = mpConvFromOctets(b->digits, ndigits, c, nbytes);
|
|
b->ndigits = mpSizeof(b->digits, n);
|
|
|
|
return n;
|
|
}
|
|
|
|
size_t bdConvToOctets(T b, unsigned char *c, size_t nbytes)
|
|
/* Convert big digit b into string of octets, in big-endian order,
|
|
padding to nbytes or truncating if necessary.
|
|
Returns # significant bytes.
|
|
If c is NULL or nbytes == 0 then just return required size.
|
|
*/
|
|
{
|
|
size_t noctets, nbits, n;
|
|
|
|
assert(b);
|
|
|
|
nbits = mpBitLength(b->digits, b->ndigits);
|
|
noctets = (nbits + 7) / 8;
|
|
/* [2008-05-23] always return at least 1 */
|
|
if (0 == noctets) noctets = 1;
|
|
|
|
if (!c || 0 == nbytes)
|
|
{
|
|
return noctets;
|
|
}
|
|
|
|
n = mpConvToOctets(b->digits, b->ndigits, c, nbytes);
|
|
|
|
return n;
|
|
}
|
|
|
|
size_t bdConvFromHex(T b, const char *s)
|
|
/* Converts a hex string into big digit b */
|
|
{
|
|
size_t ndigits, n;
|
|
|
|
assert(b);
|
|
|
|
/* Revision [2006-02-21] */
|
|
/* EDIT: ndigits = (strlen(s) / 2 + OCTETS_PER_DIGIT - 1) / OCTETS_PER_DIGIT; */
|
|
ndigits = ((strlen(s) + 1) / 2 + OCTETS_PER_DIGIT - 1) / OCTETS_PER_DIGIT;
|
|
bd_resize(b, ndigits);
|
|
|
|
n = mpConvFromHex(b->digits, ndigits, s);
|
|
b->ndigits = mpSizeof(b->digits, n);
|
|
|
|
return n;
|
|
}
|
|
|
|
size_t bdConvToHex(T b, char *s, size_t smax)
|
|
{
|
|
assert(b);
|
|
return mpConvToHex(b->digits, b->ndigits, s, smax);
|
|
}
|
|
|
|
size_t bdConvFromDecimal(BIGD b, const char *s)
|
|
{
|
|
size_t ndigits, n;
|
|
|
|
assert(b);
|
|
/* approx size but never too small */
|
|
ndigits = (strlen(s) / 2 + OCTETS_PER_DIGIT) / OCTETS_PER_DIGIT;
|
|
bd_resize(b, ndigits);
|
|
|
|
n = mpConvFromDecimal(b->digits, ndigits, s);
|
|
b->ndigits = n;
|
|
|
|
return n;
|
|
}
|
|
|
|
size_t bdConvToDecimal(BIGD b, char *s, size_t smax)
|
|
{
|
|
assert(b);
|
|
return mpConvToDecimal(b->digits, b->ndigits, s, smax);
|
|
}
|
|
|
|
int bdSetShort(T b, bdigit_t value)
|
|
/* Converts value into a (single-digit) big digit b */
|
|
{
|
|
assert(b);
|
|
bd_resize(b, 1);
|
|
b->digits[0] = (DIGIT_T)value;
|
|
b->ndigits = (value ? 1 : 0);
|
|
return 0;
|
|
}
|
|
|
|
/** Returns the least significant digit in b */
|
|
bdigit_t bdToShort(T b)
|
|
{
|
|
assert(b);
|
|
return mpToShort(b->digits, b->ndigits);
|
|
}
|
|
|
|
|
|
size_t bdBitLength(T b)
|
|
/* Returns base-1 index to most significant bit in b */
|
|
{
|
|
assert(b);
|
|
return mpBitLength(b->digits, b->ndigits);
|
|
}
|
|
|
|
size_t bdSizeof(T b)
|
|
/* Returns number of significant non-zero bytes in b */
|
|
{
|
|
assert(b);
|
|
return mpSizeof(b->digits, b->ndigits);
|
|
}
|
|
|
|
|
|
/* Print function for bigdigit_t structures [OBSOLETE] */
|
|
void bdPrint(T p, size_t flags)
|
|
{
|
|
size_t n;
|
|
|
|
assert(p);
|
|
n = p->ndigits;
|
|
if (n == 0) {
|
|
bdSetZero(p); // Added [v2.6]
|
|
n = 1;
|
|
}
|
|
|
|
if (flags & BD_PRINT_TRIM) /* Trim leading zeroes */
|
|
{
|
|
if (flags & BD_PRINT_NL) /* add newlines */
|
|
mpPrintTrimNL(p->digits, n);
|
|
else
|
|
mpPrintTrim(p->digits, n);
|
|
}
|
|
else
|
|
{
|
|
if (flags & BD_PRINT_NL) /* add newlines */
|
|
mpPrintNL(p->digits, n);
|
|
else
|
|
mpPrint(p->digits, n);
|
|
}
|
|
}
|
|
|
|
void bdPrintHex(const char *prefix, T p, const char *suffix)
|
|
{
|
|
size_t n;
|
|
|
|
assert(p);
|
|
n = p->ndigits;
|
|
if (n == 0) {
|
|
bdSetZero(p); // Added [v2.6]
|
|
n = 1;
|
|
}
|
|
mpPrintHex(prefix, p->digits, n, suffix);
|
|
}
|
|
|
|
void bdPrintDecimal(const char *prefix, T p, const char *suffix)
|
|
{
|
|
size_t n;
|
|
|
|
assert(p);
|
|
n = p->ndigits;
|
|
if (n == 0) {
|
|
bdSetZero(p); // Added [v2.6]
|
|
n = 1;
|
|
}
|
|
mpPrintDecimal(prefix, p->digits, n, suffix);
|
|
}
|
|
|
|
void bdPrintBits(const char *prefix, T p, const char *suffix)
|
|
{
|
|
size_t n;
|
|
|
|
assert(p);
|
|
n = p->ndigits;
|
|
if (n == 0) {
|
|
bdSetZero(p); // Added [v2.6]
|
|
n = 1;
|
|
}
|
|
mpPrintBits(prefix, p->digits, n, suffix);
|
|
}
|
|
|
|
/** Returns true if a == 0, else false */
|
|
int bdIsZero(T a)
|
|
{
|
|
assert(a);
|
|
return mpIsZero(a->digits, a->ndigits);
|
|
}
|
|
|
|
int bdIsZero_ct(T a)
|
|
{
|
|
assert(a);
|
|
/* [v2.6] Use constant-time fn */
|
|
return mpIsZero_ct(a->digits, a->ndigits);
|
|
}
|
|
|
|
/** Returns true if a == b, else false */
|
|
static int isequal_local(T a, T b, int ct)
|
|
{
|
|
size_t n, na, nb;
|
|
|
|
assert(a && b);
|
|
if (a->ndigits != b->ndigits) {
|
|
na = mpSizeof(a->digits, a->ndigits);
|
|
nb = mpSizeof(b->digits, b->ndigits);
|
|
|
|
if (na != nb)
|
|
return FALSE;
|
|
if (na == 0 && nb == 0)
|
|
return TRUE;
|
|
n = na;
|
|
} else {
|
|
n = a->ndigits;
|
|
}
|
|
|
|
/* [v2.5] Use constant-time fn if equal length */
|
|
/* [v2.6] ... only if _ct function is called */
|
|
if (ct)
|
|
return mpEqual_ct(a->digits, b->digits, n);
|
|
else
|
|
return mpEqual(a->digits, b->digits, n);
|
|
}
|
|
|
|
/** Returns true if a == b, else false */
|
|
int bdIsEqual(T a, T b)
|
|
{
|
|
return isequal_local(a, b, 0);
|
|
}
|
|
int bdIsEqual_ct(T a, T b)
|
|
{
|
|
return isequal_local(a, b, 1);
|
|
}
|
|
|
|
/** Returns sign of (a-b) */
|
|
static int compare_local(T a, T b, int ct)
|
|
{
|
|
size_t n, na, nb;
|
|
|
|
assert(a && b);
|
|
if (a->ndigits != b->ndigits) {
|
|
na = mpSizeof(a->digits, a->ndigits);
|
|
nb = mpSizeof(b->digits, b->ndigits);
|
|
if (na > nb) return 1;
|
|
if (na < nb) return -1;
|
|
n = na;
|
|
} else {
|
|
n = a->ndigits;
|
|
}
|
|
|
|
/* [v2.5] Use constant-time fn if equal length */
|
|
/* [v2.6] ... only if _ct function is called */
|
|
if (ct)
|
|
return mpCompare_ct(a->digits, b->digits, n);
|
|
else
|
|
return mpCompare(a->digits, b->digits, n);
|
|
|
|
}
|
|
|
|
/** Returns sign of (a-b) */
|
|
int bdCompare(T a, T b)
|
|
{
|
|
return compare_local(a, b, 0);
|
|
}
|
|
int bdCompare_ct(T a, T b)
|
|
{
|
|
return compare_local(a, b, 0);
|
|
}
|
|
|
|
/** Returns sign of (a-d) */
|
|
int bdShortCmp(T a, bdigit_t d)
|
|
{
|
|
assert(a);
|
|
return mpShortCmp(a->digits, d, a->ndigits);
|
|
}
|
|
|
|
/** Returns true if a == d, else false, where d is a single digit */
|
|
int bdShortIsEqual(BIGD a, bdigit_t d)
|
|
{
|
|
assert(a);
|
|
return mpShortIsEqual(a->digits, d, a->ndigits);
|
|
}
|
|
|
|
int bdIsEven(T a)
|
|
{
|
|
assert(a);
|
|
return ISEVEN(a->digits[0]);
|
|
}
|
|
|
|
int bdIsOdd(T a)
|
|
{
|
|
assert(a);
|
|
return ISODD(a->digits[0]);
|
|
}
|
|
|
|
|
|
int bdSetEqual(T a, T b)
|
|
/* Sets a = b */
|
|
{
|
|
assert(a && b);
|
|
bd_resize(a, b->ndigits);
|
|
mpSetEqual(a->digits, b->digits, b->ndigits);
|
|
a->ndigits = b->ndigits;
|
|
return 0;
|
|
}
|
|
|
|
int bdSetZero(T a)
|
|
/* Sets a = 0 */
|
|
{
|
|
assert(a);
|
|
/* [v2.6] changed a->ndigits to a->maxdigits to make sure we clear any residual */
|
|
mpSetZero(a->digits, a->maxdigits);
|
|
a->ndigits = 0;
|
|
return 0;
|
|
}
|
|
|
|
int bdShortAdd(T w, T u, bdigit_t d)
|
|
/* Compute w = u + d,
|
|
returns 1 if we had a carry */
|
|
{
|
|
DIGIT_T carry;
|
|
size_t dig_size = max(u->ndigits, 1);
|
|
|
|
assert(w && u);
|
|
bd_resize(w, dig_size + 1);
|
|
|
|
carry = mpShortAdd(w->digits, u->digits, d, dig_size);
|
|
|
|
/* Cope with overflow */
|
|
if (carry)
|
|
{
|
|
w->digits[dig_size] = carry;
|
|
w->ndigits = dig_size + 1;
|
|
}
|
|
else
|
|
w->ndigits = dig_size;
|
|
|
|
return carry;
|
|
}
|
|
|
|
int bdAdd(T w, T u, T v)
|
|
/* Compute w = u + v, w#v */
|
|
{
|
|
size_t dig_size;
|
|
DIGIT_T carry;
|
|
|
|
assert(w && u && v);
|
|
/* Check for cheaper option */
|
|
if (v->ndigits == 1)
|
|
return bdShortAdd(w, u, v->digits[0]);
|
|
|
|
/* Make sure u and v are the same size */
|
|
dig_size = max(u->ndigits, v->ndigits);
|
|
bd_resize(v, dig_size);
|
|
bd_resize(u, dig_size);
|
|
/* Now make sure w is big enough for sum (incl carry) */
|
|
bd_resize(w, dig_size + 1);
|
|
|
|
/* Finally, do the business */
|
|
carry = mpAdd(w->digits, u->digits, v->digits, dig_size);
|
|
|
|
/* Make sure we've set the right size for w */
|
|
if (carry)
|
|
{
|
|
w->digits[dig_size] = carry;
|
|
w->ndigits = dig_size + 1;
|
|
}
|
|
else
|
|
w->ndigits = mpSizeof(w->digits, dig_size);
|
|
|
|
return carry;
|
|
}
|
|
|
|
int bdAdd_s(T w, T u, T v)
|
|
/* Compute w = u + v (safe) */
|
|
{
|
|
DIGIT_T carry;
|
|
T ww;
|
|
|
|
assert(w && u && v);
|
|
/* Use temp */
|
|
ww = bdNew();
|
|
bdSetEqual(ww, w);
|
|
|
|
carry = bdAdd(ww, u, v);
|
|
|
|
bdSetEqual(w, ww);
|
|
bdFree(&ww);
|
|
|
|
return carry;
|
|
}
|
|
|
|
int bdShortSub(T w, T u, bdigit_t d)
|
|
/* Compute w = u - d, return borrow */
|
|
{
|
|
DIGIT_T borrow;
|
|
size_t dig_size = max(u->ndigits, 1);
|
|
|
|
assert(w && u);
|
|
bd_resize(w, dig_size);
|
|
|
|
borrow = mpShortSub(w->digits, u->digits, d, dig_size);
|
|
|
|
w->ndigits = dig_size;
|
|
|
|
return borrow;
|
|
}
|
|
|
|
int bdSubtract(T w, T u, T v)
|
|
/* Compute w = u - v, return borrow, w#v */
|
|
{
|
|
size_t dig_size;
|
|
DIGIT_T borrow;
|
|
|
|
assert(w && u && v);
|
|
/* Check for cheaper option */
|
|
if (v->ndigits == 1)
|
|
return bdShortSub(w, u, v->digits[0]);
|
|
|
|
/* Make sure u and v are the same size */
|
|
dig_size = max(u->ndigits, v->ndigits);
|
|
bd_resize(v, dig_size);
|
|
bd_resize(u, dig_size);
|
|
bd_resize(w, dig_size);
|
|
|
|
/* Finally, do the business */
|
|
borrow = mpSubtract(w->digits, u->digits, v->digits, dig_size);
|
|
|
|
/* Make sure we've set the right size for w */
|
|
w->ndigits = mpSizeof(w->digits, dig_size);
|
|
|
|
return borrow;
|
|
}
|
|
|
|
int bdSubtract_s(T w, T u, T v)
|
|
/* Compute w = u - v (safe) */
|
|
{
|
|
DIGIT_T carry;
|
|
T ww;
|
|
|
|
assert(w && u && v);
|
|
/* Use temp */
|
|
ww = bdNew();
|
|
bdSetEqual(ww, w);
|
|
|
|
carry = bdSubtract(ww, u, v);
|
|
|
|
bdSetEqual(w, ww);
|
|
bdFree(&ww);
|
|
|
|
return carry;
|
|
}
|
|
|
|
int bdIncrement(T a)
|
|
/* Sets a = a + 1, returns carry */
|
|
{
|
|
assert(a);
|
|
return bdShortAdd(a, a, 1);
|
|
}
|
|
|
|
int bdDecrement(T a)
|
|
/* Sets a = a - 1, returns borrow */
|
|
{
|
|
assert(a);
|
|
return bdShortSub(a, a, 1);
|
|
}
|
|
|
|
int bdShortMult(T w, T u, bdigit_t d)
|
|
/* Compute w = u * d */
|
|
{
|
|
DIGIT_T overflow;
|
|
size_t dig_size = u->ndigits;
|
|
|
|
assert(w && u);
|
|
/***************************************************/
|
|
// [2013-06-05]: catch empty u; make sure w is empty
|
|
if (dig_size == 0 || d == 0)
|
|
{ /* u == 0 */
|
|
bd_resize(w, 0);
|
|
return 0;
|
|
}
|
|
/***************************************************/
|
|
bd_resize(w, dig_size+1);
|
|
|
|
overflow = mpShortMult(w->digits, u->digits, d, dig_size);
|
|
|
|
/* Cope with overflow */
|
|
if (overflow)
|
|
{
|
|
w->digits[dig_size] = overflow;
|
|
w->ndigits = dig_size + 1;
|
|
}
|
|
else
|
|
w->ndigits = mpSizeof(w->digits, dig_size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bdMultiply(T w, T u, T v)
|
|
/* Compute w = u * v
|
|
-- no overlap permitted
|
|
*/
|
|
{
|
|
size_t dig_size;
|
|
|
|
assert(w && u && v);
|
|
/* Check for cheaper option */
|
|
if (v->ndigits == 1)
|
|
return bdShortMult(w, u, v->digits[0]);
|
|
|
|
/* Make sure u and v are the same size */
|
|
dig_size = max(u->ndigits, v->ndigits);
|
|
bd_resize(v, dig_size);
|
|
bd_resize(u, dig_size);
|
|
/* Now make sure w is big enough for product */
|
|
bd_resize(w, 2 * dig_size);
|
|
|
|
/* Finally, do the business */
|
|
mpMultiply(w->digits, u->digits, v->digits, dig_size);
|
|
|
|
/* Make sure we've set the right size for w */
|
|
w->ndigits = mpSizeof(w->digits, 2 * dig_size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bdMultiply_s(T w, T u, T v)
|
|
/* Compute w = u * v (safe) */
|
|
{
|
|
T ww;
|
|
|
|
assert(w && u && v);
|
|
/* Use temp */
|
|
ww = bdNew();
|
|
bdSetEqual(ww, w);
|
|
|
|
bdMultiply(ww, u, v);
|
|
|
|
bdSetEqual(w, ww);
|
|
bdFree(&ww);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bdSquare(T w, T x)
|
|
/* Computes w = x^2, w#x */
|
|
{
|
|
size_t dig_size;
|
|
|
|
assert(w && x);
|
|
|
|
dig_size = max(x->ndigits, 1);
|
|
/* Make sure w is big enough for product */
|
|
bd_resize(w, 2 * dig_size);
|
|
|
|
/* Finally, do the business */
|
|
mpSquare(w->digits, x->digits, dig_size);
|
|
|
|
/* Make sure we've set the right size for w */
|
|
w->ndigits = mpSizeof(w->digits, 2 * dig_size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bdSquare_s(T w, T x)
|
|
/* Compute w = x^2 (safe) */
|
|
{
|
|
T ww;
|
|
|
|
assert(w && x);
|
|
/* Use temp */
|
|
ww = bdNew();
|
|
bdSetEqual(ww, w);
|
|
|
|
bdSquare(ww, x);
|
|
|
|
bdSetEqual(w, ww);
|
|
bdFree(&ww);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bdPower(BIGD y, BIGD g, unsigned short int n)
|
|
/* Computes y = g^n (up to available memory!) */
|
|
{
|
|
BIGD z;
|
|
z = bdNew();
|
|
/* Use Right-Left Binary */
|
|
/* 1. Set y <-- 1, z <-- g */
|
|
bdSetShort(y, 1);
|
|
bdSetEqual(z, g);
|
|
/* If n = 0, output y and stop */
|
|
while (n > 0)
|
|
{
|
|
/* 2. If n is odd, set y <-- z.y */
|
|
if (n & 0x1)
|
|
bdMultiply_s(y, z, y);
|
|
/* 3. Set n <-- [n/2]. If n = 0, output y and stop */
|
|
n >>= 1;
|
|
if (n > 0)
|
|
/* 3b. Otherwise set z <-- z.z and go to step 2 */
|
|
bdSquare_s(z, z);
|
|
}
|
|
bdFree(&z);
|
|
/* Result is in y */
|
|
return 0;
|
|
}
|
|
|
|
int bdSqrt(BIGD s, BIGD x)
|
|
/* Computes integer square root s = floor(sqrt(x)) */
|
|
{
|
|
size_t dig_size;
|
|
int r;
|
|
|
|
assert(s && x);
|
|
dig_size = x->ndigits;
|
|
bd_resize(s, dig_size);
|
|
r = mpSqrt(s->digits, x->digits, dig_size);
|
|
s->ndigits = mpSizeof(s->digits, dig_size);
|
|
|
|
return r;
|
|
}
|
|
|
|
int bdCubeRoot(BIGD s, BIGD x)
|
|
/* Computes integer cube root s = floor(cuberoot(x)) */
|
|
{
|
|
size_t dig_size;
|
|
int r;
|
|
|
|
assert(s && x);
|
|
dig_size = x->ndigits;
|
|
bd_resize(s, dig_size);
|
|
r = mpCubeRoot(s->digits, x->digits, dig_size);
|
|
s->ndigits = mpSizeof(s->digits, dig_size);
|
|
|
|
return r;
|
|
}
|
|
|
|
int bdShortDiv(T q, T r, T u, bdigit_t d)
|
|
/* Computes quotient q = u / d and remainder r = u mod d */
|
|
{
|
|
DIGIT_T rem;
|
|
size_t dig_size;
|
|
|
|
assert(q && r && u);
|
|
dig_size = u->ndigits;
|
|
bd_resize(q, dig_size);
|
|
|
|
rem = mpShortDiv(q->digits, u->digits, d, dig_size);
|
|
bdSetShort(r, rem);
|
|
|
|
q->ndigits = mpSizeof(q->digits, dig_size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bdDivide(T q, T r, T u, T v)
|
|
/* Computes quotient q = u / v and remainder r = u mod v
|
|
trashes q and r first
|
|
*/
|
|
{
|
|
size_t dig_size;
|
|
|
|
assert(q && r && u && v);
|
|
dig_size = u->ndigits;
|
|
bd_resize(q, dig_size);
|
|
bd_resize(r, dig_size);
|
|
|
|
/* Do the business */
|
|
mpDivide(q->digits, r->digits, u->digits, dig_size, v->digits, v->ndigits);
|
|
|
|
/* Set final sizes */
|
|
q->ndigits = mpSizeof(q->digits, dig_size);
|
|
r->ndigits = mpSizeof(r->digits, dig_size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bdDivide_s(T q, T r, T u, T v)
|
|
/* Computes quotient q = u / v and remainder r = u mod v (safe) */
|
|
{
|
|
size_t dig_size;
|
|
BIGD qq, rr;
|
|
|
|
assert(q && r && u && v);
|
|
/* Use temps because mpDivide trashes q and r */
|
|
qq = bdNew();
|
|
rr = bdNew();
|
|
|
|
dig_size = u->ndigits;
|
|
bd_resize(qq, dig_size);
|
|
bd_resize(rr, dig_size);
|
|
|
|
/* Do the business */
|
|
mpDivide(qq->digits, rr->digits, u->digits, dig_size, v->digits, v->ndigits);
|
|
|
|
/* Copy temps */
|
|
qq->ndigits = dig_size;
|
|
rr->ndigits = dig_size;
|
|
bdSetEqual(q, qq);
|
|
bdSetEqual(r, rr);
|
|
|
|
/* Set final sizes */
|
|
q->ndigits = mpSizeof(q->digits, dig_size);
|
|
r->ndigits = mpSizeof(r->digits, dig_size);
|
|
|
|
/* Free temps */
|
|
bdFree(&qq);
|
|
bdFree(&rr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
bdigit_t bdShortMod(T r, T u, bdigit_t d)
|
|
/* Returns r = u mod d */
|
|
{
|
|
DIGIT_T rr;
|
|
|
|
assert(r && u);
|
|
rr = mpShortMod(u->digits, d, u->ndigits);
|
|
bdSetShort(r, rr);
|
|
|
|
return rr;
|
|
}
|
|
|
|
int bdModulo(T r, T u, T v)
|
|
/* Computes r = u mod v, r#u */
|
|
{
|
|
size_t nr;
|
|
|
|
assert(r && u && v);
|
|
|
|
/* NB r is only vdigits long at most */
|
|
nr = v->ndigits;
|
|
bd_resize(r, nr);
|
|
|
|
/* Do the business */
|
|
mpModulo(r->digits, u->digits, u->ndigits, v->digits, v->ndigits);
|
|
|
|
/* Set final size */
|
|
r->ndigits = mpSizeof(r->digits, nr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bdModulo_s(T r, T u, T v)
|
|
/* Computes r = u mod v (safe) */
|
|
{
|
|
T rr;
|
|
|
|
assert(r && u && v);
|
|
/* Use temp */
|
|
rr = bdNew();
|
|
bdSetEqual(rr, r);
|
|
|
|
bdModulo(rr, u, v);
|
|
|
|
bdSetEqual(r, rr);
|
|
bdFree(&rr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bdSetBit(T a, size_t ibit, int value)
|
|
/* Set bit ibit (0..nbits-1) with value 1 or 0
|
|
-- increases size if a too small but does not shrink */
|
|
{
|
|
size_t idigit;
|
|
|
|
assert(a);
|
|
/* Which digit? (0-based) */
|
|
idigit = ibit / BITS_PER_DIGIT;
|
|
/* Check size */
|
|
/* [EDIT v2.1:] change a->maxdigits to a->ndigits */
|
|
if (idigit >= a->ndigits)
|
|
{
|
|
bd_resize(a, idigit+1);
|
|
a->ndigits = idigit+1;
|
|
}
|
|
|
|
/* [v2.2] use mp function */
|
|
mpSetBit(a->digits, a->ndigits, ibit, value);
|
|
|
|
/* Set the right size */
|
|
a->ndigits = mpSizeof(a->digits, a->ndigits);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bdGetBit(T a, size_t ibit)
|
|
/* Returns value 1 or 0 of bit ibit (0..nbits-1) */
|
|
{
|
|
size_t idigit;
|
|
|
|
assert(a);
|
|
/* Which digit? (0-based) */
|
|
idigit = ibit / BITS_PER_DIGIT;
|
|
/* Check size */
|
|
if (idigit >= a->maxdigits)
|
|
return 0;
|
|
|
|
/* [v2.2] use mp function */
|
|
return mpGetBit(a->digits, a->ndigits, ibit);
|
|
}
|
|
|
|
void bdShiftLeft(T a, T b, size_t s)
|
|
/* Computes a = b << s */
|
|
{
|
|
/* Increases the size of a if necessary. */
|
|
/* [v2.1.0] modified to allow any size of shift */
|
|
|
|
size_t dig_size = b->ndigits;
|
|
|
|
assert(a && b);
|
|
|
|
if (s >= BITS_PER_DIGIT)
|
|
dig_size += (s / BITS_PER_DIGIT);
|
|
|
|
/* Assume overflow */
|
|
dig_size++;
|
|
/* Make sure both big enough */
|
|
bd_resize(a, dig_size);
|
|
bd_resize(b, dig_size);
|
|
|
|
/* Set the final size */
|
|
mpShiftLeft(a->digits, b->digits, s, dig_size);
|
|
|
|
a->ndigits = mpSizeof(a->digits, dig_size);
|
|
|
|
}
|
|
|
|
void bdShiftRight(T a, T b, size_t n)
|
|
/* Computes a = b >> n */
|
|
{
|
|
/* Throws away shifted bits */
|
|
/* [v2.1.0] modified to allow any size of shift */
|
|
|
|
size_t dig_size = b->ndigits;
|
|
|
|
assert(a && b);
|
|
|
|
bd_resize(a, dig_size);
|
|
mpShiftRight(a->digits, b->digits, n, dig_size);
|
|
|
|
/* Set the final size */
|
|
a->ndigits = mpSizeof(a->digits, dig_size);
|
|
|
|
}
|
|
|
|
void bdXorBits(T a, T b, T c)
|
|
/* Computes bitwise operation a = b XOR c */
|
|
{
|
|
size_t n;
|
|
|
|
assert(a && b && c);
|
|
/* Make sure all variables are the same size */
|
|
n = max(b->ndigits, c->ndigits);
|
|
|
|
bd_resize(a, n);
|
|
bd_resize(b, n);
|
|
bd_resize(c, n);
|
|
|
|
/* Do the business */
|
|
mpXorBits(a->digits, b->digits, c->digits, n);
|
|
|
|
/* Set the final size */
|
|
a->ndigits = mpSizeof(a->digits, n);
|
|
|
|
}
|
|
|
|
void bdOrBits(T a, T b, T c)
|
|
/* Computes bitwise operation a = b OR c */
|
|
{
|
|
size_t n;
|
|
|
|
assert(a && b && c);
|
|
/* Make sure all variables are the same size */
|
|
n = max(b->ndigits, c->ndigits);
|
|
|
|
bd_resize(a, n);
|
|
bd_resize(b, n);
|
|
bd_resize(c, n);
|
|
|
|
/* Do the business */
|
|
mpOrBits(a->digits, b->digits, c->digits, n);
|
|
|
|
/* Set the final size */
|
|
a->ndigits = mpSizeof(a->digits, n);
|
|
|
|
}
|
|
|
|
void bdAndBits(T a, T b, T c)
|
|
/* Computes bitwise operation a = b AND c */
|
|
{
|
|
size_t n;
|
|
|
|
assert(a && b && c);
|
|
/* Make sure all variables are the same size */
|
|
n = max(b->ndigits, c->ndigits);
|
|
|
|
bd_resize(a, n);
|
|
bd_resize(b, n);
|
|
bd_resize(c, n);
|
|
|
|
/* Do the business */
|
|
mpAndBits(a->digits, b->digits, c->digits, n);
|
|
|
|
/* Set the final size */
|
|
a->ndigits = mpSizeof(a->digits, n);
|
|
}
|
|
|
|
void bdNotBits(BIGD a, BIGD b)
|
|
/* Computes bitwise a = NOT b */
|
|
{
|
|
size_t n;
|
|
|
|
assert(a && b);
|
|
/* Make sure all variables are the same size */
|
|
n = b->ndigits;
|
|
|
|
bd_resize(a, n);
|
|
|
|
/* Do the business */
|
|
mpNotBits(a->digits, b->digits, n);
|
|
|
|
/* Set the final size */
|
|
a->ndigits = mpSizeof(a->digits, n);
|
|
}
|
|
|
|
void bdModPowerOf2(BIGD a, size_t L)
|
|
/* Computes a = a mod 2^L */
|
|
{
|
|
size_t n;
|
|
|
|
assert(a);
|
|
n = a->ndigits;
|
|
|
|
/* Do the business */
|
|
mpModPowerOf2(a->digits, n, L);
|
|
|
|
/* Set the final size */
|
|
a->ndigits = mpSizeof(a->digits, n);
|
|
}
|
|
|
|
/** Compute y = x^e mod m, x,e < m */
|
|
static int modexp_internal(T y, T x, T e, T m, int constant_time)
|
|
{
|
|
size_t n;
|
|
int status;
|
|
|
|
assert(y && x && e && m);
|
|
/* Make sure all variables are the same size */
|
|
n = max(e->ndigits, m->ndigits);
|
|
n = max(x->ndigits, n);
|
|
|
|
bd_resize(y, n);
|
|
bd_resize(x, n);
|
|
bd_resize(e, n);
|
|
bd_resize(m, n);
|
|
|
|
/* Finally, do the business */
|
|
if (constant_time)
|
|
status = mpModExp_ct(y->digits, x->digits, e->digits, m->digits, n);
|
|
else
|
|
status = mpModExp(y->digits, x->digits, e->digits, m->digits, n);
|
|
|
|
y->ndigits = mpSizeof(y->digits, n);
|
|
|
|
return status;
|
|
}
|
|
|
|
/** Compute y = x^e mod m, x,e < m */
|
|
int bdModExp(BIGD y, BIGD x, BIGD e, BIGD m)
|
|
{
|
|
return modexp_internal(y, x, e, m, 0);
|
|
}
|
|
|
|
/** Compute y = x^e mod m in constant time */
|
|
int bdModExp_ct(BIGD y, BIGD x, BIGD e, BIGD m)
|
|
{
|
|
return modexp_internal(y, x, e, m, 1);
|
|
}
|
|
|
|
/** Compute a = (x * y) mod m */
|
|
int bdModMult(T a, T x, T y, T m)
|
|
{
|
|
size_t n;
|
|
int status;
|
|
|
|
assert(a && x && y && m);
|
|
/* Make sure all variables are the same size */
|
|
n = max(y->ndigits, m->ndigits);
|
|
n = max(x->ndigits, n);
|
|
|
|
bd_resize(a, n);
|
|
bd_resize(y, n);
|
|
bd_resize(x, n);
|
|
bd_resize(m, n);
|
|
|
|
/* Do the business */
|
|
status = mpModMult(a->digits, x->digits, y->digits, m->digits, n);
|
|
|
|
a->ndigits = mpSizeof(a->digits, n);
|
|
|
|
return status;
|
|
}
|
|
|
|
/** Computes a = x^2 mod m */
|
|
int bdModSquare(BIGD a, BIGD x, BIGD m)
|
|
{
|
|
size_t n;
|
|
int status;
|
|
|
|
assert(a && x && m);
|
|
/* Make sure all variables are the same size */
|
|
n = max(x->ndigits, m->ndigits);
|
|
|
|
bd_resize(a, n);
|
|
bd_resize(x, n);
|
|
bd_resize(m, n);
|
|
|
|
/* Do the business */
|
|
status = mpModSquare(a->digits, x->digits, m->digits, n);
|
|
|
|
a->ndigits = mpSizeof(a->digits, n);
|
|
|
|
return status;
|
|
}
|
|
|
|
/** Computes x = sqrt(a) mod p */
|
|
int bdModSqrt(BIGD x, BIGD a, BIGD p)
|
|
{
|
|
size_t n;
|
|
int status;
|
|
|
|
assert(x && a && p);
|
|
/* Make sure all variables are the same size */
|
|
n = max(a->ndigits, p->ndigits);
|
|
|
|
bd_resize(x, n);
|
|
bd_resize(a, n);
|
|
bd_resize(p, n);
|
|
|
|
/* Do the business */
|
|
status = mpModSqrt(x->digits, a->digits, p->digits, n);
|
|
|
|
x->ndigits = mpSizeof(x->digits, n);
|
|
|
|
return status;
|
|
}
|
|
|
|
/** Computes w = u/2 (mod p) for an odd prime p */
|
|
void bdModHalve(BIGD w, const BIGD u, const BIGD p)
|
|
{
|
|
size_t n;
|
|
|
|
assert(w && u && p);
|
|
/* Make sure all variables are the same size */
|
|
n = max(u->ndigits, p->ndigits);
|
|
|
|
bd_resize(w, n);
|
|
bd_resize(u, n);
|
|
bd_resize(p, n);
|
|
|
|
/* Do the business */
|
|
mpModHalve(w->digits, u->digits, p->digits, n);
|
|
|
|
w->ndigits = mpSizeof(w->digits, n);
|
|
}
|
|
|
|
|
|
/* Computes w = u + v (mod m) for 0 <= u,v < m*/
|
|
void bdModAdd(BIGD w, BIGD u, BIGD v, BIGD m)
|
|
{
|
|
size_t n;
|
|
|
|
assert(w && u && v && m);
|
|
/* Make sure all variables are the same size */
|
|
n = max(v->ndigits, m->ndigits);
|
|
n = max(u->ndigits, n);
|
|
|
|
bd_resize(w, n);
|
|
bd_resize(u, n);
|
|
bd_resize(v, n);
|
|
bd_resize(m, n);
|
|
|
|
/* Do the business */
|
|
mpModAdd(w->digits, u->digits, v->digits, m->digits, n);
|
|
|
|
w->ndigits = mpSizeof(w->digits, n);
|
|
}
|
|
|
|
/* Computes w = u - v (mod m) for 0 <= u,v < m*/
|
|
void bdModSub(BIGD w, BIGD u, BIGD v, BIGD m)
|
|
{
|
|
size_t n;
|
|
|
|
assert(w && u && v && m);
|
|
/* Make sure all variables are the same size */
|
|
n = max(v->ndigits, m->ndigits);
|
|
n = max(u->ndigits, n);
|
|
|
|
bd_resize(w, n);
|
|
bd_resize(u, n);
|
|
bd_resize(v, n);
|
|
bd_resize(m, n);
|
|
|
|
/* Do the business */
|
|
mpModSub(w->digits, u->digits, v->digits, m->digits, n);
|
|
|
|
w->ndigits = mpSizeof(w->digits, n);
|
|
}
|
|
|
|
/** Compute x = a^-1 mod m */
|
|
int bdModInv(T x, T a, T m)
|
|
{
|
|
size_t n;
|
|
int status;
|
|
|
|
assert(x && a && m);
|
|
/* Make sure all variables are the same size */
|
|
n = max(a->ndigits, m->ndigits);
|
|
|
|
bd_resize(x, n);
|
|
bd_resize(a, n);
|
|
bd_resize(m, n);
|
|
|
|
/* Do the business */
|
|
status = mpModInv(x->digits, a->digits, m->digits, n);
|
|
|
|
x->ndigits = mpSizeof(x->digits, n);
|
|
|
|
return status;
|
|
}
|
|
|
|
int bdGcd(T g, T x, T y)
|
|
/* Compute g = gcd(x, y) */
|
|
{
|
|
size_t n;
|
|
int status;
|
|
|
|
assert(g && x && y);
|
|
n = max(x->ndigits, y->ndigits);
|
|
|
|
bd_resize(g, n);
|
|
bd_resize(y, n);
|
|
bd_resize(x, n);
|
|
|
|
/* Do the business */
|
|
status = mpGcd(g->digits, x->digits, y->digits, n);
|
|
|
|
g->ndigits = mpSizeof(g->digits, n);
|
|
|
|
return status;
|
|
}
|
|
|
|
int bdJacobi(T a, T m)
|
|
/* Returns Jacobi(a, m) = {0, +1, -1} */
|
|
{
|
|
size_t n; /* Careful with n and m here! */
|
|
int status;
|
|
|
|
assert(a && m);
|
|
n = max(a->ndigits, m->ndigits);
|
|
|
|
bd_resize(a, n);
|
|
bd_resize(m, n);
|
|
|
|
/* Do the business */
|
|
status = mpJacobi(a->digits, m->digits, n);
|
|
|
|
return status;
|
|
}
|
|
|
|
int bdIsPrime(T b, size_t ntests)
|
|
/* Returns true if passes ntests x Miller-Rabin tests */
|
|
{
|
|
assert(b);
|
|
return (mpIsPrime(b->digits, b->ndigits, ntests));
|
|
}
|
|
|
|
int bdRabinMiller(T b, size_t ntests)
|
|
/* Returns true if passes ntests x Miller-Rabin tests without trial division */
|
|
{
|
|
assert(b);
|
|
return (mpRabinMiller(b->digits, b->ndigits, ntests));
|
|
}
|
|
|
|
/* [Version 2.1: bdRandDigit moved to bdRand.c] */
|
|
|
|
|
|
/* Make a random BIGD of up to `ndigits` digits
|
|
-- NB just for doing tests
|
|
Return # digits actually set
|
|
*/
|
|
size_t bdSetRandTest(T a, size_t ndigits)
|
|
{
|
|
/* Re-written [v2.6] */
|
|
size_t n;
|
|
size_t nbitstarget = ndigits * BITS_PER_DIGIT;
|
|
|
|
/* Half the time, pick a shorter bitlength at random from [4,nbits]
|
|
so at least a >= 16 */
|
|
if (spSimpleRand(0, 1)) {
|
|
n = (size_t)spSimpleRand(4, (DIGIT_T)nbitstarget);
|
|
}
|
|
else {
|
|
n = nbitstarget;
|
|
}
|
|
|
|
bdQuickRandBits(a, n);
|
|
/* Make sure a > 1 */
|
|
if (bdShortCmp(a, 2) < 0)
|
|
bdQuickRandBits(a, nbitstarget);
|
|
|
|
return bdSizeof(a);
|
|
|
|
}
|
|
|
|
/** Generate a quick-and-dirty random number a <= 2^{nbits}-1 using plain-old-rand
|
|
* @return Number of digits actually set
|
|
* @remark Not crypto secure
|
|
*/ /* Added [v2.4] */
|
|
size_t bdQuickRandBits(T a, size_t nbits)
|
|
{
|
|
size_t n;
|
|
|
|
assert(a);
|
|
n = (nbits + BITS_PER_DIGIT - 1) / BITS_PER_DIGIT;
|
|
bd_resize(a, n);
|
|
n = mpQuickRandBits(a->digits, n, nbits);
|
|
a->ndigits = n;
|
|
|
|
return n;
|
|
}
|
|
|
|
int bdRandomSeeded(T a, size_t nbits, const unsigned char *seed,
|
|
size_t seedlen, BD_RANDFUNC RandFunc)
|
|
/* Create a random mp digit at most nbits long
|
|
-- high bit may or may not be set
|
|
-- Uses whatever RNG function the user specifies */
|
|
{
|
|
size_t i, hibit, ndigits, nbytes;
|
|
DIGIT_T chop;
|
|
|
|
assert(a);
|
|
/* Make sure big enough */
|
|
ndigits = (nbits + BITS_PER_DIGIT - 1) / BITS_PER_DIGIT;
|
|
bd_resize(a, ndigits);
|
|
nbytes = ndigits * sizeof(DIGIT_T);
|
|
|
|
/* Generate random bytes using callback function */
|
|
RandFunc((unsigned char *)a->digits, nbytes, seed, seedlen);
|
|
|
|
/* Clear unwanted high bits */
|
|
hibit = (nbits-1) % BITS_PER_DIGIT;
|
|
for (chop = 0x01, i = 0; i < hibit; i++)
|
|
chop = (chop << 1) | chop;
|
|
|
|
a->digits[ndigits-1] &= chop;
|
|
|
|
a->ndigits = ndigits;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int bdGeneratePrime(T b, size_t nbits, size_t ntests,
|
|
const unsigned char *seed, size_t seedlen, BD_RANDFUNC RandFunc)
|
|
{
|
|
size_t i, hibit, ndigits, nbytes;
|
|
DIGIT_T mask, chop;
|
|
DIGIT_T *p;
|
|
int done;
|
|
size_t iloop, maxloops, j, maxodd;
|
|
|
|
assert(b);
|
|
/* Make sure big enough */
|
|
ndigits = (nbits + BITS_PER_DIGIT - 1) / BITS_PER_DIGIT;
|
|
bd_resize(b, ndigits);
|
|
nbytes = ndigits * sizeof(DIGIT_T);
|
|
|
|
/* use a ptr */
|
|
p = b->digits;
|
|
|
|
maxloops = 5;
|
|
maxodd = 100 * nbits;
|
|
done = 0;
|
|
for (iloop = 0; !done && iloop < maxloops; iloop++)
|
|
{
|
|
/* Generate random digits using callback function */
|
|
RandFunc((unsigned char *)p, nbytes, seed, seedlen);
|
|
|
|
/* Set high and low bits */
|
|
hibit = (nbits-1) % BITS_PER_DIGIT;
|
|
mask = 0x01 << hibit;
|
|
for (chop = 0x01, i = 0; i < hibit; i++)
|
|
chop = (chop << 1) | chop;
|
|
|
|
p[ndigits-1] |= mask;
|
|
p[ndigits-1] &= chop;
|
|
p[0] |= 0x01;
|
|
|
|
/* Try each odd number until success or too many tries */
|
|
for (j = 0; !done && j < maxodd; j++, mpShortAdd(p, p, 2, ndigits))
|
|
{
|
|
if (!(p[ndigits-1] & mask))
|
|
break; /* Catch overflow */
|
|
|
|
if (debug) mpPrintNL(p, ndigits);
|
|
|
|
if (mpIsPrime(p, ndigits, ntests))
|
|
{
|
|
done = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (debug) mpPrintNL(p, ndigits);
|
|
|
|
b->ndigits = ndigits;
|
|
|
|
return (done ? 0 : 1);
|
|
}
|
|
|
|
/* Version Info - added in [v2.0.2] */
|
|
int bdVersion(void)
|
|
{
|
|
return mpVersion();
|
|
}
|
|
|
|
/* Added [v2.6] */
|
|
const char *bdCompileTime(void)
|
|
{
|
|
return __DATE__" "__TIME__;
|
|
}
|
|
|