parrhoasm.cu 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  1. /*
  2. * cudadl version 0.9: 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 <NTL/vec_ZZ_p.h>
  23. #include <string.h>
  24. #include <limits.h>
  25. #include <sys/time.h>
  26. #include <time.h>
  27. #include <unistd.h>
  28. #include <string>
  29. #include <sstream>
  30. #include <utility>
  31. #include <map>
  32. #include "atomic_iostream.h"
  33. #include "worker.h"
  34. // #define CHECK_RESULTS
  35. #define VERBOSE
  36. // #include "cuPrintf.cu"
  37. #define BITS_PER_WORD (8 * sizeof(unsigned int))
  38. #define TWO_32_DIV_3 1431655765U // floor( 2^32 / 3 )
  39. #define TWO_32_DIV_3_X2 2863311530U // 2 * floor( 2^32 / 3 )
  40. #define TWO_64_DIV_3 6148914691236517205UL // floor( 2^64 / 3 )
  41. #define SIZE_G WORDS
  42. #define SIZE_Y WORDS
  43. #define SIZE_X (WORDS + 1)
  44. __device__ __constant__ unsigned int c_rho[WORDS + 1], c_r_inv[WORDS + 1], c_rho_prime;
  45. __device__ __constant__ unsigned int c_y[SIZE_Y], c_g[SIZE_G];
  46. #include "cios.asm"
  47. #include "dpstream.cu"
  48. // #define X(idx) x[idx<<5]
  49. // #define Y(idx) (multtype == 0 ? c_g[idx] : multtype == 1 ? c_y[idx] : x[idx<<5])
  50. // #define Y(idx) ((c_g[idx]&typemask0) | (c_y[idx]&typemask1) | (x[idx<<5]&typemask2))
  51. // #define Z(idx) z[idx<<5]
  52. NTL_CLIENT
  53. #ifdef CHECK_RESULTS
  54. static void dump(const char *prefix, const unsigned int *di, size_t words)
  55. {
  56. size_t l = words * 4;
  57. const unsigned char *d = (const unsigned char *) di;
  58. d += l;
  59. printf("%s=", prefix);
  60. while(l)
  61. {
  62. --d;
  63. printf("%02X", *d);
  64. --l;
  65. }
  66. printf("\n");
  67. }
  68. #endif
  69. static void checkCUDAError(const char *msg)
  70. {
  71. cudaError_t err = cudaGetLastError();
  72. if (cudaSuccess != err)
  73. {
  74. fprintf(stderr, "Cuda error: %s: %s.\n", msg, cudaGetErrorString(err));
  75. exit(EXIT_FAILURE);
  76. }
  77. }
  78. typedef struct
  79. {
  80. unsigned int x[SIZE_X];
  81. unsigned int a[3], b[3];
  82. } GlobalThreadState;
  83. /*
  84. __device__ unsigned int getgy(int i)
  85. {
  86. return c_rho[i] + c_y[i] + c_g[i];
  87. }
  88. */
  89. #if 0
  90. __device__ void _sub(unsigned int *x)
  91. // x <- x - y
  92. {
  93. asm("sub.cc.u32 %0, %1, %2;" : "=r"(X(0)) : "r"(X(0)), "r"(c_rho[0]));
  94. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(1)) : "r"(X(1)), "r"(c_rho[1]));
  95. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(2)) : "r"(X(2)), "r"(c_rho[2]));
  96. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(3)) : "r"(X(3)), "r"(c_rho[3]));
  97. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(4)) : "r"(X(4)), "r"(c_rho[4]));
  98. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(5)) : "r"(X(5)), "r"(c_rho[5]));
  99. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(6)) : "r"(X(6)), "r"(c_rho[6]));
  100. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(7)) : "r"(X(7)), "r"(c_rho[7]));
  101. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(8)) : "r"(X(8)), "r"(c_rho[8]));
  102. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(9)) : "r"(X(9)), "r"(c_rho[9]));
  103. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(10)) : "r"(X(10)), "r"(c_rho[10]));
  104. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(11)) : "r"(X(11)), "r"(c_rho[11]));
  105. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(12)) : "r"(X(12)), "r"(c_rho[12]));
  106. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(13)) : "r"(X(13)), "r"(c_rho[13]));
  107. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(14)) : "r"(X(14)), "r"(c_rho[14]));
  108. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(15)) : "r"(X(15)), "r"(c_rho[15]));
  109. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(16)) : "r"(X(16)), "r"(c_rho[16]));
  110. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(17)) : "r"(X(17)), "r"(c_rho[17]));
  111. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(18)) : "r"(X(18)), "r"(c_rho[18]));
  112. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(19)) : "r"(X(19)), "r"(c_rho[19]));
  113. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(20)) : "r"(X(20)), "r"(c_rho[20]));
  114. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(21)) : "r"(X(21)), "r"(c_rho[21]));
  115. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(22)) : "r"(X(22)), "r"(c_rho[22]));
  116. asm("subc.cc.u32 %0, %1, %2;" : "=r"(X(23)) : "r"(X(23)), "r"(c_rho[23]));
  117. asm("subc.u32 %0, %1, %2;" : "=r"(X(24)) : "r"(X(24)), "r"(c_rho[24]));
  118. }
  119. __device__ inline bool _gt(const unsigned int * x)
  120. // returns true iff x > y ; x is of length WORDS+1 and y is of length WORDS
  121. {
  122. if (X(24)) return true;
  123. if (X(23) < c_rho[23]) return false;
  124. if (X(23) > c_rho[23]) return true;
  125. if (X(22) < c_rho[22]) return false;
  126. if (X(22) > c_rho[22]) return true;
  127. if (X(21) < c_rho[21]) return false;
  128. if (X(21) > c_rho[21]) return true;
  129. if (X(20) < c_rho[20]) return false;
  130. if (X(20) > c_rho[20]) return true;
  131. if (X(19) < c_rho[19]) return false;
  132. if (X(19) > c_rho[19]) return true;
  133. if (X(18) < c_rho[18]) return false;
  134. if (X(18) > c_rho[18]) return true;
  135. if (X(17) < c_rho[17]) return false;
  136. if (X(17) > c_rho[17]) return true;
  137. if (X(16) < c_rho[16]) return false;
  138. if (X(16) > c_rho[16]) return true;
  139. if (X(15) < c_rho[15]) return false;
  140. if (X(15) > c_rho[15]) return true;
  141. if (X(14) < c_rho[14]) return false;
  142. if (X(14) > c_rho[14]) return true;
  143. if (X(13) < c_rho[13]) return false;
  144. if (X(13) > c_rho[13]) return true;
  145. if (X(12) < c_rho[12]) return false;
  146. if (X(12) > c_rho[12]) return true;
  147. if (X(11) < c_rho[11]) return false;
  148. if (X(11) > c_rho[11]) return true;
  149. if (X(10) < c_rho[10]) return false;
  150. if (X(10) > c_rho[10]) return true;
  151. if (X(9) < c_rho[9]) return false;
  152. if (X(9) > c_rho[9]) return true;
  153. if (X(8) < c_rho[8]) return false;
  154. if (X(8) > c_rho[8]) return true;
  155. if (X(7) < c_rho[7]) return false;
  156. if (X(7) > c_rho[7]) return true;
  157. if (X(6) < c_rho[6]) return false;
  158. if (X(6) > c_rho[6]) return true;
  159. if (X(5) < c_rho[5]) return false;
  160. if (X(5) > c_rho[5]) return true;
  161. if (X(4) < c_rho[4]) return false;
  162. if (X(4) > c_rho[4]) return true;
  163. if (X(3) < c_rho[3]) return false;
  164. if (X(3) > c_rho[3]) return true;
  165. if (X(2) < c_rho[2]) return false;
  166. if (X(2) > c_rho[2]) return true;
  167. if (X(1) < c_rho[1]) return false;
  168. if (X(1) > c_rho[1]) return true;
  169. return (X(0) > c_rho[0]);
  170. }
  171. #endif
  172. #define nmult 1000
  173. #define nlaunch 2
  174. #define threadDimx 32
  175. __global__ void cudaMulmod(GlobalThreadState *global_ts,
  176. unsigned int order_0, unsigned int order_1, unsigned int order_2,
  177. unsigned int dpfreq)
  178. // x <- x * y mod rho
  179. {
  180. CIOS_REG_DECLARE;
  181. // extern __shared__ unsigned int sharedmem[];
  182. register int i;
  183. register int tid = threadIdx.x + threadDimx * threadIdx.y;
  184. register int global_tid = tid + blockDim.x * blockDim.y * blockIdx.x;
  185. unsigned int a_0, a_1, a_2;
  186. unsigned int b_0, b_1, b_2;
  187. unsigned int *global_x_base = global_ts[global_tid].x;
  188. unsigned int *global_a_base = global_ts[global_tid].a;
  189. unsigned int *global_b_base = global_ts[global_tid].b;
  190. // unsigned int *shared_table_base = sharedmem;
  191. // unsigned int *shared_x_base = shared_table_base + threadIdx.y * 32 * (SIZE_X) + threadIdx.x;
  192. unsigned int xlow;
  193. // cuPrintf("d_z = %08X%08X%08X\n", global_x_base[2], global_x_base[1], global_x_base[0]);
  194. CIOS_LOADX(global_x_base);
  195. a_2 = global_a_base[2];
  196. a_1 = global_a_base[1];
  197. a_0 = global_a_base[0];
  198. b_2 = global_b_base[2];
  199. b_1 = global_b_base[1];
  200. b_0 = global_b_base[0];
  201. // cuPrintf("s_A = %08X\n", (unsigned int)a);
  202. // cuPrintf("s_B = %08X\n", (unsigned int)b);
  203. // cuPrintf("s_a = %08X%08X\n", global_a_base[1], global_a_base[0]);
  204. // cuPrintf("s_b = %08X%08X\n", global_b_base[1], global_b_base[0]);
  205. #pragma unroll 1 // to prevent namespace conflicts caused by loop unrolling when 'nmult' is small
  206. for (i = 0; i < nmult; ++i)
  207. {
  208. //memset(ts[tid].z, 0, (WORDS + 2) * sizeof(unsigned int));
  209. //__syncthreads();
  210. //cuPrintf("x = %p %08X%08X%08X\n", ts[tid].x, ts[tid].x[2], ts[tid].x[1], ts[tid].x[0]);
  211. //cuPrintf("y = %p %08X%08X\n", c_y, c_y[1], c_y[0]);
  212. //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]);
  213. int multtype;
  214. asm volatile("mov.u32 %0, $xr0;" : "=r" (xlow));
  215. // volatile qualifier needed to prevent the compiler from moving it outside of the loop
  216. // change can be seen by building with 'make ptx' and reading the 'parrhoasm.ptx' file
  217. if (xlow < TWO_32_DIV_3)
  218. {
  219. multtype = 0;
  220. asm volatile("add.cc.u32 %0, %1, %2;" : "=r"(a_0) : "r"(a_0), "r"((unsigned int)1U));
  221. asm volatile("addc.cc.u32 %0, %1, %2;" : "=r"(a_1) : "r"(a_1), "r"((unsigned int)0U));
  222. asm volatile("addc.u32 %0, %1, %2;" : "=r"(a_2) : "r"(a_2), "r"((unsigned int)0U));
  223. // a += 1;
  224. // cuPrintf("inc a\n");
  225. }
  226. else if (xlow < TWO_32_DIV_3_X2)
  227. {
  228. multtype = 1;
  229. asm volatile("add.cc.u32 %0, %1, %2;" : "=r"(b_0) : "r"(b_0), "r"((unsigned int)1U));
  230. asm volatile("addc.cc.u32 %0, %1, %2;" : "=r"(b_1) : "r"(b_1), "r"((unsigned int)0U));
  231. asm volatile("addc.u32 %0, %1, %2;" : "=r"(b_2) : "r"(b_2), "r"((unsigned int)0U));
  232. // b += 1;
  233. // cuPrintf("inc b\n");
  234. }
  235. else
  236. {
  237. multtype = 2;
  238. asm volatile("add.cc.u32 %0, %1, %2;" : "=r"(a_0) : "r"(a_0), "r"(a_0));
  239. asm volatile("addc.cc.u32 %0, %1, %2;" : "=r"(a_1) : "r"(a_1), "r"(a_1));
  240. asm volatile("addc.u32 %0, %1, %2;" : "=r"(a_2) : "r"(a_2), "r"(a_2));
  241. asm volatile("add.cc.u32 %0, %1, %2;" : "=r"(b_0) : "r"(b_0), "r"(b_0));
  242. asm volatile("addc.cc.u32 %0, %1, %2;" : "=r"(b_1) : "r"(b_1), "r"(b_1));
  243. asm volatile("addc.u32 %0, %1, %2;" : "=r"(b_2) : "r"(b_2), "r"(b_2));
  244. // a += a;
  245. // b += b;
  246. // cuPrintf("double\n");
  247. }
  248. if (a_2 > order_2 || ((a_2 == order_2) && (a_1 > order_1)) || (((a_2 == order_2) && (a_1 == order_1) && (a_0 > order_0)))) {
  249. asm volatile("sub.cc.u32 %0, %1, %2;" : "=r"(a_0) : "r"(a_0), "r"(order_0));
  250. asm volatile("subc.cc.u32 %0, %1, %2;" : "=r"(a_1) : "r"(a_1), "r"(order_1));
  251. asm volatile("subc.u32 %0, %1, %2;" : "=r"(a_2) : "r"(a_2), "r"(order_2));
  252. }
  253. if (b_2 > order_2 || ((b_2 == order_2) && (b_1 > order_1)) || (((b_2 == order_2) && (b_1 == order_1) && (b_0 > order_0)))) {
  254. asm volatile("sub.cc.u32 %0, %1, %2;" : "=r"(b_0) : "r"(b_0), "r"(order_0));
  255. asm volatile("subc.cc.u32 %0, %1, %2;" : "=r"(b_1) : "r"(b_1), "r"(order_1));
  256. asm volatile("subc.u32 %0, %1, %2;" : "=r"(b_2) : "r"(b_2), "r"(order_2));
  257. }
  258. CIOS_MODMUL(multtype);
  259. //memcpy(ts[tid].x, ts[tid].z, (WORDS + 1) * sizeof(unsigned int));
  260. /*
  261. if (_gt(shared_x_base)) {
  262. _sub(shared_x_base);
  263. }
  264. */
  265. //cuPrintf("y = %p %08X%08X\n", c_y, c_y[1], c_y[0]);
  266. //cuPrintf("z = %p %08X%08X\n", ts[tid].x, ts[tid].x[1], ts[tid].x[0]);
  267. //cuPrintf("y = %p %08X%08X\n", c_y, c_y[1], c_y[0]);
  268. // Check for a distinguished point
  269. asm volatile("mov.u32 %0, $xr0;" : "=r" (xlow));
  270. if (xlow <= dpfreq) {
  271. unsigned int *ourbuffer = DPstreamAlloc();
  272. if (ourbuffer) {
  273. CIOS_WRITE_DP(ourbuffer, a_0, a_1, a_2, b_0, b_1, b_2);
  274. }
  275. }
  276. }
  277. CIOS_SAVEX(global_x_base);
  278. global_a_base[0] = a_0;
  279. global_a_base[1] = a_1;
  280. global_a_base[2] = a_2;
  281. global_b_base[0] = b_0;
  282. global_b_base[1] = b_1;
  283. global_b_base[2] = b_2;
  284. // cuPrintf("d_z = %08X%08X%08X\n", global_x_base[2], global_x_base[1], global_x_base[0]);
  285. // cuPrintf("d_A = %08X\n", (unsigned int)a);
  286. // cuPrintf("d_B = %08X\n", (unsigned int)b);
  287. // cuPrintf("d_a = %08X%08X\n", global_a_base[1], global_a_base[0]);
  288. // cuPrintf("d_b = %08X%08X\n", global_b_base[1], global_b_base[0]);
  289. }
  290. #if defined(NTHREADS) || defined(NBLOCKS)
  291. // must define both together
  292. int nthreads = NTHREADS;
  293. int nblocks = NBLOCKS;
  294. #else
  295. int nthreads = 25600;
  296. int nblocks = 50;
  297. #endif
  298. void cuda_dl(const ZZ_p &base, const ZZ_p &target, const ZZ &order,
  299. const ZZ &modulus, unsigned int dpfreq, void *cbdata,
  300. unsigned int* launch_count, bool* filled_dp_buffer)
  301. {
  302. unsigned long long totmicros = 0;
  303. ZZ_pBak pbak;
  304. pbak.save();
  305. if (NumBits(modulus) <= ((WORDS-1)*BITS_PER_WORD) ||
  306. NumBits(modulus) > WORDS*BITS_PER_WORD) {
  307. AtomicWriter(cerr) << "modulus is not " << WORDS << " words long.\n";
  308. exit(1);
  309. }
  310. long orderbits = NumBits(order);
  311. if (orderbits > 92) {
  312. AtomicWriter(cerr) << "order is larger than 92 bits.\n";
  313. exit(1);
  314. }
  315. unsigned int order_2 = trunc_long(order >> 64, 32);
  316. unsigned int order_1 = trunc_long(order >> 32, 32);
  317. unsigned int order_0 = trunc_long(order, 32);
  318. /*
  319. cerr << "order = " << order << "\n";
  320. cerr << "orderll = " << orderll << "\n";
  321. */
  322. unsigned int *rho, rho_prime, *r, *r_inv;
  323. unsigned int l_y[SIZE_Y], l_g[SIZE_G];
  324. //cout << "rho = " << zz_rho << "\n";
  325. ZZ zz_r = (to_ZZ(1) << (WORDS * BITS_PER_WORD));
  326. ZZ_p::init(zz_r);
  327. ZZ_p zz_p_rho_prime = -to_ZZ_p(1) / to_ZZ_p(modulus);
  328. //cout << "rho_prime = " << zz_p_rho_prime << "\n";
  329. ZZ_p::init(modulus);
  330. ZZ_p zz_p_r, zz_p_r_inv;
  331. zz_p_r = to_ZZ_p(zz_r);
  332. zz_p_r_inv = to_ZZ_p(1) / zz_p_r;
  333. //cout << "r = " << zz_r << "\n";
  334. //cout << "r mod rho = " << rep(zz_p_r) << "\n";
  335. //cout << "r_inv = " << rep(zz_p_r_inv) << "\n";
  336. //cout << "r * r_inv = " << zz_p_r * zz_p_r_inv << "\n";
  337. //cout << "r * r_inv - rho * rho_prime = " << zz_r * rep(zz_p_r_inv) - zz_rho * rep(zz_p_rho_prime) << "\n";
  338. rho = (unsigned int*) calloc((WORDS + 1), sizeof(unsigned int));
  339. r = (unsigned int*) calloc((WORDS + 1), sizeof(unsigned int));
  340. r_inv = (unsigned int*) calloc((WORDS + 1), sizeof(unsigned int));
  341. BytesFromZZ((unsigned char *) rho, modulus, WORDS * sizeof(unsigned int));
  342. BytesFromZZ((unsigned char *) &rho_prime, rep(zz_p_rho_prime), sizeof(unsigned int));
  343. BytesFromZZ((unsigned char *) r, rep(zz_p_r), (WORDS + 1) * sizeof(unsigned int));
  344. BytesFromZZ((unsigned char *) r_inv, rep(zz_p_r_inv), (WORDS + 1) * sizeof(unsigned int));
  345. cudaMemcpyToSymbol(c_rho, rho, (WORDS + 1) * sizeof(unsigned int), 0, cudaMemcpyHostToDevice);
  346. cudaMemcpyToSymbol(c_rho_prime, &rho_prime, sizeof(unsigned int), 0, cudaMemcpyHostToDevice);
  347. cudaMemcpyToSymbol(c_r_inv, r_inv, (WORDS + 1) * sizeof(unsigned int), 0, cudaMemcpyHostToDevice);
  348. checkCUDAError("memcpytosymbol");
  349. /*
  350. if (nthreads % threadDimx) {
  351. nthreads /= threadDimx;
  352. nthreads *= threadDimx;
  353. cerr << "Truncating to " << nthreads << " threads.\n";
  354. }
  355. */
  356. if (nthreads % nblocks) {
  357. AtomicWriter(cerr) << "Error: " << nthreads << " not a multiple of " << nblocks << "\n";
  358. exit(1);
  359. }
  360. const int threadsPerBlock = nthreads / nblocks;
  361. GlobalThreadState *d_ts;
  362. cudaMalloc((void **) &d_ts, nthreads * sizeof(GlobalThreadState));
  363. GlobalThreadState *l_ts;
  364. l_ts = (GlobalThreadState *) calloc(nthreads, sizeof(GlobalThreadState));
  365. unsigned int *l_z;
  366. l_z = (unsigned int *) calloc(nthreads, WORDS * sizeof(unsigned int));
  367. //cudaPrintfInit((1<<20)*16);
  368. DPstreamInit(1<<16);
  369. struct timeval st, et;
  370. memset(l_ts, 0, nthreads * sizeof(GlobalThreadState));
  371. memset(l_z, 0, WORDS * sizeof(unsigned int));
  372. //cout << "y = " << rep(zz_p_y) << "\n";
  373. ZZ_p zz_p_yr = target * zz_p_r;
  374. //cout << "y = " << rep(zz_p_y) << "\n";
  375. ZZ_p zz_p_gr = base * zz_p_r;
  376. BytesFromZZ((unsigned char *) l_y, rep(zz_p_yr), WORDS * sizeof(unsigned int));
  377. BytesFromZZ((unsigned char *) l_g, rep(zz_p_gr), WORDS * sizeof(unsigned int));
  378. cudaMemcpyToSymbol(c_y, l_y, (WORDS) * sizeof(unsigned int), 0, cudaMemcpyHostToDevice);
  379. cudaMemcpyToSymbol(c_g, l_g, (WORDS) * sizeof(unsigned int), 0, cudaMemcpyHostToDevice);
  380. //dump("y", l_y, WORDS);
  381. #ifdef CHECK_RESULTS
  382. vec_ZZ astart, bstart; // the starting values of a and b
  383. vec_ZZ_p zz_p_xr_start;
  384. astart.SetLength(nthreads);
  385. bstart.SetLength(nthreads);
  386. zz_p_xr_start.SetLength(nthreads);
  387. #endif
  388. ZZ a = RandomBits_ZZ(orderbits-1);
  389. ZZ b = RandomBits_ZZ(orderbits-1);
  390. ZZ astep = RandomBits_ZZ(orderbits-1);
  391. ZZ bstep = RandomBits_ZZ(orderbits-1);
  392. ZZ_p zz_p_x = power(base, a) * power(target, b);
  393. ZZ_p zz_p_step = power(base, astep) * power(target, bstep);
  394. ZZ_p zz_p_xr = zz_p_x * zz_p_r;
  395. for (int t=0; t<nthreads; ++t)
  396. {
  397. zz_p_xr *= zz_p_step;
  398. a += astep;
  399. a %= order;
  400. b += bstep;
  401. b %= order;
  402. BytesFromZZ((unsigned char *) l_ts[t].x, rep(zz_p_xr), WORDS * sizeof(unsigned int));
  403. // dump("l_x", l_ts[t].x, WORDS);
  404. BytesFromZZ((unsigned char *) l_ts[t].a, a, 3 * sizeof(unsigned int));
  405. BytesFromZZ((unsigned char *) l_ts[t].b, b, 3 * sizeof(unsigned int));
  406. #ifdef CHECK_RESULTS
  407. astart[t] = a;
  408. bstart[t] = b;
  409. zz_p_xr_start[t] = zz_p_xr;
  410. #endif
  411. //dump("x", l_ts[t].x, WORDS);
  412. //cout << "x = " << rep(zz_p_x) << "\n";
  413. //cout << "xr = " << rep(zz_p_xr) << "\n";
  414. //dump("rho", rho, WORDS);
  415. }
  416. cudaMemcpy(d_ts, l_ts, nthreads * sizeof(GlobalThreadState), cudaMemcpyHostToDevice);
  417. dim3 tpb(threadDimx, threadsPerBlock/threadDimx);
  418. gettimeofday(&st, NULL);
  419. int local_launchcount = 0;
  420. bool stop_computing = false;
  421. unsigned int num_dps = 0;
  422. #ifdef VERBOSE
  423. AtomicWriter(cerr) << getpid() << " Using (nblocks, nthreads): " << nblocks << ", " << nthreads << "\n";
  424. #endif
  425. #ifdef CHECK_RESULTS
  426. for (int ln=0; ln<nlaunch && stop_computing == false; ++ln)
  427. #else
  428. while(stop_computing == false)
  429. #endif
  430. {
  431. local_launchcount++;
  432. #ifdef VERBOSE
  433. AtomicWriter(cerr) << getpid() << " Launch " << local_launchcount << "...\n";
  434. #endif
  435. cudaMulmod<<< nblocks, nthreads/nblocks /*tpb*/, 0 >>>(d_ts,
  436. order_0, order_1, order_2, dpfreq);
  437. checkCUDAError("kernel launch");
  438. cudaThreadSynchronize();
  439. checkCUDAError("thread sync");
  440. bool single_launch_filled_dp_buffer = false;
  441. stop_computing = DPstreamParse(cbdata, &num_dps, &single_launch_filled_dp_buffer);
  442. *filled_dp_buffer = (*filled_dp_buffer || single_launch_filled_dp_buffer);
  443. #ifdef VERBOSE
  444. AtomicWriter(cerr) << getpid() << " Finished " << local_launchcount << " (" << num_dps << " DPs)\n";
  445. #endif
  446. //cudaPrintfExtractDPE(dpcallback, cbdata);
  447. //cudaPrintfDisplay(stdout, true);
  448. }
  449. gettimeofday(&et, NULL);
  450. totmicros = (unsigned long long)(et.tv_sec - st.tv_sec) * 1000000 + (et.tv_usec - st.tv_usec);
  451. #ifdef CHECK_RESULTS
  452. int totmult = 0;
  453. bool fail = false;
  454. vec_ZZ aexp, bexp; // the expected values of a and b at completion
  455. aexp.SetLength(nthreads);
  456. bexp.SetLength(nthreads);
  457. ZZ atemp;
  458. ZZ btemp;
  459. ZZ_p zz_p_xr_temp;
  460. for (int t=0; t<nthreads; ++t)
  461. {
  462. atemp = astart[t];
  463. btemp = bstart[t];
  464. zz_p_xr_temp = zz_p_xr_start[t];
  465. // local_launchcount should be <= nlaunch
  466. for (int l = 0; l < nmult * local_launchcount; ++l)
  467. {
  468. unsigned int w = trunc_long(rep(zz_p_xr_temp), 32);
  469. if (w < TWO_32_DIV_3) {
  470. zz_p_xr_temp *= base;
  471. atemp++;
  472. } else if (w < TWO_32_DIV_3_X2) {
  473. zz_p_xr_temp *= target;
  474. btemp++;
  475. } else {
  476. zz_p_xr_temp *= zz_p_xr_temp * zz_p_r_inv;
  477. atemp += atemp;
  478. btemp += btemp;
  479. }
  480. if (atemp > order) atemp -= order;
  481. if (btemp > order) btemp -= order;
  482. ++totmult;
  483. }
  484. BytesFromZZ((unsigned char *) (l_z + t * WORDS), rep(zz_p_xr_temp), WORDS * sizeof(unsigned int));
  485. aexp[t] = atemp;
  486. bexp[t] = btemp;
  487. //cout << "zr = " << rep(zz_p_xr_temp) << "\n";
  488. //dump("z", l_z + t * WORDS, WORDS);
  489. }
  490. cudaMemcpy(l_ts, d_ts, nthreads * sizeof(GlobalThreadState), cudaMemcpyDeviceToHost);
  491. checkCUDAError("memcpy");
  492. int j = 0;
  493. for (int t = 0; t < nthreads; ++t)
  494. {
  495. unsigned int *l_Z = l_ts[t].x;
  496. for (int i = 0; i < WORDS; i++)
  497. {
  498. if (l_Z[i] != l_z[i + t * WORDS])
  499. {
  500. fail = true;
  501. cout << i << ": " << l_Z[i] << " != " << l_z[i + t * WORDS] << "\n";
  502. }
  503. }
  504. if (fail)
  505. {
  506. dump("d_z", l_Z, WORDS);
  507. dump("l_z", l_z + t * WORDS, WORDS);
  508. }
  509. ZZ ares = (to_ZZ(l_ts[t].a[2]) << 64) + (to_ZZ(l_ts[t].a[1]) << 32) + to_ZZ(l_ts[t].a[0]);
  510. ZZ bres = (to_ZZ(l_ts[t].b[2]) << 64) + (to_ZZ(l_ts[t].b[1]) << 32) + to_ZZ(l_ts[t].b[0]);
  511. if (ares != aexp[t] || bres != bexp[t]) {
  512. AtomicWriter atomic_cerr(cerr);
  513. atomic_cerr << "ares = " << ares << "\n";
  514. atomic_cerr << "aexp = " << aexp[t] << "\n";
  515. atomic_cerr << "bres = " << bres << "\n";
  516. atomic_cerr << "bexp = " << bexp[t] << "\n";
  517. }
  518. ++j;
  519. }
  520. if (!fail) {
  521. AtomicWriter(cerr) << "Results correct.\n";
  522. }
  523. #endif
  524. char timestamp[20];
  525. sprintf(timestamp, "%d.%06d", et.tv_sec, et.tv_usec);
  526. unsigned long long totnanos = totmicros * 1000;
  527. AtomicWriter(cout) << timestamp << ":" << output_prefix << ": " << totmicros << " us / " << nthreads << " = " << totmicros / nthreads << " us / " << (nmult*local_launchcount) << " = " << totnanos / ((unsigned long long)nthreads * nmult * local_launchcount) << " ns\n";
  528. cout.flush();
  529. //cudaPrintfEnd();
  530. DPstreamEnd();
  531. cudaFree(d_ts);
  532. free(rho);
  533. free(r_inv);
  534. free(r);
  535. free(l_ts);
  536. free(l_z);
  537. pbak.restore();
  538. *launch_count = local_launchcount;
  539. }
  540. #ifdef TEST_CUDA
  541. string output_prefix("test_cuda");
  542. typedef map<std::string, pair<ZZ,ZZ> > DTable;
  543. struct CBData {
  544. const ZZ_p &base;
  545. const ZZ_p &target;
  546. const ZZ &order;
  547. unsigned long long numdp;
  548. DTable dtable;
  549. bool found_collision;
  550. ZZ expon;
  551. CBData(const ZZ_p &_base, const ZZ_p &_target, const ZZ &_order) :
  552. base(_base), target(_target), order(_order), numdp(0),
  553. found_collision(false) {}
  554. };
  555. // This function is called from inside cuda_dl for each DP it encounters.
  556. // It calls the function named "dpcallback" directly. It would be
  557. // cleaner if this were passed as a function pointer to cuda_dl, but
  558. // that makes nvcc 3.1 segfault. :-p
  559. // dp points to an array of WORDS+7 unsigned ints:
  560. // - 1 word of threadID/blockID
  561. // - WORDS words of the dp value
  562. // - 3 words of a
  563. // - 3 words of b
  564. bool dpcallback(void *cbdata, unsigned int *dpwords)
  565. {
  566. CBData *d = (CBData*)cbdata;
  567. // WARNING: this assumes
  568. // sizeof(unsigned long) == sizeof(unsigned long long) !
  569. ZZ zz_a = to_ZZ(dpwords[WORDS+3]);
  570. zz_a <<= 32;
  571. zz_a += dpwords[WORDS+2];
  572. zz_a <<= 32;
  573. zz_a += dpwords[WORDS+1];
  574. ZZ zz_b = to_ZZ(dpwords[WORDS+6]);
  575. zz_b <<= 32;
  576. zz_b += dpwords[WORDS+5];
  577. zz_b <<= 32;
  578. zz_b += dpwords[WORDS+4];
  579. // ZZ_p dp = power(d->base, zz_a) * power(d->target, zz_b);
  580. // cerr << zz_a << " " << zz_b << " " << dp << "\n";
  581. // cerr << "DP " << ++(d->numdp) << "\r";
  582. pair<ZZ,ZZ> ab(zz_a,zz_b);
  583. pair<DTable::iterator, bool> res;
  584. string x((const char *)(dpwords+1), WORDS*sizeof(unsigned int));
  585. res = d->dtable.insert(DTable::value_type(x, ab));
  586. if (!res.second) {
  587. // Collision!
  588. ZZ adiff = to_ZZ(res.first->second.first) - zz_a;
  589. ZZ bdiff = zz_b - to_ZZ(res.first->second.second);
  590. if (bdiff < 0) bdiff += d->order;
  591. ZZ binv;
  592. if (InvModStatus(binv, bdiff, d->order) == 0) {
  593. d->expon = MulMod(binv, adiff, d->order);
  594. d->found_collision = true;
  595. } else {
  596. if (d->order > (1<<20)) {
  597. cerr << "Unhelpful collision\n";
  598. }
  599. }
  600. }
  601. return d->found_collision;
  602. }
  603. int main(int argc, char** argv)
  604. {
  605. #ifdef DERANDOMIZE
  606. SetSeed(to_ZZ(1));
  607. #else
  608. // Initialize the prng with some randomness from the kernel
  609. unsigned char randbuf[1024];
  610. ifstream urand("/dev/urandom");
  611. urand.read((char *) randbuf, sizeof(randbuf));
  612. urand.close();
  613. ZZ randzz = ZZFromBytes(randbuf, sizeof(randbuf));
  614. SetSeed(randzz);
  615. #endif
  616. ZZ rho, p, q;
  617. vec_ZZ pfvec, qfvec;
  618. cin >> rho >> p >> pfvec >> q >> qfvec;
  619. if (argc > 1) nthreads = atoi(argv[1]);
  620. if (argc > 2) nblocks = atoi(argv[2]);
  621. ZZ_p::init(p);
  622. for (int iter = 0; iter < 1; ++iter) {
  623. // Create the subproblem for the f'th factor of p-1
  624. int f = iter;
  625. ZZ remorder = (p-1)/pfvec[f];
  626. ZZ_p g = power(to_ZZ_p(2), remorder);
  627. ZZ_p y = power(random_ZZ_p(), remorder);
  628. // g should now be of order pfvec[0]. Check that.
  629. if (g == 1 || power(g, pfvec[f]) != 1) {
  630. cerr << "base has the wrong order!\n";
  631. exit(1);
  632. }
  633. // Try to find the DL_g of y
  634. cerr << "DL_" << g << "(" << y << ") mod " << p << "\n";
  635. CBData cbdata(g, y, pfvec[f]);
  636. unsigned int* launch_count;
  637. cuda_dl(g, y, pfvec[f], p, 4294967, &cbdata, &launch_count);
  638. cerr << "e = " << cbdata.expon << "\n";
  639. cerr << ( (power(g,cbdata.expon) == y) ? "CORRECT!" : "INCORRECT!" ) << "\n";
  640. }
  641. return 0;
  642. }
  643. #endif