bitcoin-hs-0.0.1: Bitcoin/Crypto/cbits/c_word256.c
// Relatively fast arithmetic operations mod 2^256
// Output is always the last argument, and it can optionally coincide with one of the inputs.
// (c) 2013 Balazs Komuves
//------------------------------------------------------------------------------
#include "c_word256.h"
//------------------------------------------------------------------------------
void zero256(uint256 a)
{
for(int i=0;i<8;i++) { a[i]=0; }
}
void copy256(uint256 a, uint256 b)
{
for(int i=0;i<8;i++) { b[i] = a[i]; }
}
// bitwise not
void not256(uint256 a, uint256 b)
{
for(int i=0;i<8;i++)
{
b[i] = ~a[i];
}
}
// shifts right by k bits. k must be between 0 and 31
uint32_t shiftr256_small(uint256 a, int k, uint256 b)
{
if (k==0) { copy256(a,b); return 0; }
uint32_t carry = 0;
for(int i=7;i>=0;i--)
{
uint32_t tmp = a[i] << (32-k); // order is important when b and a points to the same place in the memory
b[i] = (a[i] >> k) | carry;
carry = tmp;
}
return carry;
}
// shifts left by k bits. k must be between 0 and 31
uint32_t shiftl256_small(uint256 a, int k, uint256 b)
{
if (k==0) { copy256(a,b); return 0; }
uint32_t carry = 0;
for(int i=0;i<8;i++)
{
uint32_t tmp = a[i] >> (32-k); // order is important when b and a points to the same place in the memory
b[i] = (a[i] << k) | carry;
carry = tmp;
}
return carry;
}
// shifts right by 32 bits
uint32_t shiftr256_fullword(uint256 a, uint256 b)
{
uint32_t carry = a[0];
for(int i=0;i<7;i++) { b[i] = a[i+1]; }
b[7] = 0;
return carry;
}
// shifts left by 32 bits
uint32_t shiftl256_fullword(uint256 a, uint256 b)
{
uint32_t carry = a[7];
for(int i=6;i>=0;i--) { b[i+1] = a[i]; }
b[0] = 0;
return carry;
}
//------------------------------------------------------------------------------
// addition modulo 2^256 (returns the carry)
uint32_t add256(uint256 a, uint256 b, uint256 c)
{
uint64_t carry = 0;
for(int i=0;i<8;i++)
{
uint64_t tmp = (uint64_t)(a[i]) + (uint64_t)(b[i]) + carry;
carry = tmp >> 32;
c[i] = tmp;
}
return carry;
}
// neg(x) = not(x)+1;
void neg256(uint256 a, uint256 b)
{
uint64_t carry = 1;
for(int i=0;i<8;i++)
{
uint64_t tmp = (uint64_t)(~a[i]) + carry;
carry = tmp >> 32;
b[i] = tmp;
}
}
// subtraction mod 2^256
uint32_t sub256(uint256 a, uint256 b, uint256 c)
{
uint64_t carry = 1;
for(int i=0;i<8;i++)
{
uint64_t tmp = (uint64_t)(a[i]) + (uint64_t)(~b[i]) + carry;
carry = tmp >> 32;
c[i] = tmp;
}
return carry;
}
// multiplication mod 2^256
void mul256(uint256 a, uint256 b, uint256 c)
{
uint256 tmp,acc;
zero256(acc);
for(int i=7;i>=0;i--)
{
if (i<7) { shiftl256_fullword(acc,acc); }
scale256(a,b[i],tmp);
add256(acc,tmp,acc);
}
copy256(acc,c); // because c can coincide with a or b
}
// multiplication of a 256-bit number with a 32-bit number (returns the carry)
uint32_t scale256(uint256 a, uint32_t b32, uint256 c)
{
uint64_t carry = 0;
uint64_t b64 = b32;
for(int i=0;i<8;i++)
{
uint64_t tmp = (uint64_t)(a[i])*b64 + carry;
carry = tmp >> 32;
c[i] = tmp;
}
return carry;
}
// a<b
int lessThan256(uint256 a, uint256 b)
{
for(int i=7;i>=0;i--)
{
if (a[i] < b[i]) { return 1; }
if (a[i] > b[i]) { return 0; }
}
// they are equal
return 0;
}
// a<=b
int lessOrEqual256(uint256 a, uint256 b)
{
for(int i=7;i>=0;i--)
{
if (a[i] < b[i]) { return 1; }
if (a[i] > b[i]) { return 0; }
}
// they are equal
return 1;
}
// a==b
int equals256(uint256 a, uint256 b)
{
for(int i=7;i>=0;i--)
{
if (a[i] != b[i]) { return 0; }
}
// they are equal
return 1;
}
//------------------------------------------------------------------------------
// index of the highest set bit = ceil(log2(x+1))
// log2(0) = 0 // 00000
// log2(1) = 1 // 00001
// log2(2) = 2 // 00010
// log2(3) = 2 // 00011
// log2(4) = 3 // 00100
// log2(2^256-1) = 256
int highestSetBit256(uint256 a)
{
int n = 0;
for (int i=0;i<8;i++)
{
int n0 = i<<5; // i*32
uint32_t w = a[i];
for (int k=0;k<32;k++)
{ if (w==0) { break; }
w = (w >> 1);
n = n0 + k + 1;
}
}
return n;
}
// a==0
int equalsZero256(uint256 a)
{ for(int i=0;i<8;i++) { if (a[i]) { return 0; } }
return 1;
}
// a==1
int equalsOne256(uint256 a)
{ if (a[0]!=1) { return 0; }
for(int i=1;i<8;i++) { if (a[i]) { return 0; } }
return 1;
}
//------------------------------------------------------------------------------