parrhoasm.cu 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. /*
  2. * cudadl version 0.8: Compute discrete logs in smooth group orders
  3. * using CUDA
  4. * Copyright (C) 2012 by Ryan Henry and Ian Goldberg
  5. * {rhenry,iang}@cs.uwaterloo.ca
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of version 3 of the GNU General Public License as
  9. * published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "cudadl.h"
  20. #include <fstream>
  21. #include <NTL/vec_ZZ.h>
  22. #include <string.h>
  23. #include <limits.h>
  24. #include <sys/time.h>
  25. #include <time.h>
  26. #include <string>
  27. #include <sstream>
  28. #include <utility>
  29. #include <map>
  30. // #define CHECK_RESULTS
  31. // #include "cuPrintf.cu"
  32. #define BITS_PER_WORD (8 * sizeof(unsigned int))
  33. #define TWO_32_DIV_3 1431655765U // floor( 2^32 / 3 )
  34. #define TWO_32_DIV_3_X2 2863311530U // 2 * floor( 2^32 / 3 )
  35. #define TWO_64_DIV_3 6148914691236517205UL // floor( 2^64 / 3 )
  36. #define SIZE_G WORDS
  37. #define SIZE_Y WORDS
  38. #define SIZE_X (WORDS + 1)
  39. #include "dpstream.cu"
  40. // #define X(idx) x[idx<<5]
  41. // #define Y(idx) (multtype == 0 ? c_g[idx] : multtype == 1 ? c_y[idx] : x[idx<<5])
  42. // #define Y(idx) ((c_g[idx]&typemask0) | (c_y[idx]&typemask1) | (x[idx<<5]&typemask2))
  43. // #define Z(idx) z[idx<<5]
  44. NTL_CLIENT
  45. #ifdef CHECK_RESULTS
  46. static void dump(const char *prefix, const unsigned int *di, size_t words)
  47. {
  48. size_t l = words * 4;
  49. const unsigned char *d = (const unsigned char *) di;
  50. d += l;
  51. printf("%s=", prefix);
  52. while(l)
  53. {
  54. --d;
  55. printf("%02X", *d);
  56. --l;
  57. }
  58. printf("\n");
  59. }
  60. #endif
  61. static void checkCUDAError(const char *msg)
  62. {
  63. cudaError_t err = cudaGetLastError();
  64. if (cudaSuccess != err)
  65. {
  66. fprintf(stderr, "Cuda error: %s: %s.\n", msg, cudaGetErrorString(err));
  67. exit(EXIT_FAILURE);
  68. }
  69. }
  70. typedef struct
  71. {
  72. unsigned int x[SIZE_X];
  73. unsigned int a[2], b[2];
  74. } GlobalThreadState;
  75. __device__ __constant__ unsigned int c_rho[WORDS + 1], c_r_inv[WORDS + 1], c_rho_prime;
  76. __device__ __constant__ unsigned int c_y[SIZE_Y], c_g[SIZE_G];
  77. /*
  78. __device__ unsigned int getgy(int i)
  79. {
  80. return c_rho[i] + c_y[i] + c_g[i];
  81. }
  82. */
  83. #include "cios.asm"
  84. #if 0
  85. __device__ void _sub(unsigned int *x)
  86. // x <- x - y
  87. {
  88. asm("sub.cc.u32 %0, %1, %2;" : "=r"(X(0)) : "r"(X(0)), "r"(c_rho[0]));
  89. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(1)) : "r"(X(1)), "r"(c_rho[1]));
  90. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(2)) : "r"(X(2)), "r"(c_rho[2]));
  91. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(3)) : "r"(X(3)), "r"(c_rho[3]));
  92. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(4)) : "r"(X(4)), "r"(c_rho[4]));
  93. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(5)) : "r"(X(5)), "r"(c_rho[5]));
  94. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(6)) : "r"(X(6)), "r"(c_rho[6]));
  95. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(7)) : "r"(X(7)), "r"(c_rho[7]));
  96. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(8)) : "r"(X(8)), "r"(c_rho[8]));
  97. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(9)) : "r"(X(9)), "r"(c_rho[9]));
  98. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(10)) : "r"(X(10)), "r"(c_rho[10]));
  99. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(11)) : "r"(X(11)), "r"(c_rho[11]));
  100. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(12)) : "r"(X(12)), "r"(c_rho[12]));
  101. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(13)) : "r"(X(13)), "r"(c_rho[13]));
  102. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(14)) : "r"(X(14)), "r"(c_rho[14]));
  103. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(15)) : "r"(X(15)), "r"(c_rho[15]));
  104. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(16)) : "r"(X(16)), "r"(c_rho[16]));
  105. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(17)) : "r"(X(17)), "r"(c_rho[17]));
  106. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(18)) : "r"(X(18)), "r"(c_rho[18]));
  107. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(19)) : "r"(X(19)), "r"(c_rho[19]));
  108. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(20)) : "r"(X(20)), "r"(c_rho[20]));
  109. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(21)) : "r"(X(21)), "r"(c_rho[21]));
  110. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(22)) : "r"(X(22)), "r"(c_rho[22]));
  111. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(23)) : "r"(X(23)), "r"(c_rho[23]));
  112. asm("subc.u32 %0, %1, %2;" : "=r"(X(24)) : "r"(X(24)), "r"(c_rho[24]));
  113. }
  114. __device__ inline bool _gt(const unsigned int * x)
  115. // returns true iff x > y ; x is of length WORDS+1 and y is of length WORDS
  116. {
  117. if (X(24)) return true;
  118. if (X(23) < c_rho[23]) return false;
  119. if (X(23) > c_rho[23]) return true;
  120. if (X(22) < c_rho[22]) return false;
  121. if (X(22) > c_rho[22]) return true;
  122. if (X(21) < c_rho[21]) return false;
  123. if (X(21) > c_rho[21]) return true;
  124. if (X(20) < c_rho[20]) return false;
  125. if (X(20) > c_rho[20]) return true;
  126. if (X(19) < c_rho[19]) return false;
  127. if (X(19) > c_rho[19]) return true;
  128. if (X(18) < c_rho[18]) return false;
  129. if (X(18) > c_rho[18]) return true;
  130. if (X(17) < c_rho[17]) return false;
  131. if (X(17) > c_rho[17]) return true;
  132. if (X(16) < c_rho[16]) return false;
  133. if (X(16) > c_rho[16]) return true;
  134. if (X(15) < c_rho[15]) return false;
  135. if (X(15) > c_rho[15]) return true;
  136. if (X(14) < c_rho[14]) return false;
  137. if (X(14) > c_rho[14]) return true;
  138. if (X(13) < c_rho[13]) return false;
  139. if (X(13) > c_rho[13]) return true;
  140. if (X(12) < c_rho[12]) return false;
  141. if (X(12) > c_rho[12]) return true;
  142. if (X(11) < c_rho[11]) return false;
  143. if (X(11) > c_rho[11]) return true;
  144. if (X(10) < c_rho[10]) return false;
  145. if (X(10) > c_rho[10]) return true;
  146. if (X(9) < c_rho[9]) return false;
  147. if (X(9) > c_rho[9]) return true;
  148. if (X(8) < c_rho[8]) return false;
  149. if (X(8) > c_rho[8]) return true;
  150. if (X(7) < c_rho[7]) return false;
  151. if (X(7) > c_rho[7]) return true;
  152. if (X(6) < c_rho[6]) return false;
  153. if (X(6) > c_rho[6]) return true;
  154. if (X(5) < c_rho[5]) return false;
  155. if (X(5) > c_rho[5]) return true;
  156. if (X(4) < c_rho[4]) return false;
  157. if (X(4) > c_rho[4]) return true;
  158. if (X(3) < c_rho[3]) return false;
  159. if (X(3) > c_rho[3]) return true;
  160. if (X(2) < c_rho[2]) return false;
  161. if (X(2) > c_rho[2]) return true;
  162. if (X(1) < c_rho[1]) return false;
  163. if (X(1) > c_rho[1]) return true;
  164. return (X(0) > c_rho[0]);
  165. }
  166. #endif
  167. #define nmult 1000
  168. #define nlaunch 2
  169. #define threadDimx 32
  170. __global__ void cudaMulmod(GlobalThreadState *global_ts, unsigned long long order)
  171. // x <- x * y mod rho
  172. {
  173. // extern __shared__ unsigned int sharedmem[];
  174. register int i;
  175. register int tid = threadIdx.x + threadDimx * threadIdx.y;
  176. register int global_tid = tid + blockDim.x * blockDim.y * blockIdx.x;
  177. unsigned long long a, b;
  178. unsigned int *global_x_base = global_ts[global_tid].x;
  179. unsigned int *global_a_base = global_ts[global_tid].a;
  180. unsigned int *global_b_base = global_ts[global_tid].b;
  181. // unsigned int *shared_table_base = sharedmem;
  182. // unsigned int *shared_x_base = shared_table_base + threadIdx.y * 32 * (SIZE_X) + threadIdx.x;
  183. unsigned int xlow;
  184. // cuPrintf("d_z = %08X%08X%08X\n", global_x_base[2], global_x_base[1], global_x_base[0]);
  185. loadx(global_x_base);
  186. a = global_a_base[1];
  187. a <<= 32;
  188. a |= global_a_base[0];
  189. b = global_b_base[1];
  190. b <<= 32;
  191. b |= global_b_base[0];
  192. // cuPrintf("s_A = %08X\n", (unsigned int)a);
  193. // cuPrintf("s_B = %08X\n", (unsigned int)b);
  194. // cuPrintf("s_a = %08X%08X\n", global_a_base[1], global_a_base[0]);
  195. // cuPrintf("s_b = %08X%08X\n", global_b_base[1], global_b_base[0]);
  196. for (i = 0; i < nmult; ++i)
  197. {
  198. //memset(ts[tid].z, 0, (WORDS + 2) * sizeof(unsigned int));
  199. //__syncthreads();
  200. //cuPrintf("x = %p %08X%08X%08X\n", ts[tid].x, ts[tid].x[2], ts[tid].x[1], ts[tid].x[0]);
  201. //cuPrintf("y = %p %08X%08X\n", c_y, c_y[1], c_y[0]);
  202. //cuPrintf("z = %p %08X%08X%08X%08X\n", ts[tid].z, ts[tid].z[3], ts[tid].z[2], ts[tid].z[1], ts[tid].z[0]);
  203. int multtype;
  204. asm("mov.u32 %0, $xr0;" : "=r" (xlow));
  205. if (xlow < TWO_32_DIV_3)
  206. {
  207. multtype = 0;
  208. a += 1;
  209. // cuPrintf("inc a\n");
  210. }
  211. else if (xlow < TWO_32_DIV_3_X2)
  212. {
  213. multtype = 1;
  214. b += 1;
  215. // cuPrintf("inc b\n");
  216. }
  217. else
  218. {
  219. multtype = 2;
  220. a += a;
  221. b += b;
  222. // cuPrintf("double\n");
  223. }
  224. if (a > order) a -= order;
  225. if (b > order) b -= order;
  226. modmul(multtype);
  227. //memcpy(ts[tid].x, ts[tid].z, (WORDS + 1) * sizeof(unsigned int));
  228. /*
  229. if (_gt(shared_x_base)) {
  230. _sub(shared_x_base);
  231. }
  232. */
  233. //cuPrintf("y = %p %08X%08X\n", c_y, c_y[1], c_y[0]);
  234. //cuPrintf("z = %p %08X%08X\n", ts[tid].x, ts[tid].x[1], ts[tid].x[0]);
  235. //cuPrintf("y = %p %08X%08X\n", c_y, c_y[1], c_y[0]);
  236. // Check for a distinguished point
  237. asm("mov.u32 %0, $xr0;" : "=r" (xlow));
  238. if ((xlow & 0x000003ff) == 0 || order < (1<<20)) {
  239. DPstreamWrite(a,b);
  240. }
  241. }
  242. savex(global_x_base);
  243. global_a_base[1] = (a>>32);
  244. global_a_base[0] = (unsigned int)a;
  245. global_b_base[1] = (b>>32);
  246. global_b_base[0] = (unsigned int)b;
  247. // cuPrintf("d_z = %08X%08X%08X\n", global_x_base[2], global_x_base[1], global_x_base[0]);
  248. // cuPrintf("d_A = %08X\n", (unsigned int)a);
  249. // cuPrintf("d_B = %08X\n", (unsigned int)b);
  250. // cuPrintf("d_a = %08X%08X\n", global_a_base[1], global_a_base[0]);
  251. // cuPrintf("d_b = %08X%08X\n", global_b_base[1], global_b_base[0]);
  252. if (!order) evilhack();
  253. }
  254. int nthreads = 25600;
  255. int nblocks = 50;
  256. typedef map<std::string, pair<ZZ,ZZ> > DTable;
  257. struct CBData {
  258. const ZZ_p &base;
  259. const ZZ_p &target;
  260. const ZZ &order;
  261. unsigned long long numdp;
  262. DTable dtable;
  263. bool found_collision;
  264. ZZ expon;
  265. CBData(const ZZ_p &_base, const ZZ_p &_target, const ZZ &_order) :
  266. base(_base), target(_target), order(_order), numdp(0),
  267. found_collision(false) {}
  268. };
  269. static void dpcallback(void *cbdata, unsigned short threadId,
  270. unsigned short blockId, string x, unsigned long a, unsigned long b)
  271. {
  272. CBData *d = (CBData*)cbdata;
  273. // WARNING: this assumes
  274. // sizeof(unsigned long) == sizeof(unsigned long long) !
  275. ZZ zz_a = to_ZZ((unsigned long)a);
  276. ZZ zz_b = to_ZZ((unsigned long)b);
  277. //ZZ_p dp = power(d->base, zz_a) * power(d->target, zz_b);
  278. // cerr << "DP " << ++(d->numdp) << "\r";
  279. pair<ZZ,ZZ> ab(zz_a,zz_b);
  280. pair<DTable::iterator, bool> res;
  281. res = d->dtable.insert(DTable::value_type(x, ab));
  282. if (!res.second) {
  283. // Collision!
  284. ZZ adiff = res.first->second.first - a;
  285. ZZ bdiff = b - res.first->second.second;
  286. if (bdiff < 0) bdiff += d->order;
  287. ZZ binv;
  288. if (InvModStatus(binv, bdiff, d->order) == 0) {
  289. d->expon = MulMod(binv, adiff, d->order);
  290. d->found_collision = true;
  291. } else {
  292. if (d->order > (1<<20)) {
  293. cerr << "Unhelpful collision\n";
  294. }
  295. }
  296. }
  297. }
  298. ZZ cuda_dl(const ZZ_p &base, const ZZ_p &target, const ZZ &order,
  299. const ZZ &modulus)
  300. {
  301. unsigned long long totmicros = 0;
  302. ZZ_pBak pbak;
  303. pbak.save();
  304. if (NumBits(modulus) <= ((WORDS-1)*BITS_PER_WORD) ||
  305. NumBits(modulus) > WORDS*BITS_PER_WORD) {
  306. cerr << "modulus is not " << WORDS << " words long.\n";
  307. exit(1);
  308. }
  309. long orderbits = NumBits(order);
  310. if (orderbits > 60) {
  311. cerr << "order is larger than 60 bits.\n";
  312. exit(1);
  313. }
  314. unsigned long long orderll = trunc_long(order, 32) +
  315. ((unsigned long long)(trunc_long(order >> 32, 32)) << 32);
  316. /*
  317. cerr << "order = " << order << "\n";
  318. cerr << "orderll = " << orderll << "\n";
  319. */
  320. unsigned int *rho, rho_prime, *r, *r_inv;
  321. unsigned int l_y[SIZE_Y], l_g[SIZE_G];
  322. //cout << "rho = " << zz_rho << "\n";
  323. ZZ zz_r = (to_ZZ(1) << (WORDS * BITS_PER_WORD));
  324. ZZ_p::init(zz_r);
  325. ZZ_p zz_p_rho_prime = -to_ZZ_p(1) / to_ZZ_p(modulus);
  326. //cout << "rho_prime = " << zz_p_rho_prime << "\n";
  327. ZZ_p::init(modulus);
  328. ZZ_p zz_p_r, zz_p_r_inv;
  329. zz_p_r = to_ZZ_p(zz_r);
  330. zz_p_r_inv = to_ZZ_p(1) / zz_p_r;
  331. CBData cbdata(base, target, order);
  332. //cout << "r = " << zz_r << "\n";
  333. //cout << "r mod rho = " << rep(zz_p_r) << "\n";
  334. //cout << "r_inv = " << rep(zz_p_r_inv) << "\n";
  335. //cout << "r * r_inv = " << zz_p_r * zz_p_r_inv << "\n";
  336. //cout << "r * r_inv - rho * rho_prime = " << zz_r * rep(zz_p_r_inv) - zz_rho * rep(zz_p_rho_prime) << "\n";
  337. rho = (unsigned int*) calloc((WORDS + 1), sizeof(unsigned int));
  338. r = (unsigned int*) calloc((WORDS + 1), sizeof(unsigned int));
  339. r_inv = (unsigned int*) calloc((WORDS + 1), sizeof(unsigned int));
  340. BytesFromZZ((unsigned char *) rho, modulus, WORDS * sizeof(unsigned int));
  341. BytesFromZZ((unsigned char *) &rho_prime, rep(zz_p_rho_prime), sizeof(unsigned int));
  342. BytesFromZZ((unsigned char *) r, rep(zz_p_r), (WORDS + 1) * sizeof(unsigned int));
  343. BytesFromZZ((unsigned char *) r_inv, rep(zz_p_r_inv), (WORDS + 1) * sizeof(unsigned int));
  344. cudaMemcpyToSymbol(c_rho, rho, (WORDS + 1) * sizeof(unsigned int), 0, cudaMemcpyHostToDevice);
  345. cudaMemcpyToSymbol(c_rho_prime, &rho_prime, sizeof(unsigned int), 0, cudaMemcpyHostToDevice);
  346. cudaMemcpyToSymbol(c_r_inv, r_inv, (WORDS + 1) * sizeof(unsigned int), 0, cudaMemcpyHostToDevice);
  347. checkCUDAError("memcpytosymbol");
  348. /*
  349. if (nthreads % threadDimx) {
  350. nthreads /= threadDimx;
  351. nthreads *= threadDimx;
  352. cerr << "Truncating to " << nthreads << " threads.\n";
  353. }
  354. */
  355. if (nthreads % nblocks) {
  356. cerr << "Error: " << nthreads << " not a multiple of " << nblocks << "\n";
  357. exit(1);
  358. }
  359. const int threadsPerBlock = nthreads / nblocks;
  360. GlobalThreadState *d_ts;
  361. cudaMalloc((void **) &d_ts, nthreads * sizeof(GlobalThreadState));
  362. GlobalThreadState *l_ts;
  363. l_ts = (GlobalThreadState *) calloc(nthreads, sizeof(GlobalThreadState));
  364. unsigned int *l_z;
  365. l_z = (unsigned int *) calloc(nthreads, WORDS * sizeof(unsigned int));
  366. //cudaPrintfInit((1<<20)*16);
  367. DPstreamInit(1<<16);
  368. struct timeval st, et;
  369. memset(l_ts, 0, nthreads * sizeof(GlobalThreadState));
  370. memset(l_z, 0, WORDS * sizeof(unsigned int));
  371. //cout << "y = " << rep(zz_p_y) << "\n";
  372. ZZ_p zz_p_yr = target * zz_p_r;
  373. //cout << "y = " << rep(zz_p_y) << "\n";
  374. ZZ_p zz_p_gr = base * zz_p_r;
  375. BytesFromZZ((unsigned char *) l_y, rep(zz_p_yr), WORDS * sizeof(unsigned int));
  376. BytesFromZZ((unsigned char *) l_g, rep(zz_p_gr), WORDS * sizeof(unsigned int));
  377. cudaMemcpyToSymbol(c_y, l_y, (WORDS) * sizeof(unsigned int), 0, cudaMemcpyHostToDevice);
  378. cudaMemcpyToSymbol(c_g, l_g, (WORDS) * sizeof(unsigned int), 0, cudaMemcpyHostToDevice);
  379. //dump("y", l_y, WORDS);
  380. #ifdef CHECK_RESULTS
  381. int totmult = 0;
  382. bool fail = false;
  383. vec_ZZ aexp, bexp; // The expected values of a and b at completion
  384. aexp.SetLength(nthreads);
  385. bexp.SetLength(nthreads);
  386. #endif
  387. ZZ a = RandomBits_ZZ(orderbits-1);
  388. ZZ b = RandomBits_ZZ(orderbits-1);
  389. ZZ astep = RandomBits_ZZ(orderbits-1);
  390. ZZ bstep = RandomBits_ZZ(orderbits-1);
  391. ZZ_p zz_p_x = power(base, a) * power(target, b);
  392. ZZ_p zz_p_step = power(base, astep) * power(target, bstep);
  393. ZZ_p zz_p_xr = zz_p_x * zz_p_r;
  394. for (int t=0; t<nthreads; ++t)
  395. {
  396. zz_p_xr *= zz_p_step;
  397. a += astep;
  398. a %= order;
  399. b += bstep;
  400. b %= order;
  401. BytesFromZZ((unsigned char *) l_ts[t].x, rep(zz_p_xr), WORDS * sizeof(unsigned int));
  402. // dump("l_x", l_ts[t].x, WORDS);
  403. BytesFromZZ((unsigned char *) l_ts[t].a, a, 2 * sizeof(unsigned int));
  404. BytesFromZZ((unsigned char *) l_ts[t].b, b, 2 * sizeof(unsigned int));
  405. //dump("x", l_ts[t].x, WORDS);
  406. //cout << "x = " << rep(zz_p_x) << "\n";
  407. //cout << "xr = " << rep(zz_p_xr) << "\n";
  408. //dump("rho", rho, WORDS);
  409. #ifdef CHECK_RESULTS
  410. for (int l = 0; l < nmult * nlaunch; ++l)
  411. {
  412. unsigned int w = trunc_long(rep(zz_p_xr), 32);
  413. if (w < TWO_32_DIV_3) {
  414. zz_p_xr *= base;
  415. a++;
  416. } else if (w < TWO_32_DIV_3_X2) {
  417. zz_p_xr *= target;
  418. b++;
  419. } else {
  420. zz_p_xr *= zz_p_xr * zz_p_r_inv;
  421. a += a;
  422. b += b;
  423. }
  424. if (a > order) a -= order;
  425. if (b > order) b -= order;
  426. ++totmult;
  427. }
  428. BytesFromZZ((unsigned char *) (l_z + t * WORDS), rep(zz_p_xr), WORDS * sizeof(unsigned int));
  429. aexp[t] = a;
  430. bexp[t] = b;
  431. #endif
  432. //cout << "zr = " << rep(zz_p_xr) << "\n";
  433. //dump("z", l_z + t * WORDS, WORDS);
  434. }
  435. cudaMemcpy(d_ts, l_ts, nthreads * sizeof(GlobalThreadState), cudaMemcpyHostToDevice);
  436. dim3 tpb(threadDimx, threadsPerBlock/threadDimx);
  437. gettimeofday(&st, NULL);
  438. int launchcount = 0;
  439. #ifdef CHECK_RESULTS
  440. for (int ln=0; ln<nlaunch; ++ln)
  441. #else
  442. while(cbdata.found_collision == false)
  443. #endif
  444. {
  445. cerr << getpid() << " Launch " << ++launchcount << "...\n";
  446. cudaMulmod<<< nblocks, nthreads/nblocks /*tpb*/, 0 >>>(d_ts, orderll);
  447. cudaThreadSynchronize();
  448. checkCUDAError("kernel launch");
  449. DPstreamParse(&cbdata);
  450. //cudaPrintfExtractDPE(dpcallback, &cbdata);
  451. //cudaPrintfDisplay(stdout, true);
  452. cerr << getpid() << "\n";
  453. }
  454. gettimeofday(&et, NULL);
  455. totmicros = (unsigned long long)(et.tv_sec - st.tv_sec) * 1000000 + (et.tv_usec - st.tv_usec);
  456. #ifdef CHECK_RESULTS
  457. cudaMemcpy(l_ts, d_ts, nthreads * sizeof(GlobalThreadState), cudaMemcpyDeviceToHost);
  458. checkCUDAError("memcpy");
  459. int j = 0;
  460. for (int t = 0; t < nthreads; ++t)
  461. {
  462. unsigned int *l_Z = l_ts[t].x;
  463. for (int i = 0; i < WORDS; i++)
  464. {
  465. if (l_Z[i] != l_z[i + t * WORDS])
  466. {
  467. fail = true;
  468. cout << i << ": " << l_Z[i] << " != " << l_z[i + t * WORDS] << "\n";
  469. }
  470. }
  471. if (fail)
  472. {
  473. dump("d_z", l_Z, WORDS);
  474. dump("l_z", l_z + t * WORDS, WORDS);
  475. }
  476. ZZ ares = (to_ZZ(l_ts[t].a[1]) << 32) + to_ZZ(l_ts[t].a[0]);
  477. ZZ bres = (to_ZZ(l_ts[t].b[1]) << 32) + to_ZZ(l_ts[t].b[0]);
  478. if (ares != aexp[t] || bres != bexp[t]) {
  479. cerr << "ares = " << ares << "\n";
  480. cerr << "aexp = " << aexp[t] << "\n";
  481. cerr << "bres = " << bres << "\n";
  482. cerr << "bexp = " << bexp[t] << "\n";
  483. }
  484. ++j;
  485. }
  486. if (!fail) {
  487. cerr << "Results correct.\n";
  488. }
  489. #endif
  490. unsigned long long totnanos = totmicros * 1000;
  491. cout << totmicros << " us / " << nthreads << " = " << totmicros / nthreads << " us / " << (nmult*launchcount) << " = " << totnanos / ((unsigned long long)nthreads * nmult * launchcount) << " ns\n";
  492. //cudaPrintfEnd();
  493. DPstreamEnd();
  494. cudaFree(d_ts);
  495. free(rho);
  496. free(r_inv);
  497. free(r);
  498. free(l_ts);
  499. free(l_z);
  500. pbak.restore();
  501. return cbdata.expon;
  502. }
  503. #ifdef TEST_CUDA
  504. int main(int argc, char** argv)
  505. {
  506. #ifdef DERANDOMIZE
  507. SetSeed(to_ZZ(1));
  508. #else
  509. // Initialize the prng with some randomness from the kernel
  510. unsigned char randbuf[1024];
  511. ifstream urand("/dev/urandom");
  512. urand.read((char *) randbuf, sizeof(randbuf));
  513. urand.close();
  514. ZZ randzz = ZZFromBytes(randbuf, sizeof(randbuf));
  515. SetSeed(randzz);
  516. #endif
  517. ZZ rho, p, q;
  518. vec_ZZ pfvec, qfvec;
  519. cin >> rho >> p >> pfvec >> q >> qfvec;
  520. if (argc > 1) nthreads = atoi(argv[1]);
  521. if (argc > 2) nblocks = atoi(argv[2]);
  522. ZZ_p::init(p);
  523. for (int iter = 0; iter < 1; ++iter) {
  524. // Create the subproblem for the f'th factor of p-1
  525. int f = iter;
  526. ZZ remorder = (p-1)/pfvec[f];
  527. ZZ_p g = power(to_ZZ_p(2), remorder);
  528. ZZ_p y = power(random_ZZ_p(), remorder);
  529. // g should now be of order pfvec[0]. Check that.
  530. if (g == 1 || power(g, pfvec[f]) != 1) {
  531. cerr << "base has the wrong order!\n";
  532. exit(1);
  533. }
  534. // Try to find the DL_g of y
  535. cerr << "DL_" << g << "(" << y << ") mod " << p << "\n";
  536. ZZ e = cuda_dl(g, y, pfvec[f], p);
  537. cerr << "e = " << e << "\n";
  538. cerr << ( (power(g,e) == y) ? "CORRECT!" : "INCORRECT!" ) << "\n";
  539. }
  540. return 0;
  541. }
  542. #endif