SortingNetwork.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. #include <array>
  2. #include <sgx_tcrypto.h>
  3. #include "SortingNetwork.hpp"
  4. int num_oddevenmerge_comps(uint64_t N) {
  5. int logn = calculatelog2(N);
  6. return (N/4) * logn * logn - (N/4) * logn + N - 1;
  7. }
  8. // The input-output buffer must contain N decrypted blocks of length block_size bytes each.
  9. // Each block consists of a SN_KEY_SIZE-byte key followed by a (block_size-SN_KEY_SIZE)-byte data
  10. // block. The data will be sorted in-place ascending by key. block_size must be a multiple of 16.
  11. void OddEvenMergeSort(unsigned char *buf, uint64_t N, size_t block_size) {
  12. if(block_size==4){
  13. OddEvenMergeSort<OSWAP_4>(buf, N, block_size);
  14. } else if(block_size==8){
  15. OddEvenMergeSort<OSWAP_8>(buf, N, block_size);
  16. } else if(block_size==12){
  17. OddEvenMergeSort<OSWAP_12>(buf, N, block_size);
  18. } else if(block_size%16==0){
  19. OddEvenMergeSort<OSWAP_16X>(buf, N, block_size);
  20. } else{
  21. OddEvenMergeSort<OSWAP_8_16X>(buf, N, block_size);
  22. }
  23. }
  24. #if 0
  25. double DecryptAndOddEvenMergeSort(unsigned char *encrypted_buffer, uint64_t N,
  26. size_t encrypted_block_size, unsigned char *result_buffer) {
  27. long t1, t2;
  28. //ocall_clock(&t0);
  29. // Decrypt buffer to decrypted_buffer
  30. unsigned char *decrypted_buffer = NULL;
  31. size_t decrypted_block_size = decryptBuffer(encrypted_buffer, N, encrypted_block_size,
  32. &decrypted_buffer);
  33. ocall_clock(&t1);
  34. // Apply odd-even mergesort network
  35. PRB_pool_init(1);
  36. OddEvenMergeSort(decrypted_buffer, N, decrypted_block_size);
  37. ocall_clock(&t2);
  38. // Encrypt buffer to result_buffer
  39. encryptBuffer(decrypted_buffer, N, decrypted_block_size, result_buffer);
  40. PRB_pool_shutdown();
  41. //ocall_clock(&t3);
  42. // CLOCKS_PER_SEC == 1000000, so CLOCKS_PER_MS == 1000
  43. //double decryption_ms = ((double)(t1-t0))/1000.0;
  44. double compare_ms = ((double)(t2-t1))/1000.0;
  45. //double encryption_ms = ((double)(t3-t2))/1000.0;
  46. int num_comparisons = num_oddevenmerge_comps(N);
  47. //printf("Estimated comparisons for %d items: %d\n", N, num_comparisons);
  48. //printf("Counted comparisons for %d items: %d\n", N, OSWAP_COUNTER);
  49. //printf("Buffer decryption time: %lf ms\n", decryption_ms);
  50. //printf("Compare-and-swaps time: %lf ms\n", compare_ms);
  51. //printf("Buffer encryption time: %lf ms\n", encryption_ms);
  52. free(decrypted_buffer);
  53. return(compare_ms);
  54. }
  55. // NOTE: We don't need a _timed and non-timed one. If we dont keep SN Application. We can
  56. // just make _timed the only one and remove _timed from the name
  57. double DecryptAndOddEvenMergeSort_timed(unsigned char *encrypted_buffer, uint64_t N,
  58. size_t encrypted_block_size, unsigned char *result_buffer, enc_ret *ret) {
  59. long t1, t2;
  60. //ocall_clock(&t0);
  61. // Decrypt buffer to decrypted_buffer
  62. unsigned char *decrypted_buffer = NULL;
  63. size_t decrypted_block_size = decryptBuffer(encrypted_buffer, N, encrypted_block_size,
  64. &decrypted_buffer);
  65. ocall_clock(&t1);
  66. // Apply odd-even mergesort network
  67. PRB_pool_init(1);
  68. OddEvenMergeSort(decrypted_buffer, N, decrypted_block_size);
  69. ocall_clock(&t2);
  70. // Encrypt buffer to result_buffer
  71. encryptBuffer(decrypted_buffer, N, decrypted_block_size, result_buffer);
  72. PRB_pool_shutdown();
  73. //ocall_clock(&t3);
  74. // CLOCKS_PER_SEC == 1000000, so CLOCKS_PER_MS == 1000
  75. //double decryption_ms = ((double)(t1-t0))/1000.0;
  76. double compare_ms = ((double)(t2-t1))/1000.0;
  77. //double encryption_ms = ((double)(t3-t2))/1000.0;
  78. int num_comparisons = num_oddevenmerge_comps(N);
  79. //printf("Estimated comparisons for %d items: %d\n", N, num_comparisons);
  80. //printf("Counted comparisons for %d items: %d\n", N, OSWAP_COUNTER);
  81. //printf("Buffer decryption time: %lf ms\n", decryption_ms);
  82. //printf("Compare-and-swaps time: %lf ms\n", compare_ms);
  83. //printf("Buffer encryption time: %lf ms\n", encryption_ms);
  84. free(decrypted_buffer);
  85. ret->OSWAP_count = OSWAP_COUNTER;
  86. ret->ptime = compare_ms;
  87. return(compare_ms);
  88. }
  89. #endif
  90. /*
  91. ascend: 1 = ascending
  92. 0 = descending
  93. */
  94. //Same as BitonicSort but along with key swaps, swap associated_data based on the same flag.
  95. // NOTE: 1) We assume keys are limited to 8 byte values!
  96. // 2) We assume associated_data1 and associated_data2 have the same data_size! This helps set
  97. // the Oswap_Style cleanly!
  98. void BitonicSort(unsigned char *keys, size_t N, unsigned char *associated_data1, unsigned char *associated_data2, size_t data_size, bool ascend) {
  99. if(data_size==4){
  100. BitonicSort<OSWAP_4>(keys, N, associated_data1, associated_data2, data_size, ascend);
  101. } else if(data_size==8){
  102. BitonicSort<OSWAP_8>(keys, N, associated_data1, associated_data2, data_size, ascend);
  103. } else if (data_size%16==0){
  104. BitonicSort<OSWAP_16X>(keys, N, associated_data1, associated_data2, data_size, ascend);
  105. } else{
  106. BitonicSort<OSWAP_8_16X>(keys, N, associated_data1, associated_data2, data_size, ascend);
  107. }
  108. }
  109. void BitonicSort(unsigned char *buffer, size_t N, size_t block_size, bool ascend) {
  110. if(block_size==4){
  111. BitonicSort<OSWAP_4>(buffer, N, block_size, ascend);
  112. } else if(block_size==8){
  113. BitonicSort<OSWAP_8>(buffer, N, block_size, ascend);
  114. } else if(block_size==12){
  115. BitonicSort<OSWAP_12>(buffer, N, block_size, ascend);
  116. } else if (block_size%16==0){
  117. BitonicSort<OSWAP_16X>(buffer, N, block_size, ascend);
  118. }
  119. else{
  120. BitonicSort<OSWAP_8_16X>(buffer, N, block_size, ascend);
  121. }
  122. }
  123. #if 0
  124. //TODO: Take this off, if we no longer plan to support SN_App!
  125. double DecryptAndBitonicSort(unsigned char *encrypted_buffer, uint64_t N, size_t encrypted_block_size,
  126. unsigned char *result_buffer) {
  127. long t1, t2;
  128. // Decrypt buffer to decrypted_buffer
  129. unsigned char *decrypted_buffer = NULL;
  130. size_t decrypted_block_size = decryptBuffer(encrypted_buffer, N, encrypted_block_size,
  131. &decrypted_buffer);
  132. ocall_clock(&t1);
  133. // Apply odd-even mergesort network
  134. //PRB_pool_init(1);
  135. BitonicSort(decrypted_buffer, N, decrypted_block_size, true);
  136. ocall_clock(&t2);
  137. // Encrypt buffer to result_buffer
  138. encryptBuffer(decrypted_buffer, N, decrypted_block_size, result_buffer);
  139. //PRB_pool_shutdown();
  140. // CLOCKS_PER_SEC == 1000000, so CLOCKS_PER_MS == 1000
  141. double compare_ms = ((double)(t2-t1))/1000.0;
  142. free(decrypted_buffer);
  143. return(compare_ms);
  144. }
  145. double DecryptAndBitonicSort(unsigned char *encrypted_buffer, uint64_t N, size_t encrypted_block_size,
  146. unsigned char *result_buffer, enc_ret *ret) {
  147. long t1, t2;
  148. // Decrypt buffer to decrypted_buffer
  149. unsigned char *decrypted_buffer = NULL;
  150. size_t decrypted_block_size = decryptBuffer(encrypted_buffer, N, encrypted_block_size,
  151. &decrypted_buffer);
  152. ocall_clock(&t1);
  153. memcpy(result_buffer, decrypted_buffer, N*decrypted_block_size);
  154. // Apply odd-even mergesort network
  155. PRB_pool_init(1);
  156. BitonicSort(decrypted_buffer, N, decrypted_block_size, true);
  157. //BitonicSort(decrypted_buffer, N, result_buffer, NULL, decrypted_block_size, true);
  158. ocall_clock(&t2);
  159. // Encrypt buffer to result_buffer
  160. encryptBuffer(decrypted_buffer, N, decrypted_block_size, result_buffer);
  161. PRB_pool_shutdown();
  162. // CLOCKS_PER_SEC == 1000000, so CLOCKS_PER_MS == 1000
  163. double compare_ms = ((double)(t2-t1))/1000.0;
  164. free(decrypted_buffer);
  165. ret->OSWAP_count = OSWAP_COUNTER;
  166. ret->ptime = compare_ms;
  167. return(compare_ms);
  168. }
  169. double DecryptAndOddEvenMergeSortShuffle(unsigned char *encrypted_buffer, uint64_t N, size_t encrypted_block_size,
  170. unsigned char *result_buffer, enc_ret *ret) {
  171. long t1, t2;
  172. //ocall_clock(&t0);
  173. // Decrypt buffer to decrypted_buffer
  174. PRB_pool_init(1);
  175. unsigned char *decrypted_buffer = NULL;
  176. unsigned char *random_bytes = new unsigned char[8*N];
  177. getBulkRandomBytes(random_bytes, 8*N);
  178. size_t decrypted_block_size = decryptBuffer_attachRTags(encrypted_buffer, N, encrypted_block_size,
  179. random_bytes, &decrypted_buffer);
  180. ocall_clock(&t1);
  181. // Apply odd-even mergesort network
  182. OddEvenMergeSort(decrypted_buffer, N, decrypted_block_size);
  183. ocall_clock(&t2);
  184. // Encrypt buffer to result_buffer
  185. encryptBuffer_removeRTags(decrypted_buffer, N, decrypted_block_size, result_buffer);
  186. PRB_pool_shutdown();
  187. // CLOCKS_PER_SEC == 1000000, so CLOCKS_PER_MS == 1000
  188. double compare_ms = ((double)(t2-t1))/1000.0;
  189. free(decrypted_buffer);
  190. delete []random_bytes;
  191. ret->OSWAP_count = OSWAP_COUNTER;
  192. ret->ptime = compare_ms;
  193. return(compare_ms);
  194. }
  195. double DecryptAndBitonicSortShuffle(unsigned char *encrypted_buffer, uint64_t N,
  196. size_t encrypted_block_size, unsigned char *result_buffer, enc_ret *ret) {
  197. long t1, t2;
  198. // Decrypt buffer to decrypted_buffer
  199. PRB_pool_init(1);
  200. unsigned char *decrypted_buffer = NULL;
  201. size_t rsize = 8 * (size_t) N;
  202. unsigned char *random_bytes = (unsigned char*) malloc(rsize);
  203. if(random_bytes == NULL)
  204. printf("Failed to allocate random_bytes in D&BSS\n");
  205. getBulkRandomBytes(random_bytes, rsize);
  206. size_t decrypted_block_size = decryptBuffer_attachRTags(encrypted_buffer, N,
  207. encrypted_block_size, random_bytes, &decrypted_buffer);
  208. ocall_clock(&t1);
  209. // Apply odd-even mergesort network
  210. // NOTE: We will never have decrypted_block_size==8, since attaching rTag will add 8 bytes.
  211. // So minimum block_size here is 16
  212. BitonicSort(decrypted_buffer, N, decrypted_block_size, true);
  213. ocall_clock(&t2);
  214. // Encrypt buffer to result_buffer
  215. encryptBuffer_removeRTags(decrypted_buffer, N, decrypted_block_size, result_buffer);
  216. PRB_pool_shutdown();
  217. // CLOCKS_PER_SEC == 1000000, so CLOCKS_PER_MS == 1000
  218. double compare_ms = ((double)(t2-t1))/1000.0;
  219. free(decrypted_buffer);
  220. free(random_bytes);
  221. ret->OSWAP_count = OSWAP_COUNTER;
  222. ret->ptime = compare_ms;
  223. return(compare_ms);
  224. }
  225. void testBitonicSort(){
  226. size_t N = 10;
  227. // Test the normal version of bitonic sort; each data item is a 16-byte key and two 8-byte integers
  228. unsigned char *data = new unsigned char[N*(16+8+8)];
  229. PRB_pool_init(1);
  230. for(size_t i=0; i<N; i++){
  231. unsigned char *item = data+(i*(16+8+8));
  232. getRandomBytes((unsigned char*)item, 16);
  233. *(uint64_t*)(item+16) = i;
  234. *(uint64_t*)(item+24) = N-i;
  235. }
  236. PRB_pool_shutdown();
  237. printf("Before BitonicSort\n");
  238. for(size_t i=0; i<N; i++){
  239. unsigned char *item = data+(i*(16+8+8));
  240. printf("(");
  241. for (size_t j=0; j<16; ++j) { printf("%02x", item[15-j]); }
  242. printf(", %d, %d)\n", *(uint64_t*)(item+16), *(uint64_t*)(item+24));
  243. }
  244. printf("\n");
  245. BitonicSort<OSWAP_16X, __uint128_t>((unsigned char*) data, N, 16+8+8, true);
  246. printf("After BitonicSort\n");
  247. for(size_t i=0; i<N; i++){
  248. unsigned char *item = data+(i*(16+8+8));
  249. printf("(");
  250. for (size_t j=0; j<16; ++j) { printf("%02x", item[15-j]); }
  251. printf(", %d, %d)\n", *(uint64_t*)(item+16), *(uint64_t*)(item+24));
  252. }
  253. printf("\n");
  254. printf("\n\n\n");
  255. delete []data;
  256. // Test the associated data version of bitonic sort
  257. __uint128_t *key_array = new __uint128_t[N];
  258. uint64_t *ass_data1 = new uint64_t[N];
  259. uint64_t *ass_data2 = new uint64_t[N];
  260. PRB_pool_init(1);
  261. for(size_t i=0; i<N; i++){
  262. size_t random_coin;
  263. getRandomBytes((unsigned char*) (key_array+i), 16);
  264. ass_data1[i] = i;
  265. ass_data2[i] = N-i;
  266. }
  267. PRB_pool_shutdown();
  268. printf("Before BitonicSort (with associated data)\n");
  269. for(size_t i=0; i<N; i++){
  270. printf("(");
  271. for (size_t j=0; j<16; ++j) { printf("%02x", ((unsigned char*)(key_array+i))[15-j]); }
  272. printf(", %d, %d)\n", ass_data1[i], ass_data2[i]);
  273. }
  274. printf("\n");
  275. BitonicSort<OSWAP_8, __uint128_t>((unsigned char*) key_array, N, (unsigned char*)ass_data1,
  276. (unsigned char*) ass_data2, 8, true);
  277. printf("After BitonicSort (with associated data)\n");
  278. for(size_t i=0; i<N; i++){
  279. printf("(");
  280. for (size_t j=0; j<16; ++j) { printf("%02x", ((unsigned char*)(key_array+i))[15-j]); }
  281. printf(", %d, %d)\n", ass_data1[i], ass_data2[i]);
  282. }
  283. printf("\n\n\n");
  284. delete []key_array;
  285. delete []ass_data1;
  286. delete []ass_data2;
  287. }
  288. #endif