编写ElGamal签名程序
【问题描述】
ElGamal签名是一种数字签名算法,它基于ElGamal加密算法的数学原理。ElGamal签名是一种公钥密码学技术,用于验证数据的完整性和真实性,确保数据在传输或存储过程中没有被篡改。
ElGamal签名的生成和验证过程, 密钥生成:
需要生成一对ElGamal的密钥对,包括私钥(d)和公钥(e1、p)。 签名生成:
计算e2 = e1^d mod p,其中e2是签名者使用私钥生成的一部分。 计算s1 = e1^r mod p,其中s1是签名者使用私钥生成的一部分。 计算s2 = (((m - d * s1) % (p-1)) * ModInv(r, p-1)) % (p-1),这是签名者使用私钥生成的一部分。 计算v1 = e1^m mod p,其中v1是签名者使用私钥生成的一部分。 计算a = e2^s1 mod p,以及b = s1^s2 mod p,这两个值也是签名者使用私钥生成的一部分。 计算v2 = (a * b) % p,这是签名者使用私钥生成的一部分。 签名验证:
验证者需要知道p、e1、r以及收到的签名值(s1, s2, v1, v2)。 使用公开的参数p、e1、r和收到的签名值计算v1,即v1 = e1^m mod p。 使用ModInv函数计算s2的模逆。 使用计算的模逆和公开的参数计算s1,即s1 = e1^r mod p。 使用公开的参数p、e1、s1、s2、v1和v2来计算a和b。 验证签名的有效性:如果v2等于v1,则签名有效,否则签名无效。
本步骤要求实验者实现一个名为elgamalsign.cpp的C++程序,要求输入代表p, e1, d, m和r的数字,要求输出v1
#./elgamalsign
3119
2
127
3000
107
704
【输入形式】
p
e1
d
m
r
【输出形式】
v1
【样例输入】
3119
2
127
3000
107
【样例输出】
704
def modinv(a, m):
g, x, y = egcd(a, m)
if g != 1:
raise Exception('')
else:
return x % m
def egcd(a, b):
if a == 0:
return b, 0, 1
else:
g, y, x = egcd(b % a, a)
return g, x - (b // a) * y, y
def elgamal_sign(p, e1, d, m, r):
v1 = pow(e1, m, p)
return v1
p = int(input())
e1 = int(input())
d = int(input())
m = int(input())
r = int(input())
v1 = elgamal_sign(p, e1, d, m, r)
print( v1)
编写ElGamal解密程序
【问题描述】
ElGamal加密算法包含两个主要部分:加密和解密。以下是ElGamal加密算法的基本步骤:
密钥生成:
随机选择一个大素数p。 随机选择一个小于p的整数g,称为生成元。 随机选择一个私钥x,它是一个小于p-1的整数。 计算公钥y = g^x mod p,其中^表示乘方运算,mod表示取模运算。 公开p、g和y,但保持x秘密。 加密:
随机选择一个临时私钥k,它是一个小于p-1的整数。 计算临时公钥C1 = g^k mod p。 计算共享密钥s = y^k mod p。 将消息m与共享密钥s进行异或运算,得到密文C2。 密文为(C1, C2),发送给接收者。 解密:
接收到密文(C1, C2)。 使用私钥x计算共享密钥s = C1^x mod p。 将密文C2除以共享密钥s,得到原始消息m。
在给定p=307,x=67,g=2的前提下,给定C1和C2(root目录下的cipher1.txt和cipher2.txt),要求编写/root/目录下的解密程序elgamaldec,要求还原出明文。
#cat cipher1.txt
125 77 3 163 237 205 216 167 162 51 289 2 205 155 17
#cat cipher2.txt
87 114 243 46 59 303 63 151 198 72 93 14 303 143 170
#./elgamaldec
test.educg.net
【输入形式】
cipher1.txt文件 cipher2.txt文件
【输出形式】
解密字符串
【样例输入】
#cat cipher1.txt
125 77 3 163 237 205 216 167 162 51 289 2 205 155 17
#cat cipher2.txt
87 114 243 46 59 303 63 151 198 72 93 14 303 143 170
【样例输出】
test.educg.net
#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
#include <cmath>
using namespace std;
long long modinv(long long a, long long m)
{
long long m0 = m, t, q;
long long x0 = 0, x1 = 1;
if (m == 1)
return 0;
while (a > 1)
{
q = a / m;
t = m;
m = a % m, a = t;
t = x0;
x0 = x1 - q * x0;
x1 = t;
}
if (x1 < 0)
x1 += m0;
return x1;
}
vector<int> readCipher(const string &filename)
{
vector<int> cipher;
ifstream file(filename);
string line;
if (file.is_open())
{
while (getline(file, line))
{
stringstream ss(line);
int num;
while (ss >> num)
{
cipher.push_back(num);
}
}
file.close();
}
return cipher;
}
long long modPow(long long base, long long exp, long long mod) {
long long result = 1;
while (exp > 0) {
if (exp % 2 == 1) {
result = (result * base) % mod;
}
base = (base * base) % mod;
exp /= 2;
}
return result;
}
string elgamalDecrypt(const vector<int> &c1, const vector<int> &c2, int p, int x) {
string decrypted;
for (size_t i = 0; i < c1.size(); ++i) {
long long s = modPow(c1[i], x, p);
long long inverse_s = modinv(s, p);
long long m = (c2[i] * inverse_s) % p;
decrypted.push_back(static_cast<char>(m));
}
return decrypted;
}
int main()
{
const int p = 307;
const int x = 67;
vector<int> c1 = readCipher("cipher1.txt");
vector<int> c2 = readCipher("cipher2.txt");
string decrypted = elgamalDecrypt(c1, c2, p, x);
cout << decrypted << endl;
return 0;
}
大数运算基础
【问题描述】
1、大数运算
由于编程语言提供的基本数值数据类型表示的数值范围有限,不能满足较大规模的高精度数值计算,因此需要利用其他方法实现高精度数值的计算,于是产生了大数运算。大数运算主要有加、减、乘等方法。大数运算是现代密码学的重要基础。
既然在计算机中无法直接表示,那么大数到底如何进行运算呢,学习过数据结构的都知道线性表(数组),将大数拆分然后存储在线性表中,不失为一个很好的办法。
利用数组连续性,将大数每一位上的数字单独取出放入对应的数组格中,然后再对每一位做单独的加减乘运算。形象的说,类似于小学学习加减乘所列的式子。
2、本作业需要完成的任务
本作业需要完成的任务是利用bignum_init(大数初始化),bignum_from_int(把整数转换成大数)、_lshift_word(大数左移)、bignum_add(大数加)等补充函数bignum_mul,以完成大数乘积运算。
【输入形式】
十六进制表示的第一个乘数(第二个乘数在程序中默认给出)
【输出形式】
十六进制表示的乘积
【样例输入】
1f233b47
【样例输出】
7b4f4a5794944bed1c4d399
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
/* This macro defines the word size in bytes of the array that constitues the big-number data structure. */
#ifndef WORD_SIZE
#define WORD_SIZE 4
#endif
/* Size of big-numbers in bytes */
#define BN_ARRAY_SIZE (128 / WORD_SIZE)
/* Here comes the compile-time specialization for how large the underlying array size should be. */
/* The choices are 1, 2 and 4 bytes in size with uint32, uint64 for WORD_SIZE==4, as temporary. */
#ifndef WORD_SIZE
#error Must define WORD_SIZE to be 1, 2, 4
#elif (WORD_SIZE == 1)
/* Data type of array in structure */
#define DTYPE uint8_t
/* bitmask for getting MSB */
#define DTYPE_MSB ((DTYPE_TMP)(0x80))
/* Data-type larger than DTYPE, for holding intermediate results of calculations */
#define DTYPE_TMP uint32_t
/* sprintf format string */
#define SPRINTF_FORMAT_STR "%.02x"
#define SSCANF_FORMAT_STR "%2hhx"
/* Max value of integer type */
#define MAX_VAL ((DTYPE_TMP)0xFF)
#elif (WORD_SIZE == 2)
#define DTYPE uint16_t
#define DTYPE_TMP uint32_t
#define DTYPE_MSB ((DTYPE_TMP)(0x8000))
#define SPRINTF_FORMAT_STR "%.04x"
#define SSCANF_FORMAT_STR "%4hx"
#define MAX_VAL ((DTYPE_TMP)0xFFFF)
#elif (WORD_SIZE == 4)
#define DTYPE uint32_t
#define DTYPE_TMP uint64_t
#define DTYPE_MSB ((DTYPE_TMP)(0x80000000))
#define SPRINTF_FORMAT_STR "%.08x"
#define SSCANF_FORMAT_STR "%8x"
#define MAX_VAL ((DTYPE_TMP)0xFFFFFFFF)
#endif
#ifndef DTYPE
#error DTYPE must be defined to uint8_t, uint16_t uint32_t or whatever
#endif
/* Custom assert macro - easy to disable */
#define require(p, msg) assert(p && msg)
/* Data-holding structure: array of DTYPEs */
struct bn
{
DTYPE array[BN_ARRAY_SIZE];
};
/* Tokens returned by bignum_cmp() for value comparison */
enum { SMALLER = -1, EQUAL = 0, LARGER = 1 };
void bignum_init(struct bn* n);
void bignum_from_int(struct bn* n, DTYPE_TMP i);
int bignum_to_int(struct bn* n);
void bignum_from_string(struct bn* n, char* str, int nbytes);
void bignum_to_string(struct bn* n, char* str, int maxsize);
/* Basic arithmetic operations: */
void bignum_add(struct bn* a, struct bn* b, struct bn* c); /* c = a + b */
void bignum_sub(struct bn* a, struct bn* b, struct bn* c); /* c = a - b */
void bignum_mul(struct bn* a, struct bn* b, struct bn* c); /* c = a * b */
void bignum_div(struct bn* a, struct bn* b, struct bn* c); /* c = a / b */
void bignum_mod(struct bn* a, struct bn* b, struct bn* c); /* c = a % b */
void bignum_divmod(struct bn* a, struct bn* b, struct bn* c, struct bn* d); /* c = a/b, d = a%b */
/* Bitwise operations: */
void bignum_and(struct bn* a, struct bn* b, struct bn* c); /* c = a & b */
void bignum_or(struct bn* a, struct bn* b, struct bn* c); /* c = a | b */
void bignum_xor(struct bn* a, struct bn* b, struct bn* c); /* c = a ^ b */
void bignum_lshift(struct bn* a, struct bn* b, int nbits); /* b = a << nbits */
void bignum_rshift(struct bn* a, struct bn* b, int nbits); /* b = a >> nbits */
/* Special operators and comparison */
int bignum_cmp(struct bn* a, struct bn* b); /* Compare: returns LARGER, EQUAL or SMALLER */
int bignum_is_zero(struct bn* n); /* For comparison with zero */
void bignum_inc(struct bn* n); /* Increment: add one to n */
void bignum_dec(struct bn* n); /* Decrement: subtract one from n */
void bignum_pow(struct bn* a, struct bn* b, struct bn* c); /* Calculate a^b -- e.g. 2^10 => 1024 */
void bignum_isqrt(struct bn* a, struct bn* b); /* Integer square root -- e.g. isqrt(5) => 2*/
void bignum_assign(struct bn* dst, struct bn* src); /* Copy src into dst -- dst := src */
/* Functions for shifting number in-place. */
static void _lshift_one_bit(struct bn* a);
static void _rshift_one_bit(struct bn* a);
static void _lshift_word(struct bn* a, int nwords);
static void _rshift_word(struct bn* a, int nwords);
/* Public / Exported functions. */
void bignum_init(struct bn* n)
{
require(n, "n is null");
int i;
for (i = 0; i < BN_ARRAY_SIZE; ++i)
{
n->array[i] = 0;
}
}
void bignum_from_int(struct bn* n, DTYPE_TMP i)
{
require(n, "n is null");
bignum_init(n);
/* Endianness issue if machine is not little-endian? */
#ifdef WORD_SIZE
#if (WORD_SIZE == 1)
n->array[0] = (i & 0x000000ff);
n->array[1] = (i & 0x0000ff00) >> 8;
n->array[2] = (i & 0x00ff0000) >> 16;
n->array[3] = (i & 0xff000000) >> 24;
#elif (WORD_SIZE == 2)
n->array[0] = (i & 0x0000ffff);
n->array[1] = (i & 0xffff0000) >> 16;
#elif (WORD_SIZE == 4)
n->array[0] = i;
DTYPE_TMP num_32 = 32;
DTYPE_TMP tmp = i >> num_32; /* bit-shift with U64 operands to force 64-bit results */
n->array[1] = tmp;
#endif
#endif
}
int bignum_to_int(struct bn* n)
{
require(n, "n is null");
int ret = 0;
/* Endianness issue if machine is not little-endian? */
#if (WORD_SIZE == 1)
ret += n->array[0];
ret += n->array[1] << 8;
ret += n->array[2] << 16;
ret += n->array[3] << 24;
#elif (WORD_SIZE == 2)
ret += n->array[0];
ret += n->array[1] << 16;
#elif (WORD_SIZE == 4)
ret += n->array[0];
#endif
return ret;
}
void bignum_from_string(struct bn* n, char* str, int nbytes)
{
require(n, "n is null");
require(str, "str is null");
require(nbytes > 0, "nbytes must be positive");
require((nbytes & 1) == 0, "string format must be in hex -> equal number of bytes");
require((nbytes % (sizeof(DTYPE) * 2)) == 0, "string length must be a multiple of (sizeof(DTYPE) * 2) characters");
bignum_init(n);
DTYPE tmp; /* DTYPE is defined in bn.h - uint{8,16,32,64}_t */
int i = nbytes - (2 * WORD_SIZE); /* index into string */
int j = 0; /* index into array */
/* reading last hex-byte "MSB" from string first -> big endian */
/* MSB ~= most significant byte / block ? :) */
while (i >= 0)
{
tmp = 0;
sscanf(&str[i], SSCANF_FORMAT_STR, &tmp);
n->array[j] = tmp;
i -= (2 * WORD_SIZE); /* step WORD_SIZE hex-byte(s) back in the string. */
j += 1; /* step one element forward in the array. */
}
}
void bignum_to_string(struct bn* n, char* str, int nbytes)
{
require(n, "n is null");
require(str, "str is null");
require(nbytes > 0, "nbytes must be positive");
require((nbytes & 1) == 0, "string format must be in hex -> equal number of bytes");
int j = BN_ARRAY_SIZE - 1; /* index into array - reading "MSB" first -> big-endian */
int i = 0; /* index into string representation. */
/* reading last array-element "MSB" first -> big endian */
while ((j >= 0) && (nbytes > (i + 1)))
{
sprintf(&str[i], SPRINTF_FORMAT_STR, n->array[j]);
i += (2 * WORD_SIZE); /* step WORD_SIZE hex-byte(s) forward in the string. */
j -= 1; /* step one element back in the array. */
}
/* Count leading zeros: */
j = 0;
while (str[j] == '0')
{
j += 1;
}
/* Move string j places ahead, effectively skipping leading zeros */
for (i = 0; i < (nbytes - j); ++i)
{
str[i] = str[i + j];
}
/* Zero-terminate string */
str[i] = 0;
}
void bignum_dec(struct bn* n)
{
require(n, "n is null");
DTYPE tmp; /* copy of n */
DTYPE res;
int i;
for (i = 0; i < BN_ARRAY_SIZE; ++i)
{
tmp = n->array[i];
res = tmp - 1;
n->array[i] = res;
if (!(res > tmp))
{
break;
}
}
}
void bignum_inc(struct bn* n)
{
require(n, "n is null");
DTYPE res;
DTYPE_TMP tmp; /* copy of n */
int i;
for (i = 0; i < BN_ARRAY_SIZE; ++i)
{
tmp = n->array[i];
res = tmp + 1;
n->array[i] = res;
if (res > tmp)
{
break;
}
}
}
void bignum_add(struct bn* a, struct bn* b, struct bn* c)
{
require(a, "a is null");
require(b, "b is null");
require(c, "c is null");
DTYPE_TMP tmp;
int carry = 0;
int i;
for (i = 0; i < BN_ARRAY_SIZE; ++i)
{
tmp = (DTYPE_TMP)a->array[i] + b->array[i] + carry;
carry = (tmp > MAX_VAL);
c->array[i] = (tmp & MAX_VAL);
}
}
void bignum_sub(struct bn* a, struct bn* b, struct bn* c)
{
require(a, "a is null");
require(b, "b is null");
require(c, "c is null");
DTYPE_TMP res;
DTYPE_TMP tmp1;
DTYPE_TMP tmp2;
int borrow = 0;
int i;
for (i = 0; i < BN_ARRAY_SIZE; ++i)
{
tmp1 = (DTYPE_TMP)a->array[i] + (MAX_VAL + 1); /* + number_base */
tmp2 = (DTYPE_TMP)b->array[i] + borrow;;
res = (tmp1 - tmp2);
c->array[i] = (DTYPE)(res & MAX_VAL); /* "modulo number_base" == "% (number_base - 1)" if number_base is 2^N */
borrow = (res <= MAX_VAL);
}
}
void bignum_mul(struct bn* a, struct bn* b, struct bn* c)
{
require(a, "a is null");
require(b, "b is null");
require(c, "c is null");
struct bn row;
struct bn tmp;
int i, j;
bignum_init(c);
for (i = 0; i < BN_ARRAY_SIZE; ++i)
{
bignum_init(&row);
for (j = 0; j < BN_ARRAY_SIZE; ++j)
{
if (i + j < BN_ARRAY_SIZE)
{
bignum_init(&tmp);
DTYPE_TMP intermediate = (DTYPE_TMP)a->array[i] * (DTYPE_TMP)b->array[j];
bignum_from_int(&tmp, intermediate);
_lshift_word(&tmp, i+j);
bignum_add(&row, &tmp, &row);
}
}
bignum_add(c, &row, c);
}
}
void bignum_div(struct bn* a, struct bn* b, struct bn* c)
{
require(a, "a is null");
require(b, "b is null");
require(c, "c is null");
struct bn current;
struct bn denom;
struct bn tmp;
bignum_from_int(¤t, 1); // int current = 1;
bignum_assign(&denom, b); // denom = b
bignum_assign(&tmp, a); // tmp = a
const DTYPE_TMP half_max = 1 + (DTYPE_TMP)(MAX_VAL / 2);
bool overflow = false;
while (bignum_cmp(&denom, a) != LARGER) // while (denom <= a)
{
if (denom.array[BN_ARRAY_SIZE - 1] >= half_max)
{
overflow = true;
break;
}
_lshift_one_bit(¤t); // current <<= 1;
_lshift_one_bit(&denom); // denom <<= 1;
}
if (!overflow)
{
_rshift_one_bit(&denom); // denom >>= 1;
_rshift_one_bit(¤t); // current >>= 1;
}
bignum_init(c); // int answer = 0;
while (!bignum_is_zero(¤t)) // while (current != 0)
{
if (bignum_cmp(&tmp, &denom) != SMALLER) // if (dividend >= denom)
{
bignum_sub(&tmp, &denom, &tmp); // dividend -= denom;
bignum_or(c, ¤t, c); // answer |= current;
}
_rshift_one_bit(¤t); // current >>= 1;
_rshift_one_bit(&denom); // denom >>= 1;
} // return answer;
}
void bignum_lshift(struct bn* a, struct bn* b, int nbits)
{
require(a, "a is null");
require(b, "b is null");
require(nbits >= 0, "no negative shifts");
bignum_assign(b, a);
/* Handle shift in multiples of word-size */
const int nbits_pr_word = (WORD_SIZE * 8);
int nwords = nbits / nbits_pr_word;
if (nwords != 0)
{
_lshift_word(b, nwords);
nbits -= (nwords * nbits_pr_word);
}
if (nbits != 0)
{
int i;
for (i = (BN_ARRAY_SIZE - 1); i > 0; --i)
{
b->array[i] = (b->array[i] << nbits) | (b->array[i - 1] >> ((8 * WORD_SIZE) - nbits));
}
b->array[i] <<= nbits;
}
}
void bignum_rshift(struct bn* a, struct bn* b, int nbits)
{
require(a, "a is null");
require(b, "b is null");
require(nbits >= 0, "no negative shifts");
bignum_assign(b, a);
/* Handle shift in multiples of word-size */
const int nbits_pr_word = (WORD_SIZE * 8);
int nwords = nbits / nbits_pr_word;
if (nwords != 0)
{
_rshift_word(b, nwords);
nbits -= (nwords * nbits_pr_word);
}
if (nbits != 0)
{
int i;
for (i = 0; i < (BN_ARRAY_SIZE - 1); ++i)
{
b->array[i] = (b->array[i] >> nbits) | (b->array[i + 1] << ((8 * WORD_SIZE) - nbits));
}
b->array[i] >>= nbits;
}
}
void bignum_mod(struct bn* a, struct bn* b, struct bn* c)
{
/*
Take divmod and throw away div part
*/
require(a, "a is null");
require(b, "b is null");
require(c, "c is null");
struct bn tmp;
bignum_divmod(a,b,&tmp,c);
}
void bignum_divmod(struct bn* a, struct bn* b, struct bn* c, struct bn* d)
{
/*
Puts a%b in d
and a/b in c
mod(a,b) = a - ((a / b) * b)
example:
mod(8, 3) = 8 - ((8 / 3) * 3) = 2
*/
require(a, "a is null");
require(b, "b is null");
require(c, "c is null");
struct bn tmp;
/* c = (a / b) */
bignum_div(a, b, c);
/* tmp = (c * b) */
bignum_mul(c, b, &tmp);
/* c = a - tmp */
bignum_sub(a, &tmp, d);
}
void bignum_and(struct bn* a, struct bn* b, struct bn* c)
{
require(a, "a is null");
require(b, "b is null");
require(c, "c is null");
int i;
for (i = 0; i < BN_ARRAY_SIZE; ++i)
{
c->array[i] = (a->array[i] & b->array[i]);
}
}
void bignum_or(struct bn* a, struct bn* b, struct bn* c)
{
require(a, "a is null");
require(b, "b is null");
require(c, "c is null");
int i;
for (i = 0; i < BN_ARRAY_SIZE; ++i)
{
c->array[i] = (a->array[i] | b->array[i]);
}
}
void bignum_xor(struct bn* a, struct bn* b, struct bn* c)
{
require(a, "a is null");
require(b, "b is null");
require(c, "c is null");
int i;
for (i = 0; i < BN_ARRAY_SIZE; ++i)
{
c->array[i] = (a->array[i] ^ b->array[i]);
}
}
int bignum_cmp(struct bn* a, struct bn* b)
{
require(a, "a is null");
require(b, "b is null");
int i = BN_ARRAY_SIZE;
do
{
i -= 1; /* Decrement first, to start with last array element */
if (a->array[i] > b->array[i])
{
return LARGER;
}
else if (a->array[i] < b->array[i])
{
return SMALLER;
}
}
while (i != 0);
return EQUAL;
}
int bignum_is_zero(struct bn* n)
{
require(n, "n is null");
int i;
for (i = 0; i < BN_ARRAY_SIZE; ++i)
{
if (n->array[i])
{
return 0;
}
}
return 1;
}
void bignum_pow(struct bn* a, struct bn* b, struct bn* c)
{
require(a, "a is null");
require(b, "b is null");
require(c, "c is null");
struct bn tmp;
bignum_init(c);
if (bignum_cmp(b, c) == EQUAL)
{
/* Return 1 when exponent is 0 -- n^0 = 1 */
bignum_inc(c);
}
else
{
struct bn bcopy;
bignum_assign(&bcopy, b);
/* Copy a -> tmp */
bignum_assign(&tmp, a);
bignum_dec(&bcopy);
/* Begin summing products: */
while (!bignum_is_zero(&bcopy))
{
/* c = tmp * tmp */
bignum_mul(&tmp, a, c);
/* Decrement b by one */
bignum_dec(&bcopy);
bignum_assign(&tmp, c);
}
/* c = tmp */
bignum_assign(c, &tmp);
}
}
void bignum_isqrt(struct bn *a, struct bn* b)
{
require(a, "a is null");
require(b, "b is null");
struct bn low, high, mid, tmp;
bignum_init(&low);
bignum_assign(&high, a);
bignum_rshift(&high, &mid, 1);
bignum_inc(&mid);
while (bignum_cmp(&high, &low) > 0)
{
bignum_mul(&mid, &mid, &tmp);
if (bignum_cmp(&tmp, a) > 0)
{
bignum_assign(&high, &mid);
bignum_dec(&high);
}
else
{
bignum_assign(&low, &mid);
}
bignum_sub(&high,&low,&mid);
_rshift_one_bit(&mid);
bignum_add(&low,&mid,&mid);
bignum_inc(&mid);
}
bignum_assign(b,&low);
}
void bignum_assign(struct bn* dst, struct bn* src)
{
require(dst, "dst is null");
require(src, "src is null");
int i;
for (i = 0; i < BN_ARRAY_SIZE; ++i)
{
dst->array[i] = src->array[i];
}
}
/* Private / Static functions. */
static void _rshift_word(struct bn* a, int nwords)
{
/* Naive method: */
require(a, "a is null");
require(nwords >= 0, "no negative shifts");
int i;
if (nwords >= BN_ARRAY_SIZE)
{
for (i = 0; i < BN_ARRAY_SIZE; ++i)
{
a->array[i] = 0;
}
return;
}
for (i = 0; i < BN_ARRAY_SIZE - nwords; ++i)
{
a->array[i] = a->array[i + nwords];
}
for (; i < BN_ARRAY_SIZE; ++i)
{
a->array[i] = 0;
}
}
static void _lshift_word(struct bn* a, int nwords)
{
require(a, "a is null");
require(nwords >= 0, "no negative shifts");
int i;
/* Shift whole words */
for (i = (BN_ARRAY_SIZE - 1); i >= nwords; --i)
{
a->array[i] = a->array[i - nwords];
}
/* Zero pad shifted words. */
for (; i >= 0; --i)
{
a->array[i] = 0;
}
}
static void _lshift_one_bit(struct bn* a)
{
require(a, "a is null");
int i;
for (i = (BN_ARRAY_SIZE - 1); i > 0; --i)
{
a->array[i] = (a->array[i] << 1) | (a->array[i - 1] >> ((8 * WORD_SIZE) - 1));
}
a->array[0] <<= 1;
}
static void _rshift_one_bit(struct bn* a)
{
require(a, "a is null");
int i;
for (i = 0; i < (BN_ARRAY_SIZE - 1); ++i)
{
a->array[i] = (a->array[i] >> 1) | (a->array[i + 1] << ((8 * WORD_SIZE) - 1));
}
a->array[BN_ARRAY_SIZE - 1] >>= 1;
}
int main()
{
int i = 0;
char astring[2048];
char *bstring = "3f5cc8956a812a1f";
struct bn a;
struct bn b;
struct bn c;
char buf[8192];
scanf("%s", astring);
bignum_init(&a);
bignum_init(&b);
bignum_init(&c);
bignum_from_string(&a, astring, strlen(astring));
bignum_from_string(&b, bstring, strlen(bstring));
bignum_mul(&a, &b, &c);
bignum_to_string(&c, buf, sizeof(buf));
while (buf[i] != 0) {
printf("%c", buf[i]);
i += 1;
}
printf("\n");
}