Removed submodules
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
# Ignore all compiled files regardless of location
|
||||
discrete.o
|
||||
main.o
|
||||
pthread.o
|
||||
tests/public.o
|
||||
tests/testsuite.o
|
||||
|
||||
# But not the private.o
|
||||
!tests/private.o
|
||||
|
||||
# Ignore executables for this project
|
||||
threads
|
||||
testsuite
|
||||
|
||||
# Ignore test outputs
|
||||
tests/ckstyle
|
||||
tests/itests.txt
|
||||
tests/outputs
|
||||
tests/style.txt
|
||||
tests/valgrind
|
||||
tests/utests.txt
|
||||
|
||||
**/.nfs*
|
||||
**/.vscode
|
||||
@@ -0,0 +1,52 @@
|
||||
#
|
||||
# Simple Makefile
|
||||
# Mike Lam, James Madison University, August 2016
|
||||
#
|
||||
# This makefile builds a simple application that contains a main module
|
||||
# (specified by the EXE variable) and a predefined list of additional modules
|
||||
# (specified by the MODS variable). If there are any external library
|
||||
# dependencies (e.g., the math library, "-lm"), list them in the LIBS variable.
|
||||
# If there are any precompiled object files, list them in the OBJS variable.
|
||||
#
|
||||
# By default, this makefile will build the project with debugging symbols and
|
||||
# without optimization. To change this, edit or remove the "-g" and "-O0"
|
||||
# options in CFLAGS and LDFLAGS accordingly.
|
||||
#
|
||||
# By default, this makefile build the application using the GNU C compiler,
|
||||
# adhering to the C99 standard with all warnings enabled.
|
||||
|
||||
|
||||
# application-specific settings and run target
|
||||
|
||||
EXE=threads
|
||||
MODS=pthread.o discrete.o
|
||||
OBJS=
|
||||
LIBS=-lm
|
||||
|
||||
default: $(EXE)
|
||||
|
||||
test: $(EXE)
|
||||
make -C tests test
|
||||
|
||||
# compiler/linker settings
|
||||
|
||||
CC=gcc
|
||||
#CFLAGS=-g -O0 -Wall --std=gnu99 -pedantic
|
||||
CFLAGS=-g -O0 -Wall --std=gnu99 -pedantic
|
||||
LDFLAGS=-g -O0 -pthread
|
||||
|
||||
|
||||
# build targets
|
||||
|
||||
$(EXE): main.o $(MODS) $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $(EXE) $^ $(LIBS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) $<
|
||||
|
||||
clean:
|
||||
rm -f $(EXE) main.o $(MODS)
|
||||
make -C tests clean
|
||||
|
||||
.PHONY: default clean
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "discrete.h"
|
||||
|
||||
/* Find a generator for Z_prime* */
|
||||
uint64_t
|
||||
find_generator (uint64_t prime)
|
||||
{
|
||||
uint64_t g = prime/2; // candidate generator
|
||||
uint64_t n; // the nth power of g
|
||||
uint64_t product = g; // product = g^n mod p
|
||||
bool searching = true; // still searching for g
|
||||
|
||||
while (searching)
|
||||
{
|
||||
product = g;
|
||||
searching = false; // optimistically guess g is good
|
||||
// stop at prime - 2, because g^(prime-1) = 1 for Z_p
|
||||
for (n = 1; n < prime - 2; n++)
|
||||
{
|
||||
product = (product * g) % prime;
|
||||
if (product == 1)
|
||||
{
|
||||
// FAIL: g is not a generator
|
||||
g++;
|
||||
if (g == prime) return 0; // should never get here
|
||||
searching = true;
|
||||
n = prime - 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
/* Given g^n mod p, g, and p, compute n */
|
||||
uint64_t
|
||||
discrete_log (uint64_t g2n, uint64_t g, uint64_t p)
|
||||
{
|
||||
uint64_t value = g;
|
||||
uint64_t n = 1;
|
||||
while (value != g2n)
|
||||
{
|
||||
value = (value * g) % p;
|
||||
n++;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef __discrete_h__
|
||||
#define __discrete_h__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint64_t find_generator (uint64_t);
|
||||
uint64_t discrete_log (uint64_t, uint64_t, uint64_t);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* CS 361: Template project driver
|
||||
*
|
||||
* Name: Nicholas Tamassia
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <getopt.h>
|
||||
#include <inttypes.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "discrete.h"
|
||||
#include "pthread.h"
|
||||
|
||||
int cmdline (int, char **, size_t *, uint64_t **, uint64_t **, uint64_t **,
|
||||
size_t *);
|
||||
|
||||
void
|
||||
usage (void)
|
||||
{
|
||||
printf ("Usage: threads [options] (g:p:g2n ... )\n");
|
||||
printf (" Required arguments must be an array of g:p:g2n values\n");
|
||||
printf (" Options are:\n");
|
||||
printf (" -n N Create N concurrent threads\n");
|
||||
printf (" g:p:g2n is a colon-delimited list of 3 uint64_t values\n");
|
||||
printf (" g A group generator\n");
|
||||
printf (" p A prime number\n");
|
||||
printf (" g2n g^n mod p for some unknown n\n");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
uint64_t *primes = NULL;
|
||||
uint64_t *gens = NULL;
|
||||
uint64_t *powers = NULL;
|
||||
size_t num_threads = 1;
|
||||
size_t num_args = 0;
|
||||
|
||||
if (cmdline (argc, argv, &num_args, &primes, &gens, &powers, &num_threads)
|
||||
< 0)
|
||||
{
|
||||
usage ();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (num_args < 1 || num_args > 20)
|
||||
{
|
||||
printf ("There must be between 1 and 20 arguments\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Unithreaded version to serve as a template
|
||||
if (num_threads == 1)
|
||||
{
|
||||
for (int i = 0; i < num_args; i++)
|
||||
{
|
||||
uint64_t result = discrete_log (powers[i], gens[i], primes[i]);
|
||||
printf ("Given g = %" PRId64 ", p = %" PRId64 ", g2n = %" PRId64
|
||||
" => n = %" PRId64 "\n",
|
||||
gens[i], primes[i], powers[i], result);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t *logs = calloc (num_args, sizeof (uint64_t));
|
||||
if (logs == NULL)
|
||||
{
|
||||
fprintf (stderr, "Failed to allocate logs array\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Adjust number of threads if there are fewer arguments than threads
|
||||
if (num_threads > num_args)
|
||||
num_threads = num_args;
|
||||
|
||||
size_t base
|
||||
= (num_args + num_threads - 1) / num_threads; // Ceiling division
|
||||
size_t rem = num_args % num_threads;
|
||||
|
||||
pthread_t *threads = calloc (num_threads, sizeof (pthread_t));
|
||||
struct time_args *targs
|
||||
= calloc (num_threads, sizeof (struct time_args));
|
||||
if (threads == NULL || targs == NULL)
|
||||
{
|
||||
free (logs);
|
||||
free (threads);
|
||||
free (targs);
|
||||
fprintf (stderr, "Failed to allocate thread structures\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
size_t created = 0;
|
||||
for (size_t t = 0; t < num_threads; t++)
|
||||
{
|
||||
size_t start = t * base;
|
||||
size_t count = (t + 1 == num_threads && rem > 0) ? rem : base;
|
||||
|
||||
targs[created].start_index = start;
|
||||
targs[created].number = count;
|
||||
targs[created].generators = gens;
|
||||
targs[created].primes = primes;
|
||||
targs[created].mod_powers = powers;
|
||||
targs[created].results = logs;
|
||||
|
||||
if (pthread_create (&threads[created], NULL, time_log_thread,
|
||||
(void *)&targs[created])
|
||||
!= 0)
|
||||
{
|
||||
for (size_t j = 0; j < created; j++)
|
||||
pthread_join (threads[j], NULL);
|
||||
free (logs);
|
||||
free (threads);
|
||||
free (targs);
|
||||
fprintf (stderr, "Failed to create worker thread\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
created++;
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < created; j++)
|
||||
pthread_join (threads[j], NULL);
|
||||
|
||||
for (size_t i = 0; i < num_args; i++)
|
||||
{
|
||||
printf ("Given g = %lu, p = %lu, g2n = %lu => n = %lu\n", gens[i],
|
||||
primes[i], powers[i], logs[i]);
|
||||
}
|
||||
|
||||
free (logs);
|
||||
free (threads);
|
||||
free (targs);
|
||||
}
|
||||
|
||||
if (primes != NULL)
|
||||
free (primes);
|
||||
if (gens != NULL)
|
||||
free (gens);
|
||||
if (powers != NULL)
|
||||
free (powers);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
****************** DO NOT MODIFY FUNCTIONS IN THIS SECTION ******************
|
||||
*****************************************************************************/
|
||||
|
||||
int
|
||||
cmdline (int argc, char **argv, size_t *length, uint64_t **primes,
|
||||
uint64_t **gens, uint64_t **powers, size_t *num_threads)
|
||||
{
|
||||
int option;
|
||||
|
||||
while ((option = getopt (argc, argv, "n:h")) != -1)
|
||||
{
|
||||
switch (option)
|
||||
{
|
||||
case 'n':
|
||||
*num_threads = (size_t)strtol (optarg, NULL, 10);
|
||||
break;
|
||||
case 'h':
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (optind == argc)
|
||||
return -1;
|
||||
*length = (size_t)(argc - optind);
|
||||
*primes = calloc (*length, sizeof (uint64_t));
|
||||
|
||||
size_t index;
|
||||
// These must both have g:p:g2n values
|
||||
*gens = calloc (*length, sizeof (uint64_t));
|
||||
*powers = calloc (*length, sizeof (uint64_t));
|
||||
for (index = optind; index < argc; index++)
|
||||
{
|
||||
char *token = strtok (argv[index], ":");
|
||||
uint64_t value = strtol (token, NULL, 10);
|
||||
(*gens)[index - optind] = value;
|
||||
token = strtok (NULL, ":");
|
||||
assert (token != NULL);
|
||||
value = strtol (token, NULL, 10);
|
||||
(*primes)[index - optind] = value;
|
||||
token = strtok (NULL, ":");
|
||||
assert (token != NULL);
|
||||
value = strtol (token, NULL, 10);
|
||||
(*powers)[index - optind] = value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef __private_h__
|
||||
#define __private_h__
|
||||
|
||||
void * generator (void *);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,152 @@
|
||||
#include <inttypes.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "discrete.h"
|
||||
#include "private.h"
|
||||
#include "pthread.h"
|
||||
|
||||
/* Create a thread that will run generator(prime). Use pthread_join() to
|
||||
retrieve the result from the thread and return that value. */
|
||||
uint64_t
|
||||
find_gen (uint64_t prime)
|
||||
{
|
||||
pthread_t thread;
|
||||
int rc = pthread_create (&thread, NULL, generator, (void *)prime);
|
||||
if (rc != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *result = NULL;
|
||||
rc = pthread_join (thread, &result);
|
||||
if (rc != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (uint64_t)result;
|
||||
}
|
||||
|
||||
/* Helper function that is a wrapper for calling find_generator() in a
|
||||
separate thread. Do not modify. */
|
||||
void *
|
||||
generator (void *args)
|
||||
{
|
||||
uint64_t prime = (uint64_t)args;
|
||||
uint64_t gen = find_generator (prime);
|
||||
pthread_exit ((void *)gen);
|
||||
}
|
||||
|
||||
/* Create multiple threads, each of which makes a single call to generator().
|
||||
Return a dynamically allocated array structured like the following:
|
||||
results[0] = generator (0);
|
||||
results[1] = generator (1);
|
||||
...
|
||||
The arguments are the number of threads to create and the array of primes
|
||||
to distribute between the threads (one prime per thread). */
|
||||
uint64_t *
|
||||
find_gens (size_t num_threads, uint64_t *primes)
|
||||
{
|
||||
if (num_threads == 0 || primes == NULL)
|
||||
return NULL;
|
||||
|
||||
pthread_t *threads = calloc (num_threads, sizeof (pthread_t));
|
||||
uint64_t *results = calloc (num_threads, sizeof (uint64_t));
|
||||
|
||||
for (size_t i = 0; i < num_threads; i++)
|
||||
{
|
||||
int rc
|
||||
= pthread_create (&threads[i], NULL, generator, (void *)primes[i]);
|
||||
if (rc != 0)
|
||||
{
|
||||
for (size_t j = 0; j < i; j++)
|
||||
{
|
||||
pthread_join (threads[j], NULL);
|
||||
}
|
||||
free (threads);
|
||||
free (results);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_threads; i++)
|
||||
{
|
||||
void *retval = NULL;
|
||||
int rc = pthread_join (threads[i], &retval);
|
||||
if (rc != 0)
|
||||
{
|
||||
results[i] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
results[i] = (uint64_t)retval;
|
||||
}
|
||||
}
|
||||
|
||||
free (threads);
|
||||
return results;
|
||||
}
|
||||
|
||||
/* Helper function to calculate the difference between a start and end time. */
|
||||
double
|
||||
time_diff (struct timeval start, struct timeval end)
|
||||
{
|
||||
double ending = end.tv_sec + (end.tv_usec * 0.000001);
|
||||
double starting = start.tv_sec + (start.tv_usec * 0.000001);
|
||||
return ending - starting;
|
||||
}
|
||||
|
||||
/* Calculate the discrete logarithm for several values. That is, given the
|
||||
values g, p, and g^n mod p, determine n. (Note that this is an intentionally
|
||||
SLOW operation!) The parameters are stored in three global arrays:
|
||||
gens[] - this contains the generator values (g)
|
||||
primes[] - this contains the prime numbers (p)
|
||||
mod_powers[] - this contains the values g^n mod p for unknown n values
|
||||
In pseudocode, you should be doing:
|
||||
for i in start_index .. end_index-1
|
||||
logs [i] = discrete_log (parameters[i])
|
||||
The return value is the real time it takes to compute these values. Use
|
||||
the C standard library function gettimeofday() to get a start and end time,
|
||||
then use the helper function time_diff() to compute the difference.
|
||||
This function will be called by time_log_thread() below. */
|
||||
double
|
||||
time_log (size_t start_index, size_t end_index, uint64_t *gens,
|
||||
uint64_t *primes, uint64_t *mod_powers, uint64_t *logs)
|
||||
{
|
||||
struct timeval start, end;
|
||||
gettimeofday (&start, NULL);
|
||||
|
||||
for (size_t i = start_index; i < end_index; i++)
|
||||
{
|
||||
logs[i] = discrete_log (mod_powers[i], gens[i], primes[i]);
|
||||
}
|
||||
|
||||
gettimeofday (&end, NULL);
|
||||
return time_diff (start, end);
|
||||
}
|
||||
|
||||
/* Wrapper function to call time_log() from within a thread. Given the
|
||||
arguments passed, store the return value from time_log() into the
|
||||
time_taken field. */
|
||||
void *
|
||||
time_log_thread (void *_args)
|
||||
{
|
||||
struct time_args *args = (struct time_args *)_args;
|
||||
if (args == NULL)
|
||||
pthread_exit (NULL);
|
||||
|
||||
size_t start = args->start_index;
|
||||
size_t end = start + args->number;
|
||||
|
||||
args->time_taken = time_log (start, end, args->generators, args->primes,
|
||||
args->mod_powers, args->results);
|
||||
|
||||
pthread_exit (NULL);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef __pthread_h__
|
||||
#define __pthread_h__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
uint64_t find_gen (uint64_t);
|
||||
uint64_t * find_gens (size_t, uint64_t *);
|
||||
|
||||
// struct used for passing arguments to time_log_thread ()
|
||||
struct time_args {
|
||||
size_t start_index; // starting index in the array of 20 items
|
||||
size_t number; // how many items to compute
|
||||
double time_taken; // how long total to compute all of the items
|
||||
uint64_t * generators; // pointer to array of group generators
|
||||
uint64_t * primes; // pointer to array of primes to use
|
||||
uint64_t * mod_powers; // pointer to array of g^n mod p values
|
||||
uint64_t * results; // pointer to array to capture the results
|
||||
};
|
||||
|
||||
double time_diff (struct timeval, struct timeval);
|
||||
void * time_log_thread (void *);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,86 @@
|
||||
#
|
||||
# Simple Test Makefile
|
||||
# Mike Lam, James Madison University, August 2016
|
||||
#
|
||||
# This version of the Makefile includes support for building a test suite. The
|
||||
# recommended framework is Check (http://check.sourceforge.net/). To build and
|
||||
# run the test suite, execute the "test" target. The test suite must be located
|
||||
# in a module called "testsuite". The MODS, LIBS, and OBJS variables work as
|
||||
# they do in the main Makefile.
|
||||
#
|
||||
# To change the default build target (which executes when you just type
|
||||
# "make"), change the right-hand side of the definition of the "default"
|
||||
# target.
|
||||
#
|
||||
# By default, this makefile will build the project with debugging symbols and
|
||||
# without optimization. To change this, edit or remove the "-g" and "-O0"
|
||||
# options in CFLAGS and LDFLAGS accordingly.
|
||||
#
|
||||
# By default, this makefile build the application using the GNU C compiler,
|
||||
# adhering to the C99 standard with all warnings enabled.
|
||||
|
||||
|
||||
# application-specific settings and run target
|
||||
|
||||
EXE=../threads
|
||||
TEST=testsuite
|
||||
MODS=public.o
|
||||
OBJS=../pthread.o ../discrete.o
|
||||
LIBS=
|
||||
|
||||
UTESTOUT=utests.txt
|
||||
ITESTOUT=itests.txt
|
||||
|
||||
default: $(TEST)
|
||||
|
||||
$(EXE):
|
||||
make -C ../
|
||||
|
||||
test: utest itest
|
||||
@echo "========================================"
|
||||
|
||||
utest: $(EXE) $(TEST)
|
||||
@echo "========================================"
|
||||
@echo " UNIT TESTS"
|
||||
@echo "----------------------------------------"
|
||||
@echo "Have patience:"
|
||||
@echo "This should take several seconds"
|
||||
@echo "You can see how it works by running:"
|
||||
@echo " ./tests/testsuite"
|
||||
@echo "----------------------------------------"
|
||||
@./$(TEST) 2>/dev/null >$(UTESTOUT)
|
||||
@cat $(UTESTOUT) | sed -n -e '/Checks/,$$p' | sed -e 's/^private.*:[EF]://g'
|
||||
|
||||
itest: $(EXE)
|
||||
@echo "========================================"
|
||||
@echo " INTEGRATION TESTS"
|
||||
@./integration.sh | tee $(ITESTOUT)
|
||||
|
||||
|
||||
# compiler/linker settings
|
||||
|
||||
CC=gcc
|
||||
CFLAGS=-g -O0 -Wall --std=gnu99 -pedantic
|
||||
LDFLAGS=-g -O0
|
||||
|
||||
CFLAGS=
|
||||
LIBS+=-lcheck -lm -lpthread
|
||||
|
||||
ifeq ($(shell uname -s),Linux)
|
||||
LIBS+=-lrt -lsubunit
|
||||
endif
|
||||
|
||||
|
||||
# build targets
|
||||
|
||||
$(TEST): $(TEST).o $(MODS) $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $(TEST) $^ $(LIBS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c $(CFLAGS) $<
|
||||
|
||||
clean:
|
||||
rm -rf $(TEST) $(TEST).o $(MODS) $(UTESTOUT) $(ITESTOUT) outputs valgrind
|
||||
|
||||
.PHONY: default clean test unittest inttest
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
Given g = 43013398, p = 86026793, g2n = 64520094 => n = 62484235
|
||||
Given g = 35739627, p = 71479241, g2n = 53609430 => n = 37573249
|
||||
Given g = 47594171, p = 95188343, g2n = 71391255 => n = 83365257
|
||||
Given g = 32133930, p = 64267859, g2n = 48200892 => n = 42413257
|
||||
@@ -0,0 +1,4 @@
|
||||
Given g = 43013398, p = 86026793, g2n = 64520094 => n = 62484235
|
||||
Given g = 35739627, p = 71479241, g2n = 53609430 => n = 37573249
|
||||
Given g = 47594171, p = 95188343, g2n = 71391255 => n = 83365257
|
||||
Given g = 32133930, p = 64267859, g2n = 48200892 => n = 42413257
|
||||
@@ -0,0 +1,9 @@
|
||||
Given g = 1374234, p = 2748467, g2n = 2061348 => n = 1014681
|
||||
Given g = 3290982, p = 6581963, g2n = 4936470 => n = 1229705
|
||||
Given g = 1449191, p = 2898383, g2n = 2173785 => n = 2576065
|
||||
Given g = 2511322, p = 5022643, g2n = 3766980 => n = 4460251
|
||||
Given g = 1523458, p = 3046903, g2n = 2285175 => n = 285081
|
||||
Given g = 935190, p = 1870369, g2n = 1402776 => n = 593354
|
||||
Given g = 1598454, p = 3196909, g2n = 2397681 => n = 1024170
|
||||
Given g = 2051286, p = 4102573, g2n = 3076929 => n = 2765678
|
||||
Given g = 1748890, p = 3497779, g2n = 2623332 => n = 1722817
|
||||
@@ -0,0 +1,9 @@
|
||||
Given g = 1374234, p = 2748467, g2n = 2061348 => n = 1014681
|
||||
Given g = 3290982, p = 6581963, g2n = 4936470 => n = 1229705
|
||||
Given g = 1449191, p = 2898383, g2n = 2173785 => n = 2576065
|
||||
Given g = 2511322, p = 5022643, g2n = 3766980 => n = 4460251
|
||||
Given g = 1523458, p = 3046903, g2n = 2285175 => n = 285081
|
||||
Given g = 935190, p = 1870369, g2n = 1402776 => n = 593354
|
||||
Given g = 1598454, p = 3196909, g2n = 2397681 => n = 1024170
|
||||
Given g = 2051286, p = 4102573, g2n = 3076929 => n = 2765678
|
||||
Given g = 1748890, p = 3497779, g2n = 2623332 => n = 1722817
|
||||
@@ -0,0 +1,12 @@
|
||||
Given g = 131, p = 263, g2n = 195 => n = 229
|
||||
Given g = 227, p = 439, g2n = 327 => n = 429
|
||||
Given g = 262, p = 523, g2n = 390 => n = 191
|
||||
Given g = 414, p = 829, g2n = 521 => n = 757
|
||||
Given g = 442, p = 883, g2n = 660 => n = 723
|
||||
Given g = 474, p = 947, g2n = 708 => n = 539
|
||||
Given g = 511, p = 1009, g2n = 756 => n = 974
|
||||
Given g = 526, p = 1049, g2n = 786 => n = 681
|
||||
Given g = 398, p = 797, g2n = 597 => n = 235
|
||||
Given g = 274, p = 547, g2n = 408 => n = 509
|
||||
Given g = 606, p = 1213, g2n = 909 => n = 892
|
||||
Given g = 11, p = 23, g2n = 15 => n = 19
|
||||
@@ -0,0 +1,12 @@
|
||||
Given g = 131, p = 263, g2n = 195 => n = 229
|
||||
Given g = 227, p = 439, g2n = 327 => n = 429
|
||||
Given g = 262, p = 523, g2n = 390 => n = 191
|
||||
Given g = 414, p = 829, g2n = 521 => n = 757
|
||||
Given g = 442, p = 883, g2n = 660 => n = 723
|
||||
Given g = 474, p = 947, g2n = 708 => n = 539
|
||||
Given g = 511, p = 1009, g2n = 756 => n = 974
|
||||
Given g = 526, p = 1049, g2n = 786 => n = 681
|
||||
Given g = 398, p = 797, g2n = 597 => n = 235
|
||||
Given g = 274, p = 547, g2n = 408 => n = 509
|
||||
Given g = 606, p = 1213, g2n = 909 => n = 892
|
||||
Given g = 11, p = 23, g2n = 15 => n = 19
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/bin/bash
|
||||
|
||||
EXE="../threads"
|
||||
|
||||
function run_test {
|
||||
|
||||
# parameters
|
||||
TAG=$1
|
||||
ARGS=$2
|
||||
|
||||
# file paths
|
||||
OUTPUT=outputs/$TAG.txt
|
||||
DIFF=outputs/$TAG.diff
|
||||
EXPECT=expected/$TAG.txt
|
||||
VALGRND=valgrind/$TAG.txt
|
||||
|
||||
# run test and compare output to the expected version
|
||||
$EXE $ARGS 2>/dev/null >"$OUTPUT"
|
||||
diff -u "$OUTPUT" "$EXPECT" >"$DIFF"
|
||||
PTAG=$(printf '%-30s' "$TAG")
|
||||
if [ -s "$DIFF" ]; then
|
||||
|
||||
# try alternative solution (if it exists)
|
||||
EXPECT=expected/$TAG-2.txt
|
||||
if [ -e "$EXPECT" ]; then
|
||||
diff -u "$OUTPUT" "$EXPECT" >"$DIFF"
|
||||
if [ -s "$DIFF" ]; then
|
||||
echo "$PTAG FAIL (see $DIFF for details)"
|
||||
else
|
||||
echo "$PTAG pass"
|
||||
fi
|
||||
else
|
||||
echo "$PTAG FAIL (see $DIFF for details)"
|
||||
fi
|
||||
else
|
||||
echo "$PTAG pass"
|
||||
fi
|
||||
|
||||
# run valgrind
|
||||
#valgrind $EXE $ARGS &>$VALGRND
|
||||
}
|
||||
|
||||
# initialize output folders
|
||||
mkdir -p outputs
|
||||
mkdir -p valgrind
|
||||
rm -f outputs/* valgrind/*
|
||||
|
||||
# run individual tests
|
||||
source itests.include
|
||||
|
||||
# check for memory leaks
|
||||
#LEAK=`cat valgrind/*.txt | grep 'definitely lost' | grep -v ' 0 bytes in 0 blocks'`
|
||||
#if [ -z "$LEAK" ]; then
|
||||
# echo "No memory leak found."
|
||||
#else
|
||||
# echo "Memory leak(s) found. See files listed below for details."
|
||||
# grep 'definitely lost' valgrind/*.txt | grep -v ' 0 bytes in 0 blocks' | sed -e 's/:.*$//g' | sed -e 's/^/ - /g'
|
||||
#fi
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# list of integration tests
|
||||
# format: run_test <TAG> <ARGS>
|
||||
# <TAG> used as the root for all filenames (i.e., "expected/$TAG.txt")
|
||||
# <ARGS> command-line arguments to test
|
||||
|
||||
run_test INTEG_logs_small "131:263:195 227:439:327 262:523:390 414:829:521 442:883:660 474:947:708 511:1009:756 526:1049:786 398:797:597 274:547:408 606:1213:909 11:23:15"
|
||||
run_test INTEG_logs_small_thr "-n 6 131:263:195 227:439:327 262:523:390 414:829:521 442:883:660 474:947:708 511:1009:756 526:1049:786 398:797:597 274:547:408 606:1213:909 11:23:15"
|
||||
run_test INTEG_logs_medium "1374234:2748467:2061348 3290982:6581963:4936470 1449191:2898383:2173785 2511322:5022643:3766980 1523458:3046903:2285175 935190:1870369:1402776 1598454:3196909:2397681 2051286:4102573:3076929 1748890:3497779:2623332"
|
||||
run_test INTEG_logs_medium_thr "-n 3 1374234:2748467:2061348 3290982:6581963:4936470 1449191:2898383:2173785 2511322:5022643:3766980 1523458:3046903:2285175 935190:1870369:1402776 1598454:3196909:2397681 2051286:4102573:3076929 1748890:3497779:2623332"
|
||||
run_test INTEG_logs_large "43013398:86026793:64520094 35739627:71479241:53609430 47594171:95188343:71391255 32133930:64267859:48200892"
|
||||
run_test INTEG_logs_large_thr "-n 4 43013398:86026793:64520094 35739627:71479241:53609430 47594171:95188343:71391255 32133930:64267859:48200892"
|
||||
@@ -0,0 +1,217 @@
|
||||
#include <assert.h>
|
||||
#include <check.h>
|
||||
#include <inttypes.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../discrete.h"
|
||||
#include "../pthread.h"
|
||||
|
||||
uint64_t large_primes[] = {
|
||||
22181233, 30722903, 39410039, 48210479, 23878483, 32452597, 41161361,
|
||||
49978519, 25582069, 34185953, 42918971, 51754777, 27290279, 35925737,
|
||||
44679787, 53532901, 29005421, 37666553, 46439677, 55316903
|
||||
};
|
||||
|
||||
uint64_t large_gens[] = {
|
||||
11090619, 15361451, 19705019, 24105239, 11939242, 16226298, 20580682,
|
||||
24989259, 12791034, 17092978, 21459486, 25877391, 13645139, 17962870,
|
||||
22339897, 26766452, 14502710, 18833278, 23219838, 27658451
|
||||
};
|
||||
|
||||
uint64_t mod_powers[] = {
|
||||
10722318, 10718795, 16846904, 28514080, 13198105, 21563282, 16451148,
|
||||
31188765, 8174568, 24132030, 5838284, 8726777, 10697873, 30365043,
|
||||
40656885, 6262555, 301068, 34096955, 29442656, 36415956
|
||||
};
|
||||
|
||||
// Move these to tests/private.c
|
||||
// These are p / 4 * 3
|
||||
uint64_t expected[] = {
|
||||
16635924, 23042175, 29557527, 36157857, 17908860, 24339447, 30871020,
|
||||
37483887, 19186551, 25639464, 32189226, 38816082, 20467707, 26944302,
|
||||
33509838, 40149675, 21754065, 28249914, 34829757, 41487675
|
||||
};
|
||||
|
||||
|
||||
START_TEST (MIN_find_one_generator)
|
||||
{
|
||||
printf ("======================================\n");
|
||||
printf ("PUBLIC\n");
|
||||
printf (" MIN find one generator\n");
|
||||
printf (" Calls find generator(%" PRId64 ") in a separate thread\n", large_primes[10]);
|
||||
printf (" Should compute %" PRId64 "\n\n", large_gens[10]);
|
||||
|
||||
uint64_t single = find_gen (large_primes[10]);
|
||||
ck_assert_int_eq (single, large_gens[10]);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (MIN_find_two_generators)
|
||||
{
|
||||
printf ("======================================\n");
|
||||
printf ("PUBLIC\n");
|
||||
printf (" MIN find two generators\n");
|
||||
printf (" Calls find_generator(%" PRId64 ") in a separate thread\n", large_primes[0]);
|
||||
printf (" Should compute %" PRId64 "\n", large_gens[0]);
|
||||
printf (" Calls find_generator(%" PRId64 ") in a separate thread\n", large_primes[1]);
|
||||
printf (" Should compute %" PRId64 "\n\n", large_gens[1]);
|
||||
|
||||
uint64_t * pair = find_gens (2, large_primes);
|
||||
ck_assert (pair != NULL);
|
||||
ck_assert_int_eq (pair[0], large_gens[0]);
|
||||
ck_assert_int_eq (pair[1], large_gens[1]);
|
||||
free (pair);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (MIN_find_5_generators)
|
||||
{
|
||||
printf ("======================================\n");
|
||||
printf ("PRIVATE\n");
|
||||
printf (" MIN find one generator\n");
|
||||
printf (" Calls find generator() for the following values:\n ");
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < 5; i++)
|
||||
printf (" %" PRId64, large_primes[i]);
|
||||
printf ("\n");
|
||||
uint64_t * gens = find_gens (5, large_primes);
|
||||
|
||||
printf (" Computed the following generators:\n ");
|
||||
for (i = 0; i < 5; i++)
|
||||
printf (" %" PRId64, gens[i]);
|
||||
printf ("\n");
|
||||
|
||||
printf (" Expected the following generators:\n ");
|
||||
for (i = 0; i < 5; i++)
|
||||
printf (" %" PRId64, large_gens[i]);
|
||||
printf ("\n\n");
|
||||
|
||||
ck_assert (gens != NULL);
|
||||
for (i = 0; i < 5; i++)
|
||||
ck_assert_int_eq (gens[i], large_gens[i]);
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (MIN_last_5_discrete_logs)
|
||||
{
|
||||
printf ("======================================\n");
|
||||
printf ("PUBLIC\n");
|
||||
printf (" MIN last 5 discrete logs\n");
|
||||
printf (" Uses threads to compute the discrete logarithms for:\n");
|
||||
size_t i;
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
printf (" g = %8"PRId64 "; ", large_gens[15 + i]);
|
||||
printf (" p = %"PRId64 "; ", large_primes[15 + i]);
|
||||
printf (" g^n = %"PRId64 "\n", mod_powers[15 + i]);
|
||||
}
|
||||
|
||||
struct time_args args;
|
||||
memset (&args, 0, sizeof (args));
|
||||
args.results = calloc (20, sizeof (uint64_t));
|
||||
args.start_index = 15;
|
||||
args.number = 5;
|
||||
args.generators = large_gens;
|
||||
args.primes = large_primes;
|
||||
args.mod_powers = mod_powers;
|
||||
|
||||
pthread_t thread;
|
||||
pthread_create (&thread, NULL, time_log_thread, (void *) &args);
|
||||
pthread_join (thread, NULL);
|
||||
printf (" Thread took %lf seconds\n", args.time_taken);
|
||||
for (i = 0; i < 5; i++)
|
||||
printf (" Computed n = %"PRId64 " [expected %"PRId64"]\n",
|
||||
args.results[15 + i], expected[15 + i]);
|
||||
printf ("\n");
|
||||
for (i = 0; i < 5; i++)
|
||||
ck_assert_int_eq (args.results[15 + i], expected[15 + i]);
|
||||
free (args.results);
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (MIN_parallel_discrete_logs)
|
||||
{
|
||||
printf ("======================================\n");
|
||||
printf ("PUBLIC\n");
|
||||
printf (" MIN parallel discrete logs\n");
|
||||
printf (" Uses 4 threads to compute the discrete logarithms for:\n");
|
||||
size_t i;
|
||||
for (i = 0; i < 20; i++)
|
||||
{
|
||||
printf (" g = %8"PRId64 "; ", large_gens[15 + i]);
|
||||
printf (" p = %"PRId64 "; ", large_primes[15 + i]);
|
||||
printf (" g^n = %"PRId64 "\n", mod_powers[15 + i]);
|
||||
}
|
||||
|
||||
struct timeval start, end;
|
||||
gettimeofday (&start, NULL);
|
||||
for (i = 0; i < 20; i++)
|
||||
discrete_log (mod_powers[i], large_gens[i], large_primes[i]);
|
||||
gettimeofday (&end, NULL);
|
||||
double sequential_time = time_diff (start, end);
|
||||
printf (" Sequential real-time took %lf seconds\n", sequential_time);
|
||||
|
||||
uint64_t * logs = calloc (20, sizeof (uint64_t));
|
||||
|
||||
gettimeofday (&start, NULL);
|
||||
pthread_t thread[4];
|
||||
struct time_args args[4];
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
memset (&args[i], 0, sizeof (args[i]));
|
||||
args[i].results = logs;
|
||||
args[i].start_index = i * 5;
|
||||
args[i].number = 5;
|
||||
args[i].generators = large_gens;
|
||||
args[i].primes = large_primes;
|
||||
args[i].mod_powers = mod_powers;
|
||||
pthread_create (&thread[i], NULL, time_log_thread, (void *) &args[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
pthread_join (thread[i], NULL);
|
||||
gettimeofday (&end, NULL);
|
||||
|
||||
double parallel_time = time_diff (start, end);
|
||||
printf (" Parallel real-time took %lf seconds\n", parallel_time);
|
||||
for (i = 0; i < 4; i++)
|
||||
printf (" Thread %zd took %lf seconds\n", i, args[i].time_taken);
|
||||
|
||||
size_t j;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
for (j = 0; j < 5; j++)
|
||||
printf (" Thread %zd computed n = %"PRId64 " [expected %"PRId64"]\n",
|
||||
i, logs[i * 4 + j], expected[i * 4 + j]);
|
||||
}
|
||||
printf ("\n");
|
||||
for (i = 0; i < 20; i++)
|
||||
ck_assert_int_eq (logs[i], expected[i]);
|
||||
free (logs);
|
||||
|
||||
|
||||
ck_assert (parallel_time * 2 < sequential_time);
|
||||
ck_assert (parallel_time * 4 > sequential_time);
|
||||
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void public_tests (Suite *s)
|
||||
{
|
||||
TCase *tc_public = tcase_create ("Public");
|
||||
tcase_set_timeout (tc_public, 20.0);
|
||||
tcase_add_test (tc_public, MIN_find_one_generator);
|
||||
tcase_add_test (tc_public, MIN_find_two_generators);
|
||||
tcase_add_test (tc_public, MIN_last_5_discrete_logs);
|
||||
tcase_add_test (tc_public, MIN_parallel_discrete_logs);
|
||||
suite_add_tcase (s, tc_public);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <check.h>
|
||||
|
||||
extern void public_tests (Suite *s);
|
||||
|
||||
Suite * test_suite (void)
|
||||
{
|
||||
Suite *s = suite_create ("Default");
|
||||
public_tests (s);
|
||||
return s;
|
||||
}
|
||||
|
||||
void run_testsuite ()
|
||||
{
|
||||
Suite *s = test_suite ();
|
||||
SRunner *sr = srunner_create (s);
|
||||
srunner_run_all (sr, CK_NORMAL);
|
||||
srunner_free (sr);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
srand((unsigned)time(NULL));
|
||||
run_testsuite ();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user