parrhoasm.cu 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  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. // #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[3], b[3];
  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,
  171. unsigned int order_0, unsigned int order_1, unsigned int order_2)
  172. // x <- x * y mod rho
  173. {
  174. // extern __shared__ unsigned int sharedmem[];
  175. register int i;
  176. register int tid = threadIdx.x + threadDimx * threadIdx.y;
  177. register int global_tid = tid + blockDim.x * blockDim.y * blockIdx.x;
  178. unsigned int a_0, a_1, a_2;
  179. unsigned int b_0, b_1, b_2;
  180. unsigned int *global_x_base = global_ts[global_tid].x;
  181. unsigned int *global_a_base = global_ts[global_tid].a;
  182. unsigned int *global_b_base = global_ts[global_tid].b;
  183. // unsigned int *shared_table_base = sharedmem;
  184. // unsigned int *shared_x_base = shared_table_base + threadIdx.y * 32 * (SIZE_X) + threadIdx.x;
  185. unsigned int xlow;
  186. // cuPrintf("d_z = %08X%08X%08X\n", global_x_base[2], global_x_base[1], global_x_base[0]);
  187. loadx(global_x_base);
  188. a_2 = global_a_base[2];
  189. a_1 = global_a_base[1];
  190. a_0 = global_a_base[0];
  191. b_2 = global_b_base[2];
  192. b_1 = global_b_base[1];
  193. b_0 = global_b_base[0];
  194. // cuPrintf("s_A = %08X\n", (unsigned int)a);
  195. // cuPrintf("s_B = %08X\n", (unsigned int)b);
  196. // cuPrintf("s_a = %08X%08X\n", global_a_base[1], global_a_base[0]);
  197. // cuPrintf("s_b = %08X%08X\n", global_b_base[1], global_b_base[0]);
  198. for (i = 0; i < nmult; ++i)
  199. {
  200. //memset(ts[tid].z, 0, (WORDS + 2) * sizeof(unsigned int));
  201. //__syncthreads();
  202. //cuPrintf("x = %p %08X%08X%08X\n", ts[tid].x, ts[tid].x[2], ts[tid].x[1], ts[tid].x[0]);
  203. //cuPrintf("y = %p %08X%08X\n", c_y, c_y[1], c_y[0]);
  204. //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]);
  205. int multtype;
  206. asm("mov.u32 %0, $xr0;" : "=r" (xlow));
  207. if (xlow < TWO_32_DIV_3)
  208. {
  209. multtype = 0;
  210. asm("add.cc.u32 %0, %1, %2;" : "=r"(a_0) : "r"(a_0), "r"((unsigned int)1U));
  211. asm("addc.cc.u32 %0, %1, %2;" : "=r"(a_1) : "r"(a_1), "r"((unsigned int)0U));
  212. asm("addc.u32 %0, %1, %2;" : "=r"(a_2) : "r"(a_2), "r"((unsigned int)0U));
  213. // a += 1;
  214. // cuPrintf("inc a\n");
  215. }
  216. else if (xlow < TWO_32_DIV_3_X2)
  217. {
  218. multtype = 1;
  219. asm("add.cc.u32 %0, %1, %2;" : "=r"(b_0) : "r"(b_0), "r"((unsigned int)1U));
  220. asm("addc.cc.u32 %0, %1, %2;" : "=r"(b_1) : "r"(b_1), "r"((unsigned int)0U));
  221. asm("addc.u32 %0, %1, %2;" : "=r"(b_2) : "r"(b_2), "r"((unsigned int)0U));
  222. // b += 1;
  223. // cuPrintf("inc b\n");
  224. }
  225. else
  226. {
  227. multtype = 2;
  228. asm("add.cc.u32 %0, %1, %2;" : "=r"(a_0) : "r"(a_0), "r"(a_0));
  229. asm("addc.cc.u32 %0, %1, %2;" : "=r"(a_1) : "r"(a_1), "r"(a_1));
  230. asm("addc.u32 %0, %1, %2;" : "=r"(a_2) : "r"(a_2), "r"(a_2));
  231. asm("add.cc.u32 %0, %1, %2;" : "=r"(b_0) : "r"(b_0), "r"(b_0));
  232. asm("addc.cc.u32 %0, %1, %2;" : "=r"(b_1) : "r"(b_1), "r"(b_1));
  233. asm("addc.u32 %0, %1, %2;" : "=r"(b_2) : "r"(b_2), "r"(b_2));
  234. // a += a;
  235. // b += b;
  236. // cuPrintf("double\n");
  237. }
  238. 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)))) {
  239. asm("sub.cc.u32 %0, %1, %2;" : "=r"(a_0) : "r"(a_0), "r"(order_0));
  240. asm("subc.cc.u32 %0, %1, %2;" : "=r"(a_1) : "r"(a_1), "r"(order_1));
  241. asm("subc.u32 %0, %1, %2;" : "=r"(a_2) : "r"(a_2), "r"(order_2));
  242. }
  243. 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)))) {
  244. asm("sub.cc.u32 %0, %1, %2;" : "=r"(b_0) : "r"(b_0), "r"(order_0));
  245. asm("subc.cc.u32 %0, %1, %2;" : "=r"(b_1) : "r"(b_1), "r"(order_1));
  246. asm("subc.u32 %0, %1, %2;" : "=r"(b_2) : "r"(b_2), "r"(order_2));
  247. }
  248. modmul(multtype);
  249. //memcpy(ts[tid].x, ts[tid].z, (WORDS + 1) * sizeof(unsigned int));
  250. /*
  251. if (_gt(shared_x_base)) {
  252. _sub(shared_x_base);
  253. }
  254. */
  255. //cuPrintf("y = %p %08X%08X\n", c_y, c_y[1], c_y[0]);
  256. //cuPrintf("z = %p %08X%08X\n", ts[tid].x, ts[tid].x[1], ts[tid].x[0]);
  257. //cuPrintf("y = %p %08X%08X\n", c_y, c_y[1], c_y[0]);
  258. // Check for a distinguished point
  259. asm("mov.u32 %0, $xr0;" : "=r" (xlow));
  260. if ((xlow & 0x000003ff) == 0 || !(order_2|order_1) && order_0 < (1<<20)) {
  261. DPstreamWrite(a_0,a_1,a_2,b_0,b_1,b_2);
  262. }
  263. }
  264. savex(global_x_base);
  265. global_a_base[0] = a_0;
  266. global_a_base[1] = a_1;
  267. global_a_base[2] = a_2;
  268. global_b_base[0] = b_0;
  269. global_b_base[1] = b_1;
  270. global_b_base[2] = b_2;
  271. // cuPrintf("d_z = %08X%08X%08X\n", global_x_base[2], global_x_base[1], global_x_base[0]);
  272. // cuPrintf("d_A = %08X\n", (unsigned int)a);
  273. // cuPrintf("d_B = %08X\n", (unsigned int)b);
  274. // cuPrintf("d_a = %08X%08X\n", global_a_base[1], global_a_base[0]);
  275. // cuPrintf("d_b = %08X%08X\n", global_b_base[1], global_b_base[0]);
  276. if (!(order_0|order_1|order_2)) evilhack();
  277. }
  278. int nthreads = 25600;
  279. int nblocks = 50;
  280. typedef map<std::string, pair<ZZ,ZZ> > DTable;
  281. struct CBData {
  282. const ZZ_p &base;
  283. const ZZ_p &target;
  284. const ZZ &order;
  285. unsigned long long numdp;
  286. DTable dtable;
  287. bool found_collision;
  288. ZZ expon;
  289. CBData(const ZZ_p &_base, const ZZ_p &_target, const ZZ &_order) :
  290. base(_base), target(_target), order(_order), numdp(0),
  291. found_collision(false) {}
  292. };
  293. static void dpcallback(void *cbdata, unsigned short threadId,
  294. unsigned short blockId, string x, unsigned int a_0, unsigned int a_1,
  295. unsigned int a_2, unsigned int b_0, unsigned int b_1, unsigned int b_2)
  296. {
  297. CBData *d = (CBData*)cbdata;
  298. // WARNING: this assumes
  299. // sizeof(unsigned long) == sizeof(unsigned long long) !
  300. ZZ zz_a = to_ZZ(a_2);
  301. zz_a <<= 32;
  302. zz_a += a_1;
  303. zz_a <<= 32;
  304. zz_a += a_0;
  305. ZZ zz_b = to_ZZ(b_2);
  306. zz_b <<= 32;
  307. zz_b += b_1;
  308. zz_b <<= 32;
  309. zz_b += b_0;
  310. //ZZ_p dp = power(d->base, zz_a) * power(d->target, zz_b);
  311. // cerr << "DP " << ++(d->numdp) << "\r";
  312. pair<ZZ,ZZ> ab(zz_a,zz_b);
  313. pair<DTable::iterator, bool> res;
  314. res = d->dtable.insert(DTable::value_type(x, ab));
  315. if (!res.second) {
  316. // Collision!
  317. ZZ adiff = to_ZZ(res.first->second.first) - zz_a;
  318. ZZ bdiff = zz_b - to_ZZ(res.first->second.second);
  319. if (bdiff < 0) bdiff += d->order;
  320. ZZ binv;
  321. if (InvModStatus(binv, bdiff, d->order) == 0) {
  322. d->expon = MulMod(binv, adiff, d->order);
  323. d->found_collision = true;
  324. } else {
  325. if (d->order > (1<<20)) {
  326. cerr << "Unhelpful collision\n";
  327. }
  328. }
  329. }
  330. }
  331. ZZ cuda_dl(const ZZ_p &base, const ZZ_p &target, const ZZ &order,
  332. const ZZ &modulus)
  333. {
  334. unsigned long long totmicros = 0;
  335. ZZ_pBak pbak;
  336. pbak.save();
  337. if (NumBits(modulus) <= ((WORDS-1)*BITS_PER_WORD) ||
  338. NumBits(modulus) > WORDS*BITS_PER_WORD) {
  339. cerr << "modulus is not " << WORDS << " words long.\n";
  340. exit(1);
  341. }
  342. long orderbits = NumBits(order);
  343. if (orderbits > 92) {
  344. cerr << "order is larger than 92 bits.\n";
  345. exit(1);
  346. }
  347. unsigned int order_2 = trunc_long(order >> 64, 32);
  348. unsigned int order_1 = trunc_long(order >> 32, 32);
  349. unsigned int order_0 = trunc_long(order, 32);
  350. /*
  351. cerr << "order = " << order << "\n";
  352. cerr << "orderll = " << orderll << "\n";
  353. */
  354. unsigned int *rho, rho_prime, *r, *r_inv;
  355. unsigned int l_y[SIZE_Y], l_g[SIZE_G];
  356. //cout << "rho = " << zz_rho << "\n";
  357. ZZ zz_r = (to_ZZ(1) << (WORDS * BITS_PER_WORD));
  358. ZZ_p::init(zz_r);
  359. ZZ_p zz_p_rho_prime = -to_ZZ_p(1) / to_ZZ_p(modulus);
  360. //cout << "rho_prime = " << zz_p_rho_prime << "\n";
  361. ZZ_p::init(modulus);
  362. ZZ_p zz_p_r, zz_p_r_inv;
  363. zz_p_r = to_ZZ_p(zz_r);
  364. zz_p_r_inv = to_ZZ_p(1) / zz_p_r;
  365. CBData cbdata(base, target, order);
  366. //cout << "r = " << zz_r << "\n";
  367. //cout << "r mod rho = " << rep(zz_p_r) << "\n";
  368. //cout << "r_inv = " << rep(zz_p_r_inv) << "\n";
  369. //cout << "r * r_inv = " << zz_p_r * zz_p_r_inv << "\n";
  370. //cout << "r * r_inv - rho * rho_prime = " << zz_r * rep(zz_p_r_inv) - zz_rho * rep(zz_p_rho_prime) << "\n";
  371. rho = (unsigned int*) calloc((WORDS + 1), sizeof(unsigned int));
  372. r = (unsigned int*) calloc((WORDS + 1), sizeof(unsigned int));
  373. r_inv = (unsigned int*) calloc((WORDS + 1), sizeof(unsigned int));
  374. BytesFromZZ((unsigned char *) rho, modulus, WORDS * sizeof(unsigned int));
  375. BytesFromZZ((unsigned char *) &rho_prime, rep(zz_p_rho_prime), sizeof(unsigned int));
  376. BytesFromZZ((unsigned char *) r, rep(zz_p_r), (WORDS + 1) * sizeof(unsigned int));
  377. BytesFromZZ((unsigned char *) r_inv, rep(zz_p_r_inv), (WORDS + 1) * sizeof(unsigned int));
  378. cudaMemcpyToSymbol(c_rho, rho, (WORDS + 1) * sizeof(unsigned int), 0, cudaMemcpyHostToDevice);
  379. cudaMemcpyToSymbol(c_rho_prime, &rho_prime, sizeof(unsigned int), 0, cudaMemcpyHostToDevice);
  380. cudaMemcpyToSymbol(c_r_inv, r_inv, (WORDS + 1) * sizeof(unsigned int), 0, cudaMemcpyHostToDevice);
  381. checkCUDAError("memcpytosymbol");
  382. /*
  383. if (nthreads % threadDimx) {
  384. nthreads /= threadDimx;
  385. nthreads *= threadDimx;
  386. cerr << "Truncating to " << nthreads << " threads.\n";
  387. }
  388. */
  389. if (nthreads % nblocks) {
  390. cerr << "Error: " << nthreads << " not a multiple of " << nblocks << "\n";
  391. exit(1);
  392. }
  393. const int threadsPerBlock = nthreads / nblocks;
  394. GlobalThreadState *d_ts;
  395. cudaMalloc((void **) &d_ts, nthreads * sizeof(GlobalThreadState));
  396. GlobalThreadState *l_ts;
  397. l_ts = (GlobalThreadState *) calloc(nthreads, sizeof(GlobalThreadState));
  398. unsigned int *l_z;
  399. l_z = (unsigned int *) calloc(nthreads, WORDS * sizeof(unsigned int));
  400. //cudaPrintfInit((1<<20)*16);
  401. DPstreamInit(1<<16);
  402. struct timeval st, et;
  403. memset(l_ts, 0, nthreads * sizeof(GlobalThreadState));
  404. memset(l_z, 0, WORDS * sizeof(unsigned int));
  405. //cout << "y = " << rep(zz_p_y) << "\n";
  406. ZZ_p zz_p_yr = target * zz_p_r;
  407. //cout << "y = " << rep(zz_p_y) << "\n";
  408. ZZ_p zz_p_gr = base * zz_p_r;
  409. BytesFromZZ((unsigned char *) l_y, rep(zz_p_yr), WORDS * sizeof(unsigned int));
  410. BytesFromZZ((unsigned char *) l_g, rep(zz_p_gr), WORDS * sizeof(unsigned int));
  411. cudaMemcpyToSymbol(c_y, l_y, (WORDS) * sizeof(unsigned int), 0, cudaMemcpyHostToDevice);
  412. cudaMemcpyToSymbol(c_g, l_g, (WORDS) * sizeof(unsigned int), 0, cudaMemcpyHostToDevice);
  413. //dump("y", l_y, WORDS);
  414. #ifdef CHECK_RESULTS
  415. int totmult = 0;
  416. bool fail = false;
  417. vec_ZZ aexp, bexp; // The expected values of a and b at completion
  418. aexp.SetLength(nthreads);
  419. bexp.SetLength(nthreads);
  420. #endif
  421. ZZ a = RandomBits_ZZ(orderbits-1);
  422. ZZ b = RandomBits_ZZ(orderbits-1);
  423. ZZ astep = RandomBits_ZZ(orderbits-1);
  424. ZZ bstep = RandomBits_ZZ(orderbits-1);
  425. ZZ_p zz_p_x = power(base, a) * power(target, b);
  426. ZZ_p zz_p_step = power(base, astep) * power(target, bstep);
  427. ZZ_p zz_p_xr = zz_p_x * zz_p_r;
  428. for (int t=0; t<nthreads; ++t)
  429. {
  430. zz_p_xr *= zz_p_step;
  431. a += astep;
  432. a %= order;
  433. b += bstep;
  434. b %= order;
  435. BytesFromZZ((unsigned char *) l_ts[t].x, rep(zz_p_xr), WORDS * sizeof(unsigned int));
  436. // dump("l_x", l_ts[t].x, WORDS);
  437. BytesFromZZ((unsigned char *) l_ts[t].a, a, 3 * sizeof(unsigned int));
  438. BytesFromZZ((unsigned char *) l_ts[t].b, b, 3 * sizeof(unsigned int));
  439. //dump("x", l_ts[t].x, WORDS);
  440. //cout << "x = " << rep(zz_p_x) << "\n";
  441. //cout << "xr = " << rep(zz_p_xr) << "\n";
  442. //dump("rho", rho, WORDS);
  443. #ifdef CHECK_RESULTS
  444. for (int l = 0; l < nmult * nlaunch; ++l)
  445. {
  446. unsigned int w = trunc_long(rep(zz_p_xr), 32);
  447. if (w < TWO_32_DIV_3) {
  448. zz_p_xr *= base;
  449. a++;
  450. } else if (w < TWO_32_DIV_3_X2) {
  451. zz_p_xr *= target;
  452. b++;
  453. } else {
  454. zz_p_xr *= zz_p_xr * zz_p_r_inv;
  455. a += a;
  456. b += b;
  457. }
  458. if (a > order) a -= order;
  459. if (b > order) b -= order;
  460. ++totmult;
  461. }
  462. BytesFromZZ((unsigned char *) (l_z + t * WORDS), rep(zz_p_xr), WORDS * sizeof(unsigned int));
  463. aexp[t] = a;
  464. bexp[t] = b;
  465. #endif
  466. //cout << "zr = " << rep(zz_p_xr) << "\n";
  467. //dump("z", l_z + t * WORDS, WORDS);
  468. }
  469. cudaMemcpy(d_ts, l_ts, nthreads * sizeof(GlobalThreadState), cudaMemcpyHostToDevice);
  470. dim3 tpb(threadDimx, threadsPerBlock/threadDimx);
  471. gettimeofday(&st, NULL);
  472. int launchcount = 0;
  473. #ifdef CHECK_RESULTS
  474. for (int ln=0; ln<nlaunch; ++ln)
  475. #else
  476. while(cbdata.found_collision == false)
  477. #endif
  478. {
  479. cerr << getpid() << " Launch " << ++launchcount << "...\n";
  480. cudaMulmod<<< nblocks, nthreads/nblocks /*tpb*/, 0 >>>(d_ts, order_0, order_1, order_2);
  481. cudaThreadSynchronize();
  482. checkCUDAError("kernel launch");
  483. DPstreamParse(&cbdata);
  484. //cudaPrintfExtractDPE(dpcallback, &cbdata);
  485. //cudaPrintfDisplay(stdout, true);
  486. cerr << getpid() << "\n";
  487. }
  488. gettimeofday(&et, NULL);
  489. totmicros = (unsigned long long)(et.tv_sec - st.tv_sec) * 1000000 + (et.tv_usec - st.tv_usec);
  490. #ifdef CHECK_RESULTS
  491. cudaMemcpy(l_ts, d_ts, nthreads * sizeof(GlobalThreadState), cudaMemcpyDeviceToHost);
  492. checkCUDAError("memcpy");
  493. int j = 0;
  494. for (int t = 0; t < nthreads; ++t)
  495. {
  496. unsigned int *l_Z = l_ts[t].x;
  497. for (int i = 0; i < WORDS; i++)
  498. {
  499. if (l_Z[i] != l_z[i + t * WORDS])
  500. {
  501. fail = true;
  502. cout << i << ": " << l_Z[i] << " != " << l_z[i + t * WORDS] << "\n";
  503. }
  504. }
  505. if (fail)
  506. {
  507. dump("d_z", l_Z, WORDS);
  508. dump("l_z", l_z + t * WORDS, WORDS);
  509. }
  510. ZZ ares = (to_ZZ(l_ts[t].a[1]) << 32) + to_ZZ(l_ts[t].a[0]);
  511. ZZ bres = (to_ZZ(l_ts[t].b[1]) << 32) + to_ZZ(l_ts[t].b[0]);
  512. if (ares != aexp[t] || bres != bexp[t]) {
  513. cerr << "ares = " << ares << "\n";
  514. cerr << "aexp = " << aexp[t] << "\n";
  515. cerr << "bres = " << bres << "\n";
  516. cerr << "bexp = " << bexp[t] << "\n";
  517. }
  518. ++j;
  519. }
  520. if (!fail) {
  521. cerr << "Results correct.\n";
  522. }
  523. #endif
  524. unsigned long long totnanos = totmicros * 1000;
  525. cout << totmicros << " us / " << nthreads << " = " << totmicros / nthreads << " us / " << (nmult*launchcount) << " = " << totnanos / ((unsigned long long)nthreads * nmult * launchcount) << " ns\n";
  526. //cudaPrintfEnd();
  527. DPstreamEnd();
  528. cudaFree(d_ts);
  529. free(rho);
  530. free(r_inv);
  531. free(r);
  532. free(l_ts);
  533. free(l_z);
  534. pbak.restore();
  535. return cbdata.expon;
  536. }
  537. #ifdef TEST_CUDA
  538. int main(int argc, char** argv)
  539. {
  540. #ifdef DERANDOMIZE
  541. SetSeed(to_ZZ(1));
  542. #else
  543. // Initialize the prng with some randomness from the kernel
  544. unsigned char randbuf[1024];
  545. ifstream urand("/dev/urandom");
  546. urand.read((char *) randbuf, sizeof(randbuf));
  547. urand.close();
  548. ZZ randzz = ZZFromBytes(randbuf, sizeof(randbuf));
  549. SetSeed(randzz);
  550. #endif
  551. ZZ rho, p, q;
  552. vec_ZZ pfvec, qfvec;
  553. cin >> rho >> p >> pfvec >> q >> qfvec;
  554. if (argc > 1) nthreads = atoi(argv[1]);
  555. if (argc > 2) nblocks = atoi(argv[2]);
  556. ZZ_p::init(p);
  557. for (int iter = 0; iter < 1; ++iter) {
  558. // Create the subproblem for the f'th factor of p-1
  559. int f = iter;
  560. ZZ remorder = (p-1)/pfvec[f];
  561. ZZ_p g = power(to_ZZ_p(2), remorder);
  562. ZZ_p y = power(random_ZZ_p(), remorder);
  563. // g should now be of order pfvec[0]. Check that.
  564. if (g == 1 || power(g, pfvec[f]) != 1) {
  565. cerr << "base has the wrong order!\n";
  566. exit(1);
  567. }
  568. // Try to find the DL_g of y
  569. cerr << "DL_" << g << "(" << y << ") mod " << p << "\n";
  570. ZZ e = cuda_dl(g, y, pfvec[f], p);
  571. cerr << "e = " << e << "\n";
  572. cerr << ( (power(g,e) == y) ? "CORRECT!" : "INCORRECT!" ) << "\n";
  573. }
  574. return 0;
  575. }
  576. #endif