Browse Source

Initial commit for xpir as a library

Marc-Olivier Killijian 8 years ago
commit
ab85ef48b1
100 changed files with 17018 additions and 0 deletions
  1. 2 0
      .gitignore
  2. 37 0
      CMakeCompilers.txt
  3. 61 0
      CMakeLists.txt
  4. 24 0
      FindGMP.cmake
  5. 18 0
      FindMPFR.cmake
  6. 674 0
      GPL-3.0
  7. 33 0
      LICENSE
  8. 120 0
      README.md
  9. 5 0
      TODO.txt
  10. 24 0
      apps/CMakeLists.txt
  11. 14 0
      apps/client/CMakeLists.txt
  12. 189 0
      apps/client/DESC.cpp
  13. 55 0
      apps/client/DESC.hpp
  14. 508 0
      apps/client/PIRClient.cpp
  15. 122 0
      apps/client/PIRClient.hpp
  16. 111 0
      apps/client/PIRClientLog.cpp
  17. 42 0
      apps/client/PIRClientLog.hpp
  18. 69 0
      apps/client/PIRController.cpp
  19. 47 0
      apps/client/PIRController.hpp
  20. 33 0
      apps/client/PIRView.cpp
  21. 51 0
      apps/client/PIRView.hpp
  22. 162 0
      apps/client/PIRViewCLI.cpp
  23. 48 0
      apps/client/PIRViewCLI.hpp
  24. 418 0
      apps/client/main.cpp
  25. 35 0
      apps/client/main.hpp
  26. 6 0
      apps/optim/CMakeLists.txt
  27. 1069 0
      apps/optim/PIROptimizer.cpp
  28. 148 0
      apps/optim/PIROptimizer.hpp
  29. 54 0
      apps/server/CMakeLists.txt
  30. 238 0
      apps/server/DBDirectoryProcessor.cpp
  31. 67 0
      apps/server/DBDirectoryProcessor.hpp
  32. 111 0
      apps/server/DBGenerator.cpp
  33. 52 0
      apps/server/DBGenerator.hpp
  34. 47 0
      apps/server/DBHandler.hpp
  35. 134 0
      apps/server/PIRServer.cpp
  36. 59 0
      apps/server/PIRServer.hpp
  37. 623 0
      apps/server/PIRSession.cpp
  38. 108 0
      apps/server/PIRSession.hpp
  39. 75 0
      apps/server/ServerService.cpp
  40. 37 0
      apps/server/ServerService.hpp
  41. 126 0
      apps/server/main.cpp
  42. 37 0
      apps/server/main.hpp
  43. 29 0
      apps/simplepir/CMakeLists.txt
  44. 241 0
      apps/simplepir/simplePIR.cpp
  45. 273 0
      apps/tools/check-correctness.sh
  46. 29 0
      apps/tools/makedb.sh
  47. 82 0
      apps/tools/mkdb-correctness.sh
  48. 19 0
      crypto/AbstractPublicParameters.cpp
  49. 46 0
      crypto/AbstractPublicParameters.hpp
  50. 34 0
      crypto/CMakeLists.txt
  51. 35 0
      crypto/CryptographicSystem.hpp
  52. 24 0
      crypto/HomomorphicCrypto.cpp
  53. 69 0
      crypto/HomomorphicCrypto.hpp
  54. 87 0
      crypto/HomomorphicCryptoFactory_internal.cpp
  55. 37 0
      crypto/HomomorphicCryptoFactory_internal.hpp
  56. 32 0
      crypto/LatticesBasedCryptosystem.cpp
  57. 53 0
      crypto/LatticesBasedCryptosystem.hpp
  58. 850 0
      crypto/NFLLWE.cpp
  59. 118 0
      crypto/NFLLWE.hpp
  60. 38 0
      crypto/NFLLWEDatatypes.hpp
  61. 171 0
      crypto/NFLLWEPublicParameters.cpp
  62. 81 0
      crypto/NFLLWEPublicParameters.hpp
  63. 46 0
      crypto/NFLParams.cpp
  64. 44 0
      crypto/NFLParams.hpp
  65. 922 0
      crypto/NFLlib.cpp
  66. 655 0
      crypto/NFLlib.hpp
  67. 88 0
      crypto/NoCryptography.cpp
  68. 52 0
      crypto/NoCryptography.hpp
  69. 40 0
      crypto/NoCryptographyPublicParameters.cpp
  70. 45 0
      crypto/NoCryptographyPublicParameters.hpp
  71. 27 0
      crypto/PRNGInterface.hpp
  72. 630 0
      crypto/PaillierAdapter.cpp
  73. 97 0
      crypto/PaillierAdapter.hpp
  74. 187 0
      crypto/PaillierKeys.cpp
  75. 72 0
      crypto/PaillierKeys.hpp
  76. 30 0
      crypto/PaillierPrivateParameters.cpp
  77. 34 0
      crypto/PaillierPrivateParameters.hpp
  78. 142 0
      crypto/PaillierPublicParameters.cpp
  79. 60 0
      crypto/PaillierPublicParameters.hpp
  80. 6 0
      crypto/prng/CMakeLists.txt
  81. 27 0
      crypto/prng/crypto_stream_salsa20.h
  82. 4827 0
      crypto/prng/crypto_stream_salsa20_amd64_xmm6.s
  83. 48 0
      crypto/prng/fastrandombytes.cpp
  84. 12 0
      crypto/prng/fastrandombytes.h
  85. 39 0
      crypto/prng/randombytes.cpp
  86. 11 0
      crypto/prng/randombytes.h
  87. 40 0
      helper_script.sh
  88. 226 0
      libpir.hpp
  89. 23 0
      pir/BasicLWECommon.hpp
  90. 39 0
      pir/CMakeLists.txt
  91. 23 0
      pir/ClientDefines.hpp
  92. 30 0
      pir/GlobalConstant.hpp
  93. 23 0
      pir/PIROptimizerCommand.hpp
  94. 31 0
      pir/PIRParameters.hpp
  95. 23 0
      pir/PIRParametersExchangeMethods.hpp
  96. 6 0
      pir/events/CMakeLists.txt
  97. 27 0
      pir/events/CatalogEvent.cpp
  98. 36 0
      pir/events/CatalogEvent.hpp
  99. 62 0
      pir/events/MessageEvent.cpp
  100. 47 0
      pir/events/MessageEvent.hpp

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+/local/
+/_build/

+ 37 - 0
CMakeCompilers.txt

@@ -0,0 +1,37 @@
+include(CheckCXXCompilerFlag)
+
+# C++11 support
+CHECK_CXX_COMPILER_FLAG(-std=c++11 COMPILER_SUPPORTS_CXX11)
+if(COMPILER_SUPPORTS_CXX11)
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+else()
+    CHECK_CXX_COMPILER_FLAG(-std=c++0x COMPILER_SUPPORTS_CXX0X)
+    if(COMPILER_SUPPORTS_CXX0X)
+        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
+    else()
+        message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
+    endif()
+endif()
+
+# Use openmp
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp")
+set(CMAKE_EXE_LINKER_FLAGS "-fopenmp")
+
+# optimization flags support
+if(CMAKE_BUILD_TYPE MATCHES Release)
+	set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O3")
+	foreach(FLAG -march=native -mtune=native -funroll-loops)
+		string(REGEX REPLACE -= _ FLAG_ID ${FLAG})
+		string(TOUPPER ${FLAG_ID} FLAG_ID)
+		CHECK_CXX_COMPILER_FLAG(${FLAG} COMPILER_SUPPORTS${FLAG_ID})
+	    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${FLAG}")
+	endforeach()
+  # For OSX use clang
+  if(APPLE)
+	    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -mfpmath=sse -Wa,-q")
+  endif()
+else()
+    add_definitions(-DCHECK_STRICTMOD)
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb")
+endif()
+

+ 61 - 0
CMakeLists.txt

@@ -0,0 +1,61 @@
+cmake_minimum_required(VERSION 2.6.0)
+project(XPIR)
+include(CMakeCompilers.txt)
+
+enable_language(CXX ASM)
+
+if(APPLE)
+    cmake_policy(SET CMP0042 NEW)
+endif()
+
+set(CMAKE_C_COMPILER "gcc")
+set(CMAKE_CXX_COMPILER "g++")
+set(CMAKE_CXX_FLAGS "-std=c++11 -fopenmp -ggdb")
+set(CMAKE_EXE_LINKER_FLAGS "-fopenmp")
+set(BOOST_ROOT "./local")
+
+SET( Boost_USE_STATIC_LIBS FALSE )
+find_package(Boost 1.55.0  REQUIRED
+  COMPONENTS atomic chrono date_time exception program_options regex system thread)
+include_directories(${Boost_INCLUDE_DIR})
+link_directories(${Boost_LIBRARY_DIR})
+	
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR})
+find_package(GMP 6 REQUIRED)
+find_package(MPFR 3.1.2 REQUIRED)
+
+include_directories("/opt/local/include")
+
+	option(SEND_CATALOG "Send the catalog to the client (default is send catalog if |catalog|<1000)" ON)
+	if(SEND_CATALOG)
+	    message(STATUS "Send the catalog to the client")
+	    add_definitions(-DSEND_CATALOG)
+    else()
+	    message(STATUS "Do not send the catalog to the client")	
+	endif()
+	
+	option(MULTI_THREAD "Use multi-threading" ON)
+	if(MULTI_THREAD)
+	    message(STATUS "Use multi-threading")
+	    add_definitions(-DMULTI_THREAD)
+	else()
+	    message(STATUS "Do not use multi-threading")		
+	endif()
+	
+	option(PERF_TIMERS "Show performance measurements during execution" ON)
+	if(PERF_TIMERS)
+	    message(STATUS "Show performance measurements during execution")
+	    add_definitions(-DPERF_TIMERS)
+	else()
+	    message(STATUS "Do not show performance measurements during execution")
+	endif()
+
+
+
+
+	add_subdirectory("apps")
+	add_subdirectory("crypto")
+	add_subdirectory("pir")
+	
+	
+

+ 24 - 0
FindGMP.cmake

@@ -0,0 +1,24 @@
+# Try to find the GMP librairies
+# GMP_FOUND - system has GMP lib
+# GMP_INCLUDE_DIR - the GMP include directory
+# GMP_LIBRARIES - Libraries needed to use GMP
+
+# Copyright (c) 2006, Laurent Montel, <montel@kde.org>
+#
+# Redistribution and use is allowed according to the terms of the BSD
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+if (GMP_INCLUDE_DIR AND GMP_LIBRARIES)
+		# Already in cache, be silent
+		set(GMP_FIND_QUIETLY TRUE)
+endif (GMP_INCLUDE_DIR AND GMP_LIBRARIES)
+
+find_path(GMP_INCLUDE_DIR NAMES gmp.h HINTS "./local/include")
+find_library(GMP_LIBRARIES NAMES gmp libgmp HINTS "./local/lib")
+find_library(GMPXX_LIBRARIES NAMES gmpxx libgmpxx HINTS "./local/lib")
+MESSAGE(STATUS "GMP libs: " ${GMP_LIBRARIES} " " ${GMPXX_LIBRARIES} )
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GMP DEFAULT_MSG GMP_INCLUDE_DIR GMP_LIBRARIES)
+
+mark_as_advanced(GMP_INCLUDE_DIR GMP_LIBRARIES)

+ 18 - 0
FindMPFR.cmake

@@ -0,0 +1,18 @@
+# Try to find the MPFR librairies
+# GMP_FOUND - system has GMP lib
+# GMP_INCLUDE_DIR - the GMP include directory
+# GMP_LIBRARIES - Libraries needed to use GMP
+
+if (MPFR_INCLUDE_DIR AND MPFR_LIBRARIES)
+		# Already in cache, be silent
+		set(MPFR_FIND_QUIETLY TRUE)
+endif (MPFR_INCLUDE_DIR AND MPFR_LIBRARIES)
+
+find_path(MPFR_INCLUDE_DIR NAMES mpfr.h HINTS "./local/include")
+find_library(MPFR_LIBRARIES NAMES mpfr libmpfr HINTS "./local/lib")
+MESSAGE(STATUS "mpfr libs: " ${MPFR_LIBRARIES})
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(MPFR DEFAULT_MSG MPFR_INCLUDE_DIR MPFR_LIBRARIES)
+
+mark_as_advanced(MPFR_INCLUDE_DIR MPFR_LIBRARIES)

+ 674 - 0
GPL-3.0

@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.

+ 33 - 0
LICENSE

@@ -0,0 +1,33 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+The files in this project are released under various licenses, all of
+them compatible with the GPLv3.
+
+The dependencies directory at the root of the project contains: a full
+version of the GMP library; a full version of the MPFR library; and a
+subpart of the Boost library (extracted with their internal tool
+bcp). Licensing rules for the associated files are given directly in
+the corresponding directories. GMP and MPFR are released under GPLv3
+and Boost under Boost license which is compatible with GPLv3.
+
+For the rest of the project files, most are released under the GPLv3
+itself, but we reused some pieces of code sometimes, which are either
+under a BSD license, or in the public domain. Outside of the
+dependencies directory named above, the license for each file is given
+at the beggining of the file.
+

File diff suppressed because it is too large
+ 120 - 0
README.md


+ 5 - 0
TODO.txt

@@ -0,0 +1,5 @@
+  * verifier les makefiles originaux pour etre surs qu on oublie rien qu on faisait en master
+  
+  * verifier d'autres archi/install systeme (osx par exemple en particulier là ou il traine des $home)
+  * gerer la compilation release en OSX
+

+ 24 - 0
apps/CMakeLists.txt

@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 2.6.0)
+
+add_subdirectory("client")
+add_subdirectory("optim")
+add_subdirectory("server")
+add_subdirectory("simplepir")
+
+set(CMAKE_CXX_FLAGS "-std=c++11")
+set (CMAKE_EXE_LINKER_FLAGS "-fopenmp")
+if (APPLE)
+        set(CMAKE_EXE_LINKER_FLAGS "-fopenmp -L$ENV{HOME}/Code/xpir/freshxpir/xpir-ng/local/lib/ -lboost_program_options")
+
+endif()
+include_directories(..)
+include_directories(../..)
+
+add_custom_target(build-time-make-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "server/db")
+add_custom_target(build-time-make-directory1 ALL COMMAND ${CMAKE_COMMAND} -E make_directory "server/exp")
+add_custom_target(build-time-make-directory2 ALL COMMAND ${CMAKE_COMMAND} -E make_directory "client/reception")
+add_custom_target(build-time-make-directory3 ALL COMMAND ${CMAKE_COMMAND} -E make_directory "client/exp")
+
+#add_executable(simple_pir simplePIR.cpp ../pir/libpir.hpp ./server/DBGenerator.cpp ./server/DBDirectoryProcessor.cpp)
+
+#target_link_libraries(simple_pir pir_server_pir pir_query_gen pir_reply pir pir_client_events pir_client_optim pthread ${MPFR_LIBRARIES} ${Boost_LIBRARIES} ${GMP_LIBRARIES} ${GMPXX_LIBRARIES})

+ 14 - 0
apps/client/CMakeLists.txt

@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 2.6.0)
+
+set (CMAKE_EXE_LINKER_FLAGS "-fopenmp") 
+if (APPLE)
+	set(CMAKE_EXE_LINKER_FLAGS "-fopenmp -L$ENV{HOME}/Code/xpir/freshxpir/xpir-ng/local/lib/ -lboost_program_options")
+
+endif()
+include_directories(..)
+include_directories(../..)
+
+add_executable(pir_client DESC.cpp PIRClient.cpp PIRClientLog.cpp PIRController.cpp PIRView.cpp PIRViewCLI.cpp main.cpp)
+
+target_link_libraries(pir_client pir_client_optim pir pthread ${MPFR_LIBRARIES} ${Boost_LIBRARIES} ${GMP_LIBRARIES} ${GMPXX_LIBRARIES})
+

+ 189 - 0
apps/client/DESC.cpp

@@ -0,0 +1,189 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "DESC.hpp"
+//#define NO_CATALOG //Use this option for performance tests (only with auto-choice)
+
+/**
+ *	Class constructor.
+ *	Param :
+ *		-	messageListener& messageListeners_ : message listerner reference to display error message.
+ **/
+DESC::DESC(messageListener& messageListeners_):
+	messageListeners(messageListeners_),
+	maxFileSize(0)
+{
+    ; // This semicolon is necessary under some uncertain circumstances .... e.g. OSX/gcc4.8.1
+}
+
+/**
+ *	Generate a menu from a char* buffer.
+ *	Param :
+ *		- char* receiveBuffer : buffer to parse.
+ **/
+void DESC::makeMenu(char* receivedBuffer)
+{
+	maxFileSize = 0;
+	uint64_t fileCount = 0;
+	char fileName[FILENAME_MAX_BYTE_SIZE + 1];
+	char tmpSize[FILENAME_MAX_BYTE_SIZE + 1];
+	stringstream ss (receivedBuffer);
+	unsigned int catalogType;
+#ifdef DEBUG
+  std::cout << "DESC: catalog received : ..."<<std::endl<<receivedBuffer<<std::endl;
+#endif
+	if (ss.good ())
+	{
+		//The first line of the catalog is the catalog type
+		ss >> catalogType;
+		if(catalogType==0) {
+#ifdef DEBUG
+			std::cout << "DESC: catalog type 0 : "<<catalogType<<std::endl;
+#endif		
+			ss >> fileCount;
+			//The rest of catalog alternates filename lines and size lines.
+			ss.getline (fileName, FILENAME_MAX_BYTE_SIZE);
+
+      nbFiles = 0;
+			for (uint64_t i = 0; i < fileCount; i++) 
+			{
+				ss.getline (fileName, FILENAME_MAX_BYTE_SIZE);
+				ss.getline (tmpSize, FILENAME_MAX_BYTE_SIZE);
+
+				if (ss.gcount () > 0) 
+				{
+					fileList.push_back(fileName);
+					fileSize.push_back(atoi(tmpSize));
+          nbFiles++;
+#ifdef DEBUG
+          std::cout<<"DESC: "<<i<<"-"<<fileName<<"-"<<tmpSize<<std::endl;
+#endif
+          if(maxFileSize < fileSize.back())
+						maxFileSize = fileSize.back();
+				}
+			}
+		} else if(catalogType==1) {
+#ifdef DEBUG
+			std::cout << "DESC: catalog type 0 : "<<catalogType<<std::endl;
+#endif		
+			
+			ss >> fileCount;
+			ss.getline (tmpSize, FILENAME_MAX_BYTE_SIZE);
+			ss.getline (tmpSize, FILENAME_MAX_BYTE_SIZE);
+			maxFileSize=atoi(tmpSize);
+#ifndef NO_CATALOG
+      for (uint64_t i = 0; i < fileCount; i++) 
+			{
+					fileList.push_back(std::to_string(i));
+					fileSize.push_back(maxFileSize);
+			}
+#endif
+      nbFiles = fileCount;
+		} else {
+			MessageEvent event(ERROR,"Catalog type unknown "+catalogType, __FUNCTION__);
+			messageListeners(event);
+		}
+	} else {
+			MessageEvent event(ERROR,"Impossible to read catalog from the server.", __FUNCTION__);
+			messageListeners(event);
+	}
+}
+
+/**
+ *	Get file name from a given index.
+ *	Param :
+ *		- int index : file index.
+ *
+ *	Return :
+ *		- std::string : return fileName if exist and "None" else.
+ **/
+string DESC::getFileName(uint64_t index) 
+{
+#ifndef NO_CATALOG
+	return (index < nbFiles) ?  fileList[index] : "None";
+#else
+	return (index < nbFiles) ?  std::to_string(index) : "None";
+#endif
+}
+
+/**
+ *	Get file size frome a given index.
+ *	Param :
+ *		- int index : file index.
+ *
+ *	Return :
+ *		- int : return fileSize of exist and 0 else.
+ *
+ **/
+uint64_t DESC::getFileSize(uint64_t index) 
+{
+#ifndef NO_CATALOG
+	return (index < fileSize.size()) ? fileSize[index] : -1;
+#else
+	return (index < nbFiles) ? maxFileSize : -1;
+#endif
+}
+
+/**
+ *	Checks whether the provided file number exists. 
+ *	Param : 
+ *		- int dex : file index.
+ *
+ *	Return :
+ *		- bool : true if file exist, false else.
+ **/
+bool DESC::file_exists (uint64_t index) 
+{
+	return (index < nbFiles) ? true : false; 
+}
+
+/**
+ *	Get number of files.
+ *	Return :
+ *		- unsigned int : number of files.
+ **/
+uint64_t DESC::getFilesNum() 
+{
+	return nbFiles;
+}
+
+/**
+ *	Get the biggest file.
+ *	Return :
+ *		- int : biggest file size.
+ *		
+ **/
+uint64_t DESC::getMaxFileSize()
+{
+	return maxFileSize;
+}
+
+/**
+ *	Get file list.
+ *	Return :
+ *		- const std::vector<string>& : constant reference to the fileList attribute. 
+ **/
+const vector<string>& DESC::getFileList()
+{
+	return fileList;
+}
+
+DESC::~DESC() 
+{
+	fileList.clear();
+	fileSize.clear();
+}

+ 55 - 0
apps/client/DESC.hpp

@@ -0,0 +1,55 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_DESC
+#define DEF_DESC
+
+#include <string>
+#include <vector>
+#include <sstream>
+#include <iostream>
+#include <boost/signals2.hpp>
+
+#include "pir/events/MessageEvent.hpp"
+
+using namespace std;
+#define FILENAME_MAX_BYTE_SIZE 1023	
+
+typedef boost::signals2::signal<void (MessageEvent&)>   messageListener;
+class DESC
+{
+    public :
+				DESC (messageListener& messageListeners);
+        void makeMenu(char* receivedBuffer);
+        bool file_exists (uint64_t ID);
+       
+				string 			 getFileName(uint64_t index);
+        uint64_t				 getFileSize(uint64_t index);
+				const        vector<string>& getFileList();
+        uint64_t getFilesNum();
+				uint64_t 				 getMaxFileSize();
+   
+				~DESC();
+		private:
+				messageListener& messageListeners;
+        vector<string> fileList;
+        vector<uint64_t> fileSize;
+				uint64_t maxFileSize;
+        uint64_t nbFiles;
+};
+
+#endif

+ 508 - 0
apps/client/PIRClient.cpp

@@ -0,0 +1,508 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "PIRClient.hpp"
+//Use this to limit the upload speed to UPLOAD_LIMIT bits per second
+//#define UPLOAD_LIMIT 100000000UL
+
+
+PIRClientSimple::PIRClientSimple(boost::asio::io_service& ios, ClientParams params, FixedVars vars):
+	socket_up(ios),
+  replyWriter(pirParams, writeListeners, messageListeners),
+	catalog(messageListeners),
+  clientParams(params),
+  fixedVars(vars),
+  optimum(vars),
+  no_pipeline_mode(false)
+{
+  replyWriter.setdontWrite(params.dontwrite);
+      //string lwe_params(crypto_params_const);
+  //cryptoMethod.getPublicParameters().computeNewParameters(lwe_params);
+  //pirParams.d = kDimensionNumber;
+}
+
+void PIRClientSimple::joinAllThreads()
+{
+  replyExt->replyThread.join();
+  replyWriter.join();
+}
+
+PIRClientSimple::~PIRClientSimple()
+{
+  joinAllThreads();
+  delete cryptoMethod;
+}
+
+void PIRClientSimple::connect()
+{	
+	using namespace boost::asio::ip;
+
+	try
+	{
+		socket_up.connect(tcp::endpoint(address::from_string(clientParams.server_ip), clientParams.port));
+    
+    // Tell the server we are a client
+    int is_client = 1;
+		write(socket_up, boost::asio::buffer(&is_client, sizeof(int)));
+
+  }
+	catch (const std::exception& ex)
+	{
+		exitWithErrorMessage(__FUNCTION__, ex.what());
+	}
+}
+/**
+ *  Downloads the file catalog from the server.
+ *  Exception :
+ *  - Stop the programme if any network trouble.
+ **/
+void PIRClientSimple::downloadCatalog()
+{
+	boost::uint64_t size = 1;
+	try
+	{
+		read(socket_up, boost::asio::buffer(&size, sizeof(size)));
+		std::cout<< "PIRClient: Catalog bytesize is "<<size<<std::endl;
+		char* buf = new char[size + 1]();
+	
+		if (read(socket_up, boost::asio::buffer(buf, size)) < size )
+      	  writeWarningMessage(__FUNCTION__, " Catalog has not been fully received.");
+   
+		catalog.makeMenu(buf);
+
+		if (catalog.getFilesNum() == 0) 
+		{
+			writeWarningMessage(__FUNCTION__,"Empty catalog recieved ! Is there a db directory with files in the server/ directory ? Aborting ");
+			exit(1);
+		}
+   
+    delete[] buf;
+    
+    std::cout << "PIRClient: Catalog received with " << catalog.getFilesNum() << " files" << std::endl;
+    
+  }
+	catch (const std::exception& ex)
+	{
+		exitWithErrorMessage(__FUNCTION__, ex.what());
+	}
+}
+
+void PIRClientSimple::optimize()
+{
+  if (exchange_method == CLIENT_DRIVEN)
+  {
+    PIROptimizer optimizer;
+    if (clientParams.verboseoptim == false) optimizer.silent = true;
+    std::cout << "PIRClient: Starting optimization ..." << std::endl;
+    OptimVars op = optimizer.optimizeFromServer(fixedVars, socket_up);
+    optimum = op;
+    std::cout << "PIRClient: Optimization returned alpha=" << optimum.alpha << " d=" << optimum.d << " crypto_params=" << optimum.crypto_params << std::endl;
+    pirParams.d = optimum.d;
+    pirParams.alpha = optimum.alpha;
+    optimizer.getDimSize(optimum.getFixedVars().n, optimum.alpha, optimum.d, pirParams.n);
+    pirParams.crypto_params = std::string(optimum.crypto_params);
+  }
+}
+
+void PIRClientSimple::processPIRParams()
+{
+  if (exchange_method == CLIENT_DRIVEN)
+  {
+    sendPirParams();
+  }
+  else rcvPirParams();
+}
+
+/**
+ *  Sends PIR parameters to the server.
+ *  Exception :
+ *  - Stop the programme if any network trouble.
+ **/
+void PIRClientSimple::sendPirParams()
+{
+  try 
+	{
+		write(socket_up, boost::asio::buffer(&pirParams.d, sizeof(int)));
+		write(socket_up, boost::asio::buffer(&pirParams.alpha, sizeof(int)));
+
+		for (unsigned int i = 0 ; i < pirParams.d ; i++)
+		{
+			write(socket_up, boost::asio::buffer(&pirParams.n[i], sizeof(int)));
+		}
+	}
+	catch (const std::exception& ex)
+	{
+		exitWithErrorMessage(__FUNCTION__, ex.what());
+	}
+}
+
+void PIRClientSimple::rcvPirParams()
+{
+  try 
+	{
+		read(socket_up, boost::asio::buffer(&pirParams.d, sizeof(int)));
+		read(socket_up, boost::asio::buffer(&pirParams.alpha, sizeof(int)));
+
+		for (unsigned int i = 0 ; i < pirParams.d ; i++)
+		{
+			read(socket_up, boost::asio::buffer(&pirParams.n[i], sizeof(int)));
+		}
+
+    std::cout << "PIRClient: Received PIR parameters alpha=" << pirParams.alpha << " d=" << pirParams.d << std::endl; 
+	}
+	catch (const std::exception& ex)
+	{
+		exitWithErrorMessage(__FUNCTION__, ex.what());
+	}
+}
+
+void PIRClientSimple::rcvPIRParamsExchangeMethod()
+{
+  try
+  {
+    read(socket_up, boost::asio::buffer(&exchange_method, sizeof(short)));
+    if (exchange_method == CLIENT_DRIVEN) 
+    {
+      std::cout << "PIRClient: Client-driven mode used" << std::endl;
+    } 
+    else 
+    {
+      std::cout << "PIRClient: Server-driven mode used" << std::endl;
+    }
+  }
+	catch (const std::exception& ex)
+  {
+		exitWithErrorMessage(__FUNCTION__, ex.what());
+  }
+}
+
+void PIRClientSimple::processCryptoParams() {
+  bool send_paramsandkey = true;
+  if (exchange_method == CLIENT_DRIVEN) 
+  {
+    cryptoMethod = HomomorphicCryptoFactory_internal::getCryptoMethod(optimum.crypto_params);
+    replyWriter.setCryptoMethod(cryptoMethod);
+    sendCryptoParams(send_paramsandkey);
+  }
+  else 
+  {
+    rcvCryptoParams(); 
+    cryptoMethod = HomomorphicCryptoFactory_internal::getCryptoMethod(pirParams.crypto_params);
+    replyWriter.setCryptoMethod(cryptoMethod);
+    sendCryptoParams(!send_paramsandkey);
+  }
+}
+
+/**
+ *  Send cryptographics parameters (e.g : key) to the server.
+ *  Exception :
+ *  - Stop the programme if any network trouble.
+ **/
+void PIRClientSimple::sendCryptoParams(bool paramsandkey)
+{
+	unsigned int size; 
+	char* key;
+
+	try
+	{
+    if (paramsandkey == true)
+    {
+      bool shortversion = true;
+
+      string crypto_params = cryptoMethod->getSerializedCryptoParams(!shortversion);
+      size = crypto_params.length();
+
+		  write(socket_up, boost::asio::buffer(&size, sizeof(size)));
+      write(socket_up, boost::asio::buffer(crypto_params));
+    }
+
+    size = ceil((double) cryptoMethod->getPublicParameters().getSerializedModulusBitsize() / GlobalConstant::kBitsPerByte);
+		write(socket_up, boost::asio::buffer(&size, sizeof(size)));
+
+		key = cryptoMethod->getPublicParameters().getByteModulus();
+		write(socket_up, boost::asio::buffer(key, size));//Send key
+		delete[] key;
+	}
+	catch (const std::exception& ex) 
+	{
+		exitWithErrorMessage(__FUNCTION__, ex.what());
+	}
+}
+
+void PIRClientSimple::rcvCryptoParams() {
+
+  try
+  {
+    int crypto_params_size = 0; 
+
+    read(socket_up, boost::asio::buffer(&crypto_params_size, sizeof(crypto_params_size)));
+
+    char crypto_params[crypto_params_size + 1];
+
+    int read_size = read(socket_up, boost::asio::buffer(crypto_params,crypto_params_size));
+    crypto_params[read_size] = '\0';
+
+    pirParams.crypto_params = string(crypto_params);
+
+    std::cout << "PIRClient: Received crypto parameters " << crypto_params << std::endl; 
+  }
+	catch (const std::exception& ex) 
+	{
+		exitWithErrorMessage(__FUNCTION__, ex.what());
+	}
+
+}
+
+/**
+ *  Launches the choose File action to the recorded view. If autochoice is set, 
+ *  the first file is chosen.
+ **/
+void PIRClientSimple::chooseFile() 
+{
+	chosenElement = 0;
+
+  if(!clientParams.autochoice)
+	{
+		CatalogEvent catalogEvent(catalog.getFileList());
+		menuListeners(catalogEvent); // get user input and set chosenElement.
+	}
+
+	std::ostringstream oss;
+	oss << "PIRClient: Retrieved file is nbr " + (chosenElement+1);
+	oss << + ", \"" + catalog.getFileName(chosenElement) +  "\"";
+
+	MessageEvent messageEvent(oss.str());
+	messageListeners(messageEvent);
+}
+
+/**
+ *  Set the query generator and launch parallely query generation and query upload.
+ **/
+void PIRClientSimple::startProcessQuery()
+{
+	PIRQueryGenerator_internal queryGen(pirParams, *cryptoMethod);
+
+	queryGen.setChosenElement(chosenElement);
+
+
+  if(no_pipeline_mode) {
+    std::cout << "PIRClient: Calling query generation and upload without pipelining" << std::endl;
+    queryGen.generateQuery(); 
+  } else {
+    queryGen.startGenerateQuery();
+  }
+
+	uploadWorker(queryGen);
+}
+void sleepForBytes(unsigned int bytes) {
+#ifdef UPLOAD_LIMIT
+	uint64_t seconds=(bytes*8)/UPLOAD_LIMIT;
+	uint64_t nanoseconds=((((double)bytes*8.)/(double)UPLOAD_LIMIT)-(double)seconds)*1000000000UL;
+	  struct timespec req={0},rem={0};
+	  req.tv_sec=seconds;
+	  req.tv_nsec=nanoseconds;
+    double st=omp_get_wtime();
+	  nanosleep(&req,&rem);
+#endif
+}
+/**
+ *  Upload query to the server et delete its parts from the shared query queue.
+ *  Exception :
+ *  - Stop the programme if any network trouble.
+ **/
+void PIRClientSimple::uploadWorker(PIRQueryGenerator_internal& queryGen)
+{
+	unsigned int size = 0;
+	char *tmp;
+	try 
+	{
+		for (unsigned int j = 1 ; j <= pirParams.d ; j++)
+		{
+			size = cryptoMethod->getPublicParameters().getQuerySizeFromRecLvl(j) / GlobalConstant::kBitsPerByte;
+
+			for (unsigned int i = 0 ; i < pirParams.n[j - 1] ; i++)
+			{
+				tmp = queryGen.queryBuffer.pop_front();
+				write(socket_up, boost::asio::buffer(tmp, size));
+				free(tmp);
+#ifdef UPLOAD_LIMIT
+        sleepForBytes(size);
+#endif
+			}
+		}
+	} 
+	catch (const std::exception& ex) 
+	{
+		exitWithErrorMessage(__FUNCTION__, ex.what());
+	}
+
+	
+}
+
+/**
+ *  Sets reply extractpr and lauches parallely reply download and reply extraction.
+ **/
+void PIRClientSimple::startProcessResult()
+{
+	replyExt = new PIRReplyExtraction_internal(pirParams,*cryptoMethod);
+	replyExt->setFileParam(catalog.getFileName(chosenElement), catalog.getFileSize(chosenElement)); 
+
+  if(no_pipeline_mode)
+  {
+    std::cout << "PIRClient: Calling reply download, extraction and writting without pipelining" << std::endl;
+    downloadWorker(*replyExt);
+    replyExt->extractReply(catalog.getMaxFileSize()*pirParams.alpha, replyWriter.getClearDataQueue());
+    // Tell reply writer we finished the extraction
+    replyWriter.writeAggregatedFileSecurely(chosenElement, catalog);
+  }
+  else 
+  {
+	replyExt->startExtractReply(catalog.getMaxFileSize()*pirParams.alpha, replyWriter.getClearDataQueue());
+  
+  replyWriter.startFileWritting(chosenElement, catalog);
+	downloadWorker(*replyExt);
+  }
+}
+
+/**
+ *  Download reply from the server and stores it chunks in shared replies queue.
+ *  Exception :
+ *  - Stop the program if any network trouble.
+ **/
+void PIRClientSimple::downloadWorker(PIRReplyExtraction_internal& turlututu)
+{
+  using  namespace GlobalConstant;
+  unsigned int i,  ciph_siz = cryptoMethod->getPublicParameters().getCiphBitsizeFromRecLvl(pirParams.d)/kBitsPerByte;
+
+  double paquet_nbr = ceil(static_cast<double>(catalog.getMaxFileSize()*pirParams.alpha) / double(cryptoMethod->getPublicParameters().getAbsorptionBitsize(0)/kBitsPerByte)); 
+
+#ifdef DEBUG
+  cout << "PIRClient: First layer nbr of ciphertexts is " << paquet_nbr << endl;
+#endif
+
+    for (unsigned int i = 1 ; i < pirParams.d; i++) paquet_nbr =  ceil(paquet_nbr * double(cryptoMethod->getPublicParameters().getCiphBitsizeFromRecLvl(i)/kBitsPerByte) / double(cryptoMethod->getPublicParameters().getAbsorptionBitsize(i) / kBitsPerByte));
+
+	char* buf;
+
+#ifdef DEBUG
+  cout << "PIRClient: getMaxFileSize=" << catalog.getMaxFileSize() << " alpha=" << pirParams.alpha << " getAbsorptionBitsize=" << double(cryptoMethod->getPublicParameters().getAbsorptionBitsize(0))/*kBitsPerByte);*/ << endl;
+  cout << "PIRClient: Last layer nbr of ciphertexts is " << paquet_nbr << endl;
+  cout << "PIRClient: File size of the chosen element is " << catalog.getFileSize(chosenElement) << endl;
+	cout << "PIRClient: Ciphertext bytesize is " << ciph_siz << endl;
+#endif
+
+	try
+	{
+		for (i = 0 ; i < paquet_nbr ; i++)
+		{
+			buf = (char*) malloc(ciph_siz * sizeof(char));
+			read(socket_up,boost::asio::buffer(buf, ciph_siz));
+			replyExt->repliesBuffer.push(buf);
+		}
+	}
+	catch (const std::exception& ex) 
+	{
+#ifdef DEBUG
+    cerr << "PIRReplyWriter: Number of downloaded chunks: " << i << "/" << paquet_nbr << endl;
+#endif
+		exitWithErrorMessage(__FUNCTION__, ex.what());
+    return;
+	}
+  writeWarningMessage(__FUNCTION__, "done.");
+}
+
+/**
+ *  Sets the chosen element.
+ **/
+void PIRClientSimple::setChosenElement(uint64_t choice)
+{
+	chosenElement = choice;
+}
+
+//void PIRClientSimple::setPIRParameters(PIRParameters& pirParameters)
+//{
+//  pirParams.alpha = pirParameters.alpha;
+//  pirParams.d = pirParameters.d;
+//  memcpy(pirParams.n, pirParameters.n, MAX_REC_LVL);
+//  pirParams.r;
+//}
+
+/**
+ *	Add a new message listener.
+ *	Param :
+ *		- messageListener::slot_function_type subscriber, a message listener to add.
+ **/
+boost::signals2::connection PIRClientSimple::addMessageListener(messageListener::slot_function_type subscriber)
+{
+	return messageListeners.connect(subscriber);
+}
+
+/**
+ *	Add a new menu listener.
+ *	Param :
+ *		- menuListener::slot_function_type subscriber, a menu listener to add.
+ **/
+boost::signals2::connection  PIRClientSimple::addMenuListener(menuListener::slot_function_type subscriber)
+{
+	return menuListeners.connect(subscriber);
+}
+
+/**
+ *	Add a new wite listener
+ *	Param :
+ *		- writeListener::slot_function_type subscriber, a write listener to add.
+ **/
+boost::signals2::connection PIRClientSimple::addWriteListener(writeListener::slot_function_type subscriber)
+{
+	return writeListeners.connect(subscriber);
+}
+
+void PIRClientSimple::exitWithErrorMessage(string s1, string s2)
+{
+	writeErrorMessage(s1 ,s2);
+	socket_up.close();
+	exit(errno);
+}
+
+/**
+ *	Send ERROR message to listeners
+ *	Params :
+ *		- string funcName :  usually the function name who throw the error message ;
+ *		- string message  :  message to show.
+ **/
+void PIRClientSimple::writeErrorMessage(string funcName, string message)
+{
+	MessageEvent event(ERROR, message, funcName);
+	messageListeners(event);	
+}
+
+/**
+ *	Send WARNING message to listeners
+ *	Params :
+ *		- string funcName :  usually the function name who throw the warning message ;
+ *		- string message  :  message to show.
+ **/
+void PIRClientSimple::writeWarningMessage(string funcName, string message) 
+{
+	MessageEvent event(WARNING, message, funcName);
+	messageListeners(event);
+}
+
+void PIRClientSimple::no_pipeline(bool b) 
+{
+  no_pipeline_mode = b;
+}

+ 122 - 0
apps/client/PIRClient.hpp

@@ -0,0 +1,122 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_PIRCLIENT
+#define DEF_PIRCLIENT
+//#define DEBUG
+#include <string>
+#include <iostream>
+
+#include <boost/asio.hpp>
+#include <boost/thread.hpp>
+#include <boost/signals2.hpp>
+
+#include "DESC.hpp"
+
+#include "crypto/NFLLWE.hpp"
+
+#include "pir/queryGen/PIRQueryGenerator_internal.hpp"
+#include "pir/PIRParameters.hpp"
+#include "pir/replyExtraction/PIRReplyExtraction_internal.hpp"
+#include "pir/replyExtraction/PIRReplyWriter.hpp"
+
+#include "apps/optim/PIROptimizer.hpp"
+
+#include "pir/events/WriteEvent.hpp"
+#include "pir/events/CatalogEvent.hpp"
+#include "pir/events/MessageEvent.hpp"
+
+#include "pir/PIRParametersExchangeMethods.hpp"
+#include "pir/GlobalConstant.hpp"
+
+typedef boost::signals2::signal<void (MessageEvent&)>   messageListener;
+typedef boost::signals2::signal<void (CatalogEvent&)>   menuListener;
+typedef boost::signals2::signal<void (WriteEvent&)>     writeListener;
+
+
+struct ClientParams 
+{
+  // Networking parameters
+  string server_ip;
+  int port; 
+
+  // Interface params
+  bool autochoice;
+  bool verboseoptim;
+  bool dontwrite;
+
+  // Dry-run mode
+  bool dryrunmode;
+};
+
+class PIRClientSimple
+{
+  private:
+    PIRReplyExtraction_internal *replyExt;
+    ClientParams clientParams;
+    FixedVars fixedVars;
+    OptimVars optimum;
+    HomomorphicCrypto* cryptoMethod;
+    messageListener messageListeners; 
+    menuListener 		menuListeners;
+    writeListener		writeListeners;
+    boost::asio::ip::tcp::socket socket_up;
+  
+    PIRReplyWriter replyWriter;
+    PIRParameters pirParams;
+    DESC catalog;
+    short exchange_method;
+
+    void uploadWorker(PIRQueryGenerator_internal& queryGen);
+    void downloadWorker(PIRReplyExtraction_internal& replyExt);
+    void sendPirParams();
+    void rcvPirParams();
+
+    void exitWithErrorMessage(string s1, string s2);
+    void writeErrorMessage(string funcName, string message);
+    void writeWarningMessage(string funcName, string message);
+
+    bool no_pipeline_mode;
+    uint64_t chosenElement;
+
+  public:
+    PIRClientSimple( boost::asio::io_service& ios, ClientParams params, FixedVars vars);
+    ~PIRClientSimple();
+
+    void connect();
+    void chooseFile();
+    void rcvPIRParamsExchangeMethod();
+    void processPIRParams();
+    void downloadCatalog();
+    void optimize();
+    void sendCryptoParams(bool paramsandkey);
+    void rcvCryptoParams();
+    void processCryptoParams(); 
+    void startProcessQuery();
+    void startProcessResult();
+
+    void setChosenElement(uint64_t choice);
+    void joinAllThreads();
+    void no_pipeline(bool b);
+
+    /*Add Observers*/
+    boost::signals2::connection addMessageListener(messageListener::slot_function_type subscriber);
+    boost::signals2::connection addMenuListener(menuListener::slot_function_type subscriber);
+    boost::signals2::connection addWriteListener(writeListener::slot_function_type subscriber);
+};
+
+#endif

+ 111 - 0
apps/client/PIRClientLog.cpp

@@ -0,0 +1,111 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "PIRClientLog.hpp"
+
+PIRClientLog::PIRClientLog(PIRController* controller_) :
+	PIRView(controller_),
+	file("clientError.log", std::ios::app)
+{}
+
+PIRClientLog::~PIRClientLog()
+{
+	file.close();
+}
+
+const std::string PIRClientLog::getCurrentTime()
+{
+    time_t     now = time(0);
+    struct tm  tstruct;
+    char       buf[80];
+
+    tstruct = *localtime(&now);
+    strftime(buf, sizeof(buf), "%Y-%m-%d.%X", &tstruct);
+
+    return buf;
+}
+
+/**
+ *	Called by the model when a information as to be displayed.
+ *	Param :
+ *		- MessageEvent& event : the message to write. 
+ **/
+void PIRClientLog::messageUpdate(MessageEvent& event)
+{
+	std::string m;
+	switch(event.getMessageType())
+	{
+		case WARNING :
+			{
+				m = "Warning";
+				break;
+			}
+		case ERROR :
+			{
+				m = "Message";
+				break;
+			}
+		case CHOICE:
+			{
+				m = "Choice ";
+				break;
+			}
+		case DEFAULT:
+			{
+				m = "Default";
+				break;
+			}
+		case RETRY:
+			{
+				m = "Retry";
+				break;
+			}
+	}
+	writeMessage(m, event);
+}
+/**
+ *	Called by the model when catalog is entierely received.
+ *	Param :
+ *		- CatalogEvent& event : new catalog event to write.
+ **/
+void PIRClientLog::catalogUpdate(CatalogEvent& event)
+{
+	file << "Proposed files : " << getCurrentTime() << std::endl;
+	file << "---------------  " << std::endl;
+	const	std::vector<std::string>& fileList = event.getCatalog();
+
+	for (unsigned int i = 0 ; i < fileList.size() ; i++)
+	{
+		file << fileList.at(i) << " ";
+		if (i+1 % 10 == 0)
+			file << std::endl;
+	}
+	file << std::endl;
+	file << "---------------  " << std::endl;
+	std::flush(file);
+}
+void PIRClientLog::writeUpdate(WriteEvent& event)
+{
+	event.getSizeToWrite();
+}
+
+void PIRClientLog::writeMessage(std::string type, MessageEvent& event)
+{
+	file << getCurrentTime() << " " << type << " : " << event.getMessage() << " : " << event.getInfo() << std::endl;	
+	std::flush(file);
+}
+

+ 42 - 0
apps/client/PIRClientLog.hpp

@@ -0,0 +1,42 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_PIRCLIENTLOG
+#define DEF_PRICLIENTLOG
+
+#include <fstream>
+
+#include "PIRView.hpp"
+
+class PIRClientLog : public PIRView
+{
+	private:
+		std::ofstream file;
+
+		void writeMessage(std::string, MessageEvent& event);
+    const std::string getCurrentTime();
+	
+	public:
+		PIRClientLog(PIRController* controller_);
+		~PIRClientLog();
+
+		void messageUpdate(MessageEvent& event);
+		void catalogUpdate(CatalogEvent& event);
+		void writeUpdate(WriteEvent& 		 event);
+};
+
+#endif

+ 69 - 0
apps/client/PIRController.cpp

@@ -0,0 +1,69 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "PIRController.hpp"
+#include "PIRClient.hpp"
+
+/**
+ *	Class constructor.
+ *	Param :
+ *		- pirClient_ptr model_ptr_ : PIRClient shared_ptr.
+ **/
+PIRController::PIRController(PIRClientSimple& model_ptr_):
+  model_ptr(model_ptr_),
+  view_cli(this),
+  logger(this)
+{
+  addListenersToModel();
+}
+
+/**
+ *	Add listners (attribute of PIRController) to the model (model_ptr).
+ **/
+void PIRController::addListenersToModel()
+{
+  connectionMessage.push_back(model_ptr.addMessageListener(boost::bind(&PIRView::messageUpdate, &view_cli, _1)));
+  connectionMessage.push_back(model_ptr.addMessageListener(boost::bind(&PIRView::messageUpdate, &logger, _1)));
+
+  connectionMenu.push_back(model_ptr.addMenuListener(boost::bind(&PIRView::catalogUpdate, &view_cli, _1))); 
+  connectionMenu.push_back(model_ptr.addMenuListener(boost::bind(&PIRView::catalogUpdate, &logger, _1)));
+
+  connectionWrite.push_back(model_ptr.addWriteListener(boost::bind(&PIRView::writeUpdate, &view_cli, _1))); 
+}
+
+
+/**
+ *	Notify model of a client choice.
+ *	Param :
+ *		- int c : int input.
+ **/
+void PIRController::notifyClientChoice(int c)
+{
+  model_ptr.setChosenElement(c);
+}
+
+PIRController::~PIRController()
+{
+  for (auto &messageView : connectionMessage)
+    messageView.disconnect();
+
+  for (auto &menuView : connectionMenu)
+    menuView.disconnect();
+
+  for (auto &writeView : connectionWrite)
+    writeView.disconnect();
+}

+ 47 - 0
apps/client/PIRController.hpp

@@ -0,0 +1,47 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_PIRCONTROLLER
+#define DEF_PIRCONTROLLER
+
+#include <vector>
+
+#include "PIRViewCLI.hpp"
+#include "PIRClientLog.hpp"
+
+class PIRClientSimple;
+
+class PIRController
+{
+	private:
+		PIRClientSimple& 	model_ptr;
+		PIRViewCLI 				view_cli;
+		PIRClientLog			logger;
+
+		std::vector<boost::signals2::connection> connectionMessage, connectionMenu, connectionWrite;
+	
+	public:
+			PIRController(PIRClientSimple& model_ptr_);
+			~PIRController();
+
+			void addListenersToModel();
+			void notifyClientChoice(char c);
+			void notifyClientChoice(int  c);
+
+};
+
+#endif

+ 33 - 0
apps/client/PIRView.cpp

@@ -0,0 +1,33 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "PIRView.hpp"
+#include "PIRController.hpp"
+
+/**
+ *	Class constructor.
+ *	Param : 
+ *		- PIRController* controller_ , a PIRController pointer.
+ **/
+PIRView::PIRView(PIRController* controller_) :
+	controller(controller_)
+{}
+
+PIRView::~PIRView()
+{}
+
+

+ 51 - 0
apps/client/PIRView.hpp

@@ -0,0 +1,51 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_PIRVIEW
+#define DEF_PIRVIEW
+
+#include <vector>
+#include <string>
+
+#include <boost/signals2.hpp>
+
+#include "pir/events/MessageEvent.hpp"
+#include "pir/events/CatalogEvent.hpp"
+#include "pir/events/WriteEvent.hpp"
+
+
+class PIRController;
+
+class PIRView
+{
+	private:
+		 boost::signals2::connection m_connection, m_connectionMenu;
+	
+	protected:
+		 PIRController* controller;
+
+	public:
+		PIRView(PIRController* controller_);
+		virtual ~PIRView();
+
+		virtual void messageUpdate(MessageEvent& event)=0;
+		virtual void catalogUpdate(CatalogEvent& event)=0;
+		virtual void writeUpdate(WriteEvent& 		 event)=0;
+
+};
+
+#endif

+ 162 - 0
apps/client/PIRViewCLI.cpp

@@ -0,0 +1,162 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "PIRViewCLI.hpp"
+#include "PIRController.hpp"
+
+/**
+ *	Class constructor.
+ *	Param :
+ *
+ **/
+PIRViewCLI::PIRViewCLI(PIRController* controller_) :
+	PIRView(controller_)
+{}
+
+/**
+ *	Message notification, display event content.
+ *	Param :
+ *		- MessageEvent& event : MessageEvent reference to display.
+ **/
+void PIRViewCLI::messageUpdate(MessageEvent& event)
+{
+	if(event.getMessageType() == RETRY){
+		getUserInputRetry();
+	}
+	else if(event.getMessageType() == DEFAULT){
+		std::cout << event.getMessage() << std::endl; 
+	}
+	else
+	{
+		std::string color = (event.getMessageType() == WARNING) ? ORANGE : RED;
+		std::cout << BOLD  << event.getInfo() << " : " << RESET_COLOR << color << event.getMessage() << RESET_COLOR << std::endl;
+	}
+}
+
+/**
+ *	Catalog notification, display catalog content in a framed list.
+ *	Param :
+ *		- CatalogEvent& event : CatalogEvent reference to display.
+ **/
+void PIRViewCLI::catalogUpdate(CatalogEvent& event)
+{
+	using namespace std;
+	cout << endl;
+	cout << "##############################################" << endl;
+	cout << "#                                            #" << endl;
+	cout << "# Connection established                     #" << endl;
+	cout << "#                                            #" << endl;
+	cout << "##############################################" << endl;
+	cout << "#                                            #" << endl;
+	cout << "# File List :                                #" << endl;
+	cout << "# °°°°°°°°°°°                                #" << endl;
+	cout << "#                                            #" << endl;
+
+	for (unsigned int i = 0 ; i < event.getCatalog().size() ; i++) 
+	{
+		cout << "# " << i+1 << ") " << event.getCatalog().at(i);
+
+		for(unsigned int j = 0; j < 40 - event.getCatalog().at(i).length(); j++)
+			cout << " ";
+
+		cout << "#" << endl;
+	}
+
+	cout << "#                                            #" << endl;
+	cout << "##############################################" << endl;
+	cout << "#                                            #" << endl;
+	cout << "# Which file do you want ?                   #" << endl;
+	getUserInputFile(event.getCatalog().size()) ;
+}
+
+/**
+ *	Writing notification, used when the client wants to display the writing state of the files.
+ *	Param :
+ *		- WriteEvent& event : WriteEvent reference.
+ **/
+void PIRViewCLI::writeUpdate(WriteEvent& event)
+{
+	using namespace std;
+
+	std::cout << "\033[1GPIRReplyWriter: Remaning Bytes to write : " << event.getSizeToWrite() -  event.getWrittenSize() << "                                  \033[5G"  << "\xd"<< std::flush;
+
+	if(event.getSizeToWrite() == event.getWrittenSize())
+	{
+		cout << endl << endl <<"\t## SUCESS ! ##" << endl;
+		cout << "\t   °°°°°°" << endl;
+	}
+}
+
+/**
+ *	Get user input for retry questions :
+ *	Param :
+ *		- const std::string& message : message to display.
+ **/
+void PIRViewCLI::getUserInputRetry()
+{
+	using namespace std;	
+	char choice;
+	cout << "Enable de reach the server, would you like to retry ? (Y/n) : ";
+
+retrying:
+	cin.clear();
+	choice = cin.get();
+
+	if (choice == 'N'||choice == 'n') {
+		controller->notifyClientChoice(false);
+	}
+	else if (choice == 'Y' || choice == 'y'|| choice == '\n') {
+		controller->notifyClientChoice(true);
+	}	
+	else
+	{
+		cout << "Bad input, retry : ";
+		cin.ignore(1);
+		goto retrying;
+	}
+}
+
+/**
+ *	Get user choice, used with updateCatalog method.
+ *	Param :
+ *		- int maxVulue : maximum value that the user can enter.
+ **/
+void PIRViewCLI::getUserInputFile(int maxValue)
+{
+	using namespace std;
+	int choice  = -1;
+	bool retry;
+	MessageEvent event(WARNING);
+	
+	do
+	{
+		retry = false;
+		cin >> choice ;
+		cin.clear();
+		cin.get();
+		
+		if (choice > maxValue || choice <= 0)
+		{
+			retry = true;
+			event.setMessage("This file doesn't exist, retry :");
+			messageUpdate(event);
+		}
+	}while(retry);
+
+	controller->notifyClientChoice(--choice);
+}
+

+ 48 - 0
apps/client/PIRViewCLI.hpp

@@ -0,0 +1,48 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_PIRCLIENTCLI
+#define DEF_PIRCLIENTCLI
+
+#include <boost/signals2.hpp>
+#include <string>
+#include <iostream>
+
+#include "PIRView.hpp"
+
+#define RESET_COLOR "\033[m"
+#define RED "\033[31m"
+#define BOLD "\033[1;30m"
+#define ORANGE "\033[33m"
+#define DEFAULT_BOX_SIZE 24
+
+class PIRController;
+
+class PIRViewCLI : public PIRView
+{
+	public:
+		PIRViewCLI(PIRController* controller_);
+		
+		void messageUpdate(MessageEvent& event);
+		void catalogUpdate(CatalogEvent& event);
+		void writeUpdate(WriteEvent& 		 event);
+
+		void getUserInputRetry();
+		void getUserInputFile(int maxValue);
+};
+
+#endif

+ 418 - 0
apps/client/main.cpp

@@ -0,0 +1,418 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "main.hpp"
+
+// Client constants
+static const std::string DEFAULT_IP("127.0.0.1");
+static const int DEFAULT_PORT = 1234;
+static const bool DEFAULT_AUTOCHOICE = false;
+
+// Optimizer constants
+static const int DEFAULT_SECURITY = 80;
+static const unsigned long DEFAULT_N = 1000;
+static const unsigned int DEFAULT_L = 24000000;
+static const unsigned int DEFAULT_TUPC = 100000000;
+static const unsigned int DEFAULT_TDOC = 100000000;
+static const unsigned int DEFAULT_K = 80;
+static const unsigned int DEFAULT_ALPHAMAX = 0; // 0 means no limit
+static const unsigned int DEFAULT_DMAX = 4;
+static const unsigned int DEFAULT_DMIN = 1; 
+static const FitnessType DEFAULT_FITNESSMETHOD = MAX;
+static const std::string DEFAULT_CRYPTO_PARAMS("LWE:80:1024:60:22");
+
+
+//Global vars
+string fileToOptimizeFrom;
+bool no_pipeline = false;
+
+void sighandler(int sig_num)
+{
+  FixedVars fixedVars;
+  cerr.flush();
+  if(sig_num == SIGPIPE)
+    cerr << "Broken pipe detected";
+
+  cerr << endl << "Exiting client..." << endl << endl;
+  exit(EXIT_SUCCESS);       
+}
+
+
+void defineClientOptions(ClientParams* paramsPtr, po::options_description* odptr){
+  odptr->add_options()
+    ("help,h", 
+     "help message") 
+    
+    ("serverip,ip", 
+     po::value<string>(&paramsPtr->server_ip)->default_value(DEFAULT_IP), 
+     "PIR server IP" )
+
+    ("port,p", 
+     po::value<int>(&paramsPtr->port)->default_value(DEFAULT_PORT), 
+     "PIR server port")
+    
+    ("autochoice,c", 
+     "Auto-choose the first file")
+    
+    ("dry-run", 
+     "Enable dry-run mode")
+    
+    ("verbose-optim", 
+     "Ask the optimizer to be more verbose")
+    
+    ("dont-write", 
+     "Don't write result to a file")
+    
+    ("file,f", 
+     po::value<std::string>(&fileToOptimizeFrom), 
+     "Use a config file to test different optimizations in dry-run mode (see sample.conf)"); 
+}
+
+
+void defineOptimizerOptions(FixedVars* varsPtr, po::options_description* odptr){
+  odptr->add_options()
+    ("file-nbr,n", 
+     po::value<uint64_t>(), 
+     "Used in dry-run mode only: Number of database elements" )
+
+    ("file-size,l", 
+     po::value<uint64_t>(), 
+     "Used in dry-run mode only: Database element size in bits")
+    
+    ("upload,up", 
+     po::value<double>(),  
+     "Force client upload speed in bits/s (bandwith test will be skipped)")
+    
+    ("download,down", 
+     po::value<double>(), 
+     "Force client download speed in bits/s (bandwidth test will be skipped)")
+    
+    ("crypto-params,r", 
+     po::value<string>(&varsPtr->manual_crypto_params), 
+     "Set cryptographic parameteres manually")
+    
+    ("security,k", 
+     po::value<unsigned int>(&varsPtr->k)->default_value(DEFAULT_SECURITY), 
+     "Security bits wanted")
+    
+    ("dmin", 
+     po::value<unsigned int>(&varsPtr->dMin)->default_value(DEFAULT_DMIN), 
+     "Min dimension value to test")
+    
+    ("dmax", 
+     po::value<unsigned int>(&varsPtr->dMax)->default_value(DEFAULT_DMAX), 
+     "Max dimension value to test")
+    
+    ("alphaMax,a", 
+     po::value<unsigned int>(&varsPtr->alphaMax)->default_value(DEFAULT_ALPHAMAX), 
+     "Max aggregation value to test (1 = no aggregation, 0 = no limit)")
+    
+    ("fitness,x",
+     po::value<int>((int*)&varsPtr->fitness)->default_value((int)DEFAULT_FITNESSMETHOD),
+     "Set fitness method to: \n0=SUM Sum of the times on each task\n1=MAX Max of server times + Max of client times\n2=CLOUD Dollars in a cloud model (see sourcecode)");    
+}
+
+
+void defineHiddenOptions(FixedVars* varsPtr, po::options_description* odptr){
+  odptr->add_options()
+    ("no-pipeline", "No pipeline mode\n")
+
+    ("reclvl", 
+     po::value<unsigned int>(), 
+     "Number of dimension used for database representation"); 
+}
+
+
+void processOptions(FixedVars* varsPtr, ClientParams* paramsPtr, po::variables_map vm){
+
+  // Client options
+  if(vm.count("serverip")) 
+  {
+    std::cout << "CLI: Server ip set to " <<  paramsPtr->server_ip << std::endl;
+  }
+  
+  if(vm.count("port")) 
+  {
+    std::cout << "CLI: Upload port set to " << paramsPtr->port << std::endl;
+  }
+  
+  if(vm.count("autochoice")) 
+  {
+    std::cout << "CLI: Auto-choice activated" << std::endl;
+    paramsPtr->autochoice = true;
+  }
+  
+  if(vm.count("dry-run")) 
+  {
+    std::cout << "CLI: Dry-run mode activated" << std::endl;
+    paramsPtr->dryrunmode = true;
+    varsPtr->n = DEFAULT_N;
+    varsPtr->l = DEFAULT_L;
+    varsPtr->Tupc = DEFAULT_TUPC;
+    varsPtr->Tdos = DEFAULT_TUPC;
+    varsPtr->Tdoc = DEFAULT_TDOC;
+    varsPtr->Tups = DEFAULT_TDOC;
+    std::cout << "CLI: Setting default values for dry-run mode (a thousand mp3 files, 100MBit/s connection)" <<std::endl;
+  }
+
+  if(vm.count("verbose-optim")) 
+  {
+    std::cout << "CLI: Will ask the optimizer to be more verbose" << std::endl;
+    paramsPtr->verboseoptim = true;
+  }
+
+
+  if(vm.count("dont-write")) 
+  {
+    std::cout << "CLI: Will ask PIRReplyWriter not to write to a file" << std::endl;
+    paramsPtr->dontwrite = true;
+  }
+  else paramsPtr->dontwrite = false;
+
+  // Optimizer options
+  if(vm.count("file-nbr")) 
+  {
+    if(vm.count("dry-run"))
+    {
+      varsPtr->n = vm["file-nbr"].as<uint64_t>();
+      std::cout << "CLI: Changing number of database elements to "\
+        << varsPtr->n << std::endl;
+    } 
+    else 
+    {
+      std::cout << "CLI: Option -n,--file-nbr ignored as we are not in dry-run mode"\
+        << std::endl; 
+    }
+  }
+
+  if(vm.count("file-size")) {
+    if(vm.count("dry-run"))
+    {
+      varsPtr->l = vm["file-size"].as<uint64_t>();
+      std::cout << "CLI: Changing database element size to " << varsPtr->l <<std::endl;
+    }
+    else
+    {
+      std::cout << "CLI: Option -l,--file-size ignored as we are not in dry-run mode"
+        << std::endl; 
+    }
+  }
+
+  if (vm.count("upload"))
+  {
+    varsPtr->Tupc = vm["upload"].as<double>();
+    varsPtr->Tdos = varsPtr->Tupc;
+    cout << "CLI: Upload speed forced to "<< varsPtr->Tupc << endl;
+  }
+  
+  if (vm.count("download"))
+  {
+    varsPtr->Tdoc = vm["download"].as<double>();
+    varsPtr->Tups = varsPtr->Tdoc;
+    cout << "CLI: Download speed forced to "<< varsPtr->Tdoc << endl;
+  }
+  
+  if(vm.count("crypto-params")) 
+  {
+    std::cout << "CLI: Crypto parameters set to " << varsPtr->manual_crypto_params <<  std::endl;
+    std::vector<std::string> fields;
+    boost::algorithm::split(fields, varsPtr->manual_crypto_params, boost::algorithm::is_any_of(":"));
+    if (fields.size()>1 && atoi(fields[1].c_str()) > 0)
+    {
+      varsPtr->k = atoi(fields[1].c_str());
+    }
+    if (fields.size()>4)
+    { 
+      std::cout << "CLI: WARNING Absorption size will be overriden by the optimizer" << varsPtr->manual_crypto_params <<  std::endl;
+      
+      varsPtr->k = 0;
+    } 
+  }
+
+  if(vm.count("security")) 
+  {
+    std::cout << "CLI: Security set to " << varsPtr->k <<  std::endl;
+  }
+
+  if (vm.count("dmin")) 
+  {
+    cout << "CLI: Minimum recursion level set to "<< varsPtr->dMin << endl;
+  }
+  
+  if (vm.count("dmax")) 
+  {
+    cout << "CLI: Maximum recursion level set to "<< varsPtr->dMax << endl;
+  }
+  
+  if(vm.count("alphaMax")) 
+  {
+    varsPtr->alphaMax = vm["alphaMax"].as<unsigned int>();
+    cout << "CLI: Max aggregation set to "<< varsPtr->alphaMax << endl;
+  }
+  
+  if(vm.count("fitness")) 
+  {
+    cout << "CLI: Fitness method set to "<< varsPtr->fitness << endl;
+  }   
+  
+  // Hidden options
+  if (vm.count("reclvl")) 
+  {
+    varsPtr->dMax = vm["reclvl"].as<unsigned int>(); 
+    varsPtr->dMin = vm["reclvl"].as<unsigned int>(); 
+    cout << "CLI: Recursion level forced to "<< varsPtr->dMax << endl;
+  }
+  
+  if (vm.count("no-pipeline"))
+  {
+    std::cout << "CLI: WARNING no pipeline mode activated" << std::endl;
+    no_pipeline = true;
+  }
+}
+
+
+
+int main(int argc, char** argv) 
+{
+  boost::asio::io_service ios;
+  
+  // Vars for the optimizer (and pot. client)
+  FixedVars fixedVars = {}; // Inits to default value all fields
+  
+  // Vars for the client only
+  ClientParams clientParams = {}; // Same here
+
+  // Add and define options
+  po::options_description od("Client options");
+  po::options_description optimizeropts("Optimizer options");
+  po::options_description hidden("Hidden options");
+  defineOptimizerOptions(&fixedVars, &optimizeropts);
+  defineClientOptions(&clientParams, &od);
+  defineHiddenOptions(&fixedVars, &hidden);
+
+  // Set which options are visible and which not
+  po::options_description visible;
+  visible.add(od).add(optimizeropts);
+  po::options_description all;
+  all.add(visible).add(hidden);
+  po::variables_map vm;
+
+  // Parse options from command line
+  try {
+    po::store(po::parse_command_line(argc, argv, all), vm);
+  }
+  catch (const std::exception& ex) 
+  {
+    std::cout << "CLI: Error checking program options: " << ex.what() << std::endl;
+    std::cout << visible << std::endl;
+    return 1;
+  }
+  po::notify(vm);
+
+  // Show usage help if requested
+  if(vm.count("help")) {
+    std::cout << visible << endl;
+    return 0;
+  }
+
+  // Set variables according to options
+  processOptions(&fixedVars, &clientParams, vm);
+ 
+  
+  // If we are on dry-run mode run only the optimizer not the client
+  if(vm.count("dry-run"))
+  {
+    std::cout << "CLI: Dry-run mode activated" << std::endl;
+
+    // The optimizer connects to the same PIR server but on a higher port for 
+    // optimization related exchanges
+    PIROptimizer optimizer(clientParams.server_ip, clientParams.port, fixedVars.fitness);
+    
+    if (vm.count("file"))
+    {
+      int experience_nbr = OptimService::getNumberOfExperiences(fileToOptimizeFrom);
+      if(experience_nbr == -1)
+      {
+        cout << "CLI: Unable to open : " << fileToOptimizeFrom << " aborting" << endl;
+        cout << "CLI: Try exp/sample.conf to test a predefined set of configurations" << endl;
+        return 1;
+      }
+      for (int exp_i = 0 ; exp_i <= experience_nbr ; exp_i++)
+      {
+        OptimService::readTestValues(exp_i, fixedVars, fileToOptimizeFrom);
+        OptimService::writeHeadFile(exp_i, fixedVars);
+        optimizer.optimize(fixedVars, exp_i);
+      }
+    }
+    else
+    {
+      cout << "CLI: Default example : A thousand mp3 files, ADSL, no aggregation, k=80" << endl;
+      cout << "CLI: n : " << fixedVars.n << " l : " << fixedVars.l;
+      cout << "CLI: Tupc : " << fixedVars.Tupc << " Tdoc : " << fixedVars.Tdoc << endl;
+
+      OptimService::writeHeadFile(0, fixedVars);
+      optimizer.optimize(fixedVars, 0);
+    }
+    return 0;
+  }
+
+  // If we are not in dry-run mode create client and controller
+  PIRClientSimple client(ios, clientParams, fixedVars);
+  PIRController controller(client);
+ 
+  // Set no_pipeline if needed
+  if(no_pipeline) client.no_pipeline(true);
+
+  // Start by connecting to the PIR server
+  client.connect();
+
+  // Downloads the file catalog
+  client.downloadCatalog();
+
+  // Get from the server whether we are in client-driven mode or not
+  client.rcvPIRParamsExchangeMethod();
+
+  // Use the optimizer to choose best parameters 
+  // (returns immediately in server-driven mode)
+  client.optimize();  
+
+  // Send PIR and cryptographic parameters to the server in client-driven mode
+  // and receive and process them in server-driven mode
+  client.processCryptoParams();
+  client.processPIRParams();
+
+  /*User chooses the file here.*/
+  client.chooseFile();
+  
+  double start = omp_get_wtime();
+  
+  
+  /* Asynchronously generate and send the request
+     separately in two threads*/
+  client.startProcessQuery();
+  /* Receive asynchronously the response from the server and
+     asynchronously writes it */
+  client.startProcessResult();
+
+  client.joinAllThreads();
+  double end = omp_get_wtime();
+  cout << "CLI: Query RTT was " << end-start << " seconds" << endl;
+  cout << "CLI: Exiting..." << endl;
+
+  return EXIT_SUCCESS;
+}
+

+ 35 - 0
apps/client/main.hpp

@@ -0,0 +1,35 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_MAIN
+#define DEF_MAIN
+
+#include <signal.h>
+
+#include <boost/asio.hpp>
+#include <boost/program_options.hpp>
+
+#include "PIRClient.hpp"
+#include "../client/PIRController.hpp"
+#include "../crypto/HomomorphicCryptoFactory_internal.hpp"
+
+void sighandler(int sig_num);
+
+using namespace std;
+namespace po = boost::program_options;
+
+#endif

+ 6 - 0
apps/optim/CMakeLists.txt

@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.6.0)
+
+include_directories(..)
+include_directories(../..)
+
+add_library(pir_client_optim STATIC PIROptimizer.cpp)

+ 1069 - 0
apps/optim/PIROptimizer.cpp

@@ -0,0 +1,1069 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "PIROptimizer.hpp"
+// Set this to true if the server database is stored in precomputed (e.g. NTT) form
+// TODO this should be an option given on the command line
+#define INITIAL_PRECOMPUTATION_DONE false
+
+static const unsigned int kPrecision = 5;
+const unsigned int PIROptimizer::kalphaBound = 100;
+
+/**
+ *	Class constructor.
+ *	Params :
+ *		- pirClient_ptr client : PIRClient shared_ptr ;
+ *		- int security_bits		 : security bits wanted ;
+ *		- string server_ip		 : IPv4 server adresse	;
+ *		- io_service& ios			 : boost io_service reference, used for boost socket ;
+ **/
+PIROptimizer::PIROptimizer(string server_ip_, int port_, FitnessType fitnessMethod_) :
+  serv_ip(server_ip_),
+  server_optimport(port_),
+  s(ios),
+  // Number of clients the servers would like to handle in parallel : Fixed for the moment (the server will tell in future versions)
+  nbc(1),
+  optimum(fitnessMethod_),
+  silent(false)
+{  
+  // Max latency for the socket when connecting to server
+  struct timeval tv;
+  tv.tv_sec  = 5; 
+  tv.tv_usec = 0;         
+  setsockopt(s.native(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+  setsockopt(s.native(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+}
+
+PIROptimizer::PIROptimizer():
+  s(ios),
+  nbc(1),
+  silent(false)
+{}
+
+
+OptimVars PIROptimizer::optimizeFromServer(FixedVars& partial_fixed_vars, boost::asio::ip::tcp::socket& socket)
+{
+  fixedVars = partial_fixed_vars;
+  getFixedVarsFromServer(fixedVars, socket);
+  getNetworkInfos(fixedVars, socket);
+  optimize(socket, fixedVars, 0);
+  sendExitCommand(socket);
+  return global_optimum;
+}
+void PIROptimizer::optimize(FixedVars& fixed_vars, unsigned int exp_nbr)
+{
+
+	try
+	{
+		s.connect(tcp::endpoint(boost::asio::ip::address::from_string(serv_ip), server_optimport));
+
+    // Tell server we are an optimizer not a client
+    int is_client = 0;
+		write(s, boost::asio::buffer(&is_client, sizeof(int)));
+	}
+	catch (const std::exception& ex)
+	{
+    std::cout << "Optimizer: Unable to connect to "<< serv_ip << " port " << server_optimport <<std::endl;
+	}
+  optimize(s, fixed_vars, exp_nbr);
+}
+
+/**
+ * Main function of PIROptimizer.
+ * Loop on all crypto modules to finc possible parameters
+ * Initialize caches with computing costs
+ * Iterate on all parameters except aggregation
+ * Use findAlphaDicho to explore best aggregation values through dichotomy 
+ **/
+void PIROptimizer::optimize(boost::asio::ip::tcp::socket& s, FixedVars& fixed_vars, unsigned int exp_nbr)
+{
+  std::regex *cp_rex;
+  fixedVars = fixed_vars;
+  // Do we optimize the sum of all the times or we consider the client and the server as pipelines (sum of max) ?
+  fitnessMethod = fixedVars.fitness;
+  std::cout << "Optimizer: Using fitness method " << fitnessMethod << " (use --help for code translation)" << std::endl;
+
+  set<std::string> crypto_params_desc_set;
+  vector<HomomorphicCrypto*> crypto_systems_vec;
+
+  // Get all the crypto modules
+  HomomorphicCryptoFactory_internal::getAllCryptoSystems(crypto_systems_vec);
+
+  if(fixedVars.manual_crypto_params == "")
+  {
+    noCryptoSystemOptim(exp_nbr);
+  }
+  else
+  {
+    std::cout << "Optimizer: Crypto parameters manually forced to " << fixedVars.manual_crypto_params << std::endl;
+
+    // Get a regular expression from the requested params
+    cp_rex = new std::regex(fixedVars.manual_crypto_params); 
+
+    // Only take into account NoCryptography as a possibility if requested
+    if(std::regex_match("NoCryptography", *cp_rex))
+    {
+      noCryptoSystemOptim(exp_nbr);
+    }
+  }
+//    else
+//    {
+//      std::vector<std::string> fields;
+//      boost::algorithm::split(fields, fixedVars.manual_crypto_params, boost::algorithm::is_any_of(":"));
+//      HomomorphicCrypto* h;
+//
+//      h = HomomorphicCryptoFactory_internal::getCrypto(fields[0]);
+//      crypto_systems_vec.push_back(h);
+//    }
+//  }
+
+
+  // Iterate on all crypto modules
+  for (auto crypto_system_ptr : crypto_systems_vec)
+  {
+    crypto = crypto_system_ptr;
+    //Get i-th crypto module's public parameter
+    currentPublicParams = &crypto->getPublicParameters();
+  
+    // Get all the proposed parameter sets for the requested security on this crypto module
+    crypto->getCryptoParams(fixedVars.k, crypto_params_desc_set); 
+    
+    // If special parameters requested, remove all those that don't match the regexp
+    if(fixedVars.manual_crypto_params != "")
+    {
+		const   set<std::string> crypto_params_desc_set_copy=crypto_params_desc_set;
+		
+      for (auto cp_ptr : crypto_params_desc_set_copy)
+      {
+        if (!std::regex_match(cp_ptr, *cp_rex)) crypto_params_desc_set.erase(cp_ptr);
+        //HomomorphicCrypto* h;
+
+        //h = HomomorphicCryptoFactory_internal::getCrypto(fields[0]);
+        //crypto_systems_vec.push_back(h);
+      }
+      if (crypto_params_desc_set.size() == 0) continue;
+      //crypto_params_desc_set.insert(fixedVars.manual_crypto_params);
+    }
+    // Add to cost dictionnaries (abs_cache and precompute_cache) estimates from server 
+    // or pre-established values if no server available
+		getAbsAndPreCachesFromServer(s, crypto);
+    // Add to cost dictionnaries (encryptcache, decryptcache) cost estimates (pot. precomputed)
+    getPreComputedData(crypto);
+
+    // Iterate on all the parameters for this crypto module
+    for (std::string crypto_params_desc : crypto_params_desc_set)
+    {
+      // Set the current public parameters to the parameter set values
+      currentPublicParams->computeNewParameters(crypto_params_desc);
+      // Iterate on the dimensions
+      for (unsigned int d = fixedVars.dMin ; d  <= fixedVars.dMax ; d++) 
+      {
+        // Define a OptimVars object (with the variables that we can choose for optimization)
+        OptimVars vars(fixedVars.fitness, fixedVars);
+        vars.crypto_params = crypto_params_desc;
+        // Get best alpha for this iteration given the fitness method and set the variables in vars accordingly
+        // - First do a test with no aggreggation
+        findAlpha(d, 1, 1, vars, exp_nbr);
+        // - Then search with dichotomy 
+        findAlphaDicho(0, getMaxAlpha(), d, exp_nbr, vars);
+      }
+    }
+    // Show and write the optimized values.
+    processResults(exp_nbr);
+    
+    // Save best optimum inter cryptosystems
+    std::cout << "Optimizer: Comparing (" << optimum.crypto_params << ", " << optimum.getValue() << ") with (" << global_optimum.crypto_params << ", " << global_optimum.getValue() << ")" << std::endl;
+    if(optimum < global_optimum)
+    {
+      global_optimum = optimum;
+    }
+    std::cout << "Optimizer: Winner is (" << global_optimum.crypto_params << ", " << global_optimum.getValue() << ")" << std::endl;
+
+    // Clean
+    optimum.reset();
+    crypto_params_desc_set.clear();
+    delete crypto;
+  }
+  disconnect();
+  
+  // If nothing was found say it and exit
+  if (global_optimum.crypto_params == "No crypto params")
+  {
+    std::cout << "Optimizer: No valid crypto parameters matching " << fixedVars.manual_crypto_params << " found, exiting ..." << std::endl;
+    exit(0);
+  }
+}
+
+/**
+ *  Set optimum with values giving by a trivial PIR. (i.e download the entiere database) 
+ **/
+void PIROptimizer::noCryptoSystemOptim(unsigned int exp_nbr)
+{
+  optimum.crypto_params = "NoCryptography";
+  optimum.setFixedVars(fixedVars);
+  optimum.setGenQ(0);
+  optimum.setSendQ(0);
+  optimum.setGenR(0);
+  optimum.setSendR((fixedVars.l * fixedVars.n) / fixedVars.Tdoc);
+  optimum.setDecR(0);
+  optimum.setDim(1);
+  optimum.setAlpha(fixedVars.n);
+  if (silent == false) showBestResults(exp_nbr);
+  
+  // Save this as the best result inter cryptosystems
+  global_optimum = optimum;
+
+  optimum.reset();
+}
+
+
+/**
+ *  Find Iteratively the best alpha and set the optimal variables in var
+ **/
+void PIROptimizer::findAlpha(unsigned int d, OptimVars& vars, unsigned int exp_nbr)
+{
+  // alphaMax == 0 is a convention to note that no limit should be done in aggregation
+  unsigned int alpha_max = (fixedVars.alphaMax == 0) ? fixedVars.n : fixedVars.alphaMax;
+  //Really get best alpha between 0 and alpha_max
+  findAlpha(d, 0, alpha_max, vars, exp_nbr);
+}
+
+void PIROptimizer::findAlpha(unsigned int d, unsigned int alpha_min, unsigned int alpha_max, OptimVars& vars, unsigned int exp_nbr)
+{
+  // Number of bits that can be absorbed by a ciphertext for our parameters
+  long abs_bit;
+  // If aggregation is done, try to use all plaintext space
+  unsigned int minimum_reasonable_alpha = getMinAlpha(); 
+  // Iterate on possible aggregation values
+  for (unsigned int current_alpha = alpha_min ; current_alpha <= alpha_max ; current_alpha+=minimum_reasonable_alpha)
+  {
+    // In first iteration current_alpha=0 is treated as 1 (i.e. no aggregation)
+    computeOptimVars(current_alpha, d, vars); 
+    
+    // If no bits can be absorbed for this choice ignore it
+    abs_bit = crypto->getPublicParameters().getAbsorptionBitsize();
+    if(abs_bit <= 0)
+    {
+      cout << "PIROptimizer: Unusable cryptoparams, ignoring them" << endl; 
+      break;
+    }
+    // Write test result to output file
+    OptimService::writeTestCurrentResult(1, alpha_max, current_alpha, 1, alpha_max, d, exp_nbr, vars);
+  }
+}
+
+void PIROptimizer::findAlphaDicho(unsigned int inf, unsigned int sup, unsigned int d, unsigned int exp_nbr, OptimVars& vars)
+{
+  unsigned int min_alpha = getMinAlpha();
+
+  //When the space to explore is relatively little we use an iterative method to steer clear of local optima.
+  if ((sup - inf) <= 100)
+  {
+    unsigned int max_alpha_bound = 0;
+		if (fixedVars.n < (sup * min_alpha))
+			max_alpha_bound = fixedVars.n;  
+
+		else 
+			max_alpha_bound = min(fixedVars.alphaMax, max(kalphaBound, sup * min_alpha)); 
+
+		findAlpha(d, inf * min_alpha, max_alpha_bound, vars, exp_nbr);
+		return;
+  }
+
+  //Next value to test.
+  unsigned int alpha_bound = inf + (sup - inf) / 2.0;
+  //Return the state of the slope (up or down).
+  int val = slop(alpha_bound, inf, sup, d, vars, exp_nbr);
+  //Write test restult to output file.
+  OptimService::writeTestCurrentResult(1, sup*getMinAlpha(), alpha_bound*getMinAlpha(), inf*getMinAlpha(), sup*getMinAlpha(), d, exp_nbr, vars);
+
+  if(val == -1) {  
+    findAlphaDicho(alpha_bound, sup, d, exp_nbr, vars);
+    return;
+  }
+  findAlphaDicho(inf, alpha_bound, d, exp_nbr, vars);
+}
+
+
+int PIROptimizer::slop(unsigned int alphaMul, unsigned int inf, unsigned int sup,  unsigned int d, OptimVars& vars, unsigned int exp_nbr)
+{
+  // Try ten uniformly spaced values ahead to try to find a better result
+  unsigned int deltaright = (sup-1-alphaMul)/10;
+  unsigned int deltaleft = (alphaMul - inf-1)/10;
+  unsigned int minalpha = getMinAlpha();
+  double vright, vleft, vtmp;
+  // Ten increasing tests take the best
+  // ten decreasings tests take the best
+  // compare the two bests to determine the slope
+  // each side must have alphaMul+-1 at least
+  vright = computeOptimVars((alphaMul + 1) * minalpha, d, vars); 
+  for (unsigned int i = 1 ; i <= 10 ; i++)
+  {
+    vtmp = computeOptimVars((alphaMul + 1 + i * deltaright) * minalpha, d, vars);
+    if (vtmp <= vright) vright = vtmp; 
+  }
+  vleft = computeOptimVars((alphaMul - 1) * minalpha, d, vars); 
+  for (unsigned int i = 1 ; i <= 10 ; i++)
+  {
+    vtmp = computeOptimVars((alphaMul - 1 - i * deltaleft) * minalpha, d, vars);
+    if (vtmp <= vleft) vleft = vtmp; 
+  }
+
+  return (vright < vleft - 10e-8) ? -1 : 1 ;
+}
+
+
+/**
+ * Compute dimension sizes for a d-dimensional hypercube of n elements.
+ * Params:
+ * 	- unsigned int n: the number of elements
+ * 	- unsigned int alpha: the aggregation value
+ * 	- unsigned int d: the dimension
+ * 	- unsigned int *dn: computed dimension sizes (output) 
+ **/
+void PIROptimizer::getDimSize(unsigned int n, unsigned int alpha, unsigned int d, unsigned int *dn)
+{
+
+  unsigned int prod = 1, j = 0;
+
+  // Elements in the database after the aggregation 
+  unsigned int new_n = ceil(static_cast<double>(n)/static_cast<double>(alpha)); //PAtch tres sale à reprendre
+  // Dimension sizes. Product must be > n/alpha
+  unsigned int factors[d];
+
+  // Lower bound on the dimensions sizes needed. Correct only if n/alpha is a d-power.
+  for (unsigned int i = 0 ; i < d ; i++) factors[i] = floor(pow(new_n,1./d));
+
+  // If n/alpha is not a d-power 
+  if (static_cast<double>(factors[0]) != pow(new_n, static_cast<double>(1.0 /  static_cast<double>(d))) )
+  {
+    // Increment each factor by one until the product of the dimension sizes is above n/alpha
+    while (prod < new_n && j < d)
+    {
+      prod = 1;
+      factors[j++]++;
+
+      for (unsigned int i = 0 ; i < d ; i++)
+        prod *= factors[i];
+    }
+  }
+
+  // Copy the result to the output
+  memcpy(dn, factors, sizeof(factors));
+}
+
+
+/**
+ *	Compute time needed to send the request.
+ * 	Params:
+ * 		- double Tupc : client upload throughput
+ * 		- double Tdos : server download throughput
+ * 		- unsigned int nbc : number of clients that share server throughput (currently always 1);
+ * 		- unsigned int d   : number of dimensions used for recursion
+ *
+ * 	Return:
+ * 		- double : time in seconds to send the PIR query.
+ **/
+double PIROptimizer::getSendCost(double Tupc, double Tdos, unsigned int nbc, unsigned int d, unsigned int* dn)
+{
+  // Available throughput for the transfer
+  double min_throughput = min(Tupc, Tdos/nbc );
+  // Time needed to send the query
+  double SenQ = 0.0;
+
+  // Sum the times needed for the subqueries of each dimension in the recursion 
+  for (unsigned int i = 0 ; i < d ; i++)
+  {
+    // For a given dimension time = size / throughput and size = (nb_elements * size_of_an_element)
+    SenQ +=	(dn[i] * Tcq(i)) / min_throughput;
+  }
+  //std::cout << "dn[0]="<<dn[0]<<" d=" << d << " Tcq(0)=" << Tcq(0) << " Tupc=" << Tupc << " Tdos=" << Tdos << " SenQ=" << SenQ << std::endl;
+
+  return SenQ;
+}
+
+
+/**
+ *	Compute reply generation cost.
+ *	Params:
+ * 		- unsigned int d   : number of dimension used for recursion
+ * 		- unsigned int Tmi : plaintext size on the i-th level of recursion
+ *
+ * 	Return:
+ * 		- double : time in second to generate a reply.
+ **/
+double PIROptimizer::getReplyGenCost(unsigned int alpha, unsigned int d, unsigned int *dn)
+{
+  long double prod, GenR = 0;
+  uint64_t plaintext_nbr_post_ntt, plaintext_nbr_pre_ntt;
+  bool initialprecomputationdone = INITIAL_PRECOMPUTATION_DONE;
+  
+  // In order to compute absorption size we must define it first
+  crypto->setandgetAbsBitPerCiphertext(dn[0]);
+
+  for (unsigned int i = 0 ; i < d ; i++)
+  {
+    // Compute how many elements has the intermediate database
+    prod = 1;
+    for (unsigned int j = i ; j < d ; j++)
+    { 
+      prod *= dn[j];
+    }
+
+    // Compute how large they are
+    plaintext_nbr_post_ntt = ceil((double) eltSize(alpha,i) / (double) crypto->getPublicParameters().getAbsorptionBitsize(i)); 
+    plaintext_nbr_pre_ntt = ceil((double) eltSize(alpha,i) / (double) crypto->getPublicParameters().getCiphertextBitsize()/2); 
+
+    
+    // Consider absorption cost
+    GenR += prod * plaintext_nbr_post_ntt * getAbs1PlaintextTime(crypto);
+    
+    // And potentially precomputation cost
+    if (i > 0 || initialprecomputationdone == false)
+    {
+      GenR += prod * plaintext_nbr_pre_ntt * getPrecompute1PlaintextTime(crypto);
+    }
+  }
+  return GenR;
+}
+
+/**
+ *	Compute the size of a element at dimension "i".
+ *	Params :
+ *		- unsigned int i   : dimension ;
+ *		- unsigned int Tmi : encrypted size.
+ *
+ *	Return :
+ *		- double : the size of an element at dimension "i".
+ **/
+double PIROptimizer::eltSize(unsigned int alpha, unsigned int i)
+{
+  if (i == 0)
+  {
+    return static_cast<double>(fixedVars.l * alpha); 
+  }
+  return ceil( static_cast<double>(eltSize(alpha, i - 1) /  Tp(i-1) )) * Tcr(i-1); 
+}
+
+double PIROptimizer::Tp(unsigned int i)
+{
+  return currentPublicParams->getAbsorptionBitsize(i);
+}
+
+/**
+ *	Compute decryption cost.
+ *	Params :
+ *		- unsigned int d   : dimension ;
+ *		- unsigned int Tmi : encrypted size.
+ *
+ *	Return :
+ *		- double : time in seconds to decrypt something with given paramtes.
+ **/
+double PIROptimizer::getDecryptCost(unsigned int alpha, unsigned int d)
+{
+  double DecR = 0;
+
+  for (unsigned int i = 0 ; i < d ; i++)
+  {
+    // Yet another strange formula
+    DecR += ceill((eltSize(alpha, i + 1) / Tcr(i))) * getDecCost();
+  }
+
+  return DecR;
+}
+
+/**
+ * Return the size of reply for dimension "i"
+ **/
+inline double PIROptimizer::Tcr(unsigned i)
+{
+  return currentPublicParams->getCiphBitsizeFromRecLvl(i+1);
+}
+
+/**
+ * Return the size of a query for dimension "i"
+ **/
+inline double PIROptimizer::Tcq(unsigned i)
+{
+  return Tcr(i);
+}
+
+/**
+ * Return the time in secondes to decrypt data  at dimension "i"
+ **/
+double PIROptimizer::getDecCost(unsigned int d, crypto_ptr crypto)
+{
+  PIRParameters pirParams; //Works for d = 1 
+  pirParams.d = 1;
+  pirParams.alpha = 1;
+  unsigned int chunks = 1;
+  double start, stop, elapsed_time = 0;
+
+  // Needed for calls to getAbsorptionBitsize
+  crypto->setandgetAbsBitPerCiphertext(1); // Set internally best absorption possible 
+  
+  // Use a special function to generate a ciphertext to be sure its decryption cost is average
+  char* encrypted_data = (char*) crypto->encrypt_perftest();
+  PIRReplyExtraction_internal replyExt(pirParams,*crypto); 
+
+  shared_queue<char*> clearChunks("clear_chunks");
+
+  do{
+    chunks *= 2;
+    for(unsigned int i = 0 ; i < chunks ; i++) //Fill, reply buffer with copy of "encrypted_data".
+    {
+      char* encrypted_data_copy = (char*) malloc((crypto->getPublicParameters().getCiphertextBitsize()/8) * sizeof(char));
+      memcpy(encrypted_data_copy, encrypted_data, crypto->getPublicParameters().getCiphertextBitsize()/8);
+      replyExt.repliesBuffer.push(encrypted_data_copy);
+    }
+
+
+    start = omp_get_wtime();
+    replyExt.extractReply((currentPublicParams->getAbsorptionBitsize()/8) * chunks, &clearChunks); //Do a PIR data extraction.
+    stop  = omp_get_wtime();
+
+    while(!clearChunks.empty())
+      free(clearChunks.pop_front()); //free clear data.
+
+  }while((elapsed_time = (stop - start)) < 0.20);
+
+  double result = elapsed_time / chunks;
+
+  return result;
+}
+
+double PIROptimizer::getDecCost()
+{
+  bool shortversion=true;
+  return decrypt_cache[currentPublicParams->getSerializedParams(shortversion)];
+}
+
+/**
+ *	Compute SendR.
+ *	Params :
+ *		- double Tups : server upload time/bit ;
+ *		- double Tdoc : client download time/bit;
+ *		- unsigned int nbc : number of client ;
+ *		- unsigned int Tmi : encrypted size.
+ *	Return :
+ *	  - double : Duration in seconds.
+ **/
+double PIROptimizer::getReceiveCost(unsigned int alpha, double Tups, double Tdoc, unsigned int nbc, unsigned int d)
+{
+  // This is a bad clone of eltSize. To be removed.
+  //double SendR = eltSize(alpha, 0);
+  //
+  //for (unsigned int i = 0 ; i < d; i++)
+  //{
+  //  SendR = ceil(SendR / Tp(i)) * Tcr(i);
+  //}
+  //SendR /= min(Tups/nbc, Tdoc); 
+  //
+  //return SendR;
+
+  // eltSize computes how db elements grow with recursion. 
+  // Reply size is what would be the element size for the d-th recursion (rec levels start at 0)
+  return eltSize(alpha,d)/min(Tups/nbc, Tdoc);
+}
+
+/**
+ *	Get absorption time for 1 bit.
+ *	Param :
+ *		- unsigned int d : dimension.
+ **/
+void PIROptimizer::getAbsAndPreCachesFromServer(boost::asio::ip::tcp::socket& s, crypto_ptr crypto_system)
+{
+  size_t cmd = ABS;
+  try
+  {
+
+    write(s, boost::asio::buffer(&cmd, sizeof(size_t)));
+
+    std::string crypto_name = crypto_system->toString();
+    unsigned int crypto_name_size = crypto_name.size();
+    std::cout << "Optimizer: Requesting absorption and precomputation costs file for " << crypto_name << std::endl;
+
+    write(s, boost::asio::buffer(&crypto_name_size, sizeof(int)));
+    write(s, boost::asio::buffer(crypto_name));
+
+    int file_content_size = 0;
+    read(s, boost::asio::buffer(&file_content_size, sizeof(int)));
+
+#ifdef DEBUG
+    std::cout << "Optimizer: File contents size " << file_content_size << std::endl;
+#endif 
+
+    char file_content[file_content_size + 1];
+    file_content_size = read(s, boost::asio::buffer(file_content, file_content_size));
+    file_content[file_content_size] = '\0';
+
+    makeAbsAndPrecomputeCaches(file_content);
+  }
+  catch(std::exception const& ex)
+  {
+    cout << "Optimizer: No server, using reference values for " << crypto_system->toString() << endl;
+    abs_cache.clear(); 
+    precompute_cache.clear(); 
+
+    set<string> crypto_params_set;
+    crypto_system->getAllCryptoParams(crypto_params_set);
+
+    for (auto crypto_param : crypto_params_set)
+    {
+      abs_cache[crypto_param] = crypto_system->estimateAbsTime(crypto_param);
+      precompute_cache[crypto_param] = crypto_system->estimatePrecomputeTime(crypto_param);
+    }
+  }
+}
+
+void PIROptimizer::makeAbsAndPrecomputeCaches(char* serialized_cache)
+{
+  abs_cache.clear();
+  precompute_cache.clear();
+  std::vector<string> lines;
+  boost::algorithm::split(lines, serialized_cache, boost::algorithm::is_any_of("\n"));
+
+  for (auto line : lines)
+  {
+    std::cout << line << std::endl;
+    vector<string> fields;
+    boost::algorithm::split(fields, line, boost::algorithm::is_any_of(" "));
+
+    if (fields.size() == 3)
+    {
+      abs_cache[fields.at(0)] = atof(fields.at(1).c_str());
+      precompute_cache[fields.at(0)] = atof(fields.at(2).c_str());
+    }
+    else if (line.find_first_not_of(' ') != std::string::npos)// if it is not a blank line
+    {
+      std::cout << "PIROptimizer: Absorption and precompute cache corrupted" << std::endl;
+      std::cout << "PIROptimizer: Remove files in exp/*.abs in the server before proceeding" << std::endl;
+      exit(1);
+    }
+  }
+}
+
+/**
+ *	Compute the time for generate the complete query.
+ *	Params :
+ *		 - unsigned int d : dimension ;
+ *		 - crypto_ptr	crypto : HomomorphicCrypto shared_ptr ;
+ *
+ *	Return :
+ *		- double : Complete query duration.
+ **/
+double PIROptimizer::getGenQueryCost(unsigned int d, unsigned int *dn)
+{
+  double GenQ = 0.0;
+  bool shortversion = true;
+  string current_crypto_params = currentPublicParams->getSerializedParams(shortversion);
+
+  for (unsigned int i = 0 ; i < d ; i++)
+  {
+    GenQ += dn[i]  * encrypt_cache[current_crypto_params];
+  }
+
+  return GenQ;
+}
+
+/**
+ *	Get time to encrypt a query for a given dimension.
+ * 	Params :
+ * 		- unsigned int d : dimension ;
+ *		- crypto_ptr	crypto : HomomorphicCrypto shared_ptr ;
+ *
+ *	Return :
+ *		- double : Duration in seconds.
+ **/
+double PIROptimizer::getQueryElemGenCost(unsigned int d, crypto_ptr crypto)
+{
+  double start, stop; 
+  double elapsed_time = 0;
+  unsigned int query_elts_nbr = 0;
+  PIRParameters pirParams;
+
+  pirParams.d = d;
+  pirParams.alpha = 1;
+
+  for (unsigned int i = 0 ; i < d; i++)
+    pirParams.n[i] = 1;
+
+  // Needed for calls to getAbsorptionBitsize
+  crypto->setandgetAbsBitPerCiphertext(1); // Set internally best absorption possible 
+  
+  PIRQueryGenerator_internal queryGenerator(pirParams, *crypto); 
+  queryGenerator.setChosenElement(1);
+
+  do{
+    for (unsigned int i = 0 ; i < d; i++) pirParams.n[i] *= 2;
+
+    start = omp_get_wtime();
+    queryGenerator.generateQuery();
+    stop = omp_get_wtime();
+
+    queryGenerator.cleanQueryBuffer();
+
+  }while((elapsed_time = (stop - start)) <= 0.5);
+
+  for(unsigned int i = 0 ; i < d ; i++) query_elts_nbr += pirParams.n[i];
+
+  double result = elapsed_time / query_elts_nbr;
+  return result;
+}
+
+const PIRParameters& PIROptimizer::getParameters()
+{
+  return pirParameters;
+}
+
+double PIROptimizer::getAbs1PlaintextTime(HomomorphicCrypto* crypto_system)
+{
+  bool shortversion = true; 
+  return abs_cache[currentPublicParams->getSerializedParams(shortversion)];
+}
+
+
+double PIROptimizer::getPrecompute1PlaintextTime(HomomorphicCrypto* crypto_system)
+{
+  bool shortversion = true; 
+  return precompute_cache[currentPublicParams->getSerializedParams(shortversion)];
+}
+
+
+/**
+ *	Return natural aggregation value.
+ **/
+unsigned int PIROptimizer::getMinAlpha()
+{
+  double r = ceil(Tp(0) / static_cast<double>(fixedVars.l));
+  r = (r > fixedVars.n) ? fixedVars.n : r; 
+  unsigned ret = (r < 1.0) ? 1 : unsigned(r);
+
+	/*No limit for agregation*/
+	if (fixedVars.alphaMax == 0)
+		return ret;
+
+	else
+		return min(ret, fixedVars.alphaMax);
+}
+
+unsigned int PIROptimizer::getMaxAlpha()
+{
+  return ((fixedVars.alphaMax == 0) || (fixedVars.n < fixedVars.alphaMax)) ? fixedVars.n : fixedVars.alphaMax;
+}
+
+
+/**
+ * Given the fixed vars and the choices done in the optimize loop, estimate costs.
+ * If total cost is better than the previus optimum, replace it.  
+ * Return total cost of the PIR retrieval (given the fitness method in vars).
+ **/
+double PIROptimizer::computeOptimVars(unsigned int alpha, unsigned int d, OptimVars& vars)
+{
+  if (alpha == 0) alpha = 1;
+
+  unsigned int dn[fixedVars.dMax];
+
+  // Compute dimension sizes given the number of files, aggregation, and recursion levels
+  getDimSize(fixedVars.n, alpha, d, dn);
+  //Save alpha and d values.
+  vars.setAlpha(alpha);
+  vars.setDim(d);
+  
+  crypto->setandgetAbsBitPerCiphertext(dn[0]);
+
+
+  // Get costs for query generation, emission, reply generation, reception, and decryption
+  vars.setGenQ(getGenQueryCost(d, dn));
+  vars.setSendQ(getSendCost(fixedVars.Tupc, fixedVars.Tdos, nbc, d, dn));
+  vars.setGenR(getReplyGenCost(alpha, d, dn)); 
+  vars.setSendR(getReceiveCost(alpha, fixedVars.Tups, fixedVars.Tdoc, nbc, d)); 
+  vars.setDecR(getDecryptCost(alpha, d)); 
+
+  // Decide whether this test is better than the optimum. If so replace it.
+  analyseResult(alpha, d, vars); 
+
+  // Return total cost of the PIR retrieval (given the fitness method in vars)
+  return vars.getValue();
+}
+
+
+void PIROptimizer::processResults(unsigned int i)
+{
+  if (silent == false) showBestResults(i);
+  writeTestBestResult(i);
+}
+
+/**
+ *	Test current result to get the optimum.
+ **/
+void PIROptimizer::analyseResult(unsigned int alpha, unsigned int d, OptimVars& vars)
+{
+  bool shortversion = true;
+
+  // < operator is defined in OptimVars object, compares total cost value
+  if(vars < optimum)
+  {
+    // If vars is better than the current optimum redefine it
+    optimum = vars;
+
+    // Get a final version of the parameters with the absorption size
+    optimum.crypto_params = crypto->getSerializedCryptoParams(!shortversion);
+#ifdef DEBUG
+    cout << "PIROptimizer: New optimum cryptoparams " << optimum.crypto_params << endl;
+#endif
+  }
+}
+
+void PIROptimizer::getFixedVarsFromServer(FixedVars& fixed_vars, boost::asio::ip::tcp::socket& s)
+{
+  try{
+    /*Send command*/
+    size_t cmd = DATA;
+    write(s, boost::asio::buffer(&cmd, sizeof(cmd)));
+    /*Get number of files*/
+    read(s, boost::asio::buffer(&fixed_vars.n, sizeof(fixed_vars.n)));
+    cout << "Optimizer: Number of files is " << fixed_vars.n << endl;
+
+    /*Get max file size*/
+    read(s, boost::asio::buffer(&fixed_vars.l, sizeof(fixed_vars.l)));
+    cout << "Optimizer: File bytesize is " << fixed_vars.l << endl;
+    // fixed_vars.l should be in bits
+    fixed_vars.l*=8;
+  }catch(const std::exception& ex)
+  {
+    std::cerr << "Catched exception in " << __FUNCTION__ << ": " << ex.what() << std::endl;
+  }
+}
+
+/**
+ *	Print the best result.
+ **/
+void PIROptimizer::showBestResults(unsigned int i)
+{
+  writeBigMessage(" RESULTS exp " + to_string(i+1) + " ");
+  cout << "\tparams : " << optimum.crypto_params  << endl;
+  cout << "\td      : "	<< optimum.getDim()	      << endl;
+  cout << "\talpha  : "	<< optimum.getAlpha()     << endl;
+  cout << "\tGenQ   : "	<< optimum.getGenQ()      << " sec" <<  endl;
+  cout << "\tSenQ   : " << optimum.getSendQ()     << " sec" <<  endl;
+  cout << "\tGenR   : "	<< optimum.getGenR()      << " sec" <<  endl;
+  cout << "\tSendR  : " << optimum.getSendR()	    << " sec" <<  endl;
+  cout << "\tDecR   : "	<< optimum.getDecR() 	    << " sec" <<  endl;
+  cout << "\tTotal Time : "<< optimum.getValue()  << " sec" <<  endl;
+  cout << "\t--Fixed Vars-- "                     << endl;
+  cout << "\tl      : "  << fixedVars.l << " bits"<< endl;
+  cout << "\tn      : "  << fixedVars.n           << endl;
+  cout << "\tTupc/dos : "<< fixedVars.Tupc << " b/s" << endl;
+  cout << "\tTdoc/ups : "<< fixedVars.Tdoc << " b/s" << endl;
+
+  writeBigMessage("##############");
+}
+
+void PIROptimizer::getPreComputedData(HomomorphicCrypto* crypto)
+{
+  std::string	fdec_path(OptimService::folderName + OptimService::fileName + crypto->toString() 
+      + OptimService::decFileExtension);
+  std::string	fenc_path(OptimService::folderName + OptimService::fileName + crypto->toString() 
+      + OptimService::encFileExtension);
+
+  decrypt_cache.clear();
+  encrypt_cache.clear();
+
+  set<string> crypto_params_set;
+  crypto->getAllCryptoParams(crypto_params_set);
+
+  //if (OptimService::verifyOptimData(crypto_params_set, fdec_path, fenc_path))
+  if (OptimService::fileOutdated(crypto->toString(), OptimService::encFileExtension) || 
+      OptimService::fileOutdated(crypto->toString(), OptimService::decFileExtension) )
+  {
+    cout << "PIROptimizer:: Computing cache data for " <<  crypto->toString() << ", this can take a while..." << endl;
+    computeOptimData(crypto_params_set);
+    cout << "PIROptimizer: Finished computing cache data for "<< crypto->toString() << endl;
+  }
+  else
+  {
+    OptimService::readOptimData(decrypt_cache, fdec_path);
+    OptimService::readOptimData(encrypt_cache, fenc_path);
+  }
+}
+
+void PIROptimizer::computeOptimData(set<string> &crypto_params_set )
+{
+  unsigned int i = 1;
+  unsigned int crypto_params_nbr = crypto_params_set.size();
+  string optim_data2write;
+
+  // Generate the encryption performance cache
+  std::string file_path(OptimService::folderName + OptimService::fileName + crypto->toString());
+  for (auto crypto_param : crypto_params_set)
+  {
+    cout << "PIROptimizer: Encrypt cache generation for " << crypto_param << " " << i++ 
+      << "/" << crypto_params_nbr << "." << flush;
+    crypto->setNewParameters(crypto_param);
+    cout << "." << endl;
+
+    encrypt_cache[crypto_param] = getQueryElemGenCost(1, crypto);
+    
+    std::ostringstream out;
+    out << std::setprecision(kPrecision) << encrypt_cache[crypto_param];
+    optim_data2write += crypto_param + " " + out.str() + "\n";
+  }	
+  if(OptimService::writeOptimDataBuffer(optim_data2write, file_path+OptimService::encFileExtension)) 
+  {
+    std::cout << "PIROptimizer: Error when writing optimization data, aborting." << std::endl;
+    exit(1);
+  }
+  optim_data2write = "";
+  i=1;
+
+  // Generate the decryption performance cache
+  for (auto crypto_param : crypto_params_set)
+  {
+    cout << "PIROptimizer: Decrypt cache generation for " << crypto_param << " " << i++ 
+      << "/" << crypto_params_nbr << "." << flush;
+    crypto->setNewParameters(crypto_param);
+    cout << "." << endl;
+
+    decrypt_cache[crypto_param] = getDecCost(1, crypto);
+    
+    std::ostringstream out;
+    out << std::setprecision(kPrecision) << decrypt_cache[crypto_param];
+    optim_data2write += crypto_param + " " + out.str() + "\n";
+  }	
+  if(OptimService::writeOptimDataBuffer(optim_data2write, file_path+OptimService::decFileExtension)) 
+  {
+    std::cout << "PIROptimizer: Error when writing optimization data, aborting." << std::endl;
+    exit(1);
+  }
+
+}
+
+/**
+ *	Writes values of the best result.
+ **/
+void PIROptimizer::writeTestBestResult(unsigned int i)
+{
+  OptimService::writeMessage(i, "### BEST RESULT ###");
+  OptimService::writeFootFile(i);
+  OptimService::writeConfigFile(getMinAlpha(),  optimum.getAlpha(), optimum.getDim(), i);
+}
+
+/**
+ *  Disconect to the sever's optimizer.
+ **/
+void PIROptimizer::disconnect()
+{
+  try
+  {
+    size_t cmd = EXIT;
+    s.send(boost::asio::buffer(&cmd, sizeof(size_t)));// exit function
+    s.close();
+  }catch (const std::exception& ex)
+  {}
+}
+
+void PIROptimizer::connect()
+{
+  try
+  {
+    tcp::endpoint endpoint(boost::asio::ip::address::from_string(serv_ip), server_optimport);
+    s.connect(endpoint);
+  }catch(const std::exception& ex )
+  {
+
+  }
+
+}
+
+/**
+ *	Print "big" message on the terminal.
+ **/
+void PIROptimizer::writeBigMessage(string msg)
+{
+  std::transform(msg.begin(), msg.end(), msg.begin(), ::toupper);
+  cout << "########" << msg << "########" << endl;
+}
+
+PIROptimizer::~PIROptimizer()
+{
+}
+
+/**
+ * Do a network speed test with the server.
+ * Params :
+ * 	- int port : server port
+ **/
+void PIROptimizer::getNetworkInfos(FixedVars& fixedVars, boost::asio::ip::tcp::socket& s)
+{
+  double start = 0, end=0, loop = 1;
+  char *msg = (char *) malloc(MEGA_BYTE+4);
+  unsigned int read_size = 0;
+  memset(msg, 1, MEGA_BYTE);
+
+  size_t cmd = SPEED;
+
+  /*Send command*/
+  write(s, boost::asio::buffer(&cmd, sizeof(size_t)));
+
+  // Do upload test
+  start = omp_get_wtime();
+  for (int i = 0 ; i < loop ; i++) write(s, boost::asio::buffer(msg, MEGA_BYTE));
+  end = omp_get_wtime();
+  
+  // Ignore it if value was forced
+  if (fixedVars.Tupc != 0)
+  {
+    cout << "Optimizer: Upload speed value forced, dropping network test result" << std::endl;
+  }
+  else
+  {
+    fixedVars.Tupc = (loop /(end - start)) * 8 * MEGA_BYTE;
+    fixedVars.Tdos = fixedVars.Tupc;  
+
+    cout << "Optimizer: Upload speed test gives " << fixedVars.Tupc << " bits/s" << endl;
+  }
+
+  // Do download tests
+  start = omp_get_wtime();
+  for (int i = 0 ; i < loop ; i++) read(s, boost::asio::buffer(msg, MEGA_BYTE));
+  end = omp_get_wtime();
+
+  if (fixedVars.Tdoc != 0)
+  {
+    cout << "Optimizer: Download speed value forced, dropping network test result" << endl;
+  }
+  else
+  {
+    fixedVars.Tdoc =  loop / (end - start) * 8 * MEGA_BYTE;
+    fixedVars.Tups = fixedVars.Tdoc;
+
+    cout << "Optimizer: Download speed test gives " << fixedVars.Tdoc << " bits/s" << endl;
+  }
+  free(msg);
+}
+
+void PIROptimizer::sendExitCommand(boost::asio::ip::tcp::socket& s)
+{
+  try{
+    size_t cmd = EXIT;
+    write(s, boost::asio::buffer(&cmd, sizeof(cmd)));
+  }catch(std::exception const& ex)
+  {
+    cerr << "Error when sending EXIT command to the server: " << ex.what() << endl;
+  }
+}

+ 148 - 0
apps/optim/PIROptimizer.hpp

@@ -0,0 +1,148 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_PIROPTIMIZER
+#define DEF_PIROPTIMIZER
+
+#include <math.h>
+#include <map>
+#include <limits>
+#include <iomanip>
+#include <string>
+#include <iostream>
+#include <algorithm>
+#include <omp.h>
+#include <regex>
+#include <boost/asio.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include "pir/optim/OptimVars.hpp"
+#include "pir/optim/OptimService.hpp"
+#include "pir/PIRParameters.hpp"
+#include "pir/queryGen/PIRQueryGenerator_internal.hpp"
+#include "pir/replyExtraction/PIRReplyExtraction_internal.hpp"
+#include "crypto/HomomorphicCryptoFactory_internal.hpp"
+#include "crypto/NFLLWEPublicParameters.hpp"
+#include "pir/ClientDefines.hpp"
+#include "pir/PIROptimizerCommand.hpp"
+
+#ifndef MODULBITS
+#define MODULBITS 1024
+#endif
+
+#define MAX_D 10
+
+#define MEGA_BYTE 1000000
+
+using namespace std;
+using boost::asio::ip::tcp;
+
+typedef HomomorphicCrypto* crypto_ptr;
+
+class PIROptimizer {
+
+	protected:
+    FitnessType fitnessMethod;
+		PIRParameters pirParameters;
+		HomomorphicCrypto* crypto;
+    AbstractPublicParameters* currentPublicParams;
+		string serv_ip;
+    int server_optimport;
+    boost::asio::io_service ios;
+		boost::asio::ip::tcp::socket s;
+		ofstream file;
+    map<string, double> encrypt_cache;
+    map<string, double> decrypt_cache;
+    map<string, double> abs_cache;
+    map<string, double> precompute_cache;
+
+		/** Fixed Parameters **/
+    FixedVars fixedVars;
+		unsigned int nbc; /** number of client **/
+		unsigned int dn[MAX_D];
+    unsigned int security_bits;
+    double ax[MAX_D], ayDec[MAX_D], ayEnc[MAX_D], axAbs[MAX_D], ayAbs[MAX_D];
+
+		/** Free PIR Parameters **/
+		string pir;
+		/**Outputs**/
+		OptimVars optimum, global_optimum;
+		double Tcr(unsigned i);
+		double Tcq(unsigned i);
+    double Tp(unsigned i);
+		
+		void getAbsAndPreCachesFromServer(boost::asio::ip::tcp::socket& s, crypto_ptr crypto_system);
+    void makeAbsAndPrecomputeCaches(char* serialized_cache);
+		double getAbs1PlaintextTime(HomomorphicCrypto* crypto_system);
+		double getPrecompute1PlaintextTime(HomomorphicCrypto* crypto_system);
+		double getQueryElemGenCost(unsigned int d, crypto_ptr crypto);
+		double eltSize(unsigned int alpha, unsigned int s);
+		double getDecCost(unsigned int i, crypto_ptr);
+		double getDecCost();
+		
+		void analyseResult(unsigned int alpha, unsigned int d, OptimVars& vars);
+		void showBestResults(unsigned int i);
+
+		void writeTestBestResult(unsigned int i);
+
+		void getPreComputedData(HomomorphicCrypto* crypto);
+		void computeOptimData(set<string>& crypto_params_set);
+
+    void sendExitCommand(boost::asio::ip::tcp::socket& s);
+		void disconnect();
+		void connect(); //const throw(std::exception);
+
+
+	public:
+    bool silent;
+		PIROptimizer(string server_ip, int port, FitnessType fitnessMethod);
+		PIROptimizer();
+	  virtual	~PIROptimizer();
+    void optimize(boost::asio::ip::tcp::socket& s, FixedVars& fixed_vars, unsigned int exp_nbr);
+    static const unsigned int kalphaBound;
+    void optimize(FixedVars& fixed_vars, unsigned int exp_nbr);
+    OptimVars optimizeFromServer(FixedVars& partial_fixed_vars,boost::asio::ip::tcp::socket& socket);
+    void optimizeFromConfiguredCryptosystem(FixedVars& fixed_vars, HomomorphicCrypto* crypto_system);
+    void noCryptoSystemOptim(unsigned int exp_nbr);
+    void findAlpha(unsigned int d, OptimVars& vars, unsigned int exp_nbr);
+    void findAlpha(unsigned int d, unsigned int alpha_min, unsigned int alpha_max, OptimVars& vars, unsigned int exp_nbr);
+
+    void findAlphaDicho(unsigned int inf, unsigned int sup, unsigned int d, unsigned int exp_nbr, OptimVars& vars);
+    int slop(unsigned int alphaMul, unsigned int inf, unsigned int sup, unsigned int d, OptimVars& vars, unsigned int exp_nbr);
+
+		const PIRParameters& getParameters();
+
+		static void getDimSize(unsigned int n, unsigned int alpha, unsigned int d, unsigned int *dn);
+    unsigned int getMaxAlpha();
+    unsigned int getMinAlpha();
+
+    double getGenQueryCost(unsigned int  d, unsigned int *dn);
+		double getSendCost(double Tupc, double Tdoc, unsigned int nbc, unsigned int d, unsigned int *dn);
+		double getReplyGenCost(unsigned int alpha, unsigned int d, unsigned int *dn);
+		double getReceiveCost(unsigned int alpha, double Tups, double Tdoc, unsigned int nbc, unsigned int d);
+		double getDecryptCost(unsigned int alpha, unsigned int d);
+    void getFixedVarsFromServer(FixedVars& fixed_vars0,boost::asio::ip::tcp::socket& socket);
+    void getNetworkInfos(FixedVars& fixed_vars, boost::asio::ip::tcp::socket& s);
+
+		static void writeBigMessage(string msg);
+    void processResults(unsigned int i);
+    double computeOptimVars(unsigned int alphalt, unsigned int d, OptimVars& vars);
+
+};
+
+#endif

+ 54 - 0
apps/server/CMakeLists.txt

@@ -0,0 +1,54 @@
+cmake_minimum_required(VERSION 2.6.0)
+
+if (APPLE)
+	set(CMAKE_EXE_LINKER_FLAGS "-fopenmp -L$ENV{HOME}/Code/xpir/freshxpir/xpir-ng/local/lib/ -lboost_program_options")
+
+endif()
+
+include_directories(.)
+include_directories(..)
+include_directories(../..)
+
+add_executable(pir_server DBDirectoryProcessor.cpp DBGenerator.cpp PIRServer.cpp PIRSession.cpp ServerService.cpp main.cpp)
+
+target_link_libraries(pir_server pir ${Boost_LIBRARIES} ${GMP_LIBRARIES} pthread )
+
+# set (git_cmd "git")
+# set (git_arg "--version")
+# message(STATUS "git cmd: ${git_cmd}")
+# execute_process(COMMAND ${git_cmd} ${git_arg}
+#   WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+#   RESULT_VARIABLE git_result
+#   OUTPUT_VARIABLE git_ver)
+#
+# message(STATUS "git ver[${git_result}]: ${git_ver}")
+
+file(COPY "../tools/check-correctness.sh" DESTINATION ".")
+file(COPY "../tools/makedb.sh" DESTINATION ".")
+file(COPY "../tools/mkdb-correctness.sh" DESTINATION ".")
+
+add_custom_command(
+    OUTPUT .db
+    WORKING_DIR ${PROJECT_BINARY_DIR}/apps/server
+    COMMAND ./makedb.sh 1024 16 2>/dev/null
+    COMMAND touch .db
+)
+
+add_custom_target(db ALL DEPENDS .db)
+	
+add_custom_command(
+    OUTPUT .db-correct
+    WORKING_DIR ${PROJECT_BINARY_DIR}/apps/server
+    COMMAND ./mkdb-correctness.sh
+    COMMAND touch .db-correct
+)
+
+add_custom_target(dbcorrect DEPENDS .db-correct)
+
+add_custom_command(
+    OUTPUT .check
+    WORKING_DIR ${PROJECT_BINARY_DIR}/apps/server
+    COMMAND ./check-correctness.sh
+)
+
+add_custom_target(check DEPENDS .check dbcorrect pir_client pir_server)

+ 238 - 0
apps/server/DBDirectoryProcessor.cpp

@@ -0,0 +1,238 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "DBDirectoryProcessor.hpp"
+
+/************************************************/
+/* Default constructor : no splitting           */
+/*  -> 1 input file -> 1 output stream          */
+/************************************************/
+DBDirectoryProcessor::DBDirectoryProcessor() : filesSplitting(false) {
+	// TODO(feature) deal with sub-directories in the database !
+
+	directory=std::string(DEFAULT_DIR_NAME);
+	maxFileBytesize=0;
+
+	// Create the pool of ifstream
+	for(int i=0;i<NB_FILE_DESCRIPTORS;i++)
+		fdPool.push_back(new std::ifstream());
+
+	// Then create the catalog and get the filenumbers and size
+	DIR *dir = opendir (directory.c_str());
+	struct dirent *ent = nullptr;
+
+	// If there is no error when opening the directory
+	if (dir != NULL) 
+	{
+		uint32_t i=0;
+		// For each entry
+		while ( (ent = readdir (dir)) != NULL) 
+		{
+			// Ignore files . and ..
+			if (strcmp(ent->d_name, ".") > 0 && strcmp(ent->d_name, ".."))
+			{
+				// Count processed files (one out of 2**7?)
+				if ((i << 25)==0) std::cout << "DBDirectoryProcessor: " << i+1 << " entries processed\r" << std::flush;i++;
+				// Add File object on the file list
+				std::string fileName= std::string( ent->d_name );
+				file_list.push_back( fileName );
+				uint64_t fileSize = getFileSize(directory + fileName);
+				if (fileSize > maxFileBytesize)
+					maxFileBytesize = fileSize;		
+			}
+		}
+		std::cout << "DBDirectoryProcessor: " << i << " entries processed" << std::endl;
+		closedir (dir);
+	}
+	else // If there was a problem opening the directory
+	{
+		std::cout << "DBDirectoryProcessor: Error opening database directory" << std::endl;
+	}
+
+	std::cout << "DBDirectoryProcessor: The size of the database is " << maxFileBytesize*file_list.size() << " bytes" << std::endl;
+	std::cout << "DBDirectoryProcessor: The number of elements in the catalog is " << file_list.size() << std::endl;
+}
+
+// This constructor is called when we need File-splitting
+DBDirectoryProcessor::DBDirectoryProcessor(uint64_t nbStreams) : filesSplitting(true) {
+
+	directory=std::string(DEFAULT_DIR_NAME);
+	maxFileBytesize=0;
+
+	// Create the pool of ifstream
+	for(int i=0;i<NB_FILE_DESCRIPTORS;i++)
+		fdPool.push_back(new std::ifstream());
+
+	// Then create the catalog and get the filenumbers and size
+	DIR *dir = opendir (directory.c_str());
+	struct dirent *ent = nullptr;
+
+	// If there is no error when opening the directory
+	if (dir != NULL) 
+	{
+		ent = readdir (dir);
+		// WARNING: In case of file-splitting, we deal only with the first file
+		// On some filesystems, the dir contains also special files such as "." and "..", skip them
+		while (ent->d_name == NULL || ent->d_type != DT_REG) {
+			ent = readdir (dir);
+		}
+
+		// Add File object on the file list
+		std::string fileName=directory + std::string( ent->d_name );
+		realFileName=fileName;
+		uint64_t realFileSize = getFileSize(realFileName);				
+		maxFileBytesize = realFileSize/nbStreams;
+
+		if(maxFileBytesize==0) {
+			std::cout << "DBDirectoryProcessor: ERROR cannot split a file en less than one byte elements!" << std::endl;
+			std::cout << "DBDirectoryProcessor: file " << realFileName << " is only "<< realFileSize << " long" << std::endl;
+			exit(1);
+		}
+
+		closedir (dir);
+		for(int i=0;i<nbStreams;i++) {
+			file_list.push_back( std::to_string(i) );
+		}
+	}
+	else // If there was a problem opening the directory
+	{
+		std::cout << "DBDirectoryProcessor: Error when opening directory " <<directory<< std::endl;
+		exit(1);
+	}
+
+#ifdef DEBUG
+	std::cout << "maxFileBytesize." <<maxFileBytesize<< std::endl;
+	std::cout << "file_list.size()." <<file_list.size()<< std::endl;
+
+#endif
+	std::cout << "DBDirectoryProcessor: The size of the database is " << maxFileBytesize*file_list.size() << " bytes" << std::endl;
+	std::cout << "DBDirectoryProcessor: The number of elements in the catalog is " << file_list.size() << std::endl;
+}
+
+DBDirectoryProcessor::~DBDirectoryProcessor() {
+	for (auto ifs : fdPool) delete ifs; 
+}
+
+std::string DBDirectoryProcessor::getCatalog(const bool typeOfCatalog) {
+	std::string buf;
+	directory=std::string(DEFAULT_DIR_NAME);
+	if(typeOfCatalog) {
+		// Start with the number of elements in the catalog
+		buf = std::to_string((unsigned int)0)+ "\n";	
+		buf += std::to_string(getNbStream())+ "\n";		
+		// Then for each file contactenate (with newlines) filename and filesize
+		for (auto f : file_list)
+		{
+			if(!filesSplitting) {
+				buf += f + "\n" + std::to_string(getFileSize(directory+f)) + "\n";
+			} else {
+				buf += f + "\n" + std::to_string(getmaxFileBytesize()) + "\n";
+			}
+		}
+		return buf;
+	} 
+	// else we want a compact representation, i.e. nbFiles / fileSize
+	buf = std::to_string((unsigned int)1)+ "\n";	
+	buf += std::to_string(getNbStream())+ "\n";
+	buf += std::to_string(maxFileBytesize)+ "\n";
+	return buf;
+}
+
+uint64_t DBDirectoryProcessor::getDBSizeBits() {
+	return maxFileBytesize*file_list.size()*8;
+}
+uint64_t DBDirectoryProcessor::getNbStream() {
+	return  file_list.size();
+}
+uint64_t DBDirectoryProcessor::getmaxFileBytesize() {
+	return maxFileBytesize;
+}
+
+std::ifstream* DBDirectoryProcessor::openStream(uint64_t streamNb, uint64_t requested_offset) {
+	std::string local_directory(DEFAULT_DIR_NAME);
+
+	std::ifstream* is = fdPool.back();
+	fdPool.pop_back();
+	// When there is no splitting, each ifstream is associated with a real file 
+	// (at least when no aggregation is done which is the case for now)
+	if(!filesSplitting) {
+		is->open( local_directory + file_list[streamNb], std::ios::binary );
+		is->seekg(requested_offset);
+	} else {
+		// But when we are doing file splitting, we just need to position the ifstream at the correct position
+		uint64_t splitting_offset=streamNb*getmaxFileBytesize();
+		is->open( realFileName, std::ios::binary );
+		is->seekg(splitting_offset + requested_offset);
+	}
+	return is;
+}
+
+uint64_t DBDirectoryProcessor::readStream(std::ifstream* s, char * buf, uint64_t size) {
+	uint64_t sizeRead=0;
+	//std::cout << "sizeRead = "<<sizeRead<<" size = "<<size<<std::endl;
+	while(sizeRead<size) {
+		uint64_t readThisrun=s->readsome(buf+sizeRead,size-sizeRead);
+		sizeRead+=readThisrun;
+		// Check if we need to pad
+		if(readThisrun==0 && sizeRead<size) {
+			//		std::cout << "padding = "<<size-sizeRead<<std::endl;
+			bzero(buf+sizeRead,size-sizeRead);
+			sizeRead=size;
+		}
+	}
+	return size;
+}
+
+void DBDirectoryProcessor::closeStream(std::ifstream* s) {
+	s->close();
+	fdPool.push_back(s);
+}
+
+std::streampos DBDirectoryProcessor::getFileSize( std::string filePath ){
+	std::streampos fsize = 0;
+	std::ifstream file( filePath.c_str(), std::ios::binary );
+	fsize = file.tellg();
+	file.seekg( 0, std::ios::end );
+	fsize = file.tellg() - fsize;
+	file.close();
+	return fsize;
+}
+
+void DBDirectoryProcessor::readAggregatedStream(uint64_t streamNb, uint64_t alpha, uint64_t offset, uint64_t bytes_per_file, char* rawBits){
+	uint64_t fileByteSize = std::min(bytes_per_file, getmaxFileBytesize()-offset);
+	uint64_t startStream = streamNb*alpha;
+	uint64_t endStream = std::min(streamNb*alpha + alpha - 1, getNbStream() - 1);
+	uint64_t paddingStreams = (streamNb*alpha+alpha) >= getNbStream() ? (streamNb*alpha+alpha) - getNbStream() : 0;
+
+  #pragma omp critical
+	{	
+		for (int i=startStream; i <= endStream; i++)
+		{
+			std::ifstream *stream = openStream(i, offset);
+
+			// Just read the file (plus padding for that file)
+			readStream(stream, rawBits + (i % alpha) * fileByteSize, fileByteSize);
+
+			closeStream(stream);
+		} 
+
+		if(paddingStreams !=0)
+		{
+			bzero(rawBits + (endStream % alpha) * fileByteSize, fileByteSize*paddingStreams);
+		}
+	}
+}

+ 67 - 0
apps/server/DBDirectoryProcessor.hpp

@@ -0,0 +1,67 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_DBDIRPROC
+#define DEF_DBDIRPROC
+
+#include "DBHandler.hpp"
+#include <boost/interprocess/sync/interprocess_semaphore.hpp>
+#include <boost/thread.hpp>
+#include <dirent.h>
+#include <vector>
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <stdio.h>
+#include <string.h>
+
+#define DEFAULT_DIR_NAME "db/"
+#define NB_FILE_DESCRIPTORS 50
+
+class DBDirectoryProcessor : public DBHandler
+{
+private:
+	boost::mutex mutex;
+  std::string directory;
+  std::vector<std::ifstream*> fdPool; // a pool of file descriptors
+  std::vector <std::string> file_list; // the output file list
+  bool filesSplitting;
+  std::string realFileName; // The name of the unique file in case of splitting
+  
+public:
+  DBDirectoryProcessor(); // constructor with no splitting
+  DBDirectoryProcessor(uint64_t nbStreams); // constructor with filesplitting 1 -> nbStreams
+	virtual ~DBDirectoryProcessor();
+  
+  std::string getCatalog(const bool typeOfCatalog);
+  
+  uint64_t getDBSizeBits();
+  uint64_t getNbStream();
+  uint64_t getmaxFileBytesize();
+  
+  std::ifstream* openStream(uint64_t streamNb, uint64_t requested_offset);
+  uint64_t readStream(std::ifstream* s,char * buf, uint64_t size);
+  void readAggregatedStream(uint64_t streamNb, uint64_t alpha, uint64_t offset, uint64_t bytes_per_file, char* rawBits);
+  void closeStream(std::ifstream* s);
+  
+  
+	std::streampos getFileSize( std::string filePath );
+private:
+  	uint64_t maxFileBytesize;
+};
+
+#endif //DEF_CATALOGMAKER

+ 111 - 0
apps/server/DBGenerator.cpp

@@ -0,0 +1,111 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "DBGenerator.hpp"
+
+/************************************************/
+/* Default constructor : no splitting           */
+/*  -> 1 input file -> 1 output stream          */
+/************************************************/
+DBGenerator::DBGenerator(uint64_t nbStreams, uint64_t streamBytesize, bool silent):
+random_engine(0), // Fixed seed of 0
+random_distribution()
+{
+	maxFileBytesize=streamBytesize;
+	nbFiles = 0;
+#ifdef SEND_CATALOG
+  for (unsigned int i = 0 ; i < nbStreams ; i++) {
+	std::string fileName= std::to_string(i);
+    file_list.push_back( fileName );
+	}
+#endif
+  nbFiles = nbStreams;
+  if(!silent)
+  {
+	  std::cout << "DBGenerator: The size of the database is " << maxFileBytesize*nbFiles << " bytes" << std::endl;
+	  std::cout << "DBGenerator: The number of elements in the catalog is " << nbFiles << std::endl;
+  }
+}
+
+DBGenerator::~DBGenerator() {}
+
+std::string DBGenerator::getCatalog(const bool typeOfCatalog) {
+	std::string buf;
+	if(typeOfCatalog) {
+		// Start with the number of elements in the catalog
+		buf = std::to_string((unsigned int)0)+ "\n";	
+		buf += std::to_string(getNbStream())+ "\n";		
+		// Then for each file contactenate (with newlines) filename and filesize
+		for (auto f : file_list)
+		{
+			buf += f + "\n" + std::to_string(maxFileBytesize) + "\n";
+		}
+		return buf;
+	} 
+	// else we want a compact representation, i.e. nbFiles / fileSize
+	buf = std::to_string((unsigned int)1)+ "\n";	
+	buf += std::to_string(getNbStream())+ "\n";
+	buf += std::to_string(maxFileBytesize)+ "\n";
+	return buf;
+}
+
+//uint64_t DBGenerator::getDBSizeBits() {
+//	return maxFileBytesize*nbFiles*8;
+//}
+uint64_t DBGenerator::getNbStream() {
+	return  nbFiles;
+}
+uint64_t DBGenerator::getmaxFileBytesize() {
+	return maxFileBytesize;
+}
+
+std::ifstream* DBGenerator::openStream(uint64_t streamNb, uint64_t requested_offset) {
+	return NULL;
+}
+
+uint64_t DBGenerator::readStream(std::ifstream* s, char * buf, uint64_t size) {
+  //for (unsigned char i = 0xaa, j = 0; j < size; i++, j++)
+  //{
+  //  buf[j] = i;
+	//}
+//#define NDSS_SNIFFER
+#ifdef NDSS_SNIFFER
+  for (int i = 0; i < size/4; i++) {
+    buf[i<<2] = random_distribution(random_engine);
+  }
+#else
+  char ccc=0xaa;
+  memset(buf, ccc++, size);
+#endif
+  return size;
+}
+
+void DBGenerator::closeStream(std::ifstream* s) {}
+
+void DBGenerator::readAggregatedStream(uint64_t streamNb, uint64_t alpha, uint64_t offset, uint64_t bytes_per_file, char* rawBits){
+  readStream(NULL, NULL, 0);
+	uint64_t fileByteSize = std::min(bytes_per_file, maxFileBytesize-offset);
+  uint64_t startStream = streamNb*alpha;
+  uint64_t endStream = std::min(streamNb*alpha + alpha - 1, getNbStream() - 1);
+  uint64_t paddingStreams = std::max((long long)((streamNb)*alpha+alpha) - (long long)getNbStream(), (long long)0);
+  memset(rawBits, 0xaa, fileByteSize*(endStream-startStream + 1));
+  
+  if(paddingStreams !=0)
+  {
+	  bzero(rawBits + (endStream % alpha) * fileByteSize, fileByteSize*paddingStreams);
+  }
+}

+ 52 - 0
apps/server/DBGenerator.hpp

@@ -0,0 +1,52 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_DBGEN
+#define DEF_DBGEN
+
+#include "DBHandler.hpp"
+#include <cstring>
+#include <random>
+#include <omp.h>
+
+class DBGenerator : public DBHandler
+{
+private:
+  std::vector <std::string> file_list; // the output file list
+public:
+  DBGenerator(uint64_t nbStreams, uint64_t streamBytesize, bool silent); 
+  ~DBGenerator();
+  
+  std::string getCatalog(const bool typeOfCatalog);
+  
+  uint64_t getNbStream();
+  uint64_t getmaxFileBytesize();
+  
+  std::ifstream* openStream(uint64_t streamNb, uint64_t requested_offset);
+  uint64_t readStream(std::ifstream* s, char * buf, uint64_t size);
+  void readAggregatedStream(uint64_t streamNb, uint64_t alpha, uint64_t offset, uint64_t bytes_per_file, char* rawBits);
+  void closeStream(std::ifstream* s);
+  
+private:
+  std::mt19937_64 random_engine; // Fixed seed of 0
+  std::uniform_int_distribution<> random_distribution;
+  
+ 	uint64_t maxFileBytesize;
+  uint64_t nbFiles;  
+};
+
+#endif //DEF_CATALOGMAKER

+ 47 - 0
apps/server/DBHandler.hpp

@@ -0,0 +1,47 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_DBHANDLER
+#define DEF_DBHANDLER
+
+#include <vector>
+#include <string>
+#include <iostream>
+
+class DBHandler
+{
+private:
+  std::vector <std::string> file_list; // the output file list
+public:
+  
+  virtual std::string getCatalog(const bool typeOfCatalog)=0;
+  
+  virtual uint64_t getNbStream()=0;
+  virtual uint64_t getmaxFileBytesize()=0;
+  
+  virtual std::ifstream* openStream(uint64_t streamNb, uint64_t requested_offset)=0;
+  virtual uint64_t readStream(std::ifstream* s, char * buf, uint64_t size)=0;
+  virtual void readAggregatedStream(uint64_t streamNb, uint64_t alpha, uint64_t offset, uint64_t bytes_per_file, char* rawBits)=0;
+  virtual void closeStream(std::ifstream* s)=0;
+  virtual ~DBHandler(){};
+  
+  
+private:
+  	uint64_t maxFileBytesize;
+};
+
+#endif 

+ 134 - 0
apps/server/PIRServer.cpp

@@ -0,0 +1,134 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "PIRServer.hpp"
+#include "PIRSession.hpp"
+
+/**
+ *	Class constructor:
+ *	Params :
+ *		- tcp::endpoint& endpoint_down : download enpoint ;
+ *		- tcp::endpoint& endpoint_up   : upload endpoit.
+ **/
+PIRServer::PIRServer(boost::asio::io_service &ios, unsigned int port, uint64_t split_value, bool usedbgenerator, uint64_t dbgenerator_n, uint64_t dbgenerator_l) : 
+	acceptor(ios, tcp::endpoint(tcp::v4(), port)),
+  drivenMode(true),
+  pirParamsFilePath("exp/PIRParams.cfg"),
+  no_pipeline_mode(false)
+{
+	acceptor.set_option(tcp::acceptor::reuse_address(true));
+  session_option.driven_mode = true;
+  session_option.keep_database = false;
+  session_option.got_preimported_database = false;
+  if (usedbgenerator)
+  {
+    std::cout << "PIRServer: Launching DBGenerator" << std::endl;
+    dbhandler = new DBGenerator(dbgenerator_n, dbgenerator_l, false); 
+  }
+  else if (split_value == 1)
+  {
+    std::cout << "PIRServer: Launching DBDirectoryProcessor without file splitting" << std::endl;
+    dbhandler = new DBDirectoryProcessor();
+  }
+  else
+  {
+    std::cout << "PIRServer: Launching DBDirectoryProcessor with split_value=" << split_value 
+      << std::endl;
+    dbhandler = new DBDirectoryProcessor(split_value);
+  }
+}
+
+
+/**
+ * Wait new client and fork when new connexion.
+ **/
+void PIRServer::serve()
+{
+  PIRSession::pointer new_session =  PIRSession::create(acceptor.get_io_service());
+  new_session->no_pipeline(no_pipeline_mode);
+  new_session->setDBHandler(dbhandler);
+
+  if (!drivenMode) new_session->setPIRParams(savedPIRParams);
+
+	acceptor.async_accept(new_session->getSessionSocket(), 
+    boost::bind( &PIRServer::handleAccept, this, new_session, boost::asio::placeholders::error ));
+}
+
+void PIRServer::processDrivenSession(const std::string & file_path)
+{
+	std::cout <<"PIRServer: Creating initial PIRSession" << std::endl;
+  std::cout <<"PIRServer: Please launch a client to configure the server"<<std::endl;
+
+  session_option.driven_mode = true;
+  session_option.keep_database = true;
+
+  // Loop while we get dry-run queries
+  PIRSession* session_ptr = new PIRSession(acceptor.get_io_service());
+  do 
+  {
+    // Trick to have only one PIRSession at a time ... must be a better way :)
+    delete session_ptr;
+    session_ptr = new PIRSession(acceptor.get_io_service());
+    session_ptr->setDBHandler(dbhandler);
+    session_ptr->no_pipeline(no_pipeline_mode);
+    acceptor.accept(session_ptr->getSessionSocket());
+  }while(session_ptr->start(session_option));
+ 
+  savedPIRParams = session_ptr->getPIRParams();
+  session_option.data = session_ptr->getSavedDatabase();
+
+  session_option.driven_mode = false;
+  session_option.keep_database = false;
+  if (session_option.data.imported_database_ptr != NULL) session_option.got_preimported_database = true;
+
+  if(ServerService::writePIRParameters(savedPIRParams,  file_path)) {
+    cout << "Unable to write PIR parameters configuration data, maybe target repertory doesn't exist ?" << std::endl;
+    return;
+  }
+	std::cout << "PIRServer: Configuration session successfuly ended" << endl << endl;
+  drivenMode = false;
+}
+
+void PIRServer::handleAccept(PIRSession::pointer pir_session, const boost::system::error_code& error)
+{
+	std::cout<<"PIRServer: Creating new PIRSession"<<std::endl;
+  if(!error)
+  {
+    boost::thread t(boost::bind(&PIRSession::start, pir_session, session_option));
+  }
+
+  serve();
+}
+
+void PIRServer::readPIRParamsFromFile(const std::string& file_path)
+{
+  if (ServerService::readPIRParameters(savedPIRParams, file_path)) {
+        cout << "PIR parameters configuration file not found, try to launch the server in driven mode." << std::endl;
+        exit(1);
+    }
+  drivenMode = false;
+}
+
+void PIRServer::no_pipeline(bool b)
+{
+  no_pipeline_mode = b;
+}
+
+PIRServer::~PIRServer()
+{
+  delete dbhandler; 
+}

+ 59 - 0
apps/server/PIRServer.hpp

@@ -0,0 +1,59 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_PIRSERVER
+#define DEF_PIRSERVER
+
+#include <string>
+
+#include "PIRSession.hpp"
+#include "ServerService.hpp"
+#include "../server/DBHandler.hpp"
+#include "../server/DBDirectoryProcessor.hpp"
+#include "../server/DBGenerator.hpp"
+
+#define DEFAULT_PORT 1234
+
+using namespace boost;
+
+class PIRSession;
+struct session_option_t;
+
+class PIRServer 
+{
+	private:
+    boost::asio::io_service ios;
+    boost::asio::ip::tcp::acceptor acceptor;
+    DBHandler *dbhandler;
+    PIRParameters savedPIRParams;
+    session_option_t session_option;
+    bool drivenMode;
+    std::string pirParamsFilePath;
+    void handleAccept(boost::shared_ptr<PIRSession> pir_session, const boost::system::error_code& error);
+    bool no_pipeline_mode;
+
+	public:
+		PIRServer(boost::asio::io_service &ios, unsigned int port, uint64_t split_value, 
+        bool usedbgenerator, uint64_t dbgenerator_n, uint64_t dbgenerator_l);
+		~PIRServer();
+    void serve();
+    void readPIRParamsFromFile(const std::string& file_path);
+    void processDrivenSession(const std::string& file_path);
+    void no_pipeline(bool b);
+};
+
+#endif

+ 623 - 0
apps/server/PIRSession.cpp

@@ -0,0 +1,623 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "PIRSession.hpp"
+#include "pir/replyGenerator/PIROptimizer.hpp"
+
+#define NDSS_UPLOAD_SPEED 100000000UL
+PIRSession::pointer PIRSession::create(boost::asio::io_service& ios)
+{
+  return PIRSession::pointer(new PIRSession(ios));
+}
+
+PIRSession::PIRSession(boost::asio::io_service& ios) :
+  sessionSocket(ios),
+  handmadeExceptionRaised(false),
+  finished(false),
+  cryptoMethod(NULL),
+  generator(NULL),
+  no_pipeline_mode(false)
+{
+}
+
+void PIRSession::setDBHandler(DBHandler *db)
+{
+  dbhandler = db;
+}
+
+/**
+ * Do the PIR protocol
+ **/
+bool PIRSession::start(session_option_t session_option)
+{
+  
+  uint64_t nbFiles=dbhandler->getNbStream();
+  maxFileBytesize = dbhandler->getmaxFileBytesize();
+  short exchange_method = (session_option.driven_mode) ? CLIENT_DRIVEN : SERVER_DRIVEN;
+  bool rcv_paramsandkey = true;
+
+  // Deal with Optimizer dry-run queries if requested
+  if(!rcvIsClient())
+  {
+    std::cout << "PIRSession: Incoming dry-run optimizer request, dealing with it ..." << std::endl;
+    PIROptimizer optimizer(dbhandler);
+    optimizer.prepareOptimData();
+    optimizer.controlAndCommand(sessionSocket);
+    std::cout << "PIRSession: Session finished" << std::endl << std::endl;
+    finished = true;
+    return 1; // Did deal with a dry-run query
+  }
+
+  sendCatalog();
+  sendPIRParamsExchangeMethod(exchange_method);
+
+  if(session_option.driven_mode) {
+    PIROptimizer optimizer(dbhandler);
+    optimizer.prepareOptimData();
+    optimizer.controlAndCommand(sessionSocket);
+    rcvCryptoParams(rcv_paramsandkey);
+    rcvPirParams();
+  }
+  else //not driven
+  {
+    std::vector<std::string> fields;
+    boost::algorithm::split(fields, pirParam.crypto_params, boost::algorithm::is_any_of(GlobalConstant::kDelim));
+    cryptoMethod = HomomorphicCryptoFactory_internal::getCrypto(fields.at(0));
+    cryptoMethod->setNewParameters(pirParam.crypto_params);
+
+    generator = PIRReplyGeneratorFactory::getPIRReplyGenerator(fields.at(0), pirParam,dbhandler);
+    generator->setCryptoMethod(cryptoMethod);
+    sendCryptoParams();
+    rcvCryptoParams(!rcv_paramsandkey);
+    sendPirParams();
+  }
+
+  // If one of the functions above generates an error, handmadeExceptionRaised is set 
+  if (!handmadeExceptionRaised)
+  {
+    // This is just a download thread. Reply generation is unlocked (by a mutex)
+    // when this thread finishes.
+    startProcessQuery(); 
+
+    // Import the database
+    // Start reply generation when mutex unlocked
+    // Start a thread which uploads the reply as it is generated
+    startProcessResult(session_option);
+  }
+
+  // Wait for child threads
+  if (upThread.joinable())  upThread.join();
+  if (downThread.joinable()) downThread.join();
+
+  std::cout << "PIRSession: Session finished" << std::endl << std::endl;
+  // Note that we have finished so that the PIRServer can do garbage collection
+  finished = true;
+  if (generator != NULL) delete generator;
+  return 0; // Did deal with a client query
+}
+
+
+/** 
+ * Getter for other classes (such as PIRServer) 
+ **/
+tcp::socket& PIRSession::getSessionSocket()
+{
+  return sessionSocket;
+}
+
+/**
+ * Send the catalog to the client as a string. 
+ * Format : file_list_size \n filename1 \n filesize1 \n filename2 \n ... filesizeN \n
+ *          if SEND_CATALOG is defined and catalog size is less than 1000, the full catalog is sent
+ *			otherwise only the size of the catalog is sent
+ **/
+void PIRSession::sendCatalog() 
+{
+	string buf;
+#ifdef SEND_CATALOG
+    if(dbhandler->getNbStream()>1000) {
+    	buf=dbhandler->getCatalog(false);
+    } else {
+      	buf=dbhandler->getCatalog(true);
+    }
+#else
+    buf = dbhandler->getCatalog(false);
+#endif
+  	// Send the buffer
+  	const boost::uint64_t size = buf.size();
+	  
+  	try
+  	{
+    	if (write(sessionSocket, boost::asio::buffer(&size, sizeof(size))) <= 0)
+      	 	exitWithErrorMessage(__FUNCTION__,"Error sending catalog size");
+    	if (write(sessionSocket, boost::asio::buffer(buf.c_str(), size)) < size) 
+      	  	exitWithErrorMessage(__FUNCTION__,"Error sending catalog");
+  	} catch (std::exception const& ex) {
+    	exitWithErrorMessage(__FUNCTION__,"Error sending catalog: " + string(ex.what()));
+  	}
+  	writeWarningMessage(__FUNCTION__ , "done.");
+}
+
+void PIRSession::sendCryptoParams() 
+{
+  std::cout << "PIRSession: Mandatory crypto params sent to the client are " << pirParam.crypto_params << std::endl;
+
+  try 
+  {
+    int crypto_params_size = pirParam.crypto_params.size();
+
+    write(sessionSocket, boost::asio::buffer(&crypto_params_size, sizeof(crypto_params_size)));
+
+    write(sessionSocket, boost::asio::buffer(pirParam.crypto_params));
+  } 
+  catch(std::exception const& ex) 
+  {
+    exitWithErrorMessage(__FUNCTION__, string(ex.what()));
+  }
+}
+
+bool PIRSession::rcvIsClient() 
+{
+  try{
+    int is_client;
+    while ( read(sessionSocket, boost::asio::buffer(&(is_client), sizeof(int))) == 0)
+      boost::this_thread::yield();
+      //exitWithErrorMessage(__FUNCTION__, "No client or optim choice recieved");
+
+    return is_client == 1; 
+  }catch (std::exception const& ex)
+  {
+    exitWithErrorMessage(__FUNCTION__, string(ex.what()));
+  }
+}
+
+/**
+ * Receive client's cryptographic parameters as:
+ * - An int describing a string size
+ * - A string of the given size containing the public parameters
+ * - A second int describing a byte size
+ * - A buffer of bytes of the given size with key material
+ **/
+void PIRSession::rcvCryptoParams(bool paramsandkey)
+{
+  unsigned int size = 0;
+
+  try{
+    std::vector<std::string> fields;
+    
+    if(paramsandkey == true)
+    { 
+      // First get the int and allocate space for the string (plus the null caracter) 
+      read(sessionSocket, boost::asio::buffer(&size, sizeof(int)));
+      char params_buf[size + 1];	
+
+      // Get the string in the buffer and add a null character
+      read(sessionSocket, boost::asio::buffer(params_buf, size));
+      params_buf[size] = '\0';
+
+      cout << "PIRSession: Received crypto parameters " << params_buf << " processing them ..." << endl;
+#ifdef DEBUG
+      cout << "PIRSession: Parameter string size is " << size << endl;
+#endif
+
+      // Extract cryptosystem's name
+      string crypto_system_desc(params_buf);
+      boost::algorithm::split(fields, crypto_system_desc, boost::algorithm::is_any_of(":"));
+
+      // Create cryptosystem using a factory and the extracted name
+      cryptoMethod = HomomorphicCryptoFactory_internal::getCrypto(fields[0]); 
+    
+      // Set cryptosystem with received parameters and key material
+      cryptoMethod->setNewParameters(params_buf);
+
+      // Create the PIR reply generator object using a factory to have 
+      // the correct object given the cryptosystem used (for optimization 
+      // reply generation is cryptosystem dependent)
+      generator = PIRReplyGeneratorFactory::getPIRReplyGenerator(fields[0], pirParam, dbhandler);
+      if (generator == NULL) 
+      {
+        std::cout << "PIRSession: CRITICAL no reply generator found, exiting session" << std::endl;
+        pthread_exit(this);
+      }
+      else
+      {
+        generator->setCryptoMethod(cryptoMethod);
+      } 
+    }
+    
+    // Use again size to describe the key size 
+    if (read(sessionSocket, boost::asio::buffer(&size ,sizeof(size))) <= 0)
+      exitWithErrorMessage(__FUNCTION__,"No key received, abort.");
+
+#ifdef DEBUG
+    cout << "PIRSession: Size of received key material is " << size << endl;
+#endif
+    // Get the key material only if there is some  
+    if(size > 0)
+    {
+      // This time we don't use a string so no need for an extra character
+      char buf[size];
+
+      if (read(sessionSocket, boost::asio::buffer(buf, size)) < size)
+        exitWithErrorMessage(__FUNCTION__,"No parameters received, abort.");
+    
+      cryptoMethod->getPublicParameters().setModulus(buf);
+    }
+
+  }catch(std::exception const& ex)
+  {
+    exitWithErrorMessage(__FUNCTION__, string(ex.what()));
+  }
+
+  std::cout << "PIRSession: Finished processing crypto parameters" << std::endl;
+}
+
+void PIRSession::sendPIRParamsExchangeMethod(short exchange_method)
+{
+  if (exchange_method == CLIENT_DRIVEN)
+  {
+    cout << "PIRSession: Notifying the client this is a client-driven session" << endl;
+  }
+  else
+  {
+    cout << "PIRSession: Notifying the client this is a server-driven session" << endl;
+  }
+  try
+  {
+    write(sessionSocket, boost::asio::buffer(&exchange_method, sizeof(exchange_method)));
+  }catch(std::exception const& ex)
+  {
+    exitWithErrorMessage(__FUNCTION__, string(ex.what()));
+  }
+}
+
+/**
+ * Receive client's PIR parameters.
+ **/
+void PIRSession::rcvPirParams() 
+{
+  try{
+    // First we get an int with the recursion level
+    if ( read(sessionSocket, boost::asio::buffer(&(pirParam.d), sizeof(int))) <= 0) 
+      exitWithErrorMessage(__FUNCTION__, "No pir param recieved");
+
+    // Then we get an int with the aggregation
+    if ( read(sessionSocket, boost::asio::buffer(&(pirParam.alpha), sizeof(int))) <= 0) 
+      exitWithErrorMessage(__FUNCTION__, "No pir param recieved");
+
+    // Finally for each level we get an int withe the corresponding dimension size
+    for (unsigned int i = 0 ; i < pirParam.d ; i++)
+    {
+      if ( read(sessionSocket, boost::asio::buffer(	&(pirParam.n[i]), sizeof(int))) <= 0) 
+        exitWithErrorMessage(__FUNCTION__, "No pir param recieved");
+    }
+    // The last dimension + 1 is set to 1 (used in some functions to compute the number of
+    // elements after a PIR recursion level)
+    pirParam.n[pirParam.d] = 1;
+
+    // Pass the PIR parameters to the reply generator
+    generator->setPirParams(pirParam);
+
+    cout << "PIRSession: PIR params recieved from the client are d=" << pirParam.d << ", alpha=" << pirParam.alpha << ", data_layout=";
+    for (unsigned int i = 0; i < pirParam.d; i++)
+    {
+      if (pirParam.d == 1) cout << "1x";
+      cout << pirParam.n[i];
+      if (i != pirParam.d-1) cout << "x";
+    }
+    cout << endl;
+  }catch (std::exception const& ex)
+  {
+    exitWithErrorMessage(__FUNCTION__, string(ex.what()));
+  }
+}
+
+void PIRSession::sendPirParams() 
+{
+  cout << "PIRSession: Mandatory PIR params sent to the client are d=" << pirParam.d << ", alpha=" << pirParam.alpha << ", data_layout=";
+  for (unsigned int i = 0; i < pirParam.d; i++)
+  {
+    if (pirParam.d == 1) cout << "1x";
+    cout << pirParam.n[i];
+    if (i != pirParam.d-1) cout << "x";
+  }
+  cout << endl;
+  try{
+    // First we send an int with the recursion level
+    if ( write(sessionSocket, boost::asio::buffer(&(pirParam.d), sizeof(int))) <= 0) 
+      exitWithErrorMessage(__FUNCTION__, "No pir param sended");
+
+    // Then we send an int with the aggregation 
+    if ( write(sessionSocket, boost::asio::buffer(&(pirParam.alpha), sizeof(int))) <= 0) 
+      exitWithErrorMessage(__FUNCTION__, "No pir param sended");
+
+    // Finally for each level we send an int withe the corresponding dimension size
+    for (unsigned int i = 0 ; i < pirParam.d ; i++)
+    {
+      if ( write(sessionSocket, boost::asio::buffer(	&(pirParam.n[i]), sizeof(int))) <= 0) 
+        exitWithErrorMessage(__FUNCTION__, "No pir param sended");
+    }
+    // The last dimension + 1 is set to 1 (used in some functions to compute the number of
+    // elements after a PIR recursion level)
+    pirParam.n[pirParam.d] = 1;
+
+    // Pass the PIR parameters to the reply generator
+    generator->setPirParams(pirParam);
+
+  }catch (std::exception const& ex)
+  {
+    exitWithErrorMessage(__FUNCTION__, string(ex.what()));
+  }
+}
+
+
+/**
+ * Start downloadworker in downThread.
+ **/
+void PIRSession::startProcessQuery ()
+{
+  if(no_pipeline_mode) {
+    std::cout << "No pipeline in query processing." << std::endl;
+    downloadWorker();
+  } else {
+    downThread = boost::thread(&PIRSession::downloadWorker, this);
+  }
+}
+
+
+/**
+ * Recieve queries n messages with n = nbr of files.
+ **/
+void blo(const boost::system::error_code& err) {
+  std::cout <<"rec "<<omp_get_wtime()<<std::endl;
+}
+void PIRSession::downloadWorker()
+{
+  double start = omp_get_wtime();
+  unsigned int msg_size = 0;
+
+  // Allocate an array with d dimensions with pointers to arrays of n[i] lwe_query elements 
+  generator->initQueriesBuffer();
+
+#ifdef PERF_TIMERS
+  double vtstart = omp_get_wtime();
+  bool wasVerbose = false;
+  unsigned int previous_elts = 0;
+  unsigned int total_elts = 0;
+  for (unsigned int k = 0 ;  k < pirParam.d ; k++) total_elts += pirParam.n[k];
+#endif
+
+  try{
+    for (unsigned int j = 0 ; j < pirParam.d ; j++)
+    {
+      // Compute and allocate the size in bytes of a query ELEMENT of dimension j 
+      msg_size = cryptoMethod->getPublicParameters().getQuerySizeFromRecLvl(j+1) / 8;
+      char buf[msg_size];
+      boost::asio::socket_base::receive_buffer_size opt(65535);
+      sessionSocket.set_option(opt);
+      auto boost_buffer = boost::asio::buffer(buf,msg_size); 
+  //    boost_buffer = new boost::asio::buffer(buf, msg_size); 
+#ifdef DEBUG
+      cout << "PIRSession: Size of the query element to be received is " << msg_size << endl;
+      cout << "PIRSession: Number of query elements to be received is " << pirParam.n[j] << endl;
+#endif
+
+      // Iterate over all the elements of the query corresponding to the j-th dimension
+      for (unsigned int i = 0; i < pirParam.n[j]; i++)
+      {
+      if (i==0 && j == 0) cout << "PIRSession: Waiting for query elements ..." << endl;
+        // Get a query element 
+         //( async_read(sessionSocket, boost_buffer,boost::bind(&blo,boost::asio::placeholders::error)) );
+        if (read(sessionSocket, boost_buffer) < msg_size )
+          writeWarningMessage(__FUNCTION__, "Query element not entirely recieved");	
+//  std::cout <<"PIRSession: " << total_elts << " query elements received in " << omp_get_wtime() - start << std::endl;
+
+        // Allocate the memory for the element, copy it, and point to it with the query buffer  
+        if (i==0 && j == 0) cout << "PIRSession: Starting query element reception"  << endl;
+
+#ifdef PERF_TIMERS
+        // Give some feedback if it takes too long
+        double vtstop = omp_get_wtime();
+        if (vtstop - vtstart > 1) 
+        {
+          vtstart = vtstop;
+          previous_elts = 0;
+          for (unsigned int k = 0 ;  k < j ; k++) previous_elts += pirParam.n[k];
+          std::cout <<"PIRSession: Query element " << i+1+previous_elts << "/" << total_elts << " received\r" << std::flush;
+          wasVerbose = true;
+        }
+#endif
+        
+        generator->pushQuery(buf, msg_size, j, i);
+      }
+
+    }
+  }catch (std::exception const& ex)
+  {
+    exitWithErrorMessage(__FUNCTION__, string(ex.what()));
+    return;
+  }
+
+#ifdef PERF_TIMERS
+  std::cout <<"PIRSession: Query element " << total_elts << "/" << total_elts << " received" << std::endl;
+  std::cout <<"PIRSession: " << total_elts << " query elements received in " << omp_get_wtime() - start << std::endl;
+#endif
+  
+  // All the query elements received, unlock reply generation
+  generator->mutex.unlock();
+
+  // Output we are done
+  writeWarningMessage(__FUNCTION__, "done.");
+}
+
+
+/**
+ * Start uploadWorker in a thread.
+ **/
+void PIRSession::startProcessResult(session_option_t session_option)
+{
+  if (no_pipeline_mode) {
+    std::cout << "No pipeline in query Generation." << std::endl;
+  }
+  else {
+    upThread = boost::thread(&PIRSession::uploadWorker, this);
+  }
+  // Import and generate reply once unlocked by the query downloader thread
+  // If we got a preimported database generate reply directly from it 
+  if (session_option.got_preimported_database == true) 
+  {
+    std::cout << "PIRSession: Already got an imported database available, using it" << std::endl;
+    generator->generateReplyGenericFromData(session_option.data);
+  }
+  else if (session_option.keep_database == true) {
+    savedDatabase = generator->generateReplyGeneric(true);
+  } 
+  else if (session_option.keep_database == false) 
+  {
+    generator->generateReplyGeneric(false);
+  }
+  
+  if (no_pipeline_mode) {
+    uploadWorker();
+  } 
+}
+
+void sleepForBytes(unsigned int bytes) {
+#ifdef NDSS_UPLOAD_SPEED
+	uint64_t seconds=(bytes*8)/NDSS_UPLOAD_SPEED;
+	uint64_t nanoseconds=((((double)bytes*8.)/(double)NDSS_UPLOAD_SPEED)-(double)seconds)*1000000000UL;
+	  struct timespec req={0},rem={0};
+	  req.tv_sec=seconds;
+	  req.tv_nsec=nanoseconds;
+	  nanosleep(&req,&rem);
+#endif
+}
+
+/**
+ * Send PIR's result, asynchronously. 
+ **/
+void PIRSession::uploadWorker() 
+{
+  // Ciphertext byte size 
+  unsigned int byteSize = cryptoMethod->getPublicParameters().getCiphBitsizeFromRecLvl(pirParam.d)/GlobalConstant::kBitsPerByte;
+  uint64_t totalbytesent=0;
+  // Number of ciphertexts in the reply
+  unsigned long reply_nbr = generator->computeReplySizeInChunks(maxFileBytesize), i = 0;
+#ifdef DEBUG
+  cout << "PIRSession: Number of ciphertexts to send is " << reply_nbr << endl;
+  cout << "PIRSession: maxFileBytesize is  " << maxFileBytesize << endl;
+  cout << "PIRSession: Ciphertext bytesize is " << byteSize << endl;
+#endif
+
+  try
+  {
+    // Pointer for the ciphertexts to be sent
+    char *ptr;
+
+    // For each ciphertext in the reply
+    for (unsigned i = 0 ; i < reply_nbr ; i++)
+    {
+      while (generator->repliesArray == NULL || generator->repliesArray[i] == NULL) 
+      { 
+        boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+      }
+      ptr = generator->repliesArray[i];
+      
+      // Send it
+      //int byteSent=sessionSocket.send(boost::asio::buffer(ptr, byteSize));
+      if (write(sessionSocket,boost::asio::buffer(ptr, byteSize)) <= 0)
+        exitWithErrorMessage(__FUNCTION__,"Error sending request" );
+	  	totalbytesent+=byteSize;
+#ifdef NDSS_UPLOAD_SPEED
+      sleepForBytes(byteSize);
+#endif
+      // Free its memory
+      free(ptr);
+      generator->repliesArray[i]=NULL;
+    }
+
+    // When everythind is send close the socket
+    sessionSocket.close();
+  }
+  // If there was a problem sending the reply
+  catch (std::exception const& ex)
+  {
+#ifdef DEBUG
+    std::cerr << "Number of chunks sent: " << i << "/" << reply_nbr << std::endl;
+#endif
+    exitWithErrorMessage(__FUNCTION__, string(ex.what()));
+    return;
+  }
+
+
+  // Tell when we have finished
+  writeWarningMessage(__FUNCTION__ , "done.");;
+}
+
+
+// Functions for displaying logs 
+void PIRSession::writeErrorMessage(string funcName, string message)
+{
+  cerr << BOLD  << funcName << " : " << RESET_COLOR << RED << message << RESET_COLOR <<endl;
+}
+void PIRSession::writeWarningMessage(string funcName, string message) 
+{
+  cerr << BOLD  << funcName << " : " << RESET_COLOR << ORANGE << message << RESET_COLOR <<endl;
+}
+
+// For critical erros
+void PIRSession::exitWithErrorMessage(string funcName, string message) 
+{
+  writeErrorMessage(funcName, message);
+
+  // This is used in the main function (start()) to skip costly operations if an error occurred
+  handmadeExceptionRaised = true;	
+}
+
+
+// Used by the PIRServer for garbage collection
+bool PIRSession::isFinished()
+{
+  return finished;
+}
+
+// Destructor
+PIRSession::~PIRSession()
+{
+  if (cryptoMethod != NULL) delete cryptoMethod;
+
+}
+
+PIRParameters PIRSession::getPIRParams()
+{
+  pirParam.crypto_params = cryptoMethod->getPublicParameters().getSerializedParams(false);
+  return pirParam;
+}
+
+void PIRSession::setPIRParams(PIRParameters pir_parameters)
+{
+  pirParam = pir_parameters;
+}
+
+imported_database_t PIRSession::getSavedDatabase()  {
+   return  savedDatabase;
+}
+
+void PIRSession::no_pipeline(bool b)
+{
+  no_pipeline_mode = b;
+}

+ 108 - 0
apps/server/PIRSession.hpp

@@ -0,0 +1,108 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_PIRSESSION
+#define DEF_PIRSESSION
+#include <vector>
+#include <iostream>
+#include <dirent.h>
+#include <boost/asio.hpp>
+#include <boost/thread.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include "apps/server/DBHandler.hpp"
+#include "pir/PIRParameters.hpp"
+#include "pir/replyGenerator/PIRReplyGeneratorFactory.hpp"
+#include "crypto/HomomorphicCryptoFactory_internal.hpp"
+
+#include "pir/PIRParametersExchangeMethods.hpp"
+#include "pir/GlobalConstant.hpp"
+#include "pir/shared_queue.hpp"
+
+#define DEFAULT_DIR_NAME "db/"
+
+
+
+#define MAX_ATTEMPT 10
+#define DEFAULT_PORT 1234
+
+#define RED "\033[31m"
+#define BOLD "\033[1;30m"
+#define ORANGE "\033[33m"
+#define RESET_COLOR "\033[m"
+
+using boost::asio::ip::tcp;
+
+struct session_option_t {
+  bool driven_mode;
+  bool keep_database;
+  bool got_preimported_database;
+  imported_database_t data;
+};
+
+class PIRSession : public boost::enable_shared_from_this<PIRSession>
+{
+	private:
+		DBHandler *dbhandler;
+		tcp::socket sessionSocket;
+		boost::thread upThread, downThread;
+		bool handmadeExceptionRaised;
+    	bool finished;
+
+		PIRParameters 		 pirParam;
+		CryptographicSystem* cryptoMethod;
+		GenericPIRReplyGenerator*  generator;
+
+		uint64_t maxFileBytesize; // La taille totale de la base de donnée en octets
+
+		void serveForever();
+		void rcvCryptoParams(bool paramsandkey);
+    void sendCryptoParams(); 
+    void sendPIRParamsExchangeMethod(short exchange_method);
+		void rcvPirParams();
+		void sendPirParams();
+		void sendCatalog();
+		void recieveKey();
+		void startProcessQuery ();
+		void startProcessResult(session_option_t session_option);
+    bool rcvIsClient();
+
+		void downloadWorker();
+		void uploadWorker();
+    imported_database_t savedDatabase;
+     bool no_pipeline_mode;
+
+	public:
+    	typedef boost::shared_ptr<PIRSession> pointer;
+    	static pointer create(boost::asio::io_service& ios);
+		PIRSession(boost::asio::io_service& ios);
+		~PIRSession();
+
+    void setDBHandler(DBHandler *db);
+		void writeErrorMessage(string, string);
+		void writeWarningMessage(string, string);
+		void exitWithErrorMessage(string, string);
+		bool isFinished();
+		tcp::socket& getSessionSocket();
+		bool start(session_option_t session_option);
+    PIRParameters getPIRParams();
+    void setPIRParams(PIRParameters pir_parameters);
+    imported_database_t getSavedDatabase();
+    void no_pipeline(bool b);
+};
+#endif

+ 75 - 0
apps/server/ServerService.cpp

@@ -0,0 +1,75 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "ServerService.hpp"
+
+const unsigned int ServerService::kPIRParamsOptions = 2;
+
+int ServerService::writePIRParameters(const PIRParameters& pir_params, const std::string& file_path)
+{
+  std::ofstream file(file_path);
+
+  if(!file.is_open()) return 1;
+
+  file << "d " << pir_params.d << std::endl;
+  file << "dim ";
+
+  for (unsigned int i = 0; i < pir_params.d ; i++) file << std::to_string(pir_params.n[i]) << " ";
+
+  file << std::endl;
+  file << pir_params.crypto_params << std::endl;
+
+  file.close();
+
+  return 0;
+}
+
+
+int ServerService::readPIRParameters(PIRParameters& pir_params, const std::string& file_path)
+{
+  std::ifstream file(file_path);
+
+  if (!file.is_open()) return 1;
+
+  std::string line;
+  std::vector<std::string> fields;
+
+  std::getline(file, line);
+  boost::algorithm::split(fields, line, boost::algorithm::is_any_of(" "));
+
+  pir_params.d = atoi(fields.at(1).c_str());
+
+  if (file.eof()) return 1;
+
+  std::getline(file, line);
+  boost::algorithm::split(fields, line, boost::algorithm::is_any_of(" "));
+
+  unsigned int i;
+  for (i = 0 ; i < pir_params.d && i < fields.size() - 1 ; i++)
+  {
+    pir_params.n[i] = atoi(fields.at(i+1).c_str());
+  }
+
+  if (i != pir_params.d) return 1;
+  
+  std::getline(file, line);
+
+  pir_params.crypto_params = line;
+
+  file.close();
+  return 0;
+}

+ 37 - 0
apps/server/ServerService.hpp

@@ -0,0 +1,37 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_SERVERSERVICE
+#define DEF_SERVERSERVICE
+
+#include <string>
+#include <vector>
+#include <fstream>
+#include <iostream>
+#include <boost/algorithm/string.hpp>
+
+#include "../pir/PIRParameters.hpp"
+
+class ServerService
+{
+public:
+  static const unsigned int kPIRParamsOptions;
+  static int writePIRParameters(const PIRParameters& pir_parms, const std::string& file_path);
+  static int readPIRParameters(PIRParameters& pir_params, const std::string& file_path);
+};
+
+#endif

+ 126 - 0
apps/server/main.cpp

@@ -0,0 +1,126 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "main.hpp"
+
+const std::string kDefault_file_path = "exp/PIRParams.cfg";
+
+int main(int argc, char* argv[])
+{
+  std::cout << std::endl << "########################################################" << std::endl;
+  std::cout << "# XPIR ... Private Information Retrieval for everyone #" << std::endl;
+  std::cout << "########################################################" << std::endl << std::endl;
+
+  int port = 1234;
+  bool usedbgenerator = false;
+  uint64_t dbgenerator_n = 10, dbgenerator_l = 12800000;
+  int driven = -1;
+  uint64_t split_value = 1; 
+  std::string pir_params_file_path(kDefault_file_path);
+
+	po::options_description od("Available options");	
+	od.add_options()
+		("help,h", "help message")
+    ("driven,z", po::value<std::string>()->implicit_value(pir_params_file_path),"Server-driven mode : configure crypto and PIR parameters using the first client, make them mandatory for other clients and save them into a persistent file.")
+		("load_file,L", po::value<std::string>(), "Load PIR parameters from file.")
+    ("split_file,s", po::value<uint64_t>(&split_value)->default_value(1), "Only use first file in db directory and split it in arg elements.")
+		("port,p", po::value<int>(&port)->default_value(1234), "Port used, default")
+		("db-generator-files,n", po::value<uint64_t>(&dbgenerator_n)->default_value(10), "Number of files for the DB generator")
+		("db-generator-filesize,l", po::value<uint64_t>(&dbgenerator_l)->default_value(12800000), "Size of file for the DB generator")
+		("db-generator", "Generate the database instead of reading it from a directory")
+    ("no-pipeline", "No pipeline mode");
+
+	po::variables_map vm;
+	try 
+	{
+		po::store(po::parse_command_line(argc, argv, od), vm);
+	}
+	catch (const std::exception& ex) 
+	{
+		std::cout << "Error checking program options: " << ex.what() << std::endl;
+		std::cout << od << std::endl;
+		return 1;
+	}
+
+	if (!vm.size()) 
+	{
+		std::cout << "No option specified : " << std::endl;
+		std::cout << od << std::endl;
+	}
+	if (vm.count("help")) 
+	{
+		std::cout << od << std::endl;
+		return 0;
+	}
+  if (vm.count("driven"))
+  {
+    driven = 1;
+    pir_params_file_path =  vm["driven"].as<std::string>();
+  }
+  if (vm.count("load_file"))
+  {
+    pir_params_file_path =  vm["load_file"].as<std::string>();
+    driven = 0;
+  }
+  if (vm.count("split_file"))
+  {
+    split_value = vm["split_file"].as<uint64_t>();
+  }
+  if (vm.count("db-generator-files"))
+  {
+    dbgenerator_n = vm["db-generator-files"].as<uint64_t>();
+  }
+  if (vm.count("db-generator-filesize"))
+  {
+    dbgenerator_l = vm["db-generator-filesize"].as<uint64_t>();
+  }
+  if (vm.count("db-generator"))
+  {
+    std::cout << "CLI: DBGenerator requested with params n=" << dbgenerator_n
+     << " l=" << dbgenerator_l << std::endl;
+    usedbgenerator = true;
+  }
+    
+  try
+  {
+    boost::asio::io_service io_service;
+    boost::asio::signal_set signals(io_service, SIGINT, SIGTERM);
+    signals.async_wait(
+    boost::bind(&boost::asio::io_service::stop, &io_service));
+
+    PIRServer server(io_service, port, split_value, usedbgenerator, dbgenerator_n, dbgenerator_l);
+
+    if (vm.count("no-pipeline"))
+    {
+    std::cout << "Main: WARNING no pipeline mode activated" << std::endl;
+    server.no_pipeline(true);
+    }
+
+    if (driven == 1) server.processDrivenSession(pir_params_file_path);
+
+    else if (driven == 0) server.readPIRParamsFromFile(pir_params_file_path);
+
+    server.serve();
+    io_service.run();
+
+    cout << "Main: PIRServer has stopped" << endl;
+  }
+  catch (std::exception& e)
+  {
+    std::cerr << "Exception catched in main.cpp " << e.what() << std::endl;
+  }
+}

+ 37 - 0
apps/server/main.hpp

@@ -0,0 +1,37 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_MAIN
+#define DEF_MAIN
+
+#include <signal.h>
+#include <iostream>
+
+#include <boost/asio.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/program_options.hpp>
+
+#include "../server/PIRServer.hpp"
+#include "../optim/PIROptimizer.hpp"
+
+void sighandler(int sig_num);
+
+using namespace std;
+namespace po = boost::program_options;
+
+#endif
+

+ 29 - 0
apps/simplepir/CMakeLists.txt

@@ -0,0 +1,29 @@
+cmake_minimum_required(VERSION 2.6.0)
+
+if (APPLE)
+	set(CMAKE_EXE_LINKER_FLAGS "-fopenmp -L$ENV{HOME}/Code/xpir/freshxpir/xpir-ng/local/lib/ -lboost_program_options")
+
+endif()
+
+include_directories(.)
+include_directories(..)
+include_directories(../..)
+
+add_custom_target(build-time-make-directory-simple-pir ALL COMMAND ${CMAKE_COMMAND} -E make_directory "db")
+file(COPY "../tools/makedb.sh" DESTINATION ".")
+
+
+add_executable(simple_pir simplePIR.cpp ../../libpir.hpp ../server/DBGenerator.cpp ../server/DBDirectoryProcessor.cpp)
+#target_link_libraries(simple_pir pir_server_pir pir_query_gen pir_reply pir pir_client_events pir_client_optim pthread ${MPFR_LIBRARIES} ${Boost_LIBRARIES} ${GMP_LIBRARIES} ${GMPXX_LIBRARIES})
+target_link_libraries(simple_pir pir pthread ${MPFR_LIBRARIES} ${Boost_LIBRARIES} ${GMP_LIBRARIES} ${GMPXX_LIBRARIES})
+
+
+add_custom_command(
+    OUTPUT .simplepirdb
+    WORKING_DIR ${PROJECT_BINARY_DIR}/apps/simplepir
+    COMMAND ./makedb.sh 1024 16 2>/dev/null
+    COMMAND touch .simplepirdb
+)
+
+add_custom_target(simplepirdb ALL DEPENDS .simplepirdb)
+	

+ 241 - 0
apps/simplepir/simplePIR.cpp

@@ -0,0 +1,241 @@
+#include "libpir.hpp"
+#include "apps/server/DBDirectoryProcessor.hpp"
+
+bool run(DBHandler *db, uint64_t chosen_element, PIRParameters params){
+
+
+  /******************************************************************************
+  * PIR and Crypto Setup (must be done by both the client and the server)      
+  * In a real application the client and server must agree on the parameters
+  * For example the client chooses and sends them to the server (or inversely)
+  ******************************************************************************/
+	
+	HomomorphicCrypto *crypto = HomomorphicCryptoFactory::getCryptoMethod(params.crypto_params);
+
+  // Absorption capacity of an LWE encryption scheme depends on the number of sums that are going
+  // to be done in the PIR protocol, it must therefore be initialized
+	// Warning here we suppose the biggest dimension is in d[0] 
+  // otherwise absorbtion needs to be computed accordingly
+  crypto->setandgetAbsBitPerCiphertext(params.n[0]);
+
+
+  /******************************************************************************
+  * Query generation phase (client-side)                                       
+  ******************************************************************************/
+	
+  // Create the query generator object
+	PIRQueryGenerator q_generator(params,*crypto);
+  std::cout << "SimplePIR: Generating query ..." << std::endl;
+  // Generate a query to get the FOURTH element in the database (indexes begin at 0)
+  // Warning : if we had set params.alpha=2 elements would be aggregated 2 by 2 and 
+  // generatequery would only accept as input 0 (the two first elements) or 1 (the other two)
+	q_generator.generateQuery(chosen_element);
+  std::cout << "SimplePIR: Query generated" << std::endl;
+	
+
+  /******************************************************************************
+  * Reply generation phase (server-side)
+  ******************************************************************************/
+	
+  // Create the reply generator object
+	PIRReplyGenerator r_generator(params,*crypto,db);
+  r_generator.setPirParams(params);
+
+  // In a real application the client would pop the queries from q with popQuery and 
+  // send them through the network and the server would receive and push them into s 
+  // using pushQuery
+  char* query_element;
+  while (q_generator.popQuery(&query_element))
+  {
+    r_generator.pushQuery(query_element);
+  }
+ 
+	// Import database
+  // This could have been done on the "Database setup" phase if:
+  //  - the contents are static
+  //  - AND the imported database fits in RAM
+  //  - AND the server knows in advance the PIR and crypto parameters (e.g. chosen by him)
+  std::cout << "SimplePIR: Importing database ..." << std::endl;
+  // Warning aggregation is dealt with internally the bytes_per_db_element parameter here
+  // is to be given WITHOUT multiplying it by params.alpha
+	imported_database* imported_db = r_generator.importData(/* uint64_t offset*/ 0, /*uint64_t
+    bytes_per_db_element */ db->getmaxFileBytesize());
+  std::cout << "SimplePIR: Database imported" << std::endl;
+
+	// Once the query is known and the database imported launch the reply generation
+  std::cout << "SimplePIR: Generating reply ..." << std::endl;
+	double start = omp_get_wtime();
+	r_generator.generateReply(imported_db);
+	double end = omp_get_wtime();
+  std::cout << "SimplePIR: Reply generated in " << end-start << " seconds" << std::endl;
+	
+	
+
+  /******************************************************************************
+  * Reply extraction phase (client-side)
+  ******************************************************************************/
+	
+	PIRReplyExtraction *r_extractor=new PIRReplyExtraction(params,*crypto);
+
+  // In a real application the server would pop the replies from s with popReply and 
+  // send them through the network together with nbRepliesGenerated and aggregated_maxFileSize 
+  // and the client would receive the replies and push them into r using pushEncryptedReply
+  std::cout << "SimplePIR: "<< r_generator.getnbRepliesGenerated()<< " Replies generated " << std::endl;
+
+  uint64_t clientside_maxFileBytesize = db->getmaxFileBytesize();
+  char* reply_element;
+  while (r_generator.popReply(&reply_element))
+  {
+    r_extractor->pushEncryptedReply(reply_element);
+  }
+
+  std::cout << "SimplePIR: Extracting reply ..." << std::endl;
+	r_extractor->extractReply(clientside_maxFileBytesize);
+  std::cout << "SimplePIR: Reply extracted" << std::endl;
+
+  // In a real application instead of writing to a buffer we could write to an output file
+  char *outptr, *result, *tmp;
+  outptr = result = (char*)calloc(r_extractor->getnbPlaintextReplies(clientside_maxFileBytesize)*r_extractor->getPlaintextReplyBytesize(), sizeof(char));
+  while (r_extractor->popPlaintextResult(&tmp)) 
+  {
+    memcpy(outptr, tmp, r_extractor->getPlaintextReplyBytesize()); 
+    outptr+=r_extractor->getPlaintextReplyBytesize();
+    free(tmp);
+  }
+  // Result is in ... result  
+  
+
+  /******************************************************************************
+  * Test correctness
+  ******************************************************************************/
+	char *db_element = (char*)calloc(clientside_maxFileBytesize*params.alpha, sizeof(char));
+  bool fail = false;
+	db->readAggregatedStream(chosen_element, params.alpha, 0, clientside_maxFileBytesize, db_element);
+  if (memcmp(result, db_element, clientside_maxFileBytesize*params.alpha))
+  {
+    std::cout << "SimplePIR: Test failed, the retrieved element is not correct" << std::endl;
+    fail = true;
+  }
+  else
+  {
+    std::cout << "SimplePIR: Test succeeded !!!!!!!!!!!!!!!!!!!!!!!!"  << std::endl<< std::endl;
+    fail = false;
+  }
+
+  /******************************************************************************
+  * Cleanup
+  ******************************************************************************/
+  
+  delete imported_db;
+  r_generator.freeQueries();
+
+  
+	return fail;
+	
+}
+
+
+int main(int argc, char * argv[]) {
+
+  uint64_t database_size, nb_files, chosen_element, maxFileBytesize;
+	PIRParameters params; 
+  bool tests_failed = false;
+  
+/******************************************************************************
+  * Database setup (server-side)                              
+  ******************************************************************************/
+
+
+  // To Create the database generator object
+  // it can be a DBGenerator that simulate nb_files files of size streamBytesize
+  // database_size = 1ULL<<25; nb_files = 4; maxFileBytesize = database_size/nb_files;
+  // DBGenerator db(nb_files, maxFileBytesize, /*bool silent*/ false); 
+  // 
+  // OR it can be a DBDirectoryProcessor that reads a real file in the ./db directory 
+  // and splits it into nb_files virtual files
+  // nb_files = 4;
+  // DBDirectoryProcessor db(nb_files);
+  // database_size = db.getDBSizeinbits();maxFileBytesize = database_size/nb_files;
+  //
+  // OR it can be a DBDirectoryProcessor that reads the real files in the ./db directory
+  // DBDirectoryProcessor db;
+  // nb_files=db.getNbStream();database_size = db.getDBSizeinbits();
+  // maxFileBytesize = database_size/nb_files;
+
+  // Simple test
+  database_size = 1ULL<<31; nb_files = 20; maxFileBytesize = database_size/nb_files;
+  DBGenerator db(nb_files, maxFileBytesize, /*bool silent*/ false); 
+  chosen_element = 3;
+  params.alpha = 1; params.d = 1; params.n[0] = nb_files; 
+  // The crypto parameters can be set to other values
+  // You can get a list of all available cryptographic parameters with this function call 
+  // HomomorphicCryptoFactory::printAllCryptoParams();
+  params.crypto_params = "LWE:80:2048:120"; 
+  tests_failed |= run(&db, chosen_element, params);
+  
+ 
+  // Test with aggregation
+  // WARNING we must provide the representation of the database GIVEN recursion and aggregation
+  // as here we have 100 elements and aggregate them in a unique group we have params.n[0]=1
+  database_size = 1ULL<<25; nb_files = 100; maxFileBytesize = database_size/nb_files;
+  DBGenerator db2(nb_files, maxFileBytesize, /*bool silent*/ false); 
+  chosen_element = 0;
+  params.alpha = 100; params.d = 1; params.n[0] = 1; 
+  params.crypto_params = "LWE:80:2048:120";
+  tests_failed |= run(&db2, chosen_element, params);
+  
+  // Test with recursion 2
+  database_size = 1ULL<<25; nb_files = 100; maxFileBytesize = database_size/nb_files;
+  DBGenerator db3(nb_files, maxFileBytesize, /*bool silent*/ false); 
+  chosen_element = 3;
+  params.alpha = 1; params.d = 2; params.n[0] = 50; params.n[1] = 2; 
+  params.crypto_params = "LWE:80:2048:120";
+  tests_failed |= run(&db3, chosen_element, params);
+  
+  // Test with recursion 2 and aggregation
+  database_size = 1ULL<<25; nb_files = 100; maxFileBytesize = database_size/nb_files;
+  DBGenerator db4(nb_files, maxFileBytesize, /*bool silent*/ false); 
+  chosen_element = 3;
+  params.alpha = 2; params.d = 2; params.n[0] = 25; params.n[1] = 2; 
+  params.crypto_params = "LWE:80:2048:120";
+  tests_failed |= run(&db4, chosen_element, params);
+  
+  // Test with recursion 3
+  database_size = 1ULL<<25; nb_files = 100; maxFileBytesize = database_size/nb_files;
+  DBGenerator db5(nb_files, maxFileBytesize, /*bool silent*/ false); 
+  chosen_element = 3;
+  params.alpha = 1; params.d = 3; params.n[0] = 5; params.n[1] = 5; params.n[2] = 4; 
+  params.crypto_params = "LWE:80:2048:120";
+  tests_failed |= run(&db5, chosen_element, params);
+  
+  // Test with a DBDirectoryProcessor splitting a big real file
+  database_size = 1ULL<<25; nb_files = 4; maxFileBytesize = database_size/nb_files;
+  DBDirectoryProcessor db6(/*split the bit file in*/ nb_files /*files*/);
+  chosen_element = 3;
+  params.alpha = 1; params.d = 1; params.n[0] = nb_files; 
+  params.crypto_params = "LWE:80:2048:120";
+  tests_failed |= run(&db6, chosen_element, params);
+  
+  // Test with a DBDirectoryProcessor reading real files
+  DBDirectoryProcessor db7;
+  database_size = db7.getDBSizeBits()/8; nb_files = db7.getNbStream(); 
+  maxFileBytesize = database_size/nb_files;
+  chosen_element = 0;
+  params.alpha = 1; params.d = 1; params.n[0] = nb_files; 
+  params.crypto_params = "LWE:80:2048:120";
+  tests_failed |= run(&db7, chosen_element, params);
+
+  if (tests_failed) 
+  {
+    std::cout << "WARNING : at least one tests failed" << std::endl;
+    return 1;
+  }
+  else
+  {
+    std::cout << "All tests succeeded" << std::endl;
+    return 0;
+  }
+}
+
+
+

+ 273 - 0
apps/tools/check-correctness.sh

@@ -0,0 +1,273 @@
+#!/bin/bash
+#/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+# * This file is part of XPIR.
+# *
+# *  XPIR is free software: you can redistribute it and/or modify
+# *	it under the terms of the GNU General Public License as published by
+# *  the Free Software Foundation, either version 3 of the License, or
+# *  (at your option) any later version.
+# *
+# *  XPIR is distributed in the hope that it will be useful,
+# *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+# *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# *  GNU General Public License for more details.
+# *
+# *  You should have received a copy of the GNU General Public License
+# *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+#*/
+
+
+########### CONSTANTS ##############
+MAX_REC=3
+MIN_ALPHA=0		    # Set MIN and MAX to 1 to forbid aggregation
+MAX_ALPHA=0		   
+NO_REREAD=1
+NO_PIPELINE=0
+VERBOSE=0
+
+TEST_PAILLIER=0
+TEST_NOCRYPTOGRAPHY=1
+TEST_LWE=1
+
+REMOTE=0
+IP=169.254.4.46
+USER=marco
+
+ONE_KBIT=1024
+HUNDRED_KBIT=102400
+ONE_MBIT=1024000
+TEN_MBIT=10240000
+HUNDRED_MBIT=102400000
+ONE_GBIT=1024000000
+
+#files: 1kbits, 100kbits, 10mbits 1gbit
+#bases: 1Mbits, 10M, 100M, 1G 10G
+
+########### SUBROUTINES ##############
+deal_with_options() 
+{
+    if [[ ( $NO_REREAD == 1 ) ]];
+    then
+	S_OPTION="-z"
+    fi
+    if [[ ( $NO_PIPELINE == 1 ) ]];
+    then
+	S_OPTION=$S_OPTION" --no-pipeline"
+	C_OPTION="--no-pipeline"
+	echo "Mode --no-pipeline selected"
+    fi
+}
+
+do_a_test() 
+{
+    rm -f reception/* 2> /dev/null
+	if [[ $VERBOSE == 2 ]]; then
+		echo $BASE_DIR/../server/pir_server $S_OPTION
+	    echo $BASE_DIR/../client/pir_client -r $PARAM $C_OPTION $@ -c 
+	fi
+  if [[ $N -le 1000 ]];
+  then 
+    $BASE_DIR/../server/pir_server $S_OPTION > /tmp/checkpirserver.stdout 2>/tmp/checkpirserver.stderr &
+  else
+    $BASE_DIR/../server/pir_server $S_OPTION -s $N > /tmp/checkpirserver.stdout 2>/tmp/checkpirserver.stderr &
+  fi
+  PID=$!
+  sleep 1
+  $BASE_DIR/../client/pir_client -r $PARAM $C_OPTION $@ -c  > /tmp/checkpirclient.stdout 2> /tmp/checkpirclient.stderr 
+}
+
+exploit_results()
+{
+    FILE_RETRIEVED=`ls reception`
+    MD5_R1=`sha1sum reception/$FILE_RETRIEVED 2>/dev/null |cut -d\  -f1`
+    MD5_DB=`dd if=db/test1 bs=1 count=$L_BYTE 2>/dev/null |sha1sum 2>/dev/null |cut -d\  -f1`
+    
+    if [[ ( $NO_REREAD -eq 1 ) ]];
+    then
+						#	to check no-reread-database, do it a second time
+	rm -f reception/* 2> /dev/null
+	$BASE_DIR/../client/pir_client -r $PARAM $C_OPTION $@ -c  >> /tmp/checkpirclient.stdout 2>> /tmp/checkpirclient.stderr 
+	MD5_R2=`sha1sum reception/* 2>/dev/null |cut -d\  -f1`
+	if [[ $FILE_RETRIEVED != "" && ($MD5_DB == $MD5_R1) && ($MD5_DB == $MD5_R2) ]]; then
+	    CORRECT=1;
+	else
+	    CORRECT=0;
+	fi
+    else
+	if [[ $FILE_RETRIEVED != "" && ($MD5_DB == $MD5_R1) ]]; then
+	    CORRECT=1;
+	else
+	    CORRECT=0;
+	fi
+    fi
+
+    if [[ $CORRECT == 1 ]]; then
+	    echo -e "$DB:$L:$PARAM \033[32mCORRECT\033[m"
+    else
+	    echo -e "$DB:$L:$PARAM \033[31m*************** NOT CORRECT **********\033[m"
+	    if [[ $VERBOSE -ge 1 ]]; then
+	      echo "Database : check.repo/db-$L_BYTE-$N"
+	      echo "Server : $BASE_DIR/../server/pir_server $S_OPTION"
+	      echo "Client : $BASE_DIR/../client/pir_client -r $PARAM $C_OPTION $@ -c  "
+	      echo "*************** Server stdout **********"
+        cat /tmp/checkpirserver.stdout
+	      echo "*************** Server stderr **********"
+        cat /tmp/checkpirserver.stderr
+	      echo "*************** Client stdout **********"
+        cat /tmp/checkpirclient.stdout
+	      echo "*************** Client stderr **********"
+        cat /tmp/checkpirclient.stderr
+	      echo "hit <enter> to continue";read
+	    fi    
+    fi
+    
+    (kill $PID >/dev/null 2>/dev/null)
+    # Notify when waiting for kill
+    # Use ANSI escape sequences to stay on the same line
+    while [[ `ps -ef|grep pir_server|wc -l` -ne 1 ]] ; do 
+      echo -e "Could not kill pir_server, waiting ..."
+      echo -e "\033[2A"
+      sleep 1
+    done
+    # Use ANSI escape sequences again to erase and reuse the line
+    echo  "                                     "
+    echo -e "\033[2A"
+    rm -f /tmp/checkpir* >/dev/null 2>/dev/null
+}
+
+
+########### MAIN ##############
+
+echo -e "##########################################################################"
+echo -e "This tool tests that pir_server and pir_client run correctly and that an"
+echo -e "element can be retrieved without errors. You should obtain CORRECT or "
+echo -e "\"Skipping test...\" for all tests. THE FIRST TEST CAN BE QUITE LONG if"
+echo -e "performance caches need to be built (first run for the server or client)"
+echo -e "##########################################################################"
+
+killall -9 pir_server >/dev/null 2>/dev/null; sleep 1
+
+# Notify when waiting for kill
+# Use ANSI escape sequences to stay on the same line
+while [[ `ps -ef|grep pir_server|wc -l` -ne 1 ]]; do 
+  echo -e "Could not kill pir_server, waiting ..."
+  echo -e "\033[2A"
+  sleep 1
+done
+# Use ANSI escape sequences again to erase and reuse the line
+echo  "                                     "
+echo -e "\033[2A"
+
+deal_with_options
+
+BASE_DIR=$PWD
+
+cd check.repo
+
+
+# Paillier tests only for small databases
+if [[ TEST_PAILLIER -eq 1 ]]; then
+  echo -e "\nPaillier tests\n#################\n"
+  for DB in $ONE_MBIT #$TEN_MBIT 
+    do
+	for L in $ONE_KBIT $HUNDRED_KBIT $TEN_MBIT $ONE_GBIT 
+	do
+		
+    N=`python -c"print(int($DB / $L));"`
+    L_BYTE=`python -c"print(int($L / 8 ));"`
+	    
+	    if [[ ( $DB -gt $L ) && ( -f  db-$L_BYTE-$N/test1 ) ]]; 
+	    then
+		
+		rm -fr db
+		mkdir reception 2> /dev/null
+		mkdir exp 2> /dev/null
+		
+		
+		ln -s db-$L_BYTE-$N db
+	  echo Checking db-$L_BYTE-$N 
+
+		for QP in "80:1024:2048"
+		#for QP in "80:1024:2048:1016"
+		do
+		    for REC in `eval echo {1..$MAX_REC}`
+		    do	
+		    # TODO use alpha (aggregation does not work yet)
+			for ALPHA in `eval echo {$MIN_ALPHA..$MAX_ALPHA}`
+			do	
+			    PARAM="Paillier:$QP --reclvl $REC --alpha $ALPHA "
+			    
+			    do_a_test
+			    exploit_results
+			done
+		    done
+		done
+	    fi
+	done
+    done
+fi
+
+echo -e "\n\nOther tests\n#################\n"
+for DB in $ONE_MBIT $TEN_MBIT $HUNDRED_MBIT $ONE_GBIT 
+do
+    for L in $ONE_KBIT $HUNDRED_KBIT $TEN_MBIT $ONE_GBIT  
+    do
+      N=`python -c"print(int($DB / $L));"`
+      L_BYTE=`python -c"print(int($L / 8) );"`
+      DB_BYTE=`python -c"print(int($DB / 8));"`
+
+  # If N <= 10000 a database with different files must exist 
+  # If not a database with a single file to split must exist
+  if [[ ( ( $N -le 10000 ) && ( -f  db-$L_BYTE-$N/test1 ) ) || ( $N -gt 1000 ) && ( -f db-$DB_BYTE/test1 ) ]]; 
+	then
+	    
+	    rm -fr db
+	    mkdir reception 2> /dev/null
+	    mkdir exp 2> /dev/null
+	    
+	    if [[ $N -le 1000 ]]; 
+      then
+	      ln -s db-$L_BYTE-$N db
+	      echo Checking db-$L_BYTE-$N 
+      else
+	      ln -s db-$DB_BYTE db
+	      echo Checking db-$DB_BYTE with split_value=$N 
+      fi
+
+	    if [[ TEST_NOCRYPTOGRAPHY -eq 1 ]]; then
+	        # Test No Cryptography
+		PARAM="NoCryptography"
+		do_a_test
+		exploit_results
+	    fi
+
+	    # Test LWE
+	    for QP in "4096:180" "2048:120" "1024:60"
+	    #for QP in "180:73" "120:43" "60:13"
+	    do
+		#TODO use python to compute absorption #math.floor(($Q-math.ceil(math.log($SEC/2,2))-math.ceil(math.log($N,2))-math.ceil(math.log($DEG,2)))/2)
+		for REC in `eval echo {1..$MAX_REC}`
+		do	
+		    for ALPHA in `eval echo {$MIN_ALPHA..$MAX_ALPHA}`
+		    do	
+			if [[ TEST_LWE -eq 1 ]]; then
+			  PARAM="LWE:.*:$QP --reclvl $REC --alpha $ALPHA "
+        CIPH_SIZE=`echo $QP|tr : \*`"*2"
+        QUERY_SIZE="$CIPH_SIZE*$REC*$N.0**(1/$REC.0)"
+        DB_FFT_SIZE="6*$DB"
+        if [[ ( `python -c "print(($QUERY_SIZE+$DB_FFT_SIZE)/10**9 > 40);"` == "True" ) || ( `python -c "print(($CIPH_SIZE*$N+$QUERY_SIZE)/10**9 > 40);"` == "True" ) ]]; then
+          echo "Skipping tests requiring more than 5Gbytes RAM"
+        else
+			    do_a_test
+			    exploit_results
+        fi
+			fi
+		    done
+		done
+	    done
+	fi
+    done
+done
+cd ..
+
+

+ 29 - 0
apps/tools/makedb.sh

@@ -0,0 +1,29 @@
+#!/bin/bash
+#/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+# * This file is part of XPIR.
+# *
+# *  XPIR is free software: you can redistribute it and/or modify
+# *	it under the terms of the GNU General Public License as published by
+# *  the Free Software Foundation, either version 3 of the License, or
+# *  (at your option) any later version.
+# *
+# *  XPIR is distributed in the hope that it will be useful,
+# *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+# *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# *  GNU General Public License for more details.
+# *
+# *  You should have received a copy of the GNU General Public License
+# *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+#*/
+
+
+if [[ ! -d db ]]; then
+	mkdir db;
+	touch db/foo
+fi
+/bin/rm -f db/*
+for ((  i = 1 ;  i <= $2 ; i++  ))
+	do
+		dd if=/dev/urandom of=db/test$i count=$1 bs=1024
+		#dd if=/dev/zero of=db/test$i count=$1 bs=1024
+	done

+ 82 - 0
apps/tools/mkdb-correctness.sh

@@ -0,0 +1,82 @@
+#!/bin/bash
+#/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+# * This file is part of XPIR.
+# *
+# *  XPIR is free software: you can redistribute it and/or modify
+# *	it under the terms of the GNU General Public License as published by
+# *  the Free Software Foundation, either version 3 of the License, or
+# *  (at your option) any later version.
+# *
+# *  XPIR is distributed in the hope that it will be useful,
+# *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+# *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# *  GNU General Public License for more details.
+# *
+# *  You should have received a copy of the GNU General Public License
+# *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+#*/
+
+
+ONE_KBIT=1024
+HUNDRED_KBIT=102400
+ONE_MBIT=1024000
+TEN_MBIT=10240000
+HUNDRED_MBIT=102400000
+ONE_GBIT=1024000000
+
+#files: 1kbits, 100kbits, 10mbits 1gbit
+#bases: 1Mbits, 10M, 100M, 1G, 10G
+
+mkdir check.repo
+cp -r ../client/exp check.repo/
+cd check.repo
+mkdir reception
+
+if [[ -f source.random ]]
+then
+	echo "Reusing the source.random file"
+else
+	echo "Creating the source.random file"
+  dd if=/dev/urandom of=source.random count=`python -c"print( int($ONE_GBIT / (1024000) ) );"` bs=128000
+fi
+
+echo "Creating the databases .."
+for DB in $ONE_MBIT $TEN_MBIT $HUNDRED_MBIT $ONE_GBIT
+do
+  for L in $HUNDRED_KBIT $TEN_MBIT $ONE_GBIT $ONE_KBIT 
+	do
+    N=`python -c"print( int($DB / $L) );"`
+		
+    # Only build directories with 1000 or less files
+		if [[ ( $DB -gt $L ) && ( $N -le 1000 )]]; 
+			then
+			
+			#First we need to obtain the appropriate parameters for N and L fixed
+	
+      L_KBIT=`python -c"print( int($L / 1024) );"`
+      L_BYTE=`python -c"print( int($L / 8) );"`
+				
+			rm -fr db
+			mkdir db
+			
+			dd if=source.random of=db/test1 count=$L_KBIT bs=128
+			
+      cd db
+			for ((  i = 2 ;  i <= $N ; i++  ))
+				do
+					ln -s test1 test$i
+				done
+      cd ..
+
+			mv db db-$L_BYTE-$N
+    fi      
+	done
+  
+  # For tests with more than 1000 files use a single file with split_file option
+  rm -fr db
+	mkdir db
+  dd if=source.random of=db/test1 count=`python -c"print( int($DB / 1024000) );"` bs=128000
+  mv db db-`python -c"print( int($DB / 8) );"`
+done
+rm -f source.random
+cd ..

+ 19 - 0
crypto/AbstractPublicParameters.cpp

@@ -0,0 +1,19 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "AbstractPublicParameters.hpp"
+

+ 46 - 0
crypto/AbstractPublicParameters.hpp

@@ -0,0 +1,46 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_ABSTRACTPUBLICPARAMETERS
+#define DEF_ABSTRACTPUBLICPARAMETERS
+#include <cstddef>
+#include <gmp.h>
+#include <string>
+#include <vector>
+
+#include <boost/algorithm/string.hpp>
+
+class AbstractPublicParameters {
+  protected:
+    std::string cryptoName;
+
+  public:
+    virtual std::string getSerializedParams(bool shortversion)=0;
+    virtual char* getByteModulus()=0;
+    virtual unsigned int getAbsorptionBitsize()=0;
+    virtual unsigned int getAbsorptionBitsize(unsigned int rec_lvl)=0;
+    virtual void setModulus(char* rawPubKey)=0;
+    virtual void setMockedPubKey()=0;
+    virtual unsigned int getCiphertextBitsize()=0;
+    virtual unsigned int getCiphBitsizeFromRecLvl(unsigned int)=0;
+    virtual unsigned int getQuerySizeFromRecLvl(unsigned int)=0;
+    virtual void computeNewParameters(const std::string& crypto_param_descriptor)=0;
+    virtual unsigned int getSerializedModulusBitsize()=0;
+    virtual ~AbstractPublicParameters(){};
+};
+
+#endif

+ 34 - 0
crypto/CMakeLists.txt

@@ -0,0 +1,34 @@
+cmake_minimum_required(VERSION 2.6.0)
+
+add_subdirectory("prng")
+
+set(CMAKE_CXX_FLAGS "-std=c++11 -fopenmp")
+set (CMAKE_EXE_LINKER_FLAGS "-fopenmp")
+if (APPLE)
+	set(CMAKE_EXE_LINKER_FLAGS "-fopenmp -L$ENV{HOME}/Code/xpir/freshxpir/xpir-ng/local/lib/ -lboost_program_options")
+
+endif()
+include_directories(..)
+
+add_library(pir_crypto STATIC
+    AbstractPublicParameters.cpp
+    HomomorphicCrypto.cpp
+    HomomorphicCryptoFactory_internal.cpp
+    LatticesBasedCryptosystem.cpp
+    NFLLWE.cpp
+    NFLLWEPublicParameters.cpp
+    NFLParams.cpp
+    NFLlib.cpp
+    NoCryptography.cpp
+    NoCryptographyPublicParameters.cpp
+    PaillierAdapter.cpp
+    PaillierKeys.cpp
+    PaillierPrivateParameters.cpp
+    PaillierPublicParameters.cpp)
+
+if (APPLE)
+target_link_libraries(pir_crypto pir_crypto_prng )
+else()
+target_link_libraries(pir_crypto pir_crypto_prng gmp)
+endif()
+

+ 35 - 0
crypto/CryptographicSystem.hpp

@@ -0,0 +1,35 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_CRYPTOGRAPHICSYSTEM
+#define DEF_CRYPTOGRAPHICSYSTEM
+#include <set>
+#include <string>
+#include "AbstractPublicParameters.hpp"
+#include <boost/algorithm/string.hpp>
+
+class CryptographicSystem 
+{
+  public:
+    virtual AbstractPublicParameters& getPublicParameters()=0; 
+    virtual unsigned int getAllCryptoParams(std::set<std::string>& crypto_params_set)=0;
+    virtual void setNewParameters(const std::string& crypto_param)=0;
+    virtual ~CryptographicSystem(){};
+    virtual std::string& toString()=0;
+};
+
+#endif

+ 24 - 0
crypto/HomomorphicCrypto.cpp

@@ -0,0 +1,24 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "HomomorphicCrypto.hpp"
+
+HomomorphicCrypto::HomomorphicCrypto(const std::string& crypto_name) :
+  cryptoName(crypto_name)
+{}
+HomomorphicCrypto::~HomomorphicCrypto() {}
+

+ 69 - 0
crypto/HomomorphicCrypto.hpp

@@ -0,0 +1,69 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_HOMOMORPHICCRYPTO
+#define DEF_HOMOMORPHICCRYPTO
+
+#include <string>
+#include <set>
+#include <boost/algorithm/string.hpp>
+#include "../pir/PIRParameters.hpp"
+#include "AbstractPublicParameters.hpp"
+
+#ifndef DEF_CRYPTOGRAPHICSYSTEM
+#define DEF_CRYPTOGRAPHICSYSTEM
+
+class CryptographicSystem 
+{
+  public:
+    virtual AbstractPublicParameters& getPublicParameters()=0; 
+    virtual unsigned int getAllCryptoParams(std::set<std::string>& crypto_params_set)=0;
+    virtual void setNewParameters(const std::string& crypto_param)=0;
+    virtual ~CryptographicSystem(){};
+    virtual std::string& toString()=0;
+};
+
+#endif
+class HomomorphicCrypto : public CryptographicSystem {
+    
+protected:
+    std::string cryptoName; 
+	
+    static unsigned int default_security_bits;
+public:
+    HomomorphicCrypto(const std::string& crypto_name);
+    
+    virtual char* encrypt(unsigned int ui, unsigned int )=0;
+    virtual char* encrypt(char* data, size_t, unsigned int exponent )=0;
+    virtual char* encrypt_perftest()=0;
+    virtual char* decrypt(char* cipheredData, unsigned int rec_lvl, size_t, size_t)=0;
+    
+    virtual unsigned int getCryptoParams(unsigned int k, std::set<std::string>& crypto_params)=0;
+    virtual long setandgetAbsBitPerCiphertext(unsigned int elt_nbr)=0;
+    virtual std::string getSerializedCryptoParams(bool shortversion=true)=0;
+    virtual double estimateAbsTime(std::string crypto_param)=0;
+    virtual ~HomomorphicCrypto();
+    
+    double estimatePrecomputeTime(std::string crypto_param) { return 0;}
+	uint64_t getCiphertextBytesize() {
+		return 	getPublicParameters().getQuerySizeFromRecLvl(0) / 8;
+
+	}
+    std::string& toString() { return cryptoName;}
+};
+
+#endif

+ 87 - 0
crypto/HomomorphicCryptoFactory_internal.cpp

@@ -0,0 +1,87 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "HomomorphicCryptoFactory_internal.hpp"
+
+
+const unsigned int HomomorphicCryptoFactory_internal::crypto_method_nbr = 2;
+const std::vector<std::string>  HomomorphicCryptoFactory_internal::crypto_method_name_vec = [] //use lambda function to initialise the vector
+{
+  std::vector<std::string> v;
+  v.push_back("Paillier");
+  v.push_back("LWE");
+  return v;
+}();
+
+HomomorphicCrypto* HomomorphicCryptoFactory_internal::getCrypto(std::string cryptoType)
+{
+  HomomorphicCrypto* h;
+  
+  if (cryptoType == "Paillier")
+  {
+    h = new PaillierAdapter();
+  }
+  else if (cryptoType == "LWE")
+  {
+    h = new NFLLWE();
+  }
+  else if(cryptoType == "NoCryptography")
+  {
+    h = new NoCryptography();
+  }
+  else
+  {
+    std::cerr << "HomomorphicCryptoFactory_internal: Warning, unrecognized cryptosystem. Returning NULL" << std::endl;
+    h = NULL;
+  }
+  
+  return h;
+}
+  
+HomomorphicCrypto* HomomorphicCryptoFactory_internal::getCryptoMethod(std::string crypto_system_desc)
+{
+  std::vector<std::string> fields;
+  boost::algorithm::split(fields, crypto_system_desc, boost::algorithm::is_any_of(":"));
+  HomomorphicCrypto* h;
+
+  h = getCrypto(fields[0]);
+
+  h->setNewParameters(crypto_system_desc);
+  return h;
+}
+
+  
+// Returns a vector with all the cryptosystems THAT WE WANT TO BE USED
+void HomomorphicCryptoFactory_internal::getAllCryptoSystems(std::vector<HomomorphicCrypto*>& crypto_sys_vec)
+{
+  HomomorphicCrypto* crypto_ptr = new PaillierAdapter();
+  crypto_sys_vec.push_back(crypto_ptr);
+  crypto_ptr = new NFLLWE();
+  crypto_sys_vec.push_back(crypto_ptr);
+}
+
+void HomomorphicCryptoFactory_internal::getOneCryptoSystem(std::vector<HomomorphicCrypto*>& crypto_sys_vec, std::string crypto_system_desc)
+{
+  std::vector<std::string> fields;
+  boost::algorithm::split(fields, crypto_system_desc, boost::algorithm::is_any_of(":"));
+  
+  HomomorphicCrypto* h;
+  h = getCrypto(fields[0]);
+  crypto_sys_vec.push_back(h);
+}
+
+

+ 37 - 0
crypto/HomomorphicCryptoFactory_internal.hpp

@@ -0,0 +1,37 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_HOMOMORPHIC_FACTORY
+#define DEF_HOMOMORPHIC_FACTORY
+
+#include <string>
+#include "PaillierAdapter.hpp"
+#include "NFLLWE.hpp"
+#include "NoCryptography.hpp"
+
+class HomomorphicCryptoFactory_internal
+{
+public:
+  static HomomorphicCrypto* getCrypto(std::string cryptoType);
+  static HomomorphicCrypto* getCryptoMethod(std::string cryptoType);
+  static void getAllCryptoSystems(std::vector<HomomorphicCrypto*>& crypto_sys_vec);
+  static void getOneCryptoSystem(std::vector<HomomorphicCrypto*>& crypto_sys_vec, std::string crypto_system_desc);
+  static const unsigned int crypto_method_nbr;
+  static const std::vector<std::string> crypto_method_name_vec;
+};
+
+#endif

+ 32 - 0
crypto/LatticesBasedCryptosystem.cpp

@@ -0,0 +1,32 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "LatticesBasedCryptosystem.hpp"
+
+LatticesBasedCryptosystem::LatticesBasedCryptosystem(const std::string& crypto_name):
+  HomomorphicCrypto(crypto_name)
+{}
+
+NFLlib& LatticesBasedCryptosystem::getnflInstance() { return nflInstance; }
+
+uint64_t* LatticesBasedCryptosystem::getmoduli() { return moduli; }
+
+uint64_t LatticesBasedCryptosystem::getsecurityBits() { return securityBits; }
+
+unsigned short LatticesBasedCryptosystem::getnbModuli() { return nbModuli; }
+
+void LatticesBasedCryptosystem::setsecurityBits(uint64_t security_bits) { securityBits = security_bits;} 

+ 53 - 0
crypto/LatticesBasedCryptosystem.hpp

@@ -0,0 +1,53 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_LATTICESBASEDCRYPTOSYSTEM
+#define DEF_LATTICESBASEDCRYPTOSYSTEM
+#include "NFLlib.hpp"
+#include "NFLLWEDatatypes.hpp"
+#include "HomomorphicCrypto.hpp"
+
+class LatticesBasedCryptosystem : public HomomorphicCrypto {
+  public:
+    LatticesBasedCryptosystem(const std::string& crypto_name);
+
+    virtual unsigned int getpolyDegree()=0;
+    virtual void mulandadd(lwe_cipher rop, lwe_in_data op1, lwe_query op2, lwe_query op2prime, 
+        uint64_t current_poly, int rec_lvl)=0;
+    virtual void mul(lwe_cipher rop, lwe_in_data op1, lwe_query op2, lwe_query op2prime, 
+        uint64_t current_poly, int rec_lvl)=0;
+
+    virtual long setandgetAbsBitPerCiphertext(unsigned int elt_nbr)=0;
+
+    NFLlib& getnflInstance();
+    uint64_t* getmoduli();
+    uint64_t getsecurityBits();
+    unsigned short getnbModuli();
+    void setsecurityBits(uint64_t security_bits);
+//    virtual void mulandadd(lwe_cipher rop, lwe_in_data op1, lwe_query op2, uint64_t current_poly, 
+//        int rec_lvl)=0;
+    virtual poly64* deserializeDataNFL(unsigned char **inArrayOfBuffers, uint64_t nbrOfBuffers, 
+        uint64_t dataBitsizePerBuffer, uint64_t &polyNumber)=0;
+
+  protected:
+    NFLlib nflInstance;
+    uint64_t *moduli;
+    uint64_t securityBits;
+    unsigned short nbModuli;
+};
+
+#endif //DEF_LATICEBASEDCRYPTOSYSTEM

+ 850 - 0
crypto/NFLLWE.cpp

@@ -0,0 +1,850 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "NFLLWE.hpp"
+#include <fstream> 
+//#define bench
+//#define Repetition 10000
+
+void NFLLWE_DEBUG_MESSAGE(const char *s,poly64 p, unsigned int n){
+#ifdef CRYPTO_DEBUG
+	std::cout<<s;
+	NFLlib::print_poly64hex(p,n);
+#endif
+}
+
+// *********************************************************
+// Constructors and initialization
+// The constructors are not able to set all the parameters 
+// and setNewParameters has to be called afterward, 
+// the attribute alreadyInit reflects this uninitialized 
+// status
+// *********************************************************
+
+
+NFLLWE::NFLLWE():
+    LatticesBasedCryptosystem("LWE"),
+    oldNbModuli(0),
+    polyDegree(0)
+{
+  publicParams.setcrypto_container(this);
+}
+
+
+// Expected format of the parameters
+// k:polyDegree:modululusBitsize:AbsorptionBitsize
+void NFLLWE::setNewParameters(const std::string& crypto_param_descriptor)
+{
+  unsigned int polyDegree_, aggregatedModulusBitsize_;
+  int abspc_bitsize = -1; // We don't know the absorption bit size yet
+
+  std::vector<std::string> fields;
+  boost::algorithm::split(fields, crypto_param_descriptor, boost::algorithm::is_any_of(":"));
+
+  setsecurityBits(atoi(fields[1].c_str()));
+  polyDegree_ = atoi(fields[2].c_str());
+  aggregatedModulusBitsize_ = atoi(fields[3].c_str());
+  // Does the fourth parameter exist ? If so set it 
+  if (fields.size() >= 5) abspc_bitsize = atoi(fields[4].c_str()); 
+
+  setNewParameters(polyDegree_,aggregatedModulusBitsize_, abspc_bitsize);
+}
+
+
+// The setNewParameters method does the actual parameterization of the crypto object
+// it sets the alreadyInit attribute to reflects this
+void  NFLLWE::setNewParameters(unsigned int polyDegree_, unsigned int aggregatedModulusBitsize_, int absPCBitsize_)
+{
+	// Our public parameters need a pointer on us	
+  publicParams.setcrypto_container(this);
+
+	// We still need to transfer this two attributes to the crypto_object
+	// for the transition towards public parameter elimination
+	publicParams.setAbsPCBitsize(absPCBitsize_);
+
+	publicParams.setnoiseUB(5*getsecurityBits()/2);
+
+//#ifdef DEBUG
+//  std::cout << "Security bits " << getsecurityBits()<<std::endl;
+//  std::cout << "Noise UB " << publicParams.getnoiseUB()<<std::endl;
+//#endif
+
+  // We don't use here the polyDegree setter as we would call twice NFLlib init
+	polyDegree = polyDegree_;
+
+  nflInstance.setNewParameters(polyDegree_,aggregatedModulusBitsize_);
+  clearSecretKeys();
+  nbModuli = nflInstance.getnbModuli();
+  //used to free memory
+  oldNbModuli = nbModuli;
+  moduli= nflInstance.getmoduli();
+
+
+	secretKey = new poly64[nbModuli];
+	secretKeyShoup = new poly64[nbModuli];
+	Abit_mod = new uint64_t[nbModuli];
+	Abit_mod_shoup = new uint64_t[nbModuli];
+
+
+	// initialize the secret key 
+  secretKey[0] = nflInstance.allocBoundedRandomPoly(0,true);
+	for (unsigned short currentModulus = 0; currentModulus < nbModuli; currentModulus++) {
+	  secretKey[currentModulus] = secretKey[0] + polyDegree*currentModulus;
+    secretKeyShoup[currentModulus] = (uint64_t*) calloc(polyDegree,sizeof(uint64_t));
+		// compute the Shoup representation of the secret key
+		for (unsigned int i=0; i < polyDegree; i++) {
+			secretKeyShoup[currentModulus][i]=((uint128_t) secretKey[currentModulus][i] << 64) / moduli[currentModulus];
+    }
+  }
+ recomputeNoiseAmplifiers();
+  
+}
+
+// *********************************************************
+// Getters
+// *********************************************************
+poly64* NFLLWE::getsecretKey() { return secretKey; }
+unsigned int NFLLWE::getpolyDegree() { return polyDegree; }
+
+// *********************************************************
+// Setters
+// *********************************************************
+void NFLLWE::setmodulus(uint64_t modulus_)
+{
+	// The modulus cannot be set from outside
+	std::cout << "Warning(NFLLWE.c): Modulus cannot be set externally." << std::endl;
+}
+void NFLLWE::setpolyDegree(unsigned int polyDegree_)
+{
+  polyDegree = polyDegree_;
+  nflInstance.setpolyDegree(polyDegree_);
+}
+
+// *********************************************************
+//         Serialize/Deserialize
+// *********************************************************
+
+poly64 *NFLLWE::deserializeDataNFL(unsigned char **inArrayOfBuffers, uint64_t nbrOfBuffers, uint64_t dataBitsizePerBuffer, uint64_t &polyNumber) {
+  return nflInstance.deserializeDataNFL(inArrayOfBuffers, nbrOfBuffers, dataBitsizePerBuffer, publicParams.getAbsorptionBitsize()/polyDegree, polyNumber);
+}
+
+
+
+// *********************************************************
+//         Additions and Multiplications of ciphertexts
+// *********************************************************
+
+
+void NFLLWE::add(lwe_cipher rop, lwe_cipher op1, lwe_cipher op2, int d)
+{
+  nflInstance.addmodPoly(rop.a, op1.a, op2.a);
+  nflInstance.addmodPoly(rop.b, op1.b, op2.b);
+}
+
+void NFLLWE::mulandadd(lwe_cipher rop, lwe_in_data op1, lwe_query op2, uint64_t current_poly, int rec_lvl)
+{
+	NFLLWE_DEBUG_MESSAGE("in_data[0].p : ",op1.p[0],4);
+  	NFLLWE_DEBUG_MESSAGE("in_data[0].a : ",op2.a,4);
+  	NFLLWE_DEBUG_MESSAGE("in_data[0].b : ",op2.b,4);
+	
+	mulandaddCiphertextNTT(rop, op1, op2, current_poly);
+	
+	NFLLWE_DEBUG_MESSAGE("out_data[0].a : ",rop.a,4);
+  	NFLLWE_DEBUG_MESSAGE("out_data[0].b : ",rop.b,4);
+}
+
+// Shoup version
+void NFLLWE::mulandadd(lwe_cipher rop, const lwe_in_data op1, const lwe_query op2, const lwe_query op2prime, const uint64_t current_poly, int rec_lvl)
+{
+  // Don't modify the pointers inside the data or it will be permanent
+  poly64 ropa = rop.a, ropb = rop.b, op2a = op2.a, op2b = op2.b, op2primea = op2prime.a, 
+         op2primeb = op2prime.b, op1pcurrent = op1.p[current_poly];
+
+	
+	 	const unsigned int K = polyDegree;
+		const unsigned int md = nbModuli;
+	for(unsigned short currentModulus=0;currentModulus<md;currentModulus++) 
+  {
+	  
+ 		for (unsigned i = 0; i < K; i++)
+		{
+			nflInstance.mulandaddShoup(ropa[i],op1pcurrent[i],op2a[i],op2primea[i],moduli[currentModulus]);
+		}
+ 		for (unsigned i = 0; i < K; i++)
+		{
+			nflInstance.mulandaddShoup(ropb[i],op1pcurrent[i],op2b[i],op2primeb[i],moduli[currentModulus]);
+		}
+		ropa+=K;
+		ropb+=K;
+		op1pcurrent+=K;
+		op2a+=K;
+		op2b+=K;
+		op2primea+=K;
+		op2primeb+=K;
+	}
+
+}
+
+void NFLLWE::mul(lwe_cipher rop, const lwe_in_data op1, const lwe_query op2, const lwe_query op2prime, const uint64_t current_poly, int rec_lvl)
+{
+  // Don't modify the pointers inside the data or it will be permanent
+  poly64 ropa = rop.a, ropb = rop.b, op2a = op2.a, op2b = op2.b, op2primea = op2prime.a, 
+         op2primeb = op2prime.b, op1pcurrent = op1.p[current_poly];
+
+	NFLLWE_DEBUG_MESSAGE("in_data[0].p : ",op1.p[current_poly],4);
+	NFLLWE_DEBUG_MESSAGE("in_data[0].a : ",op2.a,4);
+	NFLLWE_DEBUG_MESSAGE("in_data[0].b : ",op2.b,4);
+	NFLLWE_DEBUG_MESSAGE("in_data[0].a' : ",op2prime.a,4);
+	NFLLWE_DEBUG_MESSAGE("in_data[0].b' : ",op2.b,4);
+	
+	for(unsigned short currentModulus=0;currentModulus<nbModuli;currentModulus++) 
+  {
+		for (unsigned i = 0; i < polyDegree; i++)
+		{
+			ropa[i] = nflInstance.mulmodShoup(op1pcurrent[i],op2a[i],op2primea[i],moduli[currentModulus]);
+			ropb[i] = nflInstance.mulmodShoup(op1pcurrent[i],op2b[i],op2primeb[i],moduli[currentModulus]);
+		}
+		ropa+=polyDegree;
+		ropb+=polyDegree;
+		op1pcurrent+=polyDegree;
+		op2a+=polyDegree;
+		op2b+=polyDegree;
+		op2primea+=polyDegree;
+		op2primeb+=polyDegree;
+	}
+	NFLLWE_DEBUG_MESSAGE("out_data[0].a : ",rop.a,4);
+	NFLLWE_DEBUG_MESSAGE("out_data[0].b : ",rop.b,4);
+}
+
+// Same comment as for musAndAddCiphertextNTT we do a simpler version above
+void NFLLWE::mulandadd(lwe_cipher rop, lwe_in_data op1, lwe_query op2, int rec_lvl)
+{
+	NFLLWE_DEBUG_MESSAGE("in_data p: ",op1.p[0],4);
+	NFLLWE_DEBUG_MESSAGE("in_data a: ",op2.a,4);
+	NFLLWE_DEBUG_MESSAGE("in_data b: ",op2.b,4);
+	
+  	mulandaddCiphertextNTT(rop, op1, op2);
+	
+	NFLLWE_DEBUG_MESSAGE("out_data.a : ",rop.a,4);
+	NFLLWE_DEBUG_MESSAGE("out_data.b : ",rop.b,4);
+}
+
+// Deal just with one polynomial
+inline void NFLLWE::mulandaddCiphertextNTT(lwe_cipher rop, lwe_in_data op1, lwe_query op2, uint64_t current_poly)
+{
+    nflInstance.mulandaddPolyNTT(rop.a, op1.p[current_poly], op2.a);
+    nflInstance.mulandaddPolyNTT(rop.b, op1.p[current_poly], op2.b);
+}
+
+// Good method but too greedy in memory we start with a simpler one (below)
+// Needs to change as we always write in the same rop
+void NFLLWE::mulandaddCiphertextNTT(lwe_cipher rop, lwe_in_data op1, lwe_query op2)
+{
+  for(uint64_t i=0;i<op1.nbPolys;i++)
+  {
+    nflInstance.mulandaddPolyNTT(rop.a, op1.p[i], op2.a);
+    nflInstance.mulandaddPolyNTT(rop.b, op1.p[i], op2.b);
+  }
+}
+
+
+
+//*********************************
+// Encryption and decryption 
+//********************************* 
+
+// The internal encrypt method
+void  NFLLWE::enc(lwe_cipher *c, poly64 m)
+{
+	bool uniform = true;
+
+	NFLLWE_DEBUG_MESSAGE("Encrypting m: ",m, 4);
+
+	c->a = (poly64) calloc(polyDegree * 2 * nbModuli,  sizeof(uint64_t));
+	c->b = c->a + polyDegree * nbModuli;
+
+	// tmpa and tmpb are used to access the nbModuli polynoms of the CRT
+	poly64 tmpa = c->a;
+	poly64 tmpb = c->b;
+	poly64 tmpm = m;
+
+	//   b = (a*s) % f + e * A + m;
+    
+	// Noise creation
+	uint64_t Berr=publicParams.getnoiseUB();
+	uint64_t A_bits= publicParams.getAbsorptionBitsize() / publicParams.getpolyDegree();	
+	
+	// We deal with the nbModuli polynoms at once because the noise is the same size for all of them
+	nflInstance.setBoundedRandomPoly(c->b, 2*Berr-1, !uniform);
+
+	NFLLWE_DEBUG_MESSAGE("Noise used: ",c->b, 4);
+#ifdef CRYPTO_DEBUG
+	std::cout << "NFLLWE: Noise amplifier: " << A_bits << std::endl;
+#endif 
+		
+	// Adjustments and addition to plaintext
+	for(unsigned short currentModulus=0;currentModulus<nbModuli;currentModulus++) {
+		for(unsigned int i=0;i<polyDegree;i++) {
+			// e is multiplied by the amplifier A for which we know the size A_bits
+			// tmpb[i] = tmpb[i] << (unsigned) A_bits;
+			//  std::cout << "noise: " << tmpb[i] << std::endl;
+			//std::cout << std::hex << tmpb[i] << " " << std::dec;			
+				
+			tmpb[i] = nflInstance.mulmodShoup(tmpb[i], Abit_mod[currentModulus],Abit_mod_shoup[currentModulus], moduli[currentModulus]);
+      
+			// and shifted to be in [-(Berr-1) .. (Berr-1)]
+			//tmpb[i] += moduli[currentModulus]-((Berr-1)<<A_bits);   
+
+			// We add the shifted noise to the plaintext
+			tmpb[i] = nflInstance.addmod(tmpb[i], tmpm[i], moduli[currentModulus]);
+      
+			// And reduce the whole if needed 
+			if(tmpb[i]>moduli[currentModulus]) tmpb[i]-=moduli[currentModulus];
+			
+		}
+		tmpb+=polyDegree;
+		tmpm+=polyDegree;
+	}
+	tmpb=c->b;
+
+	NFLLWE_DEBUG_MESSAGE("Amplified noise and message: ",c->b, 4);
+
+	// Noise and plaintext are the only things that are not yet in the NTT space
+	nflInstance.nttAndPowPhi(c->b);
+
+	// We still have to get a. No NTT needed because uniformly taken
+	nflInstance.setBoundedRandomPoly(tmpa, 0, uniform);
+
+#ifdef DEBUG
+	poly64 tmp = (poly64) calloc(polyDegree*nbModuli, sizeof(uint64_t));
+#endif
+
+	for(unsigned short currentModulus=0;currentModulus<nbModuli;currentModulus++) 
+	{
+    
+		// We multiply it by s and add to the previous message and noise
+		for (unsigned int i = 0 ; i < polyDegree ; i++)
+		{
+			nflInstance.mulandaddShoup(tmpb[i],tmpa[i], secretKey[currentModulus][i],
+			secretKeyShoup[currentModulus][i], moduli[currentModulus]);
+
+#ifdef DEBUG
+			nflInstance.mulandaddShoup(tmp[i+currentModulus*polyDegree], tmpa[i],secretKey[currentModulus][i],secretKeyShoup[currentModulus][i], moduli[currentModulus]);
+#endif
+
+#ifdef SHOUP
+			tmpa[i]=tmpa[i]%moduli[currentModulus];
+			tmpb[i]=tmpb[i]%moduli[currentModulus];
+#endif
+		}
+		tmpa+=polyDegree;
+		tmpb+=polyDegree;
+	}
+
+	// There is already a ifdef debug inside this function but 
+	// tmp is not defined if we are not in debug mode
+#ifdef DEBUG 
+	NFLLWE_DEBUG_MESSAGE("a*s: ",tmp, 4);
+  free(tmp);
+#endif
+
+	NFLLWE_DEBUG_MESSAGE("Ciphertext a: ",c->a, 4);
+	NFLLWE_DEBUG_MESSAGE("Ciphertext b: ",c->b, 4);
+}
+
+
+void NFLLWE::dec(poly64 m, lwe_cipher *c)
+{
+	uint64_t A_bits = publicParams.getAbsorptionBitsize() / publicParams.getpolyDegree();
+  const uint64_t bitmask = (1ULL<<A_bits) -1; 	
+  mpz_t moduliProduct; 
+	
+  // Get the product of all moduli from the nflInstance object;
+  nflInstance.copymoduliProduct(moduliProduct);
+
+	// tmpa and tmpb are used to access the nbModuli polynoms of the CRT
+	poly64 tmpa=c->a;
+	poly64 tmpb=c->b;
+	poly64 tmpm=m;
+
+	for(unsigned short currentModulus=0;currentModulus<nbModuli;currentModulus++) {
+
+		// We firs% moduli[cm] t get the amplified noise plus message (e*A+m =b-a*S)
+		for (unsigned int i=0 ; i < polyDegree; i++) 
+    {
+			uint64_t temp=0;
+			nflInstance.mulandaddShoup(temp, tmpa[i], secretKey[currentModulus][i],
+      secretKeyShoup[currentModulus][i], moduli[currentModulus]);
+			tmpm[i] = nflInstance.submod(tmpb[i], temp, moduli[currentModulus]);
+		}
+		tmpa+=polyDegree;
+		tmpb+=polyDegree;
+    tmpm+=polyDegree;
+	}
+  tmpm=m;
+
+	// In order to mask the noise bits we need to get out of NTT space through an inverse NTT
+  nflInstance.invnttAndPowInvPhi(tmpm);
+
+  NFLLWE_DEBUG_MESSAGE("Amplified noise and message (dec): ",tmpm, 4);
+  NFLLWE_DEBUG_MESSAGE("Amplified noise and message (dec): ",tmpm+polyDegree, 4);
+
+
+  if(nbModuli>1) {
+	   	  
+	  mpz_t *tmprez=nflInstance.poly2mpz(tmpm);
+	  
+	  
+
+  	// If e*A+m < p/2 we mask the message bits: bitmask = (1ULL<<A_bits) -1
+	  // If e *A+m > p/2 we do a little trick to avoid signed integers and modulus reduction
+	  // e[i]= e[i] + 2**61 - p (we replace p by 2**61) and then bitmask the message.
+    mpz_t magicConstz;
+    mpz_init(magicConstz);
+    mpz_ui_pow_ui(magicConstz, 2, (kModulusBitsize + 1) * nbModuli);
+    mpz_sub(magicConstz,magicConstz, moduliProduct);
+    mpz_t bitmaskz;
+    mpz_init(bitmaskz);
+    mpz_ui_pow_ui(bitmaskz, 2, A_bits);
+    mpz_sub_ui(bitmaskz, bitmaskz, 1);
+#ifdef CRYPTO_DEBUG
+    gmp_printf("Mask used: %Zx\n",bitmaskz);
+#endif	
+	  // Shall we prefetch here ?
+    mpz_t tmpz;
+    mpz_init(tmpz);
+    // We need to zero tmpm as export writes nothing on the output for null values
+    bzero(tmpm,polyDegree*nbModuli*sizeof(uint64_t));
+    for (unsigned int i = 0 ; i < polyDegree ; i++)
+	  {
+		  //For testing we may do a hardcoded modulus but not always. m[i] = m[i] % modulus;
+      mpz_mul_ui(tmpz, tmprez[i], 2UL);
+      if (mpz_cmp(tmpz, moduliProduct)==1)// tmprez[i] > moduliProduct / 2
+      {
+        mpz_add(tmpz, tmprez[i], magicConstz);
+        mpz_and(tmprez[i], tmpz, bitmaskz);
+      }
+      else
+      {
+        mpz_and(tmprez[i], tmprez[i], bitmaskz);
+      }
+	
+    	// Combien d'uint32 ?
+	    int combien = ceil((double)A_bits/32);
+	    mpz_export(((uint32_t*)tmpm)+i*combien, NULL, -1, sizeof(uint32_t), 0, 0, tmprez[i]);
+	    mpz_clear(tmprez[i]);
+	  }
+    
+    free(tmprez);
+  } else { // nbModuli=1
+	
+	
+		// If e*A+m < p/2 we mask the message bits: bitmask = (1ULL<<A_bits) -1
+		// If e*A+m > p/2 we do a little trick to avoid signed integers and modulus reduction
+		// e[i]= e[i] + 2**61 - p (we replace p by 2**61) and then bitmask the message.
+		const uint64_t magicConst = (1ULL<<61)-moduli[0];// 2**61 - p
+		
+		// Shall we prefetch here ?
+		for (unsigned int i = 0 ; i < polyDegree ; i++)
+		{
+			//For testing we may do a hardcoded modulus but not always. m[i] = m[i] % modulus;
+			tmpm[i] = (tmpm[i] > moduli[0]/2) ? (tmpm[i] + magicConst)& bitmask : tmpm[i] & bitmask;
+		}	
+	}
+}
+
+// MOK is here for the CRT modification
+
+// encrypts a uint (e.g. for producing a equest element with a 0 or a 1)
+// does not return a lwe_cipher but the (char*)pointer on two consecutively allocated poly64 (a and b)
+char* NFLLWE::encrypt(unsigned int ui, unsigned int d)
+{
+	if ( ceil(log2(static_cast<double>(ui))) >= publicParams.getAbsorptionBitsize())
+	{
+		std::cerr << "NFFLWE: The given unsigned int does not fit in " << publicParams.getAbsorptionBitsize() << " bits"<< std::endl;
+		ui %= 1<<publicParams.getAbsorptionBitsize();
+	}
+
+	lwe_cipher c; 
+	poly64 m = (poly64)calloc(nbModuli*polyDegree,sizeof(uint64_t));
+	for (unsigned int cm = 0 ; cm < nbModuli ; cm++)
+  {
+    m[cm*polyDegree]=(uint64_t)ui;
+  }
+	enc(&c,m);
+	free(m);
+	return (char*) c.a;
+}
+
+char* NFLLWE::encrypt(char* data, size_t s, unsigned int exponent ){
+    std::cerr << "char* NFLLWE::encrypt(char* data, size_t, unsigned int exponent) is not implemented"<< std::endl;
+    return nullptr;
+}
+
+// Do a ciphertext for a plaintext with alternating bits (for performance tests) 
+char* NFLLWE::encrypt_perftest()
+{
+	lwe_cipher c; 
+  poly64 m = nflInstance.allocBoundedRandomPoly(0, true);
+	enc(&c,m);
+	free(m);
+	return (char*) c.a;
+}
+
+char* NFLLWE::decrypt(char* cipheredData, unsigned int rec_lvl, size_t, size_t)
+{
+  lwe_cipher ciphertext;
+  ciphertext.a = (poly64)cipheredData;
+  ciphertext.b = ciphertext.a + nbModuli * polyDegree;
+  poly64 clear_data = (poly64) calloc(nbModuli * polyDegree, sizeof(uint64_t));
+  unsigned int bits_per_coordinate = publicParams.getAbsorptionBitsize()/polyDegree;
+  
+#ifdef DEBUG
+  std::cout<<"Allocated (bytes): "<<nbModuli * polyDegree * sizeof(uint64_t)<<std::endl;
+  std::cout<<"Bits per coordinate: "<<bits_per_coordinate<<std::endl;
+#endif
+
+  dec(clear_data, &ciphertext);
+
+  NFLLWE_DEBUG_MESSAGE("Decrypting ciphertext a: ",ciphertext.a, 4);
+  NFLLWE_DEBUG_MESSAGE("Decrypting ciphertext b: ",ciphertext.b, 4);
+  NFLLWE_DEBUG_MESSAGE("Result: ",clear_data, 4);
+
+  // unsigned char* out_data = (unsigned char*) calloc(nbModuli * polyDegree+1, sizeof(uint64_t));
+  // nflInstance.serializeData64 (clear_data, out_data, bits_per_coordinate, polyDegree);
+
+  unsigned char* out_data = (unsigned char*) calloc(bits_per_coordinate*polyDegree/64 + 1, sizeof(uint64_t));
+  if (nbModuli == 1)
+  {
+    nflInstance.serializeData64(clear_data, out_data, bits_per_coordinate, ceil((double)bits_per_coordinate/64)* polyDegree);
+  }
+  else // nbModuli > 1
+  {
+    nflInstance.serializeData32 ((uint32_t*)clear_data, out_data, bits_per_coordinate, ceil((double)bits_per_coordinate/32)* polyDegree);
+  }
+#ifdef DEBUG
+  //std::cout<<"Bitgrouped into: "<<out_data<<std::endl;
+#endif
+  free(clear_data);
+  return (char*) out_data;
+}
+
+
+unsigned int NFLLWE::getAllCryptoParams(std::set<std::string>& crypto_params)
+{
+  unsigned int params_nbr  = 0;
+  unsigned int k_array_size = 5;
+  unsigned int k[5] = {80, 100, 128, 192, 256};
+
+  for (unsigned int i = 0 ; i < k_array_size ; i++)
+  {
+    params_nbr += getCryptoParams(k[i], crypto_params);
+  }
+
+  return params_nbr;
+}
+
+
+unsigned int NFLLWE::getCryptoParams(unsigned int k, std::set<std::string>& crypto_params)
+{
+  using namespace std;
+  unsigned int p_size, params_nbr = 0;
+  string k_str  = to_string(k);
+
+  for (unsigned int degree = kMinPolyDegree ; degree <= kMaxPolyDegree; degree <<= 1)
+  {
+    string param;
+    p_size = findMaxModulusBitsize(k, degree);
+    
+    // We give a very small margin 59 instead of 60 so that 100:1024:60 passes the test
+    //for (unsigned int i = 1; i * 59 <= p_size ; i++)//(p_size > 64) && ((p_size % 64) != 0))
+    for (unsigned int i = 1; i * 59 <= p_size && i * 60 <= 240; i++)
+    {
+      param =  cryptoName + ":" + to_string(estimateSecurity(degree,i*kModulusBitsize)) + ":" + to_string(degree) + ":" + to_string(i*kModulusBitsize) ;
+      if (crypto_params.insert(param).second) params_nbr++;
+      param = "";
+    }
+  }
+
+  return params_nbr;
+}
+
+void NFLLWE::recomputeNoiseAmplifiers() {
+	uint64_t A_bits= publicParams.getAbsorptionBitsize() / publicParams.getpolyDegree();	
+	mpz_t tmpz1,tmpz2; 
+	mpz_init(tmpz1);
+	mpz_init(tmpz2);
+	for(unsigned short currentModulus=0;currentModulus<nbModuli;currentModulus++) {
+		mpz_ui_pow_ui(tmpz2, 2, A_bits);
+		mpz_import(tmpz2, 1, 1, sizeof(uint64_t), 0, 0, moduli+currentModulus);
+		mpz_mod(tmpz1, tmpz1, tmpz2);
+		Abit_mod[currentModulus]=0;
+		mpz_export(&Abit_mod[currentModulus], NULL, 1, sizeof(uint64_t), 0, 0, tmpz1);
+		Abit_mod_shoup[currentModulus]=((uint128_t) Abit_mod[currentModulus] << 64) / moduli[currentModulus];
+	}
+  mpz_clears(tmpz1, tmpz2, NULL);
+}
+
+unsigned int NFLLWE::estimateSecurity(unsigned int n, unsigned int p_size)
+{
+  unsigned int estimated_k = 5;//Estimate K can not be too low
+
+  while(!checkParamsSecure(estimated_k,n,p_size)) estimated_k++; 
+
+  return --estimated_k;
+}
+
+
+long NFLLWE::setandgetAbsBitPerCiphertext(unsigned int elt_nbr)
+{
+    double Berr = static_cast<double>(publicParams.getnoiseUB());
+    double nb_sum = elt_nbr;
+    double p_size = getmodulusBitsize();
+    double nbr_bit = floor(( (p_size - 1) - log2(nb_sum) - log2(Berr) -log2(static_cast<double>(polyDegree))) / 2.0);
+
+    publicParams.setAbsPCBitsize(nbr_bit);
+	
+	recomputeNoiseAmplifiers();
+	
+    return long(nbr_bit);
+}
+
+
+unsigned int NFLLWE::findMaxModulusBitsize(unsigned int k, unsigned int n)
+{
+  unsigned int p_size;
+  //p_size can not be too low
+  p_size = 10;
+  while (!checkParamsSecure(k,n,p_size)) p_size++;
+
+  return --p_size;
+}
+
+
+bool NFLLWE::checkParamsSecure(unsigned int k, unsigned int n, unsigned int p_size)
+{
+  double p, beta, logBerr = 8, epsi, lll;
+
+  //We take an advantage of 2**(-k/2) and an attack time of 2**(k/2)
+  epsi = pow(2, -static_cast<double>(k/2));
+  //log(time) = 1.8/ log(delta) − 110 and -80 to compute processor cycles so we take pow(2, k/2) = 1.8/log(delta) - 80
+  double delta = pow(2,1.8/(k/2 + 80));
+
+  p    = pow(2, p_size) -  1;
+  beta = (p / logBerr) * sqrt(log1p( 1 / epsi) / M_PI);
+  lll  = lllOutput(n, p, delta);
+
+  // We love ugly tricks !
+  return (lll < beta);// && cout << "beta : " << beta << " p_size : " << p_size << " n :"<< n << " k : "<< k << endl;
+}
+
+
+double NFLLWE::lllOutput(unsigned int n, double& p, double delta)
+{
+  double m = 2*n + 128;
+
+  //execution log(time) = 1.8/ log(delta) − 110 and -80 to compute processor cycles. We add a margin of 20 so we take k/2 = 1.8/log(delta) - 100
+  double lll1 = pow(delta, m) * pow(p, n/m);
+
+  double lll2 = 2 * sqrt(n * log2(p) * log2(delta));
+  lll2 = pow(2, lll2);
+
+  return std::min(lll1, lll2);
+}
+
+double NFLLWE::estimateAbsTime(std::string crypto_param)
+{
+  using namespace std;
+  vector<string> fields;
+  boost::algorithm::split(fields, crypto_param, boost::algorithm::is_any_of(":"));
+  unsigned int p_size = (unsigned) atoi(fields[3].c_str());
+  double a = (p_size < 64) ? 1 : ceil(static_cast<double>(p_size)/64.0);
+  unsigned int degree = (unsigned) atoi(fields[2].c_str());
+  double b = degree/1024;
+
+  return 1/(1.75 * pow(10, 5)/(a*b));
+}
+
+double NFLLWE::estimatePrecomputeTime(std::string crypto_param)
+{
+  using namespace std;
+  vector<string> fields;
+  boost::algorithm::split(fields, crypto_param, boost::algorithm::is_any_of(":"));
+  unsigned int p_size = (unsigned) atoi(fields[3].c_str());
+  double a = (p_size < 64) ? 1 : ceil(static_cast<double>(p_size)/64.0);
+  unsigned int degree = (unsigned) atoi(fields[2].c_str());
+  double b = degree/1024;
+
+  return 1/(0.75*pow(10, 5)/(a*b));
+}
+
+unsigned int NFLLWE::getmodulusBitsize() {
+	return nbModuli*kModulusBitsize;
+}
+
+// *********************************************************
+// AbstractPublicParameters stuff
+// *********************************************************
+AbstractPublicParameters& NFLLWE::getPublicParameters()
+{
+	//This was bug chasing but should not be necessary!
+	publicParams.setcrypto_container(this);
+  	return publicParams;
+}
+
+std::string NFLLWE::getSerializedCryptoParams(bool shortversion)
+{
+  return publicParams.getSerializedParams(shortversion);
+}
+
+
+NFLLWE::~NFLLWE()
+{
+  clearSecretKeys();
+}
+
+
+std::string& NFLLWE::toString()
+{
+  return cryptoName;
+}
+
+void NFLLWE::clearSecretKeys()
+{
+  if(oldNbModuli)
+  {
+    // secreKey was allocated with a single allocation
+    delete[] Abit_mod;
+    delete[] Abit_mod_shoup;
+    free(secretKey[0]);
+    delete[] secretKey;
+  }
+
+  if(oldNbModuli)
+  {
+    for (unsigned int i = 0; i < oldNbModuli; i++) {
+      free(secretKeyShoup[i]);
+    }
+    delete[] secretKeyShoup;
+  }
+
+  oldNbModuli = 0;
+}
+
+
+//This main is for benchmarking and tests
+// 
+// int main(int c,char **v) {
+// 	
+// // Benchs et correctness enc/dec
+// 	 	NFLLWE n;	
+// 		n.setNewParameters(1024,64,22);
+//  		n.setmodulus(P64);
+//  		n.getPublicParameters().computeNewParameters("lwe:80:1024:64:22");
+//  	
+//  		poly64 p=n.boundedRandomPoly(1024, 1023);
+//  		poly64 result=(poly64)calloc(1024,sizeof(uint64_t));
+//  		
+//  	 	std::cout<<"0-RND polynom: ";n.print_poly64(p,4);std::cout<<std::endl;
+//  		
+//  		
+//  		lwe_cipher cyph;  
+//  #ifdef bench
+//  		double start     = omp_get_wtime();
+//  		for(int i        = 0;i<Repetition;i++) {
+//  #endif 
+//  			n.enc(&cyph,p);
+//  #ifdef bench
+//  		
+//  			}
+//  		double end        = omp_get_wtime();
+//  		std::cout<<Repetition/(end-start)<<" chiffre/s"<<std::endl;
+//  		
+//  		
+//  		 start     = omp_get_wtime();
+//  		for(int i        = 0;i<Repetition;i++) {
+//  #endif 
+//  			
+//  			n.dec(result,&cyph);
+//  #ifdef bench
+//  		}
+//  		 end        = omp_get_wtime();
+//  		std::cout<<Repetition/(end-start)<<" dechiffre/s"<<std::endl;
+//  #endif 
+// 		NFLLWE_DEBUG_MESSAGE("Encrypted into a",cyph.a,4);
+// 		NFLLWE_DEBUG_MESSAGE("Encrypted into b",cyph.b,4);
+//  	 	NFLLWE_DEBUG_MESSAGE("1-Encoded-Decoded (but not unshoupified): ",result,4);
+//  		
+// 	
+//  		for(int i = 0;i<1024;i++) {
+//  		  if((result[i]%P64)!=(result[i]%P64)) {
+//  			std::cout<<"err "<<(p[i])<<" != "<<(result[i]%P64)<<std::endl;
+//       	  	exit(1);
+//  			break;
+//  		  }
+//  		}
+//  	
+// 	std::cout<< "enc/dec test passed"<<std::endl;
+// 	
+// 	
+// 	
+// 	// int bytesize=1024*22/8+1;
+// 	//  	char* mydata=(char*)calloc(bytesize,1);
+// 	//  	for(int i=0;i<bytesize;i++) {
+// 	//  		mydata[i]='A'+(i%('Z'-'A'));
+// 	//  	}
+// 	//  	std::cout<<"Initial data : "<<mydata<<std::endl;
+// 	// 
+// 	//  	uint64_t bitsize=bytesize*8;
+// 	//  	uint64_t nbOfPolys;
+// 	//  	Warning, need to tranform this line with the new version of deserializeDataNTT which takes 4 parameters instead of 3 poly64 *mydata_poly=n.deserializeDataNTT((unsigned char*)mydata,bitsize,nbOfPolys);
+// 	//  	
+// 	//  	std::cout<<"The string has been encoded into ";n.print_poly64hex(*mydata_poly,1024*nbOfPolys);
+// 	//   	std::cout<<std::endl<<"nbOfPolys = "<<nbOfPolys<<std::endl;
+// 	//  	
+// 	//  	// encrypt of poly64 simulation
+// 	//  	lwe_cipher *cyphertext=new lwe_cipher[nbOfPolys];
+// 	// for(int i=0;i<nbOfPolys;i++) { 
+// 	//  		n.enc(&(cyphertext[i]),*(mydata_poly + i*1024));
+// 	//  	//std::cout<<"The string has been cyphered into a["<<i<<"]";n.print_poly64(cyphertext[i].a,1024);
+// 	//  	//std::cout<<"The string has been cyphered into b["<<i<<"]";n.print_poly64(cyphertext[i].a,1024);
+// 	// }
+// 	//  
+// 	//  	poly64 unciphereddata_poly[nbOfPolys];// = (poly64*)calloc(1024*nbOfPolys,sizeof(uint64_t));
+// 	// for(int i=0;i<nbOfPolys;i++) { 	
+// 	// 	unciphereddata_poly[i]=(poly64)n.decrypt((char*)(cyphertext[i].a), (unsigned int)0,(size_t) 0,(size_t) 0);
+// 	//  	std::cout<<"Decoded into polynom: ";n.print_poly64hex((poly64)unciphereddata_poly[i],128);std::cout<<std::endl;
+// 	// }
+// 	//  	
+// 	//  	
+// 	//  	unsigned char* unciphereddata=n.serializeData(unciphereddata_poly[0], nbOfPolys,bitsize, true);
+// 	// 
+// 	//  	std::cout<<"Decoded into "<<std::hex<<unciphereddata<<std::endl;
+// 	//  	std::cout<<"A= "<<std::dec<<(short)'A'<<std::endl<<std::endl;
+// 	//  	std::cout<<"G= "<<std::dec<<(short)'G'<<std::endl<<std::endl;
+// 	//  
+// 	//  
+//  	//  
+//  	// //lwe_cipher *cypherui;
+//  	// //cypherui=(lwe_cipher *)n.encrypt(1,0);
+//  	// //unciphereddata_poly = (poly64)n.decrypt((char*)(cypherui->a), (unsigned int)0,(size_t) 0,(size_t) 0);
+//  	// char *charptr;
+//  	// charptr=n.encrypt(1,0);
+//  	// unciphereddata_poly = (poly64)n.decrypt(charptr, (unsigned int)0,(size_t) 0,(size_t) 0);
+//  	// std::cout<<"1-Decoded into polynom: ";n.print_poly64(unciphereddata_poly,1024);std::cout<<std::endl;
+//  	// 	std::cout<<"Decoded into "<<std::hex<<unciphereddata_poly<<std::endl;
+//  }

+ 118 - 0
crypto/NFLLWE.hpp

@@ -0,0 +1,118 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_NFLLWE
+#define DEF_NFLLWE
+
+#define SHOUP
+//#define TESTSHOUP
+
+#include <omp.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <math.h>
+#include <iostream>
+#include "NFLParams.hpp"
+#include "NFLlib.hpp"
+#include "NFLLWEDatatypes.hpp"
+#include "LatticesBasedCryptosystem.hpp"
+#include "crypto/HomomorphicCrypto.hpp"
+#include "CryptographicSystem.hpp"
+#include "NFLLWEPublicParameters.hpp"
+#include <string>
+#include <cstddef>
+#include <gmp.h>
+
+class NFLLWE : public LatticesBasedCryptosystem
+{
+
+  public:
+    NFLLWEPublicParameters publicParams;
+    NFLLWE();
+    ~NFLLWE();
+
+    std::string& toString();
+    
+    unsigned int getpolyDegree();
+    poly64* getsecretKey();
+  	void recomputeNoiseAmplifiers();
+    
+    // Setters
+    void setmodulus(uint64_t modulus);
+    void setpolyDegree(unsigned int polyDegree);
+    void setNewParameters(const std::string& crypto_param_descriptor);
+    void setNewParameters(unsigned int polyDegree, unsigned int modulusBitsize, int absPCBitsize_);
+   
+    // Crypto related functions
+    long setandgetAbsBitPerCiphertext(unsigned int elt_nbr);
+    void enc(lwe_cipher *c, poly64 m);
+	  void dec(poly64 m, lwe_cipher *c);	
+    char* encrypt(unsigned int ui, unsigned int );
+    char* encrypt(char* data, size_t, unsigned int exponent );
+    char* encrypt_perftest();
+    char* decrypt(char* cipheredData, unsigned int, size_t, size_t);
+
+    // Data importation and exportation
+    poly64* deserializeDataNFL(unsigned char **inArrayOfBuffers, uint64_t nbrOfBuffers, 
+        uint64_t dataBitsizePerBuffer, uint64_t &polyNumber);
+    
+    // Functions for PIROptimizer and PIRClient
+    std::string getSerializedCryptoParams(bool shortversion);
+    unsigned int getCryptoParams(unsigned int k, std::set<std::string>& crypto_params);
+    unsigned int getAllCryptoParams(std::set<std::string>& crypto_params);
+    AbstractPublicParameters&  getPublicParameters();
+    unsigned int findMaxModulusBitsize(unsigned int security_bits, unsigned int poly_degree);
+    bool checkParamsSecure(unsigned int security_bits, unsigned int poly_degree, unsigned int p_size);
+    double lllOutput(unsigned int n, double& p, double delta);
+    double estimateAbsTime(std::string crypto_param);
+    double estimatePrecomputeTime(std::string crypto_param);
+    unsigned int estimateSecurity(unsigned int n, unsigned int p_size);
+	unsigned int getmodulusBitsize();
+    
+    // **********************************
+    // Modular ciphertext manipulation 
+    // **********************************
+
+    // Additions
+    void add(lwe_cipher rop, lwe_cipher op1, lwe_cipher op2, int d);
+    // Fused Multiplications-Additions
+    void mulandadd(lwe_cipher rop, lwe_in_data op1, lwe_query op2, int rec_lvl);
+    void mulandadd(lwe_cipher rop, lwe_in_data op1, lwe_query op2, uint64_t current_poly, 
+        int rec_lvl);
+    //Shoup version
+	  void mulandadd(lwe_cipher rop, lwe_in_data op1, lwe_query op2, lwe_query op2prime, 
+        uint64_t current_poly, int rec_lvl);
+	  void mul(lwe_cipher rop, lwe_in_data op1, lwe_query op2, lwe_query op2prime, 
+        uint64_t current_poly, int rec_lvl);
+
+    void mulandaddCiphertextNTT(lwe_cipher rop, lwe_in_data op1, lwe_query op2);
+    void mulandaddCiphertextNTT(lwe_cipher rop, lwe_in_data op1, lwe_query op2, 
+        uint64_t current_poly);
+
+
+  private:
+    // Attributes
+    unsigned int oldNbModuli;
+    unsigned int polyDegree;
+    poly64 *secretKey; // The secret key
+    poly64 *secretKeyShoup; // The secret key Shoupified
+	uint64_t *Abit_mod,*Abit_mod_shoup;
+
+    void clearSecretKeys();
+};
+
+#endif

+ 38 - 0
crypto/NFLLWEDatatypes.hpp

@@ -0,0 +1,38 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_NFLLWEDATATYPES
+#define DEF_NFLLWEDATATYPES
+struct lwe_in_data
+{
+	poly64 *p;
+    uint64_t nbPolys;
+};
+
+struct lwe_cipher
+{
+  	poly64 a;
+  	poly64 b;
+};
+
+struct lwe_query
+{
+	poly64 a;
+	poly64 b;
+};
+
+#endif //DEF_NFLLWEDATATYPES

+ 171 - 0
crypto/NFLLWEPublicParameters.cpp

@@ -0,0 +1,171 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "NFLLWEPublicParameters.hpp"
+#include "NFLLWE.hpp"
+#include <string.h>
+#include "NFLParams.hpp"
+using namespace std;
+
+NFLLWEPublicParameters::NFLLWEPublicParameters()//:
+  //polyDegree(0)
+{
+    cryptoName = "LWE";
+    crypto_container=nullptr;
+    // -1 means uninitialized, 0 means no absorption possible
+    absPerCoordinateBitsize=-1;
+    noise_ub=0;
+}
+
+
+NFLLWEPublicParameters::NFLLWEPublicParameters(unsigned int modulusBitsize_, unsigned int polyDegree_, int absPCBitsize_):
+    absPerCoordinateBitsize(absPCBitsize_)
+{
+    crypto_container=nullptr;
+    cryptoName = "LWE";
+}
+
+// Function that sets the modulus and polyDegree from a raw description sent over the network
+// Expected structure of rawPubKey (uint modulusREPRESATIONBitsize):(uint modulus)
+void NFLLWEPublicParameters::setModulus(char* rawPubKey)
+{
+    // MOK 05122013 there is no need for setting the public key in NFLLWE
+}
+
+void NFLLWEPublicParameters::setMockedPubKey()
+{
+    // MOK 05122013 there is no need for setting the public key in NFLLWE
+}
+
+
+// Getters
+unsigned int NFLLWEPublicParameters::getmodulusBitsize() { return crypto_container->getmodulusBitsize(); }
+uint64_t* NFLLWEPublicParameters::getmoduli() { return crypto_container->getmoduli(); }
+uint64_t NFLLWEPublicParameters::getnoiseUB() { return noise_ub; }
+uint64_t NFLLWEPublicParameters::getsecurityBits() { return crypto_container->getsecurityBits(); }
+unsigned int NFLLWEPublicParameters::getpolyDegree() { return crypto_container->getpolyDegree(); }
+
+// Setters
+void NFLLWEPublicParameters::setnoiseUB(uint64_t noise_upper_bound) { noise_ub = noise_upper_bound;}
+void NFLLWEPublicParameters::setAbsPCBitsize(int bitSize_)
+{
+	absPerCoordinateBitsize = bitSize_;
+	
+}
+void NFLLWEPublicParameters::setsecurityBits(uint64_t security_bits_) 
+{ 
+		crypto_container->setsecurityBits(security_bits_);
+}
+void NFLLWEPublicParameters::setmodulus(uint64_t modulus_)
+{
+		crypto_container->setmodulus(modulus_);
+}
+void NFLLWEPublicParameters::setpolyDegree(unsigned int polyDegree_)
+{
+		crypto_container->setpolyDegree(polyDegree_);
+}
+
+unsigned int NFLLWEPublicParameters::getModulusRepresentationBitsize()
+{
+  // We represent each 60 bit modulus by a 64 bit integer
+  return ceil((double)getmodulusBitsize()/kModulusRepresentationBitsize)*kModulusRepresentationBitsize;
+}
+
+
+unsigned int NFLLWEPublicParameters::getSerializedModulusBitsize()
+{
+  return getModulusRepresentationBitsize();
+}
+
+
+// Expected format of the parameters
+// k:polyDegree:modululusBitsize:AbsorptionBitsize
+void NFLLWEPublicParameters::setNewParameters(std::string crypto_param_descriptor)
+{
+  // We want to get rid of public parameter objects so we transfer the most 
+  // we can to the crypto object 
+  crypto_container->setNewParameters(crypto_param_descriptor);
+}
+
+
+// Get a serialized version of the parameters
+std::string NFLLWEPublicParameters::getSerializedParams(bool shortversion)
+{
+  std::string params;
+  
+  // Name:security:degree:modulusbitsize
+  // WARNING send modulus representation
+  params = cryptoName + ":" + std::to_string(getsecurityBits()) + ":" + std::to_string(getpolyDegree()) + ":" + std::to_string(getmodulusBitsize());
+
+  if (!shortversion)
+  {
+    // Add :abs_per_coordinate if defined or :? otherwise
+    if (absPerCoordinateBitsize==-1) params += ":?";
+    else params += ":" + std::to_string(absPerCoordinateBitsize);
+  }
+
+  return params;
+}
+
+
+char* NFLLWEPublicParameters::getByteModulus()
+{
+ char* byte_pub_key  = new char[getpolyDegree() * sizeof(uint64_t)](); 
+ memcpy(byte_pub_key, &P64, getpolyDegree() * sizeof(uint64_t));
+	return byte_pub_key;
+}
+
+
+void NFLLWEPublicParameters::getParameters()
+{
+}
+
+
+unsigned int NFLLWEPublicParameters::getAbsorptionBitsize()
+{
+	return (absPerCoordinateBitsize < 0) ? 0 : getpolyDegree() * absPerCoordinateBitsize;
+}
+
+unsigned int NFLLWEPublicParameters::getAbsorptionBitsize(unsigned int i)
+{
+	return (absPerCoordinateBitsize < 0) ? 0 : getpolyDegree() * absPerCoordinateBitsize;
+}
+
+unsigned int NFLLWEPublicParameters::getCiphertextSize()
+{
+  return getpolyDegree() * 64 * 2 *crypto_container->getnbModuli();
+}
+
+unsigned int NFLLWEPublicParameters::getCiphertextBitsize()
+{
+	return getModulusRepresentationBitsize() * getpolyDegree() * 2 ;
+}
+unsigned int NFLLWEPublicParameters::getCiphBitsizeFromRecLvl(unsigned int d)
+{
+	return getCiphertextBitsize() ;
+}
+
+unsigned int NFLLWEPublicParameters::getQuerySizeFromRecLvl(unsigned int)
+{
+	return getCiphertextBitsize();
+}
+
+void NFLLWEPublicParameters::computeNewParameters(const std::string& crypto_param_descriptor)
+{
+  setNewParameters(crypto_param_descriptor);
+}
+

+ 81 - 0
crypto/NFLLWEPublicParameters.hpp

@@ -0,0 +1,81 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#ifndef DEF_NFLLWEPUBPARAMS
+#define DEF_NFLLWEPUBPARAMS
+
+#include <inttypes.h>
+#include <string>
+#include "AbstractPublicParameters.hpp"
+#include <iostream>
+
+
+class NFLLWE;
+
+class NFLLWEPublicParameters : public AbstractPublicParameters
+{
+  public :
+    NFLLWEPublicParameters();
+    NFLLWEPublicParameters(unsigned int modulusBitsize_, unsigned int polyDegree_, int absPCBitsize_);
+    void setModulus(char* rawPubKey);
+    void setMockedPubKey();
+
+    // Getters
+    unsigned int getmodulusBitsize();
+    unsigned int getModulusRepresentationBitsize();
+    uint64_t* getmoduli();
+    unsigned int getpolyDegree();
+    unsigned int getSerializedModulusBitsize();
+    unsigned int getAbsorptionBitsize();
+    unsigned int getAbsorptionBitsize(unsigned int rec_lvl);
+    uint64_t getnoiseUB();
+    uint64_t getsecurityBits();
+
+    // Setters
+    void setmodulus(uint64_t modulus);
+    void setpolyDegree(unsigned int polyDegree);
+    void setNewParameters(std::string crypto_param_desc);
+    void setAbsPCBitsize(int absPCBitsize);
+    void setnoiseUB(uint64_t Berr_);
+    void setsecurityBits(uint64_t Berr_);
+    void setcrypto_container(NFLLWE* c) {crypto_container=c;}
+
+  private :
+    //unsigned int modulusBitsize;
+    //uint64_t modulus;
+    //unsigned int polyDegree;
+    int absPerCoordinateBitsize; // Signed as -1 means uninitialized
+    uint64_t noise_ub;
+    uint64_t securityBits; // Defines the security level
+    NFLLWE* crypto_container;
+
+
+  public:
+    char* getByteModulus();
+    std::string getSerializedParams(bool shortversion);
+    void getParameters();
+    unsigned int getCiphertextSize();
+    void computeNewParameters(const std::string&);
+    void newKeyParameter(unsigned int bitKeySize);
+    unsigned int getCiphertextBitsize();
+    unsigned int getCiphBitsizeFromRecLvl(unsigned int);
+    unsigned int getQuerySizeFromRecLvl(unsigned int);
+
+
+};
+#endif

+ 46 - 0
crypto/NFLParams.cpp

@@ -0,0 +1,46 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PARAMS_C
+#define PARAMS_C
+
+#include "NFLParams.hpp"
+
+// signed and unsigned 128-bit types
+typedef int int128_t __attribute__((mode(TI)));
+typedef unsigned int uint128_t __attribute__((mode(TI)));
+
+// The moduli used in each 64 bit block (60 bits long each)
+// They are of the form p = 2**61 - i*2**14 + 1 for increasing i
+const unsigned int kMaxNbModuli = 17;
+const uint64_t P64[kMaxNbModuli] = { 2305843009213317121ULL,  2305843009213120513ULL,  2305843009212694529ULL,2305843009212399617ULL,  2305843009211662337ULL,  2305843009211596801ULL, 2305843009211400193ULL,  2305843009210580993ULL,  2305843009210515457ULL, 2305843009210023937ULL,  2305843009209057281ULL,  2305843009208795137ULL, 2305843009208713217ULL,  2305843009208123393ULL,  2305843009207468033ULL, 2305843009206976513ULL,  2305843009206845441ULL};
+const unsigned int kModulusBitsize = 60;
+const unsigned int kModulusRepresentationBitsize = 64; 
+
+// A primitive 2**14 root of unity for each one of the moduli
+const uint64_t primitive_roots[kMaxNbModuli] = {1187132827279672845ULL, 753478288701480417ULL, 717492273700781398ULL, 1965831349000139179ULL, 2188074825493578002ULL, 232964966911499637ULL, 395215708149128273ULL, 241993652537061162ULL, 370764889455808762ULL, 1598724739621481826ULL, 610870591815427803ULL, 1880981984715338041ULL, 1389374064030612248ULL, 1508488901479281364ULL, 2111887543055470169ULL, 2020509703903079203ULL, 1120240637471598814ULL};
+
+// Inverses of kMaxPolyDegree (for the other degrees it can be derived easily)
+// for the different moduli
+const uint64_t invkMaxPolyDegree[kMaxNbModuli] = {2305561534236606511ULL, 2305561534236409927ULL, 2305561534235983995ULL, 2305561534235689119ULL, 2305561534234951929ULL, 2305561534234886401ULL, 2305561534234689817ULL, 2305561534233870717ULL, 2305561534233805189ULL, 2305561534233313729ULL, 2305561534232347191ULL, 2305561534232085079ULL, 2305561534232003169ULL, 2305561534231413417ULL, 2305561534230758137ULL, 2305561534230266677ULL, 2305561534230135621ULL};
+
+// Polynomial related data
+const unsigned int kMinPolyDegree = 512;
+const unsigned int kMaxPolyDegree = 8192;
+
+#endif
+

+ 44 - 0
crypto/NFLParams.hpp

@@ -0,0 +1,44 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PARAMS_H
+#define PARAMS_H
+#include <inttypes.h> 
+
+// signed and unsigned 128-bit types
+typedef int int128_t __attribute__((mode(TI)));
+typedef unsigned int uint128_t __attribute__((mode(TI)));
+
+// The moduli used in each 64 bit block (60 bits long each)
+extern const unsigned int kMaxNbModuli;
+extern const uint64_t P64[];
+extern const unsigned int kModulusBitsize;
+extern const unsigned int kModulusRepresentationBitsize;
+
+// A primitive 2**14 root of unity for each one of the moduli
+extern const uint64_t primitive_roots[];
+
+// Inverses of kMaxPolyDegree (for the other degrees it can be derived easily)
+// for the different moduli
+extern const uint64_t invkMaxPolyDegree[];
+
+// Polynomial related data
+extern const unsigned int kMinPolyDegree;
+extern const unsigned int kMaxPolyDegree;
+
+#endif
+

+ 922 - 0
crypto/NFLlib.cpp

@@ -0,0 +1,922 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "NFLlib.hpp"
+#include <x86intrin.h>
+	
+void DEBUG_MESSAGE(const char *s, poly64 p, unsigned int n){
+#ifdef DEBUG
+  std::cout<<s;
+  NFLlib::print_poly64hex(p,n);
+#endif
+}
+
+// *********************************************************
+//    Constructors and init functions
+// *********************************************************
+// The constructors are not able to set all the parameters and setNewParameters has to be called
+// after them. The attribute alreadyInit reflects this uninitialized status.
+
+NFLlib::NFLlib():
+    alreadyInit(0),
+    nbModuli(0),
+    polyDegree(0)
+{
+}
+
+
+// Compute all data needed to do NTT operations
+// Depends on the moduli used and polyDegree
+void  NFLlib::configureNTT()
+{
+  uint64_t phi, invphi, omega, invomega, temp;
+
+  // If this is a reconfiguration free memory before reallocating it
+  freeNTTMemory();
+
+  // Allocate space for the first dimension of the arrays needed for the NTT and CRT
+  phis = (uint64_t **) malloc(nbModuli * sizeof(uint64_t *));
+  shoupphis = (uint64_t **) malloc(nbModuli * sizeof(uint64_t *));
+  invpoly_times_invphis = (uint64_t **) malloc(nbModuli * sizeof(uint64_t *));
+  shoupinvpoly_times_invphis = (uint64_t **) malloc(nbModuli * sizeof(uint64_t *));
+  omegas = (uint64_t **) malloc(nbModuli * sizeof(uint64_t *));
+  shoupomegas = (uint64_t **) malloc(nbModuli * sizeof(uint64_t *));
+  invomegas = (uint64_t **) malloc(nbModuli * sizeof(uint64_t *));
+  shoupinvomegas = (uint64_t **) malloc(nbModuli * sizeof(uint64_t *));  
+  invpolyDegree = (uint64_t *) malloc(nbModuli * sizeof(uint64_t));
+  liftingIntegers = new mpz_t[nbModuli];
+
+  // From now on, we have to do everything nbModuli times
+  for(unsigned short currentModulus=0;currentModulus<nbModuli;currentModulus++) 
+  {
+
+    // Define the moduli we use (useful ?)
+    moduli[currentModulus] = P64[currentModulus];
+ 
+    // Allocation of the second dimension of the NTT parameters
+    phis[currentModulus] = (uint64_t *) malloc(polyDegree * sizeof(uint64_t));
+    shoupphis[currentModulus] = (uint64_t *) malloc(polyDegree * sizeof(uint64_t));
+    invpoly_times_invphis[currentModulus] = (uint64_t *) malloc(polyDegree * sizeof(uint64_t));
+    shoupinvpoly_times_invphis[currentModulus] = (uint64_t *) malloc(polyDegree * sizeof(uint64_t));
+    omegas[currentModulus] = (uint64_t *) malloc((2 * polyDegree) * sizeof(uint64_t));
+    shoupomegas[currentModulus] = omegas[currentModulus] + polyDegree;
+    invomegas[currentModulus] = (uint64_t *) malloc((2 * polyDegree) * sizeof(uint64_t));
+    shoupinvomegas[currentModulus] = invomegas[currentModulus] + polyDegree;
+    
+    // We start by computing phi 
+    // The roots in the array are primitve 2**14-th roots 
+    // Squared 14-log2(polyDegree) times they become
+    // polyDegree-th roots as required by the NTT
+    // But first we get phi = sqrt(omega) squaring them 13-log2(polyDegree) times 
+    phi = primitive_roots[currentModulus];
+    for (unsigned int i = 0 ; i < 13 - log2(polyDegree) ; i++)
+    {
+      phi = mulmod(phi, phi, moduli[currentModulus]);
+    }
+    
+    // Now that temp = phi we initialize the array of phi**i values  
+    // Initialized to phi**0
+    temp = 1;
+    for (unsigned int i = 0 ; i < polyDegree ; i++)
+    {
+      phis[currentModulus][i] = temp;
+      shoupphis[currentModulus][i] = ((uint128_t) temp << 64) / moduli[currentModulus];
+      // phi**(i+1)
+      temp = mulmod(temp, phi, moduli[currentModulus]);
+    }
+    // At the end of the loop temp = phi**polyDegree
+
+    // Computation of invphi
+    // phi**(2*polydegree)=1 -> temp*phi**(polyDegree-1) = phi**(-1)
+    invphi = mulmod(temp, phis[currentModulus][polyDegree-1], moduli[currentModulus]); 
+
+    // Computation of the inverse of polyDegree using the inverse of kMaxPolyDegree
+    invpolyDegree[currentModulus] = mulmod(invkMaxPolyDegree[currentModulus], 
+        kMaxPolyDegree/polyDegree, moduli[currentModulus]);
+
+    // Now we can compute the table invpoly_times_invphis
+    temp = invpolyDegree[currentModulus];
+    for (unsigned int i = 0 ; i < polyDegree ; i++)
+    {
+      invpoly_times_invphis[currentModulus][i] = temp;
+      shoupinvpoly_times_invphis[currentModulus][i] = ((uint128_t) temp << 64) 
+        / moduli[currentModulus];
+      // This is invpolyDegree*invphi**(i+1)
+      temp = mulmod(temp, invphi, moduli[currentModulus]);
+    }
+
+    // For the omegas it is easy, we just use the function of David Harvey modified for our needs
+    omega = mulmod(phi, phi, moduli[currentModulus]);
+    prep_wtab(omegas[currentModulus], shoupomegas[currentModulus], omega, polyDegree,
+      moduli[currentModulus]);
+
+    // And again for the invomegas
+    invomega = mulmod(invphi, invphi, moduli[currentModulus]);
+    prep_wtab(invomegas[currentModulus], shoupinvomegas[currentModulus], invomega, polyDegree,
+        moduli[currentModulus]);
+
+    // Inverse-CRT constants
+    mpz_t tmpz, mpz_inverse;
+    mpz_init(tmpz);
+    mpz_init(mpz_inverse);
+
+    // Compute first the product of all moduli but the current
+    mpz_init_set_ui(liftingIntegers[currentModulus],1UL);
+    for (unsigned int i = 0 ; i < nbModuli ; i++)
+    {
+      if (i == currentModulus) continue;
+      mpz_import(tmpz, 1, 1, sizeof(uint64_t), 0, 0, &P64[i]); 
+      mpz_mul(liftingIntegers[currentModulus], liftingIntegers[currentModulus], tmpz);
+    }
+    
+    // Compute the inverse of the product modulo the current modulus and multiply it with the product
+    mpz_import(tmpz, 1, 1, sizeof(uint64_t), 0, 0, &moduli[currentModulus]);
+    mpz_invert(mpz_inverse, liftingIntegers[currentModulus], tmpz);
+    mpz_mul(liftingIntegers[currentModulus], liftingIntegers[currentModulus], mpz_inverse);
+    mpz_clear(tmpz);
+    mpz_clear(mpz_inverse);
+  }
+  
+  // Compute  the product of all moduli 
+  mpz_t tmpz;
+  mpz_init(tmpz);
+  mpz_init_set_ui(moduliProduct,1UL);
+  for (unsigned int i = 0 ; i < nbModuli ; i++)
+  {
+    mpz_import(tmpz, 1, 1, sizeof(uint64_t), 0, 0, &moduli[i]);
+    mpz_mul(moduliProduct, moduliProduct, tmpz);
+  }
+  mpz_clear(tmpz);
+  
+  uint64_t* inv_indexes_tmp = malloc_align<32, uint64_t>(polyDegree);
+  inv_indexes = malloc_align<16>(polyDegree, inv_indexes);
+
+  // Compute permutation indexes for inv_ntt
+  for (size_t i = 0; i < polyDegree; i++) 
+  {
+    size_t ii = i, r = 0; 
+    for (unsigned h = 1; h < polyDegree; h=h<<1)
+    {    
+      r = (r << 1) | (ii & 1);
+      ii >>= 1;
+    }    
+
+    inv_indexes_tmp[i] = r; 
+  }
+
+  // Invert the previous permutation. I think we can do better than that :)
+  for (size_t i = 0; i < polyDegree; i++) {
+      for (size_t j = 0; j < polyDegree; j++) {
+          if (inv_indexes_tmp[j] == i) { 
+              inv_indexes[i] = j; 
+              break;
+          }    
+      }    
+  }
+  free(inv_indexes_tmp);
+  
+  alreadyInit = nbModuli;
+}
+
+
+
+
+// *********************************************************************
+// Fundamental setters (resulting on a call to the init function above)
+// *********************************************************************
+
+// Set or reset the degrees of the polynomials used and the modulus size (which fixes the modulus)
+void NFLlib::setNewParameters(unsigned int polyDegree_, unsigned int aggregatedModulusBitsize_)
+{
+  // We don't use setpolyDegree to avoid configureNTT being called twice
+  polyDegree = polyDegree_;
+
+  // We use a special function for setting the modulus as it can be called independently 
+  // and requires some processing. This function also ensures that the NTT params are configured.
+  setmodulus(aggregatedModulusBitsize_);
+}
+
+
+// Sets the modulus size AND configures NTT parmeters (which fixes a given modulus)
+void NFLlib::setmodulus(uint64_t aggregatedModulusBitsize_)
+{
+  // For the CRT, from the aggregated modulus bitsize, we compute the number of necessary moduli
+  if (aggregatedModulusBitsize_ % kModulusBitsize != 0)
+  {
+    std::cout << "NFLlib: CRITICAL. Modulus of " << aggregatedModulusBitsize_ 
+      << " requested but only integer multiples of " << kModulusBitsize << " bits implemented. Exiting ..." << std::endl;
+    exit(-1);
+  }
+  nbModuli=aggregatedModulusBitsize_/kModulusBitsize;
+  
+  moduli=new uint64_t[nbModuli]();
+
+  configureNTT();
+}
+
+
+// Sets polyDegree AND configures NTT
+void NFLlib::setpolyDegree(unsigned int polyDegree_)
+{
+  polyDegree = polyDegree_;
+
+  configureNTT();
+}
+
+
+
+
+// *********************************************************
+// Getters
+// *********************************************************
+
+uint64_t* NFLlib::getmoduli() { return moduli; }
+unsigned short NFLlib::getnbModuli() { return nbModuli; }
+unsigned int NFLlib::getpolyDegree() { return polyDegree; }
+void NFLlib::copymoduliProduct(mpz_t dest) { mpz_init_set(dest, moduliProduct); }
+
+
+
+
+// **************************************
+// Random polynomial generation functions
+// **************************************
+
+// Two modes uniform or bounded (if uniform is false)
+// WARNING : The bounded mode only works for a bound 
+// below the smaller of the moduli -> we use or for bounded noise
+
+// Allocates and sets a bounded random polynomial in FFT form calling setBoundedRandomPoly
+poly64 NFLlib::allocBoundedRandomPoly(uint64_t upperBound_, bool uniform_) 
+{
+  poly64 res = (poly64)calloc(polyDegree * nbModuli, sizeof(uint64_t));
+  setBoundedRandomPoly(res, upperBound_, uniform_);
+  return res;
+}
+
+
+// Sets a pre-allocated random polynomial in FFT form
+// If uniform = true upperBound is ignored and the coefficients are uniformly random
+// ASSUMPTION: if uniform = false upperBound is below all of the moduli used
+void NFLlib::setBoundedRandomPoly(poly64 res, uint64_t upperBound_, bool uniform_) 
+{
+  poly64 rnd, rnd_orig;
+  uint64_t mask;
+
+  if (uniform_ == false){
+    // In bounded mode upperBound must be below the smaller of the moduli
+    for (unsigned int cm = 0 ; cm < nbModuli ; cm++)
+    {
+      if (upperBound_ >= moduli[cm]) 
+      {
+        std::cout << "NFLlib: upperBound is larger than the moduli in setBoundedRandomPoly.";
+        std::cout << " Unpredictable results ..." << std::endl;
+        break;
+      }
+    }
+
+    // We play with the rnd pointer (in the uniform case), and thus
+    // we need to remember the allocated pointer to free it at the end
+    rnd_orig = (poly64) malloc(polyDegree * sizeof(uint64_t)); 
+    rnd = rnd_orig; 
+
+    // Get some randomness from the PRNG
+    fastrandombytes((unsigned char *)rnd, polyDegree * sizeof(uint64_t));
+
+    // upperBound is below the moduli so we create the same mask for all the moduli
+    mask=(1ULL <<  (unsigned int)ceil(log2(upperBound_))) -1;    
+    
+    for(unsigned int i=0;i<polyDegree;i++) {
+    
+      // First remove the heavy weight bits we dont need
+      rnd[i]=(rnd[i]&mask);
+    
+      // When the random is still too large, reduce it 
+      // In order to follow strictly a uniform distribution we should
+      // get another rnd but in order to follow the proofs of security
+      // strictly we should also take noise from a gaussian ...
+      if (rnd[i]>=upperBound_) 
+      {
+        rnd[i]-=upperBound_;
+      }
+      for (unsigned int cm = 0 ; cm < nbModuli ; cm++)
+      {
+        res[polyDegree*cm+i] = rnd[i];
+      }
+    }
+  }
+  else // uniform == true
+  {  
+    // In uniform mode we need randomness for all the polynomials in the CRT
+    rnd_orig = (poly64) malloc(polyDegree * nbModuli * sizeof(uint64_t)); 
+    // We play with the rnd pointer (in the uniform case), and thus
+    // we need to remember the allocated pointer to free it at the end
+    rnd = rnd_orig; 
+    fastrandombytes((unsigned char *)rnd, polyDegree * nbModuli * sizeof(uint64_t));
+  
+    for (unsigned int cm = 0 ; cm < nbModuli ; cm++)
+    {
+      // In the uniform case, instead of getting a big random (within the general moduli),
+      // We rather prefer, for performance issues, to get smaller randoms for each module
+      // The mask should be the same for all moduli (because they are the same size)
+      // But for generality we prefer to compute it for each moduli so that we could have
+      // moduli of different bitsize
+      
+      mask=(1ULL << (int)ceil(log2(moduli[cm]))) -1;    
+    
+      for(unsigned int i=0;i<polyDegree;i++) 
+      {
+        // First remove the heavy weight bits we dont need
+        rnd[i]=(rnd[i]&mask);
+    
+        // When the random is still too large, reduce it 
+        if (rnd[i]>=moduli[cm]) 
+        {
+          rnd[i]-=moduli[cm];
+        }
+        res[i] = rnd[i];
+      }
+      rnd+=polyDegree;
+      res+=polyDegree;
+    }
+  }
+  free(rnd_orig);
+}
+
+
+
+
+// *********************************************************
+// Data import and export main functions
+// *********************************************************
+
+// Takes an array of buffers and:
+// 1) Converts them into a set of polynomials with arbitrary large coefficients
+// 2) Reduces the polys through CRT to have nbModuli contiguous polys with uint64_t coefficients 
+// 3) Does the NTT transform
+// - inArrayOfBuffers array of buffers to take the bits from
+// - nbrOfBuffers nbr of buffers in the array
+// - dataBitsizePerBuffer bits that can be taken from each buffer
+// - bitsPerCoordinate bits used to create each coefficient (can be > 64 !)
+// - polyNumber set by the function to say how many polynomials are in the returned pointer
+poly64 *NFLlib::deserializeDataNFL(unsigned char **inArrayOfBuffers, uint64_t nbrOfBuffers, uint64_t dataBitsizePerBuffer, unsigned bitsPerCoordinate, uint64_t &polyNumber) {
+
+  // We need to handle dataBitsize bits of data per buffer
+  // each poly can take publicParams.getAbsorptionBitsize() bits so
+  polyNumber = ceil((double)dataBitsizePerBuffer*(double)nbrOfBuffers/(double)(bitsPerCoordinate*polyDegree));
+
+  // The uint64_t arrays are allocated and filled with zeros
+  // So that we do not have to pad with zeros beyond the limit
+  poly64* deserData = (poly64 *) calloc(polyNumber, sizeof(poly64));
+
+  // bitsplitter does all the hard work WITHOUT using large numbers !
+  deserData[0] = bitsplitter(inArrayOfBuffers, nbrOfBuffers, dataBitsizePerBuffer, bitsPerCoordinate);
+ 
+  // We finish the work by applying the NTT transform
+#ifdef MULTI_THREAD
+  #pragma omp parallel for 
+#endif
+  for (unsigned int i = 0 ; i < polyNumber ; i++)
+  {
+    deserData[i] = deserData[0]+i*nbModuli*polyDegree;
+#ifndef SIMULATE_PRE_NTT_DATA
+    nttAndPowPhi(deserData[i]);
+#endif
+  }
+  
+  return deserData;
+}
+
+// Serialize an array of poly64 elements into a compact byte buffer
+// Takes a set of polynomial coefficients and outputs their concatenation
+// - indata points to the polynomial coefficients
+// - outdata points to the concatenation obtained
+// - bitsPerChunk defines how many bits has each coefficient 
+// - nb_of_uint64 defines how many coefficients must be concatenated
+// ASSUMPTION: all the polynomials are contiguously allocated
+// ASSUMPTION: outdata has allocated one more uint64_t than needed
+// ASSUMPTION:  all the coefficients have the same size which is below 56 bits
+void NFLlib::serializeData64 (uint64_t* indata, unsigned char* outdata, unsigned int bitsPerChunk, uint64_t nb_of_uint64)
+{
+  unsigned char *tmppointer;
+  uint64_t *pointer64;
+  pointer64 = (uint64_t *) outdata;
+  uint32_t bitswritten=0;
+
+  // Tricky approach playing with pointers to be able to infinitely add
+  // up to 56 bits to any bit string present
+  for (uint64_t i = 0 ; i < nb_of_uint64 ;)
+  {
+    while(bitswritten + bitsPerChunk <= 64)
+    {
+      *pointer64 |= (*indata++)<<bitswritten; i++;
+      bitswritten += bitsPerChunk;
+      if(i==nb_of_uint64) break;
+    }
+    tmppointer = (unsigned char*) pointer64;
+    tmppointer+=bitswritten>>3;
+    pointer64 = (uint64_t *) (tmppointer);
+    bitswritten -=8*(bitswritten>>3);
+  }
+}
+
+
+// Serialize an array of poly64 elements into a compact byte buffer
+// Takes a set of polynomial coefficients and outputs their concatenation
+// - indata points to the polynomial coefficients
+// - outdata points to the concatenation obtained
+// - bitsPerChunk defines how many bits has each coefficient
+// - nb_of_uint64 defines how many coefficients must be concatenated
+// ASSUMPTION: all the polynomials are contiguously allocated
+// ASSUMPTION: outdata has allocated one more uint64_t than needed
+// IMPORTANT NOTE: Unlike in serializeData64 bitsPerChunk can be arbitrarily large. This function considers that large coefficients are retrieved by blocks of varying size up to 32 bit. For example 100-bit coefficients will be retrieved by three blocks of 32 bits and a block of 4 looping that way for each 100-bit coefficient.
+void NFLlib::serializeData32 (uint32_t* indata, unsigned char* outdata, unsigned int bitsPerChunk, uint64_t nb_of_uint32){
+  unsigned char *tmppointer;
+  uint64_t *pointer64;
+  pointer64 = (uint64_t *) outdata;
+  uint32_t bitswritten=0;
+
+  // See through how many block (=sub-chunk) we will have to loop to get each coefficient (=chunk)
+  const double uint32PerChunk = (double)bitsPerChunk/32;
+  const uint64_t int_uint32PerChunk = ceil(uint32PerChunk);
+  const bool isint_uint32PerChunk = (uint32PerChunk==(double)int_uint32PerChunk);
+ 
+  // Build masks for each sub-chunk
+  uint64_t subchunkMasks[int_uint32PerChunk];
+  unsigned int subchunkSizes[int_uint32PerChunk];
+  
+  // Increment with subchunkIndex=((subchunkIndex+1)%int_uint64PerChunk) 
+  // and use with subchunkSizes[subchunkIndex]; 
+  unsigned int subchunkIndex = 0;  
+  for (int i = 0 ; i < int_uint32PerChunk - 1 ; i++)
+  {
+    subchunkSizes[i]=32;
+    subchunkMasks[i] = (1ULL<<32)-1; // const mask for extracting 32 bits
+  }
+  subchunkSizes[int_uint32PerChunk-1] = bitsPerChunk - 32 * (int_uint32PerChunk - 1);
+  subchunkMasks[int_uint32PerChunk-1] = (1ULL<<(subchunkSizes[int_uint32PerChunk-1]))-1;
+  
+  // Apply the same approach than in serializeData64 but with varying sizes
+  for (uint64_t i = 0 ; i < nb_of_uint32 ;)
+  {
+    while(bitswritten + subchunkSizes[subchunkIndex] <= 64)
+    {
+      *pointer64 |= ((uint64_t)(*indata++))<<bitswritten; i++;
+      bitswritten += subchunkSizes[subchunkIndex];
+      subchunkIndex=((subchunkIndex+1)%int_uint32PerChunk);
+      if(i==nb_of_uint32) break;
+    }
+    tmppointer = (unsigned char*) pointer64;
+    tmppointer+=bitswritten>>3;
+    pointer64 = (uint64_t *) (tmppointer);
+    bitswritten -=8*(bitswritten>>3);
+  }
+}
+
+
+
+// *********************************************************
+// Helper functions
+// *********************************************************
+
+// Allocate a polynomial potentially with all coefficients set to zero if nullpoly = true
+poly64 NFLlib::allocpoly(bool nullpoly)
+{
+  if (nullpoly == true) return (poly64) calloc(polyDegree*nbModuli,sizeof(uint64_t));
+  else return (poly64) malloc(polyDegree*nbModuli*sizeof(uint64_t));
+}
+
+
+// Lift a polynomial in CRT representation, into a polynomial with large integer coefficients
+mpz_t* NFLlib::poly2mpz(poly64 p)
+{
+  mpz_t* resultmpz;
+  mpz_t* tmpzbuffer;
+  resultmpz=new mpz_t[polyDegree];
+  tmpzbuffer=new mpz_t[nbModuli];
+  for(unsigned i=0;i<polyDegree;i++) {
+    mpz_init2(resultmpz[i],192);
+  }
+  for(int cm = 0; cm < nbModuli;cm++) {
+    mpz_init2(tmpzbuffer[cm],192);
+  }
+  
+  for(unsigned i=0;i<polyDegree;i++) {
+    mpz_set_ui(resultmpz[i],0UL);
+    
+    for(int cm = 0; cm < nbModuli;cm++) {
+      mpz_import(tmpzbuffer[cm], 1, 1, sizeof(uint64_t), 0, 0, p+i+polyDegree*cm);
+      mpz_mul(tmpzbuffer[cm], liftingIntegers[cm], tmpzbuffer[cm]);
+      mpz_add(resultmpz[i], resultmpz[i], tmpzbuffer[cm]);
+    }
+    mpz_mod(resultmpz[i], resultmpz[i], moduliProduct);
+  }
+  for(int cm = 0; cm < nbModuli;cm++) {
+  	mpz_clear(tmpzbuffer[cm]);
+  	}
+  free(tmpzbuffer);
+  return resultmpz;
+}
+
+
+// Debug printing function
+void NFLlib::print_poly64hex(poly64 p, unsigned int coeff_nbr)
+{
+ std::cout << "[";
+ for (unsigned int i = 0 ; i < coeff_nbr ; i++)
+ {
+   std::cout << std::hex << (unsigned int)(p[i]>>32)<<(unsigned int) p[i] << " ";
+ }
+ std::cout << "]" << std::dec << std::endl;
+}
+
+// Debug printing function
+void NFLlib::print_poly64(poly64 p, unsigned int coeff_nbr)
+{
+ std::cout << "[";
+ for (unsigned int i = 0 ; i < coeff_nbr ; i++)
+ {
+   std::cout << p[i] << " ";
+ }
+ std::cout << "]" << std::endl;
+}
+
+
+
+// *********************************************************
+// Destructors and closing or freeing functions
+// *********************************************************
+
+// Destructor
+NFLlib::~NFLlib()
+{
+  freeNTTMemory();
+}
+
+
+// Everything is commented out because of hard to predict issues with MacOsX
+// Uncomment on a computer with that OS before releasing
+void NFLlib::freeNTTMemory(){
+  // alreadyInit says how many arrays we have allocated for the NTT
+  for (unsigned i = 0 ; i < alreadyInit; i++)
+  {
+    free(phis[i]);
+    free(shoupphis[i]);
+    free(invpoly_times_invphis[i]);
+    free(shoupinvpoly_times_invphis[i]);
+    free(omegas[i]);
+    free(invomegas[i]);
+    mpz_clear(liftingIntegers[i]);
+  
+    if (i == alreadyInit - 1)
+    {
+      free(shoupphis);
+      free(invpoly_times_invphis);
+      free(shoupinvpoly_times_invphis);
+      free(omegas);
+      free(shoupomegas);
+      free(invomegas);
+      free(shoupinvomegas);
+      free(invpolyDegree);
+      delete[] liftingIntegers;
+      free(inv_indexes);
+      mpz_clear(moduliProduct);
+    }
+  }
+
+  alreadyInit = 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// ****************************************************************************************
+// THE DEN: Uncommented howling functions and pointer blood magic. Enter at your own risk.
+// ****************************************************************************************
+
+// We define first a back to back funtion to test our bitsplitter function
+// If DEBUG_BITSPLIT_B2B the function is used, else it is ignored 
+
+//#define DEBUG_BITSPLIT_B2B
+#ifdef DEBUG_BITSPLIT_B2B
+#define DEBUG_BITSPLIT
+#define B2BTEST(inDataBuffers, nbrOfBuffers, bitsPerBuffer, bitsPerChunk, totalbitsread, bitsread, pointer64, bitsToRead) bitsplitter_backtoback_internal_test (inDataBuffers, nbrOfBuffers, bitsPerBuffer, bitsPerChunk, totalbitsread, bitsread, pointer64, bitsToRead)
+#else
+#define B2BTEST(inDataBuffers, nbrOfBuffers, bitsPerBuffer, bitsPerChunk, totalbitsread, bitsread, pointer64, bitsToRead) if(0);
+#endif
+
+uint64_t* NFLlib::bitsplitter_backtoback_internal_test (unsigned char** inDataBuffers, uint64_t nbrOfBuffers, uint64_t bitsPerBuffer, unsigned int bitsPerChunk, uint64_t totalbitsread,uint64_t bitsread, uint64_t* pointer64, unsigned int bitsToRead)
+{
+  unsigned int bufferIndex = totalbitsread/bitsPerBuffer;
+  uint64_t bitPositionInBuffer = totalbitsread - bufferIndex*bitsPerBuffer;
+  uint64_t bytePositionInBuffer = bitPositionInBuffer/8;
+  unsigned int bitPositionInByte = bitPositionInBuffer%8;
+  if (bitPositionInBuffer+sizeof(uint64_t)*8 > bitsPerBuffer)
+  {
+    std::cerr << "WARNING: Bitsplit goes beyond buffer size (let's hope it is allocated)" << std::endl;
+  }
+  if (bitPositionInBuffer + bitsToRead > bitsPerBuffer)
+  {
+    std::cerr << "CRITICAL: Bitsplit reads AND USES data beyond buffer space" << std::endl;
+    std::cerr << "totalbitsread " << totalbitsread << std::endl;
+    std::cerr << "bufferIndex " << bufferIndex << std::endl;
+    std::cerr << "bitPositionInBuffer " << bitPositionInBuffer << std::endl;
+    std::cerr << "bytePositionInBuffer " << bytePositionInBuffer << std::endl;
+    std::cerr << "CRITICAL: On B2B test called for " << bitsToRead << " bits" << std::endl;
+    exit(-1);
+  }
+  uint64_t b2bresult = ((*((uint64_t *)(inDataBuffers[bufferIndex]+bytePositionInBuffer)))>>bitPositionInByte) & ((1ULL<<bitsToRead)-1) ;
+  uint64_t bitsplitresult = ((*pointer64)>>bitsread) & ((1ULL<<bitsToRead)-1);
+  if (b2bresult  != bitsplitresult)
+  {
+    std::cerr << "CRITICAL: Bitsplit different from back to back function" << std::endl;
+    std::cerr << "CRITICAL: Left " << b2bresult << std::endl;
+    std::cerr << "CRITICAL: Right " << bitsplitresult << std::endl;
+    exit(-1);
+  }
+  return 0;
+}
+
+inline void NFLlib::bs_loop (unsigned char** inDataBuffers, uint64_t nbrOfBuffers, uint64_t bitsPerBuffer, unsigned int bitsPerChunk, uint64_t *&tmpdata, uint64_t bufferIndex, uint64_t &bitsread, size_t &subchunkIndex)
+{
+  // We redefine the amount of uint64 that can be produced given that we may have already read
+  uint64_t bitstoread = bitsPerBuffer - bitsread;
+  double nbChunks = (double)(bitsPerBuffer-bitsread)/bitsPerChunk;
+  uint64_t int_nbChunks = floor(nbChunks);
+
+  // How many uint64_t are needed to encode a chunk
+  const double uint64PerChunk = (double)bitsPerChunk/56;
+  const uint64_t int_uint64PerChunk = ceil(uint64PerChunk);
+  const bool  isint_uint64PerChunk = (uint64PerChunk==(double)int_uint64PerChunk);
+  
+  // Compute subchunk sizes and masks
+  uint64_t subchunkMasks[int_uint64PerChunk];
+  // Increment with subchunkIndex=((subchunkIndex+1)%int_uint64PerChunk) and 
+  // use subchunkSizes[subchunkIndex]; 
+  unsigned int subchunkSizes[int_uint64PerChunk];
+  for (unsigned i = 0 ; i < int_uint64PerChunk - 1 ; i++)
+  {
+    subchunkSizes[i]=56;
+    subchunkMasks[i] = (1ULL<<56)-1; // const mask for extracting 56 bits
+  }
+  subchunkSizes[int_uint64PerChunk-1] = bitsPerChunk - 56 * (int_uint64PerChunk - 1);
+  subchunkMasks[int_uint64PerChunk-1] = (1ULL<<(subchunkSizes[int_uint64PerChunk-1]))-1;
+  
+#ifdef DEBUG_BITSPLIT
+
+  for (int i = 0 ; i < int_uint64PerChunk ; i++)
+  {
+    std::cerr<<"bitsplit0 i="<<i<<std::endl;
+    std::cerr<<"bitsplit0 subchunkSizes[i]="<<subchunkSizes[i]<<std::endl;
+    std::cerr<<"bitsplit0 subchunkMasks[i]="<<subchunkMasks[i]<<std::endl;
+  }
+#endif
+
+  // We compute how many extra subchunks are available taking into account that we may
+  // start this new buffer on the middle of a chunk
+  uint64_t supplementalSubchunks = 0;
+  uint64_t cumulatedsize = 0;
+  for (unsigned i = 0 ; i < int_uint64PerChunk ; i++)
+  {
+    if (cumulatedsize + subchunkSizes[(subchunkIndex + i) % int_uint64PerChunk] <= (bitsPerBuffer-bitsread)-int_nbChunks*bitsPerChunk)        
+    {
+      supplementalSubchunks++;
+      cumulatedsize += subchunkSizes[(subchunkIndex + i) % int_uint64PerChunk];
+    }
+    else
+    {
+      break;
+    }
+  }
+  uint64_t totalSubChunks=int_nbChunks*int_uint64PerChunk + supplementalSubchunks;
+#ifdef DEBUG_BITSPLIT
+  std::cerr<<"bitsplit1 nbrOfBuffers="<<nbrOfBuffers<<std::endl;
+  std::cerr<<"bitsplit1 nbChunks="<<nbChunks<<std::endl;
+  std::cerr<<"bitsplit1 int_nbChunks="<<int_nbChunks<<std::endl;
+  std::cerr<<"bitsplit1 uint64PerChunk="<<uint64PerChunk<<std::endl;
+  std::cerr<<"bitsplit1 int_uint64PerChunk="<<int_uint64PerChunk<<std::endl;
+  std::cerr<<"bitsplit1 isint_uint64PerChunk="<<isint_uint64PerChunk<<std::endl;
+  std::cerr<<"bitsplit1 totalSubChunks="<<totalSubChunks<<std::endl;
+  std::cerr<<"bitsplit1 cumulatedsize " << cumulatedsize << std::endl;
+  std::cerr<<"bitsplit1 bitsPerBuffer " << bitsPerBuffer << std::endl;
+  std::cerr<<"bitsplit1 bitsread " << bitsread << std::endl;
+  std::cerr<<"bitsplit1 nextsubchunksize " <<  subchunkSizes[(subchunkIndex)]<< std::endl;
+  std::cerr<<"bitsplit1 nextsubchunk " <<  subchunkIndex<< std::endl;
+#endif
+  
+  unsigned  char *tmppointer;
+  uint64_t *pointer64;
+  pointer64 = (uint64_t *) inDataBuffers[bufferIndex];
+  uint64_t bitsremaining=0; 
+
+  
+  
+  // Loop over the subchunks in the current buffer
+  for (uint64_t i = 0 ; i < totalSubChunks ; )
+  {
+    // Get up to 64bits
+    while (bitsread + subchunkSizes[subchunkIndex] <= 64)
+    {
+      *tmpdata = ((*pointer64)>>bitsread) & subchunkMasks[subchunkIndex];
+      tmpdata++;i++;
+      bitsread += subchunkSizes[subchunkIndex];
+      subchunkIndex= (subchunkIndex+1 == int_uint64PerChunk ? 0 : subchunkIndex + 1);
+      if(i==totalSubChunks) break;
+    }
+    if (bitstoread > 128)
+    {
+      unsigned shift = bitsread >>3; 
+      tmppointer = (unsigned char*) pointer64;
+      tmppointer += shift;
+      pointer64 = (uint64_t *) (tmppointer);
+      bitstoread-= shift<<3;
+      bitsread -= shift<<3;
+    } 
+    else
+    {
+      tmppointer = (unsigned char*) pointer64;
+      while ((64 - bitsread < subchunkSizes[subchunkIndex]) && bitstoread > 0)
+      {
+        tmppointer++;
+        bitsread -= 8;
+        bitstoread -= 8;
+      }
+      pointer64 = (uint64_t *) (tmppointer);
+    }
+  }
+
+  // If there is a last partial subchunk in this buffer, read it part from this buffer and part 
+  // from next buffer if available
+  bitsremaining = (uint64_t) round((nbChunks-int_nbChunks)*bitsPerChunk - cumulatedsize );
+#ifdef DEBUG_BITSPLIT
+    std::cout<<"bitsplit2 bitsremaining (should be <56)="<<bitsremaining<<std::endl;
+#endif
+  if (bitsremaining !=0) 
+  {
+    size_t shift=(64-(bitsread+bitsremaining))/8;
+    bitsread+=(shift<<3);
+    tmppointer = (unsigned char*) pointer64;
+    tmppointer-=shift; 
+    pointer64 = (uint64_t *) (tmppointer);
+    *tmpdata = ((*pointer64)>>bitsread) & ((1ULL<<bitsremaining)-1);
+    // If there is another buffer to deal with, finish the current tmpdata uint64_t 
+    if (bufferIndex < nbrOfBuffers - 1)  
+    {
+      pointer64 = (uint64_t *) inDataBuffers[bufferIndex+1];
+      *tmpdata |= ((*pointer64)<<bitsremaining) & subchunkMasks[subchunkIndex];
+      // We restart bitsread to the bits read in the new buffer
+      bitsread = subchunkSizes[subchunkIndex] - bitsremaining;  
+      subchunkIndex= (subchunkIndex+1 == int_uint64PerChunk ? 0 : subchunkIndex + 1);
+      tmpdata++;
+    }
+  }
+  else
+  {
+    bitsread = 0;
+  }
+}
+
+
+inline void NFLlib::bs_finish(poly64 &outdata, uint64_t int_uint64PerChunk, uint64_t polyNumber, uint64_t* splitData, uint64_t nbrOfBuffers, uint64_t bitsPerBuffer, unsigned int bitsPerChunk)
+{
+  if(int_uint64PerChunk>1) {
+    outdata=(poly64) calloc(polyNumber*nbModuli*polyDegree + 1,sizeof(uint64_t));   
+    internalLongIntegersToCRT( splitData, outdata,   int_uint64PerChunk, ceil(((double)bitsPerBuffer*nbrOfBuffers)/bitsPerChunk));
+    free(splitData);
+  }
+  else 
+  {
+    if (nbModuli > 1)
+    {
+      outdata=(poly64) calloc(polyNumber*nbModuli*polyDegree + 1,sizeof(uint64_t));   
+      for (unsigned i = 0 ; i < polyNumber ; i++)
+      {
+        for (int cm = 0 ; cm < nbModuli ; cm++)
+        {
+          memcpy(outdata + i*polyDegree*nbModuli + cm*polyDegree, 
+              splitData + i*polyDegree, polyDegree*sizeof(uint64_t));
+        }
+      }
+	  free(splitData);
+    }
+    else
+    {
+      outdata=splitData;
+    }
+  }
+}
+
+
+// This function does all the hard work of deserializeDataNFL
+// 1) Converts input into a set of polynomials with arbitrary large coefficients
+// 2) Reduces the polys through CRT to have nbModuli contiguous polys with uint64_t coefficients 
+// Do not try to understand it, it is a nightmare, we won't try to explain it :)
+uint64_t* NFLlib::bitsplitter (unsigned char** inDataBuffers, uint64_t nbrOfBuffers, uint64_t bitsPerBuffer, unsigned int bitsPerChunk)
+{
+  // If you don't need to change me don't try to understand me
+  // If you need to change me, build me again from scratch :)
+
+  // How many uint64_t are needed to encode a chunk
+  const double uint64PerChunk = (double)bitsPerChunk/56;
+  const uint64_t int_uint64PerChunk = ceil(uint64PerChunk);
+  // How many polynomials are needed to encode the data
+  uint64_t polyNumber = 
+    ceil((double)bitsPerBuffer*(double)nbrOfBuffers/(double)(bitsPerChunk*polyDegree));
+  uint64_t* splitData =
+    (uint64_t*)(calloc(polyNumber*polyDegree*int_uint64PerChunk+1,sizeof(uint64_t)));
+  uint64_t* tmpdata=splitData;
+
+  uint64_t bitsread=0;
+  size_t subchunkIndex=0;
+  
+  // Loop over the buffers
+  for (uint64_t h = 0 ; h < nbrOfBuffers ; h++)
+  { 
+    bs_loop (inDataBuffers, nbrOfBuffers, bitsPerBuffer, bitsPerChunk, 
+        tmpdata, h, bitsread, subchunkIndex);
+  }
+ 
+  poly64 outdata;
+
+  bs_finish(outdata, int_uint64PerChunk, polyNumber, splitData, nbrOfBuffers, bitsPerBuffer, bitsPerChunk);
+  
+  return outdata;
+}
+
+
+
+// Subroutine for bitsplitter, the daemonic function. This is the function that allows
+// us to circumvect GMP
+void NFLlib::internalLongIntegersToCRT(uint64_t* tmpdata, poly64 outdata, uint64_t int_uint64PerChunk, uint64_t totalNbChunks) 
+{
+  uint64_t* outdataPtr=outdata;
+  uint64_t* indataPtr=tmpdata;
+  uint64_t multiplier[nbModuli][int_uint64PerChunk];
+
+  uint64_t* chunkParts[int_uint64PerChunk];
+
+  for(int cm=0;cm<nbModuli;cm++) 
+  {
+    multiplier[cm][0]=1;
+    for(unsigned j=1;j<int_uint64PerChunk;j++) 
+    {
+      multiplier[cm][j] = mulmod(multiplier[cm][j-1],1ULL<<56,moduli[cm]);  
+    }
+  }
+
+  for(unsigned i=0;i<totalNbChunks;i++) 
+  {
+    for(unsigned j=0;j<int_uint64PerChunk;j++) 
+    {
+      for(int cm=0;cm<nbModuli;cm++) 
+      {
+      // set to zero before computation if not calloc'd
+      *(outdataPtr+cm*polyDegree) += mulmod(*(indataPtr+j), multiplier[cm][j],moduli[cm]);  
+      }
+    }
+    indataPtr+=int_uint64PerChunk;
+    outdataPtr++;
+    if((i+1)%polyDegree==0) 
+    {
+      outdataPtr += polyDegree*(nbModuli-1);
+    }
+  }    
+}
+
+
+// ****************************************************************************************
+// YOU EXITED THE DEN ALIVE! Either you jumped a lot of lines,
+// or you became completely insane ... in the latter case ...
+// Welcome to the group!
+// ****************************************************************************************

+ 655 - 0
crypto/NFLlib.hpp

@@ -0,0 +1,655 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and  
+ * permission notice:  
+ * 
+ *   Demonstration code for the paper "Faster arithmetic for number-theoretic
+ *   transforms", May 2012
+ *
+ *   Copyright (C) 2014, David Harvey
+ *
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions are met:
+ *
+ *   * Redistributions of source code must retain the above copyright notice, this
+ *     list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright notice,
+ *     this list of conditions and the following disclaimer in the documentation
+ *     and/or other materials provided with the distribution.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ *   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ *   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ *   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ *   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef DEF_NFLlib
+#define DEF_NFLlib
+
+#define SHOUP
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <math.h>
+#include <cstddef>
+#include <gmp.h>
+#include <iostream>
+#include "NFLParams.hpp"
+#include "prng/fastrandombytes.h"
+#include <cstring>
+#include <fstream>
+#include <cassert>
+// SSE/AVX(2) instructions
+#include <immintrin.h>
+#include <x86intrin.h>
+
+	
+using namespace std;
+
+// Polynomials are pointers to arrays of uint64_t coefficients
+typedef uint64_t* poly64;
+
+template <size_t Align, class T>
+static inline T* malloc_align(const size_t n)
+{
+       T* ret;
+       if(posix_memalign((void**) &ret, Align, n*sizeof(T)))
+         std::cout << "NFLlib: WARNING posix_memalign failed" << std::endl;
+       return ret;
+}
+
+template <size_t Align, class T>
+static inline T* malloc_align(const size_t n, T const* const)
+{
+       return malloc_align<Align, T>(n);
+}
+
+template <size_t Align, class T>
+static inline T* calloc_align(const size_t n)
+{
+       T* ret = malloc_align<Align, T>(n);
+       memset(ret, 0, n*sizeof(T));
+       return ret;
+}
+
+template <size_t Align, class T>
+static inline T* calloc_align(const size_t n, T const* const)
+{
+       T* ret = malloc_align<Align, T>(n);
+       memset(ret, 0, n*sizeof(T));
+       return ret;
+}
+
+template <size_t Align, class T, class V>
+static inline T* calloc_align_other(const size_t n)
+{
+       T* ret = malloc_align<Align, T>(n);
+       memset(ret, 0, n*sizeof(V));
+       return ret;
+}
+
+// Number-Theoretic Transform Tools class
+class NFLlib  
+{
+
+  public:
+    // Constructors and initializing functions
+    NFLlib();
+    void configureNTT(); // Only called from setmodulus and setpolyDegree
+
+    // Fundamental setters (result in a call to initializing functions above) 
+    void setmodulus(uint64_t modulus);
+    void setpolyDegree(unsigned int polyDegree);
+    void setNewParameters(unsigned int polyDegree, unsigned int modulusBitsize);
+ 
+    // Getters
+    uint64_t* getmoduli();
+    unsigned int getpolyDegree();
+    unsigned short getnbModuli();
+    void copymoduliProduct(mpz_t dest);
+   
+    // Random polynomial generation functions
+    void setBoundedRandomPoly(poly64 res, uint64_t upperBound_, bool uniform); 
+    poly64 allocBoundedRandomPoly(uint64_t upperBound_, bool uniform);
+
+    // Data import and export main functions
+    poly64* deserializeDataNFL(unsigned char **inArrayOfBuffers, uint64_t nbrOfBuffers, 
+        uint64_t dataBitsizePerBuffer, unsigned bitsPerCoordinate, uint64_t &polyNumber);
+    static void serializeData64 (uint64_t* indata, unsigned char* outdata, 
+        unsigned int bitsPerChunk, uint64_t nb_of_uint64);
+    static void serializeData32 (uint32_t* indata, unsigned char* outdata, unsigned int bitsPerChunk, 
+        uint64_t nb_of_uint32);
+
+    // Helper functions
+    poly64 allocpoly(bool nullpoly);
+    mpz_t* poly2mpz (poly64 p);
+    static void print_poly64(poly64 p, unsigned int coeff_nbr);
+    static void print_poly64hex(poly64 p, unsigned int coeff_nbr);
+
+    // Destructors memory freeing routines
+    ~NFLlib();
+    void freeNTTMemory(); // Only called from configureNTT and ~NFLlib
+    
+    
+    // ****************************************************
+    // Modular and Polynomial computation inlined functions
+    // ****************************************************
+
+    ///////////////////// Operations over uint64_t (polynomial coefficients)
+    // Additions
+    static uint64_t addmod(uint64_t x, uint64_t y, uint64_t p);
+    static uint64_t submod(uint64_t x, uint64_t y, uint64_t p);
+    // Multiplications
+    static uint64_t mulmod(uint64_t x, uint64_t y, uint64_t p);
+    static uint64_t mulmodShoup(uint64_t x, uint64_t y, uint64_t yprime, uint64_t p);
+    // Fused Multiplications-Additions
+    static void mulandadd(uint64_t &rop, uint64_t x, uint64_t y, uint64_t p);
+    static void mulandaddShoup(uint64_t &rop, uint64_t x, uint64_t y, uint64_t yprime, uint64_t p);
+
+    ///////////////////// Operations over polynomials
+    // Additions
+    void addmodPoly(poly64 rop, poly64 op1, poly64 op2);
+    void submodPoly(poly64 rop, poly64 op1, poly64 op2);
+    // Multiplications 
+    void mulmodPolyNTT(poly64 rop, poly64 op1, poly64 op2);
+    void mulmodPolyNTTShoup(poly64 rop, poly64 op1, poly64 op2, poly64 op2prime);
+    // Fused Multiplications-Additions
+    void mulandaddPolyNTT(poly64 rop, poly64 op1, poly64 op2);
+    void mulandaddPolyNTTShoup(poly64 rop, poly64 op1, poly64 op2, poly64 op2prime);
+    
+    // Number-Theoretic Transorm functions
+    static void ntt(uint64_t*  x, const uint64_t*  wtab, const uint64_t*  winvtab, 
+        const unsigned K, const uint64_t p);
+    static void inv_ntt(uint64_t* const x, const uint64_t* const inv_wtab, const uint64_t* const inv_winvtab,
+        const unsigned K, const uint64_t invK, const uint64_t p, const uint64_t* const inv_indexes);
+    static void prep_wtab(uint64_t* wtab, uint64_t* winvtab, uint64_t w, unsigned K, uint64_t p);
+    void nttAndPowPhi(poly64 op);
+    void invnttAndPowInvPhi(poly64);
+    
+    // Pre-computation functions
+    poly64 allocandcomputeShouppoly(poly64 x);
+
+  private: 
+    // Says whether the object has been initialized for the int amount of moduli it is set to
+    unsigned int alreadyInit;
+    // Polynomial attributes
+    uint64_t *moduli;
+    unsigned short nbModuli;
+    unsigned int polyDegree;
+    // Chinese Remainder Theorem (CRT) and Inverse CRT related attributes
+    mpz_t *liftingIntegers;
+    mpz_t moduliProduct;
+    
+    // NTT and inversse NTT related attributes
+    // omega**i values (omega = polydegree-th primitive root of unity), and their inverses
+    // phi**i values (phi = square root of omega), and their inverses multiplied by a constant
+    // Shoup variables contain redundant data to speed up the process
+    // NOTE : omega and derived values are ordered following David Harvey's algorithm
+    // w**0 w**1 ... w**(polyDegree/2) w**0 w**2 ... w**(polyDegree/2) w**0 w**4 ...
+    // w**(polyDegree/2) etc. (polyDegree values)
+    uint64_t **phis, **shoupphis, **invpoly_times_invphis, 
+             **shoupinvpoly_times_invphis, **omegas, 
+             **shoupomegas, **invomegas, **shoupinvomegas, *invpolyDegree;
+    uint64_t* inv_indexes;
+
+    // WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
+    // ENTERING THE DEN... Internal functions you should never read and we will never comment
+    uint64_t* bitsplitter (unsigned char** inDataBuffers, uint64_t nbrOfBuffers, 
+        uint64_t bitsPerBuffer, unsigned int bitsPerChunk);
+    void internalLongIntegersToCRT(uint64_t* tmpdata, poly64 outdata, uint64_t int_uint64PerChunk,
+        uint64_t totalNbChunks) ;
+    void bs_finish(poly64 &outdata, uint64_t int_uint64PerChunk, uint64_t polyNumber, 
+        uint64_t *splitData, uint64_t nbrOfBuffers, uint64_t bitsPerBuffer, unsigned int bitsPerChunk);
+    void bs_loop (unsigned char** inDataBuffers, uint64_t nbrOfBuffers, 
+        uint64_t bitsPerBuffer, unsigned int bitsPerChunk, uint64_t *&tmpdata, 
+        uint64_t bufferIndex, uint64_t &bitsread, size_t &subchunkIndex);
+    uint64_t* bitsplitter_backtoback_internal_test (unsigned char** inDataBuffers, 
+        uint64_t nbrOfBuffers, uint64_t bitsPerBuffer, unsigned int bitsPerChunk, 
+        uint64_t totalbitsread,uint64_t bitsread, uint64_t* pointer64, unsigned int bitsToRead);
+    // END OF THE DEN
+};
+
+
+// We hate C++ inlining
+// These function sources were included here to force inlining
+//
+/* WARNING: For performance, our modular functions often do not do a complete modular reduction.
+ * For example when adding two integers x, y modulo an integer p we do not check if they are
+ * larger than p or not and only subtract to the result at most p. This is noted x + y lazymod p
+ * in our comments. Applications using our functions should ensure that no overflow is possible given
+ * our implementation. This is dangerous and a bad programming habit but mandatory for high
+ * performance.
+ * */
+
+
+// *********************************************************
+//     Operations over uint64_t (polynomial coefficients)
+// *********************************************************
+
+// Modular addition plain and simple : add then test if sum is superior 
+// to the modulus in which case substract the modulus to the sum
+// ASSUMPTION: x + y < 2**64
+// OUTPUT: x + y lazymod p
+inline uint64_t NFLlib::addmod(uint64_t x, uint64_t y, uint64_t p)
+{
+    uint64_t z = x + y;
+    return z -= ((z >= p) ? p : 0);
+}
+
+
+// Modular subtract trick: if y is smaller than p return x+p-y else return x+p-(y%p)
+// OUTPUT: x - y lazymod p
+inline uint64_t NFLlib::submod(uint64_t x, uint64_t y, uint64_t p)
+{
+    return (y < p) ? addmod(x, p-y, p) : addmod(x, p - (y % p), p);
+}
+
+
+// Modular multiplication: trivial (and very costly) approach with complete reduction
+// OUTPUT: x * y mod p
+inline uint64_t NFLlib::mulmod(uint64_t x, uint64_t y, uint64_t p)
+{
+  return (uint128_t) x * y % p;
+}
+
+
+// Modular multiplication: much faster alternative
+// Works only if yprime = ((uint128_t) y << 64) / p has been pre-computed
+// ASSUMPTION: p is at most 62 bits
+// OUTPUT: x * y lazymod p (if x and y are below p the result is x * y mod p)
+inline uint64_t NFLlib::mulmodShoup(uint64_t x, uint64_t y, uint64_t yprime, uint64_t p)
+{
+  uint128_t res;
+  uint64_t q = ((uint128_t) x * yprime) >> 64;
+  res = x * y - q * p;
+  res -= ((res>=p) ? p : 0);
+  return res;  
+}
+
+
+// Fused Multiply and Addition (FMA) : trivial approach
+inline void NFLlib::mulandadd(uint64_t& rop, uint64_t x, uint64_t y, uint64_t p)
+{
+  rop = (((uint128_t) (x) * y) + rop) % p; 
+}
+
+
+// Fused Multiply and Addition (FMA) : Shoup's precomputed approach again
+// Works only if yprime = ((uint128_t) y << 64) / p has been pre-computed
+// ASSUMPTION: p is at most 62 bits
+// OUTPUT: x * y lazymod p (if x and y are below p the result is below 2p)
+inline void NFLlib::mulandaddShoup(uint64_t& rop, const uint64_t x, const uint64_t y, const uint64_t yprime, const uint64_t p)
+{
+  //mulandadd(rop, x, y, p);
+#ifdef DEBUG  
+  // This must be before the real computation modifies rop
+  uint128_t res = ((uint128_t) x * y + rop) % p;
+#endif  
+  uint64_t q = ((uint128_t) x * yprime) >> 64;
+  rop += x * y - q * p;
+  rop -= ((rop>=p) ? p : 0);
+#ifdef DEBUG  
+  // And this must be after the modification of rop
+  if((res%p)!=(rop%p))
+  {
+    std::cout<<"NFLlib: CRITICAL Shoup multiplication failed (prob. orig. precomputation or bounds)"<<std::endl;
+    exit(1);
+  }
+#endif      
+}
+
+
+
+
+// *********************************************************
+//     Operations over polynomials
+// *********************************************************
+
+// Apply addmod to all the coefficients of a polynomial
+inline void NFLlib::addmodPoly(poly64 rop, poly64 op1,poly64 op2) {
+  for(unsigned short currentModulus=0;currentModulus<nbModuli;currentModulus++) 
+  {
+    for(unsigned i=0;i<polyDegree;i++)
+    {
+      rop[i]=addmod(op1[i],op2[i],moduli[currentModulus]);
+    }
+    rop+=polyDegree;
+    op1+=polyDegree;
+    op2+=polyDegree;
+  }
+}
+
+
+// Apply submod to all the coefficients of a polynomial
+inline void NFLlib::submodPoly(poly64 rop, poly64 op1,poly64 op2) {
+  for(unsigned short currentModulus=0;currentModulus<nbModuli;currentModulus++) 
+  {
+    for(unsigned i=0;i<polyDegree;i++)
+    {
+      rop[i]=submod(op1[i],op2[i],moduli[currentModulus]);
+    }
+    rop+=polyDegree;
+    op1+=polyDegree;
+    op2+=polyDegree;
+  }
+}
+
+
+// Apply mulmod to all the coefficients of a polynomial
+// This is a polynomial multiplication mod X**n+1 iff the operands
+// have been processed through nttAndPowPhi
+inline void NFLlib::mulmodPolyNTT(poly64 rop, poly64 op1, poly64 op2)
+{
+  for(unsigned short currentModulus=0;currentModulus<nbModuli;currentModulus++) {  
+    for (unsigned i = 0 ; i < polyDegree ;i++)
+    {
+      rop[i] = mulmod(op1[i],op2[i],moduli[currentModulus]);
+    }
+    rop+=polyDegree;
+    op1+=polyDegree;
+    op2+=polyDegree;
+  }
+}
+
+
+// Apply mulmodShoup to all the coefficients of a polynomial (much faster)
+// This is a polynomial multiplication mod X**n+1 iff the operands
+// have been processed through nttAndPowPhi
+// op2prime must be a polynomial with op2 coefficients converted with Shoup's precomputation
+inline void NFLlib::mulmodPolyNTTShoup(poly64 rop, poly64 op1,poly64 op2,poly64 op2prime)
+{
+  for(unsigned short currentModulus=0;currentModulus<nbModuli;currentModulus++) {
+    //#pragma omp parallel for
+    for (unsigned i = 0 ; i < polyDegree ;i++) {
+      rop[i] = mulmodShoup(op1[i],op2[i],op2prime[i],moduli[currentModulus]);
+    }
+    rop+=polyDegree;
+    op1+=polyDegree;
+    op2+=polyDegree;
+    op2prime+=polyDegree;
+  }
+}
+
+
+// Same as mulmodPolyNTT but with fused multiplication and addition
+inline void NFLlib::mulandaddPolyNTT(poly64 rop, poly64 op1,poly64 op2)
+{
+  for(unsigned short currentModulus=0;currentModulus<nbModuli;currentModulus++) {  
+    for (unsigned i = 0 ; i < polyDegree ;i++)
+    {
+      mulandadd(rop[i],op1[i],op2[i],moduli[currentModulus]);
+    }
+    rop+=polyDegree;
+    op1+=polyDegree;
+    op2+=polyDegree;
+  }
+}
+
+
+// Same as mulmodPolyNTTShoup but with fused multiplication and addition
+inline void NFLlib::mulandaddPolyNTTShoup(poly64 rop, poly64 op1,poly64 op2,poly64 op2prime)
+{
+  for(unsigned short currentModulus=0;currentModulus<nbModuli;currentModulus++) {
+  //#pragma omp parallel for
+    for (unsigned i = 0 ; i < polyDegree ;i++) {
+      mulandaddShoup(rop[i],op1[i],op2[i],op2prime[i],moduli[currentModulus]);
+    }
+    rop+=polyDegree;
+    op1+=polyDegree;
+    op2+=polyDegree;
+    op2prime+=polyDegree;
+  }
+}
+
+
+
+
+// *********************************************************
+//     Number-Theoretic Functions
+// *********************************************************
+
+// *****************************************************************
+// NTT functions from David Harvey 
+// From : http://web.maths.unsw.edu.au/~davidharvey/papers/fastntt/
+// Most of the functions have been modified for our needs
+// The associated copyright notice is at the beginning of this file
+// *****************************************************************
+
+
+// Number-Theoretic Transform: replaces a coefficient representation of a polynomial
+// by the values of the polynomial on a set of points. Allows to do coefficient wise 
+// multiplication of polynomials instead of the usual convolution product
+// - x points to the polynomial to which we will apply the NTT
+// - wtab is a pre-computed table with the powers of a root of unity
+// - winvtab is another pre-computed table with the powers of the inverse of a root of unity
+// - K is the log_2 of the degree of the polynomial
+// - p is the modulus coefficient operations are done with
+// The NTT is computed in-place on x, so x is the output
+inline void NFLlib::ntt(uint64_t* x, const uint64_t* wtab, const uint64_t* winvtab,
+    const unsigned K, const uint64_t p)
+{
+  if (K == 1)
+    return;
+
+  // special case
+  if (K == 2)
+  {
+    uint64_t u0 = x[0];
+    uint64_t u1 = x[1];
+    uint64_t t0 = u0 + u1;
+    uint64_t t1 = u0 - u1;
+    t0 -= (t0 >= 2*p) ? (2*p) : 0;
+    t1 += ((int64_t) t1 < 0) ? (2*p) : 0;
+    x[0] = t0;
+    x[1] = t1;
+    return;
+  }
+
+  size_t N0 = K;           // size of block
+  //size_t M0 = 1;                         // number of blocks
+
+  // log2(N)-2
+  const int J = _bit_scan_reverse(K)-2;
+  for (int w = 0; w < J; w++) {
+	const size_t M = 1 << w; 
+	const size_t N = N0 >> w;
+//#pragma omp parallel for schedule(static) num_threads(4)
+	for (size_t r = 0; r < M; r++) {
+		for (size_t i = 0; i < N/2; i++) {
+			uint64_t u0 = x[N * r + i];
+			uint64_t u1 = x[N * r + i + N/2];
+
+			uint64_t t0 = u0 + u1;
+			t0 -= ((t0 >= 2*p) ? (2*p) : 0);
+
+			uint64_t t1 = u0 - u1 + 2*p;
+
+			uint64_t q = ((uint128_t) t1 * winvtab[i]) >> 64;
+			uint64_t t2 = t1 * wtab[i] - q * p;
+
+			x[N * r + i] = t0;
+			x[N * r + i + N/2] = t2;
+		}
+	}
+    wtab += N/2;
+    winvtab += N/2;
+  }
+
+  const size_t M = 1 << J;
+  // last two layers
+  for (size_t r = 0; r < M; r++, x += 4)
+  {
+    uint64_t u0 = x[0];
+    uint64_t u1 = x[1];
+    uint64_t u2 = x[2];
+    uint64_t u3 = x[3];
+
+    uint64_t v0 = u0 + u2;
+    v0 -= (v0 >= 2*p) ? (2*p) : 0;
+    uint64_t v2 = u0 - u2;
+    v2 += ((int64_t) v2 < 0) ? (2*p) : 0;
+
+    uint64_t v1 = u1 + u3;
+    v1 -= (v1 >= 2*p) ? (2*p) : 0;
+    uint64_t t = u1 - u3 + 2*p;
+
+    uint64_t q = ((uint128_t) t * winvtab[1]) >> 64;
+    uint64_t v3 = t * wtab[1] - q * p;
+
+    uint64_t z0 = v0 + v1;
+    z0 -= (z0 >= 2*p) ? (2*p) : 0;
+    uint64_t z1 = v0 - v1;
+    z1 += ((int64_t) z1 < 0) ? (2*p) : 0;
+
+    uint64_t z2 = v2 + v3;
+    z2 -= (z2 >= 2*p) ? (2*p) : 0;
+    uint64_t z3 = v2 - v3;
+    z3 += ((int64_t) z3 < 0) ? (2*p) : 0;
+
+    x[0] = z0 ;
+    x[1] = z1 ;
+    x[2] = z2 ;
+    x[3] = z3 ;
+  }
+
+}
+
+inline static void permut(uint64_t* const y, uint64_t const* const x, uint64_t const* const inv_indexes, size_t K)
+{
+  for (size_t i = 0; i < K; i += 1)
+  {
+    y[inv_indexes[i]] = x[i];
+  }
+}
+
+// Inverse NTT: replaces values representation by the classic coefficient representation
+inline void NFLlib::inv_ntt(uint64_t* const x, const uint64_t* const inv_wtab, const uint64_t* const inv_winvtab,
+        const unsigned K, const uint64_t invK, const uint64_t p, const uint64_t* const inv_indexes)
+{
+	// Do we need to align on 32 ?
+  uint64_t* y = calloc_align<16, uint64_t>(K+1);
+
+  if (K == 1)
+    return;
+
+  // bit-reverse
+  permut(y, x, inv_indexes, K);
+
+  ntt(y, inv_wtab, inv_winvtab, K, p);
+
+  // bit-reverse again
+  permut(x, y, inv_indexes, K);
+  
+  free(y);
+}
+
+
+// This function just computes the powers of the root of unity and its inverse
+// It is included here just to have all the NTT functions together
+inline void NFLlib::prep_wtab(uint64_t* wtab, uint64_t* wtabshoup, uint64_t w, unsigned K, uint64_t p)
+{
+
+  while (K >= 2)
+  {
+    uint64_t wi = 1;     // w^i
+    for (size_t i = 0; i < K/2; i++)
+    {
+      *wtab++ = wi;
+      *wtabshoup++ = ((uint128_t) wi << 64) / p;
+      wi = mulmod(wi, w, p);
+    }
+    w = mulmod(w, w, p);
+    K /= 2;
+  }
+}
+// *****************************************************************
+// END OF NTT functions from David Harvey 
+// From : http://web.maths.unsw.edu.au/~davidharvey/papers/fastntt/
+// Most of the functions have been modified for our needs
+// The associated copyright notice is at the beginning of this file
+// *****************************************************************
+
+
+// In order to have polynomial operations mod X**n + 1 as we want
+// we must multiply the polynomial coefficients by phi powers before doing the NTT
+inline void NFLlib::nttAndPowPhi(poly64 op) 
+{
+  for (unsigned int cm = 0 ; cm < nbModuli ; cm++)
+  {
+    for (unsigned int i = 0; i < polyDegree; i++)
+    {
+      op[i] = mulmodShoup(op[i], phis[cm][i], shoupphis[cm][i], moduli[cm]);
+    }
+    ntt(op, omegas[cm], shoupomegas[cm], polyDegree, moduli[cm]);
+    op+=polyDegree;
+  }
+}
+
+
+// In order to have polynomial operations mod X**n + 1 as we want
+// we must multiply the polynomial coefficients by invphi powers before doing the inverse-NTT
+inline void NFLlib::invnttAndPowInvPhi(poly64 op) 
+{
+  for(unsigned short currentModulus=0;currentModulus<nbModuli;currentModulus++) 
+  {
+    inv_ntt(op, invomegas[currentModulus], shoupinvomegas[currentModulus], 
+        polyDegree, invpolyDegree[currentModulus] , moduli[currentModulus], inv_indexes);
+    for (unsigned int i = 0; i < polyDegree; i++)
+    {
+      op[i] = mulmodShoup(op[i], invpoly_times_invphis[currentModulus][i],
+          shoupinvpoly_times_invphis[currentModulus][i], moduli[currentModulus]);
+    }
+    op+=polyDegree;
+  }
+}
+
+
+
+
+// *********************************************************
+// Pre-computation functions
+// *********************************************************
+
+// Pre-compute quotients for Shoup's multiplication for all the coefficients of a polynomial
+inline poly64 NFLlib::allocandcomputeShouppoly(poly64 x)
+{
+  poly64 res = (poly64) malloc(polyDegree*nbModuli*sizeof(uint64_t));
+  poly64 res_orig = res;
+  for (unsigned short currentModulus = 0; currentModulus < nbModuli ; currentModulus++)
+  {
+    for (unsigned int i = 0; i < polyDegree; i++)
+    {
+      res[i] = ((uint128_t) x[i] << 64) / moduli[currentModulus];
+    }
+    res+=polyDegree;
+    x+=polyDegree;
+  }
+  return res_orig;
+}
+
+
+// All the other functions are in the cpp file. A more carefull study should be done to see what needs inlining and what not.
+
+#endif

+ 88 - 0
crypto/NoCryptography.cpp

@@ -0,0 +1,88 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "NoCryptography.hpp"
+
+ 
+NoCryptography::NoCryptography(): 
+  HomomorphicCrypto("NoCryptography")
+{}
+
+NoCryptography::NoCryptography(const std::string& crypto_name):
+  HomomorphicCrypto(crypto_name)
+{}
+
+AbstractPublicParameters& NoCryptography::getPublicParameters(){ return publicParams; } 
+
+unsigned int NoCryptography::getAllCryptoParams(std::set<std::string>& crypto_params_set) 
+{ 
+  crypto_params_set.insert(std::string("NoCryptography"));
+  return 1; 
+}
+
+void NoCryptography::setNewParameters(const std::string& crypto_param) {}
+std::string& NoCryptography::toString() { return cryptoName; }
+
+char* NoCryptography::encrypt(unsigned int ui, unsigned int d )
+{ 
+  char* charptr = (char *) malloc(sizeof(char)); 
+  *charptr =  (char) ui;
+  return charptr; 
+}
+
+char* NoCryptography::encrypt(char* data, size_t lkjlkj, unsigned int exponent ) 
+{
+  unsigned int ciphBytesize = publicParams.getCiphertextBitsize()/8;
+  char* encrypted_data = (char *) malloc(ciphBytesize);
+  memcpy(encrypted_data, data, ciphBytesize);
+  return encrypted_data;
+}
+
+char* NoCryptography::encrypt_perftest()
+{
+  return encrypt(1,1);
+}
+
+char* NoCryptography::decrypt(char* cipheredData, unsigned int rec_lvl, size_t, size_t)
+{
+  unsigned int clearBytesize = publicParams.getAbsorptionBitsize()/8;
+  char* clear_data = (char *) malloc(clearBytesize);
+  memcpy(clear_data, cipheredData, clearBytesize);
+  return clear_data;
+}
+
+unsigned int NoCryptography::getCryptoParams(unsigned int k, std::set<std::string>& crypto_params)
+{
+  crypto_params.insert(std::string("NoCryptography"));
+  return 1; 
+}
+
+long NoCryptography::setandgetAbsBitPerCiphertext(unsigned int elt_nbr)
+{
+  return 8*1024;
+}
+
+std::string NoCryptography::getSerializedCryptoParams(bool shortversion)
+{
+  return cryptoName;
+}
+
+double NoCryptography::estimateAbsTime(std::string crypto_param){
+  return 1;
+}
+//NoCryptography::~NoCryptography() {}
+

+ 52 - 0
crypto/NoCryptography.hpp

@@ -0,0 +1,52 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_NOCRYPTOGRAPHY
+#define DEF_NOCRYPTOGRAPHY
+
+#include "../pir/PIRParameters.hpp"
+#include "HomomorphicCrypto.hpp"
+#include "NoCryptographyPublicParameters.hpp"
+#include "AbstractPublicParameters.hpp"
+
+
+class NoCryptography : public HomomorphicCrypto 
+{
+  public:
+    NoCryptography();
+    NoCryptography(const std::string& crypto_name);
+    AbstractPublicParameters& getPublicParameters(); 
+    unsigned int getAllCryptoParams(std::set<std::string>& crypto_params_set);
+    void setNewParameters(const std::string& crypto_param);
+    std::string& toString();
+    PIRParameters* pirParam;
+    NoCryptographyPublicParameters publicParams;
+    static unsigned int default_security_bits;
+    
+    char* encrypt(unsigned int ui, unsigned int );
+    char* encrypt(char* data, size_t, unsigned int exponent );
+    char* encrypt_perftest();
+    char* decrypt(char* cipheredData, unsigned int rec_lvl, size_t, size_t);
+    
+    unsigned int getCryptoParams(unsigned int k, std::set<std::string>& crypto_params);
+    long setandgetAbsBitPerCiphertext(unsigned int elt_nbr);
+    std::string getSerializedCryptoParams(bool shortversion=true);
+    double estimateAbsTime(std::string crypto_param);
+    
+};
+
+#endif

+ 40 - 0
crypto/NoCryptographyPublicParameters.cpp

@@ -0,0 +1,40 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "NoCryptographyPublicParameters.hpp"
+
+using namespace std;
+
+NoCryptographyPublicParameters::NoCryptographyPublicParameters()
+{
+    cryptoName = "NoCryptography";
+}
+
+
+string NoCryptographyPublicParameters::getSerializedParams(bool shortversion) { return string("NoCryptography"); }
+char* NoCryptographyPublicParameters::getByteModulus() { return (char*) malloc(1); }
+unsigned int NoCryptographyPublicParameters::getAbsorptionBitsize(){ return 8*1024; }
+unsigned int NoCryptographyPublicParameters::getAbsorptionBitsize(unsigned int rec_lvl){ return 8*1024; }
+void NoCryptographyPublicParameters::setModulus(char* rawPubKey){}
+void NoCryptographyPublicParameters::setMockedPubKey(){}
+unsigned int NoCryptographyPublicParameters::getCiphertextBitsize(){ return 8*1024; }
+unsigned int NoCryptographyPublicParameters::getCiphBitsizeFromRecLvl(unsigned int){ return 8*1024; }
+unsigned int NoCryptographyPublicParameters::getQuerySizeFromRecLvl(unsigned int){ return 64;}//64 bits as an uint64_t
+void NoCryptographyPublicParameters::computeNewParameters(const std::string& crypto_param_descriptor){}
+unsigned int NoCryptographyPublicParameters::getSerializedModulusBitsize(){ return 0;}
+
+

+ 45 - 0
crypto/NoCryptographyPublicParameters.hpp

@@ -0,0 +1,45 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_NOCRYPTOGRAPHYPUBLICPARAMETERS
+#define DEF_NOCRYPTOGRAPHYPUBLICPARAMETERS
+#include <string>
+#include <vector>
+
+#include <boost/algorithm/string.hpp>
+#include "AbstractPublicParameters.hpp"
+
+class NoCryptographyPublicParameters : public AbstractPublicParameters {
+  protected:
+    std::string cryptoName;
+
+  public:
+    NoCryptographyPublicParameters();
+    std::string getSerializedParams(bool shortversion);
+    char* getByteModulus();
+    unsigned int getAbsorptionBitsize();
+    unsigned int getAbsorptionBitsize(unsigned int rec_lvl);
+    void setModulus(char* rawPubKey);
+    void setMockedPubKey();
+    unsigned int getCiphertextBitsize();
+    unsigned int getCiphBitsizeFromRecLvl(unsigned int);
+    unsigned int getQuerySizeFromRecLvl(unsigned int);
+    void computeNewParameters(const std::string& crypto_param_descriptor);
+    unsigned int getSerializedModulusBitsize();
+};
+
+#endif

+ 27 - 0
crypto/PRNGInterface.hpp

@@ -0,0 +1,27 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_PRNGINTERFACE
+#define DEF_PRNGINTERFACE
+
+// A simple PRNG interface
+class PRNGInterface {
+ public:
+  // Return x drawn uniformly from [-bound, bound].
+  virtual int AbsBoundedUniform(const int bound) = 0;
+};
+#endif

+ 630 - 0
crypto/PaillierAdapter.cpp

@@ -0,0 +1,630 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "PaillierAdapter.hpp"
+#include <set>
+#include <iostream>
+namespace {
+const int kMagicConstant1 = 1;
+const int kMillion = 1000000;
+}
+
+/**
+ * Static fonction to feet approximately standards. NIST SP800-57 table 2 page 64
+ * Beyond 128 bits of security modules will not be used as getCryptoParams blocks when ciphertext modulus is above 10K bits.
+ **/
+unsigned int PaillierAdapter::securityToModulus(int security_bits) 
+{
+  if(security_bits <= 40)
+    return 128;
+  if (security_bits <= 80)
+    return 1024;
+  if (security_bits <= 112)
+    return 2048;
+  if (security_bits <= 128)
+    return 3072;
+  if (security_bits <= 192)
+    return 7680;
+  // Unimplemented
+  //return 15360;
+  return 0;
+}
+
+PaillierAdapter::PaillierAdapter() :
+  HomomorphicCrypto("Paillier")
+{
+  initRandomGenerator();
+}
+
+/**
+ *	PaillierAdapter constructor
+ * 	Params:
+ * 		- int security_bits : number of security bit wanted (size of the cipher space);
+ * 		- int recLvl				: number of recursion level.
+ **/
+PaillierAdapter::PaillierAdapter(int _security_bits, int init_s ) : 
+  HomomorphicCrypto("Paillier"),
+  security_bits(_security_bits),
+  privateParameters(),
+  modulusbits(securityToModulus(_security_bits)),
+  publicParameters()
+{
+  initRandomGenerator();
+  publicParameters.setModulusbits(modulusbits);
+
+  keygen(
+      modulusbits,
+      publicParameters.getPubKey(),
+      privateParameters.getPrvKey(),
+      init_s );
+}
+
+void PaillierAdapter::initRandomGenerator()
+{
+  mpz_t s;
+  mpz_init(s);
+
+  gmp_randinit_default(rand);
+  // Get a 1024 bit seed from /dev/urandom
+  getRandFromfile( 128 , &s);
+  gmp_randseed(rand, s);
+
+  mpz_clear(s);
+
+}
+
+/**
+ *	Encrypt an unsigned int and return the encrypted bytes in char*
+ *	Params :
+ *		- unsigned int ui : the value to encrypt ;
+ *		- unsigned int s  : the exponent (recursion lvl).
+ *
+ *	Return :
+ *		- char* : an allocated pointer to the encrypted data.
+ **/
+  char* 
+PaillierAdapter::encrypt(unsigned int ui, unsigned int s) 
+{
+  unsigned int ciph_size = publicParameters.getKeyBitsize()*(s+1)/8;
+  char *tmp, *request = (char*) calloc((ciph_size + 1), sizeof(char));
+  size_t n;
+  mpz_t pt, ct;
+
+  mpz_init(ct);
+  mpz_init_set_ui( pt, ui); // convert the 0 or the 1 to an mpz_t
+
+  enc( this->publicParameters.getPubKey(), pt, s, ct );
+#ifdef CRYPTO_DEBUG
+  gmp_printf("Created query element: %Zd with args %Zd and %d\n",ct, pt, s);
+#endif
+  tmp = (char*)mpz_export(NULL, &n, 1, sizeof(char), 0, 0, ct);
+  //Padding
+  memcpy(request+sizeof(char)*((ciph_size) - n), tmp, n);	
+
+  //Free memory
+  mpz_clears(ct, pt, NULL);
+
+  free(tmp);
+
+  return request;
+}
+
+// To test decryption performance
+char* PaillierAdapter::encrypt_perftest()
+{
+	return encrypt(1,1);// Decryption performance test work well with this small plaintext
+}
+
+/**
+ *	Encrypt an char* of size dataSize and return char*
+ *	Params :
+ *		- char* data 				: data to encrypt ;
+ *		- size_t dataSize 	: size of the data ;
+ *		- unsigned exponent : the exponent (recursion lvl).
+ *	Return :
+ *		- char* : an allocated pointer to the encrypted data.
+ **/
+char* PaillierAdapter::encrypt(char* data, size_t dataSize,  unsigned int exponent) 
+{
+  char* request;
+  mpz_t ct, imported_data;
+
+  mpz_inits(ct, imported_data, NULL);
+
+  mpz_import(imported_data, dataSize, 1, sizeof(char), 0, 0, data);
+
+  enc( this->publicParameters.getPubKey(),
+      imported_data,
+      exponent,
+      ct );
+
+  request = (char*)mpz_export(NULL, NULL, 1, sizeof(char) , 0, 0, ct);
+
+  mpz_clears(ct, imported_data, NULL);
+
+  return request;
+}
+
+/**
+ *	Decrypt reply sended by the server and return clear bytes in char*.
+ *	Params :
+ * 		- char* cipheredData 	 : encrypted data ;
+ * 		- unsigned int exp_fac : the exponent (recursion lvl) ;
+ * 		- size_t ciph_size		 : size of encrypted data ;
+ * 		- size_t clear_size		 : size of decrypted data to return.
+ * 		Return :
+ * 		- char* : an allocated pointer to the decrypted data.
+ **/
+char* PaillierAdapter::decrypt( char* cipheredData, 
+    unsigned int exp_fac, 
+    size_t ciph_size , 
+    size_t clear_size) 
+{
+  size_t n = 0; 
+  mpz_t ct, res;
+  char* tmp;
+  mpz_inits(ct, res, NULL);
+
+  mpz_import(ct, ciph_size, 1, sizeof(char), 0, 0, cipheredData);
+
+  dec(publicParameters.getPubKey(),
+      privateParameters.getPrvKey(),
+      ct, 
+      exp_fac,
+      res );
+
+#ifdef DEBUG_ENCRYPT
+  gmp_printf("PaillierAdapter : Decrypting %Zd into %Zd\n\n", ct, res);
+#endif
+
+  tmp = (char*) mpz_export(NULL, &n, 1, sizeof(char) , 0, 0, res);
+  
+  mpz_clears(res, ct, NULL); //clear content of mpz_t, t
+
+  if( n < clear_size)
+  {
+    char *pt = (char*)calloc(clear_size+1, sizeof(char)); 
+    memcpy(pt+sizeof(char)*((clear_size) - n), tmp, n);
+    free(tmp); // malloc'd
+    return pt;
+  }
+  else
+  {
+    return tmp;
+  }
+}
+
+
+PaillierAdapter::~PaillierAdapter() 
+{
+  gmp_randclear(rand);
+}
+
+AbstractPublicParameters& PaillierAdapter::getPublicParameters() 
+{
+  return publicParameters;
+}
+
+/**
+ *	Private encrypt methode.
+ *	Params :
+ *		- paillier_pubkey* pub : Paillier public key pointer ;
+ *		- mpz_t m	: data to encrypt ;
+ *		- unsigned int s : recursion level ;
+ *		- mpz_t c				 : result operande .
+ **/
+  void 
+PaillierAdapter::enc( paillier_pubkey* pub,
+    mpz_t m,
+    unsigned int s,
+    mpz_t c )
+{
+  mpz_t gm, rns, r;
+  mpz_inits( gm, rns, r, NULL);
+  unsigned int modulusbits = publicParameters.getKeyBitsize();
+  do
+  {
+    mpz_urandomb(r, rand, (s+1)*modulusbits); 
+  } while( mpz_cmp(r, *pub->getnj(s+1)) >= 0 );
+  
+  mpz_powm(gm, *pub->getg(), m,  *pub->getnj(s+1));
+  mpz_powm(rns, r, *pub->getnj(s), *pub->getnj(s+1));
+  mpz_mul(c, gm, rns);
+  mpz_mod(c,c, *pub->getnj(s+1));
+
+#ifdef DEBUG_ENCRYPT
+  mpz_t test;
+  mpz_init(test);
+  dec(pub, privateParameters.getPrvKey(), c, s, test); 
+  gmp_printf("Decrypting %Zd into %Zd\n\n", c, test);
+#endif
+
+  mpz_clears(gm, rns, r, NULL);
+}
+
+/**
+ *	Reimplemented version of decrypt to not use paillier structures. 
+ *	Params:
+ *		- paillier_prvkey* prv : Paillier private key pointer ;
+ *		- mpz_t c : encrypted data ;
+ *		- unsigned int s : recursion level ;
+ *		- mpz_t i : result operande .
+ *  This function is an exact copy of the one in libdj
+ **/
+/*
+	libdj - A library implementing the Damgård-Jurik cryptosystem.
+
+	Copyright 2012 Fred Douglas (fed2@illinois.edu)
+	This library is an extension/modification of libpaillier.
+	libpaillier is copyright 2006 SRI International (written by John Bethencourt).
+
+	This file is part of libdj.
+
+    libdj is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    libdj is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with libdj.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+  void 
+PaillierAdapter::dec( paillier_pubkey* pub,
+    paillier_prvkey* prv,
+    mpz_t c, 
+    unsigned int s,
+    mpz_t res)
+{
+	int i,j,k;
+	mpz_t cprime, temp, tempDivisor, i_jCur, i_jPrev;
+
+	mpz_init(cprime);
+	
+	//cprime = c^key mod n^{s+1}
+	mpz_powm(cprime,c,prv->d,*pub->getnj(s+1));
+	
+	
+	
+	//the algorithm from extracting i from (1+n)^i described in the paper.
+	
+	//the algorithm iteratively extracts i mod n, i mod n^2, etc. i mod n starts us off, and is just input - 1 / n.
+	mpz_init(temp);
+	mpz_init(tempDivisor);
+	mpz_init(i_jCur);
+	mpz_init_set(i_jPrev,cprime);
+	mpz_sub_ui(i_jPrev,i_jPrev,1);
+	mpz_divexact(i_jPrev,i_jPrev,*pub->getnj(1));
+	mpz_mod(i_jPrev,i_jPrev,*pub->getnj(2));
+	
+	//just in case s=1; in that case we need this line to actually set i_jcur
+	if(s==1)
+		mpz_set(i_jCur,i_jPrev);
+	
+	//extract i_j = i mod n^j given i_{j-1}. this is done by taking (input - 1 mod n^{j+1}) / n , and subtracting
+	//from that: ((  (i_{j-1} choose 2)*n  + (i_{j-1} choose 3)*n^2  + ... +  (i_{j-1} choose j)*n^{j-1}  ))   mod n^j
+	for(j=2;j<=s;j++)
+	{
+		//L((1+n)^i) as they call it 
+		mpz_mod(i_jCur,cprime,*pub->getnj(j+1));
+		mpz_sub_ui(i_jCur,i_jCur,1);
+		mpz_divexact(i_jCur,i_jCur,*pub->getnj(1));
+		
+		mpz_mod(i_jCur,i_jCur,*pub->getnj(j));
+		
+		//subtract each of the binomial things
+		for(k=2;k<=j;k++)
+		{
+			mpz_bin_ui(temp,i_jPrev,k);
+			mpz_mul(temp,temp,*pub->getnj(k-1));
+			mpz_mod(temp,temp,*pub->getnj(j));
+			mpz_sub(i_jCur,i_jCur,temp);
+			mpz_mod(i_jCur,i_jCur,*pub->getnj(j));
+		}
+		mpz_set(i_jPrev,i_jCur);
+	}
+	
+	//i_jCur is currently the message times the private key.
+	mpz_invert(temp, prv->d, *pub->getnj(s));
+	mpz_mul(res, i_jCur, temp);
+	mpz_mod(res, res, *pub->getnj(s));
+	
+	//cleanup and return
+	mpz_clear(cprime);
+	mpz_clear(i_jPrev);
+	mpz_clear(i_jCur);
+	mpz_clear(temp);
+	mpz_clear(tempDivisor);
+	
+
+  //  unsigned int kfac, k;
+//  mpz_t t1, t2, t3, a, id ;
+//  std::cout << "dec called with s="<<s<<std::endl;
+//  mpz_inits(t1, t2, t3, a, NULL);
+//  mpz_init_set_ui(id,  0);
+//
+//  mpz_powm(a, c, prv->d, *pub->getnj(s+1));
+//
+//  for(unsigned int j = 1 ; j <= s; j++)
+//  {
+//    mpz_set(t1, a);
+//    mpz_mod(t1, t1, *pub->getnj(j+1));
+//    mpz_sub_ui(t1, t1, 1);
+//    mpz_div(t1, t1, *pub->getnj(1));
+//    mpz_set(t2, id);
+//    kfac = 1;
+//
+//    for (k = 2; k <= j; k++)
+//    {
+//      kfac *= k;
+//      mpz_sub_ui(id, id, 1);
+//      mpz_mul(t2, t2, id);
+//      mpz_mod(t2, t2, *pub->getnj(j));
+//      mpz_set_ui(t3, kfac);
+//
+//      mpz_invert(t3, t3, *pub->getnj(j));
+//
+//      mpz_mul(t3, t3, t2);
+//      mpz_mod(t3, t3, *pub->getnj(j));
+//      mpz_mul(t3, t3, *pub->getnj(k-1));
+//      mpz_mod(t3, t3, *pub->getnj(j));
+//      mpz_sub(t1, t1, t3);
+//      mpz_mod(t1, t1, *pub->getnj(j));
+//    }
+//    mpz_set(id, t1);
+//  }
+//
+//  mpz_mul(rop, id, prv->inv_d);
+//
+//  mpz_mod(rop, rop, *pub->getnj(s));
+//
+//  mpz_clears(t1, t2, t3, a, id, NULL);
+}
+
+
+  void
+PaillierAdapter::keygen( unsigned int modulusbits,
+    paillier_pubkey* pub,
+    paillier_prvkey* prv,
+    unsigned int init_s)
+{
+  mpz_t p, q;
+
+  mpz_inits(p, q, NULL);
+
+  /* pick random (modulusbits/2)-bit primes p and q */
+  do
+  {
+    get_prime_of_size(p, modulusbits / 2);
+    get_prime_of_size(q, modulusbits / 2);
+
+    mpz_mul(*pub->getnj(1), p, q);
+
+  }while(mpz_sizeinbase(*pub->getnj(1), 2) != modulusbits);
+
+  pub->setbits(modulusbits);
+  pub->setinit_s(init_s);
+  pub->complete_key(init_s+1); /*we don't know if it will be used beyond one level*/
+
+  /* compute the private key lambda = lcm(p-1,q-1) */
+  mpz_sub_ui(p, p, 1);
+  mpz_sub_ui(q, q, 1);
+  mpz_lcm(prv->d, p, q);
+  mpz_invert(prv->inv_d, prv->d ,*pub->getnj(init_s));
+
+  /* clear temporary integers */
+  mpz_clears(p, q, NULL);
+}
+
+/**
+ *	Get prime number of given size.
+ *	Parms :
+ *		- mpz_t rop  : result operand ;
+ *		- unsigned int length : length in bit.
+ **/
+  void
+PaillierAdapter::get_prime_of_size(mpz_t rop, unsigned int length)
+{
+
+  mpz_t z_p, z_min;
+  mpz_init(z_p);
+  mpz_init_set_ui(z_min, 1);
+
+  mpz_mul_2exp(z_min, z_min, length - 1);
+  do
+  {
+    mpz_urandomb(z_p, rand, length);
+    mpz_add(z_p, z_min, z_p);
+    mpz_nextprime(z_p, z_p);
+  }
+  while(mpz_sizeinbase(z_p, 2) != length);
+
+  mpz_set(rop, z_p);
+  mpz_clears(z_p, z_min, NULL);
+}
+
+  void 
+PaillierAdapter::getRandFromfile(int len, mpz_t* val )
+{
+  char* p = new char[len + 1]();
+  std::ifstream f("/dev/urandom", ios::in | ios::binary);
+
+  for(int i = 0; i < len; i++)
+  {
+    f.read(p+i, 1);
+  }
+  mpz_import(*val, len, 1, sizeof(char), 0, 0, p);
+
+  f.close();
+
+  delete[] p;
+}
+
+  void
+PaillierAdapter::setNewParameters(const std::string& crypto_params)
+{
+  std::vector<std::string> fields;
+  boost::algorithm::split(fields, crypto_params, boost::algorithm::is_any_of(":"));
+  unsigned int keySize = (unsigned)atoi(fields[2].c_str());
+  security_bits = atoi(fields[1].c_str());
+  publicParameters.setModulusbits(keySize);
+  publicParameters.setSecurityBits(security_bits);
+  // TODO(performance) : Takes too much time when generating the encrypt and decrypt caches
+  // An option should be included so that it is a fixed key from a file when called to build caches
+  keygen(
+      keySize,
+      publicParameters.getPubKey(),
+      privateParameters.getPrvKey(),
+      kMagicConstant1);
+}
+  double
+PaillierAdapter::getDecCost(unsigned int length, unsigned int s)
+{
+  double  start, result;
+  unsigned int cores = omp_get_num_procs(); 
+  unsigned int rounds = 2000/pow((length*(s+1)/2048), 3);//Amount of rounds for a one second test on the poor devlopper's computer.
+  mpz_t z_r, z_a[cores];
+  mpz_init(z_r);
+
+#pragma omp parallel for
+  for (unsigned int i = 0 ; i < cores ; i++)
+    mpz_init(z_a[i]);
+
+  gmp_randstate_t prng;
+  gmp_randinit_default(prng);
+  gmp_randseed_ui(prng, time(NULL));
+
+  getRandInteger(z_r, length, prng);
+
+  start = omp_get_wtime();
+
+  for(unsigned int round = 0 ; round < rounds ; round++)
+  {
+#pragma omp parallel for
+    for (unsigned int i = 0 ; i < cores ; i++)
+    {
+      dec(publicParameters.getPubKey(),
+          privateParameters.getPrvKey(),
+          z_r, 
+          s ,
+          z_a[i] );
+      usleep(5);
+    }
+  }
+  mpz_clear(z_r);
+
+#pragma omp parallel for
+  for (unsigned int i = 0 ; i < cores ; i++)
+    mpz_clear(z_a[i]);
+
+  result = omp_get_wtime() - start;
+
+  return result /(cores)/rounds ; 
+}
+
+  void 
+PaillierAdapter::getRandInteger(mpz_t rop, unsigned int length, gmp_randstate_t prng)
+{
+  do {
+    mpz_urandomb(rop, prng, length);	
+  }while(mpz_sizeinbase(rop, 2) != length);
+}
+
+unsigned int PaillierAdapter::getAllCryptoParams(std::set<std::string>& crypto_params)
+{
+  unsigned int params_nbr = 0;
+  unsigned int k_array_size = 4;
+  // k=256 gives a 15K bit plaintext modulus and a 30K bit ciphertext modulus
+  // as this is huge we turn off this proposal by default
+  unsigned int k[4] = {80, 100, 128, 192};
+
+  for (unsigned int i = 0 ; i < k_array_size ; i++)
+  {
+    params_nbr += getCryptoParams(k[i], crypto_params);
+  }
+
+  return params_nbr;
+}
+
+unsigned int PaillierAdapter::getCryptoParams(unsigned int k, std::set<std::string>& crypto_params)
+{
+  unsigned int params_nbr = 0;
+  string k_str = std::to_string(k);
+
+  unsigned int modulus_size = securityToModulus(k);
+  if (modulus_size == 0) return 0;
+  // We'll increase params_nbr when the client handles better s
+  for (unsigned int s = 1 ; params_nbr < 1 ; s++)
+  {
+    string param = cryptoName + ":" + k_str + ":" + to_string(modulus_size*s) + ":" + to_string(modulus_size*(s+1)); 
+    if(crypto_params.insert(param).second) params_nbr++;
+    param = "";
+  }
+  return params_nbr;
+}
+
+
+long PaillierAdapter::setandgetAbsBitPerCiphertext(unsigned int elt_nbr)
+{
+  return publicParameters.getAbsorptionBitsize();
+}
+
+std::string PaillierAdapter::getSerializedCryptoParams(bool shortversion)
+{
+  return publicParameters.getSerializedParams(shortversion);
+}
+
+double PaillierAdapter::estimateAbsTime(std::string crypto_param)
+{
+  vector<string> fields;
+  boost::algorithm::split(fields, crypto_param, boost::algorithm::is_any_of(":"));
+  const double mod_size_s = static_cast<double>(atoi(fields[3].c_str()));
+  return 1.0 / (kMillion/(3.0*1016) * pow(2048 / mod_size_s, 3));
+}
+
+/**
+ *	Compute a modular exponentiation in crypted space who is a operation in clear space.
+ *	Params :
+ *		- mpz_t res : operation result;
+ *		- mpz_t a   : first operand, crypted data ;
+ *		- mpz_t b   : second operans, crypted data;
+ *		- int		s		: modulus index  .
+ **/
+void PaillierAdapter::e_add(mpz_t res, mpz_t a, mpz_t b, int s)
+{
+	mpz_mul(res, a, b);
+	mpz_mod(res, res, *publicParameters.getPubKey()->getnj(s));
+}
+
+/**
+ *	Compute modular multiplication in crypted space who is a multiplicaton in clear space.
+ *	Params :
+ *		- mpz_t res : operation result;
+ *		- mpz_t a   : first operand, crypted data ;
+ *		- mpz_t n   : second operand, a constant  ;
+ *		- int   s   : modulus index .
+ **/
+void PaillierAdapter::e_mul_const(mpz_t res, mpz_t a, mpz_t n, int s)
+{
+	mpz_powm(res, a, n , *publicParameters.getPubKey()->getnj(s));
+}

+ 97 - 0
crypto/PaillierAdapter.hpp

@@ -0,0 +1,97 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_PAILLIERADAPTER
+#define DEF_PAILLIERADAPTER
+static const unsigned int kNumSecurityBits = 80;
+#include <fstream>
+#include <omp.h>
+#include <math.h>
+#include <string>
+#include <unistd.h>
+#include <boost/algorithm/string.hpp>
+#include "HomomorphicCrypto.hpp"
+#include "PaillierPublicParameters.hpp"
+#include "PaillierPrivateParameters.hpp"
+
+using namespace std;
+
+class PaillierAdapter : public HomomorphicCrypto {
+
+	private:
+		/*Attributs*/
+		gmp_randstate_t rand;
+		int unsigned modulusbits;
+		int security_bits;
+		PaillierPrivateParameters privateParameters;
+	
+		/*Methods*/
+		void keygen(unsigned int modulusbits,
+											paillier_pubkey* pub,
+											paillier_prvkey* prv,
+											unsigned int s);
+		void complete_prvkey( 	paillier_prvkey* prv, 
+								paillier_pubkey* pub, 
+								unsigned int s );
+		void generatePrivateKey(void);
+		void generatePublicKey(void);
+		void enc(paillier_pubkey* pub,
+							mpz_t m,
+							unsigned int s,
+							mpz_t c
+							);
+		
+		void dec( paillier_pubkey* pub,
+							paillier_prvkey* prv,
+							mpz_t ct,  
+							unsigned int,
+							mpz_t i);
+
+		void getRandFromfile( int len, mpz_t* val );
+		void getRandInteger(mpz_t rop, unsigned int length, gmp_randstate_t prng);
+    void initRandomGenerator();
+
+	public:
+		void e_add(mpz_t res, mpz_t a, mpz_t b, int);
+		void e_mul_const(mpz_t res, mpz_t a, mpz_t n, int);
+		static unsigned int securityToModulus(int); 
+		/*Attributs*/
+		PaillierPublicParameters publicParameters;
+		
+		/*Methods*/
+		char* encrypt(unsigned int ui, unsigned int);
+		char* encrypt(char* data, size_t, unsigned int exponent);
+    char* encrypt_perftest();
+		char* decrypt(char* cipheredData, unsigned int rec_lvl, size_t, size_t);
+    unsigned int getCryptoParams(unsigned int k,set<std::string>& crypto_params);
+    unsigned int getAllCryptoParams(set<std::string>& crypto_params);
+    long setandgetAbsBitPerCiphertext(unsigned int elt_nbr);
+    std::string getSerializedCryptoParams(bool shortversion);
+
+    PaillierAdapter();
+    PaillierAdapter(int security_bits, int recLvl);
+		~PaillierAdapter(void);
+		
+    double estimateAbsTime(std::string crypto_param);
+		AbstractPublicParameters&  getPublicParameters(void);
+		double getDecCost(unsigned int length, unsigned int s);
+		void setNewParameters(const std::string& crypto_params);
+
+		void get_prime_of_size(mpz_t rop, unsigned int size);
+};
+
+#endif

+ 187 - 0
crypto/PaillierKeys.cpp

@@ -0,0 +1,187 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "PaillierKeys.hpp"
+#include <iostream>
+#include <cstring>
+
+/*************** PRVKEY**************/
+paillier_prvkey::paillier_prvkey(){
+  init_key();
+}
+
+paillier_prvkey::~paillier_prvkey(){
+  clear_key();
+}
+
+void paillier_prvkey::init_key(){
+  mpz_inits(d, inv_d, NULL);
+}
+
+void paillier_prvkey::clear_key()
+{
+  mpz_clears(d, inv_d, NULL);
+}
+
+
+/*************** PUBKEY**************/
+paillier_pubkey::paillier_pubkey() :
+  bits(0), 
+  init_s(1)
+{
+  init_key();
+}
+
+paillier_pubkey::paillier_pubkey(unsigned int bits, char* rawKey) :
+  bits(0), 
+  init_s(1)
+{
+  init_key(bits, rawKey);
+}
+
+void paillier_pubkey::init_key() {
+  for (int i = 0; i <= MAX_S; i++)
+  {
+    mpz_init_set_ui(nj[i],1);
+  }
+  mpz_init_set_ui(g,1);
+}
+
+void paillier_pubkey::init_key(unsigned int _bits, char* rawKey) {
+  int init_s_;
+  bits = _bits;
+
+  init_key();
+  
+  mpz_import(nj[1], _bits / 8, 1, sizeof(char), 0, 0, rawKey);
+  mpz_add_ui(g, nj[1], 1);
+  memcpy(&init_s_, rawKey+_bits/8, sizeof(int));
+  
+  // The client should not be using s above MAX_S
+  if (init_s_ >= MAX_S)
+  {
+    std::cout << "PaillierKeys: WARNING. The client tries to use s>=MAX_S. Setting s=MAX_S-1."<<std::endl;
+    init_s = MAX_S-1;
+  } 
+  else init_s = init_s_;
+
+  for (int i = 2; i <= init_s+1; i++)
+  {
+    mpz_pow_ui(nj[i], nj[1], i);
+  }
+}
+
+//mocked key
+void paillier_pubkey::init_key(unsigned int key_bit_size)
+{
+  init_s = 1;
+  gmp_randstate_t rand;
+  gmp_randinit_default(rand);
+
+  mpz_urandomb(nj[1], rand, key_bit_size); 
+  mpz_add_ui(g, nj[1], 1);
+  
+  for (int i = 2; i <= init_s+1; i++)
+	{
+		mpz_pow_ui(nj[i], nj[1], i);
+	}
+  gmp_randclear(rand);
+}
+
+inline void paillier_pubkey::init_nj(int i)
+{
+	mpz_pow_ui(nj[i], nj[1], i);
+}
+
+
+paillier_pubkey::~paillier_pubkey(){
+  mpz_clear(g);
+
+  for(int i = 0; i < MAX_S; i++)
+    mpz_clear(nj[i]);
+}
+
+
+// Complete nj array up to index s_
+void paillier_pubkey::complete_key(unsigned int s_){
+  int s = s_;
+
+  // The client should not be using moduli above MAX_S
+  if (s > MAX_S)
+  {
+    std::cerr << "PaillierKeys: WARNING trying to complete keys above MAX_S bounding it to MAX_S" << std::endl;
+    s = MAX_S;
+  }
+
+  // If g's value has not been initialized do it now
+  if (mpz_get_ui(g) == 1 ) mpz_add_ui(g, nj[1], 1);
+  
+  // Initialize the array's values
+  for (unsigned int i = 2; i <= s ; i++){
+    // Should we save polar bears ? if (mpz_get_ui(nj[i]) == 1 ) 
+    init_nj(i);
+  }
+}
+
+
+// Provides the ciphertext modulus key i levels above the s defined in the class
+// Ugly to return an mpz_t but the function purpose is to ensure that it has the correct
+// value before its reference is returned
+mpz_t* paillier_pubkey::getnj(int s_)
+{
+  int s = s_;
+
+  // The client should not be using moduli above MAX_S
+  if (s > MAX_S)
+  {
+    std::cerr << "PaillierKeys: WARNING trying to get key above MAX_S bounding it to MAX_S" << std::endl;
+    s = MAX_S;
+  }
+
+  // If the key has been defined do it now
+  if (mpz_get_ui(nj[s]) == 1 ) init_nj(s);
+  
+  return &nj[s];
+}
+
+// Simple getters
+int paillier_pubkey::getinit_s()
+{
+  return init_s;
+}
+
+mpz_t* paillier_pubkey::getg()
+{
+  return &g;
+}
+
+int paillier_pubkey::getbits()
+{
+  return bits;
+} 
+
+// Simple setters
+void paillier_pubkey::setinit_s(int init_s_)
+{
+  init_s = init_s_;
+}
+
+void paillier_pubkey::setbits(int bits_)
+{
+  bits = bits_;
+} 
+

+ 72 - 0
crypto/PaillierKeys.hpp

@@ -0,0 +1,72 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_PAILLIER_STRUCT
+#define DEF_PAILLIER_STRUCT
+#include <cstddef>
+#include <gmp.h>
+
+// Maximum s such that encryption is donne from n^s to n^(s+1)
+#define MAX_S 7 
+
+class paillier_prvkey
+{
+public:
+  paillier_prvkey();
+  void init_key();
+  void clear_key();
+  mpz_t d; /* use CRT, d = mod n^s and d = O mod lambda*/
+  mpz_t inv_d;
+  ~paillier_prvkey();
+};
+
+class paillier_pubkey
+{
+public:
+  paillier_pubkey();
+  paillier_pubkey(unsigned int bits, char* rawKey);
+  ~paillier_pubkey();
+  void init_key();
+  void init_key(unsigned int bits, char* rawKey);
+  void init_key(unsigned int key_bit_size);
+  // Complete nj array up to index s
+  void complete_key(unsigned int s);
+  // Get nj[s] = n^s initializing it if needed
+  mpz_t* getnj(int s);
+  // Simple getters
+  mpz_t* getg();
+  int getinit_s();
+  int getbits();
+  // Simple setters
+  void setinit_s(int init_s_);
+  void setbits(int bits_);
+
+  void clear_key();
+private:
+  // Bit-size of the modulus
+  int bits; 
+  // nj[s] is n^s, nj[0] is therefore 1 (should not be used)
+  mpz_t nj[MAX_S+1];  
+  // Basic plaintext space is n^init_s and ciphertext space n^(init_s+1)
+  unsigned int init_s;
+  // Generator, i.e: n+1
+  mpz_t g; 
+  // Function initializing nj[i] for i>=2 when needed
+  void init_nj(int i);
+};
+
+#endif

+ 30 - 0
crypto/PaillierPrivateParameters.cpp

@@ -0,0 +1,30 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "PaillierPrivateParameters.hpp"
+
+PaillierPrivateParameters::PaillierPrivateParameters():
+prvkey()
+{ 
+}
+
+PaillierPrivateParameters::~PaillierPrivateParameters(){ 
+}
+
+paillier_prvkey* PaillierPrivateParameters::getPrvKey(){ 
+	return &prvkey;
+}

+ 34 - 0
crypto/PaillierPrivateParameters.hpp

@@ -0,0 +1,34 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_PAILLIERPRIVATEPARAMETERS
+#define DEF_PAILLIERPRIVATEPARAMETERS
+
+#include "PaillierKeys.hpp"
+
+class PaillierPrivateParameters {
+
+	private:
+		paillier_prvkey prvkey;
+
+	public:
+		PaillierPrivateParameters();
+		~PaillierPrivateParameters();
+		paillier_prvkey* getPrvKey();
+};
+
+#endif

+ 142 - 0
crypto/PaillierPublicParameters.cpp

@@ -0,0 +1,142 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "PaillierPublicParameters.hpp"
+#include <iostream>
+
+PaillierPublicParameters::PaillierPublicParameters()
+{
+  cryptoName = "Paillier";
+  securityBits = 0;
+}
+//PaillierPublicParameters::PaillierPublicParameters(unsigned int bit_key_size) :
+//	bitKeySize(bit_key_size),
+//	bitAbsSize(bitKeySize - 8),
+//	ciphSize(bitKeySize * 2)
+//{ 
+//  cryptoName = "Paillier";
+//  securityBits = 0;
+//}
+
+PaillierPublicParameters::~PaillierPublicParameters()
+{
+}
+
+char* PaillierPublicParameters::getByteModulus() {
+  char *key = new char[(getKeyBitsize() / 8 ) + sizeof(int)](); 
+  mpz_export(key, NULL, 1, sizeof(char) , 0, 0, *pubkey.getnj(1));
+  int init_s = pubkey.getinit_s();
+  memcpy(key+(getKeyBitsize()/8), &init_s, sizeof(int));
+	return key;
+}
+
+unsigned int PaillierPublicParameters::getCiphertextSize() {
+	return ciphSize; 
+}
+
+unsigned int PaillierPublicParameters::getKeyBitsize() { 
+	return bitKeySize;
+}
+
+unsigned int PaillierPublicParameters::getAbsorptionBitsize() { 
+	return bitAbsSize;
+}
+
+unsigned int PaillierPublicParameters::getAbsorptionBitsize(unsigned int rec_lvl)
+{
+  if (rec_lvl == 0)
+  {
+    return getAbsorptionBitsize();
+  }
+  else
+  {
+    // If we are being used in a recursive scheme take all the bits
+    return getKeyBitsize()*(rec_lvl+1);
+  }
+}
+
+paillier_pubkey* PaillierPublicParameters::getPubKey() {
+	return &pubkey;
+}
+
+void PaillierPublicParameters::setModulus(char* rawPubKey){
+  pubkey.init_key(getKeyBitsize(), rawPubKey);	
+}
+
+//lvl starts at 1 !!!
+unsigned int PaillierPublicParameters::getCiphBitsizeFromRecLvl(unsigned int lvl) 
+{
+  return (lvl+pubkey.getinit_s()) * bitKeySize;
+}
+
+unsigned int PaillierPublicParameters::getQuerySizeFromRecLvl(unsigned int lvl)
+{
+  return getCiphBitsizeFromRecLvl(lvl);
+}
+
+unsigned int PaillierPublicParameters::getSerializedModulusBitsize()
+{
+  return  getKeyBitsize() + sizeof(int) * 8;
+}
+
+void PaillierPublicParameters::setModulusbits(unsigned int modulusbits_)
+{
+	bitKeySize  = modulusbits_ ;
+	bitAbsSize = (bitKeySize - 8);
+	ciphSize    = (bitKeySize * 2);
+}
+
+void PaillierPublicParameters::setSecurityBits(unsigned int securitybits_)
+{
+  securityBits = securitybits_;
+} 
+
+void PaillierPublicParameters::computeNewParameters(const std::string& crypto_param_descriptor)
+{
+  std::vector<std::string> fields;
+  boost::algorithm::split(fields, crypto_param_descriptor, boost::algorithm::is_any_of(":"));
+  securityBits = (unsigned)atoi (fields[1].c_str());
+  unsigned int keySize = (unsigned)atoi(fields[2].c_str());
+  setModulusbits(keySize);
+}
+
+
+// Get a serialized version of the parameters
+std::string PaillierPublicParameters::getSerializedParams(bool shortversion)
+{
+  std::string params;
+  
+  // Name:security:plaintext_modulusbitsize:ciphertext_modulusbitsize:abs_bits
+  params = cryptoName + ":" + std::to_string(securityBits) + ":" + std::to_string(bitKeySize) + ":" + std::to_string(ciphSize);
+  
+  if (!shortversion) params += ":" + std::to_string(bitAbsSize);
+
+  return params;
+}
+
+
+unsigned int PaillierPublicParameters::getCiphertextBitsize()
+{
+  return getCiphBitsizeFromRecLvl(1);
+}
+
+void PaillierPublicParameters::setMockedPubKey()
+{
+  pubkey.init_key(getKeyBitsize());
+}
+    
+

+ 60 - 0
crypto/PaillierPublicParameters.hpp

@@ -0,0 +1,60 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_PAILLIERPUBLICPARAMETERS
+#define DEF_PAILLIERPUBLICPARAMETERS
+
+#include <string.h>
+
+#include "AbstractPublicParameters.hpp"
+#include "PaillierKeys.hpp"
+
+class PaillierPublicParameters : public AbstractPublicParameters {
+
+	private:
+		unsigned int bitKeySize;
+		unsigned int byteKeySize;
+		unsigned int bitAbsSize;
+		unsigned int ciphSize;
+    unsigned int securityBits;
+		paillier_pubkey pubkey;
+
+	public:
+		unsigned int getCiphBitsizeFromRecLvl(unsigned int);
+    unsigned int getCiphertextBitsize();
+		unsigned int getQuerySizeFromRecLvl(unsigned int);
+		PaillierPublicParameters();
+		~PaillierPublicParameters();
+    void setModulusbits(unsigned int modulusbits);
+    void setSecurityBits(unsigned int securitybits);
+    void computeNewParameters(const std::string& crypto_param_descriptor);
+		char* getByteModulus();
+    std::string getSerializedParams(bool shortversion);
+		unsigned int getKeyBitsize();
+		unsigned int getAbsorptionBitsize();
+    unsigned int getAbsorptionBitsize(unsigned int i);
+
+		unsigned int getCiphertextSize();
+    unsigned int getSerializedModulusBitsize();
+		paillier_pubkey* getPubKey();
+		void setModulus(char* pubKey);
+    void setMockedPubKey();
+
+		
+};
+
+#endif

+ 6 - 0
crypto/prng/CMakeLists.txt

@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.6.0)
+
+set(CMAKE_CXX_FLAGS "-std=c++11")
+
+add_library(pir_crypto_prng STATIC crypto_stream_salsa20_amd64_xmm6.s fastrandombytes.cpp randombytes.cpp)
+set_property(TARGET pir_crypto_prng PROPERTY COMPILE_DEFINITIONS SHARED_C)

+ 27 - 0
crypto/prng/crypto_stream_salsa20.h

@@ -0,0 +1,27 @@
+/*
+D. J. Bernstein
+Public domain.
+*/
+#ifndef CRYPTO_STREAM_H
+#define CRYPTO_STREAM_H
+
+#define crypto_stream_salsa20_KEYBYTES 32
+#define crypto_stream_salsa20_NONCEBYTES 8
+
+#ifdef __cplusplus
+#include <string>
+extern "C" {
+#endif
+extern
+int crypto_stream_salsa20_amd64_xmm6(
+        unsigned char *c,unsigned long long clen,
+  const unsigned char *n,
+  const unsigned char *k
+);
+    
+#ifdef __cplusplus
+}
+#endif
+#define crypto_stream_salsa20 crypto_stream_salsa20_amd64_xmm6
+
+#endif

+ 4827 - 0
crypto/prng/crypto_stream_salsa20_amd64_xmm6.s

@@ -0,0 +1,4827 @@
+#
+#D. J. Bernstein
+#Public domain.
+#
+
+# qhasm: int64 r11_caller
+
+# qhasm: int64 r12_caller
+
+# qhasm: int64 r13_caller
+
+# qhasm: int64 r14_caller
+
+# qhasm: int64 r15_caller
+
+# qhasm: int64 rbx_caller
+
+# qhasm: int64 rbp_caller
+
+# qhasm: caller r11_caller
+
+# qhasm: caller r12_caller
+
+# qhasm: caller r13_caller
+
+# qhasm: caller r14_caller
+
+# qhasm: caller r15_caller
+
+# qhasm: caller rbx_caller
+
+# qhasm: caller rbp_caller
+
+# qhasm: stack64 r11_stack
+
+# qhasm: stack64 r12_stack
+
+# qhasm: stack64 r13_stack
+
+# qhasm: stack64 r14_stack
+
+# qhasm: stack64 r15_stack
+
+# qhasm: stack64 rbx_stack
+
+# qhasm: stack64 rbp_stack
+
+# qhasm: int64 a
+
+# qhasm: int64 arg1
+
+# qhasm: int64 arg2
+
+# qhasm: int64 arg3
+
+# qhasm: int64 arg4
+
+# qhasm: int64 arg5
+
+# qhasm: input arg1
+
+# qhasm: input arg2
+
+# qhasm: input arg3
+
+# qhasm: input arg4
+
+# qhasm: input arg5
+
+# qhasm: int64 k
+
+# qhasm: int64 kbits
+
+# qhasm: int64 iv
+
+# qhasm: int64 i
+
+# qhasm: stack128 x0
+
+# qhasm: stack128 x1
+
+# qhasm: stack128 x2
+
+# qhasm: stack128 x3
+
+# qhasm: int64 m
+
+# qhasm: int64 out
+
+# qhasm: int64 bytes
+
+# qhasm: stack32 eax_stack
+
+# qhasm: stack32 ebx_stack
+
+# qhasm: stack32 esi_stack
+
+# qhasm: stack32 edi_stack
+
+# qhasm: stack32 ebp_stack
+
+# qhasm: int6464 diag0
+
+# qhasm: int6464 diag1
+
+# qhasm: int6464 diag2
+
+# qhasm: int6464 diag3
+
+# qhasm: int6464 a0
+
+# qhasm: int6464 a1
+
+# qhasm: int6464 a2
+
+# qhasm: int6464 a3
+
+# qhasm: int6464 a4
+
+# qhasm: int6464 a5
+
+# qhasm: int6464 a6
+
+# qhasm: int6464 a7
+
+# qhasm: int6464 b0
+
+# qhasm: int6464 b1
+
+# qhasm: int6464 b2
+
+# qhasm: int6464 b3
+
+# qhasm: int6464 b4
+
+# qhasm: int6464 b5
+
+# qhasm: int6464 b6
+
+# qhasm: int6464 b7
+
+# qhasm: int6464 z0
+
+# qhasm: int6464 z1
+
+# qhasm: int6464 z2
+
+# qhasm: int6464 z3
+
+# qhasm: int6464 z4
+
+# qhasm: int6464 z5
+
+# qhasm: int6464 z6
+
+# qhasm: int6464 z7
+
+# qhasm: int6464 z8
+
+# qhasm: int6464 z9
+
+# qhasm: int6464 z10
+
+# qhasm: int6464 z11
+
+# qhasm: int6464 z12
+
+# qhasm: int6464 z13
+
+# qhasm: int6464 z14
+
+# qhasm: int6464 z15
+
+# qhasm: stack128 z0_stack
+
+# qhasm: stack128 z1_stack
+
+# qhasm: stack128 z2_stack
+
+# qhasm: stack128 z3_stack
+
+# qhasm: stack128 z4_stack
+
+# qhasm: stack128 z5_stack
+
+# qhasm: stack128 z6_stack
+
+# qhasm: stack128 z7_stack
+
+# qhasm: stack128 z8_stack
+
+# qhasm: stack128 z9_stack
+
+# qhasm: stack128 z10_stack
+
+# qhasm: stack128 z11_stack
+
+# qhasm: stack128 z12_stack
+
+# qhasm: stack128 z13_stack
+
+# qhasm: stack128 z14_stack
+
+# qhasm: stack128 z15_stack
+
+# qhasm: int6464 y0
+
+# qhasm: int6464 y1
+
+# qhasm: int6464 y2
+
+# qhasm: int6464 y3
+
+# qhasm: int6464 y4
+
+# qhasm: int6464 y5
+
+# qhasm: int6464 y6
+
+# qhasm: int6464 y7
+
+# qhasm: int6464 y8
+
+# qhasm: int6464 y9
+
+# qhasm: int6464 y10
+
+# qhasm: int6464 y11
+
+# qhasm: int6464 y12
+
+# qhasm: int6464 y13
+
+# qhasm: int6464 y14
+
+# qhasm: int6464 y15
+
+# qhasm: int6464 r0
+
+# qhasm: int6464 r1
+
+# qhasm: int6464 r2
+
+# qhasm: int6464 r3
+
+# qhasm: int6464 r4
+
+# qhasm: int6464 r5
+
+# qhasm: int6464 r6
+
+# qhasm: int6464 r7
+
+# qhasm: int6464 r8
+
+# qhasm: int6464 r9
+
+# qhasm: int6464 r10
+
+# qhasm: int6464 r11
+
+# qhasm: int6464 r12
+
+# qhasm: int6464 r13
+
+# qhasm: int6464 r14
+
+# qhasm: int6464 r15
+
+# qhasm: stack128 orig0
+
+# qhasm: stack128 orig1
+
+# qhasm: stack128 orig2
+
+# qhasm: stack128 orig3
+
+# qhasm: stack128 orig4
+
+# qhasm: stack128 orig5
+
+# qhasm: stack128 orig6
+
+# qhasm: stack128 orig7
+
+# qhasm: stack128 orig8
+
+# qhasm: stack128 orig9
+
+# qhasm: stack128 orig10
+
+# qhasm: stack128 orig11
+
+# qhasm: stack128 orig12
+
+# qhasm: stack128 orig13
+
+# qhasm: stack128 orig14
+
+# qhasm: stack128 orig15
+
+# qhasm: int64 in0
+
+# qhasm: int64 in1
+
+# qhasm: int64 in2
+
+# qhasm: int64 in3
+
+# qhasm: int64 in4
+
+# qhasm: int64 in5
+
+# qhasm: int64 in6
+
+# qhasm: int64 in7
+
+# qhasm: int64 in8
+
+# qhasm: int64 in9
+
+# qhasm: int64 in10
+
+# qhasm: int64 in11
+
+# qhasm: int64 in12
+
+# qhasm: int64 in13
+
+# qhasm: int64 in14
+
+# qhasm: int64 in15
+
+# qhasm: stack512 tmp
+
+# qhasm: int64 ctarget
+
+# qhasm: stack64 bytes_backup
+
+# qhasm: enter crypto_stream_salsa20_amd64_xmm6
+.text
+.p2align 5
+.globl _crypto_stream_salsa20_amd64_xmm6
+.globl crypto_stream_salsa20_amd64_xmm6
+_crypto_stream_salsa20_amd64_xmm6:
+crypto_stream_salsa20_amd64_xmm6:
+mov %rsp,%r11
+and $31,%r11
+add $480,%r11
+sub %r11,%rsp
+
+# qhasm: r11_stack = r11_caller
+# asm 1: movq <r11_caller=int64#9,>r11_stack=stack64#1
+# asm 2: movq <r11_caller=%r11,>r11_stack=352(%rsp)
+movq %r11,352(%rsp)
+
+# qhasm: r12_stack = r12_caller
+# asm 1: movq <r12_caller=int64#10,>r12_stack=stack64#2
+# asm 2: movq <r12_caller=%r12,>r12_stack=360(%rsp)
+movq %r12,360(%rsp)
+
+# qhasm: r13_stack = r13_caller
+# asm 1: movq <r13_caller=int64#11,>r13_stack=stack64#3
+# asm 2: movq <r13_caller=%r13,>r13_stack=368(%rsp)
+movq %r13,368(%rsp)
+
+# qhasm: r14_stack = r14_caller
+# asm 1: movq <r14_caller=int64#12,>r14_stack=stack64#4
+# asm 2: movq <r14_caller=%r14,>r14_stack=376(%rsp)
+movq %r14,376(%rsp)
+
+# qhasm: r15_stack = r15_caller
+# asm 1: movq <r15_caller=int64#13,>r15_stack=stack64#5
+# asm 2: movq <r15_caller=%r15,>r15_stack=384(%rsp)
+movq %r15,384(%rsp)
+
+# qhasm: rbx_stack = rbx_caller
+# asm 1: movq <rbx_caller=int64#14,>rbx_stack=stack64#6
+# asm 2: movq <rbx_caller=%rbx,>rbx_stack=392(%rsp)
+movq %rbx,392(%rsp)
+
+# qhasm: rbp_stack = rbp_caller
+# asm 1: movq <rbp_caller=int64#15,>rbp_stack=stack64#7
+# asm 2: movq <rbp_caller=%rbp,>rbp_stack=400(%rsp)
+movq %rbp,400(%rsp)
+
+# qhasm: bytes = arg2
+# asm 1: mov  <arg2=int64#2,>bytes=int64#6
+# asm 2: mov  <arg2=%rsi,>bytes=%r9
+mov  %rsi,%r9
+
+# qhasm: out = arg1
+# asm 1: mov  <arg1=int64#1,>out=int64#1
+# asm 2: mov  <arg1=%rdi,>out=%rdi
+mov  %rdi,%rdi
+
+# qhasm: m = out
+# asm 1: mov  <out=int64#1,>m=int64#2
+# asm 2: mov  <out=%rdi,>m=%rsi
+mov  %rdi,%rsi
+
+# qhasm: iv = arg3
+# asm 1: mov  <arg3=int64#3,>iv=int64#3
+# asm 2: mov  <arg3=%rdx,>iv=%rdx
+mov  %rdx,%rdx
+
+# qhasm: k = arg4
+# asm 1: mov  <arg4=int64#4,>k=int64#8
+# asm 2: mov  <arg4=%rcx,>k=%r10
+mov  %rcx,%r10
+
+# qhasm:               unsigned>? bytes - 0
+# asm 1: cmp  $0,<bytes=int64#6
+# asm 2: cmp  $0,<bytes=%r9
+cmp  $0,%r9
+# comment:fp stack unchanged by jump
+
+# qhasm: goto done if !unsigned>
+jbe ._done
+
+# qhasm: a = 0
+# asm 1: mov  $0,>a=int64#7
+# asm 2: mov  $0,>a=%rax
+mov  $0,%rax
+
+# qhasm: i = bytes
+# asm 1: mov  <bytes=int64#6,>i=int64#4
+# asm 2: mov  <bytes=%r9,>i=%rcx
+mov  %r9,%rcx
+
+# qhasm: while (i) { *out++ = a; --i }
+rep stosb
+
+# qhasm: out -= bytes
+# asm 1: sub  <bytes=int64#6,<out=int64#1
+# asm 2: sub  <bytes=%r9,<out=%rdi
+sub  %r9,%rdi
+# comment:fp stack unchanged by jump
+
+# qhasm: goto start
+jmp ._start
+
+# qhasm: enter crypto_stream_salsa20_amd64_xmm6_xor
+.text
+.p2align 5
+.globl _crypto_stream_salsa20_amd64_xmm6_xor
+.globl crypto_stream_salsa20_amd64_xmm6_xor
+_crypto_stream_salsa20_amd64_xmm6_xor:
+crypto_stream_salsa20_amd64_xmm6_xor:
+mov %rsp,%r11
+and $31,%r11
+add $480,%r11
+sub %r11,%rsp
+
+# qhasm: r11_stack = r11_caller
+# asm 1: movq <r11_caller=int64#9,>r11_stack=stack64#1
+# asm 2: movq <r11_caller=%r11,>r11_stack=352(%rsp)
+movq %r11,352(%rsp)
+
+# qhasm: r12_stack = r12_caller
+# asm 1: movq <r12_caller=int64#10,>r12_stack=stack64#2
+# asm 2: movq <r12_caller=%r12,>r12_stack=360(%rsp)
+movq %r12,360(%rsp)
+
+# qhasm: r13_stack = r13_caller
+# asm 1: movq <r13_caller=int64#11,>r13_stack=stack64#3
+# asm 2: movq <r13_caller=%r13,>r13_stack=368(%rsp)
+movq %r13,368(%rsp)
+
+# qhasm: r14_stack = r14_caller
+# asm 1: movq <r14_caller=int64#12,>r14_stack=stack64#4
+# asm 2: movq <r14_caller=%r14,>r14_stack=376(%rsp)
+movq %r14,376(%rsp)
+
+# qhasm: r15_stack = r15_caller
+# asm 1: movq <r15_caller=int64#13,>r15_stack=stack64#5
+# asm 2: movq <r15_caller=%r15,>r15_stack=384(%rsp)
+movq %r15,384(%rsp)
+
+# qhasm: rbx_stack = rbx_caller
+# asm 1: movq <rbx_caller=int64#14,>rbx_stack=stack64#6
+# asm 2: movq <rbx_caller=%rbx,>rbx_stack=392(%rsp)
+movq %rbx,392(%rsp)
+
+# qhasm: rbp_stack = rbp_caller
+# asm 1: movq <rbp_caller=int64#15,>rbp_stack=stack64#7
+# asm 2: movq <rbp_caller=%rbp,>rbp_stack=400(%rsp)
+movq %rbp,400(%rsp)
+
+# qhasm: out = arg1
+# asm 1: mov  <arg1=int64#1,>out=int64#1
+# asm 2: mov  <arg1=%rdi,>out=%rdi
+mov  %rdi,%rdi
+
+# qhasm: m = arg2
+# asm 1: mov  <arg2=int64#2,>m=int64#2
+# asm 2: mov  <arg2=%rsi,>m=%rsi
+mov  %rsi,%rsi
+
+# qhasm: bytes = arg3
+# asm 1: mov  <arg3=int64#3,>bytes=int64#6
+# asm 2: mov  <arg3=%rdx,>bytes=%r9
+mov  %rdx,%r9
+
+# qhasm: iv = arg4
+# asm 1: mov  <arg4=int64#4,>iv=int64#3
+# asm 2: mov  <arg4=%rcx,>iv=%rdx
+mov  %rcx,%rdx
+
+# qhasm: k = arg5
+# asm 1: mov  <arg5=int64#5,>k=int64#8
+# asm 2: mov  <arg5=%r8,>k=%r10
+mov  %r8,%r10
+
+# qhasm:               unsigned>? bytes - 0
+# asm 1: cmp  $0,<bytes=int64#6
+# asm 2: cmp  $0,<bytes=%r9
+cmp  $0,%r9
+# comment:fp stack unchanged by jump
+
+# qhasm: goto done if !unsigned>
+jbe ._done
+# comment:fp stack unchanged by fallthrough
+
+# qhasm: start:
+._start:
+
+# qhasm:   in12 = *(uint32 *) (k + 20)
+# asm 1: movl   20(<k=int64#8),>in12=int64#4d
+# asm 2: movl   20(<k=%r10),>in12=%ecx
+movl   20(%r10),%ecx
+
+# qhasm:   in1 = *(uint32 *) (k + 0)
+# asm 1: movl   0(<k=int64#8),>in1=int64#5d
+# asm 2: movl   0(<k=%r10),>in1=%r8d
+movl   0(%r10),%r8d
+
+# qhasm:   in6 = *(uint32 *) (iv + 0)
+# asm 1: movl   0(<iv=int64#3),>in6=int64#7d
+# asm 2: movl   0(<iv=%rdx),>in6=%eax
+movl   0(%rdx),%eax
+
+# qhasm:   in11 = *(uint32 *) (k + 16)
+# asm 1: movl   16(<k=int64#8),>in11=int64#9d
+# asm 2: movl   16(<k=%r10),>in11=%r11d
+movl   16(%r10),%r11d
+
+# qhasm:   ((uint32 *)&x1)[0] = in12
+# asm 1: movl <in12=int64#4d,>x1=stack128#1
+# asm 2: movl <in12=%ecx,>x1=0(%rsp)
+movl %ecx,0(%rsp)
+
+# qhasm:   ((uint32 *)&x1)[1] = in1
+# asm 1: movl <in1=int64#5d,4+<x1=stack128#1
+# asm 2: movl <in1=%r8d,4+<x1=0(%rsp)
+movl %r8d,4+0(%rsp)
+
+# qhasm:   ((uint32 *)&x1)[2] = in6
+# asm 1: movl <in6=int64#7d,8+<x1=stack128#1
+# asm 2: movl <in6=%eax,8+<x1=0(%rsp)
+movl %eax,8+0(%rsp)
+
+# qhasm:   ((uint32 *)&x1)[3] = in11
+# asm 1: movl <in11=int64#9d,12+<x1=stack128#1
+# asm 2: movl <in11=%r11d,12+<x1=0(%rsp)
+movl %r11d,12+0(%rsp)
+
+# qhasm:   in8 = 0
+# asm 1: mov  $0,>in8=int64#4
+# asm 2: mov  $0,>in8=%rcx
+mov  $0,%rcx
+
+# qhasm:   in13 = *(uint32 *) (k + 24)
+# asm 1: movl   24(<k=int64#8),>in13=int64#5d
+# asm 2: movl   24(<k=%r10),>in13=%r8d
+movl   24(%r10),%r8d
+
+# qhasm:   in2 = *(uint32 *) (k + 4)
+# asm 1: movl   4(<k=int64#8),>in2=int64#7d
+# asm 2: movl   4(<k=%r10),>in2=%eax
+movl   4(%r10),%eax
+
+# qhasm:   in7 = *(uint32 *) (iv + 4)
+# asm 1: movl   4(<iv=int64#3),>in7=int64#3d
+# asm 2: movl   4(<iv=%rdx),>in7=%edx
+movl   4(%rdx),%edx
+
+# qhasm:   ((uint32 *)&x2)[0] = in8
+# asm 1: movl <in8=int64#4d,>x2=stack128#2
+# asm 2: movl <in8=%ecx,>x2=16(%rsp)
+movl %ecx,16(%rsp)
+
+# qhasm:   ((uint32 *)&x2)[1] = in13
+# asm 1: movl <in13=int64#5d,4+<x2=stack128#2
+# asm 2: movl <in13=%r8d,4+<x2=16(%rsp)
+movl %r8d,4+16(%rsp)
+
+# qhasm:   ((uint32 *)&x2)[2] = in2
+# asm 1: movl <in2=int64#7d,8+<x2=stack128#2
+# asm 2: movl <in2=%eax,8+<x2=16(%rsp)
+movl %eax,8+16(%rsp)
+
+# qhasm:   ((uint32 *)&x2)[3] = in7
+# asm 1: movl <in7=int64#3d,12+<x2=stack128#2
+# asm 2: movl <in7=%edx,12+<x2=16(%rsp)
+movl %edx,12+16(%rsp)
+
+# qhasm:   in4 = *(uint32 *) (k + 12)
+# asm 1: movl   12(<k=int64#8),>in4=int64#3d
+# asm 2: movl   12(<k=%r10),>in4=%edx
+movl   12(%r10),%edx
+
+# qhasm:   in9 = 0
+# asm 1: mov  $0,>in9=int64#4
+# asm 2: mov  $0,>in9=%rcx
+mov  $0,%rcx
+
+# qhasm:   in14 = *(uint32 *) (k + 28)
+# asm 1: movl   28(<k=int64#8),>in14=int64#5d
+# asm 2: movl   28(<k=%r10),>in14=%r8d
+movl   28(%r10),%r8d
+
+# qhasm:   in3 = *(uint32 *) (k + 8)
+# asm 1: movl   8(<k=int64#8),>in3=int64#7d
+# asm 2: movl   8(<k=%r10),>in3=%eax
+movl   8(%r10),%eax
+
+# qhasm:   ((uint32 *)&x3)[0] = in4
+# asm 1: movl <in4=int64#3d,>x3=stack128#3
+# asm 2: movl <in4=%edx,>x3=32(%rsp)
+movl %edx,32(%rsp)
+
+# qhasm:   ((uint32 *)&x3)[1] = in9
+# asm 1: movl <in9=int64#4d,4+<x3=stack128#3
+# asm 2: movl <in9=%ecx,4+<x3=32(%rsp)
+movl %ecx,4+32(%rsp)
+
+# qhasm:   ((uint32 *)&x3)[2] = in14
+# asm 1: movl <in14=int64#5d,8+<x3=stack128#3
+# asm 2: movl <in14=%r8d,8+<x3=32(%rsp)
+movl %r8d,8+32(%rsp)
+
+# qhasm:   ((uint32 *)&x3)[3] = in3
+# asm 1: movl <in3=int64#7d,12+<x3=stack128#3
+# asm 2: movl <in3=%eax,12+<x3=32(%rsp)
+movl %eax,12+32(%rsp)
+
+# qhasm:   in0 = 1634760805
+# asm 1: mov  $1634760805,>in0=int64#3
+# asm 2: mov  $1634760805,>in0=%rdx
+mov  $1634760805,%rdx
+
+# qhasm:   in5 = 857760878
+# asm 1: mov  $857760878,>in5=int64#4
+# asm 2: mov  $857760878,>in5=%rcx
+mov  $857760878,%rcx
+
+# qhasm:   in10 = 2036477234
+# asm 1: mov  $2036477234,>in10=int64#5
+# asm 2: mov  $2036477234,>in10=%r8
+mov  $2036477234,%r8
+
+# qhasm:   in15 = 1797285236
+# asm 1: mov  $1797285236,>in15=int64#7
+# asm 2: mov  $1797285236,>in15=%rax
+mov  $1797285236,%rax
+
+# qhasm:   ((uint32 *)&x0)[0] = in0
+# asm 1: movl <in0=int64#3d,>x0=stack128#4
+# asm 2: movl <in0=%edx,>x0=48(%rsp)
+movl %edx,48(%rsp)
+
+# qhasm:   ((uint32 *)&x0)[1] = in5
+# asm 1: movl <in5=int64#4d,4+<x0=stack128#4
+# asm 2: movl <in5=%ecx,4+<x0=48(%rsp)
+movl %ecx,4+48(%rsp)
+
+# qhasm:   ((uint32 *)&x0)[2] = in10
+# asm 1: movl <in10=int64#5d,8+<x0=stack128#4
+# asm 2: movl <in10=%r8d,8+<x0=48(%rsp)
+movl %r8d,8+48(%rsp)
+
+# qhasm:   ((uint32 *)&x0)[3] = in15
+# asm 1: movl <in15=int64#7d,12+<x0=stack128#4
+# asm 2: movl <in15=%eax,12+<x0=48(%rsp)
+movl %eax,12+48(%rsp)
+
+# qhasm:                               unsigned<? bytes - 256
+# asm 1: cmp  $256,<bytes=int64#6
+# asm 2: cmp  $256,<bytes=%r9
+cmp  $256,%r9
+# comment:fp stack unchanged by jump
+
+# qhasm:   goto bytesbetween1and255 if unsigned<
+jb ._bytesbetween1and255
+
+# qhasm:   z0 = x0
+# asm 1: movdqa <x0=stack128#4,>z0=int6464#1
+# asm 2: movdqa <x0=48(%rsp),>z0=%xmm0
+movdqa 48(%rsp),%xmm0
+
+# qhasm:   z5 = z0[1,1,1,1]
+# asm 1: pshufd $0x55,<z0=int6464#1,>z5=int6464#2
+# asm 2: pshufd $0x55,<z0=%xmm0,>z5=%xmm1
+pshufd $0x55,%xmm0,%xmm1
+
+# qhasm:   z10 = z0[2,2,2,2]
+# asm 1: pshufd $0xaa,<z0=int6464#1,>z10=int6464#3
+# asm 2: pshufd $0xaa,<z0=%xmm0,>z10=%xmm2
+pshufd $0xaa,%xmm0,%xmm2
+
+# qhasm:   z15 = z0[3,3,3,3]
+# asm 1: pshufd $0xff,<z0=int6464#1,>z15=int6464#4
+# asm 2: pshufd $0xff,<z0=%xmm0,>z15=%xmm3
+pshufd $0xff,%xmm0,%xmm3
+
+# qhasm:   z0 = z0[0,0,0,0]
+# asm 1: pshufd $0x00,<z0=int6464#1,>z0=int6464#1
+# asm 2: pshufd $0x00,<z0=%xmm0,>z0=%xmm0
+pshufd $0x00,%xmm0,%xmm0
+
+# qhasm:   orig5 = z5
+# asm 1: movdqa <z5=int6464#2,>orig5=stack128#5
+# asm 2: movdqa <z5=%xmm1,>orig5=64(%rsp)
+movdqa %xmm1,64(%rsp)
+
+# qhasm:   orig10 = z10
+# asm 1: movdqa <z10=int6464#3,>orig10=stack128#6
+# asm 2: movdqa <z10=%xmm2,>orig10=80(%rsp)
+movdqa %xmm2,80(%rsp)
+
+# qhasm:   orig15 = z15
+# asm 1: movdqa <z15=int6464#4,>orig15=stack128#7
+# asm 2: movdqa <z15=%xmm3,>orig15=96(%rsp)
+movdqa %xmm3,96(%rsp)
+
+# qhasm:   orig0 = z0
+# asm 1: movdqa <z0=int6464#1,>orig0=stack128#8
+# asm 2: movdqa <z0=%xmm0,>orig0=112(%rsp)
+movdqa %xmm0,112(%rsp)
+
+# qhasm:   z1 = x1
+# asm 1: movdqa <x1=stack128#1,>z1=int6464#1
+# asm 2: movdqa <x1=0(%rsp),>z1=%xmm0
+movdqa 0(%rsp),%xmm0
+
+# qhasm:   z6 = z1[2,2,2,2]
+# asm 1: pshufd $0xaa,<z1=int6464#1,>z6=int6464#2
+# asm 2: pshufd $0xaa,<z1=%xmm0,>z6=%xmm1
+pshufd $0xaa,%xmm0,%xmm1
+
+# qhasm:   z11 = z1[3,3,3,3]
+# asm 1: pshufd $0xff,<z1=int6464#1,>z11=int6464#3
+# asm 2: pshufd $0xff,<z1=%xmm0,>z11=%xmm2
+pshufd $0xff,%xmm0,%xmm2
+
+# qhasm:   z12 = z1[0,0,0,0]
+# asm 1: pshufd $0x00,<z1=int6464#1,>z12=int6464#4
+# asm 2: pshufd $0x00,<z1=%xmm0,>z12=%xmm3
+pshufd $0x00,%xmm0,%xmm3
+
+# qhasm:   z1 = z1[1,1,1,1]
+# asm 1: pshufd $0x55,<z1=int6464#1,>z1=int6464#1
+# asm 2: pshufd $0x55,<z1=%xmm0,>z1=%xmm0
+pshufd $0x55,%xmm0,%xmm0
+
+# qhasm:   orig6 = z6
+# asm 1: movdqa <z6=int6464#2,>orig6=stack128#9
+# asm 2: movdqa <z6=%xmm1,>orig6=128(%rsp)
+movdqa %xmm1,128(%rsp)
+
+# qhasm:   orig11 = z11
+# asm 1: movdqa <z11=int6464#3,>orig11=stack128#10
+# asm 2: movdqa <z11=%xmm2,>orig11=144(%rsp)
+movdqa %xmm2,144(%rsp)
+
+# qhasm:   orig12 = z12
+# asm 1: movdqa <z12=int6464#4,>orig12=stack128#11
+# asm 2: movdqa <z12=%xmm3,>orig12=160(%rsp)
+movdqa %xmm3,160(%rsp)
+
+# qhasm:   orig1 = z1
+# asm 1: movdqa <z1=int6464#1,>orig1=stack128#12
+# asm 2: movdqa <z1=%xmm0,>orig1=176(%rsp)
+movdqa %xmm0,176(%rsp)
+
+# qhasm:   z2 = x2
+# asm 1: movdqa <x2=stack128#2,>z2=int6464#1
+# asm 2: movdqa <x2=16(%rsp),>z2=%xmm0
+movdqa 16(%rsp),%xmm0
+
+# qhasm:   z7 = z2[3,3,3,3]
+# asm 1: pshufd $0xff,<z2=int6464#1,>z7=int6464#2
+# asm 2: pshufd $0xff,<z2=%xmm0,>z7=%xmm1
+pshufd $0xff,%xmm0,%xmm1
+
+# qhasm:   z13 = z2[1,1,1,1]
+# asm 1: pshufd $0x55,<z2=int6464#1,>z13=int6464#3
+# asm 2: pshufd $0x55,<z2=%xmm0,>z13=%xmm2
+pshufd $0x55,%xmm0,%xmm2
+
+# qhasm:   z2 = z2[2,2,2,2]
+# asm 1: pshufd $0xaa,<z2=int6464#1,>z2=int6464#1
+# asm 2: pshufd $0xaa,<z2=%xmm0,>z2=%xmm0
+pshufd $0xaa,%xmm0,%xmm0
+
+# qhasm:   orig7 = z7
+# asm 1: movdqa <z7=int6464#2,>orig7=stack128#13
+# asm 2: movdqa <z7=%xmm1,>orig7=192(%rsp)
+movdqa %xmm1,192(%rsp)
+
+# qhasm:   orig13 = z13
+# asm 1: movdqa <z13=int6464#3,>orig13=stack128#14
+# asm 2: movdqa <z13=%xmm2,>orig13=208(%rsp)
+movdqa %xmm2,208(%rsp)
+
+# qhasm:   orig2 = z2
+# asm 1: movdqa <z2=int6464#1,>orig2=stack128#15
+# asm 2: movdqa <z2=%xmm0,>orig2=224(%rsp)
+movdqa %xmm0,224(%rsp)
+
+# qhasm:   z3 = x3
+# asm 1: movdqa <x3=stack128#3,>z3=int6464#1
+# asm 2: movdqa <x3=32(%rsp),>z3=%xmm0
+movdqa 32(%rsp),%xmm0
+
+# qhasm:   z4 = z3[0,0,0,0]
+# asm 1: pshufd $0x00,<z3=int6464#1,>z4=int6464#2
+# asm 2: pshufd $0x00,<z3=%xmm0,>z4=%xmm1
+pshufd $0x00,%xmm0,%xmm1
+
+# qhasm:   z14 = z3[2,2,2,2]
+# asm 1: pshufd $0xaa,<z3=int6464#1,>z14=int6464#3
+# asm 2: pshufd $0xaa,<z3=%xmm0,>z14=%xmm2
+pshufd $0xaa,%xmm0,%xmm2
+
+# qhasm:   z3 = z3[3,3,3,3]
+# asm 1: pshufd $0xff,<z3=int6464#1,>z3=int6464#1
+# asm 2: pshufd $0xff,<z3=%xmm0,>z3=%xmm0
+pshufd $0xff,%xmm0,%xmm0
+
+# qhasm:   orig4 = z4
+# asm 1: movdqa <z4=int6464#2,>orig4=stack128#16
+# asm 2: movdqa <z4=%xmm1,>orig4=240(%rsp)
+movdqa %xmm1,240(%rsp)
+
+# qhasm:   orig14 = z14
+# asm 1: movdqa <z14=int6464#3,>orig14=stack128#17
+# asm 2: movdqa <z14=%xmm2,>orig14=256(%rsp)
+movdqa %xmm2,256(%rsp)
+
+# qhasm:   orig3 = z3
+# asm 1: movdqa <z3=int6464#1,>orig3=stack128#18
+# asm 2: movdqa <z3=%xmm0,>orig3=272(%rsp)
+movdqa %xmm0,272(%rsp)
+
+# qhasm: bytesatleast256:
+._bytesatleast256:
+
+# qhasm:   in8 = ((uint32 *)&x2)[0]
+# asm 1: movl <x2=stack128#2,>in8=int64#3d
+# asm 2: movl <x2=16(%rsp),>in8=%edx
+movl 16(%rsp),%edx
+
+# qhasm:   in9 = ((uint32 *)&x3)[1]
+# asm 1: movl 4+<x3=stack128#3,>in9=int64#4d
+# asm 2: movl 4+<x3=32(%rsp),>in9=%ecx
+movl 4+32(%rsp),%ecx
+
+# qhasm:   ((uint32 *) &orig8)[0] = in8
+# asm 1: movl <in8=int64#3d,>orig8=stack128#19
+# asm 2: movl <in8=%edx,>orig8=288(%rsp)
+movl %edx,288(%rsp)
+
+# qhasm:   ((uint32 *) &orig9)[0] = in9
+# asm 1: movl <in9=int64#4d,>orig9=stack128#20
+# asm 2: movl <in9=%ecx,>orig9=304(%rsp)
+movl %ecx,304(%rsp)
+
+# qhasm:   in8 += 1
+# asm 1: add  $1,<in8=int64#3
+# asm 2: add  $1,<in8=%rdx
+add  $1,%rdx
+
+# qhasm:   in9 <<= 32
+# asm 1: shl  $32,<in9=int64#4
+# asm 2: shl  $32,<in9=%rcx
+shl  $32,%rcx
+
+# qhasm:   in8 += in9
+# asm 1: add  <in9=int64#4,<in8=int64#3
+# asm 2: add  <in9=%rcx,<in8=%rdx
+add  %rcx,%rdx
+
+# qhasm:   in9 = in8
+# asm 1: mov  <in8=int64#3,>in9=int64#4
+# asm 2: mov  <in8=%rdx,>in9=%rcx
+mov  %rdx,%rcx
+
+# qhasm:   (uint64) in9 >>= 32
+# asm 1: shr  $32,<in9=int64#4
+# asm 2: shr  $32,<in9=%rcx
+shr  $32,%rcx
+
+# qhasm:   ((uint32 *) &orig8)[1] = in8
+# asm 1: movl <in8=int64#3d,4+<orig8=stack128#19
+# asm 2: movl <in8=%edx,4+<orig8=288(%rsp)
+movl %edx,4+288(%rsp)
+
+# qhasm:   ((uint32 *) &orig9)[1] = in9
+# asm 1: movl <in9=int64#4d,4+<orig9=stack128#20
+# asm 2: movl <in9=%ecx,4+<orig9=304(%rsp)
+movl %ecx,4+304(%rsp)
+
+# qhasm:   in8 += 1
+# asm 1: add  $1,<in8=int64#3
+# asm 2: add  $1,<in8=%rdx
+add  $1,%rdx
+
+# qhasm:   in9 <<= 32
+# asm 1: shl  $32,<in9=int64#4
+# asm 2: shl  $32,<in9=%rcx
+shl  $32,%rcx
+
+# qhasm:   in8 += in9
+# asm 1: add  <in9=int64#4,<in8=int64#3
+# asm 2: add  <in9=%rcx,<in8=%rdx
+add  %rcx,%rdx
+
+# qhasm:   in9 = in8
+# asm 1: mov  <in8=int64#3,>in9=int64#4
+# asm 2: mov  <in8=%rdx,>in9=%rcx
+mov  %rdx,%rcx
+
+# qhasm:   (uint64) in9 >>= 32
+# asm 1: shr  $32,<in9=int64#4
+# asm 2: shr  $32,<in9=%rcx
+shr  $32,%rcx
+
+# qhasm:   ((uint32 *) &orig8)[2] = in8
+# asm 1: movl <in8=int64#3d,8+<orig8=stack128#19
+# asm 2: movl <in8=%edx,8+<orig8=288(%rsp)
+movl %edx,8+288(%rsp)
+
+# qhasm:   ((uint32 *) &orig9)[2] = in9
+# asm 1: movl <in9=int64#4d,8+<orig9=stack128#20
+# asm 2: movl <in9=%ecx,8+<orig9=304(%rsp)
+movl %ecx,8+304(%rsp)
+
+# qhasm:   in8 += 1
+# asm 1: add  $1,<in8=int64#3
+# asm 2: add  $1,<in8=%rdx
+add  $1,%rdx
+
+# qhasm:   in9 <<= 32
+# asm 1: shl  $32,<in9=int64#4
+# asm 2: shl  $32,<in9=%rcx
+shl  $32,%rcx
+
+# qhasm:   in8 += in9
+# asm 1: add  <in9=int64#4,<in8=int64#3
+# asm 2: add  <in9=%rcx,<in8=%rdx
+add  %rcx,%rdx
+
+# qhasm:   in9 = in8
+# asm 1: mov  <in8=int64#3,>in9=int64#4
+# asm 2: mov  <in8=%rdx,>in9=%rcx
+mov  %rdx,%rcx
+
+# qhasm:   (uint64) in9 >>= 32
+# asm 1: shr  $32,<in9=int64#4
+# asm 2: shr  $32,<in9=%rcx
+shr  $32,%rcx
+
+# qhasm:   ((uint32 *) &orig8)[3] = in8
+# asm 1: movl <in8=int64#3d,12+<orig8=stack128#19
+# asm 2: movl <in8=%edx,12+<orig8=288(%rsp)
+movl %edx,12+288(%rsp)
+
+# qhasm:   ((uint32 *) &orig9)[3] = in9
+# asm 1: movl <in9=int64#4d,12+<orig9=stack128#20
+# asm 2: movl <in9=%ecx,12+<orig9=304(%rsp)
+movl %ecx,12+304(%rsp)
+
+# qhasm:   in8 += 1
+# asm 1: add  $1,<in8=int64#3
+# asm 2: add  $1,<in8=%rdx
+add  $1,%rdx
+
+# qhasm:   in9 <<= 32
+# asm 1: shl  $32,<in9=int64#4
+# asm 2: shl  $32,<in9=%rcx
+shl  $32,%rcx
+
+# qhasm:   in8 += in9
+# asm 1: add  <in9=int64#4,<in8=int64#3
+# asm 2: add  <in9=%rcx,<in8=%rdx
+add  %rcx,%rdx
+
+# qhasm:   in9 = in8
+# asm 1: mov  <in8=int64#3,>in9=int64#4
+# asm 2: mov  <in8=%rdx,>in9=%rcx
+mov  %rdx,%rcx
+
+# qhasm:   (uint64) in9 >>= 32
+# asm 1: shr  $32,<in9=int64#4
+# asm 2: shr  $32,<in9=%rcx
+shr  $32,%rcx
+
+# qhasm:   ((uint32 *)&x2)[0] = in8
+# asm 1: movl <in8=int64#3d,>x2=stack128#2
+# asm 2: movl <in8=%edx,>x2=16(%rsp)
+movl %edx,16(%rsp)
+
+# qhasm:   ((uint32 *)&x3)[1] = in9
+# asm 1: movl <in9=int64#4d,4+<x3=stack128#3
+# asm 2: movl <in9=%ecx,4+<x3=32(%rsp)
+movl %ecx,4+32(%rsp)
+
+# qhasm:   bytes_backup = bytes
+# asm 1: movq <bytes=int64#6,>bytes_backup=stack64#8
+# asm 2: movq <bytes=%r9,>bytes_backup=408(%rsp)
+movq %r9,408(%rsp)
+
+# qhasm: i = 20
+# asm 1: mov  $20,>i=int64#3
+# asm 2: mov  $20,>i=%rdx
+mov  $20,%rdx
+
+# qhasm:   z5 = orig5
+# asm 1: movdqa <orig5=stack128#5,>z5=int6464#1
+# asm 2: movdqa <orig5=64(%rsp),>z5=%xmm0
+movdqa 64(%rsp),%xmm0
+
+# qhasm:   z10 = orig10
+# asm 1: movdqa <orig10=stack128#6,>z10=int6464#2
+# asm 2: movdqa <orig10=80(%rsp),>z10=%xmm1
+movdqa 80(%rsp),%xmm1
+
+# qhasm:   z15 = orig15
+# asm 1: movdqa <orig15=stack128#7,>z15=int6464#3
+# asm 2: movdqa <orig15=96(%rsp),>z15=%xmm2
+movdqa 96(%rsp),%xmm2
+
+# qhasm:   z14 = orig14
+# asm 1: movdqa <orig14=stack128#17,>z14=int6464#4
+# asm 2: movdqa <orig14=256(%rsp),>z14=%xmm3
+movdqa 256(%rsp),%xmm3
+
+# qhasm:   z3 = orig3
+# asm 1: movdqa <orig3=stack128#18,>z3=int6464#5
+# asm 2: movdqa <orig3=272(%rsp),>z3=%xmm4
+movdqa 272(%rsp),%xmm4
+
+# qhasm:   z6 = orig6
+# asm 1: movdqa <orig6=stack128#9,>z6=int6464#6
+# asm 2: movdqa <orig6=128(%rsp),>z6=%xmm5
+movdqa 128(%rsp),%xmm5
+
+# qhasm:   z11 = orig11
+# asm 1: movdqa <orig11=stack128#10,>z11=int6464#7
+# asm 2: movdqa <orig11=144(%rsp),>z11=%xmm6
+movdqa 144(%rsp),%xmm6
+
+# qhasm:   z1 = orig1
+# asm 1: movdqa <orig1=stack128#12,>z1=int6464#8
+# asm 2: movdqa <orig1=176(%rsp),>z1=%xmm7
+movdqa 176(%rsp),%xmm7
+
+# qhasm:   z7 = orig7
+# asm 1: movdqa <orig7=stack128#13,>z7=int6464#9
+# asm 2: movdqa <orig7=192(%rsp),>z7=%xmm8
+movdqa 192(%rsp),%xmm8
+
+# qhasm:   z13 = orig13
+# asm 1: movdqa <orig13=stack128#14,>z13=int6464#10
+# asm 2: movdqa <orig13=208(%rsp),>z13=%xmm9
+movdqa 208(%rsp),%xmm9
+
+# qhasm:   z2 = orig2
+# asm 1: movdqa <orig2=stack128#15,>z2=int6464#11
+# asm 2: movdqa <orig2=224(%rsp),>z2=%xmm10
+movdqa 224(%rsp),%xmm10
+
+# qhasm:   z9 = orig9
+# asm 1: movdqa <orig9=stack128#20,>z9=int6464#12
+# asm 2: movdqa <orig9=304(%rsp),>z9=%xmm11
+movdqa 304(%rsp),%xmm11
+
+# qhasm:   z0 = orig0
+# asm 1: movdqa <orig0=stack128#8,>z0=int6464#13
+# asm 2: movdqa <orig0=112(%rsp),>z0=%xmm12
+movdqa 112(%rsp),%xmm12
+
+# qhasm:   z12 = orig12
+# asm 1: movdqa <orig12=stack128#11,>z12=int6464#14
+# asm 2: movdqa <orig12=160(%rsp),>z12=%xmm13
+movdqa 160(%rsp),%xmm13
+
+# qhasm:   z4 = orig4
+# asm 1: movdqa <orig4=stack128#16,>z4=int6464#15
+# asm 2: movdqa <orig4=240(%rsp),>z4=%xmm14
+movdqa 240(%rsp),%xmm14
+
+# qhasm:   z8 = orig8
+# asm 1: movdqa <orig8=stack128#19,>z8=int6464#16
+# asm 2: movdqa <orig8=288(%rsp),>z8=%xmm15
+movdqa 288(%rsp),%xmm15
+
+# qhasm: mainloop1:
+._mainloop1:
+
+# qhasm: 						z10_stack = z10
+# asm 1: movdqa <z10=int6464#2,>z10_stack=stack128#21
+# asm 2: movdqa <z10=%xmm1,>z10_stack=320(%rsp)
+movdqa %xmm1,320(%rsp)
+
+# qhasm: 								z15_stack = z15
+# asm 1: movdqa <z15=int6464#3,>z15_stack=stack128#22
+# asm 2: movdqa <z15=%xmm2,>z15_stack=336(%rsp)
+movdqa %xmm2,336(%rsp)
+
+# qhasm: 		y4 = z12
+# asm 1: movdqa <z12=int6464#14,>y4=int6464#2
+# asm 2: movdqa <z12=%xmm13,>y4=%xmm1
+movdqa %xmm13,%xmm1
+
+# qhasm: uint32323232	y4 += z0
+# asm 1: paddd <z0=int6464#13,<y4=int6464#2
+# asm 2: paddd <z0=%xmm12,<y4=%xmm1
+paddd %xmm12,%xmm1
+
+# qhasm: 		r4 = y4
+# asm 1: movdqa <y4=int6464#2,>r4=int6464#3
+# asm 2: movdqa <y4=%xmm1,>r4=%xmm2
+movdqa %xmm1,%xmm2
+
+# qhasm: uint32323232	y4 <<= 7
+# asm 1: pslld $7,<y4=int6464#2
+# asm 2: pslld $7,<y4=%xmm1
+pslld $7,%xmm1
+
+# qhasm: 		z4 ^= y4
+# asm 1: pxor  <y4=int6464#2,<z4=int6464#15
+# asm 2: pxor  <y4=%xmm1,<z4=%xmm14
+pxor  %xmm1,%xmm14
+
+# qhasm: uint32323232	r4 >>= 25
+# asm 1: psrld $25,<r4=int6464#3
+# asm 2: psrld $25,<r4=%xmm2
+psrld $25,%xmm2
+
+# qhasm: 		z4 ^= r4
+# asm 1: pxor  <r4=int6464#3,<z4=int6464#15
+# asm 2: pxor  <r4=%xmm2,<z4=%xmm14
+pxor  %xmm2,%xmm14
+
+# qhasm: 				y9 = z1
+# asm 1: movdqa <z1=int6464#8,>y9=int6464#2
+# asm 2: movdqa <z1=%xmm7,>y9=%xmm1
+movdqa %xmm7,%xmm1
+
+# qhasm: uint32323232			y9 += z5
+# asm 1: paddd <z5=int6464#1,<y9=int6464#2
+# asm 2: paddd <z5=%xmm0,<y9=%xmm1
+paddd %xmm0,%xmm1
+
+# qhasm: 				r9 = y9
+# asm 1: movdqa <y9=int6464#2,>r9=int6464#3
+# asm 2: movdqa <y9=%xmm1,>r9=%xmm2
+movdqa %xmm1,%xmm2
+
+# qhasm: uint32323232			y9 <<= 7
+# asm 1: pslld $7,<y9=int6464#2
+# asm 2: pslld $7,<y9=%xmm1
+pslld $7,%xmm1
+
+# qhasm: 				z9 ^= y9
+# asm 1: pxor  <y9=int6464#2,<z9=int6464#12
+# asm 2: pxor  <y9=%xmm1,<z9=%xmm11
+pxor  %xmm1,%xmm11
+
+# qhasm: uint32323232			r9 >>= 25
+# asm 1: psrld $25,<r9=int6464#3
+# asm 2: psrld $25,<r9=%xmm2
+psrld $25,%xmm2
+
+# qhasm: 				z9 ^= r9
+# asm 1: pxor  <r9=int6464#3,<z9=int6464#12
+# asm 2: pxor  <r9=%xmm2,<z9=%xmm11
+pxor  %xmm2,%xmm11
+
+# qhasm: 		y8 = z0
+# asm 1: movdqa <z0=int6464#13,>y8=int6464#2
+# asm 2: movdqa <z0=%xmm12,>y8=%xmm1
+movdqa %xmm12,%xmm1
+
+# qhasm: uint32323232	y8 += z4
+# asm 1: paddd <z4=int6464#15,<y8=int6464#2
+# asm 2: paddd <z4=%xmm14,<y8=%xmm1
+paddd %xmm14,%xmm1
+
+# qhasm: 		r8 = y8
+# asm 1: movdqa <y8=int6464#2,>r8=int6464#3
+# asm 2: movdqa <y8=%xmm1,>r8=%xmm2
+movdqa %xmm1,%xmm2
+
+# qhasm: uint32323232	y8 <<= 9
+# asm 1: pslld $9,<y8=int6464#2
+# asm 2: pslld $9,<y8=%xmm1
+pslld $9,%xmm1
+
+# qhasm: 		z8 ^= y8
+# asm 1: pxor  <y8=int6464#2,<z8=int6464#16
+# asm 2: pxor  <y8=%xmm1,<z8=%xmm15
+pxor  %xmm1,%xmm15
+
+# qhasm: uint32323232	r8 >>= 23
+# asm 1: psrld $23,<r8=int6464#3
+# asm 2: psrld $23,<r8=%xmm2
+psrld $23,%xmm2
+
+# qhasm: 		z8 ^= r8
+# asm 1: pxor  <r8=int6464#3,<z8=int6464#16
+# asm 2: pxor  <r8=%xmm2,<z8=%xmm15
+pxor  %xmm2,%xmm15
+
+# qhasm: 				y13 = z5
+# asm 1: movdqa <z5=int6464#1,>y13=int6464#2
+# asm 2: movdqa <z5=%xmm0,>y13=%xmm1
+movdqa %xmm0,%xmm1
+
+# qhasm: uint32323232			y13 += z9
+# asm 1: paddd <z9=int6464#12,<y13=int6464#2
+# asm 2: paddd <z9=%xmm11,<y13=%xmm1
+paddd %xmm11,%xmm1
+
+# qhasm: 				r13 = y13
+# asm 1: movdqa <y13=int6464#2,>r13=int6464#3
+# asm 2: movdqa <y13=%xmm1,>r13=%xmm2
+movdqa %xmm1,%xmm2
+
+# qhasm: uint32323232			y13 <<= 9
+# asm 1: pslld $9,<y13=int6464#2
+# asm 2: pslld $9,<y13=%xmm1
+pslld $9,%xmm1
+
+# qhasm: 				z13 ^= y13
+# asm 1: pxor  <y13=int6464#2,<z13=int6464#10
+# asm 2: pxor  <y13=%xmm1,<z13=%xmm9
+pxor  %xmm1,%xmm9
+
+# qhasm: uint32323232			r13 >>= 23
+# asm 1: psrld $23,<r13=int6464#3
+# asm 2: psrld $23,<r13=%xmm2
+psrld $23,%xmm2
+
+# qhasm: 				z13 ^= r13
+# asm 1: pxor  <r13=int6464#3,<z13=int6464#10
+# asm 2: pxor  <r13=%xmm2,<z13=%xmm9
+pxor  %xmm2,%xmm9
+
+# qhasm: 		y12 = z4
+# asm 1: movdqa <z4=int6464#15,>y12=int6464#2
+# asm 2: movdqa <z4=%xmm14,>y12=%xmm1
+movdqa %xmm14,%xmm1
+
+# qhasm: uint32323232	y12 += z8
+# asm 1: paddd <z8=int6464#16,<y12=int6464#2
+# asm 2: paddd <z8=%xmm15,<y12=%xmm1
+paddd %xmm15,%xmm1
+
+# qhasm: 		r12 = y12
+# asm 1: movdqa <y12=int6464#2,>r12=int6464#3
+# asm 2: movdqa <y12=%xmm1,>r12=%xmm2
+movdqa %xmm1,%xmm2
+
+# qhasm: uint32323232	y12 <<= 13
+# asm 1: pslld $13,<y12=int6464#2
+# asm 2: pslld $13,<y12=%xmm1
+pslld $13,%xmm1
+
+# qhasm: 		z12 ^= y12
+# asm 1: pxor  <y12=int6464#2,<z12=int6464#14
+# asm 2: pxor  <y12=%xmm1,<z12=%xmm13
+pxor  %xmm1,%xmm13
+
+# qhasm: uint32323232	r12 >>= 19
+# asm 1: psrld $19,<r12=int6464#3
+# asm 2: psrld $19,<r12=%xmm2
+psrld $19,%xmm2
+
+# qhasm: 		z12 ^= r12
+# asm 1: pxor  <r12=int6464#3,<z12=int6464#14
+# asm 2: pxor  <r12=%xmm2,<z12=%xmm13
+pxor  %xmm2,%xmm13
+
+# qhasm: 				y1 = z9
+# asm 1: movdqa <z9=int6464#12,>y1=int6464#2
+# asm 2: movdqa <z9=%xmm11,>y1=%xmm1
+movdqa %xmm11,%xmm1
+
+# qhasm: uint32323232			y1 += z13
+# asm 1: paddd <z13=int6464#10,<y1=int6464#2
+# asm 2: paddd <z13=%xmm9,<y1=%xmm1
+paddd %xmm9,%xmm1
+
+# qhasm: 				r1 = y1
+# asm 1: movdqa <y1=int6464#2,>r1=int6464#3
+# asm 2: movdqa <y1=%xmm1,>r1=%xmm2
+movdqa %xmm1,%xmm2
+
+# qhasm: uint32323232			y1 <<= 13
+# asm 1: pslld $13,<y1=int6464#2
+# asm 2: pslld $13,<y1=%xmm1
+pslld $13,%xmm1
+
+# qhasm: 				z1 ^= y1
+# asm 1: pxor  <y1=int6464#2,<z1=int6464#8
+# asm 2: pxor  <y1=%xmm1,<z1=%xmm7
+pxor  %xmm1,%xmm7
+
+# qhasm: uint32323232			r1 >>= 19
+# asm 1: psrld $19,<r1=int6464#3
+# asm 2: psrld $19,<r1=%xmm2
+psrld $19,%xmm2
+
+# qhasm: 				z1 ^= r1
+# asm 1: pxor  <r1=int6464#3,<z1=int6464#8
+# asm 2: pxor  <r1=%xmm2,<z1=%xmm7
+pxor  %xmm2,%xmm7
+
+# qhasm: 		y0 = z8
+# asm 1: movdqa <z8=int6464#16,>y0=int6464#2
+# asm 2: movdqa <z8=%xmm15,>y0=%xmm1
+movdqa %xmm15,%xmm1
+
+# qhasm: uint32323232	y0 += z12
+# asm 1: paddd <z12=int6464#14,<y0=int6464#2
+# asm 2: paddd <z12=%xmm13,<y0=%xmm1
+paddd %xmm13,%xmm1
+
+# qhasm: 		r0 = y0
+# asm 1: movdqa <y0=int6464#2,>r0=int6464#3
+# asm 2: movdqa <y0=%xmm1,>r0=%xmm2
+movdqa %xmm1,%xmm2
+
+# qhasm: uint32323232	y0 <<= 18
+# asm 1: pslld $18,<y0=int6464#2
+# asm 2: pslld $18,<y0=%xmm1
+pslld $18,%xmm1
+
+# qhasm: 		z0 ^= y0
+# asm 1: pxor  <y0=int6464#2,<z0=int6464#13
+# asm 2: pxor  <y0=%xmm1,<z0=%xmm12
+pxor  %xmm1,%xmm12
+
+# qhasm: uint32323232	r0 >>= 14
+# asm 1: psrld $14,<r0=int6464#3
+# asm 2: psrld $14,<r0=%xmm2
+psrld $14,%xmm2
+
+# qhasm: 		z0 ^= r0
+# asm 1: pxor  <r0=int6464#3,<z0=int6464#13
+# asm 2: pxor  <r0=%xmm2,<z0=%xmm12
+pxor  %xmm2,%xmm12
+
+# qhasm: 						z10 = z10_stack
+# asm 1: movdqa <z10_stack=stack128#21,>z10=int6464#2
+# asm 2: movdqa <z10_stack=320(%rsp),>z10=%xmm1
+movdqa 320(%rsp),%xmm1
+
+# qhasm: 		z0_stack = z0
+# asm 1: movdqa <z0=int6464#13,>z0_stack=stack128#21
+# asm 2: movdqa <z0=%xmm12,>z0_stack=320(%rsp)
+movdqa %xmm12,320(%rsp)
+
+# qhasm: 				y5 = z13
+# asm 1: movdqa <z13=int6464#10,>y5=int6464#3
+# asm 2: movdqa <z13=%xmm9,>y5=%xmm2
+movdqa %xmm9,%xmm2
+
+# qhasm: uint32323232			y5 += z1
+# asm 1: paddd <z1=int6464#8,<y5=int6464#3
+# asm 2: paddd <z1=%xmm7,<y5=%xmm2
+paddd %xmm7,%xmm2
+
+# qhasm: 				r5 = y5
+# asm 1: movdqa <y5=int6464#3,>r5=int6464#13
+# asm 2: movdqa <y5=%xmm2,>r5=%xmm12
+movdqa %xmm2,%xmm12
+
+# qhasm: uint32323232			y5 <<= 18
+# asm 1: pslld $18,<y5=int6464#3
+# asm 2: pslld $18,<y5=%xmm2
+pslld $18,%xmm2
+
+# qhasm: 				z5 ^= y5
+# asm 1: pxor  <y5=int6464#3,<z5=int6464#1
+# asm 2: pxor  <y5=%xmm2,<z5=%xmm0
+pxor  %xmm2,%xmm0
+
+# qhasm: uint32323232			r5 >>= 14
+# asm 1: psrld $14,<r5=int6464#13
+# asm 2: psrld $14,<r5=%xmm12
+psrld $14,%xmm12
+
+# qhasm: 				z5 ^= r5
+# asm 1: pxor  <r5=int6464#13,<z5=int6464#1
+# asm 2: pxor  <r5=%xmm12,<z5=%xmm0
+pxor  %xmm12,%xmm0
+
+# qhasm: 						y14 = z6
+# asm 1: movdqa <z6=int6464#6,>y14=int6464#3
+# asm 2: movdqa <z6=%xmm5,>y14=%xmm2
+movdqa %xmm5,%xmm2
+
+# qhasm: uint32323232					y14 += z10
+# asm 1: paddd <z10=int6464#2,<y14=int6464#3
+# asm 2: paddd <z10=%xmm1,<y14=%xmm2
+paddd %xmm1,%xmm2
+
+# qhasm: 						r14 = y14
+# asm 1: movdqa <y14=int6464#3,>r14=int6464#13
+# asm 2: movdqa <y14=%xmm2,>r14=%xmm12
+movdqa %xmm2,%xmm12
+
+# qhasm: uint32323232					y14 <<= 7
+# asm 1: pslld $7,<y14=int6464#3
+# asm 2: pslld $7,<y14=%xmm2
+pslld $7,%xmm2
+
+# qhasm: 						z14 ^= y14
+# asm 1: pxor  <y14=int6464#3,<z14=int6464#4
+# asm 2: pxor  <y14=%xmm2,<z14=%xmm3
+pxor  %xmm2,%xmm3
+
+# qhasm: uint32323232					r14 >>= 25
+# asm 1: psrld $25,<r14=int6464#13
+# asm 2: psrld $25,<r14=%xmm12
+psrld $25,%xmm12
+
+# qhasm: 						z14 ^= r14
+# asm 1: pxor  <r14=int6464#13,<z14=int6464#4
+# asm 2: pxor  <r14=%xmm12,<z14=%xmm3
+pxor  %xmm12,%xmm3
+
+# qhasm: 								z15 = z15_stack
+# asm 1: movdqa <z15_stack=stack128#22,>z15=int6464#3
+# asm 2: movdqa <z15_stack=336(%rsp),>z15=%xmm2
+movdqa 336(%rsp),%xmm2
+
+# qhasm: 				z5_stack = z5
+# asm 1: movdqa <z5=int6464#1,>z5_stack=stack128#22
+# asm 2: movdqa <z5=%xmm0,>z5_stack=336(%rsp)
+movdqa %xmm0,336(%rsp)
+
+# qhasm: 								y3 = z11
+# asm 1: movdqa <z11=int6464#7,>y3=int6464#1
+# asm 2: movdqa <z11=%xmm6,>y3=%xmm0
+movdqa %xmm6,%xmm0
+
+# qhasm: uint32323232							y3 += z15
+# asm 1: paddd <z15=int6464#3,<y3=int6464#1
+# asm 2: paddd <z15=%xmm2,<y3=%xmm0
+paddd %xmm2,%xmm0
+
+# qhasm: 								r3 = y3
+# asm 1: movdqa <y3=int6464#1,>r3=int6464#13
+# asm 2: movdqa <y3=%xmm0,>r3=%xmm12
+movdqa %xmm0,%xmm12
+
+# qhasm: uint32323232							y3 <<= 7
+# asm 1: pslld $7,<y3=int6464#1
+# asm 2: pslld $7,<y3=%xmm0
+pslld $7,%xmm0
+
+# qhasm: 								z3 ^= y3
+# asm 1: pxor  <y3=int6464#1,<z3=int6464#5
+# asm 2: pxor  <y3=%xmm0,<z3=%xmm4
+pxor  %xmm0,%xmm4
+
+# qhasm: uint32323232							r3 >>= 25
+# asm 1: psrld $25,<r3=int6464#13
+# asm 2: psrld $25,<r3=%xmm12
+psrld $25,%xmm12
+
+# qhasm: 								z3 ^= r3
+# asm 1: pxor  <r3=int6464#13,<z3=int6464#5
+# asm 2: pxor  <r3=%xmm12,<z3=%xmm4
+pxor  %xmm12,%xmm4
+
+# qhasm: 						y2 = z10
+# asm 1: movdqa <z10=int6464#2,>y2=int6464#1
+# asm 2: movdqa <z10=%xmm1,>y2=%xmm0
+movdqa %xmm1,%xmm0
+
+# qhasm: uint32323232					y2 += z14
+# asm 1: paddd <z14=int6464#4,<y2=int6464#1
+# asm 2: paddd <z14=%xmm3,<y2=%xmm0
+paddd %xmm3,%xmm0
+
+# qhasm: 						r2 = y2
+# asm 1: movdqa <y2=int6464#1,>r2=int6464#13
+# asm 2: movdqa <y2=%xmm0,>r2=%xmm12
+movdqa %xmm0,%xmm12
+
+# qhasm: uint32323232					y2 <<= 9
+# asm 1: pslld $9,<y2=int6464#1
+# asm 2: pslld $9,<y2=%xmm0
+pslld $9,%xmm0
+
+# qhasm: 						z2 ^= y2
+# asm 1: pxor  <y2=int6464#1,<z2=int6464#11
+# asm 2: pxor  <y2=%xmm0,<z2=%xmm10
+pxor  %xmm0,%xmm10
+
+# qhasm: uint32323232					r2 >>= 23
+# asm 1: psrld $23,<r2=int6464#13
+# asm 2: psrld $23,<r2=%xmm12
+psrld $23,%xmm12
+
+# qhasm: 						z2 ^= r2
+# asm 1: pxor  <r2=int6464#13,<z2=int6464#11
+# asm 2: pxor  <r2=%xmm12,<z2=%xmm10
+pxor  %xmm12,%xmm10
+
+# qhasm: 								y7 = z15
+# asm 1: movdqa <z15=int6464#3,>y7=int6464#1
+# asm 2: movdqa <z15=%xmm2,>y7=%xmm0
+movdqa %xmm2,%xmm0
+
+# qhasm: uint32323232							y7 += z3
+# asm 1: paddd <z3=int6464#5,<y7=int6464#1
+# asm 2: paddd <z3=%xmm4,<y7=%xmm0
+paddd %xmm4,%xmm0
+
+# qhasm: 								r7 = y7
+# asm 1: movdqa <y7=int6464#1,>r7=int6464#13
+# asm 2: movdqa <y7=%xmm0,>r7=%xmm12
+movdqa %xmm0,%xmm12
+
+# qhasm: uint32323232							y7 <<= 9
+# asm 1: pslld $9,<y7=int6464#1
+# asm 2: pslld $9,<y7=%xmm0
+pslld $9,%xmm0
+
+# qhasm: 								z7 ^= y7
+# asm 1: pxor  <y7=int6464#1,<z7=int6464#9
+# asm 2: pxor  <y7=%xmm0,<z7=%xmm8
+pxor  %xmm0,%xmm8
+
+# qhasm: uint32323232							r7 >>= 23
+# asm 1: psrld $23,<r7=int6464#13
+# asm 2: psrld $23,<r7=%xmm12
+psrld $23,%xmm12
+
+# qhasm: 								z7 ^= r7
+# asm 1: pxor  <r7=int6464#13,<z7=int6464#9
+# asm 2: pxor  <r7=%xmm12,<z7=%xmm8
+pxor  %xmm12,%xmm8
+
+# qhasm: 						y6 = z14
+# asm 1: movdqa <z14=int6464#4,>y6=int6464#1
+# asm 2: movdqa <z14=%xmm3,>y6=%xmm0
+movdqa %xmm3,%xmm0
+
+# qhasm: uint32323232					y6 += z2
+# asm 1: paddd <z2=int6464#11,<y6=int6464#1
+# asm 2: paddd <z2=%xmm10,<y6=%xmm0
+paddd %xmm10,%xmm0
+
+# qhasm: 						r6 = y6
+# asm 1: movdqa <y6=int6464#1,>r6=int6464#13
+# asm 2: movdqa <y6=%xmm0,>r6=%xmm12
+movdqa %xmm0,%xmm12
+
+# qhasm: uint32323232					y6 <<= 13
+# asm 1: pslld $13,<y6=int6464#1
+# asm 2: pslld $13,<y6=%xmm0
+pslld $13,%xmm0
+
+# qhasm: 						z6 ^= y6
+# asm 1: pxor  <y6=int6464#1,<z6=int6464#6
+# asm 2: pxor  <y6=%xmm0,<z6=%xmm5
+pxor  %xmm0,%xmm5
+
+# qhasm: uint32323232					r6 >>= 19
+# asm 1: psrld $19,<r6=int6464#13
+# asm 2: psrld $19,<r6=%xmm12
+psrld $19,%xmm12
+
+# qhasm: 						z6 ^= r6
+# asm 1: pxor  <r6=int6464#13,<z6=int6464#6
+# asm 2: pxor  <r6=%xmm12,<z6=%xmm5
+pxor  %xmm12,%xmm5
+
+# qhasm: 								y11 = z3
+# asm 1: movdqa <z3=int6464#5,>y11=int6464#1
+# asm 2: movdqa <z3=%xmm4,>y11=%xmm0
+movdqa %xmm4,%xmm0
+
+# qhasm: uint32323232							y11 += z7
+# asm 1: paddd <z7=int6464#9,<y11=int6464#1
+# asm 2: paddd <z7=%xmm8,<y11=%xmm0
+paddd %xmm8,%xmm0
+
+# qhasm: 								r11 = y11
+# asm 1: movdqa <y11=int6464#1,>r11=int6464#13
+# asm 2: movdqa <y11=%xmm0,>r11=%xmm12
+movdqa %xmm0,%xmm12
+
+# qhasm: uint32323232							y11 <<= 13
+# asm 1: pslld $13,<y11=int6464#1
+# asm 2: pslld $13,<y11=%xmm0
+pslld $13,%xmm0
+
+# qhasm: 								z11 ^= y11
+# asm 1: pxor  <y11=int6464#1,<z11=int6464#7
+# asm 2: pxor  <y11=%xmm0,<z11=%xmm6
+pxor  %xmm0,%xmm6
+
+# qhasm: uint32323232							r11 >>= 19
+# asm 1: psrld $19,<r11=int6464#13
+# asm 2: psrld $19,<r11=%xmm12
+psrld $19,%xmm12
+
+# qhasm: 								z11 ^= r11
+# asm 1: pxor  <r11=int6464#13,<z11=int6464#7
+# asm 2: pxor  <r11=%xmm12,<z11=%xmm6
+pxor  %xmm12,%xmm6
+
+# qhasm: 						y10 = z2
+# asm 1: movdqa <z2=int6464#11,>y10=int6464#1
+# asm 2: movdqa <z2=%xmm10,>y10=%xmm0
+movdqa %xmm10,%xmm0
+
+# qhasm: uint32323232					y10 += z6
+# asm 1: paddd <z6=int6464#6,<y10=int6464#1
+# asm 2: paddd <z6=%xmm5,<y10=%xmm0
+paddd %xmm5,%xmm0
+
+# qhasm: 						r10 = y10
+# asm 1: movdqa <y10=int6464#1,>r10=int6464#13
+# asm 2: movdqa <y10=%xmm0,>r10=%xmm12
+movdqa %xmm0,%xmm12
+
+# qhasm: uint32323232					y10 <<= 18
+# asm 1: pslld $18,<y10=int6464#1
+# asm 2: pslld $18,<y10=%xmm0
+pslld $18,%xmm0
+
+# qhasm: 						z10 ^= y10
+# asm 1: pxor  <y10=int6464#1,<z10=int6464#2
+# asm 2: pxor  <y10=%xmm0,<z10=%xmm1
+pxor  %xmm0,%xmm1
+
+# qhasm: uint32323232					r10 >>= 14
+# asm 1: psrld $14,<r10=int6464#13
+# asm 2: psrld $14,<r10=%xmm12
+psrld $14,%xmm12
+
+# qhasm: 						z10 ^= r10
+# asm 1: pxor  <r10=int6464#13,<z10=int6464#2
+# asm 2: pxor  <r10=%xmm12,<z10=%xmm1
+pxor  %xmm12,%xmm1
+
+# qhasm: 		z0 = z0_stack
+# asm 1: movdqa <z0_stack=stack128#21,>z0=int6464#1
+# asm 2: movdqa <z0_stack=320(%rsp),>z0=%xmm0
+movdqa 320(%rsp),%xmm0
+
+# qhasm: 						z10_stack = z10
+# asm 1: movdqa <z10=int6464#2,>z10_stack=stack128#21
+# asm 2: movdqa <z10=%xmm1,>z10_stack=320(%rsp)
+movdqa %xmm1,320(%rsp)
+
+# qhasm: 		y1 = z3
+# asm 1: movdqa <z3=int6464#5,>y1=int6464#2
+# asm 2: movdqa <z3=%xmm4,>y1=%xmm1
+movdqa %xmm4,%xmm1
+
+# qhasm: uint32323232	y1 += z0
+# asm 1: paddd <z0=int6464#1,<y1=int6464#2
+# asm 2: paddd <z0=%xmm0,<y1=%xmm1
+paddd %xmm0,%xmm1
+
+# qhasm: 		r1 = y1
+# asm 1: movdqa <y1=int6464#2,>r1=int6464#13
+# asm 2: movdqa <y1=%xmm1,>r1=%xmm12
+movdqa %xmm1,%xmm12
+
+# qhasm: uint32323232	y1 <<= 7
+# asm 1: pslld $7,<y1=int6464#2
+# asm 2: pslld $7,<y1=%xmm1
+pslld $7,%xmm1
+
+# qhasm: 		z1 ^= y1
+# asm 1: pxor  <y1=int6464#2,<z1=int6464#8
+# asm 2: pxor  <y1=%xmm1,<z1=%xmm7
+pxor  %xmm1,%xmm7
+
+# qhasm: uint32323232	r1 >>= 25
+# asm 1: psrld $25,<r1=int6464#13
+# asm 2: psrld $25,<r1=%xmm12
+psrld $25,%xmm12
+
+# qhasm: 		z1 ^= r1
+# asm 1: pxor  <r1=int6464#13,<z1=int6464#8
+# asm 2: pxor  <r1=%xmm12,<z1=%xmm7
+pxor  %xmm12,%xmm7
+
+# qhasm: 								y15 = z7
+# asm 1: movdqa <z7=int6464#9,>y15=int6464#2
+# asm 2: movdqa <z7=%xmm8,>y15=%xmm1
+movdqa %xmm8,%xmm1
+
+# qhasm: uint32323232							y15 += z11
+# asm 1: paddd <z11=int6464#7,<y15=int6464#2
+# asm 2: paddd <z11=%xmm6,<y15=%xmm1
+paddd %xmm6,%xmm1
+
+# qhasm: 								r15 = y15
+# asm 1: movdqa <y15=int6464#2,>r15=int6464#13
+# asm 2: movdqa <y15=%xmm1,>r15=%xmm12
+movdqa %xmm1,%xmm12
+
+# qhasm: uint32323232							y15 <<= 18
+# asm 1: pslld $18,<y15=int6464#2
+# asm 2: pslld $18,<y15=%xmm1
+pslld $18,%xmm1
+
+# qhasm: 								z15 ^= y15
+# asm 1: pxor  <y15=int6464#2,<z15=int6464#3
+# asm 2: pxor  <y15=%xmm1,<z15=%xmm2
+pxor  %xmm1,%xmm2
+
+# qhasm: uint32323232							r15 >>= 14
+# asm 1: psrld $14,<r15=int6464#13
+# asm 2: psrld $14,<r15=%xmm12
+psrld $14,%xmm12
+
+# qhasm: 								z15 ^= r15
+# asm 1: pxor  <r15=int6464#13,<z15=int6464#3
+# asm 2: pxor  <r15=%xmm12,<z15=%xmm2
+pxor  %xmm12,%xmm2
+
+# qhasm: 				z5 = z5_stack
+# asm 1: movdqa <z5_stack=stack128#22,>z5=int6464#13
+# asm 2: movdqa <z5_stack=336(%rsp),>z5=%xmm12
+movdqa 336(%rsp),%xmm12
+
+# qhasm: 								z15_stack = z15
+# asm 1: movdqa <z15=int6464#3,>z15_stack=stack128#22
+# asm 2: movdqa <z15=%xmm2,>z15_stack=336(%rsp)
+movdqa %xmm2,336(%rsp)
+
+# qhasm: 				y6 = z4
+# asm 1: movdqa <z4=int6464#15,>y6=int6464#2
+# asm 2: movdqa <z4=%xmm14,>y6=%xmm1
+movdqa %xmm14,%xmm1
+
+# qhasm: uint32323232			y6 += z5
+# asm 1: paddd <z5=int6464#13,<y6=int6464#2
+# asm 2: paddd <z5=%xmm12,<y6=%xmm1
+paddd %xmm12,%xmm1
+
+# qhasm: 				r6 = y6
+# asm 1: movdqa <y6=int6464#2,>r6=int6464#3
+# asm 2: movdqa <y6=%xmm1,>r6=%xmm2
+movdqa %xmm1,%xmm2
+
+# qhasm: uint32323232			y6 <<= 7
+# asm 1: pslld $7,<y6=int6464#2
+# asm 2: pslld $7,<y6=%xmm1
+pslld $7,%xmm1
+
+# qhasm: 				z6 ^= y6
+# asm 1: pxor  <y6=int6464#2,<z6=int6464#6
+# asm 2: pxor  <y6=%xmm1,<z6=%xmm5
+pxor  %xmm1,%xmm5
+
+# qhasm: uint32323232			r6 >>= 25
+# asm 1: psrld $25,<r6=int6464#3
+# asm 2: psrld $25,<r6=%xmm2
+psrld $25,%xmm2
+
+# qhasm: 				z6 ^= r6
+# asm 1: pxor  <r6=int6464#3,<z6=int6464#6
+# asm 2: pxor  <r6=%xmm2,<z6=%xmm5
+pxor  %xmm2,%xmm5
+
+# qhasm: 		y2 = z0
+# asm 1: movdqa <z0=int6464#1,>y2=int6464#2
+# asm 2: movdqa <z0=%xmm0,>y2=%xmm1
+movdqa %xmm0,%xmm1
+
+# qhasm: uint32323232	y2 += z1
+# asm 1: paddd <z1=int6464#8,<y2=int6464#2
+# asm 2: paddd <z1=%xmm7,<y2=%xmm1
+paddd %xmm7,%xmm1
+
+# qhasm: 		r2 = y2
+# asm 1: movdqa <y2=int6464#2,>r2=int6464#3
+# asm 2: movdqa <y2=%xmm1,>r2=%xmm2
+movdqa %xmm1,%xmm2
+
+# qhasm: uint32323232	y2 <<= 9
+# asm 1: pslld $9,<y2=int6464#2
+# asm 2: pslld $9,<y2=%xmm1
+pslld $9,%xmm1
+
+# qhasm: 		z2 ^= y2
+# asm 1: pxor  <y2=int6464#2,<z2=int6464#11
+# asm 2: pxor  <y2=%xmm1,<z2=%xmm10
+pxor  %xmm1,%xmm10
+
+# qhasm: uint32323232	r2 >>= 23
+# asm 1: psrld $23,<r2=int6464#3
+# asm 2: psrld $23,<r2=%xmm2
+psrld $23,%xmm2
+
+# qhasm: 		z2 ^= r2
+# asm 1: pxor  <r2=int6464#3,<z2=int6464#11
+# asm 2: pxor  <r2=%xmm2,<z2=%xmm10
+pxor  %xmm2,%xmm10
+
+# qhasm: 				y7 = z5
+# asm 1: movdqa <z5=int6464#13,>y7=int6464#2
+# asm 2: movdqa <z5=%xmm12,>y7=%xmm1
+movdqa %xmm12,%xmm1
+
+# qhasm: uint32323232			y7 += z6
+# asm 1: paddd <z6=int6464#6,<y7=int6464#2
+# asm 2: paddd <z6=%xmm5,<y7=%xmm1
+paddd %xmm5,%xmm1
+
+# qhasm: 				r7 = y7
+# asm 1: movdqa <y7=int6464#2,>r7=int6464#3
+# asm 2: movdqa <y7=%xmm1,>r7=%xmm2
+movdqa %xmm1,%xmm2
+
+# qhasm: uint32323232			y7 <<= 9
+# asm 1: pslld $9,<y7=int6464#2
+# asm 2: pslld $9,<y7=%xmm1
+pslld $9,%xmm1
+
+# qhasm: 				z7 ^= y7
+# asm 1: pxor  <y7=int6464#2,<z7=int6464#9
+# asm 2: pxor  <y7=%xmm1,<z7=%xmm8
+pxor  %xmm1,%xmm8
+
+# qhasm: uint32323232			r7 >>= 23
+# asm 1: psrld $23,<r7=int6464#3
+# asm 2: psrld $23,<r7=%xmm2
+psrld $23,%xmm2
+
+# qhasm: 				z7 ^= r7
+# asm 1: pxor  <r7=int6464#3,<z7=int6464#9
+# asm 2: pxor  <r7=%xmm2,<z7=%xmm8
+pxor  %xmm2,%xmm8
+
+# qhasm: 		y3 = z1
+# asm 1: movdqa <z1=int6464#8,>y3=int6464#2
+# asm 2: movdqa <z1=%xmm7,>y3=%xmm1
+movdqa %xmm7,%xmm1
+
+# qhasm: uint32323232	y3 += z2
+# asm 1: paddd <z2=int6464#11,<y3=int6464#2
+# asm 2: paddd <z2=%xmm10,<y3=%xmm1
+paddd %xmm10,%xmm1
+
+# qhasm: 		r3 = y3
+# asm 1: movdqa <y3=int6464#2,>r3=int6464#3
+# asm 2: movdqa <y3=%xmm1,>r3=%xmm2
+movdqa %xmm1,%xmm2
+
+# qhasm: uint32323232	y3 <<= 13
+# asm 1: pslld $13,<y3=int6464#2
+# asm 2: pslld $13,<y3=%xmm1
+pslld $13,%xmm1
+
+# qhasm: 		z3 ^= y3
+# asm 1: pxor  <y3=int6464#2,<z3=int6464#5
+# asm 2: pxor  <y3=%xmm1,<z3=%xmm4
+pxor  %xmm1,%xmm4
+
+# qhasm: uint32323232	r3 >>= 19
+# asm 1: psrld $19,<r3=int6464#3
+# asm 2: psrld $19,<r3=%xmm2
+psrld $19,%xmm2
+
+# qhasm: 		z3 ^= r3
+# asm 1: pxor  <r3=int6464#3,<z3=int6464#5
+# asm 2: pxor  <r3=%xmm2,<z3=%xmm4
+pxor  %xmm2,%xmm4
+
+# qhasm: 				y4 = z6
+# asm 1: movdqa <z6=int6464#6,>y4=int6464#2
+# asm 2: movdqa <z6=%xmm5,>y4=%xmm1
+movdqa %xmm5,%xmm1
+
+# qhasm: uint32323232			y4 += z7
+# asm 1: paddd <z7=int6464#9,<y4=int6464#2
+# asm 2: paddd <z7=%xmm8,<y4=%xmm1
+paddd %xmm8,%xmm1
+
+# qhasm: 				r4 = y4
+# asm 1: movdqa <y4=int6464#2,>r4=int6464#3
+# asm 2: movdqa <y4=%xmm1,>r4=%xmm2
+movdqa %xmm1,%xmm2
+
+# qhasm: uint32323232			y4 <<= 13
+# asm 1: pslld $13,<y4=int6464#2
+# asm 2: pslld $13,<y4=%xmm1
+pslld $13,%xmm1
+
+# qhasm: 				z4 ^= y4
+# asm 1: pxor  <y4=int6464#2,<z4=int6464#15
+# asm 2: pxor  <y4=%xmm1,<z4=%xmm14
+pxor  %xmm1,%xmm14
+
+# qhasm: uint32323232			r4 >>= 19
+# asm 1: psrld $19,<r4=int6464#3
+# asm 2: psrld $19,<r4=%xmm2
+psrld $19,%xmm2
+
+# qhasm: 				z4 ^= r4
+# asm 1: pxor  <r4=int6464#3,<z4=int6464#15
+# asm 2: pxor  <r4=%xmm2,<z4=%xmm14
+pxor  %xmm2,%xmm14
+
+# qhasm: 		y0 = z2
+# asm 1: movdqa <z2=int6464#11,>y0=int6464#2
+# asm 2: movdqa <z2=%xmm10,>y0=%xmm1
+movdqa %xmm10,%xmm1
+
+# qhasm: uint32323232	y0 += z3
+# asm 1: paddd <z3=int6464#5,<y0=int6464#2
+# asm 2: paddd <z3=%xmm4,<y0=%xmm1
+paddd %xmm4,%xmm1
+
+# qhasm: 		r0 = y0
+# asm 1: movdqa <y0=int6464#2,>r0=int6464#3
+# asm 2: movdqa <y0=%xmm1,>r0=%xmm2
+movdqa %xmm1,%xmm2
+
+# qhasm: uint32323232	y0 <<= 18
+# asm 1: pslld $18,<y0=int6464#2
+# asm 2: pslld $18,<y0=%xmm1
+pslld $18,%xmm1
+
+# qhasm: 		z0 ^= y0
+# asm 1: pxor  <y0=int6464#2,<z0=int6464#1
+# asm 2: pxor  <y0=%xmm1,<z0=%xmm0
+pxor  %xmm1,%xmm0
+
+# qhasm: uint32323232	r0 >>= 14
+# asm 1: psrld $14,<r0=int6464#3
+# asm 2: psrld $14,<r0=%xmm2
+psrld $14,%xmm2
+
+# qhasm: 		z0 ^= r0
+# asm 1: pxor  <r0=int6464#3,<z0=int6464#1
+# asm 2: pxor  <r0=%xmm2,<z0=%xmm0
+pxor  %xmm2,%xmm0
+
+# qhasm: 						z10 = z10_stack
+# asm 1: movdqa <z10_stack=stack128#21,>z10=int6464#2
+# asm 2: movdqa <z10_stack=320(%rsp),>z10=%xmm1
+movdqa 320(%rsp),%xmm1
+
+# qhasm: 		z0_stack = z0
+# asm 1: movdqa <z0=int6464#1,>z0_stack=stack128#21
+# asm 2: movdqa <z0=%xmm0,>z0_stack=320(%rsp)
+movdqa %xmm0,320(%rsp)
+
+# qhasm: 				y5 = z7
+# asm 1: movdqa <z7=int6464#9,>y5=int6464#1
+# asm 2: movdqa <z7=%xmm8,>y5=%xmm0
+movdqa %xmm8,%xmm0
+
+# qhasm: uint32323232			y5 += z4
+# asm 1: paddd <z4=int6464#15,<y5=int6464#1
+# asm 2: paddd <z4=%xmm14,<y5=%xmm0
+paddd %xmm14,%xmm0
+
+# qhasm: 				r5 = y5
+# asm 1: movdqa <y5=int6464#1,>r5=int6464#3
+# asm 2: movdqa <y5=%xmm0,>r5=%xmm2
+movdqa %xmm0,%xmm2
+
+# qhasm: uint32323232			y5 <<= 18
+# asm 1: pslld $18,<y5=int6464#1
+# asm 2: pslld $18,<y5=%xmm0
+pslld $18,%xmm0
+
+# qhasm: 				z5 ^= y5
+# asm 1: pxor  <y5=int6464#1,<z5=int6464#13
+# asm 2: pxor  <y5=%xmm0,<z5=%xmm12
+pxor  %xmm0,%xmm12
+
+# qhasm: uint32323232			r5 >>= 14
+# asm 1: psrld $14,<r5=int6464#3
+# asm 2: psrld $14,<r5=%xmm2
+psrld $14,%xmm2
+
+# qhasm: 				z5 ^= r5
+# asm 1: pxor  <r5=int6464#3,<z5=int6464#13
+# asm 2: pxor  <r5=%xmm2,<z5=%xmm12
+pxor  %xmm2,%xmm12
+
+# qhasm: 						y11 = z9
+# asm 1: movdqa <z9=int6464#12,>y11=int6464#1
+# asm 2: movdqa <z9=%xmm11,>y11=%xmm0
+movdqa %xmm11,%xmm0
+
+# qhasm: uint32323232					y11 += z10
+# asm 1: paddd <z10=int6464#2,<y11=int6464#1
+# asm 2: paddd <z10=%xmm1,<y11=%xmm0
+paddd %xmm1,%xmm0
+
+# qhasm: 						r11 = y11
+# asm 1: movdqa <y11=int6464#1,>r11=int6464#3
+# asm 2: movdqa <y11=%xmm0,>r11=%xmm2
+movdqa %xmm0,%xmm2
+
+# qhasm: uint32323232					y11 <<= 7
+# asm 1: pslld $7,<y11=int6464#1
+# asm 2: pslld $7,<y11=%xmm0
+pslld $7,%xmm0
+
+# qhasm: 						z11 ^= y11
+# asm 1: pxor  <y11=int6464#1,<z11=int6464#7
+# asm 2: pxor  <y11=%xmm0,<z11=%xmm6
+pxor  %xmm0,%xmm6
+
+# qhasm: uint32323232					r11 >>= 25
+# asm 1: psrld $25,<r11=int6464#3
+# asm 2: psrld $25,<r11=%xmm2
+psrld $25,%xmm2
+
+# qhasm: 						z11 ^= r11
+# asm 1: pxor  <r11=int6464#3,<z11=int6464#7
+# asm 2: pxor  <r11=%xmm2,<z11=%xmm6
+pxor  %xmm2,%xmm6
+
+# qhasm: 								z15 = z15_stack
+# asm 1: movdqa <z15_stack=stack128#22,>z15=int6464#3
+# asm 2: movdqa <z15_stack=336(%rsp),>z15=%xmm2
+movdqa 336(%rsp),%xmm2
+
+# qhasm: 				z5_stack = z5
+# asm 1: movdqa <z5=int6464#13,>z5_stack=stack128#22
+# asm 2: movdqa <z5=%xmm12,>z5_stack=336(%rsp)
+movdqa %xmm12,336(%rsp)
+
+# qhasm: 								y12 = z14
+# asm 1: movdqa <z14=int6464#4,>y12=int6464#1
+# asm 2: movdqa <z14=%xmm3,>y12=%xmm0
+movdqa %xmm3,%xmm0
+
+# qhasm: uint32323232							y12 += z15
+# asm 1: paddd <z15=int6464#3,<y12=int6464#1
+# asm 2: paddd <z15=%xmm2,<y12=%xmm0
+paddd %xmm2,%xmm0
+
+# qhasm: 								r12 = y12
+# asm 1: movdqa <y12=int6464#1,>r12=int6464#13
+# asm 2: movdqa <y12=%xmm0,>r12=%xmm12
+movdqa %xmm0,%xmm12
+
+# qhasm: uint32323232							y12 <<= 7
+# asm 1: pslld $7,<y12=int6464#1
+# asm 2: pslld $7,<y12=%xmm0
+pslld $7,%xmm0
+
+# qhasm: 								z12 ^= y12
+# asm 1: pxor  <y12=int6464#1,<z12=int6464#14
+# asm 2: pxor  <y12=%xmm0,<z12=%xmm13
+pxor  %xmm0,%xmm13
+
+# qhasm: uint32323232							r12 >>= 25
+# asm 1: psrld $25,<r12=int6464#13
+# asm 2: psrld $25,<r12=%xmm12
+psrld $25,%xmm12
+
+# qhasm: 								z12 ^= r12
+# asm 1: pxor  <r12=int6464#13,<z12=int6464#14
+# asm 2: pxor  <r12=%xmm12,<z12=%xmm13
+pxor  %xmm12,%xmm13
+
+# qhasm: 						y8 = z10
+# asm 1: movdqa <z10=int6464#2,>y8=int6464#1
+# asm 2: movdqa <z10=%xmm1,>y8=%xmm0
+movdqa %xmm1,%xmm0
+
+# qhasm: uint32323232					y8 += z11
+# asm 1: paddd <z11=int6464#7,<y8=int6464#1
+# asm 2: paddd <z11=%xmm6,<y8=%xmm0
+paddd %xmm6,%xmm0
+
+# qhasm: 						r8 = y8
+# asm 1: movdqa <y8=int6464#1,>r8=int6464#13
+# asm 2: movdqa <y8=%xmm0,>r8=%xmm12
+movdqa %xmm0,%xmm12
+
+# qhasm: uint32323232					y8 <<= 9
+# asm 1: pslld $9,<y8=int6464#1
+# asm 2: pslld $9,<y8=%xmm0
+pslld $9,%xmm0
+
+# qhasm: 						z8 ^= y8
+# asm 1: pxor  <y8=int6464#1,<z8=int6464#16
+# asm 2: pxor  <y8=%xmm0,<z8=%xmm15
+pxor  %xmm0,%xmm15
+
+# qhasm: uint32323232					r8 >>= 23
+# asm 1: psrld $23,<r8=int6464#13
+# asm 2: psrld $23,<r8=%xmm12
+psrld $23,%xmm12
+
+# qhasm: 						z8 ^= r8
+# asm 1: pxor  <r8=int6464#13,<z8=int6464#16
+# asm 2: pxor  <r8=%xmm12,<z8=%xmm15
+pxor  %xmm12,%xmm15
+
+# qhasm: 								y13 = z15
+# asm 1: movdqa <z15=int6464#3,>y13=int6464#1
+# asm 2: movdqa <z15=%xmm2,>y13=%xmm0
+movdqa %xmm2,%xmm0
+
+# qhasm: uint32323232							y13 += z12
+# asm 1: paddd <z12=int6464#14,<y13=int6464#1
+# asm 2: paddd <z12=%xmm13,<y13=%xmm0
+paddd %xmm13,%xmm0
+
+# qhasm: 								r13 = y13
+# asm 1: movdqa <y13=int6464#1,>r13=int6464#13
+# asm 2: movdqa <y13=%xmm0,>r13=%xmm12
+movdqa %xmm0,%xmm12
+
+# qhasm: uint32323232							y13 <<= 9
+# asm 1: pslld $9,<y13=int6464#1
+# asm 2: pslld $9,<y13=%xmm0
+pslld $9,%xmm0
+
+# qhasm: 								z13 ^= y13
+# asm 1: pxor  <y13=int6464#1,<z13=int6464#10
+# asm 2: pxor  <y13=%xmm0,<z13=%xmm9
+pxor  %xmm0,%xmm9
+
+# qhasm: uint32323232							r13 >>= 23
+# asm 1: psrld $23,<r13=int6464#13
+# asm 2: psrld $23,<r13=%xmm12
+psrld $23,%xmm12
+
+# qhasm: 								z13 ^= r13
+# asm 1: pxor  <r13=int6464#13,<z13=int6464#10
+# asm 2: pxor  <r13=%xmm12,<z13=%xmm9
+pxor  %xmm12,%xmm9
+
+# qhasm: 						y9 = z11
+# asm 1: movdqa <z11=int6464#7,>y9=int6464#1
+# asm 2: movdqa <z11=%xmm6,>y9=%xmm0
+movdqa %xmm6,%xmm0
+
+# qhasm: uint32323232					y9 += z8
+# asm 1: paddd <z8=int6464#16,<y9=int6464#1
+# asm 2: paddd <z8=%xmm15,<y9=%xmm0
+paddd %xmm15,%xmm0
+
+# qhasm: 						r9 = y9
+# asm 1: movdqa <y9=int6464#1,>r9=int6464#13
+# asm 2: movdqa <y9=%xmm0,>r9=%xmm12
+movdqa %xmm0,%xmm12
+
+# qhasm: uint32323232					y9 <<= 13
+# asm 1: pslld $13,<y9=int6464#1
+# asm 2: pslld $13,<y9=%xmm0
+pslld $13,%xmm0
+
+# qhasm: 						z9 ^= y9
+# asm 1: pxor  <y9=int6464#1,<z9=int6464#12
+# asm 2: pxor  <y9=%xmm0,<z9=%xmm11
+pxor  %xmm0,%xmm11
+
+# qhasm: uint32323232					r9 >>= 19
+# asm 1: psrld $19,<r9=int6464#13
+# asm 2: psrld $19,<r9=%xmm12
+psrld $19,%xmm12
+
+# qhasm: 						z9 ^= r9
+# asm 1: pxor  <r9=int6464#13,<z9=int6464#12
+# asm 2: pxor  <r9=%xmm12,<z9=%xmm11
+pxor  %xmm12,%xmm11
+
+# qhasm: 								y14 = z12
+# asm 1: movdqa <z12=int6464#14,>y14=int6464#1
+# asm 2: movdqa <z12=%xmm13,>y14=%xmm0
+movdqa %xmm13,%xmm0
+
+# qhasm: uint32323232							y14 += z13
+# asm 1: paddd <z13=int6464#10,<y14=int6464#1
+# asm 2: paddd <z13=%xmm9,<y14=%xmm0
+paddd %xmm9,%xmm0
+
+# qhasm: 								r14 = y14
+# asm 1: movdqa <y14=int6464#1,>r14=int6464#13
+# asm 2: movdqa <y14=%xmm0,>r14=%xmm12
+movdqa %xmm0,%xmm12
+
+# qhasm: uint32323232							y14 <<= 13
+# asm 1: pslld $13,<y14=int6464#1
+# asm 2: pslld $13,<y14=%xmm0
+pslld $13,%xmm0
+
+# qhasm: 								z14 ^= y14
+# asm 1: pxor  <y14=int6464#1,<z14=int6464#4
+# asm 2: pxor  <y14=%xmm0,<z14=%xmm3
+pxor  %xmm0,%xmm3
+
+# qhasm: uint32323232							r14 >>= 19
+# asm 1: psrld $19,<r14=int6464#13
+# asm 2: psrld $19,<r14=%xmm12
+psrld $19,%xmm12
+
+# qhasm: 								z14 ^= r14
+# asm 1: pxor  <r14=int6464#13,<z14=int6464#4
+# asm 2: pxor  <r14=%xmm12,<z14=%xmm3
+pxor  %xmm12,%xmm3
+
+# qhasm: 						y10 = z8
+# asm 1: movdqa <z8=int6464#16,>y10=int6464#1
+# asm 2: movdqa <z8=%xmm15,>y10=%xmm0
+movdqa %xmm15,%xmm0
+
+# qhasm: uint32323232					y10 += z9
+# asm 1: paddd <z9=int6464#12,<y10=int6464#1
+# asm 2: paddd <z9=%xmm11,<y10=%xmm0
+paddd %xmm11,%xmm0
+
+# qhasm: 						r10 = y10
+# asm 1: movdqa <y10=int6464#1,>r10=int6464#13
+# asm 2: movdqa <y10=%xmm0,>r10=%xmm12
+movdqa %xmm0,%xmm12
+
+# qhasm: uint32323232					y10 <<= 18
+# asm 1: pslld $18,<y10=int6464#1
+# asm 2: pslld $18,<y10=%xmm0
+pslld $18,%xmm0
+
+# qhasm: 						z10 ^= y10
+# asm 1: pxor  <y10=int6464#1,<z10=int6464#2
+# asm 2: pxor  <y10=%xmm0,<z10=%xmm1
+pxor  %xmm0,%xmm1
+
+# qhasm: uint32323232					r10 >>= 14
+# asm 1: psrld $14,<r10=int6464#13
+# asm 2: psrld $14,<r10=%xmm12
+psrld $14,%xmm12
+
+# qhasm: 						z10 ^= r10
+# asm 1: pxor  <r10=int6464#13,<z10=int6464#2
+# asm 2: pxor  <r10=%xmm12,<z10=%xmm1
+pxor  %xmm12,%xmm1
+
+# qhasm: 								y15 = z13
+# asm 1: movdqa <z13=int6464#10,>y15=int6464#1
+# asm 2: movdqa <z13=%xmm9,>y15=%xmm0
+movdqa %xmm9,%xmm0
+
+# qhasm: uint32323232							y15 += z14
+# asm 1: paddd <z14=int6464#4,<y15=int6464#1
+# asm 2: paddd <z14=%xmm3,<y15=%xmm0
+paddd %xmm3,%xmm0
+
+# qhasm: 								r15 = y15
+# asm 1: movdqa <y15=int6464#1,>r15=int6464#13
+# asm 2: movdqa <y15=%xmm0,>r15=%xmm12
+movdqa %xmm0,%xmm12
+
+# qhasm: uint32323232							y15 <<= 18
+# asm 1: pslld $18,<y15=int6464#1
+# asm 2: pslld $18,<y15=%xmm0
+pslld $18,%xmm0
+
+# qhasm: 								z15 ^= y15
+# asm 1: pxor  <y15=int6464#1,<z15=int6464#3
+# asm 2: pxor  <y15=%xmm0,<z15=%xmm2
+pxor  %xmm0,%xmm2
+
+# qhasm: uint32323232							r15 >>= 14
+# asm 1: psrld $14,<r15=int6464#13
+# asm 2: psrld $14,<r15=%xmm12
+psrld $14,%xmm12
+
+# qhasm: 								z15 ^= r15
+# asm 1: pxor  <r15=int6464#13,<z15=int6464#3
+# asm 2: pxor  <r15=%xmm12,<z15=%xmm2
+pxor  %xmm12,%xmm2
+
+# qhasm: 		z0 = z0_stack
+# asm 1: movdqa <z0_stack=stack128#21,>z0=int6464#13
+# asm 2: movdqa <z0_stack=320(%rsp),>z0=%xmm12
+movdqa 320(%rsp),%xmm12
+
+# qhasm: 				z5 = z5_stack
+# asm 1: movdqa <z5_stack=stack128#22,>z5=int6464#1
+# asm 2: movdqa <z5_stack=336(%rsp),>z5=%xmm0
+movdqa 336(%rsp),%xmm0
+
+# qhasm:                   unsigned>? i -= 2
+# asm 1: sub  $2,<i=int64#3
+# asm 2: sub  $2,<i=%rdx
+sub  $2,%rdx
+# comment:fp stack unchanged by jump
+
+# qhasm: goto mainloop1 if unsigned>
+ja ._mainloop1
+
+# qhasm:   uint32323232 z0 += orig0
+# asm 1: paddd <orig0=stack128#8,<z0=int6464#13
+# asm 2: paddd <orig0=112(%rsp),<z0=%xmm12
+paddd 112(%rsp),%xmm12
+
+# qhasm:   uint32323232 z1 += orig1
+# asm 1: paddd <orig1=stack128#12,<z1=int6464#8
+# asm 2: paddd <orig1=176(%rsp),<z1=%xmm7
+paddd 176(%rsp),%xmm7
+
+# qhasm:   uint32323232 z2 += orig2
+# asm 1: paddd <orig2=stack128#15,<z2=int6464#11
+# asm 2: paddd <orig2=224(%rsp),<z2=%xmm10
+paddd 224(%rsp),%xmm10
+
+# qhasm:   uint32323232 z3 += orig3
+# asm 1: paddd <orig3=stack128#18,<z3=int6464#5
+# asm 2: paddd <orig3=272(%rsp),<z3=%xmm4
+paddd 272(%rsp),%xmm4
+
+# qhasm:   in0 = z0
+# asm 1: movd   <z0=int6464#13,>in0=int64#3
+# asm 2: movd   <z0=%xmm12,>in0=%rdx
+movd   %xmm12,%rdx
+
+# qhasm:   in1 = z1
+# asm 1: movd   <z1=int6464#8,>in1=int64#4
+# asm 2: movd   <z1=%xmm7,>in1=%rcx
+movd   %xmm7,%rcx
+
+# qhasm:   in2 = z2
+# asm 1: movd   <z2=int6464#11,>in2=int64#5
+# asm 2: movd   <z2=%xmm10,>in2=%r8
+movd   %xmm10,%r8
+
+# qhasm:   in3 = z3
+# asm 1: movd   <z3=int6464#5,>in3=int64#6
+# asm 2: movd   <z3=%xmm4,>in3=%r9
+movd   %xmm4,%r9
+
+# qhasm:   z0 <<<= 96
+# asm 1: pshufd $0x39,<z0=int6464#13,<z0=int6464#13
+# asm 2: pshufd $0x39,<z0=%xmm12,<z0=%xmm12
+pshufd $0x39,%xmm12,%xmm12
+
+# qhasm:   z1 <<<= 96
+# asm 1: pshufd $0x39,<z1=int6464#8,<z1=int6464#8
+# asm 2: pshufd $0x39,<z1=%xmm7,<z1=%xmm7
+pshufd $0x39,%xmm7,%xmm7
+
+# qhasm:   z2 <<<= 96
+# asm 1: pshufd $0x39,<z2=int6464#11,<z2=int6464#11
+# asm 2: pshufd $0x39,<z2=%xmm10,<z2=%xmm10
+pshufd $0x39,%xmm10,%xmm10
+
+# qhasm:   z3 <<<= 96
+# asm 1: pshufd $0x39,<z3=int6464#5,<z3=int6464#5
+# asm 2: pshufd $0x39,<z3=%xmm4,<z3=%xmm4
+pshufd $0x39,%xmm4,%xmm4
+
+# qhasm:   (uint32) in0 ^= *(uint32 *) (m + 0)
+# asm 1: xorl 0(<m=int64#2),<in0=int64#3d
+# asm 2: xorl 0(<m=%rsi),<in0=%edx
+xorl 0(%rsi),%edx
+
+# qhasm:   (uint32) in1 ^= *(uint32 *) (m + 4)
+# asm 1: xorl 4(<m=int64#2),<in1=int64#4d
+# asm 2: xorl 4(<m=%rsi),<in1=%ecx
+xorl 4(%rsi),%ecx
+
+# qhasm:   (uint32) in2 ^= *(uint32 *) (m + 8)
+# asm 1: xorl 8(<m=int64#2),<in2=int64#5d
+# asm 2: xorl 8(<m=%rsi),<in2=%r8d
+xorl 8(%rsi),%r8d
+
+# qhasm:   (uint32) in3 ^= *(uint32 *) (m + 12)
+# asm 1: xorl 12(<m=int64#2),<in3=int64#6d
+# asm 2: xorl 12(<m=%rsi),<in3=%r9d
+xorl 12(%rsi),%r9d
+
+# qhasm:   *(uint32 *) (out + 0) = in0
+# asm 1: movl   <in0=int64#3d,0(<out=int64#1)
+# asm 2: movl   <in0=%edx,0(<out=%rdi)
+movl   %edx,0(%rdi)
+
+# qhasm:   *(uint32 *) (out + 4) = in1
+# asm 1: movl   <in1=int64#4d,4(<out=int64#1)
+# asm 2: movl   <in1=%ecx,4(<out=%rdi)
+movl   %ecx,4(%rdi)
+
+# qhasm:   *(uint32 *) (out + 8) = in2
+# asm 1: movl   <in2=int64#5d,8(<out=int64#1)
+# asm 2: movl   <in2=%r8d,8(<out=%rdi)
+movl   %r8d,8(%rdi)
+
+# qhasm:   *(uint32 *) (out + 12) = in3
+# asm 1: movl   <in3=int64#6d,12(<out=int64#1)
+# asm 2: movl   <in3=%r9d,12(<out=%rdi)
+movl   %r9d,12(%rdi)
+
+# qhasm:   in0 = z0
+# asm 1: movd   <z0=int6464#13,>in0=int64#3
+# asm 2: movd   <z0=%xmm12,>in0=%rdx
+movd   %xmm12,%rdx
+
+# qhasm:   in1 = z1
+# asm 1: movd   <z1=int6464#8,>in1=int64#4
+# asm 2: movd   <z1=%xmm7,>in1=%rcx
+movd   %xmm7,%rcx
+
+# qhasm:   in2 = z2
+# asm 1: movd   <z2=int6464#11,>in2=int64#5
+# asm 2: movd   <z2=%xmm10,>in2=%r8
+movd   %xmm10,%r8
+
+# qhasm:   in3 = z3
+# asm 1: movd   <z3=int6464#5,>in3=int64#6
+# asm 2: movd   <z3=%xmm4,>in3=%r9
+movd   %xmm4,%r9
+
+# qhasm:   z0 <<<= 96
+# asm 1: pshufd $0x39,<z0=int6464#13,<z0=int6464#13
+# asm 2: pshufd $0x39,<z0=%xmm12,<z0=%xmm12
+pshufd $0x39,%xmm12,%xmm12
+
+# qhasm:   z1 <<<= 96
+# asm 1: pshufd $0x39,<z1=int6464#8,<z1=int6464#8
+# asm 2: pshufd $0x39,<z1=%xmm7,<z1=%xmm7
+pshufd $0x39,%xmm7,%xmm7
+
+# qhasm:   z2 <<<= 96
+# asm 1: pshufd $0x39,<z2=int6464#11,<z2=int6464#11
+# asm 2: pshufd $0x39,<z2=%xmm10,<z2=%xmm10
+pshufd $0x39,%xmm10,%xmm10
+
+# qhasm:   z3 <<<= 96
+# asm 1: pshufd $0x39,<z3=int6464#5,<z3=int6464#5
+# asm 2: pshufd $0x39,<z3=%xmm4,<z3=%xmm4
+pshufd $0x39,%xmm4,%xmm4
+
+# qhasm:   (uint32) in0 ^= *(uint32 *) (m + 64)
+# asm 1: xorl 64(<m=int64#2),<in0=int64#3d
+# asm 2: xorl 64(<m=%rsi),<in0=%edx
+xorl 64(%rsi),%edx
+
+# qhasm:   (uint32) in1 ^= *(uint32 *) (m + 68)
+# asm 1: xorl 68(<m=int64#2),<in1=int64#4d
+# asm 2: xorl 68(<m=%rsi),<in1=%ecx
+xorl 68(%rsi),%ecx
+
+# qhasm:   (uint32) in2 ^= *(uint32 *) (m + 72)
+# asm 1: xorl 72(<m=int64#2),<in2=int64#5d
+# asm 2: xorl 72(<m=%rsi),<in2=%r8d
+xorl 72(%rsi),%r8d
+
+# qhasm:   (uint32) in3 ^= *(uint32 *) (m + 76)
+# asm 1: xorl 76(<m=int64#2),<in3=int64#6d
+# asm 2: xorl 76(<m=%rsi),<in3=%r9d
+xorl 76(%rsi),%r9d
+
+# qhasm:   *(uint32 *) (out + 64) = in0
+# asm 1: movl   <in0=int64#3d,64(<out=int64#1)
+# asm 2: movl   <in0=%edx,64(<out=%rdi)
+movl   %edx,64(%rdi)
+
+# qhasm:   *(uint32 *) (out + 68) = in1
+# asm 1: movl   <in1=int64#4d,68(<out=int64#1)
+# asm 2: movl   <in1=%ecx,68(<out=%rdi)
+movl   %ecx,68(%rdi)
+
+# qhasm:   *(uint32 *) (out + 72) = in2
+# asm 1: movl   <in2=int64#5d,72(<out=int64#1)
+# asm 2: movl   <in2=%r8d,72(<out=%rdi)
+movl   %r8d,72(%rdi)
+
+# qhasm:   *(uint32 *) (out + 76) = in3
+# asm 1: movl   <in3=int64#6d,76(<out=int64#1)
+# asm 2: movl   <in3=%r9d,76(<out=%rdi)
+movl   %r9d,76(%rdi)
+
+# qhasm:   in0 = z0
+# asm 1: movd   <z0=int6464#13,>in0=int64#3
+# asm 2: movd   <z0=%xmm12,>in0=%rdx
+movd   %xmm12,%rdx
+
+# qhasm:   in1 = z1
+# asm 1: movd   <z1=int6464#8,>in1=int64#4
+# asm 2: movd   <z1=%xmm7,>in1=%rcx
+movd   %xmm7,%rcx
+
+# qhasm:   in2 = z2
+# asm 1: movd   <z2=int6464#11,>in2=int64#5
+# asm 2: movd   <z2=%xmm10,>in2=%r8
+movd   %xmm10,%r8
+
+# qhasm:   in3 = z3
+# asm 1: movd   <z3=int6464#5,>in3=int64#6
+# asm 2: movd   <z3=%xmm4,>in3=%r9
+movd   %xmm4,%r9
+
+# qhasm:   z0 <<<= 96
+# asm 1: pshufd $0x39,<z0=int6464#13,<z0=int6464#13
+# asm 2: pshufd $0x39,<z0=%xmm12,<z0=%xmm12
+pshufd $0x39,%xmm12,%xmm12
+
+# qhasm:   z1 <<<= 96
+# asm 1: pshufd $0x39,<z1=int6464#8,<z1=int6464#8
+# asm 2: pshufd $0x39,<z1=%xmm7,<z1=%xmm7
+pshufd $0x39,%xmm7,%xmm7
+
+# qhasm:   z2 <<<= 96
+# asm 1: pshufd $0x39,<z2=int6464#11,<z2=int6464#11
+# asm 2: pshufd $0x39,<z2=%xmm10,<z2=%xmm10
+pshufd $0x39,%xmm10,%xmm10
+
+# qhasm:   z3 <<<= 96
+# asm 1: pshufd $0x39,<z3=int6464#5,<z3=int6464#5
+# asm 2: pshufd $0x39,<z3=%xmm4,<z3=%xmm4
+pshufd $0x39,%xmm4,%xmm4
+
+# qhasm:   (uint32) in0 ^= *(uint32 *) (m + 128)
+# asm 1: xorl 128(<m=int64#2),<in0=int64#3d
+# asm 2: xorl 128(<m=%rsi),<in0=%edx
+xorl 128(%rsi),%edx
+
+# qhasm:   (uint32) in1 ^= *(uint32 *) (m + 132)
+# asm 1: xorl 132(<m=int64#2),<in1=int64#4d
+# asm 2: xorl 132(<m=%rsi),<in1=%ecx
+xorl 132(%rsi),%ecx
+
+# qhasm:   (uint32) in2 ^= *(uint32 *) (m + 136)
+# asm 1: xorl 136(<m=int64#2),<in2=int64#5d
+# asm 2: xorl 136(<m=%rsi),<in2=%r8d
+xorl 136(%rsi),%r8d
+
+# qhasm:   (uint32) in3 ^= *(uint32 *) (m + 140)
+# asm 1: xorl 140(<m=int64#2),<in3=int64#6d
+# asm 2: xorl 140(<m=%rsi),<in3=%r9d
+xorl 140(%rsi),%r9d
+
+# qhasm:   *(uint32 *) (out + 128) = in0
+# asm 1: movl   <in0=int64#3d,128(<out=int64#1)
+# asm 2: movl   <in0=%edx,128(<out=%rdi)
+movl   %edx,128(%rdi)
+
+# qhasm:   *(uint32 *) (out + 132) = in1
+# asm 1: movl   <in1=int64#4d,132(<out=int64#1)
+# asm 2: movl   <in1=%ecx,132(<out=%rdi)
+movl   %ecx,132(%rdi)
+
+# qhasm:   *(uint32 *) (out + 136) = in2
+# asm 1: movl   <in2=int64#5d,136(<out=int64#1)
+# asm 2: movl   <in2=%r8d,136(<out=%rdi)
+movl   %r8d,136(%rdi)
+
+# qhasm:   *(uint32 *) (out + 140) = in3
+# asm 1: movl   <in3=int64#6d,140(<out=int64#1)
+# asm 2: movl   <in3=%r9d,140(<out=%rdi)
+movl   %r9d,140(%rdi)
+
+# qhasm:   in0 = z0
+# asm 1: movd   <z0=int6464#13,>in0=int64#3
+# asm 2: movd   <z0=%xmm12,>in0=%rdx
+movd   %xmm12,%rdx
+
+# qhasm:   in1 = z1
+# asm 1: movd   <z1=int6464#8,>in1=int64#4
+# asm 2: movd   <z1=%xmm7,>in1=%rcx
+movd   %xmm7,%rcx
+
+# qhasm:   in2 = z2
+# asm 1: movd   <z2=int6464#11,>in2=int64#5
+# asm 2: movd   <z2=%xmm10,>in2=%r8
+movd   %xmm10,%r8
+
+# qhasm:   in3 = z3
+# asm 1: movd   <z3=int6464#5,>in3=int64#6
+# asm 2: movd   <z3=%xmm4,>in3=%r9
+movd   %xmm4,%r9
+
+# qhasm:   (uint32) in0 ^= *(uint32 *) (m + 192)
+# asm 1: xorl 192(<m=int64#2),<in0=int64#3d
+# asm 2: xorl 192(<m=%rsi),<in0=%edx
+xorl 192(%rsi),%edx
+
+# qhasm:   (uint32) in1 ^= *(uint32 *) (m + 196)
+# asm 1: xorl 196(<m=int64#2),<in1=int64#4d
+# asm 2: xorl 196(<m=%rsi),<in1=%ecx
+xorl 196(%rsi),%ecx
+
+# qhasm:   (uint32) in2 ^= *(uint32 *) (m + 200)
+# asm 1: xorl 200(<m=int64#2),<in2=int64#5d
+# asm 2: xorl 200(<m=%rsi),<in2=%r8d
+xorl 200(%rsi),%r8d
+
+# qhasm:   (uint32) in3 ^= *(uint32 *) (m + 204)
+# asm 1: xorl 204(<m=int64#2),<in3=int64#6d
+# asm 2: xorl 204(<m=%rsi),<in3=%r9d
+xorl 204(%rsi),%r9d
+
+# qhasm:   *(uint32 *) (out + 192) = in0
+# asm 1: movl   <in0=int64#3d,192(<out=int64#1)
+# asm 2: movl   <in0=%edx,192(<out=%rdi)
+movl   %edx,192(%rdi)
+
+# qhasm:   *(uint32 *) (out + 196) = in1
+# asm 1: movl   <in1=int64#4d,196(<out=int64#1)
+# asm 2: movl   <in1=%ecx,196(<out=%rdi)
+movl   %ecx,196(%rdi)
+
+# qhasm:   *(uint32 *) (out + 200) = in2
+# asm 1: movl   <in2=int64#5d,200(<out=int64#1)
+# asm 2: movl   <in2=%r8d,200(<out=%rdi)
+movl   %r8d,200(%rdi)
+
+# qhasm:   *(uint32 *) (out + 204) = in3
+# asm 1: movl   <in3=int64#6d,204(<out=int64#1)
+# asm 2: movl   <in3=%r9d,204(<out=%rdi)
+movl   %r9d,204(%rdi)
+
+# qhasm:   uint32323232 z4 += orig4
+# asm 1: paddd <orig4=stack128#16,<z4=int6464#15
+# asm 2: paddd <orig4=240(%rsp),<z4=%xmm14
+paddd 240(%rsp),%xmm14
+
+# qhasm:   uint32323232 z5 += orig5
+# asm 1: paddd <orig5=stack128#5,<z5=int6464#1
+# asm 2: paddd <orig5=64(%rsp),<z5=%xmm0
+paddd 64(%rsp),%xmm0
+
+# qhasm:   uint32323232 z6 += orig6
+# asm 1: paddd <orig6=stack128#9,<z6=int6464#6
+# asm 2: paddd <orig6=128(%rsp),<z6=%xmm5
+paddd 128(%rsp),%xmm5
+
+# qhasm:   uint32323232 z7 += orig7
+# asm 1: paddd <orig7=stack128#13,<z7=int6464#9
+# asm 2: paddd <orig7=192(%rsp),<z7=%xmm8
+paddd 192(%rsp),%xmm8
+
+# qhasm:   in4 = z4
+# asm 1: movd   <z4=int6464#15,>in4=int64#3
+# asm 2: movd   <z4=%xmm14,>in4=%rdx
+movd   %xmm14,%rdx
+
+# qhasm:   in5 = z5
+# asm 1: movd   <z5=int6464#1,>in5=int64#4
+# asm 2: movd   <z5=%xmm0,>in5=%rcx
+movd   %xmm0,%rcx
+
+# qhasm:   in6 = z6
+# asm 1: movd   <z6=int6464#6,>in6=int64#5
+# asm 2: movd   <z6=%xmm5,>in6=%r8
+movd   %xmm5,%r8
+
+# qhasm:   in7 = z7
+# asm 1: movd   <z7=int6464#9,>in7=int64#6
+# asm 2: movd   <z7=%xmm8,>in7=%r9
+movd   %xmm8,%r9
+
+# qhasm:   z4 <<<= 96
+# asm 1: pshufd $0x39,<z4=int6464#15,<z4=int6464#15
+# asm 2: pshufd $0x39,<z4=%xmm14,<z4=%xmm14
+pshufd $0x39,%xmm14,%xmm14
+
+# qhasm:   z5 <<<= 96
+# asm 1: pshufd $0x39,<z5=int6464#1,<z5=int6464#1
+# asm 2: pshufd $0x39,<z5=%xmm0,<z5=%xmm0
+pshufd $0x39,%xmm0,%xmm0
+
+# qhasm:   z6 <<<= 96
+# asm 1: pshufd $0x39,<z6=int6464#6,<z6=int6464#6
+# asm 2: pshufd $0x39,<z6=%xmm5,<z6=%xmm5
+pshufd $0x39,%xmm5,%xmm5
+
+# qhasm:   z7 <<<= 96
+# asm 1: pshufd $0x39,<z7=int6464#9,<z7=int6464#9
+# asm 2: pshufd $0x39,<z7=%xmm8,<z7=%xmm8
+pshufd $0x39,%xmm8,%xmm8
+
+# qhasm:   (uint32) in4 ^= *(uint32 *) (m + 16)
+# asm 1: xorl 16(<m=int64#2),<in4=int64#3d
+# asm 2: xorl 16(<m=%rsi),<in4=%edx
+xorl 16(%rsi),%edx
+
+# qhasm:   (uint32) in5 ^= *(uint32 *) (m + 20)
+# asm 1: xorl 20(<m=int64#2),<in5=int64#4d
+# asm 2: xorl 20(<m=%rsi),<in5=%ecx
+xorl 20(%rsi),%ecx
+
+# qhasm:   (uint32) in6 ^= *(uint32 *) (m + 24)
+# asm 1: xorl 24(<m=int64#2),<in6=int64#5d
+# asm 2: xorl 24(<m=%rsi),<in6=%r8d
+xorl 24(%rsi),%r8d
+
+# qhasm:   (uint32) in7 ^= *(uint32 *) (m + 28)
+# asm 1: xorl 28(<m=int64#2),<in7=int64#6d
+# asm 2: xorl 28(<m=%rsi),<in7=%r9d
+xorl 28(%rsi),%r9d
+
+# qhasm:   *(uint32 *) (out + 16) = in4
+# asm 1: movl   <in4=int64#3d,16(<out=int64#1)
+# asm 2: movl   <in4=%edx,16(<out=%rdi)
+movl   %edx,16(%rdi)
+
+# qhasm:   *(uint32 *) (out + 20) = in5
+# asm 1: movl   <in5=int64#4d,20(<out=int64#1)
+# asm 2: movl   <in5=%ecx,20(<out=%rdi)
+movl   %ecx,20(%rdi)
+
+# qhasm:   *(uint32 *) (out + 24) = in6
+# asm 1: movl   <in6=int64#5d,24(<out=int64#1)
+# asm 2: movl   <in6=%r8d,24(<out=%rdi)
+movl   %r8d,24(%rdi)
+
+# qhasm:   *(uint32 *) (out + 28) = in7
+# asm 1: movl   <in7=int64#6d,28(<out=int64#1)
+# asm 2: movl   <in7=%r9d,28(<out=%rdi)
+movl   %r9d,28(%rdi)
+
+# qhasm:   in4 = z4
+# asm 1: movd   <z4=int6464#15,>in4=int64#3
+# asm 2: movd   <z4=%xmm14,>in4=%rdx
+movd   %xmm14,%rdx
+
+# qhasm:   in5 = z5
+# asm 1: movd   <z5=int6464#1,>in5=int64#4
+# asm 2: movd   <z5=%xmm0,>in5=%rcx
+movd   %xmm0,%rcx
+
+# qhasm:   in6 = z6
+# asm 1: movd   <z6=int6464#6,>in6=int64#5
+# asm 2: movd   <z6=%xmm5,>in6=%r8
+movd   %xmm5,%r8
+
+# qhasm:   in7 = z7
+# asm 1: movd   <z7=int6464#9,>in7=int64#6
+# asm 2: movd   <z7=%xmm8,>in7=%r9
+movd   %xmm8,%r9
+
+# qhasm:   z4 <<<= 96
+# asm 1: pshufd $0x39,<z4=int6464#15,<z4=int6464#15
+# asm 2: pshufd $0x39,<z4=%xmm14,<z4=%xmm14
+pshufd $0x39,%xmm14,%xmm14
+
+# qhasm:   z5 <<<= 96
+# asm 1: pshufd $0x39,<z5=int6464#1,<z5=int6464#1
+# asm 2: pshufd $0x39,<z5=%xmm0,<z5=%xmm0
+pshufd $0x39,%xmm0,%xmm0
+
+# qhasm:   z6 <<<= 96
+# asm 1: pshufd $0x39,<z6=int6464#6,<z6=int6464#6
+# asm 2: pshufd $0x39,<z6=%xmm5,<z6=%xmm5
+pshufd $0x39,%xmm5,%xmm5
+
+# qhasm:   z7 <<<= 96
+# asm 1: pshufd $0x39,<z7=int6464#9,<z7=int6464#9
+# asm 2: pshufd $0x39,<z7=%xmm8,<z7=%xmm8
+pshufd $0x39,%xmm8,%xmm8
+
+# qhasm:   (uint32) in4 ^= *(uint32 *) (m + 80)
+# asm 1: xorl 80(<m=int64#2),<in4=int64#3d
+# asm 2: xorl 80(<m=%rsi),<in4=%edx
+xorl 80(%rsi),%edx
+
+# qhasm:   (uint32) in5 ^= *(uint32 *) (m + 84)
+# asm 1: xorl 84(<m=int64#2),<in5=int64#4d
+# asm 2: xorl 84(<m=%rsi),<in5=%ecx
+xorl 84(%rsi),%ecx
+
+# qhasm:   (uint32) in6 ^= *(uint32 *) (m + 88)
+# asm 1: xorl 88(<m=int64#2),<in6=int64#5d
+# asm 2: xorl 88(<m=%rsi),<in6=%r8d
+xorl 88(%rsi),%r8d
+
+# qhasm:   (uint32) in7 ^= *(uint32 *) (m + 92)
+# asm 1: xorl 92(<m=int64#2),<in7=int64#6d
+# asm 2: xorl 92(<m=%rsi),<in7=%r9d
+xorl 92(%rsi),%r9d
+
+# qhasm:   *(uint32 *) (out + 80) = in4
+# asm 1: movl   <in4=int64#3d,80(<out=int64#1)
+# asm 2: movl   <in4=%edx,80(<out=%rdi)
+movl   %edx,80(%rdi)
+
+# qhasm:   *(uint32 *) (out + 84) = in5
+# asm 1: movl   <in5=int64#4d,84(<out=int64#1)
+# asm 2: movl   <in5=%ecx,84(<out=%rdi)
+movl   %ecx,84(%rdi)
+
+# qhasm:   *(uint32 *) (out + 88) = in6
+# asm 1: movl   <in6=int64#5d,88(<out=int64#1)
+# asm 2: movl   <in6=%r8d,88(<out=%rdi)
+movl   %r8d,88(%rdi)
+
+# qhasm:   *(uint32 *) (out + 92) = in7
+# asm 1: movl   <in7=int64#6d,92(<out=int64#1)
+# asm 2: movl   <in7=%r9d,92(<out=%rdi)
+movl   %r9d,92(%rdi)
+
+# qhasm:   in4 = z4
+# asm 1: movd   <z4=int6464#15,>in4=int64#3
+# asm 2: movd   <z4=%xmm14,>in4=%rdx
+movd   %xmm14,%rdx
+
+# qhasm:   in5 = z5
+# asm 1: movd   <z5=int6464#1,>in5=int64#4
+# asm 2: movd   <z5=%xmm0,>in5=%rcx
+movd   %xmm0,%rcx
+
+# qhasm:   in6 = z6
+# asm 1: movd   <z6=int6464#6,>in6=int64#5
+# asm 2: movd   <z6=%xmm5,>in6=%r8
+movd   %xmm5,%r8
+
+# qhasm:   in7 = z7
+# asm 1: movd   <z7=int6464#9,>in7=int64#6
+# asm 2: movd   <z7=%xmm8,>in7=%r9
+movd   %xmm8,%r9
+
+# qhasm:   z4 <<<= 96
+# asm 1: pshufd $0x39,<z4=int6464#15,<z4=int6464#15
+# asm 2: pshufd $0x39,<z4=%xmm14,<z4=%xmm14
+pshufd $0x39,%xmm14,%xmm14
+
+# qhasm:   z5 <<<= 96
+# asm 1: pshufd $0x39,<z5=int6464#1,<z5=int6464#1
+# asm 2: pshufd $0x39,<z5=%xmm0,<z5=%xmm0
+pshufd $0x39,%xmm0,%xmm0
+
+# qhasm:   z6 <<<= 96
+# asm 1: pshufd $0x39,<z6=int6464#6,<z6=int6464#6
+# asm 2: pshufd $0x39,<z6=%xmm5,<z6=%xmm5
+pshufd $0x39,%xmm5,%xmm5
+
+# qhasm:   z7 <<<= 96
+# asm 1: pshufd $0x39,<z7=int6464#9,<z7=int6464#9
+# asm 2: pshufd $0x39,<z7=%xmm8,<z7=%xmm8
+pshufd $0x39,%xmm8,%xmm8
+
+# qhasm:   (uint32) in4 ^= *(uint32 *) (m + 144)
+# asm 1: xorl 144(<m=int64#2),<in4=int64#3d
+# asm 2: xorl 144(<m=%rsi),<in4=%edx
+xorl 144(%rsi),%edx
+
+# qhasm:   (uint32) in5 ^= *(uint32 *) (m + 148)
+# asm 1: xorl 148(<m=int64#2),<in5=int64#4d
+# asm 2: xorl 148(<m=%rsi),<in5=%ecx
+xorl 148(%rsi),%ecx
+
+# qhasm:   (uint32) in6 ^= *(uint32 *) (m + 152)
+# asm 1: xorl 152(<m=int64#2),<in6=int64#5d
+# asm 2: xorl 152(<m=%rsi),<in6=%r8d
+xorl 152(%rsi),%r8d
+
+# qhasm:   (uint32) in7 ^= *(uint32 *) (m + 156)
+# asm 1: xorl 156(<m=int64#2),<in7=int64#6d
+# asm 2: xorl 156(<m=%rsi),<in7=%r9d
+xorl 156(%rsi),%r9d
+
+# qhasm:   *(uint32 *) (out + 144) = in4
+# asm 1: movl   <in4=int64#3d,144(<out=int64#1)
+# asm 2: movl   <in4=%edx,144(<out=%rdi)
+movl   %edx,144(%rdi)
+
+# qhasm:   *(uint32 *) (out + 148) = in5
+# asm 1: movl   <in5=int64#4d,148(<out=int64#1)
+# asm 2: movl   <in5=%ecx,148(<out=%rdi)
+movl   %ecx,148(%rdi)
+
+# qhasm:   *(uint32 *) (out + 152) = in6
+# asm 1: movl   <in6=int64#5d,152(<out=int64#1)
+# asm 2: movl   <in6=%r8d,152(<out=%rdi)
+movl   %r8d,152(%rdi)
+
+# qhasm:   *(uint32 *) (out + 156) = in7
+# asm 1: movl   <in7=int64#6d,156(<out=int64#1)
+# asm 2: movl   <in7=%r9d,156(<out=%rdi)
+movl   %r9d,156(%rdi)
+
+# qhasm:   in4 = z4
+# asm 1: movd   <z4=int6464#15,>in4=int64#3
+# asm 2: movd   <z4=%xmm14,>in4=%rdx
+movd   %xmm14,%rdx
+
+# qhasm:   in5 = z5
+# asm 1: movd   <z5=int6464#1,>in5=int64#4
+# asm 2: movd   <z5=%xmm0,>in5=%rcx
+movd   %xmm0,%rcx
+
+# qhasm:   in6 = z6
+# asm 1: movd   <z6=int6464#6,>in6=int64#5
+# asm 2: movd   <z6=%xmm5,>in6=%r8
+movd   %xmm5,%r8
+
+# qhasm:   in7 = z7
+# asm 1: movd   <z7=int6464#9,>in7=int64#6
+# asm 2: movd   <z7=%xmm8,>in7=%r9
+movd   %xmm8,%r9
+
+# qhasm:   (uint32) in4 ^= *(uint32 *) (m + 208)
+# asm 1: xorl 208(<m=int64#2),<in4=int64#3d
+# asm 2: xorl 208(<m=%rsi),<in4=%edx
+xorl 208(%rsi),%edx
+
+# qhasm:   (uint32) in5 ^= *(uint32 *) (m + 212)
+# asm 1: xorl 212(<m=int64#2),<in5=int64#4d
+# asm 2: xorl 212(<m=%rsi),<in5=%ecx
+xorl 212(%rsi),%ecx
+
+# qhasm:   (uint32) in6 ^= *(uint32 *) (m + 216)
+# asm 1: xorl 216(<m=int64#2),<in6=int64#5d
+# asm 2: xorl 216(<m=%rsi),<in6=%r8d
+xorl 216(%rsi),%r8d
+
+# qhasm:   (uint32) in7 ^= *(uint32 *) (m + 220)
+# asm 1: xorl 220(<m=int64#2),<in7=int64#6d
+# asm 2: xorl 220(<m=%rsi),<in7=%r9d
+xorl 220(%rsi),%r9d
+
+# qhasm:   *(uint32 *) (out + 208) = in4
+# asm 1: movl   <in4=int64#3d,208(<out=int64#1)
+# asm 2: movl   <in4=%edx,208(<out=%rdi)
+movl   %edx,208(%rdi)
+
+# qhasm:   *(uint32 *) (out + 212) = in5
+# asm 1: movl   <in5=int64#4d,212(<out=int64#1)
+# asm 2: movl   <in5=%ecx,212(<out=%rdi)
+movl   %ecx,212(%rdi)
+
+# qhasm:   *(uint32 *) (out + 216) = in6
+# asm 1: movl   <in6=int64#5d,216(<out=int64#1)
+# asm 2: movl   <in6=%r8d,216(<out=%rdi)
+movl   %r8d,216(%rdi)
+
+# qhasm:   *(uint32 *) (out + 220) = in7
+# asm 1: movl   <in7=int64#6d,220(<out=int64#1)
+# asm 2: movl   <in7=%r9d,220(<out=%rdi)
+movl   %r9d,220(%rdi)
+
+# qhasm:   uint32323232 z8 += orig8
+# asm 1: paddd <orig8=stack128#19,<z8=int6464#16
+# asm 2: paddd <orig8=288(%rsp),<z8=%xmm15
+paddd 288(%rsp),%xmm15
+
+# qhasm:   uint32323232 z9 += orig9
+# asm 1: paddd <orig9=stack128#20,<z9=int6464#12
+# asm 2: paddd <orig9=304(%rsp),<z9=%xmm11
+paddd 304(%rsp),%xmm11
+
+# qhasm:   uint32323232 z10 += orig10
+# asm 1: paddd <orig10=stack128#6,<z10=int6464#2
+# asm 2: paddd <orig10=80(%rsp),<z10=%xmm1
+paddd 80(%rsp),%xmm1
+
+# qhasm:   uint32323232 z11 += orig11
+# asm 1: paddd <orig11=stack128#10,<z11=int6464#7
+# asm 2: paddd <orig11=144(%rsp),<z11=%xmm6
+paddd 144(%rsp),%xmm6
+
+# qhasm:   in8 = z8
+# asm 1: movd   <z8=int6464#16,>in8=int64#3
+# asm 2: movd   <z8=%xmm15,>in8=%rdx
+movd   %xmm15,%rdx
+
+# qhasm:   in9 = z9
+# asm 1: movd   <z9=int6464#12,>in9=int64#4
+# asm 2: movd   <z9=%xmm11,>in9=%rcx
+movd   %xmm11,%rcx
+
+# qhasm:   in10 = z10
+# asm 1: movd   <z10=int6464#2,>in10=int64#5
+# asm 2: movd   <z10=%xmm1,>in10=%r8
+movd   %xmm1,%r8
+
+# qhasm:   in11 = z11
+# asm 1: movd   <z11=int6464#7,>in11=int64#6
+# asm 2: movd   <z11=%xmm6,>in11=%r9
+movd   %xmm6,%r9
+
+# qhasm:   z8 <<<= 96
+# asm 1: pshufd $0x39,<z8=int6464#16,<z8=int6464#16
+# asm 2: pshufd $0x39,<z8=%xmm15,<z8=%xmm15
+pshufd $0x39,%xmm15,%xmm15
+
+# qhasm:   z9 <<<= 96
+# asm 1: pshufd $0x39,<z9=int6464#12,<z9=int6464#12
+# asm 2: pshufd $0x39,<z9=%xmm11,<z9=%xmm11
+pshufd $0x39,%xmm11,%xmm11
+
+# qhasm:   z10 <<<= 96
+# asm 1: pshufd $0x39,<z10=int6464#2,<z10=int6464#2
+# asm 2: pshufd $0x39,<z10=%xmm1,<z10=%xmm1
+pshufd $0x39,%xmm1,%xmm1
+
+# qhasm:   z11 <<<= 96
+# asm 1: pshufd $0x39,<z11=int6464#7,<z11=int6464#7
+# asm 2: pshufd $0x39,<z11=%xmm6,<z11=%xmm6
+pshufd $0x39,%xmm6,%xmm6
+
+# qhasm:   (uint32) in8 ^= *(uint32 *) (m + 32)
+# asm 1: xorl 32(<m=int64#2),<in8=int64#3d
+# asm 2: xorl 32(<m=%rsi),<in8=%edx
+xorl 32(%rsi),%edx
+
+# qhasm:   (uint32) in9 ^= *(uint32 *) (m + 36)
+# asm 1: xorl 36(<m=int64#2),<in9=int64#4d
+# asm 2: xorl 36(<m=%rsi),<in9=%ecx
+xorl 36(%rsi),%ecx
+
+# qhasm:   (uint32) in10 ^= *(uint32 *) (m + 40)
+# asm 1: xorl 40(<m=int64#2),<in10=int64#5d
+# asm 2: xorl 40(<m=%rsi),<in10=%r8d
+xorl 40(%rsi),%r8d
+
+# qhasm:   (uint32) in11 ^= *(uint32 *) (m + 44)
+# asm 1: xorl 44(<m=int64#2),<in11=int64#6d
+# asm 2: xorl 44(<m=%rsi),<in11=%r9d
+xorl 44(%rsi),%r9d
+
+# qhasm:   *(uint32 *) (out + 32) = in8
+# asm 1: movl   <in8=int64#3d,32(<out=int64#1)
+# asm 2: movl   <in8=%edx,32(<out=%rdi)
+movl   %edx,32(%rdi)
+
+# qhasm:   *(uint32 *) (out + 36) = in9
+# asm 1: movl   <in9=int64#4d,36(<out=int64#1)
+# asm 2: movl   <in9=%ecx,36(<out=%rdi)
+movl   %ecx,36(%rdi)
+
+# qhasm:   *(uint32 *) (out + 40) = in10
+# asm 1: movl   <in10=int64#5d,40(<out=int64#1)
+# asm 2: movl   <in10=%r8d,40(<out=%rdi)
+movl   %r8d,40(%rdi)
+
+# qhasm:   *(uint32 *) (out + 44) = in11
+# asm 1: movl   <in11=int64#6d,44(<out=int64#1)
+# asm 2: movl   <in11=%r9d,44(<out=%rdi)
+movl   %r9d,44(%rdi)
+
+# qhasm:   in8 = z8
+# asm 1: movd   <z8=int6464#16,>in8=int64#3
+# asm 2: movd   <z8=%xmm15,>in8=%rdx
+movd   %xmm15,%rdx
+
+# qhasm:   in9 = z9
+# asm 1: movd   <z9=int6464#12,>in9=int64#4
+# asm 2: movd   <z9=%xmm11,>in9=%rcx
+movd   %xmm11,%rcx
+
+# qhasm:   in10 = z10
+# asm 1: movd   <z10=int6464#2,>in10=int64#5
+# asm 2: movd   <z10=%xmm1,>in10=%r8
+movd   %xmm1,%r8
+
+# qhasm:   in11 = z11
+# asm 1: movd   <z11=int6464#7,>in11=int64#6
+# asm 2: movd   <z11=%xmm6,>in11=%r9
+movd   %xmm6,%r9
+
+# qhasm:   z8 <<<= 96
+# asm 1: pshufd $0x39,<z8=int6464#16,<z8=int6464#16
+# asm 2: pshufd $0x39,<z8=%xmm15,<z8=%xmm15
+pshufd $0x39,%xmm15,%xmm15
+
+# qhasm:   z9 <<<= 96
+# asm 1: pshufd $0x39,<z9=int6464#12,<z9=int6464#12
+# asm 2: pshufd $0x39,<z9=%xmm11,<z9=%xmm11
+pshufd $0x39,%xmm11,%xmm11
+
+# qhasm:   z10 <<<= 96
+# asm 1: pshufd $0x39,<z10=int6464#2,<z10=int6464#2
+# asm 2: pshufd $0x39,<z10=%xmm1,<z10=%xmm1
+pshufd $0x39,%xmm1,%xmm1
+
+# qhasm:   z11 <<<= 96
+# asm 1: pshufd $0x39,<z11=int6464#7,<z11=int6464#7
+# asm 2: pshufd $0x39,<z11=%xmm6,<z11=%xmm6
+pshufd $0x39,%xmm6,%xmm6
+
+# qhasm:   (uint32) in8 ^= *(uint32 *) (m + 96)
+# asm 1: xorl 96(<m=int64#2),<in8=int64#3d
+# asm 2: xorl 96(<m=%rsi),<in8=%edx
+xorl 96(%rsi),%edx
+
+# qhasm:   (uint32) in9 ^= *(uint32 *) (m + 100)
+# asm 1: xorl 100(<m=int64#2),<in9=int64#4d
+# asm 2: xorl 100(<m=%rsi),<in9=%ecx
+xorl 100(%rsi),%ecx
+
+# qhasm:   (uint32) in10 ^= *(uint32 *) (m + 104)
+# asm 1: xorl 104(<m=int64#2),<in10=int64#5d
+# asm 2: xorl 104(<m=%rsi),<in10=%r8d
+xorl 104(%rsi),%r8d
+
+# qhasm:   (uint32) in11 ^= *(uint32 *) (m + 108)
+# asm 1: xorl 108(<m=int64#2),<in11=int64#6d
+# asm 2: xorl 108(<m=%rsi),<in11=%r9d
+xorl 108(%rsi),%r9d
+
+# qhasm:   *(uint32 *) (out + 96) = in8
+# asm 1: movl   <in8=int64#3d,96(<out=int64#1)
+# asm 2: movl   <in8=%edx,96(<out=%rdi)
+movl   %edx,96(%rdi)
+
+# qhasm:   *(uint32 *) (out + 100) = in9
+# asm 1: movl   <in9=int64#4d,100(<out=int64#1)
+# asm 2: movl   <in9=%ecx,100(<out=%rdi)
+movl   %ecx,100(%rdi)
+
+# qhasm:   *(uint32 *) (out + 104) = in10
+# asm 1: movl   <in10=int64#5d,104(<out=int64#1)
+# asm 2: movl   <in10=%r8d,104(<out=%rdi)
+movl   %r8d,104(%rdi)
+
+# qhasm:   *(uint32 *) (out + 108) = in11
+# asm 1: movl   <in11=int64#6d,108(<out=int64#1)
+# asm 2: movl   <in11=%r9d,108(<out=%rdi)
+movl   %r9d,108(%rdi)
+
+# qhasm:   in8 = z8
+# asm 1: movd   <z8=int6464#16,>in8=int64#3
+# asm 2: movd   <z8=%xmm15,>in8=%rdx
+movd   %xmm15,%rdx
+
+# qhasm:   in9 = z9
+# asm 1: movd   <z9=int6464#12,>in9=int64#4
+# asm 2: movd   <z9=%xmm11,>in9=%rcx
+movd   %xmm11,%rcx
+
+# qhasm:   in10 = z10
+# asm 1: movd   <z10=int6464#2,>in10=int64#5
+# asm 2: movd   <z10=%xmm1,>in10=%r8
+movd   %xmm1,%r8
+
+# qhasm:   in11 = z11
+# asm 1: movd   <z11=int6464#7,>in11=int64#6
+# asm 2: movd   <z11=%xmm6,>in11=%r9
+movd   %xmm6,%r9
+
+# qhasm:   z8 <<<= 96
+# asm 1: pshufd $0x39,<z8=int6464#16,<z8=int6464#16
+# asm 2: pshufd $0x39,<z8=%xmm15,<z8=%xmm15
+pshufd $0x39,%xmm15,%xmm15
+
+# qhasm:   z9 <<<= 96
+# asm 1: pshufd $0x39,<z9=int6464#12,<z9=int6464#12
+# asm 2: pshufd $0x39,<z9=%xmm11,<z9=%xmm11
+pshufd $0x39,%xmm11,%xmm11
+
+# qhasm:   z10 <<<= 96
+# asm 1: pshufd $0x39,<z10=int6464#2,<z10=int6464#2
+# asm 2: pshufd $0x39,<z10=%xmm1,<z10=%xmm1
+pshufd $0x39,%xmm1,%xmm1
+
+# qhasm:   z11 <<<= 96
+# asm 1: pshufd $0x39,<z11=int6464#7,<z11=int6464#7
+# asm 2: pshufd $0x39,<z11=%xmm6,<z11=%xmm6
+pshufd $0x39,%xmm6,%xmm6
+
+# qhasm:   (uint32) in8 ^= *(uint32 *) (m + 160)
+# asm 1: xorl 160(<m=int64#2),<in8=int64#3d
+# asm 2: xorl 160(<m=%rsi),<in8=%edx
+xorl 160(%rsi),%edx
+
+# qhasm:   (uint32) in9 ^= *(uint32 *) (m + 164)
+# asm 1: xorl 164(<m=int64#2),<in9=int64#4d
+# asm 2: xorl 164(<m=%rsi),<in9=%ecx
+xorl 164(%rsi),%ecx
+
+# qhasm:   (uint32) in10 ^= *(uint32 *) (m + 168)
+# asm 1: xorl 168(<m=int64#2),<in10=int64#5d
+# asm 2: xorl 168(<m=%rsi),<in10=%r8d
+xorl 168(%rsi),%r8d
+
+# qhasm:   (uint32) in11 ^= *(uint32 *) (m + 172)
+# asm 1: xorl 172(<m=int64#2),<in11=int64#6d
+# asm 2: xorl 172(<m=%rsi),<in11=%r9d
+xorl 172(%rsi),%r9d
+
+# qhasm:   *(uint32 *) (out + 160) = in8
+# asm 1: movl   <in8=int64#3d,160(<out=int64#1)
+# asm 2: movl   <in8=%edx,160(<out=%rdi)
+movl   %edx,160(%rdi)
+
+# qhasm:   *(uint32 *) (out + 164) = in9
+# asm 1: movl   <in9=int64#4d,164(<out=int64#1)
+# asm 2: movl   <in9=%ecx,164(<out=%rdi)
+movl   %ecx,164(%rdi)
+
+# qhasm:   *(uint32 *) (out + 168) = in10
+# asm 1: movl   <in10=int64#5d,168(<out=int64#1)
+# asm 2: movl   <in10=%r8d,168(<out=%rdi)
+movl   %r8d,168(%rdi)
+
+# qhasm:   *(uint32 *) (out + 172) = in11
+# asm 1: movl   <in11=int64#6d,172(<out=int64#1)
+# asm 2: movl   <in11=%r9d,172(<out=%rdi)
+movl   %r9d,172(%rdi)
+
+# qhasm:   in8 = z8
+# asm 1: movd   <z8=int6464#16,>in8=int64#3
+# asm 2: movd   <z8=%xmm15,>in8=%rdx
+movd   %xmm15,%rdx
+
+# qhasm:   in9 = z9
+# asm 1: movd   <z9=int6464#12,>in9=int64#4
+# asm 2: movd   <z9=%xmm11,>in9=%rcx
+movd   %xmm11,%rcx
+
+# qhasm:   in10 = z10
+# asm 1: movd   <z10=int6464#2,>in10=int64#5
+# asm 2: movd   <z10=%xmm1,>in10=%r8
+movd   %xmm1,%r8
+
+# qhasm:   in11 = z11
+# asm 1: movd   <z11=int6464#7,>in11=int64#6
+# asm 2: movd   <z11=%xmm6,>in11=%r9
+movd   %xmm6,%r9
+
+# qhasm:   (uint32) in8 ^= *(uint32 *) (m + 224)
+# asm 1: xorl 224(<m=int64#2),<in8=int64#3d
+# asm 2: xorl 224(<m=%rsi),<in8=%edx
+xorl 224(%rsi),%edx
+
+# qhasm:   (uint32) in9 ^= *(uint32 *) (m + 228)
+# asm 1: xorl 228(<m=int64#2),<in9=int64#4d
+# asm 2: xorl 228(<m=%rsi),<in9=%ecx
+xorl 228(%rsi),%ecx
+
+# qhasm:   (uint32) in10 ^= *(uint32 *) (m + 232)
+# asm 1: xorl 232(<m=int64#2),<in10=int64#5d
+# asm 2: xorl 232(<m=%rsi),<in10=%r8d
+xorl 232(%rsi),%r8d
+
+# qhasm:   (uint32) in11 ^= *(uint32 *) (m + 236)
+# asm 1: xorl 236(<m=int64#2),<in11=int64#6d
+# asm 2: xorl 236(<m=%rsi),<in11=%r9d
+xorl 236(%rsi),%r9d
+
+# qhasm:   *(uint32 *) (out + 224) = in8
+# asm 1: movl   <in8=int64#3d,224(<out=int64#1)
+# asm 2: movl   <in8=%edx,224(<out=%rdi)
+movl   %edx,224(%rdi)
+
+# qhasm:   *(uint32 *) (out + 228) = in9
+# asm 1: movl   <in9=int64#4d,228(<out=int64#1)
+# asm 2: movl   <in9=%ecx,228(<out=%rdi)
+movl   %ecx,228(%rdi)
+
+# qhasm:   *(uint32 *) (out + 232) = in10
+# asm 1: movl   <in10=int64#5d,232(<out=int64#1)
+# asm 2: movl   <in10=%r8d,232(<out=%rdi)
+movl   %r8d,232(%rdi)
+
+# qhasm:   *(uint32 *) (out + 236) = in11
+# asm 1: movl   <in11=int64#6d,236(<out=int64#1)
+# asm 2: movl   <in11=%r9d,236(<out=%rdi)
+movl   %r9d,236(%rdi)
+
+# qhasm:   uint32323232 z12 += orig12
+# asm 1: paddd <orig12=stack128#11,<z12=int6464#14
+# asm 2: paddd <orig12=160(%rsp),<z12=%xmm13
+paddd 160(%rsp),%xmm13
+
+# qhasm:   uint32323232 z13 += orig13
+# asm 1: paddd <orig13=stack128#14,<z13=int6464#10
+# asm 2: paddd <orig13=208(%rsp),<z13=%xmm9
+paddd 208(%rsp),%xmm9
+
+# qhasm:   uint32323232 z14 += orig14
+# asm 1: paddd <orig14=stack128#17,<z14=int6464#4
+# asm 2: paddd <orig14=256(%rsp),<z14=%xmm3
+paddd 256(%rsp),%xmm3
+
+# qhasm:   uint32323232 z15 += orig15
+# asm 1: paddd <orig15=stack128#7,<z15=int6464#3
+# asm 2: paddd <orig15=96(%rsp),<z15=%xmm2
+paddd 96(%rsp),%xmm2
+
+# qhasm:   in12 = z12
+# asm 1: movd   <z12=int6464#14,>in12=int64#3
+# asm 2: movd   <z12=%xmm13,>in12=%rdx
+movd   %xmm13,%rdx
+
+# qhasm:   in13 = z13
+# asm 1: movd   <z13=int6464#10,>in13=int64#4
+# asm 2: movd   <z13=%xmm9,>in13=%rcx
+movd   %xmm9,%rcx
+
+# qhasm:   in14 = z14
+# asm 1: movd   <z14=int6464#4,>in14=int64#5
+# asm 2: movd   <z14=%xmm3,>in14=%r8
+movd   %xmm3,%r8
+
+# qhasm:   in15 = z15
+# asm 1: movd   <z15=int6464#3,>in15=int64#6
+# asm 2: movd   <z15=%xmm2,>in15=%r9
+movd   %xmm2,%r9
+
+# qhasm:   z12 <<<= 96
+# asm 1: pshufd $0x39,<z12=int6464#14,<z12=int6464#14
+# asm 2: pshufd $0x39,<z12=%xmm13,<z12=%xmm13
+pshufd $0x39,%xmm13,%xmm13
+
+# qhasm:   z13 <<<= 96
+# asm 1: pshufd $0x39,<z13=int6464#10,<z13=int6464#10
+# asm 2: pshufd $0x39,<z13=%xmm9,<z13=%xmm9
+pshufd $0x39,%xmm9,%xmm9
+
+# qhasm:   z14 <<<= 96
+# asm 1: pshufd $0x39,<z14=int6464#4,<z14=int6464#4
+# asm 2: pshufd $0x39,<z14=%xmm3,<z14=%xmm3
+pshufd $0x39,%xmm3,%xmm3
+
+# qhasm:   z15 <<<= 96
+# asm 1: pshufd $0x39,<z15=int6464#3,<z15=int6464#3
+# asm 2: pshufd $0x39,<z15=%xmm2,<z15=%xmm2
+pshufd $0x39,%xmm2,%xmm2
+
+# qhasm:   (uint32) in12 ^= *(uint32 *) (m + 48)
+# asm 1: xorl 48(<m=int64#2),<in12=int64#3d
+# asm 2: xorl 48(<m=%rsi),<in12=%edx
+xorl 48(%rsi),%edx
+
+# qhasm:   (uint32) in13 ^= *(uint32 *) (m + 52)
+# asm 1: xorl 52(<m=int64#2),<in13=int64#4d
+# asm 2: xorl 52(<m=%rsi),<in13=%ecx
+xorl 52(%rsi),%ecx
+
+# qhasm:   (uint32) in14 ^= *(uint32 *) (m + 56)
+# asm 1: xorl 56(<m=int64#2),<in14=int64#5d
+# asm 2: xorl 56(<m=%rsi),<in14=%r8d
+xorl 56(%rsi),%r8d
+
+# qhasm:   (uint32) in15 ^= *(uint32 *) (m + 60)
+# asm 1: xorl 60(<m=int64#2),<in15=int64#6d
+# asm 2: xorl 60(<m=%rsi),<in15=%r9d
+xorl 60(%rsi),%r9d
+
+# qhasm:   *(uint32 *) (out + 48) = in12
+# asm 1: movl   <in12=int64#3d,48(<out=int64#1)
+# asm 2: movl   <in12=%edx,48(<out=%rdi)
+movl   %edx,48(%rdi)
+
+# qhasm:   *(uint32 *) (out + 52) = in13
+# asm 1: movl   <in13=int64#4d,52(<out=int64#1)
+# asm 2: movl   <in13=%ecx,52(<out=%rdi)
+movl   %ecx,52(%rdi)
+
+# qhasm:   *(uint32 *) (out + 56) = in14
+# asm 1: movl   <in14=int64#5d,56(<out=int64#1)
+# asm 2: movl   <in14=%r8d,56(<out=%rdi)
+movl   %r8d,56(%rdi)
+
+# qhasm:   *(uint32 *) (out + 60) = in15
+# asm 1: movl   <in15=int64#6d,60(<out=int64#1)
+# asm 2: movl   <in15=%r9d,60(<out=%rdi)
+movl   %r9d,60(%rdi)
+
+# qhasm:   in12 = z12
+# asm 1: movd   <z12=int6464#14,>in12=int64#3
+# asm 2: movd   <z12=%xmm13,>in12=%rdx
+movd   %xmm13,%rdx
+
+# qhasm:   in13 = z13
+# asm 1: movd   <z13=int6464#10,>in13=int64#4
+# asm 2: movd   <z13=%xmm9,>in13=%rcx
+movd   %xmm9,%rcx
+
+# qhasm:   in14 = z14
+# asm 1: movd   <z14=int6464#4,>in14=int64#5
+# asm 2: movd   <z14=%xmm3,>in14=%r8
+movd   %xmm3,%r8
+
+# qhasm:   in15 = z15
+# asm 1: movd   <z15=int6464#3,>in15=int64#6
+# asm 2: movd   <z15=%xmm2,>in15=%r9
+movd   %xmm2,%r9
+
+# qhasm:   z12 <<<= 96
+# asm 1: pshufd $0x39,<z12=int6464#14,<z12=int6464#14
+# asm 2: pshufd $0x39,<z12=%xmm13,<z12=%xmm13
+pshufd $0x39,%xmm13,%xmm13
+
+# qhasm:   z13 <<<= 96
+# asm 1: pshufd $0x39,<z13=int6464#10,<z13=int6464#10
+# asm 2: pshufd $0x39,<z13=%xmm9,<z13=%xmm9
+pshufd $0x39,%xmm9,%xmm9
+
+# qhasm:   z14 <<<= 96
+# asm 1: pshufd $0x39,<z14=int6464#4,<z14=int6464#4
+# asm 2: pshufd $0x39,<z14=%xmm3,<z14=%xmm3
+pshufd $0x39,%xmm3,%xmm3
+
+# qhasm:   z15 <<<= 96
+# asm 1: pshufd $0x39,<z15=int6464#3,<z15=int6464#3
+# asm 2: pshufd $0x39,<z15=%xmm2,<z15=%xmm2
+pshufd $0x39,%xmm2,%xmm2
+
+# qhasm:   (uint32) in12 ^= *(uint32 *) (m + 112)
+# asm 1: xorl 112(<m=int64#2),<in12=int64#3d
+# asm 2: xorl 112(<m=%rsi),<in12=%edx
+xorl 112(%rsi),%edx
+
+# qhasm:   (uint32) in13 ^= *(uint32 *) (m + 116)
+# asm 1: xorl 116(<m=int64#2),<in13=int64#4d
+# asm 2: xorl 116(<m=%rsi),<in13=%ecx
+xorl 116(%rsi),%ecx
+
+# qhasm:   (uint32) in14 ^= *(uint32 *) (m + 120)
+# asm 1: xorl 120(<m=int64#2),<in14=int64#5d
+# asm 2: xorl 120(<m=%rsi),<in14=%r8d
+xorl 120(%rsi),%r8d
+
+# qhasm:   (uint32) in15 ^= *(uint32 *) (m + 124)
+# asm 1: xorl 124(<m=int64#2),<in15=int64#6d
+# asm 2: xorl 124(<m=%rsi),<in15=%r9d
+xorl 124(%rsi),%r9d
+
+# qhasm:   *(uint32 *) (out + 112) = in12
+# asm 1: movl   <in12=int64#3d,112(<out=int64#1)
+# asm 2: movl   <in12=%edx,112(<out=%rdi)
+movl   %edx,112(%rdi)
+
+# qhasm:   *(uint32 *) (out + 116) = in13
+# asm 1: movl   <in13=int64#4d,116(<out=int64#1)
+# asm 2: movl   <in13=%ecx,116(<out=%rdi)
+movl   %ecx,116(%rdi)
+
+# qhasm:   *(uint32 *) (out + 120) = in14
+# asm 1: movl   <in14=int64#5d,120(<out=int64#1)
+# asm 2: movl   <in14=%r8d,120(<out=%rdi)
+movl   %r8d,120(%rdi)
+
+# qhasm:   *(uint32 *) (out + 124) = in15
+# asm 1: movl   <in15=int64#6d,124(<out=int64#1)
+# asm 2: movl   <in15=%r9d,124(<out=%rdi)
+movl   %r9d,124(%rdi)
+
+# qhasm:   in12 = z12
+# asm 1: movd   <z12=int6464#14,>in12=int64#3
+# asm 2: movd   <z12=%xmm13,>in12=%rdx
+movd   %xmm13,%rdx
+
+# qhasm:   in13 = z13
+# asm 1: movd   <z13=int6464#10,>in13=int64#4
+# asm 2: movd   <z13=%xmm9,>in13=%rcx
+movd   %xmm9,%rcx
+
+# qhasm:   in14 = z14
+# asm 1: movd   <z14=int6464#4,>in14=int64#5
+# asm 2: movd   <z14=%xmm3,>in14=%r8
+movd   %xmm3,%r8
+
+# qhasm:   in15 = z15
+# asm 1: movd   <z15=int6464#3,>in15=int64#6
+# asm 2: movd   <z15=%xmm2,>in15=%r9
+movd   %xmm2,%r9
+
+# qhasm:   z12 <<<= 96
+# asm 1: pshufd $0x39,<z12=int6464#14,<z12=int6464#14
+# asm 2: pshufd $0x39,<z12=%xmm13,<z12=%xmm13
+pshufd $0x39,%xmm13,%xmm13
+
+# qhasm:   z13 <<<= 96
+# asm 1: pshufd $0x39,<z13=int6464#10,<z13=int6464#10
+# asm 2: pshufd $0x39,<z13=%xmm9,<z13=%xmm9
+pshufd $0x39,%xmm9,%xmm9
+
+# qhasm:   z14 <<<= 96
+# asm 1: pshufd $0x39,<z14=int6464#4,<z14=int6464#4
+# asm 2: pshufd $0x39,<z14=%xmm3,<z14=%xmm3
+pshufd $0x39,%xmm3,%xmm3
+
+# qhasm:   z15 <<<= 96
+# asm 1: pshufd $0x39,<z15=int6464#3,<z15=int6464#3
+# asm 2: pshufd $0x39,<z15=%xmm2,<z15=%xmm2
+pshufd $0x39,%xmm2,%xmm2
+
+# qhasm:   (uint32) in12 ^= *(uint32 *) (m + 176)
+# asm 1: xorl 176(<m=int64#2),<in12=int64#3d
+# asm 2: xorl 176(<m=%rsi),<in12=%edx
+xorl 176(%rsi),%edx
+
+# qhasm:   (uint32) in13 ^= *(uint32 *) (m + 180)
+# asm 1: xorl 180(<m=int64#2),<in13=int64#4d
+# asm 2: xorl 180(<m=%rsi),<in13=%ecx
+xorl 180(%rsi),%ecx
+
+# qhasm:   (uint32) in14 ^= *(uint32 *) (m + 184)
+# asm 1: xorl 184(<m=int64#2),<in14=int64#5d
+# asm 2: xorl 184(<m=%rsi),<in14=%r8d
+xorl 184(%rsi),%r8d
+
+# qhasm:   (uint32) in15 ^= *(uint32 *) (m + 188)
+# asm 1: xorl 188(<m=int64#2),<in15=int64#6d
+# asm 2: xorl 188(<m=%rsi),<in15=%r9d
+xorl 188(%rsi),%r9d
+
+# qhasm:   *(uint32 *) (out + 176) = in12
+# asm 1: movl   <in12=int64#3d,176(<out=int64#1)
+# asm 2: movl   <in12=%edx,176(<out=%rdi)
+movl   %edx,176(%rdi)
+
+# qhasm:   *(uint32 *) (out + 180) = in13
+# asm 1: movl   <in13=int64#4d,180(<out=int64#1)
+# asm 2: movl   <in13=%ecx,180(<out=%rdi)
+movl   %ecx,180(%rdi)
+
+# qhasm:   *(uint32 *) (out + 184) = in14
+# asm 1: movl   <in14=int64#5d,184(<out=int64#1)
+# asm 2: movl   <in14=%r8d,184(<out=%rdi)
+movl   %r8d,184(%rdi)
+
+# qhasm:   *(uint32 *) (out + 188) = in15
+# asm 1: movl   <in15=int64#6d,188(<out=int64#1)
+# asm 2: movl   <in15=%r9d,188(<out=%rdi)
+movl   %r9d,188(%rdi)
+
+# qhasm:   in12 = z12
+# asm 1: movd   <z12=int6464#14,>in12=int64#3
+# asm 2: movd   <z12=%xmm13,>in12=%rdx
+movd   %xmm13,%rdx
+
+# qhasm:   in13 = z13
+# asm 1: movd   <z13=int6464#10,>in13=int64#4
+# asm 2: movd   <z13=%xmm9,>in13=%rcx
+movd   %xmm9,%rcx
+
+# qhasm:   in14 = z14
+# asm 1: movd   <z14=int6464#4,>in14=int64#5
+# asm 2: movd   <z14=%xmm3,>in14=%r8
+movd   %xmm3,%r8
+
+# qhasm:   in15 = z15
+# asm 1: movd   <z15=int6464#3,>in15=int64#6
+# asm 2: movd   <z15=%xmm2,>in15=%r9
+movd   %xmm2,%r9
+
+# qhasm:   (uint32) in12 ^= *(uint32 *) (m + 240)
+# asm 1: xorl 240(<m=int64#2),<in12=int64#3d
+# asm 2: xorl 240(<m=%rsi),<in12=%edx
+xorl 240(%rsi),%edx
+
+# qhasm:   (uint32) in13 ^= *(uint32 *) (m + 244)
+# asm 1: xorl 244(<m=int64#2),<in13=int64#4d
+# asm 2: xorl 244(<m=%rsi),<in13=%ecx
+xorl 244(%rsi),%ecx
+
+# qhasm:   (uint32) in14 ^= *(uint32 *) (m + 248)
+# asm 1: xorl 248(<m=int64#2),<in14=int64#5d
+# asm 2: xorl 248(<m=%rsi),<in14=%r8d
+xorl 248(%rsi),%r8d
+
+# qhasm:   (uint32) in15 ^= *(uint32 *) (m + 252)
+# asm 1: xorl 252(<m=int64#2),<in15=int64#6d
+# asm 2: xorl 252(<m=%rsi),<in15=%r9d
+xorl 252(%rsi),%r9d
+
+# qhasm:   *(uint32 *) (out + 240) = in12
+# asm 1: movl   <in12=int64#3d,240(<out=int64#1)
+# asm 2: movl   <in12=%edx,240(<out=%rdi)
+movl   %edx,240(%rdi)
+
+# qhasm:   *(uint32 *) (out + 244) = in13
+# asm 1: movl   <in13=int64#4d,244(<out=int64#1)
+# asm 2: movl   <in13=%ecx,244(<out=%rdi)
+movl   %ecx,244(%rdi)
+
+# qhasm:   *(uint32 *) (out + 248) = in14
+# asm 1: movl   <in14=int64#5d,248(<out=int64#1)
+# asm 2: movl   <in14=%r8d,248(<out=%rdi)
+movl   %r8d,248(%rdi)
+
+# qhasm:   *(uint32 *) (out + 252) = in15
+# asm 1: movl   <in15=int64#6d,252(<out=int64#1)
+# asm 2: movl   <in15=%r9d,252(<out=%rdi)
+movl   %r9d,252(%rdi)
+
+# qhasm:   bytes = bytes_backup
+# asm 1: movq <bytes_backup=stack64#8,>bytes=int64#6
+# asm 2: movq <bytes_backup=408(%rsp),>bytes=%r9
+movq 408(%rsp),%r9
+
+# qhasm:   bytes -= 256
+# asm 1: sub  $256,<bytes=int64#6
+# asm 2: sub  $256,<bytes=%r9
+sub  $256,%r9
+
+# qhasm:   m += 256
+# asm 1: add  $256,<m=int64#2
+# asm 2: add  $256,<m=%rsi
+add  $256,%rsi
+
+# qhasm:   out += 256
+# asm 1: add  $256,<out=int64#1
+# asm 2: add  $256,<out=%rdi
+add  $256,%rdi
+
+# qhasm:                            unsigned<? bytes - 256
+# asm 1: cmp  $256,<bytes=int64#6
+# asm 2: cmp  $256,<bytes=%r9
+cmp  $256,%r9
+# comment:fp stack unchanged by jump
+
+# qhasm:   goto bytesatleast256 if !unsigned<
+jae ._bytesatleast256
+
+# qhasm:                 unsigned>? bytes - 0
+# asm 1: cmp  $0,<bytes=int64#6
+# asm 2: cmp  $0,<bytes=%r9
+cmp  $0,%r9
+# comment:fp stack unchanged by jump
+
+# qhasm:   goto done if !unsigned>
+jbe ._done
+# comment:fp stack unchanged by fallthrough
+
+# qhasm: bytesbetween1and255:
+._bytesbetween1and255:
+
+# qhasm:                   unsigned<? bytes - 64
+# asm 1: cmp  $64,<bytes=int64#6
+# asm 2: cmp  $64,<bytes=%r9
+cmp  $64,%r9
+# comment:fp stack unchanged by jump
+
+# qhasm:   goto nocopy if !unsigned<
+jae ._nocopy
+
+# qhasm:     ctarget = out
+# asm 1: mov  <out=int64#1,>ctarget=int64#3
+# asm 2: mov  <out=%rdi,>ctarget=%rdx
+mov  %rdi,%rdx
+
+# qhasm:     out = &tmp
+# asm 1: leaq <tmp=stack512#1,>out=int64#1
+# asm 2: leaq <tmp=416(%rsp),>out=%rdi
+leaq 416(%rsp),%rdi
+
+# qhasm:     i = bytes
+# asm 1: mov  <bytes=int64#6,>i=int64#4
+# asm 2: mov  <bytes=%r9,>i=%rcx
+mov  %r9,%rcx
+
+# qhasm:     while (i) { *out++ = *m++; --i }
+rep movsb
+
+# qhasm:     out = &tmp
+# asm 1: leaq <tmp=stack512#1,>out=int64#1
+# asm 2: leaq <tmp=416(%rsp),>out=%rdi
+leaq 416(%rsp),%rdi
+
+# qhasm:     m = &tmp
+# asm 1: leaq <tmp=stack512#1,>m=int64#2
+# asm 2: leaq <tmp=416(%rsp),>m=%rsi
+leaq 416(%rsp),%rsi
+# comment:fp stack unchanged by fallthrough
+
+# qhasm:   nocopy:
+._nocopy:
+
+# qhasm:   bytes_backup = bytes
+# asm 1: movq <bytes=int64#6,>bytes_backup=stack64#8
+# asm 2: movq <bytes=%r9,>bytes_backup=408(%rsp)
+movq %r9,408(%rsp)
+
+# qhasm: diag0 = x0
+# asm 1: movdqa <x0=stack128#4,>diag0=int6464#1
+# asm 2: movdqa <x0=48(%rsp),>diag0=%xmm0
+movdqa 48(%rsp),%xmm0
+
+# qhasm: diag1 = x1
+# asm 1: movdqa <x1=stack128#1,>diag1=int6464#2
+# asm 2: movdqa <x1=0(%rsp),>diag1=%xmm1
+movdqa 0(%rsp),%xmm1
+
+# qhasm: diag2 = x2
+# asm 1: movdqa <x2=stack128#2,>diag2=int6464#3
+# asm 2: movdqa <x2=16(%rsp),>diag2=%xmm2
+movdqa 16(%rsp),%xmm2
+
+# qhasm: diag3 = x3
+# asm 1: movdqa <x3=stack128#3,>diag3=int6464#4
+# asm 2: movdqa <x3=32(%rsp),>diag3=%xmm3
+movdqa 32(%rsp),%xmm3
+
+# qhasm:                     a0 = diag1
+# asm 1: movdqa <diag1=int6464#2,>a0=int6464#5
+# asm 2: movdqa <diag1=%xmm1,>a0=%xmm4
+movdqa %xmm1,%xmm4
+
+# qhasm: i = 20
+# asm 1: mov  $20,>i=int64#4
+# asm 2: mov  $20,>i=%rcx
+mov  $20,%rcx
+
+# qhasm: mainloop2:
+._mainloop2:
+
+# qhasm: uint32323232        a0 += diag0
+# asm 1: paddd <diag0=int6464#1,<a0=int6464#5
+# asm 2: paddd <diag0=%xmm0,<a0=%xmm4
+paddd %xmm0,%xmm4
+
+# qhasm:                                 a1 = diag0
+# asm 1: movdqa <diag0=int6464#1,>a1=int6464#6
+# asm 2: movdqa <diag0=%xmm0,>a1=%xmm5
+movdqa %xmm0,%xmm5
+
+# qhasm:                     b0 = a0
+# asm 1: movdqa <a0=int6464#5,>b0=int6464#7
+# asm 2: movdqa <a0=%xmm4,>b0=%xmm6
+movdqa %xmm4,%xmm6
+
+# qhasm: uint32323232        a0 <<= 7
+# asm 1: pslld $7,<a0=int6464#5
+# asm 2: pslld $7,<a0=%xmm4
+pslld $7,%xmm4
+
+# qhasm: uint32323232        b0 >>= 25
+# asm 1: psrld $25,<b0=int6464#7
+# asm 2: psrld $25,<b0=%xmm6
+psrld $25,%xmm6
+
+# qhasm:                 diag3 ^= a0
+# asm 1: pxor  <a0=int6464#5,<diag3=int6464#4
+# asm 2: pxor  <a0=%xmm4,<diag3=%xmm3
+pxor  %xmm4,%xmm3
+
+# qhasm:                 diag3 ^= b0
+# asm 1: pxor  <b0=int6464#7,<diag3=int6464#4
+# asm 2: pxor  <b0=%xmm6,<diag3=%xmm3
+pxor  %xmm6,%xmm3
+
+# qhasm: uint32323232                        a1 += diag3
+# asm 1: paddd <diag3=int6464#4,<a1=int6464#6
+# asm 2: paddd <diag3=%xmm3,<a1=%xmm5
+paddd %xmm3,%xmm5
+
+# qhasm:                                                 a2 = diag3
+# asm 1: movdqa <diag3=int6464#4,>a2=int6464#5
+# asm 2: movdqa <diag3=%xmm3,>a2=%xmm4
+movdqa %xmm3,%xmm4
+
+# qhasm:                                     b1 = a1
+# asm 1: movdqa <a1=int6464#6,>b1=int6464#7
+# asm 2: movdqa <a1=%xmm5,>b1=%xmm6
+movdqa %xmm5,%xmm6
+
+# qhasm: uint32323232                        a1 <<= 9
+# asm 1: pslld $9,<a1=int6464#6
+# asm 2: pslld $9,<a1=%xmm5
+pslld $9,%xmm5
+
+# qhasm: uint32323232                        b1 >>= 23
+# asm 1: psrld $23,<b1=int6464#7
+# asm 2: psrld $23,<b1=%xmm6
+psrld $23,%xmm6
+
+# qhasm:                                 diag2 ^= a1
+# asm 1: pxor  <a1=int6464#6,<diag2=int6464#3
+# asm 2: pxor  <a1=%xmm5,<diag2=%xmm2
+pxor  %xmm5,%xmm2
+
+# qhasm:                 diag3 <<<= 32
+# asm 1: pshufd $0x93,<diag3=int6464#4,<diag3=int6464#4
+# asm 2: pshufd $0x93,<diag3=%xmm3,<diag3=%xmm3
+pshufd $0x93,%xmm3,%xmm3
+
+# qhasm:                                 diag2 ^= b1
+# asm 1: pxor  <b1=int6464#7,<diag2=int6464#3
+# asm 2: pxor  <b1=%xmm6,<diag2=%xmm2
+pxor  %xmm6,%xmm2
+
+# qhasm: uint32323232                                        a2 += diag2
+# asm 1: paddd <diag2=int6464#3,<a2=int6464#5
+# asm 2: paddd <diag2=%xmm2,<a2=%xmm4
+paddd %xmm2,%xmm4
+
+# qhasm:                                                                 a3 = diag2
+# asm 1: movdqa <diag2=int6464#3,>a3=int6464#6
+# asm 2: movdqa <diag2=%xmm2,>a3=%xmm5
+movdqa %xmm2,%xmm5
+
+# qhasm:                                                     b2 = a2
+# asm 1: movdqa <a2=int6464#5,>b2=int6464#7
+# asm 2: movdqa <a2=%xmm4,>b2=%xmm6
+movdqa %xmm4,%xmm6
+
+# qhasm: uint32323232                                        a2 <<= 13
+# asm 1: pslld $13,<a2=int6464#5
+# asm 2: pslld $13,<a2=%xmm4
+pslld $13,%xmm4
+
+# qhasm: uint32323232                                        b2 >>= 19
+# asm 1: psrld $19,<b2=int6464#7
+# asm 2: psrld $19,<b2=%xmm6
+psrld $19,%xmm6
+
+# qhasm:                                                 diag1 ^= a2
+# asm 1: pxor  <a2=int6464#5,<diag1=int6464#2
+# asm 2: pxor  <a2=%xmm4,<diag1=%xmm1
+pxor  %xmm4,%xmm1
+
+# qhasm:                                 diag2 <<<= 64
+# asm 1: pshufd $0x4e,<diag2=int6464#3,<diag2=int6464#3
+# asm 2: pshufd $0x4e,<diag2=%xmm2,<diag2=%xmm2
+pshufd $0x4e,%xmm2,%xmm2
+
+# qhasm:                                                 diag1 ^= b2
+# asm 1: pxor  <b2=int6464#7,<diag1=int6464#2
+# asm 2: pxor  <b2=%xmm6,<diag1=%xmm1
+pxor  %xmm6,%xmm1
+
+# qhasm: uint32323232                                                        a3 += diag1
+# asm 1: paddd <diag1=int6464#2,<a3=int6464#6
+# asm 2: paddd <diag1=%xmm1,<a3=%xmm5
+paddd %xmm1,%xmm5
+
+# qhasm:                 a4 = diag3
+# asm 1: movdqa <diag3=int6464#4,>a4=int6464#5
+# asm 2: movdqa <diag3=%xmm3,>a4=%xmm4
+movdqa %xmm3,%xmm4
+
+# qhasm:                                                                     b3 = a3
+# asm 1: movdqa <a3=int6464#6,>b3=int6464#7
+# asm 2: movdqa <a3=%xmm5,>b3=%xmm6
+movdqa %xmm5,%xmm6
+
+# qhasm: uint32323232                                                        a3 <<= 18
+# asm 1: pslld $18,<a3=int6464#6
+# asm 2: pslld $18,<a3=%xmm5
+pslld $18,%xmm5
+
+# qhasm: uint32323232                                                        b3 >>= 14
+# asm 1: psrld $14,<b3=int6464#7
+# asm 2: psrld $14,<b3=%xmm6
+psrld $14,%xmm6
+
+# qhasm:                                                                 diag0 ^= a3
+# asm 1: pxor  <a3=int6464#6,<diag0=int6464#1
+# asm 2: pxor  <a3=%xmm5,<diag0=%xmm0
+pxor  %xmm5,%xmm0
+
+# qhasm:                                                 diag1 <<<= 96
+# asm 1: pshufd $0x39,<diag1=int6464#2,<diag1=int6464#2
+# asm 2: pshufd $0x39,<diag1=%xmm1,<diag1=%xmm1
+pshufd $0x39,%xmm1,%xmm1
+
+# qhasm:                                                                 diag0 ^= b3
+# asm 1: pxor  <b3=int6464#7,<diag0=int6464#1
+# asm 2: pxor  <b3=%xmm6,<diag0=%xmm0
+pxor  %xmm6,%xmm0
+
+# qhasm: uint32323232        a4 += diag0
+# asm 1: paddd <diag0=int6464#1,<a4=int6464#5
+# asm 2: paddd <diag0=%xmm0,<a4=%xmm4
+paddd %xmm0,%xmm4
+
+# qhasm:                                 a5 = diag0
+# asm 1: movdqa <diag0=int6464#1,>a5=int6464#6
+# asm 2: movdqa <diag0=%xmm0,>a5=%xmm5
+movdqa %xmm0,%xmm5
+
+# qhasm:                     b4 = a4
+# asm 1: movdqa <a4=int6464#5,>b4=int6464#7
+# asm 2: movdqa <a4=%xmm4,>b4=%xmm6
+movdqa %xmm4,%xmm6
+
+# qhasm: uint32323232        a4 <<= 7
+# asm 1: pslld $7,<a4=int6464#5
+# asm 2: pslld $7,<a4=%xmm4
+pslld $7,%xmm4
+
+# qhasm: uint32323232        b4 >>= 25
+# asm 1: psrld $25,<b4=int6464#7
+# asm 2: psrld $25,<b4=%xmm6
+psrld $25,%xmm6
+
+# qhasm:                 diag1 ^= a4
+# asm 1: pxor  <a4=int6464#5,<diag1=int6464#2
+# asm 2: pxor  <a4=%xmm4,<diag1=%xmm1
+pxor  %xmm4,%xmm1
+
+# qhasm:                 diag1 ^= b4
+# asm 1: pxor  <b4=int6464#7,<diag1=int6464#2
+# asm 2: pxor  <b4=%xmm6,<diag1=%xmm1
+pxor  %xmm6,%xmm1
+
+# qhasm: uint32323232                        a5 += diag1
+# asm 1: paddd <diag1=int6464#2,<a5=int6464#6
+# asm 2: paddd <diag1=%xmm1,<a5=%xmm5
+paddd %xmm1,%xmm5
+
+# qhasm:                                                 a6 = diag1
+# asm 1: movdqa <diag1=int6464#2,>a6=int6464#5
+# asm 2: movdqa <diag1=%xmm1,>a6=%xmm4
+movdqa %xmm1,%xmm4
+
+# qhasm:                                     b5 = a5
+# asm 1: movdqa <a5=int6464#6,>b5=int6464#7
+# asm 2: movdqa <a5=%xmm5,>b5=%xmm6
+movdqa %xmm5,%xmm6
+
+# qhasm: uint32323232                        a5 <<= 9
+# asm 1: pslld $9,<a5=int6464#6
+# asm 2: pslld $9,<a5=%xmm5
+pslld $9,%xmm5
+
+# qhasm: uint32323232                        b5 >>= 23
+# asm 1: psrld $23,<b5=int6464#7
+# asm 2: psrld $23,<b5=%xmm6
+psrld $23,%xmm6
+
+# qhasm:                                 diag2 ^= a5
+# asm 1: pxor  <a5=int6464#6,<diag2=int6464#3
+# asm 2: pxor  <a5=%xmm5,<diag2=%xmm2
+pxor  %xmm5,%xmm2
+
+# qhasm:                 diag1 <<<= 32
+# asm 1: pshufd $0x93,<diag1=int6464#2,<diag1=int6464#2
+# asm 2: pshufd $0x93,<diag1=%xmm1,<diag1=%xmm1
+pshufd $0x93,%xmm1,%xmm1
+
+# qhasm:                                 diag2 ^= b5
+# asm 1: pxor  <b5=int6464#7,<diag2=int6464#3
+# asm 2: pxor  <b5=%xmm6,<diag2=%xmm2
+pxor  %xmm6,%xmm2
+
+# qhasm: uint32323232                                        a6 += diag2
+# asm 1: paddd <diag2=int6464#3,<a6=int6464#5
+# asm 2: paddd <diag2=%xmm2,<a6=%xmm4
+paddd %xmm2,%xmm4
+
+# qhasm:                                                                 a7 = diag2
+# asm 1: movdqa <diag2=int6464#3,>a7=int6464#6
+# asm 2: movdqa <diag2=%xmm2,>a7=%xmm5
+movdqa %xmm2,%xmm5
+
+# qhasm:                                                     b6 = a6
+# asm 1: movdqa <a6=int6464#5,>b6=int6464#7
+# asm 2: movdqa <a6=%xmm4,>b6=%xmm6
+movdqa %xmm4,%xmm6
+
+# qhasm: uint32323232                                        a6 <<= 13
+# asm 1: pslld $13,<a6=int6464#5
+# asm 2: pslld $13,<a6=%xmm4
+pslld $13,%xmm4
+
+# qhasm: uint32323232                                        b6 >>= 19
+# asm 1: psrld $19,<b6=int6464#7
+# asm 2: psrld $19,<b6=%xmm6
+psrld $19,%xmm6
+
+# qhasm:                                                 diag3 ^= a6
+# asm 1: pxor  <a6=int6464#5,<diag3=int6464#4
+# asm 2: pxor  <a6=%xmm4,<diag3=%xmm3
+pxor  %xmm4,%xmm3
+
+# qhasm:                                 diag2 <<<= 64
+# asm 1: pshufd $0x4e,<diag2=int6464#3,<diag2=int6464#3
+# asm 2: pshufd $0x4e,<diag2=%xmm2,<diag2=%xmm2
+pshufd $0x4e,%xmm2,%xmm2
+
+# qhasm:                                                 diag3 ^= b6
+# asm 1: pxor  <b6=int6464#7,<diag3=int6464#4
+# asm 2: pxor  <b6=%xmm6,<diag3=%xmm3
+pxor  %xmm6,%xmm3
+
+# qhasm: uint32323232                                                        a7 += diag3
+# asm 1: paddd <diag3=int6464#4,<a7=int6464#6
+# asm 2: paddd <diag3=%xmm3,<a7=%xmm5
+paddd %xmm3,%xmm5
+
+# qhasm:                 a0 = diag1
+# asm 1: movdqa <diag1=int6464#2,>a0=int6464#5
+# asm 2: movdqa <diag1=%xmm1,>a0=%xmm4
+movdqa %xmm1,%xmm4
+
+# qhasm:                                                                     b7 = a7
+# asm 1: movdqa <a7=int6464#6,>b7=int6464#7
+# asm 2: movdqa <a7=%xmm5,>b7=%xmm6
+movdqa %xmm5,%xmm6
+
+# qhasm: uint32323232                                                        a7 <<= 18
+# asm 1: pslld $18,<a7=int6464#6
+# asm 2: pslld $18,<a7=%xmm5
+pslld $18,%xmm5
+
+# qhasm: uint32323232                                                        b7 >>= 14
+# asm 1: psrld $14,<b7=int6464#7
+# asm 2: psrld $14,<b7=%xmm6
+psrld $14,%xmm6
+
+# qhasm:                                                                 diag0 ^= a7
+# asm 1: pxor  <a7=int6464#6,<diag0=int6464#1
+# asm 2: pxor  <a7=%xmm5,<diag0=%xmm0
+pxor  %xmm5,%xmm0
+
+# qhasm:                                                 diag3 <<<= 96
+# asm 1: pshufd $0x39,<diag3=int6464#4,<diag3=int6464#4
+# asm 2: pshufd $0x39,<diag3=%xmm3,<diag3=%xmm3
+pshufd $0x39,%xmm3,%xmm3
+
+# qhasm:                                                                 diag0 ^= b7
+# asm 1: pxor  <b7=int6464#7,<diag0=int6464#1
+# asm 2: pxor  <b7=%xmm6,<diag0=%xmm0
+pxor  %xmm6,%xmm0
+
+# qhasm: uint32323232        a0 += diag0
+# asm 1: paddd <diag0=int6464#1,<a0=int6464#5
+# asm 2: paddd <diag0=%xmm0,<a0=%xmm4
+paddd %xmm0,%xmm4
+
+# qhasm:                                 a1 = diag0
+# asm 1: movdqa <diag0=int6464#1,>a1=int6464#6
+# asm 2: movdqa <diag0=%xmm0,>a1=%xmm5
+movdqa %xmm0,%xmm5
+
+# qhasm:                     b0 = a0
+# asm 1: movdqa <a0=int6464#5,>b0=int6464#7
+# asm 2: movdqa <a0=%xmm4,>b0=%xmm6
+movdqa %xmm4,%xmm6
+
+# qhasm: uint32323232        a0 <<= 7
+# asm 1: pslld $7,<a0=int6464#5
+# asm 2: pslld $7,<a0=%xmm4
+pslld $7,%xmm4
+
+# qhasm: uint32323232        b0 >>= 25
+# asm 1: psrld $25,<b0=int6464#7
+# asm 2: psrld $25,<b0=%xmm6
+psrld $25,%xmm6
+
+# qhasm:                 diag3 ^= a0
+# asm 1: pxor  <a0=int6464#5,<diag3=int6464#4
+# asm 2: pxor  <a0=%xmm4,<diag3=%xmm3
+pxor  %xmm4,%xmm3
+
+# qhasm:                 diag3 ^= b0
+# asm 1: pxor  <b0=int6464#7,<diag3=int6464#4
+# asm 2: pxor  <b0=%xmm6,<diag3=%xmm3
+pxor  %xmm6,%xmm3
+
+# qhasm: uint32323232                        a1 += diag3
+# asm 1: paddd <diag3=int6464#4,<a1=int6464#6
+# asm 2: paddd <diag3=%xmm3,<a1=%xmm5
+paddd %xmm3,%xmm5
+
+# qhasm:                                                 a2 = diag3
+# asm 1: movdqa <diag3=int6464#4,>a2=int6464#5
+# asm 2: movdqa <diag3=%xmm3,>a2=%xmm4
+movdqa %xmm3,%xmm4
+
+# qhasm:                                     b1 = a1
+# asm 1: movdqa <a1=int6464#6,>b1=int6464#7
+# asm 2: movdqa <a1=%xmm5,>b1=%xmm6
+movdqa %xmm5,%xmm6
+
+# qhasm: uint32323232                        a1 <<= 9
+# asm 1: pslld $9,<a1=int6464#6
+# asm 2: pslld $9,<a1=%xmm5
+pslld $9,%xmm5
+
+# qhasm: uint32323232                        b1 >>= 23
+# asm 1: psrld $23,<b1=int6464#7
+# asm 2: psrld $23,<b1=%xmm6
+psrld $23,%xmm6
+
+# qhasm:                                 diag2 ^= a1
+# asm 1: pxor  <a1=int6464#6,<diag2=int6464#3
+# asm 2: pxor  <a1=%xmm5,<diag2=%xmm2
+pxor  %xmm5,%xmm2
+
+# qhasm:                 diag3 <<<= 32
+# asm 1: pshufd $0x93,<diag3=int6464#4,<diag3=int6464#4
+# asm 2: pshufd $0x93,<diag3=%xmm3,<diag3=%xmm3
+pshufd $0x93,%xmm3,%xmm3
+
+# qhasm:                                 diag2 ^= b1
+# asm 1: pxor  <b1=int6464#7,<diag2=int6464#3
+# asm 2: pxor  <b1=%xmm6,<diag2=%xmm2
+pxor  %xmm6,%xmm2
+
+# qhasm: uint32323232                                        a2 += diag2
+# asm 1: paddd <diag2=int6464#3,<a2=int6464#5
+# asm 2: paddd <diag2=%xmm2,<a2=%xmm4
+paddd %xmm2,%xmm4
+
+# qhasm:                                                                 a3 = diag2
+# asm 1: movdqa <diag2=int6464#3,>a3=int6464#6
+# asm 2: movdqa <diag2=%xmm2,>a3=%xmm5
+movdqa %xmm2,%xmm5
+
+# qhasm:                                                     b2 = a2
+# asm 1: movdqa <a2=int6464#5,>b2=int6464#7
+# asm 2: movdqa <a2=%xmm4,>b2=%xmm6
+movdqa %xmm4,%xmm6
+
+# qhasm: uint32323232                                        a2 <<= 13
+# asm 1: pslld $13,<a2=int6464#5
+# asm 2: pslld $13,<a2=%xmm4
+pslld $13,%xmm4
+
+# qhasm: uint32323232                                        b2 >>= 19
+# asm 1: psrld $19,<b2=int6464#7
+# asm 2: psrld $19,<b2=%xmm6
+psrld $19,%xmm6
+
+# qhasm:                                                 diag1 ^= a2
+# asm 1: pxor  <a2=int6464#5,<diag1=int6464#2
+# asm 2: pxor  <a2=%xmm4,<diag1=%xmm1
+pxor  %xmm4,%xmm1
+
+# qhasm:                                 diag2 <<<= 64
+# asm 1: pshufd $0x4e,<diag2=int6464#3,<diag2=int6464#3
+# asm 2: pshufd $0x4e,<diag2=%xmm2,<diag2=%xmm2
+pshufd $0x4e,%xmm2,%xmm2
+
+# qhasm:                                                 diag1 ^= b2
+# asm 1: pxor  <b2=int6464#7,<diag1=int6464#2
+# asm 2: pxor  <b2=%xmm6,<diag1=%xmm1
+pxor  %xmm6,%xmm1
+
+# qhasm: uint32323232                                                        a3 += diag1
+# asm 1: paddd <diag1=int6464#2,<a3=int6464#6
+# asm 2: paddd <diag1=%xmm1,<a3=%xmm5
+paddd %xmm1,%xmm5
+
+# qhasm:                 a4 = diag3
+# asm 1: movdqa <diag3=int6464#4,>a4=int6464#5
+# asm 2: movdqa <diag3=%xmm3,>a4=%xmm4
+movdqa %xmm3,%xmm4
+
+# qhasm:                                                                     b3 = a3
+# asm 1: movdqa <a3=int6464#6,>b3=int6464#7
+# asm 2: movdqa <a3=%xmm5,>b3=%xmm6
+movdqa %xmm5,%xmm6
+
+# qhasm: uint32323232                                                        a3 <<= 18
+# asm 1: pslld $18,<a3=int6464#6
+# asm 2: pslld $18,<a3=%xmm5
+pslld $18,%xmm5
+
+# qhasm: uint32323232                                                        b3 >>= 14
+# asm 1: psrld $14,<b3=int6464#7
+# asm 2: psrld $14,<b3=%xmm6
+psrld $14,%xmm6
+
+# qhasm:                                                                 diag0 ^= a3
+# asm 1: pxor  <a3=int6464#6,<diag0=int6464#1
+# asm 2: pxor  <a3=%xmm5,<diag0=%xmm0
+pxor  %xmm5,%xmm0
+
+# qhasm:                                                 diag1 <<<= 96
+# asm 1: pshufd $0x39,<diag1=int6464#2,<diag1=int6464#2
+# asm 2: pshufd $0x39,<diag1=%xmm1,<diag1=%xmm1
+pshufd $0x39,%xmm1,%xmm1
+
+# qhasm:                                                                 diag0 ^= b3
+# asm 1: pxor  <b3=int6464#7,<diag0=int6464#1
+# asm 2: pxor  <b3=%xmm6,<diag0=%xmm0
+pxor  %xmm6,%xmm0
+
+# qhasm: uint32323232        a4 += diag0
+# asm 1: paddd <diag0=int6464#1,<a4=int6464#5
+# asm 2: paddd <diag0=%xmm0,<a4=%xmm4
+paddd %xmm0,%xmm4
+
+# qhasm:                                 a5 = diag0
+# asm 1: movdqa <diag0=int6464#1,>a5=int6464#6
+# asm 2: movdqa <diag0=%xmm0,>a5=%xmm5
+movdqa %xmm0,%xmm5
+
+# qhasm:                     b4 = a4
+# asm 1: movdqa <a4=int6464#5,>b4=int6464#7
+# asm 2: movdqa <a4=%xmm4,>b4=%xmm6
+movdqa %xmm4,%xmm6
+
+# qhasm: uint32323232        a4 <<= 7
+# asm 1: pslld $7,<a4=int6464#5
+# asm 2: pslld $7,<a4=%xmm4
+pslld $7,%xmm4
+
+# qhasm: uint32323232        b4 >>= 25
+# asm 1: psrld $25,<b4=int6464#7
+# asm 2: psrld $25,<b4=%xmm6
+psrld $25,%xmm6
+
+# qhasm:                 diag1 ^= a4
+# asm 1: pxor  <a4=int6464#5,<diag1=int6464#2
+# asm 2: pxor  <a4=%xmm4,<diag1=%xmm1
+pxor  %xmm4,%xmm1
+
+# qhasm:                 diag1 ^= b4
+# asm 1: pxor  <b4=int6464#7,<diag1=int6464#2
+# asm 2: pxor  <b4=%xmm6,<diag1=%xmm1
+pxor  %xmm6,%xmm1
+
+# qhasm: uint32323232                        a5 += diag1
+# asm 1: paddd <diag1=int6464#2,<a5=int6464#6
+# asm 2: paddd <diag1=%xmm1,<a5=%xmm5
+paddd %xmm1,%xmm5
+
+# qhasm:                                                 a6 = diag1
+# asm 1: movdqa <diag1=int6464#2,>a6=int6464#5
+# asm 2: movdqa <diag1=%xmm1,>a6=%xmm4
+movdqa %xmm1,%xmm4
+
+# qhasm:                                     b5 = a5
+# asm 1: movdqa <a5=int6464#6,>b5=int6464#7
+# asm 2: movdqa <a5=%xmm5,>b5=%xmm6
+movdqa %xmm5,%xmm6
+
+# qhasm: uint32323232                        a5 <<= 9
+# asm 1: pslld $9,<a5=int6464#6
+# asm 2: pslld $9,<a5=%xmm5
+pslld $9,%xmm5
+
+# qhasm: uint32323232                        b5 >>= 23
+# asm 1: psrld $23,<b5=int6464#7
+# asm 2: psrld $23,<b5=%xmm6
+psrld $23,%xmm6
+
+# qhasm:                                 diag2 ^= a5
+# asm 1: pxor  <a5=int6464#6,<diag2=int6464#3
+# asm 2: pxor  <a5=%xmm5,<diag2=%xmm2
+pxor  %xmm5,%xmm2
+
+# qhasm:                 diag1 <<<= 32
+# asm 1: pshufd $0x93,<diag1=int6464#2,<diag1=int6464#2
+# asm 2: pshufd $0x93,<diag1=%xmm1,<diag1=%xmm1
+pshufd $0x93,%xmm1,%xmm1
+
+# qhasm:                                 diag2 ^= b5
+# asm 1: pxor  <b5=int6464#7,<diag2=int6464#3
+# asm 2: pxor  <b5=%xmm6,<diag2=%xmm2
+pxor  %xmm6,%xmm2
+
+# qhasm: uint32323232                                        a6 += diag2
+# asm 1: paddd <diag2=int6464#3,<a6=int6464#5
+# asm 2: paddd <diag2=%xmm2,<a6=%xmm4
+paddd %xmm2,%xmm4
+
+# qhasm:                                                                 a7 = diag2
+# asm 1: movdqa <diag2=int6464#3,>a7=int6464#6
+# asm 2: movdqa <diag2=%xmm2,>a7=%xmm5
+movdqa %xmm2,%xmm5
+
+# qhasm:                                                     b6 = a6
+# asm 1: movdqa <a6=int6464#5,>b6=int6464#7
+# asm 2: movdqa <a6=%xmm4,>b6=%xmm6
+movdqa %xmm4,%xmm6
+
+# qhasm: uint32323232                                        a6 <<= 13
+# asm 1: pslld $13,<a6=int6464#5
+# asm 2: pslld $13,<a6=%xmm4
+pslld $13,%xmm4
+
+# qhasm: uint32323232                                        b6 >>= 19
+# asm 1: psrld $19,<b6=int6464#7
+# asm 2: psrld $19,<b6=%xmm6
+psrld $19,%xmm6
+
+# qhasm:                                                 diag3 ^= a6
+# asm 1: pxor  <a6=int6464#5,<diag3=int6464#4
+# asm 2: pxor  <a6=%xmm4,<diag3=%xmm3
+pxor  %xmm4,%xmm3
+
+# qhasm:                                 diag2 <<<= 64
+# asm 1: pshufd $0x4e,<diag2=int6464#3,<diag2=int6464#3
+# asm 2: pshufd $0x4e,<diag2=%xmm2,<diag2=%xmm2
+pshufd $0x4e,%xmm2,%xmm2
+
+# qhasm:                                                 diag3 ^= b6
+# asm 1: pxor  <b6=int6464#7,<diag3=int6464#4
+# asm 2: pxor  <b6=%xmm6,<diag3=%xmm3
+pxor  %xmm6,%xmm3
+
+# qhasm:                  unsigned>? i -= 4
+# asm 1: sub  $4,<i=int64#4
+# asm 2: sub  $4,<i=%rcx
+sub  $4,%rcx
+
+# qhasm: uint32323232                                                        a7 += diag3
+# asm 1: paddd <diag3=int6464#4,<a7=int6464#6
+# asm 2: paddd <diag3=%xmm3,<a7=%xmm5
+paddd %xmm3,%xmm5
+
+# qhasm:                 a0 = diag1
+# asm 1: movdqa <diag1=int6464#2,>a0=int6464#5
+# asm 2: movdqa <diag1=%xmm1,>a0=%xmm4
+movdqa %xmm1,%xmm4
+
+# qhasm:                                                                     b7 = a7
+# asm 1: movdqa <a7=int6464#6,>b7=int6464#7
+# asm 2: movdqa <a7=%xmm5,>b7=%xmm6
+movdqa %xmm5,%xmm6
+
+# qhasm: uint32323232                                                        a7 <<= 18
+# asm 1: pslld $18,<a7=int6464#6
+# asm 2: pslld $18,<a7=%xmm5
+pslld $18,%xmm5
+
+# qhasm:                 b0 = 0
+# asm 1: pxor   >b0=int6464#8,>b0=int6464#8
+# asm 2: pxor   >b0=%xmm7,>b0=%xmm7
+pxor   %xmm7,%xmm7
+
+# qhasm: uint32323232                                                        b7 >>= 14
+# asm 1: psrld $14,<b7=int6464#7
+# asm 2: psrld $14,<b7=%xmm6
+psrld $14,%xmm6
+
+# qhasm:                                                                 diag0 ^= a7
+# asm 1: pxor  <a7=int6464#6,<diag0=int6464#1
+# asm 2: pxor  <a7=%xmm5,<diag0=%xmm0
+pxor  %xmm5,%xmm0
+
+# qhasm:                                                 diag3 <<<= 96
+# asm 1: pshufd $0x39,<diag3=int6464#4,<diag3=int6464#4
+# asm 2: pshufd $0x39,<diag3=%xmm3,<diag3=%xmm3
+pshufd $0x39,%xmm3,%xmm3
+
+# qhasm:                                                                 diag0 ^= b7
+# asm 1: pxor  <b7=int6464#7,<diag0=int6464#1
+# asm 2: pxor  <b7=%xmm6,<diag0=%xmm0
+pxor  %xmm6,%xmm0
+# comment:fp stack unchanged by jump
+
+# qhasm: goto mainloop2 if unsigned>
+ja ._mainloop2
+
+# qhasm: uint32323232 diag0 += x0
+# asm 1: paddd <x0=stack128#4,<diag0=int6464#1
+# asm 2: paddd <x0=48(%rsp),<diag0=%xmm0
+paddd 48(%rsp),%xmm0
+
+# qhasm: uint32323232 diag1 += x1
+# asm 1: paddd <x1=stack128#1,<diag1=int6464#2
+# asm 2: paddd <x1=0(%rsp),<diag1=%xmm1
+paddd 0(%rsp),%xmm1
+
+# qhasm: uint32323232 diag2 += x2
+# asm 1: paddd <x2=stack128#2,<diag2=int6464#3
+# asm 2: paddd <x2=16(%rsp),<diag2=%xmm2
+paddd 16(%rsp),%xmm2
+
+# qhasm: uint32323232 diag3 += x3
+# asm 1: paddd <x3=stack128#3,<diag3=int6464#4
+# asm 2: paddd <x3=32(%rsp),<diag3=%xmm3
+paddd 32(%rsp),%xmm3
+
+# qhasm: in0 = diag0
+# asm 1: movd   <diag0=int6464#1,>in0=int64#4
+# asm 2: movd   <diag0=%xmm0,>in0=%rcx
+movd   %xmm0,%rcx
+
+# qhasm: in12 = diag1
+# asm 1: movd   <diag1=int6464#2,>in12=int64#5
+# asm 2: movd   <diag1=%xmm1,>in12=%r8
+movd   %xmm1,%r8
+
+# qhasm: in8 = diag2
+# asm 1: movd   <diag2=int6464#3,>in8=int64#6
+# asm 2: movd   <diag2=%xmm2,>in8=%r9
+movd   %xmm2,%r9
+
+# qhasm: in4 = diag3
+# asm 1: movd   <diag3=int6464#4,>in4=int64#7
+# asm 2: movd   <diag3=%xmm3,>in4=%rax
+movd   %xmm3,%rax
+
+# qhasm: diag0 <<<= 96
+# asm 1: pshufd $0x39,<diag0=int6464#1,<diag0=int6464#1
+# asm 2: pshufd $0x39,<diag0=%xmm0,<diag0=%xmm0
+pshufd $0x39,%xmm0,%xmm0
+
+# qhasm: diag1 <<<= 96
+# asm 1: pshufd $0x39,<diag1=int6464#2,<diag1=int6464#2
+# asm 2: pshufd $0x39,<diag1=%xmm1,<diag1=%xmm1
+pshufd $0x39,%xmm1,%xmm1
+
+# qhasm: diag2 <<<= 96
+# asm 1: pshufd $0x39,<diag2=int6464#3,<diag2=int6464#3
+# asm 2: pshufd $0x39,<diag2=%xmm2,<diag2=%xmm2
+pshufd $0x39,%xmm2,%xmm2
+
+# qhasm: diag3 <<<= 96
+# asm 1: pshufd $0x39,<diag3=int6464#4,<diag3=int6464#4
+# asm 2: pshufd $0x39,<diag3=%xmm3,<diag3=%xmm3
+pshufd $0x39,%xmm3,%xmm3
+
+# qhasm: (uint32) in0 ^= *(uint32 *) (m + 0)
+# asm 1: xorl 0(<m=int64#2),<in0=int64#4d
+# asm 2: xorl 0(<m=%rsi),<in0=%ecx
+xorl 0(%rsi),%ecx
+
+# qhasm: (uint32) in12 ^= *(uint32 *) (m + 48)
+# asm 1: xorl 48(<m=int64#2),<in12=int64#5d
+# asm 2: xorl 48(<m=%rsi),<in12=%r8d
+xorl 48(%rsi),%r8d
+
+# qhasm: (uint32) in8 ^= *(uint32 *) (m + 32)
+# asm 1: xorl 32(<m=int64#2),<in8=int64#6d
+# asm 2: xorl 32(<m=%rsi),<in8=%r9d
+xorl 32(%rsi),%r9d
+
+# qhasm: (uint32) in4 ^= *(uint32 *) (m + 16)
+# asm 1: xorl 16(<m=int64#2),<in4=int64#7d
+# asm 2: xorl 16(<m=%rsi),<in4=%eax
+xorl 16(%rsi),%eax
+
+# qhasm: *(uint32 *) (out + 0) = in0
+# asm 1: movl   <in0=int64#4d,0(<out=int64#1)
+# asm 2: movl   <in0=%ecx,0(<out=%rdi)
+movl   %ecx,0(%rdi)
+
+# qhasm: *(uint32 *) (out + 48) = in12
+# asm 1: movl   <in12=int64#5d,48(<out=int64#1)
+# asm 2: movl   <in12=%r8d,48(<out=%rdi)
+movl   %r8d,48(%rdi)
+
+# qhasm: *(uint32 *) (out + 32) = in8
+# asm 1: movl   <in8=int64#6d,32(<out=int64#1)
+# asm 2: movl   <in8=%r9d,32(<out=%rdi)
+movl   %r9d,32(%rdi)
+
+# qhasm: *(uint32 *) (out + 16) = in4
+# asm 1: movl   <in4=int64#7d,16(<out=int64#1)
+# asm 2: movl   <in4=%eax,16(<out=%rdi)
+movl   %eax,16(%rdi)
+
+# qhasm: in5 = diag0
+# asm 1: movd   <diag0=int6464#1,>in5=int64#4
+# asm 2: movd   <diag0=%xmm0,>in5=%rcx
+movd   %xmm0,%rcx
+
+# qhasm: in1 = diag1
+# asm 1: movd   <diag1=int6464#2,>in1=int64#5
+# asm 2: movd   <diag1=%xmm1,>in1=%r8
+movd   %xmm1,%r8
+
+# qhasm: in13 = diag2
+# asm 1: movd   <diag2=int6464#3,>in13=int64#6
+# asm 2: movd   <diag2=%xmm2,>in13=%r9
+movd   %xmm2,%r9
+
+# qhasm: in9 = diag3
+# asm 1: movd   <diag3=int6464#4,>in9=int64#7
+# asm 2: movd   <diag3=%xmm3,>in9=%rax
+movd   %xmm3,%rax
+
+# qhasm: diag0 <<<= 96
+# asm 1: pshufd $0x39,<diag0=int6464#1,<diag0=int6464#1
+# asm 2: pshufd $0x39,<diag0=%xmm0,<diag0=%xmm0
+pshufd $0x39,%xmm0,%xmm0
+
+# qhasm: diag1 <<<= 96
+# asm 1: pshufd $0x39,<diag1=int6464#2,<diag1=int6464#2
+# asm 2: pshufd $0x39,<diag1=%xmm1,<diag1=%xmm1
+pshufd $0x39,%xmm1,%xmm1
+
+# qhasm: diag2 <<<= 96
+# asm 1: pshufd $0x39,<diag2=int6464#3,<diag2=int6464#3
+# asm 2: pshufd $0x39,<diag2=%xmm2,<diag2=%xmm2
+pshufd $0x39,%xmm2,%xmm2
+
+# qhasm: diag3 <<<= 96
+# asm 1: pshufd $0x39,<diag3=int6464#4,<diag3=int6464#4
+# asm 2: pshufd $0x39,<diag3=%xmm3,<diag3=%xmm3
+pshufd $0x39,%xmm3,%xmm3
+
+# qhasm: (uint32) in5 ^= *(uint32 *) (m + 20)
+# asm 1: xorl 20(<m=int64#2),<in5=int64#4d
+# asm 2: xorl 20(<m=%rsi),<in5=%ecx
+xorl 20(%rsi),%ecx
+
+# qhasm: (uint32) in1 ^= *(uint32 *) (m + 4)
+# asm 1: xorl 4(<m=int64#2),<in1=int64#5d
+# asm 2: xorl 4(<m=%rsi),<in1=%r8d
+xorl 4(%rsi),%r8d
+
+# qhasm: (uint32) in13 ^= *(uint32 *) (m + 52)
+# asm 1: xorl 52(<m=int64#2),<in13=int64#6d
+# asm 2: xorl 52(<m=%rsi),<in13=%r9d
+xorl 52(%rsi),%r9d
+
+# qhasm: (uint32) in9 ^= *(uint32 *) (m + 36)
+# asm 1: xorl 36(<m=int64#2),<in9=int64#7d
+# asm 2: xorl 36(<m=%rsi),<in9=%eax
+xorl 36(%rsi),%eax
+
+# qhasm: *(uint32 *) (out + 20) = in5
+# asm 1: movl   <in5=int64#4d,20(<out=int64#1)
+# asm 2: movl   <in5=%ecx,20(<out=%rdi)
+movl   %ecx,20(%rdi)
+
+# qhasm: *(uint32 *) (out + 4) = in1
+# asm 1: movl   <in1=int64#5d,4(<out=int64#1)
+# asm 2: movl   <in1=%r8d,4(<out=%rdi)
+movl   %r8d,4(%rdi)
+
+# qhasm: *(uint32 *) (out + 52) = in13
+# asm 1: movl   <in13=int64#6d,52(<out=int64#1)
+# asm 2: movl   <in13=%r9d,52(<out=%rdi)
+movl   %r9d,52(%rdi)
+
+# qhasm: *(uint32 *) (out + 36) = in9
+# asm 1: movl   <in9=int64#7d,36(<out=int64#1)
+# asm 2: movl   <in9=%eax,36(<out=%rdi)
+movl   %eax,36(%rdi)
+
+# qhasm: in10 = diag0
+# asm 1: movd   <diag0=int6464#1,>in10=int64#4
+# asm 2: movd   <diag0=%xmm0,>in10=%rcx
+movd   %xmm0,%rcx
+
+# qhasm: in6 = diag1
+# asm 1: movd   <diag1=int6464#2,>in6=int64#5
+# asm 2: movd   <diag1=%xmm1,>in6=%r8
+movd   %xmm1,%r8
+
+# qhasm: in2 = diag2
+# asm 1: movd   <diag2=int6464#3,>in2=int64#6
+# asm 2: movd   <diag2=%xmm2,>in2=%r9
+movd   %xmm2,%r9
+
+# qhasm: in14 = diag3
+# asm 1: movd   <diag3=int6464#4,>in14=int64#7
+# asm 2: movd   <diag3=%xmm3,>in14=%rax
+movd   %xmm3,%rax
+
+# qhasm: diag0 <<<= 96
+# asm 1: pshufd $0x39,<diag0=int6464#1,<diag0=int6464#1
+# asm 2: pshufd $0x39,<diag0=%xmm0,<diag0=%xmm0
+pshufd $0x39,%xmm0,%xmm0
+
+# qhasm: diag1 <<<= 96
+# asm 1: pshufd $0x39,<diag1=int6464#2,<diag1=int6464#2
+# asm 2: pshufd $0x39,<diag1=%xmm1,<diag1=%xmm1
+pshufd $0x39,%xmm1,%xmm1
+
+# qhasm: diag2 <<<= 96
+# asm 1: pshufd $0x39,<diag2=int6464#3,<diag2=int6464#3
+# asm 2: pshufd $0x39,<diag2=%xmm2,<diag2=%xmm2
+pshufd $0x39,%xmm2,%xmm2
+
+# qhasm: diag3 <<<= 96
+# asm 1: pshufd $0x39,<diag3=int6464#4,<diag3=int6464#4
+# asm 2: pshufd $0x39,<diag3=%xmm3,<diag3=%xmm3
+pshufd $0x39,%xmm3,%xmm3
+
+# qhasm: (uint32) in10 ^= *(uint32 *) (m + 40)
+# asm 1: xorl 40(<m=int64#2),<in10=int64#4d
+# asm 2: xorl 40(<m=%rsi),<in10=%ecx
+xorl 40(%rsi),%ecx
+
+# qhasm: (uint32) in6 ^= *(uint32 *) (m + 24)
+# asm 1: xorl 24(<m=int64#2),<in6=int64#5d
+# asm 2: xorl 24(<m=%rsi),<in6=%r8d
+xorl 24(%rsi),%r8d
+
+# qhasm: (uint32) in2 ^= *(uint32 *) (m + 8)
+# asm 1: xorl 8(<m=int64#2),<in2=int64#6d
+# asm 2: xorl 8(<m=%rsi),<in2=%r9d
+xorl 8(%rsi),%r9d
+
+# qhasm: (uint32) in14 ^= *(uint32 *) (m + 56)
+# asm 1: xorl 56(<m=int64#2),<in14=int64#7d
+# asm 2: xorl 56(<m=%rsi),<in14=%eax
+xorl 56(%rsi),%eax
+
+# qhasm: *(uint32 *) (out + 40) = in10
+# asm 1: movl   <in10=int64#4d,40(<out=int64#1)
+# asm 2: movl   <in10=%ecx,40(<out=%rdi)
+movl   %ecx,40(%rdi)
+
+# qhasm: *(uint32 *) (out + 24) = in6
+# asm 1: movl   <in6=int64#5d,24(<out=int64#1)
+# asm 2: movl   <in6=%r8d,24(<out=%rdi)
+movl   %r8d,24(%rdi)
+
+# qhasm: *(uint32 *) (out + 8) = in2
+# asm 1: movl   <in2=int64#6d,8(<out=int64#1)
+# asm 2: movl   <in2=%r9d,8(<out=%rdi)
+movl   %r9d,8(%rdi)
+
+# qhasm: *(uint32 *) (out + 56) = in14
+# asm 1: movl   <in14=int64#7d,56(<out=int64#1)
+# asm 2: movl   <in14=%eax,56(<out=%rdi)
+movl   %eax,56(%rdi)
+
+# qhasm: in15 = diag0
+# asm 1: movd   <diag0=int6464#1,>in15=int64#4
+# asm 2: movd   <diag0=%xmm0,>in15=%rcx
+movd   %xmm0,%rcx
+
+# qhasm: in11 = diag1
+# asm 1: movd   <diag1=int6464#2,>in11=int64#5
+# asm 2: movd   <diag1=%xmm1,>in11=%r8
+movd   %xmm1,%r8
+
+# qhasm: in7 = diag2
+# asm 1: movd   <diag2=int6464#3,>in7=int64#6
+# asm 2: movd   <diag2=%xmm2,>in7=%r9
+movd   %xmm2,%r9
+
+# qhasm: in3 = diag3
+# asm 1: movd   <diag3=int6464#4,>in3=int64#7
+# asm 2: movd   <diag3=%xmm3,>in3=%rax
+movd   %xmm3,%rax
+
+# qhasm: (uint32) in15 ^= *(uint32 *) (m + 60)
+# asm 1: xorl 60(<m=int64#2),<in15=int64#4d
+# asm 2: xorl 60(<m=%rsi),<in15=%ecx
+xorl 60(%rsi),%ecx
+
+# qhasm: (uint32) in11 ^= *(uint32 *) (m + 44)
+# asm 1: xorl 44(<m=int64#2),<in11=int64#5d
+# asm 2: xorl 44(<m=%rsi),<in11=%r8d
+xorl 44(%rsi),%r8d
+
+# qhasm: (uint32) in7 ^= *(uint32 *) (m + 28)
+# asm 1: xorl 28(<m=int64#2),<in7=int64#6d
+# asm 2: xorl 28(<m=%rsi),<in7=%r9d
+xorl 28(%rsi),%r9d
+
+# qhasm: (uint32) in3 ^= *(uint32 *) (m + 12)
+# asm 1: xorl 12(<m=int64#2),<in3=int64#7d
+# asm 2: xorl 12(<m=%rsi),<in3=%eax
+xorl 12(%rsi),%eax
+
+# qhasm: *(uint32 *) (out + 60) = in15
+# asm 1: movl   <in15=int64#4d,60(<out=int64#1)
+# asm 2: movl   <in15=%ecx,60(<out=%rdi)
+movl   %ecx,60(%rdi)
+
+# qhasm: *(uint32 *) (out + 44) = in11
+# asm 1: movl   <in11=int64#5d,44(<out=int64#1)
+# asm 2: movl   <in11=%r8d,44(<out=%rdi)
+movl   %r8d,44(%rdi)
+
+# qhasm: *(uint32 *) (out + 28) = in7
+# asm 1: movl   <in7=int64#6d,28(<out=int64#1)
+# asm 2: movl   <in7=%r9d,28(<out=%rdi)
+movl   %r9d,28(%rdi)
+
+# qhasm: *(uint32 *) (out + 12) = in3
+# asm 1: movl   <in3=int64#7d,12(<out=int64#1)
+# asm 2: movl   <in3=%eax,12(<out=%rdi)
+movl   %eax,12(%rdi)
+
+# qhasm:   bytes = bytes_backup
+# asm 1: movq <bytes_backup=stack64#8,>bytes=int64#6
+# asm 2: movq <bytes_backup=408(%rsp),>bytes=%r9
+movq 408(%rsp),%r9
+
+# qhasm:   in8 = ((uint32 *)&x2)[0]
+# asm 1: movl <x2=stack128#2,>in8=int64#4d
+# asm 2: movl <x2=16(%rsp),>in8=%ecx
+movl 16(%rsp),%ecx
+
+# qhasm:   in9 = ((uint32 *)&x3)[1]
+# asm 1: movl 4+<x3=stack128#3,>in9=int64#5d
+# asm 2: movl 4+<x3=32(%rsp),>in9=%r8d
+movl 4+32(%rsp),%r8d
+
+# qhasm:   in8 += 1
+# asm 1: add  $1,<in8=int64#4
+# asm 2: add  $1,<in8=%rcx
+add  $1,%rcx
+
+# qhasm:   in9 <<= 32
+# asm 1: shl  $32,<in9=int64#5
+# asm 2: shl  $32,<in9=%r8
+shl  $32,%r8
+
+# qhasm:   in8 += in9
+# asm 1: add  <in9=int64#5,<in8=int64#4
+# asm 2: add  <in9=%r8,<in8=%rcx
+add  %r8,%rcx
+
+# qhasm:   in9 = in8
+# asm 1: mov  <in8=int64#4,>in9=int64#5
+# asm 2: mov  <in8=%rcx,>in9=%r8
+mov  %rcx,%r8
+
+# qhasm:   (uint64) in9 >>= 32
+# asm 1: shr  $32,<in9=int64#5
+# asm 2: shr  $32,<in9=%r8
+shr  $32,%r8
+
+# qhasm:   ((uint32 *)&x2)[0] = in8
+# asm 1: movl <in8=int64#4d,>x2=stack128#2
+# asm 2: movl <in8=%ecx,>x2=16(%rsp)
+movl %ecx,16(%rsp)
+
+# qhasm:   ((uint32 *)&x3)[1] = in9
+# asm 1: movl <in9=int64#5d,4+<x3=stack128#3
+# asm 2: movl <in9=%r8d,4+<x3=32(%rsp)
+movl %r8d,4+32(%rsp)
+
+# qhasm:                          unsigned>? unsigned<? bytes - 64
+# asm 1: cmp  $64,<bytes=int64#6
+# asm 2: cmp  $64,<bytes=%r9
+cmp  $64,%r9
+# comment:fp stack unchanged by jump
+
+# qhasm:   goto bytesatleast65 if unsigned>
+ja ._bytesatleast65
+# comment:fp stack unchanged by jump
+
+# qhasm:     goto bytesatleast64 if !unsigned<
+jae ._bytesatleast64
+
+# qhasm:       m = out
+# asm 1: mov  <out=int64#1,>m=int64#2
+# asm 2: mov  <out=%rdi,>m=%rsi
+mov  %rdi,%rsi
+
+# qhasm:       out = ctarget
+# asm 1: mov  <ctarget=int64#3,>out=int64#1
+# asm 2: mov  <ctarget=%rdx,>out=%rdi
+mov  %rdx,%rdi
+
+# qhasm:       i = bytes
+# asm 1: mov  <bytes=int64#6,>i=int64#4
+# asm 2: mov  <bytes=%r9,>i=%rcx
+mov  %r9,%rcx
+
+# qhasm:       while (i) { *out++ = *m++; --i }
+rep movsb
+# comment:fp stack unchanged by fallthrough
+
+# qhasm:     bytesatleast64:
+._bytesatleast64:
+# comment:fp stack unchanged by fallthrough
+
+# qhasm:     done:
+._done:
+
+# qhasm:     r11_caller = r11_stack
+# asm 1: movq <r11_stack=stack64#1,>r11_caller=int64#9
+# asm 2: movq <r11_stack=352(%rsp),>r11_caller=%r11
+movq 352(%rsp),%r11
+
+# qhasm:     r12_caller = r12_stack
+# asm 1: movq <r12_stack=stack64#2,>r12_caller=int64#10
+# asm 2: movq <r12_stack=360(%rsp),>r12_caller=%r12
+movq 360(%rsp),%r12
+
+# qhasm:     r13_caller = r13_stack
+# asm 1: movq <r13_stack=stack64#3,>r13_caller=int64#11
+# asm 2: movq <r13_stack=368(%rsp),>r13_caller=%r13
+movq 368(%rsp),%r13
+
+# qhasm:     r14_caller = r14_stack
+# asm 1: movq <r14_stack=stack64#4,>r14_caller=int64#12
+# asm 2: movq <r14_stack=376(%rsp),>r14_caller=%r14
+movq 376(%rsp),%r14
+
+# qhasm:     r15_caller = r15_stack
+# asm 1: movq <r15_stack=stack64#5,>r15_caller=int64#13
+# asm 2: movq <r15_stack=384(%rsp),>r15_caller=%r15
+movq 384(%rsp),%r15
+
+# qhasm:     rbx_caller = rbx_stack
+# asm 1: movq <rbx_stack=stack64#6,>rbx_caller=int64#14
+# asm 2: movq <rbx_stack=392(%rsp),>rbx_caller=%rbx
+movq 392(%rsp),%rbx
+
+# qhasm:     rbp_caller = rbp_stack
+# asm 1: movq <rbp_stack=stack64#7,>rbp_caller=int64#15
+# asm 2: movq <rbp_stack=400(%rsp),>rbp_caller=%rbp
+movq 400(%rsp),%rbp
+
+# qhasm:     leave
+add %r11,%rsp
+xor %rax,%rax
+xor %rdx,%rdx
+ret
+
+# qhasm:   bytesatleast65:
+._bytesatleast65:
+
+# qhasm:   bytes -= 64
+# asm 1: sub  $64,<bytes=int64#6
+# asm 2: sub  $64,<bytes=%r9
+sub  $64,%r9
+
+# qhasm:   out += 64
+# asm 1: add  $64,<out=int64#1
+# asm 2: add  $64,<out=%rdi
+add  $64,%rdi
+
+# qhasm:   m += 64
+# asm 1: add  $64,<m=int64#2
+# asm 2: add  $64,<m=%rsi
+add  $64,%rsi
+# comment:fp stack unchanged by jump
+
+# qhasm: goto bytesbetween1and255
+jmp ._bytesbetween1and255

+ 48 - 0
crypto/prng/fastrandombytes.cpp

@@ -0,0 +1,48 @@
+/*
+ * File:   lattisigns512-20130329/fastrandombytes.c
+ * Author: Gim Güneysu, Tobias Oder, Thomas Pöppelmann, Peter Schwabe
+ * Public Domain
+ */
+
+#include "crypto_stream_salsa20.h"
+#include "randombytes.h"
+#include <omp.h>
+#include <inttypes.h>
+#include <iostream>
+
+static int init = 0;
+static unsigned char key[crypto_stream_salsa20_KEYBYTES];
+static unsigned char nonce[crypto_stream_salsa20_NONCEBYTES] = {0};
+
+void fastrandombytes(unsigned char *r, unsigned long long rlen)
+{
+  unsigned long long n=0;
+  int i;
+  if(!init)
+  {
+    randombytes(key, crypto_stream_salsa20_KEYBYTES);
+    init = 1;
+  }
+  //crypto_stream(r,rlen,nonce,key);
+  crypto_stream_salsa20(r,rlen,nonce,key);
+
+  // Increase 64-bit counter (nonce)
+  for(i=0;i<8;i++)
+    n ^= ((unsigned long long)nonce[i]) << 8*i;
+  n++;
+  for(i=0;i<8;i++)
+    nonce[i] = (n >> 8*i) & 0xff;
+}
+
+/*int main(int argc, char**argv) {
+    int randlen = 1024;
+    unsigned char t[randlen*sizeof(unsigned long long)];
+    double start = omp_get_wtime();
+    fastrandombytes((unsigned char *)t, randlen*sizeof(unsigned long long));
+    double end= omp_get_wtime();
+    std::cout << (end-start) << std::endl;
+    for(int i=0;i<1024*sizeof(unsigned long long);i++) std::cout<<std::hex<<(int)t[i]<<" ";
+    std::cout<<std::endl;
+    
+    
+}*/

+ 12 - 0
crypto/prng/fastrandombytes.h

@@ -0,0 +1,12 @@
+/*
+ * File:   lattisigns512-20130329/fastrandombytes.h
+ * Author: Gim Güneysu, Tobias Oder, Thomas Pöppelmann, Peter Schwabe
+ * Public Domain
+ */
+
+#ifndef FASTRANDOMBYTES_H
+#define FASTRANDOMBYTES_H
+
+void fastrandombytes(unsigned char *r, unsigned long long rlen);
+
+#endif

+ 39 - 0
crypto/prng/randombytes.cpp

@@ -0,0 +1,39 @@
+/*
+D. J. Bernstein
+Public domain.
+*/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "randombytes.h"
+
+/* it's really stupid that there isn't a syscall for this */
+
+static int fd = -1;
+
+void randombytes(unsigned char *x,unsigned long long xlen)
+{
+  int i;
+
+  if (fd == -1) {
+    for (;;) {
+      fd = open("/dev/urandom",O_RDONLY);
+      if (fd != -1) break;
+      sleep(1);
+    }
+  }
+
+  while (xlen > 0) {
+    if (xlen < 1048576) i = xlen; else i = 1048576;
+
+    i = read(fd,x,i);
+    if (i < 1) {
+      sleep(1);
+      continue;
+    }
+
+    x += i;
+    xlen -= i;
+  }
+}

+ 11 - 0
crypto/prng/randombytes.h

@@ -0,0 +1,11 @@
+/*
+D. J. Bernstein
+Public domain.
+*/
+
+#ifndef RANDOMBYTES_H
+#define RANDOMBYTES_H
+
+void randombytes(unsigned char *,unsigned long long);
+
+#endif

+ 40 - 0
helper_script.sh

@@ -0,0 +1,40 @@
+#!/bin/bash
+#/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+# * This file is part of XPIR.
+# *
+# *  XPIR is free software: you can redistribute it and/or modify
+# *	it under the terms of the GNU General Public License as published by
+# *  the Free Software Foundation, either version 3 of the License, or
+# *  (at your option) any later version.
+# *
+# *  XPIR is distributed in the hope that it will be useful,
+# *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+# *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# *  GNU General Public License for more details.
+# *
+# *  You should have received a copy of the GNU General Public License
+# *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+#*/
+
+wget http://homepages.laas.fr/~mkilliji/dependencies.tgz
+tar zxf dependencies.tgz
+rm dependencies.tgz
+mkdir local
+
+CONFIGURE="./configure CFLAGS=-I$PWD/local/include LDFLAGS=-L$PWD/local/lib --prefix=$PWD/local/"
+
+  cd dependencies/mpfr-3.1.2 && $CONFIGURE && make && make install
+  cd ../..
+  cd dependencies/gmp-6.0.0 && $CONFIGURE && make && make check && make install
+  cd ../..
+  LOCAL_PATH="$PWD/local/ "
+  # Boostrap the build module
+  cd dependencies/boost; 
+  ./bootstrap.sh
+   ./bjam --prefix=$LOCAL_PATH install 
+  if [ `uname` = "Darwin" ]
+    then 
+	cd ../../local/lib/
+	install_name_tool -change libboost_system.dylib `pwd`/libboost_system.dylib libboost_thread.dylib
+  fi
+  cd ../..

+ 226 - 0
libpir.hpp

@@ -0,0 +1,226 @@
+#ifndef DEF_LIBPIR
+#define DEF_LIBPIR
+
+#include <pir/shared_queue.hpp>
+#include <pir/PIRParameters.hpp>
+#include <pir/queryGen/PIRQueryGenerator_internal.hpp>
+#include <pir/replyExtraction/PIRReplyExtraction_internal.hpp>
+#include <pir/replyGenerator/PIRReplyGeneratorNFL_internal.hpp>
+#include <crypto/NFLLWE.hpp>
+#include <crypto/HomomorphicCryptoFactory_internal.hpp>
+#include <crypto/HomomorphicCrypto.hpp>
+#include <stdint.h>
+
+
+
+/**
+ * Class storing the database (or a chunk of it) after pre-processing
+ * Type returned by the funcion importData below
+**/
+class imported_database : public imported_database_t
+{
+public:
+  ~imported_database();
+};
+
+
+
+/** 
+ *	HomomorphicCryptoFactory is used to create a generic cryptographic object (Ring-LWE, Paillier, 
+ *	mockup-cryptography, etc.). This API only exposes the Ring-LWE cryptosystem, but we still 
+ *	use the generic factory to get an instance of this cryptosystem in order to avoid code duplication.
+**/
+class HomomorphicCryptoFactory : public HomomorphicCryptoFactory_internal
+{
+public:
+  /** prints a list of the available crypto parameters 
+  *   (CryptoSystem:SecurityMax:PolyDegree:ModulusBitsize)
+  **/
+  static void printAllCryptoParams();
+  
+  /** takes one of the parameters given by the previous 
+  *   method as a string and returns an instance of a cryptosystem for the given parameters  
+  **/
+  static HomomorphicCrypto* getCryptoMethod(std::string cryptoParams);
+};
+
+
+
+
+/** 
+ *	PIRQueryGenerator is Client side, it initiates the PIR protocol by generating a query
+ *	corresponding to the chosen element
+**/
+class PIRQueryGenerator : public PIRQueryGenerator_internal
+{
+public:
+
+  /**
+  *	Class constructor
+  *	Params:
+  *		- PIRParameters& pirParameters_ 	: PIRParameters structure defining the cryptographic
+  *		  parameters, aggregation, recursion, and the shape of the database, see the main() 
+  *		  function of apps/simplepir/simplePIR.cpp for detailed usage examples
+  *		- NFLLWE& cryptoMethod_ 			: shared_pointer of the cryptographic instance
+  **/
+  PIRQueryGenerator(PIRParameters& pirParameters, HomomorphicCrypto& cryptoMethod_);
+  
+  /**
+   * Generates asynchronously queries (a set of encryptions of 0 or 1).
+   * Params:
+   *   - uint64_t _chosenElement : index of the element to be retrieved (indexes start at 0)
+   * Can be called on a separate thread.
+  **/
+  void generateQuery(uint64_t _chosenElement );
+
+  /** 
+   * Function to get a pointer to a char* query element.
+   * Returns false when the queue is over (true otherwise) and waits when it's empty
+   * Can be called on a separate thread.
+  **/
+  bool popQuery(char** query);
+
+  /**
+   * Get the size in bytes of a query element
+  **/ 
+  uint64_t getQueryElementBytesize();
+
+private:
+  int nbQueries;
+};
+
+
+
+/** 
+ *	PIRReplyGenerator is Server side
+ *	It handles the request generated by the client and generates the reply
+**/
+class PIRReplyGenerator : public PIRReplyGeneratorNFL_internal
+{
+public:
+
+  /**
+   *	Constructor of the class.
+   *	Params :
+   *	- vector <std::string>& database : reference of vector of the database elements
+   *	- PIRParameters& param : reference to a PIRParameters structure (see the PIRQueryGenerator 
+   *	  constructor help for more details).
+   *	- DBHandler* db : abstract type for a database handler, at the moment it can be a DBGenerator
+   *	  that generates a fake database or a DBDirectoryProcessor that works on real files. See the
+   *	  main() function of apps/simplepir/simplePIR.cpp for examples.
+  **/
+  PIRReplyGenerator(PIRParameters& param, HomomorphicCrypto& cryptoMethod_, DBHandler *db);
+
+  /**
+   *  Feeds the Server with the queries, this includes a pre-computation phase that speeds up
+   *  reply generation (computation of newton coefficients, see the associated paper)
+   *  Can be called on a separate thread but all the query elements must be pushed before 
+   *  starting the reply generation.
+  **/		
+  void pushQuery(char* rawQuery);
+	
+  /**
+   *  Imports the database into a usable form. If the database is too large to fit in RAM
+   *  (there is an expansion factor of 3 due to pre-processing) it can be cut by reading
+   *  only for each element a chunk of size bytes_per_db_element starting at a given offset
+   *  Can be called on a separate thread but the database must be imported before starting 
+   *  the reply generation.
+  **/
+  imported_database* importData(uint64_t offset, uint64_t bytes_per_db_element);
+
+  /**
+   *  Prepares reply and start absoptions, returns number of chunks. 
+   *  Precondition: database is precomputed
+   *
+   *  The PIRParameters given to the constructor are used and therefore the reply will
+   *  be potentially generated with recursion and aggregation 
+   *  Can be called on a separate thread but the database must be imported and the query pushed
+   *  before starting the reply generation.
+  **/
+  void generateReply(const imported_database* database);
+ 
+  /** 
+   *  Frees the queries allocated 
+  **/ 
+  void freeQueries();
+	
+  /** 
+   *  Gets a pointer to a char* reply element.
+   *  Returns false when the queue is over (true otherwise) and waits when it's empty
+   *  Can be called on a separate thread
+  **/
+  bool popReply(char** reply);
+
+  /** 
+   *  Getter for nbRepliesGenerated, the amount or reply elements generated 
+  **/
+  uint64_t getnbRepliesGenerated();
+
+  /**
+   *  Gets the size in bytes of a reply element
+  **/ 
+  uint64_t getReplyElementBytesize();
+
+private:
+	uint64_t nbRepliesToHandle, nbRepliesGenerated, currentReply;
+};
+
+
+
+/** 
+ *	PIRReplyExtraction is Client side, it extracts the chosen element from the reply of the Server
+**/
+class PIRReplyExtraction : public PIRReplyExtraction_internal
+{
+public :
+
+  /**
+   *  Class constructor
+   *  Params:
+   *  - PIRParameters& pirParameters : reference to a PIRParameters structure (see the
+   *  	PIRQueryGenerator constructor help for more details).
+   *  - NFLLWE& cryptoMethod_ 			: shared_pointer of the cryptographic instance.
+  **/
+  PIRReplyExtraction(PIRParameters& pirParameters, HomomorphicCrypto& cryptoMethod);
+	
+  /**
+   *  Can be called on a separate thread
+   *  Feed the client with the reply, may wait if the internal queue is full until
+   *  enough replies are decrypted. If such thing happens extractReply should be called
+   *  on a different thread
+  **/			
+  void pushEncryptedReply(char* rawBytes);
+	
+  /**
+   *  Can be called on a separate thread
+   *  extract/decrypt the result from the pushed replies, the plaintext results have to be popped.
+   *  May block if the internal queue of plaintext results is full. If such a thing happens
+   *  a thread that calls regularly popPlaintextResult must be used.
+  **/	
+  void extractReply(uint64_t maxFileBytesize);
+			
+  /** 
+   *  Can be called on a separate thread
+   *  Function to get a pointer to a char* result element
+   *  Returns false when the queue is over (true otherwise) and waits when its empty
+  **/
+  bool popPlaintextResult(char** result);
+
+  /**
+   *  Get plaintext reply size
+  **/ 
+  uint64_t getPlaintextReplyBytesize();
+  
+  /** 
+   *  Getter for nbPlaintextReplies, the number of plaintext replies that will be generated
+   *  in the extraction processs
+  **/
+  uint64_t getnbPlaintextReplies(uint64_t maxFileBytesize);
+  
+private:
+	shared_queue<char*> clearChunks;
+	uint64_t nbPlaintextReplies;
+};
+
+#endif
+

+ 23 - 0
pir/BasicLWECommon.hpp

@@ -0,0 +1,23 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEGREE
+#define DEGREE 1023
+#endif
+#ifndef NOISE_MULT
+#define NOISE_MULT 256
+#endif

+ 39 - 0
pir/CMakeLists.txt

@@ -0,0 +1,39 @@
+cmake_minimum_required(VERSION 2.8)
+#project(nfl CXX ASM-ATT)
+enable_testing()
+if(APPLE)
+    cmake_policy(SET CMP0042 NEW)
+endif()
+
+find_package(GMP REQUIRED)
+
+include_directories("/opt/local/include" ${CMAKE_SOURCE_DIR}/crypto ${CMAKE_SOURCE_DIR}/pir ${CMAKE_SOURCE_DIR})
+
+add_subdirectory("events")
+add_subdirectory("optim")
+add_subdirectory("queryGen")
+add_subdirectory("replyExtraction")
+add_subdirectory("replyGenerator")
+
+file(GLOB PIRLIB_ASMS ${CMAKE_SOURCE_DIR}/crypto/prng/*.s )
+file(GLOB PIRLIB_SRCS 
+	${CMAKE_SOURCE_DIR}/crypto/*.cpp 
+	${CMAKE_SOURCE_DIR}/crypto/prng/*.cpp 
+	${CMAKE_SOURCE_DIR}/pir/*.cpp 
+	${CMAKE_SOURCE_DIR}/apps/client/DESC.cpp 
+	${CMAKE_SOURCE_DIR}/apps/server/DB*.cpp 
+	${CMAKE_SOURCE_DIR}/pir/events/*.cpp 
+	${CMAKE_SOURCE_DIR}/pir/optim/*.cpp 
+	${CMAKE_SOURCE_DIR}/pir/queryGen/*.cpp 
+	${CMAKE_SOURCE_DIR}/pir/replyExtraction/*.cpp 
+	${CMAKE_SOURCE_DIR}/pir/replyGenerator/*.cpp )
+
+add_library(pir SHARED ${PIRLIB_ASMS} ${PIRLIB_SRCS})
+target_link_libraries(pir  ${MPFR_LIBRARY} ${Boost_LIBRARIES} ${GMP_LIBRARIES} ${GOBJECT_LIBRARIES})
+install(TARGETS pir LIBRARY DESTINATION lib)
+
+#if(!APPLE)
+add_library(pir_static STATIC ${PIRLIB_ASMS} ${PIRLIB_SRCS})
+target_link_libraries(pir_static ${MPFR_LIBRARY} ${Boost_LIBRARIES} ${GMP_LIBRARY} ${GOBJECT_LIBRARIES} gmp libgmp )
+install(TARGETS pir_static ARCHIVE DESTINATION lib)
+#endif()

+ 23 - 0
pir/ClientDefines.hpp

@@ -0,0 +1,23 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_CLIENTDEFINES
+#define DEF_CLIENTDEFINES
+
+enum message_type {WARNING, ERROR, CHOICE, RETRY, DEFAULT};
+
+#endif

+ 30 - 0
pir/GlobalConstant.hpp

@@ -0,0 +1,30 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_GLOBALCONSTANT
+#define DEF_GLOBALCONSTANT
+#include <string>
+
+namespace GlobalConstant {
+
+  static const unsigned int kBitsPerByte = 8;
+  
+  static const std::string kDelim(":");
+
+}
+
+#endif //DEF_GLOBALCONSTANT

+ 23 - 0
pir/PIROptimizerCommand.hpp

@@ -0,0 +1,23 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_OPTICOMMAND
+#define DEF_OPTICOMMAND
+
+enum OptiCom {ABS, DATA, SPEED, EXIT, NOP};
+
+#endif

+ 31 - 0
pir/PIRParameters.hpp

@@ -0,0 +1,31 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_PIRPARAMETERS
+#define DEF_PIRPARAMETERS
+#include <string>
+
+#define MAX_REC_LVL 10
+
+struct PIRParameters {
+  unsigned int alpha;
+  unsigned int d;
+  unsigned int n[MAX_REC_LVL];
+  std::string crypto_params;
+};
+
+#endif

+ 23 - 0
pir/PIRParametersExchangeMethods.hpp

@@ -0,0 +1,23 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_PIRPARAMERTERSEXCHANGEMETHODS
+#define DEF_PIRPARAMERTERSEXCHANGEMETHODS
+
+enum PIRParamsExchangeMethod {CLIENT_DRIVEN, SERVER_DRIVEN};
+
+#endif

+ 6 - 0
pir/events/CMakeLists.txt

@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.6.0)
+
+include_directories(..)
+include_directories(../..)
+
+add_library(pir_client_events STATIC CatalogEvent.cpp MessageEvent.cpp WriteEvent.cpp)

+ 27 - 0
pir/events/CatalogEvent.cpp

@@ -0,0 +1,27 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "CatalogEvent.hpp"
+
+CatalogEvent::CatalogEvent(const std::vector<std::string>& catalog_):
+catalog(catalog_)
+{}
+
+const std::vector<std::string>& CatalogEvent::getCatalog()
+{
+	return catalog;
+}

+ 36 - 0
pir/events/CatalogEvent.hpp

@@ -0,0 +1,36 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_CATALOGEVENT
+#define DEF_CATALOGEVENT
+
+#include <string>
+#include <vector>
+
+class CatalogEvent
+{
+	private:
+		const std::vector<std::string>& catalog;
+
+	public:
+		CatalogEvent(const std::vector<std::string>& catalog);
+
+		const std::vector<std::string>& getCatalog();
+
+};
+
+#endif

+ 62 - 0
pir/events/MessageEvent.cpp

@@ -0,0 +1,62 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "MessageEvent.hpp"
+
+MessageEvent::MessageEvent():
+	mtype(DEFAULT)
+{}
+
+MessageEvent::MessageEvent(message_type mtype_):
+	mtype(mtype_)
+{}
+
+MessageEvent::MessageEvent(std::string message_):
+	mtype(DEFAULT),
+	message(message_)
+{}
+
+MessageEvent::MessageEvent(message_type mtype_, std::string message_):
+	mtype(mtype_),
+	message(message_),
+	info(message_)
+{}
+
+MessageEvent::MessageEvent(message_type mtype_, std::string message_, std::string info_):
+	mtype(mtype_),
+	message(message_),
+	info(info_)
+{}
+
+message_type MessageEvent::getMessageType()
+{
+	return mtype;
+}
+
+const std::string& MessageEvent::getMessage()
+{
+	return message;
+}
+
+const std::string& MessageEvent::getInfo()
+{
+	return info;
+}
+void MessageEvent::setMessage(std::string message_)
+{
+	message = message_;
+}

+ 47 - 0
pir/events/MessageEvent.hpp

@@ -0,0 +1,47 @@
+/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian
+ * This file is part of XPIR.
+ *
+ *  XPIR is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  XPIR is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XPIR.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef DEF_MESSAGEEVENT
+#define DEF_MESSAGEEVENT
+
+#include <string>
+#include "pir/ClientDefines.hpp"
+
+/**
+ * Used to send a message (like error message, info message etc )
+ * of type message_type to the view.
+ **/
+
+class MessageEvent {
+		private :
+			message_type mtype;
+			std::string message, info;
+
+		public :
+			MessageEvent();
+			MessageEvent(message_type m_type);
+			MessageEvent(std::string message_);	
+			MessageEvent(message_type mtype_, std::string message_);
+			MessageEvent(message_type mtype_, std::string message_, std::string info);	
+
+			message_type getMessageType();
+			const std::string& getMessage();
+			const std::string& getInfo();
+			void  setMessage(std::string message_);
+};
+
+#endif

Some files were not shown because too many files changed in this diff