├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── SECURITY.md ├── VisualStudio ├── frodo.sln ├── frodo.vcxproj ├── frodo.vcxproj.filters ├── test_kex │ ├── test_kex.vcxproj │ └── test_kex.vcxproj.filters └── test_rand │ ├── test_rand.vcxproj │ └── test_rand.vcxproj.filters ├── src ├── aes │ ├── aes.c │ ├── aes.h │ ├── aes_c.c │ ├── aes_local.h │ ├── aes_ni.c │ └── test_aes.c ├── frodo.h ├── frodo_macrify.h ├── kex.c ├── kex.h ├── kex_lwe_frodo.c ├── kex_lwe_frodo.h ├── kex_lwe_frodo_macrify.c ├── lwe.c ├── lwe_macrify.c ├── lwe_macrify_reference.c ├── lwe_noise.c ├── random │ ├── rand.c │ ├── rand.h │ ├── rand_urandom_aesctr │ │ ├── rand_urandom_aesctr.c │ │ └── rand_urandom_aesctr.h │ └── test_rand.c └── sha3 │ ├── fips202.c │ ├── fips202.h │ ├── fips202x4.c │ ├── fips202x4.h │ └── keccak4x │ ├── KeccakP-1600-times4-SIMD256.c │ ├── KeccakP-1600-times4-SnP.h │ ├── KeccakP-1600-unrolling.macros │ ├── KeccakP-1600-unrolling.txt │ ├── SIMD256-config.h │ ├── align.h │ └── brg_endian.h └── tests ├── ds_benchmark.h └── test_kex.c /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # .NET Core 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | **/Properties/launchSettings.json 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # Visual Studio code coverage results 117 | *.coverage 118 | *.coveragexml 119 | 120 | # NCrunch 121 | _NCrunch_* 122 | .*crunch*.local.xml 123 | nCrunchTemp_* 124 | 125 | # MightyMoose 126 | *.mm.* 127 | AutoTest.Net/ 128 | 129 | # Web workbench (sass) 130 | .sass-cache/ 131 | 132 | # Installshield output folder 133 | [Ee]xpress/ 134 | 135 | # DocProject is a documentation generator add-in 136 | DocProject/buildhelp/ 137 | DocProject/Help/*.HxT 138 | DocProject/Help/*.HxC 139 | DocProject/Help/*.hhc 140 | DocProject/Help/*.hhk 141 | DocProject/Help/*.hhp 142 | DocProject/Help/Html2 143 | DocProject/Help/html 144 | 145 | # Click-Once directory 146 | publish/ 147 | 148 | # Publish Web Output 149 | *.[Pp]ublish.xml 150 | *.azurePubxml 151 | # TODO: Comment the next line if you want to checkin your web deploy settings 152 | # but database connection strings (with potential passwords) will be unencrypted 153 | *.pubxml 154 | *.publishproj 155 | 156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 157 | # checkin your Azure Web App publish settings, but sensitive information contained 158 | # in these scripts will be unencrypted 159 | PublishScripts/ 160 | 161 | # NuGet Packages 162 | *.nupkg 163 | # The packages folder can be ignored because of Package Restore 164 | **/packages/* 165 | # except build/, which is used as an MSBuild target. 166 | !**/packages/build/ 167 | # Uncomment if necessary however generally it will be regenerated when needed 168 | #!**/packages/repositories.config 169 | # NuGet v3's project.json files produces more ignorable files 170 | *.nuget.props 171 | *.nuget.targets 172 | 173 | # Microsoft Azure Build Output 174 | csx/ 175 | *.build.csdef 176 | 177 | # Microsoft Azure Emulator 178 | ecf/ 179 | rcf/ 180 | 181 | # Windows Store app package directories and files 182 | AppPackages/ 183 | BundleArtifacts/ 184 | Package.StoreAssociation.xml 185 | _pkginfo.txt 186 | 187 | # Visual Studio cache files 188 | # files ending in .cache can be ignored 189 | *.[Cc]ache 190 | # but keep track of directories ending in .cache 191 | !*.[Cc]ache/ 192 | 193 | # Others 194 | ClientBin/ 195 | ~$* 196 | *~ 197 | *.dbmdl 198 | *.dbproj.schemaview 199 | *.jfm 200 | *.pfx 201 | *.publishsettings 202 | orleans.codegen.cs 203 | 204 | # Since there are multiple workflows, uncomment next line to ignore bower_components 205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 206 | #bower_components/ 207 | 208 | # RIA/Silverlight projects 209 | Generated_Code/ 210 | 211 | # Backup & report files from converting an old project file 212 | # to a newer Visual Studio version. Backup files are not needed, 213 | # because we have git ;-) 214 | _UpgradeReport_Files/ 215 | Backup*/ 216 | UpgradeLog*.XML 217 | UpgradeLog*.htm 218 | 219 | # SQL Server files 220 | *.mdf 221 | *.ldf 222 | *.ndf 223 | 224 | # Business Intelligence projects 225 | *.rdl.data 226 | *.bim.layout 227 | *.bim_*.settings 228 | 229 | # Microsoft Fakes 230 | FakesAssemblies/ 231 | 232 | # GhostDoc plugin setting file 233 | *.GhostDoc.xml 234 | 235 | # Node.js Tools for Visual Studio 236 | .ntvs_analysis.dat 237 | node_modules/ 238 | 239 | # Typescript v1 declaration files 240 | typings/ 241 | 242 | # Visual Studio 6 build log 243 | *.plg 244 | 245 | # Visual Studio 6 workspace options file 246 | *.opt 247 | 248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 249 | *.vbw 250 | 251 | # Visual Studio LightSwitch build output 252 | **/*.HTMLClient/GeneratedArtifacts 253 | **/*.DesktopClient/GeneratedArtifacts 254 | **/*.DesktopClient/ModelManifest.xml 255 | **/*.Server/GeneratedArtifacts 256 | **/*.Server/ModelManifest.xml 257 | _Pvt_Extensions 258 | 259 | # Paket dependency manager 260 | .paket/paket.exe 261 | paket-files/ 262 | 263 | # FAKE - F# Make 264 | .fake/ 265 | 266 | # JetBrains Rider 267 | .idea/ 268 | *.sln.iml 269 | 270 | # CodeRush 271 | .cr/ 272 | 273 | # Python Tools for Visual Studio (PTVS) 274 | __pycache__/ 275 | *.pyc 276 | 277 | # Cake - Uncomment if you are using it 278 | # tools/** 279 | # !tools/packages.config 280 | 281 | # Telerik's JustMock configuration file 282 | *.jmconfig 283 | 284 | # BizTalk build output 285 | *.btp.cs 286 | *.btm.cs 287 | *.odx.cs 288 | *.xsd.cs 289 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #### Makefile for compilation on Linux #### 2 | 3 | CC=gcc 4 | ifeq "$(CC)" "gcc" 5 | COMPILER=gcc 6 | else ifeq "$(CC)" "clang" 7 | COMPILER=clang 8 | endif 9 | 10 | ARCH=x64 11 | ifeq "$(ARCH)" "x64" 12 | ARCHITECTURE=_AMD64_ 13 | else ifeq "$(ARCH)" "x86" 14 | ARCHITECTURE=_X86_ 15 | else ifeq "$(ARCH)" "ARM" 16 | ARCHITECTURE=_ARM_ 17 | endif 18 | 19 | AR=ar rcs 20 | RANLIB=ranlib 21 | LN=ln -s 22 | 23 | CFLAGS= -O3 -std=gnu11 -Wall -Wextra -march=native -DLINUX -D $(ARCHITECTURE) 24 | LDFLAGS=-lm 25 | INCLUDES=-Iinclude 26 | 27 | ifeq "$(ARCH)" "x64" 28 | ifeq "$(USE_AVX2)" "FALSE" 29 | else 30 | CFLAGS += -DAVX2 31 | endif 32 | ifeq "$(AES_NI)" "FALSE" 33 | CFLAGS += -DAES_DISABLE_NI 34 | else 35 | CFLAGS += -maes -msse2 -DAES_ENABLE_NI 36 | endif 37 | else 38 | CFLAGS += -DAES_DISABLE_NI 39 | endif 40 | 41 | ifeq "$(USE_REFERENCE)" "TRUE" 42 | CFLAGS += -DREFERENCE 43 | endif 44 | 45 | .PHONY: all check clean prettyprint 46 | 47 | all: links lib tests 48 | 49 | objs/%.o: src/%.c 50 | @mkdir -p $(@D) 51 | $(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@ 52 | 53 | links: 54 | rm -rf include/frodo 55 | mkdir -p include/frodo 56 | $(LN) ../../src/aes/aes.h include/frodo 57 | $(LN) ../../src/frodo.h include/frodo 58 | $(LN) ../../src/frodo_macrify.h include/frodo 59 | $(LN) ../../src/kex.h include/frodo 60 | $(LN) ../../src/kex_lwe_frodo.h include/frodo 61 | $(LN) ../../src/random/rand.h include/frodo 62 | $(LN) ../../src/random/rand_urandom_aesctr/rand_urandom_aesctr.h include/frodo 63 | $(LN) ../../src/sha3/fips202.h include/frodo 64 | $(LN) ../../src/sha3/fips202x4.h include/frodo 65 | 66 | # RAND_URANDOM_AESCTR 67 | RAND_URANDOM_AESCTR_OBJS := $(addprefix objs/random/rand_urandom_aesctr/, rand_urandom_aesctr.o) 68 | $(RAND_URANDOM_AESCTR_OBJS): src/random/rand_urandom_aesctr/rand_urandom_aesctr.h 69 | 70 | # RAND 71 | objs/random/rand.o: src/random/rand.h 72 | 73 | # KEX_LWE_FRODO 74 | KEX_LWE_FRODO_OBJS := $(addprefix objs/, lwe.o kex_lwe_frodo.o lwe_noise.o) 75 | KEX_LWE_FRODO_HEADERS := $(addprefix src/, kex_lwe_frodo.h frodo_macrify.h) 76 | $(KEX_LWE_FRODO_OBJS): $(KEX_LWE_FRODO_HEADERS) 77 | 78 | # AES 79 | AES_OBJS := $(addprefix objs/aes/, aes.o aes_c.o aes_ni.o) 80 | AES_HEADERS := $(addprefix src/aes/, aes.h) 81 | $(AES_OBJS): $(AES_HEADERS) 82 | 83 | # SHAKE 84 | SHAKE_OBJS := $(addprefix objs/sha3/, fips202.o) 85 | SHAKE_HEADERS := $(addprefix src/sha3/, fips202.h) 86 | $(SHAKE_OBJS): $(SHAKE_HEADERS) 87 | 88 | # SHAKEx4 89 | ifneq "$(ARCH)" "ARM" 90 | SHAKEx4_OBJS := $(addprefix objs/sha3/, fips202x4.o keccak4x/KeccakP-1600-times4-SIMD256.o) 91 | SHAKEx4_HEADERS := $(addprefix src/sha3/, fips202x4.h keccak4x/KeccakP-1600-times4-SnP.h) 92 | $(SHAKEx4_OBJS): $(SHAKEx4_HEADERS) 93 | endif 94 | 95 | # KEX 96 | objs/kex/kex.o: src/kex.h 97 | 98 | RAND_OBJS := $(RAND_URANDOM_AESCTR_OBJS) $(RAND_URANDOM_CHACHA_OBJS) objs/random/rand.o 99 | 100 | KEX_OBJS := $(KEX_LWE_FRODO_OBJS) objs/kex.o 101 | 102 | lib: $(RAND_OBJS) $(KEX_OBJS) $(AES_OBJS) $(SHAKE_OBJS) $(SHAKEx4_OBJS) 103 | rm -f libfrodo.a 104 | $(AR) libfrodo.a $^ 105 | $(RANLIB) libfrodo.a 106 | 107 | tests: lib src/random/test_rand.c tests/test_kex.c src/aes/test_aes.c tests/ds_benchmark.h 108 | $(CC) $(CFLAGS) $(INCLUDES) -L. src/random/test_rand.c -lfrodo $(LDFLAGS) -o test_rand 109 | $(CC) $(CFLAGS) $(INCLUDES) -L. tests/test_kex.c -lfrodo $(LDFLAGS) -o test_kex 110 | $(CC) $(CFLAGS) $(INCLUDES) -L. src/aes/test_aes.c -lfrodo $(LDFLAGS) -o test_aes 111 | 112 | docs: links 113 | doxygen 114 | 115 | check: links tests 116 | ./test_kex 117 | ./test_rand 118 | ./test_aes 119 | 120 | clean: 121 | rm -rf docs objs include 122 | rm -f test_rand test_kex test_aes libfrodo.a 123 | find . -name .DS_Store -type f -delete 124 | 125 | prettyprint: 126 | astyle --style=java --indent=tab --pad-header --pad-oper --align-pointer=name --align-reference=name --suffix=none src/*.h src/*/*.h src/*/*.c 127 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | LWE Library 2 | =========== 3 | 4 | This library implements Frodo, a lattice-based key exchange based on the Learning with Errors (LWE) problem. 5 | The library uses Frodo's "recommended parameters". See [1] for details. 6 | 7 | The library was developed by Microsoft Research for experimentation purposes. 8 | 9 | Building and Running 10 | -------------------- 11 | 12 | On Windows, the library builds with Visual Studio 2015, using the solution file (frodo.sln) in the "VisualStudio" folder. It has been tested with Windows 10. 13 | On Linux, the library builds with GNU GCC or clang. It has been tested on Ubuntu 16.04 using GNU GCC version 5.4, and clang 3.8. 14 | 15 | ### Linux 16 | 17 | To build, type with the following options: 18 | 19 | $ make ARCH=[x64/x86/ARM] CC=[gcc/clang] USE_REFERENCE=[TRUE/FALSE] USE_AVX2=[TRUE/FALSE] AES_NI=[TRUE/FALSE] 20 | 21 | When simply typing: 22 | 23 | $make 24 | 25 | the library is built using ARCH=x64, CC=gcc, USE_REFERENCE=FALSE, USE_AVX2=TRUE and AES_NI=TRUE, by default. 26 | 27 | Building generates: 28 | 29 | - `libfrodo.a`: a static library based on Frodo. 30 | - `test_aes`: a test harness for AES. 31 | - `test_rand`: a test harness for the random number generator. 32 | - `test_kex`: a test harness for Frodo. 33 | 34 | To run the tests for Frodo, simply type: 35 | 36 | $ ./test_kex 37 | 38 | License 39 | ------- 40 | 41 | The library is licensed under the MIT License. Part of the implementation is based on liboqs, also released under MIT. 42 | The library includes third party modules which have been released as public domain. Specifically: 43 | 44 | - `src/aes/aes.c`: public domain 45 | - `src/aes/aes_c.c`: public domain 46 | - `src/aes/aes_ni.c`: public domain 47 | - `src/sha3/fips202.c`: public domain 48 | - `src/sha3/fips202x4.c`: public domain 49 | 50 | Reference 51 | --------- 52 | [1] Joppe W. Bos, Craig Costello, Leo Ducas, Ilya Mironov, Michael Naehrig, Valeria Nikolaenko, Ananth Raghunathan, and Douglas Stebila, "Frodo: Take off the Ring! Practical, Quantum-Secure Key Exchange from LWE". 53 | ACM CCS 2016, 2016. The extended version is available at: https://eprint.iacr.org/2016/659. 54 | 55 | # Contributing 56 | 57 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 58 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 59 | the rights to use your contribution. For details, visit https://cla.microsoft.com. 60 | 61 | When you submit a pull request, a CLA-bot will automatically determine whether you need to provide 62 | a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions 63 | provided by the bot. You will only need to do this once across all repos using our CLA. 64 | 65 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 66 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 67 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 68 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /VisualStudio/frodo.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_rand", "test_rand\test_rand.vcxproj", "{6BB96591-0BCD-42E6-8863-4B9BFE75530C}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {DCFEFB81-4696-45D2-9FCA-351CCFC13C74} = {DCFEFB81-4696-45D2-9FCA-351CCFC13C74} 9 | EndProjectSection 10 | EndProject 11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_kex", "test_kex\test_kex.vcxproj", "{820B79FE-57D7-4539-A0CA-B668A0723B9B}" 12 | ProjectSection(ProjectDependencies) = postProject 13 | {DCFEFB81-4696-45D2-9FCA-351CCFC13C74} = {DCFEFB81-4696-45D2-9FCA-351CCFC13C74} 14 | EndProjectSection 15 | EndProject 16 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Frodo", "frodo.vcxproj", "{DCFEFB81-4696-45D2-9FCA-351CCFC13C74}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|x64 = Debug|x64 21 | Debug|x86 = Debug|x86 22 | Reference|x64 = Reference|x64 23 | Reference|x86 = Reference|x86 24 | Release|x64 = Release|x64 25 | Release|x86 = Release|x86 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {6BB96591-0BCD-42E6-8863-4B9BFE75530C}.Debug|x64.ActiveCfg = Debug|x64 29 | {6BB96591-0BCD-42E6-8863-4B9BFE75530C}.Debug|x64.Build.0 = Debug|x64 30 | {6BB96591-0BCD-42E6-8863-4B9BFE75530C}.Debug|x86.ActiveCfg = Debug|Win32 31 | {6BB96591-0BCD-42E6-8863-4B9BFE75530C}.Debug|x86.Build.0 = Debug|Win32 32 | {6BB96591-0BCD-42E6-8863-4B9BFE75530C}.Reference|x64.ActiveCfg = Reference|x64 33 | {6BB96591-0BCD-42E6-8863-4B9BFE75530C}.Reference|x64.Build.0 = Reference|x64 34 | {6BB96591-0BCD-42E6-8863-4B9BFE75530C}.Reference|x86.ActiveCfg = Reference|Win32 35 | {6BB96591-0BCD-42E6-8863-4B9BFE75530C}.Reference|x86.Build.0 = Reference|Win32 36 | {6BB96591-0BCD-42E6-8863-4B9BFE75530C}.Release|x64.ActiveCfg = Release|x64 37 | {6BB96591-0BCD-42E6-8863-4B9BFE75530C}.Release|x64.Build.0 = Release|x64 38 | {6BB96591-0BCD-42E6-8863-4B9BFE75530C}.Release|x86.ActiveCfg = Release|Win32 39 | {6BB96591-0BCD-42E6-8863-4B9BFE75530C}.Release|x86.Build.0 = Release|Win32 40 | {820B79FE-57D7-4539-A0CA-B668A0723B9B}.Debug|x64.ActiveCfg = Debug|x64 41 | {820B79FE-57D7-4539-A0CA-B668A0723B9B}.Debug|x64.Build.0 = Debug|x64 42 | {820B79FE-57D7-4539-A0CA-B668A0723B9B}.Debug|x86.ActiveCfg = Debug|Win32 43 | {820B79FE-57D7-4539-A0CA-B668A0723B9B}.Debug|x86.Build.0 = Debug|Win32 44 | {820B79FE-57D7-4539-A0CA-B668A0723B9B}.Reference|x64.ActiveCfg = Reference|x64 45 | {820B79FE-57D7-4539-A0CA-B668A0723B9B}.Reference|x64.Build.0 = Reference|x64 46 | {820B79FE-57D7-4539-A0CA-B668A0723B9B}.Reference|x86.ActiveCfg = Reference|Win32 47 | {820B79FE-57D7-4539-A0CA-B668A0723B9B}.Reference|x86.Build.0 = Reference|Win32 48 | {820B79FE-57D7-4539-A0CA-B668A0723B9B}.Release|x64.ActiveCfg = Release|x64 49 | {820B79FE-57D7-4539-A0CA-B668A0723B9B}.Release|x64.Build.0 = Release|x64 50 | {820B79FE-57D7-4539-A0CA-B668A0723B9B}.Release|x86.ActiveCfg = Release|Win32 51 | {820B79FE-57D7-4539-A0CA-B668A0723B9B}.Release|x86.Build.0 = Release|Win32 52 | {DCFEFB81-4696-45D2-9FCA-351CCFC13C74}.Debug|x64.ActiveCfg = Debug|x64 53 | {DCFEFB81-4696-45D2-9FCA-351CCFC13C74}.Debug|x64.Build.0 = Debug|x64 54 | {DCFEFB81-4696-45D2-9FCA-351CCFC13C74}.Debug|x86.ActiveCfg = Debug|Win32 55 | {DCFEFB81-4696-45D2-9FCA-351CCFC13C74}.Debug|x86.Build.0 = Debug|Win32 56 | {DCFEFB81-4696-45D2-9FCA-351CCFC13C74}.Reference|x64.ActiveCfg = Reference|x64 57 | {DCFEFB81-4696-45D2-9FCA-351CCFC13C74}.Reference|x64.Build.0 = Reference|x64 58 | {DCFEFB81-4696-45D2-9FCA-351CCFC13C74}.Reference|x86.ActiveCfg = Reference|Win32 59 | {DCFEFB81-4696-45D2-9FCA-351CCFC13C74}.Reference|x86.Build.0 = Reference|Win32 60 | {DCFEFB81-4696-45D2-9FCA-351CCFC13C74}.Release|x64.ActiveCfg = Release|x64 61 | {DCFEFB81-4696-45D2-9FCA-351CCFC13C74}.Release|x64.Build.0 = Release|x64 62 | {DCFEFB81-4696-45D2-9FCA-351CCFC13C74}.Release|x86.ActiveCfg = Release|Win32 63 | {DCFEFB81-4696-45D2-9FCA-351CCFC13C74}.Release|x86.Build.0 = Release|Win32 64 | EndGlobalSection 65 | GlobalSection(SolutionProperties) = preSolution 66 | HideSolutionNode = FALSE 67 | EndGlobalSection 68 | EndGlobal 69 | -------------------------------------------------------------------------------- /VisualStudio/frodo.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Source Files\AES 6 | 7 | 8 | Source Files\AES 9 | 10 | 11 | Source Files\AES 12 | 13 | 14 | Source Files\random 15 | 16 | 17 | Source Files\random 18 | 19 | 20 | Source Files 21 | 22 | 23 | Source Files 24 | 25 | 26 | Source Files 27 | 28 | 29 | Source Files 30 | 31 | 32 | Source Files 33 | 34 | 35 | Source Files 36 | 37 | 38 | Source Files\random 39 | 40 | 41 | Source Files\sha3 42 | 43 | 44 | Source Files 45 | 46 | 47 | Source Files\sha3 48 | 49 | 50 | Source Files\sha3\fips202x4 51 | 52 | 53 | 54 | 55 | Source Files\AES 56 | 57 | 58 | Source Files\random 59 | 60 | 61 | Source Files\random 62 | 63 | 64 | Header Files 65 | 66 | 67 | Header Files 68 | 69 | 70 | Header Files 71 | 72 | 73 | Header Files 74 | 75 | 76 | Source Files\random 77 | 78 | 79 | Source Files\sha3 80 | 81 | 82 | Source Files\sha3 83 | 84 | 85 | Source Files\sha3\fips202x4 86 | 87 | 88 | Source Files\sha3\fips202x4 89 | 90 | 91 | Source Files\sha3\fips202x4 92 | 93 | 94 | Source Files\sha3\fips202x4 95 | 96 | 97 | 98 | 99 | {47469e83-ec7a-4d69-baf0-ab15e961629e} 100 | 101 | 102 | {7041c366-2ed8-4a00-8e92-4f6e2471eb9d} 103 | 104 | 105 | {71c917ec-9181-4b88-bdfc-9611ee1abe9a} 106 | 107 | 108 | {fd44eb34-2f81-411e-a55f-f279c4b101de} 109 | 110 | 111 | {656e58e0-96ef-4f93-9711-0ebe15c55da2} 112 | 113 | 114 | {a4e39759-10c0-4a8e-bbf8-6462b7fe0c2f} 115 | 116 | 117 | 118 | 119 | Source Files\sha3\fips202x4 120 | 121 | 122 | -------------------------------------------------------------------------------- /VisualStudio/test_kex/test_kex.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Reference 10 | Win32 11 | 12 | 13 | Reference 14 | x64 15 | 16 | 17 | Release 18 | Win32 19 | 20 | 21 | Debug 22 | x64 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | {820B79FE-57D7-4539-A0CA-B668A0723B9B} 37 | Win32Proj 38 | test_kex 39 | 8.1 40 | 41 | 42 | 43 | Application 44 | true 45 | v140 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v140 52 | true 53 | Unicode 54 | 55 | 56 | Application 57 | false 58 | v140 59 | true 60 | Unicode 61 | 62 | 63 | Application 64 | true 65 | v140 66 | Unicode 67 | 68 | 69 | Application 70 | false 71 | v140 72 | true 73 | Unicode 74 | 75 | 76 | Application 77 | false 78 | v140 79 | true 80 | Unicode 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | true 108 | $(SolutionDir)$(Platform)\$(Configuration)\ 109 | $(Platform)\$(Configuration)\ 110 | 111 | 112 | 113 | 114 | 115 | true 116 | 117 | 118 | 119 | 120 | 121 | false 122 | $(SolutionDir)$(Platform)\$(Configuration)\ 123 | $(Platform)\$(Configuration)\ 124 | 125 | 126 | 127 | 128 | 129 | false 130 | $(SolutionDir)$(Platform)\$(Configuration)\ 131 | $(Platform)\$(Configuration)\ 132 | 133 | 134 | 135 | 136 | 137 | false 138 | 139 | 140 | 141 | 142 | 143 | false 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | Level3 153 | Disabled 154 | WINDOWS;_X86_;_CRT_SECURE_NO_WARNINGS; 155 | true 156 | 157 | 158 | MultiThreadedDebug 159 | 160 | 161 | Console 162 | true 163 | $(SolutionDir)$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories) 164 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;frodo.lib;%(AdditionalDependencies) 165 | 166 | 167 | false 168 | 169 | 170 | 171 | 172 | 173 | 174 | Level3 175 | Disabled 176 | WINDOWS;_AMD64_;_CRT_SECURE_NO_WARNINGS; 177 | true 178 | 179 | 180 | MultiThreadedDebug 181 | 182 | 183 | Console 184 | true 185 | $(SolutionDir)$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories) 186 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;frodo.lib;%(AdditionalDependencies) 187 | 188 | 189 | false 190 | 191 | 192 | 193 | 194 | Level3 195 | 196 | 197 | Disabled 198 | true 199 | true 200 | WINDOWS;_X86_;_CRT_SECURE_NO_WARNINGS; 201 | true 202 | 203 | 204 | MultiThreaded 205 | 206 | 207 | Console 208 | true 209 | true 210 | true 211 | $(SolutionDir)$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories) 212 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;frodo.lib;%(AdditionalDependencies) 213 | 214 | 215 | false 216 | 217 | 218 | 219 | 220 | Level3 221 | 222 | 223 | Disabled 224 | true 225 | true 226 | WINDOWS;_X86_;_CRT_SECURE_NO_WARNINGS; 227 | true 228 | 229 | 230 | MultiThreaded 231 | 232 | 233 | Console 234 | true 235 | true 236 | true 237 | $(SolutionDir)$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories) 238 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;frodo.lib;%(AdditionalDependencies) 239 | 240 | 241 | false 242 | 243 | 244 | 245 | 246 | Level3 247 | 248 | 249 | Disabled 250 | true 251 | true 252 | WINDOWS;_AMD64_;_CRT_SECURE_NO_WARNINGS; 253 | true 254 | 255 | 256 | MultiThreaded 257 | 258 | 259 | Console 260 | true 261 | true 262 | true 263 | $(SolutionDir)$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories) 264 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;frodo.lib;%(AdditionalDependencies) 265 | 266 | 267 | false 268 | 269 | 270 | 271 | 272 | Level3 273 | 274 | 275 | Disabled 276 | true 277 | true 278 | WINDOWS;_AMD64_;_CRT_SECURE_NO_WARNINGS; 279 | true 280 | 281 | 282 | MultiThreaded 283 | 284 | 285 | Console 286 | true 287 | true 288 | true 289 | $(SolutionDir)$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories) 290 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;frodo.lib;%(AdditionalDependencies) 291 | 292 | 293 | false 294 | 295 | 296 | 297 | 298 | 299 | -------------------------------------------------------------------------------- /VisualStudio/test_kex/test_kex.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | 23 | 24 | Header Files 25 | 26 | 27 | -------------------------------------------------------------------------------- /VisualStudio/test_rand/test_rand.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Reference 10 | Win32 11 | 12 | 13 | Reference 14 | x64 15 | 16 | 17 | Release 18 | Win32 19 | 20 | 21 | Debug 22 | x64 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | 31 | 32 | 33 | {6BB96591-0BCD-42E6-8863-4B9BFE75530C} 34 | Win32Proj 35 | test_rand 36 | 8.1 37 | 38 | 39 | 40 | Application 41 | true 42 | v140 43 | Unicode 44 | 45 | 46 | Application 47 | false 48 | v140 49 | true 50 | Unicode 51 | 52 | 53 | Application 54 | false 55 | v140 56 | true 57 | Unicode 58 | 59 | 60 | Application 61 | true 62 | v140 63 | Unicode 64 | 65 | 66 | Application 67 | false 68 | v140 69 | true 70 | Unicode 71 | 72 | 73 | Application 74 | false 75 | v140 76 | true 77 | Unicode 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | true 105 | $(SolutionDir)$(Platform)\$(Configuration)\ 106 | $(Platform)\$(Configuration)\ 107 | 108 | 109 | 110 | 111 | 112 | true 113 | 114 | 115 | 116 | 117 | 118 | false 119 | $(SolutionDir)$(Platform)\$(Configuration)\ 120 | $(Platform)\$(Configuration)\ 121 | 122 | 123 | 124 | 125 | 126 | false 127 | $(SolutionDir)$(Platform)\$(Configuration)\ 128 | $(Platform)\$(Configuration)\ 129 | 130 | 131 | 132 | 133 | 134 | false 135 | 136 | 137 | 138 | 139 | 140 | false 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | Level3 150 | Disabled 151 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 152 | true 153 | 154 | 155 | MultiThreadedDebug 156 | 157 | 158 | Console 159 | true 160 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;frodo.lib;%(AdditionalDependencies) 161 | $(SolutionDir)$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories) 162 | 163 | 164 | 165 | 166 | 167 | 168 | Level3 169 | Disabled 170 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 171 | true 172 | 173 | 174 | MultiThreadedDebug 175 | 176 | 177 | Console 178 | true 179 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;frodo.lib;%(AdditionalDependencies) 180 | $(SolutionDir)$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories) 181 | 182 | 183 | 184 | 185 | Level3 186 | 187 | 188 | Disabled 189 | true 190 | true 191 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 192 | true 193 | 194 | 195 | MultiThreaded 196 | 197 | 198 | Console 199 | true 200 | true 201 | true 202 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;frodo.lib;%(AdditionalDependencies) 203 | $(SolutionDir)$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories) 204 | 205 | 206 | 207 | 208 | Level3 209 | 210 | 211 | Disabled 212 | true 213 | true 214 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 215 | true 216 | 217 | 218 | MultiThreaded 219 | 220 | 221 | Console 222 | true 223 | true 224 | true 225 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;frodo.lib;%(AdditionalDependencies) 226 | $(SolutionDir)$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories) 227 | 228 | 229 | 230 | 231 | Level3 232 | 233 | 234 | Disabled 235 | true 236 | true 237 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 238 | true 239 | 240 | 241 | MultiThreaded 242 | 243 | 244 | Console 245 | true 246 | true 247 | true 248 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;frodo.lib;%(AdditionalDependencies) 249 | $(SolutionDir)$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories) 250 | 251 | 252 | 253 | 254 | Level3 255 | 256 | 257 | Disabled 258 | true 259 | true 260 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 261 | true 262 | 263 | 264 | MultiThreaded 265 | 266 | 267 | Console 268 | true 269 | true 270 | true 271 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;frodo.lib;%(AdditionalDependencies) 272 | $(SolutionDir)$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories) 273 | 274 | 275 | 276 | 277 | 278 | -------------------------------------------------------------------------------- /VisualStudio/test_rand/test_rand.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/aes/aes.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "aes.h" 4 | #include "aes_local.h" 5 | 6 | void OQS_AES128_load_schedule(const uint8_t *key, void **schedule, int for_encryption) { 7 | #ifdef USE_OPENSSL 8 | oqs_aes128_load_schedule_ossl(key, schedule, for_encryption); 9 | #else 10 | for_encryption++; // need some dummy operation to avoid unused parameter warning 11 | #ifdef AES_ENABLE_NI 12 | oqs_aes128_load_schedule_ni(key, schedule); 13 | #else 14 | oqs_aes128_load_schedule_c(key, schedule); 15 | #endif 16 | #endif 17 | } 18 | 19 | void OQS_AES128_free_schedule(void *schedule) { 20 | #ifdef USE_OPENSSL 21 | oqs_aes128_free_schedule_ossl(schedule); 22 | #else 23 | #ifdef AES_ENABLE_NI 24 | oqs_aes128_free_schedule_ni(schedule); 25 | #else 26 | oqs_aes128_free_schedule_c(schedule); 27 | #endif 28 | #endif 29 | } 30 | 31 | void OQS_AES128_ECB_enc(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext) { 32 | #ifdef USE_OPENSSL 33 | oqs_aes128_ecb_enc_ossl(plaintext, plaintext_len, key, ciphertext); 34 | #else 35 | #ifdef AES_ENABLE_NI 36 | oqs_aes128_ecb_enc_ni(plaintext, plaintext_len, key, ciphertext); 37 | #else 38 | oqs_aes128_ecb_enc_c(plaintext, plaintext_len, key, ciphertext); 39 | #endif 40 | #endif 41 | } 42 | 43 | void OQS_AES128_ECB_dec(const uint8_t *ciphertext, const size_t ciphertext_len, const uint8_t *key, uint8_t *plaintext) { 44 | #ifdef USE_OPENSSL 45 | oqs_aes128_ecb_dec_ossl(ciphertext, ciphertext_len, key, plaintext); 46 | #else 47 | #ifdef AES_ENABLE_NI 48 | oqs_aes128_ecb_dec_ni(ciphertext, ciphertext_len, key, plaintext); 49 | #else 50 | oqs_aes128_ecb_dec_c(ciphertext, ciphertext_len, key, plaintext); 51 | #endif 52 | #endif 53 | } 54 | 55 | void OQS_AES128_ECB_enc_sch(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext) { 56 | #ifdef USE_OPENSSL 57 | oqs_aes128_ecb_enc_sch_ossl(plaintext, plaintext_len, schedule, ciphertext); 58 | #else 59 | #ifdef AES_ENABLE_NI 60 | oqs_aes128_ecb_enc_sch_ni(plaintext, plaintext_len, schedule, ciphertext); 61 | #else 62 | oqs_aes128_ecb_enc_sch_c(plaintext, plaintext_len, schedule, ciphertext); 63 | #endif 64 | #endif 65 | } 66 | 67 | void OQS_AES128_ECB_dec_sch(const uint8_t *ciphertext, const size_t ciphertext_len, const void *schedule, uint8_t *plaintext) { 68 | #ifdef USE_OPENSSL 69 | oqs_aes128_ecb_dec_sch_ossl(ciphertext, ciphertext_len, schedule, plaintext); 70 | #else 71 | #ifdef AES_ENABLE_NI 72 | oqs_aes128_ecb_dec_sch_ni(ciphertext, ciphertext_len, schedule, plaintext); 73 | #else 74 | oqs_aes128_ecb_dec_sch_c(ciphertext, ciphertext_len, schedule, plaintext); 75 | #endif 76 | #endif 77 | } 78 | 79 | #ifdef AES_ENABLE_NI 80 | inline void oqs_aes128_ecb_enc_ni(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext) { 81 | void *schedule = NULL; 82 | oqs_aes128_load_schedule_ni(key, &schedule); 83 | oqs_aes128_ecb_enc_sch_ni(plaintext, plaintext_len, schedule, ciphertext); 84 | oqs_aes128_free_schedule_ni(schedule); 85 | } 86 | #endif 87 | 88 | inline void oqs_aes128_ecb_enc_c(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext) { 89 | void *schedule = NULL; 90 | oqs_aes128_load_schedule_c(key, &schedule); 91 | oqs_aes128_ecb_enc_sch_c(plaintext, plaintext_len, schedule, ciphertext); 92 | oqs_aes128_free_schedule_c(schedule); 93 | } 94 | 95 | #ifdef AES_ENABLE_NI 96 | inline void oqs_aes128_ecb_enc_sch_ni(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext) { 97 | assert(plaintext_len % 16 == 0); 98 | for (size_t block = 0; block < plaintext_len / 16; block++) { 99 | oqs_aes128_enc_ni(plaintext + (16 * block), schedule, ciphertext + (16 * block)); 100 | } 101 | } 102 | #endif 103 | 104 | inline void oqs_aes128_ecb_enc_sch_c(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext) { 105 | assert(plaintext_len % 16 == 0); 106 | for (size_t block = 0; block < plaintext_len / 16; block++) { 107 | oqs_aes128_enc_c(plaintext + (16 * block), schedule, ciphertext + (16 * block)); 108 | } 109 | } 110 | 111 | #ifdef AES_ENABLE_NI 112 | inline void oqs_aes128_ecb_dec_ni(const uint8_t *ciphertext, const size_t ciphertext_len, const uint8_t *key, uint8_t *plaintext) { 113 | void *schedule = NULL; 114 | oqs_aes128_load_schedule_ni(key, &schedule); 115 | oqs_aes128_ecb_dec_sch_ni(ciphertext, ciphertext_len, schedule, plaintext); 116 | oqs_aes128_free_schedule_ni(schedule); 117 | } 118 | #endif 119 | 120 | inline void oqs_aes128_ecb_dec_c(const uint8_t *ciphertext, const size_t ciphertext_len, const uint8_t *key, uint8_t *plaintext) { 121 | void *schedule = NULL; 122 | oqs_aes128_load_schedule_c(key, &schedule); 123 | oqs_aes128_ecb_dec_sch_c(ciphertext, ciphertext_len, schedule, plaintext); 124 | oqs_aes128_free_schedule_c(schedule); 125 | } 126 | 127 | #ifdef AES_ENABLE_NI 128 | inline void oqs_aes128_ecb_dec_sch_ni(const uint8_t *ciphertext, const size_t ciphertext_len, const void *schedule, uint8_t *plaintext) { 129 | assert(ciphertext_len % 16 == 0); 130 | for (size_t block = 0; block < ciphertext_len / 16; block++) { 131 | oqs_aes128_dec_ni(ciphertext + (16 * block), schedule, plaintext + (16 * block)); 132 | } 133 | } 134 | #endif 135 | 136 | inline void oqs_aes128_ecb_dec_sch_c(const uint8_t *ciphertext, const size_t ciphertext_len, const void *schedule, uint8_t *plaintext) { 137 | assert(ciphertext_len % 16 == 0); 138 | for (size_t block = 0; block < ciphertext_len / 16; block++) { 139 | oqs_aes128_dec_c(ciphertext + (16 * block), schedule, plaintext + (16 * block)); 140 | } 141 | } 142 | 143 | #ifdef USE_OPENSSL 144 | #include 145 | 146 | inline void oqs_aes128_load_schedule_ossl(const uint8_t *key, void **schedule, int for_encryption) { 147 | EVP_CIPHER_CTX *aes_ctx = EVP_CIPHER_CTX_new(); 148 | assert(aes_ctx != NULL); 149 | if (for_encryption) { 150 | assert(1 == EVP_EncryptInit_ex(aes_ctx, EVP_aes_128_ecb(), NULL, key, NULL)); 151 | } else { 152 | assert(1 == EVP_DecryptInit_ex(aes_ctx, EVP_aes_128_ecb(), NULL, key, NULL)); 153 | } 154 | EVP_CIPHER_CTX_set_padding(aes_ctx, 0); 155 | *schedule = aes_ctx; 156 | } 157 | 158 | inline void oqs_aes128_free_schedule_ossl(void *schedule) { 159 | if (schedule != NULL) { 160 | EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *) schedule); 161 | } 162 | } 163 | 164 | inline void oqs_aes128_ecb_enc_ossl(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext) { 165 | void *schedule = NULL; 166 | oqs_aes128_load_schedule_ossl(key, &schedule, 1); 167 | oqs_aes128_ecb_enc_sch_ossl(plaintext, plaintext_len, schedule, ciphertext); 168 | oqs_aes128_free_schedule_ossl(schedule); 169 | } 170 | 171 | inline void oqs_aes128_ecb_dec_ossl(const uint8_t *ciphertext, const size_t ciphertext_len, const uint8_t *key, uint8_t *plaintext) { 172 | void *schedule = NULL; 173 | oqs_aes128_load_schedule_ossl(key, &schedule, 0); 174 | oqs_aes128_ecb_dec_sch_ossl(ciphertext, ciphertext_len, schedule, plaintext); 175 | oqs_aes128_free_schedule_ossl(schedule); 176 | } 177 | 178 | inline void oqs_aes128_ecb_enc_sch_ossl(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext) { 179 | assert(plaintext_len % 16 == 0); 180 | int outlen; 181 | assert(1 == EVP_EncryptUpdate((EVP_CIPHER_CTX *) schedule, ciphertext, &outlen, plaintext, plaintext_len)); 182 | assert((size_t) outlen == plaintext_len); 183 | assert(1 == EVP_EncryptFinal_ex((EVP_CIPHER_CTX *) schedule, ciphertext, &outlen)); 184 | } 185 | 186 | inline void oqs_aes128_ecb_dec_sch_ossl(const uint8_t *ciphertext, const size_t ciphertext_len, const void *schedule, uint8_t *plaintext) { 187 | assert(ciphertext_len % 16 == 0); 188 | int outlen; 189 | assert(1 == EVP_DecryptUpdate((EVP_CIPHER_CTX *) schedule, plaintext, &outlen, ciphertext, ciphertext_len)); 190 | assert((size_t) outlen == ciphertext_len); 191 | assert(1 == EVP_DecryptFinal_ex((EVP_CIPHER_CTX *) schedule, plaintext, &outlen)); 192 | } 193 | 194 | #endif 195 | -------------------------------------------------------------------------------- /src/aes/aes.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file aes.h 3 | * \brief Header defining the API for OQS AES 4 | */ 5 | 6 | #ifndef __OQS_AES_H 7 | #define __OQS_AES_H 8 | 9 | #include 10 | #include 11 | 12 | /** 13 | * Function to fill a key schedule given an initial key. 14 | * 15 | * @param key Initial Key. 16 | * @param schedule Abstract data structure for a key schedule. 17 | * @param forEncryption 1 if key schedule is for encryption, 0 if for decryption. 18 | */ 19 | void OQS_AES128_load_schedule(const uint8_t *key, void **schedule, int for_encryption); 20 | 21 | /** 22 | * Function to free a key schedule. 23 | * 24 | * @param schedule Schedule generated with OQS_AES128_load_schedule(). 25 | */ 26 | void OQS_AES128_free_schedule(void *schedule); 27 | 28 | /** 29 | * Function to encrypt blocks of plaintext using ECB mode. 30 | * A schedule based on the key is generated and used internally. 31 | * 32 | * @param plaintext Plaintext to be encrypted. 33 | * @param plaintext_len Length on the plaintext in bytes. Must be a multiple of 16. 34 | * @param key Key to be used for encryption. 35 | * @param ciphertext Pointer to a block of memory which >= in size to the plaintext block. The result will be written here. 36 | */ 37 | void OQS_AES128_ECB_enc(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext); 38 | 39 | /** 40 | * Function to decrypt blocks of plaintext using ECB mode. 41 | * A schedule based on the key is generated and used internally. 42 | * 43 | * @param ciphertext Ciphertext to be decrypted. 44 | * @param ciphertext_len Length on the ciphertext in bytes. Must be a multiple of 16. 45 | * @param key Key to be used for encryption. 46 | * @param ciphertext Pointer to a block of memory which >= in size to the ciphertext block. The result will be written here. 47 | */ 48 | void OQS_AES128_ECB_dec(const uint8_t *ciphertext, const size_t ciphertext_len, const uint8_t *key, uint8_t *plaintext); 49 | 50 | /** 51 | * Same as OQS_AES128_ECB_enc() except a schedule generated by 52 | * OQS_AES128_load_schedule() is passed rather then a key. This is faster 53 | * if the same schedule is used for multiple encryptions since it does 54 | * not have to be regenerated from the key. 55 | */ 56 | void OQS_AES128_ECB_enc_sch(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext); 57 | 58 | /** 59 | * Same as OQS_AES128_ECB_dec() except a schedule generated by 60 | * OQS_AES128_load_schedule() is passed rather then a key. This is faster 61 | * if the same schedule is used for multiple encryptions since it does 62 | * not have to be regenerated from the key. 63 | */ 64 | void OQS_AES128_ECB_dec_sch(const uint8_t *ciphertext, const size_t ciphertext_len, const void *schedule, uint8_t *plaintext); 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /src/aes/aes_local.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file aes_local.h 3 | * \brief Header defining additional internal functions for OQS AES 4 | */ 5 | 6 | #ifndef __OQS_AES_LOCAL_H 7 | #define __OQS_AES_LOCAL_H 8 | 9 | #include 10 | #include 11 | 12 | void oqs_aes128_load_schedule_ni(const uint8_t *key, void **schedule); 13 | void oqs_aes128_free_schedule_ni(void *schedule); 14 | void oqs_aes128_enc_ni(const uint8_t *plaintext, const void *schedule, uint8_t *ciphertext); 15 | void oqs_aes128_dec_ni(const uint8_t *ciphertext, const void *schedule, uint8_t *plaintext); 16 | void oqs_aes128_ecb_enc_ni(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext); 17 | void oqs_aes128_ecb_dec_ni(const uint8_t *ciphertext, const size_t ciphertext_len, const uint8_t *key, uint8_t *plaintext); 18 | void oqs_aes128_ecb_enc_sch_ni(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext); 19 | void oqs_aes128_ecb_dec_sch_ni(const uint8_t *ciphertext, const size_t ciphertext_len, const void *schedule, uint8_t *plaintext); 20 | 21 | void oqs_aes128_load_schedule_c(const uint8_t *key, void **schedule); 22 | void oqs_aes128_free_schedule_c(void *schedule); 23 | void oqs_aes128_enc_c(const uint8_t *plaintext, const void *schedule, uint8_t *ciphertext); 24 | void oqs_aes128_dec_c(const uint8_t *ciphertext, const void *schedule, uint8_t *plaintext); 25 | void oqs_aes128_ecb_enc_c(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext); 26 | void oqs_aes128_ecb_dec_c(const uint8_t *ciphertext, const size_t ciphertext_len, const uint8_t *key, uint8_t *plaintext); 27 | void oqs_aes128_ecb_enc_sch_c(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext); 28 | void oqs_aes128_ecb_dec_sch_c(const uint8_t *ciphertext, const size_t ciphertext_len, const void *schedule, uint8_t *plaintext); 29 | 30 | #ifdef USE_OPENSSL 31 | void oqs_aes128_load_schedule_ossl(const uint8_t *key, void **schedule, int for_encryption); 32 | void oqs_aes128_free_schedule_ossl(void *schedule); 33 | void oqs_aes128_ecb_enc_ossl(const uint8_t *plaintext, const size_t plaintext_len, const uint8_t *key, uint8_t *ciphertext); 34 | void oqs_aes128_ecb_dec_ossl(const uint8_t *ciphertext, const size_t ciphertext_len, const uint8_t *key, uint8_t *plaintext); 35 | void oqs_aes128_ecb_enc_sch_ossl(const uint8_t *plaintext, const size_t plaintext_len, const void *schedule, uint8_t *ciphertext); 36 | void oqs_aes128_ecb_dec_sch_ossl(const uint8_t *ciphertext, const size_t ciphertext_len, const void *schedule, uint8_t *plaintext); 37 | #endif 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/aes/aes_ni.c: -------------------------------------------------------------------------------- 1 | #if defined(WINDOWS) 2 | #define UNUSED 3 | // __attribute__ not supported in VS, is there something else I should define? 4 | #else 5 | #define UNUSED __attribute__((unused)) 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #ifndef AES_ENABLE_NI 13 | #include 14 | void oqs_aes128_load_schedule_ni(UNUSED const uint8_t *key, UNUSED void **_schedule) { 15 | assert(0); 16 | } 17 | void oqs_aes128_free_schedule_ni(UNUSED void *_schedule) { 18 | assert(0); 19 | } 20 | void oqs_aes128_enc_ni(UNUSED const uint8_t *plaintext, UNUSED const void *_schedule, UNUSED uint8_t *ciphertext) { 21 | assert(0); 22 | } 23 | void oqs_aes128_dec_ni(UNUSED const uint8_t *ciphertext, UNUSED const void *_schedule, UNUSED uint8_t *plaintext) { 24 | assert(0); 25 | } 26 | #else 27 | 28 | #include 29 | 30 | static __m128i key_expand(__m128i key, __m128i keygened) { 31 | key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); 32 | key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); 33 | key = _mm_xor_si128(key, _mm_slli_si128(key, 4)); 34 | // The last 4 bytes from aeskeygenassist store the values we want so 35 | // and they need to be xored all four sets of bytes in the result so 36 | keygened = _mm_shuffle_epi32(keygened, _MM_SHUFFLE(3, 3, 3, 3)); 37 | return _mm_xor_si128(key, keygened); 38 | } 39 | 40 | //This is needed since the rcon argument to _mm_aeskeygenassist_si128 41 | //must be a compile time constaint 42 | 43 | #define key_exp(k, rcon) key_expand(k, _mm_aeskeygenassist_si128(k, rcon)) 44 | 45 | void oqs_aes128_load_schedule_ni(const uint8_t *key, void **_schedule) { 46 | *_schedule = malloc(20 * 16); 47 | assert(*_schedule != NULL); 48 | __m128i *schedule = (__m128i *) *_schedule; 49 | schedule[0] = _mm_loadu_si128((const __m128i *) key); 50 | schedule[1] = key_exp(schedule[0], 0x01); 51 | schedule[2] = key_exp(schedule[1], 0x02); 52 | schedule[3] = key_exp(schedule[2], 0x04); 53 | schedule[4] = key_exp(schedule[3], 0x08); 54 | schedule[5] = key_exp(schedule[4], 0x10); 55 | schedule[6] = key_exp(schedule[5], 0x20); 56 | schedule[7] = key_exp(schedule[6], 0x40); 57 | schedule[8] = key_exp(schedule[7], 0x80); 58 | schedule[9] = key_exp(schedule[8], 0x1b); 59 | schedule[10] = key_exp(schedule[9], 0x36); 60 | // generate decryption keys in reverse order. 61 | // schedule[10] is shared by last encryption and first decryption rounds 62 | // schedule[0] is shared by first encryption round and last decryption round 63 | for (size_t i = 0; i < 9; i++) { 64 | schedule[11 + i] = _mm_aesimc_si128(schedule[9 - i]); 65 | } 66 | } 67 | 68 | void oqs_aes128_free_schedule_ni(void *schedule) { 69 | if (schedule != NULL) { 70 | free(schedule); 71 | } 72 | } 73 | 74 | void oqs_aes128_enc_ni(const uint8_t *plaintext, const void *_schedule, uint8_t *ciphertext) { 75 | __m128i *schedule = (__m128i *) _schedule; 76 | __m128i m = _mm_loadu_si128((__m128i *) plaintext); 77 | 78 | m = _mm_xor_si128(m, schedule[0]); 79 | for (size_t i = 1; i < 10; i++) { 80 | m = _mm_aesenc_si128(m, schedule[i]); 81 | } 82 | m = _mm_aesenclast_si128(m, schedule[10]); 83 | 84 | _mm_storeu_si128((__m128i *) ciphertext, m); 85 | } 86 | 87 | void oqs_aes128_dec_ni(const uint8_t *ciphertext, const void *_schedule, uint8_t *plaintext) { 88 | __m128i *schedule = (__m128i *) _schedule; 89 | __m128i m = _mm_loadu_si128((__m128i *) ciphertext); 90 | 91 | m = _mm_xor_si128(m, schedule[10]); 92 | for (size_t i = 1; i < 10; i++) { 93 | m = _mm_aesdec_si128(m, schedule[10 + i]); 94 | } 95 | m = _mm_aesdeclast_si128(m, schedule[0]); 96 | 97 | _mm_storeu_si128((__m128i *) plaintext, m); 98 | } 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /src/aes/test_aes.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "../random/rand.h" 7 | #include "../../tests/ds_benchmark.h" 8 | #include "aes.h" 9 | #include "aes_local.h" 10 | 11 | #define BENCH_DURATION 1 12 | 13 | #define TEST_ITERATIONS 100 14 | 15 | #define TEST_REPEATEDLY(x) \ 16 | for (int i = 0; i < TEST_ITERATIONS; i++) { \ 17 | int ok = (x); \ 18 | if (ok != EXIT_SUCCESS) { \ 19 | fprintf(stderr, "Failure in %s (iteration %d)\n", #x, i); \ 20 | return EXIT_FAILURE; \ 21 | } \ 22 | } 23 | 24 | static void print_bytes(uint8_t *bytes, size_t num_bytes) { 25 | for (size_t i = 0; i < num_bytes; i++) { 26 | printf("%02x", (unsigned) bytes[i]); 27 | } 28 | } 29 | 30 | static int test_aes128_correctness_c(OQS_RAND *rand) { 31 | uint8_t key[16], plaintext[16], ciphertext[16], decrypted[16]; 32 | void *schedule = NULL; 33 | OQS_RAND_n(rand, key, 16); 34 | OQS_RAND_n(rand, plaintext, 16); 35 | oqs_aes128_load_schedule_c(key, &schedule); 36 | oqs_aes128_enc_c(plaintext, schedule, ciphertext); 37 | oqs_aes128_dec_c(ciphertext, schedule, decrypted); 38 | oqs_aes128_free_schedule_c(schedule); 39 | if (memcmp(plaintext, decrypted, 16) == 0) { 40 | return EXIT_SUCCESS; 41 | } else { 42 | print_bytes(plaintext, 16); 43 | printf("\n"); 44 | print_bytes(decrypted, 16); 45 | printf("\n"); 46 | return EXIT_FAILURE; 47 | } 48 | } 49 | 50 | #ifdef AES_ENABLE_NI 51 | static int test_aes128_correctness_ni(OQS_RAND *rand) { 52 | uint8_t key[16], plaintext[16], ciphertext[16], decrypted[16]; 53 | void *schedule = NULL; 54 | OQS_RAND_n(rand, key, 16); 55 | OQS_RAND_n(rand, plaintext, 16); 56 | oqs_aes128_load_schedule_ni(key, &schedule); 57 | oqs_aes128_enc_ni(plaintext, schedule, ciphertext); 58 | oqs_aes128_dec_ni(ciphertext, schedule, decrypted); 59 | oqs_aes128_free_schedule_ni(schedule); 60 | if (memcmp(plaintext, decrypted, 16) == 0) { 61 | return EXIT_SUCCESS; 62 | } else { 63 | print_bytes(plaintext, 16); 64 | printf("\n"); 65 | print_bytes(decrypted, 16); 66 | printf("\n"); 67 | return EXIT_FAILURE; 68 | } 69 | } 70 | 71 | static int test_aes128_c_equals_ni(OQS_RAND *rand) { 72 | uint8_t key[16], plaintext[16], ciphertext_c[16], ciphertext_ni[16]; 73 | void *schedule_c = NULL, *schedule_ni = NULL; 74 | OQS_RAND_n(rand, key, 16); 75 | OQS_RAND_n(rand, plaintext, 16); 76 | oqs_aes128_load_schedule_c(key, &schedule_c); 77 | oqs_aes128_load_schedule_ni(key, &schedule_ni); 78 | oqs_aes128_enc_c(plaintext, schedule_c, ciphertext_c); 79 | oqs_aes128_enc_ni(plaintext, schedule_ni, ciphertext_ni); 80 | oqs_aes128_free_schedule_c(schedule_c); 81 | oqs_aes128_free_schedule_ni(schedule_ni); 82 | if (memcmp(ciphertext_c, ciphertext_ni, 16) == 0) { 83 | return EXIT_SUCCESS; 84 | } else { 85 | print_bytes(ciphertext_c, 16); 86 | printf("\n"); 87 | print_bytes(ciphertext_ni, 16); 88 | printf("\n"); 89 | return EXIT_FAILURE; 90 | } 91 | } 92 | 93 | static int test_aes128_ecb_correctness_ni(OQS_RAND *rand) { 94 | uint8_t key[16], plaintext[320], ciphertext[320], decrypted[320]; 95 | void *schedule = NULL; 96 | OQS_RAND_n(rand, key, 16); 97 | OQS_RAND_n(rand, plaintext, 320); 98 | oqs_aes128_load_schedule_ni(key, &schedule); 99 | oqs_aes128_ecb_enc_ni(plaintext, 320, schedule, ciphertext); 100 | oqs_aes128_ecb_dec_ni(ciphertext, 320, schedule, decrypted); 101 | oqs_aes128_free_schedule_ni(schedule); 102 | if (memcmp(plaintext, decrypted, 320) == 0) { 103 | return EXIT_SUCCESS; 104 | } else { 105 | print_bytes(plaintext, 320); 106 | printf("\n"); 107 | print_bytes(decrypted, 320); 108 | printf("\n"); 109 | return EXIT_FAILURE; 110 | } 111 | } 112 | #endif 113 | 114 | static int test_aes128_ecb_correctness_c(OQS_RAND *rand) { 115 | uint8_t key[16], plaintext[320], ciphertext[320], decrypted[320]; 116 | void *schedule = NULL; 117 | OQS_RAND_n(rand, key, 16); 118 | OQS_RAND_n(rand, plaintext, 320); 119 | oqs_aes128_load_schedule_c(key, &schedule); 120 | oqs_aes128_ecb_enc_c(plaintext, 320, schedule, ciphertext); 121 | oqs_aes128_ecb_dec_c(ciphertext, 320, schedule, decrypted); 122 | oqs_aes128_free_schedule_c(schedule); 123 | if (memcmp(plaintext, decrypted, 320) == 0) { 124 | return EXIT_SUCCESS; 125 | } else { 126 | print_bytes(plaintext, 320); 127 | printf("\n"); 128 | print_bytes(decrypted, 320); 129 | printf("\n"); 130 | return EXIT_FAILURE; 131 | } 132 | } 133 | 134 | #ifdef USE_OPENSSL 135 | static int test_aes128_ecb_correctness_ossl(OQS_RAND *rand) { 136 | uint8_t key[16], plaintext[320], ciphertext[320], decrypted[320]; 137 | void *schedule = NULL; 138 | OQS_RAND_n(rand, key, 16); 139 | OQS_RAND_n(rand, plaintext, 320); 140 | oqs_aes128_load_schedule_ossl(key, &schedule, 1); 141 | oqs_aes128_ecb_enc_ossl(plaintext, 320, schedule, ciphertext); 142 | oqs_aes128_free_schedule_ossl(schedule); 143 | oqs_aes128_load_schedule_ossl(key, &schedule, 0); 144 | oqs_aes128_ecb_dec_ossl(ciphertext, 320, schedule, decrypted); 145 | oqs_aes128_free_schedule_ossl(schedule); 146 | if (memcmp(plaintext, decrypted, 320) == 0) { 147 | return EXIT_SUCCESS; 148 | } else { 149 | print_bytes(plaintext, 320); 150 | printf("\n"); 151 | print_bytes(decrypted, 320); 152 | printf("\n"); 153 | return EXIT_FAILURE; 154 | } 155 | } 156 | #endif 157 | 158 | static void speed_aes128_c(OQS_RAND *rand) { 159 | uint8_t key[16], plaintext[320], ciphertext[320], decrypted[320]; 160 | void *schedule = NULL; 161 | OQS_RAND_n(rand, key, 16); 162 | OQS_RAND_n(rand, plaintext, 320); 163 | TIME_OPERATION_SECONDS({ oqs_aes128_load_schedule_c(key, &schedule); oqs_aes128_free_schedule_c(schedule); }, "oqs_aes128_load_schedule_c", BENCH_DURATION); 164 | 165 | oqs_aes128_load_schedule_c(key, &schedule); 166 | TIME_OPERATION_SECONDS(oqs_aes128_enc_c(plaintext, schedule, ciphertext), "oqs_aes128_enc_c", BENCH_DURATION); 167 | TIME_OPERATION_SECONDS(oqs_aes128_dec_c(ciphertext, schedule, decrypted), "oqs_aes128_dec_c", BENCH_DURATION); 168 | TIME_OPERATION_SECONDS(oqs_aes128_ecb_enc_c(plaintext, 320, key, ciphertext), "oqs_aes128_ecb_enc_c", BENCH_DURATION); 169 | TIME_OPERATION_SECONDS(oqs_aes128_ecb_dec_c(ciphertext, 320, key, decrypted), "oqs_aes128_ecb_dec_c", BENCH_DURATION); 170 | TIME_OPERATION_SECONDS(oqs_aes128_ecb_enc_sch_c(plaintext, 320, schedule, ciphertext), "oqs_aes128_ecb_enc_sch_c", BENCH_DURATION); 171 | TIME_OPERATION_SECONDS(oqs_aes128_ecb_dec_sch_c(ciphertext, 320, schedule, decrypted), "oqs_aes128_ecb_dec_sch_c", BENCH_DURATION); 172 | oqs_aes128_free_schedule_c(schedule); 173 | } 174 | 175 | #ifdef AES_ENABLE_NI 176 | 177 | static void speed_aes128_ni(OQS_RAND *rand) { 178 | uint8_t key[16], plaintext[320], ciphertext[320], decrypted[320]; 179 | void *schedule = NULL; 180 | OQS_RAND_n(rand, key, 16); 181 | OQS_RAND_n(rand, plaintext, 320); 182 | TIME_OPERATION_SECONDS({ oqs_aes128_load_schedule_ni(key, &schedule); oqs_aes128_free_schedule_ni(schedule); }, "oqs_aes128_load_schedule_ni", BENCH_DURATION); 183 | 184 | oqs_aes128_load_schedule_ni(key, &schedule); 185 | TIME_OPERATION_SECONDS(oqs_aes128_enc_ni(plaintext, schedule, ciphertext), "oqs_aes128_enc_ni", BENCH_DURATION); 186 | TIME_OPERATION_SECONDS(oqs_aes128_dec_ni(ciphertext, schedule, decrypted), "oqs_aes128_dec_ni", BENCH_DURATION); 187 | TIME_OPERATION_SECONDS(oqs_aes128_ecb_enc_ni(plaintext, 320, key, ciphertext), "oqs_aes128_ecb_enc_ni", BENCH_DURATION); 188 | TIME_OPERATION_SECONDS(oqs_aes128_ecb_dec_ni(ciphertext, 320, key, decrypted), "oqs_aes128_ecb_dec_ni", BENCH_DURATION); 189 | TIME_OPERATION_SECONDS(oqs_aes128_ecb_enc_sch_ni(plaintext, 320, schedule, ciphertext), "oqs_aes128_ecb_enc_sch_ni", BENCH_DURATION); 190 | TIME_OPERATION_SECONDS(oqs_aes128_ecb_dec_sch_ni(ciphertext, 320, schedule, decrypted), "oqs_aes128_ecb_dec_sch_ni", BENCH_DURATION); 191 | oqs_aes128_free_schedule_ni(schedule); 192 | } 193 | #endif 194 | 195 | #ifdef USE_OPENSSL 196 | static void speed_aes128_ossl(OQS_RAND *rand) { 197 | uint8_t key[16], plaintext[320], ciphertext[320]; 198 | void *schedule = NULL; 199 | OQS_RAND_n(rand, key, 16); 200 | OQS_RAND_n(rand, plaintext, 320); 201 | TIME_OPERATION_SECONDS(oqs_aes128_load_schedule_ossl(key, &schedule, 1), "oqs_aes128_load_schedule_ossl 1", BENCH_DURATION); 202 | TIME_OPERATION_SECONDS(oqs_aes128_load_schedule_ossl(key, &schedule, 0), "oqs_aes128_load_schedule_ossl 0", BENCH_DURATION); 203 | TIME_OPERATION_SECONDS(oqs_aes128_ecb_enc_ossl(plaintext, 320, key, ciphertext), "oqs_aes128_ecb_enc_ossl", BENCH_DURATION); 204 | TIME_OPERATION_SECONDS(oqs_aes128_ecb_dec_ossl(ciphertext, 320, key, plaintext), "oqs_aes128_ecb_dec_ossl", BENCH_DURATION); 205 | oqs_aes128_load_schedule_ossl(key, &schedule, 1); 206 | TIME_OPERATION_SECONDS(oqs_aes128_ecb_enc_sch_ossl(plaintext, 320, schedule, ciphertext), "oqs_aes128_ecb_enc_sch_ossl", BENCH_DURATION); 207 | oqs_aes128_load_schedule_ossl(key, &schedule, 0); 208 | TIME_OPERATION_SECONDS(oqs_aes128_ecb_dec_sch_ossl(ciphertext, 320, schedule, plaintext), "oqs_aes128_ecb_dec_sch_ossl", BENCH_DURATION); 209 | } 210 | #endif 211 | 212 | int main(int argc, char **argv) { 213 | int ret; 214 | bool bench = false; 215 | 216 | for (int i = 1; i < argc; i++) { 217 | if (argv[i][0] == '-') { 218 | if (strcmp(argv[i], "--bench") == 0 || strcmp(argv[i], "-b") == 0) { 219 | bench = true; 220 | } else { 221 | printf("Usage: ./test_rand [options]\n"); 222 | printf("\nOptions:\n"); 223 | printf(" --bench, -b\n"); 224 | printf(" Run benchmarks\n"); 225 | if ((strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "-help") == 0) || (strcmp(argv[i], "--help") == 0)) { 226 | return EXIT_SUCCESS; 227 | } else { 228 | return EXIT_FAILURE; 229 | } 230 | } 231 | } 232 | } 233 | 234 | printf("=== test_aes correctness ===\n"); 235 | OQS_RAND *rand = OQS_RAND_new(OQS_RAND_alg_default); 236 | if (rand == NULL) { 237 | fprintf(stderr, "OQS_RAND_new() failed\n"); 238 | goto err; 239 | } 240 | TEST_REPEATEDLY(test_aes128_correctness_c(rand)); 241 | #ifdef AES_ENABLE_NI 242 | TEST_REPEATEDLY(test_aes128_correctness_ni(rand)); 243 | TEST_REPEATEDLY(test_aes128_c_equals_ni(rand)); 244 | #endif 245 | TEST_REPEATEDLY(test_aes128_ecb_correctness_c(rand)); 246 | #ifdef AES_ENABLE_NI 247 | TEST_REPEATEDLY(test_aes128_ecb_correctness_ni(rand)); 248 | #endif 249 | #ifdef USE_OPENSSL 250 | TEST_REPEATEDLY(test_aes128_ecb_correctness_ossl(rand)); 251 | #endif 252 | printf("Tests passed.\n\n"); 253 | 254 | if (bench) { 255 | printf("=== test_aes performance ===\n"); 256 | PRINT_TIMER_HEADER 257 | speed_aes128_c(rand); 258 | #ifdef AES_ENABLE_NI 259 | speed_aes128_ni(rand); 260 | #endif 261 | #ifdef USE_OPENSSL 262 | speed_aes128_ossl(rand); 263 | #endif 264 | PRINT_TIMER_FOOTER 265 | } 266 | 267 | ret = EXIT_SUCCESS; 268 | goto cleanup; 269 | err: 270 | ret = EXIT_FAILURE; 271 | cleanup: 272 | OQS_RAND_free(rand); 273 | return ret; 274 | } 275 | -------------------------------------------------------------------------------- /src/frodo.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************************** 2 | * Frodo: a post-quantum key exchange based on the Learning with Errors (LWE) problem. 3 | * 4 | * Abstract: header for settings 5 | *********************************************************************************************/ 6 | 7 | #ifndef __FRODO_H 8 | #define __FRODO_H 9 | 10 | #include 11 | #include 12 | 13 | 14 | // Definition of operating system 15 | 16 | #define OS_WIN 1 17 | #define OS_LINUX 2 18 | 19 | #if defined(WINDOWS) // Microsoft Windows 20 | #define OS_TARGET OS_WIN 21 | #elif defined(LINUX) // Linux 22 | #define OS_TARGET OS_LINUX 23 | #else 24 | #error -- "Unsupported OS" 25 | #endif 26 | 27 | 28 | // Definition of compiler 29 | 30 | #define COMPILER_VC 1 31 | #define COMPILER_GCC 2 32 | #define COMPILER_CLANG 3 33 | 34 | #if defined(_MSC_VER) // Microsoft Visual C compiler 35 | #define COMPILER COMPILER_VC 36 | #elif defined(__GNUC__) // GNU GCC compiler 37 | #define COMPILER COMPILER_GCC 38 | #elif defined(__clang__) // Clang compiler 39 | #define COMPILER COMPILER_CLANG 40 | #else 41 | #error -- "Unsupported COMPILER" 42 | #endif 43 | 44 | 45 | // Definition of the targeted architecture and basic data types 46 | 47 | #define TARGET_AMD64 1 48 | #define TARGET_x86 2 49 | #define TARGET_ARM 3 50 | 51 | #if defined(_AMD64_) 52 | #define TARGET TARGET_AMD64 53 | #elif defined(_X86_) 54 | #define TARGET TARGET_x86 55 | #elif defined(_ARM_) 56 | #define TARGET TARGET_ARM 57 | #else 58 | #error -- "Unsupported ARCHITECTURE" 59 | #endif 60 | 61 | 62 | #if defined(WINDOWS) 63 | #define ALIGN_HEADER(N) __declspec(align(N)) 64 | #define ALIGN_FOOTER(N) 65 | #else 66 | #define ALIGN_HEADER(N) 67 | #define ALIGN_FOOTER(N) __attribute__((aligned(N))) 68 | #endif 69 | 70 | 71 | #if defined(AVX2) 72 | #define USE_AVX2 73 | #endif 74 | 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /src/frodo_macrify.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************************** 2 | * Frodo: a post-quantum key exchange based on the Learning with Errors (LWE) problem. 3 | * 4 | * Abstract: header for functions with parameter-specific instantiations 5 | *********************************************************************************************/ 6 | 7 | #ifndef _FRODO_MACRIFY_H_ 8 | #define _FRODO_MACRIFY_H_ 9 | 10 | #include 11 | #include "frodo.h" 12 | #include "random/rand.h" 13 | 14 | 15 | struct oqs_kex_lwe_frodo_params { 16 | uint8_t *seed; 17 | size_t seed_len; 18 | char *param_name; 19 | uint8_t log2_q; 20 | uint16_t q; 21 | uint16_t n; 22 | uint16_t extracted_bits; 23 | uint16_t nbar; 24 | uint16_t key_bits; 25 | uint16_t rec_hint_len; 26 | //uint16_t aux_len; //////////// FOR FRODOSIMPLE 27 | uint32_t pub_len; 28 | uint16_t stripe_step; 29 | int sampler_num; 30 | uint16_t *cdf_table; 31 | size_t cdf_table_len; 32 | }; 33 | 34 | void oqs_kex_lwe_frodo_crossround2_recommended(unsigned char *out, const uint16_t *in); 35 | void oqs_kex_lwe_frodo_round2_recommended(unsigned char *out, uint16_t *in); 36 | void oqs_kex_lwe_frodo_reconcile_recommended(unsigned char *out, uint16_t *w, const unsigned char *hint); 37 | 38 | void oqs_kex_lwe_frodo_key_round(uint16_t *vec, const size_t length, const int b); 39 | void oqs_kex_lwe_frodo_key_round_hints(uint16_t *vec, const size_t length, const int b, const unsigned char *hint); 40 | void oqs_kex_lwe_frodo_pack(unsigned char *out, const size_t outlen, const uint16_t *in, const size_t inlen, const unsigned char lsb); 41 | void oqs_kex_lwe_frodo_unpack(uint16_t *out, const size_t outlen, const unsigned char *in, const size_t inlen, const unsigned char lsb); 42 | int oqs_kex_lwe_frodo_sample_n(uint16_t *s, const size_t n, struct oqs_kex_lwe_frodo_params *params, OQS_RAND *rand); 43 | 44 | int oqs_kex_lwe_frodo_mul_add_as_plus_e_on_the_fly_recommended(uint16_t *b, const uint16_t *s, const uint16_t *e, struct oqs_kex_lwe_frodo_params *params); 45 | int oqs_kex_lwe_frodo_mul_add_sa_plus_e_on_the_fly_recommended(uint16_t *b, const uint16_t *s, const uint16_t *e, struct oqs_kex_lwe_frodo_params *params); 46 | void oqs_kex_lwe_frodo_mul_add_sb_plus_e_recommended(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e); 47 | void oqs_kex_lwe_frodo_mul_bs_recommended(uint16_t *out, const uint16_t *b, const uint16_t *s); 48 | 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/kex.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "kex.h" 3 | #include "kex_lwe_frodo.h" 4 | 5 | 6 | OQS_KEX *OQS_KEX_new(OQS_RAND *rand, enum OQS_KEX_alg_name alg_name, const uint8_t *seed, const size_t seed_len, const char *named_parameters) { 7 | switch (alg_name) { 8 | case OQS_KEX_alg_default: 9 | case OQS_KEX_alg_lwe_frodo: 10 | return OQS_KEX_lwe_frodo_new(rand, seed, seed_len, named_parameters); 11 | default: 12 | assert(0); 13 | return NULL; 14 | } 15 | } 16 | 17 | 18 | int OQS_KEX_alice_0(OQS_KEX *k, void **alice_priv, uint8_t **alice_msg, size_t *alice_msg_len) { 19 | if (k == NULL) { 20 | return 0; 21 | } else { 22 | return k->alice_0(k, alice_priv, alice_msg, alice_msg_len); 23 | } 24 | } 25 | 26 | 27 | int OQS_KEX_bob(OQS_KEX *k, const uint8_t *alice_msg, const size_t alice_msg_len, uint8_t **bob_msg, size_t *bob_msg_len, uint8_t **key, size_t *key_len) { 28 | if (k == NULL) { 29 | return 0; 30 | } else { 31 | return k->bob(k, alice_msg, alice_msg_len, bob_msg, bob_msg_len, key, key_len); 32 | } 33 | } 34 | 35 | 36 | int OQS_KEX_alice_1(OQS_KEX *k, const void *alice_priv, const uint8_t *bob_msg, const size_t bob_msg_len, uint8_t **key, size_t *key_len) { 37 | if (k == NULL) { 38 | return 0; 39 | } else { 40 | return k->alice_1(k, alice_priv, bob_msg, bob_msg_len, key, key_len); 41 | } 42 | } 43 | 44 | 45 | void OQS_KEX_alice_priv_free(OQS_KEX *k, void *alice_priv) { 46 | if (k) { 47 | k->alice_priv_free(k, alice_priv); 48 | } 49 | } 50 | 51 | 52 | void OQS_KEX_free(OQS_KEX *k) { 53 | if (k) { 54 | k->free(k); 55 | } 56 | } -------------------------------------------------------------------------------- /src/kex.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file kex.h 3 | * \brief Header defining the API for generic OQS Key exchange 4 | */ 5 | 6 | #ifndef __OQS_KEX_H 7 | #define __OQS_KEX_H 8 | 9 | #include 10 | #include 11 | #include "frodo.h" 12 | #include "random/rand.h" 13 | 14 | 15 | enum OQS_KEX_alg_name { 16 | OQS_KEX_alg_default, 17 | OQS_KEX_alg_lwe_frodo, 18 | }; 19 | 20 | typedef struct OQS_KEX OQS_KEX; 21 | 22 | /** 23 | * OQS key exchange object 24 | */ 25 | typedef struct OQS_KEX { 26 | OQS_RAND *rand; // PRNG 27 | char *method_name; // Specifies the name of the key exchange method. 28 | uint16_t estimated_classical_security; // Classical security in terms of the number of bits provided by the key exchange method. 29 | uint16_t estimated_quantum_security; // Equivalent quantum security in terms of the number of bits provided by the key exchange method. 30 | uint8_t *seed; // An instance-specific seed, if any. 31 | size_t seed_len; // Size of instance-specific seed, if any. 32 | char *named_parameters; // Named parameters for this key exchange method instance, if any. 33 | void *params; // Opaque pointer for passing around instance-specific data. 34 | void *ctx; // Opaque pointer for passing around any computation context. 35 | 36 | /** 37 | * Pointer to a function for public and private key generation by Alice. 38 | * 39 | * @param k Key exchange structure 40 | * @param alice_priv Alice's private key 41 | * @param alice_msg Alice's message (public key + optional additional data) 42 | * @param alice_msg_len Alice's message length 43 | * @return 1 on success, or 0 on failure 44 | */ 45 | int (*alice_0)(OQS_KEX *k, void **alive_priv, uint8_t **alice_msg, size_t *alice_msg_len); 46 | 47 | /** 48 | * Pointer to a function for shared key generation by Bob. 49 | * 50 | * @param k Key exchange structure 51 | * @param alice_msg Alice's message (public key + optional additional data) 52 | * @param alice_msg_len Alice's message length 53 | * @param bob_msg Bob's message (public key / encryption of shared key + optional additional data) 54 | * @param bob_msg_len Bob's message length 55 | * @param key Shared key 56 | * @param key_len Shared key length 57 | * @return 1 on success, or 0 on failure 58 | */ 59 | int (*bob)(OQS_KEX *k, const uint8_t *alice_msg, const size_t alice_msg_len, uint8_t **bob_msg, size_t *bob_msg_len, uint8_t **key, size_t *key_len); 60 | 61 | /** 62 | * Pointer to a function for shared key generation by Alice. 63 | * 64 | * @param k Key exchange structure 65 | * @param alice_priv Alice's private key 66 | * @param bob_msg Bob's message (public key / encryption of shared key + optional additional data) 67 | * @param bob_msg_len Bob's message length 68 | * @param key Shared key 69 | * @param key_len Shared key length 70 | * @return 1 on success, or 0 on failure 71 | */ 72 | int (*alice_1)(OQS_KEX *k, const void *alice_priv, const uint8_t *bob_msg, const size_t bob_msg_len, uint8_t **key, size_t *key_len); 73 | 74 | /** 75 | * Pointer to a function for freeing Alice's private key 76 | * 77 | * @param k Key exchange structure 78 | * @param alice_priv Alice's private key 79 | */ 80 | void (*alice_priv_free)(OQS_KEX *k, void *alice_priv); 81 | 82 | /** 83 | * Pointer to a function for freeing the allocated key exchange structure 84 | * 85 | * @param k Key exchange structure 86 | */ 87 | void (*free)(OQS_KEX *k); 88 | 89 | } OQS_KEX; 90 | 91 | 92 | /** 93 | * Allocate a new key exchange object. 94 | * 95 | * @param rand Random number generator. 96 | * @param alg_name Algorithm to be instantiated 97 | * @param seed An instance-specific seed, if any, or NULL. 98 | * @param seed_len The length of seed, or 0. 99 | * @param named_parameters Name or description of method-specific parameters 100 | * to use for this instance (as a NULL-terminated C string), 101 | * if any, or NULL. 102 | * @return The object on success, or NULL on failure. 103 | */ 104 | OQS_KEX *OQS_KEX_new(OQS_RAND *rand, enum OQS_KEX_alg_name alg_name, const uint8_t *seed, const size_t seed_len, const char *named_parameters); 105 | 106 | int OQS_KEX_alice_0(OQS_KEX *k, void **alice_priv, uint8_t **alice_msg, size_t *alice_msg_len); 107 | int OQS_KEX_bob(OQS_KEX *k, const uint8_t *alice_msg, const size_t alice_msg_len, uint8_t **bob_msg, size_t *bob_msg_len, uint8_t **key, size_t *key_len); 108 | int OQS_KEX_alice_1(OQS_KEX *k, const void *alice_priv, const uint8_t *bob_msg, const size_t bob_msg_len, uint8_t **key, size_t *key_len); 109 | 110 | void OQS_KEX_alice_priv_free(OQS_KEX *k, void *alice_priv); 111 | void OQS_KEX_free(OQS_KEX *k); 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /src/kex_lwe_frodo.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************************** 2 | * Frodo: a post-quantum key exchange based on the Learning with Errors (LWE) problem. 3 | * 4 | * Abstract: key exchange 5 | * Instantiates "kex_lwe_frodo_macrify.c" with the necessary kex functions 6 | *********************************************************************************************/ 7 | 8 | #if defined(WINDOWS) 9 | #define UNUSED 10 | #else 11 | #define UNUSED __attribute__ ((unused)) 12 | #endif 13 | 14 | #include 15 | #include 16 | #if !defined(WINDOWS) 17 | #include 18 | #include 19 | #endif 20 | 21 | #include "kex.h" 22 | #include "random/rand.h" 23 | #include "kex_lwe_frodo.h" 24 | #include "frodo_macrify.h" 25 | 26 | #if defined(USE_AVX2) 27 | #if defined(WINDOWS) 28 | #include 29 | #else 30 | #include 31 | #endif 32 | #endif 33 | 34 | #define LWE_DIV_ROUNDUP(x, y) (((x) + (y)-1) / y) 35 | 36 | 37 | OQS_KEX *OQS_KEX_lwe_frodo_new(OQS_RAND *rand, const uint8_t *seed, const size_t seed_len, const char *named_parameters) 38 | { // Create a new Frodo structure 39 | OQS_KEX *k; 40 | struct oqs_kex_lwe_frodo_params *params; 41 | 42 | if ((seed_len == 0) || (seed == NULL)) { 43 | return NULL; 44 | } 45 | 46 | k = malloc(sizeof(OQS_KEX)); 47 | if (k == NULL) { 48 | goto err; 49 | } 50 | k->named_parameters = NULL; 51 | k->method_name = NULL; 52 | 53 | k->params = malloc(sizeof(struct oqs_kex_lwe_frodo_params)); 54 | if (NULL == k->params) { 55 | goto err; 56 | } 57 | params = (struct oqs_kex_lwe_frodo_params*)k->params; 58 | params->cdf_table = NULL; 59 | params->seed = NULL; 60 | params->param_name = NULL; 61 | 62 | k->rand = rand; 63 | k->ctx = NULL; 64 | k->alice_priv_free = &OQS_KEX_lwe_frodo_alice_priv_free; 65 | k->free = &OQS_KEX_lwe_frodo_free; 66 | 67 | if (strcmp(named_parameters, "recommended") == 0) 68 | { 69 | k->alice_0 = &OQS_KEX_lwe_frodo_alice_0_recommended; 70 | k->bob = &OQS_KEX_lwe_frodo_bob_recommended; 71 | k->alice_1 = &OQS_KEX_lwe_frodo_alice_1_recommended; 72 | 73 | k->method_name = strdup("LWE Frodo recommended"); 74 | if (NULL == k->method_name) { 75 | goto err; 76 | } 77 | k->estimated_classical_security = 144; 78 | k->estimated_quantum_security = 130; 79 | k->named_parameters = strdup(named_parameters); 80 | if (k->named_parameters == NULL) { 81 | goto err; 82 | } 83 | 84 | params->seed = malloc(seed_len); 85 | if (NULL == params->seed) { 86 | goto err; 87 | } 88 | memcpy(params->seed, seed, seed_len); 89 | params->seed_len = seed_len; 90 | params->param_name = strdup("recommended"); 91 | if (NULL == params->param_name) { 92 | goto err; 93 | } 94 | params->log2_q = 15; 95 | params->q = 1 << params->log2_q; 96 | params->n = 752; 97 | params->extracted_bits = 4; 98 | params->nbar = 8; 99 | params->key_bits = 256; 100 | params->rec_hint_len = LWE_DIV_ROUNDUP(params->nbar * params->nbar, 8); 101 | params->pub_len = LWE_DIV_ROUNDUP(params->n * params->nbar * params->log2_q, 8); 102 | params->stripe_step = 8; 103 | params->sampler_num = 12; 104 | params->cdf_table_len = 6; 105 | params->cdf_table = malloc(params->cdf_table_len * sizeof(uint16_t)); 106 | if (NULL == params->cdf_table) { 107 | goto err; 108 | } 109 | uint16_t cdf_table_tmp[6] = {602, 1521, 1927, 2031, 2046, 2047}; 110 | memcpy(params->cdf_table, cdf_table_tmp, sizeof(cdf_table_tmp)); 111 | } else { 112 | goto err; 113 | } 114 | 115 | return k; 116 | 117 | err: 118 | if (k) { 119 | if (k->params) { 120 | free(params->cdf_table); 121 | free(params->seed); 122 | free(params->param_name); 123 | free(k->params); 124 | } 125 | free(k->named_parameters); 126 | free(k->method_name); 127 | free(k); 128 | } 129 | return NULL; 130 | } 131 | 132 | 133 | // Pre-process code to obtain "recommended" functions 134 | #define MACRIFY(NAME) NAME ## _recommended 135 | #define PARAMS_N 752 136 | #define PARAMS_NBAR 8 137 | #define PARAMS_EXTRACTED_BITS 4 138 | #include "kex_lwe_frodo_macrify.c" 139 | // Undefine macros to avoid any confusion later 140 | #undef PARAMS_N 141 | #undef PARAMS_NBAR 142 | #undef MACRIFY 143 | 144 | 145 | void OQS_KEX_lwe_frodo_alice_priv_free(UNUSED OQS_KEX *k, void *alice_priv) 146 | { 147 | if (alice_priv) { 148 | #if !defined(USE_AVX2) 149 | free(alice_priv); 150 | #else 151 | _mm_free(alice_priv); 152 | #endif 153 | } 154 | } 155 | 156 | 157 | void OQS_KEX_lwe_frodo_free(OQS_KEX *k) 158 | { // Free Frodo structure 159 | if (!k) { 160 | return; 161 | } 162 | if (k->params) { 163 | struct oqs_kex_lwe_frodo_params *params = (struct oqs_kex_lwe_frodo_params*)k->params; 164 | free(params->cdf_table); 165 | params->cdf_table = NULL; 166 | free(params->seed); 167 | params->seed = NULL; 168 | free(params->param_name); 169 | params->param_name = NULL; 170 | free(k->params); 171 | k->params = NULL; 172 | } 173 | free(k->named_parameters); 174 | k->named_parameters = NULL; 175 | free(k->method_name); 176 | k->method_name = NULL; 177 | free(k); 178 | } 179 | -------------------------------------------------------------------------------- /src/kex_lwe_frodo.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************************** 2 | * Frodo: a post-quantum key exchange based on the Learning with Errors (LWE) problem. 3 | * 4 | * Abstract: header for key exchange 5 | *********************************************************************************************/ 6 | 7 | #ifndef __OQS_KEX_LWE_FRODO_H 8 | #define __OQS_KEX_LWE_FRODO_H 9 | 10 | #include 11 | #include 12 | #include "kex.h" 13 | #include "random/rand.h" 14 | 15 | 16 | OQS_KEX *OQS_KEX_lwe_frodo_new(OQS_RAND *rand, const uint8_t *seed, const size_t seed_len, const char *named_parameters); 17 | int OQS_KEX_lwe_frodo_alice_0_recommended(OQS_KEX *k, void **alice_priv, uint8_t **alice_msg, size_t *alice_msg_len); 18 | int OQS_KEX_lwe_frodo_bob_recommended(OQS_KEX *k, const uint8_t *alice_msg, const size_t alice_msg_len, uint8_t **bob_msg, size_t *bob_msg_len, uint8_t **key, size_t *key_len); 19 | int OQS_KEX_lwe_frodo_alice_1_recommended(OQS_KEX *k, const void *alice_priv, const uint8_t *bob_msg, const size_t bob_msg_len, uint8_t **key, size_t *key_len); 20 | void OQS_KEX_lwe_frodo_alice_priv_free(OQS_KEX *k, void *alice_priv); 21 | void OQS_KEX_lwe_frodo_free(OQS_KEX *k); 22 | 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/kex_lwe_frodo_macrify.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************************** 2 | * Frodo: a post-quantum key exchange based on the Learning with Errors (LWE) problem. 3 | * 4 | * Abstract: key exchange functions 5 | *********************************************************************************************/ 6 | 7 | 8 | int MACRIFY(OQS_KEX_lwe_frodo_alice_0)(OQS_KEX *k, void **alice_priv, uint8_t **alice_msg, size_t *alice_msg_len) 9 | { 10 | int ret; 11 | struct oqs_kex_lwe_frodo_params *params = (struct oqs_kex_lwe_frodo_params*)k->params; 12 | uint16_t b[PARAMS_N * PARAMS_NBAR] = {0}, e[PARAMS_N * PARAMS_NBAR] = {0}; 13 | 14 | *alice_priv = NULL; 15 | *alice_msg = NULL; 16 | 17 | // Allocate private key and outgoing message 18 | #if !defined(USE_AVX2) 19 | *alice_priv = malloc(params->n * params->nbar * sizeof(uint16_t)); 20 | #else 21 | *alice_priv = _mm_malloc(params->n * params->nbar * sizeof(uint16_t), 32); 22 | #endif 23 | if (*alice_priv == NULL) { 24 | goto err; 25 | } 26 | *alice_msg = malloc(params->pub_len); 27 | if (*alice_msg == NULL) { 28 | goto err; 29 | } 30 | 31 | // Generate S and E 32 | ret = oqs_kex_lwe_frodo_sample_n(*alice_priv, params->n * params->nbar, params, k->rand); 33 | if (ret != 1) { 34 | goto err; 35 | } 36 | ret = oqs_kex_lwe_frodo_sample_n(e, params->n * params->nbar, params, k->rand); 37 | if (ret != 1) { 38 | goto err; 39 | } 40 | 41 | // Compute B = AS + E 42 | ret = MACRIFY(oqs_kex_lwe_frodo_mul_add_as_plus_e_on_the_fly)(b, *alice_priv, e, params); 43 | if (ret != 1) { 44 | goto err; 45 | } 46 | oqs_kex_lwe_frodo_pack(*alice_msg, params->pub_len, b, params->n * params->nbar, params->log2_q); 47 | 48 | *alice_msg_len = params->pub_len; 49 | 50 | ret = 1; 51 | return ret; 52 | 53 | err: 54 | ret = 0; 55 | free(*alice_msg); 56 | *alice_msg = NULL; 57 | free(*alice_priv); 58 | *alice_priv = NULL; 59 | return ret; 60 | } 61 | 62 | 63 | int MACRIFY(OQS_KEX_lwe_frodo_bob)(OQS_KEX *k, const uint8_t *alice_msg, const size_t alice_msg_len, uint8_t **bob_msg, size_t *bob_msg_len, uint8_t **key, size_t *key_len) 64 | { 65 | int ret; 66 | struct oqs_kex_lwe_frodo_params *params = (struct oqs_kex_lwe_frodo_params*)k->params; 67 | uint8_t *bob_rec = NULL; 68 | ALIGN_HEADER(32) uint16_t bob_priv[PARAMS_NBAR * PARAMS_N] ALIGN_FOOTER(32) = {0}; 69 | ALIGN_HEADER(32) uint16_t b[PARAMS_NBAR * PARAMS_N] ALIGN_FOOTER(32) = {0}; 70 | uint16_t bprime[PARAMS_NBAR * PARAMS_N] = {0}; 71 | uint16_t eprime[PARAMS_NBAR * PARAMS_N] = {0}; 72 | uint16_t eprimeprime[PARAMS_NBAR * PARAMS_NBAR] = {0}; 73 | uint16_t v[PARAMS_NBAR * PARAMS_NBAR] = {0}; 74 | *bob_msg = NULL; 75 | *key = NULL; 76 | 77 | // Check length of other party's public key 78 | if (alice_msg_len != params->pub_len) { 79 | goto err; 80 | } 81 | 82 | // Allocate outgoing message and key 83 | *bob_msg = malloc(params->pub_len + params->rec_hint_len); 84 | if (*bob_msg == NULL) { 85 | goto err; 86 | } 87 | bob_rec = *bob_msg + params->pub_len; 88 | *key = malloc(params->key_bits >> 3); 89 | if (*key == NULL) { 90 | goto err; 91 | } 92 | 93 | // Generate S' and E' 94 | ret = oqs_kex_lwe_frodo_sample_n(bob_priv, params->n * params->nbar, params, k->rand); 95 | if (ret != 1) { 96 | goto err; 97 | } 98 | ret = oqs_kex_lwe_frodo_sample_n(eprime, params->n * params->nbar, params, k->rand); 99 | if (ret != 1) { 100 | goto err; 101 | } 102 | 103 | // Compute B' = S'A + E' 104 | ret = MACRIFY(oqs_kex_lwe_frodo_mul_add_sa_plus_e_on_the_fly)(bprime, bob_priv, eprime, params); 105 | if (ret != 1) { 106 | goto err; 107 | } 108 | oqs_kex_lwe_frodo_pack(*bob_msg, params->pub_len, bprime, params->n * params->nbar, params->log2_q); 109 | 110 | // Generate E'' 111 | ret = oqs_kex_lwe_frodo_sample_n(eprimeprime, params->nbar * params->nbar, params, k->rand); 112 | if (ret != 1) { 113 | goto err; 114 | } 115 | 116 | // Unpack B 117 | oqs_kex_lwe_frodo_unpack(b, params->n * params->nbar, alice_msg, alice_msg_len, params->log2_q); 118 | 119 | // Compute V = S'B + E'' 120 | MACRIFY(oqs_kex_lwe_frodo_mul_add_sb_plus_e)(v, b, bob_priv, eprimeprime); 121 | 122 | // Compute C = _{2^B} 123 | MACRIFY(oqs_kex_lwe_frodo_crossround2)(bob_rec, v); 124 | 125 | // Compute K = round(V)_{2^B} 126 | MACRIFY(oqs_kex_lwe_frodo_round2)(*key, v); 127 | 128 | *bob_msg_len = params->pub_len + params->rec_hint_len; 129 | *key_len = params->key_bits >> 3; 130 | 131 | ret = 1; 132 | goto cleanup; 133 | 134 | err: 135 | ret = 0; 136 | free(*bob_msg); 137 | *bob_msg = NULL; 138 | if (*key != NULL) { 139 | memset(*key, 0, params->key_bits >> 3); 140 | } 141 | free(*key); 142 | *key = NULL; 143 | 144 | cleanup: 145 | memset(eprime, 0, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t)); 146 | memset(eprimeprime, 0, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); 147 | memset(v, 0, PARAMS_NBAR * PARAMS_NBAR * sizeof(uint16_t)); 148 | return ret; 149 | } 150 | 151 | 152 | int MACRIFY(OQS_KEX_lwe_frodo_alice_1)(OQS_KEX *k, const void *alice_priv, const uint8_t *bob_msg, const size_t bob_msg_len, uint8_t **key, size_t *key_len) 153 | { 154 | int ret; 155 | struct oqs_kex_lwe_frodo_params *params = (struct oqs_kex_lwe_frodo_params*)k->params; 156 | uint16_t *bprime = NULL, *w = NULL; 157 | //uint16_t bprime[PARAMS_NBAR * PARAMS_N] = {0}; 158 | //uint16_t w[PARAMS_NBAR * PARAMS_NBAR] = {0}; 159 | *key = NULL; 160 | 161 | // Check length of other party's public key 162 | if (bob_msg_len != params->pub_len + params->rec_hint_len) { 163 | goto err; 164 | } 165 | 166 | // Allocate working values and session key 167 | bprime = malloc(params->n * params->nbar * sizeof(uint16_t)); 168 | if (bprime == NULL) { 169 | goto err; 170 | } 171 | w = malloc(params->nbar * params->nbar * sizeof(uint16_t)); 172 | if (w == NULL) { 173 | goto err; 174 | } 175 | *key = malloc(params->key_bits >> 3); 176 | if (*key == NULL) { 177 | goto err; 178 | } 179 | 180 | // Unpack B' 181 | oqs_kex_lwe_frodo_unpack(bprime, params->n * params->nbar, bob_msg, params->pub_len, params->log2_q); 182 | 183 | // Compute W = B'S 184 | MACRIFY(oqs_kex_lwe_frodo_mul_bs)(w, bprime, (uint16_t*)alice_priv); 185 | 186 | // Compute K = rec(B'S, C) 187 | const uint8_t *bob_rec = bob_msg + params->pub_len; 188 | MACRIFY(oqs_kex_lwe_frodo_reconcile)(*key, w, bob_rec); 189 | 190 | *key_len = params->key_bits >> 3; 191 | 192 | ret = 1; 193 | goto cleanup; 194 | //goto exit; 195 | 196 | err: 197 | ret = 0; 198 | memset(key, 0, params->key_bits >> 3); 199 | free(*key); 200 | *key = NULL; 201 | 202 | cleanup: 203 | free(w); 204 | free(bprime); 205 | 206 | //exit: 207 | return ret; 208 | } -------------------------------------------------------------------------------- /src/lwe.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************************** 2 | * Frodo: a post-quantum key exchange based on the Learning with Errors (LWE) problem. 3 | * 4 | * Abstract: functions for the kex scheme 5 | * Instantiates "lwe_macrify.c" with the necessary matrix arithmetic functions 6 | *********************************************************************************************/ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "frodo_macrify.h" 14 | 15 | #define min(x, y) (((x) < (y)) ? (x) : (y)) 16 | 17 | 18 | void oqs_kex_lwe_frodo_key_round(uint16_t *vec, const size_t length, const int b) 19 | { // Round all elements of a vector to the nearest multiple of 2^b 20 | size_t i; 21 | uint16_t negmask = ~((1 << b) - 1); 22 | uint16_t half = b > 0 ? 1 << (b - 1) : 0; 23 | 24 | for (i = 0; i < length; i++) { 25 | vec[i] = (vec[i] + half) & negmask; 26 | } 27 | } 28 | 29 | 30 | void oqs_kex_lwe_frodo_key_round_hints(uint16_t *vec, const size_t length, const int b, const unsigned char *hint) 31 | { // Round all elements of a vector to the multiple of 2^b, with a hint for the direction of rounding when close to the boundary. 32 | size_t i; 33 | uint16_t whole = 1 << b; 34 | uint16_t mask = whole - 1; 35 | uint16_t negmask = ~mask; 36 | uint16_t half = 1 << (b - 1); 37 | uint16_t quarter = 1 << (b - 2); 38 | 39 | for (i = 0; i < length; i++) { 40 | uint16_t remainder = vec[i] & mask; 41 | uint16_t use_hint = ((remainder + quarter) >> (b - 1)) & 0x1; 42 | 43 | unsigned char h = (hint[i / 8] >> (i % 8)) % 2; // the hint 44 | uint16_t shift = use_hint * (2 * h - 1) * quarter; 45 | 46 | // If use_hint = 1 and h = 0, adding -quarter forces rounding down 47 | // h = 1, adding quarter forces rounding up 48 | 49 | vec[i] = (vec[i] + half + shift) & negmask; 50 | } 51 | } 52 | 53 | 54 | void oqs_kex_lwe_frodo_pack(unsigned char *out, const size_t outlen, const uint16_t *in, const size_t inlen, const unsigned char lsb) 55 | { // Pack the input uint16 vector into a char output vector, copying lsb bits from each input element. 56 | // If inlen * lsb / 8 > outlen, only outlen * 8 bits are copied. 57 | memset(out, 0, outlen); 58 | 59 | size_t i = 0; // whole bytes already filled in 60 | size_t j = 0; // whole uint16_t already copied 61 | uint16_t w = 0; // the leftover, not yet copied 62 | unsigned char bits = 0; // the number of lsb in w 63 | 64 | while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) { 65 | /* 66 | in: | | |********|********| 67 | ^ 68 | j 69 | w : | ****| 70 | ^ 71 | bits 72 | out:|**|**|**|**|**|**|**|**|* | 73 | ^^ 74 | ib 75 | */ 76 | unsigned char b = 0; // bits in out[i] already filled in 77 | while (b < 8) { 78 | int nbits = min(8 - b, bits); 79 | uint16_t mask = (1 << nbits) - 1; 80 | unsigned char t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out 81 | out[i] = out[i] + (t << (8 - b - nbits)); 82 | b += nbits; 83 | bits -= nbits; 84 | w &= ~(mask << bits); // not strictly necessary; mostly for debugging 85 | 86 | if (bits == 0) { 87 | if (j < inlen) { 88 | w = in[j]; 89 | bits = lsb; 90 | j++; 91 | } else { 92 | break; // the input vector is exhausted 93 | } 94 | } 95 | } 96 | if (b == 8) { // out[i] is filled in 97 | i++; 98 | } 99 | } 100 | } 101 | 102 | 103 | void oqs_kex_lwe_frodo_unpack(uint16_t *out, const size_t outlen, const unsigned char *in, const size_t inlen, const unsigned char lsb) 104 | { // Unpack the input char vector into a uint16_t output vector, copying lsb bits 105 | // for each output element from input. outlen must be at least ceil(inlen * 8 / lsb). 106 | memset(out, 0, outlen * sizeof(uint16_t)); 107 | 108 | size_t i = 0; // whole uint16_t already filled in 109 | size_t j = 0; // whole bytes already copied 110 | unsigned char w = 0; // the leftover, not yet copied 111 | unsigned char bits = 0; // the number of lsb bits of w 112 | 113 | while (i < outlen && (j < inlen || ((j == inlen) && (bits > 0)))) { 114 | /* 115 | in: | | | | | | |**|**|... 116 | ^ 117 | j 118 | w : | *| 119 | ^ 120 | bits 121 | out:| *****| *****| *** | |... 122 | ^ ^ 123 | i b 124 | */ 125 | unsigned char b = 0; // bits in out[i] already filled in 126 | while (b < lsb) { 127 | int nbits = min(lsb - b, bits); 128 | uint16_t mask = (1 << nbits) - 1; 129 | unsigned char t = (w >> (bits - nbits)) & mask; // the bits to copy from w to out 130 | out[i] = out[i] + (t << (lsb - b - nbits)); 131 | b += nbits; 132 | bits -= nbits; 133 | w &= ~(mask << bits); // not strictly necessary; mostly for debugging 134 | 135 | if (bits == 0) { 136 | if (j < inlen) { 137 | w = in[j]; 138 | bits = 8; 139 | j++; 140 | } else { 141 | break; // the input vector is exhausted 142 | } 143 | } 144 | } 145 | if (b == lsb) { // out[i] is filled in 146 | i++; 147 | } 148 | } 149 | } 150 | 151 | 152 | #define LWE_DIV_ROUNDUP(x, y) (((x) + (y)-1) / y) 153 | 154 | // Define parameters for "recommended" parameter set 155 | #define PARAMS_N 752 156 | #define PARAMS_NBAR 8 157 | #define PARAMS_LOG2Q 15 158 | #define PARAMS_Q (1 << PARAMS_LOG2Q) 159 | #define PARAMS_EXTRACTED_BITS 4 160 | #define PARAMS_SWITCH_MODULUS (PARAMS_LOG2Q-PARAMS_EXTRACTED_BITS-1) 161 | #define PARAMS_KEY_BITS 256 162 | #define PARAMS_STRIPE_STEP 8 163 | #define PARAMS_REC_HINT_LENGTH LWE_DIV_ROUNDUP(PARAMS_NBAR * PARAMS_NBAR, 8) 164 | #define PARAMS_PARALLEL 4 165 | // Pre-process code to obtain "recommended" functions 166 | #define MACRIFY(NAME) NAME ## _recommended 167 | 168 | #if defined(REFERENCE) 169 | #include "lwe_macrify_reference.c" 170 | #else 171 | #include "lwe_macrify.c" 172 | #endif 173 | 174 | // Undefine macros to avoid any confusion later 175 | #undef PARAMS_N 176 | #undef PARAMS_NBAR 177 | #undef PARAMS_LOG2Q 178 | #undef PARAMS_Q 179 | #undef PARAMS_EXTRACTED_BITS 180 | #undef PARAMS_KEY_BITS 181 | #undef PARAMS_STRIPE_STEP 182 | #undef PARAMS_REC_HINT_LENGTH 183 | #undef PARAMS_PARALLEL 184 | #undef MACRIFY 185 | -------------------------------------------------------------------------------- /src/lwe_macrify_reference.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************************** 2 | * Frodo: a post-quantum key exchange based on the Learning with Errors (LWE) problem. 3 | * 4 | * Abstract: matrix arithmetic functions required by the kex scheme 5 | *********************************************************************************************/ 6 | 7 | //#define AES128_ECB 8 | 9 | #include "malloc.h" 10 | #if defined(AES128_ECB) 11 | #include "aes/aes.h" 12 | #else 13 | #include "sha3/fips202.h" 14 | #endif 15 | 16 | 17 | int MACRIFY(oqs_kex_lwe_frodo_mul_add_as_plus_e_on_the_fly)(uint16_t *out, const uint16_t *s, const uint16_t *e, struct oqs_kex_lwe_frodo_params *params) 18 | { // Generate-and-multiply: generate matrix A (N x N) row-wise, multiply by s on the right. 19 | // Inputs: s, e (N x N_BAR) 20 | // Output: out = A*s + e (N x N_BAR) 21 | int i, j, k; 22 | int ret = 0; 23 | int16_t* A = NULL; 24 | size_t A_len = PARAMS_N * PARAMS_N * sizeof(int16_t); 25 | 26 | A = calloc(1, A_len); 27 | if (A == NULL) { 28 | return ret; 29 | } 30 | 31 | #if defined(AES128_ECB) // Matrix A generation using AES128-ECB, done per 128-bit block 32 | for (i = 0; i < PARAMS_N; i++) { 33 | for (j = 0; j < PARAMS_N; j += PARAMS_STRIPE_STEP) { 34 | A[i*PARAMS_N + j] = i; // Loading values in the little-endian order 35 | A[i*PARAMS_N + j + 1] = j; 36 | } 37 | } 38 | 39 | assert(params->seed_len == 16); 40 | void *aes_key_schedule = NULL; 41 | OQS_AES128_load_schedule(params->seed, &aes_key_schedule, 1); 42 | OQS_AES128_ECB_enc_sch((uint8_t*)A, A_len, aes_key_schedule, (uint8_t*)A); 43 | #else // Matrix A generation using cSHAKE128, done per 16*N-bit row 44 | for (i = 0; i < PARAMS_N; i++) { 45 | cshake128_simple((unsigned char*)(A + i*PARAMS_N), (unsigned long long)(2*PARAMS_N), (uint16_t)i, params->seed, (unsigned long long)params->seed_len); 46 | } 47 | #endif 48 | memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t)); 49 | 50 | for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e 51 | for (k = 0; k < PARAMS_NBAR; k++) { 52 | uint16_t sum = 0; 53 | for (j = 0; j < PARAMS_N; j++) { 54 | sum += A[i*PARAMS_N + j] * s[j*PARAMS_NBAR + k]; 55 | } 56 | out[i*PARAMS_NBAR + k] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on. 57 | } 58 | } 59 | 60 | #if defined(AES128_ECB) 61 | OQS_AES128_free_schedule(aes_key_schedule); 62 | #endif 63 | return 1; 64 | } 65 | 66 | 67 | int MACRIFY(oqs_kex_lwe_frodo_mul_add_sa_plus_e_on_the_fly)(uint16_t *out, const uint16_t *s, const uint16_t *e, struct oqs_kex_lwe_frodo_params *params) 68 | { // Generate-and-multiply: generate matrix A (N x N) column-wise, multiply by s' on the left. 69 | // Inputs: s', e' (N_BAR x N) 70 | // Output: out = s'*A + e' (N_BAR x N) 71 | int i, j, k; 72 | int ret = 0; 73 | int16_t* A = NULL; 74 | size_t A_len = PARAMS_N * PARAMS_N * sizeof(int16_t); 75 | 76 | A = calloc(1, A_len); 77 | if (A == NULL) { 78 | return ret; 79 | } 80 | 81 | #if defined(AES128_ECB) // Matrix A generation using AES128-ECB, done per 128-bit block 82 | for (i = 0; i < PARAMS_N; i++) { 83 | for (j = 0; j < PARAMS_N; j += PARAMS_STRIPE_STEP) { 84 | A[i*PARAMS_N + j] = i; // Loading values in the little-endian order 85 | A[i*PARAMS_N + j + 1] = j; 86 | } 87 | } 88 | 89 | assert(params->seed_len == 16); 90 | void *aes_key_schedule = NULL; 91 | OQS_AES128_load_schedule(params->seed, &aes_key_schedule, 1); 92 | OQS_AES128_ECB_enc_sch((uint8_t*)A, A_len, aes_key_schedule, (uint8_t*)A); 93 | #else // Matrix A generation using cSHAKE128, done per 16*N-bit row 94 | for (i = 0; i < PARAMS_N; i++) { 95 | cshake128_simple((unsigned char*)(A + i*PARAMS_N), (unsigned long long)(2*PARAMS_N), (uint16_t)i, params->seed, (unsigned long long)params->seed_len); 96 | } 97 | #endif 98 | memcpy(out, e, PARAMS_NBAR * PARAMS_N * sizeof(uint16_t)); 99 | 100 | for (i = 0; i < PARAMS_N; i++) { // Matrix multiplication-addition A*s + e 101 | for (k = 0; k < PARAMS_NBAR; k++) { 102 | uint16_t sum = 0; 103 | for (j = 0; j < PARAMS_N; j++) { 104 | sum += A[j*PARAMS_N + i] * s[k*PARAMS_N + j]; 105 | } 106 | out[k*PARAMS_N + i] += sum; // Adding e. No need to reduce modulo 2^15, extra bits are taken care of during packing later on. 107 | } 108 | } 109 | 110 | #if defined(AES128_ECB) 111 | OQS_AES128_free_schedule(aes_key_schedule); 112 | #endif 113 | return 1; 114 | } 115 | 116 | 117 | void MACRIFY(oqs_kex_lwe_frodo_mul_bs)(uint16_t *out, const uint16_t *b, const uint16_t *s) 118 | { // Multiply by s on the right 119 | // Inputs: b (N_BAR x N), s (N x N_BAR) 120 | // Output: out = b*s 121 | int i, j, k; 122 | 123 | for (i = 0; i < PARAMS_NBAR; i++) { 124 | for (j = 0; j < PARAMS_NBAR; j++) { 125 | out[i * PARAMS_NBAR + j] = 0; 126 | for (k = 0; k < PARAMS_N; k++) { 127 | out[i * PARAMS_NBAR + j] += b[i * PARAMS_N + k] * s[k*PARAMS_NBAR + j]; 128 | } 129 | out[i * PARAMS_NBAR + j] = (uint32_t)(out[i * PARAMS_NBAR + j] << 17) >> 17; // Fixed to params->q = 1 << 15) 130 | } 131 | } 132 | } 133 | 134 | 135 | void MACRIFY(oqs_kex_lwe_frodo_mul_add_sb_plus_e)(uint16_t *out, const uint16_t *b, const uint16_t *s, const uint16_t *e) 136 | { // Multiply by s on the left 137 | // Inputs: b (N x N_BAR), s (N_BAR x N), e (N_BAR x N_BAR) 138 | // Output: out = s*b + e 139 | int i, j, k; 140 | 141 | for (k = 0; k < PARAMS_NBAR; k++) { 142 | for (i = 0; i < PARAMS_NBAR; i++) { 143 | out[k * PARAMS_NBAR + i] = e[k * PARAMS_NBAR + i]; 144 | for (j = 0; j < PARAMS_N; j++) { 145 | out[k * PARAMS_NBAR + i] += s[k * PARAMS_N + j] * b[j * PARAMS_NBAR + i]; 146 | } 147 | out[k * PARAMS_NBAR + i] = (uint32_t)(out[k * PARAMS_NBAR + i] << 17) >> 17; // Fixed to params->q = 1 << 15) 148 | } 149 | } 150 | } 151 | 152 | 153 | void MACRIFY(oqs_kex_lwe_frodo_add)(uint32_t *out, const uint32_t *a, const uint32_t *b) 154 | { // Add a and b 155 | // Inputs: a, b (N_BAR x N_BAR) 156 | // Output: c = a + b 157 | 158 | for (int i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) { 159 | out[i] = ((a[i] + b[i]) << 17) >> 17; // Fixed to params->q = 1 << 15 160 | } 161 | } 162 | 163 | 164 | void MACRIFY(oqs_kex_lwe_frodo_sub)(uint32_t *out, const uint32_t *a, const uint32_t *b) 165 | { // Subtract a and b 166 | // Inputs: a, b (N_BAR x N_BAR) 167 | // Output: c = a - b 168 | 169 | for (int i = 0; i < (PARAMS_NBAR * PARAMS_NBAR); i++) { 170 | out[i] = ((a[i] - b[i]) << 17) >> 17; // Fixed to params->q = 1 << 15 171 | } 172 | } 173 | 174 | 175 | void MACRIFY(oqs_kex_lwe_frodo_round2)(unsigned char *out, uint16_t *in) 176 | { 177 | oqs_kex_lwe_frodo_key_round(in, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOG2Q - PARAMS_EXTRACTED_BITS); 178 | int i; 179 | 180 | for (i = 0; i < PARAMS_NBAR * PARAMS_NBAR; i++) { 181 | in[i] >>= PARAMS_LOG2Q - PARAMS_EXTRACTED_BITS; // Drop bits that were zeroed out 182 | } 183 | 184 | // Out should have enough space for the key 185 | oqs_kex_lwe_frodo_pack(out, PARAMS_KEY_BITS / 8, in, PARAMS_NBAR * PARAMS_NBAR, PARAMS_EXTRACTED_BITS); 186 | } 187 | 188 | 189 | void MACRIFY(oqs_kex_lwe_frodo_crossround2)(unsigned char *out, const uint16_t *in) 190 | { 191 | int i; 192 | // Out should have enough space for N_BAR * N_BAR bits 193 | memset((unsigned char *)out, 0, PARAMS_REC_HINT_LENGTH); 194 | 195 | uint16_t whole = 1 << (PARAMS_LOG2Q - PARAMS_EXTRACTED_BITS); 196 | uint16_t half = whole >> 1; 197 | uint16_t mask = whole - 1; 198 | 199 | for (i = 0; i < PARAMS_NBAR * PARAMS_NBAR; i++) { 200 | uint16_t remainder = in[i] & mask; 201 | out[i / 8] += (remainder >= half) << (i % 8); 202 | } 203 | } 204 | 205 | 206 | void MACRIFY(oqs_kex_lwe_frodo_reconcile)(unsigned char *out, uint16_t *w, const unsigned char *hint) 207 | { 208 | oqs_kex_lwe_frodo_key_round_hints(w, PARAMS_NBAR * PARAMS_NBAR, PARAMS_LOG2Q - PARAMS_EXTRACTED_BITS, hint); 209 | int i; 210 | 211 | for (i = 0; i < PARAMS_NBAR * PARAMS_NBAR; i++) { 212 | w[i] >>= PARAMS_LOG2Q - PARAMS_EXTRACTED_BITS; // Drop bits that were zeroed out 213 | } 214 | oqs_kex_lwe_frodo_pack(out, PARAMS_KEY_BITS / 8, w, PARAMS_NBAR * PARAMS_NBAR, PARAMS_EXTRACTED_BITS); 215 | } -------------------------------------------------------------------------------- /src/lwe_noise.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************************** 2 | * Frodo: a post-quantum key exchange based on the Learning with Errors (LWE) problem. 3 | * 4 | * Abstract: sampling functions 5 | *********************************************************************************************/ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "random/rand.h" 13 | #include "frodo_macrify.h" 14 | 15 | 16 | static int lwe_sample_n_inverse_8(uint16_t *s, const size_t n, const uint8_t *cdf_table, const size_t cdf_table_len, OQS_RAND *rand) 17 | { // Fills vector s with n samples from the noise distribution which requires 8 bits to sample. The distribution is specified by its CDF. 18 | // Super-constant timing: the CDF table is ingested for every sample. 19 | size_t rndlen = n; 20 | uint8_t *rndvec = (uint8_t *)malloc(rndlen); 21 | 22 | if (rndvec == NULL) { 23 | fprintf(stderr, "malloc failure\n"); 24 | return 0; 25 | } 26 | OQS_RAND_n(rand, rndvec, rndlen); 27 | 28 | size_t i, j; 29 | 30 | for (i = 0; i < n; ++i) { 31 | uint8_t sample = 0; 32 | uint8_t rnd = rndvec[i] >> 1; // Drop the least significant bit 33 | uint8_t sign = rndvec[i] & 0x1; // Pick the least significant bit 34 | 35 | // No need to compare with the last value. 36 | for (j = 0; j < cdf_table_len - 1; j++) { 37 | // Constant time comparison: 1 if cdf_table[j] < rnd, 0 otherwise. 38 | // Critically uses the fact that cdf_table[j] and rnd fit in 7 bits. 39 | sample += (uint8_t)(cdf_table[j] - rnd) >> 7; 40 | } 41 | // Assuming that sign is either 0 or 1, flips sample iff sign = 1 42 | s[i] = ((-sign) ^ sample) + sign; 43 | } 44 | 45 | memset(rndvec, 0, rndlen); 46 | free(rndvec); 47 | return 1; 48 | } 49 | 50 | 51 | static int lwe_sample_n_inverse_12(uint16_t *s, const size_t n, const uint16_t *cdf_table, const size_t cdf_table_len, OQS_RAND *rand) 52 | { // Fills vector s with n samples from the noise distribution which requires 12 bits to sample. The distribution is specified by its CDF. 53 | // Super-constant timing: the CDF table is ingested for every sample. 54 | size_t rndlen = 3 * ((n + 1) / 2); // 12 bits of unif randomness per output element 55 | uint8_t *rnd = (uint8_t *)malloc(rndlen); 56 | 57 | if (rnd == NULL) { 58 | fprintf(stderr, "malloc failure\n"); 59 | return 0; 60 | } 61 | OQS_RAND_n(rand, rnd, rndlen); 62 | 63 | size_t i; 64 | 65 | for (i = 0; i < n; i += 2) { // two output elements at a time 66 | uint8_t *pRnd = (rnd + 3 * i / 2); 67 | 68 | uint16_t rnd1 = (((pRnd[0] << 8) + pRnd[1]) & 0xFFE0) >> 5; // first 11 bits (0..10) 69 | uint16_t rnd2 = (((pRnd[1] << 8) + pRnd[2]) & 0x1FFC) >> 2; // next 11 bits (11..21) 70 | 71 | uint8_t sample1 = 0; 72 | uint8_t sample2 = 0; 73 | 74 | size_t j; 75 | // No need to compare with the last value. 76 | for (j = 0; j < cdf_table_len - 1; j++) { 77 | // Constant time comparison: 1 if LWE_CDF_TABLE[j] < rnd1, 0 otherwise. 78 | // Critically uses the fact that LWE_CDF_TABLE[j] and rnd1 fit in 15 bits. 79 | sample1 += (uint16_t)(cdf_table[j] - rnd1) >> 15; 80 | sample2 += (uint16_t)(cdf_table[j] - rnd2) >> 15; 81 | } 82 | 83 | uint8_t sign1 = (pRnd[2] & 0x02) >> 1; // 22nd bit 84 | uint8_t sign2 = pRnd[2] & 0x01; // 23rd bit 85 | 86 | // Assuming that sign1 is either 0 or 1, flips sample1 iff sign1 = 1 87 | s[i] = ((-sign1) ^ sample1) + sign1; 88 | 89 | if (i + 1 < n) { 90 | s[i + 1] = ((-sign2) ^ sample2) + sign2; 91 | } 92 | } 93 | 94 | memset(rnd, 0, rndlen); 95 | free(rnd); 96 | return 1; 97 | } 98 | 99 | 100 | static int lwe_sample_n_inverse_16(uint16_t *s, const size_t n, const uint16_t *cdf_table, const size_t cdf_table_len, OQS_RAND *rand) 101 | { // Fills vector s with n samples from the noise distribution which requires 16 bits to sample. The distribution is specified by its CDF. 102 | // Super-constant timing: the CDF table is ingested for every sample. 103 | size_t rndlen = 2 * n; 104 | uint16_t *rndvec = (uint16_t *)malloc(rndlen); 105 | 106 | if (rndvec == NULL) { 107 | return 0; 108 | } 109 | OQS_RAND_n(rand, (uint8_t *) rndvec, rndlen); 110 | 111 | size_t i, j; 112 | 113 | for (i = 0; i < n; ++i) { 114 | uint8_t sample = 0; 115 | uint16_t rnd = rndvec[i] >> 1; // Drop the least significant bit 116 | uint8_t sign = rndvec[i] & 0x1; // Pick the least significant bit 117 | 118 | // No need to compare with the last value. 119 | for (j = 0; j < cdf_table_len - 1; j++) { 120 | // Constant time comparison: 1 if LWE_CDF_TABLE[j] < rnd, 0 otherwise. 121 | // Critically uses the fact that LWE_CDF_TABLE[j] and rnd fit in 15 bits. 122 | sample += (uint16_t)(cdf_table[j] - rnd) >> 15; 123 | } 124 | // Assuming that sign is either 0 or 1, flips sample iff sign = 1 125 | s[i] = ((-sign) ^ sample) + sign; 126 | } 127 | 128 | memset(rndvec, 0, rndlen); 129 | free(rndvec); 130 | return 1; 131 | } 132 | 133 | 134 | int oqs_kex_lwe_frodo_sample_n(uint16_t *s, const size_t n, struct oqs_kex_lwe_frodo_params *params, OQS_RAND *rand) 135 | { 136 | switch (params->sampler_num) { 137 | case 8: { 138 | // Have to copy cdf_table from uint16_t to uint8_t 139 | uint8_t *cdf_table_8 = malloc(params->cdf_table_len * sizeof(uint8_t)); 140 | if (NULL == cdf_table_8) { 141 | return 0; 142 | } 143 | for (size_t i = 0; i < params->cdf_table_len; i++) { 144 | cdf_table_8[i] = (uint8_t) params->cdf_table[i]; 145 | } 146 | int ret = lwe_sample_n_inverse_8(s, n, cdf_table_8, params->cdf_table_len, rand); 147 | free(cdf_table_8); 148 | return ret; 149 | } 150 | case 12: 151 | return lwe_sample_n_inverse_12(s, n, params->cdf_table, params->cdf_table_len, rand); 152 | case 16: 153 | return lwe_sample_n_inverse_16(s, n, params->cdf_table, params->cdf_table_len, rand); 154 | default: 155 | return 0; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/random/rand.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #if defined(WINDOWS) 5 | #include 6 | #include 7 | #else 8 | #include 9 | #include 10 | #include 11 | #endif 12 | 13 | #include "rand.h" 14 | #include "rand_urandom_aesctr/rand_urandom_aesctr.h" 15 | 16 | 17 | OQS_RAND *OQS_RAND_new(enum OQS_RAND_alg_name alg_name) { 18 | switch (alg_name) { 19 | case OQS_RAND_alg_default: 20 | case OQS_RAND_alg_urandom_aesctr: 21 | return OQS_RAND_urandom_aesctr_new(); 22 | default: 23 | assert(0); 24 | return NULL; // Avoid the warning of potentialy uninitialized variable in VS 25 | } 26 | } 27 | 28 | uint8_t OQS_RAND_8(OQS_RAND *r) { 29 | return r->rand_8(r); 30 | } 31 | 32 | uint32_t OQS_RAND_32(OQS_RAND *r) { 33 | return r->rand_32(r); 34 | } 35 | 36 | uint64_t OQS_RAND_64(OQS_RAND *r) { 37 | return r->rand_64(r); 38 | } 39 | 40 | void OQS_RAND_n(OQS_RAND *r, uint8_t *out, size_t n) { 41 | r->rand_n(r, out, n); 42 | } 43 | 44 | void OQS_RAND_free(OQS_RAND *r) { 45 | if (r) { 46 | r->free(r); 47 | } 48 | } 49 | 50 | __inline void OQS_RAND_test_record_occurrence(const unsigned char b, unsigned long occurrences[256]) { 51 | occurrences[b] += 1; 52 | } 53 | 54 | 55 | double OQS_RAND_test_statistical_distance_from_uniform(const unsigned long occurrences[256]) { 56 | 57 | // compute total number of samples 58 | unsigned long total = 0; 59 | for (int i = 0; i < 256; i++) { 60 | total += occurrences[i]; 61 | } 62 | 63 | // compute statistical distance from uniform 64 | // SD(X,Y) = 1/2 \sum_z | Pr[X=z] - Pr[Y=z] | 65 | // = 1/2 \sum_z | 1/256 - Pr[Y=z] | 66 | double distance = 0.0; 67 | for (int i = 0; i < 256; i++) { 68 | distance += fabs(1.0 / 256.0 - (double) occurrences[i] / (double) total); 69 | } 70 | distance /= 2.0; 71 | 72 | return distance; 73 | } 74 | 75 | 76 | // Even for a perfectly uniform generator, if the number of samples is 77 | // low then the std dev of the counts will be high. So, instead, whilst 78 | // still assuming the number of samples isn't super-low, we calculate an 79 | // approximate Chi-squared statistic and back-convert to the Normal 80 | // distribution. The number of sigmas is reported: -3 to +3 is pretty 81 | // ordinary, big negative is suspiciously-flat counts, big positive is 82 | // wildly-fluctuating counts. 83 | double OQS_RAND_zscore_deviation_from_uniform(const unsigned long occurrences[256]) { 84 | double quantiles[102] = { 85 | 156.7872, 158.4155, 160.0555, 161.7072, 163.3707, 165.0460, 166.7331, 168.4321, 86 | 170.1430, 171.8658, 173.6006, 175.3475, 177.1064, 178.8773, 180.6604, 182.4557, 87 | 184.2631, 186.0828, 187.9147, 189.7589, 191.6155, 193.4844, 195.3657, 197.2594, 88 | 199.1656, 201.0843, 203.0155, 204.9593, 206.9157, 208.8847, 210.8663, 212.8607, 89 | 214.8678, 216.8877, 218.9203, 220.9658, 223.0241, 225.0953, 227.1794, 229.2765, 90 | 231.3866, 233.5096, 235.6457, 237.7949, 239.9572, 242.1326, 244.3212, 246.5230, 91 | 248.7380, 250.9663, 253.2079, 255.4627, 257.7310, 260.0126, 262.3076, 264.6160, 92 | 266.9379, 269.2733, 271.6222, 273.9846, 276.3607, 278.7503, 281.1536, 283.5705, 93 | 286.0011, 288.4454, 290.9035, 293.3754, 295.8610, 298.3605, 300.8739, 303.4011, 94 | 305.9422, 308.4973, 311.0663, 313.6493, 316.2463, 318.8574, 321.4825, 324.1217, 95 | 326.7751, 329.4426, 332.1242, 334.8201, 337.5301, 340.2544, 342.9930, 345.7459, 96 | 348.5131, 351.2947, 354.0906, 356.9009, 359.7256, 362.5648, 365.4184, 368.2866, 97 | 371.1692, 374.0664, 376.9782, 379.9045, 382.8454, 385.8010}; // -5.05 to +5.05 sigma: qchisq(pnorm(seq(-5.05,5.05,length.out=102)),255) 98 | unsigned long total; 99 | double chsq; 100 | int i; 101 | 102 | for (total = i = 0; i < 256; i++) { 103 | total += occurrences[i]; 104 | } 105 | if (total / 256. < 5) { 106 | return ZSCORE_SPARSE; 107 | } 108 | 109 | for (chsq = i = 0; i < 256; i++) { 110 | chsq += pow(occurrences[i] - total / 256., 2) * 256. / total; 111 | } 112 | 113 | if (chsq <= quantiles[0]) { 114 | return ZSCORE_BIGNEG; 115 | } 116 | for (i = 1; i < 102; i++) { 117 | if (chsq <= quantiles[i]) { 118 | return (i - 51) / 10.0; 119 | } 120 | } 121 | return ZSCORE_BIGPOS; 122 | } 123 | 124 | 125 | // Convenience function for statistics reporting 126 | void OQS_RAND_report_statistics(const unsigned long occurrences[256], const char *indent) { 127 | double zscore = OQS_RAND_zscore_deviation_from_uniform(occurrences); 128 | printf("%sStatistical distance from uniform: %12.10f\n", indent, OQS_RAND_test_statistical_distance_from_uniform(occurrences)); 129 | printf("%s Z-score deviation from uniform: ", indent); 130 | if (zscore == ZSCORE_BIGNEG) { 131 | printf("less than -5.0 sigma ***\n"); 132 | } else if (zscore == ZSCORE_BIGPOS) { 133 | printf("more than +5.0 sigma ***\n"); 134 | } else if (zscore == ZSCORE_SPARSE) { 135 | printf("(too few data)\n"); 136 | } else { 137 | printf("about %.1f sigma\n", zscore); 138 | } 139 | return; 140 | } 141 | 142 | int OQS_RAND_get_system_entropy(uint8_t *buf, size_t n) { 143 | int result = 0; 144 | 145 | #if !defined(WINDOWS) 146 | int fd = 0; 147 | #endif 148 | 149 | if (!buf) { 150 | goto err; 151 | } 152 | 153 | #if defined(WINDOWS) 154 | HCRYPTPROV hCryptProv; 155 | if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) || 156 | !CryptGenRandom(hCryptProv, n, buf)) { 157 | goto err; 158 | } 159 | #else 160 | fd = open("/dev/urandom", O_RDONLY); 161 | if (fd <= 0) { 162 | goto err; 163 | } 164 | size_t r = read(fd, buf, n); 165 | if (r != n) { 166 | goto err; 167 | } 168 | #endif 169 | result = 1; 170 | 171 | err: 172 | #if !defined(WINDOWS) 173 | if (fd > 0) { 174 | close(fd); 175 | } 176 | #endif 177 | 178 | return result; 179 | } 180 | -------------------------------------------------------------------------------- /src/random/rand.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file rand.h 3 | * \brief Header defining the generic OQS PRNG 4 | */ 5 | 6 | #ifndef __OQS_RAND_H 7 | #define __OQS_RAND_H 8 | 9 | #include 10 | #include 11 | 12 | enum OQS_RAND_alg_name { 13 | OQS_RAND_alg_default, 14 | OQS_RAND_alg_urandom_chacha20, 15 | OQS_RAND_alg_urandom_aesctr, 16 | }; 17 | 18 | typedef struct OQS_RAND OQS_RAND; 19 | 20 | /** 21 | * OQS PRNG object 22 | */ 23 | typedef struct OQS_RAND { 24 | 25 | /** 26 | * Specifies the name of the random number function 27 | */ 28 | char *method_name; 29 | 30 | /** 31 | * Estimated number of bits of security provided against a classical 32 | * attacker 33 | */ 34 | uint16_t estimated_classical_security; 35 | 36 | /** 37 | * Estimated number of bits of security provided against a quantum 38 | * attacker 39 | */ 40 | uint16_t estimated_quantum_security; 41 | 42 | /** 43 | * Pointer for storing the state of the PRNG 44 | */ 45 | void *ctx; 46 | 47 | /** 48 | * Function which returns an 8-bit random unsigned integer 49 | */ 50 | uint8_t (*rand_8)(OQS_RAND *r); 51 | 52 | /** 53 | * Function which returns an 32-bit random unsigned integer 54 | */ 55 | uint32_t (*rand_32)(OQS_RAND *r); 56 | 57 | /** 58 | * Function which returns an 64-bit random unsigned integer 59 | */ 60 | uint64_t (*rand_64)(OQS_RAND *r); 61 | 62 | /** 63 | * Function which generates n random 8-bit unsigned integers 64 | * 65 | * @param out : pointer to an array large enough to store the output integers (\f$\text{size} \geq n\f$) 66 | * @param n : number of integers to generate 67 | */ 68 | void (*rand_n)(OQS_RAND *r, uint8_t *out, size_t n); 69 | 70 | /** 71 | * Pointer to a function for freeing the allocated key exchange structure 72 | * 73 | * @param k : Key exchange structure 74 | * 75 | */ 76 | void (*free)(OQS_RAND *r); 77 | 78 | } OQS_RAND; 79 | 80 | OQS_RAND *OQS_RAND_new(enum OQS_RAND_alg_name alg_name); 81 | 82 | uint8_t OQS_RAND_8(OQS_RAND *r); 83 | uint32_t OQS_RAND_32(OQS_RAND *r); 84 | uint64_t OQS_RAND_64(OQS_RAND *r); 85 | void OQS_RAND_n(OQS_RAND *r, uint8_t *out, size_t n); 86 | 87 | void OQS_RAND_free(OQS_RAND *r); 88 | 89 | extern void OQS_RAND_test_record_occurrence(const unsigned char b, unsigned long occurrences[256]); 90 | double OQS_RAND_test_statistical_distance_from_uniform(const unsigned long occurrences[256]); 91 | 92 | #define ZSCORE_SPARSE (999.999) 93 | #define ZSCORE_BIGNEG (-100.0) 94 | #define ZSCORE_BIGPOS (+100.0) 95 | double OQS_RAND_zscore_deviation_from_uniform(const unsigned long occurrences[256]); 96 | void OQS_RAND_report_statistics(const unsigned long occurrences[256], const char *indent); 97 | 98 | int OQS_RAND_get_system_entropy(uint8_t *buf, size_t n); 99 | #endif 100 | -------------------------------------------------------------------------------- /src/random/rand_urandom_aesctr/rand_urandom_aesctr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #if defined(WINDOWS) 3 | #include 4 | #include 5 | #else 6 | #include 7 | #include 8 | #include 9 | #endif 10 | #include 11 | #include 12 | #include 13 | #include //memcpy 14 | 15 | #include 16 | #include "../rand.h" 17 | #include "rand_urandom_aesctr.h" 18 | #include "../../aes/aes.h" 19 | 20 | typedef struct oqs_rand_urandom_aesctr_ctx { 21 | uint64_t ctr; 22 | void *schedule; 23 | uint8_t cache[64]; 24 | size_t cache_next_byte; 25 | } oqs_rand_urandom_aesctr_ctx; 26 | 27 | static oqs_rand_urandom_aesctr_ctx *oqs_rand_urandom_aesctr_ctx_new() { 28 | oqs_rand_urandom_aesctr_ctx *rand_ctx = NULL; 29 | rand_ctx = (oqs_rand_urandom_aesctr_ctx *) malloc(sizeof(oqs_rand_urandom_aesctr_ctx)); 30 | if (rand_ctx == NULL) { 31 | goto err; 32 | } 33 | uint8_t key[16]; 34 | if (!OQS_RAND_get_system_entropy(key, 16)) { 35 | goto err; 36 | } 37 | OQS_AES128_load_schedule(key, &rand_ctx->schedule, 1); 38 | rand_ctx->cache_next_byte = 64; // cache is empty 39 | rand_ctx->ctr = 0; 40 | goto okay; 41 | err: 42 | if (rand_ctx) { 43 | free(rand_ctx); 44 | } 45 | return NULL; 46 | okay: 47 | return rand_ctx; 48 | } 49 | 50 | void OQS_RAND_urandom_aesctr_n(OQS_RAND *r, uint8_t *out, size_t n) { 51 | oqs_rand_urandom_aesctr_ctx *rand_ctx = (oqs_rand_urandom_aesctr_ctx *) r->ctx; 52 | const uint64_t num_full_blocks = n / 16; 53 | uint64_t *half_blocks = (uint64_t *) out; 54 | for (size_t i = 0; i < num_full_blocks; i++) { 55 | half_blocks[2 * i] = rand_ctx->ctr++; 56 | half_blocks[2 * i + 1] = rand_ctx->ctr++; 57 | } 58 | OQS_AES128_ECB_enc_sch(out, 16 * num_full_blocks, rand_ctx->schedule, out); 59 | if (n % 16 > 0) { 60 | uint8_t tmp_8[16]; 61 | uint64_t *tmp_64 = (uint64_t *) tmp_8; 62 | tmp_64[0] = rand_ctx->ctr++; 63 | tmp_64[1] = rand_ctx->ctr++; 64 | OQS_AES128_ECB_enc_sch(tmp_8, 16, rand_ctx->schedule, tmp_8); 65 | memcpy(out + 16 * num_full_blocks, tmp_8, n % 16); 66 | } 67 | } 68 | 69 | static void OQS_RAND_urandom_aesctr_fill_cache(OQS_RAND *r) { 70 | oqs_rand_urandom_aesctr_ctx *rand_ctx = (oqs_rand_urandom_aesctr_ctx *) r->ctx; 71 | OQS_RAND_urandom_aesctr_n(r, rand_ctx->cache, sizeof(rand_ctx->cache)); 72 | rand_ctx->cache_next_byte = 0; 73 | } 74 | 75 | uint8_t OQS_RAND_urandom_aesctr_8(OQS_RAND *r) { 76 | oqs_rand_urandom_aesctr_ctx *rand_ctx = (oqs_rand_urandom_aesctr_ctx *) r->ctx; 77 | if (rand_ctx->cache_next_byte > sizeof(rand_ctx->cache) - 1) { 78 | OQS_RAND_urandom_aesctr_fill_cache(r); 79 | } 80 | uint8_t out = rand_ctx->cache[rand_ctx->cache_next_byte]; 81 | rand_ctx->cache_next_byte += 1; 82 | return out; 83 | } 84 | 85 | uint32_t OQS_RAND_urandom_aesctr_32(OQS_RAND *r) { 86 | oqs_rand_urandom_aesctr_ctx *rand_ctx = (oqs_rand_urandom_aesctr_ctx *) r->ctx; 87 | if (rand_ctx->cache_next_byte > sizeof(rand_ctx->cache) - 4) { 88 | OQS_RAND_urandom_aesctr_fill_cache(r); 89 | } 90 | uint32_t out; 91 | memcpy(&out, &rand_ctx->cache[rand_ctx->cache_next_byte], 4); 92 | rand_ctx->cache_next_byte += 4; 93 | return out; 94 | } 95 | 96 | uint64_t OQS_RAND_urandom_aesctr_64(OQS_RAND *r) { 97 | oqs_rand_urandom_aesctr_ctx *rand_ctx = (oqs_rand_urandom_aesctr_ctx *) r->ctx; 98 | if (rand_ctx->cache_next_byte > sizeof(rand_ctx->cache) - 8) { 99 | OQS_RAND_urandom_aesctr_fill_cache(r); 100 | } 101 | uint64_t out; 102 | memcpy(&out, &rand_ctx->cache[rand_ctx->cache_next_byte], 8); 103 | rand_ctx->cache_next_byte += 8; 104 | return out; 105 | } 106 | 107 | void OQS_RAND_urandom_aesctr_free(OQS_RAND *r) { 108 | if (r) { 109 | oqs_rand_urandom_aesctr_ctx *rand_ctx = (oqs_rand_urandom_aesctr_ctx *) r->ctx; 110 | if (rand_ctx) { 111 | OQS_AES128_free_schedule(rand_ctx->schedule); 112 | } 113 | free(r->ctx); 114 | free(r->method_name); 115 | } 116 | free(r); 117 | } 118 | 119 | OQS_RAND *OQS_RAND_urandom_aesctr_new() { 120 | OQS_RAND *r = malloc(sizeof(OQS_RAND)); 121 | if (r == NULL) { 122 | return NULL; 123 | } 124 | r->method_name = strdup("urandom_aesctr"); 125 | r->ctx = oqs_rand_urandom_aesctr_ctx_new(); 126 | if (r->ctx == NULL || r->method_name == NULL) { 127 | OQS_RAND_urandom_aesctr_free(r); 128 | return NULL; 129 | } 130 | r->estimated_classical_security = 128; 131 | r->estimated_quantum_security = 64; // Grover search 132 | r->rand_8 = &OQS_RAND_urandom_aesctr_8; 133 | r->rand_32 = &OQS_RAND_urandom_aesctr_32; 134 | r->rand_64 = &OQS_RAND_urandom_aesctr_64; 135 | r->rand_n = &OQS_RAND_urandom_aesctr_n; 136 | r->free = &OQS_RAND_urandom_aesctr_free; 137 | return r; 138 | } 139 | -------------------------------------------------------------------------------- /src/random/rand_urandom_aesctr/rand_urandom_aesctr.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \file rand_urandom_aesctr.h 3 | * \brief Header for the chacha implementation of OQS_RAND 4 | */ 5 | 6 | #ifndef __OQS_RAND_URANDOM_AESCTR_H 7 | #define __OQS_RAND_URANDOM_AESCTR_H 8 | 9 | #include 10 | #include 11 | 12 | #include "../rand.h" 13 | 14 | OQS_RAND *OQS_RAND_urandom_aesctr_new(); 15 | 16 | uint8_t OQS_RAND_urandom_aesctr_8(OQS_RAND *r); 17 | uint32_t OQS_RAND_urandom_aesctr_32(OQS_RAND *r); 18 | uint64_t OQS_RAND_urandom_aesctr_64(OQS_RAND *r); 19 | void OQS_RAND_urandom_aesctr_n(OQS_RAND *r, uint8_t *out, size_t n); 20 | 21 | void OQS_RAND_urandom_aesctr_free(OQS_RAND *r); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/random/test_rand.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "rand.h" 9 | 10 | struct rand_testcase { 11 | enum OQS_RAND_alg_name alg_name; 12 | }; 13 | 14 | /* Add new testcases here */ 15 | struct rand_testcase rand_testcases[] = { 16 | {OQS_RAND_alg_urandom_aesctr}, 17 | }; 18 | 19 | #define RAND_TEST_ITERATIONS 10000000L 20 | 21 | static void rand_test_distribution_8(OQS_RAND *rand, unsigned long occurrences[256], int iterations) { 22 | uint8_t b; 23 | for (int i = 0; i < iterations; i++) { 24 | b = OQS_RAND_8(rand); 25 | OQS_RAND_test_record_occurrence(b, occurrences); 26 | } 27 | } 28 | 29 | static void rand_test_distribution_32(OQS_RAND *rand, unsigned long occurrences[256], int iterations) { 30 | uint32_t x; 31 | for (int i = 0; i < iterations; i++) { 32 | x = OQS_RAND_32(rand); 33 | uint8_t b; 34 | for (size_t j = 0; j < sizeof(uint32_t); j++) { 35 | b = (x >> j) & 0xFF; 36 | OQS_RAND_test_record_occurrence(b, occurrences); 37 | } 38 | } 39 | } 40 | 41 | static void rand_test_distribution_64(OQS_RAND *rand, unsigned long occurrences[256], int iterations) { 42 | uint64_t x; 43 | for (int i = 0; i < iterations; i++) { 44 | x = OQS_RAND_64(rand); 45 | uint8_t b; 46 | for (size_t j = 0; j < sizeof(uint64_t); j++) { 47 | b = (x >> j) & 0xFF; 48 | OQS_RAND_test_record_occurrence(b, occurrences); 49 | } 50 | } 51 | } 52 | 53 | static int rand_test_distribution_n(OQS_RAND *rand, unsigned long occurrences[256], int len) { 54 | uint8_t *x = malloc(len); 55 | if (x == NULL) { 56 | return 0; 57 | } 58 | OQS_RAND_n(rand, x, len); 59 | for (int i = 0; i < len; i++) { 60 | OQS_RAND_test_record_occurrence(x[i], occurrences); 61 | } 62 | free(x); 63 | return 1; 64 | } 65 | 66 | #define PRINT_HEX_STRING(label, str, len) \ 67 | { \ 68 | printf("%-20s (%4zu bytes): ", (label), (size_t)(len)); \ 69 | for (size_t i = 0; i < (len); i++) { \ 70 | printf("%02X", ((unsigned char *) (str))[i]); \ 71 | } \ 72 | printf("\n"); \ 73 | } 74 | 75 | static int rand_test_distribution_wrapper(enum OQS_RAND_alg_name alg_name, int iterations, bool quiet) { 76 | 77 | OQS_RAND *rand = OQS_RAND_new(alg_name); 78 | if (rand == NULL) { 79 | fprintf(stderr, "rand is NULL\n"); 80 | return 0; 81 | } 82 | 83 | if (!quiet) { 84 | printf("================================================================================\n"); 85 | printf("Sample outputs of PRNG %s\n", rand->method_name); 86 | printf("================================================================================\n"); 87 | 88 | uint8_t x[256]; 89 | OQS_RAND_n(rand, x, 256); 90 | PRINT_HEX_STRING("OQS_RAND_n, n = 256", x, 256) 91 | 92 | uint8_t y8 = OQS_RAND_8(rand); 93 | PRINT_HEX_STRING("OQS_RAND_8", (uint8_t *) &y8, sizeof(y8)); 94 | y8 = OQS_RAND_8(rand); 95 | PRINT_HEX_STRING("OQS_RAND_8", (uint8_t *) &y8, sizeof(y8)); 96 | 97 | uint32_t y32 = OQS_RAND_32(rand); 98 | PRINT_HEX_STRING("OQS_RAND_32", (uint8_t *) &y32, sizeof(y32)); 99 | y32 = OQS_RAND_32(rand); 100 | PRINT_HEX_STRING("OQS_RAND_32", (uint8_t *) &y32, sizeof(y32)); 101 | 102 | uint64_t y64 = OQS_RAND_64(rand); 103 | PRINT_HEX_STRING("OQS_RAND_64", (uint8_t *) &y64, sizeof(y64)); 104 | y64 = OQS_RAND_64(rand); 105 | PRINT_HEX_STRING("OQS_RAND_64", (uint8_t *) &y64, sizeof(y64)); 106 | 107 | OQS_RAND_n(rand, x, 256); 108 | PRINT_HEX_STRING("OQS_RAND_n, n = 256", x, 256) 109 | } 110 | 111 | printf("================================================================================\n"); 112 | printf("Testing distribution of PRNG %s\n", rand->method_name); 113 | printf("================================================================================\n"); 114 | 115 | unsigned long occurrences[256]; 116 | for (int i = 0; i < 256; i++) { 117 | occurrences[i] = 0; 118 | } 119 | 120 | printf("1-byte mode for %d iterations\n", 8 * iterations); 121 | rand_test_distribution_8(rand, occurrences, 8 * iterations); 122 | OQS_RAND_report_statistics(occurrences, " "); 123 | 124 | for (int i = 0; i < 256; i++) { 125 | occurrences[i] = 0; 126 | } 127 | 128 | printf("4-byte mode for %d iterations\n", 2 * iterations); 129 | rand_test_distribution_32(rand, occurrences, 2 * iterations); 130 | OQS_RAND_report_statistics(occurrences, " "); 131 | 132 | for (int i = 0; i < 256; i++) { 133 | occurrences[i] = 0; 134 | } 135 | 136 | printf("8-byte mode for %d iterations\n", iterations); 137 | rand_test_distribution_64(rand, occurrences, iterations); 138 | OQS_RAND_report_statistics(occurrences, " "); 139 | 140 | for (int i = 0; i < 256; i++) { 141 | occurrences[i] = 0; 142 | } 143 | 144 | printf("n-byte mode for %d bytes\n", 8 * iterations); 145 | rand_test_distribution_n(rand, occurrences, 8 * iterations); 146 | OQS_RAND_report_statistics(occurrences, " "); 147 | 148 | OQS_RAND_free(rand); 149 | 150 | return 1; 151 | } 152 | 153 | int main(int argc, char **argv) { 154 | 155 | int success; 156 | bool quiet = false; 157 | 158 | for (int i = 1; i < argc; i++) { 159 | if (argv[i][0] == '-') { 160 | if (strcmp(argv[i], "--quiet") == 0 || strcmp(argv[i], "-q") == 0) { 161 | quiet = true; 162 | } else { 163 | printf("Usage: ./test_rand [options]\n"); 164 | printf("\nOptions:\n"); 165 | printf(" --quiet, -q\n"); 166 | printf(" Less verbose output\n"); 167 | if ((strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "-help") == 0) || (strcmp(argv[i], "--help") == 0)) { 168 | return EXIT_SUCCESS; 169 | } else { 170 | return EXIT_FAILURE; 171 | } 172 | } 173 | } 174 | } 175 | 176 | size_t rand_testcases_len = sizeof(rand_testcases) / sizeof(struct rand_testcase); 177 | for (size_t i = 0; i < rand_testcases_len; i++) { 178 | success = rand_test_distribution_wrapper(rand_testcases[i].alg_name, RAND_TEST_ITERATIONS, quiet); 179 | if (success != 1) { 180 | goto err; 181 | } 182 | } 183 | 184 | success = 1; 185 | goto cleanup; 186 | 187 | err: 188 | success = 0; 189 | fprintf(stderr, "ERROR!\n"); 190 | 191 | cleanup: 192 | 193 | return (success == 1) ? EXIT_SUCCESS : EXIT_FAILURE; 194 | } 195 | -------------------------------------------------------------------------------- /src/sha3/fips202.h: -------------------------------------------------------------------------------- 1 | #ifndef FIPS202_H 2 | #define FIPS202_H 3 | 4 | #include 5 | 6 | 7 | #define SHAKE128_RATE 168 8 | #define SHAKE256_RATE 136 9 | 10 | void shake128_absorb(uint64_t *s, const unsigned char *input, unsigned int inputByteLen); 11 | void shake128_squeezeblocks(unsigned char *output, unsigned long long nblocks, uint64_t *s); 12 | void shake128(unsigned char *output, unsigned long long outlen, const unsigned char *input, unsigned long long inlen); 13 | 14 | void cshake128_simple_absorb(uint64_t *s, uint16_t cstm, const unsigned char *in, unsigned long long inlen); 15 | void cshake128_simple_squeezeblocks(unsigned char *output, unsigned long long nblocks, uint64_t *s); 16 | void cshake128_simple(unsigned char *output, unsigned long long outlen, uint16_t cstm, const unsigned char *in, unsigned long long inlen); 17 | 18 | void shake256_absorb(uint64_t *s, const unsigned char *input, unsigned int inputByteLen); 19 | void shake256_squeezeblocks(unsigned char *output, unsigned long long nblocks, uint64_t *s); 20 | void shake256(unsigned char *output, unsigned long long outlen, const unsigned char *input, unsigned long long inlen); 21 | 22 | void cshake256_simple_absorb(uint64_t *s, uint16_t cstm, const unsigned char *in, unsigned long long inlen); 23 | void cshake256_simple_squeezeblocks(unsigned char *output, unsigned long long nblocks, uint64_t *s); 24 | void cshake256_simple(unsigned char *output, unsigned long long outlen, uint16_t cstm, const unsigned char *in, unsigned long long inlen); 25 | 26 | void kmac256_simple(unsigned char *output, uint8_t outlen, uint16_t cstm, const unsigned char *in, unsigned long long inlen, const unsigned char *key, uint8_t keylen, unsigned char *temp); 27 | 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/sha3/fips202x4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "fips202.h" 5 | 6 | #define NROUNDS 24 7 | #define ROL(a, offset) ((a << offset) ^ (a >> (64-offset))) 8 | 9 | static uint64_t load64(const unsigned char *x) 10 | { 11 | unsigned long long r = 0, i; 12 | 13 | for (i = 0; i < 8; ++i) { 14 | r |= (unsigned long long)x[i] << 8 * i; 15 | } 16 | return r; 17 | } 18 | 19 | static void store64(uint8_t *x, uint64_t u) 20 | { 21 | unsigned int i; 22 | 23 | for(i=0; i<8; ++i) { 24 | x[i] = u; 25 | u >>= 8; 26 | } 27 | } 28 | 29 | /* Use implementation from the Keccak Code Package */ 30 | extern void KeccakP1600times4_PermuteAll_24rounds(__m256i *s); 31 | #define KeccakF1600_StatePermute4x KeccakP1600times4_PermuteAll_24rounds 32 | 33 | 34 | static void keccak_absorb4x(__m256i *s, 35 | unsigned int r, 36 | const unsigned char *m0, 37 | const unsigned char *m1, 38 | const unsigned char *m2, 39 | const unsigned char *m3, 40 | unsigned long long int mlen, 41 | unsigned char p) 42 | { 43 | unsigned long long i; 44 | unsigned char t0[200]; 45 | unsigned char t1[200]; 46 | unsigned char t2[200]; 47 | unsigned char t3[200]; 48 | 49 | unsigned long long *ss = (unsigned long long *)s; 50 | 51 | 52 | while (mlen >= r) 53 | { 54 | for (i = 0; i < r / 8; ++i) 55 | { 56 | ss[4*i+0] ^= load64(m0 + 8 * i); 57 | ss[4*i+1] ^= load64(m1 + 8 * i); 58 | ss[4*i+2] ^= load64(m2 + 8 * i); 59 | ss[4*i+3] ^= load64(m3 + 8 * i); 60 | } 61 | 62 | KeccakF1600_StatePermute4x(s); 63 | mlen -= r; 64 | m0 += r; 65 | m1 += r; 66 | m2 += r; 67 | m3 += r; 68 | } 69 | 70 | for (i = 0; i < r; ++i) 71 | { 72 | t0[i] = 0; 73 | t1[i] = 0; 74 | t2[i] = 0; 75 | t3[i] = 0; 76 | } 77 | for (i = 0; i < mlen; ++i) 78 | { 79 | t0[i] = m0[i]; 80 | t1[i] = m1[i]; 81 | t2[i] = m2[i]; 82 | t3[i] = m3[i]; 83 | } 84 | 85 | t0[i] = p; 86 | t1[i] = p; 87 | t2[i] = p; 88 | t3[i] = p; 89 | 90 | t0[r - 1] |= 128; 91 | t1[r - 1] |= 128; 92 | t2[r - 1] |= 128; 93 | t3[r - 1] |= 128; 94 | 95 | for (i = 0; i < r / 8; ++i) 96 | { 97 | ss[4*i+0] ^= load64(t0 + 8 * i); 98 | ss[4*i+1] ^= load64(t1 + 8 * i); 99 | ss[4*i+2] ^= load64(t2 + 8 * i); 100 | ss[4*i+3] ^= load64(t3 + 8 * i); 101 | } 102 | } 103 | 104 | 105 | static void keccak_squeezeblocks4x(unsigned char *h0, 106 | unsigned char *h1, 107 | unsigned char *h2, 108 | unsigned char *h3, 109 | unsigned long long int nblocks, 110 | __m256i *s, 111 | unsigned int r) 112 | { 113 | unsigned int i; 114 | 115 | unsigned long long *ss = (unsigned long long *)s; 116 | 117 | while(nblocks > 0) 118 | { 119 | KeccakF1600_StatePermute4x(s); 120 | for(i=0;i<(r>>3);i++) 121 | { 122 | store64(h0+8*i, ss[4*i+0]); 123 | store64(h1+8*i, ss[4*i+1]); 124 | store64(h2+8*i, ss[4*i+2]); 125 | store64(h3+8*i, ss[4*i+3]); 126 | } 127 | h0 += r; 128 | h1 += r; 129 | h2 += r; 130 | h3 += r; 131 | nblocks--; 132 | } 133 | } 134 | 135 | void cshake128_simple_absorb4x(__m256i *s, 136 | uint16_t cstm0, 137 | uint16_t cstm1, 138 | uint16_t cstm2, 139 | uint16_t cstm3, 140 | const unsigned char *in, unsigned long long inlen) 141 | { 142 | unsigned char *sep = (unsigned char *)s; 143 | unsigned int i; 144 | 145 | for(i=0;i<25;i++) 146 | s[i] = _mm256_xor_si256(s[i], s[i]); // zero state 147 | 148 | /* Absorb customization (domain-separation) string */ 149 | for(i=0;i<4;i++) 150 | { 151 | sep[8*i+0] = 0x01; 152 | sep[8*i+1] = 0xa8; 153 | sep[8*i+2] = 0x01; 154 | sep[8*i+3] = 0x00; 155 | sep[8*i+4] = 0x01; 156 | sep[8*i+5] = 16; 157 | } 158 | sep[ 6] = cstm0 & 0xff; 159 | sep[ 7] = cstm0 >> 8; 160 | sep[14] = cstm1 & 0xff; 161 | sep[15] = cstm1 >> 8; 162 | sep[22] = cstm2 & 0xff; 163 | sep[23] = cstm2 >> 8; 164 | sep[30] = cstm3 & 0xff; 165 | sep[31] = cstm3 >> 8; 166 | 167 | KeccakF1600_StatePermute4x(s); 168 | 169 | /* Absorb input */ 170 | keccak_absorb4x(s, SHAKE128_RATE, in, in, in, in, inlen, 0x04); 171 | } 172 | 173 | void cshake128_simple_squeezeblocks4x(unsigned char *output0, 174 | unsigned char *output1, 175 | unsigned char *output2, 176 | unsigned char *output3, unsigned long long outlen, 177 | __m256i *s) 178 | { 179 | keccak_squeezeblocks4x(output0, output1, output2, output3, outlen/SHAKE128_RATE, s, SHAKE128_RATE); 180 | } 181 | 182 | 183 | /* N is assumed to be empty; S is assumed to have at most 2 characters */ 184 | void cshake128_simple4x(unsigned char *output0, 185 | unsigned char *output1, 186 | unsigned char *output2, 187 | unsigned char *output3, unsigned long long outlen, 188 | uint16_t cstm0, 189 | uint16_t cstm1, 190 | uint16_t cstm2, 191 | uint16_t cstm3, 192 | const unsigned char *in, unsigned long long inlen) 193 | { 194 | __m256i s[25]; 195 | unsigned char t0[SHAKE128_RATE]; 196 | unsigned char t1[SHAKE128_RATE]; 197 | unsigned char t2[SHAKE128_RATE]; 198 | unsigned char t3[SHAKE128_RATE]; 199 | unsigned int i; 200 | 201 | cshake128_simple_absorb4x(s,cstm0,cstm1,cstm2,cstm3,in,inlen); 202 | 203 | /* Squeeze output */ 204 | keccak_squeezeblocks4x(output0, output1, output2, output3, outlen/SHAKE128_RATE, s, SHAKE128_RATE); 205 | output0 += (outlen/SHAKE128_RATE)*SHAKE128_RATE; 206 | output1 += (outlen/SHAKE128_RATE)*SHAKE128_RATE; 207 | output2 += (outlen/SHAKE128_RATE)*SHAKE128_RATE; 208 | output3 += (outlen/SHAKE128_RATE)*SHAKE128_RATE; 209 | 210 | if(outlen%SHAKE128_RATE) 211 | { 212 | keccak_squeezeblocks4x(t0, t1, t2, t3, 1, s, SHAKE128_RATE); 213 | for(i=0;i 5 | 6 | void cshake128_simple_absorb4x(__m256i *s, 7 | uint16_t cstm0, 8 | uint16_t cstm1, 9 | uint16_t cstm2, 10 | uint16_t cstm3, 11 | const unsigned char *in, unsigned long long inlen); 12 | 13 | void cshake128_simple_squeezeblocks4x(unsigned char *output0, 14 | unsigned char *output1, 15 | unsigned char *output2, 16 | unsigned char *output3, unsigned long long outlen, 17 | __m256i *s); 18 | 19 | 20 | /* N is assumed to be empty; S is assumed to have at most 2 characters */ 21 | void cshake128_simple4x(unsigned char *output0, 22 | unsigned char *output1, 23 | unsigned char *output2, 24 | unsigned char *output3, unsigned long long outlen, 25 | uint16_t cstm0, 26 | uint16_t cstm1, 27 | uint16_t cstm2, 28 | uint16_t cstm3, 29 | const unsigned char *in, unsigned long long inlen); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/sha3/keccak4x/KeccakP-1600-times4-SnP.h: -------------------------------------------------------------------------------- 1 | /* 2 | Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, 3 | Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby 4 | denoted as "the implementer". 5 | 6 | For more information, feedback or questions, please refer to our websites: 7 | http://keccak.noekeon.org/ 8 | http://keyak.noekeon.org/ 9 | http://ketje.noekeon.org/ 10 | 11 | To the extent possible under law, the implementer has waived all copyright 12 | and related or neighboring rights to the source code in this file. 13 | http://creativecommons.org/publicdomain/zero/1.0/ 14 | */ 15 | 16 | #ifndef _KeccakP_1600_times4_SnP_h_ 17 | #define _KeccakP_1600_times4_SnP_h_ 18 | 19 | /** For the documentation, see PlSnP-documentation.h. 20 | */ 21 | 22 | #include "SIMD256-config.h" 23 | 24 | #define KeccakP1600times4_implementation "256-bit SIMD implementation (" KeccakP1600times4_implementation_config ")" 25 | #define KeccakP1600times4_statesSizeInBytes 800 26 | #define KeccakP1600times4_statesAlignment 32 27 | #define KeccakF1600times4_FastLoop_supported 28 | #define KeccakP1600times4_12rounds_FastLoop_supported 29 | 30 | #include 31 | 32 | #define KeccakP1600times4_StaticInitialize() 33 | void KeccakP1600times4_InitializeAll(void *states); 34 | #define KeccakP1600times4_AddByte(states, instanceIndex, byte, offset) \ 35 | ((unsigned char*)(states))[(instanceIndex)*8 + ((offset)/8)*4*8 + (offset)%8] ^= (byte) 36 | void KeccakP1600times4_AddBytes(void *states, unsigned int instanceIndex, const unsigned char *data, unsigned int offset, unsigned int length); 37 | void KeccakP1600times4_AddLanesAll(void *states, const unsigned char *data, unsigned int laneCount, unsigned int laneOffset); 38 | void KeccakP1600times4_OverwriteBytes(void *states, unsigned int instanceIndex, const unsigned char *data, unsigned int offset, unsigned int length); 39 | void KeccakP1600times4_OverwriteLanesAll(void *states, const unsigned char *data, unsigned int laneCount, unsigned int laneOffset); 40 | void KeccakP1600times4_OverwriteWithZeroes(void *states, unsigned int instanceIndex, unsigned int byteCount); 41 | void KeccakP1600times4_PermuteAll_12rounds(void *states); 42 | void KeccakP1600times4_PermuteAll_24rounds(void *states); 43 | void KeccakP1600times4_ExtractBytes(const void *states, unsigned int instanceIndex, unsigned char *data, unsigned int offset, unsigned int length); 44 | void KeccakP1600times4_ExtractLanesAll(const void *states, unsigned char *data, unsigned int laneCount, unsigned int laneOffset); 45 | void KeccakP1600times4_ExtractAndAddBytes(const void *states, unsigned int instanceIndex, const unsigned char *input, unsigned char *output, unsigned int offset, unsigned int length); 46 | void KeccakP1600times4_ExtractAndAddLanesAll(const void *states, const unsigned char *input, unsigned char *output, unsigned int laneCount, unsigned int laneOffset); 47 | size_t KeccakF1600times4_FastLoop_Absorb(void *states, unsigned int laneCount, unsigned int laneOffsetParallel, unsigned int laneOffsetSerial, const unsigned char *data, size_t dataByteLen); 48 | size_t KeccakP1600times4_12rounds_FastLoop_Absorb(void *states, unsigned int laneCount, unsigned int laneOffsetParallel, unsigned int laneOffsetSerial, const unsigned char *data, size_t dataByteLen); 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/sha3/keccak4x/KeccakP-1600-unrolling.macros: -------------------------------------------------------------------------------- 1 | /* 2 | Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, 3 | Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby 4 | denoted as "the implementer". 5 | 6 | For more information, feedback or questions, please refer to our websites: 7 | http://keccak.noekeon.org/ 8 | http://keyak.noekeon.org/ 9 | http://ketje.noekeon.org/ 10 | 11 | To the extent possible under law, the implementer has waived all copyright 12 | and related or neighboring rights to the source code in this file. 13 | http://creativecommons.org/publicdomain/zero/1.0/ 14 | */ 15 | 16 | #if (defined(FullUnrolling)) 17 | #define rounds24 \ 18 | prepareTheta \ 19 | thetaRhoPiChiIotaPrepareTheta( 0, A, E) \ 20 | thetaRhoPiChiIotaPrepareTheta( 1, E, A) \ 21 | thetaRhoPiChiIotaPrepareTheta( 2, A, E) \ 22 | thetaRhoPiChiIotaPrepareTheta( 3, E, A) \ 23 | thetaRhoPiChiIotaPrepareTheta( 4, A, E) \ 24 | thetaRhoPiChiIotaPrepareTheta( 5, E, A) \ 25 | thetaRhoPiChiIotaPrepareTheta( 6, A, E) \ 26 | thetaRhoPiChiIotaPrepareTheta( 7, E, A) \ 27 | thetaRhoPiChiIotaPrepareTheta( 8, A, E) \ 28 | thetaRhoPiChiIotaPrepareTheta( 9, E, A) \ 29 | thetaRhoPiChiIotaPrepareTheta(10, A, E) \ 30 | thetaRhoPiChiIotaPrepareTheta(11, E, A) \ 31 | thetaRhoPiChiIotaPrepareTheta(12, A, E) \ 32 | thetaRhoPiChiIotaPrepareTheta(13, E, A) \ 33 | thetaRhoPiChiIotaPrepareTheta(14, A, E) \ 34 | thetaRhoPiChiIotaPrepareTheta(15, E, A) \ 35 | thetaRhoPiChiIotaPrepareTheta(16, A, E) \ 36 | thetaRhoPiChiIotaPrepareTheta(17, E, A) \ 37 | thetaRhoPiChiIotaPrepareTheta(18, A, E) \ 38 | thetaRhoPiChiIotaPrepareTheta(19, E, A) \ 39 | thetaRhoPiChiIotaPrepareTheta(20, A, E) \ 40 | thetaRhoPiChiIotaPrepareTheta(21, E, A) \ 41 | thetaRhoPiChiIotaPrepareTheta(22, A, E) \ 42 | thetaRhoPiChiIota(23, E, A) \ 43 | 44 | #define rounds12 \ 45 | prepareTheta \ 46 | thetaRhoPiChiIotaPrepareTheta(12, A, E) \ 47 | thetaRhoPiChiIotaPrepareTheta(13, E, A) \ 48 | thetaRhoPiChiIotaPrepareTheta(14, A, E) \ 49 | thetaRhoPiChiIotaPrepareTheta(15, E, A) \ 50 | thetaRhoPiChiIotaPrepareTheta(16, A, E) \ 51 | thetaRhoPiChiIotaPrepareTheta(17, E, A) \ 52 | thetaRhoPiChiIotaPrepareTheta(18, A, E) \ 53 | thetaRhoPiChiIotaPrepareTheta(19, E, A) \ 54 | thetaRhoPiChiIotaPrepareTheta(20, A, E) \ 55 | thetaRhoPiChiIotaPrepareTheta(21, E, A) \ 56 | thetaRhoPiChiIotaPrepareTheta(22, A, E) \ 57 | thetaRhoPiChiIota(23, E, A) \ 58 | 59 | #elif (Unrolling == 12) 60 | #define rounds24 \ 61 | prepareTheta \ 62 | for(i=0; i<24; i+=12) { \ 63 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 64 | thetaRhoPiChiIotaPrepareTheta(i+ 1, E, A) \ 65 | thetaRhoPiChiIotaPrepareTheta(i+ 2, A, E) \ 66 | thetaRhoPiChiIotaPrepareTheta(i+ 3, E, A) \ 67 | thetaRhoPiChiIotaPrepareTheta(i+ 4, A, E) \ 68 | thetaRhoPiChiIotaPrepareTheta(i+ 5, E, A) \ 69 | thetaRhoPiChiIotaPrepareTheta(i+ 6, A, E) \ 70 | thetaRhoPiChiIotaPrepareTheta(i+ 7, E, A) \ 71 | thetaRhoPiChiIotaPrepareTheta(i+ 8, A, E) \ 72 | thetaRhoPiChiIotaPrepareTheta(i+ 9, E, A) \ 73 | thetaRhoPiChiIotaPrepareTheta(i+10, A, E) \ 74 | thetaRhoPiChiIotaPrepareTheta(i+11, E, A) \ 75 | } \ 76 | 77 | #define rounds12 \ 78 | prepareTheta \ 79 | thetaRhoPiChiIotaPrepareTheta(12, A, E) \ 80 | thetaRhoPiChiIotaPrepareTheta(13, E, A) \ 81 | thetaRhoPiChiIotaPrepareTheta(14, A, E) \ 82 | thetaRhoPiChiIotaPrepareTheta(15, E, A) \ 83 | thetaRhoPiChiIotaPrepareTheta(16, A, E) \ 84 | thetaRhoPiChiIotaPrepareTheta(17, E, A) \ 85 | thetaRhoPiChiIotaPrepareTheta(18, A, E) \ 86 | thetaRhoPiChiIotaPrepareTheta(19, E, A) \ 87 | thetaRhoPiChiIotaPrepareTheta(20, A, E) \ 88 | thetaRhoPiChiIotaPrepareTheta(21, E, A) \ 89 | thetaRhoPiChiIotaPrepareTheta(22, A, E) \ 90 | thetaRhoPiChiIota(23, E, A) \ 91 | 92 | #elif (Unrolling == 6) 93 | #define rounds24 \ 94 | prepareTheta \ 95 | for(i=0; i<24; i+=6) { \ 96 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 97 | thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ 98 | thetaRhoPiChiIotaPrepareTheta(i+2, A, E) \ 99 | thetaRhoPiChiIotaPrepareTheta(i+3, E, A) \ 100 | thetaRhoPiChiIotaPrepareTheta(i+4, A, E) \ 101 | thetaRhoPiChiIotaPrepareTheta(i+5, E, A) \ 102 | } \ 103 | 104 | #define rounds12 \ 105 | prepareTheta \ 106 | for(i=12; i<24; i+=6) { \ 107 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 108 | thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ 109 | thetaRhoPiChiIotaPrepareTheta(i+2, A, E) \ 110 | thetaRhoPiChiIotaPrepareTheta(i+3, E, A) \ 111 | thetaRhoPiChiIotaPrepareTheta(i+4, A, E) \ 112 | thetaRhoPiChiIotaPrepareTheta(i+5, E, A) \ 113 | } \ 114 | 115 | #elif (Unrolling == 4) 116 | #define rounds24 \ 117 | prepareTheta \ 118 | for(i=0; i<24; i+=4) { \ 119 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 120 | thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ 121 | thetaRhoPiChiIotaPrepareTheta(i+2, A, E) \ 122 | thetaRhoPiChiIotaPrepareTheta(i+3, E, A) \ 123 | } \ 124 | 125 | #define rounds12 \ 126 | prepareTheta \ 127 | for(i=12; i<24; i+=4) { \ 128 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 129 | thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ 130 | thetaRhoPiChiIotaPrepareTheta(i+2, A, E) \ 131 | thetaRhoPiChiIotaPrepareTheta(i+3, E, A) \ 132 | } \ 133 | 134 | #elif (Unrolling == 3) 135 | #define rounds24 \ 136 | prepareTheta \ 137 | for(i=0; i<24; i+=3) { \ 138 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 139 | thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ 140 | thetaRhoPiChiIotaPrepareTheta(i+2, A, E) \ 141 | copyStateVariables(A, E) \ 142 | } \ 143 | 144 | #define rounds12 \ 145 | prepareTheta \ 146 | for(i=12; i<24; i+=3) { \ 147 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 148 | thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ 149 | thetaRhoPiChiIotaPrepareTheta(i+2, A, E) \ 150 | copyStateVariables(A, E) \ 151 | } \ 152 | 153 | #elif (Unrolling == 2) 154 | #define rounds24 \ 155 | prepareTheta \ 156 | for(i=0; i<24; i+=2) { \ 157 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 158 | thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ 159 | } \ 160 | 161 | #define rounds12 \ 162 | prepareTheta \ 163 | for(i=12; i<24; i+=2) { \ 164 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 165 | thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ 166 | } \ 167 | 168 | #elif (Unrolling == 1) 169 | #define rounds24 \ 170 | prepareTheta \ 171 | for(i=0; i<24; i++) { \ 172 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 173 | copyStateVariables(A, E) \ 174 | } \ 175 | 176 | #define rounds12 \ 177 | prepareTheta \ 178 | for(i=12; i<24; i++) { \ 179 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 180 | copyStateVariables(A, E) \ 181 | } \ 182 | 183 | #else 184 | #error "Unrolling is not correctly specified!" 185 | #endif 186 | 187 | #define roundsN(__nrounds) \ 188 | prepareTheta \ 189 | i = 24 - (__nrounds); \ 190 | if ((i&1) != 0) { \ 191 | thetaRhoPiChiIotaPrepareTheta(i, A, E) \ 192 | copyStateVariables(A, E) \ 193 | ++i; \ 194 | } \ 195 | for( /* empty */; i<24; i+=2) { \ 196 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 197 | thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ 198 | } 199 | -------------------------------------------------------------------------------- /src/sha3/keccak4x/KeccakP-1600-unrolling.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, 3 | Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby 4 | denoted as "the implementer". 5 | 6 | For more information, feedback or questions, please refer to our websites: 7 | http://keccak.noekeon.org/ 8 | http://keyak.noekeon.org/ 9 | http://ketje.noekeon.org/ 10 | 11 | To the extent possible under law, the implementer has waived all copyright 12 | and related or neighboring rights to the source code in this file. 13 | http://creativecommons.org/publicdomain/zero/1.0/ 14 | */ 15 | 16 | #if (defined(FullUnrolling)) 17 | #define rounds24 \ 18 | prepareTheta \ 19 | thetaRhoPiChiIotaPrepareTheta( 0, A, E) \ 20 | thetaRhoPiChiIotaPrepareTheta( 1, E, A) \ 21 | thetaRhoPiChiIotaPrepareTheta( 2, A, E) \ 22 | thetaRhoPiChiIotaPrepareTheta( 3, E, A) \ 23 | thetaRhoPiChiIotaPrepareTheta( 4, A, E) \ 24 | thetaRhoPiChiIotaPrepareTheta( 5, E, A) \ 25 | thetaRhoPiChiIotaPrepareTheta( 6, A, E) \ 26 | thetaRhoPiChiIotaPrepareTheta( 7, E, A) \ 27 | thetaRhoPiChiIotaPrepareTheta( 8, A, E) \ 28 | thetaRhoPiChiIotaPrepareTheta( 9, E, A) \ 29 | thetaRhoPiChiIotaPrepareTheta(10, A, E) \ 30 | thetaRhoPiChiIotaPrepareTheta(11, E, A) \ 31 | thetaRhoPiChiIotaPrepareTheta(12, A, E) \ 32 | thetaRhoPiChiIotaPrepareTheta(13, E, A) \ 33 | thetaRhoPiChiIotaPrepareTheta(14, A, E) \ 34 | thetaRhoPiChiIotaPrepareTheta(15, E, A) \ 35 | thetaRhoPiChiIotaPrepareTheta(16, A, E) \ 36 | thetaRhoPiChiIotaPrepareTheta(17, E, A) \ 37 | thetaRhoPiChiIotaPrepareTheta(18, A, E) \ 38 | thetaRhoPiChiIotaPrepareTheta(19, E, A) \ 39 | thetaRhoPiChiIotaPrepareTheta(20, A, E) \ 40 | thetaRhoPiChiIotaPrepareTheta(21, E, A) \ 41 | thetaRhoPiChiIotaPrepareTheta(22, A, E) \ 42 | thetaRhoPiChiIota(23, E, A) \ 43 | 44 | #define rounds12 \ 45 | prepareTheta \ 46 | thetaRhoPiChiIotaPrepareTheta(12, A, E) \ 47 | thetaRhoPiChiIotaPrepareTheta(13, E, A) \ 48 | thetaRhoPiChiIotaPrepareTheta(14, A, E) \ 49 | thetaRhoPiChiIotaPrepareTheta(15, E, A) \ 50 | thetaRhoPiChiIotaPrepareTheta(16, A, E) \ 51 | thetaRhoPiChiIotaPrepareTheta(17, E, A) \ 52 | thetaRhoPiChiIotaPrepareTheta(18, A, E) \ 53 | thetaRhoPiChiIotaPrepareTheta(19, E, A) \ 54 | thetaRhoPiChiIotaPrepareTheta(20, A, E) \ 55 | thetaRhoPiChiIotaPrepareTheta(21, E, A) \ 56 | thetaRhoPiChiIotaPrepareTheta(22, A, E) \ 57 | thetaRhoPiChiIota(23, E, A) \ 58 | 59 | #elif (Unrolling == 12) 60 | #define rounds24 \ 61 | prepareTheta \ 62 | for(i=0; i<24; i+=12) { \ 63 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 64 | thetaRhoPiChiIotaPrepareTheta(i+ 1, E, A) \ 65 | thetaRhoPiChiIotaPrepareTheta(i+ 2, A, E) \ 66 | thetaRhoPiChiIotaPrepareTheta(i+ 3, E, A) \ 67 | thetaRhoPiChiIotaPrepareTheta(i+ 4, A, E) \ 68 | thetaRhoPiChiIotaPrepareTheta(i+ 5, E, A) \ 69 | thetaRhoPiChiIotaPrepareTheta(i+ 6, A, E) \ 70 | thetaRhoPiChiIotaPrepareTheta(i+ 7, E, A) \ 71 | thetaRhoPiChiIotaPrepareTheta(i+ 8, A, E) \ 72 | thetaRhoPiChiIotaPrepareTheta(i+ 9, E, A) \ 73 | thetaRhoPiChiIotaPrepareTheta(i+10, A, E) \ 74 | thetaRhoPiChiIotaPrepareTheta(i+11, E, A) \ 75 | } \ 76 | 77 | #define rounds12 \ 78 | prepareTheta \ 79 | thetaRhoPiChiIotaPrepareTheta(12, A, E) \ 80 | thetaRhoPiChiIotaPrepareTheta(13, E, A) \ 81 | thetaRhoPiChiIotaPrepareTheta(14, A, E) \ 82 | thetaRhoPiChiIotaPrepareTheta(15, E, A) \ 83 | thetaRhoPiChiIotaPrepareTheta(16, A, E) \ 84 | thetaRhoPiChiIotaPrepareTheta(17, E, A) \ 85 | thetaRhoPiChiIotaPrepareTheta(18, A, E) \ 86 | thetaRhoPiChiIotaPrepareTheta(19, E, A) \ 87 | thetaRhoPiChiIotaPrepareTheta(20, A, E) \ 88 | thetaRhoPiChiIotaPrepareTheta(21, E, A) \ 89 | thetaRhoPiChiIotaPrepareTheta(22, A, E) \ 90 | thetaRhoPiChiIota(23, E, A) \ 91 | 92 | #elif (Unrolling == 6) 93 | #define rounds24 \ 94 | prepareTheta \ 95 | for(i=0; i<24; i+=6) { \ 96 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 97 | thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ 98 | thetaRhoPiChiIotaPrepareTheta(i+2, A, E) \ 99 | thetaRhoPiChiIotaPrepareTheta(i+3, E, A) \ 100 | thetaRhoPiChiIotaPrepareTheta(i+4, A, E) \ 101 | thetaRhoPiChiIotaPrepareTheta(i+5, E, A) \ 102 | } \ 103 | 104 | #define rounds12 \ 105 | prepareTheta \ 106 | for(i=12; i<24; i+=6) { \ 107 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 108 | thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ 109 | thetaRhoPiChiIotaPrepareTheta(i+2, A, E) \ 110 | thetaRhoPiChiIotaPrepareTheta(i+3, E, A) \ 111 | thetaRhoPiChiIotaPrepareTheta(i+4, A, E) \ 112 | thetaRhoPiChiIotaPrepareTheta(i+5, E, A) \ 113 | } \ 114 | 115 | #elif (Unrolling == 4) 116 | #define rounds24 \ 117 | prepareTheta \ 118 | for(i=0; i<24; i+=4) { \ 119 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 120 | thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ 121 | thetaRhoPiChiIotaPrepareTheta(i+2, A, E) \ 122 | thetaRhoPiChiIotaPrepareTheta(i+3, E, A) \ 123 | } \ 124 | 125 | #define rounds12 \ 126 | prepareTheta \ 127 | for(i=12; i<24; i+=4) { \ 128 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 129 | thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ 130 | thetaRhoPiChiIotaPrepareTheta(i+2, A, E) \ 131 | thetaRhoPiChiIotaPrepareTheta(i+3, E, A) \ 132 | } \ 133 | 134 | #elif (Unrolling == 3) 135 | #define rounds24 \ 136 | prepareTheta \ 137 | for(i=0; i<24; i+=3) { \ 138 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 139 | thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ 140 | thetaRhoPiChiIotaPrepareTheta(i+2, A, E) \ 141 | copyStateVariables(A, E) \ 142 | } \ 143 | 144 | #define rounds12 \ 145 | prepareTheta \ 146 | for(i=12; i<24; i+=3) { \ 147 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 148 | thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ 149 | thetaRhoPiChiIotaPrepareTheta(i+2, A, E) \ 150 | copyStateVariables(A, E) \ 151 | } \ 152 | 153 | #elif (Unrolling == 2) 154 | #define rounds24 \ 155 | prepareTheta \ 156 | for(i=0; i<24; i+=2) { \ 157 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 158 | thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ 159 | } \ 160 | 161 | #define rounds12 \ 162 | prepareTheta \ 163 | for(i=12; i<24; i+=2) { \ 164 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 165 | thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ 166 | } \ 167 | 168 | #elif (Unrolling == 1) 169 | #define rounds24 \ 170 | prepareTheta \ 171 | for(i=0; i<24; i++) { \ 172 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 173 | copyStateVariables(A, E) \ 174 | } \ 175 | 176 | #define rounds12 \ 177 | prepareTheta \ 178 | for(i=12; i<24; i++) { \ 179 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 180 | copyStateVariables(A, E) \ 181 | } \ 182 | 183 | #else 184 | #error "Unrolling is not correctly specified!" 185 | #endif 186 | 187 | #define roundsN(__nrounds) \ 188 | prepareTheta \ 189 | i = 24 - (__nrounds); \ 190 | if ((i&1) != 0) { \ 191 | thetaRhoPiChiIotaPrepareTheta(i, A, E) \ 192 | copyStateVariables(A, E) \ 193 | ++i; \ 194 | } \ 195 | for( /* empty */; i<24; i+=2) { \ 196 | thetaRhoPiChiIotaPrepareTheta(i , A, E) \ 197 | thetaRhoPiChiIotaPrepareTheta(i+1, E, A) \ 198 | } 199 | -------------------------------------------------------------------------------- /src/sha3/keccak4x/SIMD256-config.h: -------------------------------------------------------------------------------- 1 | #define KeccakP1600times4_implementation_config "AVX2, all rounds unrolled" 2 | #define KeccakP1600times4_fullUnrolling 3 | #define KeccakP1600times4_useAVX2 4 | -------------------------------------------------------------------------------- /src/sha3/keccak4x/align.h: -------------------------------------------------------------------------------- 1 | /* 2 | Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni, 3 | Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby 4 | denoted as "the implementer". 5 | 6 | For more information, feedback or questions, please refer to our websites: 7 | http://keccak.noekeon.org/ 8 | http://keyak.noekeon.org/ 9 | http://ketje.noekeon.org/ 10 | 11 | To the extent possible under law, the implementer has waived all copyright 12 | and related or neighboring rights to the source code in this file. 13 | http://creativecommons.org/publicdomain/zero/1.0/ 14 | */ 15 | 16 | #ifndef _align_h_ 17 | #define _align_h_ 18 | 19 | /* on Mac OS-X and possibly others, ALIGN(x) is defined in param.h, and -Werror chokes on the redef. */ 20 | #ifdef ALIGN 21 | #undef ALIGN 22 | #endif 23 | 24 | #if defined(__GNUC__) 25 | #define ALIGN(x) __attribute__ ((aligned(x))) 26 | #elif defined(_MSC_VER) 27 | #define ALIGN(x) __declspec(align(x)) 28 | #elif defined(__ARMCC_VERSION) 29 | #define ALIGN(x) __align(x) 30 | #else 31 | #define ALIGN(x) 32 | #endif 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/sha3/keccak4x/brg_endian.h: -------------------------------------------------------------------------------- 1 | /* 2 | --------------------------------------------------------------------------- 3 | Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. 4 | 5 | LICENSE TERMS 6 | 7 | The redistribution and use of this software (with or without changes) 8 | is allowed without the payment of fees or royalties provided that: 9 | 10 | 1. source code distributions include the above copyright notice, this 11 | list of conditions and the following disclaimer; 12 | 13 | 2. binary distributions include the above copyright notice, this list 14 | of conditions and the following disclaimer in their documentation; 15 | 16 | 3. the name of the copyright holder is not used to endorse products 17 | built using this software without specific written permission. 18 | 19 | DISCLAIMER 20 | 21 | This software is provided 'as is' with no explicit or implied warranties 22 | in respect of its properties, including, but not limited to, correctness 23 | and/or fitness for purpose. 24 | --------------------------------------------------------------------------- 25 | Issue Date: 20/12/2007 26 | Changes for ARM 9/9/2010 27 | */ 28 | 29 | #ifndef _BRG_ENDIAN_H 30 | #define _BRG_ENDIAN_H 31 | 32 | #define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ 33 | #define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ 34 | 35 | #if 0 36 | /* Include files where endian defines and byteswap functions may reside */ 37 | #if defined( __sun ) 38 | # include 39 | #elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ ) 40 | # include 41 | #elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \ 42 | defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ ) 43 | # include 44 | #elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ ) 45 | # if !defined( __MINGW32__ ) && !defined( _AIX ) 46 | # include 47 | # if !defined( __BEOS__ ) 48 | # include 49 | # endif 50 | # endif 51 | #endif 52 | #endif 53 | 54 | /* Now attempt to set the define for platform byte order using any */ 55 | /* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */ 56 | /* seem to encompass most endian symbol definitions */ 57 | 58 | #if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN ) 59 | # if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN 60 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 61 | # elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN 62 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 63 | # endif 64 | #elif defined( BIG_ENDIAN ) 65 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 66 | #elif defined( LITTLE_ENDIAN ) 67 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 68 | #endif 69 | 70 | #if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN ) 71 | # if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN 72 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 73 | # elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN 74 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 75 | # endif 76 | #elif defined( _BIG_ENDIAN ) 77 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 78 | #elif defined( _LITTLE_ENDIAN ) 79 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 80 | #endif 81 | 82 | #if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN ) 83 | # if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN 84 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 85 | # elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN 86 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 87 | # endif 88 | #elif defined( __BIG_ENDIAN ) 89 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 90 | #elif defined( __LITTLE_ENDIAN ) 91 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 92 | #endif 93 | 94 | #if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ ) 95 | # if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__ 96 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 97 | # elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__ 98 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 99 | # endif 100 | #elif defined( __BIG_ENDIAN__ ) 101 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 102 | #elif defined( __LITTLE_ENDIAN__ ) 103 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 104 | #endif 105 | 106 | /* if the platform byte order could not be determined, then try to */ 107 | /* set this define using common machine defines */ 108 | #if !defined(PLATFORM_BYTE_ORDER) 109 | 110 | #if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \ 111 | defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \ 112 | defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \ 113 | defined( vax ) || defined( vms ) || defined( VMS ) || \ 114 | defined( __VMS ) || defined( _M_X64 ) 115 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 116 | 117 | #elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \ 118 | defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \ 119 | defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \ 120 | defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \ 121 | defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \ 122 | defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \ 123 | defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX ) 124 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 125 | 126 | #elif defined(__arm__) 127 | # ifdef __BIG_ENDIAN 128 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 129 | # else 130 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 131 | # endif 132 | #elif 1 /* **** EDIT HERE IF NECESSARY **** */ 133 | # define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN 134 | #elif 0 /* **** EDIT HERE IF NECESSARY **** */ 135 | # define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN 136 | #else 137 | # error Please edit lines 132 or 134 in brg_endian.h to set the platform byte order 138 | #endif 139 | 140 | #endif 141 | 142 | #endif 143 | -------------------------------------------------------------------------------- /tests/ds_benchmark.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************************** 2 | * ds_benchmark.h: Macros for simple benchmarking of C code. 3 | * 4 | * See instructions for usage below. 5 | * Software originally developed by Douglas Stebila. 6 | * Most recent version at https://gist.github.com/dstebila/6980008ec98209ef6075 7 | * 8 | * This is free and unencumbered software released into the public domain. 9 | * 10 | * Anyone is free to copy, modify, publish, use, compile, sell, or 11 | * distribute this software, either in source code form or as a compiled 12 | * binary, for any purpose, commercial or non-commercial, and by any 13 | * means. 14 | * 15 | * In jurisdictions that recognize copyright laws, the author or authors 16 | * of this software dedicate any and all copyright interest in the 17 | * software to the public domain. We make this dedication for the benefit 18 | * of the public at large and to the detriment of our heirs and 19 | * successors. We intend this dedication to be an overt act of 20 | * relinquishment in perpetuity of all present and future rights to this 21 | * software under copyright law. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 26 | * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 27 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 28 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 29 | * OTHER DEALINGS IN THE SOFTWARE. 30 | * 31 | * For more information, please refer to 32 | ********************************************************************************************/ 33 | 34 | /** \file ds_benchmark.h 35 | * Macros for simple benchmarking of C code. 36 | */ 37 | 38 | #ifndef _DS_BENCHMARK_H 39 | #define _DS_BENCHMARK_H 40 | 41 | #include "../src/frodo.h" 42 | #include 43 | #include 44 | #include 45 | #if (OS_TARGET == OS_LINUX) 46 | #include 47 | #endif 48 | #include 49 | #include 50 | 51 | 52 | #if (OS_TARGET == OS_WIN) 53 | #include 54 | 55 | int gettimeofday(struct timeval *tp, struct timezone *tzp) { 56 | // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's 57 | static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL); 58 | 59 | SYSTEMTIME system_time; 60 | FILETIME file_time; 61 | uint64_t time; 62 | 63 | GetSystemTime(&system_time); 64 | SystemTimeToFileTime(&system_time, &file_time); 65 | time = ((uint64_t)file_time.dwLowDateTime); 66 | time += ((uint64_t)file_time.dwHighDateTime) << 32; 67 | 68 | tp->tv_sec = (long)((time - EPOCH) / 10000000L); 69 | tp->tv_usec = (long)(system_time.wMilliseconds * 1000); 70 | return 0; 71 | } 72 | #endif 73 | 74 | 75 | static uint64_t rdtsc(void) { 76 | #if (OS_TARGET == OS_WIN) 77 | return __rdtsc(); 78 | #elif (OS_TARGET == OS_LINUX) && (TARGET == TARGET_AMD64 || TARGET == TARGET_x86) 79 | uint64_t x; 80 | __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); 81 | return x; 82 | #elif (OS_TARGET == OS_LINUX && TARGET == TARGET_ARM) 83 | struct timespec time; 84 | clock_gettime(CLOCK_REALTIME, &time); 85 | return (int64_t)(time.tv_sec*1e9 + time.tv_nsec); 86 | #else 87 | return 0; 88 | #endif 89 | } 90 | 91 | 92 | #define DEFINE_TIMER_VARIABLES \ 93 | volatile uint64_t _bench_cycles_start, _bench_cycles_end; \ 94 | uint64_t _bench_cycles_cumulative = 0; \ 95 | int64_t _bench_cycles_diff; \ 96 | struct timeval _bench_timeval_start, _bench_timeval_end; \ 97 | uint64_t _bench_iterations, _bench_time_cumulative; \ 98 | double _bench_cycles_x, _bench_cycles_mean, _bench_cycles_delta, _bench_cycles_M2, _bench_cycles_stdev; \ 99 | double _bench_time_x, _bench_time_mean, _bench_time_delta, _bench_time_M2, _bench_time_stdev; 100 | 101 | #define INITIALIZE_TIMER \ 102 | _bench_iterations = 0; \ 103 | _bench_cycles_mean = 0.0; \ 104 | _bench_cycles_M2 = 0.0; \ 105 | _bench_time_cumulative = 0; \ 106 | _bench_time_mean = 0.0; \ 107 | _bench_time_M2 = 0.0; 108 | 109 | #define START_TIMER \ 110 | gettimeofday(&_bench_timeval_start, NULL); \ 111 | _bench_cycles_start = rdtsc(); 112 | 113 | 114 | // Mean and population standard deviation are calculated in an online way using the algorithm in 115 | // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online_algorithm 116 | 117 | #define STOP_TIMER \ 118 | _bench_cycles_end = rdtsc(); \ 119 | gettimeofday(&_bench_timeval_end, NULL); \ 120 | _bench_iterations += 1; \ 121 | if (_bench_cycles_end < _bench_cycles_start) { _bench_cycles_end += 1UL << 32; } \ 122 | _bench_cycles_diff = _bench_cycles_end; \ 123 | _bench_cycles_diff -= _bench_cycles_start; \ 124 | _bench_cycles_cumulative += _bench_cycles_diff; \ 125 | _bench_cycles_x = (double) (_bench_cycles_diff); \ 126 | _bench_cycles_delta = _bench_cycles_x - _bench_cycles_mean; \ 127 | _bench_cycles_mean += _bench_cycles_delta / (double) _bench_iterations; \ 128 | _bench_cycles_M2 += _bench_cycles_delta * (_bench_cycles_x - _bench_cycles_mean); \ 129 | _bench_time_x = (double) ((_bench_timeval_end.tv_sec * 1000000 + _bench_timeval_end.tv_usec) - (_bench_timeval_start.tv_sec * 1000000 + _bench_timeval_start.tv_usec)); \ 130 | _bench_time_delta = _bench_time_x - _bench_time_mean; \ 131 | _bench_time_mean += _bench_time_delta / (double) _bench_iterations; \ 132 | _bench_time_M2 += _bench_time_delta * (_bench_time_x - _bench_time_mean); \ 133 | _bench_time_cumulative += _bench_time_x; 134 | 135 | #define FINALIZE_TIMER \ 136 | if (_bench_iterations == 2) { _bench_cycles_stdev = 0.0; } \ 137 | else { _bench_cycles_stdev = sqrt(_bench_cycles_M2 / (double) _bench_iterations); } \ 138 | if (_bench_iterations == 2) { _bench_time_stdev = 0.0; } \ 139 | else { _bench_time_stdev = sqrt(_bench_time_M2 / (double) _bench_iterations); } 140 | 141 | #define PRINT_CURRENT_TIME \ 142 | { \ 143 | char _bench_time_buff[20]; \ 144 | time_t _bench_time_now = time(0); \ 145 | strftime(_bench_time_buff, 20, "%Y-%m-%d %H:%M:%S", localtime (&_bench_time_now)); \ 146 | printf("%s", _bench_time_buff); \ 147 | } 148 | 149 | #define PRINT_TIMER_HEADER \ 150 | printf("Started at "); \ 151 | PRINT_CURRENT_TIME \ 152 | printf("\n"); \ 153 | printf("%-30s %15s %15s %15s %15s %15s %15s\n", "Operation", "Iterations", "Total time (s)", "Time(us): mean", "pop. stdev", "Cycles: mean", "pop. stdev"); 154 | 155 | #define PRINT_TIMER_FOOTER \ 156 | printf("Ended at "); \ 157 | PRINT_CURRENT_TIME \ 158 | printf("\n"); 159 | 160 | #define PRINT_TIMER_AVG(op_name) \ 161 | printf("%-30s %15" PRIu64 " %15.3f %15.3f %15.3f %15.0f %15.0f\n", (op_name), _bench_iterations, ((double) _bench_time_cumulative) / 1000000.0, _bench_time_mean, _bench_time_stdev, ((double) _bench_cycles_cumulative) / (double) _bench_iterations, _bench_cycles_stdev); 162 | 163 | #define TIME_OPERATION_ITERATIONS(op, op_name, it) \ 164 | { \ 165 | DEFINE_TIMER_VARIABLES \ 166 | INITIALIZE_TIMER \ 167 | for (int i = 0; i < (it); i++) { \ 168 | START_TIMER \ 169 | { op ; } \ 170 | STOP_TIMER \ 171 | } \ 172 | FINALIZE_TIMER \ 173 | PRINT_TIMER_AVG(op_name) \ 174 | } 175 | 176 | #define TIME_OPERATION_SECONDS(op, op_name, secs) \ 177 | { \ 178 | DEFINE_TIMER_VARIABLES \ 179 | INITIALIZE_TIMER \ 180 | uint64_t _bench_time_goal_usecs = 1000000 * secs; \ 181 | while (_bench_time_cumulative < _bench_time_goal_usecs) { \ 182 | START_TIMER \ 183 | { op ; } \ 184 | STOP_TIMER \ 185 | } \ 186 | FINALIZE_TIMER \ 187 | PRINT_TIMER_AVG(op_name) \ 188 | } 189 | #endif 190 | -------------------------------------------------------------------------------- /tests/test_kex.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "../src/random/rand.h" 6 | #include "../src/kex.h" 7 | #include "ds_benchmark.h" 8 | 9 | 10 | struct kex_testcase { 11 | enum OQS_KEX_alg_name alg_name; 12 | unsigned char *seed; 13 | size_t seed_len; 14 | char *named_parameters; 15 | char *id; 16 | int run; 17 | }; 18 | 19 | 20 | /* Add new testcases here */ 21 | struct kex_testcase kex_testcases[] = { 22 | { OQS_KEX_alg_lwe_frodo, (unsigned char*)"01234567890123456", 16, "recommended", "lwe_frodo_recommended", 0 }, 23 | }; 24 | 25 | 26 | #define KEX_TEST_ITERATIONS 100 27 | #define KEX_BENCH_SECONDS 1 28 | 29 | #define PRINT_HEX_STRING(label, str, len) { \ 30 | printf("%-20s (%4zu bytes): ", (label), (size_t) (len)); \ 31 | for (size_t i = 0; i < (len); i++) { \ 32 | printf("%02X", ((unsigned char *) (str)) [i]); \ 33 | } \ 34 | printf("\n"); \ 35 | } 36 | 37 | 38 | static int kex_test_correctness(OQS_RAND *rand, enum OQS_KEX_alg_name alg_name, const uint8_t *seed, const size_t seed_len, const char *named_parameters, const int print, unsigned long occurrences[256]) 39 | { 40 | OQS_KEX *kex = NULL; 41 | int rc; 42 | 43 | void *alice_priv = NULL; 44 | uint8_t *alice_msg = NULL; 45 | size_t alice_msg_len; 46 | uint8_t *alice_key = NULL; 47 | size_t alice_key_len; 48 | 49 | uint8_t *bob_msg = NULL; 50 | size_t bob_msg_len; 51 | uint8_t *bob_key = NULL; 52 | size_t bob_key_len; 53 | 54 | 55 | //uint8_t in1[32], in2[32]; 56 | //uint32_t out1[64]; 57 | 58 | 59 | /* setup KEX */ 60 | kex = OQS_KEX_new(rand, alg_name, seed, seed_len, named_parameters); 61 | if (kex == NULL) { 62 | fprintf(stderr, "new_method failed\n"); 63 | goto err; 64 | } 65 | 66 | if (print) { 67 | printf("================================================================================\n"); 68 | printf("Sample computation for key exchange method %s\n", kex->method_name); 69 | printf("================================================================================\n"); 70 | } 71 | 72 | /* Alice's initial message */ 73 | rc = OQS_KEX_alice_0(kex, &alice_priv, &alice_msg, &alice_msg_len); 74 | if (rc != 1) { 75 | fprintf(stderr, "OQS_KEX_alice_0 failed\n"); 76 | goto err; 77 | } 78 | 79 | if (print) { 80 | PRINT_HEX_STRING("Alice message", alice_msg, alice_msg_len) 81 | } 82 | 83 | /* Bob's response */ 84 | rc = OQS_KEX_bob(kex, alice_msg, alice_msg_len, &bob_msg, &bob_msg_len, &bob_key, &bob_key_len); 85 | if (rc != 1) { 86 | fprintf(stderr, "OQS_KEX_bob failed\n"); 87 | goto err; 88 | } 89 | 90 | if (print) { 91 | PRINT_HEX_STRING("Bob message", bob_msg, bob_msg_len) 92 | PRINT_HEX_STRING("Bob session key", bob_key, bob_key_len) 93 | } 94 | 95 | /* Alice processes Bob's response */ 96 | rc = OQS_KEX_alice_1(kex, alice_priv, bob_msg, bob_msg_len, &alice_key, &alice_key_len); 97 | if (rc != 1) { 98 | fprintf(stderr, "OQS_KEX_alice_1 failed\n"); 99 | goto err; 100 | } 101 | 102 | if (print) { 103 | PRINT_HEX_STRING("Alice session key", alice_key, alice_key_len) 104 | } 105 | 106 | /* compare session key lengths and values */ 107 | if (alice_key_len != bob_key_len) { 108 | fprintf(stderr, "ERROR: Alice's session key and Bob's session key are different lengths (%zu vs %zu)\n", alice_key_len, bob_key_len); 109 | goto err; 110 | } 111 | rc = memcmp(alice_key, bob_key, alice_key_len); 112 | if (rc != 0) { 113 | fprintf(stderr, "ERROR: Alice's session key and Bob's session key are not equal\n"); 114 | PRINT_HEX_STRING("Alice session key", alice_key, alice_key_len) 115 | PRINT_HEX_STRING("Bob session key", bob_key, bob_key_len) 116 | goto err; 117 | } 118 | if (print) { 119 | printf("Alice and Bob's session keys match.\n"); 120 | printf("\n\n"); 121 | } 122 | 123 | /* record generated bytes for statistical analysis */ 124 | for (size_t i = 0; i < alice_key_len; i++) { 125 | OQS_RAND_test_record_occurrence(alice_key[i], occurrences); 126 | } 127 | 128 | rc = 1; 129 | goto cleanup; 130 | 131 | err: 132 | rc = 0; 133 | 134 | cleanup: 135 | free(alice_msg); 136 | free(alice_key); 137 | free(bob_msg); 138 | free(bob_key); 139 | OQS_KEX_alice_priv_free(kex, alice_priv); 140 | OQS_KEX_free(kex); 141 | 142 | return rc; 143 | } 144 | 145 | 146 | static int kex_test_correctness_wrapper(OQS_RAND *rand, enum OQS_KEX_alg_name alg_name, const uint8_t *seed, const size_t seed_len, const char *named_parameters, int iterations) 147 | { 148 | OQS_KEX *kex = NULL; 149 | unsigned long occurrences[256] = {0}; 150 | int ret; 151 | 152 | /* setup KEX */ 153 | kex = OQS_KEX_new(rand, alg_name, seed, seed_len, named_parameters); 154 | if (kex == NULL) { 155 | goto err; 156 | } 157 | 158 | printf("==========================================================================================================================================\n"); 159 | printf("Testing correctness and randomness of key exchange method %s (params=%s) for %d iterations\n", 160 | kex->method_name, named_parameters, iterations); 161 | printf("==========================================================================================================================================\n"); 162 | for (int i = 0; i < iterations; i++) { 163 | ret = kex_test_correctness(rand, alg_name, seed, seed_len, named_parameters, 0, occurrences); 164 | if (ret != 1) { 165 | goto err; 166 | } 167 | } 168 | printf("Tests PASSED. All session keys matched.\n"); 169 | printf("Statistical distance from uniform: %12.10f\n", OQS_RAND_test_statistical_distance_from_uniform(occurrences)); 170 | printf("\n\n"); 171 | 172 | ret = 1; 173 | goto cleanup; 174 | 175 | err: 176 | ret = 0; 177 | 178 | cleanup: 179 | OQS_KEX_free(kex); 180 | 181 | return ret; 182 | } 183 | 184 | 185 | static void cleanup_alice_0(OQS_KEX *kex, void *alice_priv, uint8_t *alice_msg) 186 | { 187 | free(alice_msg); 188 | OQS_KEX_alice_priv_free(kex, alice_priv); 189 | } 190 | 191 | 192 | static void cleanup_bob(uint8_t *bob_msg, uint8_t *bob_key) 193 | { 194 | free(bob_msg); 195 | free(bob_key); 196 | } 197 | 198 | 199 | static int kex_bench_wrapper(OQS_RAND *rand, enum OQS_KEX_alg_name alg_name, const uint8_t *seed, const size_t seed_len, const char *named_parameters, const int seconds) 200 | { 201 | OQS_KEX *kex = NULL; 202 | int rc; 203 | 204 | void *alice_priv = NULL; 205 | uint8_t *alice_msg = NULL; 206 | size_t alice_msg_len; 207 | uint8_t *alice_key = NULL; 208 | size_t alice_key_len; 209 | 210 | uint8_t *bob_msg = NULL; 211 | size_t bob_msg_len; 212 | uint8_t *bob_key = NULL; 213 | size_t bob_key_len; 214 | 215 | /* setup KEX */ 216 | kex = OQS_KEX_new(rand, alg_name, seed, seed_len, named_parameters); 217 | if (kex == NULL) { 218 | fprintf(stderr, "new_method failed\n"); 219 | goto err; 220 | } 221 | printf("%s\n", kex->method_name); 222 | 223 | TIME_OPERATION_SECONDS({ OQS_KEX_alice_0(kex, &alice_priv, &alice_msg, &alice_msg_len); cleanup_alice_0(kex, alice_priv, alice_msg); }, "alice 0", seconds); 224 | 225 | OQS_KEX_alice_0(kex, &alice_priv, &alice_msg, &alice_msg_len); 226 | TIME_OPERATION_SECONDS({ OQS_KEX_bob(kex, alice_msg, alice_msg_len, &bob_msg, &bob_msg_len, &bob_key, &bob_key_len); cleanup_bob(bob_msg, bob_key); }, "bob", seconds); 227 | 228 | OQS_KEX_bob(kex, alice_msg, alice_msg_len, &bob_msg, &bob_msg_len, &bob_key, &bob_key_len); 229 | TIME_OPERATION_SECONDS({ OQS_KEX_alice_1(kex, alice_priv, bob_msg, bob_msg_len, &alice_key, &alice_key_len); free(alice_key); }, "alice 1", seconds); 230 | alice_key = NULL; 231 | 232 | rc = 1; 233 | goto cleanup; 234 | 235 | err: 236 | rc = 0; 237 | 238 | cleanup: 239 | free(alice_msg); 240 | free(alice_key); 241 | free(bob_msg); 242 | free(bob_key); 243 | OQS_KEX_alice_priv_free(kex, alice_priv); 244 | OQS_KEX_free(kex); 245 | 246 | return rc; 247 | } 248 | 249 | 250 | int main(int argc, char **argv) 251 | { 252 | int success = 1; 253 | bool run_all = true; 254 | size_t kex_testcases_len = sizeof(kex_testcases) / sizeof(struct kex_testcase); 255 | 256 | if (argc > 1) { 257 | if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "-help") == 0) || (strcmp(argv[1], "--help") == 0)) { 258 | printf("Usage: ./test_kex [algorithms]\n\n"); 259 | printf("algorithms:\n"); 260 | for (size_t i = 0; i < kex_testcases_len; i++) { 261 | printf(" %s\n", kex_testcases[i].id); 262 | } 263 | return EXIT_SUCCESS; 264 | } 265 | run_all = false; 266 | for (int i = 1; i < argc; i++) { 267 | for (size_t j = 0; j < kex_testcases_len; j++) { 268 | if (strcmp(argv[i], kex_testcases[j].id) == 0) { 269 | kex_testcases[j].run = 1; 270 | } 271 | } 272 | } 273 | } 274 | 275 | /* setup RAND */ 276 | OQS_RAND *rand = OQS_RAND_new(OQS_RAND_alg_urandom_aesctr); 277 | if (rand == NULL) { 278 | goto err; 279 | } 280 | 281 | for (size_t i = 0; i < kex_testcases_len; i++) { 282 | if (run_all || kex_testcases[i].run == 1) { 283 | int num_iter = KEX_TEST_ITERATIONS; 284 | success = kex_test_correctness_wrapper(rand, kex_testcases[i].alg_name, kex_testcases[i].seed, kex_testcases[i].seed_len, kex_testcases[i].named_parameters, num_iter); 285 | } 286 | if (success != 1) { 287 | goto err; 288 | } 289 | } 290 | 291 | PRINT_TIMER_HEADER 292 | for (size_t i = 0; i < kex_testcases_len; i++) { 293 | if (run_all || kex_testcases[i].run == 1) { 294 | kex_bench_wrapper(rand, kex_testcases[i].alg_name, kex_testcases[i].seed, kex_testcases[i].seed_len, kex_testcases[i].named_parameters, KEX_BENCH_SECONDS); 295 | } 296 | } 297 | PRINT_TIMER_FOOTER 298 | 299 | success = 1; 300 | goto cleanup; 301 | 302 | err: 303 | success = 0; 304 | fprintf(stderr, "ERROR!\n"); 305 | 306 | cleanup: 307 | OQS_RAND_free(rand); 308 | 309 | return (success == 1) ? EXIT_SUCCESS : EXIT_FAILURE; 310 | } 311 | --------------------------------------------------------------------------------