├── .gitignore ├── src ├── client │ ├── threads │ │ ├── threads.cpp │ │ ├── Makefile │ │ ├── win32.cpp │ │ └── posix.cpp │ ├── client │ │ ├── cpu │ │ │ ├── math │ │ │ │ ├── x86 │ │ │ │ │ ├── Makefile │ │ │ │ │ ├── x86.sh │ │ │ │ │ ├── x86.h │ │ │ │ │ └── gen.py │ │ │ │ ├── Makefile │ │ │ │ ├── Fp.cpp │ │ │ │ ├── gmp │ │ │ │ │ └── gmp_math.h │ │ │ │ └── Fp.h │ │ │ ├── Makefile │ │ │ ├── RhoCPU.h │ │ │ ├── ECDLCPU.h │ │ │ ├── ECDLCpuContext.cpp │ │ │ ├── workerthread.cpp │ │ │ └── RhoCPU.cpp │ │ ├── settings.json │ │ ├── cuda │ │ │ ├── util.cu │ │ │ ├── Makefile │ │ │ ├── cudapp.h │ │ │ ├── ECDLCuda.h │ │ │ ├── ECDLCudaContext.cpp │ │ │ ├── kernels.h │ │ │ ├── cudapp.cpp │ │ │ ├── RhoCUDA.h │ │ │ └── Fp.cu │ │ ├── client.h │ │ ├── ECDLContext.h │ │ ├── config.cpp │ │ ├── Makefile │ │ ├── ServerConnection.h │ │ ├── fp_test.cpp │ │ ├── benchmark.cpp │ │ ├── ServerConnection.cpp │ │ └── main.cpp │ ├── ecc │ │ ├── Makefile │ │ ├── ecpoint.cpp │ │ ├── jacobian.cpp │ │ ├── eccutil.cpp │ │ └── ecc.cpp │ ├── util │ │ ├── Makefile │ │ └── util.cpp │ ├── bigint │ │ ├── Makefile │ │ └── bigint.cpp │ ├── logger │ │ ├── Makefile │ │ └── logger.cpp │ ├── configfile │ │ ├── Makefile │ │ └── ConfigFile.cpp │ ├── include │ │ ├── logger.h │ │ ├── ECDLPParams.h │ │ ├── config.h │ │ ├── util.h │ │ ├── threads.h │ │ ├── Config.h │ │ ├── ecc.h │ │ └── BigInteger.h │ └── Makefile └── server │ ├── config │ └── config.json │ ├── schemas.json │ ├── PointDatabase.py │ ├── curves.py │ ├── ecdl.py │ ├── ecc.py │ ├── util.py │ ├── server.py │ ├── solve.py │ └── solver.py ├── scripts ├── gencurve.sh ├── create.sh ├── helper.py └── gencurve.sage └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.a 3 | *.so 4 | *.o 5 | -------------------------------------------------------------------------------- /src/client/threads/threads.cpp: -------------------------------------------------------------------------------- 1 | #ifdef _WIN32 2 | #include"win32.cpp" 3 | #else 4 | #include"posix.cpp" 5 | #endif 6 | 7 | -------------------------------------------------------------------------------- /src/client/client/cpu/math/x86/Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: 3 | ./x86.sh 4 | ${NASM} -f elf32 x86.asm -o x86.o 5 | 6 | clean: 7 | rm -f *.o 8 | -------------------------------------------------------------------------------- /src/server/config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "port":9999, 3 | "dbUser":"user", 4 | "dbPassword":"password", 5 | "dbHost":"127.0.0.1" 6 | } 7 | -------------------------------------------------------------------------------- /scripts/gencurve.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# != 2 ]; then 4 | echo "Usage: " 5 | exit 1 6 | fi 7 | 8 | echo -e "load('gencurve.sage')\ngenerate_ecdlp($1,'$2')" | sage 9 | -------------------------------------------------------------------------------- /src/client/threads/Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: ${SRC} 3 | ${CXX} -c threads.cpp -o threads.o ${INCLUDE} ${CXXFLAGS} 4 | mkdir -p ${LIBDIR} 5 | ar rvs ${LIBDIR}/libthread.a threads.o 6 | 7 | clean: 8 | rm -rf *.o 9 | -------------------------------------------------------------------------------- /scripts/create.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# != 3 ]; then 4 | echo "Usage: create " 5 | exit 1 6 | fi 7 | 8 | curl --verbose -H "Content-Type: application/json" --data @$2 http://$1/create/$3 9 | -------------------------------------------------------------------------------- /src/client/ecc/Makefile: -------------------------------------------------------------------------------- 1 | SRC=$(wildcard *.cpp) 2 | OBJS=$(SRC:.cpp=.o) 3 | 4 | all: ${SRC} 5 | for file in ${SRC} ; do\ 6 | ${CXX} -c $$file ${INCLUDE} ${CXXFLAGS};\ 7 | done 8 | mkdir -p ${LIBDIR} 9 | ar rvs ${LIBDIR}/libecc.a ${OBJS} 10 | 11 | clean: 12 | rm -rf *.o 13 | -------------------------------------------------------------------------------- /src/client/util/Makefile: -------------------------------------------------------------------------------- 1 | SRC=$(wildcard *.cpp) 2 | OBJS=$(SRC:.cpp=.o) 3 | 4 | all: ${SRC} 5 | for file in ${SRC} ; do\ 6 | ${CXX} -c $$file ${INCLUDE} ${CXXFLAGS};\ 7 | done 8 | mkdir -p ${LIBDIR} 9 | ar rvs ${LIBDIR}/libutil.a ${OBJS} 10 | 11 | clean: 12 | rm -rf *.o 13 | -------------------------------------------------------------------------------- /src/client/bigint/Makefile: -------------------------------------------------------------------------------- 1 | SRC=$(wildcard *.cpp) 2 | OBJS=$(SRC:.cpp=.o) 3 | 4 | all: ${SRC} 5 | for file in ${SRC} ; do\ 6 | ${CXX} -c $$file ${INCLUDE} ${CXXFLAGS};\ 7 | done 8 | mkdir -p ${LIBDIR} 9 | ar rvs ${LIBDIR}/libbigint.a ${OBJS} 10 | 11 | clean: 12 | rm -rf *.o 13 | -------------------------------------------------------------------------------- /src/client/logger/Makefile: -------------------------------------------------------------------------------- 1 | SRC=$(wildcard *.cpp) 2 | OBJS=$(SRC:.cpp=.o) 3 | 4 | all: ${SRC} 5 | for file in ${SRC} ; do\ 6 | ${CXX} -c $$file ${INCLUDE} ${CXXFLAGS};\ 7 | done 8 | mkdir -p ${LIBDIR} 9 | ar rvs ${LIBDIR}/liblogger.a ${OBJS} 10 | 11 | clean: 12 | rm -rf *.o 13 | -------------------------------------------------------------------------------- /src/client/configfile/Makefile: -------------------------------------------------------------------------------- 1 | SRC=$(wildcard *.cpp) 2 | OBJS=$(SRC:.cpp=.o) 3 | 4 | all: ${SRC} 5 | for file in ${SRC} ; do\ 6 | ${CXX} -c $$file ${INCLUDE} ${CXXFLAGS};\ 7 | done 8 | mkdir -p ${LIBDIR} 9 | ar rvs ${LIBDIR}/libconfigfile.a ${OBJS} 10 | 11 | clean: 12 | rm -rf *.o 13 | -------------------------------------------------------------------------------- /src/client/client/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "server_host": "127.0.0.1", 3 | "server_port": 9999, 4 | 5 | "point_cache_size": 1, 6 | "cpu_threads": 1, 7 | "cpu_points_per_thread": 1, 8 | 9 | 10 | "cuda_threads": 32, 11 | "cuda_blocks": 1, 12 | "cuda_points_per_thread": 1, 13 | "cuda_device": 0 14 | } 15 | -------------------------------------------------------------------------------- /src/client/include/logger.h: -------------------------------------------------------------------------------- 1 | #ifndef _LOGGER_H 2 | #define _LOGGER_H 3 | 4 | #include 5 | 6 | class Logger { 7 | public: 8 | static void logInfo(std::string s); 9 | static void logInfo(const char *format, ...); 10 | 11 | static void logError(std::string s); 12 | static void logError(const char *format, ...); 13 | }; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /src/server/schemas.json: -------------------------------------------------------------------------------- 1 | { 2 | "submit": { 3 | "type": "object", 4 | "point":{ 5 | "startA": {"type":"string"}, 6 | "startB": {"type":"string"}, 7 | "endX": {"type":"string"}, 8 | "endY": {"type":"string"} 9 | }, 10 | "required": ["startA", "startB", "endX", "endY"] 11 | } 12 | } -------------------------------------------------------------------------------- /src/client/client/cuda/util.cu: -------------------------------------------------------------------------------- 1 | #ifndef _UTIL_CU 2 | #define _UTIL_CU 3 | 4 | template __device__ void zero(unsigned int *x) 5 | { 6 | #pragma unroll 7 | for(int i = 0; i < N; i++) { 8 | x[i] = 0; 9 | } 10 | } 11 | 12 | template __device__ void copy(const unsigned int *a, unsigned int *b) 13 | { 14 | #pragma unroll 15 | for(int i = 0; i < N; i++) { 16 | b[i] = a[i]; 17 | } 18 | } 19 | 20 | #endif -------------------------------------------------------------------------------- /src/client/client/cuda/Makefile: -------------------------------------------------------------------------------- 1 | CPPSRC:=$(wildcard *.cpp) 2 | CUSRC+=$(wildcard *.cu) 3 | CUSRC:=$(filter-out Fp.cu, $(CUSRC)) 4 | 5 | all: cuda 6 | 7 | cuda: 8 | for file in ${CPPSRC} ; do\ 9 | ${CXX} -c $$file ${INCLUDE} -I../ -I${CUDA_INCLUDE} ${CXXFLAGS};\ 10 | done 11 | for file in ${CUSRC} ; do\ 12 | ${NVCC} -c ${NVCCFLAGS} ${INCLUDE} -I${CUDA_INCLUDE} ${CUSRC};\ 13 | done 14 | ar rvs cuda.a *.o 15 | 16 | clean: 17 | rm -f *.o 18 | rm -f *.a 19 | rm -f client-cuda 20 | -------------------------------------------------------------------------------- /src/client/include/ECDLPParams.h: -------------------------------------------------------------------------------- 1 | #ifndef _ECDL_PARAMS_H 2 | #define _ECDL_PARAMS_H 3 | 4 | #define NUM_R_POINTS 32 5 | 6 | #include 7 | #include "BigInteger.h" 8 | 9 | typedef struct { 10 | BigInteger p; 11 | BigInteger a; 12 | BigInteger b; 13 | BigInteger n; 14 | BigInteger gx; 15 | BigInteger gy; 16 | BigInteger qx; 17 | BigInteger qy; 18 | unsigned int dBits; 19 | std::vector rx; 20 | std::vector ry; 21 | }ECDLPParams; 22 | 23 | #endif -------------------------------------------------------------------------------- /src/client/client/client.h: -------------------------------------------------------------------------------- 1 | #ifndef _CLIENT_H 2 | #define _CLIENT_H 3 | 4 | #include 5 | 6 | typedef struct { 7 | 8 | std::string serverHost; 9 | unsigned short serverPort; 10 | unsigned int pointCacheSize; 11 | 12 | #ifdef _CUDA 13 | int device; 14 | int blocks; 15 | int threads; 16 | int pointsPerThread; 17 | #else 18 | int threads; 19 | int pointsPerThread; 20 | #endif 21 | 22 | }ClientConfig; 23 | 24 | 25 | extern ClientConfig _config; 26 | 27 | ClientConfig loadConfig(std::string fileName); 28 | void doBenchmark(); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/client/client/cpu/Makefile: -------------------------------------------------------------------------------- 1 | 2 | SRC=$(wildcard *.cpp) 3 | SRC:=$(filter-out workerthread.cpp, $(SRC)) 4 | #SRC:=$(filter-out RhoCPU.cpp, $(SRC)) 5 | 6 | OBJS=$(SRC:.cpp=.o) 7 | 8 | ifeq ($(X86_ASM),1) 9 | INCLUDE+=-I./math/x86 10 | CXXFLAGS += -D_X86 11 | else 12 | INCLUDE+=-I./math/gmp 13 | endif 14 | 15 | all: fpmath 16 | for file in ${SRC} ; do\ 17 | ${CXX} -c $$file ${INCLUDE} -I../ -I./ -I./math ${CXXFLAGS};\ 18 | done 19 | ar rvs cpu.a ${OBJS} math/obj/*.o 20 | 21 | fpmath: 22 | make --directory math 23 | 24 | clean: 25 | make --directory math clean 26 | rm -rf *.o 27 | rm -rf *.a 28 | -------------------------------------------------------------------------------- /src/client/client/cpu/math/Makefile: -------------------------------------------------------------------------------- 1 | 2 | SRC=$(wildcard *.cpp) 3 | SRC:=$(filter-out Fp_templates.cpp, $(SRC)) 4 | OBJS=$(SRC:.cpp=.o) 5 | TARGETS= 6 | 7 | ifeq ($(X86_ASM),1) 8 | OBJS+=x86/x86.o 9 | INCLUDE+=-I./x86 10 | TARGETS=x86asm 11 | #CXXFLAGS+=-D_X86 12 | else 13 | INCLUDE+=-I./gmp 14 | endif 15 | 16 | all: ${TARGETS} 17 | for file in ${SRC} ; do\ 18 | ${CXX} -c $$file ${INCLUDE} -I../ -I./ ${CXXFLAGS};\ 19 | done 20 | mkdir -p obj 21 | cp ${OBJS} obj 22 | 23 | x86asm: 24 | make --directory x86 all 25 | 26 | clean: 27 | make --directory x86 clean 28 | rm -rf obj 29 | rm -rf *.o 30 | rm -rf *.a 31 | -------------------------------------------------------------------------------- /src/client/include/config.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONFIG_H 2 | #define _CONFIG_H 3 | 4 | #include 5 | #include 6 | #include"BigInteger.h" 7 | 8 | typedef std::pair ConfigPair; 9 | typedef std::map ConfigMap; 10 | 11 | ConfigMap readConfigFile(std::string filename, const char **fields); 12 | 13 | class Config { 14 | 15 | private: 16 | ConfigMap _configMap; 17 | 18 | public: 19 | Config(std::string path); 20 | 21 | 22 | int readInt(std::string name); 23 | std::string readString(std::string name); 24 | BigInteger readBigInt(std::string name); 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/client/include/util.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTIL_H 2 | #define _UTIL_H 3 | 4 | #include"BigInteger.h" 5 | 6 | namespace util { 7 | 8 | class Timer { 9 | 10 | private: 11 | unsigned int _startTime; 12 | 13 | public: 14 | Timer(); 15 | void start(); 16 | unsigned int getTime(); 17 | }; 18 | 19 | unsigned int getSystemTime(); 20 | std::string hexEncode(const unsigned char *bytes, unsigned int len); 21 | void hexDecode(std::string hex, unsigned char *bytes); 22 | void printHex(unsigned long x); 23 | void printHex(unsigned long *x, int len); 24 | void getRandomBytes(unsigned char *buf, unsigned int count); 25 | unsigned int toInt(const unsigned char *bytes); 26 | void fromInt(unsigned int x, unsigned char *bytes); 27 | 28 | } 29 | 30 | #endif -------------------------------------------------------------------------------- /src/client/client/ECDLContext.h: -------------------------------------------------------------------------------- 1 | #ifndef _ECDL_CONTEXT_H 2 | #define _ECDL_CONTEXT_H 3 | 4 | #define NUM_R_POINTS 32 5 | 6 | #include 7 | #include "BigInteger.h" 8 | #include "ECDLPParams.h" 9 | 10 | /** 11 | Parameters passed to the callback when a distinguished point is found 12 | */ 13 | struct CallbackParameters { 14 | BigInteger aStart; 15 | BigInteger bStart; 16 | BigInteger x; 17 | BigInteger y; 18 | unsigned long long length; 19 | }; 20 | 21 | class ECDLContext { 22 | 23 | public: 24 | virtual bool init() = 0; 25 | virtual void reset() = 0; 26 | virtual bool stop() = 0; 27 | virtual bool run() = 0; 28 | virtual bool isRunning() = 0; 29 | virtual bool benchmark(unsigned long long *pointsPerSecond) = 0; 30 | }; 31 | 32 | #endif -------------------------------------------------------------------------------- /src/client/ecc/ecpoint.cpp: -------------------------------------------------------------------------------- 1 | #include "ecc.h" 2 | #include "BigInteger.h" 3 | 4 | ECPoint::ECPoint() 5 | { 6 | } 7 | 8 | ECPoint::ECPoint( const BigInteger &x, const BigInteger &y ) 9 | { 10 | this->x = x; 11 | this->y = y; 12 | } 13 | 14 | ECPoint::ECPoint( const ECPoint &p ) 15 | { 16 | this->x = p.x; 17 | this->y = p.y; 18 | } 19 | 20 | bool ECPoint::isPointAtInfinity() 21 | { 22 | return this->x.isZero() && this->y.isZero(); 23 | } 24 | 25 | BigInteger ECPoint::getX() const 26 | { 27 | return this->x; 28 | } 29 | 30 | BigInteger ECPoint::getY() const 31 | { 32 | return this->y; 33 | } 34 | 35 | bool ECPoint::operator==( ECPoint &p ) 36 | { 37 | if( this->x == p.x && this->y == p.y ) { 38 | return true; 39 | } else { 40 | return false; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/client/client/cpu/math/x86/x86.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script for generating x86 assembly code for big integer routines 4 | echo "section .text" > x86.asm 5 | 6 | for ((bits=64; bits <=256; bits+=32)) 7 | do 8 | python gen.py add $bits >> x86.asm 9 | if [ $? -ne 0 ]; then 10 | echo "Error" 11 | exit 12 | fi 13 | python gen.py sub $bits >> x86.asm 14 | if [ $? -ne 0 ]; then 15 | echo "Error" 16 | exit 17 | fi 18 | python gen.py mul $bits >> x86.asm 19 | if [ $? -ne 0 ]; then 20 | echo "Error" 21 | exit 22 | fi 23 | python gen.py square $bits >> x86.asm 24 | if [ $? -ne 0 ]; then 25 | echo "Error" 26 | exit 27 | fi 28 | python gen.py mul2n $bits >> x86.asm 29 | if [ $? -ne 0 ]; then 30 | echo "Error" 31 | exit 32 | fi 33 | done 34 | -------------------------------------------------------------------------------- /src/client/client/cuda/cudapp.h: -------------------------------------------------------------------------------- 1 | #ifndef _CUDAPP_H 2 | #define _CUDAPP_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace CUDA { 9 | typedef struct { 10 | unsigned int major; 11 | unsigned int minor; 12 | unsigned int mpCount; 13 | unsigned int cores; 14 | unsigned long long globalMemory; 15 | std::string name; 16 | }DeviceInfo; 17 | 18 | void memcpy(void *dest, const void *src, size_t count, enum cudaMemcpyKind kind); 19 | void *malloc(size_t); 20 | void *hostAlloc(size_t size, unsigned int flags); 21 | void free(void *ptr); 22 | void setDevice(int device); 23 | void setDeviceFlags(unsigned int flags); 24 | void *getDevicePointer(void *hostPtr, unsigned int flags); 25 | int getDeviceCount(); 26 | void getDeviceInfo(int device, DeviceInfo &devInfo); 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/client/threads/win32.cpp: -------------------------------------------------------------------------------- 1 | #include "threads.h" 2 | 3 | Thread::Thread() 4 | { 5 | } 6 | 7 | Thread::Thread(DWORD (*routine)(LPVOID), void *arg) 8 | { 9 | this->handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)routine, arg, 0, &this->id); 10 | 11 | if( thread == NULL ) { 12 | throw "Error creating thread"; 13 | } 14 | } 15 | 16 | void Thread::kill() 17 | { 18 | CloseHandle(this->handle); 19 | } 20 | 21 | void Thread::wait() 22 | { 23 | WaitForSingleObject(this->handle, INFINITE); 24 | } 25 | 26 | 27 | 28 | 29 | Mutex::Mutex() 30 | { 31 | this->handle = CreateMutex(NULL, FALSE, NULL); 32 | } 33 | 34 | Mutex::~Mutex() 35 | { 36 | CloseHandle(this->handle); 37 | } 38 | 39 | void Mutex::grab() 40 | { 41 | if(WaitForSingleObject( mutex->handle, INFINITE) != 0) { 42 | throw "Error waiting for mutex"; 43 | } 44 | } 45 | 46 | void Mutex::release() 47 | { 48 | ReleaseMutex(this->handle); 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/client/include/threads.h: -------------------------------------------------------------------------------- 1 | #ifndef _THREADS_H 2 | #define _THREADS_H 3 | 4 | #ifdef WIN32 5 | /* Use windows threading */ 6 | 7 | #include 8 | 9 | typedef DWORD THREAD_FUNCTION; 10 | typedef LPVOID VOID_PTR; 11 | 12 | #else 13 | 14 | /* Use POSIX threading */ 15 | #include 16 | 17 | typedef void* THREAD_FUNCTION; 18 | typedef void* VOID_PTR; 19 | #endif 20 | 21 | 22 | class Thread { 23 | private: 24 | #ifdef WIN32 25 | HANDLE handle; 26 | DWORD id; 27 | #else 28 | pthread_t handle; 29 | #endif 30 | 31 | public: 32 | 33 | Thread(); 34 | Thread( THREAD_FUNCTION (*routine)(VOID_PTR), void *arg ); 35 | ~Thread(); 36 | void wait(); 37 | void kill(); 38 | }; 39 | 40 | class Mutex { 41 | private: 42 | #ifdef WIN32 43 | HANDLE handle; 44 | #else 45 | pthread_mutex_t handle; 46 | #endif 47 | 48 | public: 49 | Mutex(); 50 | ~Mutex(); 51 | void grab(); 52 | void release(); 53 | void destroy(); 54 | }; 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/client/include/Config.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONFIGFILE_H 2 | #define _CONFIGFILE_H 3 | 4 | #include 5 | #include 6 | 7 | class ConfigField { 8 | 9 | private: 10 | std::string _key; 11 | std::string _value; 12 | 13 | public: 14 | 15 | ConfigField() 16 | { 17 | 18 | } 19 | 20 | ConfigField(std::string key, std::string value) 21 | { 22 | _key = key; 23 | _value = value; 24 | } 25 | 26 | int asInt() 27 | { 28 | return atoi(_value.c_str()); 29 | } 30 | 31 | std::string asString() 32 | { 33 | return _value; 34 | } 35 | }; 36 | 37 | class ConfigFile { 38 | 39 | private: 40 | 41 | std::map _fields; 42 | 43 | 44 | public: 45 | 46 | static ConfigFile parse(const std::string &path); 47 | 48 | bool contains (const std::string &key); 49 | 50 | ConfigField get(const std::string &key); 51 | 52 | ConfigField get(const std::string &key, const std::string &defaultValue); 53 | }; 54 | 55 | #endif -------------------------------------------------------------------------------- /src/client/client/cpu/math/Fp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "BigInteger.h" 4 | 5 | #include "Fp.h" 6 | 7 | /** 8 | * Prints a big integer in hex format to stdout 9 | */ 10 | void printInt(const unsigned long *x, int len) 11 | { 12 | for(int i = len - 1; i >= 0; i--) { 13 | #ifdef _X86 14 | printf("%.8x", x[i]); 15 | #else 16 | printf("%.16lx", x[i]); 17 | #endif 18 | } 19 | printf("\n"); 20 | } 21 | 22 | FpBase *getFp(BigInteger &p) 23 | { 24 | int pLen = p.getWordLength(); 25 | 26 | switch(pLen) { 27 | case 1: 28 | return new Fp<1>(p); 29 | case 2: 30 | return new Fp<2>(p); 31 | case 3: 32 | return new Fp<3>(p); 33 | case 4: 34 | return new Fp<4>(p); 35 | case 5: 36 | return new Fp<5>(p); 37 | case 6: 38 | return new Fp<6>(p); 39 | case 7: 40 | return new Fp<7>(p); 41 | case 8: 42 | return new Fp<8>(p); 43 | } 44 | 45 | throw "Compile for larger integers"; 46 | } -------------------------------------------------------------------------------- /src/client/ecc/jacobian.cpp: -------------------------------------------------------------------------------- 1 | #include "BigInteger.h" 2 | #include "ecc.h" 3 | 4 | ECPointJacobian::ECPointJacobian() 5 | { 6 | } 7 | 8 | ECPointJacobian::ECPointJacobian( const BigInteger &x, const BigInteger &y ) 9 | { 10 | this->x = x; 11 | this->y = y; 12 | this->z = BigInteger( 1 ); 13 | } 14 | 15 | ECPointJacobian::ECPointJacobian( const BigInteger &x, const BigInteger &y, const BigInteger &z ) 16 | { 17 | this->x = x; 18 | this->y = y; 19 | this->z = z; 20 | } 21 | 22 | ECPointJacobian::ECPointJacobian( const ECPointJacobian &p ) 23 | { 24 | this->x = p.x; 25 | this->y = p.y; 26 | this->z = p.z; 27 | } 28 | 29 | BigInteger ECPointJacobian::getX() 30 | { 31 | return this->x; 32 | } 33 | 34 | BigInteger ECPointJacobian::getY() 35 | { 36 | return this->y; 37 | } 38 | 39 | BigInteger ECPointJacobian::getZ() 40 | { 41 | return this->z; 42 | } 43 | 44 | bool ECPointJacobian::isPointAtInfinity() 45 | { 46 | if( this->x.isZero() && this->y.isZero() ) { 47 | return true; 48 | } else { 49 | return false; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /scripts/helper.py: -------------------------------------------------------------------------------- 1 | 2 | def parseInt(n): 3 | return int(n, 0) 4 | 5 | def read_int(prompt): 6 | s = raw_input(prompt) 7 | s.rstrip("0x") 8 | 9 | return parseInt(s); 10 | 11 | def read_string(prompt): 12 | return raw_input(prompt) 13 | 14 | def main(): 15 | 16 | p = read_int("p:") 17 | 18 | a = read_int("a:") 19 | 20 | b = read_int("b:") 21 | 22 | n = read_int("n:") 23 | 24 | gx = read_int("Gx:") 25 | 26 | gy = read_int("Gy:") 27 | 28 | qx = read_int("Qx:") 29 | 30 | qy = read_int("Qy:") 31 | 32 | dBits = read_int("distinguished bits:") 33 | 34 | filename = read_string("Filename:") 35 | 36 | data = {} 37 | data['params'] = {} 38 | data['params']['field'] = "prime" 39 | data['params']['a'] = str(a) 40 | data['params']['b'] = str(b) 41 | data['params']['p'] = str(p) 42 | data['params']['n'] = str(n) 43 | data['params']['gx'] = str(gx) 44 | data['params']['gy'] = str(gy) 45 | data['params']['qx'] = str(qx) 46 | data['params']['qy'] = str(qy) 47 | data['params']['bits'] = dBits 48 | 49 | dataStr = str(data).replace("\'", "\"") 50 | f = file(filename, 'w') 51 | f.write(dataStr) 52 | f.close() 53 | 54 | if __name__ == "__main__": 55 | main() 56 | -------------------------------------------------------------------------------- /src/client/threads/posix.cpp: -------------------------------------------------------------------------------- 1 | #include "threads.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | Thread::Thread() 8 | { 9 | } 10 | 11 | Thread::Thread(THREAD_FUNCTION (*routine)(VOID_PTR), void *arg) 12 | { 13 | int r = pthread_create(&this->handle, NULL, routine, arg); 14 | 15 | if(r != 0) { 16 | throw "Error creating new thread"; 17 | } 18 | } 19 | 20 | Thread::~Thread() 21 | { 22 | } 23 | 24 | void Thread::kill() 25 | { 26 | int r = pthread_cancel(this->handle); 27 | if(r != 0) { 28 | throw "Error killing thread"; 29 | } 30 | } 31 | 32 | void Thread::wait() 33 | { 34 | pthread_join(this->handle, NULL); 35 | } 36 | 37 | 38 | Mutex::Mutex() 39 | { 40 | if(pthread_mutex_init(&this->handle, NULL)) { 41 | throw "Error creating mutex"; 42 | } 43 | } 44 | 45 | void Mutex::destroy() 46 | { 47 | pthread_mutex_destroy(&this->handle); 48 | } 49 | 50 | Mutex::~Mutex() 51 | { 52 | } 53 | 54 | void Mutex::grab() 55 | { 56 | if(pthread_mutex_lock(&this->handle)) { 57 | printf("Error locking mutex: %s\n", strerror(errno)); 58 | } 59 | } 60 | 61 | void Mutex::release() 62 | { 63 | if(pthread_mutex_unlock(&this->handle)) { 64 | printf("Error unlocking mutex: %s\n", strerror(errno)); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/client/client/config.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "client.h" 3 | #include "json/json.h" 4 | #include "Config.h" 5 | 6 | static std::string readFile(std::string fileName) 7 | { 8 | std::ifstream file(fileName.c_str()); 9 | std::string s; 10 | std::string buf; 11 | 12 | while(std::getline(file, buf)) { 13 | s += buf; 14 | } 15 | 16 | return s; 17 | } 18 | 19 | ClientConfig loadConfig(std::string fileName) 20 | { 21 | ClientConfig configObj; 22 | ConfigFile config = ConfigFile::parse(fileName); 23 | 24 | configObj.serverHost = config.get("server_host", "").asString(); 25 | configObj.serverPort = config.get("server_port", "-1").asInt(); 26 | configObj.pointCacheSize = config.get("point_cache_size").asInt(); 27 | 28 | #ifdef _CUDA 29 | configObj.threads = config.get("cuda_threads", "32").asInt(); 30 | configObj.blocks = config.get("cuda_blocks", "1").asInt(); 31 | configObj.pointsPerThread = config.get("cuda_points_per_thread").asInt(); 32 | configObj.device = config.get("cuda_device").asInt(); 33 | configObj.pointCacheSize = config.get("point_cache_size", "4").asInt(); 34 | #else 35 | configObj.threads = config.get("cpu_threads", "-1").asInt(); 36 | configObj.pointsPerThread = config.get("cpu_points_per_thread", "-1").asInt(); 37 | #endif 38 | 39 | return configObj; 40 | } 41 | -------------------------------------------------------------------------------- /src/client/client/cuda/ECDLCuda.h: -------------------------------------------------------------------------------- 1 | #ifndef _ECDL_CUDA_H 2 | #define _ECDL_CUDA_H 3 | 4 | #include "ecc.h" 5 | #include "BigInteger.h" 6 | #include "ECDLContext.h" 7 | #include "RhoCUDA.h" 8 | #include "cudapp.h" 9 | 10 | class ECDLCudaContext : public ECDLContext { 11 | 12 | private: 13 | RhoCUDA *_rho; 14 | ECDLPParams _params; 15 | ECCurve _curve; 16 | void (*_callback)(struct CallbackParameters *); 17 | 18 | BigInteger _rx[NUM_R_POINTS]; 19 | BigInteger _ry[NUM_R_POINTS]; 20 | 21 | unsigned int _device; 22 | unsigned int _blocks; 23 | unsigned int _threads; 24 | unsigned int _totalPoints; 25 | int _pointsPerThread; 26 | int _rPoints; 27 | 28 | public: 29 | 30 | virtual ~ECDLCudaContext(); 31 | virtual bool init(); 32 | virtual void reset(); 33 | virtual bool run(); 34 | virtual bool stop(); 35 | virtual bool isRunning(); 36 | 37 | ECDLCudaContext( int device, 38 | unsigned int blocks, 39 | unsigned int threads, 40 | unsigned int pointsPerThread, 41 | const ECDLPParams *params, 42 | const BigInteger *rx, 43 | const BigInteger *ry, 44 | int rPoints, 45 | void (*callback)(struct CallbackParameters *)); 46 | 47 | virtual bool benchmark(unsigned long long *pointsPerSecond); 48 | }; 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/client/client/Makefile: -------------------------------------------------------------------------------- 1 | CPPSRC:=$(wildcard *.cpp) 2 | CPPSRC:=$(filter-out fp_test.cpp, $(CPPSRC)) 3 | CPPSRC:=$(filter-out jsoncpp.cpp, $(CPPSRC)) 4 | CPPSRC:=$(filter-out ecctest.cpp, $(CPPSRC)) 5 | CPPSRC:=$(filter-out tle_test.cpp, $(CPPSRC)) 6 | 7 | all: client_cuda client_cpu 8 | 9 | cuda_lib: 10 | make --directory cuda 11 | 12 | json_lib: 13 | ${CXX} -c jsoncpp.cpp -o jsoncpp.o -O2 -I./ 14 | 15 | client_cuda: cuda_lib json_lib 16 | ${CXX} -o client-cuda ${CPPSRC} jsoncpp.o ${INCLUDE} ${LIBS} ${CXXFLAGS} -D_CUDA -I./ -Icuda cuda/cuda.a -L${CUDA_LIB} -I${CUDA_INCLUDE} -lbigint -lutil -lecc -lgmp -llogger -lsha256 -lthread -lpthread -lcudart -lcurl -ltle -lconfigfile 17 | 18 | cpu_lib: 19 | make --directory cpu 20 | 21 | client_cpu: cpu_lib json_lib fp_test 22 | ${CXX} -o client-cpu ${CPPSRC} jsoncpp.o ${INCLUDE} ${LIBS} ${CXXFLAGS} -D_CPU -I./ -Icpu cpu/cpu.a -lbigint -lsha256 -lutil -lecc -lgmp -llogger -lthread -lpthread -lcurl -ltle -lconfigfile 23 | 24 | fp_test: cpu_lib 25 | ${CXX} -o fp_test.bin fp_test.cpp ${INCLUDE} ${LIBS} -Icpu/math -Icpu/math/gmp cpu/cpu.a -lbigint -lgmp -lutil 26 | 27 | ecc_test: 28 | ${CXX} -o ecc_test ecctest.cpp ${INCLUDE} ${LIBS} ${CXXFLAGS} -I./ -lbigint -lutil -lecc -lgmp 29 | 30 | #tle_test: 31 | # ${CXX} -o tle_test tle_test.cpp ${INCLUDE} ${LIBS} ${CXXFLAGS} -I./ -lbigint -lgmp -ltle -lutil 32 | 33 | clean: 34 | rm -f *.o 35 | rm -f client-cuda 36 | rm -f client-cpu 37 | rm -f fp_test.bin 38 | rm -f ecc_test 39 | make --directory cuda clean 40 | make --directory cpu clean 41 | -------------------------------------------------------------------------------- /src/client/configfile/ConfigFile.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "Config.h" 5 | 6 | static std::string trim(std::string s, char c) 7 | { 8 | int start = s.find_first_not_of(c); 9 | int end = s.find_last_not_of(c); 10 | 11 | return s.substr(start, end-start); 12 | } 13 | 14 | static bool getFields(std::string s, std::string &left, std::string &right) 15 | { 16 | int eq = s.find("="); 17 | 18 | if(eq == -1) { 19 | return false; 20 | } 21 | 22 | left = trim(s.substr(0, eq), ' '); 23 | right = trim(s.substr(eq), ' '); 24 | } 25 | 26 | ConfigFile ConfigFile::parse(const std::string &path) 27 | { 28 | std::ifstream fs(path.c_str()); 29 | 30 | std::string line; 31 | 32 | ConfigFile config; 33 | 34 | while(std::getline(fs, line)) { 35 | 36 | std::string left; 37 | std::string right; 38 | 39 | if(!getFields(line, left, right)) { 40 | continue; 41 | } 42 | 43 | config._fields.insert(std::pair(left, ConfigField(left, right))); 44 | } 45 | 46 | return config; 47 | } 48 | 49 | ConfigField ConfigFile::get(const std::string &fieldName) 50 | { 51 | return _fields[fieldName]; 52 | } 53 | 54 | ConfigField ConfigFile::get(const std::string &fieldName, const std::string &defaultValue) 55 | { 56 | if(_fields.find(fieldName) != _fields.end()) { 57 | return _fields[fieldName]; 58 | } 59 | 60 | return ConfigField(fieldName, defaultValue); 61 | } -------------------------------------------------------------------------------- /src/client/client/cpu/math/gmp/gmp_math.h: -------------------------------------------------------------------------------- 1 | #ifndef _GMP_MATH_H 2 | #define _GMP_MATH_H 3 | #include 4 | 5 | template int sub(const unsigned long *a, const unsigned long *b, unsigned long *diff) 6 | { 7 | return mpn_sub_n((long unsigned int *)diff, (const long unsigned int *)a, (const long unsigned int *)b, N); 8 | } 9 | 10 | template< int N> void add(const unsigned long *a, const unsigned long *b, unsigned long *sum) 11 | { 12 | mpn_add_n((long unsigned int *)sum, (const long unsigned int *)a, (const long unsigned int *)b, N); 13 | } 14 | 15 | template void mul(const unsigned long *a, const unsigned long *b, unsigned long *product) 16 | { 17 | mpn_mul_n((long unsigned int *)product, (const long unsigned int *)a, (const long unsigned int *)b, N); 18 | } 19 | 20 | template void mul(const unsigned long *a, const unsigned long *b, unsigned long *product) 21 | { 22 | mpn_mul((long unsigned int *)product, (const long unsigned int *)a, N1, (const long unsigned int *)b, N2); 23 | } 24 | 25 | template void square(const unsigned long *a, unsigned long *product) 26 | { 27 | mpn_sqr((long unsigned int*)product, (long unsigned int *)a, N); 28 | } 29 | 30 | /** 31 | * Returns true if a >= b 32 | */ 33 | template bool greaterThanEqualTo(const unsigned long *a, const unsigned long *b) 34 | { 35 | for(int i = N - 1; i >= 0; i--) { 36 | if(a[i] < b[i]) { 37 | return false; 38 | } else if(a[i] > b[i]) { 39 | return true; 40 | } 41 | } 42 | 43 | return true; 44 | } 45 | 46 | #endif -------------------------------------------------------------------------------- /src/client/logger/logger.cpp: -------------------------------------------------------------------------------- 1 | #include"logger.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static std::string getDateString() 9 | { 10 | time_t rawtime; 11 | struct tm * timeinfo; 12 | char buffer[128]; 13 | 14 | time (&rawtime); 15 | timeinfo = localtime(&rawtime); 16 | 17 | strftime(buffer,128,"%d-%m-%Y %I:%M:%S",timeinfo); 18 | 19 | return std::string(buffer); 20 | 21 | } 22 | 23 | void Logger::logInfo(std::string s) 24 | { 25 | std::string dateTime = getDateString(); 26 | 27 | fprintf(stdout, "[%s] ", dateTime.c_str()); 28 | fprintf(stdout, "%s\n", s.c_str()); 29 | } 30 | 31 | void Logger::logInfo(const char *format, ...) 32 | { 33 | va_list args; 34 | 35 | std::string dateTime = getDateString(); 36 | 37 | fprintf(stdout, "[%s] ", dateTime.c_str()); 38 | va_start(args, format); 39 | vfprintf(stdout,format, args); 40 | fprintf(stdout, "\n"); 41 | va_end(args); 42 | } 43 | 44 | void Logger::logError(std::string s) 45 | { 46 | std::string dateTime = getDateString(); 47 | 48 | fprintf(stdout, "[%s] ", dateTime.c_str()); 49 | fprintf(stdout, "%s\n", s.c_str()); 50 | } 51 | 52 | 53 | void Logger::logError(const char *format, ...) 54 | { 55 | std::string dateTime = getDateString(); 56 | 57 | fprintf(stderr, "[%s] ", dateTime.c_str()); 58 | 59 | va_list args; 60 | va_start(args, format); 61 | fprintf(stderr, "[ERROR] "); 62 | vfprintf(stderr, format, args); 63 | fprintf(stderr, "\n"); 64 | va_end(args); 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/client/client/ServerConnection.h: -------------------------------------------------------------------------------- 1 | #ifndef _SERVER_H 2 | #define _SERVER_H 3 | 4 | #include 5 | #include "BigInteger.h" 6 | 7 | #define DEFAULT_PORT 9999 8 | 9 | enum { 10 | SERVER_STATUS_RUNNING, 11 | SERVER_STATUS_STOPPED 12 | }; 13 | 14 | /** 15 | * Stores all the parameters that the server sends to the client 16 | */ 17 | class ParamsMsg { 18 | 19 | public: 20 | unsigned int dBits; 21 | BigInteger p; 22 | BigInteger a; 23 | BigInteger b; 24 | BigInteger n; 25 | BigInteger gx; 26 | BigInteger gy; 27 | BigInteger qx; 28 | BigInteger qy; 29 | BigInteger rx[32]; 30 | BigInteger ry[32]; 31 | }; 32 | 33 | /** 34 | * Represents a distinguished point 35 | */ 36 | class DistinguishedPoint { 37 | 38 | public: 39 | DistinguishedPoint(BigInteger &a, BigInteger &b, BigInteger &x, BigInteger &y, unsigned int length) 40 | { 41 | this->a = a; 42 | this->b = b; 43 | this->x = x; 44 | this->y = y; 45 | this->length = length; 46 | } 47 | 48 | BigInteger a; 49 | BigInteger b; 50 | BigInteger x; 51 | BigInteger y; 52 | unsigned int length; 53 | }; 54 | 55 | /** 56 | * Represents a connection the server 57 | */ 58 | class ServerConnection { 59 | 60 | private: 61 | int _port; 62 | std::string _host; 63 | std::string _url; 64 | 65 | public: 66 | ServerConnection(std::string host, int port=DEFAULT_PORT); 67 | 68 | int getStatus(std::string id); 69 | ParamsMsg getParameters(std::string id); 70 | void submitPoints(std::string id, std::vector &points); 71 | }; 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /src/client/client/fp_test.cpp: -------------------------------------------------------------------------------- 1 | #include "Fp.h" 2 | 3 | void printInt(const unsigned long *x, int len) 4 | { 5 | for(int i = len - 1; i >= 0; i--) { 6 | #ifdef _X86 7 | printf("%.8x", x[i]); 8 | #else 9 | printf("%.16lx", x[i]); 10 | #endif 11 | } 12 | printf("\n"); 13 | } 14 | 15 | int main(int argc, char **argv) 16 | { 17 | for(int i = 0; i < 100000000; i++) { 18 | //BigInteger a("1c0d76b18c305fbd771", 16); 19 | //BigInteger b("1c0d76b18c305fbd771", 16); 20 | BigInteger p("8369143598070916186121", 10); 21 | BigInteger a = randomBigInteger(2, p); 22 | //BigInteger b = randomBigInteger(2, p); 23 | BigInteger b = a; 24 | 25 | /* 26 | printf("%s\n", a.toString().c_str()); 27 | printf("%s\n", b.toString().c_str()); 28 | printf("%s\n", p.toString().c_str()); 29 | */ 30 | 31 | unsigned long x[2] = {0}; 32 | unsigned long y[2] = {0}; 33 | unsigned long z[2] = {0}; 34 | 35 | 36 | a.getWords(x, 2); 37 | b.getWords(y, 2); 38 | 39 | Fp<2> fp(p); 40 | 41 | //fp.multiplyModP(x, y, z); 42 | fp.squareModP(x, z); 43 | 44 | BigInteger zBig(z, 2); 45 | BigInteger product = (a * b) % p; 46 | 47 | if(zBig != product) { 48 | printf("%s\n", a.toString().c_str()); 49 | printf("%s\n", b.toString().c_str()); 50 | printf("%s\n", p.toString().c_str()); 51 | printf("%s\n", zBig.toString().c_str()); 52 | printf("%s\n", product.toString().c_str()); 53 | printf("Error!\n"); 54 | break; 55 | } 56 | 57 | } 58 | return 0; 59 | } -------------------------------------------------------------------------------- /src/client/client/cpu/RhoCPU.h: -------------------------------------------------------------------------------- 1 | #ifndef _RHO_CPU_H 2 | #define _RHO_CPU_H 3 | 4 | #include "ecc.h" 5 | #include "Fp.h" 6 | #include "ECDLContext.h" 7 | 8 | //#define N 8 9 | #define FP_MAX 8 10 | 11 | class RhoBase { 12 | 13 | public: 14 | virtual void doStep() = 0; 15 | }; 16 | 17 | 18 | class RhoCPU : public RhoBase { 19 | 20 | private: 21 | 22 | ECPoint _g; 23 | ECPoint _q; 24 | ECDLPParams _params; 25 | ECCurve _curve; 26 | 27 | // Starting G and Q coefficients 28 | BigInteger *_a; 29 | BigInteger *_b; 30 | 31 | // Current X and Y coordinates 32 | unsigned long *_x; 33 | unsigned long *_y; 34 | 35 | // R points 36 | unsigned long *_rx; 37 | unsigned long *_ry; 38 | 39 | // Buffers for simultaneous inversion 40 | unsigned long *_diffBuf; 41 | unsigned long *_chainBuf; 42 | 43 | // Length of each walk 44 | unsigned long long *_lengthBuf; 45 | 46 | unsigned int _pointsInParallel; 47 | unsigned int _rPointMask; 48 | unsigned long _dBitsMask; 49 | unsigned int _pLen; 50 | 51 | FpBase *_fp; 52 | 53 | void (*_callback)(struct CallbackParameters *); 54 | 55 | void generateStartingPoint(BigInteger &x, BigInteger &y, BigInteger &a, BigInteger &b); 56 | bool checkDistinguishedBits(const unsigned long *x); 57 | 58 | void doStepSingle(); 59 | void doStepMulti(); 60 | 61 | public: 62 | RhoCPU(const ECDLPParams *params, 63 | const BigInteger *rx, 64 | const BigInteger *ry, 65 | int numRPoints, 66 | int numPoints, 67 | void (*callback)(struct CallbackParameters *) 68 | ); 69 | virtual ~RhoCPU(); 70 | 71 | virtual void doStep(); 72 | }; 73 | 74 | #endif -------------------------------------------------------------------------------- /scripts/gencurve.sage: -------------------------------------------------------------------------------- 1 | ''' 2 | Sage script for generating an elliptic curve over a prime field 3 | of the given bit size. The curve has a prime order. A generator 4 | of the group and a random element are also selected. The data is 5 | written to a file in json format. 6 | ''' 7 | 8 | def generate_ecdlp(bits, filename): 9 | 10 | print("Generating " + str(bits) + "-bit curve") 11 | 12 | curve, a, b, n, p = generate_curve(bits) 13 | g = curve.gens() 14 | q = curve.random_element() 15 | gx = g[0][0] 16 | gy = g[0][1] 17 | qx = q.xy()[0] 18 | qy = q.xy()[1] 19 | 20 | print("Modulus: " + str(p)) 21 | print("a: " + str(a)) 22 | print("b: " + str(b)) 23 | print("order: " + str(curve.order())) 24 | print("G: (" + str(gx) + "," + str(gy) + ")") 25 | print("Q: (" + str(qx) + "," + str(qy) + ")") 26 | 27 | data = {} 28 | data['params'] = {} 29 | data['params']['field'] = "prime" 30 | data['params']['a'] = str(a) 31 | data['params']['b'] = str(b) 32 | data['params']['p'] = str(p) 33 | data['params']['n'] = str(n) 34 | data['params']['gx'] = str(gx) 35 | data['params']['gy'] = str(gy) 36 | data['params']['qx'] = str(qx) 37 | data['params']['qy'] = str(qy) 38 | data['params']['bits'] = 24 39 | 40 | dataStr = str(data).replace("\'", "\"") 41 | f = file(filename, 'w') 42 | f.write(dataStr) 43 | f.close() 44 | 45 | exit() 46 | 47 | def randint(low, high): 48 | return low + int((high-low)*random() ) 49 | 50 | def generate_curve(bits): 51 | low = 2^(bits-1)+1 52 | high = 2^(bits)-1 53 | p = next_prime(randint(low, high)) 54 | field = GF(p) 55 | 56 | while True: 57 | a = randint(1, p) 58 | b = randint(1, p) 59 | curve = EllipticCurve(field,[a,b]) 60 | order = curve.order() 61 | if order < p and order > low and order in Primes(): 62 | return curve, a, b, order, p 63 | -------------------------------------------------------------------------------- /src/server/PointDatabase.py: -------------------------------------------------------------------------------- 1 | 2 | class PointDatabase: 3 | 4 | def createContext(self, name, email, params, rPoints): 5 | raise NotImplementedError("This should be implemented in subclass") 6 | 7 | def getConnection(self, name): 8 | raise NotImplementedError("This should be implemented in subclass") 9 | 10 | ''' 11 | Abstract class for hashtable to storing distinguished points 12 | ''' 13 | class PointDatabaseConnection: 14 | 15 | ''' 16 | Check if the database contains a distinguished point with the given 17 | x value 18 | ''' 19 | def contains(self, x, y): 20 | raise NotImplementedError("This should be implemented in subclass") 21 | 22 | ''' 23 | Insert a distinguished point into the database 24 | a: 'a' value of the starting point 25 | b: 'b' value of the starting point 26 | x: 'x' value of the distinguished point 27 | y: 'y' value of the distinguished point 28 | ''' 29 | def insert(self, a, b, x, y, length): 30 | raise NotImplementedError("This should be implemented in subclass") 31 | 32 | ''' 33 | Insert an array of distinguished points into the database 34 | Each element is a dictionary in the form 35 | 'a': a value 36 | 'b': b value 37 | 'x': distinguished x 38 | 'y': distinguished y 39 | ''' 40 | def insertMultiple(self, points): 41 | raise NotImplementedError("This should be implemented in subclass") 42 | 43 | ''' 44 | Look up a distinguished point based on the x value 45 | Returns an object containing a, b, x, y 46 | ''' 47 | def get(self, x, y): 48 | raise NotImplementedError("This should be implemented in subclass") 49 | 50 | def getSize(): 51 | raise NotImplementedError("This should be implemented in subclass") 52 | 53 | def getRPoints(self): 54 | raise NotImplementedError("This shou,d be implemented in subclass") 55 | 56 | def getParams(self): 57 | raise NotImplementedError("This shou,d be implemented in subclass") 58 | 59 | def open(self): 60 | raise NotImplementedError("This shou,d be implemented in subclass") 61 | 62 | def close(self): 63 | raise NotImplementedError("This shou,d be implemented in subclass") 64 | -------------------------------------------------------------------------------- /src/client/client/cuda/ECDLCudaContext.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "logger.h" 6 | #include "ECDLCuda.h" 7 | #include "ecc.h" 8 | #include "BigInteger.h" 9 | #include "util.h" 10 | 11 | 12 | ECDLCudaContext::ECDLCudaContext( int device, 13 | unsigned int blocks, 14 | unsigned int threads, 15 | unsigned int pointsPerThread, 16 | const ECDLPParams *params, 17 | const BigInteger *rx, 18 | const BigInteger *ry, 19 | int rPoints, 20 | void (*callback)(struct CallbackParameters *)) 21 | { 22 | _device = device; 23 | _blocks = blocks; 24 | _threads = threads; 25 | _pointsPerThread = pointsPerThread; 26 | _params = *params; 27 | 28 | for(int i = 0; i < rPoints; i++) { 29 | _rx[i] = rx[i]; 30 | _ry[i] = ry[i]; 31 | } 32 | 33 | _rPoints = rPoints; 34 | _callback = callback; 35 | 36 | _rho = NULL; 37 | Logger::logInfo("ECDLCudaContext created"); 38 | } 39 | 40 | ECDLCudaContext::~ECDLCudaContext() 41 | { 42 | delete _rho; 43 | } 44 | 45 | bool ECDLCudaContext::init() 46 | { 47 | Logger::logInfo("Creating RhoCUDA..."); 48 | _rho = new RhoCUDA(_device, _blocks, _threads, _pointsPerThread, &_params, _rx, _ry, _rPoints, _callback); 49 | _rho->init(); 50 | 51 | return true; 52 | } 53 | 54 | bool ECDLCudaContext::run() 55 | { 56 | return _rho->run(); 57 | } 58 | 59 | void ECDLCudaContext::reset() 60 | { 61 | _rho->reset(); 62 | } 63 | 64 | bool ECDLCudaContext::stop() 65 | { 66 | _rho->stop(); 67 | 68 | return true; 69 | } 70 | 71 | bool ECDLCudaContext::isRunning() 72 | { 73 | return _rho->isRunning(); 74 | } 75 | 76 | bool ECDLCudaContext::benchmark(unsigned long long *pointsPerSecond) 77 | { 78 | if (_rho != NULL) { 79 | throw std::string("Cannot run benchmark. GPU is currently busy"); 80 | } 81 | 82 | RhoCUDA *r = new RhoCUDA(_device, _blocks, _threads, _pointsPerThread, &_params, _rx, _ry, _rPoints, _callback); 83 | 84 | r->init(); 85 | r->benchmark(pointsPerSecond); 86 | 87 | delete r; 88 | 89 | return true; 90 | } -------------------------------------------------------------------------------- /src/client/client/cpu/ECDLCPU.h: -------------------------------------------------------------------------------- 1 | #ifndef _ECDL_CPU_H 2 | #define _ECDL_CPU_H 3 | 4 | #include "threads.h" 5 | #include "BigInteger.h" 6 | #include "ecc.h" 7 | 8 | #include "ECDLContext.h" 9 | 10 | #include 11 | 12 | class ECDLCpuContext; 13 | class RhoBase; 14 | 15 | typedef struct { 16 | ECDLCpuContext *instance; 17 | int threadId; 18 | }WorkerThreadParams; 19 | 20 | typedef struct { 21 | ECDLCpuContext *instance; 22 | int threadId; 23 | unsigned long long iterationsPerSecond; 24 | }BenchmarkThreadParams; 25 | 26 | 27 | 28 | class ECDLCpuContext : public ECDLContext { 29 | 30 | private: 31 | 32 | // Problem parameters 33 | ECDLPParams _params; 34 | ECCurve _curve; 35 | 36 | // Number of threads 37 | int _numThreads; 38 | 39 | // Workers 40 | std::vector _workerThreads; 41 | std::vector _workerThreadParams; 42 | std::vector _workerCtx; 43 | 44 | // Flag to indicate if the threads are running 45 | volatile bool _running; 46 | 47 | // Callback that gets called when distinguished point is found 48 | void (*_callback)(struct CallbackParameters *); 49 | 50 | // Number of points each thread works on in parallel 51 | unsigned int _pointsPerThread; 52 | 53 | // R-points 54 | int _rPoints; 55 | BigInteger _rx[ NUM_R_POINTS ]; 56 | BigInteger _ry[ NUM_R_POINTS ]; 57 | 58 | static void *workerThreadEntry(void *ptr); 59 | static void *benchmarkThreadEntry(void *ptr); 60 | 61 | void workerThreadFunction(int threadId); 62 | void benchmarkThreadFunction(unsigned long long *iterationsPerSecond); 63 | 64 | RhoBase *getRho(bool callback = true); 65 | 66 | public: 67 | 68 | virtual bool init(); 69 | void reset(); 70 | virtual bool run(); 71 | virtual bool stop(); 72 | virtual bool isRunning(); 73 | virtual bool benchmark(unsigned long long *pointsPerSecond); 74 | 75 | ECDLCpuContext( 76 | unsigned int threads, 77 | unsigned int pointsPerThread, 78 | const ECDLPParams *params, 79 | const BigInteger *rx, 80 | const BigInteger *ry, 81 | int rPoints, 82 | void (*callback)(struct CallbackParameters *) 83 | ); 84 | 85 | virtual ~ECDLCpuContext(); 86 | }; 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /src/client/util/util.cpp: -------------------------------------------------------------------------------- 1 | #include"util.h" 2 | #ifdef _WIN32 3 | #include 4 | #else 5 | #include 6 | #include 7 | #include 8 | #endif 9 | 10 | namespace util { 11 | 12 | unsigned int getSystemTime() 13 | { 14 | #ifdef _WIN32 15 | return GetTickCount(); 16 | #else 17 | struct timeval t; 18 | gettimeofday( &t, NULL ); 19 | return t.tv_sec * 1000 + t.tv_usec / 1000; 20 | #endif 21 | } 22 | 23 | Timer::Timer() 24 | { 25 | _startTime = 0; 26 | } 27 | 28 | void Timer::start() 29 | { 30 | _startTime = getSystemTime(); 31 | } 32 | 33 | unsigned int Timer::getTime() 34 | { 35 | return getSystemTime() - _startTime; 36 | } 37 | 38 | std::string hexEncode(const unsigned char *bytes, unsigned int len) 39 | { 40 | char buf[3] = {0}; 41 | std::string hex = ""; 42 | 43 | for(unsigned int i = 0; i < len; i++) { 44 | sprintf(buf, "%.2x", (unsigned int)bytes[i]); 45 | hex += std::string(buf); 46 | } 47 | 48 | return hex; 49 | } 50 | 51 | void hexDecode(std::string hex, unsigned char *bytes) 52 | { 53 | char hexByte[3] = {0}; 54 | const char *ptr = hex.c_str(); 55 | unsigned int len = hex.length(); 56 | 57 | for(unsigned int i = 0; i < len; i+=2) { 58 | hexByte[0] = ptr[i]; 59 | hexByte[1] = ptr[i+1]; 60 | hexByte[2] = '\0'; 61 | 62 | unsigned int value = 0; 63 | sscanf(hexByte, "%x", &value); 64 | bytes[i/2] = (unsigned char)value; 65 | } 66 | } 67 | 68 | void printHex(unsigned long x) 69 | { 70 | printf("%.*lx", (int)sizeof(unsigned long)*2, x); 71 | } 72 | 73 | void printHex(unsigned long *x, int len) 74 | { 75 | for(int i = len - 1; i >= 0; i--) { 76 | printf("%.*lx", (int)sizeof(unsigned long)*2, x[i]); 77 | } 78 | } 79 | 80 | void getRandomBytes(unsigned char *buf, unsigned int count) 81 | { 82 | for(unsigned int i = 0; i < count; i++) { 83 | buf[i] = (unsigned char)rand(); 84 | } 85 | } 86 | 87 | 88 | unsigned int toInt(const unsigned char *bytes) 89 | { 90 | unsigned int x = 0; 91 | x |= bytes[0] << 24; 92 | x |= bytes[1] << 16; 93 | x |= bytes[2] << 8; 94 | x |= bytes[3]; 95 | 96 | return x; 97 | } 98 | 99 | void fromInt(unsigned int x, unsigned char *bytes) 100 | { 101 | bytes[0] = (unsigned char)(x >> 24); 102 | bytes[1] = (unsigned char)(x >> 16); 103 | bytes[2] = (unsigned char)(x >> 8); 104 | bytes[3] = (unsigned char)x; 105 | } 106 | 107 | } -------------------------------------------------------------------------------- /src/server/curves.py: -------------------------------------------------------------------------------- 1 | from collections import namedtuple 2 | from ecc import ECCurve 3 | 4 | CurveParams = namedtuple("CurveParams", "p a b x y n") 5 | 6 | # 521r1 curve parameters 7 | secp521r1 = CurveParams( 8 | p = int('1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF',16), 9 | a = int('1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC',16), 10 | b = int('0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00',16), 11 | 12 | x = int('C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66', 16), 13 | y = int('11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650', 16), 14 | n = int('1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409', 16) 15 | ) 16 | 17 | # 256k1 curve parameters 18 | secp256k1 = CurveParams( 19 | p = int('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F', 16), 20 | a = int('0000000000000000000000000000000000000000000000000000000000000000', 16), 21 | b = int('0000000000000000000000000000000000000000000000000000000000000007', 16), 22 | 23 | x = int('79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798', 16), 24 | y = int('483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8', 16), 25 | n = int('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141', 16) 26 | ) 27 | 28 | # Certicom 131-bit challenge curve 29 | ecp131 = CurveParams( 30 | p = int('048E1D43F293469E33194C43186B3ABC0B',16), 31 | a = int('41CB121CE2B31F608A76FC8F23D73CB66', 16), 32 | b = int('2F74F717E8DEC90991E5EA9B2FF03DA58', 16), 33 | 34 | n = int('48E1D43F293469E317F7ED728F6B8E6F1', 16), 35 | x = int('03DF84A96B5688EF574FA91A32E197198A', 16), 36 | y = int('014721161917A44FB7B4626F36F0942E71', 16) 37 | ) 38 | 39 | def getCurveByName(curveName): 40 | curve = None 41 | if( curveName == "secp521r1" ): 42 | curve = secp521r1 43 | if( curveName == "secp256k1" ): 44 | curve = secp256k1 45 | if( curveName == "ecp131p" ): 46 | curve = ecp131 47 | 48 | if curve == None: 49 | return None 50 | 51 | return ECCurve(curve.a, curve.b, curve.p, curve.n, curve.x, curve.y) 52 | -------------------------------------------------------------------------------- /src/client/client/cuda/kernels.h: -------------------------------------------------------------------------------- 1 | #ifndef _ECDL_CUDA_KERNELS_H 2 | #define _ECDL_CUDA_KERNELS_H 3 | 4 | #include 5 | 6 | #define NUM_R_POINTS 32 // Must be a power of 2 7 | #define FIXED_R_MASK (NUM_R_POINTS-1) 8 | 9 | cudaError_t copyMultiplesToDevice( const unsigned int *px, 10 | const unsigned int *py, 11 | const unsigned int *qx, 12 | const unsigned int *qy, 13 | const unsigned int *gqx, 14 | const unsigned int *gqy, 15 | unsigned int len, 16 | unsigned int count ); 17 | 18 | cudaError_t copyRPointsToDevice(const unsigned int *rx, const unsigned int *ry, int length, int count); 19 | 20 | cudaError_t multiplyAddG( unsigned int blocks, 21 | unsigned int threads, 22 | unsigned int pointsPerThread, 23 | const unsigned int *a, 24 | const unsigned int *b, 25 | const unsigned int *gx, 26 | const unsigned int *gy, 27 | const unsigned int *qx, 28 | const unsigned int *qy, 29 | const unsigned int *gqx, 30 | const unsigned int *gqy, 31 | unsigned int *rx, 32 | unsigned int *ry, 33 | unsigned int *diffBuf, 34 | unsigned int *chainBuf, 35 | unsigned int step); 36 | 37 | cudaError_t resetPoints( unsigned int blocks, 38 | unsigned int threads, 39 | unsigned int pointsPerThread, 40 | unsigned int *rx, 41 | unsigned int *ry); 42 | 43 | cudaError_t cudaDoStep( int pLen, 44 | int blocks, 45 | int threads, 46 | int pointsPerThread, 47 | unsigned int *rx, 48 | unsigned int *ry, 49 | unsigned int *diffBuf, 50 | unsigned int *chainBuf, 51 | unsigned int *blockFlags, 52 | unsigned int *pointFlags); 53 | 54 | cudaError_t initDeviceParams(const unsigned int *p, unsigned int pBits, const unsigned int *m, unsigned int mBits, unsigned int dBits); 55 | 56 | cudaError_t initDeviceConstants(unsigned int numPoints); 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/client/include/ecc.h: -------------------------------------------------------------------------------- 1 | #ifndef _ECC_H 2 | #define _ECC_H 3 | 4 | #include "BigInteger.h" 5 | 6 | typedef struct { 7 | const char *p; 8 | const char *a; 9 | const char *b; 10 | const char *n; 11 | const char *bpx; 12 | const char *bpy; 13 | }ECParams; 14 | 15 | class ECPoint { 16 | 17 | public: 18 | 19 | ECPoint(); 20 | ECPoint(const ECPoint &p); 21 | ECPoint(const BigInteger &x, const BigInteger &y); 22 | 23 | BigInteger getX() const; 24 | BigInteger getY() const; 25 | 26 | BigInteger x; 27 | BigInteger y; 28 | 29 | bool isPointAtInfinity(); 30 | bool operator==(ECPoint &p); 31 | }; 32 | 33 | class ECPointJacobian { 34 | 35 | private: 36 | BigInteger x; 37 | BigInteger y; 38 | BigInteger z; 39 | 40 | public: 41 | ECPointJacobian(); 42 | ECPointJacobian(const ECPointJacobian &p); 43 | ECPointJacobian(const BigInteger &x, const BigInteger &y); 44 | ECPointJacobian(const BigInteger &x, const BigInteger &y, const BigInteger &z); 45 | 46 | BigInteger getX(); 47 | BigInteger getY(); 48 | BigInteger getZ(); 49 | bool isPointAtInfinity(); 50 | }; 51 | 52 | class ECCurve { 53 | 54 | private: 55 | BigInteger _a; 56 | BigInteger _b; 57 | BigInteger _n; 58 | BigInteger _p; 59 | BigInteger _bpx; 60 | BigInteger _bpy; 61 | 62 | public: 63 | ECCurve(); 64 | ECCurve(ECParams ¶ms); 65 | ECCurve(BigInteger p, BigInteger n, BigInteger a, BigInteger b, BigInteger bpx, BigInteger bpy); 66 | ECPoint getBasepoint(); 67 | 68 | ECPoint add(ECPoint &p, ECPoint &q); 69 | ECPoint doubl(ECPoint &p); 70 | ECPoint multiply(BigInteger &k, ECPoint &p); 71 | ECPointJacobian toJacobian(ECPoint &p); 72 | ECPoint toAffine(ECPointJacobian &p); 73 | ECPointJacobian addJacobian(ECPointJacobian &p, ECPointJacobian &q); 74 | ECPointJacobian doubleJacobian(ECPointJacobian &p); 75 | 76 | BigInteger a() const { return _a; }; 77 | BigInteger b() const { return _b; }; 78 | BigInteger p() const { return _p; }; 79 | BigInteger n() const { return _n; }; 80 | 81 | BigInteger compressPoint(ECPoint &p); 82 | 83 | bool pointExists(ECPoint &p); 84 | 85 | ECCurve &operator=(const ECCurve &p); 86 | }; 87 | 88 | void generateRPoints(ECCurve &curve, ECPoint &q, BigInteger *aAra, BigInteger *bAra, BigInteger *xAra, BigInteger *yAra, int n); 89 | void compressPoint(ECPoint &point, unsigned char *encoded); 90 | bool decompressPoint(const ECCurve &curve, const unsigned char *encoded, int len, ECPoint &out); 91 | int squareRootModP(const BigInteger &n, const BigInteger &p, BigInteger *out); 92 | #endif 93 | -------------------------------------------------------------------------------- /src/client/include/BigInteger.h: -------------------------------------------------------------------------------- 1 | #ifndef _BIG_INTEGER_H 2 | #define _BIG_INTEGER_H 3 | 4 | #include 5 | 6 | #ifdef _WIN32 7 | #include "mpirxx.h" 8 | #else 9 | #include "gmpxx.h" 10 | #endif 11 | 12 | #define GMP_BYTE_ORDER_MSB 1 13 | #define GMP_BYTE_ORDER_LSB -1 14 | 15 | #define GMP_ENDIAN_BIG 1 16 | #define GMP_ENDIAN_LITTLE -1 17 | #define GMP_ENDIAN_NATIVE 0 18 | 19 | class BigInteger { 20 | 21 | private: 22 | mpz_class e; 23 | 24 | public: 25 | BigInteger(); 26 | BigInteger( int i ); 27 | BigInteger( const BigInteger &i ); 28 | BigInteger( std::string s, int base = 0); 29 | BigInteger( const unsigned char *bytes, size_t len ); 30 | BigInteger( const unsigned long *words, size_t len ); 31 | BigInteger( const unsigned int *words, size_t len); 32 | 33 | ~BigInteger(); 34 | 35 | std::string toString(int base = 10) const; 36 | 37 | BigInteger pow( unsigned int exponent ) const; 38 | BigInteger pow( const BigInteger &exponent, const BigInteger &modulus ) const; 39 | BigInteger pow( unsigned int exponent, const BigInteger &modulus ) const; 40 | BigInteger invm( const BigInteger &modulus ) const; 41 | 42 | int lsb() const; 43 | BigInteger rshift( int n ) const; 44 | bool isZero() const; 45 | bool operator==(const BigInteger &i) const; 46 | bool operator==(const int &i) const; 47 | bool operator<(const BigInteger &i) const; 48 | 49 | bool operator!=( const BigInteger &i ) const; 50 | size_t getBitLength() const; 51 | size_t getByteLength() const; 52 | size_t getWordLength() const; 53 | size_t getLength32() const; 54 | size_t getLength64() const; 55 | size_t getLengthNative() const; 56 | void getWords(unsigned long *words, size_t size) const; 57 | void getWords(unsigned int *words, size_t size) const; 58 | void getWords(unsigned int *words) const; 59 | void getBytes(unsigned char *bytes, size_t size) const; 60 | bool equals( BigInteger &i ) const; 61 | 62 | BigInteger operator-(const BigInteger &i) const; 63 | BigInteger operator+(const BigInteger &i) const; 64 | BigInteger operator%(const BigInteger &i) const; 65 | BigInteger operator*(const BigInteger &i) const; 66 | BigInteger operator*(int &i) const; 67 | BigInteger operator/(const BigInteger &i) const; 68 | BigInteger operator+=(const BigInteger &a) const; 69 | BigInteger operator& (const int &i) const; 70 | BigInteger operator<< (const int &i) const; 71 | BigInteger operator>> (const int &i) const; 72 | 73 | //BigInteger operator=(const BigInteger &i) const; 74 | }; 75 | 76 | BigInteger randomBigInteger( const BigInteger &min, const BigInteger &max ); 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /src/client/Makefile: -------------------------------------------------------------------------------- 1 | INCLUDE += -I$(shell pwd)/include 2 | LIBDIR=$(shell pwd)/lib 3 | LIBS+=-L$(LIBDIR) 4 | 5 | # C++ options 6 | CXX=g++ 7 | CXXFLAGS=-O2 8 | 9 | # CUDA variables 10 | COMPUTE_CAP=30 11 | NVCC=nvcc -O3 12 | NVCCFLAGS=-gencode=arch=compute_${COMPUTE_CAP},code=\"sm_${COMPUTE_CAP}\" -Xptxas="-v" -Xcompiler "${CXXFLAGS}" 13 | CUDA_HOME=/usr/local/cuda-7.5 14 | CUDA_LIB=${CUDA_HOME}/lib64 15 | CUDA_INCLUDE=${CUDA_HOME}/include 16 | 17 | # Google test variables 18 | GTEST_DIR=$(shell pwd)/gtest 19 | GTEST_SRC=${GTEST_DIR}/src/*.cc 20 | GTEST_INCLUDE=${GTEST_DIR}/include 21 | 22 | #GTEST_INCLUDE=${GTEST_DIR}/include 23 | #GTEST_HEADERS=$(GTEST_DIR)/include/gtest/*.h $(GTEST_DIR)/include/gtest/internal/*.h 24 | #GTEST_SRC=$(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS) 25 | #GTEST_INCLUDE=-I${GTEST_DIR}/include 26 | #GTEST_SRC=${GTEST_DIR}/src/*.cc 27 | #GTEST_SRC=$(wildcard ${GTEST_DIR}/src/*.cc}) 28 | 29 | # ASM variables 30 | NASM=nasm 31 | X86_ASM=0 32 | 33 | export INCLUDE 34 | export LIBDIR 35 | export NVCC 36 | export NVCCFLAGS 37 | export LIBS 38 | export CXX 39 | export CXXFLAGS 40 | export NASM 41 | export CUDA_LIB 42 | export CUDA_INCLUDE 43 | export X86_ASM 44 | export GTEST_DIR 45 | export GTEST_SRC 46 | export GTEST_INCLUDE 47 | 48 | bigint: client_bigint 49 | ecc: client_ecc 50 | cuda: client_cuda 51 | logger: client_logger 52 | tle: client_tle 53 | sha256: client_sha256 54 | util: client_util 55 | ecdb: client_ecdb 56 | tests: client_tests 57 | config: client_config 58 | 59 | client_bigint: 60 | make --directory bigint 61 | 62 | client_ecc: client_bigint 63 | make --directory ecc 64 | 65 | client_tle: client_bigint 66 | make --directory tle 67 | 68 | client_logger: 69 | make --directory logger 70 | 71 | client_threads: 72 | make --directory threads 73 | 74 | client_util: 75 | make --directory util 76 | 77 | client_cuda: client_bigint client_ecc client_logger client_threads client_util client_tle client_sha256 client_config 78 | make --directory client client_cuda 79 | 80 | client_cpu: client_bigint client_ecc client_logger client_threads client_util client_tle client_sha256 81 | make --directory client client_cpu ecc_test 82 | 83 | client_sha256: 84 | make --directory sha256 85 | 86 | client_config: 87 | make --directory config 88 | 89 | client_ecdb: client_bigint 90 | make --directory ecdb 91 | 92 | client_tests: client_sha256 93 | make --directory test 94 | 95 | clean: 96 | make --directory client clean 97 | make --directory bigint clean 98 | make --directory ecc clean 99 | make --directory logger clean 100 | make --directory util clean 101 | make --directory threads clean 102 | make --directory config clean 103 | rm -rf ${LIBDIR} 104 | -------------------------------------------------------------------------------- /src/client/client/cuda/cudapp.cpp: -------------------------------------------------------------------------------- 1 | #include"cudapp.h" 2 | 3 | namespace CUDA { 4 | 5 | void memcpy(void *dest, const void *src, size_t count, enum cudaMemcpyKind kind) 6 | { 7 | cudaError_t cudaError = cudaMemcpy(dest, src, count, kind); 8 | if(cudaError != cudaSuccess) { 9 | throw cudaError; 10 | } 11 | } 12 | 13 | void *malloc(size_t size) 14 | { 15 | void *ptr; 16 | cudaError_t cudaError = cudaMalloc(&ptr, size); 17 | 18 | if(cudaError != cudaSuccess) { 19 | throw cudaError; 20 | } 21 | 22 | return ptr; 23 | } 24 | 25 | void *hostAlloc(size_t size, unsigned int flags ) 26 | { 27 | void *ptr; 28 | cudaError_t cudaError = cudaHostAlloc(&ptr, size, flags); 29 | 30 | if(cudaError != cudaSuccess) { 31 | throw cudaError; 32 | } 33 | 34 | return ptr; 35 | } 36 | 37 | void free(void *ptr) 38 | { 39 | cudaError_t cudaError = cudaFree(ptr); 40 | 41 | if(cudaError != cudaSuccess) { 42 | throw cudaError; 43 | } 44 | } 45 | 46 | void setDevice(int device) 47 | { 48 | cudaError_t cudaError = cudaSetDevice(device); 49 | if(cudaError != cudaSuccess) { 50 | throw cudaError; 51 | } 52 | } 53 | 54 | void setDeviceFlags(unsigned int flags) 55 | { 56 | cudaError_t cudaError = cudaSetDeviceFlags(flags); 57 | if(cudaError != cudaSuccess) { 58 | throw cudaError; 59 | } 60 | } 61 | 62 | void *getDevicePointer(void *hostPtr, unsigned int flags) 63 | { 64 | void *devPtr = NULL; 65 | cudaError_t cudaError = cudaHostGetDevicePointer(&devPtr, hostPtr, flags); 66 | 67 | if(cudaError != cudaSuccess) { 68 | throw cudaError; 69 | } 70 | 71 | return devPtr; 72 | } 73 | 74 | /** 75 | * Gets the number of available CUDA devices 76 | */ 77 | int getDeviceCount() 78 | { 79 | int count = 0; 80 | cudaError_t cudaError = cudaSuccess; 81 | 82 | cudaError = cudaGetDeviceCount(&count); 83 | 84 | if(cudaError != cudaSuccess) { 85 | return 0; 86 | } 87 | 88 | return count; 89 | } 90 | 91 | /** 92 | * Function to get device information 93 | */ 94 | void getDeviceInfo(int device, DeviceInfo &devInfo) 95 | { 96 | cudaDeviceProp properties; 97 | cudaError_t cudaError = cudaSuccess; 98 | 99 | cudaError = cudaSetDevice(device); 100 | if(cudaError != cudaSuccess) { 101 | throw cudaError; 102 | } 103 | 104 | cudaError = cudaGetDeviceProperties(&properties, device); 105 | if(cudaError != cudaSuccess) { 106 | throw cudaError; 107 | } 108 | 109 | devInfo.major = properties.major; 110 | devInfo.minor = properties.minor; 111 | devInfo.mpCount = properties.multiProcessorCount; 112 | devInfo.globalMemory = properties.totalGlobalMem; 113 | devInfo.name = std::string(properties.name); 114 | 115 | int cores = 0; 116 | switch(devInfo.major) { 117 | case 1: 118 | cores = 8; 119 | break; 120 | case 2: 121 | cores = devInfo.minor == 0 ? 32 : 48; 122 | break; 123 | case 3: 124 | cores = 192; 125 | break; 126 | case 5: 127 | cores = 128; 128 | break; 129 | } 130 | devInfo.cores = cores; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/server/ecdl.py: -------------------------------------------------------------------------------- 1 | import json 2 | from MySQLPointDatabase import MySQLPointDatabase 3 | 4 | from ecc import ECCurve, ECPoint 5 | import random 6 | 7 | NUM_R_POINTS = 32 8 | 9 | ''' 10 | Converts a string to integer by guessing the base 11 | ''' 12 | def parseInt(n): 13 | return int(n, 0) 14 | 15 | ''' 16 | Config object. Need to call loadConfig() to load it 17 | ''' 18 | Config = None 19 | Database = None 20 | 21 | class ServerConfig: 22 | 23 | dbUser = "" 24 | dbPassword = "" 25 | dbHost = "" 26 | port = 9999 27 | 28 | def __init__(self, path): 29 | 30 | with open(path) as data_file: 31 | data = json.load(data_file) 32 | 33 | self.dbUser = data['dbUser'] 34 | self.dbPassword = data['dbPassword'] 35 | self.dbHost = data['dbHost'] 36 | self.port = data['port'] 37 | 38 | ''' 39 | Loads the config 40 | ''' 41 | def loadConfig(path): 42 | global Config 43 | global Database 44 | 45 | Config = ServerConfig(path) 46 | Database = MySQLPointDatabase(Config.dbHost, Config.dbUser, Config.dbPassword) 47 | 48 | ''' 49 | Class to store ECDLP context. 50 | ''' 51 | class ECDLPContext: 52 | 53 | def __init__(self, ctxName): 54 | self.name = ctxName 55 | self.database = None 56 | self.rPoints = [] 57 | self.curve = None 58 | self.params = None 59 | self.status = "running" 60 | self.email = None 61 | self.collisions = 0 62 | 63 | def getConnection(self): 64 | return database.getConnection(self.name) 65 | 66 | ''' 67 | Generates the R points for the random walk from the ECDLP parameters 68 | ''' 69 | def generateRPoints(params): 70 | 71 | curve = ECCurve(params.a, params.b, params.p, params.n, params.gx, params.gy) 72 | pointG = ECPoint(params.gx, params.gy) 73 | pointQ = ECPoint(params.qx, params.qy) 74 | 75 | rPoints = [] 76 | 77 | for i in range(NUM_R_POINTS): 78 | a = random.randint(2, curve.n) 79 | b = random.randint(2, curve.n) 80 | 81 | aG = curve.multiply(a, pointG) 82 | bQ = curve.multiply(b, pointQ) 83 | 84 | r = curve.add(aG, bQ) 85 | 86 | e = {} 87 | e['a'] = a 88 | e['b'] = b 89 | e['x'] = r.x 90 | e['y'] = r.y 91 | rPoints.append(e) 92 | 93 | return rPoints 94 | 95 | ''' 96 | Creates a new context 97 | ''' 98 | def createContext(params, name, email): 99 | 100 | ctx = ECDLPContext(name) 101 | 102 | ctx.params = params 103 | ctx.rPoints = generateRPoints(ctx.params) 104 | 105 | Database.createContext(ctx.name, ctx.email, ctx.params, ctx.rPoints) 106 | 107 | ctx.curve = ECCurve(ctx.params.a, ctx.params.b, ctx.params.p, ctx.params.n, ctx.params.gx, ctx.params.gy) 108 | ctx.pointG = ECPoint(ctx.params.gx, ctx.params.gy) 109 | ctx.pointQ = ECPoint(ctx.params.qx, ctx.params.qy) 110 | 111 | ctx.database = Database.getConnection(ctx.name) 112 | 113 | return ctx 114 | 115 | ''' 116 | Loads an existing context 117 | ''' 118 | def loadContext(name): 119 | ctx = ECDLPContext(name) 120 | 121 | ctx.database = Database.getConnection(ctx.name) 122 | 123 | ctx.database.open() 124 | ctx.rPoints = ctx.database.getRPoints() 125 | ctx.params = ctx.database.getParams() 126 | ctx.status = ctx.database.getStatus() 127 | ctx.solution = ctx.database.getSolution() 128 | ctx.collisions = ctx.database.getNumCollisions() 129 | ctx.database.close() 130 | 131 | ctx.curve = ECCurve(ctx.params.a, ctx.params.b, ctx.params.p, ctx.params.n, ctx.params.gx, ctx.params.gy) 132 | ctx.pointG = ECPoint(ctx.params.gx, ctx.params.gy) 133 | ctx.pointQ = ECPoint(ctx.params.qx, ctx.params.qy) 134 | 135 | return ctx 136 | -------------------------------------------------------------------------------- /src/client/ecc/eccutil.cpp: -------------------------------------------------------------------------------- 1 | #include "ecc.h" 2 | #include "BigInteger.h" 3 | 4 | /** 5 | * Generates a set of R points for performing random walk 6 | */ 7 | void generateRPoints(ECCurve &curve, ECPoint &q, BigInteger *aAra, BigInteger *bAra, BigInteger *xAra, BigInteger *yAra, int n) 8 | { 9 | ECPoint g = curve.getBasepoint(); 10 | BigInteger order = curve.n(); 11 | BigInteger modulus = curve.p(); 12 | 13 | // Generate random Ri = aiG + biQ 14 | for( int i = 0; i < n; i++ ) { 15 | ECPoint r1; 16 | ECPoint r2; 17 | ECPoint r3; 18 | 19 | // Generate random multiplies 20 | BigInteger a = randomBigInteger(BigInteger(2), order); 21 | BigInteger b = randomBigInteger(BigInteger(2), order); 22 | 23 | // Multiply G and Q 24 | r1 = curve.multiply(a, g); 25 | r2 = curve.multiply(b, q); 26 | 27 | // Add the two points 28 | r3 = curve.add(r1, r2); 29 | 30 | xAra[ i ] = r3.getX(); 31 | yAra[ i ] = r3.getY(); 32 | 33 | if(aAra != NULL) { 34 | aAra[ i ] = a; 35 | } 36 | 37 | if(bAra != NULL) { 38 | bAra[ i ] = b; 39 | } 40 | } 41 | } 42 | 43 | static BigInteger legendreSymbol(const BigInteger &a, const BigInteger &p) 44 | { 45 | BigInteger ls = a.pow((p-1)/2, p); 46 | 47 | if(ls == p-1) { 48 | return -1; 49 | } 50 | 51 | return ls; 52 | } 53 | 54 | 55 | int squareRootModP(const BigInteger &n, const BigInteger &p, BigInteger *out) 56 | { 57 | if(n == 0) { 58 | return 0; 59 | } 60 | 61 | if(p == 2) { 62 | *out = n; 63 | return 1; 64 | } 65 | 66 | 67 | BigInteger ls = legendreSymbol(n, p); 68 | 69 | if(ls != 1) { 70 | return 0; 71 | } 72 | 73 | if(n % 4 == 3) { 74 | BigInteger r = n.pow((p+1)/4, p); 75 | out[0] = r; 76 | out[1] = p - r; 77 | return 2; 78 | } 79 | 80 | unsigned int s = 0; 81 | BigInteger q = p - 1; 82 | 83 | while(q % 2 == 0) { 84 | s = s + 1; 85 | q = q / 2; 86 | } 87 | 88 | BigInteger z = 2; 89 | while(legendreSymbol(z, p) != -1) { 90 | z = z + 1; 91 | } 92 | 93 | 94 | BigInteger c = z.pow(q, p); 95 | BigInteger r = n.pow((q+1)/2, p); 96 | BigInteger t = n.pow(q, p); 97 | 98 | unsigned int m = s; 99 | 100 | while(t != 1) { 101 | 102 | //Find lowest i where t^(2^i) = 1 103 | unsigned int i = 1; 104 | unsigned int e = 1; 105 | while(e < m) { 106 | if(t.pow(BigInteger(2).pow(i), p) == 1) { 107 | break; 108 | } 109 | i = i * 2; 110 | } 111 | 112 | BigInteger b = c.pow(BigInteger(2).pow(m - i - 1), p); 113 | r = (r * b) % p; 114 | t = (t * b * b) % p; 115 | c = (b * b) % p; 116 | m = i; 117 | } 118 | 119 | out[0] = r; 120 | out[1] = p - r; 121 | 122 | return 2; 123 | } 124 | 125 | void compressPoint(ECPoint &point, unsigned char *buf) 126 | { 127 | unsigned char sign = 0x00; 128 | BigInteger x = point.getX(); 129 | BigInteger y = point.getY(); 130 | 131 | if((y & 0x01) == 0x01) { 132 | sign = 0x01; 133 | } 134 | 135 | int len = x.getByteLength(); 136 | x.getBytes(buf + 1, len); 137 | buf[0] = sign; 138 | } 139 | 140 | bool decompressPoint(const ECCurve &curve, const unsigned char *encoded, int encodedLen, ECPoint &out) 141 | { 142 | unsigned char sign = encoded[0]; 143 | 144 | BigInteger x(&encoded[1], encodedLen-1); 145 | 146 | BigInteger a = curve.a(); 147 | BigInteger b = curve.b(); 148 | BigInteger p = curve.p(); 149 | 150 | BigInteger z = (x.pow(3) + a * x + b) % p; 151 | 152 | BigInteger roots[2]; 153 | 154 | int numRoots = squareRootModP(z, p, roots); 155 | 156 | if(numRoots != 2) { 157 | return false; 158 | } 159 | 160 | // Make sure roots[0] is even, roots[1] is odd 161 | if((roots[0] & 1) == 0) { 162 | BigInteger tmp = roots[0]; 163 | roots[0] = roots[1]; 164 | roots[1] = tmp; 165 | } 166 | 167 | out.x = x; 168 | if(sign) { 169 | out.y = roots[0]; 170 | } else { 171 | out.y = roots[1]; 172 | } 173 | 174 | return true; 175 | } -------------------------------------------------------------------------------- /src/client/client/cuda/RhoCUDA.h: -------------------------------------------------------------------------------- 1 | #ifndef _RHO_CUDA_H 2 | #define _RHH_CUDA_H 3 | 4 | #include "ECDLContext.h" 5 | #include "ecc.h" 6 | #include "BigInteger.h" 7 | #include 8 | 9 | class RhoCUDA { 10 | 11 | private: 12 | unsigned long long _mainCounter; 13 | volatile bool _runFlag; 14 | 15 | unsigned int _pointsPerThread; 16 | unsigned int _blocks; 17 | unsigned int _threadsPerBlock; 18 | unsigned int _numThreads; 19 | unsigned int _numRPoints; 20 | 21 | /** 22 | * Pointers to host memory 23 | */ 24 | unsigned int *_aStart; 25 | unsigned int *_bStart; 26 | unsigned int *_pointFoundFlags; 27 | unsigned int *_blockFlags; 28 | unsigned long long *_counters; 29 | 30 | /** 31 | * Pointers to host memory from device 32 | */ 33 | unsigned int *_devAStart; 34 | unsigned int *_devBStart; 35 | unsigned int *_devBlockFlags; 36 | unsigned int *_devPointFoundFlags; 37 | 38 | /** 39 | * Pointers to device memory 40 | */ 41 | unsigned int *_devDiffBuf; 42 | unsigned int *_devChainBuf; 43 | unsigned int *_devX; 44 | unsigned int *_devY; 45 | 46 | ECDLPParams _params; 47 | ECCurve _curve; 48 | 49 | BigInteger _rx[NUM_R_POINTS]; 50 | BigInteger _ry[NUM_R_POINTS]; 51 | 52 | int _pBits; 53 | int _mBits; 54 | int _pWords; 55 | int _mWords; 56 | BigInteger _m; 57 | 58 | // The current device 59 | int _device; 60 | bool _initialized; 61 | 62 | void (*_callback)(struct CallbackParameters *); 63 | 64 | void readX(unsigned int *x, unsigned int block, unsigned int thread, unsigned int index); 65 | void readY(unsigned int *y, unsigned int block, unsigned int thread, unsigned int index); 66 | void readA(unsigned int *a, unsigned int block, unsigned int thread, unsigned int index); 67 | void readB(unsigned int *b, unsigned int block, unsigned int thread, unsigned int index); 68 | 69 | void writeX(const unsigned int *x, unsigned int block, unsigned int thread, unsigned int index); 70 | void writeY(const unsigned int *y, unsigned int block, unsigned int thread, unsigned int index); 71 | void writeA(const unsigned int *a, unsigned int block, unsigned int thread, unsigned int index); 72 | void writeB(const unsigned int *b, unsigned int block, unsigned int thread, unsigned int index); 73 | 74 | void splatBigInt(unsigned int *ara, const unsigned int *x, unsigned int block, unsigned int thread, unsigned int index ); 75 | void extractBigInt(unsigned int *x, const unsigned int *ara, unsigned int block, unsigned int thread, unsigned int index); 76 | 77 | void writeBigInt(unsigned int *dest, const unsigned int *src, unsigned int block, unsigned int thread, unsigned int index); 78 | void readBigInt(unsigned int *dest, const unsigned int *src, unsigned int block, unsigned int thread, unsigned int index); 79 | 80 | unsigned int getIndex(unsigned int block, unsigned int thread, unsigned int idx); 81 | 82 | // Initializaton 83 | void generateLookupTable(unsigned int *gx, unsigned int *gy, unsigned int *qx, unsigned int *qy, unsigned int *gqx, unsigned int *gqy); 84 | 85 | void generateExponentsHost(); 86 | void generateStartingPoints(bool doVerify = false); 87 | void allocateBuffers(); 88 | void freeBuffers(); 89 | void setupDeviceConstants(); 90 | 91 | void uninitializeDevice(); 92 | bool initializeDevice(); 93 | bool getFlag(); 94 | void getRandomPoint(unsigned int *x, unsigned int *y, unsigned int *a, unsigned int *b); 95 | bool verifyPoint(BigInteger &x, BigInteger &y); 96 | void setRunFlag(bool flag); 97 | void setRPoints(); 98 | bool pointFound(); 99 | 100 | bool doStep(); 101 | 102 | void cudaException(cudaError_t error); 103 | 104 | public: 105 | RhoCUDA( int device, 106 | unsigned int blocks, 107 | unsigned int threads, 108 | unsigned int pointsPerThread, 109 | const ECDLPParams *params, 110 | const BigInteger *rx, 111 | const BigInteger *ry, 112 | int rPoints, 113 | void (*callback)(struct CallbackParameters *)); 114 | 115 | ~RhoCUDA(); 116 | bool init(); 117 | void reset(); 118 | bool run(); 119 | bool stop(); 120 | bool isRunning(); 121 | 122 | // Debug code 123 | bool benchmark(unsigned long long *pointsPerSecond); 124 | }; 125 | 126 | #endif -------------------------------------------------------------------------------- /src/server/ecc.py: -------------------------------------------------------------------------------- 1 | import random 2 | import sys 3 | import binascii 4 | import math 5 | 6 | ''' 7 | Compute inverse mod p 8 | ''' 9 | def invModP(n, p): 10 | a = n 11 | b = p 12 | x,y, u,v = 0,1, 1,0 13 | while a != 0: 14 | q,r = b//a,b%a; m,n = x-u*q,y-v*q # use x//y for floor "floor division" 15 | b,a, x,y, u,v = a,r, u,v, m,n 16 | return x % p 17 | 18 | class ECPoint: 19 | x = 0 20 | y = 0 21 | 22 | def __init__(self,x=0,y=0): 23 | self.x = x 24 | self.y = y 25 | 26 | def isPointAtInfinity(self): 27 | if self.x == 0 and self.y == 0: 28 | return True 29 | else: 30 | return False 31 | 32 | # Determines if a number is prime using the 33 | # Miller-Rabin primality test 34 | def isPrime(p): 35 | k = 128 36 | s = 0 37 | t = p - 1 38 | q = 1 39 | 40 | # Eliminate even numbers 41 | if( p & 1 == 0 ): 42 | return False 43 | 44 | # Fermat's little theorem check 45 | if(pow(2, p - 1, p) != 1): 46 | return False 47 | 48 | # Factor powers of 2 from p - 1 49 | while(t & 1 == 0): 50 | t = t >> 1 51 | s = s + 1 52 | q = q * 2 53 | 54 | d = int((p - 1) / q) 55 | 56 | while(k >= 0): 57 | k = k - 1 58 | a = random.randint(2, p - 2) 59 | 60 | x = pow(a, d, p) 61 | 62 | if( x == 1 or x == p - 1 ): 63 | continue 64 | 65 | r = 1 66 | while( r <= s - 1 ): 67 | x = (x*x)%p 68 | if( x == 1 ): 69 | return False 70 | if( x == p - 1 ): 71 | break 72 | r = r + 1 73 | 74 | if( r == s ): 75 | return False 76 | else: 77 | continue 78 | 79 | return True 80 | 81 | # Checks that elliptic curve parameters are correct 82 | def verifyCurveParameters(a, b, p, n, x, y): 83 | 84 | # Verify P is prime 85 | if not isPrime(p): 86 | return False 87 | 88 | # Verify n is order of the group 89 | curve = ECCurve(a, b, p, n, x, y) 90 | bp = curve.bp 91 | 92 | p1 = curve.multiply(n, bp) 93 | if not p1.isPointAtInfinity(): 94 | return False 95 | 96 | return True 97 | 98 | class ECCurve: 99 | a = 0 100 | b = 0 101 | p = 0 102 | n = 0 103 | bp = None 104 | 105 | def __init__(self, a, b, p, n, x, y): 106 | self.a = a 107 | self.b = b 108 | self.p = p 109 | self.n = n 110 | self.bp = ECPoint(x, y) 111 | 112 | def add(self, p, q): 113 | 114 | if( p.isPointAtInfinity() ): 115 | return q 116 | 117 | if( q.isPointAtInfinity() ): 118 | return p 119 | 120 | # P + Q = 2P where P == Q 121 | if( p.x == q.x and p.y == q.y ): 122 | return ECCurve.double(self, p) 123 | 124 | # P + Q = 0 where Q == -P 125 | if( p.x == q.x ): 126 | return ECPoint() 127 | 128 | rise = (p.y - q.y) % self.p 129 | run = (p.x - q.x) % self.p 130 | s = ( rise * invModP( run, self.p ) ) % self.p 131 | r = ECPoint() 132 | r.x = ( s * s - p.x - q.x ) % self.p 133 | r.y = ( -p.y + s * (p.x - r.x ) ) % self.p 134 | 135 | return r 136 | 137 | # Performs EC point doubling 138 | def double(self, point): 139 | r = ECPoint() 140 | 141 | if( point.y == 0 ): 142 | return r 143 | 144 | # 3 * p.x 145 | t = (point.x * point.x) % self.p 146 | px3 = ((t << 1) + t) % self.p 147 | 148 | # calculate the slope 149 | rise = (px3 + self.a) % self.p 150 | run = (point.y << 1) % self.p 151 | s = ( rise * invModP( run, self.p ) ) % self.p 152 | 153 | r.x = ( s * s - ( point.x << 1 ) ) % self.p 154 | r.y = ( -point.y + s * ( point.x - r.x ) ) % self.p 155 | 156 | return r 157 | 158 | # Multiply an EC point by a scalar 159 | def multiply(self, k, point): 160 | y = k 161 | r = ECPoint() 162 | 163 | while( y > 0 ): 164 | if( y & 1 == 1 ): 165 | r = ECCurve.add(self, r, point) 166 | y = y >> 1 167 | point = ECCurve.double(self, point) 168 | 169 | return r 170 | 171 | def verifyPoint(self, point ): 172 | y1 = (point.y * point.y) % self.p 173 | y2 = (pow(point.x,3,self.p) + self.a * point.x + self.b) % self.p 174 | 175 | if( y1 == y2 ): 176 | return True 177 | else: 178 | return False 179 | -------------------------------------------------------------------------------- /src/server/util.py: -------------------------------------------------------------------------------- 1 | from ecc import ECCurve, ECPoint 2 | import random 3 | 4 | 5 | ''' 6 | Converts a string to integer by guessing the base 7 | ''' 8 | def parseInt(n): 9 | return int(n, 0) 10 | 11 | def toHex(n): 12 | return hex(n).rstrip("L").lstrip("0x") or "0" 13 | 14 | ''' 15 | Converts integer to string 16 | ''' 17 | def intToString(n): 18 | return str(n).rstrip("L") 19 | 20 | ''' 21 | Generates the R points for the random walk from the ECDLP parameters 22 | ''' 23 | def generateRPoints(params): 24 | 25 | curve = ECCurve(params.a, params.b, params.p, params.n, params.gx, params.gy) 26 | pointG = ECPoint(params.gx, params.gy) 27 | pointQ = ECPoint(params.qx, params.qy) 28 | 29 | rPoints = [] 30 | 31 | for i in range(NUM_R_POINTS): 32 | a = random.randint(2, curve.n) 33 | b = random.randint(2, curve.n) 34 | 35 | aG = curve.multiply(a, pointG) 36 | bQ = curve.multiply(b, pointQ) 37 | 38 | r = curve.add(aG, bQ) 39 | 40 | e = {} 41 | e['a'] = a 42 | e['b'] = b 43 | e['x'] = r.x 44 | e['y'] = r.y 45 | rPoints.append(e) 46 | 47 | return rPoints 48 | 49 | ''' 50 | Class to hold ECDLP parameters 51 | ''' 52 | class ECDLPParams: 53 | 54 | ''' 55 | ECDLPParams constructor 56 | Takes a dictionary containing the parameters 57 | ''' 58 | def __init__(self): 59 | self.field = None 60 | self.p = 0 61 | self.n = 0 62 | self.a = 0 63 | self.b = 0 64 | self.gx = 0 65 | self.gy = 0 66 | self.qx = 0 67 | self.qy = 0 68 | self.dBits = 0 69 | 70 | def decode(self, params): 71 | self.field = params['field'] 72 | self.p = parseInt(params['p']) 73 | self.n = parseInt(params['n']) 74 | self.a = parseInt(params['a']) 75 | self.b = parseInt(params['b']) 76 | self.gx = parseInt(params['gx']) 77 | self.gy = parseInt(params['gy']) 78 | self.qx = parseInt(params['qx']) 79 | self.qy = parseInt(params['qy']) 80 | self.dBits = params['bits'] 81 | 82 | ''' 83 | Encode into json format 84 | ''' 85 | def encode(self): 86 | encoded = {} 87 | encoded['field'] = self.field 88 | encoded['p'] = str(self.p) 89 | encoded['n'] = str(self.n) 90 | encoded['a'] = str(self.a) 91 | encoded['b'] = str(self.b) 92 | encoded['gx'] = str(self.gx) 93 | encoded['gy'] = str(self.gy) 94 | encoded['qx'] = str(self.qx) 95 | encoded['qy'] = str(self.qy) 96 | encoded['bits'] = self.dBits 97 | 98 | return encoded 99 | 100 | ''' 101 | Compresses an elliptic curve point 102 | ''' 103 | def compress_point(x, y): 104 | even = True 105 | 106 | if y & 0x01 == 0x01: 107 | even = False 108 | 109 | if even: 110 | return "02" + toHex(x) 111 | else: 112 | return "03" + toHex(x) 113 | 114 | 115 | ''' 116 | Decompresses a compressed point 117 | ''' 118 | def decompress_point(compressed, a, b, p): 119 | 120 | # Get the even/odd of the y coordinate 121 | sign = compressed[:2] 122 | 123 | # Extract x coordinate 124 | x = int(compressed[2:], 16) 125 | 126 | # compute the solutions of y to y^2 = x^3 + ax + b 127 | z = ((x*x*x) + a * x + b) % p 128 | y = squareRootModP(z, p) 129 | 130 | #y1 is even, y2 is odd 131 | y1 = y[0] 132 | y2 = y[1] 133 | 134 | if y1 & 0x01 == 0x01: 135 | tmp = y1 136 | y1 = y2 137 | y2 = tmp 138 | 139 | # Return the x,y pair 140 | if sign == "02": 141 | return x, y1 142 | else: 143 | return x, y2 144 | 145 | 146 | def legendre_symbol(a,p): 147 | ls = pow(a, (p-1)//2, p) 148 | 149 | if(ls == p - 1): 150 | return -1 151 | return ls 152 | 153 | def squareRootModP(n,p): 154 | 155 | if(n == 0): 156 | return [0] 157 | 158 | if(p == 2): 159 | return [n] 160 | 161 | if(legendre_symbol(n,p) != 1): 162 | return [] 163 | 164 | # Check for easy case 165 | if(n % 4 == 3): 166 | r = pow(n, (p+1)/4, p) 167 | return [r, p - r] 168 | 169 | # Factor out powers of 2 from p - 1 170 | q = p - 1 171 | s = 0 172 | 173 | while(q % 2 == 0): 174 | s = s + 1 175 | q = q // 2 176 | 177 | # Select z which is a quadratic non-residue mod p 178 | z = 2 179 | while(legendre_symbol(z,p) != -1): 180 | z = z + 1 181 | 182 | c = pow(z, q, p) 183 | 184 | r = pow(n, (q+1)//2, p) 185 | t = pow(n, q, p) 186 | m = s 187 | 188 | while(t != 1): 189 | 190 | # Find lowest i where t^(2^i) = 1 191 | i = 1 192 | e = 0 193 | for e in range(1,m): 194 | if(pow(t, pow(2,i), p) == 1): 195 | break 196 | i = i * 2 197 | 198 | b = pow(c, 2**(m - i - 1), p) 199 | r = (r * b) % p 200 | t = (t * b * b) % p 201 | c = (b * b) % p 202 | m = i 203 | 204 | return [r, p - r] -------------------------------------------------------------------------------- /src/client/client/benchmark.cpp: -------------------------------------------------------------------------------- 1 | #include "client.h" 2 | 3 | #ifdef _CUDA 4 | #include "ECDLCuda.h" 5 | #include "kernels.h" 6 | #include "cudapp.h" 7 | #else 8 | #include "ECDLCPU.h" 9 | #endif 10 | 11 | #include "BigInteger.h" 12 | #include "logger.h" 13 | 14 | #include "util.h" 15 | 16 | static const int bits[] = { 17 | 64, 96, 128, 160, 192, 224 18 | }; 19 | 20 | #define CURVE_64 0 21 | #define CURVE_96 1 22 | #define CURVE_128 2 23 | #define CURVE_160 3 24 | #define CURVE_192 4 25 | #define CURVE_224 5 26 | 27 | #define PARAM_P 0 28 | #define PARAM_A 1 29 | #define PARAM_B 2 30 | #define PARAM_N 3 31 | 32 | #define PARAM_GX 4 33 | #define PARAM_GY 5 34 | #define PARAM_QX 6 35 | #define PARAM_QY 7 36 | 37 | static const char *_paramStrings[][8] = { 38 | { 39 | "10346548290527483921", // p 40 | "8213110108256840705", // a 41 | "5359355018093152257", // b 42 | "10346548285891636157", // n 43 | 44 | "2516376822311234657", // gx 45 | "4288374045943717916", // gy 46 | 47 | "5062051216356272720", // qx 48 | "8555742863554926061" // qy 49 | }, 50 | { 51 | "78981521739689554908020736013", 52 | "58784168200570774359499603969", 53 | "47494327795442261632384761857", 54 | "78981521739689465582500230217", 55 | 56 | "18103986262720072890098715416", 57 | "52944065473593986531071869154", 58 | 59 | "748975810752021896566294904", 60 | "27241524238649937039403119779" 61 | }, 62 | { 63 | "200928183426328164807859180258556117041", 64 | "86691786142570278779847599195353513985", 65 | "110242031934209319368482290082496118785", 66 | "200928183426328164802453963091476992749", 67 | 68 | "64750113582711562095673901358611790991", 69 | "48363172895708030153257722930462146474", 70 | 71 | "26076691982360896544369846918428630918", 72 | "136810230350086971534375335248495674369" 73 | }, 74 | { 75 | "865806661822871998623160485581077455704841781483", 76 | "409134317488780658785352322416272562458671972353", 77 | "137070141856338712184360102975493199442378489857", 78 | "865806661822871998623159860641677594758258670073", 79 | 80 | "840665358702132694797322237271982618142154224941", 81 | "170744561051647536319710637442406320214802928748", 82 | 83 | "510642232687460243288359605410492948380688537005", 84 | "379030859946867953298980230660914598579105762000" 85 | }, 86 | { 87 | "3287620281068379841326166099363253391071869123043868541117", 88 | "1253356721748952464022637580491996618124230631347693027329", 89 | "1709831987121145453285182085135647694393587792211810975745", 90 | "3287620281068379841326166099359249568449273560353013620147", 91 | 92 | "1655536773327969337442160376548055971211387649095171974415", 93 | "777824550077092965471860025935337052275515268507535242467", 94 | 95 | "37626691205442454457877423801261059929491832007111212301", 96 | "1255236264293804341975890212966073212491138693635972262025" 97 | }, 98 | { 99 | "20808685163008145908235023645553668146435030868584130872857791037659", 100 | "17844349681778935434661105936076298713967005369370891804661870755841", 101 | "7605732306787334301343640825373619088025286957757700551773180133377", 102 | "20808685163008145908235023645553664404297390168478224022643977635197", 103 | 104 | "4601116937491803330253385207580447122436304623872407352894717558269", 105 | "1817948758263560681394000696005448808262808471329486120513420912604", 106 | 107 | "9728980498913250221612222565486170926088128648755254481964477778254", 108 | "7758514135545535486433083143040083446671723285043190155310745444754" 109 | } 110 | }; 111 | 112 | void doBenchmark() 113 | { 114 | #ifdef _CUDA 115 | ECDLCudaContext *ctx; 116 | #else 117 | ECDLCpuContext *ctx; 118 | #endif 119 | 120 | BigInteger rx[ 32 ]; 121 | BigInteger ry[ 32 ]; 122 | 123 | for(int i = 0; i < 6; i++) { 124 | ECDLPParams params; 125 | params.p = BigInteger(_paramStrings[i][0]); 126 | params.a = BigInteger(_paramStrings[i][1]); 127 | params.b = BigInteger(_paramStrings[i][2]); 128 | params.n = BigInteger(_paramStrings[i][3]); 129 | params.gx = BigInteger(_paramStrings[i][4]); 130 | params.gy = BigInteger(_paramStrings[i][5]); 131 | params.qx = BigInteger(_paramStrings[i][6]); 132 | params.qy = BigInteger(_paramStrings[i][7]); 133 | params.dBits = 32; 134 | 135 | ECCurve curve(params.p, params.n, params.a, params.b, params.gx, params.gy); 136 | 137 | ECPoint q(params.qx, params.qy); 138 | generateRPoints(curve, q, NULL, NULL, rx, ry, 32); 139 | 140 | Logger::logInfo("Running benchmark for %d-bit prime curve\n", bits[i]); 141 | #ifdef _CUDA 142 | ctx = new ECDLCudaContext(_config.device, _config.blocks, _config.threads, _config.pointsPerThread, ¶ms, rx, ry, 32, NULL); 143 | #else 144 | ctx = new ECDLCpuContext(_config.threads, _config.pointsPerThread, ¶ms, rx, ry, 32, NULL); 145 | #endif 146 | //ctx->init(); 147 | ctx->benchmark(NULL); 148 | fflush(stdout); 149 | delete ctx; 150 | } 151 | 152 | } 153 | -------------------------------------------------------------------------------- /src/client/client/cpu/ECDLCpuContext.cpp: -------------------------------------------------------------------------------- 1 | #include "ECDLCPU.h" 2 | #include "logger.h" 3 | #include "util.h" 4 | #include "logger.h" 5 | #include "RhoCPU.h" 6 | 7 | #define BENCHMARK_ITERATIONS 10000000 8 | 9 | ECDLCpuContext::ECDLCpuContext( unsigned int numThreads, 10 | unsigned int pointsPerThread, 11 | const ECDLPParams *params, 12 | const BigInteger *rx, 13 | const BigInteger *ry, 14 | int rPoints, 15 | void (*callback)(struct CallbackParameters *) 16 | ) 17 | { 18 | _numThreads = numThreads; 19 | _pointsPerThread = pointsPerThread; 20 | _callback = callback; 21 | _params = *params; 22 | _rPoints = rPoints; 23 | _running = false; 24 | 25 | // Copy random walk points 26 | for(int i = 0; i < rPoints; i++) { 27 | _rx[i] = rx[i]; 28 | _ry[i] = ry[i]; 29 | } 30 | 31 | // Set up curve using parameters 32 | _curve = ECCurve(_params.p, _params.n, _params.a, _params.b, _params.gx, _params.gy); 33 | } 34 | 35 | RhoBase *ECDLCpuContext::getRho(bool callback) 36 | { 37 | return new RhoCPU(&_params, _rx, _ry, _rPoints, _pointsPerThread, callback ? _callback : NULL); 38 | } 39 | 40 | ECDLCpuContext::~ECDLCpuContext() 41 | { 42 | _workerThreads.clear(); 43 | _workerThreadParams.clear(); 44 | } 45 | 46 | bool ECDLCpuContext::init() 47 | { 48 | reset(); 49 | 50 | 51 | for(int i = 0; i < _numThreads; i++) { 52 | _workerCtx.push_back(getRho()); 53 | } 54 | 55 | return true; 56 | } 57 | 58 | void ECDLCpuContext::reset() 59 | { 60 | _workerThreads.clear(); 61 | _workerThreadParams.clear(); 62 | } 63 | 64 | bool ECDLCpuContext::stop() 65 | { 66 | // TODO: Protect with mutex 67 | _running = false; 68 | 69 | // Wait for threads to finish 70 | for(int i = 0; i < _numThreads; i++) { 71 | _workerThreads[i].wait(); 72 | } 73 | 74 | return true; 75 | } 76 | 77 | bool ECDLCpuContext::run() 78 | { 79 | _running = true; 80 | 81 | // Run the threads 82 | for(int i = 0; i < _numThreads; i++) { 83 | WorkerThreadParams params; 84 | 85 | params.threadId = i; 86 | params.instance = this; 87 | _workerThreadParams.push_back(params); 88 | 89 | _workerThreads.push_back(Thread(&ECDLCpuContext::workerThreadEntry, &_workerThreadParams[i])); 90 | } 91 | 92 | // Wait for threads to finish 93 | for(int i = 0; i < _numThreads; i++) { 94 | _workerThreads[i].wait(); 95 | } 96 | 97 | return true; 98 | } 99 | 100 | /** 101 | * Entry point method for the thread 102 | */ 103 | void *ECDLCpuContext::workerThreadEntry(void *ptr) 104 | { 105 | WorkerThreadParams *params = (WorkerThreadParams *)ptr; 106 | 107 | ((ECDLCpuContext *)params->instance)->workerThreadFunction(params->threadId); 108 | 109 | return NULL; 110 | } 111 | 112 | /** 113 | * The method where all the work is done for the thread 114 | */ 115 | void ECDLCpuContext::workerThreadFunction(int threadId) 116 | { 117 | RhoBase *r = _workerCtx[threadId]; 118 | 119 | while(_running) { 120 | r->doStep(); 121 | } 122 | } 123 | 124 | void *ECDLCpuContext::benchmarkThreadEntry(void *ptr) 125 | { 126 | BenchmarkThreadParams *params = (BenchmarkThreadParams *)ptr; 127 | 128 | ((ECDLCpuContext *)params->instance)->benchmarkThreadFunction(¶ms->iterationsPerSecond); 129 | 130 | return NULL; 131 | } 132 | 133 | void ECDLCpuContext::benchmarkThreadFunction(unsigned long long *iterationsPerSecond) 134 | { 135 | util::Timer timer; 136 | timer.start(); 137 | 138 | RhoBase *r = getRho(false); 139 | 140 | for(int i = 0; i < BENCHMARK_ITERATIONS; i++) 141 | { 142 | r->doStep(); 143 | } 144 | 145 | unsigned int t = timer.getTime(); 146 | 147 | *iterationsPerSecond = (unsigned long long) ((double)BENCHMARK_ITERATIONS / ((double)t/1000.0)); 148 | } 149 | 150 | bool ECDLCpuContext::isRunning() 151 | { 152 | return _running; 153 | } 154 | 155 | bool ECDLCpuContext::benchmark(unsigned long long *pointsPerSecondOut) 156 | { 157 | int numThreads = _numThreads; 158 | int pointsPerThread = _pointsPerThread; 159 | 160 | std::vector params; 161 | std::vector threads; 162 | 163 | // Start threads 164 | for(int i = 0; i < numThreads; i++) { 165 | BenchmarkThreadParams *p = new BenchmarkThreadParams; 166 | 167 | p->threadId = i; 168 | p->instance = this; 169 | params.push_back(p); 170 | 171 | Thread t(benchmarkThreadEntry, p); 172 | 173 | threads.push_back(t); 174 | } 175 | 176 | // Wait for all threads to finish 177 | for(int i = 0; i < numThreads; i++) { 178 | threads[i].wait(); 179 | } 180 | 181 | unsigned long long iterationsPerSecond = 0; 182 | unsigned long long pointsPerSecond = 0; 183 | 184 | for(int i = 0; i < numThreads; i++) { 185 | iterationsPerSecond += params[i]->iterationsPerSecond; 186 | pointsPerSecond += params[i]->iterationsPerSecond * _pointsPerThread; 187 | } 188 | 189 | Logger::logInfo("%lld iterations per second\n", iterationsPerSecond); 190 | Logger::logInfo("%lld points per second\n", pointsPerSecond); 191 | 192 | if(pointsPerSecondOut) { 193 | *pointsPerSecondOut = pointsPerSecond; 194 | } 195 | 196 | return true; 197 | } -------------------------------------------------------------------------------- /src/client/client/cpu/math/Fp.h: -------------------------------------------------------------------------------- 1 | #ifndef _PRIME_FIELD_H 2 | #define _PRIME_FIELD_H 3 | 4 | #include "BigInteger.h" 5 | 6 | #ifdef _X86 7 | #include "x86.h" 8 | #else 9 | #include "gmp_math.h" 10 | #endif 11 | 12 | // use unsigned long because it's the CPUs natural word length 13 | #define WORD_LENGTH_BITS (sizeof(unsigned long)*8) 14 | 15 | void printInt(const unsigned long *x, int len); 16 | 17 | 18 | class FpBase { 19 | public: 20 | virtual void subModP(const unsigned long *a, const unsigned long *b, unsigned long *diff) = 0; 21 | virtual void multiplyModP(const unsigned long *a, const unsigned long *b, unsigned long *c) = 0; 22 | virtual void squareModP(const unsigned long *a, unsigned long *aSquared) = 0; 23 | virtual void inverseModP(const unsigned long *input, unsigned long *inverse) = 0; 24 | }; 25 | 26 | FpBase *getFp(BigInteger &p); 27 | 28 | template 29 | class Fp : public FpBase { 30 | 31 | private: 32 | // m value for Barrett reduction. 33 | unsigned long _m[N]; 34 | 35 | // Prime modulus 36 | unsigned long _p[N]; 37 | 38 | // Modulus length in bits 39 | int _pBits; 40 | 41 | // Modulus length in words 42 | int _pWords; 43 | 44 | // Length of m in words 45 | int _mWords; 46 | 47 | // Length of m in bits 48 | int _mBits; 49 | 50 | // P in GMP format because GMP does the modular inversion 51 | mpz_t _gmp_p; 52 | 53 | void getHighBits(const unsigned long *in, unsigned long *out); 54 | void reduceModP(const unsigned long *x, unsigned long *c); 55 | 56 | public: 57 | 58 | Fp() {} 59 | 60 | Fp(const BigInteger &p) 61 | { 62 | memset(_p, 0, sizeof(_p)); 63 | memset(_m, 0, sizeof(_m)); 64 | _pBits = p.getBitLength(); 65 | _pWords = p.getWordLength(); 66 | p.getWords(_p, _pWords); 67 | 68 | // Precompute m = 4^n / p 69 | BigInteger k = BigInteger(2).pow(2 * _pBits); 70 | BigInteger m = k / p; 71 | 72 | _mWords = m.getWordLength(); 73 | _mBits = m.getBitLength(); 74 | m.getWords(_m, _mWords); 75 | 76 | mpz_init(_gmp_p); 77 | 78 | mpz_import(_gmp_p, _pWords, GMP_BYTE_ORDER_LSB, sizeof(unsigned long), GMP_ENDIAN_LITTLE, 0, _p); 79 | } 80 | 81 | 82 | void subModP(const unsigned long *a, const unsigned long *b, unsigned long *diff); 83 | void multiplyModP(const unsigned long *a, const unsigned long *b, unsigned long *c); 84 | void squareModP(const unsigned long *a, unsigned long *aSquared); 85 | void inverseModP(const unsigned long *input, unsigned long *inverse); 86 | }; 87 | 88 | 89 | /** 90 | * Given a number 3 * _pBits in length, get the high _pBits bits 91 | */ 92 | template void Fp::getHighBits(const unsigned long *in, unsigned long *out) 93 | { 94 | int rShift = (2*_pBits) % WORD_LENGTH_BITS; 95 | int lShift = WORD_LENGTH_BITS - rShift; 96 | int index = (2 * _pBits) / WORD_LENGTH_BITS; 97 | 98 | if(rShift > 0) { 99 | for(int i = 0; i < N; i++) { 100 | out[ i ] = (in[ index + i ] >> rShift) | (in[ index + i + 1 ] << lShift); 101 | } 102 | } else { 103 | for(int i = 0; i < N; i++) { 104 | out[ i ] = in[index + i]; 105 | } 106 | } 107 | } 108 | 109 | /** 110 | * Performs reduction mod P using the barrett reduction. It is assumed that 111 | * the product is <= (p-1)^2 112 | */ 113 | template void Fp::reduceModP(const unsigned long *x, unsigned long *c) 114 | { 115 | unsigned long xm[3 * N] = {0}; 116 | 117 | // Multiply by m to get a 3k-bit value 118 | mul(_m, x, xm); 119 | 120 | // It's possible m can be 1 bit longer than P. If P ends on a word boundary then 121 | // m will be 1 word longer than p, so it's quicker to do an addition on the higher 122 | // bits of xm than to multiply by 1. 123 | if(_mWords > N) { 124 | add<2*N>(x, &xm[N], &xm[N]); 125 | } 126 | 127 | // Get the high k bits of xm 128 | unsigned long q[N] = {0}; 129 | getHighBits(xm, q); 130 | 131 | // Multiply by p to get a 2k-bit value 132 | unsigned long qp[2*N] = {0}; 133 | mul(q, _p, qp); 134 | 135 | // Subtract from x to get a k-bit value 136 | sub(x, qp, c); 137 | 138 | qp[N-1] &= ((unsigned long)~0 >> (_pBits % WORD_LENGTH_BITS)); 139 | 140 | // Subtract again if necessary 141 | if(greaterThanEqualTo(c, _p)) { 142 | sub(c, _p, c); 143 | } 144 | } 145 | 146 | /** 147 | * Subtraction mod P 148 | */ 149 | template void Fp::subModP(const unsigned long *a, const unsigned long *b, unsigned long *diff) 150 | { 151 | int borrow = sub(a, b, diff); 152 | 153 | // Check for negative 154 | if(borrow) { 155 | add(diff, _p, diff); 156 | } 157 | } 158 | 159 | /** 160 | * Multiplication mod P 161 | */ 162 | template void Fp::multiplyModP(const unsigned long *a, const unsigned long *b, unsigned long *c) 163 | { 164 | unsigned long product[N*2]; 165 | mul(a, b, product); 166 | reduceModP(product, c); 167 | } 168 | 169 | /** 170 | * Square mod P 171 | */ 172 | template void Fp::squareModP(const unsigned long *a, unsigned long *aSquared) 173 | { 174 | unsigned long product[N*2]; 175 | 176 | square(a, product); 177 | reduceModP(product, aSquared); 178 | } 179 | 180 | /** 181 | * Modular inverse mod P 182 | */ 183 | template void Fp::inverseModP(const unsigned long *input, unsigned long *inverse) 184 | { 185 | mpz_t a; 186 | mpz_t aInv; 187 | 188 | mpz_init(a); 189 | mpz_init(aInv); 190 | 191 | mpz_import(a, _pWords, GMP_BYTE_ORDER_LSB, sizeof(unsigned long), GMP_ENDIAN_LITTLE, 0, input); 192 | 193 | mpz_invert(aInv, a, _gmp_p); 194 | 195 | // Need to zero out the destination 196 | memset(inverse, 0, sizeof(unsigned long) * N); 197 | 198 | mpz_export(inverse, NULL, GMP_BYTE_ORDER_LSB, sizeof(unsigned long), GMP_ENDIAN_LITTLE, 0, aInv); 199 | 200 | mpz_clear(a); 201 | mpz_clear(aInv); 202 | } 203 | #endif -------------------------------------------------------------------------------- /src/client/ecc/ecc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "ecc.h" 3 | #include "BigInteger.h" 4 | 5 | ECCurve::ECCurve() 6 | { 7 | } 8 | 9 | ECCurve::ECCurve(ECParams ¶ms) 10 | { 11 | _p = BigInteger( params.p, 16 ); 12 | _n = BigInteger( params.n, 16 ); 13 | _a = BigInteger( params.a, 16 ); 14 | _b = BigInteger( params.b, 16 ); 15 | _bpx = BigInteger( params.bpx, 16 ); 16 | _bpy = BigInteger( params.bpy, 16 ); 17 | } 18 | 19 | ECCurve::ECCurve(BigInteger p, BigInteger n, BigInteger a, BigInteger b, BigInteger bpx, BigInteger bpy) 20 | { 21 | _p = p; 22 | _n = n; 23 | _a = a; 24 | _b = b; 25 | _bpx = bpx; 26 | _bpy = bpy; 27 | } 28 | 29 | ECCurve& ECCurve::operator=(const ECCurve& curve) 30 | { 31 | _p = curve._p; 32 | _n = curve._n; 33 | _a = curve._a; 34 | _b = curve._b; 35 | _bpx = curve._bpx; 36 | _bpy = curve._bpx; 37 | 38 | return *this; 39 | } 40 | 41 | ECPoint ECCurve::add( ECPoint &p, ECPoint &q ) 42 | { 43 | BigInteger rx; 44 | BigInteger ry; 45 | BigInteger px = p.getX(); 46 | BigInteger py = p.getY(); 47 | BigInteger qx = q.getX(); 48 | BigInteger qy = q.getY(); 49 | 50 | // Px == Qx && Py == Qy 51 | if( p == q ) { 52 | return doubl( p ); 53 | } 54 | 55 | // Px == Qx && Py != Qy 56 | if( px == qx ) { 57 | return ECPoint(); 58 | } 59 | 60 | if( p.isPointAtInfinity() ) { 61 | return q; 62 | } 63 | 64 | if( q.isPointAtInfinity() ) { 65 | return p; 66 | } 67 | 68 | // s = (py - qy)/(px - qx) 69 | BigInteger rise = (py - qy) % _p; 70 | BigInteger run = (px - qx) % _p; 71 | BigInteger s = (run.invm(_p) * rise) % _p; 72 | 73 | // rx = s^2 - px - qx 74 | rx = (s*s - px - qx) % _p; 75 | 76 | // ry = -py + s(px - rx) 77 | ry = (s * (px - rx) - py) % _p; 78 | 79 | return ECPoint( rx, ry ); 80 | } 81 | 82 | ECPoint ECCurve::doubl( ECPoint &p ) 83 | { 84 | if( p.isPointAtInfinity() ) { 85 | return p; 86 | } 87 | 88 | BigInteger px = p.getX(); 89 | BigInteger py = p.getY(); 90 | BigInteger rx; 91 | BigInteger ry; 92 | 93 | // 1 / 2py 94 | BigInteger yInv = (py + py) % _p; 95 | yInv = yInv.invm(_p); 96 | 97 | // 3 * px^2 + a 98 | BigInteger s = ((((px * px) * 3) + _a) * yInv) % _p; 99 | 100 | // rx = s^2 - 2px 101 | rx = (s * s - px - px) % _p; 102 | 103 | // ry = -py + s(px - rx) 104 | ry = (s * (px - rx) - py) % _p; 105 | 106 | return ECPoint( rx, ry ); 107 | } 108 | 109 | ECPoint ECCurve::multiply( BigInteger &k, ECPoint &p ) 110 | { 111 | BigInteger m = k; 112 | ECPointJacobian q = toJacobian( p ); 113 | 114 | m = m % _n; 115 | 116 | ECPointJacobian r; 117 | 118 | while( !m.isZero() ) { 119 | if( m.lsb() ) { 120 | r = addJacobian( r, q ); 121 | } 122 | m = m.rshift( 1 ); 123 | q = doubleJacobian( q ); 124 | } 125 | 126 | return toAffine( r ); 127 | } 128 | 129 | ECPointJacobian ECCurve::toJacobian( ECPoint &p ) 130 | { 131 | return ECPointJacobian( p.getX(), p.getY() ); 132 | } 133 | 134 | ECPoint ECCurve::toAffine( ECPointJacobian &p ) 135 | { 136 | BigInteger z = p.getZ(); 137 | 138 | BigInteger zInv = z.invm( _p ); 139 | BigInteger z2Inv = (zInv * zInv) % _p; 140 | BigInteger z3Inv = (z2Inv * zInv) % _p; 141 | 142 | BigInteger x = p.getX(); 143 | BigInteger y = p.getY(); 144 | 145 | return ECPoint( (x * z2Inv) % _p, (y * z3Inv) % _p ); 146 | } 147 | 148 | ECPoint ECCurve::getBasepoint() 149 | { 150 | return ECPoint( _bpx, _bpy ); 151 | } 152 | 153 | bool ECCurve::pointExists( ECPoint &p ) 154 | { 155 | BigInteger x = p.getX(); 156 | BigInteger y = p.getY(); 157 | 158 | BigInteger leftSide = (y * y) % _p; 159 | BigInteger rightSide = ((x*x*x) + (_a*x) + _b) % _p; 160 | 161 | return leftSide == rightSide; 162 | } 163 | 164 | ECPointJacobian ECCurve::doubleJacobian( ECPointJacobian &p ) 165 | { 166 | BigInteger x = p.getX(); 167 | BigInteger y = p.getY(); 168 | BigInteger z = p.getZ(); 169 | 170 | if( p.isPointAtInfinity() ) { 171 | return p; 172 | } 173 | 174 | // S = 4XY^2 175 | BigInteger s = ((x * y * y) * 4) % _p; 176 | 177 | // M = 3X^2 + AZ^4 178 | BigInteger z4 = (z * z) % _p; 179 | z4 = (z4 * z4) % _p; 180 | 181 | BigInteger m = (((x * x) * 3) + (_a * z4)) % _p; 182 | 183 | // X' = M^2 - 2S 184 | BigInteger x2 = (m * m - s - s) % _p; 185 | 186 | // Y' = M(S - X') - 8Y^4 187 | BigInteger y4 = (y * y) % _p; 188 | y4 = (y4 * y4) % _p; 189 | 190 | BigInteger y2 = ((m * (s - x2)) - (y4 * 8)) % _p; 191 | 192 | // Z' = 2YZ 193 | BigInteger z2 = ((y * z) * 2) % _p; 194 | 195 | return ECPointJacobian( x2, y2, z2 ); 196 | } 197 | 198 | ECPointJacobian ECCurve::addJacobian( ECPointJacobian &p1, ECPointJacobian &p2 ) 199 | { 200 | BigInteger x1 = p1.getX(); 201 | BigInteger y1 = p1.getY(); 202 | BigInteger z1 = p1.getZ(); 203 | 204 | BigInteger x2 = p2.getX(); 205 | BigInteger y2 = p2.getY(); 206 | BigInteger z2 = p2.getZ(); 207 | 208 | if( p1.isPointAtInfinity() ) { 209 | return p2; 210 | } else if( p2.isPointAtInfinity() ) { 211 | return p1; 212 | } 213 | 214 | // U1 = X1*Z2^2 215 | BigInteger u1 = (x1 * z2 * z2) % _p; 216 | 217 | // U2 = X2*Z1^2 218 | BigInteger u2 = (x2 * z1 * z1) % _p; 219 | 220 | // S1 = Y1*Z2^3 221 | BigInteger s1 = (y1 * z2 * z2 * z2) % _p; 222 | 223 | // S2 = Y2*Z1^3 224 | BigInteger s2 = (y2 * z1 * z1 *z1) % _p; 225 | 226 | if( u1 == u2 ) { 227 | if( s1 != s2 ) { 228 | return ECPointJacobian(); 229 | } else { 230 | return doubleJacobian( p1 ); 231 | } 232 | } 233 | 234 | BigInteger h = (u2 - u1) % _p; 235 | BigInteger h2 = (h * h) % _p; 236 | BigInteger h3 = (h2 * h) % _p; 237 | BigInteger r = (s2 - s1) % _p; 238 | BigInteger t = ((u1 * h2) * 2) % _p; 239 | 240 | // X' = R^2 - H^3 - 2*U1*H^2 241 | BigInteger newX = ((r * r) - h3 - t) % _p; 242 | 243 | // Y' = R*(U1*H^2 - X') - S1*H^3 244 | BigInteger newY = ((r * (u1*h2 - newX)) - (s1 * h3)) % _p; 245 | 246 | // Z' = H*Z1*Z2 247 | BigInteger newZ = (h * z1 * z2) % _p; 248 | 249 | return ECPointJacobian(newX, newY, newZ); 250 | } 251 | -------------------------------------------------------------------------------- /src/server/server.py: -------------------------------------------------------------------------------- 1 | import json 2 | import ecc 3 | from ecc import ECCurve, ECPoint 4 | import os 5 | import random 6 | import sys 7 | import ecdl 8 | import util 9 | from util import ECDLPParams 10 | 11 | from pprint import pprint 12 | from flask import Flask, jsonify, request 13 | from flask_jsonschema import JsonSchema, ValidationError 14 | 15 | app = Flask(__name__) 16 | app.config['JSONSCHEMA_DIR'] = os.path.join(app.root_path, '/') 17 | app.config['PROPAGATE_EXCEPTIONS'] = True 18 | 19 | jsonschema = JsonSchema(app) 20 | 21 | ''' 22 | Look up a context based on id 23 | ''' 24 | def getContext(id): 25 | names = ecdl.Database.getNames() 26 | 27 | if id in names: 28 | return ecdl.loadContext(id) 29 | 30 | return None 31 | 32 | ''' 33 | Encodes ECDLP parameters as json 34 | ''' 35 | def encodeContextParams(ctx): 36 | 37 | content = {} 38 | content['params'] = ctx.params.encode() 39 | 40 | # Convert R points to string values 41 | content['points'] = [] 42 | for e in ctx.rPoints: 43 | p = {} 44 | p['a'] = str(e['a']) 45 | p['b'] = str(e['b']) 46 | p['x'] = str(e['x']) 47 | p['y'] = str(e['y']) 48 | content['points'].append(p) 49 | 50 | return content 51 | 52 | ''' 53 | Route for /status/ 54 | 55 | Gets the status of a job 56 | ''' 57 | @app.route("/status/", methods=['GET']) 58 | def status(id): 59 | 60 | # Get the context 61 | ctx = getContext(id) 62 | if ctx == None: 63 | return "", 404 64 | 65 | # Get the status 66 | response = {} 67 | response['status'] = ctx.status; 68 | 69 | # Return the status 70 | return jsonify(response) 71 | 72 | ''' 73 | Route for /create/ 74 | 75 | Create a news job with the specified id 76 | ''' 77 | @app.route("/create/", methods=['POST']) 78 | def create(id): 79 | 80 | # Make sure it doesn't already exist 81 | if getContext(id) != None: 82 | return "", 500 83 | 84 | content = request.json 85 | 86 | # Decode parameters 87 | params = ECDLPParams() 88 | params.decode(content['params']) 89 | 90 | if content.has_key('email'): 91 | email = content['email'] 92 | else: 93 | email = '' 94 | 95 | #Verify parameters are correct 96 | if not ecc.verifyCurveParameters(params.a, params.b, params.p, params.n, params.gx, params.gy): 97 | return "Invalid ECC parameters", 400 98 | 99 | # Create the context 100 | ctx = ecdl.createContext(params, id, email) 101 | 102 | return "" 103 | 104 | ''' 105 | Route for /params/ 106 | 107 | Gets the parameters for a job 108 | ''' 109 | @app.route("/params/", methods=['GET']) 110 | def get_params(id): 111 | 112 | # Get the context 113 | ctx = getContext(id) 114 | 115 | if ctx == None: 116 | return "", 404 117 | 118 | # Get the parameters 119 | content = encodeContextParams(ctx) 120 | 121 | # Return parameters 122 | return json.dumps(content) 123 | 124 | ''' 125 | Route for /submit/ 126 | 127 | This route is for submitting distinguished points to the server 128 | ''' 129 | @app.route("/submit/", methods=['POST']) 130 | def submit_points(id): 131 | 132 | # Get the context 133 | ctx = getContext(id) 134 | 135 | if ctx == None: 136 | print("Count not find context " + id) 137 | return "", 404 138 | 139 | # Check if the job is still running 140 | if ctx.status == "stopped": 141 | return "", 500 142 | 143 | content = request.json 144 | 145 | modulus = pow(2, ctx.params.dBits) 146 | 147 | points = [] 148 | 149 | # Verify all points 150 | for i in range(len(content)): 151 | 152 | a = util.parseInt(content[i]['a']) 153 | b = util.parseInt(content[i]['b']) 154 | x = util.parseInt(content[i]['x']) 155 | y = util.parseInt(content[i]['y']) 156 | length = content[i]['length'] 157 | 158 | # Verify the exponents are within range 159 | if a <= 0 or a >= ctx.curve.n or b <= 0 or b >= ctx.curve.n: 160 | print("Invalid exponents:") 161 | print(str(a)) 162 | print(str(b)) 163 | return "", 400 164 | 165 | # Verify point is valid 166 | if x < 0 or x >= ctx.curve.p or y < 0 or y >= ctx.curve.p: 167 | print("Invalid point:") 168 | print("X: " + str(x)) 169 | print("y: " + str(y)) 170 | return "", 400 171 | 172 | # Check that the x value has the correct number of 0 bits 173 | if x % modulus != 0: 174 | print("[" + hex(x) + "," + hex(y) +"]") 175 | print("Not distinguished point! Rejecting!") 176 | return "", 400 177 | 178 | # Verify aG = bQ = (x,y) 179 | endPoint = ECPoint(x, y) 180 | if verifyPoint(ctx.curve, ctx.pointG, ctx.pointQ, a, b, endPoint) == False: 181 | print("Invalid point!") 182 | print(content[i]) 183 | print("") 184 | return "", 400 185 | 186 | # Append to list 187 | dp = {} 188 | dp['a'] = a 189 | dp['b'] = b 190 | dp['x'] = x 191 | dp['y'] = y 192 | dp['length'] = length 193 | points.append(dp) 194 | 195 | # Connect to database 196 | ctx.database.open() 197 | 198 | # Write list to database 199 | collisions = ctx.database.insertMultiple(points) 200 | 201 | # If there are any collisions, add them to the collisions table 202 | if collisions != None: 203 | for c in collisions: 204 | dp = ctx.database.get(c['x'], c['y']) 205 | print("==== FOUND COLLISION ====") 206 | print("a1: " + hex(c['a'])) 207 | print("b1: " + hex(c['b'])) 208 | print("length: " + util.intToString(c['length'])) 209 | print("") 210 | print("a2: " + hex(dp['a'])) 211 | print("b2: " + hex(dp['b'])) 212 | print("length: " + util.intToString(dp['length'])) 213 | print("") 214 | print("x: " + hex(c['x'])) 215 | print("y: " + hex(c['y'])) 216 | 217 | ctx.database.insertCollision(c['a'], c['b'], c['length'], dp['a'], dp['b'], dp['length'], c['x'], c['y']) 218 | 219 | ctx.database.close() 220 | 221 | return "" 222 | 223 | ''' 224 | Verify that a point is on the curve 225 | ''' 226 | def verifyPoint(curve, g, q, endA, endB, endPoint): 227 | 228 | # Check that end point exists 229 | if not curve.verifyPoint(endPoint): 230 | return False 231 | 232 | return True 233 | 234 | ''' 235 | Program entry point 236 | ''' 237 | def main(): 238 | 239 | print("ECDLP Server") 240 | 241 | try: 242 | ecdl.loadConfig("config/config.json") 243 | except Exception as e: 244 | print("Error opening config file " + str(e)) 245 | sys.exit(1) 246 | 247 | print("Starting server") 248 | app.run(host = "0.0.0.0", port = ecdl.Config.port) 249 | 250 | if __name__ == "__main__": 251 | main() 252 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ecdl 2 | 3 | This is an implementation of the parallel Pollard's rho algorithm, applied to the elliptic curve discrete logarithm problem. 4 | 5 | It solves the ECDLP for curves over a prime field, in Weierstrass form `Y^2 = X^3 + aX + b` 6 | 7 | It consists of a central server program and a client program. The client program can be run on many machines to help solve 8 | the problem faster. The client requests work from the server and sends back the results. 9 | 10 | It is not a mature project yet, so watch out for bugs. 11 | 12 | #### Dependencies 13 | 14 | Currently builds on Linux using make. 15 | 16 | Client: 17 | 18 | * g++ 19 | * GNU Multiprecision Arithmetic Library ([https://gmplib.org/](https://gmplib.org/)) 20 | * libcurl ([http://curl.haxx.se/](http://curl.haxx.se/)) 21 | 22 | CUDA client: 23 | 24 | * CUDA Toolkit ([https://developer.nvidia.com/cuda-toolkit](https://developer.nvidia.com/cuda-toolkit)) 25 | 26 | Server: 27 | * mysql database 28 | * python 2.7 with flask and MySQLdb 29 | 30 | Optional: 31 | * NASM for building with the optimized x86 routines 32 | * sage ([http://www.sagemath.org](http://www.sagemath.org)) for running script to generate ECDL problems 33 | 34 | ### Building the client 35 | 36 | To build the client, run the Makefile in the `src/client` directory. 37 | 38 | To build the CPU client: 39 | 40 | ``` 41 | # make client_cpu 42 | ``` 43 | 44 | To build the CUDA client: 45 | 46 | ``` 47 | # make client_cuda 48 | ``` 49 | 50 | 51 | #### Running the server 52 | 53 | The server consists of two programs: `server.py` and `solver.py`. 54 | 55 | `server.py` is whats clients connect to when they request work. 56 | 57 | `solver.py` waits until a collision is found in the database and then attempts to solve the discrete logarithm 58 | 59 | There is a server config file `config/config.json` which needs to be edited 60 | 61 | ``` 62 | { 63 | "port":9999, // Port the server listens on 64 | "dbUser":"user", // mysql user name 65 | "dbPassword":"password", // mysql user password 66 | "dbHost":"127.0.0.1" // mysql host 67 | } 68 | ``` 69 | 70 | ``` 71 | Both programs are run using `python`: 72 | ``` 73 | 74 | 75 | ``` 76 | # python server.py 77 | ``` 78 | 79 | ``` 80 | # python solver.py 81 | ``` 82 | 83 | 84 | 85 | #### Setting up a job on the server 86 | 87 | The parameters for the particular problem you want to solve are encded in JSON format 88 | 89 | Values can be in decimal or hex with the `0x` prefix 90 | 91 | ``` 92 | params:{ 93 | "field":"prime", // Field used. Currently only "prime" is supported 94 | "a":"0x39C95E6DDDB1BC45733C", // 'a' term in the curve equation 95 | "b":"0x1F16D880E89D5A1C0ED1 ", // 'b' term in the curve equation 96 | "p":"0x62CE5177412ACA899CF5", // prime modulus of the field 97 | "n":"0x62CE5177407B7258DC31", // order of the curve 98 | "gx":"0x315D4B201C208475057D", // 'x' value of generator point G 99 | "gy":"0x035F3DF5AB370252450A", // 'y' value of generator point G 100 | "qx":"0x0679834CEFB7215DC365", // 'x' value of point Q 101 | "qy":"0x4084BC50388C4E6FDFAB", // 'y' value of point Q 102 | "bits":"20" // Number of distinguished bits (default is 20) 103 | } 104 | ``` 105 | 106 | There is a sage script in the scripts directory can generate random parameters and write them to the file for you. 107 | 108 | For example, to generate a curve with a 56-bit prime modulus, run: 109 | 110 | ``` 111 | # ./gencurve.sh 56 ecp56.json 112 | ``` 113 | 114 | Once you have your JSON file, you can upload it to the server using the create.sh script. As arguments it takes the json file and the name of the job 115 | 116 | ``` 117 | ./create.sh ecp56.json ecp56 118 | ``` 119 | 120 | #### Running the client 121 | 122 | There is a `settings.json` file that needs to be edited 123 | 124 | ``` 125 | { 126 | "server_host": "127.0.0.1", // Server host 127 | "server_port": 9999, // server port 128 | 129 | "point_cache_size": 128, // Points to collect before sending to server 130 | "cpu_threads": 4, // Number of threads. 1 thread per core is optimal 131 | "cpu_points_per_thread": 16 // Number of points each thread will compute in parallel 132 | 133 | 134 | "cuda_blocks": 1, // Number of CUDA blocks 135 | "cuda_threads": 32, // Number of CUDA threads per block 136 | "cuda_points_per_thread": 16, // Number of points each CUDA thread will compute in parallel 137 | "cuda_device": 0 // The index of the CUDA device to use 138 | } 139 | ``` 140 | 141 | After a job has been set up on the server, the client can be run. It takes the job name as its argument: 142 | 143 | ``` 144 | # ./client-cpu ecp56 145 | ``` 146 | 147 | 148 | #### Solving 149 | 150 | When the server finds two colliding distinguished points, it will output them to stdout like this: 151 | 152 | ``` 153 | ==== FOUND COLLISION ==== 154 | a1: 0x55bd5461e01ade 155 | b1: 0x3a1c06b8843ff7 156 | 157 | a2: 0x2ab615a84ce098 158 | b2: 0x39fe7a74c5175a 159 | 160 | x: 0x64355cd6200000 161 | y: 0x71d04a7b43448 162 | 163 | ``` 164 | 165 | If `solver.py` is running, it will detect the collision and attempt to find the solution. 166 | 167 | 168 | The output will look something like this: 169 | ``` 170 | Counting walk #1 length 171 | Found endpoint 172 | 1410541 173 | Counting walk #2 length 174 | Found endpoint 175 | 1380960 176 | Checking for Robin Hood 177 | Not a Robin Hood :) 178 | Stepping 29581 times 179 | Searching for collision 180 | Found collision! 181 | 0x3547e3e36752e8 0x25d6f02438168 0x1a8454e115340b 0x9df3a3469de720 182 | 0x90ce1fd597aa72 0xd25379c576bfe 0x1a8454e115340b 0x9df3a3469de720 183 | Verification successful 184 | The solution is 77fc86a17007 185 | 186 | ``` 187 | 188 | #### Choosing the number of distinguished bits 189 | 190 | The number of distinguished bits determines the trade-off between space and running time of the algorithm. 191 | 192 | The value to choose depends on the amount of storage available, number of processors, and speed of the processors. 193 | 194 | A naive collision search on a curve of order `2^n` requires `2^(n/2)` storage and `(2^(n/2))/m` time for `m` processors. 195 | 196 | Using the distinguished point technique, the search requires `(2^(n/2-d)` storage and `((2^(n/2))/m + 2.5 * 2^d)t` time where `d` is the number of distinguished bits, `m` is the number of processors and `t` is the time it takes to perform 1 point addition. Note that this is including the time it takes for the collison to be detected and solved on the server. 197 | 198 | For example, to solve the discrete logarithm on a curve with an order of `~2^80`, it would require about `2^40` points to find a collision. 199 | 200 | If using a 24-bit distinguisher, then you will need to find about `2^16` distinguished points. On 128 processors where each processor can do 1 million point additions per second, the running time would be approximately `(2^40 / 128 + 2.5 * 2^24)0.000001` = 2.3 hours. 201 | 202 | -------------------------------------------------------------------------------- /src/server/solve.py: -------------------------------------------------------------------------------- 1 | import json 2 | from ecc import ECCurve, ECPoint 3 | import os 4 | import ecdl 5 | import sys 6 | 7 | NUM_R_POINTS = 32 8 | 9 | def getContext(id): 10 | if id in _ctx: 11 | return _ctx[id] 12 | 13 | return None 14 | 15 | ''' 16 | Converts a string to integer by guessing the base 17 | ''' 18 | def parseInt(n): 19 | return int(n, 0) 20 | 21 | ''' 22 | Verify that a point is on the curve 23 | ''' 24 | def verifyPoint(curve, g, q, endA, endB, endPoint): 25 | 26 | # Check that end point exists 27 | if not curve.verifyPoint(endPoint): 28 | return False 29 | 30 | return True 31 | 32 | ''' 33 | Checks if the end point in the first random walk is the 34 | start point of the second walk 35 | 36 | Robin Hood is a reference to character in English 37 | folklore hero who could shoot a second arrow on the 38 | exact trajectory as the first. 39 | ''' 40 | def checkForRobinHood(curve, start, end, start2, rPoints): 41 | 42 | point = start 43 | count = 0 44 | while True: 45 | idx = point.x & 0x1f 46 | 47 | if point.x == start2.x and point.y == start2.y: 48 | return True 49 | 50 | if point.x == end.x and point.y == end.y: 51 | return False 52 | 53 | point = curve.add(point, ECPoint(rPoints[idx]['x'], rPoints[idx]['y'])) 54 | 55 | ''' 56 | Gets the total length of the random walk 57 | ''' 58 | def getLength(curve, startA, startB, startPoint, endPoint, rPoints, dBits): 59 | 60 | point = startPoint 61 | a = startA 62 | b = startB 63 | points = [] 64 | i = 0 65 | length = 1 66 | 67 | # We want to terminate the walk if it is statistically too long 68 | limit = (2**dBits) * 4 69 | while True: 70 | idx = point.x & 0x1f 71 | 72 | length = length + 1 73 | 74 | if point.x == endPoint.x and point.y == endPoint.y: 75 | print("Found endpoint") 76 | return length 77 | break 78 | 79 | # Increment the point and coefficients 80 | r = ECPoint(rPoints[idx]['x'], rPoints[idx]['y']) 81 | point = curve.add(point, r) 82 | a = (a + rPoints[idx]['a']) % curve.n 83 | b = (b + rPoints[idx]['b']) % curve.n 84 | 85 | if i > limit: 86 | print("Walk is too long. Terminating") 87 | return -1 88 | 89 | return length 90 | 91 | ''' 92 | Inversion mod p using Fermat method 93 | ''' 94 | def invm(x, m): 95 | y = x % m 96 | return pow(y, m-2, m) 97 | 98 | def swap(a, b): 99 | return b, a 100 | 101 | ''' 102 | Gets the next point in the random walk 103 | ''' 104 | def nextPoint(curve, a, b, point, rPoints): 105 | 106 | idx = point.x & 0x1f 107 | 108 | newPoint = curve.add(point, ECPoint(rPoints[idx]['x'], rPoints[idx]['y'])) 109 | newA = (a + rPoints[idx]['a']) % curve.n 110 | newB = (b + rPoints[idx]['b']) % curve.n 111 | 112 | return newA, newB, newPoint 113 | 114 | 115 | ''' 116 | Given two walks with the same ending point, it finds where the walks collide. 117 | ''' 118 | def findCollision(curve, g, q, a1Start, b1Start, p1Start, a2Start, b2Start, p2Start, endPoint, rPoints, dBits): 119 | 120 | a1 = a1Start 121 | b1 = b1Start 122 | 123 | a2 = a2Start 124 | b2 = b2Start 125 | 126 | print("Counting walk #1 length") 127 | p1Len = getLength(curve, a1, b1, p1Start, endPoint, rPoints, dBits) 128 | 129 | if p1Len < 0: 130 | return None, None, None, None, None, None 131 | print(str(p1Len)) 132 | 133 | print("Counting walk #2 length") 134 | p2Len = getLength(curve, a2, b2, p2Start, endPoint, rPoints, dBits) 135 | 136 | if p2Len < 0: 137 | return None, None, None, None, None, None 138 | print(str(p2Len)) 139 | 140 | # For simplicity, we want P1 to always be the longer one 141 | if p1Len < p2Len: 142 | a1, a2 = swap(a1, a2) 143 | b1, b2 = swap(b1, b2) 144 | p1Start, b2Start = swap(p1Start, p2Start) 145 | p1Len, p2Len = swap(p1Len, p2Len) 146 | 147 | print("Checking for Robin Hood") 148 | 149 | if checkForRobinHood(curve, p1Start, endPoint, p2Start, rPoints): 150 | print("It's a Robin Hood :(") 151 | return None, None, None, None, None, None 152 | else: 153 | print("Not a Robin Hood :)") 154 | 155 | point1 = p1Start 156 | point2 = p2Start 157 | 158 | diff = p1Len - p2Len 159 | print("Stepping " + str(diff) + " times") 160 | for i in xrange(diff): 161 | a1, b1, point1 = nextPoint(curve, a1, b1, point1, rPoints) 162 | 163 | print("Searching for collision") 164 | while True: 165 | 166 | if (point1.x == endPoint.x and point1.y == endPoint.y) or (point2.x == endPoint.x and point2.y == endPoint.y): 167 | print("Reached the end :(") 168 | return None 169 | 170 | a1Old = a1 171 | b1Old = b1 172 | point1Old = point1 173 | 174 | a2Old = a2 175 | b2Old = b2 176 | point2Old = point2 177 | 178 | a1, b1, point1 = nextPoint(curve, a1Old, b1Old, point1Old, rPoints) 179 | a2, b2, point2 = nextPoint(curve, a2Old, b2Old, point2Old, rPoints) 180 | 181 | if point1.x == point2.x and point1.y == point2.y: 182 | print("Found collision!") 183 | print(hex(a1) + " " + hex(b1) + " " + hex(point1.x) + " " + hex(point1.y)) 184 | print(hex(a2) + " " + hex(b2) + " " + hex(point2.x) + " " + hex(point2.y)) 185 | return a1, b1, point1, a2, b2, point2 186 | 187 | ''' 188 | Program entry point 189 | ''' 190 | def main(): 191 | 192 | if len(sys.argv) != 8: 193 | print("Usage: a1 b1 a2 b2 x y job") 194 | exit() 195 | 196 | a1 = parseInt(sys.argv[1]) 197 | b1 = parseInt(sys.argv[2]) 198 | a2 = parseInt(sys.argv[3]) 199 | b2 = parseInt(sys.argv[4]) 200 | endX = parseInt(sys.argv[5]) 201 | endY = parseInt(sys.argv[6]) 202 | 203 | name = sys.argv[7] 204 | 205 | try: 206 | ecdl.loadConfig("config/config.json") 207 | except: 208 | print("Error opening config: " + sys.exc_info[0]) 209 | sys.exit(1) 210 | 211 | ctx = ecdl.loadContext(name) 212 | curve = ctx.curve 213 | rPoints = ctx.rPoints 214 | dBits = ctx.params.dBits 215 | 216 | # Get G and Q 217 | g = ECPoint(ctx.params.gx, ctx.params.gy) 218 | q = ECPoint(ctx.params.qx, ctx.params.qy) 219 | 220 | endPoint = ECPoint(endX, endY) 221 | 222 | # Calculate starting points 223 | p1Start = curve.add(curve.multiply(a1, g), curve.multiply(b1, q)) 224 | p2Start = curve.add(curve.multiply(a2, g), curve.multiply(b2, q)) 225 | 226 | 227 | a1, b1, point1, a2, b2, point2 = findCollision(curve, g, q, a1, b1, p1Start, a2, b2, p2Start, endPoint, rPoints, dBits) 228 | 229 | if a1 == None: 230 | return 231 | 232 | # Compute private key 233 | k = (((a1 - a2)%curve.n) * invm(b2 - b1, curve.n)) % curve.n 234 | r = curve.multiply(k, g) 235 | print("Q= " + hex(q.x) + " " + hex(q.y)) 236 | print("kG = " + hex(r.x) + " " + hex(r.y)) 237 | print("") 238 | print("k=" + hex(k)) 239 | 240 | if __name__ == "__main__": 241 | main() 242 | -------------------------------------------------------------------------------- /src/client/client/ServerConnection.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "json/json.h" 8 | #include "ServerConnection.h" 9 | #include "logger.h" 10 | 11 | static std::string toString(int x) 12 | { 13 | char str[10] = {0}; 14 | 15 | sprintf(str, "%d", x); 16 | 17 | return std::string(str); 18 | } 19 | 20 | static std::string encodePoints(std::vector points) 21 | { 22 | Json::Value root; 23 | unsigned int count = points.size(); 24 | for(unsigned int i = 0; i < count; i++) { 25 | root[i]["a"] = points[i].a.toString(10); 26 | root[i]["b"] = points[i].b.toString(10); 27 | root[i]["x"] = points[i].x.toString(10); 28 | root[i]["y"] = points[i].y.toString(10); 29 | root[i]["length"] = points[i].length; 30 | } 31 | 32 | Json::StyledWriter writer; 33 | 34 | return writer.write(root); 35 | } 36 | 37 | static int decodeStatusMsg(std::string encoded) 38 | { 39 | Json::Value root; 40 | Json::Reader reader; 41 | 42 | if(!reader.parse(encoded, root)) { 43 | std::cout << "JSON parsing error: " << reader.getFormattedErrorMessages(); 44 | return -1; 45 | } 46 | 47 | std::string statusString = root.get("status", "").asString(); 48 | 49 | if(statusString == "unsolved") { 50 | return SERVER_STATUS_RUNNING; 51 | } else if(statusString == "solved") { 52 | return SERVER_STATUS_STOPPED; 53 | } 54 | 55 | throw "Unknown status '" + statusString + "'"; 56 | } 57 | 58 | /** 59 | * Reads a BigInteger from a JSON string 60 | */ 61 | static BigInteger readBigInt(Json::Value &root, std::string field) 62 | { 63 | std::string s = root.get(field, "").asString(); 64 | if(s == "") { 65 | throw std::string("Parsing error: " + field + " is not an integer"); 66 | } 67 | return BigInteger(s); 68 | } 69 | 70 | static ParamsMsg decodeParametersMsg(std::string encoded) 71 | { 72 | ParamsMsg paramsMsg; 73 | 74 | Json::Value root; 75 | Json::Reader reader; 76 | 77 | if(!reader.parse(encoded, root)) { 78 | std::string err = "JSON parsing error: " + reader.getFormattedErrorMessages(); 79 | throw err; 80 | } 81 | 82 | // Decode problem parameters 83 | Json::Value params = root["params"]; 84 | 85 | paramsMsg.a = readBigInt(params, "a"); 86 | paramsMsg.b = readBigInt(params, "b"); 87 | paramsMsg.p = readBigInt(params, "p"); 88 | paramsMsg.n = readBigInt(params, "n"); 89 | paramsMsg.gx = readBigInt(params, "gx"); 90 | paramsMsg.gy = readBigInt(params, "gy"); 91 | paramsMsg.qx = readBigInt(params, "qx"); 92 | paramsMsg.qy = readBigInt(params, "qy"); 93 | paramsMsg.dBits = params.get("bits", -1).asInt(); 94 | 95 | // Decode R points 96 | Json::Value points = root["points"]; 97 | for(int i = 0; i < 32; i++) { 98 | Json::Value point = points[i]; 99 | paramsMsg.rx[i] = readBigInt(point, "x"); 100 | paramsMsg.ry[i] = readBigInt(point, "y"); 101 | } 102 | 103 | return paramsMsg; 104 | } 105 | 106 | /** 107 | * CURL callback. Appends data string 108 | */ 109 | static size_t curlCallback(void *data, size_t size, size_t count, void *destPtr) 110 | { 111 | if(data == NULL || count == 0) { 112 | return 0; 113 | } 114 | 115 | std::string *dest = (std::string *)destPtr; 116 | std::string dataString((char *)data, size * count); 117 | 118 | (*dest) += dataString; 119 | 120 | return size * count; 121 | } 122 | 123 | 124 | ServerConnection::ServerConnection(std::string host, int port) 125 | { 126 | if(port < 0 || port > 65535) { 127 | throw std::string("Invalid port number"); 128 | } 129 | 130 | _host = host; 131 | _port = port; 132 | 133 | // Convert port number to string 134 | char buf[8] = {0}; 135 | sprintf(buf, "%d", port); 136 | 137 | _url = host + ":" + std::string(buf); 138 | } 139 | 140 | 141 | ParamsMsg ServerConnection::getParameters(std::string id) 142 | { 143 | CURL *curl; 144 | 145 | std::string url = _url + "/params/" + id; 146 | std::string result; 147 | long httpCode = 0; 148 | curl = curl_easy_init(); 149 | 150 | curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); 151 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlCallback); 152 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result); 153 | 154 | CURLcode res = curl_easy_perform(curl); 155 | if(res != CURLE_OK) { 156 | std::string errorMsg(curl_easy_strerror(res)); 157 | printf("curl error: %s\n", errorMsg.c_str()); 158 | curl_easy_cleanup(curl); 159 | throw errorMsg; 160 | } 161 | curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); 162 | 163 | if(httpCode != 200) { 164 | curl_easy_cleanup(curl); 165 | throw std::string("HTTP error " + toString(httpCode)); 166 | } 167 | 168 | curl_easy_cleanup(curl); 169 | 170 | return decodeParametersMsg(result); 171 | } 172 | 173 | 174 | void ServerConnection::submitPoints(std::string id, std::vector &points) 175 | { 176 | std::string encodedPoints = encodePoints(points); 177 | 178 | CURL *curl; 179 | 180 | std::string url = _url + "/submit/" + id; 181 | std::string result; 182 | long httpCode = 0; 183 | 184 | curl = curl_easy_init(); 185 | 186 | struct curl_slist *headers = NULL; 187 | headers = curl_slist_append(headers, "Content-Type: application/json"); 188 | 189 | curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); 190 | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 191 | curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, NULL); 192 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, encodedPoints.c_str()); 193 | 194 | CURLcode res = curl_easy_perform(curl); 195 | if(res != CURLE_OK) { 196 | std::string errorMsg(curl_easy_strerror(res)); 197 | curl_easy_cleanup(curl); 198 | throw errorMsg; 199 | } 200 | 201 | curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); 202 | 203 | if(httpCode != 200) { 204 | curl_easy_cleanup(curl); 205 | throw std::string("HTTP error " + toString(httpCode)); 206 | } 207 | curl_easy_cleanup(curl); 208 | } 209 | 210 | int ServerConnection::getStatus(std::string id) 211 | { 212 | CURL *curl = NULL; 213 | CURLcode res; 214 | long httpCode = 0; 215 | 216 | std::string url = _url + "/status/" + id; 217 | std::string result = ""; 218 | 219 | curl = curl_easy_init(); 220 | 221 | curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); 222 | curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, NULL); 223 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlCallback); 224 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result); 225 | res = curl_easy_perform(curl); 226 | 227 | if(res != CURLE_OK) { 228 | std::string errorMsg(curl_easy_strerror(res)); 229 | curl_easy_cleanup(curl); 230 | throw errorMsg; 231 | } 232 | 233 | curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); 234 | 235 | if(httpCode == 404) { 236 | curl_easy_cleanup(curl); 237 | throw std::string("id does not exist"); 238 | } else if(httpCode != 200) { 239 | std::string errorMsg("HTTP error " + toString(httpCode)); 240 | curl_easy_cleanup(curl); 241 | throw errorMsg; 242 | } 243 | 244 | curl_easy_cleanup(curl); 245 | 246 | return decodeStatusMsg(result); 247 | } 248 | -------------------------------------------------------------------------------- /src/client/client/cpu/math/x86/x86.h: -------------------------------------------------------------------------------- 1 | #ifndef _FP_X86_H 2 | #define _FP_X86_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | /** 9 | Declarations for x86 assembly routines 10 | */ 11 | int x86_sub64(const unsigned long *a, const unsigned long *b, unsigned long *diff); 12 | int x86_sub96(const unsigned long *a, const unsigned long *b, unsigned long *diff); 13 | int x86_sub128(const unsigned long *a, const unsigned long *b, unsigned long *diff); 14 | int x86_sub160(const unsigned long *a, const unsigned long *b, unsigned long *diff); 15 | int x86_sub192(const unsigned long *a, const unsigned long *b, unsigned long *diff); 16 | int x86_sub224(const unsigned long *a, const unsigned long *b, unsigned long *diff); 17 | int x86_sub256(const unsigned long *a, const unsigned long *b, unsigned long *diff); 18 | 19 | void x86_add64(const unsigned long *a, const unsigned long *b, unsigned long *sum); 20 | void x86_add96(const unsigned long *a, const unsigned long *b, unsigned long *sum); 21 | void x86_add128(const unsigned long *a, const unsigned long *b, unsigned long *sum); 22 | void x86_add160(const unsigned long *a, const unsigned long *b, unsigned long *sum); 23 | void x86_add192(const unsigned long *a, const unsigned long *b, unsigned long *sum); 24 | void x86_add224(const unsigned long *a, const unsigned long *b, unsigned long *sum); 25 | void x86_add256(const unsigned long *a, const unsigned long *b, unsigned long *sum); 26 | 27 | void x86_mul64(const unsigned long *a, const unsigned long *b, unsigned long *product); 28 | void x86_mul96(const unsigned long *a, const unsigned long *b, unsigned long *product); 29 | void x86_mul128(const unsigned long *a, const unsigned long *b, unsigned long *product); 30 | void x86_mul160(const unsigned long *a, const unsigned long *b, unsigned long *product); 31 | void x86_mul192(const unsigned long *a, const unsigned long *b, unsigned long *product); 32 | void x86_mul224(const unsigned long *a, const unsigned long *b, unsigned long *product); 33 | void x86_mul256(const unsigned long *a, const unsigned long *b, unsigned long *product); 34 | 35 | void x86_mul64_128(const unsigned long *a, const unsigned long *b, unsigned long *product); 36 | void x86_mul96_192(const unsigned long *a, const unsigned long *b, unsigned long *product); 37 | void x86_mul128_256(const unsigned long *a, const unsigned long *b, unsigned long *product); 38 | void x86_mul160_320(const unsigned long *a, const unsigned long *b, unsigned long *product); 39 | void x86_mul192_384(const unsigned long *a, const unsigned long *b, unsigned long *product); 40 | void x86_mul224_448(const unsigned long *a, const unsigned long *b, unsigned long *product); 41 | void x86_mul256_512(const unsigned long *a, const unsigned long *b, unsigned long *product); 42 | 43 | void x86_square64(const unsigned long *a, unsigned long *product); 44 | void x86_square96(const unsigned long *a, unsigned long *product); 45 | void x86_square128(const unsigned long *a, unsigned long *product); 46 | void x86_square160(const unsigned long *a, unsigned long *product); 47 | void x86_square192(const unsigned long *a, unsigned long *product); 48 | void x86_square224(const unsigned long *a, unsigned long *product); 49 | void x86_square256(const unsigned long *a, unsigned long *product); 50 | 51 | 52 | #ifdef __cplusplus 53 | } 54 | #endif 55 | 56 | 57 | template int sub(const unsigned long *a, const unsigned long *b, unsigned long *diff) 58 | { 59 | switch(N) { 60 | case 2: 61 | return x86_sub64(a, b, diff); 62 | case 3: 63 | return x86_sub96(a, b, diff); 64 | case 4: 65 | return x86_sub128(a, b, diff); 66 | case 5: 67 | return x86_sub160(a, b, diff); 68 | case 6: 69 | return x86_sub192(a, b, diff); 70 | case 7: 71 | return x86_sub224(a, b, diff); 72 | case 8: 73 | return x86_sub256(a, b, diff); 74 | default: 75 | fprintf(stderr, "Error: Not compiled for %d-bit integers\n", N*32); 76 | exit(1); 77 | } 78 | } 79 | 80 | template< int N> void add(const unsigned long *a, const unsigned long *b, unsigned long *sum) 81 | { 82 | 83 | switch(N) { 84 | case 2: 85 | x86_add64(a, b, sum); 86 | break; 87 | case 3: 88 | x86_add96(a, b, sum); 89 | break; 90 | case 4: 91 | x86_add128(a, b, sum); 92 | break; 93 | case 5: 94 | x86_add160(a, b, sum); 95 | break; 96 | case 6: 97 | x86_add192(a, b, sum); 98 | break; 99 | case 7: 100 | x86_add224(a, b, sum); 101 | break; 102 | case 8: 103 | x86_add256(a, b, sum); 104 | break; 105 | default: 106 | fprintf(stderr, "Error: Not compiled for %d-bit integers\n", N*32); 107 | exit(1); 108 | } 109 | } 110 | 111 | template void mul(const unsigned long *a, const unsigned long *b, unsigned long *product) 112 | { 113 | switch(N) { 114 | case 2: 115 | x86_mul64(a, b, product); 116 | break; 117 | case 3: 118 | x86_mul96(a, b, product); 119 | break; 120 | case 4: 121 | x86_mul128(a, b, product); 122 | break; 123 | case 5: 124 | x86_mul160(a, b, product); 125 | break; 126 | case 6: 127 | x86_mul192(a, b, product); 128 | break; 129 | case 7: 130 | x86_mul224(a, b, product); 131 | break; 132 | case 8: 133 | x86_mul256(a, b, product); 134 | break; 135 | default: 136 | fprintf(stderr, "Error: Not compiled for %d-bit integers\n", N*32); 137 | exit(1); 138 | } 139 | } 140 | 141 | template void mul(const unsigned long *a, const unsigned long *b, unsigned long *product) 142 | { 143 | switch(N1) { 144 | case 2: 145 | x86_mul64_128(a, b, product); 146 | break; 147 | case 3: 148 | x86_mul96_192(a, b, product); 149 | break; 150 | case 4: 151 | x86_mul128_256(a, b, product); 152 | break; 153 | case 5: 154 | x86_mul160_320(a, b, product); 155 | break; 156 | case 6: 157 | x86_mul192_384(a, b, product); 158 | break; 159 | case 7: 160 | x86_mul224_448(a, b, product); 161 | break; 162 | case 8: 163 | x86_mul256_512(a, b, product); 164 | break; 165 | default: 166 | fprintf(stderr, "Error: Not compiled for %d-bit integers\n", N1*32); 167 | exit(1); 168 | } 169 | } 170 | 171 | template void square(const unsigned long *a, unsigned long *product) 172 | { 173 | switch(N) { 174 | case 2: 175 | x86_square64(a, product); 176 | break; 177 | case 3: 178 | x86_square96(a, product); 179 | break; 180 | case 4: 181 | x86_square128(a, product); 182 | break; 183 | case 5: 184 | x86_square160(a, product); 185 | break; 186 | case 6: 187 | x86_square192(a, product); 188 | break; 189 | case 7: 190 | x86_square224(a, product); 191 | break; 192 | case 8: 193 | x86_square256(a, product); 194 | break; 195 | default: 196 | fprintf(stderr, "Error: Not compiled for %d-bit integers\n", N*32); 197 | exit(1); 198 | } 199 | } 200 | 201 | /** 202 | * Returns true if a >= b 203 | */ 204 | template bool greaterThanEqualTo(const unsigned long *a, const unsigned long *b) 205 | { 206 | for(int i = N - 1; i >= 0; i--) { 207 | if(a[i] < b[i]) { 208 | return false; 209 | } else if(a[i] > b[i]) { 210 | return true; 211 | } 212 | } 213 | 214 | return true; 215 | } 216 | 217 | #endif -------------------------------------------------------------------------------- /src/server/solver.py: -------------------------------------------------------------------------------- 1 | import json 2 | from ecc import ECCurve, ECPoint 3 | import os 4 | import ecdl 5 | import sys 6 | 7 | import util 8 | import time 9 | import smtplib 10 | from email.mime.text import MIMEText 11 | 12 | ''' 13 | Inversion mod p using Fermat method 14 | ''' 15 | def invm(x, m): 16 | y = x % m 17 | return pow(y, m-2, m) 18 | 19 | def swap(a, b): 20 | return b, a 21 | 22 | class RhoSolver: 23 | point1 = None 24 | p1Len = 0 25 | point2 = None 26 | p2Len = 0 27 | endPoint = None 28 | params = None 29 | curve = None 30 | a1 = None 31 | b1 = None 32 | a2 = None 33 | b2 = None 34 | rPoints = None 35 | solved = False 36 | k = None 37 | 38 | ''' 39 | Constructs a new RhoSolver object 40 | ''' 41 | def __init__(self, params, rPoints, a1, b1, a2, b2, endPoint): 42 | 43 | # Get params 44 | self.params = params 45 | self.a1 = a1 46 | self.b1 = b1 47 | self.a2 = a2 48 | self.b2 = b2 49 | self.endPoint = endPoint 50 | self.rPoints = rPoints 51 | 52 | # Set up curve 53 | self.curve = ECCurve(params.a, params.b, params.p, params.n, params.gx, params.gy) 54 | 55 | # Compute starting points 56 | g = ECPoint(self.params.gx, self.params.gy) 57 | q = ECPoint(self.params.qx, self.params.qy) 58 | 59 | self.point1 = self.curve.add(self.curve.multiply(a1, g), self.curve.multiply(b1, q)) 60 | self.point2 = self.curve.add(self.curve.multiply(a2, g), self.curve.multiply(b2, q)) 61 | 62 | # Set up array of random walk points 63 | #self.rPoints = [] 64 | #for rPoint in rPoints: 65 | # self.rPoints.append(ECPoint(rPoint['x'], rPoint['y'])) 66 | 67 | 68 | ''' 69 | Checks if the end point in the first random walk is the 70 | start point of the second walk 71 | 72 | Robin Hood is a reference to character in English 73 | folklore hero who could shoot a second arrow on the 74 | exact trajectory as the first. 75 | ''' 76 | def _isRobinHood(self): 77 | 78 | currentPoint = self.point1 79 | count = 0 80 | while True: 81 | idx = currentPoint.x & 0x1f 82 | 83 | if currentPoint.x == self.point2.x and currentPoint.y == self.point2.y: 84 | return True 85 | 86 | if currentPoint.x == self.endPoint.x and currentPoint.y == self.endPoint.y: 87 | return False 88 | 89 | # Iterate to next point 90 | currentPoint = self.curve.add(currentPoint, ECPoint(self.rPoints[idx]['x'], self.rPoints[idx]['y'])) 91 | 92 | ''' 93 | Gets the total length of the random walk 94 | ''' 95 | def _getWalkLength(self, startA, startB, startPoint): 96 | 97 | point = startPoint 98 | a = startA 99 | b = startB 100 | i = 0 101 | length = 1 102 | 103 | # We want to terminate the walk if it is statistically too long 104 | limit = (2**self.params.dBits) * 4 105 | 106 | while True: 107 | idx = point.x & 0x1f 108 | 109 | length = length + 1 110 | 111 | if point.x == self.endPoint.x and point.y == self.endPoint.y: 112 | print("Found endpoint") 113 | return length 114 | break 115 | 116 | # Increment the point and coefficients 117 | r = ECPoint(self.rPoints[idx]['x'], self.rPoints[idx]['y']) 118 | point = self.curve.add(point, r) 119 | 120 | a = (a + self.rPoints[idx]['a']) % self.curve.n 121 | b = (b + self.rPoints[idx]['b']) % self.curve.n 122 | 123 | if i > limit: 124 | print("Walk is too long. Terminating") 125 | return -1 126 | 127 | return length 128 | 129 | 130 | 131 | ''' 132 | Gets the next point in the random walk 133 | ''' 134 | def _nextPoint(self, a, b, point): 135 | 136 | idx = point.x & 0x1f 137 | 138 | newPoint = self.curve.add(point, ECPoint(self.rPoints[idx]['x'], self.rPoints[idx]['y'])) 139 | newA = (a + self.rPoints[idx]['a']) % self.curve.n 140 | newB = (b + self.rPoints[idx]['b']) % self.curve.n 141 | 142 | return newA, newB, newPoint 143 | 144 | 145 | def _countWalkLengths(self): 146 | 147 | print("Counting walk #1 length") 148 | self.p1Len = self._getWalkLength(self.a1, self.b1, self.point1) 149 | 150 | #if self.p1Len < 0: 151 | # return None, None, None, None, None, None 152 | print(str(self.p1Len)) 153 | 154 | print("Counting walk #2 length") 155 | self.p2Len = self._getWalkLength(self.a2, self.b2, self.point2) 156 | 157 | #if p2Len < 0: 158 | # return None, None, None, None, None, None 159 | print(str(self.p2Len)) 160 | 161 | # For simplicity, we want P1 to always be the longer one 162 | if self.p1Len < self.p2Len: 163 | self.a1, self.a2 = swap(self.a1, self.a2) 164 | self.b1, self.b2 = swap(self.b1, self.b2) 165 | self.point1, self.point2 = swap(self.point1, self.point2) 166 | self.p1Len, self.p2Len = swap(self.p1Len, self.p2Len) 167 | 168 | 169 | ''' 170 | Given two walks with the same ending point, it finds where the walks collide. 171 | ''' 172 | #curve, g, q, a1Start, b1Start, p1Start, a2Start, b2Start, p2Start, endPoint, rPoints, dBits): 173 | def _findCollision(self): 174 | 175 | self._countWalkLengths() 176 | 177 | print("Checking for Robin Hood") 178 | 179 | if self._isRobinHood(): 180 | print("It's a Robin Hood :(") 181 | return None, None, None, None, None, None 182 | else: 183 | print("Not a Robin Hood :)") 184 | 185 | point1 = self.point1 186 | point2 = self.point2 187 | 188 | diff = self.p1Len - self.p2Len 189 | print("Stepping " + str(diff) + " times") 190 | 191 | a1 = self.a1 192 | b1 = self.b1 193 | 194 | a2 = self.a2 195 | b2 = self.b2 196 | 197 | for i in xrange(diff): 198 | a1, b1, point1 = self._nextPoint(a1, b1, point1) 199 | 200 | print("Searching for collision") 201 | while True: 202 | 203 | if (point1.x == self.endPoint.x and point1.y == self.endPoint.y) or (point2.x == self.endPoint.x and point2.y == self.endPoint.y): 204 | print("Reached the end :(") 205 | return None 206 | 207 | a1Old = a1 208 | b1Old = b1 209 | point1Old = point1 210 | 211 | a2Old = a2 212 | b2Old = b2 213 | point2Old = point2 214 | 215 | a1, b1, point1 = self._nextPoint(a1, b1, point1) 216 | a2, b2, point2 = self._nextPoint(a2, b2, point2) 217 | 218 | if point1.x == point2.x and point1.y == point2.y: 219 | print("Found collision!") 220 | print(hex(a1) + " " + hex(b1) + " " + hex(point1.x) + " " + hex(point1.y)) 221 | print(hex(a2) + " " + hex(b2) + " " + hex(point2.x) + " " + hex(point2.y)) 222 | return a1, b1, point1, a2, b2, point2 223 | 224 | def solve(self): 225 | a1, b1, point1, a2, b2, point2 = self._findCollision() 226 | 227 | if a1 == None: 228 | self.solved = False 229 | return 230 | 231 | k = (((a1 - a2)%self.curve.n) * invm(b2 - b1, self.curve.n)) % self.curve.n 232 | 233 | # Verify 234 | r = self.curve.multiply(k, self.curve.bp) 235 | 236 | if r.x != self.params.qx or r.y != self.params.qy: 237 | print("Verification failed") 238 | self.solved = False 239 | else: 240 | print("Verification successful") 241 | self.solved = True 242 | 243 | self.k = k 244 | 245 | def sendNotificationEmail(ctx): 246 | print("Sending email to " + ctx.email) 247 | 248 | 249 | def solveNextCollision(ctx): 250 | 251 | ctx.database.open() 252 | coll = ctx.database.getNextCollision() 253 | ctx.database.close() 254 | 255 | if coll == None: 256 | return 257 | 258 | solver = RhoSolver(ctx.params, ctx.rPoints, coll['a1'], coll['b1'], coll['a2'], coll['b2'], ECPoint(coll['x'], coll['y'])) 259 | 260 | solver.solve() 261 | 262 | ctx.database.open() 263 | 264 | if solver.solved == True: 265 | print("The solution is " + util.toHex(solver.k)) 266 | ctx.database.setSolution(solver.k) 267 | ctx.database.updateCollisionStatus(coll['id'], 'T') 268 | else: 269 | ctx.database.updateCollisionStatus(coll['id'], 'F') 270 | 271 | ctx.database.close() 272 | 273 | def mainLoop(): 274 | 275 | while True: 276 | 277 | contextNames = ecdl.Database.getNames() 278 | 279 | if contextNames != None and len(contextNames) != 0: 280 | 281 | # Get a list of unsolved contexts 282 | ctxList = [] 283 | for name in contextNames: 284 | ctx = ecdl.loadContext(name) 285 | 286 | if ctx.status.lower() == 'unsolved' and ctx.collisions > 0: 287 | ctxList.append(ctx) 288 | solveNextCollision(ctx) 289 | 290 | # If anything is in the list, solve them 291 | if len(ctxList) > 0: 292 | for ctx in ctxList: 293 | solveNextCollision(ctx) 294 | else: 295 | time.sleep(30) 296 | else: 297 | time.sleep(30) 298 | 299 | ''' 300 | Program entry point 301 | ''' 302 | def main(): 303 | 304 | try: 305 | ecdl.loadConfig("config/config.json") 306 | except: 307 | print("Error opening config: " + sys.exc_info[0]) 308 | sys.exit(1) 309 | 310 | mainLoop() 311 | 312 | 313 | if __name__ == "__main__": 314 | main() 315 | -------------------------------------------------------------------------------- /src/client/client/cpu/math/x86/gen.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This program generates x86 assembly code for big integer arithmetic 3 | ''' 4 | 5 | import sys 6 | 7 | # Generate addition function 8 | def gen_add(bits): 9 | words = bits / 32 10 | 11 | print("global x86_add" + str(bits)) 12 | print("x86_add" + str(bits) + ":") 13 | print("") 14 | print("push ebx") 15 | 16 | print(" mov ebx, dword [esp + 8]") 17 | print(" mov ecx, dword [esp + 12]") 18 | print(" mov edx, dword [esp + 16]") 19 | print("") 20 | 21 | print(" mov eax, dword [ebx]") 22 | print(" add eax, dword [ecx]") 23 | print(" mov dword [edx], eax") 24 | 25 | for i in range(1,words): 26 | print(" mov eax, dword [ebx + %d]" % (i*4)) 27 | print(" adc eax, dword [ecx + %d]" % (i*4)) 28 | 29 | print(" mov dword [edx + %d], eax" % (i*4)) 30 | print("") 31 | 32 | print(" pop ebx") 33 | print(" ret") 34 | print("") 35 | 36 | # Generate subtraction function 37 | def gen_sub(bits): 38 | words = bits / 32 39 | 40 | print("global x86_sub" + str(bits)) 41 | print("x86_sub" + str(bits) + ":") 42 | print("") 43 | print(" push ebp") 44 | print(" mov ebp, esp") 45 | print(" push ebx") 46 | print("") 47 | 48 | print(" mov ebx, dword [ebp + 8]") 49 | print(" mov ecx, dword [ebp + 12]") 50 | print(" mov edx, dword [ebp + 16]") 51 | print("") 52 | 53 | for i in range(words): 54 | print(" ; a[%d] + b[%d]" % (i,i)) 55 | print(" mov eax, dword [ebx + %d]" % (i*4)) 56 | if i == 0: 57 | print(" sub eax, dword [ecx + %d]" % (i*4)) 58 | else: 59 | print(" sbb eax, dword [ecx + %d]" % (i*4)) 60 | 61 | print(" mov dword [edx + %d], eax" % (i*4)) 62 | print("") 63 | 64 | # Return the borrow bit 65 | print(" mov eax, 0") 66 | print(" adc eax, 0") 67 | 68 | print(" pop ebx") 69 | print(" mov esp, ebp") 70 | print(" pop ebp") 71 | print(" ret") 72 | print("") 73 | 74 | def gen_multiply(bits): 75 | words = bits / 32 76 | 77 | print("global x86_mul" + str(bits)) 78 | print("x86_mul" + str(bits) + ":") 79 | print("") 80 | print(" push ebp") 81 | print(" mov ebp, esp") 82 | print(" push ebx") 83 | print(" push edi") 84 | print(" push esi") 85 | print("") 86 | 87 | print(" mov esi, dword [ebp + 8]") 88 | print(" mov ecx, dword [ebp + 12]") 89 | print(" mov edi, dword [ebp + 16]") 90 | print("") 91 | 92 | 93 | # Do b[0] * a[0] to a[n-1]. This is a separate loop because we move the 94 | # result to the buffer, not add them 95 | print(" mov ebx, 0") 96 | for j in range(0, words): 97 | print(" mov eax, dword [ecx + %d]" % (0)) 98 | print(" mul dword [esi + %d]" % (j*4)) 99 | print(" add eax, ebx") 100 | print(" mov ebx, edx") 101 | print(" mov dword [edi + %d], eax" % (j*4)) 102 | print(" adc ebx, 0") 103 | 104 | print(" mov dword [edi + %d], ebx" % (words*4)) 105 | 106 | 107 | for i in range(1, words): 108 | 109 | #Reset high word to 0 110 | print(" mov ebx, 0") 111 | 112 | for j in range(words): 113 | 114 | # Read b[i] from memory 115 | print(" mov eax, dword [ecx + %d]" % (i*4)) 116 | 117 | # Multiply by a[j] 118 | print(" mul dword [esi + %d]" % (j*4)) 119 | 120 | # add old high to new low word 121 | print(" add eax, ebx") 122 | 123 | # add the carry 124 | print(" adc edx, 0") 125 | 126 | # store new high word in ebx 127 | print(" mov ebx, edx") 128 | 129 | # add new low + old high to s[i + j] 130 | print(" add dword [edi + %d], eax" % ((i+j)*4)) 131 | 132 | # add the carry to the new high word 133 | print(" adc ebx, 0") 134 | 135 | # Write high word to the end 136 | print(" mov dword [edi + %d], ebx" % ((i+words)*4)) 137 | 138 | 139 | print(" pop esi") 140 | print(" pop edi") 141 | print(" pop ebx") 142 | print(" mov esp, ebp") 143 | print(" pop ebp") 144 | print(" ret") 145 | print("") 146 | 147 | # Performs N by 2N multiplication 148 | def gen_multiply2n(bits): 149 | #words = bits / 32 150 | n1Bits = bits 151 | n1Words = n1Bits / 32 152 | 153 | n2Bits = 2 * bits 154 | n2Words = n2Bits / 32 155 | 156 | print("global x86_mul" + str(n1Bits) + "_" + str(n2Bits)) 157 | print("x86_mul" + str(n1Bits) + "_" + str(n2Bits) + ":"); 158 | print("") 159 | print(" push ebp") 160 | print(" mov ebp, esp") 161 | print(" push ebx") 162 | print(" push edi") 163 | print(" push esi") 164 | print("") 165 | 166 | #print(" mov esi, dword [ebp + 8]") 167 | #print(" mov ecx, dword [ebp + 12]") 168 | print(" mov ecx, dword [ebp + 8]") 169 | print(" mov esi, dword [ebp + 12]") 170 | print(" mov edi, dword [ebp + 16]") 171 | print("") 172 | 173 | 174 | # Do b[0] * a[0] to a[n-1]. This is a separate loop because we move the 175 | # result to the buffer, not add them 176 | print(" mov ebx, 0") 177 | for j in range(0, n2Words): 178 | print(" mov eax, dword [ecx + %d]" % (0)) 179 | print(" mul dword [esi + %d]" % (j*4)) 180 | print(" add eax, ebx") 181 | print(" mov ebx, edx") 182 | print(" mov dword [edi + %d], eax" % (j*4)) 183 | print(" adc ebx, 0") 184 | 185 | print(" mov dword [edi + %d], ebx" % (n2Words*4)) 186 | 187 | 188 | for i in range(1, n1Words): 189 | 190 | #Reset high word to 0 191 | print(" mov ebx, 0") 192 | 193 | for j in range(n2Words): 194 | 195 | # Read b[i] from memory 196 | print(" mov eax, dword [ecx + %d]" % (i*4)) 197 | 198 | # Multiply by a[j] 199 | print(" mul dword [esi + %d]" % (j*4)) 200 | 201 | # add old high to new low word 202 | print(" add eax, ebx") 203 | 204 | # add the carry 205 | print(" adc edx, 0") 206 | 207 | # store new high word in ebx 208 | print(" mov ebx, edx") 209 | 210 | # add new low + old high to s[i + j] 211 | print(" add dword [edi + %d], eax" % ((i+j)*4)) 212 | 213 | # add the carry to the new high word 214 | print(" adc ebx, 0") 215 | 216 | # Write high word to the end 217 | print(" mov dword [edi + %d], ebx" % ((i+n2Words)*4)) 218 | 219 | 220 | print(" pop esi") 221 | print(" pop edi") 222 | print(" pop ebx") 223 | print(" mov esp, ebp") 224 | print(" pop ebp") 225 | print(" ret") 226 | print("") 227 | 228 | def gen_square(bits): 229 | words = bits / 32 230 | 231 | print("global x86_square" + str(bits)) 232 | print("x86_square" + str(bits) + ":") 233 | print("") 234 | print(" push ebp") 235 | print(" mov ebp, esp") 236 | print(" push ebx") 237 | print(" push edi") 238 | print(" push esi") 239 | print("") 240 | 241 | print(" mov esi, dword [ebp + 8]") 242 | print(" mov edi, dword [ebp + 12]") 243 | print("") 244 | 245 | 246 | # Do b[0] * a[0] to a[n-1]. This is a separate loop because we move the 247 | # result to the buffer, not add them 248 | print(" mov ebx, 0") 249 | for j in range(0, words): 250 | print(" mov eax, dword [esi + %d]" % (0)) 251 | print(" mul dword [esi + %d]" % (j*4)) 252 | print(" add eax, ebx") 253 | print(" mov ebx, edx") 254 | print(" mov dword [edi + %d], eax" % (j*4)) 255 | print(" adc ebx, 0") 256 | 257 | print(" mov dword [edi + %d], ebx" % (words*4)) 258 | 259 | 260 | for i in range(1, words): 261 | 262 | #Reset high word to 0 263 | print(" mov ebx, 0") 264 | 265 | for j in range(words): 266 | 267 | # Read b[i] from memory 268 | print(" mov eax, dword [esi + %d]" % (i*4)) 269 | 270 | # Multiply by a[j] 271 | print(" mul dword [esi + %d]" % (j*4)) 272 | 273 | # add old high to new low word 274 | print(" add eax, ebx") 275 | 276 | # add the carry 277 | print(" adc edx, 0") 278 | 279 | # store new high word in ebx 280 | print(" mov ebx, edx") 281 | 282 | # add new low + old high to to s[i + j] 283 | print(" add dword [edi + %d], eax" % ((i+j)*4)) 284 | 285 | # add the carry to the new high word 286 | print(" adc ebx, 0") 287 | 288 | # Write high word to the end 289 | print(" mov dword [edi + %d], ebx" % ((i+words)*4)) 290 | 291 | 292 | print(" pop esi") 293 | print(" pop edi") 294 | print(" pop ebx") 295 | print(" mov esp, ebp") 296 | print(" pop ebp") 297 | print(" ret") 298 | print("") 299 | 300 | # Generate multiplication function 301 | def main(): 302 | if len(sys.argv) < 3: 303 | print("Invalid arguments") 304 | exit() 305 | 306 | method = sys.argv[1] 307 | bits = int(sys.argv[2]) 308 | 309 | if method == "add": 310 | gen_add(bits) 311 | elif method == "sub": 312 | gen_sub(bits) 313 | elif method == "mul": 314 | gen_multiply(bits) 315 | elif method == "square": 316 | gen_square(bits) 317 | elif method == "cmpgte": 318 | gen_cmpgt(bits) 319 | elif method == "mul2n": 320 | gen_multiply2n(bits) 321 | else: 322 | print("Invalid method") 323 | exit(1) 324 | 325 | if __name__ == "__main__": 326 | main() 327 | -------------------------------------------------------------------------------- /src/client/bigint/bigint.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "BigInteger.h" 3 | #include "util.h" 4 | 5 | #ifdef _WIN32 6 | #include "mpirxx.h" 7 | #else 8 | #include "gmpxx.h" 9 | #endif 10 | 11 | BigInteger::BigInteger() 12 | { 13 | //mpz_set_si(e.get_mpz_t(), 0); 14 | } 15 | 16 | BigInteger::~BigInteger() 17 | { 18 | } 19 | 20 | BigInteger::BigInteger(int i) 21 | { 22 | //mpz_set_si(this->e.get_mpz_t(), i); 23 | this->e = i; 24 | } 25 | 26 | BigInteger::BigInteger(std::string s, int base) 27 | { 28 | // Try to detect the base 29 | if(base == 0) { 30 | 31 | // Check for hex 32 | if(s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { 33 | base = 16; 34 | s = s.substr(2); 35 | } else { 36 | for(unsigned int i = 0; i < s.length(); i++) { 37 | char c = s[i]; 38 | if((c >= 'A' && c <= 'F') || (c >= 'a' && c<= 'f')) { 39 | base = 16; 40 | break; 41 | } 42 | } 43 | } 44 | 45 | if(base == 0) { 46 | base = 10; 47 | } 48 | } 49 | 50 | if(mpz_set_str(this->e.get_mpz_t(), s.c_str(), base)){ 51 | throw std::string("Error converting string to BigInteger"); 52 | } 53 | } 54 | 55 | BigInteger::BigInteger(const BigInteger &i) 56 | { 57 | this->e = i.e; 58 | } 59 | 60 | BigInteger::BigInteger(const unsigned char *bytes, size_t len) 61 | { 62 | // Import the bytes interprated as an integer with least significant bytes first 63 | mpz_import(this->e.get_mpz_t(), len, GMP_BYTE_ORDER_LSB, 1, GMP_ENDIAN_NATIVE, 0, bytes); 64 | } 65 | 66 | BigInteger::BigInteger(const unsigned long *words, size_t len) 67 | { 68 | mpz_import(this->e.get_mpz_t(), len, GMP_BYTE_ORDER_LSB, sizeof(unsigned long), GMP_ENDIAN_NATIVE, 0, words); 69 | } 70 | 71 | BigInteger::BigInteger(const unsigned int *words, size_t len) 72 | { 73 | mpz_import(this->e.get_mpz_t(), len, GMP_BYTE_ORDER_LSB, sizeof(unsigned int), GMP_ENDIAN_NATIVE, 0, words); 74 | } 75 | 76 | BigInteger BigInteger::pow(unsigned int exponent) const 77 | { 78 | BigInteger product; 79 | 80 | mpz_pow_ui(product.e.get_mpz_t(), this->e.get_mpz_t(), exponent); 81 | 82 | return product; 83 | } 84 | 85 | BigInteger BigInteger::pow(const BigInteger &exponent, const BigInteger &modulus) const 86 | { 87 | BigInteger product; 88 | 89 | mpz_powm( product.e.get_mpz_t(), this->e.get_mpz_t(), exponent.e.get_mpz_t(), modulus.e.get_mpz_t() ); 90 | 91 | return product; 92 | } 93 | 94 | BigInteger BigInteger::pow(unsigned int exponent, const BigInteger &modulus) const 95 | { 96 | BigInteger product; 97 | 98 | mpz_powm_ui( product.e.get_mpz_t(), this->e.get_mpz_t(), exponent, modulus.e.get_mpz_t() ); 99 | 100 | return product; 101 | } 102 | 103 | BigInteger BigInteger::invm(const BigInteger &modulus) const 104 | { 105 | BigInteger inverse; 106 | 107 | mpz_invert( inverse.e.get_mpz_t(), this->e.get_mpz_t(), modulus.e.get_mpz_t() ); 108 | 109 | return inverse; 110 | } 111 | 112 | BigInteger BigInteger::rshift(int n) const 113 | { 114 | BigInteger tmp; 115 | 116 | tmp.e = this->e; 117 | tmp.e >>= n; 118 | 119 | return tmp; 120 | } 121 | 122 | int BigInteger::lsb() const 123 | { 124 | return mpz_tstbit( this->e.get_mpz_t(), 0 ); 125 | } 126 | 127 | bool BigInteger::isZero() const 128 | { 129 | int zero = mpz_cmp_ui( this->e.get_mpz_t(), 0 ); 130 | 131 | if( zero == 0 ) { 132 | return true; 133 | } else { 134 | return false; 135 | } 136 | } 137 | 138 | bool BigInteger::operator==(const BigInteger &i) const 139 | { 140 | int r = mpz_cmp( this->e.get_mpz_t(), i.e.get_mpz_t() ); 141 | 142 | if( r == 0 ) { 143 | return true; 144 | } 145 | 146 | return false; 147 | } 148 | 149 | bool BigInteger::operator==(const int &i) const 150 | { 151 | int r = mpz_cmp_si( this->e.get_mpz_t(), i); 152 | 153 | if( r == 0 ) { 154 | return true; 155 | } 156 | 157 | return false; 158 | } 159 | 160 | bool BigInteger::operator<(const BigInteger &i) const 161 | { 162 | int r = mpz_cmp(this->e.get_mpz_t(), i.e.get_mpz_t()); 163 | 164 | if( r < 0) { 165 | return true; 166 | } else { 167 | return false; 168 | } 169 | } 170 | 171 | bool BigInteger::operator!=(const BigInteger &i) const 172 | { 173 | if (this->e != i.e) { 174 | return true; 175 | } else { 176 | return false; 177 | } 178 | /* 179 | int r = mpz_cmp( this->e.get_mpz_t(), i.e.get_mpz_t() ); 180 | 181 | if( r != 0 ) { 182 | return true; 183 | } 184 | 185 | return false; 186 | */ 187 | } 188 | 189 | BigInteger BigInteger::operator%(const BigInteger &m) const 190 | { 191 | BigInteger mod; 192 | mod.e = this->e % m.e; 193 | 194 | if(mod.e < 0) { 195 | mod.e = mod.e + m.e; 196 | } 197 | 198 | return mod; 199 | } 200 | 201 | BigInteger BigInteger::operator-(const BigInteger &a) const 202 | { 203 | BigInteger diff; 204 | 205 | diff.e = this->e - a.e; 206 | return diff; 207 | } 208 | 209 | BigInteger BigInteger::operator+(const BigInteger &a) const 210 | { 211 | BigInteger sum; 212 | sum.e = this->e + a.e; 213 | 214 | return sum; 215 | } 216 | 217 | BigInteger BigInteger::operator+=(const BigInteger &a) const 218 | { 219 | BigInteger sum; 220 | 221 | sum.e = this->e + a.e; 222 | 223 | return sum; 224 | } 225 | 226 | /* 227 | BigInteger BigInteger::operator=(const BigInteger &i) const 228 | { 229 | printf("BigInteger assignment operator %s\n", i.toString().c_str()); 230 | fflush(stdout); 231 | //this->e = i.e; 232 | BigInteger x; 233 | //mpz_set(x.e, i.e); 234 | x.e = i.e; 235 | 236 | return x; 237 | } 238 | */ 239 | 240 | BigInteger BigInteger::operator*(const BigInteger &a) const 241 | { 242 | BigInteger product; 243 | product.e = this->e * a.e; 244 | return product; 245 | } 246 | 247 | BigInteger BigInteger::operator*(int &i) const 248 | { 249 | BigInteger product; 250 | product.e = this->e * i; 251 | 252 | return product; 253 | } 254 | 255 | BigInteger BigInteger::operator&(const int &i) const 256 | { 257 | BigInteger result; 258 | result.e = this->e & i; 259 | 260 | return result; 261 | } 262 | 263 | BigInteger BigInteger::operator/(const BigInteger &i) const 264 | { 265 | BigInteger quotient; 266 | quotient.e = this->e / i.e; 267 | 268 | return quotient; 269 | } 270 | 271 | BigInteger BigInteger::operator<<(const int &i) const 272 | { 273 | BigInteger tmp; 274 | 275 | tmp.e = this->e; 276 | tmp.e <<= i; 277 | 278 | return tmp; 279 | } 280 | 281 | BigInteger BigInteger::operator>>(const int &i) const 282 | { 283 | BigInteger tmp; 284 | 285 | tmp.e = this->e; 286 | tmp.e >>= i; 287 | 288 | return tmp; 289 | } 290 | 291 | std::string BigInteger::toString(int base) const 292 | { 293 | char *ptr = mpz_get_str(NULL, base, this->e.get_mpz_t()); 294 | std::string s(ptr); 295 | free( ptr ); 296 | 297 | return s; 298 | } 299 | 300 | size_t BigInteger::getBitLength() const 301 | { 302 | size_t bits = mpz_sizeinbase( this->e.get_mpz_t(), 2 ); 303 | 304 | return bits; 305 | } 306 | 307 | size_t BigInteger::getByteLength() const 308 | { 309 | size_t bits = mpz_sizeinbase( this->e.get_mpz_t(), 2 ); 310 | 311 | return (bits + 7) / 8; 312 | } 313 | 314 | size_t BigInteger::getWordLength() const 315 | { 316 | size_t bits = mpz_sizeinbase( this->e.get_mpz_t(), 2 ); 317 | int wordSize = sizeof(unsigned long)*8; 318 | 319 | return (bits + wordSize - 1) / wordSize; 320 | } 321 | 322 | size_t BigInteger::getLengthNative() const 323 | { 324 | size_t bits = mpz_sizeinbase( this->e.get_mpz_t(), 2 ); 325 | int wordSize = sizeof(unsigned long)*8; 326 | 327 | return (bits + wordSize - 1) / wordSize; 328 | } 329 | 330 | size_t BigInteger::getLength32() const 331 | { 332 | size_t bits = mpz_sizeinbase( this->e.get_mpz_t(), 2 ); 333 | 334 | return (bits + 31) / 32; 335 | } 336 | 337 | size_t BigInteger::getLength64() const 338 | { 339 | size_t bits = mpz_sizeinbase( this->e.get_mpz_t(), 2 ); 340 | 341 | return (bits + 63) / 64; 342 | } 343 | 344 | void BigInteger::getWords(unsigned long *words, size_t size) const 345 | { 346 | memset( words, 0, size * sizeof(unsigned long) ); 347 | mpz_export( words, NULL, GMP_BYTE_ORDER_LSB, sizeof(unsigned long), GMP_ENDIAN_NATIVE, 0, this->e.get_mpz_t() ); 348 | } 349 | 350 | 351 | void BigInteger::getWords(unsigned int *words, size_t size) const 352 | { 353 | memset( words, 0, size * sizeof(unsigned int) ); 354 | mpz_export( words, NULL, GMP_BYTE_ORDER_LSB, sizeof(unsigned int), GMP_ENDIAN_NATIVE, 0, this->e.get_mpz_t() ); 355 | } 356 | 357 | void BigInteger::getWords(unsigned int *words) const 358 | { 359 | mpz_export( words, NULL, GMP_BYTE_ORDER_LSB, sizeof(unsigned int), GMP_ENDIAN_NATIVE, 0, this->e.get_mpz_t() ); 360 | } 361 | 362 | 363 | void BigInteger::getBytes(unsigned char *bytes, size_t size) const 364 | { 365 | memset( bytes, 0, size ); 366 | mpz_export( bytes, NULL, GMP_BYTE_ORDER_LSB, 1, GMP_ENDIAN_NATIVE, 0, this->e.get_mpz_t() ); 367 | } 368 | 369 | bool BigInteger::equals(BigInteger &i) const 370 | { 371 | int r = mpz_cmp( this->e.get_mpz_t(), i.e.get_mpz_t() ); 372 | 373 | if( r == 0 ) { 374 | return true; 375 | } else { 376 | return false; 377 | } 378 | } 379 | 380 | BigInteger randomBigInteger(const BigInteger &min, const BigInteger &max) 381 | { 382 | BigInteger range = max - min; 383 | 384 | unsigned int len = range.getByteLength(); 385 | 386 | unsigned char bytes[len]; 387 | 388 | util::getRandomBytes(bytes, len); 389 | 390 | BigInteger x( bytes, len ); 391 | 392 | x = x % range; 393 | BigInteger value = min + x; 394 | 395 | return value; 396 | } 397 | -------------------------------------------------------------------------------- /src/client/client/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "client.h" 6 | #include "util.h" 7 | #include "logger.h" 8 | #include "threads.h" 9 | #include "ServerConnection.h" 10 | #include "config.h" 11 | #include "client.h" 12 | #include "ECDLContext.h" 13 | #include "ecc.h" 14 | 15 | #ifdef _CUDA 16 | #include "ECDLCuda.h" 17 | #else 18 | #include "ECDLCPU.h" 19 | #endif 20 | 21 | 22 | ECDLContext *getNewContext(const ECDLPParams *params, BigInteger *rx, BigInteger *ry, int numRPoints, void (*callback)(struct CallbackParameters *)) 23 | { 24 | ECDLContext *ctx = NULL; 25 | #ifdef _CUDA 26 | Logger::logInfo("Creating CUDA context..."); 27 | ctx = new ECDLCudaContext(_config.device, _config.blocks, _config.threads, _config.pointsPerThread, params, rx, ry, numRPoints, callback); 28 | #endif 29 | 30 | #ifdef _CPU 31 | ctx = new ECDLCpuContext(_config.threads, _config.pointsPerThread, params, rx, ry, numRPoints, callback); 32 | #endif 33 | 34 | return ctx; 35 | } 36 | 37 | #ifdef _CUDA 38 | bool cudaInit() 39 | { 40 | CUDA::DeviceInfo devInfo; 41 | 42 | if(CUDA::getDeviceCount() == 0) { 43 | Logger::logError("No CUDA devices detected\n"); 44 | return false; 45 | } 46 | 47 | // Get device info 48 | try { 49 | CUDA::getDeviceInfo(_config.device, devInfo); 50 | }catch(cudaError_t cudaError) { 51 | Logger::logError("Error getting info for device %d: %s\n", _config.device, cudaGetErrorString(cudaError)); 52 | return false; 53 | } 54 | 55 | Logger::logInfo("Device info:"); 56 | Logger::logInfo("Name: %s", devInfo.name.c_str()); 57 | Logger::logInfo("version: %d.%d", devInfo.major, devInfo.minor); 58 | Logger::logInfo("MP count: %d", devInfo.mpCount); 59 | Logger::logInfo("Cores: %d", devInfo.mpCount * devInfo.cores); 60 | Logger::logInfo("Memory: %lldMB", devInfo.globalMemory/(2<<19)); 61 | Logger::logInfo(""); 62 | 63 | return true; 64 | } 65 | #endif 66 | 67 | 68 | ECDLContext *_context; 69 | 70 | #define NUM_R_POINTS 32 71 | 72 | // X and Y values for the random walk points 73 | BigInteger _rx[NUM_R_POINTS]; 74 | BigInteger _ry[NUM_R_POINTS]; 75 | 76 | // Problem parameters 77 | ECDLPParams _params; 78 | 79 | // problem id 80 | std::string _id; 81 | 82 | Mutex _pointsMutex; 83 | 84 | ServerConnection *_serverConnection = NULL; 85 | 86 | // Declared extern in client.h 87 | ClientConfig _config; 88 | 89 | // Collection of distinguished points to be sent to the server 90 | std::vector _pointsCache; 91 | 92 | bool _running = true; 93 | 94 | Thread *_ecdlThread = NULL; 95 | 96 | /** 97 | Verifies a point is on the curve 98 | */ 99 | bool verifyPoint(BigInteger &x, BigInteger &y) 100 | { 101 | ECCurve curve(_params.p, _params.n, _params.a, _params.b, _params.gx, _params.gy); 102 | ECPoint p(x, y); 103 | 104 | return curve.pointExists(p); 105 | } 106 | 107 | /** 108 | * Adds distinguished point to cache 109 | */ 110 | void addPointToCache(BigInteger a, BigInteger b, BigInteger x, BigInteger y, unsigned int length) 111 | { 112 | DistinguishedPoint p(a, b, x, y, length); 113 | _pointsMutex.grab(); 114 | _pointsCache.push_back(p); 115 | _pointsMutex.release(); 116 | } 117 | 118 | void pointFoundCallback(struct CallbackParameters *p) 119 | { 120 | bool valid = verifyPoint(p->x, p->y); 121 | 122 | if(!valid) { 123 | Logger::logInfo("INVALID POINT\n"); 124 | Logger::logInfo("a: %s", p->aStart.toString(16).c_str()); 125 | Logger::logInfo("b: %s", p->bStart.toString(16).c_str()); 126 | Logger::logInfo("x: %s", p->x.toString(16).c_str()); 127 | Logger::logInfo("y: %s", p->y.toString(16).c_str()); 128 | Logger::logInfo("length: %d", p->length); 129 | return; 130 | } 131 | 132 | addPointToCache(p->aStart, p->bStart, p->x, p->y, p->length); 133 | } 134 | 135 | /** 136 | * Gets the problem parameters and R points from the server 137 | */ 138 | bool getParameters(ECDLPParams ¶ms, BigInteger *rx, BigInteger *ry) 139 | { 140 | ParamsMsg paramsMsg; 141 | 142 | try { 143 | paramsMsg = _serverConnection->getParameters(_id); 144 | } catch(std::string e) { 145 | Logger::logInfo("Error: %s\n", e.c_str()); 146 | return false; 147 | } 148 | 149 | params.p = paramsMsg.p; 150 | params.n = paramsMsg.n; 151 | params.a = paramsMsg.a; 152 | params.b = paramsMsg.b; 153 | params.gx = paramsMsg.gx; 154 | params.gy = paramsMsg.gy; 155 | params.qx = paramsMsg.qx; 156 | params.qy = paramsMsg.qy; 157 | params.dBits = paramsMsg.dBits; 158 | 159 | for(int i = 0; i < 32; i++) { 160 | rx[ i ] = paramsMsg.rx[i]; 161 | ry[ i ] = paramsMsg.ry[i]; 162 | } 163 | 164 | return true; 165 | } 166 | 167 | /** 168 | * Thread to poll the cache of distinguished points. Will send them to the server 169 | * when there are enough 170 | */ 171 | void *sendPointsThread(void *p) 172 | { 173 | 174 | while(_running) { 175 | _pointsMutex.grab(); 176 | 177 | if(_pointsCache.size() >= _config.pointCacheSize) { 178 | 179 | Logger::logInfo("Sending %d points to server", _pointsCache.size()); 180 | bool success = true; 181 | 182 | std::vector points; 183 | 184 | for(int i = 0; i < _pointsCache.size(); i++) { 185 | points.push_back(_pointsCache[i]); 186 | } 187 | 188 | try { 189 | Logger::logInfo("Sending to server\n"); 190 | _serverConnection->submitPoints(_id, points); 191 | } catch(std::string err) { 192 | success = false; 193 | Logger::logInfo("Error sending points to server: %s. Will try again later\n", err.c_str()); 194 | } 195 | 196 | if(success) { 197 | _pointsCache.clear(); 198 | } 199 | } 200 | _pointsMutex.release(); 201 | 202 | sleep(30); 203 | } 204 | 205 | return NULL; 206 | } 207 | 208 | /** 209 | * Holding thread for running the context 210 | */ 211 | void *runningThread(void *p) 212 | { 213 | // This is a blocking call 214 | _context->run(); 215 | 216 | return NULL; 217 | } 218 | 219 | /** 220 | * Main loop of the program. It periodically polls the server 221 | */ 222 | void pollConnections() 223 | { 224 | _running = true; 225 | 226 | Thread pointsThread(sendPointsThread, NULL); 227 | 228 | while(_running) { 229 | 230 | unsigned int status = 0; 231 | 232 | Logger::logInfo("Connecting to server..."); 233 | // Attempt to connect to the server 234 | try { 235 | status = _serverConnection->getStatus(_id); 236 | }catch(std::string s) { 237 | Logger::logInfo("Connection error: %s\n", s.c_str()); 238 | Logger::logInfo("Retrying in 60 seconds...\n"); 239 | sleep(60); 240 | continue; 241 | } 242 | 243 | Logger::logInfo("Status = %d\n", status); 244 | 245 | // If not currently running, then get the parameters and start 246 | if(status == SERVER_STATUS_RUNNING) { 247 | if(_context == NULL) { 248 | 249 | // Get parameters from the server 250 | if(!getParameters(_params, _rx, _ry)) { 251 | Logger::logError("Error getting the parameters from server\n"); 252 | } else { 253 | Logger::logInfo("Received parameters from server"); 254 | Logger::logInfo("GF(p) = %s", _params.p.toString().c_str()); 255 | Logger::logInfo("y^2 = x^3 + %sx + %s", _params.a.toString().c_str(), _params.b.toString().c_str()); 256 | Logger::logInfo("n = %s", _params.n.toString().c_str()); 257 | Logger::logInfo("G = [%s, %s]", _params.gx.toString().c_str(), _params.gy.toString().c_str()); 258 | Logger::logInfo("Q = [%s, %s]", _params.qx.toString().c_str(), _params.qy.toString().c_str()); 259 | Logger::logInfo("%d distinguished bits", _params.dBits); 260 | 261 | _context = getNewContext(&_params, _rx, _ry, NUM_R_POINTS, pointFoundCallback); 262 | _context->init(); 263 | 264 | Thread t(runningThread, NULL); 265 | } 266 | } else if(!_context->isRunning()) { 267 | Thread t(runningThread, NULL); 268 | } 269 | } else if(status == SERVER_STATUS_STOPPED) { 270 | Logger::logInfo("Stopping"); 271 | if(_context != NULL) { 272 | _context->stop(); 273 | delete _context; 274 | } 275 | break; 276 | } 277 | 278 | // Sleep 5 minutes 279 | sleep(300); 280 | } 281 | } 282 | 283 | 284 | void enterEventLoop () 285 | { 286 | // Enter main loop 287 | try { 288 | _serverConnection = new ServerConnection(_config.serverHost, _config.serverPort); 289 | }catch(std::string err) { 290 | Logger::logError("Error: %s", err.c_str()); 291 | return; 292 | } 293 | 294 | pollConnections(); 295 | } 296 | 297 | /** 298 | * Program entry point 299 | */ 300 | int main(int argc, char **argv) 301 | { 302 | // TODO: Use proper RNG 303 | srand(util::getSystemTime()); 304 | 305 | // Load configuration 306 | try { 307 | _config = loadConfig("settings.json"); 308 | }catch(std::string err) { 309 | Logger::logError("Error loading settings: " + err); 310 | return 1; 311 | } 312 | 313 | // Check for CUDA devices 314 | #ifdef _CUDA 315 | if (!cudaInit()) 316 | { 317 | return 1; 318 | } 319 | #endif 320 | 321 | //TODO: Properly parse arguments (getopt?) 322 | // Run benchmark on -b option 323 | if(argc >= 2 && strcmp(argv[1], "-b") == 0) { 324 | doBenchmark(); 325 | return 0; 326 | } else { 327 | if(argc < 2) { 328 | Logger::logInfo("usage: [options] id\n"); 329 | return 0; 330 | } else { 331 | _id = std::string(argv[1]); 332 | } 333 | } 334 | 335 | enterEventLoop(); 336 | 337 | return 0; 338 | } 339 | -------------------------------------------------------------------------------- /src/client/client/cpu/workerthread.cpp: -------------------------------------------------------------------------------- 1 | #include "BigInteger.h" 2 | #include "ECDLCPU.h" 3 | 4 | #include "math/Fp.h" 5 | #include "util.h" 6 | 7 | static ECPoint _g; 8 | static ECPoint _q; 9 | static ECDLPParams _params; 10 | static ECCurve _curve; 11 | static BigInteger *_a; 12 | static BigInteger *_b; 13 | static unsigned long *_x; 14 | static unsigned long *_y; 15 | static unsigned long *_rx; 16 | static unsigned long *_ry; 17 | static unsigned long *_diffBuf; 18 | static unsigned long *_chainBuf; 19 | static unsigned int *_lengthBuf; 20 | 21 | static unsigned int _numPoints; 22 | static unsigned int _rPointMask; 23 | static unsigned long _dBitsMask; 24 | static unsigned int _pLen; 25 | 26 | static void (*_callback)(struct CallbackParameters *); 27 | 28 | static inline bool checkDistinguishedBits(const unsigned long *x) 29 | { 30 | if((x[ 0 ] & _dBitsMask) == 0) { 31 | return true; 32 | } else { 33 | return false; 34 | } 35 | } 36 | 37 | /** 38 | * Generates a random point on the curve 39 | */ 40 | static void generateStartingPoint(BigInteger &x, BigInteger &y, BigInteger &a, BigInteger &b) 41 | { 42 | unsigned long buf[_pLen]; 43 | 44 | do { 45 | a = randomBigInteger(2, _params.n); 46 | b = randomBigInteger(2, _params.n); 47 | 48 | ECPoint p1 = _curve.multiplyPoint(a, _g); 49 | ECPoint p2 = _curve.multiplyPoint(b, _q); 50 | ECPoint p3 = _curve.addPoint(p1, p2); 51 | 52 | x = p3.getX(); 53 | y = p3.getY(); 54 | 55 | // Check that we don't start on a distinguished point 56 | x.getWords(buf, _pLen); 57 | }while(checkDistinguishedBits(buf)); 58 | 59 | } 60 | 61 | void initThreadGlobals(ECDLPParams *params, 62 | BigInteger *rx, 63 | BigInteger *ry, 64 | int numRPoints, 65 | BigInteger *a, 66 | BigInteger *b, 67 | BigInteger *x, 68 | BigInteger *y, 69 | int numThreads, 70 | int numPoints, 71 | int dBits, 72 | void (*callback)(struct CallbackParameters *) 73 | ) 74 | { 75 | // Copy parameters 76 | _params = *params; 77 | 78 | // Create curve 79 | _curve = ECCurve(_params.p, _params.n, _params.a, _params.b, _params.gx, _params.gy); 80 | 81 | // Create points 82 | _g = ECPoint(_params.gx, _params.gy); 83 | _q = ECPoint(_params.qx, _params.qy); 84 | 85 | _numPoints = numPoints; 86 | 87 | // Initialize Barrett code for modulus P 88 | BigInteger p = _curve.p(); 89 | initFp(p); 90 | unsigned int pLen = p.getWordLength(); 91 | _pLen = pLen; 92 | 93 | // Pointer to the coefficients of the starting points 94 | _a = a; 95 | _b = b; 96 | 97 | // (x,y) of the current points 98 | _x = new unsigned long[numPoints * numThreads * pLen]; 99 | _y = new unsigned long[numPoints * numThreads * pLen]; 100 | _rx = new unsigned long[32 * pLen]; 101 | _ry = new unsigned long[32 * pLen]; 102 | _diffBuf = new unsigned long[numPoints * numThreads * pLen]; 103 | _chainBuf = new unsigned long[numPoints * numThreads * pLen]; 104 | _lengthBuf = new unsigned int[numPoints * numThreads]; 105 | 106 | // Initialize length to 1 (starting point counts as 1 point) 107 | memset(_lengthBuf, 0, sizeof(unsigned int) * numPoints * numThreads); 108 | for(int i = 0; i < numPoints * numThreads; i++) { 109 | _lengthBuf[i] = 1; 110 | } 111 | 112 | // Copy points 113 | for(int i = 0; i < numPoints * numThreads; i++) { 114 | int index = i * pLen; 115 | x[i].getWords(&_x[index], pLen); 116 | y[i].getWords(&_y[index], pLen); 117 | } 118 | 119 | // Copy R points 120 | for(int i = 0; i < 32; i++) { 121 | int index = i * pLen; 122 | rx[i].getWords(&_rx[index], pLen); 123 | ry[i].getWords(&_ry[index], pLen); 124 | } 125 | 126 | // Set mask for detecting distinguished points 127 | _dBitsMask = ~0; 128 | _dBitsMask >>= WORD_LENGTH_BITS - dBits; 129 | 130 | // Mask for selecting R point 131 | _rPointMask = numRPoints - 1; 132 | 133 | // Gets called when distinguished point is found 134 | _callback = callback; 135 | } 136 | 137 | void cleanupThreadGlobals() 138 | { 139 | delete[] _x; 140 | delete[] _y; 141 | delete[] _rx; 142 | delete[] _ry; 143 | delete[] _diffBuf; 144 | delete[] _chainBuf; 145 | delete[] _lengthBuf; 146 | } 147 | 148 | template void copyWords(const unsigned long *src, unsigned long *dest) 149 | { 150 | memcpy(dest, src, sizeof(unsigned long) * N); 151 | } 152 | 153 | 154 | template void doStepInternal(int threadId) 155 | { 156 | unsigned long *x = &_x[threadId * _numPoints * N]; 157 | unsigned long *y = &_y[threadId * _numPoints * N]; 158 | unsigned long *chainBuf = &_chainBuf[threadId * _numPoints * N]; 159 | unsigned long *diffBuf = &_diffBuf[threadId * _numPoints * N]; 160 | unsigned int *lengthBuf = &_lengthBuf[threadId * _numPoints]; 161 | 162 | // Initialize to 1 163 | unsigned long product[N] = {0}; 164 | product[0] = 1; 165 | 166 | for(unsigned int i = 0; i < _numPoints; i++) { 167 | unsigned int index = i * N; 168 | 169 | unsigned int idx = x[ index ] & _rPointMask; 170 | unsigned long diff[N]; 171 | 172 | subModP(&x[index], &_rx[idx * N], diff); 173 | copyWords(diff, &diffBuf[ index ]); 174 | 175 | multiplyModP(product, diff, product); 176 | copyWords(product, &chainBuf[ index ]); 177 | } 178 | 179 | 180 | unsigned long inverse[N]; 181 | inverseModP(product, inverse); 182 | 183 | // Extract inverse of the differences 184 | for(int i = _numPoints - 1; i >= 0; i--) { 185 | int index = i * N; 186 | 187 | // Get the inverse of the last difference by multiplying the inverse 188 | // of the product of all the differences with the product of all but 189 | // the last difference 190 | unsigned long invDiff[N]; 191 | 192 | if(i >= 1) { 193 | multiplyModP(inverse, &chainBuf[(i - 1) * N], invDiff); 194 | multiplyModP(inverse, &diffBuf[ index ], inverse); 195 | } else { 196 | copyWords(inverse, invDiff); 197 | } 198 | 199 | 200 | unsigned int idx = x[ index ] & _rPointMask; 201 | 202 | unsigned long px[N]; 203 | unsigned long py[N]; 204 | 205 | // Copy onto stack 206 | copyWords(&x[ index ], px); 207 | copyWords(&y[ index ], py); 208 | 209 | // Calculate slope (Py - Qy)/(Px - Qx) 210 | unsigned long rise[N]; 211 | subModP(py, &_ry[ idx * _pLen ], rise); 212 | unsigned long s[N]; 213 | multiplyModP(invDiff, rise, s); 214 | 215 | // calculate s^2 216 | unsigned long s2[N]; 217 | squareModP(s, s2); 218 | 219 | // Rx = s^2 - Px - Qx 220 | unsigned long newX[N]; 221 | subModP(s2, px, newX); 222 | subModP(newX, &_rx[ idx * _pLen ], newX); 223 | 224 | // Ry = s(Px - Rx) - Py 225 | unsigned long k[N]; 226 | subModP(px, newX, k); 227 | 228 | multiplyModP(k, s, k); 229 | unsigned long newY[N]; 230 | subModP(k, py, newY); 231 | 232 | // Increment walk length 233 | lengthBuf[i]++; 234 | 235 | bool isDistinguishedPoint = checkDistinguishedBits(newX); 236 | 237 | bool isFruitlessCycle = false; 238 | 239 | if ( lengthBuf[i] >= (unsigned long long)1 << (_params.dBits + 2)) { 240 | isFruitlessCycle = true; 241 | } 242 | 243 | //Check for distinguished point 244 | if(isDistinguishedPoint || isFruitlessCycle) { 245 | 246 | BigInteger *a = &_a[threadId * _numPoints]; 247 | BigInteger *b = &_b[threadId * _numPoints]; 248 | 249 | if(isDistinguishedPoint) { 250 | 251 | // Call callback function 252 | if(_callback != NULL) { 253 | struct CallbackParameters cp; 254 | cp.aStart = a[i]; 255 | cp.bStart = b[i]; 256 | cp.x = BigInteger(newX, N); 257 | cp.y = BigInteger(newY, N); 258 | cp.length = lengthBuf[i]; 259 | _callback(&cp); 260 | } 261 | } else { 262 | Logger::logInfo("Thread %d: Possible cycle found (%d iterations), rejecting\n", threadId, lengthBuf[i]); 263 | } 264 | 265 | // Generate new starting point 266 | BigInteger aNew; 267 | BigInteger bNew; 268 | BigInteger xNew; 269 | BigInteger yNew; 270 | 271 | // Generate new starting point 272 | generateStartingPoint(xNew, yNew, aNew, bNew); 273 | 274 | // Copy new point to memory 275 | xNew.getWords(&x[index], N); 276 | yNew.getWords(&y[index], N); 277 | a[i] = aNew; 278 | b[i] = bNew; 279 | lengthBuf[i] = 0; 280 | } else { 281 | // Write result to memory 282 | copyWords(newX, &x[ index ]); 283 | copyWords(newY, &y[ index ]); 284 | } 285 | 286 | } 287 | } 288 | 289 | static void doStep(int threadId) { 290 | switch(_pLen) { 291 | case 1: 292 | doStepInternal<1>(threadId); 293 | break; 294 | case 2: 295 | doStepInternal<2>(threadId); 296 | break; 297 | case 3: 298 | doStepInternal<3>(threadId); 299 | break; 300 | case 4: 301 | doStepInternal<4>(threadId); 302 | break; 303 | case 5: 304 | doStepInternal<5>(threadId); 305 | break; 306 | case 6: 307 | doStepInternal<6>(threadId); 308 | break; 309 | case 7: 310 | doStepInternal<7>(threadId); 311 | break; 312 | default: 313 | logger::logError("ERROR: COMPILE SUPPORT FOR LARGER INTEGERS\n"); 314 | exit(1); 315 | break; 316 | } 317 | } 318 | 319 | void *benchmarkThreadFunction(void *p) 320 | { 321 | BenchmarkThreadParams *params = (BenchmarkThreadParams *)p; 322 | 323 | unsigned int threadId = params->threadId; 324 | 325 | unsigned int t0 = util::getSystemTime(); 326 | for(unsigned int i = 0; i < params->iterations; i++) { 327 | doStep(threadId); 328 | } 329 | params->t = util::getSystemTime() - t0; 330 | 331 | return NULL; 332 | } 333 | 334 | void *workerThreadFunction(void *p) 335 | { 336 | WorkerThreadParams *params = (WorkerThreadParams *)p; 337 | 338 | unsigned int threadId = params->threadId; 339 | 340 | while(params->running) { 341 | doStep(threadId); 342 | } 343 | 344 | return NULL; 345 | } 346 | -------------------------------------------------------------------------------- /src/client/client/cuda/Fp.cu: -------------------------------------------------------------------------------- 1 | #ifndef _FP_CU 2 | #define _FP_CU 3 | 4 | #include "util.cu" 5 | 6 | // Length of p in words 7 | __constant__ unsigned int _PWORDS; 8 | 9 | // Length of m in words 10 | __constant__ unsigned int _MWORDS; 11 | 12 | // p, prime modulus 13 | __shared__ unsigned int _P[10]; 14 | __constant__ unsigned int _P_CONST[10]; 15 | 16 | // 2 * p 17 | __shared__ unsigned int _2P[10]; 18 | __constant__ unsigned int _2P_CONST[10]; 19 | 20 | // 3 * p 21 | __shared__ unsigned int _3P[10]; 22 | __constant__ unsigned int _3P_CONST[10]; 23 | 24 | // m = 2^2n / k 25 | __shared__ unsigned int _M[10]; 26 | __constant__ unsigned int _M_CONST[10]; 27 | 28 | // p - 2, used in modular inverse 29 | __shared__ unsigned int _PMINUS2[10]; 30 | __constant__ unsigned int _PMINUS2_CONST[10]; 31 | 32 | // Lenght of p in bits 33 | __shared__ unsigned int _PBITS; 34 | __constant__ unsigned int _PBITS_CONST; 35 | 36 | // Length of m in bits 37 | __shared__ unsigned int _MBITS; 38 | __constant__ unsigned int _MBITS_CONST; 39 | 40 | __constant__ unsigned int _NUM_POINTS; 41 | 42 | template __device__ int getIndex(int idx) 43 | { 44 | return N * (gridDim.x * blockDim.x * idx + blockIdx.x * blockDim.x + threadIdx.x); 45 | } 46 | 47 | template __device__ void add(const unsigned int *a, const unsigned int *b, unsigned int *c) 48 | { 49 | // No carry in 50 | asm volatile( "add.cc.u32 %0, %1, %2;\n\t" : "=r"(c[ 0 ]) : "r"(a[ 0 ]), "r"(b[ 0 ]) ); 51 | 52 | // Carry in and carry out 53 | #pragma unroll 54 | for(int i = 1; i < N; i++) { 55 | asm volatile( "addc.cc.u32 %0, %1, %2;\n\t" : "=r"(c[ i ]) : "r"(a[ i ]), "r"(b[ i ]) ); 56 | } 57 | } 58 | 59 | /** 60 | * Subtracts two arrays. Returns non-zero if there is a borrow 61 | */ 62 | template __device__ unsigned int sub(const unsigned int *a, const unsigned int *b, unsigned int *c) 63 | { 64 | // No borrow in 65 | asm volatile( "sub.cc.u32 %0, %1, %2;\n\t" : "=r"(c[ 0 ]) : "r"(a[ 0 ]), "r"(b[ 0 ]) ); 66 | 67 | // Borrow in and borrow out 68 | #pragma unroll 69 | for(int i = 1; i < N; i++) { 70 | asm volatile( "subc.cc.u32 %0, %1, %2;\n\t" : "=r"(c[ i ]) : "r"(a[ i ]), "r"(b[ i ]) ); 71 | } 72 | 73 | // Return non-zero on borrow 74 | unsigned int borrow = 0; 75 | asm volatile( "subc.u32 %0, %1, %2;\n\t" : "=r"(borrow) : "r"(0), "r"(0)); 76 | 77 | return borrow; 78 | } 79 | 80 | /** 81 | * Performs N x N word multiplication 82 | */ 83 | template __device__ void multiply(const unsigned int *a, const unsigned int *b, unsigned int *c) 84 | { 85 | 86 | // Compute low 32-bits of each 64-bit product 87 | for(int i = 0; i < N; i++) { 88 | c[i] = a[0] * b[i]; 89 | c[i+N] = 0; 90 | } 91 | 92 | // Compute high 32-bits of each 64-bit product, perform add + carry 93 | asm volatile( "mad.hi.cc.u32 %0, %1, %2, %3;\n\t" : "=r"(c[1]) : "r"(a[ 0 ]), "r"(b[ 0 ] ), "r"(c[1]) ); 94 | 95 | for(int i = 1; i < N-1; i++) { 96 | asm volatile( "madc.hi.cc.u32 %0, %1, %2, %3;\n\t" : "=r"(c[i+1]) : "r"(a[ 0 ]), "r"(b[ i ]), "r"(c[i+1])); 97 | } 98 | 99 | asm volatile( "madc.hi.u32 %0, %1, %2, %3;\n\t" : "=r"(c[N]) : "r"(a[ 0 ]), "r"(b[ N-1 ]), "r"(c[N])); 100 | 101 | for(int i = 1; i < N; i++) { 102 | unsigned int t = a[i]; 103 | asm volatile( "mad.lo.cc.u32 %0, %1, %2, %3;\n\t" : "=r"(c[i]) : "r"(t), "r"(b[0]), "r"(c[i])); 104 | 105 | for(int j = 1; j < N; j++) { 106 | asm volatile( "madc.lo.cc.u32 %0, %1, %2, %3;\n\t" : "=r"(c[ i + j ]) : "r"(t), "r"(b[j]),"r"(c[i+j])); 107 | } 108 | asm volatile( "addc.u32 %0, %1, %2;\n\t" : "=r"(c[ i + N ]) : "r"(c[ i + N ]), "r"(0) ); 109 | 110 | 111 | asm volatile( "mad.hi.cc.u32 %0, %1, %2, %3;\n\t" : "=r"(c[i+1]) : "r"(t), "r"(b[ 0 ] ), "r"(c[i+1]) ); 112 | 113 | for(int j = 1; j < N-1; j++) { 114 | asm volatile( "madc.hi.cc.u32 %0, %1, %2, %3;\n\t" : "=r"(c[j+i+1]) : "r"(t), "r"(b[ j ] ), "r"(c[i+j+1]) ); 115 | } 116 | asm volatile( "madc.hi.u32 %0, %1, %2, %3;\n\t" : "=r"(c[i+N]) : "r"(t), "r"(b[ N-1 ] ), "r"(c[i+N]) ); 117 | } 118 | } 119 | 120 | 121 | /** 122 | * Squares an N-word value 123 | */ 124 | template __device__ void square(const unsigned int *a, unsigned int *c) 125 | { 126 | multiply(a, a, c); 127 | } 128 | 129 | /** 130 | * Read constants into shared memory 131 | */ 132 | __device__ void initFp() 133 | { 134 | if( threadIdx.x == 0 ) { 135 | memcpy(_P, _P_CONST, sizeof(_P_CONST)); 136 | memcpy(_M, _M_CONST, sizeof(_M_CONST)); 137 | memcpy(_2P, _2P_CONST, sizeof(_2P_CONST)); 138 | memcpy(_3P, _3P_CONST, sizeof(_2P_CONST)); 139 | memcpy(_PMINUS2, _PMINUS2_CONST, sizeof(_PMINUS2_CONST)); 140 | _PBITS = _PBITS_CONST; 141 | } 142 | __syncthreads(); 143 | } 144 | 145 | template __device__ void readBigInt(const unsigned int *ara, int idx, unsigned int *x) 146 | { 147 | for(int i = 0; i < N; i++ ) { 148 | x[i] = ara[getIndex(idx) + i]; 149 | } 150 | } 151 | 152 | /** 153 | * Retrives a single word from an integer in global memory 154 | */ 155 | template __device__ unsigned int readBigIntWord(const unsigned int *ara, int idx, int word) 156 | { 157 | return ara[getIndex(idx) + word]; 158 | } 159 | 160 | 161 | __device__ void writeBigInt(unsigned int *ara, int idx, const unsigned int *x, int len) 162 | { 163 | for(int i = 0; i < len; i++) { 164 | ara[len * (gridDim.x * blockDim.x * idx + blockIdx.x * blockDim.x + threadIdx.x) + i] = x[i]; 165 | } 166 | } 167 | 168 | template __device__ void writeBigInt(unsigned int *ara, int idx, const unsigned int *x) 169 | { 170 | for(int i = 0; i < N; i++) { 171 | ara[getIndex(idx) + i] = x[i]; 172 | } 173 | } 174 | 175 | template __device__ unsigned int equalTo(const unsigned int *a, const unsigned int *b) 176 | { 177 | unsigned int result = 0xffffffff; 178 | for(int i = 0; i < N; i++) { 179 | unsigned int eq = 0; 180 | asm volatile("set.eq.u32.u32 %0, %1, %2;\n\t" : "=r"(eq) : "r"(a[i]), "r"(b[i])); 181 | result &= eq; 182 | } 183 | 184 | return result; 185 | } 186 | 187 | template __device__ void rightShift(const unsigned int *in, unsigned int *out) 188 | { 189 | int rShift = (_PBITS) % 32; 190 | int lShift = 32 - rShift; 191 | 192 | if(rShift > 0) { 193 | for(int i = 0; i < N; i++) { 194 | out[ i ] = (in[ N - 1 + i ] >> rShift) | (in[ N + i ] << lShift); 195 | } 196 | } else { 197 | for(int i = 0; i < N; i++) { 198 | out[ i ] = in[ N + i]; 199 | } 200 | } 201 | } 202 | 203 | /** 204 | * Branchless greater than or equal to comparison. Returns non-zero on true and zero on false 205 | */ 206 | template __device__ unsigned int greaterThanEqualTo(const unsigned int *a, const unsigned int *b) 207 | { 208 | unsigned int sum = 0; 209 | unsigned int mask = 0xffffffff; 210 | for(int i = N - 1; i >= 0; i--) { 211 | unsigned int lt = 0; 212 | unsigned int eq = 0; 213 | unsigned int x = a[i]; 214 | unsigned int y = b[i]; 215 | asm volatile("set.lo.u32.u32 %0, %1, %2;\n\t" : "=r"(lt) : "r"(x), "r"(y)); 216 | asm volatile("set.eq.u32.u32 %0, %1, %2;\n\t" : "=r"(eq) : "r"(x), "r"(y)); 217 | 218 | sum |= lt & mask; 219 | mask &= eq; 220 | } 221 | 222 | return ~sum; 223 | } 224 | 225 | /** 226 | * Subtraction mod P 227 | */ 228 | template __device__ void subModP(const unsigned int *a, const unsigned int *b, unsigned int *c) 229 | { 230 | unsigned int borrow = sub(a, b, c); 231 | 232 | if(borrow) { 233 | add(c, _P, c); 234 | } 235 | } 236 | 237 | 238 | /** 239 | * Barrett reduction 240 | */ 241 | template __device__ void reduceModP(const unsigned int *x, unsigned int *c) 242 | { 243 | unsigned int xHigh[N]; 244 | unsigned int xm[N*2]; 245 | unsigned int q[N]; 246 | unsigned int qp[N*2]; 247 | 248 | // Get top N bits 249 | rightShift(x, xHigh); 250 | 251 | // Multiply by m 252 | multiply(xHigh, _M, xm); 253 | 254 | // Get the high bits of xHigh * m. 255 | rightShift(xm, q); 256 | 257 | // It is possible that m is 1 bit longer than p. If p ends on a word boundry then m will 258 | // be 1 word longer than p. To avoid doing an extra multiplication when doing xHigh * m 259 | // (because the 1 would be in the next word), add xHigh to the result after shifting 260 | if(_MWORDS > _PWORDS) { 261 | add(q, xHigh, q); 262 | } 263 | 264 | // Multiply by p 265 | multiply(q, _P, qp); 266 | 267 | // Subtract from x 268 | unsigned int r[N+1]; 269 | sub(x, qp, r); 270 | 271 | // The trick here is that instead of multiplying xm by p, we multiplied only the top 272 | // half by p. This still works because the lower bits of the product are discarded anyway. 273 | // But it could have been the case that there was a carry from the multiplication operation on 274 | // the lower bits, which will result in r being >= 2p because in that case we would be 275 | // doing x - (q-1) * p instead of x - q*p. So we need to check for >= 2p and >= p. Its more checks 276 | // but saves us from doing a multiplication. 277 | 278 | unsigned int gte3p = greaterThanEqualTo(r, _3P); 279 | unsigned int gte2p = greaterThanEqualTo(r, _2P); 280 | unsigned int gtep = greaterThanEqualTo(r, _P); 281 | 282 | if(gte3p) { 283 | sub(r, _3P, c); 284 | } else if(gte2p) { 285 | sub(r, _2P, c); 286 | } else if(gtep) { 287 | sub(r, _P, c); 288 | } else { 289 | copy(r, c); 290 | } 291 | } 292 | 293 | template __device__ void multiplyModP(const unsigned int *a, const unsigned int *b, unsigned int *c) 294 | { 295 | unsigned int x[2*N]; 296 | multiply(a, b, x); 297 | reduceModP(x, c); 298 | } 299 | /** 300 | * Square with montgomery reduction 301 | */ 302 | template __device__ void squareModP(const unsigned int *a, unsigned int *c) 303 | { 304 | //multiplyModP(a, a, c); 305 | unsigned int x[2*N]; 306 | square(a, x); 307 | reduceModP(x, c); 308 | } 309 | 310 | 311 | /** 312 | * Computes multiplicative inverse of a mod P using x^(P-2) mod P 313 | */ 314 | template __device__ void inverseModP(const unsigned int *a, unsigned int *inverse) 315 | { 316 | unsigned int x[N]; 317 | copy(a, x); 318 | 319 | unsigned int y[N] = {0}; 320 | y[0] = 1; 321 | 322 | // First N -1 words in the exponent 323 | for(int j = 0; j < N-1; j++) { 324 | unsigned int e = _PMINUS2[j]; 325 | for(int i = 0; i < 32; i++) { 326 | if(e & 1) { 327 | multiplyModP(y, x, y); 328 | } 329 | 330 | squareModP(x, x); 331 | e >>= 1; 332 | } 333 | } 334 | 335 | // Last word in the exponent 336 | unsigned int e = _PMINUS2[N-1]; 337 | while( e ) { 338 | if( e & 1 ) { 339 | multiplyModP(y, x, y); 340 | } 341 | squareModP(x, x); 342 | e >>= 1; 343 | } 344 | 345 | copy(y, inverse); 346 | } 347 | 348 | #endif -------------------------------------------------------------------------------- /src/client/client/cpu/RhoCPU.cpp: -------------------------------------------------------------------------------- 1 | #include "RhoCPU.h" 2 | #include "logger.h" 3 | 4 | static void copyWords(const unsigned long *src, unsigned long *dest, int n) 5 | { 6 | memcpy(dest, src, sizeof(unsigned long) * n); 7 | } 8 | 9 | /** 10 | * Generates a random point on the curve 11 | */ 12 | void RhoCPU::generateStartingPoint(BigInteger &x, BigInteger &y, BigInteger &a, BigInteger &b) 13 | { 14 | unsigned long buf[FP_MAX]; 15 | 16 | do { 17 | // 1 < a,b < n 18 | a = randomBigInteger(2, _params.n); 19 | b = randomBigInteger(2, _params.n); 20 | 21 | // aG, bQ, aG + bQ 22 | ECPoint p1 = _curve.multiply(a, _g); 23 | ECPoint p2 = _curve.multiply(b, _q); 24 | ECPoint p3 = _curve.add(p1, p2); 25 | 26 | x = p3.getX(); 27 | y = p3.getY(); 28 | 29 | // Check that we don't start on a distinguished point 30 | x.getWords(buf, _pLen); 31 | }while((buf[0] & _dBitsMask) == 0); 32 | 33 | } 34 | 35 | bool inline RhoCPU::checkDistinguishedBits(const unsigned long *x) 36 | { 37 | if((x[ 0 ] & _dBitsMask) == 0) { 38 | return true; 39 | } else { 40 | return false; 41 | } 42 | } 43 | 44 | RhoCPU::RhoCPU(const ECDLPParams *params, 45 | const BigInteger *rx, 46 | const BigInteger *ry, 47 | int numRPoints, 48 | int pointsInParallel, 49 | void (*callback)(struct CallbackParameters *) 50 | ) 51 | { 52 | // Copy parameters 53 | _params = *params; 54 | 55 | _fp = getFp(_params.p); 56 | _pLen = _params.p.getWordLength(); 57 | 58 | // Create curve 59 | _curve = ECCurve(_params.p, _params.n, _params.a, _params.b, _params.gx, _params.gy); 60 | 61 | // Create points 62 | _g = ECPoint(_params.gx, _params.gy); 63 | _q = ECPoint(_params.qx, _params.qy); 64 | 65 | _pointsInParallel = pointsInParallel; 66 | 67 | // Initialize Barrett code for modulus P 68 | BigInteger p = _curve.p(); 69 | 70 | // Pointer to the coefficients of the starting points 71 | _a = new BigInteger[pointsInParallel]; 72 | _b = new BigInteger[pointsInParallel]; 73 | 74 | for(int i = 0; i < pointsInParallel; i++) { 75 | _a[i] = BigInteger(0); 76 | _b[i] = BigInteger(0); 77 | } 78 | 79 | // (x,y) of the current points 80 | _x = new unsigned long[pointsInParallel * _pLen]; 81 | _y = new unsigned long[pointsInParallel * _pLen]; 82 | _rx = new unsigned long[32 * _pLen]; 83 | _ry = new unsigned long[32 * _pLen]; 84 | _diffBuf = new unsigned long[pointsInParallel * _pLen]; 85 | _chainBuf = new unsigned long[pointsInParallel * _pLen]; 86 | _lengthBuf = new unsigned long long [pointsInParallel]; 87 | 88 | // Initialize length to 1 (starting point counts as 1 point) 89 | memset(_lengthBuf, 0, sizeof(unsigned int) * pointsInParallel); 90 | for(int i = 0; i < pointsInParallel; i++) { 91 | _lengthBuf[i] = 1; 92 | } 93 | 94 | // Copy R points 95 | for(int i = 0; i < 32; i++) { 96 | int index = i * _pLen; 97 | rx[i].getWords(&_rx[index], _pLen); 98 | ry[i].getWords(&_ry[index], _pLen); 99 | } 100 | 101 | // Set mask for detecting distinguished points 102 | _dBitsMask = ~0; 103 | _dBitsMask >>= WORD_LENGTH_BITS - params->dBits; 104 | 105 | // Mask for selecting R point 106 | _rPointMask = numRPoints - 1; 107 | 108 | // Gets called when distinguished point is found 109 | _callback = callback; 110 | 111 | // Generate starting points and exponents 112 | for(unsigned int i = 0; i < _pointsInParallel; i++) { 113 | BigInteger a; 114 | BigInteger b; 115 | BigInteger x; 116 | BigInteger y; 117 | 118 | generateStartingPoint(x, y, a, b); 119 | 120 | _a[i] = a; 121 | _b[i] = b; 122 | 123 | x.getWords((unsigned long *)&_x[i * _pLen], _pLen); 124 | y.getWords((unsigned long *)&_y[i * _pLen], _pLen); 125 | } 126 | } 127 | 128 | RhoCPU::~RhoCPU() 129 | { 130 | delete[] _x; 131 | delete[] _y; 132 | delete[] _rx; 133 | delete[] _ry; 134 | delete[] _diffBuf; 135 | delete[] _chainBuf; 136 | delete[] _lengthBuf; 137 | } 138 | 139 | void RhoCPU::doStepSingle() 140 | { 141 | unsigned long px[FP_MAX] = {0}; 142 | unsigned long py[FP_MAX] = {0}; 143 | 144 | // Copy onto stack 145 | copyWords(_x, px, _pLen); 146 | copyWords(_y, py, _pLen); 147 | 148 | int idx = px[0] & _rPointMask; 149 | 150 | unsigned long run[FP_MAX] = {0}; 151 | _fp->subModP(px, &_rx[idx * _pLen], run); 152 | 153 | unsigned long runInv[FP_MAX] = {0}; 154 | _fp->inverseModP(run, runInv); 155 | 156 | // Calculate (Py - Qy)/(Px - Qx) 157 | unsigned long rise[FP_MAX] = {0}; 158 | _fp->subModP(py, &_ry[idx * _pLen], rise); 159 | 160 | unsigned long s[FP_MAX] = {0}; 161 | 162 | _fp->multiplyModP(runInv, rise, s); 163 | 164 | // calculate s^2 165 | unsigned long s2[FP_MAX] = {0}; 166 | _fp->squareModP(s, s2); 167 | 168 | // Rx = s^2 - Px - Qx 169 | unsigned long newX[FP_MAX] = {0}; 170 | 171 | _fp->subModP(s2, px, newX); 172 | _fp->subModP(newX, &_rx[ idx * _pLen], newX); 173 | 174 | // Ry = s(Px - Rx) - Py 175 | unsigned long k[FP_MAX] = {0}; 176 | _fp->subModP(px, newX, k); 177 | 178 | _fp->multiplyModP(k, s, k); 179 | unsigned long newY[FP_MAX] = {0}; 180 | _fp->subModP(k, py, newY); 181 | 182 | // Increment walk length 183 | (*_lengthBuf)++; 184 | 185 | bool isDistinguishedPoint = checkDistinguishedBits(newX); 186 | 187 | bool isFruitlessCycle = false; 188 | 189 | if ( *_lengthBuf >= (unsigned long long)1 << (_params.dBits + 2)) { 190 | isFruitlessCycle = true; 191 | } 192 | 193 | //Check for distinguished point 194 | if(isDistinguishedPoint || isFruitlessCycle) { 195 | 196 | if(isDistinguishedPoint) { 197 | Logger::logInfo("Found distinguished point!\n"); 198 | // Call callback function 199 | if(_callback != NULL) { 200 | struct CallbackParameters cp; 201 | 202 | cp.aStart = *_a; 203 | cp.bStart = *_b; 204 | cp.x = BigInteger(newX, _pLen); 205 | cp.y = BigInteger(newY, _pLen); 206 | cp.length = *_lengthBuf; 207 | 208 | _callback(&cp); 209 | } 210 | } else { 211 | Logger::logInfo("Possible cycle found (%lld iterations), rejecting\n", *_lengthBuf); 212 | } 213 | 214 | // Generate new starting point 215 | BigInteger aNew; 216 | BigInteger bNew; 217 | BigInteger xNew; 218 | BigInteger yNew; 219 | 220 | // Generate new starting point 221 | generateStartingPoint(xNew, yNew, aNew, bNew); 222 | 223 | // Copy new point to memory 224 | xNew.getWords(_x, _pLen); 225 | yNew.getWords(_y, _pLen); 226 | *_a = aNew; 227 | *_b = bNew; 228 | 229 | *_lengthBuf = 1; 230 | 231 | } else { 232 | // Write result to memory 233 | copyWords(newX, _x, _pLen); 234 | copyWords(newY, _y, _pLen); 235 | } 236 | } 237 | 238 | 239 | void RhoCPU::doStepMulti() 240 | { 241 | unsigned long *chainBuf = _chainBuf; 242 | unsigned long *diffBuf = _diffBuf; 243 | unsigned long long *lengthBuf = _lengthBuf; 244 | 245 | // Initialize to 1 246 | unsigned long product[FP_MAX] = {0}; 247 | product[0] = 1; 248 | 249 | for(unsigned int i = 0; i < _pointsInParallel; i++) { 250 | unsigned int index = i * _pLen; 251 | 252 | unsigned int idx = _x[ index ] & _rPointMask; 253 | unsigned long diff[FP_MAX]; 254 | 255 | _fp->subModP(&_x[index], &_rx[idx * _pLen], diff); 256 | copyWords(diff, &diffBuf[ index ], _pLen); 257 | 258 | _fp->multiplyModP(product, diff, product); 259 | copyWords(product, &chainBuf[ index ], _pLen); 260 | } 261 | 262 | 263 | unsigned long inverse[FP_MAX]; 264 | _fp->inverseModP(product, inverse); 265 | 266 | // Extract inverse of the differences 267 | for(int i = _pointsInParallel - 1; i >= 0; i--) { 268 | int index = i * _pLen; 269 | 270 | // Get the inverse of the last difference by multiplying the inverse 271 | // of the product of all the differences with the product of all but 272 | // the last difference 273 | unsigned long invDiff[FP_MAX]; 274 | 275 | if(i >= 1) { 276 | _fp->multiplyModP(inverse, &chainBuf[(i - 1) * _pLen], invDiff); 277 | _fp->multiplyModP(inverse, &diffBuf[ index ], inverse); 278 | } else { 279 | copyWords(inverse, invDiff, _pLen); 280 | } 281 | 282 | 283 | unsigned int idx = _x[ index ] & _rPointMask; 284 | 285 | unsigned long px[FP_MAX]; 286 | unsigned long py[FP_MAX]; 287 | 288 | // Copy onto stack 289 | copyWords(&_x[ index ], px, _pLen); 290 | copyWords(&_y[ index ], py, _pLen); 291 | 292 | // Calculate slope (Py - Qy)/(Px - Qx) 293 | unsigned long rise[FP_MAX]; 294 | _fp->subModP(py, &_ry[ idx * _pLen], rise); 295 | unsigned long s[FP_MAX]; 296 | _fp->multiplyModP(invDiff, rise, s); 297 | 298 | // calculate s^2 299 | unsigned long s2[FP_MAX]; 300 | _fp->squareModP(s, s2); 301 | 302 | // Rx = s^2 - Px - Qx 303 | unsigned long newX[FP_MAX]; 304 | _fp->subModP(s2, px, newX); 305 | _fp->subModP(newX, &_rx[ idx * _pLen], newX); 306 | 307 | // Ry = s(Px - Rx) - Py 308 | unsigned long k[FP_MAX]; 309 | _fp->subModP(px, newX, k); 310 | 311 | _fp->multiplyModP(k, s, k); 312 | unsigned long newY[FP_MAX]; 313 | _fp->subModP(k, py, newY); 314 | 315 | // Increment walk length 316 | lengthBuf[i]++; 317 | 318 | bool isDistinguishedPoint = checkDistinguishedBits(newX); 319 | 320 | bool isFruitlessCycle = false; 321 | 322 | if ( lengthBuf[i] >= (unsigned long long)1 << (_params.dBits + 2)) { 323 | isFruitlessCycle = true; 324 | } 325 | 326 | //Check for distinguished point 327 | if(isDistinguishedPoint || isFruitlessCycle) { 328 | 329 | if(isDistinguishedPoint) { 330 | 331 | // Call callback function 332 | if(_callback != NULL) { 333 | struct CallbackParameters cp; 334 | cp.aStart = _a[i]; 335 | cp.bStart = _b[i]; 336 | cp.x = BigInteger(newX, _pLen); 337 | cp.y = BigInteger(newY, _pLen); 338 | cp.length = lengthBuf[i]; 339 | _callback(&cp); 340 | } 341 | } else { 342 | //printf("Possible cycle found (%lld iterations), rejecting\n", lengthBuf[i]); 343 | } 344 | 345 | // Generate new starting point 346 | BigInteger aNew; 347 | BigInteger bNew; 348 | BigInteger xNew; 349 | BigInteger yNew; 350 | 351 | // Generate new starting point 352 | generateStartingPoint(xNew, yNew, aNew, bNew); 353 | 354 | // Copy new point to memory 355 | xNew.getWords(&_x[index], _pLen); 356 | yNew.getWords(&_y[index], _pLen); 357 | _a[i] = aNew; 358 | _b[i] = bNew; 359 | lengthBuf[i] = 0; 360 | 361 | } else { 362 | // Write result to memory 363 | copyWords(newX, &_x[ index ], _pLen); 364 | copyWords(newY, &_y[ index ], _pLen); 365 | } 366 | } 367 | } 368 | 369 | void RhoCPU::doStep() 370 | { 371 | if(_pointsInParallel > 1) { 372 | doStepMulti(); 373 | } else { 374 | doStepSingle(); 375 | } 376 | } --------------------------------------------------------------------------------