#include "mode.h"
/*+ Режим компиляции SELF_TEST/TEST_COMPARE +*/
#include "../self_test/ports.h" /*+ Интерфейс
с ОС, символы: __inline__, _POSIX_, __cdecl +*/
#ifdef SELF_TEST
#include "../self_test/self_test.h" /*+ pack, packbuf, hand, их
типы, процедуры печати +*/
#include "../self_test/statistic.h" /*+ test_verojat +*/
#endif /* SELF_TEST */
/*+++ Внешний интерфейс +++*/
/*++ Процедуры ++*/
void add_randomize(const void *buf, size_t len);
/*+ Добавить "случайности" из независимого источника +*/
void add_randomize_time(void);
/*+ Добавить "случайности" из сиcтемного таймера +*/
void rand_buf(unsigned int id, void *buf, size_t len); /*+ Выработать
len байт псевдослучайных чисел +*/
void Serge3_shuffle(void);
/*+ Тасование и раздача +*/
/*+++ Внутрение процедуры +++*/
static unsigned int __inline__ _substitute(unsigned int d);
/*+ Применение узла замены +*/
static void __inline__ _crypt(const unsigned int key[], unsigned
int *d1, unsigned int *d2); /*+ Простая замена +*/
static void __inline__ _gammald(unsigned int id, unsigned int a1,
unsigned int a2); /*+ Инициализация генератора гаммы +*/
static void __inline__ _gamma(unsigned int id, unsigned int *d1,
unsigned int *d2); /*+ Выработка гаммы +*/
/*+++
* Узел замены (SBOX) и ключ KEY[0] получены с датчика BSD4.4
Lite (gcc)
* srand(19651228);
* KEY[1] получен с датчика Microsoft VC 6.0 srand(19651228);
+++*/
const unsigned char SBOX[8][16] = { /*+ Узел замены 512 бит +*/
{ 0x5,0xe,0x1,0xe,0x3,0xe,0x0,0xc,0x0,0xd,0x1,0xc,0xe,0x8,0x6,0xf
},
{ 0x6,0x0,0x6,0x0,0x3,0x8,0x4,0x6,0x6,0x7,0xa,0x3,0xd,0x5,0x4,0xb
},
{ 0x7,0x2,0x1,0xd,0xd,0x6,0x8,0xa,0x8,0x9,0xa,0x8,0x4,0x7,0xe,0xf
},
{ 0x0,0x9,0xd,0xd,0xc,0x0,0xc,0xb,0xe,0xf,0xf,0x9,0x2,0x2,0xf,0xe
},
{ 0x1,0xd,0x3,0xa,0x6,0x2,0x3,0xb,0x5,0xf,0x9,0x8,0xe,0x1,0xc,0x0
},
{ 0xe,0x0,0xd,0x8,0x3,0xc,0x0,0x7,0x5,0x8,0xc,0xb,0xa,0x3,0x4,0x0
},
{ 0x1,0x2,0xf,0x6,0x5,0x3,0x8,0x3,0xe,0xb,0x7,0x3,0xd,0x6,0x9,0x0
},
{ 0xd,0x5,0x6,0x2,0x4,0x8,0x8,0x8,0x5,0x2,0xe,0x2,0xa,0xd,0xd,0x0
}
};
const unsigned int KEY[2][8] = {
/*+ Ключи по 256 бит +*/
{ 0x1e2a69a4, 0x251730f6, 0x426dea0c,
0xb713fee5,
0xf6f5349f, 0xeaa2ddac,
0xa4161aad, 0xfd6352c8 },
{ 0x284b9cca, 0x4d5575c5, 0xf55c7670,
0x91e075bb,
0x54cd9673, 0x129bff1d,
0xc8374d8b, 0x557fd28a }
};
/*+++
* Vipul Ved Prakash</a>, 1997-98. All Rights Reserved.
*
* Трансляция с Perl http://www.vipul.net/gost/software/Gost.pm
+++*/
/*++
* Подстановка
++*/
static unsigned int __inline__ _substitute(unsigned int d)
{
unsigned int retur = 0;
unsigned int i;
for (i = 0; i < 8; i++) {
retur |= (SBOX[i][(d >> (i*4))&0xf]&0xf) <<
(i*4);
}
return ((retur << 11)&0xfffff800) | ((retur >>
21)&0x7ff);
}
/*++
* Шифрование в режиме простой замены
++*/
static void __inline__ _crypt(const unsigned int key[],
unsigned int *d1, unsigned int *d2)
{
int i, j;
for (i = 1; i <= 32; i++) {
if ((j = (i%8) - 1) == -1) {
j = 7;
}
if (i >= 25) {
j = 32 - i;
}
if ((i%2) == 1) {
*d2 ^= _substitute(*d1 + key[j]);
} else {
*d1 ^= _substitute(*d2 + key[j]);
}
}
i = *d1;
*d1 = *d2;
*d2 = i;
}
/*+++
* Версия 0.991 от 29.01.99. (c) 1998-1999 Андрей Винокуров.
* http://www.halyava.ru/crypto/frame.htm
*
* Трансляция с ассемблера http://www.chat.ru/~avin/gost_s32.zip
+++*/
/*++
* Генерация гаммы (датчик псевдослучайных чисел)
++*/
#define C2 (0x01010101)
#define C1 (0x01010104)
/*++
* Внутреннее состояние генератора.
* При переносе в многопоточную среду лучше это состояние
разделять
* между потоками блокируя доступ семафорами.
++*/
static struct
{
unsigned int d3;
unsigned int d4;
} gamma_sts[2] = {
{ 0, 0 },
{ 0, 0 }
};
static struct
{
union
{
unsigned int d[2];
unsigned char b[2*sizeof(unsigned int)];
} buf;
size_t nbyte;
} rand_sts[2] = {
{{{0, 0}}, 0},
{{{0, 0}}, 0}
};
/*+
* Инициализация генератора гаммы
*
* Для накопления "случайности" входные значения должны отличаться
* хотя бы одним битом, тогда результаты _crypt будут отличаться,
* в среднем, 32 битами
+*/
static void __inline__ _gammald(unsigned int id,
unsigned int a1, unsigned int a2)
{
unsigned int d1 = a1;
unsigned int d2 = a2;
id &= 1;
_crypt(KEY[id], &d1, &d2);
gamma_sts[id].d3 ^= d1;
gamma_sts[id].d4 ^= d2;
}
/*+ Выработка гаммы +*/
static void __inline__ _gamma(unsigned int id,
unsigned int *d1, unsigned int *d2)
{
unsigned int eax;
id &= 1;
gamma_sts[id].d3 = gamma_sts[id].d3 + C2;
eax = gamma_sts[id].d4 + C1;
gamma_sts[id].d4 = eax + (eax < gamma_sts[id].d4 || eax
< C1);
*d1 = gamma_sts[id].d3;
*d2 = gamma_sts[id].d4;
_crypt(KEY[id], d1, d2);
}
/*+ Добавить "случайности" из независимого источника +*/
void add_randomize(const void *buf, size_t len)
{
unsigned int d[2] = { 0, 0 };
int i = 0;
int j = 0;
static unsigned int last_d[2] = { -1, -1 };
while (len >= sizeof(d[0])) {
d[i] ^= *(unsigned int *)buf;
((const unsigned char *)buf) += sizeof(d[0]);
len -= sizeof(d[0]);
i ^= 1;
}
/* len >= 0 && len < sizeof(d[0]) */
while (len > 0) {
((unsigned char *)&d[i])[j] ^= ((const unsigned char
*)buf)[j];
len--;
j++;
}
/*+ Одинаковые значения анигилируют +*/
if (d[0] != last_d[0] || d[1] != last_d[1]) {
last_d[0] = d[0];
last_d[1] = d[1];
_gammald(0, d[0], d[1]);
_gammald(1, d[0], d[1]);
}
}
#ifdef PENTIUM
/*++
* Возвращает кол-во тактов процессора с момента его инициализации
++*/
static int pentium_microtime()
{
#ifdef WIN32
__asm {
rdtsc
}
#elif defined(__FreeBSD__)
asm(".byte 0x0f, 0x31" : : );
#endif
/*+ Возвращаемое значение уже в EAX +*/
}
#endif /* PENTIUM */
/*+ Добавить "случайности" из системного таймера +*/
void add_randomize_time()
{
#ifdef PENTIUM
struct {
int
ptime;
time_t time;
} rb;
rb.time = time(NULL);
rb.ptime = pentium_microtime();
add_randomize(&rb, sizeof(rb));
#else
struct timeb tb;
(void)ftime(&tb);
add_randomize(&tb, sizeof(tb));
#endif /* PENTIUM */
}
/*+ Выработать len байт псевдослучайных чисел +*/
void rand_buf(unsigned int id, void *buf, size_t len)
{
if (id&~1) {
fprintf(stderr, __FILE__":
rand_buf: %d: bad call\n", __LINE__);
}
id &= 1;
while (len >= rand_sts[id].nbyte || rand_sts[id].nbyte
<= 0) {
if (rand_sts[id].nbyte
> 0) {
memcpy(buf,
&rand_sts[id].buf.b[sizeof(rand_sts[id].buf.d)-rand_sts[id].nbyte],
rand_sts[id].nbyte);
((unsigned
char *)buf) += rand_sts[id].nbyte;
len
-= rand_sts[id].nbyte;
rand_sts[id].nbyte
= 0;
}
_gamma(id, &rand_sts[id].buf.d[0],
&rand_sts[id].buf.d[1]);
rand_sts[id].nbyte =
sizeof(rand_sts[id].buf.d);
}
if (len > 0) {
memcpy(buf,
&rand_sts[id].buf.b[sizeof(rand_sts[id].buf.d)-rand_sts[id].nbyte],
len);
((unsigned char *)buf) +=
len;
rand_sts[id].nbyte -= len;
len = 0;
}
}
/*++
* Собствено тасование и раздача
++*/
void Serge3_shuffle() {
int id, j, k;
unsigned short rbuf[31];
#ifndef SELF_TEST /* Тест сам разберётся с рандомизацией */
add_randomize_time();
#endif /* SELF_TEST */
for (id = 0; id < 2; id++) {
rand_buf(id, rbuf, sizeof(rbuf));
/*+
* Алгоритм тасования.
* Обоснование (очевидное) см.
* [Д.Кнут Искусство програмирования
т.2, 3.4.2.Р, стр. 155]
+*/
for (j = 32-1; j > 0; j--) {
/*+
* Вырабатываем сл. число 0..i-1
с точностью 0.05%
+*/
k = (rbuf[j-1]*j) >> (sizeof(rbuf[0])*8);
packbuf[0] = pack[k]; /* Лучше бы
локальную переменную, да не известно
какого типа :( */
pack[k] = pack[j];
pack[j] = packbuf[0];
}
}
for (k = 0; k < 3; k++) {
hand[k].cards = 10;
for (j = 0; j < 10; j++) {
hand[k].card[j]
= pack[k*10+j];
}
#ifndef SELF_TEST
sort_hand = hand + k;
hsort(sort_hand->cards, less_card, swap_card);
#else
/* Что-то лениво имитировать hsort, отойдём
ANSI qsort-ом */
qsort(hand[k].card, hand[k].cards, sizeof(hand[k].card[0]),
less_cardp);
#endif /* SELF_TEST */
}
}
#ifdef SELF_TEST
#define CHECK(a,va,b,vb) { \
printf(__FILE__ ": %d: " __FUNCTION__ ": " #a " = 0x%08x,
" #b " = 0x%08x - %s\n",\
__LINE__, (a), (b),
\
((a) == (va) &&
(b) == (vb) ? "Ok" : "Fail")); \
if (!((a) == (va) && (b) == (vb))) { \
(void)getchar(); \
} \
}
int __cdecl main(int ac, char *av)
{
unsigned int d1, d2;
int i;
unsigned char obuf[16];
unsigned int ibuf[4] = {
0x60387f34, 0x27e0cad4, 0x56df1cca, 0xf44ab372
};
unsigned char cbuf[16][2] = {
{ 0x3f, 0x3f },
{ 0xb2, 0x12 },
{ 0x87, 0x70 },
{ 0x0a, 0x36 },
{ 0xa1, 0x2b },
{ 0x33, 0x3f },
{ 0xce, 0x73 },
{ 0x14, 0x88 },
{ 0xb6, 0x1d },
{ 0x86, 0x3a },
{ 0x21, 0x1d },
{ 0xac, 0x7f },
{ 0x95, 0x6a },
{ 0x30, 0xfe },
{ 0x46, 0x9b },
{ 0xb9, 0xd3 }
};
d1 = 0xe83a3536;
d2 = 0x462e27e5;
_crypt(KEY[0], &d1, &d2);
CHECK(d1, 0, d2, 0);
d1 = 0;
d2 = 0;
_crypt(KEY[0], &d1, &d2);
CHECK(d1, 0x5bf6b4e0, d2, 0xa5621da9);
d1 = 0xdc27ba9f;
d2 = 0xd80f7321;
_crypt(KEY[0], &d1, &d2);
CHECK(d1, 0x5d4d726a, d2, 0xf44ab372);
_gammald(0, 0xe83a3536, 0x462e27e5);
CHECK(gamma_sts[0].d3, 0, gamma_sts[0].d4, 0);
_gammald(0, 0, 0);
CHECK(gamma_sts[0].d3, 0x5bf6b4e0, gamma_sts[0].d4, 0xa5621da9);
_gammald(0, 0xdc27ba9f, 0xd80f7321);
CHECK(gamma_sts[0].d3, 0x06bbc68a, gamma_sts[0].d4, 0x5128aedb);
_gammald(0, 0xe83a3536, 0x462e27e5);
_gamma(0, &d1, &d2);
CHECK(d1, 0xafbc2eb3, d2, 0xdb047b76);
for (i = 0; i < 257; i++) {
_gamma(0, &d1, &d2);
}
CHECK(d1, 0xaa942634, d2, 0xaa934df4);
_gammald(0, 31425926, 271828182);
_gamma(0, &d1, &d2);
CHECK(d1, 0xa35c94d6, d2, 0xc8e1bdf7);
for (i = 0; i < 257; i++) {
_gamma(0, &d1, &d2);
}
CHECK(d1, 0xccb789fe, d2, 0xb6e39b0d);
_gammald(0, 0, 0);
_gamma(0, &d1, &d2);
CHECK(d1, 0xecc56cd8, d2, 0x9c89778e);
for (i = 0; i < 257; i++) {
_gamma(0, &d1, &d2);
}
CHECK(d1, 0x9d133ec4, d2, 0xd65d0c27);
_gammald(0, 31425926, 271828182);
_gamma(0, &d1, &d2);
CHECK(d1, 0xb8d49867, d2, 0x6a1ccc05);
for (i = 0; i < 257; i++) {
_gamma(0, &d1, &d2);
}
CHECK(d1, 0x60387f34, d2, 0xa80f37fa);
_gammald(0, 0xdc27ba9f, 0xd80f7321);
_gamma(0, &d1, &d2);
CHECK(d1, 0x34035e34, d2, 0x27e0cad4);
for (i = 0; i < 257; i++) {
_gamma(0, &d1, &d2);
}
CHECK(d1, 0x1842a6fc, d2, 0x5554f68f);
_gammald(0, 31425926, 271828182);
_gamma(0, &d1, &d2);
CHECK(d1, 0x19e8d7f1, d2, 0xff802dd2);
for (i = 0; i < 257; i++) {
_gamma(0, &d1, &d2);
}
CHECK(d1, 0x429511a3, d2, 0x56df1cca);
for (i = 0; i < sizeof(ibuf) && i < sizeof(obuf);
i++) {
add_randomize(ibuf, i+1);
rand_buf(0, obuf, i+1);
CHECK(obuf[0], cbuf[i][0], obuf[i], cbuf[i][1]);
}
init_pack();
for (i = 0; i < 32; i++) {
Serge3_shuffle();
}
CHECK(((int *)pack)[0], 0x0603, ((int *)pack)[(32/2) - 1],
0x0101);
#if 0
for (i = 0; i < 257; i++) {
add_randomize_time();
rand_buf(&d1, sizeof(d1));
printf(__FILE__ ": " __FUNCTION__ ": %d: 0x%08x\n", __LINE__,
d1);
}
#endif
#ifdef PENTIUM
printf("%d %d %d %d\n", pentium_microtime(),
pentium_microtime(), pentium_microtime(),
pentium_microtime());
getchar();
printf("%d %d %d %d\n", pentium_microtime(),
pentium_microtime(), pentium_microtime(),
pentium_microtime());
getchar();
#endif /* PENTIUM */
/*+
* Опечатки проверили. Теперь немного статистики
+*/
test_verojat(NULL, Serge3_shuffle, "GOST1");
getchar();
return 0;
}
#endif /* SELF_TEST */
Эта страница создана с помощью: Netscape Navigator Gold, Emacs, XVScan и GIMP.