540 lines
13 KiB
C
540 lines
13 KiB
C
/*
|
|
* GF-Complete: A Comprehensive Open Source Library for Galois Field Arithmetic
|
|
* James S. Plank, Ethan L. Miller, Kevin M. Greenan,
|
|
* Benjamin A. Arnold, John A. Burnum, Adam W. Disney, Allen C. McBride.
|
|
*
|
|
* gf_general.c
|
|
*
|
|
* This file has helper routines for doing basic GF operations with any
|
|
* legal value of w. The problem is that w <= 32, w=64 and w=128 all have
|
|
* different data types, which is a pain. The procedures in this file try
|
|
* to alleviate that pain. They are used in gf_unit and gf_time.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <getopt.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <assert.h>
|
|
|
|
#include "gf_complete.h"
|
|
#include "gf_int.h"
|
|
#include "gf_method.h"
|
|
#include "gf_rand.h"
|
|
#include "gf_general.h"
|
|
|
|
void gf_general_set_zero(gf_general_t *v, int w)
|
|
{
|
|
if (w <= 32) {
|
|
v->w32 = 0;
|
|
} else if (w <= 64) {
|
|
v->w64 = 0;
|
|
} else {
|
|
v->w128[0] = 0;
|
|
v->w128[1] = 0;
|
|
}
|
|
}
|
|
|
|
void gf_general_set_one(gf_general_t *v, int w)
|
|
{
|
|
if (w <= 32) {
|
|
v->w32 = 1;
|
|
} else if (w <= 64) {
|
|
v->w64 = 1;
|
|
} else {
|
|
v->w128[0] = 0;
|
|
v->w128[1] = 1;
|
|
}
|
|
}
|
|
|
|
void gf_general_set_two(gf_general_t *v, int w)
|
|
{
|
|
if (w <= 32) {
|
|
v->w32 = 2;
|
|
} else if (w <= 64) {
|
|
v->w64 = 2;
|
|
} else {
|
|
v->w128[0] = 0;
|
|
v->w128[1] = 2;
|
|
}
|
|
}
|
|
|
|
int gf_general_is_zero(gf_general_t *v, int w)
|
|
{
|
|
if (w <= 32) {
|
|
return (v->w32 == 0);
|
|
} else if (w <= 64) {
|
|
return (v->w64 == 0);
|
|
} else {
|
|
return (v->w128[0] == 0 && v->w128[1] == 0);
|
|
}
|
|
}
|
|
|
|
int gf_general_is_one(gf_general_t *v, int w)
|
|
{
|
|
if (w <= 32) {
|
|
return (v->w32 == 1);
|
|
} else if (w <= 64) {
|
|
return (v->w64 == 1);
|
|
} else {
|
|
return (v->w128[0] == 0 && v->w128[1] == 1);
|
|
}
|
|
}
|
|
|
|
void gf_general_set_random(gf_general_t *v, int w, int zero_ok)
|
|
{
|
|
if (w <= 32) {
|
|
v->w32 = MOA_Random_W(w, zero_ok);
|
|
} else if (w <= 64) {
|
|
while (1) {
|
|
v->w64 = MOA_Random_64();
|
|
if (v->w64 != 0 || zero_ok) return;
|
|
}
|
|
} else {
|
|
while (1) {
|
|
MOA_Random_128(v->w128);
|
|
if (v->w128[0] != 0 || v->w128[1] != 0 || zero_ok) return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void gf_general_val_to_s(gf_general_t *v, int w, char *s, int hex)
|
|
{
|
|
if (w <= 32) {
|
|
if (hex) {
|
|
sprintf(s, "%x", v->w32);
|
|
} else {
|
|
sprintf(s, "%u", v->w32);
|
|
}
|
|
} else if (w <= 64) {
|
|
if (hex) {
|
|
sprintf(s, "%llx", (long long unsigned int) v->w64);
|
|
} else {
|
|
sprintf(s, "%lld", (long long unsigned int) v->w64);
|
|
}
|
|
} else {
|
|
if (v->w128[0] == 0) {
|
|
sprintf(s, "%llx", (long long unsigned int) v->w128[1]);
|
|
} else {
|
|
sprintf(s, "%llx%016llx", (long long unsigned int) v->w128[0],
|
|
(long long unsigned int) v->w128[1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
int gf_general_s_to_val(gf_general_t *v, int w, char *s, int hex)
|
|
{
|
|
int l;
|
|
int save;
|
|
|
|
if (w <= 32) {
|
|
if (hex) {
|
|
if (sscanf(s, "%x", &(v->w32)) == 0) return 0;
|
|
} else {
|
|
if (sscanf(s, "%u", &(v->w32)) == 0) return 0;
|
|
}
|
|
if (w == 32) return 1;
|
|
if (w == 31) {
|
|
if (v->w32 & ((gf_val_32_t)1 << 31)) return 0;
|
|
return 1;
|
|
}
|
|
if (v->w32 & ~((1 << w)-1)) return 0;
|
|
return 1;
|
|
} else if (w <= 64) {
|
|
if (hex) return (sscanf(s, "%llx", (long long unsigned int *) (&(v->w64))) == 1);
|
|
return (sscanf(s, "%lld", (long long int *) (&(v->w64))) == 1);
|
|
} else {
|
|
if (!hex) return 0;
|
|
l = strlen(s);
|
|
if (l <= 16) {
|
|
v->w128[0] = 0;
|
|
return (sscanf(s, "%llx", (long long unsigned int *) (&(v->w128[1]))) == 1);
|
|
} else {
|
|
if (l > 32) return 0;
|
|
save = s[l-16];
|
|
s[l-16] = '\0';
|
|
if (sscanf(s, "%llx", (long long unsigned int *) (&(v->w128[0]))) == 0) {
|
|
s[l-16] = save;
|
|
return 0;
|
|
}
|
|
return (sscanf(s+(l-16), "%llx", (long long unsigned int *) (&(v->w128[1]))) == 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void gf_general_add(gf_t *gf, gf_general_t *a, gf_general_t *b, gf_general_t *c)
|
|
{
|
|
gf_internal_t *h;
|
|
int w;
|
|
|
|
h = (gf_internal_t *) gf->scratch;
|
|
w = h->w;
|
|
|
|
if (w <= 32) {
|
|
c->w32 = a->w32 ^ b->w32;
|
|
} else if (w <= 64) {
|
|
c->w64 = a->w64 ^ b->w64;
|
|
} else {
|
|
c->w128[0] = a->w128[0] ^ b->w128[0];
|
|
c->w128[1] = a->w128[1] ^ b->w128[1];
|
|
}
|
|
}
|
|
|
|
void gf_general_multiply(gf_t *gf, gf_general_t *a, gf_general_t *b, gf_general_t *c)
|
|
{
|
|
gf_internal_t *h;
|
|
int w;
|
|
|
|
h = (gf_internal_t *) gf->scratch;
|
|
w = h->w;
|
|
|
|
if (w <= 32) {
|
|
c->w32 = gf->multiply.w32(gf, a->w32, b->w32);
|
|
} else if (w <= 64) {
|
|
c->w64 = gf->multiply.w64(gf, a->w64, b->w64);
|
|
} else {
|
|
gf->multiply.w128(gf, a->w128, b->w128, c->w128);
|
|
}
|
|
}
|
|
|
|
void gf_general_divide(gf_t *gf, gf_general_t *a, gf_general_t *b, gf_general_t *c)
|
|
{
|
|
gf_internal_t *h;
|
|
int w;
|
|
|
|
h = (gf_internal_t *) gf->scratch;
|
|
w = h->w;
|
|
|
|
if (w <= 32) {
|
|
c->w32 = gf->divide.w32(gf, a->w32, b->w32);
|
|
} else if (w <= 64) {
|
|
c->w64 = gf->divide.w64(gf, a->w64, b->w64);
|
|
} else {
|
|
gf->divide.w128(gf, a->w128, b->w128, c->w128);
|
|
}
|
|
}
|
|
|
|
void gf_general_inverse(gf_t *gf, gf_general_t *a, gf_general_t *b)
|
|
{
|
|
gf_internal_t *h;
|
|
int w;
|
|
|
|
h = (gf_internal_t *) gf->scratch;
|
|
w = h->w;
|
|
|
|
if (w <= 32) {
|
|
b->w32 = gf->inverse.w32(gf, a->w32);
|
|
} else if (w <= 64) {
|
|
b->w64 = gf->inverse.w64(gf, a->w64);
|
|
} else {
|
|
gf->inverse.w128(gf, a->w128, b->w128);
|
|
}
|
|
}
|
|
|
|
int gf_general_are_equal(gf_general_t *v1, gf_general_t *v2, int w)
|
|
{
|
|
if (w <= 32) {
|
|
return (v1->w32 == v2->w32);
|
|
} else if (w <= 64) {
|
|
return (v1->w64 == v2->w64);
|
|
} else {
|
|
return (v1->w128[0] == v2->w128[0] &&
|
|
v1->w128[1] == v2->w128[1]);
|
|
}
|
|
}
|
|
|
|
void gf_general_do_region_multiply(gf_t *gf, gf_general_t *a, void *ra, void *rb, int bytes, int xor)
|
|
{
|
|
gf_internal_t *h;
|
|
int w;
|
|
|
|
h = (gf_internal_t *) gf->scratch;
|
|
w = h->w;
|
|
|
|
if (w <= 32) {
|
|
gf->multiply_region.w32(gf, ra, rb, a->w32, bytes, xor);
|
|
} else if (w <= 64) {
|
|
gf->multiply_region.w64(gf, ra, rb, a->w64, bytes, xor);
|
|
} else {
|
|
gf->multiply_region.w128(gf, ra, rb, a->w128, bytes, xor);
|
|
}
|
|
}
|
|
|
|
void gf_general_do_region_check(gf_t *gf, gf_general_t *a, void *orig_a, void *orig_target, void *final_target, int bytes, int xor)
|
|
{
|
|
gf_internal_t *h;
|
|
int w, words, i;
|
|
gf_general_t oa, ot, ft, sb;
|
|
char sa[50], soa[50], sot[50], sft[50], ssb[50];
|
|
|
|
h = (gf_internal_t *) gf->scratch;
|
|
w = h->w;
|
|
|
|
words = (bytes * 8) / w;
|
|
for (i = 0; i < words; i++) {
|
|
if (w <= 32) {
|
|
oa.w32 = gf->extract_word.w32(gf, orig_a, bytes, i);
|
|
ot.w32 = gf->extract_word.w32(gf, orig_target, bytes, i);
|
|
ft.w32 = gf->extract_word.w32(gf, final_target, bytes, i);
|
|
sb.w32 = gf->multiply.w32(gf, a->w32, oa.w32);
|
|
if (xor) sb.w32 ^= ot.w32;
|
|
} else if (w <= 64) {
|
|
oa.w64 = gf->extract_word.w64(gf, orig_a, bytes, i);
|
|
ot.w64 = gf->extract_word.w64(gf, orig_target, bytes, i);
|
|
ft.w64 = gf->extract_word.w64(gf, final_target, bytes, i);
|
|
sb.w64 = gf->multiply.w64(gf, a->w64, oa.w64);
|
|
if (xor) sb.w64 ^= ot.w64;
|
|
} else {
|
|
gf->extract_word.w128(gf, orig_a, bytes, i, oa.w128);
|
|
gf->extract_word.w128(gf, orig_target, bytes, i, ot.w128);
|
|
gf->extract_word.w128(gf, final_target, bytes, i, ft.w128);
|
|
gf->multiply.w128(gf, a->w128, oa.w128, sb.w128);
|
|
if (xor) {
|
|
sb.w128[0] ^= ot.w128[0];
|
|
sb.w128[1] ^= ot.w128[1];
|
|
}
|
|
}
|
|
|
|
if (!gf_general_are_equal(&ft, &sb, w)) {
|
|
|
|
fprintf(stderr,"Problem with region multiply (all values in hex):\n");
|
|
fprintf(stderr," Target address base: 0x%lx. Word 0x%x of 0x%x. Xor: %d\n",
|
|
(unsigned long) final_target, i, words, xor);
|
|
gf_general_val_to_s(a, w, sa, 1);
|
|
gf_general_val_to_s(&oa, w, soa, 1);
|
|
gf_general_val_to_s(&ot, w, sot, 1);
|
|
gf_general_val_to_s(&ft, w, sft, 1);
|
|
gf_general_val_to_s(&sb, w, ssb, 1);
|
|
fprintf(stderr," Value: %s\n", sa);
|
|
fprintf(stderr," Original source word: %s\n", soa);
|
|
if (xor) fprintf(stderr," XOR with target word: %s\n", sot);
|
|
fprintf(stderr," Product word: %s\n", sft);
|
|
fprintf(stderr," It should be: %s\n", ssb);
|
|
assert(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void gf_general_set_up_single_timing_test(int w, void *ra, void *rb, int size)
|
|
{
|
|
void *top;
|
|
gf_general_t g;
|
|
uint8_t *r8, *r8a;
|
|
uint16_t *r16;
|
|
uint32_t *r32;
|
|
uint64_t *r64;
|
|
int i;
|
|
|
|
top = (uint8_t *)rb+size;
|
|
|
|
/* If w is 8, 16, 32, 64 or 128, fill the regions with random bytes.
|
|
However, don't allow for zeros in rb, because that will screw up
|
|
division.
|
|
|
|
When w is 4, you fill the regions with random 4-bit words in each byte.
|
|
|
|
Otherwise, treat every four bytes as an uint32_t
|
|
and fill it with a random value mod (1 << w).
|
|
*/
|
|
|
|
if (w == 8 || w == 16 || w == 32 || w == 64 || w == 128) {
|
|
MOA_Fill_Random_Region (ra, size);
|
|
while (rb < top) {
|
|
gf_general_set_random(&g, w, 0);
|
|
switch (w) {
|
|
case 8:
|
|
r8 = (uint8_t *) rb;
|
|
*r8 = g.w32;
|
|
break;
|
|
case 16:
|
|
r16 = (uint16_t *) rb;
|
|
*r16 = g.w32;
|
|
break;
|
|
case 32:
|
|
r32 = (uint32_t *) rb;
|
|
*r32 = g.w32;
|
|
break;
|
|
case 64:
|
|
r64 = (uint64_t *) rb;
|
|
*r64 = g.w64;
|
|
break;
|
|
case 128:
|
|
r64 = (uint64_t *) rb;
|
|
r64[0] = g.w128[0];
|
|
r64[1] = g.w128[1];
|
|
break;
|
|
}
|
|
rb = (uint8_t *)rb + (w/8);
|
|
}
|
|
} else if (w == 4) {
|
|
r8a = (uint8_t *) ra;
|
|
r8 = (uint8_t *) rb;
|
|
while (r8 < (uint8_t *) top) {
|
|
gf_general_set_random(&g, w, 1);
|
|
*r8a = g.w32;
|
|
gf_general_set_random(&g, w, 0);
|
|
*r8 = g.w32;
|
|
r8a++;
|
|
r8++;
|
|
}
|
|
} else {
|
|
r32 = (uint32_t *) ra;
|
|
for (i = 0; i < size/4; i++) r32[i] = MOA_Random_W(w, 1);
|
|
r32 = (uint32_t *) rb;
|
|
for (i = 0; i < size/4; i++) r32[i] = MOA_Random_W(w, 0);
|
|
}
|
|
}
|
|
|
|
/* This sucks, but in order to time, you really need to avoid putting ifs in
|
|
the inner loops. So, I'm doing a separate timing test for each w:
|
|
(4 & 8), 16, 32, 64, 128 and everything else. Fortunately, the "everything else"
|
|
tests can be equivalent to w=32.
|
|
|
|
I'm also putting the results back into ra, because otherwise, the optimizer might
|
|
figure out that we're not really doing anything in the inner loops and it
|
|
will chuck that. */
|
|
|
|
int gf_general_do_single_timing_test(gf_t *gf, void *ra, void *rb, int size, char test)
|
|
{
|
|
gf_internal_t *h;
|
|
void *top;
|
|
uint8_t *r8a, *r8b, *top8;
|
|
uint16_t *r16a, *r16b, *top16;
|
|
uint32_t *r32a, *r32b, *top32;
|
|
uint64_t *r64a, *r64b, *top64, *r64c;
|
|
int w, rv;
|
|
|
|
h = (gf_internal_t *) gf->scratch;
|
|
w = h->w;
|
|
top = (uint8_t *)ra + size;
|
|
|
|
if (w == 8 || w == 4) {
|
|
r8a = (uint8_t *) ra;
|
|
r8b = (uint8_t *) rb;
|
|
top8 = (uint8_t *) top;
|
|
if (test == 'M') {
|
|
while (r8a < top8) {
|
|
*r8a = gf->multiply.w32(gf, *r8a, *r8b);
|
|
r8a++;
|
|
r8b++;
|
|
}
|
|
} else if (test == 'D') {
|
|
while (r8a < top8) {
|
|
*r8a = gf->divide.w32(gf, *r8a, *r8b);
|
|
r8a++;
|
|
r8b++;
|
|
}
|
|
} else if (test == 'I') {
|
|
while (r8a < top8) {
|
|
*r8a = gf->inverse.w32(gf, *r8a);
|
|
r8a++;
|
|
}
|
|
}
|
|
return (top8 - (uint8_t *) ra);
|
|
}
|
|
|
|
if (w == 16) {
|
|
r16a = (uint16_t *) ra;
|
|
r16b = (uint16_t *) rb;
|
|
top16 = (uint16_t *) top;
|
|
if (test == 'M') {
|
|
while (r16a < top16) {
|
|
*r16a = gf->multiply.w32(gf, *r16a, *r16b);
|
|
r16a++;
|
|
r16b++;
|
|
}
|
|
} else if (test == 'D') {
|
|
while (r16a < top16) {
|
|
*r16a = gf->divide.w32(gf, *r16a, *r16b);
|
|
r16a++;
|
|
r16b++;
|
|
}
|
|
} else if (test == 'I') {
|
|
while (r16a < top16) {
|
|
*r16a = gf->inverse.w32(gf, *r16a);
|
|
r16a++;
|
|
}
|
|
}
|
|
return (top16 - (uint16_t *) ra);
|
|
}
|
|
if (w <= 32) {
|
|
r32a = (uint32_t *) ra;
|
|
r32b = (uint32_t *) rb;
|
|
top32 = (uint32_t *) ra + (size/4); /* This is for the "everything elses" */
|
|
|
|
if (test == 'M') {
|
|
while (r32a < top32) {
|
|
*r32a = gf->multiply.w32(gf, *r32a, *r32b);
|
|
r32a++;
|
|
r32b++;
|
|
}
|
|
} else if (test == 'D') {
|
|
while (r32a < top32) {
|
|
*r32a = gf->divide.w32(gf, *r32a, *r32b);
|
|
r32a++;
|
|
r32b++;
|
|
}
|
|
} else if (test == 'I') {
|
|
while (r32a < top32) {
|
|
*r32a = gf->inverse.w32(gf, *r32a);
|
|
r32a++;
|
|
}
|
|
}
|
|
return (top32 - (uint32_t *) ra);
|
|
}
|
|
if (w == 64) {
|
|
r64a = (uint64_t *) ra;
|
|
r64b = (uint64_t *) rb;
|
|
top64 = (uint64_t *) top;
|
|
if (test == 'M') {
|
|
while (r64a < top64) {
|
|
*r64a = gf->multiply.w64(gf, *r64a, *r64b);
|
|
r64a++;
|
|
r64b++;
|
|
}
|
|
} else if (test == 'D') {
|
|
while (r64a < top64) {
|
|
*r64a = gf->divide.w64(gf, *r64a, *r64b);
|
|
r64a++;
|
|
r64b++;
|
|
}
|
|
} else if (test == 'I') {
|
|
while (r64a < top64) {
|
|
*r64a = gf->inverse.w64(gf, *r64a);
|
|
r64a++;
|
|
}
|
|
}
|
|
return (top64 - (uint64_t *) ra);
|
|
}
|
|
if (w == 128) {
|
|
r64a = (uint64_t *) ra;
|
|
r64c = r64a;
|
|
r64a += 2;
|
|
r64b = (uint64_t *) rb;
|
|
top64 = (uint64_t *) top;
|
|
rv = (top64 - r64a)/2;
|
|
if (test == 'M') {
|
|
while (r64a < top64) {
|
|
gf->multiply.w128(gf, r64a, r64b, r64c);
|
|
r64a += 2;
|
|
r64b += 2;
|
|
}
|
|
} else if (test == 'D') {
|
|
while (r64a < top64) {
|
|
gf->divide.w128(gf, r64a, r64b, r64c);
|
|
r64a += 2;
|
|
r64b += 2;
|
|
}
|
|
} else if (test == 'I') {
|
|
while (r64a < top64) {
|
|
gf->inverse.w128(gf, r64a, r64c);
|
|
r64a += 2;
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
return 0;
|
|
}
|