├── LICENSE ├── README.md ├── lib ├── .DS_Store ├── .gitignore ├── makefile ├── objects.mk ├── sources.mk └── src │ ├── .gitignore │ ├── Ciphertext.d │ ├── Ciphertext.o │ ├── Context.d │ ├── Context.o │ ├── EvaluatorUtils.d │ ├── EvaluatorUtils.o │ ├── Key.d │ ├── Key.o │ ├── Numb.d │ ├── Numb.o │ ├── Plaintext.d │ ├── Plaintext.o │ ├── Scheme.d │ ├── Scheme.o │ ├── SchemeAlgo.d │ ├── SchemeAlgo.o │ ├── SecretKey.d │ ├── SecretKey.o │ ├── StringUtils.d │ ├── StringUtils.o │ ├── TestScheme.d │ ├── TestScheme.o │ ├── TimeUtils.d │ ├── TimeUtils.o │ └── subdir.mk ├── run ├── .DS_Store ├── FRNSHEAAN ├── main.cpp └── makefile └── src ├── .DS_Store ├── Ciphertext.cpp ├── Ciphertext.h ├── Common.h ├── Context.cpp ├── Context.h ├── EvaluatorUtils.cpp ├── EvaluatorUtils.h ├── Key.cpp ├── Key.h ├── Numb.cpp ├── Numb.h ├── Plaintext.cpp ├── Plaintext.h ├── Scheme.cpp ├── Scheme.h ├── SchemeAlgo.cpp ├── SchemeAlgo.h ├── SecretKey.cpp ├── SecretKey.h ├── StringUtils.cpp ├── StringUtils.h ├── TestScheme.cpp ├── TestScheme.h ├── TimeUtils.cpp ├── TimeUtils.h └── main.cpp /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | Attribution-NonCommercial 3.0 Unported 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR 10 | DAMAGES RESULTING FROM ITS USE. 11 | 12 | License 13 | 14 | THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE 15 | COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY 16 | COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS 17 | AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. 18 | 19 | BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE 20 | TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY 21 | BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS 22 | CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND 23 | CONDITIONS. 24 | 25 | 1. Definitions 26 | 27 | a. "Adaptation" means a work based upon the Work, or upon the Work and 28 | other pre-existing works, such as a translation, adaptation, 29 | derivative work, arrangement of music or other alterations of a 30 | literary or artistic work, or phonogram or performance and includes 31 | cinematographic adaptations or any other form in which the Work may be 32 | recast, transformed, or adapted including in any form recognizably 33 | derived from the original, except that a work that constitutes a 34 | Collection will not be considered an Adaptation for the purpose of 35 | this License. For the avoidance of doubt, where the Work is a musical 36 | work, performance or phonogram, the synchronization of the Work in 37 | timed-relation with a moving image ("synching") will be considered an 38 | Adaptation for the purpose of this License. 39 | b. "Collection" means a collection of literary or artistic works, such as 40 | encyclopedias and anthologies, or performances, phonograms or 41 | broadcasts, or other works or subject matter other than works listed 42 | in Section 1(f) below, which, by reason of the selection and 43 | arrangement of their contents, constitute intellectual creations, in 44 | which the Work is included in its entirety in unmodified form along 45 | with one or more other contributions, each constituting separate and 46 | independent works in themselves, which together are assembled into a 47 | collective whole. A work that constitutes a Collection will not be 48 | considered an Adaptation (as defined above) for the purposes of this 49 | License. 50 | c. "Distribute" means to make available to the public the original and 51 | copies of the Work or Adaptation, as appropriate, through sale or 52 | other transfer of ownership. 53 | d. "Licensor" means the individual, individuals, entity or entities that 54 | offer(s) the Work under the terms of this License. 55 | e. "Original Author" means, in the case of a literary or artistic work, 56 | the individual, individuals, entity or entities who created the Work 57 | or if no individual or entity can be identified, the publisher; and in 58 | addition (i) in the case of a performance the actors, singers, 59 | musicians, dancers, and other persons who act, sing, deliver, declaim, 60 | play in, interpret or otherwise perform literary or artistic works or 61 | expressions of folklore; (ii) in the case of a phonogram the producer 62 | being the person or legal entity who first fixes the sounds of a 63 | performance or other sounds; and, (iii) in the case of broadcasts, the 64 | organization that transmits the broadcast. 65 | f. "Work" means the literary and/or artistic work offered under the terms 66 | of this License including without limitation any production in the 67 | literary, scientific and artistic domain, whatever may be the mode or 68 | form of its expression including digital form, such as a book, 69 | pamphlet and other writing; a lecture, address, sermon or other work 70 | of the same nature; a dramatic or dramatico-musical work; a 71 | choreographic work or entertainment in dumb show; a musical 72 | composition with or without words; a cinematographic work to which are 73 | assimilated works expressed by a process analogous to cinematography; 74 | a work of drawing, painting, architecture, sculpture, engraving or 75 | lithography; a photographic work to which are assimilated works 76 | expressed by a process analogous to photography; a work of applied 77 | art; an illustration, map, plan, sketch or three-dimensional work 78 | relative to geography, topography, architecture or science; a 79 | performance; a broadcast; a phonogram; a compilation of data to the 80 | extent it is protected as a copyrightable work; or a work performed by 81 | a variety or circus performer to the extent it is not otherwise 82 | considered a literary or artistic work. 83 | g. "You" means an individual or entity exercising rights under this 84 | License who has not previously violated the terms of this License with 85 | respect to the Work, or who has received express permission from the 86 | Licensor to exercise rights under this License despite a previous 87 | violation. 88 | h. "Publicly Perform" means to perform public recitations of the Work and 89 | to communicate to the public those public recitations, by any means or 90 | process, including by wire or wireless means or public digital 91 | performances; to make available to the public Works in such a way that 92 | members of the public may access these Works from a place and at a 93 | place individually chosen by them; to perform the Work to the public 94 | by any means or process and the communication to the public of the 95 | performances of the Work, including by public digital performance; to 96 | broadcast and rebroadcast the Work by any means including signs, 97 | sounds or images. 98 | i. "Reproduce" means to make copies of the Work by any means including 99 | without limitation by sound or visual recordings and the right of 100 | fixation and reproducing fixations of the Work, including storage of a 101 | protected performance or phonogram in digital form or other electronic 102 | medium. 103 | 104 | 2. Fair Dealing Rights. Nothing in this License is intended to reduce, 105 | limit, or restrict any uses free from copyright or rights arising from 106 | limitations or exceptions that are provided for in connection with the 107 | copyright protection under copyright law or other applicable laws. 108 | 109 | 3. License Grant. Subject to the terms and conditions of this License, 110 | Licensor hereby grants You a worldwide, royalty-free, non-exclusive, 111 | perpetual (for the duration of the applicable copyright) license to 112 | exercise the rights in the Work as stated below: 113 | 114 | a. to Reproduce the Work, to incorporate the Work into one or more 115 | Collections, and to Reproduce the Work as incorporated in the 116 | Collections; 117 | b. to create and Reproduce Adaptations provided that any such Adaptation, 118 | including any translation in any medium, takes reasonable steps to 119 | clearly label, demarcate or otherwise identify that changes were made 120 | to the original Work. For example, a translation could be marked "The 121 | original work was translated from English to Spanish," or a 122 | modification could indicate "The original work has been modified."; 123 | c. to Distribute and Publicly Perform the Work including as incorporated 124 | in Collections; and, 125 | d. to Distribute and Publicly Perform Adaptations. 126 | 127 | The above rights may be exercised in all media and formats whether now 128 | known or hereafter devised. The above rights include the right to make 129 | such modifications as are technically necessary to exercise the rights in 130 | other media and formats. Subject to Section 8(f), all rights not expressly 131 | granted by Licensor are hereby reserved, including but not limited to the 132 | rights set forth in Section 4(d). 133 | 134 | 4. Restrictions. The license granted in Section 3 above is expressly made 135 | subject to and limited by the following restrictions: 136 | 137 | a. You may Distribute or Publicly Perform the Work only under the terms 138 | of this License. You must include a copy of, or the Uniform Resource 139 | Identifier (URI) for, this License with every copy of the Work You 140 | Distribute or Publicly Perform. You may not offer or impose any terms 141 | on the Work that restrict the terms of this License or the ability of 142 | the recipient of the Work to exercise the rights granted to that 143 | recipient under the terms of the License. You may not sublicense the 144 | Work. You must keep intact all notices that refer to this License and 145 | to the disclaimer of warranties with every copy of the Work You 146 | Distribute or Publicly Perform. When You Distribute or Publicly 147 | Perform the Work, You may not impose any effective technological 148 | measures on the Work that restrict the ability of a recipient of the 149 | Work from You to exercise the rights granted to that recipient under 150 | the terms of the License. This Section 4(a) applies to the Work as 151 | incorporated in a Collection, but this does not require the Collection 152 | apart from the Work itself to be made subject to the terms of this 153 | License. If You create a Collection, upon notice from any Licensor You 154 | must, to the extent practicable, remove from the Collection any credit 155 | as required by Section 4(c), as requested. If You create an 156 | Adaptation, upon notice from any Licensor You must, to the extent 157 | practicable, remove from the Adaptation any credit as required by 158 | Section 4(c), as requested. 159 | b. You may not exercise any of the rights granted to You in Section 3 160 | above in any manner that is primarily intended for or directed toward 161 | commercial advantage or private monetary compensation. The exchange of 162 | the Work for other copyrighted works by means of digital file-sharing 163 | or otherwise shall not be considered to be intended for or directed 164 | toward commercial advantage or private monetary compensation, provided 165 | there is no payment of any monetary compensation in connection with 166 | the exchange of copyrighted works. 167 | c. If You Distribute, or Publicly Perform the Work or any Adaptations or 168 | Collections, You must, unless a request has been made pursuant to 169 | Section 4(a), keep intact all copyright notices for the Work and 170 | provide, reasonable to the medium or means You are utilizing: (i) the 171 | name of the Original Author (or pseudonym, if applicable) if supplied, 172 | and/or if the Original Author and/or Licensor designate another party 173 | or parties (e.g., a sponsor institute, publishing entity, journal) for 174 | attribution ("Attribution Parties") in Licensor's copyright notice, 175 | terms of service or by other reasonable means, the name of such party 176 | or parties; (ii) the title of the Work if supplied; (iii) to the 177 | extent reasonably practicable, the URI, if any, that Licensor 178 | specifies to be associated with the Work, unless such URI does not 179 | refer to the copyright notice or licensing information for the Work; 180 | and, (iv) consistent with Section 3(b), in the case of an Adaptation, 181 | a credit identifying the use of the Work in the Adaptation (e.g., 182 | "French translation of the Work by Original Author," or "Screenplay 183 | based on original Work by Original Author"). The credit required by 184 | this Section 4(c) may be implemented in any reasonable manner; 185 | provided, however, that in the case of a Adaptation or Collection, at 186 | a minimum such credit will appear, if a credit for all contributing 187 | authors of the Adaptation or Collection appears, then as part of these 188 | credits and in a manner at least as prominent as the credits for the 189 | other contributing authors. For the avoidance of doubt, You may only 190 | use the credit required by this Section for the purpose of attribution 191 | in the manner set out above and, by exercising Your rights under this 192 | License, You may not implicitly or explicitly assert or imply any 193 | connection with, sponsorship or endorsement by the Original Author, 194 | Licensor and/or Attribution Parties, as appropriate, of You or Your 195 | use of the Work, without the separate, express prior written 196 | permission of the Original Author, Licensor and/or Attribution 197 | Parties. 198 | d. For the avoidance of doubt: 199 | 200 | i. Non-waivable Compulsory License Schemes. In those jurisdictions in 201 | which the right to collect royalties through any statutory or 202 | compulsory licensing scheme cannot be waived, the Licensor 203 | reserves the exclusive right to collect such royalties for any 204 | exercise by You of the rights granted under this License; 205 | ii. Waivable Compulsory License Schemes. In those jurisdictions in 206 | which the right to collect royalties through any statutory or 207 | compulsory licensing scheme can be waived, the Licensor reserves 208 | the exclusive right to collect such royalties for any exercise by 209 | You of the rights granted under this License if Your exercise of 210 | such rights is for a purpose or use which is otherwise than 211 | noncommercial as permitted under Section 4(b) and otherwise waives 212 | the right to collect royalties through any statutory or compulsory 213 | licensing scheme; and, 214 | iii. Voluntary License Schemes. The Licensor reserves the right to 215 | collect royalties, whether individually or, in the event that the 216 | Licensor is a member of a collecting society that administers 217 | voluntary licensing schemes, via that society, from any exercise 218 | by You of the rights granted under this License that is for a 219 | purpose or use which is otherwise than noncommercial as permitted 220 | under Section 4(c). 221 | e. Except as otherwise agreed in writing by the Licensor or as may be 222 | otherwise permitted by applicable law, if You Reproduce, Distribute or 223 | Publicly Perform the Work either by itself or as part of any 224 | Adaptations or Collections, You must not distort, mutilate, modify or 225 | take other derogatory action in relation to the Work which would be 226 | prejudicial to the Original Author's honor or reputation. Licensor 227 | agrees that in those jurisdictions (e.g. Japan), in which any exercise 228 | of the right granted in Section 3(b) of this License (the right to 229 | make Adaptations) would be deemed to be a distortion, mutilation, 230 | modification or other derogatory action prejudicial to the Original 231 | Author's honor and reputation, the Licensor will waive or not assert, 232 | as appropriate, this Section, to the fullest extent permitted by the 233 | applicable national law, to enable You to reasonably exercise Your 234 | right under Section 3(b) of this License (right to make Adaptations) 235 | but not otherwise. 236 | 237 | 5. Representations, Warranties and Disclaimer 238 | 239 | UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR 240 | OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY 241 | KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, 242 | INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, 243 | FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF 244 | LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, 245 | WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION 246 | OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. 247 | 248 | 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE 249 | LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR 250 | ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES 251 | ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS 252 | BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 253 | 254 | 7. Termination 255 | 256 | a. This License and the rights granted hereunder will terminate 257 | automatically upon any breach by You of the terms of this License. 258 | Individuals or entities who have received Adaptations or Collections 259 | from You under this License, however, will not have their licenses 260 | terminated provided such individuals or entities remain in full 261 | compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will 262 | survive any termination of this License. 263 | b. Subject to the above terms and conditions, the license granted here is 264 | perpetual (for the duration of the applicable copyright in the Work). 265 | Notwithstanding the above, Licensor reserves the right to release the 266 | Work under different license terms or to stop distributing the Work at 267 | any time; provided, however that any such election will not serve to 268 | withdraw this License (or any other license that has been, or is 269 | required to be, granted under the terms of this License), and this 270 | License will continue in full force and effect unless terminated as 271 | stated above. 272 | 273 | 8. Miscellaneous 274 | 275 | a. Each time You Distribute or Publicly Perform the Work or a Collection, 276 | the Licensor offers to the recipient a license to the Work on the same 277 | terms and conditions as the license granted to You under this License. 278 | b. Each time You Distribute or Publicly Perform an Adaptation, Licensor 279 | offers to the recipient a license to the original Work on the same 280 | terms and conditions as the license granted to You under this License. 281 | c. If any provision of this License is invalid or unenforceable under 282 | applicable law, it shall not affect the validity or enforceability of 283 | the remainder of the terms of this License, and without further action 284 | by the parties to this agreement, such provision shall be reformed to 285 | the minimum extent necessary to make such provision valid and 286 | enforceable. 287 | d. No term or provision of this License shall be deemed waived and no 288 | breach consented to unless such waiver or consent shall be in writing 289 | and signed by the party to be charged with such waiver or consent. 290 | e. This License constitutes the entire agreement between the parties with 291 | respect to the Work licensed here. There are no understandings, 292 | agreements or representations with respect to the Work not specified 293 | here. Licensor shall not be bound by any additional provisions that 294 | may appear in any communication from You. This License may not be 295 | modified without the mutual written agreement of the Licensor and You. 296 | f. The rights granted under, and the subject matter referenced, in this 297 | License were drafted utilizing the terminology of the Berne Convention 298 | for the Protection of Literary and Artistic Works (as amended on 299 | September 28, 1979), the Rome Convention of 1961, the WIPO Copyright 300 | Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 301 | and the Universal Copyright Convention (as revised on July 24, 1971). 302 | These rights and subject matter take effect in the relevant 303 | jurisdiction in which the License terms are sought to be enforced 304 | according to the corresponding provisions of the implementation of 305 | those treaty provisions in the applicable national law. If the 306 | standard suite of rights granted under applicable copyright law 307 | includes additional rights not granted under this License, such 308 | additional rights are deemed to be included in the License; this 309 | License is not intended to restrict the license of any rights under 310 | applicable law. 311 | 312 | 313 | Creative Commons Notice 314 | 315 | Creative Commons is not a party to this License, and makes no warranty 316 | whatsoever in connection with the Work. Creative Commons will not be 317 | liable to You or any party on any legal theory for any damages 318 | whatsoever, including without limitation any general, special, 319 | incidental or consequential damages arising in connection to this 320 | license. Notwithstanding the foregoing two (2) sentences, if Creative 321 | Commons has expressly identified itself as the Licensor hereunder, it 322 | shall have all rights and obligations of Licensor. 323 | 324 | Except for the limited purpose of indicating to the public that the 325 | Work is licensed under the CCPL, Creative Commons does not authorize 326 | the use by either party of the trademark "Creative Commons" or any 327 | related trademark or logo of Creative Commons without the prior 328 | written consent of Creative Commons. Any permitted use will be in 329 | compliance with Creative Commons' then-current trademark usage 330 | guidelines, as may be published on its website or otherwise made 331 | available upon request from time to time. For the avoidance of doubt, 332 | this trademark restriction does not form part of the License. 333 | 334 | Creative Commons may be contacted at https://creativecommons.org/. 335 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FullRNS-HEAAN 2 | 3 | ## This code is implementation of the paper "A Full RNS variant of Approximate Homomorphic Encryption" which will appear in SAC 2018. 4 | 5 | ## To install the HE library, you need to type in the "lib" folder as follows: 6 | 1. make clean 7 | 2. make all 8 | 9 | ## To run and test this code, you need to type in the "run" folder as follows: 10 | 1. make clean 11 | 2. make 12 | 3. ./FRNSHEAAN 13 | 14 | - Notice that this code will run only at gcc (this code uses unsigned __int128 variable) 15 | 16 | ## License 17 | Copyright (c) by CryptoLab inc. 18 | This program is licensed under a 19 | Creative Commons Attribution-NonCommercial 3.0 Unported License. 20 | You should have received a copy of the license along with this 21 | work. If not, see . 22 | -------------------------------------------------------------------------------- /lib/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KyoohyungHan/FullRNS-HEAAN/515f6414076ca387996cb12e0798b4e3fcee653e/lib/.DS_Store -------------------------------------------------------------------------------- /lib/.gitignore: -------------------------------------------------------------------------------- 1 | /*.a 2 | -------------------------------------------------------------------------------- /lib/makefile: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Automatically-generated file. Do not edit! 3 | ################################################################################ 4 | 5 | -include ../makefile.init 6 | 7 | RM := rm -rf 8 | 9 | # All of the sources participating in the build are defined here 10 | -include sources.mk 11 | -include src/subdir.mk 12 | -include subdir.mk 13 | -include objects.mk 14 | 15 | ifneq ($(MAKECMDGOALS),clean) 16 | ifneq ($(strip $(CC_DEPS)),) 17 | -include $(CC_DEPS) 18 | endif 19 | ifneq ($(strip $(C++_DEPS)),) 20 | -include $(C++_DEPS) 21 | endif 22 | ifneq ($(strip $(C_UPPER_DEPS)),) 23 | -include $(C_UPPER_DEPS) 24 | endif 25 | ifneq ($(strip $(CXX_DEPS)),) 26 | -include $(CXX_DEPS) 27 | endif 28 | ifneq ($(strip $(CPP_DEPS)),) 29 | -include $(CPP_DEPS) 30 | endif 31 | ifneq ($(strip $(C_DEPS)),) 32 | -include $(C_DEPS) 33 | endif 34 | endif 35 | 36 | -include ../makefile.defs 37 | 38 | # Add inputs and outputs from these tool invocations to the build variables 39 | 40 | # All Target 41 | all: libFRNSHEAAN.a 42 | 43 | # Tool invocations 44 | libFRNSHEAAN.a: $(OBJS) $(USER_OBJS) 45 | @echo 'Building target: $@' 46 | @echo 'Invoking: GCC Archiver' 47 | ar -r "libFRNSHEAAN.a" $(OBJS) $(USER_OBJS) $(LIBS) 48 | @echo 'Finished building target: $@' 49 | @echo ' ' 50 | 51 | # Other Targets 52 | clean: 53 | -$(RM) $(CC_DEPS)$(C++_DEPS)$(ARCHIVES)$(C_UPPER_DEPS)$(CXX_DEPS)$(OBJS)$(CPP_DEPS)$(C_DEPS) libHEAAN.a 54 | -@echo ' ' 55 | 56 | .PHONY: all clean dependents 57 | 58 | -include ../makefile.targets 59 | -------------------------------------------------------------------------------- /lib/objects.mk: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Automatically-generated file. Do not edit! 3 | ################################################################################ 4 | 5 | USER_OBJS := 6 | 7 | LIBS := 8 | 9 | -------------------------------------------------------------------------------- /lib/sources.mk: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Automatically-generated file. Do not edit! 3 | ################################################################################ 4 | 5 | C_UPPER_SRCS := 6 | CXX_SRCS := 7 | C++_SRCS := 8 | OBJ_SRCS := 9 | CC_SRCS := 10 | ASM_SRCS := 11 | CPP_SRCS := 12 | C_SRCS := 13 | O_SRCS := 14 | S_UPPER_SRCS := 15 | CC_DEPS := 16 | C++_DEPS := 17 | EXECUTABLES := 18 | C_UPPER_DEPS := 19 | CXX_DEPS := 20 | OBJS := 21 | CPP_DEPS := 22 | C_DEPS := 23 | 24 | # Every subdirectory with source files must be described here 25 | SUBDIRS := \ 26 | src \ 27 | 28 | -------------------------------------------------------------------------------- /lib/src/.gitignore: -------------------------------------------------------------------------------- 1 | /BootKey.d 2 | -------------------------------------------------------------------------------- /lib/src/Ciphertext.d: -------------------------------------------------------------------------------- 1 | src/Ciphertext.o: ../src/Ciphertext.cpp ../src/Ciphertext.h \ 2 | ../src/Common.h 3 | 4 | ../src/Ciphertext.h: 5 | 6 | ../src/Common.h: 7 | -------------------------------------------------------------------------------- /lib/src/Ciphertext.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KyoohyungHan/FullRNS-HEAAN/515f6414076ca387996cb12e0798b4e3fcee653e/lib/src/Ciphertext.o -------------------------------------------------------------------------------- /lib/src/Context.d: -------------------------------------------------------------------------------- 1 | src/Context.o: ../src/Context.cpp ../src/Context.h ../src/Common.h \ 2 | ../src/Numb.h ../src/EvaluatorUtils.h 3 | 4 | ../src/Context.h: 5 | 6 | ../src/Common.h: 7 | 8 | ../src/Numb.h: 9 | 10 | ../src/EvaluatorUtils.h: 11 | -------------------------------------------------------------------------------- /lib/src/Context.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KyoohyungHan/FullRNS-HEAAN/515f6414076ca387996cb12e0798b4e3fcee653e/lib/src/Context.o -------------------------------------------------------------------------------- /lib/src/EvaluatorUtils.d: -------------------------------------------------------------------------------- 1 | src/EvaluatorUtils.o: ../src/EvaluatorUtils.cpp ../src/EvaluatorUtils.h \ 2 | ../src/Context.h ../src/Common.h ../src/Numb.h 3 | 4 | ../src/EvaluatorUtils.h: 5 | 6 | ../src/Context.h: 7 | 8 | ../src/Common.h: 9 | 10 | ../src/Numb.h: 11 | -------------------------------------------------------------------------------- /lib/src/EvaluatorUtils.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KyoohyungHan/FullRNS-HEAAN/515f6414076ca387996cb12e0798b4e3fcee653e/lib/src/EvaluatorUtils.o -------------------------------------------------------------------------------- /lib/src/Key.d: -------------------------------------------------------------------------------- 1 | src/Key.o: ../src/Key.cpp ../src/Key.h 2 | 3 | ../src/Key.h: 4 | -------------------------------------------------------------------------------- /lib/src/Key.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KyoohyungHan/FullRNS-HEAAN/515f6414076ca387996cb12e0798b4e3fcee653e/lib/src/Key.o -------------------------------------------------------------------------------- /lib/src/Numb.d: -------------------------------------------------------------------------------- 1 | src/Numb.o: ../src/Numb.cpp ../src/Numb.h ../src/Common.h 2 | 3 | ../src/Numb.h: 4 | 5 | ../src/Common.h: 6 | -------------------------------------------------------------------------------- /lib/src/Numb.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KyoohyungHan/FullRNS-HEAAN/515f6414076ca387996cb12e0798b4e3fcee653e/lib/src/Numb.o -------------------------------------------------------------------------------- /lib/src/Plaintext.d: -------------------------------------------------------------------------------- 1 | src/Plaintext.o: ../src/Plaintext.cpp ../src/Plaintext.h ../src/Common.h 2 | 3 | ../src/Plaintext.h: 4 | 5 | ../src/Common.h: 6 | -------------------------------------------------------------------------------- /lib/src/Plaintext.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KyoohyungHan/FullRNS-HEAAN/515f6414076ca387996cb12e0798b4e3fcee653e/lib/src/Plaintext.o -------------------------------------------------------------------------------- /lib/src/Scheme.d: -------------------------------------------------------------------------------- 1 | src/Scheme.o: ../src/Scheme.cpp ../src/Scheme.h ../src/Common.h \ 2 | ../src/Ciphertext.h ../src/Context.h ../src/Numb.h ../src/Plaintext.h \ 3 | ../src/SecretKey.h ../src/Key.h 4 | 5 | ../src/Scheme.h: 6 | 7 | ../src/Common.h: 8 | 9 | ../src/Ciphertext.h: 10 | 11 | ../src/Context.h: 12 | 13 | ../src/Numb.h: 14 | 15 | ../src/Plaintext.h: 16 | 17 | ../src/SecretKey.h: 18 | 19 | ../src/Key.h: 20 | -------------------------------------------------------------------------------- /lib/src/Scheme.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KyoohyungHan/FullRNS-HEAAN/515f6414076ca387996cb12e0798b4e3fcee653e/lib/src/Scheme.o -------------------------------------------------------------------------------- /lib/src/SchemeAlgo.d: -------------------------------------------------------------------------------- 1 | src/SchemeAlgo.o: ../src/SchemeAlgo.cpp ../src/SchemeAlgo.h \ 2 | ../src/Common.h ../src/EvaluatorUtils.h ../src/Context.h ../src/Numb.h \ 3 | ../src/Plaintext.h ../src/SecretKey.h ../src/Ciphertext.h \ 4 | ../src/Scheme.h ../src/Key.h 5 | 6 | ../src/SchemeAlgo.h: 7 | 8 | ../src/Common.h: 9 | 10 | ../src/EvaluatorUtils.h: 11 | 12 | ../src/Context.h: 13 | 14 | ../src/Numb.h: 15 | 16 | ../src/Plaintext.h: 17 | 18 | ../src/SecretKey.h: 19 | 20 | ../src/Ciphertext.h: 21 | 22 | ../src/Scheme.h: 23 | 24 | ../src/Key.h: 25 | -------------------------------------------------------------------------------- /lib/src/SchemeAlgo.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KyoohyungHan/FullRNS-HEAAN/515f6414076ca387996cb12e0798b4e3fcee653e/lib/src/SchemeAlgo.o -------------------------------------------------------------------------------- /lib/src/SecretKey.d: -------------------------------------------------------------------------------- 1 | src/SecretKey.o: ../src/SecretKey.cpp ../src/SecretKey.h ../src/Common.h \ 2 | ../src/Context.h ../src/Numb.h 3 | 4 | ../src/SecretKey.h: 5 | 6 | ../src/Common.h: 7 | 8 | ../src/Context.h: 9 | 10 | ../src/Numb.h: 11 | -------------------------------------------------------------------------------- /lib/src/SecretKey.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KyoohyungHan/FullRNS-HEAAN/515f6414076ca387996cb12e0798b4e3fcee653e/lib/src/SecretKey.o -------------------------------------------------------------------------------- /lib/src/StringUtils.d: -------------------------------------------------------------------------------- 1 | src/StringUtils.o: ../src/StringUtils.cpp ../src/StringUtils.h \ 2 | ../src/Common.h 3 | 4 | ../src/StringUtils.h: 5 | 6 | ../src/Common.h: 7 | -------------------------------------------------------------------------------- /lib/src/StringUtils.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KyoohyungHan/FullRNS-HEAAN/515f6414076ca387996cb12e0798b4e3fcee653e/lib/src/StringUtils.o -------------------------------------------------------------------------------- /lib/src/TestScheme.d: -------------------------------------------------------------------------------- 1 | src/TestScheme.o: ../src/TestScheme.cpp ../src/TestScheme.h ../src/Numb.h \ 2 | ../src/Common.h ../src/Context.h ../src/SecretKey.h ../src/Scheme.h \ 3 | ../src/Ciphertext.h ../src/Plaintext.h ../src/Key.h \ 4 | ../src/EvaluatorUtils.h ../src/StringUtils.h ../src/TimeUtils.h \ 5 | ../src/SchemeAlgo.h 6 | 7 | ../src/TestScheme.h: 8 | 9 | ../src/Numb.h: 10 | 11 | ../src/Common.h: 12 | 13 | ../src/Context.h: 14 | 15 | ../src/SecretKey.h: 16 | 17 | ../src/Scheme.h: 18 | 19 | ../src/Ciphertext.h: 20 | 21 | ../src/Plaintext.h: 22 | 23 | ../src/Key.h: 24 | 25 | ../src/EvaluatorUtils.h: 26 | 27 | ../src/StringUtils.h: 28 | 29 | ../src/TimeUtils.h: 30 | 31 | ../src/SchemeAlgo.h: 32 | -------------------------------------------------------------------------------- /lib/src/TestScheme.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KyoohyungHan/FullRNS-HEAAN/515f6414076ca387996cb12e0798b4e3fcee653e/lib/src/TestScheme.o -------------------------------------------------------------------------------- /lib/src/TimeUtils.d: -------------------------------------------------------------------------------- 1 | src/TimeUtils.o: ../src/TimeUtils.cpp ../src/TimeUtils.h ../src/Common.h 2 | 3 | ../src/TimeUtils.h: 4 | 5 | ../src/Common.h: 6 | -------------------------------------------------------------------------------- /lib/src/TimeUtils.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KyoohyungHan/FullRNS-HEAAN/515f6414076ca387996cb12e0798b4e3fcee653e/lib/src/TimeUtils.o -------------------------------------------------------------------------------- /lib/src/subdir.mk: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Automatically-generated file. Do not edit! 3 | ################################################################################ 4 | 5 | # Add inputs and outputs from these tool invocations to the build variables 6 | CPP_SRCS += \ 7 | ../src/Ciphertext.cpp \ 8 | ../src/Context.cpp \ 9 | ../src/EvaluatorUtils.cpp \ 10 | ../src/Key.cpp \ 11 | ../src/Numb.cpp \ 12 | ../src/Plaintext.cpp \ 13 | ../src/Scheme.cpp \ 14 | ../src/SchemeAlgo.cpp \ 15 | ../src/SecretKey.cpp \ 16 | ../src/StringUtils.cpp \ 17 | ../src/TestScheme.cpp \ 18 | ../src/TimeUtils.cpp 19 | 20 | OBJS += \ 21 | ./src/Ciphertext.o \ 22 | ./src/Context.o \ 23 | ./src/EvaluatorUtils.o \ 24 | ./src/Key.o \ 25 | ./src/Numb.o \ 26 | ./src/Plaintext.o \ 27 | ./src/Scheme.o \ 28 | ./src/SchemeAlgo.o \ 29 | ./src/SecretKey.o \ 30 | ./src/StringUtils.o \ 31 | ./src/TestScheme.o \ 32 | ./src/TimeUtils.o 33 | 34 | CPP_DEPS += \ 35 | ./src/Ciphertext.d \ 36 | ./src/Context.d \ 37 | ./src/EvaluatorUtils.d \ 38 | ./src/Key.d \ 39 | ./src/Numb.d \ 40 | ./src/Plaintext.d \ 41 | ./src/Scheme.d \ 42 | ./src/SchemeAlgo.d \ 43 | ./src/SecretKey.d \ 44 | ./src/StringUtils.d \ 45 | ./src/TestScheme.d \ 46 | ./src/TimeUtils.d 47 | 48 | 49 | # Each subdirectory must supply rules for building sources it contributes 50 | src/%.o: ../src/%.cpp 51 | @echo 'Building file: $<' 52 | @echo 'Invoking: GCC C++ Compiler' 53 | g++ -I/usr/local/include -O3 -c -std=c++11 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<" 54 | @echo 'Finished building: $<' 55 | @echo ' ' 56 | 57 | 58 | -------------------------------------------------------------------------------- /run/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KyoohyungHan/FullRNS-HEAAN/515f6414076ca387996cb12e0798b4e3fcee653e/run/.DS_Store -------------------------------------------------------------------------------- /run/FRNSHEAAN: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KyoohyungHan/FullRNS-HEAAN/515f6414076ca387996cb12e0798b4e3fcee653e/run/FRNSHEAAN -------------------------------------------------------------------------------- /run/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #include "../src/TestScheme.h" 10 | 11 | int main() { 12 | 13 | TestScheme::testEncodeSingle(14, 1, 55); 14 | 15 | TestScheme::testEncodeBatch(15, 6, 55, 3); 16 | 17 | TestScheme::testBasic(15, 11, 55, 3); 18 | 19 | // TestScheme::testConjugateBatch(15, 6, 55, 1); 20 | 21 | // TestScheme::testRotateByPo2Batch(16, 26, 40, 1, 4, false); 22 | 23 | // TestScheme::testRotateBatch(15, 6, 55, 3, 4, true); 24 | 25 | // TestScheme::testimultBatch(16, 16, 55, 2); 26 | 27 | // TestScheme::testPowerOf2Batch(16, 15, 50, 2, 3); 28 | 29 | TestScheme::testInverseBatch(14, 5, 55, 4, 3); 30 | 31 | TestScheme::testExponentBatch(14, 5, 55, 7, 3); 32 | 33 | TestScheme::testSigmoidBatch(16, 15, 55, 3, 3); 34 | 35 | // TestScheme::testSlotsSum(16, 15, 40, 3); 36 | 37 | // TestScheme::testMeanVariance(14, 3, 55, 13); 38 | 39 | // TestScheme::testHEML("data/uis.txt", 0, 5); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /run/makefile: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Automatically-generated file. Do not edit! 3 | ################################################################################ 4 | 5 | # All Target 6 | all: FRNSHEAAN 7 | 8 | # Tool invocations 9 | FRNSHEAAN: 10 | @echo 'Building target: $@' 11 | @echo 'Invoking: MacOS X C++ Linker' 12 | g++ -std=c++11 -pthread -o "FRNSHEAAN" main.cpp ../lib/libFRNSHEAAN.a -I/../src/ 13 | @echo 'Finished building target: $@' 14 | @echo ' ' 15 | 16 | # Other Targets 17 | clean: 18 | rm -rf FRNSHEAAN 19 | -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KyoohyungHan/FullRNS-HEAAN/515f6414076ca387996cb12e0798b4e3fcee653e/src/.DS_Store -------------------------------------------------------------------------------- /src/Ciphertext.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #include "Ciphertext.h" 10 | 11 | Ciphertext::Ciphertext() : ax(nullptr), bx(nullptr), N(0), slots(0), l(0) {} 12 | 13 | Ciphertext::Ciphertext(uint64_t* ax, uint64_t* bx, long N, long slots, long l) : ax(ax), bx(bx), N(N), slots(slots), l(l){} 14 | 15 | Ciphertext::Ciphertext(const Ciphertext& cipher) : N(cipher.N), slots(cipher.slots), l(cipher.l) { 16 | ax = new uint64_t[N * l]; 17 | bx = new uint64_t[N * l]; 18 | for (long i = 0; i < N * l; ++i) { 19 | ax[i] = cipher.ax[i]; 20 | bx[i] = cipher.bx[i]; 21 | } 22 | } 23 | 24 | Ciphertext& Ciphertext::operator=(const Ciphertext& o) { 25 | if(this == &o) return *this; // handling of self assignment, thanks for your advice, arul. 26 | delete[] ax; 27 | delete[] bx; 28 | N = o.N; 29 | l = o.l; 30 | slots = o.slots; 31 | ax = new uint64_t[N * l]; 32 | bx = new uint64_t[N * l]; 33 | for (long i = 0; i < N * l; ++i) { 34 | ax[i] = o.ax[i]; 35 | bx[i] = o.bx[i]; 36 | } 37 | return *this; 38 | } 39 | -------------------------------------------------------------------------------- /src/Ciphertext.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #ifndef HEAANNTT_CIPHERTEXT_H_ 10 | #define HEAANNTT_CIPHERTEXT_H_ 11 | 12 | #include "Common.h" 13 | 14 | class Ciphertext { 15 | 16 | public: 17 | 18 | uint64_t* bx; 19 | uint64_t* ax; 20 | 21 | long N; ///< Dimension of Ring 22 | 23 | long slots; ///< The length of plaintext vector 24 | 25 | long l; ///< The level of this ciphertext 26 | 27 | // Default constructor 28 | Ciphertext(); 29 | 30 | // Constructor 31 | Ciphertext(uint64_t* ax, uint64_t* bx, long N, long slots, long l); 32 | 33 | // Copy constructor 34 | Ciphertext(const Ciphertext& cipher); 35 | Ciphertext& operator=(const Ciphertext &o); 36 | 37 | }; 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/Common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #ifndef HEAANNTT_COMMON_H_ 10 | #define HEAANNTT_COMMON_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/Context.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #include 10 | 11 | #include "Context.h" 12 | #include "EvaluatorUtils.h" 13 | 14 | Context::Context(long logN, long logp, long L, long K, long h, double sigma) : 15 | logN(logN), logp(logp), L(L), K(K), h(h), sigma(sigma) { 16 | 17 | N = 1L << logN; 18 | M = N << 1; 19 | logNh = logN - 1; 20 | Nh = N >> 1; 21 | p = 1L << logp; 22 | 23 | qVec = new uint64_t[L](); 24 | qrVec = new uint64_t[L](); 25 | qTwok = new long[L](); 26 | qkVec = new uint64_t[L](); 27 | qdVec = new uint64_t[L](); 28 | qInvVec = new uint64_t[L](); 29 | qRoots = new uint64_t[L](); 30 | qRootsInv = new uint64_t[L](); 31 | qRootPows = new uint64_t*[L]; 32 | qRootScalePows = new uint64_t*[L]; 33 | qRootScalePowsOverq = new uint64_t*[L]; 34 | qRootScalePowsInv = new uint64_t*[L]; 35 | qRootPowsInv = new uint64_t*[L]; 36 | NInvModq = new uint64_t[L](); 37 | NScaleInvModq = new uint64_t[L](); 38 | 39 | // Generate Primes // 40 | long bnd = 1; 41 | long cnt = 1; 42 | 43 | bnd = 1; 44 | while(1) { 45 | uint64_t prime = (1ULL << Q0_BIT_SIZE) + bnd * M + 1; 46 | if(primeTest(prime)) { 47 | qVec[0] = prime; 48 | break; 49 | } 50 | bnd++; 51 | } 52 | 53 | bnd = 1; 54 | while(cnt < L) { 55 | uint64_t prime1 = (1ULL << logp) + bnd * M + 1; 56 | if(primeTest(prime1)) { 57 | qVec[cnt] = prime1; 58 | cnt++; 59 | } 60 | uint64_t prime2 = (1ULL << logp) - bnd * M + 1; 61 | if(primeTest(prime2)) { 62 | qVec[cnt] = prime2; 63 | cnt++; 64 | } 65 | bnd++; 66 | } 67 | 68 | if(logp - logN - 1 - ceil(log2(bnd)) < 10) { 69 | cerr << "ERROR: too small number of precision" << endl; 70 | cerr << "TRY to use larger logp or smaller depth" << endl; 71 | } 72 | 73 | for (long i = 0; i < L; ++i) { 74 | qTwok[i] = (2 * ((long)log2(qVec[i]) + 1)); 75 | qrVec[i] = (static_cast(1) << qTwok[i]) / qVec[i]; 76 | qkVec[i] = static_cast(((static_cast(invMod(((uint64_t)(1) << 62), qVec[i])) << 62) - 1) / qVec[i]); 77 | qdVec[i] = qVec[i] << 1; 78 | qRoots[i] = findMthRootOfUnity(M, qVec[i]); 79 | qRootsInv[i] = invMod(qRoots[i], qVec[i]); 80 | NInvModq[i] = invMod(N, qVec[i]); 81 | mulMod(NScaleInvModq[i], NInvModq[i], (static_cast(1) << 32), qVec[i]); 82 | mulMod(NScaleInvModq[i], NScaleInvModq[i], (static_cast(1) << 32), qVec[i]); 83 | qInvVec[i] = inv(qVec[i]); 84 | qRootPows[i] = new uint64_t[N](); 85 | qRootPowsInv[i] = new uint64_t[N](); 86 | qRootScalePows[i] = new uint64_t[N](); 87 | qRootScalePowsOverq[i] = new uint64_t[N](); 88 | qRootScalePowsInv[i] = new uint64_t[N](); 89 | uint64_t power = static_cast(1); 90 | uint64_t powerInv = static_cast(1); 91 | 92 | for (long j = 0; j < N; ++j) { 93 | uint64_t jprime = bitReverse(static_cast(j)) >> (32 - logN); 94 | qRootPows[i][jprime] = power; 95 | unsigned __int128 tmp = (static_cast(power) << 64); 96 | qRootScalePowsOverq[i][jprime] = static_cast(tmp / qVec[i]); 97 | mulMod(qRootScalePows[i][jprime], qRootPows[i][jprime], (static_cast(1) << 32), qVec[i]); 98 | mulMod(qRootScalePows[i][jprime], qRootScalePows[i][jprime], (static_cast(1) << 32), qVec[i]); 99 | qRootPowsInv[i][jprime] = powerInv; 100 | mulMod(qRootScalePowsInv[i][jprime], qRootPowsInv[i][jprime], (static_cast(1) << 32), qVec[i]); 101 | mulMod(qRootScalePowsInv[i][jprime], qRootScalePowsInv[i][jprime], (static_cast(1) << 32), qVec[i]); 102 | 103 | if (j < N - 1) { 104 | mulMod(power, power, qRoots[i], qVec[i]); 105 | mulMod(powerInv, powerInv, qRootsInv[i], qVec[i]); 106 | } 107 | } 108 | } 109 | 110 | pVec = new uint64_t[K](); 111 | prVec = new uint64_t[K](); 112 | pTwok = new long[K](); 113 | pkVec = new uint64_t[K](); 114 | pdVec = new uint64_t[K](); 115 | pInvVec = new uint64_t[K](); 116 | pRoots = new uint64_t[K](); 117 | pRootsInv = new uint64_t[K](); 118 | pRootPows = new uint64_t*[K]; 119 | pRootPowsInv = new uint64_t*[K]; 120 | pRootScalePows = new uint64_t*[K]; 121 | pRootScalePowsOverp = new uint64_t*[K]; 122 | pRootScalePowsInv = new uint64_t*[K]; 123 | NInvModp = new uint64_t[K](); 124 | NScaleInvModp = new uint64_t[K](); 125 | 126 | // Generate Special Primes // 127 | cnt = 0; 128 | while(cnt < K) { 129 | uint64_t prime1 = (1ULL << logp) + bnd * M + 1; 130 | if(primeTest(prime1)) { 131 | pVec[cnt] = prime1; 132 | cnt++; 133 | } 134 | if(cnt == K) break; 135 | uint64_t prime2 = (1ULL << logp) - bnd * M + 1; 136 | if(primeTest(prime2)) { 137 | pVec[cnt] = prime2; 138 | cnt++; 139 | } 140 | bnd++; 141 | } 142 | 143 | for (long i = 0; i < K; ++i) { 144 | pTwok[i] = (2 * ((long)log2(pVec[i]) + 1)); 145 | prVec[i] = (static_cast(1) << pTwok[i]) / pVec[i]; 146 | pkVec[i] = static_cast(((static_cast(invMod(((uint64_t)(1) << 62), pVec[i])) << 62) - 1) / pVec[i]); 147 | pdVec[i] = pVec[i] << 1; 148 | pRoots[i] = findMthRootOfUnity(M, pVec[i]); 149 | pRootsInv[i] = invMod(pRoots[i], pVec[i]); 150 | NInvModp[i] = invMod(N, pVec[i]); 151 | mulMod(NScaleInvModp[i], NInvModp[i], (static_cast(1) << 32), pVec[i]); 152 | mulMod(NScaleInvModp[i], NScaleInvModp[i], (static_cast(1) << 32), pVec[i]); 153 | pRootPows[i] = new uint64_t[N](); 154 | pRootScalePows[i] = new uint64_t[N](); 155 | pRootScalePowsOverp[i] = new uint64_t[N](); 156 | pRootScalePowsInv[i] = new uint64_t[N](); 157 | pRootPowsInv[i] = new uint64_t[N](); 158 | pInvVec[i] = inv(pVec[i]); 159 | uint64_t power = static_cast(1); 160 | uint64_t powerInv = static_cast(1); 161 | for (long j = 0; j < N; ++j) { 162 | uint64_t jprime = bitReverse(static_cast(j)) >> (32 - logN); 163 | pRootPows[i][jprime] = power; 164 | unsigned __int128 tmp = (static_cast(power) << 64); 165 | mulMod(pRootScalePows[i][jprime], pRootPows[i][jprime], (static_cast(1) << 32), pVec[i]); 166 | mulMod(pRootScalePows[i][jprime], pRootScalePows[i][jprime], (static_cast(1) << 32), pVec[i]); 167 | pRootPowsInv[i][jprime] = powerInv; 168 | mulMod(pRootScalePowsInv[i][jprime], pRootPowsInv[i][jprime], (static_cast(1) << 32), pVec[i]); 169 | mulMod(pRootScalePowsInv[i][jprime], pRootScalePowsInv[i][jprime], (static_cast(1) << 32), pVec[i]); 170 | if (j < N - 1) { 171 | mulMod(power, power, pRoots[i], pVec[i]); 172 | mulMod(powerInv, powerInv, pRootsInv[i], pVec[i]); 173 | } 174 | } 175 | } 176 | 177 | qHatModq = new uint64_t*[L]; // [l][i] (phat_i)_l mod p_i 178 | for (long l = 0; l < L; ++l) { 179 | qHatModq[l] = new uint64_t[l + 1](); 180 | for (long i = 0; i < l + 1; ++i) { 181 | qHatModq[l][i] = 1; 182 | for (long j = 0; j < i; ++j) { 183 | uint64_t temp = qVec[j] % qVec[i]; 184 | mulMod(qHatModq[l][i], qHatModq[l][i], temp, qVec[i]); 185 | } 186 | for (long j = i + 1; j < l + 1; ++j) { 187 | uint64_t temp = qVec[j] % qVec[i]; 188 | mulMod(qHatModq[l][i], qHatModq[l][i], temp, qVec[i]); 189 | } 190 | } 191 | } 192 | 193 | qHatInvModq = new uint64_t*[L]; // [l][i] (phat_i)_l^-1 mod p_i 194 | for (long l = 0; l < L; ++l) { 195 | qHatInvModq[l] = new uint64_t[l + 1](); 196 | for (long i = 0; i < l + 1; ++i) { 197 | qHatInvModq[l][i] = invMod(qHatModq[l][i], qVec[i]); 198 | } 199 | } 200 | 201 | pHatModp = new uint64_t[K](); // [k] qhat_k mod q_k 202 | 203 | for (long k = 0; k < K; ++k) { 204 | pHatModp[k] = 1; 205 | for (long j = 0; j < k; ++j) { 206 | uint64_t temp = pVec[j] % pVec[k]; 207 | mulMod(pHatModp[k], pHatModp[k], temp, pVec[k]); 208 | } 209 | for (long j = k + 1; j < K; ++j) { 210 | uint64_t temp = pVec[j] % pVec[k]; 211 | mulMod(pHatModp[k], pHatModp[k], temp, pVec[k]); 212 | } 213 | } 214 | 215 | pHatInvModp = new uint64_t[K](); // [k] qhat_k^-1 mod q_k 216 | for (long k = 0; k < K; ++k) { 217 | pHatInvModp[k] = invMod(pHatModp[k], pVec[k]); 218 | } 219 | 220 | qHatModp = new uint64_t**[L]; // [l] [i] [k] (phat_i)_l mod q_k 221 | for (long l = 0; l < L; ++l) { 222 | qHatModp[l] = new uint64_t*[l + 1]; 223 | for (long i = 0; i < l + 1; ++i) { 224 | qHatModp[l][i] = new uint64_t[K](); 225 | for (long k = 0; k < K; ++k) { 226 | qHatModp[l][i][k] = 1; 227 | for (long j = 0; j < i; ++j) { 228 | uint64_t temp = qVec[j] % pVec[k]; 229 | mulMod(qHatModp[l][i][k], qHatModp[l][i][k], temp, pVec[k]); 230 | } 231 | for (long j = i + 1; j < l + 1; ++j) { 232 | uint64_t temp = qVec[j] % pVec[k]; 233 | mulMod(qHatModp[l][i][k], qHatModp[l][i][k], temp, pVec[k]); 234 | } 235 | } 236 | } 237 | } 238 | 239 | pHatModq = new uint64_t*[K]; // [k][i] qhat_k mod p_i 240 | for (long k = 0; k < K; ++k) { 241 | pHatModq[k] = new uint64_t[L](); 242 | for (long i = 0; i < L; ++i) { 243 | pHatModq[k][i] = 1; 244 | for (long s = 0; s < k; ++s) { 245 | uint64_t temp = pVec[s] % qVec[i]; 246 | mulMod(pHatModq[k][i], pHatModq[k][i], temp, qVec[i]); 247 | } 248 | for (long s = k + 1; s < K; ++s) { 249 | uint64_t temp = pVec[s] % qVec[i]; 250 | mulMod(pHatModq[k][i], pHatModq[k][i], temp, qVec[i]); 251 | } 252 | } 253 | } 254 | 255 | PModq = new uint64_t[L](); // [i] qprod mod p_i 256 | for (long i = 0; i < L; ++i) { 257 | PModq[i] = 1; 258 | for (long k = 0; k < K; ++k) { 259 | uint64_t temp = pVec[k] % qVec[i]; 260 | mulMod(PModq[i], PModq[i], temp, qVec[i]); 261 | } 262 | } 263 | 264 | PInvModq = new uint64_t[L](); // [i] qprod^-1 mod p_i 265 | for (long i = 0; i < L; ++i) { 266 | PInvModq[i] = invMod(PModq[i], qVec[i]); 267 | } 268 | 269 | QModp = new uint64_t*[L]; 270 | for (long i = 0; i < L; ++i) { 271 | QModp[i] = new uint64_t[K](); 272 | for (long k = 0; k < K; ++k) { 273 | QModp[i][k] = 1; 274 | for (long j = 0; j < i + 1; ++j) { 275 | uint64_t temp = qVec[j] % pVec[k]; 276 | mulMod(QModp[i][k], QModp[i][k], temp, pVec[k]); 277 | } 278 | } 279 | } 280 | QInvModp = new uint64_t*[L]; 281 | for (long i = 0; i < L; ++i) { 282 | QInvModp[i] = new uint64_t[K](); 283 | for (long k = 0; k < K; ++k) { 284 | QInvModp[i][k] = invMod(QModp[i][k], pVec[k]); 285 | } 286 | } 287 | 288 | qInvModq = new uint64_t*[L]; // [i][j] p_i^-1 mod p_j 289 | for (long i = 0; i < L; ++i) { 290 | qInvModq[i] = new uint64_t[L](); 291 | for (long j = 0; j < i; ++j) { 292 | qInvModq[i][j] = invMod(qVec[i], qVec[j]); 293 | } 294 | for (long j = i + 1; j < L; ++j) { 295 | qInvModq[i][j] = invMod(qVec[i], qVec[j]); 296 | } 297 | } 298 | 299 | rotGroup = new long[Nh](); 300 | long fivePows = 1; 301 | for (long i = 0; i < Nh; ++i) { 302 | rotGroup[i] = fivePows; 303 | fivePows *= 5; 304 | fivePows %= M; 305 | } 306 | 307 | ksiPows = new complex[M + 1]; 308 | for (long j = 0; j < M; ++j) { 309 | double angle = 2.0 * M_PI * j / M; 310 | ksiPows[j].real(cos(angle)); 311 | ksiPows[j].imag(sin(angle)); 312 | } 313 | 314 | ksiPows[M] = ksiPows[0]; 315 | 316 | p2coeff = new uint64_t[L << logN]; 317 | 318 | for (long i = 0; i < L; ++i) { 319 | for (long n = 0; n < N; ++n) { 320 | mulModBarrett(p2coeff[n + (i << logN)], p, p, qVec[i], qrVec[i], qTwok[i]); 321 | } 322 | } 323 | p2hcoeff = new uint64_t[L << logN]; 324 | 325 | for (long i = 0; i < L; ++i) { 326 | for (long n = 0; n < N; ++n) { 327 | mulModBarrett(p2hcoeff[n + (i << logN)], (p >> 1), p, qVec[i], qrVec[i], qTwok[i]); 328 | } 329 | } 330 | 331 | pccoeff = new uint64_t[L << logN](); 332 | for (long i = 0; i < L; ++i) { 333 | for (long n = 0; n < N; ++n) { 334 | mulModBarrett(pccoeff[n + (i << logN)], (94.2372881) * (p >> 20), (1L << 20), qVec[i], qrVec[i], qTwok[i]); 335 | } 336 | } 337 | negateAndEqual(pccoeff, L); 338 | 339 | 340 | taylorCoeffsMap.insert(pair(LOGARITHM, new double[11]{0,1,-0.5,1./3,-1./4,1./5,-1./6,1./7,-1./8,1./9,-1./10})); 341 | taylorCoeffsMap.insert(pair(EXPONENT, new double[11]{1,1,0.5,1./6,1./24,1./120,1./720,1./5040, 1./40320,1./362880,1./3628800})); 342 | taylorCoeffsMap.insert(pair(SIGMOID, new double[11]{1./2,1./4,0,-1./48,0,1./480,0,-17./80640,0,31./1451520,0})); 343 | 344 | } 345 | 346 | void Context::arrayBitReverse(complex* vals, const long size) { 347 | for (long i = 1, j = 0; i < size; ++i) { 348 | long bit = size >> 1; 349 | for (; j >= bit; bit >>= 1) { 350 | j -= bit; 351 | } 352 | j += bit; 353 | if (i < j) { 354 | swap(vals[i], vals[j]); 355 | } 356 | } 357 | } 358 | 359 | void Context::arrayBitReverse(uint64_t* vals, const long size) { 360 | for (long i = 1, j = 0; i < size; ++i) { 361 | long bit = size >> 1; 362 | for (; j >= bit; bit >>= 1) { 363 | j -= bit; 364 | } 365 | j += bit; 366 | if (i < j) { 367 | swap(vals[i], vals[j]); 368 | } 369 | } 370 | } 371 | 372 | void Context::fft(complex* vals, const long size) { 373 | arrayBitReverse(vals, size); 374 | for (long len = 2; len <= size; len <<= 1) { 375 | long MoverLen = M / len; 376 | long lenh = len >> 1; 377 | for (long i = 0; i < size; i += len) { 378 | for (long j = 0; j < lenh; ++j) { 379 | long idx = j * MoverLen; 380 | complex u = vals[i + j]; 381 | complex v = vals[i + j + lenh]; 382 | v *= ksiPows[idx]; 383 | vals[i + j] = u + v; 384 | vals[i + j + lenh] = u - v; 385 | } 386 | } 387 | } 388 | } 389 | 390 | void Context::fftInvLazy(complex* vals, const long size) { 391 | arrayBitReverse(vals, size); 392 | for (long len = 2; len <= size; len <<= 1) { 393 | long MoverLen = M / len; 394 | long lenh = len >> 1; 395 | for (long i = 0; i < size; i += len) { 396 | for (long j = 0; j < lenh; ++j) { 397 | long idx = (len - j) * MoverLen; 398 | complex u = vals[i + j]; 399 | complex v = vals[i + j + lenh]; 400 | v *= ksiPows[idx]; 401 | vals[i + j] = u + v; 402 | vals[i + j + lenh] = u - v; 403 | } 404 | } 405 | } 406 | } 407 | 408 | void Context::fftInv(complex* vals, const long size) { 409 | fftInvLazy(vals, size); 410 | for (long i = 0; i < size; ++i) { 411 | vals[i] /= size; 412 | } 413 | } 414 | 415 | void Context::fftSpecial(complex* vals, const long size) { 416 | arrayBitReverse(vals, size); 417 | for (long len = 2; len <= size; len <<= 1) { 418 | for (long i = 0; i < size; i += len) { 419 | long lenh = len >> 1; 420 | long lenq = len << 2; 421 | for (long j = 0; j < lenh; ++j) { 422 | long idx = ((rotGroup[j] % lenq)) * M / lenq; 423 | complex u = vals[i + j]; 424 | complex v = vals[i + j + lenh]; 425 | v *= ksiPows[idx]; 426 | vals[i + j] = u + v; 427 | vals[i + j + lenh] = u - v; 428 | } 429 | } 430 | } 431 | } 432 | 433 | void Context::fftSpecialInvLazy(complex* vals, const long size) { 434 | for (long len = size; len >= 1; len >>= 1) { 435 | for (long i = 0; i < size; i += len) { 436 | long lenh = len >> 1; 437 | long lenq = len << 2; 438 | for (long j = 0; j < lenh; ++j) { 439 | long idx = (lenq - (rotGroup[j] % lenq)) * M / lenq; 440 | complex u = vals[i + j] + vals[i + j + lenh]; 441 | complex v = vals[i + j] - vals[i + j + lenh]; 442 | v *= ksiPows[idx]; 443 | vals[i + j] = u; 444 | vals[i + j + lenh] = v; 445 | } 446 | } 447 | } 448 | arrayBitReverse(vals, size); 449 | } 450 | 451 | void Context::fftSpecialInv(complex* vals, const long size) { 452 | fftSpecialInvLazy(vals, size); 453 | for (long i = 0; i < size; ++i) { 454 | vals[i] /= size; 455 | } 456 | } 457 | 458 | void Context::encode(uint64_t* a, complex* v, long slots, long l) { 459 | complex* uvals = new complex [slots](); 460 | copy(v, v + slots, uvals); 461 | 462 | long gap = Nh / slots; 463 | 464 | fftSpecialInv(uvals, slots); 465 | 466 | for (long j = 0; j < slots; ++j) { 467 | uvals[j] *= p; 468 | } 469 | 470 | for (long i = 0; i < l; ++i) { 471 | uint64_t* mi = a + i * N; 472 | for (long j = 0, jdx = Nh, idx = 0; j < slots; ++j, jdx += gap, idx += gap) { 473 | long mir = uvals[j].real(); 474 | long mii = uvals[j].imag(); 475 | mi[idx] = mir >= 0 ? (uint64_t) mir : (uint64_t) (qVec[i] + mir); 476 | mi[jdx] = mii >= 0 ? (uint64_t) mii : (uint64_t) (qVec[i] + mii); 477 | } 478 | qiNTTAndEqual(mi, i); 479 | } 480 | delete[] uvals; 481 | } 482 | 483 | void Context::encode(uint64_t* ax, double* vals, long slots, long l) { 484 | 485 | } 486 | 487 | void Context::encodeSingle(uint64_t* ax, complex& val, long l) { 488 | long vr = val.real() * p; 489 | long vi = val.imag() * p; 490 | 491 | for (long i = 0; i < l; ++i) { 492 | uint64_t* ai = ax + i * N; 493 | ai[0] = vr >= 0 ? vr : qVec[i] + vr; 494 | ai[Nh] = vi >= 0 ? vi : qVec[i] + vi; 495 | qiNTTAndEqual(ai, i); 496 | } 497 | } 498 | 499 | void Context::encodeSingle(uint64_t* ax, double val, long l) { 500 | 501 | } 502 | 503 | void Context::decode(uint64_t* a, complex* v, long slots, long l) { 504 | uint64_t* tmp = new uint64_t[N](); 505 | copy(a, a + N, tmp); 506 | long gap = Nh / slots; 507 | qiINTTAndEqual(tmp, 0); 508 | 509 | uint64_t pr = qVec[0]; 510 | uint64_t pr_2 = qVec[0] / 2; 511 | 512 | for (long j = 0, jdx = Nh, idx = 0; j < slots; ++j, jdx += gap, idx += gap) { 513 | double mir = tmp[idx] <= pr_2 ? ((double) (tmp[idx]) / p) : (((double) (tmp[idx]) - (double) (pr)) / p); 514 | double mii = tmp[jdx] <= pr_2 ? ((double) (tmp[jdx]) / p) : (((double) (tmp[jdx]) - (double) (pr)) / p); 515 | v[j].real(mir); 516 | v[j].imag(mii); 517 | } 518 | fftSpecial(v, slots); 519 | } 520 | 521 | void Context::decodeSingle(uint64_t* ax, complex& val, long l) { 522 | uint64_t* tmp = new uint64_t[N](); 523 | copy(ax, ax + N, tmp); 524 | qiINTTAndEqual(tmp, 0); 525 | 526 | uint64_t pr = qVec[0]; 527 | uint64_t pr_2 = qVec[0] / 2; 528 | 529 | double vr = tmp[0] <= pr_2 ? ((double) tmp[0]) / p : (((double) tmp[0]) - ((double) pr)) / (double) p; 530 | double vi = tmp[Nh] <= pr_2 ? ((double) tmp[Nh]) / p : (((double) tmp[Nh]) - ((double) pr)) / (double) p; 531 | 532 | val.real(vr); 533 | val.imag(vi); 534 | } 535 | 536 | void Context::decodeSingle(uint64_t* ax, double val, long l) { 537 | //TODO implement method 538 | 539 | } 540 | 541 | void Context::qiNTT(uint64_t* res, uint64_t* a, long index) { 542 | copy(a, a + N, res); 543 | qiNTTAndEqual(res, index); 544 | } 545 | 546 | void Context::piNTT(uint64_t* res, uint64_t* a, long index) { 547 | copy(a, a + N, res); 548 | piNTTAndEqual(res, index); 549 | } 550 | 551 | void Context::NTT(uint64_t* res, uint64_t* a, long l, long k) { 552 | for (long index = 0; index < l; ++index) { 553 | uint64_t* ai = a + (index << logN); 554 | uint64_t* resi = a + (index << logN); 555 | qiNTT(resi, ai, index); 556 | } 557 | 558 | for (long index = l; index < l + k; ++index) { 559 | uint64_t* ai = a + (index << logN); 560 | uint64_t* resi = a + (index << logN); 561 | piNTT(resi, ai, index - l); 562 | } 563 | } 564 | 565 | void Context::qiNTTAndEqual(uint64_t* a, long index) { 566 | long t = N; 567 | long logt1 = logN + 1; 568 | uint64_t q = qVec[index]; 569 | // uint64_t qd = qdVec[index]; 570 | uint64_t qInv = qInvVec[index]; 571 | for (long m = 1; m < N; m <<= 1) { 572 | t >>= 1; 573 | logt1 -= 1; 574 | for (long i = 0; i < m; i++) { 575 | long j1 = i << logt1; 576 | long j2 = j1 + t - 1; 577 | uint64_t W = qRootScalePows[index][m + i]; 578 | // uint64_t W = qRootScalePowsOverq[index][m + i]; 579 | // uint64_t w = qRootPows[index][m + i]; 580 | for (long j = j1; j <= j2; j++) { 581 | 582 | uint64_t T = a[j + t]; 583 | unsigned __int128 U = static_cast(T) * W; 584 | uint64_t U0 = static_cast(U); 585 | uint64_t U1 = static_cast(U >> 64); 586 | uint64_t Q = U0 * qInv; 587 | unsigned __int128 Hx = static_cast(Q) * q; 588 | uint64_t H = static_cast(Hx >> 64); 589 | uint64_t V = U1 < H ? U1 + q - H : U1 - H; 590 | a[j + t] = a[j] < V ? a[j] + q - V: a[j] - V; 591 | a[j] += V; 592 | if(a[j] > q) a[j] -= q; 593 | 594 | // if(a[j] >= qd) a[j] -= qd; 595 | // uint64_t T = a[j + t]; 596 | // unsigned __int128 U = static_cast(T) * W; 597 | // uint64_t Q = static_cast(U >> 64); 598 | // T *= w; 599 | // uint64_t T1 = Q * q; 600 | // T -= T1; 601 | // a[j + t] = a[j] + qd - T; 602 | // a[j] += T; 603 | } 604 | } 605 | } 606 | // for(long i = 0; i < N; i++) { 607 | // if(a[i] >= qd) a[i] -= qd; 608 | // if(a[i] >= q) a[i] -= q; 609 | // } 610 | } 611 | 612 | void Context::piNTTAndEqual(uint64_t* a, long index) { 613 | long t = N; 614 | long logt1 = logN + 1; 615 | uint64_t pi = pVec[index]; 616 | // uint64_t pd = pdVec[index]; 617 | uint64_t pInv = pInvVec[index]; 618 | for (long m = 1; m < N; m <<= 1) { 619 | t >>= 1; 620 | logt1 -= 1; 621 | for (long i = 0; i < m; i++) { 622 | long j1 = i << logt1; 623 | long j2 = j1 + t - 1; 624 | uint64_t W = pRootScalePows[index][m + i]; 625 | // uint64_t W = pRootScalePowsOverp[index][m + i]; 626 | // uint64_t w = pRootPows[index][m + i]; 627 | for (long j = j1; j <= j2; j++) { 628 | 629 | uint64_t T = a[j + t]; 630 | unsigned __int128 U = static_cast(T) * W; 631 | uint64_t U0 = static_cast(U); 632 | uint64_t U1 = static_cast(U >> 64); 633 | uint64_t Q = U0 * pInv; 634 | unsigned __int128 Hx = static_cast(Q) * pi; 635 | uint64_t H = static_cast(Hx >> 64); 636 | uint64_t V = U1 < H ? U1 + pi - H : U1 - H; 637 | a[j + t] = a[j] < V ? a[j] + pi - V: a[j] - V; 638 | a[j] += V; 639 | if(a[j] > pi) a[j] -= pi; 640 | 641 | // if(a[j] >= pd) a[j] -= pd; 642 | // uint64_t T = a[j + t]; 643 | // unsigned __int128 U = static_cast(T) * W; 644 | // uint64_t Q = static_cast(U >> 64); 645 | // T *= w; 646 | // uint64_t T1 = Q * pi; 647 | // T -= T1; 648 | // a[j + t] = a[j] + pd - T; 649 | // a[j] += T; 650 | } 651 | } 652 | } 653 | // for(long i = 0; i < N; i++) { 654 | // if(a[i] >= pd) a[i] -= pd; 655 | // if(a[i] >= p) a[i] -= pi; 656 | // } 657 | } 658 | 659 | void Context::NTTAndEqual(uint64_t* a, long l, long k) { 660 | for (long index = 0; index < l; ++index) { 661 | uint64_t* ai = a + (index << logN); 662 | qiNTTAndEqual(ai, index); 663 | } 664 | 665 | for (long index = l; index < l + k; ++index) { 666 | uint64_t* ai = a + (index << logN); 667 | piNTTAndEqual(ai, index - l); 668 | } 669 | } 670 | 671 | void Context::qiINTT(uint64_t* res, uint64_t* a, long index) { 672 | copy(a, a + N, res); 673 | qiINTTAndEqual(res, index); 674 | } 675 | 676 | void Context::qiINTTAndEqual(uint64_t* a, long index) { 677 | uint64_t q = qVec[index]; 678 | uint64_t qd = qdVec[index]; 679 | uint64_t qInv = qInvVec[index]; 680 | long t = 1; 681 | for (long m = N; m > 1; m >>= 1) { 682 | long j1 = 0; 683 | long h = m >> 1; 684 | for (long i = 0; i < h; i++) { 685 | long j2 = j1 + t - 1; 686 | uint64_t W = qRootScalePowsInv[index][h + i]; 687 | for (long j = j1; j <= j2; j++) { 688 | uint64_t T = a[j] + qd; 689 | T -= a[j + t]; 690 | a[j] += a[j + t]; 691 | if(a[j] >= qd) a[j] -= qd; 692 | unsigned __int128 UU = static_cast(T) * W; 693 | uint64_t U0 = static_cast(UU); 694 | uint64_t U1 = static_cast(UU >> 64); 695 | uint64_t Q = U0 * qInv; 696 | unsigned __int128 Hx = static_cast(Q) * q; 697 | uint64_t H = static_cast(Hx >> 64); 698 | a[j + t] = U1 + q; 699 | a[j + t] -= H; 700 | } 701 | j1 += (t << 1); 702 | } 703 | t <<= 1; 704 | } 705 | 706 | uint64_t NScale = NScaleInvModq[index]; 707 | for (long i = 0; i < N; i++) { 708 | uint64_t T = (a[i] < q) ? a[i] : a[i] - q; 709 | unsigned __int128 U = static_cast(T) * NScale; 710 | uint64_t U0 = static_cast(U); 711 | uint64_t U1 = static_cast(U >> 64); 712 | uint64_t Q = U0 * qInv; 713 | unsigned __int128 Hx = static_cast(Q) * q; 714 | uint64_t H = static_cast(Hx >> 64); 715 | a[i] = (U1 < H) ? U1 + q - H : U1 - H; 716 | } 717 | } 718 | 719 | void Context::piINTTAndEqual(uint64_t* a, long index) { 720 | uint64_t pi = pVec[index]; 721 | uint64_t pd = pdVec[index]; 722 | uint64_t pInv = pInvVec[index]; 723 | long t = 1; 724 | for (long m = N; m > 1; m >>= 1) { 725 | long j1 = 0; 726 | long h = m >> 1; 727 | for (long i = 0; i < h; i++) { 728 | long j2 = j1 + t - 1; 729 | uint64_t W = pRootScalePowsInv[index][h + i]; 730 | for (long j = j1; j <= j2; j++) { 731 | uint64_t T = a[j] + pd; 732 | T -= a[j + t]; 733 | a[j] += a[j + t]; 734 | if(a[j] >= pd) a[j] -= pd; 735 | unsigned __int128 UU = static_cast(T) * W; 736 | uint64_t U0 = static_cast(UU); 737 | uint64_t U1 = static_cast(UU >> 64); 738 | uint64_t Q = U0 * pInv; 739 | unsigned __int128 Hx = static_cast(Q) * pi; 740 | uint64_t H = static_cast(Hx >> 64); 741 | a[j + t] = U1 + pi; 742 | a[j + t] -= H; 743 | } 744 | j1 += (t << 1); 745 | } 746 | t <<= 1; 747 | } 748 | 749 | uint64_t NScale = NScaleInvModp[index]; 750 | for (long i = 0; i < N; i++) { 751 | uint64_t T = (a[i] < pi) ? a[i] : a[i] - pi; 752 | unsigned __int128 U = static_cast(T) * NScale; 753 | uint64_t U0 = static_cast(U); 754 | uint64_t U1 = static_cast(U >> 64); 755 | uint64_t Q = U0 * pInv; 756 | unsigned __int128 Hx = static_cast(Q) * pi; 757 | uint64_t H = static_cast(Hx >> 64); 758 | a[i] = (U1 < H) ? U1 + pi - H : U1 - H; 759 | } 760 | } 761 | 762 | void Context::INTTAndEqual(uint64_t* a, long l, long k) { 763 | for (long index = 0; index < l; ++index) { 764 | uint64_t* ai = a + (index << logN); 765 | qiINTTAndEqual(ai, index); 766 | } 767 | 768 | for (long index = l; index < l + k; ++index) { 769 | uint64_t* ai = a + (index << logN); 770 | piINTTAndEqual(ai, index - l); 771 | } 772 | } 773 | 774 | void Context::qiNegate(uint64_t* res, uint64_t* a, long index) { 775 | for (long i = 0; i < N; ++i) { 776 | res[i] = (a[i] == 0) ? 0 : qVec[index] - a[i]; 777 | } 778 | } 779 | 780 | void Context::piNegate(uint64_t* res, uint64_t* a, long index) { 781 | for (long i = 0; i < N; ++i) { 782 | res[i] = (a[i] == 0) ? 0 : pVec[index] - a[i]; 783 | } 784 | } 785 | 786 | void Context::negate(uint64_t* res, uint64_t* a, long l, long k) { 787 | for (long i = 0; i < l; ++i) { 788 | uint64_t* ai = a + (i << logN); 789 | uint64_t* resi = res + (i << logN); 790 | qiNegate(resi, ai, i); 791 | } 792 | 793 | for (long i = l; i < l + k; ++i) { 794 | uint64_t* ai = a + (i << logN); 795 | uint64_t* resi = res + (i << logN); 796 | piNegate(resi, ai, i - l); 797 | } 798 | } 799 | 800 | void Context::qiNegateAndEqual(uint64_t* a, long index) { 801 | for (long i = 0; i < N; ++i) { 802 | a[i] = (a[i] == 0) ? 0 : qVec[index] - a[i]; 803 | } 804 | } 805 | 806 | void Context::piNegateAndEqual(uint64_t* a, long index) { 807 | for (long i = 0; i < N; ++i) { 808 | a[i] = (a[i] == 0) ? 0 : pVec[index] - a[i]; 809 | } 810 | } 811 | 812 | void Context::negateAndEqual(uint64_t* a, long l, long k) { 813 | for (long i = 0; i < l; ++i) { 814 | uint64_t* ai = a + (i << logN); 815 | qiNegateAndEqual(ai, i); 816 | } 817 | 818 | for (long i = l; i < l + k; ++i) { 819 | uint64_t* ai = a + (i << logN); 820 | piNegateAndEqual(ai, i - l); 821 | } 822 | } 823 | 824 | void Context::qiAddConst(uint64_t* res, uint64_t* a, uint64_t c, long index) { 825 | for (long i = 0; i < N; ++i) { 826 | addMod(res[i], a[i], c, qVec[index]); 827 | } 828 | } 829 | 830 | void Context::piAddConst(uint64_t* res, uint64_t* a, uint64_t c, long index) { 831 | for (long i = 0; i < N; ++i) { 832 | addMod(res[i], a[i], c, pVec[index]); 833 | } 834 | } 835 | 836 | void Context::addConst(uint64_t* res, uint64_t* a, uint64_t c, long l, long k) { 837 | for (long i = 0; i < l; ++i) { 838 | uint64_t* ai = a + (i << logN); 839 | uint64_t* resi = res + (i << logN); 840 | qiAddConst(resi, ai, c, i); 841 | } 842 | 843 | for (long i = l; i < l + k; ++i) { 844 | uint64_t* ai = a + (i << logN); 845 | uint64_t* resi = res + (i << logN); 846 | piAddConst(resi, ai, c, i - l); 847 | } 848 | } 849 | 850 | void Context::qiAddConstAndEqual(uint64_t* a, uint64_t c, long index) { 851 | for (long i = 0; i < N; ++i) { 852 | addMod(a[i], a[i], c, qVec[index]); 853 | } 854 | } 855 | 856 | void Context::piAddConstAndEqual(uint64_t* a, uint64_t c, long index) { 857 | for (long i = 0; i < N; ++i) { 858 | addMod(a[i], a[i], c, pVec[index]); 859 | } 860 | } 861 | 862 | void Context::addConstAndEqual(uint64_t* a, uint64_t c, long l, long k) { 863 | for (long i = 0; i < l; ++i) { 864 | uint64_t* ai = a + (i << logN); 865 | qiAddConstAndEqual(ai, c, i); 866 | } 867 | 868 | for (long i = l; i < l + k; ++i) { 869 | uint64_t* ai = a + (i << logN); 870 | piAddConstAndEqual(ai, c, i - l); 871 | } 872 | } 873 | 874 | void Context::qiSubConst(uint64_t* res, uint64_t* a, uint64_t c, long index) { 875 | for (long i = 0; i < N; ++i) { 876 | subMod(res[i], a[i], c, qVec[index]); 877 | } 878 | } 879 | 880 | void Context::piSubConst(uint64_t* res, uint64_t* a, uint64_t c, long index) { 881 | for (long i = 0; i < N; ++i) { 882 | subMod(res[i], a[i], c, pVec[index]); 883 | } 884 | } 885 | 886 | void Context::subConst(uint64_t* res, uint64_t* a, uint64_t c, long l, long k) { 887 | for (long i = 0; i < l; ++i) { 888 | uint64_t* ai = a + (i << logN); 889 | uint64_t* resi = res + (i << logN); 890 | qiSubConst(resi, ai, c, i); 891 | } 892 | 893 | for (long i = l; i < l + k; ++i) { 894 | uint64_t* ai = a + (i << logN); 895 | uint64_t* resi = res + (i << logN); 896 | piSubConst(resi, ai, c, i - l); 897 | } 898 | } 899 | 900 | void Context::qiSubConstAndEqual(uint64_t* a, uint64_t c, long index) { 901 | for (long i = 0; i < N; ++i) { 902 | subMod(a[i], a[i], c, qVec[index]); 903 | } 904 | } 905 | 906 | void Context::piSubConstAndEqual(uint64_t* a, uint64_t c, long index) { 907 | for (long i = 0; i < N; ++i) { 908 | subMod(a[i], a[i], c, pVec[index]); 909 | } 910 | } 911 | 912 | void Context::subConstAndEqual(uint64_t* a, uint64_t c, long l, long k) { 913 | for (long i = 0; i < l; ++i) { 914 | uint64_t* ai = a + (i << logN); 915 | qiSubConstAndEqual(ai, c, i); 916 | } 917 | 918 | for (long i = l; i < l + k; ++i) { 919 | uint64_t* ai = a + (i << logN); 920 | piSubConstAndEqual(ai, c, i - l); 921 | } 922 | } 923 | 924 | void Context::qiAdd(uint64_t* res, uint64_t* a, uint64_t* b, long index) { 925 | for (long i = 0; i < N; ++i) { 926 | addMod(res[i], a[i], b[i], qVec[index]); 927 | } 928 | } 929 | 930 | void Context::piAdd(uint64_t* res, uint64_t* a, uint64_t* b, long index) { 931 | for (long i = 0; i < N; ++i) { 932 | addMod(res[i], a[i], b[i], pVec[index]); 933 | } 934 | } 935 | 936 | void Context::add(uint64_t* res, uint64_t* a, uint64_t* b, long l, long k) { 937 | for (long i = 0; i < l; ++i) { 938 | uint64_t* ai = a + (i << logN); 939 | uint64_t* bi = b + (i << logN); 940 | uint64_t* resi = res + (i << logN); 941 | qiAdd(resi, ai, bi, i); 942 | } 943 | 944 | for (long i = l; i < l + k; ++i) { 945 | uint64_t* ai = a + (i << logN); 946 | uint64_t* bi = b + (i << logN); 947 | uint64_t* resi = res + (i << logN); 948 | piAdd(resi, ai, bi, i - l); 949 | } 950 | } 951 | 952 | void Context::qiAddAndEqual(uint64_t* a, uint64_t* b, long index) { 953 | for (long i = 0; i < N; ++i) { 954 | addMod(a[i], a[i], b[i], qVec[index]); 955 | } 956 | } 957 | 958 | void Context::piAddAndEqual(uint64_t* a, uint64_t* b, long index) { 959 | for (long i = 0; i < N; ++i) { 960 | addMod(a[i], a[i], b[i], pVec[index]); 961 | } 962 | } 963 | 964 | void Context::addAndEqual(uint64_t* a, uint64_t* b, long l, long k) { 965 | for (long i = 0; i < l; ++i) { 966 | uint64_t* ai = a + (i << logN); 967 | uint64_t* bi = b + (i << logN); 968 | qiAddAndEqual(ai, bi, i); 969 | } 970 | 971 | for (long i = l; i < l + k; ++i) { 972 | uint64_t* ai = a + (i << logN); 973 | uint64_t* bi = b + (i << logN); 974 | piAddAndEqual(ai, bi, i - l); 975 | } 976 | } 977 | 978 | void Context::qiSub(uint64_t* res, uint64_t* a, uint64_t* b, long index) { 979 | for (long i = 0; i < N; ++i) { 980 | subMod(res[i], a[i], b[i], qVec[index]); 981 | } 982 | } 983 | 984 | void Context::piSub(uint64_t* res, uint64_t* a, uint64_t* b, long index) { 985 | for (long i = 0; i < N; ++i) { 986 | subMod(res[i], a[i], b[i], pVec[index]); 987 | } 988 | } 989 | 990 | void Context::sub(uint64_t* res, uint64_t* a, uint64_t* b, long l, long k) { 991 | for (long i = 0; i < l; ++i) { 992 | uint64_t* ai = a + (i << logN); 993 | uint64_t* bi = b + (i << logN); 994 | uint64_t* resi = res + (i << logN); 995 | qiSub(resi, ai, bi, i); 996 | } 997 | 998 | for (long i = l; i < l + k; ++i) { 999 | uint64_t* ai = a + (i << logN); 1000 | uint64_t* bi = b + (i << logN); 1001 | uint64_t* resi = res + (i << logN); 1002 | piSub(resi, ai, bi, i - l); 1003 | } 1004 | } 1005 | 1006 | void Context::qiSubAndEqual(uint64_t* a, uint64_t* b, long index) { 1007 | for (long i = 0; i < N; ++i) { 1008 | subMod(a[i], a[i], b[i], qVec[index]); 1009 | } 1010 | } 1011 | 1012 | void Context::piSubAndEqual(uint64_t* a, uint64_t* b, long index) { 1013 | for (long i = 0; i < N; ++i) { 1014 | subMod(a[i], a[i], b[i], pVec[index]); 1015 | } 1016 | } 1017 | 1018 | void Context::subAndEqual(uint64_t* a, uint64_t* b, long l, long k) { 1019 | for (long i = 0; i < l; ++i) { 1020 | uint64_t* ai = a + (i << logN); 1021 | uint64_t* bi = b + (i << logN); 1022 | qiSubAndEqual(ai, bi, i); 1023 | } 1024 | 1025 | for (long i = l; i < l + k; ++i) { 1026 | uint64_t* ai = a + (i << logN); 1027 | uint64_t* bi = b + (i << logN); 1028 | piSubAndEqual(ai, bi, i - l); 1029 | } 1030 | } 1031 | 1032 | void Context::qiSub2AndEqual(uint64_t* a, uint64_t* b, long index) { 1033 | for (long i = 0; i < N; ++i) { 1034 | subMod(b[i], a[i], b[i], qVec[index]); 1035 | } 1036 | } 1037 | 1038 | void Context::piSub2AndEqual(uint64_t* a, uint64_t* b, long index) { 1039 | for (long i = 0; i < N; ++i) { 1040 | subMod(b[i], a[i], b[i], pVec[index]); 1041 | } 1042 | } 1043 | 1044 | void Context::sub2AndEqual(uint64_t* a, uint64_t* b, long l, long k) { 1045 | for (long i = 0; i < l; ++i) { 1046 | uint64_t* ai = a + (i << logN); 1047 | uint64_t* bi = b + (i << logN); 1048 | qiSub2AndEqual(ai, bi, i); 1049 | } 1050 | 1051 | for (long i = l; i < l + k; ++i) { 1052 | uint64_t* ai = a + (i << logN); 1053 | uint64_t* bi = b + (i << logN); 1054 | piSub2AndEqual(ai, bi, i - l); 1055 | } 1056 | } 1057 | 1058 | void Context::qiMulConst(uint64_t* res, uint64_t* a, uint64_t cnst, long index) { 1059 | for (long i = 0; i < N; ++i) { 1060 | mulModBarrett(res[i], a[i], cnst, qVec[index], qrVec[index], qTwok[index]); 1061 | } 1062 | } 1063 | 1064 | void Context::piMulConst(uint64_t* res, uint64_t* a, uint64_t cnst, long index) { 1065 | for (long i = 0; i < N; ++i) { 1066 | mulModBarrett(res[i], a[i], cnst, pVec[index], prVec[index], pTwok[index]); 1067 | } 1068 | } 1069 | 1070 | void Context::mulConst(uint64_t* res, uint64_t* a, uint64_t cnst, long l, long k) { 1071 | for (long i = 0; i < l; ++i) { 1072 | uint64_t* ai = a + (i << logN); 1073 | uint64_t* resi = res + (i << logN); 1074 | qiMulConst(resi, ai, cnst, i); 1075 | } 1076 | 1077 | for (long i = l; i < l + k; ++i) { 1078 | uint64_t* ai = a + (i << logN); 1079 | uint64_t* resi = res + (i << logN); 1080 | piMulConst(resi, ai, cnst, i - l); 1081 | } 1082 | } 1083 | 1084 | void Context::qiMulConstAndEqual(uint64_t* res, uint64_t cnst, long index) { 1085 | for (long i = 0; i < N; ++i) { 1086 | mulModBarrett(res[i], res[i], cnst, qVec[index], qrVec[index], qTwok[index]); 1087 | } 1088 | } 1089 | 1090 | void Context::piMulConstAndEqual(uint64_t* res, uint64_t cnst, long index) { 1091 | for (long i = 0; i < N; ++i) { 1092 | mulModBarrett(res[i], res[i], cnst, pVec[index], prVec[index], pTwok[index]); 1093 | } 1094 | } 1095 | 1096 | void Context::mulConstAndEqual(uint64_t* a, uint64_t cnst, long l, long k) { 1097 | for (long i = 0; i < l; ++i) { 1098 | uint64_t* ai = a + (i << logN); 1099 | qiMulConstAndEqual(ai, cnst, i); 1100 | } 1101 | 1102 | for (long i = l; i < l + k; ++i) { 1103 | uint64_t* ai = a + (i << logN); 1104 | piMulConstAndEqual(ai, cnst, i - l); 1105 | } 1106 | } 1107 | 1108 | void Context::qiMul(uint64_t* res, uint64_t* a, uint64_t* b, long index) { 1109 | for (long i = 0; i < N; ++i) { 1110 | mulModBarrett(res[i], a[i], b[i], qVec[index], qrVec[index], qTwok[index]); 1111 | } 1112 | } 1113 | 1114 | void Context::piMul(uint64_t* res, uint64_t* a, uint64_t* b, long index) { 1115 | for (long i = 0; i < N; ++i) { 1116 | mulModBarrett(res[i], a[i], b[i], pVec[index], prVec[index], pTwok[index]); 1117 | } 1118 | } 1119 | 1120 | void Context::mul(uint64_t* res, uint64_t* a, uint64_t* b, long l, long k) { 1121 | for (long i = 0; i < l; ++i) { 1122 | uint64_t* ai = a + (i << logN); 1123 | uint64_t* bi = b + (i << logN); 1124 | uint64_t* resi = res + (i << logN); 1125 | qiMul(resi, ai, bi, i); 1126 | } 1127 | 1128 | for (long i = l; i < l + k; ++i) { 1129 | uint64_t* ai = a + (i << logN); 1130 | uint64_t* bi = b + (i << logN); 1131 | uint64_t* resi = res + (i << logN); 1132 | piMul(resi, ai, bi, i - l); 1133 | } 1134 | } 1135 | 1136 | void Context::mulKey(uint64_t* res, uint64_t* a, uint64_t* key, long l) { 1137 | for (long i = 0; i < l; ++i) { 1138 | uint64_t* ai = a + (i << logN); 1139 | uint64_t* keyi = key + (i << logN); 1140 | uint64_t* resi = res + (i << logN); 1141 | qiMul(resi, ai, keyi, i); 1142 | } 1143 | 1144 | for (long i = l; i < l + K; ++i) { 1145 | uint64_t* ai = a + (i << logN); 1146 | uint64_t* keyi = key + ((i - l + L) << logN); 1147 | uint64_t* resi = res + (i << logN); 1148 | piMul(resi, ai, keyi, i - l); 1149 | } 1150 | } 1151 | 1152 | void Context::qiMulAndEqual(uint64_t* a, uint64_t* b, long index) { 1153 | for (long i = 0; i < N; ++i) { 1154 | mulModBarrett(a[i], a[i], b[i], qVec[index], qrVec[index], qTwok[index]); 1155 | } 1156 | } 1157 | 1158 | void Context::piMulAndEqual(uint64_t* a, uint64_t* b, long index) { 1159 | for (long i = 0; i < N; ++i) { 1160 | mulModBarrett(a[i], a[i], b[i], pVec[index], prVec[index], pTwok[index]); 1161 | } 1162 | } 1163 | 1164 | void Context::mulAndEqual(uint64_t* a, uint64_t* b, long l, long k) { 1165 | for (long i = 0; i < l; ++i) { 1166 | uint64_t* ai = a + (i << logN); 1167 | uint64_t* bi = b + (i << logN); 1168 | qiMulAndEqual(ai, bi, i); 1169 | } 1170 | 1171 | for (long i = l; i < l + k; ++i) { 1172 | uint64_t* ai = a + (i << logN); 1173 | uint64_t* bi = b + (i << logN); 1174 | piMulAndEqual(ai, bi, i - l); 1175 | } 1176 | } 1177 | 1178 | void Context::qiSquare(uint64_t* res, uint64_t* a, long index) { 1179 | for (long i = 0; i < N; ++i) { 1180 | mulModBarrett(res[i], a[i], a[i], qVec[index], qrVec[index], qTwok[index]); 1181 | } 1182 | } 1183 | 1184 | void Context::piSquare(uint64_t* res, uint64_t* a, long index) { 1185 | for (long i = 0; i < N; ++i) { 1186 | mulModBarrett(res[i], a[i], a[i], pVec[index], prVec[index], pTwok[index]); 1187 | } 1188 | } 1189 | 1190 | void Context::square(uint64_t* res, uint64_t* a, long l, long k) { 1191 | for (long i = 0; i < l; ++i) { 1192 | uint64_t* ai = a + (i << logN); 1193 | uint64_t* resi = res + (i << logN); 1194 | qiSquare(resi, ai, i); 1195 | } 1196 | 1197 | for (long i = l; i < l + k; ++i) { 1198 | uint64_t* ai = a + (i << logN); 1199 | uint64_t* resi = res + (i << logN); 1200 | piSquare(resi, ai, i - l); 1201 | } 1202 | } 1203 | 1204 | void Context::qiSquareAndEqual(uint64_t* a, long index) { 1205 | for (long i = 0; i < N; ++i) { 1206 | mulModBarrett(a[i], a[i], a[i], qVec[index], qrVec[index], qTwok[index]); 1207 | } 1208 | } 1209 | 1210 | void Context::piSquareAndEqual(uint64_t* a, long index) { 1211 | for (long i = 0; i < N; ++i) { 1212 | mulModBarrett(a[i], a[i], a[i], pVec[index], prVec[index], pTwok[index]); 1213 | } 1214 | } 1215 | 1216 | void Context::squareAndEqual(uint64_t* a, long l, long k) { 1217 | for (long i = 0; i < l; ++i) { 1218 | uint64_t* ai = a + (i << logN); 1219 | qiSquare(ai, ai, i); 1220 | } 1221 | 1222 | for (long i = l; i < l + k; ++i) { 1223 | uint64_t* ai = a + (i << logN); 1224 | piSquare(ai, ai, i - l); 1225 | } 1226 | } 1227 | 1228 | void Context::evalAndEqual(uint64_t* a, long l) { 1229 | INTTAndEqual(a, l); 1230 | for (long i = 0; i < l; ++i) { 1231 | uint64_t* ai = a + (i << logN); 1232 | for (long n = 0; n < N; ++n) { 1233 | mulModBarrett(ai[n], ai[n], PModq[i], qVec[i], qrVec[i], qTwok[i]); 1234 | } 1235 | } 1236 | NTTAndEqual(a, l); 1237 | } 1238 | 1239 | void Context::raise(uint64_t* res, uint64_t* a, long l) { 1240 | //TODO implement method 1241 | 1242 | } 1243 | 1244 | void Context::raiseAndEqual(uint64_t*& a, long l) { 1245 | uint64_t* ra = new uint64_t[(l + K) << logN](); 1246 | copy(a, a + (l << logN), ra); 1247 | 1248 | INTTAndEqual(a, l); 1249 | 1250 | uint64_t* tmp3 = new uint64_t[l << logN]; 1251 | for(long i = 0; i < l; ++i) { 1252 | uint64_t* tmp3i = tmp3 + (i << logN); 1253 | uint64_t* ai = a + (i << logN); 1254 | for(long n = 0; n < N; ++n) { 1255 | mulModBarrett(tmp3i[n], ai[n], qHatInvModq[l - 1][i], qVec[i], qrVec[i], qTwok[i]); 1256 | } 1257 | } 1258 | for (long k = 0; k < K; ++k) { 1259 | uint64_t* rak = ra + ((l + k) << logN); 1260 | for (long n = 0; n < N; ++n) { 1261 | uint64_t tt = tmp3[n]; 1262 | unsigned __int128 sum = static_cast(tt) * qHatModp[l - 1][0][k]; 1263 | for (long i = 1; i < l; ++i) { 1264 | tt = tmp3[n + (i << logN)]; 1265 | sum += static_cast(tt) * qHatModp[l - 1][i][k]; 1266 | } 1267 | modBarrett(rak[n], sum, pVec[k], prVec[k], pTwok[k]); 1268 | } 1269 | } 1270 | NTTAndEqual(ra + (l << logN), 0, K); 1271 | 1272 | delete[] a; 1273 | a = ra; 1274 | 1275 | } 1276 | 1277 | void Context::back(uint64_t* res, uint64_t* a, long l) { 1278 | uint64_t* tmp = new uint64_t[(l + K) << logN]; 1279 | copy(a, a + ((l + K) << logN), tmp); 1280 | INTTAndEqual(tmp, l, K); 1281 | uint64_t* tmp3 = new uint64_t[K << logN]; 1282 | for(long k = 0; k < K; k++) { 1283 | uint64_t* tmpk = tmp + ((k + l) << logN); 1284 | uint64_t* tmp3k = tmp3 + (k << logN); 1285 | for(long n = 0; n < N; ++n) { 1286 | mulModBarrett(tmp3k[n], tmpk[n], pHatInvModp[k], pVec[k], prVec[k], pTwok[k]); 1287 | } 1288 | } 1289 | for (long i = 0; i < l; ++i) { 1290 | uint64_t* resi = res + (i << logN); 1291 | uint64_t* tmpi = tmp + (i << logN); 1292 | 1293 | for (long n = 0; n < N; ++n) { 1294 | uint64_t tt = tmp3[n]; 1295 | unsigned __int128 sum = static_cast(tt) * pHatModq[0][i]; 1296 | for (long k = 1; k < K; ++k) { 1297 | tt = tmp3[n + (k << logN)]; 1298 | sum += static_cast(tt) * pHatModq[k][i]; 1299 | } 1300 | modBarrett(resi[n], sum, qVec[i], qrVec[i], qTwok[i]); 1301 | subMod(resi[n], tmpi[n], resi[n], qVec[i]); 1302 | mulModBarrett(resi[n], resi[n], PInvModq[i], qVec[i], qrVec[i], qTwok[i]); 1303 | } 1304 | } 1305 | 1306 | delete[] tmp; 1307 | 1308 | NTTAndEqual(res, l); 1309 | } 1310 | 1311 | void Context::backAndEqual(uint64_t*& a, long l) { 1312 | 1313 | INTTAndEqual(a, l, K); 1314 | 1315 | uint64_t* ra = new uint64_t[l << logN](); 1316 | uint64_t* tmp3 = new uint64_t[K << logN]; 1317 | 1318 | for(long k = 0; k < K; k++) { 1319 | uint64_t* tmp3k = tmp3 + (k << logN); 1320 | uint64_t* ak = a + ((k + l) << logN); 1321 | for(long n = 0; n < N; ++n) { 1322 | mulModBarrett(tmp3k[n], ak[n], pHatInvModp[k], pVec[k], prVec[k], pTwok[k]); 1323 | } 1324 | } 1325 | 1326 | for (long i = 0; i < l; ++i) { 1327 | uint64_t* rai = ra + (i << logN); 1328 | uint64_t* ai = a + (i << logN); 1329 | for (long n = 0; n < N; ++n) { 1330 | uint64_t tt = tmp3[n]; 1331 | unsigned __int128 sum = static_cast(tt) * pHatModq[0][i]; 1332 | for (long k = 1; k < K; ++k) { 1333 | tt = tmp3[n + (k << logN)]; 1334 | sum += static_cast(tt) * pHatModq[k][i]; 1335 | } 1336 | modBarrett(rai[n], sum, qVec[i], qrVec[i], qTwok[i]); 1337 | subMod(rai[n], ai[n], rai[n], qVec[i]); 1338 | mulModBarrett(rai[n], rai[n], PInvModq[i], qVec[i], qrVec[i], qTwok[i]); 1339 | } 1340 | } 1341 | NTTAndEqual(ra, l); 1342 | delete[] a; 1343 | a = ra; 1344 | } 1345 | 1346 | void Context::reScale(uint64_t* res, uint64_t* a, long l) { 1347 | //TODO implement method 1348 | } 1349 | 1350 | void Context::reScaleAndEqual(uint64_t*& a, long l) { 1351 | uint64_t* ra = new uint64_t[(l - 1) << logN](); 1352 | uint64_t* al = a + ((l - 1) << logN); 1353 | qiINTTAndEqual(al, l - 1); 1354 | for (long i = 0; i < l - 1; ++i) { 1355 | uint64_t* rai = ra + (i << logN); 1356 | uint64_t* ai = a + (i << logN); 1357 | 1358 | copy(al, al + N, rai); 1359 | for (long n = 0; n < N; ++n) { 1360 | modBarrett(rai[n], al[n], qVec[i], qrVec[i], qTwok[i]); 1361 | } 1362 | qiNTTAndEqual(rai, i); 1363 | 1364 | 1365 | for (long n = 0; n < N; ++n) { 1366 | subMod(rai[n], ai[n], rai[n], qVec[i]); 1367 | mulModBarrett(rai[n], rai[n], qInvModq[l - 1][i], qVec[i], qrVec[i], qTwok[i]); 1368 | } 1369 | } 1370 | delete[] a; 1371 | a = ra; 1372 | } 1373 | 1374 | void Context::modDownAndEqual(uint64_t*& a, long l, long dl) { 1375 | uint64_t* ra = new uint64_t[(l - dl) << logN](); 1376 | copy(a, a + ((l - dl) << logN), ra); 1377 | delete[] a; 1378 | a = ra; 1379 | } 1380 | 1381 | uint64_t* Context::modDown(uint64_t* a, long l, long dl) { 1382 | uint64_t* ra = new uint64_t[(l - dl) << logN](); 1383 | copy(a, a + ((l - dl) << logN), ra); 1384 | return ra; 1385 | } 1386 | 1387 | void Context::leftRot(uint64_t* res, uint64_t* a, long l, long rotSlots) { 1388 | // long idx = rotSlots % Nh; 1389 | // for (long n = 0; n < N; ++n) { 1390 | // uint32_t reversed = bitReverse(static_cast(n)) >> (32 - logN); 1391 | // uint64_t index_raw = rotGroup[idx] * (2 * reversed + 1); 1392 | // index_raw &= (M - 1); 1393 | // long index = bitReverse((static_cast(index_raw) - 1) >> 1) >> (32 - logN); 1394 | // for (long i = 0; i < l; ++i) { 1395 | // res[n + (i << logN)] = a[index + (i << logN)]; 1396 | // } 1397 | // } 1398 | 1399 | uint64_t* tmp = new uint64_t[l << logN](); 1400 | copy(a, a + (l << logN), tmp); 1401 | INTTAndEqual(tmp, l); 1402 | long pow = rotGroup[rotSlots]; 1403 | for (long i = 0; i < l; ++i) { 1404 | uint64_t* resi = res + (i << logN); 1405 | uint64_t* tmpi = tmp + (i << logN); 1406 | for (long n = 0; n < N; ++n) { 1407 | long npow = n * pow; 1408 | long shift = npow % M; 1409 | if(shift < N) { 1410 | resi[shift] = tmpi[n]; 1411 | } else { 1412 | resi[shift - N] = qVec[i] - tmpi[n]; 1413 | } 1414 | } 1415 | } 1416 | NTTAndEqual(res, l); 1417 | } 1418 | 1419 | void Context::leftRotAndEqual(uint64_t* a, long l, long rotSlots) { 1420 | uint64_t* tmp = new uint64_t[l << logN]; 1421 | copy(a, a + (l << logN), tmp); 1422 | long idx = rotSlots % Nh; 1423 | for (long n = 0; n < N; ++n) { 1424 | uint32_t reversed = bitReverse(static_cast(n)) >> (32 - logN); 1425 | uint64_t index_raw = rotGroup[idx] * (2 * reversed + 1); 1426 | index_raw &= M - 1; 1427 | uint32_t index = bitReverse((static_cast(index_raw) - 1) >> 1) >> (32 - logN); 1428 | for (long i = 0; i < l; ++i) { 1429 | a[n + (i << logN)] = tmp[index + (i << logN)]; 1430 | } 1431 | } 1432 | // INTTAndEqual(tmp, l); 1433 | // long pow = rotGroup[rotSlots]; 1434 | // for (long i = 0; i < l; ++i) { 1435 | // uint64_t* ai = a + (i << logN); 1436 | // uint64_t* tmpi = tmp + (i << logN); 1437 | // for (long n = 0; n < N; ++n) { 1438 | // long jpow = n * pow; 1439 | // long shift = jpow % M; 1440 | // if(shift < N) { 1441 | // ai[shift] = tmpi[n]; 1442 | // } else { 1443 | // ai[shift - N] = qVec[i] - tmpi[n]; 1444 | // } 1445 | // } 1446 | // } 1447 | // NTTAndEqual(a, l); 1448 | } 1449 | 1450 | void Context::conjugate(uint64_t* res, uint64_t* a, long l) { 1451 | for (long i = 0; i < l; ++i) { 1452 | uint64_t* resi = res + (i << logN); 1453 | uint64_t* ai = a + (i << logN); 1454 | for (int n = 0; n < N; ++n) { 1455 | resi[n] = ai[N - 1 - n]; 1456 | } 1457 | } 1458 | } 1459 | 1460 | void Context::conjugateAndEqual(uint64_t* a, long l) { 1461 | for (long i = 0; i < l; ++i) { 1462 | uint64_t* ai = a + (i << logN); 1463 | for (int n = 0; n < N; ++n) { 1464 | swap(ai[n], ai[N - 1 - n]); 1465 | } 1466 | } 1467 | } 1468 | 1469 | void Context::mulByMonomial(uint64_t* res, uint64_t* a, long l, long mdeg) { 1470 | for (long i = 0; i < l; ++i) { 1471 | uint64_t* resi = res + (i << logN); 1472 | uint64_t* ai = a + (i << logN); 1473 | for (long n = 0; n < N; ++n) { 1474 | mulModBarrett(resi[n], ai[n], qRootPows[i][n], qVec[i], qrVec[i], qTwok[i]); 1475 | } 1476 | } 1477 | } 1478 | 1479 | void Context::mulByMonomialAndEqual(uint64_t* a, long l, long mdeg) { 1480 | 1481 | } 1482 | 1483 | void Context::sampleGauss(uint64_t* res, long l, long k) { 1484 | static long const bignum = 0xfffffff; 1485 | for (long i = 0; i < N; i += 2) { 1486 | double r1 = (1 + (uint64_t)rand() % bignum) / ((double) bignum + 1); 1487 | double r2 = (1 + (uint64_t)rand() % bignum) / ((double) bignum + 1); 1488 | double theta = 2 * M_PI * r1; 1489 | double rr = sqrt(-2.0 * log(r2)) * sigma; 1490 | 1491 | long g1 = floor(rr * cos(theta) + 0.5); 1492 | long g2 = floor(rr * sin(theta) + 0.5); 1493 | 1494 | for (long j = 0; j < l; ++j) { 1495 | uint64_t* resj = res + (j << logN); 1496 | resj[i] = g1 >= 0 ? g1 : qVec[j] + g1; 1497 | resj[i + 1] = g2 >= 0 ? g2 : qVec[j] + g2; 1498 | } 1499 | for (long j = 0; j < k; ++j) { 1500 | uint64_t* resj = res + ((j + l) << logN); 1501 | resj[i] = g1 >= 0 ? g1 : pVec[j] + g1; 1502 | resj[i + 1] = g2 >= 0 ? g2 : pVec[j] + g2; 1503 | } 1504 | } 1505 | } 1506 | 1507 | void Context::sampleZO(uint64_t* res, long s, long l, long k) { 1508 | for (long i = 0; i < N; ++i) { 1509 | long zo = (rand() % 2) == 0 ? 0 : (rand() % 2) ? 1 : -1; 1510 | for (long j = 0; j < l; ++j) { 1511 | uint64_t* resj = res + (j << logN); 1512 | resj[i] = zo >= 0 ? zo : qVec[j] + zo; 1513 | } 1514 | for (long j = 0; j < k; ++j) { 1515 | uint64_t* resj = res + ((j + l) << logN); 1516 | resj[i] = zo >= 0 ? zo : pVec[j] + zo; 1517 | } 1518 | } 1519 | } 1520 | 1521 | void Context::sampleUniform(uint64_t* res, long l, long k) { 1522 | for (long j = 0; j < l; ++j) { 1523 | uint64_t* resj = res + (j << logN); 1524 | for (long n = 0; n < N; ++n) { 1525 | resj[n] = floor(((double) rand() / (RAND_MAX)) * qVec[j]); 1526 | } 1527 | } 1528 | for (long j = 0; j < k; ++j) { 1529 | uint64_t* resj = res + ((j + l) << logN); 1530 | for (long n = 0; n < N; ++n) { 1531 | resj[n] = floor(((double) rand() / (RAND_MAX)) * pVec[j]); 1532 | } 1533 | } 1534 | } 1535 | 1536 | void Context::sampleHWT(uint64_t* res, long l, long k) { 1537 | long idx = 0; 1538 | while (idx < h) { 1539 | long i = ((double) rand() / (RAND_MAX)) * N; 1540 | if (res[i] == 0) { 1541 | long hwt = (rand() % 2) ? 1 : -1; 1542 | for (long j = 0; j < l; ++j) { 1543 | uint64_t* resj = res + (j << logN); 1544 | resj[i] = hwt >= 0 ? hwt : qVec[j] + hwt; 1545 | } 1546 | for (long j = 0; j < k; ++j) { 1547 | uint64_t* resj = res + ((j + l) << logN); 1548 | resj[i] = hwt >= 0 ? hwt : pVec[j] + hwt; 1549 | } 1550 | idx++; 1551 | } 1552 | } 1553 | } 1554 | 1555 | -------------------------------------------------------------------------------- /src/Context.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #ifndef HEAANNTT_CONTEXT_H_ 10 | #define HEAANNTT_CONTEXT_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "Common.h" 17 | #include "Numb.h" 18 | 19 | #define Q0_BIT_SIZE 61 20 | 21 | using namespace std; 22 | 23 | static string LOGARITHM = "Logarithm"; ///< log(x) 24 | static string EXPONENT = "Exponent"; ///< exp(x) 25 | static string SIGMOID = "Sigmoid"; ///< sigmoid(x) = exp(x) / (1 + exp(x)) 26 | 27 | class Context { 28 | public: 29 | 30 | // Encryption parameters 31 | long logN; ///< Logarithm of Ring Dimension 32 | long logNh; ///< Logarithm of Ring Dimension - 1 33 | long L; ///< Maximum Level that we want to support 34 | long K; ///< The number of special modulus (usually L + 1) 35 | 36 | long N; 37 | long M; 38 | long Nh; 39 | 40 | long logp; 41 | long p; 42 | 43 | long h; 44 | double sigma; 45 | 46 | uint64_t* qVec; 47 | uint64_t* pVec; 48 | 49 | uint64_t* qrVec; // Barrett reduction 50 | uint64_t* prVec; // Barrett recution 51 | 52 | long* qTwok; // Barrett reduction 53 | long* pTwok; // Barrett reduction 54 | 55 | uint64_t* qkVec; // Montgomery reduction 56 | uint64_t* pkVec; // Montgomery reduction 57 | 58 | uint64_t* qdVec; 59 | uint64_t* pdVec; 60 | 61 | uint64_t* qInvVec; 62 | uint64_t* pInvVec; 63 | 64 | uint64_t* qRoots; 65 | uint64_t* pRoots; 66 | 67 | uint64_t* qRootsInv; 68 | uint64_t* pRootsInv; 69 | 70 | uint64_t** qRootPows; 71 | uint64_t** pRootPows; 72 | 73 | uint64_t** qRootPowsInv; 74 | uint64_t** pRootPowsInv; 75 | 76 | uint64_t* NInvModq; 77 | uint64_t* NInvModp; 78 | 79 | uint64_t** qRootScalePows; 80 | uint64_t** pRootScalePows; 81 | 82 | uint64_t** qRootScalePowsOverq; 83 | uint64_t** pRootScalePowsOverp; 84 | 85 | uint64_t** qRootScalePowsInv; 86 | uint64_t** pRootScalePowsInv; 87 | 88 | uint64_t* NScaleInvModq; // [i] 89 | uint64_t* NScaleInvModp; // [k] 90 | 91 | uint64_t** qHatModq; // [l][i] (phat_i)_l mod p_i 92 | uint64_t* pHatModp; // [k] qhat_k mod q_k 93 | 94 | uint64_t** qHatInvModq; // [l][i] (qhat_i)_l^-1 mod q_i 95 | uint64_t* pHatInvModp; // [k] phat_k^-1 mod p_k 96 | 97 | uint64_t*** qHatModp; // [l] [i] [k] (phat_i)_l mod q_k 98 | 99 | uint64_t** pHatModq; // [k][i] qhat_k mod p_i 100 | 101 | uint64_t* PModq; // [i] qprod mod p_i 102 | uint64_t* PInvModq; // [i] qprod mod p_i 103 | 104 | uint64_t** QModp; // [i] qprod mod p_i 105 | uint64_t** QInvModp; // [i] qprod mod p_i 106 | 107 | uint64_t** qInvModq; // [i][j] p_i^-1 mod p_j 108 | 109 | long* rotGroup; ///< precomputed rotation group indexes 110 | 111 | complex* ksiPows; ///< precomputed ksi powers 112 | 113 | map taylorCoeffsMap; ///< precomputed taylor coefficients 114 | 115 | uint64_t* p2coeff; 116 | uint64_t* pccoeff; 117 | uint64_t* p2hcoeff; 118 | 119 | Context(long logN, long logp, long L, long K, long h = 64, double sigma = 3.2); 120 | 121 | void arrayBitReverse(complex* vals, const long size); 122 | void arrayBitReverse(uint64_t* vals, const long size); 123 | 124 | void fft(complex* vals, const long size); 125 | void fftInvLazy(complex* vals, const long size); 126 | void fftInv(complex* vals, const long size); 127 | 128 | void fftSpecial(complex* vals, const long size); 129 | void fftSpecialInvLazy(complex* vals, const long size); 130 | void fftSpecialInv(complex* vals, const long size); 131 | 132 | void encode(uint64_t* ax, complex* vals, long slots, long l); 133 | void encode(uint64_t* ax, double* vals, long slots, long l); 134 | 135 | void encodeSingle(uint64_t* ax, complex& val, long l); 136 | void encodeSingle(uint64_t* ax, double val, long l); 137 | 138 | void decode(uint64_t* ax, complex* vals, long slots, long l); 139 | void decode(uint64_t* ax, double* vals, long slots, long l); 140 | 141 | void decodeSingle(uint64_t* ax, complex& val, long l); 142 | void decodeSingle(uint64_t* ax, double val, long l); 143 | 144 | void qiNTT(uint64_t* res, uint64_t* a, long index); 145 | void piNTT(uint64_t* res, uint64_t* a, long index); 146 | 147 | void NTT(uint64_t* res, uint64_t* a, long l, long k = 0); 148 | 149 | void qiNTTAndEqual(uint64_t* a, long index); 150 | void piNTTAndEqual(uint64_t* a, long index); 151 | 152 | void NTTAndEqual(uint64_t* a, long l, long k = 0); 153 | 154 | void qiINTT(uint64_t* res, uint64_t* a, long index); 155 | void piINTT(uint64_t* res, uint64_t* a, long index); 156 | 157 | void INTT(uint64_t* res, uint64_t* a, long l, long k = 0); 158 | 159 | void qiINTTAndEqual(uint64_t* a, long index); 160 | void piINTTAndEqual(uint64_t* a, long index); 161 | 162 | void INTTAndEqual(uint64_t* a, long l, long k = 0); 163 | 164 | void qiNegate(uint64_t* res, uint64_t* a, long index); 165 | void piNegate(uint64_t* res, uint64_t* a, long index); 166 | 167 | void negate(uint64_t* res, uint64_t* a, long l, long k = 0); 168 | 169 | void qiNegateAndEqual(uint64_t* a, long index); 170 | void piNegateAndEqual(uint64_t* a, long index); 171 | 172 | void negateAndEqual(uint64_t* a, long l, long k = 0); 173 | 174 | void qiAddConst(uint64_t* res, uint64_t* a, uint64_t c, long index); 175 | void piAddConst(uint64_t* res, uint64_t* a, uint64_t c, long index); 176 | 177 | void addConst(uint64_t* res, uint64_t* a, uint64_t c, long l, long k = 0); 178 | 179 | void qiAddConstAndEqual(uint64_t* a, uint64_t c, long index); 180 | void piAddConstAndEqual(uint64_t* a, uint64_t c, long index); 181 | 182 | void addConstAndEqual(uint64_t* a, uint64_t c, long l, long k = 0); 183 | 184 | void qiSubConst(uint64_t* res, uint64_t* a, uint64_t c, long index); 185 | void piSubConst(uint64_t* res, uint64_t* a, uint64_t c, long index); 186 | 187 | void subConst(uint64_t* res, uint64_t* a, uint64_t c, long l, long k = 0); 188 | 189 | void qiSubConstAndEqual(uint64_t* a, uint64_t c, long index); 190 | void piSubConstAndEqual(uint64_t* a, uint64_t c, long index); 191 | 192 | void subConstAndEqual(uint64_t* a, uint64_t c, long l, long k = 0); 193 | 194 | void qiAdd(uint64_t* res, uint64_t* a, uint64_t* b, long index); 195 | void piAdd(uint64_t* res, uint64_t* a, uint64_t* b, long index); 196 | 197 | void add(uint64_t* res, uint64_t* a, uint64_t* b, long l, long k = 0); 198 | 199 | void qiAddAndEqual(uint64_t* a, uint64_t* b, long index); 200 | void piAddAndEqual(uint64_t* a, uint64_t* b, long index); 201 | 202 | void addAndEqual(uint64_t* a, uint64_t* b, long l, long k = 0); 203 | 204 | void qiSub(uint64_t* res, uint64_t* a, uint64_t* b, long index); 205 | void piSub(uint64_t* res, uint64_t* a, uint64_t* b, long index); 206 | 207 | void sub(uint64_t* res, uint64_t* a, uint64_t* b, long l, long k = 0); 208 | 209 | void qiSubAndEqual(uint64_t* a, uint64_t* b, long index); 210 | void piSubAndEqual(uint64_t* a, uint64_t* b, long index); 211 | 212 | void subAndEqual(uint64_t* a, uint64_t* b, long l, long k = 0); 213 | 214 | void qiSub2AndEqual(uint64_t* a, uint64_t* b, long index); 215 | void piSub2AndEqual(uint64_t* a, uint64_t* b, long index); 216 | 217 | void sub2AndEqual(uint64_t* a, uint64_t* b, long l, long k = 0); 218 | 219 | void qiMulConst(uint64_t* res, uint64_t* a, uint64_t cnst, long index); 220 | void piMulConst(uint64_t* res, uint64_t* a, uint64_t cnst, long index); 221 | 222 | void mulConst(uint64_t* res, uint64_t* a, uint64_t cnst, long l, long k = 0); 223 | 224 | void qiMulConstAndEqual(uint64_t* res, uint64_t cnst, long index); 225 | void piMulConstAndEqual(uint64_t* res, uint64_t cnst, long index); 226 | 227 | void mulConstAndEqual(uint64_t* res, uint64_t cnst, long l, long k = 0); 228 | 229 | void qiMul(uint64_t* res, uint64_t* a, uint64_t* b, long index); 230 | void piMul(uint64_t* res, uint64_t* a, uint64_t* b, long index); 231 | 232 | void mul(uint64_t* res, uint64_t* a, uint64_t* b, long l, long k = 0); 233 | 234 | void mulKey(uint64_t* res, uint64_t* a, uint64_t* b, long l); 235 | 236 | void qiMulAndEqual(uint64_t* a, uint64_t* b, long index); 237 | void piMulAndEqual(uint64_t* a, uint64_t* b, long index); 238 | 239 | void mulAndEqual(uint64_t* a, uint64_t* b, long l, long k = 0); 240 | 241 | void qiSquare(uint64_t* res, uint64_t* a, long index); 242 | void piSquare(uint64_t* res, uint64_t* a, long index); 243 | 244 | void square(uint64_t* res, uint64_t* a, long l, long k = 0); 245 | 246 | void qiSquareAndEqual(uint64_t* a, long index); 247 | void piSquareAndEqual(uint64_t* a, long index); 248 | 249 | void squareAndEqual(uint64_t* a, long l, long k = 0); 250 | 251 | void evalAndEqual(uint64_t* a, long l); 252 | 253 | void raiseAndEqual(uint64_t*& a, long l); 254 | void raise(uint64_t* res, uint64_t* a, long l); 255 | 256 | void backAndEqual(uint64_t*& a, long l); 257 | void back(uint64_t* res, uint64_t* a, long l); 258 | 259 | void reScaleAndEqual(uint64_t*& a, long l); 260 | void reScale(uint64_t* res, uint64_t* a, long l); 261 | 262 | void modDownAndEqual(uint64_t*& a, long l, long dl); 263 | uint64_t* modDown(uint64_t* a, long l, long dl); 264 | 265 | void leftRot(uint64_t* res, uint64_t* a, long l, long rotSlots); 266 | void leftRotAndEqual(uint64_t* a, long l, long rotSlots); 267 | 268 | void conjugate(uint64_t* res, uint64_t* a, long l); 269 | void conjugateAndEqual(uint64_t* a, long l); 270 | 271 | void mulByMonomial(uint64_t* res, uint64_t* a, long l, long mdeg); 272 | void mulByMonomialAndEqual(uint64_t* a, long l, long mdeg); 273 | 274 | void sampleGauss(uint64_t* res, long l, long k = 0); 275 | void sampleZO(uint64_t* res, long s, long l, long k = 0); 276 | void sampleUniform(uint64_t* res, long l, long k = 0); 277 | void sampleHWT(uint64_t* res, long l, long k = 0); 278 | 279 | }; 280 | 281 | #endif 282 | -------------------------------------------------------------------------------- /src/EvaluatorUtils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "EvaluatorUtils.h" 14 | 15 | //---------------------------------------------------------------------------------- 16 | // RANDOM REAL AND COMPLEX NUMBERS 17 | //---------------------------------------------------------------------------------- 18 | 19 | double EvaluatorUtils::randomReal(double bound) { 20 | return (double) rand()/(RAND_MAX) * bound; 21 | } 22 | 23 | complex EvaluatorUtils::randomComplex(double bound) { 24 | complex res; 25 | res.real(randomReal(bound)); 26 | res.imag(randomReal(bound)); 27 | return res; 28 | } 29 | 30 | complex EvaluatorUtils::randomCircle(double anglebound) { 31 | double angle = randomReal(anglebound); 32 | complex res; 33 | res.real(cos(angle * 2 * M_PI)); 34 | res.imag(sin(angle * 2 * M_PI)); 35 | return res; 36 | } 37 | 38 | double* EvaluatorUtils::randomRealArray(long size, double bound) { 39 | double* res = new double[size]; 40 | for (long i = 0; i < size; ++i) { 41 | res[i] = randomReal(bound); 42 | } 43 | return res; 44 | } 45 | 46 | complex* EvaluatorUtils::randomComplexArray(long size, double bound) { 47 | complex* res = new complex[size]; 48 | for (long i = 0; i < size; ++i) { 49 | res[i] = randomComplex(bound); 50 | } 51 | return res; 52 | } 53 | 54 | complex* EvaluatorUtils::randomCircleArray(long size, double bound) { 55 | complex* res = new complex[size]; 56 | for (long i = 0; i < size; ++i) { 57 | res[i] = randomCircle(bound); 58 | } 59 | return res; 60 | } 61 | 62 | //---------------------------------------------------------------------------------- 63 | // ROTATIONS 64 | //---------------------------------------------------------------------------------- 65 | 66 | void EvaluatorUtils::leftRotateAndEqual(complex* vals, const long size, const long rotSize) { 67 | long remrotSize = rotSize % size; 68 | if(remrotSize != 0) { 69 | long divisor = gcd(remrotSize, size); 70 | long steps = size / divisor; 71 | for (long i = 0; i < divisor; ++i) { 72 | complex tmp = vals[i]; 73 | long idx = i; 74 | for (long j = 0; j < steps - 1; ++j) { 75 | vals[idx] = vals[(idx + remrotSize) % size]; 76 | idx = (idx + remrotSize) % size; 77 | } 78 | vals[idx] = tmp; 79 | } 80 | } 81 | } 82 | 83 | void EvaluatorUtils::rightRotateAndEqual(complex* vals, const long size, const long rotSize) { 84 | long remrotSize = rotSize % size; 85 | long leftremrotSize = (size - remrotSize) % size; 86 | leftRotateAndEqual(vals, size, leftremrotSize); 87 | } 88 | -------------------------------------------------------------------------------- /src/EvaluatorUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #ifndef HEAAN_EVALUATORUTILS_H_ 10 | #define HEAAN_EVALUATORUTILS_H_ 11 | 12 | #include "Context.h" 13 | 14 | class EvaluatorUtils { 15 | public: 16 | 17 | //---------------------------------------------------------------------------------- 18 | // RANDOM REAL AND COMPLEX NUMBERS 19 | //---------------------------------------------------------------------------------- 20 | 21 | /** 22 | * generate random real value in range (0, bound). 23 | */ 24 | static double randomReal(double bound = 1.0); 25 | 26 | /** 27 | * generate random complex value with both real and imaginary part in range (0, bound). 28 | */ 29 | static complex randomComplex(double bound = 1.0); 30 | 31 | /** 32 | * generate random complex value with norm 1 and angle bound in (0, anglebound) in radiant 33 | */ 34 | static complex randomCircle(double anglebound = 1.0); 35 | 36 | /** 37 | * generate array of random real values in range (0, bound) 38 | */ 39 | static double* randomRealArray(long size, double bound = 1.0); 40 | 41 | /** 42 | * generate array of random complex values with both real and imaginary part in range (0, bound). 43 | */ 44 | static complex* randomComplexArray(long size, double bound = 1.0); 45 | 46 | /** 47 | * generate array of random complex values with norm 1 and angle bound in (0, anglebound) in radiant 48 | */ 49 | static complex* randomCircleArray(long size, double bound = 1.0); 50 | 51 | //---------------------------------------------------------------------------------- 52 | // ROTATIONS 53 | //---------------------------------------------------------------------------------- 54 | 55 | /** 56 | * left indexes rotation of values 57 | * @param[in, out] vals: array of values 58 | * @param[in] size: array size 59 | * @param[in] rotSize: rotation size 60 | */ 61 | static void leftRotateAndEqual(complex* vals, const long size, const long rotSize); 62 | 63 | /** 64 | * right indexes rotation of values 65 | * @param[in, out] vals: array of values 66 | * @param[in] size: array size 67 | * @param[in] rotSize: rotation size 68 | */ 69 | static void rightRotateAndEqual(complex* vals, const long size, const long rotSize); 70 | 71 | }; 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /src/Key.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #include "Key.h" 10 | 11 | Key::Key(uint64_t* ax, uint64_t* bx) : ax(ax), bx(bx) {} 12 | 13 | Key::~Key() {} 14 | 15 | -------------------------------------------------------------------------------- /src/Key.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #ifndef HEAANNTT_KEY_H_ 10 | #define HEAANNTT_KEY_H_ 11 | 12 | #include 13 | 14 | using namespace std; 15 | class Key { 16 | public: 17 | 18 | uint64_t* ax; 19 | uint64_t* bx; 20 | 21 | Key(uint64_t* ax, uint64_t* bx); 22 | 23 | virtual ~Key(); 24 | }; 25 | 26 | #endif /* KEY_H_ */ 27 | -------------------------------------------------------------------------------- /src/Numb.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #include "Numb.h" 10 | 11 | void negate(uint64_t &r, uint64_t a) { 12 | r = -a; 13 | } 14 | 15 | void addMod(uint64_t &r, uint64_t a, uint64_t b, uint64_t m) { 16 | r = (a + b) % m; 17 | } 18 | 19 | void subMod(uint64_t &r, uint64_t a, uint64_t b, uint64_t m) { 20 | r = b % m; 21 | r = (a + m - r) % m; 22 | } 23 | 24 | void mulMod(uint64_t &r, uint64_t a, uint64_t b, uint64_t m) { 25 | unsigned __int128 mul = static_cast(a % m) * (b % m); 26 | mul %= static_cast(m); 27 | r = static_cast(mul); 28 | } 29 | 30 | void mulModBarrett(uint64_t& r, uint64_t a, uint64_t b, uint64_t p, uint64_t pr, long twok) { 31 | unsigned __int128 mul = static_cast(a % p) * (b % p); 32 | modBarrett(r, mul, p, pr, twok); 33 | } 34 | 35 | void modBarrett(uint64_t &r, uint64_t a, uint64_t m, uint64_t mr, long twok) { 36 | unsigned __int128 tmp = static_cast(a) * mr; 37 | tmp >>= twok; 38 | tmp *= m; 39 | tmp = a - tmp; 40 | r = static_cast(tmp); 41 | if(r < m) { 42 | return; 43 | } 44 | else { 45 | r -= m; 46 | return; 47 | } 48 | 49 | } 50 | 51 | void modBarrett(uint64_t &r, unsigned __int128 a, uint64_t m, uint64_t mr, long twok) { 52 | uint64_t atop, abot; 53 | abot = static_cast(a); 54 | atop = static_cast(a >> 64); 55 | unsigned __int128 tmp = static_cast(abot) * mr; 56 | tmp >>= 64; 57 | tmp += static_cast(atop) * mr; 58 | tmp >>= twok - 64; 59 | tmp *= m; 60 | tmp = a - tmp; 61 | r = static_cast(tmp); 62 | if(r >= m) r-= m; 63 | } 64 | 65 | uint64_t invMod(uint64_t x, uint64_t m) { 66 | uint64_t temp = x % m; 67 | if (gcd(temp, m) != 1) { 68 | throw invalid_argument("Inverse doesn't exist!!!"); 69 | } else { 70 | return powMod(temp, m - 2, m); 71 | } 72 | } 73 | 74 | uint64_t powMod(uint64_t x, uint64_t y, uint64_t modulus) { 75 | uint64_t res = 1; 76 | while (y > 0) { 77 | if (y & 1) { 78 | mulMod(res, res, x, modulus); 79 | } 80 | y = y >> 1; 81 | mulMod(x, x, x, modulus); 82 | } 83 | return res; 84 | } 85 | 86 | uint64_t inv(uint64_t x) { 87 | return pow(x, static_cast(-1)); 88 | } 89 | 90 | uint64_t pow(uint64_t x, uint64_t y) { 91 | uint64_t res = 1; 92 | while (y > 0) { 93 | if (y & 1) { 94 | res *= x; 95 | } 96 | y = y >> 1; 97 | x *= x; 98 | } 99 | return res; 100 | } 101 | 102 | uint32_t bitReverse(uint32_t x) { 103 | x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); 104 | x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2)); 105 | x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4)); 106 | x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8)); 107 | return ((x >> 16) | (x << 16)); 108 | } 109 | 110 | uint64_t gcd(uint64_t a, uint64_t b) { 111 | if (a == 0) { 112 | return b; 113 | } 114 | return gcd(b % a, a); 115 | } 116 | 117 | long gcd(long a, long b) { 118 | if (a == 0) { 119 | return b; 120 | } 121 | return gcd(b % a, a); 122 | } 123 | 124 | void findPrimeFactors(set &s, uint64_t number) { 125 | while (number % 2 == 0) { 126 | s.insert(2); 127 | number /= 2; 128 | } 129 | for (uint64_t i = 3; i < sqrt(number); i++) { 130 | while (number % i == 0) { 131 | s.insert(i); 132 | number /= i; 133 | } 134 | } 135 | if (number > 2) { 136 | s.insert(number); 137 | } 138 | } 139 | 140 | uint64_t findPrimitiveRoot(uint64_t modulus) { 141 | set s; 142 | uint64_t phi = modulus - 1; 143 | findPrimeFactors(s, phi); 144 | for (uint64_t r = 2; r <= phi; r++) { 145 | bool flag = false; 146 | for (auto it = s.begin(); it != s.end(); it++) { 147 | if (powMod(r, phi / (*it), modulus) == 1) { 148 | flag = true; 149 | break; 150 | } 151 | } 152 | if (flag == false) { 153 | return r; 154 | } 155 | } 156 | return -1; 157 | } 158 | 159 | uint64_t findMthRootOfUnity(uint64_t M, uint64_t mod) { 160 | uint64_t res; 161 | res = findPrimitiveRoot(mod); 162 | if((mod - 1) % M == 0) { 163 | uint64_t factor = (mod - 1) / M; 164 | res = powMod(res, factor, mod); 165 | return res; 166 | } 167 | else { 168 | return -1; 169 | } 170 | } 171 | 172 | // Miller-Rabin Prime Test // 173 | bool primeTest(uint64_t p) { 174 | if(p < 2) return false; 175 | if(p != 2 && p % 2 == 0) return false; 176 | uint64_t s = p - 1; 177 | while(s % 2 == 0) { 178 | s /= 2; 179 | } 180 | for(long i = 0; i < 200; i++) { 181 | uint64_t temp1 = rand(); 182 | temp1 = (temp1 << 32) | rand(); 183 | temp1 = temp1 % (p - 1) + 1; 184 | uint64_t temp2 = s; 185 | uint64_t mod = powMod(temp1,temp2,p); 186 | while (temp2 != p - 1 && mod != 1 && mod != p - 1) { 187 | mulMod(mod, mod, mod, p); 188 | temp2 *= 2; 189 | } 190 | if (mod != p - 1 && temp2 % 2 == 0) return false; 191 | } 192 | return true; 193 | } 194 | -------------------------------------------------------------------------------- /src/Numb.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #ifndef HEAANNTT_NUMB_H_ 10 | #define HEAANNTT_NUMB_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "Common.h" 19 | 20 | using namespace std; 21 | 22 | void negate(uint64_t& r, uint64_t a); 23 | 24 | void addMod(uint64_t& r, uint64_t a, uint64_t b, uint64_t p); 25 | 26 | void addModAndEqual(uint64_t& a, uint64_t b, uint64_t p); 27 | 28 | void subMod(uint64_t& r, uint64_t a, uint64_t b, uint64_t p); 29 | 30 | void subModAndEqual(uint64_t& a, uint64_t b, uint64_t p); 31 | 32 | void mulMod(uint64_t& r, uint64_t a, uint64_t b, uint64_t p); 33 | 34 | void mulModBarrett(uint64_t& r, uint64_t a, uint64_t b, uint64_t p, uint64_t pr, long twok); 35 | 36 | void modBarrett(uint64_t &r, uint64_t a, uint64_t m, uint64_t mr, long twok); 37 | 38 | void modBarrett(uint64_t &r, unsigned __int128 a, uint64_t m, uint64_t mr, long twok); 39 | 40 | void mulModAndEqual(uint64_t& a, uint64_t b, uint64_t p); 41 | 42 | uint64_t invMod(uint64_t x, uint64_t p); 43 | 44 | uint64_t powMod(uint64_t x, uint64_t y, uint64_t p); 45 | 46 | uint64_t inv(uint64_t x); 47 | 48 | uint64_t pow(uint64_t x, uint64_t y); 49 | 50 | uint32_t bitReverse(uint32_t x); 51 | 52 | uint64_t gcd(uint64_t a, uint64_t b); 53 | 54 | long gcd(long a, long b); 55 | 56 | void findPrimeFactors(set &s, uint64_t number); 57 | 58 | uint64_t findPrimitiveRoot(uint64_t m); 59 | 60 | uint64_t findMthRootOfUnity(uint64_t M, uint64_t p); 61 | 62 | bool primeTest(uint64_t p); 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /src/Plaintext.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #include "Plaintext.h" 10 | 11 | Plaintext::Plaintext() : mx(nullptr), N(0), slots(0), l(0) {} 12 | 13 | Plaintext::Plaintext(uint64_t* mx, long N, long slots, long l) : mx(mx), N(N), slots(slots), l(l) {} 14 | 15 | Plaintext::Plaintext(const Plaintext& ptxt) : N(ptxt.N), slots(ptxt.slots), l(ptxt.l){ 16 | mx = new uint64_t[N * l]; 17 | for (long i = 0; i < N * l; ++i) { 18 | mx[i] = ptxt.mx[i]; 19 | } 20 | } 21 | 22 | Plaintext& Plaintext::operator=(const Plaintext& o) { 23 | if(this == &o) return *this; // handling of self assignment, thanks for your advice, arul. 24 | delete[] mx; 25 | N = o.N; 26 | l = o.l; 27 | slots = o.slots; 28 | mx = new uint64_t[N * l]; 29 | for (long i = 0; i < N * l; ++i) { 30 | mx[i] = o.mx[i]; 31 | } 32 | return *this; 33 | } 34 | -------------------------------------------------------------------------------- /src/Plaintext.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #ifndef HEAANNTT_PLAINTEXT_H_ 10 | #define HEAANNTT_PLAINTEXT_H_ 11 | 12 | #include "Common.h" 13 | 14 | class Plaintext { 15 | 16 | public: 17 | 18 | uint64_t* mx; 19 | 20 | long N; 21 | 22 | long slots; 23 | 24 | long l; 25 | 26 | Plaintext(); 27 | 28 | Plaintext(uint64_t* mx, long N, long slots, long l); 29 | 30 | Plaintext(const Plaintext& ptxt); 31 | 32 | Plaintext& operator=(const Plaintext &o); 33 | 34 | }; 35 | 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/Scheme.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #include "Scheme.h" 10 | 11 | Scheme::Scheme(Context& context) : context(context) {} 12 | 13 | Scheme::Scheme(SecretKey& secretKey, Context& context) : context(context) { 14 | addEncKey(secretKey); 15 | addMultKey(secretKey); 16 | } 17 | 18 | void Scheme::addEncKey(SecretKey& secretKey) { 19 | uint64_t* ex = new uint64_t[context.L << context.logN](); 20 | uint64_t* ax = new uint64_t[context.L << context.logN](); 21 | uint64_t* bx = new uint64_t[context.L << context.logN](); 22 | 23 | context.sampleUniform(ax, context.L); 24 | 25 | context.sampleGauss(ex, context.L); 26 | context.NTTAndEqual(ex, context.L); 27 | 28 | context.mul(bx, ax, secretKey.sx, context.L); 29 | context.sub2AndEqual(ex, bx, context.L); 30 | 31 | delete[] ex; 32 | 33 | keyMap.insert(pair(ENCRYPTION, Key(ax, bx))); 34 | } 35 | 36 | void Scheme::addMultKey(SecretKey& secretKey) { 37 | uint64_t* ex = new uint64_t[(context.L + context.K) << context.logN](); 38 | uint64_t* ax = new uint64_t[(context.L + context.K) << context.logN](); 39 | uint64_t* bx = new uint64_t[(context.L + context.K) << context.logN](); 40 | uint64_t* sxsx = new uint64_t[(context.L + context.K) << context.logN](); 41 | 42 | context.mul(sxsx, secretKey.sx, secretKey.sx, context.L); 43 | 44 | context.evalAndEqual(sxsx, context.L); 45 | 46 | context.sampleGauss(ex, context.L, context.K); 47 | context.NTTAndEqual(ex, context.L, context.K); 48 | 49 | context.addAndEqual(ex, sxsx, context.L); 50 | 51 | context.sampleUniform(ax, context.L, context.K); 52 | context.mul(bx, ax, secretKey.sx, context.L, context.K); 53 | context.sub2AndEqual(ex, bx, context.L, context.K); 54 | 55 | delete[] ex; 56 | delete[] sxsx; 57 | 58 | keyMap.insert(pair(MULTIPLICATION, Key(ax, bx))); 59 | } 60 | 61 | void Scheme::addConjKey(SecretKey& secretKey) { 62 | uint64_t* ex = new uint64_t[(context.L + context.K) << context.logN](); 63 | uint64_t* ax = new uint64_t[(context.L + context.K) << context.logN](); 64 | uint64_t* bx = new uint64_t[(context.L + context.K) << context.logN](); 65 | uint64_t* sxconj = new uint64_t[(context.L + context.K) << context.logN](); 66 | 67 | context.conjugate(sxconj, secretKey.sx, context.L); 68 | context.evalAndEqual(sxconj, context.L); 69 | 70 | context.sampleGauss(ex, context.L, context.K); 71 | context.NTTAndEqual(ex, context.L, context.K); 72 | 73 | context.addAndEqual(ex, sxconj, context.L); 74 | 75 | context.sampleUniform(ax, context.L, context.K); 76 | context.mul(bx, ax, secretKey.sx, context.L, context.K); 77 | context.sub2AndEqual(ex, bx, context.L, context.K); 78 | 79 | delete[] ex; 80 | delete[] sxconj; 81 | 82 | keyMap.insert(pair(CONJUGATION, Key(ax, bx))); 83 | } 84 | 85 | void Scheme::addLeftRotKey(SecretKey& secretKey, long rot) { 86 | uint64_t* ex = new uint64_t[(context.L + context.K) << context.logN](); 87 | uint64_t* ax = new uint64_t[(context.L + context.K) << context.logN](); 88 | uint64_t* bx = new uint64_t[(context.L + context.K) << context.logN](); 89 | uint64_t* sxrot = new uint64_t[(context.L + context.K) << context.logN](); 90 | 91 | context.leftRot(sxrot, secretKey.sx, context.L, rot); 92 | context.evalAndEqual(sxrot, context.L); 93 | 94 | context.sampleGauss(ex, context.L, context.K); 95 | context.NTTAndEqual(ex, context.L, context.K); 96 | 97 | context.addAndEqual(ex, sxrot, context.L); 98 | 99 | context.sampleUniform(ax, context.L, context.K); 100 | context.mul(bx, ax, secretKey.sx, context.L, context.K); 101 | context.sub2AndEqual(ex, bx, context.L, context.K); 102 | 103 | delete[] ex; 104 | delete[] sxrot; 105 | 106 | leftRotKeyMap.insert(pair(rot, Key(ax, bx))); 107 | } 108 | 109 | void Scheme::addLeftRotKeys(SecretKey& secretKey) { 110 | for (long i = 0; i < context.logNh; ++i) { 111 | long idx = 1 << i; 112 | if(leftRotKeyMap.find(idx) == leftRotKeyMap.end()) { 113 | addLeftRotKey(secretKey, idx); 114 | } 115 | } 116 | } 117 | 118 | void Scheme::addRightRotKeys(SecretKey& secretKey) { 119 | for (long i = 0; i < context.logNh; ++i) { 120 | long idx = context.Nh - (1 << i); 121 | if(leftRotKeyMap.find(idx) == leftRotKeyMap.end()) { 122 | addLeftRotKey(secretKey, idx); 123 | } 124 | } 125 | } 126 | 127 | Plaintext Scheme::encode(double* v, long slots, long l) { 128 | uint64_t* m = new uint64_t[l << context.logN](); 129 | context.encode(m, v, slots, l); 130 | return Plaintext(m, context.N, slots, l); 131 | } 132 | 133 | Plaintext Scheme::encode(complex* v, long slots, long l) { 134 | uint64_t* m = new uint64_t[l << context.logN](); 135 | context.encode(m, v, slots, l); 136 | return Plaintext(m, context.N, slots, l); 137 | } 138 | 139 | Plaintext Scheme::encodeSingle(complex val, long l) { 140 | uint64_t* m = new uint64_t[l << context.logN](); 141 | context.encodeSingle(m, val, l); 142 | return Plaintext(m, context.N, 1, l); 143 | } 144 | 145 | complex* Scheme::decode(Plaintext& msg) { 146 | complex* res = new complex[msg.slots](); 147 | context.decode(msg.mx, res, msg.slots, msg.l); 148 | return res; 149 | } 150 | 151 | complex Scheme::decodeSingle(Plaintext& msg) { 152 | complex res; 153 | context.decodeSingle(msg.mx, res, msg.l); 154 | return res; 155 | } 156 | 157 | Ciphertext Scheme::encryptMsg(SecretKey& secretkey, Plaintext& message) { 158 | Ciphertext res; 159 | return res; 160 | } 161 | 162 | 163 | Ciphertext Scheme::encryptMsg(Plaintext& message) { 164 | Key key = keyMap.at(ENCRYPTION); 165 | 166 | uint64_t* ax = new uint64_t[message.l << context.logN](); 167 | uint64_t* bx = new uint64_t[message.l << context.logN](); 168 | uint64_t* vx = new uint64_t[message.l << context.logN](); 169 | uint64_t* ex = new uint64_t[message.l << context.logN](); 170 | 171 | context.sampleZO(vx, context.Nh, message.l); 172 | context.NTTAndEqual(vx, message.l); 173 | 174 | context.mul(ax, vx, key.ax, message.l); 175 | 176 | context.sampleGauss(ex, message.l); 177 | context.NTTAndEqual(ex, message.l); 178 | 179 | context.addAndEqual(ax, ex, message.l); 180 | 181 | context.mul(bx, vx, key.bx, message.l); 182 | 183 | context.sampleGauss(ex, message.l); 184 | context.NTTAndEqual(ex, message.l); 185 | 186 | context.addAndEqual(bx, ex, message.l); 187 | context.addAndEqual(bx, message.mx, message.l); 188 | 189 | return Ciphertext(ax, bx, context.N, message.slots, message.l); 190 | } 191 | 192 | Plaintext Scheme::decryptMsg(SecretKey& secretKey, Ciphertext& cipher) { 193 | uint64_t* mx = new uint64_t[context.N](); 194 | context.mul(mx, cipher.ax, secretKey.sx, 1); 195 | context.addAndEqual(mx, cipher.bx, 1); 196 | 197 | return Plaintext(mx, context.N, cipher.slots, 1); 198 | } 199 | 200 | Ciphertext Scheme::encrypt(double* vals, long slots, long l) { 201 | Plaintext msg = encode(vals, slots, l); 202 | return encryptMsg(msg); 203 | } 204 | 205 | Ciphertext Scheme::encrypt(complex* vals, long slots, long l) { 206 | Plaintext msg = encode(vals, slots, l); 207 | return encryptMsg(msg); 208 | } 209 | 210 | Ciphertext Scheme::encryptSingle(complex val, long l) { 211 | Plaintext msg = encodeSingle(val, l); 212 | return encryptMsg(msg); 213 | } 214 | 215 | complex* Scheme::decrypt(SecretKey& secretKey, Ciphertext& cipher) { 216 | Plaintext msg = decryptMsg(secretKey, cipher); 217 | return decode(msg); 218 | } 219 | 220 | complex Scheme::decryptSingle(SecretKey& secretKey, Ciphertext& cipher) { 221 | Plaintext msg = decryptMsg(secretKey, cipher); 222 | return decodeSingle(msg); 223 | } 224 | 225 | Ciphertext Scheme::negate(Ciphertext& cipher) { 226 | uint64_t* axres = new uint64_t[cipher.l << context.logN]; 227 | uint64_t* bxres = new uint64_t[cipher.l << context.logN]; 228 | 229 | context.negate(axres, cipher.ax, cipher.l); 230 | context.negate(bxres, cipher.bx, cipher.l); 231 | 232 | return Ciphertext(axres, bxres, context.N, cipher.slots, cipher.l); 233 | } 234 | 235 | void Scheme::negateAndEqual(Ciphertext& cipher) { 236 | long shift = 0; 237 | for (long i = 0; i < cipher.l; ++i) { 238 | context.qiNegateAndEqual(cipher.ax + shift, i); 239 | context.qiNegateAndEqual(cipher.bx + shift, i); 240 | shift += context.N; 241 | } 242 | } 243 | 244 | Ciphertext Scheme::add(Ciphertext& cipher1, Ciphertext& cipher2) { 245 | uint64_t* axres = new uint64_t[cipher1.l << context.logN]; 246 | uint64_t* bxres = new uint64_t[cipher1.l << context.logN]; 247 | 248 | context.add(axres, cipher1.ax, cipher2.ax, cipher1.l); 249 | context.add(bxres, cipher1.bx, cipher2.bx, cipher1.l); 250 | 251 | return Ciphertext(axres, bxres, context.N, cipher1.slots, cipher1.l); 252 | } 253 | 254 | void Scheme::addAndEqual(Ciphertext& cipher1, Ciphertext& cipher2) { 255 | if(cipher1.l != cipher2.l) { 256 | throw invalid_argument("Ciphertexts are not comparable"); 257 | } 258 | 259 | context.addAndEqual(cipher1.ax, cipher2.ax, cipher1.l); 260 | context.addAndEqual(cipher1.bx, cipher2.bx, cipher1.l); 261 | } 262 | 263 | Ciphertext Scheme::sub(Ciphertext& cipher1, Ciphertext& cipher2) { 264 | if(cipher1.l != cipher2.l) { 265 | throw invalid_argument("Ciphertexts are not comparable"); 266 | } 267 | 268 | uint64_t* axres = new uint64_t[cipher1.l << context.logN]; 269 | uint64_t* bxres = new uint64_t[cipher1.l << context.logN]; 270 | 271 | context.sub(axres, cipher1.ax, cipher2.ax, cipher1.l); 272 | context.sub(bxres, cipher1.bx, cipher2.bx, cipher1.l); 273 | 274 | return Ciphertext(axres, bxres, context.N, cipher1.slots, cipher1.l); 275 | } 276 | 277 | void Scheme::subAndEqual(Ciphertext& cipher1, Ciphertext& cipher2) { 278 | if(cipher1.l != cipher2.l) { 279 | throw invalid_argument("Ciphertexts are not comparable"); 280 | } 281 | 282 | context.subAndEqual(cipher1.ax, cipher2.ax, cipher1.l); 283 | context.subAndEqual(cipher1.bx, cipher2.bx, cipher1.l); 284 | } 285 | 286 | void Scheme::sub2AndEqual(Ciphertext& cipher1, Ciphertext& cipher2) { 287 | if(cipher1.l != cipher2.l) { 288 | throw invalid_argument("Ciphertexts are not comparable"); 289 | } 290 | 291 | context.sub2AndEqual(cipher1.ax, cipher2.ax, cipher1.l); 292 | context.sub2AndEqual(cipher1.bx, cipher2.bx, cipher1.l); 293 | } 294 | 295 | Ciphertext Scheme::mult(Ciphertext& cipher1, Ciphertext& cipher2) { 296 | uint64_t* axbx1 = new uint64_t[cipher1.l << context.logN](); 297 | uint64_t* axbx2 = new uint64_t[cipher1.l << context.logN](); 298 | 299 | uint64_t* axax = new uint64_t[cipher1.l << context.logN](); 300 | uint64_t* bxbx = new uint64_t[cipher1.l << context.logN](); 301 | 302 | uint64_t* axmult = new uint64_t[(cipher1.l + context.K) << context.logN](); 303 | uint64_t* bxmult = new uint64_t[(cipher1.l + context.K) << context.logN](); 304 | 305 | context.add(axbx1, cipher1.ax, cipher1.bx, cipher1.l); 306 | context.add(axbx2, cipher2.ax, cipher2.bx, cipher2.l); 307 | context.mulAndEqual(axbx1, axbx2, cipher1.l); 308 | context.mul(bxbx, cipher1.bx, cipher2.bx, cipher1.l); 309 | context.mul(axax, cipher1.ax, cipher2.ax, cipher1.l); 310 | 311 | context.raiseAndEqual(axax, cipher1.l); 312 | 313 | Key key = keyMap.at(MULTIPLICATION); 314 | 315 | context.mulKey(axmult, axax, key.ax, cipher1.l); 316 | context.mulKey(bxmult, axax, key.bx, cipher1.l); 317 | 318 | context.backAndEqual(axmult, cipher1.l); 319 | context.backAndEqual(bxmult, cipher1.l); 320 | 321 | context.addAndEqual(axmult, axbx1, cipher1.l); 322 | context.subAndEqual(axmult, bxbx, cipher1.l); 323 | context.subAndEqual(axmult, axax, cipher1.l); 324 | context.addAndEqual(bxmult, bxbx, cipher1.l); 325 | 326 | delete[] axax; 327 | delete[] bxbx; 328 | delete[] axbx1; 329 | delete[] axbx2; 330 | 331 | return Ciphertext(axmult, bxmult, context.N, cipher1.slots, cipher1.l); 332 | } 333 | 334 | void Scheme::multAndEqual(Ciphertext& cipher1, Ciphertext& cipher2) { 335 | 336 | uint64_t* axbx1 = new uint64_t[cipher1.l << context.logN](); 337 | uint64_t* axbx2 = new uint64_t[cipher1.l << context.logN](); 338 | 339 | uint64_t* axax = new uint64_t[cipher1.l << context.logN](); 340 | uint64_t* bxbx = new uint64_t[cipher1.l << context.logN](); 341 | 342 | context.add(axbx1, cipher1.ax, cipher1.bx, cipher1.l); // ax1 + bx1 mod P, 0 mod Q 343 | context.add(axbx2, cipher2.ax, cipher2.bx, cipher2.l); // ax2 + bx2 mod P, 0 mod Q 344 | 345 | context.mulAndEqual(axbx1, axbx2, cipher1.l); // (ax1 + bx1) * (ax2 + bx2) mod P, 0 mod Q 346 | 347 | context.mul(bxbx, cipher1.bx, cipher2.bx, cipher1.l); // bx1 * bx2 mod P, 0 mod Q 348 | context.mul(axax, cipher1.ax, cipher2.ax, cipher1.l); // ax1 * ax2 mod P, 0 mod Q 349 | context.raiseAndEqual(axax, cipher1.l); // ax1 * ax2 mod P, ax1 * ax2 + e * P mod Q 350 | 351 | Key key = keyMap.at(MULTIPLICATION); // kbx - kax * sx = (sxsx * Q + ex mod P, ex mod Q) 352 | 353 | delete[] cipher1.ax; 354 | delete[] cipher1.bx; 355 | 356 | cipher1.ax = new uint64_t[(cipher1.l + context.K) << context.logN](); 357 | cipher1.bx = new uint64_t[(cipher1.l + context.K) << context.logN](); 358 | 359 | context.mulKey(cipher1.ax, axax, key.ax, cipher1.l); 360 | context.mulKey(cipher1.bx, axax, key.bx, cipher1.l); 361 | 362 | context.backAndEqual(cipher1.ax, cipher1.l); 363 | context.backAndEqual(cipher1.bx, cipher1.l); 364 | 365 | context.addAndEqual(cipher1.ax, axbx1, cipher1.l); 366 | context.subAndEqual(cipher1.ax, bxbx, cipher1.l); 367 | context.subAndEqual(cipher1.ax, axax, cipher1.l); 368 | context.addAndEqual(cipher1.bx, bxbx, cipher1.l); 369 | 370 | delete[] axax; 371 | delete[] bxbx; 372 | delete[] axbx1; 373 | delete[] axbx2; 374 | } 375 | 376 | 377 | Ciphertext Scheme::square(Ciphertext& cipher) { 378 | uint64_t* axbx = new uint64_t[cipher.l << context.logN](); 379 | 380 | uint64_t* axax = new uint64_t[cipher.l << context.logN](); 381 | uint64_t* bxbx = new uint64_t[cipher.l << context.logN](); 382 | 383 | uint64_t* axmult = new uint64_t[(cipher.l + context.K) << context.logN](); 384 | uint64_t* bxmult = new uint64_t[(cipher.l + context.K) << context.logN](); 385 | 386 | context.add(axbx, cipher.ax, cipher.bx, cipher.l); // ax1 + bx1 mod P, 0 mod Q 387 | 388 | context.squareAndEqual(axbx, cipher.l); // (ax1 + bx1) * (ax2 + bx2) mod P, 0 mod Q 389 | context.square(bxbx, cipher.bx, cipher.l); 390 | context.square(axax, cipher.ax, cipher.l); 391 | 392 | context.raiseAndEqual(axax, cipher.l); 393 | 394 | Key key = keyMap.at(MULTIPLICATION); 395 | 396 | context.mulKey(axmult, axax, key.ax, cipher.l); 397 | context.mulKey(bxmult, axax, key.bx, cipher.l); 398 | 399 | context.backAndEqual(axmult, cipher.l); 400 | context.backAndEqual(bxmult, cipher.l); 401 | 402 | context.addAndEqual(axmult, axbx, cipher.l); 403 | context.subAndEqual(axmult, bxbx, cipher.l); 404 | context.subAndEqual(axmult, axax, cipher.l); 405 | context.addAndEqual(bxmult, bxbx, cipher.l); 406 | 407 | delete[] axax; 408 | delete[] bxbx; 409 | delete[] axbx; 410 | 411 | return Ciphertext(axmult, bxmult, context.N, cipher.slots, cipher.l); 412 | } 413 | 414 | void Scheme::squareAndEqual(Ciphertext& cipher) { 415 | uint64_t* axbx = new uint64_t[cipher.l << context.logN](); 416 | uint64_t* axax = new uint64_t[cipher.l << context.logN](); 417 | uint64_t* bxbx = new uint64_t[cipher.l << context.logN](); 418 | 419 | context.add(axbx, cipher.ax, cipher.bx, cipher.l); // ax1 + bx1 mod P, 0 mod Q 420 | 421 | context.squareAndEqual(axbx, cipher.l); // (ax1 + bx1) * (ax2 + bx2) mod P, 0 mod Q 422 | context.square(bxbx, cipher.bx, cipher.l); 423 | context.square(axax, cipher.ax, cipher.l); 424 | 425 | context.raiseAndEqual(axax, cipher.l); 426 | 427 | delete[] cipher.ax; 428 | delete[] cipher.bx; 429 | 430 | cipher.ax = new uint64_t[(cipher.l + context.K) << context.logN](); 431 | cipher.bx = new uint64_t[(cipher.l + context.K) << context.logN](); 432 | 433 | Key key = keyMap.at(MULTIPLICATION); 434 | 435 | context.mulKey(cipher.ax, axax, key.ax, cipher.l); 436 | context.mulKey(cipher.bx, axax, key.bx, cipher.l); 437 | 438 | context.backAndEqual(cipher.ax, cipher.l); 439 | context.backAndEqual(cipher.bx, cipher.l); 440 | 441 | context.addAndEqual(cipher.ax, axbx, cipher.l); 442 | context.subAndEqual(cipher.ax, bxbx, cipher.l); 443 | context.subAndEqual(cipher.ax, axax, cipher.l); 444 | context.addAndEqual(cipher.bx, bxbx, cipher.l); 445 | 446 | delete[] axax; 447 | delete[] bxbx; 448 | delete[] axbx; 449 | } 450 | 451 | Ciphertext Scheme::imult(Ciphertext& cipher) { 452 | uint64_t* ax = new uint64_t[cipher.l << context.logN](); 453 | uint64_t* bx = new uint64_t[cipher.l << context.logN](); 454 | 455 | context.mulByMonomial(ax, cipher.ax, cipher.l, context.Nh); 456 | context.mulByMonomial(bx, cipher.bx, cipher.l, context.Nh); 457 | 458 | return Ciphertext(ax, bx, context.N, cipher.slots, cipher.l); 459 | } 460 | 461 | void Scheme::imultAndEqual(Ciphertext& cipher) { 462 | //TODO implement method 463 | } 464 | 465 | Ciphertext Scheme::idiv(Ciphertext& cipher) { 466 | //TODO implement method 467 | Ciphertext res; 468 | return res; 469 | 470 | } 471 | 472 | void Scheme::idivAndEqual(Ciphertext& cipher) { 473 | //TODO implement method 474 | } 475 | 476 | Ciphertext Scheme::addConst(Ciphertext& cipher, double cnst) { 477 | uint64_t tmpr = abs(cnst) * context.p; 478 | uint64_t* ax = new uint64_t[cipher.l << context.logN](); 479 | uint64_t* bx = new uint64_t[cipher.l << context.logN](); 480 | copy(cipher.ax, cipher.ax + (cipher.l << context.logN), ax); 481 | 482 | if(cnst >= 0) { 483 | context.addConst(bx, cipher.bx, tmpr, cipher.l); 484 | } else { 485 | context.subConst(bx, cipher.bx, tmpr, cipher.l); 486 | } 487 | 488 | return Ciphertext(ax, bx, context.N, cipher.slots, cipher.l); 489 | 490 | } 491 | 492 | Ciphertext Scheme::addConst(Ciphertext& cipher, complex cnst) { 493 | //TODO implement method 494 | Ciphertext res; 495 | return res; 496 | 497 | } 498 | 499 | void Scheme::addConstAndEqual(Ciphertext& cipher, double cnst) { 500 | uint64_t tmpr = abs(cnst) * context.p; 501 | if(cnst >= 0) { 502 | context.addConstAndEqual(cipher.bx, tmpr, cipher.l); 503 | } else { 504 | context.subConstAndEqual(cipher.bx, tmpr, cipher.l); 505 | } 506 | } 507 | 508 | void Scheme::addConstAndEqual(Ciphertext& cipher, complex cnst) { 509 | //TODO implement method 510 | } 511 | 512 | void Scheme::addPcAndEqual(Ciphertext& cipher) { 513 | context.addAndEqual(cipher.bx, context.pccoeff, cipher.l); 514 | } 515 | 516 | void Scheme::addP2AndEqual(Ciphertext& cipher) { 517 | context.addAndEqual(cipher.bx, context.p2coeff, cipher.l); 518 | } 519 | 520 | void Scheme::addP2hAndEqual(Ciphertext& cipher) { 521 | context.addAndEqual(cipher.bx, context.p2hcoeff, cipher.l); 522 | } 523 | 524 | Ciphertext Scheme::multByConst(Ciphertext& cipher, double cnst) { 525 | uint64_t tmpr = abs(cnst) * context.p; 526 | 527 | uint64_t* ax = new uint64_t[cipher.l << context.logN](); 528 | uint64_t* bx = new uint64_t[cipher.l << context.logN](); 529 | 530 | context.mulConst(ax, cipher.ax, tmpr, cipher.l); 531 | context.mulConst(bx, cipher.bx, tmpr, cipher.l); 532 | 533 | if(cnst < 0) { 534 | context.negateAndEqual(ax, cipher.l); 535 | context.negateAndEqual(bx, cipher.l); 536 | } 537 | return Ciphertext(ax, bx, context.N, cipher.slots, cipher.l); 538 | } 539 | 540 | Ciphertext Scheme::multByConst(Ciphertext& cipher, complex cnst) { 541 | uint64_t tmpr = cnst.real() * context.p; 542 | uint64_t tmpi = cnst.imag() * context.p; 543 | 544 | uint64_t* ax = new uint64_t[cipher.l << context.logN](); 545 | uint64_t* bx = new uint64_t[cipher.l << context.logN](); 546 | uint64_t* axi = new uint64_t[cipher.l << context.logN](); 547 | uint64_t* bxi = new uint64_t[cipher.l << context.logN](); 548 | 549 | context.mulByMonomial(axi, cipher.ax, cipher.l, context.Nh); 550 | context.mulByMonomial(bxi, cipher.bx, cipher.l, context.Nh); 551 | 552 | context.mulConst(ax, cipher.ax, tmpr, cipher.l); 553 | context.mulConst(bx, cipher.bx, tmpr, cipher.l); 554 | 555 | context.mulConstAndEqual(axi, tmpi, cipher.l); 556 | context.mulConstAndEqual(bxi, tmpi, cipher.l); 557 | 558 | context.addAndEqual(ax, axi, cipher.l); 559 | context.addAndEqual(bx, bxi, cipher.l); 560 | 561 | return Ciphertext(ax, bx, context.N, cipher.slots, cipher.l); 562 | } 563 | 564 | Ciphertext Scheme::multByConstVec(Ciphertext& cipher, double* cnstVec, long slots) { 565 | uint64_t* ax = new uint64_t[cipher.l << context.logN](); 566 | uint64_t* bx = new uint64_t[cipher.l << context.logN](); 567 | uint64_t* mx = new uint64_t[cipher.l << context.logN](); 568 | 569 | context.encode(mx, cnstVec, slots, cipher.l); 570 | context.mul(ax, cipher.ax, mx, cipher.l); 571 | context.mul(bx, cipher.bx, mx, cipher.l); 572 | delete[] mx; 573 | return Ciphertext(ax, bx, context.N, cipher.slots, cipher.l); 574 | } 575 | 576 | Ciphertext Scheme::multByConstVec(Ciphertext& cipher, complex* cnstVec, long slots) { 577 | uint64_t* ax = new uint64_t[cipher.l << context.logN](); 578 | uint64_t* bx = new uint64_t[cipher.l << context.logN](); 579 | uint64_t* mx = new uint64_t[cipher.l << context.logN](); 580 | 581 | context.encode(mx, cnstVec, slots, cipher.l); 582 | context.mul(ax, cipher.ax, mx, cipher.l); 583 | context.mul(bx, cipher.bx, mx, cipher.l); 584 | delete[] mx; 585 | return Ciphertext(ax, bx, context.N, cipher.slots, cipher.l); 586 | } 587 | 588 | void Scheme::multByConstAndEqual(Ciphertext& cipher, double cnst) { 589 | uint64_t tmpr = abs(cnst) * context.p; 590 | 591 | uint64_t* ax = new uint64_t[cipher.l << context.logN](); 592 | uint64_t* bx = new uint64_t[cipher.l << context.logN](); 593 | 594 | context.mulConstAndEqual(cipher.ax, tmpr, cipher.l); 595 | context.mulConstAndEqual(cipher.bx, tmpr, cipher.l); 596 | 597 | if(cnst < 0) { 598 | context.negateAndEqual(cipher.ax, cipher.l); 599 | context.negateAndEqual(cipher.bx, cipher.l); 600 | } 601 | } 602 | 603 | void Scheme::multByConstAndEqual(Ciphertext& cipher, complex cnst) { 604 | } 605 | 606 | void Scheme::multByPolyAndEqual(Ciphertext& cipher, uint64_t* poly) { 607 | context.mulAndEqual(cipher.ax, poly, cipher.l); 608 | context.mulAndEqual(cipher.bx, poly, cipher.l); 609 | } 610 | 611 | Ciphertext Scheme::multByMonomial(Ciphertext& cipher, long mdeg) { 612 | //TODO implement method 613 | Ciphertext res; 614 | return res; 615 | } 616 | 617 | void Scheme::multByMonomialAndEqual(Ciphertext& cipher, long mdeg) { 618 | //TODO implement method 619 | } 620 | 621 | 622 | Ciphertext Scheme::reScaleBy(Ciphertext& cipher, long dl) { 623 | //TODO implement method 624 | Ciphertext res; 625 | return res; 626 | } 627 | 628 | void Scheme::reScaleByAndEqual(Ciphertext& cipher, long dl) { 629 | for (long i = 0; i < dl; ++i) { 630 | context.reScaleAndEqual(cipher.ax, cipher.l); 631 | context.reScaleAndEqual(cipher.bx, cipher.l); 632 | cipher.l -= 1; 633 | } 634 | } 635 | 636 | Ciphertext Scheme::reScaleTo(Ciphertext& cipher, long l) { 637 | long dl = cipher.l - l; 638 | return reScaleBy(cipher, dl); 639 | } 640 | 641 | void Scheme::reScaleToAndEqual(Ciphertext& cipher, long l) { 642 | long dl = cipher.l - l; 643 | reScaleByAndEqual(cipher, dl); 644 | } 645 | 646 | Ciphertext Scheme::modDownBy(Ciphertext& cipher, long dl) { 647 | uint64_t* ax = context.modDown(cipher.ax, cipher.l, dl); 648 | uint64_t* bx = context.modDown(cipher.bx, cipher.l, dl); 649 | return Ciphertext(ax, bx, context.N, cipher.slots, cipher.l - dl); 650 | } 651 | 652 | void Scheme::modDownByAndEqual(Ciphertext& cipher, long dl) { 653 | context.modDownAndEqual(cipher.ax, cipher.l, dl); 654 | context.modDownAndEqual(cipher.bx, cipher.l, dl); 655 | cipher.l -= dl; 656 | } 657 | 658 | Ciphertext Scheme::modDownTo(Ciphertext& cipher, long l) { 659 | long dl = cipher.l - l; 660 | return modDownBy(cipher, dl); 661 | } 662 | 663 | void Scheme::modDownToAndEqual(Ciphertext& cipher, long l) { 664 | long dl = cipher.l - l; 665 | modDownByAndEqual(cipher, dl); 666 | } 667 | 668 | Ciphertext Scheme::leftRotateFast(Ciphertext& cipher, long rotSlots) { 669 | uint64_t* bxrot = new uint64_t[cipher.l << context.logN](); 670 | uint64_t* bx = new uint64_t[cipher.l << context.logN](); 671 | 672 | uint64_t* ax = new uint64_t[(cipher.l + context.K) << context.logN](); 673 | 674 | Key key = leftRotKeyMap.at(rotSlots); 675 | 676 | context.leftRot(bxrot, cipher.bx, cipher.l, rotSlots); 677 | context.leftRot(bx, cipher.ax, cipher.l, rotSlots); 678 | 679 | context.raiseAndEqual(bx, cipher.l); 680 | 681 | context.mulKey(ax, bx, key.ax, cipher.l); 682 | context.mulKey(bx, bx, key.bx, cipher.l); 683 | 684 | context.backAndEqual(ax, cipher.l); 685 | context.backAndEqual(bx, cipher.l); 686 | 687 | context.addAndEqual(bx, bxrot, cipher.l); 688 | 689 | return Ciphertext(ax, bx, context.N, cipher.slots, cipher.l); 690 | } 691 | 692 | void Scheme::leftRotateAndEqualFast(Ciphertext& cipher, long rotSlots) { 693 | uint64_t* bxrot = new uint64_t[cipher.l << context.logN](); 694 | uint64_t* bx = new uint64_t[cipher.l << context.logN](); 695 | uint64_t* ax = new uint64_t[(cipher.l + context.K) << context.logN](); 696 | 697 | context.leftRot(bxrot, cipher.bx, cipher.l, rotSlots); 698 | context.leftRot(bx, cipher.ax, cipher.l, rotSlots); 699 | 700 | Key key = leftRotKeyMap.at(rotSlots); 701 | 702 | context.raiseAndEqual(bx, cipher.l); 703 | 704 | context.mulKey(ax, bx, key.ax, cipher.l); 705 | context.mulKey(bx, bx, key.bx, cipher.l); 706 | 707 | context.back(cipher.ax, ax, cipher.l); 708 | context.back(cipher.bx, bx, cipher.l); 709 | 710 | context.addAndEqual(cipher.bx, bxrot, cipher.l); 711 | } 712 | 713 | Ciphertext Scheme::leftRotateByPo2(Ciphertext& cipher, long logRotSlots) { 714 | long rotSlots = (1 << logRotSlots); 715 | return leftRotateFast(cipher, rotSlots); 716 | } 717 | 718 | void Scheme::leftRotateByPo2AndEqual(Ciphertext& cipher, long logRotSlots) { 719 | long rotSlots = (1 << logRotSlots); 720 | leftRotateAndEqualFast(cipher, rotSlots); 721 | } 722 | 723 | Ciphertext Scheme::rightRotateByPo2(Ciphertext& cipher, long logRotSlots) { 724 | long rotSlots = context.Nh - (1 << logRotSlots); 725 | return leftRotateFast(cipher, rotSlots); 726 | } 727 | 728 | void Scheme::rightRotateByPo2AndEqual(Ciphertext& cipher, long logRotSlots) { 729 | long rotSlots = context.Nh - (1 << logRotSlots); 730 | leftRotateAndEqualFast(cipher, rotSlots); 731 | } 732 | 733 | Ciphertext Scheme::leftRotate(Ciphertext& cipher, long rotSlots) { 734 | Ciphertext res = cipher; 735 | leftRotateAndEqual(res, rotSlots); 736 | return res; 737 | } 738 | 739 | void Scheme::leftRotateAndEqual(Ciphertext& cipher, long rotSlots) { 740 | long remrotSlots = rotSlots % cipher.slots; 741 | long logrotSlots = log2((double)remrotSlots) + 1; 742 | for (long i = 0; i < logrotSlots; ++i) { 743 | if(remrotSlots & 1 << i) { 744 | leftRotateByPo2AndEqual(cipher, i); 745 | } 746 | } 747 | } 748 | 749 | Ciphertext Scheme::rightRotate(Ciphertext& cipher, long rotSlots) { 750 | Ciphertext res = cipher; 751 | rightRotateAndEqual(res, rotSlots); 752 | return res; 753 | } 754 | 755 | void Scheme::rightRotateAndEqual(Ciphertext& cipher, long rotSlots) { 756 | long remrotSlots = rotSlots % cipher.slots; 757 | long logrotSlots = log2((double)remrotSlots) + 1; 758 | for (long i = 0; i < logrotSlots; ++i) { 759 | if(remrotSlots & 1 << i) { 760 | rightRotateByPo2AndEqual(cipher, i); 761 | } 762 | } 763 | } 764 | 765 | Ciphertext Scheme::conjugate(Ciphertext& cipher) { 766 | uint64_t* bxconj = new uint64_t[context.N * cipher.l]; 767 | uint64_t* bx = new uint64_t[context.N * cipher.l]; 768 | uint64_t* ax = new uint64_t[context.N * (cipher.l + context.K)]; 769 | 770 | context.conjugate(bxconj, cipher.bx, cipher.l); 771 | context.conjugate(bx, cipher.ax, cipher.l); 772 | 773 | Key key = keyMap.at(CONJUGATION); 774 | 775 | context.raiseAndEqual(bx, cipher.l); 776 | 777 | long shift = 0; 778 | for (long i = 0; i < cipher.l; ++i) { 779 | context.qiMul(ax + shift, bx + shift, key.ax + shift, i); 780 | context.qiMulAndEqual(bx + shift, key.bx + shift, i); 781 | shift += context.N; 782 | } 783 | 784 | long msshift = context.N * context.L; 785 | for (long i = 0; i < context.K; ++i) { 786 | context.piMul(ax + shift, bx + shift, key.ax + msshift, i); 787 | context.piMulAndEqual(bx + shift, key.bx + msshift, i); 788 | shift += context.N; 789 | msshift += context.N; 790 | } 791 | 792 | context.backAndEqual(ax, cipher.l); 793 | context.backAndEqual(bx, cipher.l); 794 | 795 | context.addAndEqual(bx, bxconj, cipher.l); 796 | 797 | delete[] bxconj; 798 | 799 | return Ciphertext(ax, bx, context.N, cipher.slots, cipher.l); 800 | } 801 | 802 | void Scheme::conjugateAndEqual(Ciphertext& cipher) { 803 | uint64_t* bxconj = new uint64_t[context.N * cipher.l]; 804 | uint64_t* bx = new uint64_t[context.N * cipher.l]; 805 | uint64_t* ax = new uint64_t[context.N * (cipher.l + context.K)]; 806 | 807 | context.conjugate(bxconj, cipher.bx, cipher.l); 808 | context.conjugate(bx, cipher.ax, cipher.l); 809 | 810 | Key key = keyMap.at(CONJUGATION); 811 | 812 | context.raiseAndEqual(bx, cipher.l); 813 | 814 | long shift = 0; 815 | for (long i = 0; i < cipher.l; ++i) { 816 | context.qiMul(ax + shift, bx + shift, key.ax + shift, i); 817 | context.qiMulAndEqual(bx + shift, key.bx + shift, i); 818 | shift += context.N; 819 | } 820 | 821 | long msshift = context.N * context.L; 822 | for (long i = 0; i < context.K; ++i) { 823 | context.piMul(ax + shift, bx + shift, key.ax + msshift, i); 824 | context.piMulAndEqual(bx + shift, key.bx + msshift, i); 825 | shift += context.N; 826 | msshift += context.N; 827 | } 828 | 829 | context.back(cipher.ax, ax, cipher.l); 830 | context.back(cipher.bx, bx, cipher.l); 831 | 832 | context.addAndEqual(cipher.bx, bxconj, cipher.l); 833 | 834 | delete[] bxconj; 835 | } 836 | 837 | 838 | -------------------------------------------------------------------------------- /src/Scheme.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #ifndef HEAANNTT_SCHEME_H_ 10 | #define HEAANNTT_SCHEME_H_ 11 | 12 | #include 13 | #include 14 | 15 | #include "Common.h" 16 | #include "Ciphertext.h" 17 | #include "Context.h" 18 | #include "Plaintext.h" 19 | #include "SecretKey.h" 20 | #include "Key.h" 21 | #include "Numb.h" 22 | 23 | using namespace std; 24 | 25 | static long ENCRYPTION = 0; 26 | static long MULTIPLICATION = 1; 27 | static long CONJUGATION = 2; 28 | 29 | class Scheme { 30 | public: 31 | 32 | Context& context; 33 | 34 | map keyMap; ///< contain Encryption, Multiplication and Conjugation keys, if generated 35 | map leftRotKeyMap; ///< contain left rotation keys, if generated 36 | 37 | Scheme(Context& context); 38 | 39 | Scheme(SecretKey& secretKey, Context& context); 40 | 41 | /** 42 | * generates key for public encryption (key is stored in keyMap) 43 | */ 44 | void addEncKey(SecretKey& secretKey); 45 | 46 | /** 47 | * generates key for multiplication (key is stored in keyMap) 48 | */ 49 | void addMultKey(SecretKey& secretKey); 50 | 51 | /** 52 | * generates key for conjugation (key is stored in keyMap) 53 | */ 54 | void addConjKey(SecretKey& secretKey); 55 | 56 | /** 57 | * generates key for left rotation (key is stored in leftRotKeyMap) 58 | */ 59 | void addLeftRotKey(SecretKey& secretKey, long rot); 60 | 61 | /** 62 | * generates all keys for power-of-two left rotations (keys are stored in leftRotKeyMap) 63 | */ 64 | void addLeftRotKeys(SecretKey& secretKey); 65 | 66 | /** 67 | * generates all keys for power-of-two right rotations (keys are stored in leftRotKeyMap) 68 | */ 69 | void addRightRotKeys(SecretKey& secretKey); 70 | 71 | Plaintext encode(double* vals, long slots, long l); 72 | 73 | Plaintext encode(complex* vals, long slots, long l); 74 | 75 | Plaintext encodeSingle(complex val, long l); 76 | 77 | complex* decode(Plaintext& msg); 78 | 79 | complex decodeSingle(Plaintext& msg); 80 | 81 | // Encryption (secret and public version) 82 | Ciphertext encryptMsg(SecretKey& secretkey, Plaintext& message); 83 | 84 | Ciphertext encryptMsg(Plaintext& message); 85 | 86 | Plaintext decryptMsg(SecretKey& secretkey, Ciphertext& cipher); 87 | 88 | Ciphertext encrypt(double* vals, long slots, long l); 89 | 90 | Ciphertext encrypt(complex* vals, long slots, long l); 91 | 92 | Ciphertext encryptSingle(complex val, long l); 93 | 94 | complex* decrypt(SecretKey& secretKey, Ciphertext& cipher); 95 | 96 | complex decryptSingle(SecretKey& secretKey, Ciphertext& cipher); 97 | 98 | // Homomorphic Negation 99 | Ciphertext negate(Ciphertext& cipher); 100 | void negateAndEqual(Ciphertext& cipher); 101 | 102 | // Homomorphic Addition 103 | Ciphertext add(Ciphertext& cipher1, Ciphertext& cipher2); 104 | void addAndEqual(Ciphertext& cipher1, Ciphertext& cipher2); 105 | 106 | // Homomorphic Substraction 107 | Ciphertext sub(Ciphertext& cipher1, Ciphertext& cipher2); 108 | 109 | void subAndEqual(Ciphertext& cipher1, Ciphertext& cipher2); 110 | void sub2AndEqual(Ciphertext& cipher1, Ciphertext& cipher2); 111 | 112 | // Homomorphic Multiplication 113 | Ciphertext mult(Ciphertext& cipher1, Ciphertext& cipher2); 114 | void multAndEqual(Ciphertext& cipher1, Ciphertext& cipher2); 115 | 116 | // Homomorphic Squaring 117 | Ciphertext square(Ciphertext& cipher); 118 | void squareAndEqual(Ciphertext& cipher); 119 | 120 | // Homomorphic Operations with Constant 121 | 122 | Ciphertext imult(Ciphertext& cipher); 123 | void imultAndEqual(Ciphertext& cipher); 124 | 125 | Ciphertext idiv(Ciphertext& cipher); 126 | void idivAndEqual(Ciphertext& cipher); 127 | 128 | Ciphertext addConst(Ciphertext& cipher, double cnst); 129 | Ciphertext addConst(Ciphertext& cipher, complex cnst); 130 | 131 | void addConstAndEqual(Ciphertext& cipher, double cnst); 132 | void addConstAndEqual(Ciphertext& cipher, complex cnst); 133 | 134 | void addPcAndEqual(Ciphertext& cipher); 135 | void addP2AndEqual(Ciphertext& cipher); 136 | void addP2hAndEqual(Ciphertext& cipher); 137 | 138 | Ciphertext multByConst(Ciphertext& cipher, double cnst); 139 | Ciphertext multByConst(Ciphertext& cipher, complex cnst); 140 | 141 | Ciphertext multByConstVec(Ciphertext& cipher, double* cnstVec, long slots); 142 | Ciphertext multByConstVec(Ciphertext& cipher, complex* cnstVec, long slots); 143 | 144 | void multByConstAndEqual(Ciphertext& cipher, double cnst); 145 | void multByConstAndEqual(Ciphertext& cipher, complex cnst); 146 | 147 | void multByPolyAndEqual(Ciphertext& cipher, uint64_t* poly); 148 | 149 | Ciphertext multByMonomial(Ciphertext& cipher, long mdeg); 150 | void multByMonomialAndEqual(Ciphertext& cipher, long mdeg); 151 | 152 | Ciphertext reScaleBy(Ciphertext& cipher, long dl); 153 | void reScaleByAndEqual(Ciphertext& cipher, long dl); 154 | 155 | Ciphertext reScaleTo(Ciphertext& cipher, long l); 156 | void reScaleToAndEqual(Ciphertext& cipher, long l); 157 | 158 | Ciphertext modDownBy(Ciphertext& cipher, long dl); 159 | void modDownByAndEqual(Ciphertext& cipher, long dl); 160 | 161 | Ciphertext modDownTo(Ciphertext& cipher, long dl); 162 | void modDownToAndEqual(Ciphertext& cipher, long dl); 163 | 164 | Ciphertext leftRotateFast(Ciphertext& cipher, long rotSlots); 165 | void leftRotateAndEqualFast(Ciphertext& cipher, long rotSlots); 166 | 167 | Ciphertext leftRotateByPo2(Ciphertext& cipher, long logRotSlots); 168 | void leftRotateByPo2AndEqual(Ciphertext& cipher, long logRotSlots); 169 | 170 | Ciphertext rightRotateByPo2(Ciphertext& cipher, long logRotSlots); 171 | void rightRotateByPo2AndEqual(Ciphertext& cipher, long logRotSlots); 172 | 173 | Ciphertext leftRotate(Ciphertext& cipher, long rotSlots); 174 | void leftRotateAndEqual(Ciphertext& cipher, long rotSlots); 175 | 176 | Ciphertext rightRotate(Ciphertext& cipher, long rotSlots); 177 | void rightRotateAndEqual(Ciphertext& cipher, long rotSlots); 178 | 179 | Ciphertext conjugate(Ciphertext& cipher); 180 | void conjugateAndEqual(Ciphertext& cipher); 181 | 182 | }; 183 | 184 | #endif 185 | -------------------------------------------------------------------------------- /src/SchemeAlgo.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #include "SchemeAlgo.h" 10 | 11 | //---------------------------------------------------------------------------------- 12 | // ARRAY ENCRYPTION & DECRYPTION 13 | //---------------------------------------------------------------------------------- 14 | 15 | 16 | Ciphertext* SchemeAlgo::encryptSingleArray(complex* vals, long size) { 17 | Ciphertext* res = new Ciphertext[size]; 18 | for (long i = 0; i < size; ++i) { 19 | res[i] = scheme.encryptSingle(vals[i], scheme.context.L); 20 | } 21 | return res; 22 | } 23 | 24 | Ciphertext* SchemeAlgo::encryptSingleArray(double* vals, long size) { 25 | Ciphertext* res = new Ciphertext[size]; 26 | for (long i = 0; i < size; ++i) { 27 | res[i] = scheme.encryptSingle(vals[i], scheme.context.L); 28 | } 29 | return res; 30 | } 31 | 32 | complex* SchemeAlgo::decryptSingleArray(SecretKey& secretKey, Ciphertext* ciphers, long size) { 33 | complex* res = new complex[size]; 34 | for (long i = 0; i < size; ++i) { 35 | res[i] = scheme.decryptSingle(secretKey, ciphers[i]); 36 | } 37 | return res; 38 | } 39 | 40 | //---------------------------------------------------------------------------------- 41 | // POWERS & PRODUCTS 42 | //---------------------------------------------------------------------------------- 43 | 44 | 45 | Ciphertext SchemeAlgo::powerOf2(Ciphertext& cipher, const long logDegree) { 46 | Ciphertext res = cipher; 47 | for (long i = 0; i < logDegree; ++i) { 48 | scheme.squareAndEqual(res); 49 | scheme.reScaleByAndEqual(res, 1); 50 | } 51 | return res; 52 | } 53 | 54 | Ciphertext* SchemeAlgo::powerOf2Extended(Ciphertext& cipher, const long logDegree) { 55 | Ciphertext* res = new Ciphertext[logDegree + 1]; 56 | res[0] = cipher; 57 | for (long i = 1; i < logDegree + 1; ++i) { 58 | res[i] = scheme.square(res[i-1]); 59 | scheme.reScaleByAndEqual(res[i], 1); 60 | } 61 | return res; 62 | } 63 | 64 | Ciphertext SchemeAlgo::power(Ciphertext& cipher, const long degree) { 65 | long logDegree = log2((double)degree); 66 | long po2Degree = 1 << logDegree; 67 | 68 | Ciphertext res = powerOf2(cipher, logDegree); 69 | long remDegree = degree - po2Degree; 70 | if(remDegree > 0) { 71 | Ciphertext tmp = power(cipher, remDegree); 72 | scheme.modDownToAndEqual(tmp, tmp.l - 1); 73 | scheme.multAndEqual(res, tmp); 74 | scheme.reScaleByAndEqual(res, 1); 75 | } 76 | return res; 77 | } 78 | 79 | Ciphertext* SchemeAlgo::powerExtended(Ciphertext& cipher, const long degree) { 80 | Ciphertext* res = new Ciphertext[degree]; 81 | long logDegree = log2((double)degree); 82 | Ciphertext* cpows = powerOf2Extended(cipher, logDegree); 83 | long idx = 0; 84 | for (long i = 0; i < logDegree; ++i) { 85 | long powi = (1 << i); 86 | res[idx++] = cpows[i]; 87 | for (int j = 0; j < powi-1; ++j) { 88 | res[idx] = scheme.modDownTo(res[j], cpows[i].l); 89 | scheme.multAndEqual(res[idx], cpows[i]); 90 | scheme.reScaleByAndEqual(res[idx++], 1); 91 | } 92 | } 93 | res[idx++] = cpows[logDegree]; 94 | long degree2 = (1 << logDegree); 95 | for (int i = 0; i < (degree - degree2); ++i) { 96 | res[idx] = scheme.modDownTo(res[i], cpows[logDegree].l); 97 | scheme.multAndEqual(res[idx], cpows[logDegree]); 98 | scheme.reScaleByAndEqual(res[idx++], 1); 99 | } 100 | return res; 101 | } 102 | 103 | Ciphertext SchemeAlgo::prodOfPo2(Ciphertext* ciphers, const long logDegree) { 104 | Ciphertext* res = ciphers; 105 | for (long i = logDegree - 1; i >= 0; --i) { 106 | long powih = (1 << i); 107 | Ciphertext* tmp = new Ciphertext[powih]; 108 | for (long j = 0; j < powih; ++j) { 109 | tmp[j] = scheme.mult(res[2 * j], res[2 * j + 1]); 110 | scheme.reScaleByAndEqual(tmp[j], 1); 111 | } 112 | res = tmp; 113 | } 114 | return res[0]; 115 | } 116 | 117 | Ciphertext SchemeAlgo::prod(Ciphertext* ciphers, const long degree) { 118 | long logDegree = log2((double)degree) + 1; 119 | long idx = 0; 120 | bool isinit = false; 121 | Ciphertext res; 122 | for (long i = 0; i < logDegree; ++i) { 123 | if(degree & 1 << i) { 124 | long powi = (1 << i); 125 | Ciphertext* tmp = new Ciphertext[powi]; 126 | for (long j = 0; j < powi; ++j) { 127 | tmp[j] = ciphers[idx + j]; 128 | } 129 | Ciphertext iprod = prodOfPo2(tmp, i); 130 | if(isinit) { 131 | long dl = res.l - iprod.l; 132 | scheme.modDownByAndEqual(res, dl); 133 | scheme.multAndEqual(res, iprod); 134 | scheme.reScaleByAndEqual(res, 1); 135 | } else { 136 | res = iprod; 137 | isinit = true; 138 | } 139 | idx += powi; 140 | } 141 | } 142 | return res; 143 | } 144 | 145 | 146 | //---------------------------------------------------------------------------------- 147 | // METHODS ON ARRAYS OF CIPHERTEXTS 148 | //---------------------------------------------------------------------------------- 149 | 150 | 151 | Ciphertext SchemeAlgo::sum(Ciphertext* ciphers, const long size) { 152 | Ciphertext res = ciphers[0]; 153 | for (long i = 1; i < size; ++i) { 154 | scheme.addAndEqual(res, ciphers[i]); 155 | } 156 | return res; 157 | } 158 | 159 | Ciphertext SchemeAlgo::distance(Ciphertext& cipher1, Ciphertext& cipher2) { 160 | Ciphertext cres = scheme.sub(cipher1, cipher2); 161 | scheme.squareAndEqual(cres); 162 | scheme.reScaleByAndEqual(cres, 1); 163 | partialSlotsSumAndEqual(cres, cres.slots); 164 | return cres; 165 | } 166 | 167 | Ciphertext* SchemeAlgo::multVec(Ciphertext* ciphers1, Ciphertext* ciphers2, const long size) { 168 | Ciphertext* res = new Ciphertext[size]; 169 | for (long i = 0; i < size; ++i) { 170 | res[i] = scheme.mult(ciphers1[i], ciphers2[i]); 171 | } 172 | return res; 173 | } 174 | 175 | void SchemeAlgo::multAndEqualVec(Ciphertext* ciphers1, Ciphertext* ciphers2, const long size) { 176 | for (long i = 0; i < size; ++i) { 177 | scheme.multAndEqual(ciphers1[i], ciphers2[i]); 178 | } 179 | } 180 | 181 | 182 | Ciphertext* SchemeAlgo::multAndModSwitchVec(Ciphertext* ciphers1, Ciphertext* ciphers2, const long size) { 183 | Ciphertext* res = new Ciphertext[size]; 184 | for (long i = 0; i < size; ++i) { 185 | res[i] = scheme.mult(ciphers1[i], ciphers2[i]); 186 | scheme.reScaleByAndEqual(res[i], 1); 187 | } 188 | return res; 189 | } 190 | 191 | void SchemeAlgo::multModSwitchAndEqualVec(Ciphertext* ciphers1, Ciphertext* ciphers2, const long size) { 192 | for (long i = 0; i < size; ++i) { 193 | scheme.multAndEqual(ciphers1[i], ciphers2[i]); 194 | scheme.reScaleByAndEqual(ciphers1[i], 1); 195 | } 196 | } 197 | 198 | Ciphertext SchemeAlgo::innerProd(Ciphertext* ciphers1, Ciphertext* ciphers2, const long size) { 199 | Ciphertext cip = scheme.mult(ciphers1[size-1], ciphers2[size-1]); 200 | 201 | for (long i = 0; i < size - 1; ++i) { 202 | Ciphertext cprodi = scheme.mult(ciphers1[i], ciphers2[i]); 203 | scheme.addAndEqual(cip, cprodi); 204 | } 205 | 206 | scheme.reScaleByAndEqual(cip, 1); 207 | return cip; 208 | } 209 | 210 | Ciphertext SchemeAlgo::partialSlotsSum(Ciphertext& cipher, const long slots) { 211 | Ciphertext res = cipher; 212 | for (long i = 1; i < slots; i <<= 1) { 213 | Ciphertext rot = scheme.leftRotateFast(res, i); 214 | scheme.addAndEqual(res, rot); 215 | } 216 | return res; 217 | } 218 | 219 | void SchemeAlgo::partialSlotsSumAndEqual(Ciphertext& cipher, const long slots) { 220 | for (long i = 1; i < slots; i <<= 1) { 221 | Ciphertext rot = scheme.leftRotateFast(cipher, i); 222 | scheme.addAndEqual(cipher, rot); 223 | } 224 | } 225 | 226 | 227 | //---------------------------------------------------------------------------------- 228 | // FUNCTIONS 229 | //---------------------------------------------------------------------------------- 230 | 231 | 232 | Ciphertext SchemeAlgo::inverse(Ciphertext& cipher, const long steps) { 233 | Ciphertext cbar = scheme.negate(cipher); 234 | scheme.addConstAndEqual(cbar, 1.0); 235 | Ciphertext cpow = cbar; 236 | Ciphertext tmp = scheme.addConst(cbar, 1.0); 237 | scheme.modDownByAndEqual(tmp, 1); 238 | Ciphertext res = tmp; 239 | 240 | for (long i = 1; i < steps; ++i) { 241 | scheme.squareAndEqual(cpow); 242 | scheme.reScaleByAndEqual(cpow, 1); 243 | tmp = cpow; 244 | scheme.addConstAndEqual(tmp, 1.0); 245 | scheme.multAndEqual(tmp, res); 246 | scheme.reScaleByAndEqual(tmp, 1); 247 | res = tmp; 248 | } 249 | return res; 250 | } 251 | 252 | Ciphertext* SchemeAlgo::inverseExtended(Ciphertext& cipher, const long steps) { 253 | Ciphertext* res = new Ciphertext[steps]; 254 | Ciphertext cpow = cipher; 255 | Ciphertext tmp = scheme.addConst(cipher, 1.0); 256 | scheme.modDownByAndEqual(tmp, 1); 257 | res[0] = tmp; 258 | 259 | for (long i = 1; i < steps; ++i) { 260 | scheme.squareAndEqual(cpow); 261 | scheme.reScaleByAndEqual(cpow, 1); 262 | tmp = cpow; 263 | scheme.addConstAndEqual(tmp, 1.0); 264 | scheme.multAndEqual(tmp, res[i - 1]); 265 | scheme.reScaleByAndEqual(tmp, 1); 266 | res[i] = tmp; 267 | } 268 | return res; 269 | } 270 | 271 | Ciphertext SchemeAlgo::exponent(Ciphertext& cipher, long degree) { 272 | Ciphertext* cpows = powerExtended(cipher, degree); 273 | 274 | double* coeffs = scheme.context.taylorCoeffsMap.at(EXPONENT); 275 | 276 | Ciphertext res = scheme.multByConst(cpows[0], coeffs[1]); 277 | scheme.addP2AndEqual(res); // 2 lvl 278 | for (int i = 1; i < degree; ++i) { 279 | if(abs(coeffs[i + 1]) > 1e-27) { 280 | Ciphertext aixi = scheme.multByConst(cpows[i], coeffs[i + 1]); 281 | scheme.modDownToAndEqual(res, aixi.l); 282 | scheme.addAndEqual(res, aixi); 283 | } 284 | } 285 | scheme.reScaleByAndEqual(res, 1); 286 | return res; 287 | } 288 | 289 | Ciphertext SchemeAlgo::sigmoid(Ciphertext& cipher, long degree) { 290 | Ciphertext* cpows = powerExtended(cipher, degree); 291 | 292 | double* coeffs = scheme.context.taylorCoeffsMap.at(SIGMOID); 293 | 294 | Ciphertext res = scheme.multByConst(cpows[0], coeffs[1]); 295 | scheme.addP2hAndEqual(res); // 2 lvl 296 | for (int i = 1; i < degree; ++i) { 297 | if(abs(coeffs[i + 1]) > 1e-27) { 298 | Ciphertext aixi = scheme.multByConst(cpows[i], coeffs[i + 1]); 299 | scheme.modDownToAndEqual(res, aixi.l); 300 | scheme.addAndEqual(res, aixi); 301 | } 302 | } 303 | scheme.reScaleByAndEqual(res, 1); 304 | return res; 305 | } 306 | 307 | Ciphertext SchemeAlgo::function(Ciphertext& cipher, string& funcName, const long degree) { 308 | Ciphertext* cpows = powerExtended(cipher, degree); 309 | 310 | double* coeffs = scheme.context.taylorCoeffsMap.at(funcName); 311 | 312 | Ciphertext res = scheme.multByConst(cpows[0], coeffs[1]); 313 | scheme.addConstAndEqual(res, coeffs[0]); // 2 lvl 314 | 315 | for (int i = 1; i < degree; ++i) { 316 | if(abs(coeffs[i + 1]) > 1e-27) { 317 | Ciphertext aixi = scheme.multByConst(cpows[i], coeffs[i + 1]); 318 | scheme.modDownToAndEqual(res, aixi.l); 319 | scheme.addAndEqual(res, aixi); 320 | } 321 | } 322 | scheme.reScaleByAndEqual(res, 1); 323 | return res; 324 | } 325 | 326 | Ciphertext* SchemeAlgo::functionExtended(Ciphertext& cipher, string& funcName, const long degree) { 327 | Ciphertext* cpows = powerExtended(cipher, degree); 328 | 329 | double* coeffs = scheme.context.taylorCoeffsMap.at(funcName); 330 | 331 | Ciphertext aixi = scheme.multByConst(cpows[0], coeffs[1]); 332 | 333 | // scheme.addConstAndEqual(aixi, coeffs[0], dlogp); 334 | 335 | Ciphertext* res = new Ciphertext[degree]; 336 | res[0] = aixi; 337 | for (long i = 1; i < degree; ++i) { 338 | if(abs(coeffs[i + 1]) > 1e-27) { 339 | aixi = scheme.multByConst(cpows[i], coeffs[i + 1]); 340 | Ciphertext ctmp = scheme.modDownTo(res[i - 1], aixi.l); 341 | scheme.addAndEqual(aixi, ctmp); 342 | res[i] = aixi; 343 | } else { 344 | res[i] = res[i - 1]; 345 | } 346 | } 347 | for (long i = 0; i < degree; ++i) { 348 | scheme.reScaleByAndEqual(res[i], 1); 349 | } 350 | return res; 351 | } 352 | 353 | 354 | //---------------------------------------------------------------------------------- 355 | // FFT & FFT INVERSE 356 | //---------------------------------------------------------------------------------- 357 | 358 | 359 | void SchemeAlgo::bitReverse(Ciphertext* ciphers, const long size) { 360 | for (long i = 1, j = 0; i < size; ++i) { 361 | long bit = size >> 1; 362 | for (; j >= bit; bit>>=1) { 363 | j -= bit; 364 | } 365 | j += bit; 366 | if(i < j) { 367 | swap(ciphers[i], ciphers[j]); 368 | } 369 | } 370 | } 371 | 372 | void SchemeAlgo::fft(Ciphertext* ciphers, const long size) { 373 | bitReverse(ciphers, size); 374 | for (long len = 2; len <= size; len <<= 1) { 375 | long shift = scheme.context.M / len; 376 | for (long i = 0; i < size; i += len) { 377 | for (long j = 0; j < len / 2; ++j) { 378 | Ciphertext u = ciphers[i + j]; 379 | scheme.multByMonomialAndEqual(ciphers[i + j + len / 2], shift * j); 380 | scheme.addAndEqual(ciphers[i + j], ciphers[i + j + len / 2]); 381 | scheme.sub2AndEqual(u, ciphers[i + j + len / 2]); 382 | } 383 | } 384 | } 385 | } 386 | 387 | void SchemeAlgo::fftInvLazy(Ciphertext* ciphers, const long size) { 388 | bitReverse(ciphers, size); 389 | for (long len = 2; len <= size; len <<= 1) { 390 | long shift = scheme.context.M - scheme.context.M / len; 391 | for (long i = 0; i < size; i += len) { 392 | for (long j = 0; j < len / 2; ++j) { 393 | Ciphertext u = ciphers[i + j]; 394 | scheme.multByMonomialAndEqual(ciphers[i + j + len / 2], shift * j); 395 | scheme.addAndEqual(ciphers[i + j], ciphers[i + j + len / 2]); 396 | scheme.sub2AndEqual(u, ciphers[i + j + len / 2]); 397 | } 398 | } 399 | } 400 | } 401 | 402 | void SchemeAlgo::fftInv(Ciphertext* ciphers, const long size) { 403 | fftInvLazy(ciphers, size); 404 | 405 | } 406 | -------------------------------------------------------------------------------- /src/SchemeAlgo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #ifndef HEAAN_SCHEMEALGO_H_ 10 | #define HEAAN_SCHEMEALGO_H_ 11 | 12 | #include "Common.h" 13 | #include "EvaluatorUtils.h" 14 | #include "Plaintext.h" 15 | #include "SecretKey.h" 16 | #include "Ciphertext.h" 17 | #include "Scheme.h" 18 | 19 | class SchemeAlgo { 20 | public: 21 | Scheme& scheme; 22 | 23 | SchemeAlgo(Scheme& scheme) : scheme(scheme) {}; 24 | 25 | 26 | //---------------------------------------------------------------------------------- 27 | // ARRAY ENCRYPTION & DECRYPTION 28 | //---------------------------------------------------------------------------------- 29 | 30 | 31 | Ciphertext* encryptSingleArray(complex* vals, long size); 32 | 33 | Ciphertext* encryptSingleArray(double* vals, long size); 34 | 35 | complex* decryptSingleArray(SecretKey& secretKey, Ciphertext* ciphers, long size); 36 | 37 | 38 | //---------------------------------------------------------------------------------- 39 | // POWERS & PRODUCTS 40 | //---------------------------------------------------------------------------------- 41 | 42 | 43 | Ciphertext powerOf2(Ciphertext& cipher, const long logDegree); 44 | 45 | Ciphertext* powerOf2Extended(Ciphertext& cipher, const long logDegree); 46 | 47 | Ciphertext power(Ciphertext& cipher, const long degree); 48 | 49 | Ciphertext* powerExtended(Ciphertext& cipher, const long degree); 50 | 51 | Ciphertext prodOfPo2(Ciphertext* ciphers, const long logDegree); 52 | 53 | Ciphertext prod(Ciphertext* ciphers, const long degree); 54 | 55 | 56 | //---------------------------------------------------------------------------------- 57 | // METHODS ON ARRAYS OF CIPHERTEXTS 58 | //---------------------------------------------------------------------------------- 59 | 60 | 61 | Ciphertext sum(Ciphertext* ciphers, const long size); 62 | 63 | Ciphertext distance(Ciphertext& cipher1, Ciphertext& cipher2); 64 | 65 | Ciphertext* multVec(Ciphertext* ciphers1, Ciphertext* ciphers2, const long size); 66 | 67 | void multAndEqualVec(Ciphertext* ciphers1, Ciphertext* ciphers2, const long size); 68 | 69 | Ciphertext* multAndModSwitchVec(Ciphertext* ciphers1, Ciphertext* ciphers2, const long size); 70 | 71 | void multModSwitchAndEqualVec(Ciphertext* ciphers1, Ciphertext* ciphers2, const long size); 72 | 73 | Ciphertext innerProd(Ciphertext* ciphers1, Ciphertext* ciphers2, const long size); 74 | 75 | Ciphertext partialSlotsSum(Ciphertext& cipher, const long slots); 76 | 77 | void partialSlotsSumAndEqual(Ciphertext& cipher, const long slots); 78 | 79 | 80 | //---------------------------------------------------------------------------------- 81 | // FUNCTIONS 82 | //---------------------------------------------------------------------------------- 83 | 84 | 85 | Ciphertext inverse(Ciphertext& cipher, const long steps); 86 | 87 | Ciphertext* inverseExtended(Ciphertext& cipher, const long steps); 88 | 89 | Ciphertext exponent(Ciphertext& cipher, long degree = 7); 90 | 91 | Ciphertext sigmoid(Ciphertext& cipher, long degree = 7); 92 | 93 | Ciphertext function(Ciphertext& cipher, string& funcName, const long degree); 94 | 95 | Ciphertext* functionExtended(Ciphertext& cipher, string& funcName, const long degree); 96 | 97 | //---------------------------------------------------------------------------------- 98 | // FFT & FFT INVERSE 99 | //---------------------------------------------------------------------------------- 100 | 101 | 102 | void bitReverse(Ciphertext* ciphers, const long size); 103 | 104 | void fft(Ciphertext* ciphers, const long size); 105 | 106 | void fftInvLazy(Ciphertext* ciphers, const long size); 107 | 108 | void fftInv(Ciphertext* ciphers, const long size); 109 | 110 | }; 111 | 112 | #endif 113 | -------------------------------------------------------------------------------- /src/SecretKey.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #include "SecretKey.h" 10 | 11 | SecretKey::SecretKey(Context& context) { 12 | sx = new uint64_t[context.N * (context.L + context.K)](); 13 | context.sampleHWT(sx, context.L, context.K); 14 | context.NTTAndEqual(sx, context.L, context.K); 15 | } 16 | -------------------------------------------------------------------------------- /src/SecretKey.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #ifndef HEAANNTT_SECRETKEY_H_ 10 | #define HEAANNTT_SECRETKEY_H_ 11 | 12 | #include "Common.h" 13 | #include "Context.h" 14 | 15 | class SecretKey { 16 | public: 17 | 18 | uint64_t* sx; 19 | 20 | SecretKey(Context& context); 21 | 22 | }; 23 | 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/StringUtils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #include "StringUtils.h" 10 | 11 | //---------------------------------------------------------------------------------- 12 | // SHOW ARRAY 13 | //---------------------------------------------------------------------------------- 14 | 15 | void StringUtils::show(uint64_t* vals, long size) { 16 | cout << "["; 17 | for (long i = 0; i < size; ++i) { 18 | cout << vals[i] << ", "; 19 | } 20 | cout << "]" << endl; 21 | } 22 | 23 | void StringUtils::show(long* vals, long size) { 24 | cout << "["; 25 | for (long i = 0; i < size; ++i) { 26 | cout << vals[i] << ", "; 27 | } 28 | cout << "]" << endl; 29 | } 30 | 31 | void StringUtils::show(double* vals, long size) { 32 | cout << "["; 33 | for (long i = 0; i < size; ++i) { 34 | cout << vals[i] << ", "; 35 | } 36 | cout << "]" << endl; 37 | } 38 | 39 | void StringUtils::show(complex* vals, long size) { 40 | cout << "["; 41 | for (long i = 0; i < size; ++i) { 42 | cout << vals[i] << ", "; 43 | } 44 | cout << "]" << endl; 45 | } 46 | 47 | 48 | //---------------------------------------------------------------------------------- 49 | // SHOW & COMPARE ARRAY 50 | //---------------------------------------------------------------------------------- 51 | 52 | 53 | void StringUtils::showcompare(double val1, double val2, string prefix) { 54 | cout << "---------------------" << endl; 55 | cout << "m" + prefix + ":" << val1 << endl; 56 | cout << "d" + prefix + ":" << val2 << endl; 57 | cout << "e" + prefix + ":" << val1-val2 << endl; 58 | cout << "---------------------" << endl; 59 | } 60 | 61 | void StringUtils::showcompare(complex val1, complex val2, string prefix) { 62 | cout << "---------------------" << endl; 63 | cout << "m" + prefix + ":" << val1 << endl; 64 | cout << "d" + prefix + ":" << val2 << endl; 65 | cout << "e" + prefix + ":" << val1-val2 << endl; 66 | cout << "---------------------" << endl; 67 | } 68 | 69 | void StringUtils::showcompare(double* vals1, double* vals2, long size, string prefix) { 70 | for (long i = 0; i < size; ++i) { 71 | cout << "---------------------" << endl; 72 | cout << "m" + prefix + ": " << i << " :" << vals1[i] << endl; 73 | cout << "d" + prefix + ": " << i << " :" << vals2[i] << endl; 74 | cout << "e" + prefix + ": " << i << " :" << (vals1[i]-vals2[i]) << endl; 75 | cout << "---------------------" << endl; 76 | } 77 | } 78 | 79 | void StringUtils::showcompare(complex* vals1, complex* vals2, long size, string prefix) { 80 | for (long i = 0; i < size; ++i) { 81 | cout << "---------------------" << endl; 82 | cout << "m" + prefix + ": " << i << " :" << vals1[i] << endl; 83 | cout << "d" + prefix + ": " << i << " :" << vals2[i] << endl; 84 | cout << "e" + prefix + ": " << i << " :" << (vals1[i]-vals2[i]) << endl; 85 | cout << "---------------------" << endl; 86 | } 87 | } 88 | 89 | 90 | void StringUtils::showcompare(double* vals1, double val2, long size, string prefix) { 91 | for (long i = 0; i < size; ++i) { 92 | cout << "---------------------" << endl; 93 | cout << "m" + prefix + ": " << i << " :" << vals1[i] << endl; 94 | cout << "d" + prefix + ": " << i << " :" << val2 << endl; 95 | cout << "e" + prefix + ": " << i << " :" << vals1[i]-val2 << endl; 96 | cout << "---------------------" << endl; 97 | } 98 | } 99 | 100 | void StringUtils::showcompare(complex* vals1, complex val2, long size, string prefix) { 101 | for (long i = 0; i < size; ++i) { 102 | cout << "---------------------" << endl; 103 | cout << "m" + prefix + ": " << i << " :" << vals1[i] << endl; 104 | cout << "d" + prefix + ": " << i << " :" << val2 << endl; 105 | cout << "e" + prefix + ": " << i << " :" << vals1[i]-val2 << endl; 106 | cout << "---------------------" << endl; 107 | } 108 | } 109 | 110 | void StringUtils::showcompare(double val1, double* vals2, long size, string prefix) { 111 | for (long i = 0; i < size; ++i) { 112 | cout << "---------------------" << endl; 113 | cout << "m" + prefix + ": " << i << " :" << val1 << endl; 114 | cout << "d" + prefix + ": " << i << " :" << vals2[i] << endl; 115 | cout << "e" + prefix + ": " << i << " :" << val1-vals2[i] << endl; 116 | cout << "---------------------" << endl; 117 | } 118 | } 119 | 120 | void StringUtils::showcompare(complex val1, complex* vals2, long size, string prefix) { 121 | for (long i = 0; i < size; ++i) { 122 | cout << "---------------------" << endl; 123 | cout << "m" + prefix + ": " << i << " :" << val1 << endl; 124 | cout << "d" + prefix + ": " << i << " :" << vals2[i] << endl; 125 | cout << "e" + prefix + ": " << i << " :" << val1-vals2[i] << endl; 126 | cout << "---------------------" << endl; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/StringUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #ifndef HEAAN_STRINGUTILS_H_ 10 | #define HEAAN_STRINGUTILS_H_ 11 | 12 | #include 13 | 14 | #include "Common.h" 15 | 16 | using namespace std; 17 | 18 | class StringUtils { 19 | public: 20 | 21 | 22 | //---------------------------------------------------------------------------------- 23 | // SHOW ARRAY 24 | //---------------------------------------------------------------------------------- 25 | 26 | 27 | static void show(uint64_t* vals, long size); 28 | /** 29 | * prints in console array 30 | * @param[in] vals: long array 31 | * @param[in] size: array size 32 | */ 33 | static void show(long* vals, long size); 34 | 35 | /** 36 | * prints in console array 37 | * @param[in] vals: double array 38 | * @param[in] size: array size 39 | */ 40 | static void show(double* vals, long size); 41 | 42 | /** 43 | * prints in console array 44 | * @param[in] vals: complex array 45 | * @param[in] size: array size 46 | */ 47 | static void show(complex* vals, long size); 48 | 49 | 50 | //---------------------------------------------------------------------------------- 51 | // SHOW & COMPARE ARRAY 52 | //---------------------------------------------------------------------------------- 53 | 54 | 55 | /** 56 | * prints in console val1, val2 and (val1-val2) 57 | * @param[in] val1: double value 58 | * @param[in] val2: double value 59 | * @param[in] prefix: string prefix 60 | */ 61 | static void showcompare(double val1, double val2, string prefix); 62 | 63 | /** 64 | * prints in console val1, val2 and (val1-val2) 65 | * @param[in] val1: complex value 66 | * @param[in] val2: complex value 67 | * @param[in] prefix: string prefix 68 | */ 69 | static void showcompare(complex val1, complex val2, string prefix); 70 | 71 | /** 72 | * prints in console pairwise val1[i], val2[i] and (val1[i]-val2[i]) 73 | * @param[in] vals1: double array 74 | * @param[in] vals2: double array 75 | * @param[in] size: array size 76 | * @param[in] prefix: string prefix 77 | */ 78 | static void showcompare(double* vals1, double* vals2, long size, string prefix); 79 | 80 | /** 81 | * prints in console pairwise val1[i], val2[i] and (val1[i]-val2[i]) 82 | * @param[in] vals1: complex array 83 | * @param[in] vals2: complex array 84 | * @param[in] size: array size 85 | * @param[in] prefix: string prefix 86 | */ 87 | static void showcompare(complex* vals1, complex* vals2, long size, string prefix); 88 | 89 | /** 90 | * prints in console pairwise val1[i], val2 and (val1[i]-val2) 91 | * @param[in] vals1: double array 92 | * @param[in] val2: double value 93 | * @param[in] size: array size 94 | * @param[in] prefix: string prefix 95 | */ 96 | static void showcompare(double* vals1, double val2, long size, string prefix); 97 | 98 | /** 99 | * prints in console pairwise val1[i], val2 and (val1[i]-val2) 100 | * @param[in] vals1: complex array 101 | * @param[in] val2: complex value 102 | * @param[in] size: array size 103 | * @param[in] prefix: string prefix 104 | */ 105 | static void showcompare(complex* vals1, complex val2, long size, string prefix); 106 | 107 | /** 108 | * prints in console pairwise val1, val2[i] and (val1-val2[i]) 109 | * @param[in] val1: double value 110 | * @param[in] vals2: double array 111 | * @param[in] size: array size 112 | * @param[in] prefix: string prefix 113 | */ 114 | static void showcompare(double val1, double* vals2, long size, string prefix); 115 | 116 | /** 117 | * prints in console pairwise val1, val2[i] and (val1-val2[i]) 118 | * @param[in] val1: complex value 119 | * @param[in] vals2: complex array 120 | * @param[in] size: array size 121 | * @param[in] prefix: string prefix 122 | */ 123 | static void showcompare(complex val1, complex* vals2, long size, string prefix); 124 | 125 | }; 126 | 127 | #endif 128 | -------------------------------------------------------------------------------- /src/TestScheme.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #include "TestScheme.h" 10 | #include "Numb.h" 11 | #include "Context.h" 12 | #include "SecretKey.h" 13 | #include "Scheme.h" 14 | #include "EvaluatorUtils.h" 15 | #include "StringUtils.h" 16 | #include "TimeUtils.h" 17 | #include "SchemeAlgo.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | using namespace std; 24 | using namespace chrono; 25 | 26 | void TestScheme::testEncodeSingle(long logN, long L, long logp) { 27 | cout << "!!! START TEST ENCODE SINGLE !!!" << endl; 28 | //----------------------------------------- 29 | TimeUtils timeutils; 30 | long k = 1; 31 | Context context(logN, logp, L, k); 32 | SecretKey secretKey(context); 33 | Scheme scheme(secretKey, context); 34 | //----------------------------------------- 35 | srand(time(NULL)); 36 | //----------------------------------------- 37 | complex m = EvaluatorUtils::randomCircle(); 38 | 39 | timeutils.start("Encrypt single"); 40 | Ciphertext cipher = scheme.encryptSingle(m, L); 41 | timeutils.stop("Encrypt single"); 42 | 43 | timeutils.start("Decrypt single"); 44 | complex d = scheme.decryptSingle(secretKey, cipher); 45 | timeutils.stop("Decrypt single"); 46 | 47 | StringUtils::showcompare(m, d, "val"); 48 | 49 | cout << "!!! END TEST ENCODE SINGLE !!!" << endl; 50 | } 51 | 52 | void TestScheme::testEncodeBatch(long logN, long L, long logp, long logSlots) { 53 | cout << "!!! START TEST ENCODE BATCH !!!" << endl; 54 | //----------------------------------------- 55 | TimeUtils timeutils; 56 | long k = L; 57 | Context context(logN, logp, L, k); 58 | SecretKey secretKey(context); 59 | Scheme scheme(secretKey, context); 60 | //----------------------------------------- 61 | srand(time(NULL)); 62 | //----------------------------------------- 63 | long slots = 1L << logSlots; 64 | complex* mvec = EvaluatorUtils::randomComplexArray(slots); 65 | 66 | timeutils.start("Encrypt batch"); 67 | Ciphertext cipher = scheme.encrypt(mvec, slots, L); 68 | timeutils.stop("Encrypt batch"); 69 | 70 | timeutils.start("Decrypt batch"); 71 | complex* dvec = scheme.decrypt(secretKey, cipher); 72 | timeutils.stop("Decrypt batch"); 73 | 74 | StringUtils::showcompare(mvec, dvec, slots, "val"); 75 | 76 | cout << "!!! END TEST ENCODE BATCH !!!" << endl; 77 | } 78 | 79 | void TestScheme::testBasic(long logN, long L, long logp, long logSlots) { 80 | cout << "!!! START TEST BASIC !!!" << endl; 81 | //----------------------------------------- 82 | TimeUtils timeutils; 83 | long K = L + 1; 84 | Context context(logN, logp, L, K); 85 | SecretKey secretKey(context); 86 | Scheme scheme(secretKey, context); 87 | 88 | //----------------------------------------- 89 | srand(time(NULL)); 90 | //----------------------------------------- 91 | long slots = (1 << logSlots); 92 | double bound = 1.0; 93 | complex* mvec1 = EvaluatorUtils::randomComplexArray(slots, bound); 94 | complex* mvec2 = EvaluatorUtils::randomComplexArray(slots, bound); 95 | complex* cvec = EvaluatorUtils::randomComplexArray(slots, bound); 96 | 97 | complex* mvecAdd = new complex[slots]; 98 | complex* mvecMult = new complex[slots]; 99 | complex* mvecCMult = new complex[slots]; 100 | 101 | for(long i = 0; i < slots; i++) { 102 | mvecAdd[i] = mvec1[i] + mvec2[i]; 103 | mvecMult[i] = mvec1[i] * mvec2[i]; 104 | mvecCMult[i] = mvec1[i] * cvec[i]; 105 | } 106 | 107 | timeutils.start("Encrypt two batch"); 108 | Ciphertext cipher1 = scheme.encrypt(mvec1, slots, L); 109 | Ciphertext cipher2 = scheme.encrypt(mvec2, slots, L); 110 | timeutils.stop("Encrypt two batch"); 111 | 112 | timeutils.start("Homomorphic Addition"); 113 | Ciphertext addCipher = scheme.add(cipher1, cipher2); 114 | timeutils.stop("Homomorphic Addition"); 115 | 116 | timeutils.start("Homomorphic Multiplication & Rescaling"); 117 | Ciphertext multCipher = scheme.mult(cipher1, cipher2); 118 | scheme.reScaleByAndEqual(multCipher, 1); 119 | timeutils.stop("Homomorphic Multiplication & Rescaling"); 120 | 121 | timeutils.start("Homomorphic Constant Multiplication & Rescaling"); 122 | Ciphertext cmultCipher = scheme.multByConstVec(cipher1, cvec, slots); 123 | scheme.reScaleByAndEqual(cmultCipher, 1); 124 | timeutils.stop("Homomorphic Constant Multiplication & Rescaling"); 125 | 126 | timeutils.start("Decrypt batch"); 127 | complex* dvecAdd = scheme.decrypt(secretKey, addCipher); 128 | complex* dvecCMult = scheme.decrypt(secretKey, cmultCipher); 129 | complex* dvecMult = scheme.decrypt(secretKey, multCipher); 130 | timeutils.stop("Decrypt batch"); 131 | 132 | StringUtils::showcompare(mvecAdd, dvecAdd, slots, "add"); 133 | StringUtils::showcompare(mvecMult, dvecMult, slots, "mult"); 134 | StringUtils::showcompare(mvecCMult, dvecCMult, slots, "cmult"); 135 | 136 | } 137 | 138 | void TestScheme::testConjugateBatch(long logN, long L, long logp, long logSlots) { 139 | cout << "!!! START TEST CONJUGATE BATCH !!!" << endl; 140 | TimeUtils timeutils; 141 | long K = L; 142 | Context context(logN, logp, L, K); 143 | SecretKey secretKey(context); 144 | Scheme scheme(secretKey, context); 145 | //----------------------------------------- 146 | scheme.addConjKey(secretKey); 147 | //----------------------------------------- 148 | srand(time(NULL)); 149 | //----------------------------------------- 150 | long slots = (1 << logSlots); 151 | complex* mvec = EvaluatorUtils::randomComplexArray(slots); 152 | complex* mvecconj = new complex[slots]; 153 | for (long i = 0; i < slots; ++i) { 154 | mvecconj[i] = conj(mvec[i]); 155 | } 156 | 157 | Ciphertext cipher = scheme.encrypt(mvec, slots, L); 158 | 159 | timeutils.start("Conjugate batch"); 160 | Ciphertext cconj = scheme.conjugate(cipher); 161 | timeutils.stop("Conjugate batch"); 162 | 163 | complex* dvecconj = scheme.decrypt(secretKey, cconj); 164 | 165 | StringUtils::showcompare(mvecconj, dvecconj, slots, "conj"); 166 | 167 | cout << "!!! END TEST CONJUGATE BATCH !!!" << endl; 168 | } 169 | 170 | void TestScheme::testimultBatch(long logN, long L, long logp, long logSlots) { 171 | cout << "!!! START TEST i MULTIPLICATION BATCH !!!" << endl; 172 | TimeUtils timeutils; 173 | long K = L; 174 | Context context(logN, logp, L, K); 175 | SecretKey secretKey(context); 176 | Scheme scheme(secretKey, context); 177 | //----------------------------------------- 178 | srand(time(NULL)); 179 | //----------------------------------------- 180 | long slots = (1 << logSlots); 181 | complex* mvec = EvaluatorUtils::randomComplexArray(slots); 182 | complex* imvec = new complex[slots]; 183 | for (long i = 0; i < slots; ++i) { 184 | imvec[i].real(-mvec[i].imag()); 185 | imvec[i].imag(mvec[i].real()); 186 | } 187 | 188 | Ciphertext cipher = scheme.encrypt(mvec, slots, L); 189 | 190 | timeutils.start("Multiplication by i batch"); 191 | Ciphertext icipher = scheme.imult(cipher); 192 | timeutils.stop("Multiplication by i batch"); 193 | 194 | complex* idvec = scheme.decrypt(secretKey, icipher); 195 | 196 | StringUtils::showcompare(imvec, idvec, slots, "imult"); 197 | 198 | cout << "!!! END TEST i MULTIPLICATION BATCH !!!" << endl; 199 | } 200 | 201 | void TestScheme::testRotateByPo2Batch(long logN, long L, long logp, long logRotSlots, long logSlots, bool isLeft) { 202 | cout << "!!! START TEST ROTATE BY POWER OF 2 BATCH !!!" << endl; 203 | //----------------------------------------- 204 | TimeUtils timeutils; 205 | long K = L + 1; 206 | Context context(logN, logp, L, K); 207 | SecretKey secretKey(context); 208 | Scheme scheme(secretKey, context); 209 | scheme.addLeftRotKeys(secretKey); 210 | scheme.addRightRotKeys(secretKey); 211 | //----------------------------------------- 212 | srand(time(NULL)); 213 | //----------------------------------------- 214 | long slots = (1 << logSlots); 215 | long rotSlots = (1 << logRotSlots); 216 | complex* mvec = EvaluatorUtils::randomComplexArray(slots); 217 | Ciphertext cipher = scheme.encrypt(mvec, slots, L); 218 | 219 | if(isLeft) { 220 | timeutils.start("Left Rotate by power of 2 batch"); 221 | scheme.leftRotateByPo2AndEqual(cipher, logRotSlots); 222 | timeutils.stop("Left Rotate by power of 2 batch"); 223 | } else { 224 | timeutils.start("Right Rotate by power of 2 batch"); 225 | scheme.rightRotateByPo2AndEqual(cipher, logRotSlots); 226 | timeutils.stop("Right Rotate by power of 2 batch"); 227 | } 228 | 229 | complex* dvec = scheme.decrypt(secretKey, cipher); 230 | 231 | if(isLeft) { 232 | EvaluatorUtils::leftRotateAndEqual(mvec, slots, rotSlots); 233 | } else { 234 | EvaluatorUtils::rightRotateAndEqual(mvec, slots, rotSlots); 235 | } 236 | 237 | StringUtils::showcompare(mvec, dvec, slots, "rot"); 238 | //----------------------------------------- 239 | cout << "!!! END TEST ROTATE BY POWER OF 2 BATCH !!!" << endl; 240 | } 241 | 242 | void TestScheme::testRotateBatch(long logN, long L, long logp, long rotSlots, long logSlots, bool isLeft) { 243 | cout << "!!! START TEST ROTATE BATCH !!!" << endl; 244 | //----------------------------------------- 245 | TimeUtils timeutils; 246 | long K = L; 247 | Context context(logN, logp, L, K); 248 | SecretKey secretKey(context); 249 | Scheme scheme(secretKey, context); 250 | scheme.addLeftRotKeys(secretKey); 251 | scheme.addRightRotKeys(secretKey); 252 | //----------------------------------------- 253 | srand(time(NULL)); 254 | //----------------------------------------- 255 | long slots = (1 << logSlots); 256 | complex* mvec = EvaluatorUtils::randomComplexArray(slots); 257 | Ciphertext cipher = scheme.encrypt(mvec, slots, L); 258 | 259 | if(isLeft) { 260 | timeutils.start("Left rotate batch"); 261 | scheme.leftRotateAndEqual(cipher, rotSlots); 262 | timeutils.stop("Left rotate batch"); 263 | } else { 264 | timeutils.start("Right rotate batch"); 265 | scheme.rightRotateAndEqual(cipher, rotSlots); 266 | timeutils.stop("Right rotate batch"); 267 | } 268 | 269 | complex* dvec = scheme.decrypt(secretKey, cipher); 270 | 271 | if(isLeft) { 272 | EvaluatorUtils::leftRotateAndEqual(mvec, slots, rotSlots); 273 | } else { 274 | EvaluatorUtils::rightRotateAndEqual(mvec, slots, rotSlots); 275 | } 276 | 277 | StringUtils::showcompare(mvec, dvec, slots, "rot"); 278 | 279 | cout << "!!! END TEST ROTATE BATCH !!!" << endl; 280 | } 281 | 282 | void TestScheme::testSlotsSum(long logN, long L, long logp, long logSlots) { 283 | cout << "!!! START TEST SLOTS SUM !!!" << endl; 284 | //----------------------------------------- 285 | TimeUtils timeutils; 286 | long K = L + 1; 287 | Context context(logN, logp, L, K); 288 | SecretKey secretKey(context); 289 | Scheme scheme(secretKey, context); 290 | SchemeAlgo algo(scheme); 291 | scheme.addLeftRotKeys(secretKey); 292 | //----------------------------------------- 293 | srand(time(NULL)); 294 | //----------------------------------------- 295 | long slots = (1 << logSlots); 296 | complex* mvec = EvaluatorUtils::randomComplexArray(slots); 297 | Ciphertext cipher = scheme.encrypt(mvec, slots, L); 298 | 299 | timeutils.start("slots sum"); 300 | algo.partialSlotsSumAndEqual(cipher, slots); 301 | timeutils.stop("slots sum"); 302 | 303 | complex* dvec = scheme.decrypt(secretKey, cipher); 304 | 305 | complex msum; 306 | for (long i = 0; i < slots; ++i) { 307 | msum += mvec[i]; 308 | } 309 | 310 | StringUtils::showcompare(msum, dvec, slots, "slotsum"); 311 | 312 | cout << "!!! END TEST SLOTS SUM !!!" << endl; 313 | } 314 | 315 | 316 | //---------------------------------------------------------------------------------- 317 | // POWER & PRODUCT TESTS 318 | //---------------------------------------------------------------------------------- 319 | 320 | 321 | void TestScheme::testPowerOf2Batch(long logN, long L, long logp, long logDegree, long logSlots) { 322 | cout << "!!! START TEST POWER OF 2 BATCH !!!" << endl; 323 | //----------------------------------------- 324 | TimeUtils timeutils; 325 | long K = L + 1; 326 | Context context(logN, logp, L, K); 327 | SecretKey secretKey(context); 328 | Scheme scheme(secretKey, context); 329 | SchemeAlgo algo(scheme); 330 | //----------------------------------------- 331 | srand(time(NULL)); 332 | //----------------------------------------- 333 | long slots = 1 << logSlots; 334 | long degree = 1 << logDegree; 335 | complex* mvec = new complex[slots]; 336 | complex* mpow = new complex[slots]; 337 | 338 | for (long i = 0; i < slots; ++i) { 339 | mvec[i] = EvaluatorUtils::randomCircle(); 340 | mpow[i] = pow(mvec[i], degree); 341 | } 342 | 343 | Ciphertext cipher = scheme.encrypt(mvec, slots, L); 344 | 345 | timeutils.start("Power of 2 batch"); 346 | Ciphertext cpow = algo.powerOf2(cipher, logDegree); 347 | timeutils.stop("Power of 2 batch"); 348 | 349 | complex* dpow = scheme.decrypt(secretKey, cpow); 350 | 351 | StringUtils::showcompare(mpow, dpow, slots, "pow2"); 352 | 353 | cout << "!!! END TEST POWER OF 2 BATCH !!!" << endl; 354 | } 355 | 356 | //----------------------------------------- 357 | 358 | void TestScheme::testPowerBatch(long logN, long L, long logp, long degree, long logSlots) { 359 | cout << "!!! START TEST POWER BATCH !!!" << endl; 360 | //----------------------------------------- 361 | TimeUtils timeutils; 362 | long K = L; 363 | Context context(logN, logp, L, K); 364 | SecretKey secretKey(context); 365 | Scheme scheme(secretKey, context); 366 | SchemeAlgo algo(scheme); 367 | //----------------------------------------- 368 | srand(time(NULL)); 369 | //----------------------------------------- 370 | long slots = 1 << logSlots; 371 | complex* mvec = EvaluatorUtils::randomCircleArray(slots); 372 | complex* mpow = new complex[slots]; 373 | for (long i = 0; i < slots; ++i) { 374 | mpow[i] = pow(mvec[i], degree); 375 | } 376 | 377 | Ciphertext cipher = scheme.encrypt(mvec, slots, L); 378 | 379 | timeutils.start("Power batch"); 380 | Ciphertext cpow = algo.power(cipher, degree); 381 | timeutils.stop("Power batch"); 382 | 383 | complex* dpow = scheme.decrypt(secretKey, cpow); 384 | 385 | StringUtils::showcompare(mpow, dpow, slots, "pow"); 386 | 387 | cout << "!!! END TEST POWER BATCH !!!" << endl; 388 | } 389 | 390 | //----------------------------------------- 391 | 392 | void TestScheme::testProdOfPo2Batch(long logN, long L, long logp, long logDegree, long logSlots) { 393 | cout << "!!! START TEST PROD OF POWER OF 2 BATCH !!!" << endl; 394 | //----------------------------------------- 395 | TimeUtils timeutils; 396 | long K = L; 397 | Context context(logN, logp, L, K); 398 | SecretKey secretKey(context); 399 | Scheme scheme(secretKey, context); 400 | SchemeAlgo algo(scheme); 401 | //----------------------------------------- 402 | srand(time(NULL)); 403 | //----------------------------------------- 404 | long slots = 1 << logSlots; 405 | long degree = 1 << logDegree; 406 | 407 | complex** mvec = new complex*[degree]; 408 | for (long i = 0; i < degree; ++i) { 409 | mvec[i] = EvaluatorUtils::randomCircleArray(slots); 410 | } 411 | 412 | complex* pvec = new complex[slots]; 413 | for (long j = 0; j < slots; ++j) { 414 | pvec[j] = mvec[0][j]; 415 | for (long i = 1; i < degree; ++i) { 416 | pvec[j] *= mvec[i][j]; 417 | } 418 | } 419 | 420 | Ciphertext* cvec = new Ciphertext[degree]; 421 | for (long i = 0; i < degree; ++i) { 422 | cvec[i] = scheme.encrypt(mvec[i], slots, L); 423 | } 424 | 425 | timeutils.start("Product of power of 2 batch"); 426 | Ciphertext cprod = algo.prodOfPo2(cvec, logDegree); 427 | timeutils.stop("Product of power of 2 batch"); 428 | 429 | complex* dvec = scheme.decrypt(secretKey, cprod); 430 | 431 | StringUtils::showcompare(pvec, dvec, slots, "prod"); 432 | 433 | cout << "!!! END TEST PROD OF POWER OF 2 BATCH !!!" << endl; 434 | } 435 | 436 | void TestScheme::testProdBatch(long logN, long L, long logp, long degree, long logSlots) { 437 | cout << "!!! START TEST PROD BATCH !!!" << endl; 438 | //----------------------------------------- 439 | TimeUtils timeutils; 440 | long K = L; 441 | Context context(logN, logp, L, K); 442 | SecretKey secretKey(context); 443 | Scheme scheme(secretKey, context); 444 | SchemeAlgo algo(scheme); 445 | //----------------------------------------- 446 | srand(time(NULL)); 447 | //----------------------------------------- 448 | long slots = 1 << logSlots; 449 | complex** mvec = new complex*[degree]; 450 | for (long i = 0; i < degree; ++i) { 451 | mvec[i] = EvaluatorUtils::randomCircleArray(slots); 452 | } 453 | 454 | complex* pvec = new complex[slots]; 455 | for (long j = 0; j < slots; ++j) { 456 | pvec[j] = mvec[0][j]; 457 | for (long i = 1; i < degree; ++i) { 458 | pvec[j] *= mvec[i][j]; 459 | } 460 | } 461 | 462 | Ciphertext* cvec = new Ciphertext[degree]; 463 | for (long i = 0; i < degree; ++i) { 464 | cvec[i] = scheme.encrypt(mvec[i], slots, L); 465 | } 466 | 467 | timeutils.start("Product batch"); 468 | Ciphertext cprod = algo.prod(cvec, degree); 469 | timeutils.stop("Product batch"); 470 | 471 | complex* dvec = scheme.decrypt(secretKey, cprod); 472 | 473 | StringUtils::showcompare(pvec, dvec, slots, "prod"); 474 | 475 | cout << "!!! END TEST PROD BATCH !!!" << endl; 476 | } 477 | 478 | 479 | //---------------------------------------------------------------------------------- 480 | // FUNCTION TESTS 481 | //---------------------------------------------------------------------------------- 482 | 483 | 484 | void TestScheme::testInverseBatch(long logN, long L, long logp, long invSteps, long logSlots) { 485 | cout << "!!! START TEST INVERSE BATCH !!!" << endl; 486 | //----------------------------------------- 487 | TimeUtils timeutils; 488 | long K = L + 1; 489 | Context context(logN, logp, L, K); 490 | SecretKey secretKey(context); 491 | Scheme scheme(secretKey, context); 492 | SchemeAlgo algo(scheme); 493 | //----------------------------------------- 494 | srand(time(NULL)); 495 | //----------------------------------------- 496 | long slots = 1 << logSlots; 497 | complex* mvec = EvaluatorUtils::randomCircleArray(slots, 0.1); 498 | complex* minv = new complex[slots]; 499 | for (long i = 0; i < slots; ++i) { 500 | minv[i] = 1. / mvec[i]; 501 | } 502 | 503 | Ciphertext cipher = scheme.encrypt(mvec, slots, L); 504 | 505 | timeutils.start("Inverse batch"); 506 | Ciphertext cinv = algo.inverse(cipher, invSteps); 507 | timeutils.stop("Inverse batch"); 508 | 509 | complex* dinv = scheme.decrypt(secretKey, cinv); 510 | 511 | StringUtils::showcompare(minv, dinv, slots, "inv"); 512 | 513 | cout << "!!! END TEST INVERSE BATCH !!!" << endl; 514 | } 515 | 516 | void TestScheme::testLogarithmBatch(long logN, long L, long logp, long degree, long logSlots) { 517 | cout << "!!! START TEST LOGARITHM BATCH !!!" << endl; 518 | //----------------------------------------- 519 | TimeUtils timeutils; 520 | long K = L; 521 | Context context(logN, logp, L, K); 522 | SecretKey secretKey(context); 523 | Scheme scheme(secretKey, context); 524 | SchemeAlgo algo(scheme); 525 | //----------------------------------------- 526 | srand(time(NULL)); 527 | //----------------------------------------- 528 | long slots = 1 << logSlots; 529 | complex* mvec = EvaluatorUtils::randomComplexArray(slots, 0.1); 530 | complex* mlog = new complex[slots]; 531 | for (long i = 0; i < slots; ++i) { 532 | mlog[i] = log(mvec[i] + 1.); 533 | } 534 | 535 | Ciphertext cipher = scheme.encrypt(mvec, slots, L); 536 | 537 | timeutils.start(LOGARITHM + " batch"); 538 | Ciphertext clog = algo.function(cipher, LOGARITHM, degree); 539 | timeutils.stop(LOGARITHM + " batch"); 540 | 541 | complex* dlog = scheme.decrypt(secretKey, clog); 542 | 543 | StringUtils::showcompare(mlog, dlog, slots, LOGARITHM); 544 | 545 | cout << "!!! END TEST LOGARITHM BATCH !!!" << endl; 546 | } 547 | 548 | void TestScheme::testExponentBatch(long logN, long L, long logp, long degree, long logSlots) { 549 | cout << "!!! START TEST EXPONENT BATCH !!!" << endl; 550 | //----------------------------------------- 551 | TimeUtils timeutils; 552 | long K = L; 553 | Context context(logN, logp, L, K); 554 | SecretKey secretKey(context); 555 | Scheme scheme(secretKey, context); 556 | SchemeAlgo algo(scheme); 557 | //----------------------------------------- 558 | srand(time(NULL)); 559 | //----------------------------------------- 560 | long slots = 1 << logSlots; 561 | complex* mvec = EvaluatorUtils::randomComplexArray(slots); 562 | complex* mexp = new complex[slots]; 563 | for (long i = 0; i < slots; ++i) { 564 | mexp[i] = exp(mvec[i]); 565 | } 566 | 567 | Ciphertext cipher = scheme.encrypt(mvec, slots, L); 568 | 569 | timeutils.start(EXPONENT + " batch"); 570 | Ciphertext cexp = algo.exponent(cipher, degree); 571 | timeutils.stop(EXPONENT + " batch"); 572 | 573 | complex* dexp = scheme.decrypt(secretKey, cexp); 574 | 575 | StringUtils::showcompare(mexp, dexp, slots, EXPONENT); 576 | 577 | cout << "!!! END TEST EXPONENT BATCH !!!" << endl; 578 | } 579 | 580 | //----------------------------------------- 581 | 582 | void TestScheme::testSigmoidBatch(long logN, long L, long logp, long degree, long logSlots) { 583 | cout << "!!! START TEST SIGMOID BATCH !!!" << endl; 584 | //----------------------------------------- 585 | TimeUtils timeutils; 586 | long K = L + 1; 587 | Context context(logN, logp, L, K); 588 | SecretKey secretKey(context); 589 | Scheme scheme(secretKey, context); 590 | SchemeAlgo algo(scheme); 591 | //----------------------------------------- 592 | srand(time(NULL)); 593 | //----------------------------------------- 594 | long slots = 1 << logSlots; 595 | 596 | complex* mvec = EvaluatorUtils::randomComplexArray(slots); 597 | complex* msig = new complex[slots]; 598 | for (long i = 0; i < slots; ++i) { 599 | msig[i] = exp(mvec[i]) / (1. + exp(mvec[i])); 600 | } 601 | 602 | Ciphertext cipher = scheme.encrypt(mvec, slots, L); 603 | 604 | timeutils.start(SIGMOID + " batch"); 605 | Ciphertext csig = algo.sigmoid(cipher, degree); 606 | timeutils.stop(SIGMOID + " batch"); 607 | 608 | complex* dsig = scheme.decrypt(secretKey, csig); 609 | 610 | StringUtils::showcompare(msig, dsig, slots, SIGMOID); 611 | 612 | cout << "!!! END TEST SIGMOID BATCH !!!" << endl; 613 | } 614 | -------------------------------------------------------------------------------- /src/TestScheme.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #ifndef HEAANNTT_TESTSCHEME_H_ 10 | #define HEAANNTT_TESTSCHEME_H_ 11 | 12 | #include 13 | 14 | using namespace std; 15 | 16 | class TestScheme { 17 | public: 18 | static void testEncodeSingle(long logN, long L, long logp); 19 | 20 | static void testEncodeBatch(long logN, long L, long logp, long logSlots); 21 | 22 | static void testBasic(long logN, long L, long logp, long logSlots); 23 | 24 | static void testConjugateBatch(long logN, long L, long logp, long logSlots); 25 | 26 | static void testimultBatch(long logN, long L, long logp, long logSlots); 27 | 28 | static void testRotateByPo2Batch(long logN, long L, long logp, long logRotSlots, long logSlots, bool isLeft); 29 | 30 | static void testRotateBatch(long logN, long L, long logp, long rotSlots, long logSlots, bool isLeft); 31 | 32 | static void testSlotsSum(long logN, long L, long logp, long logSlots); 33 | 34 | //---------------------------------------------------------------------------------- 35 | // POWER & PRODUCT TESTS 36 | //---------------------------------------------------------------------------------- 37 | 38 | static void testPowerOf2Batch(long logN, long L, long logp, long logDegree, long logSlots); 39 | 40 | static void testPowerBatch(long logN, long L, long logp, long degree, long logSlots); 41 | 42 | static void testProdOfPo2Batch(long logN, long L, long logp, long logDegree, long logSlots); 43 | 44 | static void testProdBatch(long logN, long L, long logp, long degree, long logSlots); 45 | 46 | //---------------------------------------------------------------------------------- 47 | // FUNCTION TESTS 48 | //---------------------------------------------------------------------------------- 49 | 50 | static void testInverseBatch(long logN, long L, long logp, long invSteps, long logSlots); 51 | 52 | static void testLogarithmBatch(long logN, long L, long logp, long degree, long logSlots); 53 | 54 | static void testExponentBatch(long logN, long L, long logp, long degree, long logSlots); 55 | 56 | static void testSigmoidBatch(long logN, long L, long logp, long degree, long logSlots); 57 | 58 | }; 59 | 60 | #endif /* TESTSCHEME_H_ */ 61 | -------------------------------------------------------------------------------- /src/TimeUtils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #include "TimeUtils.h" 10 | 11 | using namespace std; 12 | 13 | TimeUtils::TimeUtils() { 14 | timeElapsed = 0; 15 | } 16 | 17 | void TimeUtils::start(string msg) { 18 | cout << "------------------" << endl; 19 | cout <<"Start " + msg << endl; 20 | gettimeofday(&startTime, 0); 21 | } 22 | 23 | void TimeUtils::stop(string msg) { 24 | gettimeofday(&stopTime, 0); 25 | timeElapsed = (stopTime.tv_sec - startTime.tv_sec) * 1000.0; 26 | timeElapsed += (stopTime.tv_usec - startTime.tv_usec) / 1000.0; 27 | cout << msg + " time = "<< timeElapsed << " ms" << endl; 28 | cout << "------------------" << endl; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /src/TimeUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #ifndef HEAAN_TIMEUTILS_H_ 10 | #define HEAAN_TIMEUTILS_H_ 11 | 12 | #include "Common.h" 13 | 14 | struct timeval; 15 | 16 | using namespace std; 17 | 18 | class TimeUtils { 19 | public: 20 | 21 | struct timeval startTime, stopTime; 22 | double timeElapsed; 23 | 24 | //----------------------------------------- 25 | 26 | TimeUtils(); 27 | 28 | //----------------------------------------- 29 | 30 | /** 31 | * starts timer 32 | * @param[in] string message 33 | */ 34 | void start(string msg); 35 | 36 | /** 37 | * stops timer and prints time elapsed in console 38 | * @param[in] string message 39 | */ 40 | void stop(string msg); 41 | 42 | //----------------------------------------- 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) by CryptoLab inc. 3 | * This program is licensed under a 4 | * Creative Commons Attribution-NonCommercial 3.0 Unported License. 5 | * You should have received a copy of the license along with this 6 | * work. If not, see . 7 | */ 8 | 9 | #include "TestScheme.h" 10 | #include "Numb.h" 11 | 12 | int main() { 13 | 14 | TestScheme::testEncodeSingle(14, 1, 55); 15 | 16 | TestScheme::testEncodeBatch(15, 6, 55, 3); 17 | 18 | TestScheme::testBasic(15, 11, 55, 3); 19 | 20 | // TestScheme::testConjugateBatch(15, 6, 55, 1); 21 | 22 | // TestScheme::testRotateByPo2Batch(16, 26, 40, 1, 4, false); 23 | 24 | // TestScheme::testRotateBatch(15, 6, 55, 3, 4, true); 25 | 26 | // TestScheme::testimultBatch(16, 16, 55, 2); 27 | 28 | // TestScheme::testPowerOf2Batch(16, 15, 50, 2, 3); 29 | 30 | TestScheme::testInverseBatch(14, 5, 55, 4, 3); 31 | 32 | TestScheme::testExponentBatch(14, 5, 55, 7, 3); 33 | 34 | TestScheme::testSigmoidBatch(16, 15, 55, 3, 3); 35 | 36 | // TestScheme::testSlotsSum(16, 15, 40, 3); 37 | 38 | // TestScheme::testMeanVariance(14, 3, 55, 13); 39 | 40 | // TestScheme::testHEML("data/uis.txt", 0, 5); 41 | 42 | return 0; 43 | } 44 | --------------------------------------------------------------------------------