📄 integer.cpp
字号:
CopyWords(R, A, N);
while (k--)
if (ShiftWordsLeftByBits(R, N, 1) || Compare(R, M, N)>=0)
Subtract(R, R, M, N);
}
// ******************************************************************
static const unsigned int RoundupSizeTable[] = {2, 2, 2, 4, 4, 8, 8, 8, 8};
static inline unsigned int RoundupSize(unsigned int n)
{
if (n<=8)
return RoundupSizeTable[n];
else if (n<=16)
return 16;
else if (n<=32)
return 32;
else if (n<=64)
return 64;
else return 1U << BitPrecision(n-1);
}
Integer::Integer()
: reg(2), sign(POSITIVE)
{
reg[0] = reg[1] = 0;
}
Integer::Integer(const Integer& t)
: reg(RoundupSize(t.WordCount())), sign(t.sign)
{
CopyWords(reg, t.reg, reg.size);
}
Integer::Integer(signed long value)
: reg(2)
{
if (value >= 0)
sign = POSITIVE;
else
{
sign = NEGATIVE;
value = -value;
}
reg[0] = word(value);
reg[1] = sizeof(value)>WORD_SIZE ? word(value>>WORD_BITS) : 0;
}
bool Integer::IsConvertableToLong() const
{
if (ByteCount() > sizeof(long))
return false;
unsigned long value = reg[0];
value += sizeof(value)>WORD_SIZE ? ((unsigned long)reg[1]<<WORD_BITS) : 0;
if (sign==POSITIVE)
return (signed long)value >= 0;
else
return -(signed long)value < 0;
}
signed long Integer::ConvertToLong() const
{
unsigned long value = reg[0];
value += sizeof(value)>WORD_SIZE ? ((unsigned long)reg[1]<<WORD_BITS) : 0;
return sign==POSITIVE ? value : -(signed long)value;
}
Integer::Integer(BufferedTransformation &encodedInteger, unsigned int byteCount, Signedness s)
{
Decode(encodedInteger, byteCount, s);
}
Integer::Integer(const byte *encodedInteger, unsigned int byteCount, Signedness s)
{
Decode(encodedInteger, byteCount, s);
}
Integer::Integer(BufferedTransformation &bt)
{
BERDecode(bt);
}
Integer::Integer(RandomNumberGenerator &rng, unsigned int bitcount)
{
Randomize(rng, bitcount);
}
Integer::Integer(RandomNumberGenerator &rng, const Integer &min, const Integer &max, RandomNumberType rnType, const Integer &equiv, const Integer &mod)
{
if (!Randomize(rng, min, max, rnType, equiv, mod))
throw Integer::RandomNumberNotFound();
}
Integer Integer::Power2(unsigned int e)
{
Integer r((word)0, bitsToWords(e+1));
r.SetBit(e);
return r;
}
const Integer &Integer::Zero()
{
static const Integer zero;
return zero;
}
const Integer &Integer::One()
{
static const Integer one(1,2);
return one;
}
bool Integer::operator!() const
{
return IsNegative() ? false : (reg[0]==0 && WordCount()==0);
}
Integer& Integer::operator=(const Integer& t)
{
if (this != &t)
{
reg.New(RoundupSize(t.WordCount()));
CopyWords(reg, t.reg, reg.size);
sign = t.sign;
}
return *this;
}
bool Integer::GetBit(unsigned int n) const
{
if (n/WORD_BITS >= reg.size)
return 0;
else
return bool((reg[n/WORD_BITS] >> (n % WORD_BITS)) & 1);
}
void Integer::SetBit(unsigned int n, bool value)
{
if (value)
{
reg.CleanGrow(RoundupSize(bitsToWords(n+1)));
reg[n/WORD_BITS] |= (word(1) << (n%WORD_BITS));
}
else
{
if (n/WORD_BITS < reg.size)
reg[n/WORD_BITS] &= ~(word(1) << (n%WORD_BITS));
}
}
byte Integer::GetByte(unsigned int n) const
{
if (n/WORD_SIZE >= reg.size)
return 0;
else
return byte(reg[n/WORD_SIZE] >> ((n%WORD_SIZE)*8));
}
void Integer::SetByte(unsigned int n, byte value)
{
reg.CleanGrow(RoundupSize(bytesToWords(n+1)));
reg[n/WORD_SIZE] &= ~(word(0xff) << 8*(n%WORD_SIZE));
reg[n/WORD_SIZE] |= (word(value) << 8*(n%WORD_SIZE));
}
unsigned long Integer::GetBits(unsigned int i, unsigned int n) const
{
assert(n <= sizeof(unsigned long)*8);
unsigned long v = 0;
for (unsigned int j=0; j<n; j++)
v |= GetBit(i+j) << j;
return v;
}
Integer Integer::operator-() const
{
Integer result(*this);
result.Negate();
return result;
}
Integer Integer::AbsoluteValue() const
{
Integer result(*this);
result.sign = POSITIVE;
return result;
}
void Integer::swap(Integer &a)
{
reg.swap(a.reg);
std::swap(sign, a.sign);
}
Integer::Integer(word value, unsigned int length)
: reg(RoundupSize(length)), sign(POSITIVE)
{
reg[0] = value;
SetWords(reg+1, 0, reg.size-1);
}
Integer::Integer(const char *str)
: reg(2), sign(POSITIVE)
{
word radix;
unsigned length = strlen(str);
SetWords(reg, 0, 2);
if (length == 0)
return;
switch (str[length-1])
{
case 'h':
case 'H':
radix=16;
break;
case 'o':
case 'O':
radix=8;
break;
case 'b':
case 'B':
radix=2;
break;
default:
radix=10;
}
if (strncmp("0x", str, 2) == 0)
radix = 16;
for (unsigned i=0; i<length; i++)
{
word digit;
if (str[i] >= '0' && str[i] <= '9')
digit = str[i] - '0';
else if (str[i] >= 'A' && str[i] <= 'F')
digit = str[i] - 'A' + 10;
else if (str[i] >= 'a' && str[i] <= 'f')
digit = str[i] - 'a' + 10;
else
digit = radix;
if (digit < radix)
{
*this *= radix;
*this += digit;
}
}
if (str[0] == '-')
Negate();
}
unsigned int Integer::WordCount() const
{
return CountWords(reg, reg.size);
}
unsigned int Integer::ByteCount() const
{
unsigned wordCount = WordCount();
if (wordCount)
return (wordCount-1)*WORD_SIZE + BytePrecision(reg[wordCount-1]);
else
return 0;
}
unsigned int Integer::BitCount() const
{
unsigned wordCount = WordCount();
if (wordCount)
return (wordCount-1)*WORD_BITS + BitPrecision(reg[wordCount-1]);
else
return 0;
}
void Integer::Decode(const byte *input, unsigned int inputLen, Signedness s)
{
StringStore store(input, inputLen);
Decode(store, inputLen, s);
}
void Integer::Decode(BufferedTransformation &bt, unsigned int inputLen, Signedness s)
{
assert(bt.MaxRetrievable() >= inputLen);
byte b;
bt.Peek(b);
sign = ((s==SIGNED) && (b & 0x80)) ? NEGATIVE : POSITIVE;
while (inputLen>0 && (sign==POSITIVE ? b==0 : b==0xff))
{
bt.Skip(1);
inputLen--;
bt.Peek(b);
}
reg.CleanNew(RoundupSize(bytesToWords(inputLen)));
for (unsigned int i=inputLen; i > 0; i--)
{
bt.Get(b);
reg[(i-1)/WORD_SIZE] |= b << ((i-1)%WORD_SIZE)*8;
}
if (sign == NEGATIVE)
{
for (unsigned i=inputLen; i<reg.size*WORD_SIZE; i++)
reg[i/WORD_SIZE] |= 0xff << (i%WORD_SIZE)*8;
TwosComplement(reg, reg.size);
}
}
unsigned int Integer::MinEncodedSize(Signedness signedness) const
{
unsigned int outputLen = STDMAX(1U, ByteCount());
if (signedness == UNSIGNED)
return outputLen;
if (NotNegative() && (GetByte(outputLen-1) & 0x80))
outputLen++;
if (IsNegative() && *this < -Power2(outputLen*8-1))
outputLen++;
return outputLen;
}
unsigned int Integer::Encode(byte *output, unsigned int outputLen, Signedness signedness) const
{
ArraySink sink(output, outputLen);
return Encode(sink, outputLen);
}
unsigned int Integer::Encode(BufferedTransformation &bt, unsigned int outputLen, Signedness signedness) const
{
if (signedness == UNSIGNED || NotNegative())
{
for (unsigned int i=outputLen; i > 0; i--)
bt.Put(GetByte(i-1));
}
else
{
// take two's complement of *this
Integer temp = Integer::Power2(8*STDMAX(ByteCount(), outputLen)) + *this;
for (unsigned i=0; i<outputLen; i++)
bt.Put(temp.GetByte(outputLen-i-1));
}
return outputLen;
}
void Integer::DEREncode(BufferedTransformation &bt) const
{
DERGeneralEncoder enc(bt, INTEGER);
Encode(enc, MinEncodedSize(SIGNED), SIGNED);
enc.MessageEnd();
}
void Integer::BERDecode(const byte *input, unsigned int len)
{
StringStore store(input, len);
BERDecode(store);
}
void Integer::BERDecode(BufferedTransformation &bt)
{
BERGeneralDecoder dec(bt, INTEGER);
if (!dec.IsDefiniteLength() || dec.MaxRetrievable() < dec.RemainingLength())
BERDecodeError();
Decode(dec, dec.RemainingLength(), SIGNED);
dec.MessageEnd();
}
void Integer::DEREncodeAsOctetString(BufferedTransformation &bt, unsigned int length) const
{
DERGeneralEncoder enc(bt, OCTET_STRING);
Encode(enc, length);
enc.MessageEnd();
}
void Integer::BERDecodeAsOctetString(BufferedTransformation &bt, unsigned int length)
{
BERGeneralDecoder dec(bt, OCTET_STRING);
if (!dec.IsDefiniteLength() || dec.RemainingLength() != length)
BERDecodeError();
Decode(dec, length);
dec.MessageEnd();
}
unsigned int Integer::OpenPGPEncode(byte *output, unsigned int len) const
{
ArraySink sink(output, len);
return OpenPGPEncode(sink);
}
unsigned int Integer::OpenPGPEncode(BufferedTransformation &bt) const
{
word16 bitCount = BitCount();
bt.PutWord16(bitCount);
return 2 + Encode(bt, bitsToBytes(bitCount));
}
void Integer::OpenPGPDecode(const byte *input, unsigned int len)
{
StringStore store(input, len);
OpenPGPDecode(store);
}
void Integer::OpenPGPDecode(BufferedTransformation &bt)
{
word16 bitCount;
if (bt.GetWord16(bitCount) != 2 || bt.MaxRetrievable() < bitsToBytes(bitCount))
throw OpenPGPDecodeErr();
Decode(bt, bitsToBytes(bitCount));
}
void Integer::Randomize(RandomNumberGenerator &rng, unsigned int nbits)
{
const unsigned int nbytes = nbits/8 + 1;
SecByteBlock buf(nbytes);
rng.GetBlock(buf, nbytes);
if (nbytes)
buf[0] = (byte)Crop(buf[0], nbits % 8);
Decode(buf, nbytes, UNSIGNED);
}
void Integer::Randomize(RandomNumberGenerator &rng, const Integer &min, const Integer &max)
{
assert(max >= min);
Integer range = max - min;
const unsigned int nbits = range.BitCount();
do
{
Randomize(rng, nbits);
}
while (*this > range);
*this += min;
}
bool Integer::Randomize(RandomNumberGenerator &rng, const Integer &min, const Integer &max, RandomNumberType rnType, const Integer &equiv, const Integer &mod)
{
assert(!equiv.IsNegative() && equiv < mod);
switch (rnType)
{
case ANY:
if (mod == One())
Randomize(rng, min, max);
else
{
Integer min1 = min + (equiv-min)%mod;
if (max < min1)
return false;
Randomize(rng, Zero(), (max - min1) / mod);
*this *= mod;
*this += min1;
}
return true;
case PRIME:
int i;
i = 0;
while (1)
{
if (++i==16)
{
// check if there are any suitable primes in [min, max]
Integer first = min;
if (FirstPrime(first, max, equiv, mod))
{
// if there is only one suitable prime, we're done
*this = first;
if (!FirstPrime(first, max, equiv, mod))
return true;
}
else
return false;
}
Randomize(rng, min, max);
if (FirstPrime(*this, STDMIN(*this+mod*PrimeSearchInterval(max), max), equiv, mod))
return true;
}
default:
assert(false);
return false;
}
}
std::istream& operator>>(std::istream& in, Integer &a)
{
char c;
unsigned int length = 0;
SecBlock<char> str(length + 16);
std::ws(in);
do
{
in.read(&c, 1);
str[length++] = c;
if (length >= str.size)
str.Grow(length + 16);
}
while (in && (c=='-' || c=='x' || (c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F') || c=='h' || c=='H' || c=='o' || c=='O' || c==',' || c=='.'));
if (in.gcount())
in.putback(c);
str[length-1] = '\0';
a = Integer(str);
return in;
}
std::ostream& operator<<(std::ostream& out, const Integer &a)
{
// Get relevant conversion specifications from ostream.
long f = out.flags() & std::ios::basefield; // Get base digits.
int base, block;
char suffix;
switch(f)
{
case std::ios::oct :
base = 8;
block = 8;
suffix = 'o';
break;
case std::ios::hex :
base = 16;
block = 4;
suffix = 'h';
break;
default :
base = 10;
block = 3;
suffix = '.';
}
SecBlock<char> s(a.BitCount() / (BitPrecision(base)-1) + 1);
Integer temp1=a, temp2;
unsigned i=0;
const char vec[]="0123456789ABCDEF";
if (a.IsNegative())
{
out << '-';
temp1.Negate();
}
if (!a)
out << '0';
while (!!temp1)
{
word digit;
Integer::Divide(digit, temp2, temp1, base);
s[i++]=vec[digit];
temp1=temp2;
}
while (i--)
{
out << s[i];
// if (i && !(i%block))
// out << ",";
}
return out << suffix;
}
Integer& Integer::operator++()
{
if (NotNegative())
{
if (Increment(reg, reg.size))
{
reg.CleanGrow(2*reg.size);
reg[reg.size/2]=1;
}
}
else
{
word borrow = Decrement(reg, reg.size);
assert(!borrow);
if (WordCount()==0)
*this = Zero();
}
return *this;
}
Integer& Integer::operator--()
{
if (IsNegative())
{
if (Increment(reg, reg.size))
{
reg.CleanGrow(2*reg.size);
reg[reg.size/2]=1;
}
}
else
{
if (Decrement(reg, reg.size))
*this = -One();
}
return *this;
}
void PositiveAdd(Integer &sum, const Integer &a, const Integer& b)
{
word carry;
if (a.reg.size == b.reg.size)
carry = Add(sum.reg, a.reg, b.reg, a.reg.size);
else if (a.reg.size > b.reg.size)
{
carry = Add(sum.reg, a.reg, b.reg, b.reg.size);
CopyWords(sum.reg+b.reg.size, a.reg+b.reg.size, a.reg.size-b.reg.size);
carry = Increment(sum.reg+b.reg.size, a.reg.size-b.reg.size, carry);
}
else
{
carry = Add(sum.reg, a.reg, b.reg, a.reg.size);
CopyWords(sum.reg+a.reg.size, b.reg+a.reg.size, b.reg.size-a.reg.size);
carry = Increment(sum.reg+a.reg.size, b.reg.size-a.reg.size, carry);
}
if (carry)
{
sum.reg.CleanGrow(2*sum.reg.size);
sum.reg[sum.reg.size/2] = 1;
}
sum.sign = Integer::POSITIVE;
}
void PositiveSubtract(Integer &diff, const Integer &a, const Integer& b)
{
unsigned aSize = a.WordCount();
aSize += aSize%2;
unsigned bSize = b.WordCount();
bSize += bSize%2;
if (aSize == bSize)
{
if (Compare(a.reg, b.reg, aSize) >= 0)
{
Subtract(diff.reg, a.reg, b.reg, aSize);
diff.sign = Integer::POSITIVE;
}
else
{
Subtract(diff.reg, b.reg, a.reg, aSize);
diff.sign = Integer::NEGATIVE;
}
}
else if (aSize > bSize)
{
word borrow = Subtract(diff.reg, a.reg, b.reg, bSize);
CopyWords(diff.reg+bSize, a.reg+bSize, aSize-bSize);
borrow = Decrement(diff.reg+bSize, aSize-bSize, borrow);
assert(!borrow);
diff.sign = Integer::POSITIVE;
}
else
{
word borrow = Subtract(diff.reg, b.reg, a.reg, aSize);
CopyWords(diff.reg+aSize, b.reg+aSize, bSize-aSize);
borrow = Decrement(diff.reg+aSize, bSize-aSize, borrow);
assert(!borrow);
diff.sign = Integer::NEGATIVE;
}
}
Integer Integer::Plus(const Integer& b) const
{
Integer sum((word)0, STDMAX(reg.size, b.reg.size));
if (NotNegative())
{
if (b.NotNegative())
PositiveAdd(sum, *this, b);
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -