parrhoasm.cu 20 KB

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