├── .gitignore ├── AMD64 ├── ZMULT_HW.h ├── ZMULT_SK.h ├── ZREDC_6x4_SH_HW.S ├── ZREDC_6x4_SH_SK.S ├── Z_ADD_SUB.h ├── fp_x64.c └── fp_x64_asm.S ├── ARM64 ├── fp_arm64.c └── fp_arm64_asm.S ├── CMakeLists.txt ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SIDH-Magma ├── Kummer_Weierstrass_equivalence.mag ├── README.txt ├── SIDH-compression.mag ├── SIDH-curve-and-isogeny-arithmetic.mag ├── SIDH-field-arithmetic.mag ├── SIDH-pairings.mag ├── SIDH-parameters.mag ├── SIDH-pohlig-hellman.mag ├── SIDH.mag ├── TestSIDH-kex.mag └── optimalstrategies.mag ├── SIDH.c ├── SIDH.h ├── SIDH_api.h ├── SIDH_internal.h ├── SIDH_setup.c ├── Visual Studio ├── SIDH │ ├── SIDH.sln │ ├── SIDH.vcxproj │ └── SIDH.vcxproj.filters ├── arith_tests │ ├── arith_tests.vcxproj │ └── arith_tests.vcxproj.filters └── kex_tests │ ├── kex_tests.vcxproj │ └── kex_tests.vcxproj.filters ├── ec_isogeny.c ├── fpx.c ├── generic └── fp_generic.c ├── kex.c ├── look_up_tables.h ├── makefile └── tests ├── arith_tests.c ├── kex_tests.c ├── test ├── P503_api.h ├── P751_api.h └── sike.c ├── test_extras.c └── test_extras.h /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | -------------------------------------------------------------------------------- /AMD64/ZREDC_6x4_SH_SK.S: -------------------------------------------------------------------------------- 1 | //******************************************************************************************* 2 | // Copyright (c) Sept,2017 Ochoa-Jiménez 3 | // Computer Science Department 4 | // CINVESTAV-IPN. Mexico. 5 | // 6 | // This program is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // This program is distributed in the hope that it will be useful, but 11 | // WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public License 16 | // along with this program. If not, see . 17 | //******************************************************************************************/ 18 | // Registers that are used for parameter passing: 19 | 20 | #define reg_p1 %rdi 21 | #define reg_p2 %rsi 22 | #define reg_p3 %rdx 23 | 24 | // p3_239 = 3^239 25 | p3_239: 26 | .quad 0xC968549F878A8EEB 27 | .quad 0x59B1A13F7CC76E3E 28 | .quad 0xE9867D6EBE876DA9 29 | .quad 0x2B5045CB25748084 30 | .quad 0x2909F97BADC66856 31 | .quad 0x6FE5D541F71C0E1 32 | 33 | //********************************************************************** 34 | // Montgomery reduction 35 | // Based on the algorithm 7 of "Improved algorithms for the 36 | // supersingular isogeny Diffie-Hellman key exchange protocol" 37 | // Operation: c [reg_p2] = a [reg_p1] 38 | // NOTE: a=c is not allowed (a is destroyed) 39 | //********************************************************************** 40 | .global REDC 41 | REDC: 42 | 43 | push %rbx 44 | push %r12 45 | push %r13 46 | push %r14 47 | push %r15 48 | sub $16, %rsp 49 | 50 | // X = p3_239*(reg_p2[0-3])) 51 | // (multiplication of 6-word by 4-word operands) 52 | movq (reg_p2), %rdx 53 | mulx (p3_239), %r8 , %r9 54 | mulx (p3_239+8), %rax, %r10 55 | addq %rax, %r9 56 | mulx (p3_239+16), %rax, %r11 57 | adcq %rax, %r10 58 | mulx (p3_239+24), %rax, %r12 59 | adcq %rax, %r11 60 | mulx (p3_239+32), %rax, %r13 61 | adcq %rax, %r12 62 | mulx (p3_239+40), %rax, %r14 63 | adcq %rax, %r13 64 | adcq $0, %r14 65 | 66 | movq %r8, (%rsp) 67 | movq 8(reg_p2), %rdx 68 | xorq %r15, %r15 69 | mulx (p3_239), %rax, %rcx 70 | adcx %rax, %r9 71 | adox %rcx, %r10 72 | mulx (p3_239+8), %rax, %rcx 73 | adcx %rax, %r10 74 | adox %rcx, %r11 75 | mulx (p3_239+16), %rax, %rcx 76 | adcx %rax, %r11 77 | adox %rcx, %r12 78 | mulx (p3_239+24), %rax, %rcx 79 | adcx %rax, %r12 80 | adox %rcx, %r13 81 | mulx (p3_239+32), %rax, %rcx 82 | adcx %rax, %r13 83 | adox %rcx, %r14 84 | mulx (p3_239+40), %rax, %rcx 85 | adcx %rax, %r14 86 | adox %rcx, %r15 87 | adcq $0, %r15 88 | 89 | movq %r9, 8(%rsp) 90 | movq 16(reg_p2), %rdx 91 | xorq %r8, %r8 92 | mulx (p3_239), %rax, %rcx 93 | adcx %rax, %r10 94 | adox %rcx, %r11 95 | mulx (p3_239+8), %rax, %rcx 96 | adcx %rax, %r11 97 | adox %rcx, %r12 98 | mulx (p3_239+16), %rax, %rcx 99 | adcx %rax, %r12 100 | adox %rcx, %r13 101 | mulx (p3_239+24), %rax, %rcx 102 | adcx %rax, %r13 103 | adox %rcx, %r14 104 | mulx (p3_239+32), %rax, %rcx 105 | adcx %rax, %r14 106 | adox %rcx, %r15 107 | mulx (p3_239+40), %rax, %rcx 108 | adcx %rax, %r15 109 | adox %rcx, %r8 110 | adcq $0, %r8 111 | 112 | movq 24(reg_p2), %rdx 113 | xorq %r9 , %r9 114 | mulx (p3_239), %rax, %rcx 115 | adcx %rax, %r11 116 | adox %rcx, %r12 117 | mulx (p3_239+8), %rax, %rcx 118 | adcx %rax, %r12 119 | adox %rcx, %r13 120 | mulx (p3_239+16), %rax, %rcx 121 | adcx %rax, %r13 122 | adox %rcx, %r14 123 | mulx (p3_239+24), %rax, %rcx 124 | adcx %rax, %r14 125 | adox %rcx, %r15 126 | mulx (p3_239+32), %rax, %rcx 127 | adcx %rax, %r15 128 | adox %rcx, %r8 129 | mulx (p3_239+40), %rax, %rcx 130 | adcx %rax, %r8 131 | adox %rcx, %r9 132 | adcq $0, %r9 133 | 134 | // X = X << 52 135 | movq (%rsp), %rax 136 | movq 8(%rsp), %rcx 137 | xorq %rdx, %rdx 138 | shld $52, %r9 , %rdx 139 | shld $52, %r8 , %r9 140 | shld $52, %r15, %r8 141 | shld $52, %r14, %r15 142 | shld $52, %r13, %r14 143 | shld $52, %r12, %r13 144 | shld $52, %r11, %r12 145 | shld $52, %r10, %r11 146 | shld $52, %rcx, %r10 147 | shld $52, %rax, %rcx 148 | shl $52, %rax 149 | 150 | // reg_p2[5-16] = X + (reg_p2[5-15]) 151 | addq %rax, 40(reg_p2) 152 | adcq %rcx, 48(reg_p2) 153 | adcq %r10, 56(reg_p2) 154 | adcq %r11, 64(reg_p2) 155 | adcq %r12, 72(reg_p2) 156 | adcq %r13, 80(reg_p2) 157 | adcq %r14, 88(reg_p2) 158 | adcq %r15, 96(reg_p2) 159 | adcq %r8, 104(reg_p2) 160 | adcq %r9, 112(reg_p2) 161 | adcq %rdx, 120(reg_p2) 162 | adcq $0, 128(reg_p2) 163 | 164 | 165 | 166 | // X = p3_239*(reg_p2[4-7]) 167 | // (multiplication of 6-word by 4-word operands) 168 | movq 32(reg_p2), %rdx 169 | mulx (p3_239), %r8 , %r9 170 | mulx (p3_239+8), %rax, %r10 171 | addq %rax, %r9 172 | mulx (p3_239+16), %rax, %r11 173 | adcq %rax, %r10 174 | mulx (p3_239+24), %rax, %r12 175 | adcq %rax, %r11 176 | mulx (p3_239+32), %rax, %r13 177 | adcq %rax, %r12 178 | mulx (p3_239+40), %rax, %r14 179 | adcq %rax, %r13 180 | adcq $0, %r14 181 | 182 | movq %r8, (%rsp) 183 | movq 40(reg_p2), %rdx 184 | xorq %r15, %r15 185 | mulx (p3_239), %rax, %rcx 186 | adcx %rax, %r9 187 | adox %rcx, %r10 188 | mulx (p3_239+8), %rax, %rcx 189 | adcx %rax, %r10 190 | adox %rcx, %r11 191 | mulx (p3_239+16), %rax, %rcx 192 | adcx %rax, %r11 193 | adox %rcx, %r12 194 | mulx (p3_239+24), %rax, %rcx 195 | adcx %rax, %r12 196 | adox %rcx, %r13 197 | mulx (p3_239+32), %rax, %rcx 198 | adcx %rax, %r13 199 | adox %rcx, %r14 200 | mulx (p3_239+40), %rax, %rcx 201 | adcx %rax, %r14 202 | adox %rcx, %r15 203 | adcq $0, %r15 204 | 205 | movq %r9, 8(%rsp) 206 | movq 48(reg_p2), %rdx 207 | xorq %r8, %r8 208 | mulx (p3_239), %rax, %rcx 209 | adcx %rax, %r10 210 | adox %rcx, %r11 211 | mulx (p3_239+8), %rax, %rcx 212 | adcx %rax, %r11 213 | adox %rcx, %r12 214 | mulx (p3_239+16), %rax, %rcx 215 | adcx %rax, %r12 216 | adox %rcx, %r13 217 | mulx (p3_239+24), %rax, %rcx 218 | adcx %rax, %r13 219 | adox %rcx, %r14 220 | mulx (p3_239+32), %rax, %rcx 221 | adcx %rax, %r14 222 | adox %rcx, %r15 223 | mulx (p3_239+40), %rax, %rcx 224 | adcx %rax, %r15 225 | adox %rcx, %r8 226 | adcq $0, %r8 227 | 228 | movq 56(reg_p2), %rdx 229 | xorq %r9 , %r9 230 | mulx (p3_239), %rax, %rcx 231 | adcx %rax, %r11 232 | adox %rcx, %r12 233 | mulx (p3_239+8), %rax, %rcx 234 | adcx %rax, %r12 235 | adox %rcx, %r13 236 | mulx (p3_239+16), %rax, %rcx 237 | adcx %rax, %r13 238 | adox %rcx, %r14 239 | mulx (p3_239+24), %rax, %rcx 240 | adcx %rax, %r14 241 | adox %rcx, %r15 242 | mulx (p3_239+32), %rax, %rcx 243 | adcx %rax, %r15 244 | adox %rcx, %r8 245 | mulx (p3_239+40), %rax, %rcx 246 | adcx %rax, %r8 247 | adox %rcx, %r9 248 | adcq $0, %r9 249 | 250 | // X = X << 52 251 | movq (%rsp), %rax 252 | movq 8(%rsp), %rcx 253 | xorq %rdx, %rdx 254 | shld $52, %r9 , %rdx 255 | shld $52, %r8 , %r9 256 | shld $52, %r15, %r8 257 | shld $52, %r14, %r15 258 | shld $52, %r13, %r14 259 | shld $52, %r12, %r13 260 | shld $52, %r11, %r12 261 | shld $52, %r10, %r11 262 | shld $52, %rcx, %r10 263 | shld $52, %rax, %rcx 264 | shl $52, %rax 265 | 266 | // reg_p2[9-20] = X + (reg_p2[9-19]) 267 | addq %rax, 72(reg_p2) 268 | adcq %rcx, 80(reg_p2) 269 | adcq %r10, 88(reg_p2) 270 | adcq 96(reg_p2), %r11 271 | adcq %r12, 104(reg_p2) 272 | adcq %r13, 112(reg_p2) 273 | adcq %r14, 120(reg_p2) 274 | adcq %r15, 128(reg_p2) 275 | adcq %r8, 136(reg_p2) 276 | adcq %r9, 144(reg_p2) 277 | adcq %rdx, 152(reg_p2) 278 | adcq $0, 160(reg_p2) 279 | 280 | 281 | // X = p3_239*(reg_p2[8-11]) 282 | // (multiplication of 6-word by 4-word operands) 283 | movq %r11, (reg_p1) 284 | movq 64(reg_p2), %rdx 285 | mulx (p3_239), %r8 , %r9 286 | mulx (p3_239+8), %rax, %r10 287 | addq %rax, %r9 288 | mulx (p3_239+16), %rax, %r11 289 | adcq %rax, %r10 290 | mulx (p3_239+24), %rax, %r12 291 | adcq %rax, %r11 292 | mulx (p3_239+32), %rax, %r13 293 | adcq %rax, %r12 294 | mulx (p3_239+40), %rax, %r14 295 | adcq %rax, %r13 296 | adcq $0, %r14 297 | 298 | movq %r8, (%rsp) 299 | movq 72(reg_p2), %rdx 300 | xorq %r15, %r15 301 | mulx (p3_239), %rax, %rcx 302 | adcx %rax, %r9 303 | adox %rcx, %r10 304 | mulx (p3_239+8), %rax, %rcx 305 | adcx %rax, %r10 306 | adox %rcx, %r11 307 | mulx (p3_239+16), %rax, %rcx 308 | adcx %rax, %r11 309 | adox %rcx, %r12 310 | mulx (p3_239+24), %rax, %rcx 311 | adcx %rax, %r12 312 | adox %rcx, %r13 313 | mulx (p3_239+32), %rax, %rcx 314 | adcx %rax, %r13 315 | adox %rcx, %r14 316 | mulx (p3_239+40), %rax, %rcx 317 | adcx %rax, %r14 318 | adox %rcx, %r15 319 | adcq $0, %r15 320 | 321 | movq %r9, 8(%rsp) 322 | movq 80(reg_p2), %rdx 323 | xorq %r8, %r8 324 | mulx (p3_239), %rax, %rcx 325 | adcx %rax, %r10 326 | adox %rcx, %r11 327 | mulx (p3_239+8), %rax, %rcx 328 | adcx %rax, %r11 329 | adox %rcx, %r12 330 | mulx (p3_239+16), %rax, %rcx 331 | adcx %rax, %r12 332 | adox %rcx, %r13 333 | mulx (p3_239+24), %rax, %rcx 334 | adcx %rax, %r13 335 | adox %rcx, %r14 336 | mulx (p3_239+32), %rax, %rcx 337 | adcx %rax, %r14 338 | adox %rcx, %r15 339 | mulx (p3_239+40), %rax, %rcx 340 | adcx %rax, %r15 341 | adox %rcx, %r8 342 | adcq $0, %r8 343 | 344 | movq 88(reg_p2), %rdx 345 | xorq %r9 , %r9 346 | mulx (p3_239), %rax, %rcx 347 | adcx %rax, %r11 348 | adox %rcx, %r12 349 | mulx (p3_239+8), %rax, %rcx 350 | adcx %rax, %r12 351 | adox %rcx, %r13 352 | mulx (p3_239+16), %rax, %rcx 353 | adcx %rax, %r13 354 | adox %rcx, %r14 355 | mulx (p3_239+24), %rax, %rcx 356 | adcx %rax, %r14 357 | adox %rcx, %r15 358 | mulx (p3_239+32), %rax, %rcx 359 | adcx %rax, %r15 360 | adox %rcx, %r8 361 | mulx (p3_239+40), %rax, %rcx 362 | adcx %rax, %r8 363 | adox %rcx, %r9 364 | adcq $0, %r9 365 | 366 | // X = X << 52 367 | movq (%rsp), %rax 368 | movq 8(%rsp), %rcx 369 | xorq %rdx, %rdx 370 | shld $52, %r9 , %rdx 371 | shld $52, %r8 , %r9 372 | shld $52, %r15, %r8 373 | shld $52, %r14, %r15 374 | shld $52, %r13, %r14 375 | shld $52, %r12, %r13 376 | shld $52, %r11, %r12 377 | shld $52, %r10, %r11 378 | shld $52, %rcx, %r10 379 | shld $52, %rax, %rcx 380 | shl $52, %rax 381 | 382 | // reg_p1[0-11] = X + (reg_p1[0-11]) 383 | addq 104(reg_p2), %rax 384 | adcq 112(reg_p2), %rcx 385 | adcq 120(reg_p2), %r10 386 | adcq 128(reg_p2), %r11 387 | adcq 136(reg_p2), %r12 388 | adcq 144(reg_p2), %r13 389 | adcq 152(reg_p2), %r14 390 | adcq 160(reg_p2), %r15 391 | adcq 168(reg_p2), %r8 392 | adcq 176(reg_p2), %r9 393 | adcq 184(reg_p2), %rdx 394 | 395 | 396 | movq %rax, 8(reg_p1) 397 | movq %rcx, 16(reg_p1) 398 | movq %r10, 24(reg_p1) 399 | movq %r11, 32(reg_p1) 400 | movq %r12, 40(reg_p1) 401 | movq %r13, 48(reg_p1) 402 | movq %r14, 56(reg_p1) 403 | movq %r15, 64(reg_p1) 404 | movq %r8 , 72(reg_p1) 405 | movq %r9 , 80(reg_p1) 406 | movq %rdx, 88(reg_p1) 407 | 408 | 409 | add $16, %rsp 410 | pop %r15 411 | pop %r14 412 | pop %r13 413 | pop %r12 414 | pop %rbx 415 | 416 | ret 417 | 418 | 419 | 420 | 421 | -------------------------------------------------------------------------------- /ARM64/fp_arm64.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************************** 2 | * SIDH: an efficient supersingular isogeny-based cryptography library for ephemeral 3 | * Diffie-Hellman key exchange. 4 | * 5 | * Author: David Urbanik; dburbani@uwaterloo.ca 6 | * 7 | * Abstract: Finite field arithmetic for ARM64 using code modified from the original x86_64 8 | * and generic implementations by Microsoft. 9 | * 10 | * Most of this file is just a wrapper for the asm file. The other routines are 11 | * direct copies of their counterparts on the AMD64 side. 12 | * 13 | * Modified to allow inputs in [0, 2*p751-1]. 14 | * 15 | *********************************************************************************************/ 16 | 17 | #include "../SIDH_internal.h" 18 | 19 | // Global constants 20 | extern const uint64_t p751[NWORDS_FIELD]; 21 | extern const uint64_t p751x2[NWORDS_FIELD]; 22 | 23 | 24 | __inline void fpadd751(const digit_t* a, const digit_t* b, digit_t* c) 25 | { // Modular addition, c = a+b mod p751. 26 | // Inputs: a, b in [0, 2*p751-1] 27 | // Output: c in [0, 2*p751-1] 28 | 29 | fpadd751_asm(a, b, c); 30 | } 31 | 32 | 33 | __inline void fpsub751(const digit_t* a, const digit_t* b, digit_t* c) 34 | { // Modular subtraction, c = a-b mod p751. 35 | // Inputs: a, b in [0, 2*p751-1] 36 | // Output: c in [0, 2*p751-1] 37 | 38 | fpsub751_asm(a, b, c); 39 | } 40 | 41 | 42 | __inline void fpneg751(digit_t* a) 43 | { // Modular negation, a = -a mod p751. 44 | // Input/output: a in [0, 2*p751-1] 45 | unsigned int i, borrow = 0; 46 | 47 | for (i = 0; i < NWORDS_FIELD; i++) { 48 | SUBC(borrow, ((digit_t*)p751x2)[i], a[i], borrow, a[i]); 49 | } 50 | } 51 | 52 | 53 | void fpdiv2_751(const digit_t* a, digit_t* c) 54 | { // Modular division by two, c = a/2 mod p751. 55 | // Input : a in [0, 2*p751-1] 56 | // Output: c in [0, 2*p751-1] 57 | unsigned int i, carry = 0; 58 | digit_t mask; 59 | 60 | mask = 0 - (digit_t)(a[0] & 1); // If a is odd compute a+p521 61 | for (i = 0; i < NWORDS_FIELD; i++) { 62 | ADDC(carry, a[i], ((digit_t*)p751)[i] & mask, carry, c[i]); 63 | } 64 | 65 | mp_shiftr1(c, NWORDS_FIELD); 66 | } 67 | 68 | 69 | void fpcorrection751(digit_t* a) 70 | { // Modular correction to reduce field element a in [0, 2*p751-1] to [0, p751-1]. 71 | unsigned int i, borrow = 0; 72 | digit_t mask; 73 | 74 | for (i = 0; i < NWORDS_FIELD; i++) { 75 | SUBC(borrow, a[i], ((digit_t*)p751)[i], borrow, a[i]); 76 | } 77 | mask = 0 - (digit_t)borrow; 78 | 79 | borrow = 0; 80 | for (i = 0; i < NWORDS_FIELD; i++) { 81 | ADDC(borrow, a[i], ((digit_t*)p751)[i] & mask, borrow, a[i]); 82 | } 83 | } 84 | 85 | 86 | void mp_mul(const digit_t* a, const digit_t* b, digit_t* c, const unsigned int nwords) 87 | { // Multiprecision multiply, c = a*b, where lng(a) = lng(b) = nwords. 88 | 89 | UNREFERENCED_PARAMETER(nwords); 90 | 91 | mul751_asm(a, b, c); 92 | } 93 | 94 | 95 | 96 | void rdc_mont(const digit_t* ma, digit_t* mc) 97 | { // Efficient Montgomery reduction using comba and exploiting the special form of the prime p751. 98 | // mc = ma*R^-1 mod p751x2, where R = 2^768. 99 | // If ma < 2^768*p751, the output mc is in the range [0, 2*p751-1]. 100 | // ma is assumed to be in Montgomery representation. 101 | 102 | rdc751_asm(ma, mc); 103 | } 104 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.4) 2 | project(flor-sidh-x64 C) 3 | 4 | include_directories(./include) 5 | link_directories(./lib) 6 | set(EXECUTABLE_OUTPUT_PATH ./bin) 7 | set(LIBRARY_OUTPUT_PATH ./lib) 8 | set(TARGET flor-sidh-x64) 9 | set(SRC ./src) 10 | enable_language(ASM) 11 | 12 | add_definitions(-D_AMD64_) 13 | add_definitions(-D__LINUX__) 14 | 15 | #-pedantic -std=c99 16 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -mbmi -mbmi2 -march=native -mtune=native -fwrapv -fomit-frame-pointer") 17 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -O3 -mbmi -mbmi2 -march=native -mtune=native -fwrapv -fomit-frame-pointer") 18 | 19 | SET(obj_HW 20 | AMD64/ZMULT_HW.h 21 | AMD64/ZREDC_6x4_SH_HW.S 22 | ) 23 | 24 | SET(obj_SK 25 | AMD64/ZMULT_SK.h 26 | AMD64/ZREDC_6x4_SH_SK.S 27 | ) 28 | 29 | SET(objects 30 | AMD64/Z_ADD_SUB.h 31 | AMD64/fp_x64.c 32 | AMD64/fp_x64_asm.S 33 | fpx.c 34 | ec_isogeny.c 35 | look_up_tables.h 36 | SIDH_internal.h 37 | SIDH_setup.c 38 | SIDH.c 39 | kex.c 40 | tests/test_extras.c 41 | tests/test_extras.h 42 | ) 43 | 44 | add_executable(kex_native tests/kex_tests.c ${objects}) 45 | add_executable(kex_haswell ${obj_HW} tests/kex_tests.c ${objects}) 46 | add_executable(kex_skylake ${obj_SK} tests/kex_tests.c ${objects}) 47 | add_executable(arith_native tests/arith_tests.c ${objects}) 48 | add_executable(arith_haswell ${obj_HW} tests/arith_tests.c ${objects}) 49 | add_executable(arith_skylake ${obj_SK} tests/arith_tests.c ${objects}) 50 | 51 | target_compile_definitions( kex_native PRIVATE -D__NATIVE__ ) 52 | target_compile_definitions( kex_haswell PRIVATE -D__HASWELL__) 53 | target_compile_definitions( kex_skylake PRIVATE -D__SKYLAKE__) 54 | target_compile_definitions(arith_native PRIVATE -D__NATIVE__ ) 55 | target_compile_definitions(arith_haswell PRIVATE -D__HASWELL__) 56 | target_compile_definitions(arith_skylake PRIVATE -D__SKYLAKE__) 57 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Instructions for Contributing Code 2 | 3 | ## Contributing bug fixes and features 4 | SIDH is currently accepting contributions in the form of bug fixes and new features. Any submission must have an issue tracking it in the issue tracker that has been approved by the SIDH team. Your pull request should include a link to the bug that you are fixing. If you've submitted a PR for a bug, please post a comment in the bug to avoid duplication of effort. 5 | 6 | ## Legal 7 | If your contribution is more than 15 lines of code, you will need to complete a Contributor License Agreement (CLA). Briefly, this agreement testifies that you are granting us permission to use the submitted change according to the terms of the project's license, and that the work being submitted is under appropriate copyright. 8 | 9 | Please submit a Contributor License Agreement (CLA) before submitting a pull request. You may visit https://cla.microsoft.com to sign digitally. Alternatively, download the agreement ([Microsoft Contribution License Agreement.docx](https://www.codeplex.com/Download?ProjectName=typescript&DownloadId=822190) or [Microsoft Contribution License Agreement.pdf](https://www.codeplex.com/Download?ProjectName=typescript&DownloadId=921298)), sign, scan, and email it back to cla@microsoft.com. Be sure to include your github user name along with the agreement. Once we have received the signed CLA, we'll review the request. 10 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FLOR-SIDH-x64 2 | 3 | This software library contains C-language + optimized x86_64 assembly code for implementing the Super-Singular Isogeny Diffie-Hellman algorithm proposed by Jao, De Feo and Plût. 4 | 5 | The code base is forked from the [PQCrypto-SIDH](https://github.com/Microsoft/PQCrypto-SIDH) project of Microsoft introduced by Costelo, Longa and Naehrig on CRYPTO 2016. 6 | 7 | ---- 8 | 9 | ### Additional contributions 10 | * New **Three-Point Ladder algorithm** to calculate P+[k]Q operation. 11 | * A new right-to-left ladder replaces the 3-point ladder algorithm of De Feo et al. accelerating the shared secret phase. 12 | * A new right-to-left ladder with precomputation tables that accelerate key generation phase. 13 | * New **Point-Tripling Formula** for Montgomery curves. An improvement of 1M-1S-1A operations in Fp2. 14 | * **Optimized implementation** of arithmetic operations of Fp and Fp2 using MULX and ADCX/ADOX instructions. 15 | * Around 25% of improvement on Haswell and Skylake processors. 16 | 17 | --- 18 | 19 | ### Research Resources 20 | 21 | This source code is part of the research work titled: 22 | *"A Faster Software Implementation of the Supersingular Isogeny Diffie-Hellman Key Exchange Protocol"* published at IEEE Transactions on Computers journal by the authors: 23 | * [Armando Faz-Hernández](http://www.ic.unicamp.br/~armfazh), University of Campinas, Brazil. 24 | * [Julio López](http://www.ic.unicamp.br/pessoas/docentes/jlopez), University of Campinas, Brazil. 25 | * [Eduardo Ochoa-Jiménez](https://twitter.com/_Eduardo_Ochoa), Computer Science Department, Cinvestav-IPN, Mexico. 26 | * [Francisco Rodríguez-Henríquez](http://delta.cs.cinvestav.mx/~francisco/), Computer Science Department, Cinvestav-IPN, Mexico. 27 | 28 | DOI: [10.1109/TC.2017.2771535](https://doi.org/10.1109/TC.2017.2771535). 29 | 30 | IACR ePrint Archive: [[PDF](https://eprint.iacr.org/2017/1015)] 31 | 32 | To cite this work use: 33 | 34 | ```tex 35 | @article{flor_sidh_x64, 36 | author = {A. Faz-Hern\'{a}ndez and J. L\'{o}pez and 37 | E. Ochoa-Jim\'{e}nez and F. Rodr\'{i}guez-Henr\'{i}quez}, 38 | title = {A Faster Software Implementation of the Supersingular 39 | Isogeny Diffie-Hellman Key Exchange Protocol}, 40 | year = {2018}, 41 | journal = {IEEE Transactions on Computers}, 42 | publisher = {IEEE}, 43 | volume = {67}, 44 | number = {11}, 45 | pages = {1622-1636}, 46 | month = {Nov}, 47 | keywords = {sidh protocol, montgomery ladder, post-quantum cryptography, 48 | montgomery reduction}, 49 | doi = {10.1109/TC.2017.2771535}, 50 | url = {http://doi.org/10.1109/TC.2017.2771535}, 51 | } 52 | ``` 53 | 54 | --- 55 | 56 | ### Compilation 57 | Clone repository and configure project using the [CMake](https://cmake.org/) tool: 58 | 59 | ```sh 60 | $ git clone https://github.com/armfazh/flor-sidh-x64 61 | $ cd flor-sidh-x64 62 | $ mkdir build 63 | $ cd build 64 | ``` 65 | You can specify the compiler as follows: 66 | ```sh 67 | $ CC=gcc cmake .. 68 | $ make 69 | ``` 70 | 71 | ---- 72 | 73 | ### Running Benchmark 74 | 75 | #### Key Exchange Performance Report 76 | Once compilation was done, you can run the ```kex_haswell``` companion program if you are in a processor supporting MULX instruction, e.g. on Haswell. 77 | ```sh 78 | $ bin/kex_haswell 79 | ``` 80 | 81 | Optionally, you can run the ```kex_skylake``` companion program if you are in a processor supporting MULX and ADCX/ADOX instructions, e.g. on Skylake. 82 | ```sh 83 | $ bin/kex_skylake 84 | ``` 85 | 86 | To run the original arithmetic provided by SIDH v2, you can run: 87 | ```sh 88 | $ bin/kex_native 89 | ``` 90 | 91 | #### Low level Arithmetic Performance Report 92 | If you want to obtain a detailed benchamrk of the operations in Fp, Fp2, and ECC, you can execute: 93 | ```sh 94 | $ bin/arith_haswell 95 | ``` 96 | Optionally, you can also run ```arith_skylake``` or ```arith_native```. 97 | 98 | 99 | ---- 100 | 101 | 102 | ### Compilation options 103 | 104 | There are two implementations of the prime field arithmetic in this library that can be enabled by using the ```ARCH_EX = [native|haswell|skylake]``` 105 | flag. 106 | 107 | * Optimized for Haswell processors (append ARCH_EX=haswell): 108 | 109 | ```sh 110 | $ make ARCH=x64 CC=[gcc/clang] GENERIC=FALSE SET=EXTENDED ASM=TRUE ARCH_EX=haswell 111 | ``` 112 | 113 | * Optimized for Skylake processors (append ARCH_EX=skylake): 114 | 115 | ```sh 116 | $ make ARCH=x64 CC=[gcc/clang] GENERIC=FALSE SET=EXTENDED ASM=TRUE ARCH_EX=skylake 117 | ``` 118 | 119 | * Compile using the original prime field arithmetic. 120 | 121 | ```sh 122 | $ make ARCH=x64 CC=[gcc/clang] GENERIC=FALSE SET=EXTENDED ASM=TRUE ARCH_EX=native 123 | ``` 124 | 125 | 126 | ### License 127 | MIT License 128 | 129 | ---- 130 | 131 | ### Contact 132 | 133 | To report some issues or comments of this project, please use the issues webpage [[here](https://github.com/armfazh/flor-sidh-x64/issues)]. 134 | 135 | ---- 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /SIDH-Magma/README.txt: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Code for SIDH key exchange with optional public key compression 4 | // 5 | // (c) 2016 Microsoft Corporation. All rights reserved. 6 | // 7 | //////////////////////////////////////////////////////////////////////////////// 8 | // 9 | // References: 10 | // 11 | // Efficient algorithms for supersingular isogeny Diffie-Hellman 12 | // Craig Costello, Patrick Longa, Michael Naehrig, CRYPTO 2016. 13 | // 14 | // Efficient compression of SIDH public keys 15 | // Craig Costello, David Jao, Patrick Longa, Michael Naehrig, Joost Renes, 16 | // David Urbanik, EUROCRYPT 2017. 17 | // 18 | //////////////////////////////////////////////////////////////////////////////// 19 | 20 | This folder contains Magma scripts that implement SIDH key exchange as 21 | described in the above two papers. 22 | 23 | SIDH-parameters.mag 24 | SIDH-field-arithmetic.mag 25 | SIDH-curve-and-isogeny-arithmetic.mag 26 | SIDH.mag 27 | SIDH-pairings.mag 28 | SIDH-pohlig-hellman.mag 29 | SIDH-compression.mag 30 | TestSIDH-kex.mag 31 | Kummer_Weierstrass_equivalence.mag 32 | optimalstrategies.mag 33 | 34 | Running the test script 35 | 36 | > load "TestSIDH-kex.mag"; 37 | 38 | loads all the other files in the right order and provides two test functions. 39 | The function 40 | 41 | > kextest(n, simple); 42 | 43 | will run and test n random instances of SIDH key exchange without public-key 44 | compression. Setting the option simple:=false only runs the fast algorithms 45 | via optimal strategies for isogeny computation and evaluation. Setting it to 46 | simple:=true also runs the simple multiplication-based strategy and asserts 47 | that the results obtained in both approaches are equal. The function 48 | 49 | > kextest_compress(n); 50 | 51 | will run and test n random instances of SIDH key exchange including public-key 52 | compression. 53 | 54 | 55 | Running the script 56 | 57 | > load "Kummer_Weierstrass_equivalence.mag"; 58 | 59 | demonstrates the equivalence of computations on the Kummer variety with those 60 | on the Weierstrass model. 61 | Its purpose is to show that our computations give the same result as Magma's. 62 | In particular, we work explicitly on the Kummer variety of supersingular 63 | curves, almost entirely in projective space P^1, and using the Montgomery 64 | x-coordinate. This script shows that this gives equivalent results to the 65 | traditional way of computing isogenies: i.e., Velu's formulas on the affine 66 | Weierstrass model, which are implemented in Magma's "IsogenyFromKernel" 67 | function. 68 | 69 | WARNING: The script "Kummer_Weierstrass_equivalence.mag" will take several 70 | minutes to execute fully, since Magma's "IsogenyFromKernel" function is slow 71 | in contrast to the projective Kummer computations. 72 | 73 | Finally, the script "optimalstrategies.mag" computes an optimal strategy for 74 | traversing the isogeny tree based on the cost ratios of computing an 75 | m-isogeny versus the multiplication-by-m map. It follows the discussion in the 76 | paper and is based on the original method described by De Feo, Jao and Plut: 77 | Towards quantum-resistant cryptosystems from supersingular elliptic curve 78 | isogenies, J. Math. Crypt., 8(3):209-247, 2014. 79 | 80 | -------------------------------------------------------------------------------- /SIDH-Magma/SIDH-compression.mag: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Code for SIDH key exchange with optional public key compression 4 | // 5 | // (c) 2016 Microsoft Corporation. All rights reserved. 6 | // 7 | //////////////////////////////////////////////////////////////////////////////// 8 | // 9 | // SIDH-compression.mag 10 | // 11 | // This file contains functions for public-key compression and decompression as 12 | // well as adjusted functions for computing the shared secret that merge 13 | // decompression into the shared secret computation. 14 | // 15 | //////////////////////////////////////////////////////////////////////////////// 16 | // 17 | // References: 18 | // 19 | // Efficient algorithms for supersingular isogeny Diffie-Hellman 20 | // Craig Costello, Patrick Longa, Michael Naehrig, CRYPTO 2016. 21 | // 22 | // Efficient compression of SIDH public keys 23 | // Craig Costello, David Jao, Patrick Longa, Michael Naehrig, Joost Renes, 24 | // David Urbanik, EUROCRYPT 2017. 25 | // 26 | //////////////////////////////////////////////////////////////////////////////// 27 | 28 | 29 | compress_2_torsion := function(PK) 30 | phP,phQ,phX,A := recover_y(PK); 31 | 32 | XP,YP,ZP,XQ,YQ,ZQ:=generate_2_torsion_basis(A); 33 | Zinv := mont_n_way_inv([phP[3],phQ[3]],2); 34 | R1 := [XP,YP,ZP]; 35 | R2 := [XQ,YQ,ZQ]; 36 | phiP := [phP[1]*Zinv[1],phP[2]*Zinv[1]]; 37 | phiQ := [phQ[1]*Zinv[2],phQ[2]*Zinv[2]]; 38 | 39 | a0,b0,a1,b1 := ph_2(phiP,phiQ,R1,R2,A); 40 | if a0 lt 0 then a0 +:= oA; end if; 41 | if b0 lt 0 then b0 +:= oA; end if; 42 | if a1 lt 0 then a1 +:= oA; end if; 43 | if b1 lt 0 then b1 +:= oA; end if; 44 | 45 | if (a0 mod lA) ne 0 then 46 | a0inv := Modinv(a0, oA); 47 | comp := [0, (b0*a0inv) mod oA, (a1*a0inv) mod oA, (b1*a0inv) mod oA]; 48 | else 49 | b0inv := Modinv(b0, oA); 50 | comp := [1, (a0*b0inv) mod oA, (a1*b0inv) mod oA, (b1*b0inv) mod oA]; 51 | end if; 52 | // comp is the compressed form of [phiP,phiQ] 53 | 54 | return comp,A; 55 | // comp and A together are 1 + 3*372 + 2*751 = 2619 bits = 328 bytes. 56 | end function; 57 | 58 | compress_3_torsion := function(PK) 59 | phP,phQ,phX,A := recover_y(PK); 60 | 61 | XP,YP,ZP,XQ,YQ,ZQ:=generate_3_torsion_basis(A); 62 | Zinv := mont_n_way_inv([ZP,ZQ,phP[3],phQ[3]],4); 63 | R1 := [XP*Zinv[1],YP*Zinv[1]]; 64 | R2 := [XQ*Zinv[2],YQ*Zinv[2]]; 65 | phiP := [phP[1]*Zinv[3],phP[2]*Zinv[3]]; 66 | phiQ := [phQ[1]*Zinv[4],phQ[2]*Zinv[4]]; 67 | 68 | a0,b0,a1,b1 := ph_3(phiP,phiQ,R1,R2,A); 69 | if a0 lt 0 then a0 +:= oB; end if; 70 | if b0 lt 0 then b0 +:= oB; end if; 71 | if a1 lt 0 then a1 +:= oB; end if; 72 | if b1 lt 0 then b1 +:= oB; end if; 73 | 74 | if a0 mod lB ne 0 then 75 | a0inv := Modinv(a0, oB); 76 | comp := [0, b0*a0inv mod oB, a1*a0inv mod oB, b1*a0inv mod oB]; 77 | else 78 | b0inv := Modinv(b0, oB); 79 | comp := [1, a0*b0inv mod oB, a1*b0inv mod oB, b1*b0inv mod oB]; 80 | end if; 81 | // comp together with A is the compressed form of [phiP,phiQ] 82 | 83 | return comp,A; 84 | // comp and A together are 1 + 3*379 + 2*751 = 2640 bits = 330 bytes. 85 | end function; 86 | 87 | decompress_2_torsion_fast := function(SK,comp,A) 88 | X1,Y1,Z1,X2,Y2,Z2 := generate_2_torsion_basis(A); 89 | 90 | // normalize basis points 91 | invs:=mont_n_way_inv([Z1,Z2],2); 92 | R1X := X1*invs[1]; 93 | R1Y := Y1*invs[1]; 94 | R2X := X2*invs[2]; 95 | R2Y := Y2*invs[2]; 96 | R1 := [R1X,R1Y]; 97 | R2 := [R2X,R2Y]; 98 | 99 | A24:=A+2; 100 | A24:=A24/2; 101 | A24:=A24/2; 102 | 103 | if comp[1] eq 0 then 104 | inv := Modinv(1+SK*comp[3],oA); 105 | scal := ((comp[2]+SK*comp[4])*inv) mod oA; 106 | X0,Y0,Z0 := mont_twodim_scalarmult(scal,R1,R2,A,A24); 107 | else 108 | inv := Modinv(1+SK*comp[4],oA); 109 | scal := ((comp[2]+SK*comp[3])*inv) mod oA; 110 | X0,Y0,Z0 := mont_twodim_scalarmult(scal,R2,R1,A,A24); 111 | end if; 112 | 113 | return X0,Z0; 114 | end function; 115 | 116 | decompress_3_torsion_fast := function(SK,comp,A) 117 | X1,Y1,Z1,X2,Y2,Z2 := generate_3_torsion_basis(A); 118 | 119 | // normalize basis points 120 | invs:=mont_n_way_inv([Z1,Z2],2); 121 | R1X := X1*invs[1]; 122 | R1Y := Y1*invs[1]; 123 | R2X := X2*invs[2]; 124 | R2Y := Y2*invs[2]; 125 | R1 := [R1X,R1Y]; 126 | R2 := [R2X,R2Y]; 127 | 128 | A24:=A+2; 129 | A24:=A24/2; 130 | A24:=A24/2; 131 | 132 | if comp[1] eq 0 then 133 | inv := Modinv(1+SK*comp[3],oB); 134 | scal := (comp[2]+SK*comp[4])*inv mod oB; 135 | X0,Y0,Z0 := mont_twodim_scalarmult(scal,R1,R2,A,A24); 136 | else 137 | inv := Modinv(1+SK*comp[4],oB); 138 | scal := (comp[2]+SK*comp[3])*inv mod oB; 139 | X0,Y0,Z0 := mont_twodim_scalarmult(scal,R2,R1,A,A24); 140 | end if; 141 | 142 | return X0,Z0; 143 | end function; 144 | 145 | shared_secret_Alice_decompression:=function(SK_Alice,PK_Bob_comp_0,PK_Bob_comp_1,params,splits,MAX) 146 | 147 | /* 148 | This function generates Alice's shared secret from her secret key and Bob's 149 | compressed public key. It uses the optimal way of traversing the isogeny tree as 150 | described by De Feo, Jao and Plut. 151 | 152 | Input: 153 | - Alice's secret key SK_Alice, a random even number between 1 and oA-1, 154 | - Bob's compressed public key PK_Bob_comp=[PK_Bob_comp_0,PK_Bob_comp_1], 155 | - the parameter "splits", a vector that guides the optimal route through the 156 | isogeny tree; it is generated individually for Alice using 157 | "optimalstrategies.m" and the ratios of 4-isogeny evaluation versus 158 | multiplication-by-4, 159 | - the parameter "MAX", the maximum number of multiplication-by-4 160 | computations. 161 | 162 | Output: 163 | - Alice's shared secret: the j-invariant of E_AB. 164 | */ 165 | 166 | A:=PK_Bob_comp_1; 167 | RX,RZ:=decompress_2_torsion_fast(SK_Alice,PK_Bob_comp_0,A); 168 | 169 | C:=1; // starting on Bob's Montgomery curve 170 | 171 | isos:=0; mulm:=0; 172 | 173 | // the first iteration is different so not in the main loop 174 | RX,RZ,A,C:=first_4_isog(RX,RZ,A); isos+:=1; 175 | 176 | pts:=[]; 177 | index:=0; 178 | 179 | // Alice's main loop 180 | for row:=1 to MAX-1 do 181 | 182 | // multiply (RX:RZ) until it has order 4, and store intermediate points 183 | while index lt (MAX - row) do 184 | Append(~pts, [RX,RZ,index]); 185 | m := splits[MAX-index-row+1]; 186 | RX,RZ:=xDBLe(RX,RZ,A,C,2*m); mulm +:= m; 187 | index +:= m; 188 | end while; 189 | 190 | // compute the 4-isogeny based on kernel (RX:RZ) 191 | A,C,consts:=get_4_isog(RX,RZ); 192 | // evaluate the 4-isogeny at every point in pts 193 | for i:=1 to #pts do 194 | pts[i][1],pts[i][2]:=eval_4_isog(consts,pts[i][1],pts[i][2]); 195 | isos+:=1; 196 | end for; 197 | 198 | // R becomes the last point in pts and then pts is pruned 199 | RX:=pts[#pts][1]; 200 | RZ:=pts[#pts][2]; 201 | index:=Integers()!pts[#pts][3]; 202 | 203 | Prune(~pts); 204 | 205 | end for; 206 | // compute the last 4-isogeny 207 | A,C,consts:=get_4_isog(RX,RZ); 208 | 209 | // compute the j Invariant of E_AB 210 | shared_secret_Alice:=j_inv(A,C); 211 | 212 | "Alice FAST secret requires: ", mulm, "muls-by-4 and ", isos, "4-isogenies"; 213 | 214 | return shared_secret_Alice; 215 | 216 | end function; 217 | 218 | shared_secret_Bob_decompression:=function(SK_Bob,PK_Alice_comp_0,PK_Alice_comp_1,params,splits,MAX) 219 | 220 | /* 221 | This function generates Bob's shared secret from his secret key and Alice's 222 | public key. It uses the optimal way of traversing the isogeny tree as 223 | described by De Feo, Jao and Plut. 224 | 225 | Input: 226 | - Bob's secret key SK_Bob, a random number between 1 and oB-1, 227 | - Alice's public key PK_Alice=[phi_A(xPB),phi_A(xQB),phi_A(x(QB-PB))], 228 | - the parameter "splits", a vector that guides the optimal route through the 229 | isogeny tree; it is generated individually for Bob using 230 | "optimalstrategies.m" and the ratios of 3-isogeny evaluation versus 231 | multiplication-by-3, 232 | - the parameter "MAX", the maximum number of multiplication-by-3 233 | computations. 234 | 235 | Output: 236 | - Bob's shared secret: the j-invariant of E_BA. 237 | */ 238 | 239 | A:=PK_Alice_comp_1; 240 | RX,RZ:=decompress_3_torsion_fast(SK_Bob,PK_Alice_comp_0,A); 241 | C:=1; // starting on Alice's Montgomery curve 242 | 243 | pts:=[]; 244 | index:=0; 245 | 246 | isos:=0; mulm:=0; 247 | 248 | // Bob's main loop 249 | for row:=1 to MAX-1 do 250 | 251 | // multiply (RX:RZ) until it has order 3, and store intermediate points 252 | while index lt (MAX - row) do 253 | Append(~pts, [RX,RZ,index]); 254 | m := splits[MAX-index-row+1]; 255 | RX,RZ:=xTPLe(RX,RZ,A,C,m); mulm +:= m; 256 | index +:= m; 257 | end while; 258 | 259 | // compute the 3-isogeny based on kernel (RX:RZ) 260 | A,C:=get_3_isog(RX,RZ); 261 | 262 | // evaluate the 3-isogeny at every point in pts 263 | for i:=1 to #pts do 264 | pts[i][1],pts[i][2]:=eval_3_isog(RX,RZ,pts[i][1],pts[i][2]); 265 | isos+:=1; 266 | end for; 267 | 268 | // R becomes the last point in pts and then pts is pruned 269 | RX:=pts[#pts][1]; 270 | RZ:=pts[#pts][2]; 271 | index:=Integers()!pts[#pts][3]; 272 | 273 | Prune(~pts); 274 | 275 | end for; 276 | 277 | // compute the last 3-isogeny 278 | A,C:=get_3_isog(RX,RZ); 279 | 280 | // compute the j Invariant of E_BA 281 | shared_secret_Bob:=j_inv(A,C); 282 | 283 | "Bob FAST secret requires: ", mulm, "muls-by-3 and ", isos, "3-isogenies"; 284 | 285 | return shared_secret_Bob; 286 | 287 | end function; 288 | 289 | 290 | -------------------------------------------------------------------------------- /SIDH-Magma/SIDH-field-arithmetic.mag: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Code for SIDH key exchange with optional public key compression 4 | // 5 | // (c) 2016 Microsoft Corporation. All rights reserved. 6 | // 7 | //////////////////////////////////////////////////////////////////////////////// 8 | // 9 | // SIDH-field-arithmetic.mag 10 | // 11 | // Arithmetic file implementing some special field arithmetic functions, such as 12 | // cubing formulas, square roots and arithmetic in the cyclotomic subgroup. 13 | // 14 | //////////////////////////////////////////////////////////////////////////////// 15 | // 16 | // References: 17 | // 18 | // Efficient algorithms for supersingular isogeny Diffie-Hellman 19 | // Craig Costello, Patrick Longa, Michael Naehrig, CRYPTO 2016. 20 | // 21 | // Efficient compression of SIDH public keys 22 | // Craig Costello, David Jao, Patrick Longa, Michael Naehrig, Joost Renes, 23 | // David Urbanik, EUROCRYPT 2017. 24 | // 25 | //////////////////////////////////////////////////////////////////////////////// 26 | 27 | 28 | //////////////////////////////////////////////////////////////////////////////// 29 | //////////////////////////// Cubing //////////////////////////////////////////// 30 | //////////////////////////////////////////////////////////////////////////////// 31 | 32 | Fp2_cub_formula := function(a) 33 | /* 34 | This function is for cubing in Fp2. It can be implemented with 2S + 2M 35 | and is thus slightly faster than a naive square and multiplication 36 | approach (5M), see below. 37 | */ 38 | aseq := ElementToSequence(Fp2!a); 39 | a0 := aseq[1]; 40 | a1 := aseq[2]; 41 | 42 | return a0*(a0^2-3*a1^2) + i*a1*(3*a0^2-a1^2); 43 | end function; 44 | 45 | Fp2_cub := function(a) 46 | /* 47 | This function is for cubing in Fp2. It uses 2S + 2M and is thus 48 | slightly faster than a naive square and multiplication approach (5M). 49 | */ 50 | aseq := ElementToSequence(Fp2!a); 51 | a0 := aseq[1]; 52 | a1 := aseq[2]; 53 | 54 | t0 := a0^2; 55 | t1 := a1^2; 56 | c1 := t0 - t1; 57 | t0 := t0 + t0; 58 | t1 := t1 + t1; 59 | c0 := c1 - t1; 60 | c1 := c1 + t0; 61 | c0 := c0*a0; 62 | c1 := c1*a1; 63 | 64 | return c0 + c1*i; 65 | end function; 66 | 67 | //////////////////////////////////////////////////////////////////////////////// 68 | ////////////////////////////// Square roots //////////////////////////////////// 69 | //////////////////////////////////////////////////////////////////////////////// 70 | 71 | sqrt_Fp2:=function(v) 72 | /* 73 | This function computes square roots (of elements that are square) of 74 | elements in Fp2 using only Fp arithmetic. Inputs and outputs Fp2 elements 75 | and makes arbitrary (but deterministic) choice of square root. 76 | */ 77 | a:=Fp!ElementToSequence(v)[1]; //parse into Fp 78 | b:=Fp!ElementToSequence(v)[2]; 79 | 80 | //Fp arithmetic 81 | t0:=a^2; 82 | t1:=b^2; 83 | t0:=t0+t1; 84 | t1:=t0^((p+1) div 4); //370 squarings, 239 cubes 85 | t0:=a+t1; 86 | t0:=t0/2; 87 | t2:=t0^((p-3) div 4); //subchain from inversion 88 | t1:=t0*t2; 89 | t2:=t2*b; 90 | t2:=t2/2; 91 | t3:=t1^2; 92 | 93 | if t3 eq t0 then 94 | y:=t1+t2*i; //parsing back into Fp2 95 | else 96 | y:=t2-t1*i; //parsing back into Fp2 97 | end if; 98 | 99 | return y; 100 | 101 | end function; 102 | 103 | 104 | sqrt_Fp2_frac:=function(u,v) 105 | /* 106 | This function computes square roots of elements in (Fp2)^2 using Hamburg's 107 | trick. Works entirely with Fp arithmetic. 108 | */ 109 | u0:=ElementToSequence(u)[1]; 110 | u1:=ElementToSequence(u)[2]; 111 | v0:=ElementToSequence(v)[1]; 112 | v1:=ElementToSequence(v)[2]; 113 | 114 | // below is all Fp arithmetic 115 | t0:=v0^2; 116 | t1:=v1^2; 117 | t0:=t0+t1; 118 | t1:=u0*v0; 119 | t2:=u1*v1; 120 | t1:=t1+t2; 121 | t2:=u1*v0; 122 | t3:=u0*v1; 123 | t2:=t2-t3; 124 | t3:=t1^2; 125 | t4:=t2^2; 126 | t3:=t3+t4; 127 | t:=t3^((p+1) div 4); // 370 squarings, 239 cubings 128 | t:=t+t1; 129 | t:=2*t; 130 | t3:=t0^2; 131 | t3:=t3*t0; 132 | t3:=t3*t; 133 | t3:=t3^((p-3) div 4); // should be in inversion chain 134 | t3:=t0*t3; 135 | t1:=t*t3; 136 | y0:=t1/2; 137 | y1:=t3*t2; 138 | t1:=t1^2; 139 | t1:=t1*t0; 140 | 141 | if t1 ne t then 142 | temp:=y0; 143 | y0:=y1; 144 | y1:=temp; 145 | end if; 146 | 147 | t0:=y0^2; 148 | t1:=y1^2; 149 | t0:=t0-t1; 150 | t0:=t0*v0; 151 | t1:=y0*y1; 152 | t1:=t1*v1; 153 | t1:=t1+t1; 154 | t0:=t0-t1; 155 | 156 | if t0 ne u0 then 157 | y1:=-y1; 158 | end if; 159 | 160 | return y0+y1*i; //parse back into Fp2 161 | 162 | end function; 163 | 164 | 165 | //////////////////////////////////////////////////////////////////////////////// 166 | //////////////// Almost Montgomery inversion (base field) ////////////////////// 167 | //////////////////////////////////////////////////////////////////////////////// 168 | 169 | // Notation following Savas-Koc 170 | moninv_phasei := function(a,p) 171 | u := p; 172 | v := a; 173 | r := 0; 174 | s := 1; 175 | k := 0; 176 | 177 | while v gt 0 do 178 | if IsEven(u) then 179 | u := ShiftRight(u,1); 180 | s := 2*s; 181 | elif IsEven(v) then 182 | v := ShiftRight(v,1); 183 | r := 2*r; 184 | elif u gt v then 185 | u := ShiftRight(u-v,1); 186 | r := r+s; 187 | s := 2*s; 188 | elif v ge u then 189 | v := ShiftRight(v-u,1); 190 | s := s+r; 191 | r := 2*r; 192 | end if; 193 | k +:= 1; 194 | end while; 195 | 196 | if r ge p then 197 | r -:= p; 198 | end if; 199 | 200 | r := p-r; 201 | 202 | return r, k; 203 | end function; 204 | 205 | moninv_phaseii := function(r,p,k,n) 206 | 207 | for j in [1..k-n] do 208 | if r mod 2 eq 0 then 209 | r := ShiftRight(r,1); 210 | else 211 | r := ShiftRight(r+p,1); 212 | end if; 213 | end for; 214 | 215 | return r; 216 | end function; 217 | 218 | moninv := function(a,p,n) 219 | r,k := moninv_phasei(a,p); 220 | x := moninv_phaseii(r,p,k,n); 221 | 222 | return x; 223 | end function; 224 | 225 | 226 | //////////////////////////////////////////////////////////////////////////////// 227 | //////////// Montgomery inversion (quadratic extension field) ////////////////// 228 | //////////////////////////////////////////////////////////////////////////////// 229 | 230 | fp2_inv := function(a,p,n) 231 | a0 := Eltseq(a)[1]; // Re 232 | a1 := Eltseq(a)[2]; // Im 233 | 234 | num := a0-i*a1; 235 | den := a0^2+a1^2; 236 | den := GF(p)!(moninv(Integers()!den,p,n)); 237 | 238 | return num*den; 239 | end function; 240 | 241 | 242 | //////////////////////////////////////////////////////////////////////////////// 243 | /////// n-way simultaneous inversion using Montgomery's trick ////////////////// 244 | //////////////////////////////////////////////////////////////////////////////// 245 | 246 | mont_n_way_inv:=function(vec,n) 247 | 248 | a:=[Fp2!0: j in [1..n]]; //initialize vector of length n 249 | 250 | a[1]:=vec[1]; 251 | for j:=2 to n do 252 | a[j]:=a[j-1]*vec[j]; 253 | end for; 254 | 255 | a_inv:=1/a[n]; 256 | 257 | for j:=n to 2 by -1 do 258 | a[j]:=a_inv*a[j-1]; 259 | a_inv:=a_inv*vec[j]; 260 | end for; 261 | 262 | a[1]:=a_inv; 263 | 264 | return a; 265 | 266 | end function; 267 | 268 | 269 | //////////////////////////////////////////////////////////////////////////////// 270 | /////// Arithmetic operations in the cyclotomic subgroup of Fp2 //////////////// 271 | //////////////////////////////////////////////////////////////////////////////// 272 | 273 | cube_Fp2_cycl_formula := function(a) 274 | // Cyclotomic cubing on elements of norm 1, using a^(p+1) = 1. 275 | aseq := ElementToSequence(Fp2!a); 276 | a0 := aseq[1]; 277 | a1 := aseq[2]; 278 | 279 | return (a0*(4*a0^2-3)) + i*(a1*(4*a0^2-1)); 280 | end function; 281 | 282 | cube_Fp2_cycl := function(a) 283 | aseq := ElementToSequence(a); 284 | a0 := aseq[1]; 285 | a1 := aseq[2]; 286 | 287 | t0 := a0 + a0; 288 | t0 := t0^2; 289 | t0 := t0 - 1; 290 | a1 := t0*a1; 291 | t0 := t0 - 2; 292 | a0 := t0*a0; 293 | 294 | return a0 + i*a1; 295 | end function; 296 | 297 | 298 | inv_Fp2_cycl := function(a) 299 | // Cyclotomic inversion, a^(p+1) = 1 => a^(-1) = a^p = a0 - i*a1. 300 | aseq := ElementToSequence(Fp2!a); 301 | a0 := aseq[1]; 302 | a1 := aseq[2]; 303 | 304 | return a0 - i*a1; 305 | end function; 306 | 307 | 308 | sqr_Fp2_cycl_formula := function(a) 309 | /* 310 | Cyclotomic squaring on elements of norm 1, using a^(p+1) = 1. 311 | This uses 2 base field squarings. If base field squaring is not faster 312 | than base field multiplication, savings are very small. 313 | */ 314 | aseq := ElementToSequence(Fp2!a); 315 | a0 := aseq[1]; 316 | a1 := aseq[2]; 317 | 318 | return (2*a0^2-1) + i*((a0+a1)^2-1); 319 | end function; 320 | 321 | sqr_Fp2_cycl := function(a) 322 | aseq := ElementToSequence(Fp2!a); 323 | a0 := aseq[1]; 324 | a1 := aseq[2]; 325 | 326 | t0 := a0 + a1; 327 | t0 := t0^2; 328 | a1 := t0 - 1; 329 | t0 := a0^2; 330 | t0 := t0 + t0; 331 | a0 := t0 - 1; 332 | 333 | return a0 + i*a1; 334 | end function; 335 | 336 | 337 | exp_Fp2_cycl := function(y,t) 338 | // exponentiation y^t via square and multiply in the cyclotomic group 339 | res:=y; 340 | 341 | if t eq 0 then 342 | res := 1; 343 | else 344 | seq := IntegerToSequence(t, 2); 345 | for i in [1..#seq-1] do 346 | res := sqr_Fp2_cycl(res); 347 | if seq[#seq-i] eq 1 then 348 | res := res*y; 349 | end if; 350 | end for; 351 | end if; 352 | 353 | return res; 354 | end function; 355 | 356 | 357 | //////////////////////////////////////////////////////////////////////////////// 358 | //////////////////////////// Cube test ///////////////////////////////////////// 359 | //////////////////////////////////////////////////////////////////////////////// 360 | 361 | is_cube_Fp2:=function(u) 362 | /* 363 | Function for deciding whether an element in Fp2 is a cube. 364 | */ 365 | u0:=ElementToSequence(u)[1]; 366 | u1:=ElementToSequence(u)[2]; 367 | 368 | //Fp arith from here 369 | v0:=u0^2; 370 | v1:=u1^2; 371 | t0:=v0+v1; 372 | t0:=1/t0; //Fp inversion the quick and dirty one with binary Euclid 373 | v0:=v0-v1; 374 | v1:=u0*u1; 375 | v1:=2*v1; 376 | v1:=-v1; 377 | v0:=v0*t0; 378 | v1:=v1*t0; 379 | //parse back to Fp2 for (cheap) exponentiation 380 | 381 | v:=v0+v1*i; 382 | for e:=1 to 372 do 383 | v:=sqr_Fp2_cycl(v); 384 | end for; 385 | for e:=1 to 238 do 386 | v:=cube_Fp2_cycl(v); 387 | end for; 388 | if v eq 1 then 389 | assert u^((p^2-1) div 3) eq 1; 390 | return true; 391 | else 392 | assert not u^((p^2-1) div 3) eq 1; 393 | return false; 394 | end if; 395 | 396 | end function; 397 | 398 | 399 | 400 | -------------------------------------------------------------------------------- /SIDH-Magma/SIDH-pairings.mag: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Code for SIDH key exchange with optional public key compression 4 | // 5 | // (c) 2016 Microsoft Corporation. All rights reserved. 6 | // 7 | //////////////////////////////////////////////////////////////////////////////// 8 | // 9 | // SIDH-pairings.mag 10 | // 11 | // This file implements the Tate pairing on the 2- and 3-torsion groups, 12 | // respectively. The Miller loops are done as doubling-only and tripling-only 13 | // loops using parabolas during the 3-torsion pairing. Functions are tailored 14 | // towards doing 5 pairings at a time to be used for the Pohlig-Hellman DL 15 | // compuation for public-key compression. 16 | // 17 | //////////////////////////////////////////////////////////////////////////////// 18 | // 19 | // References: 20 | // 21 | // Efficient algorithms for supersingular isogeny Diffie-Hellman 22 | // Craig Costello, Patrick Longa, Michael Naehrig, CRYPTO 2016. 23 | // 24 | // Efficient compression of SIDH public keys 25 | // Craig Costello, David Jao, Patrick Longa, Michael Naehrig, Joost Renes, 26 | // David Urbanik, EUROCRYPT 2017. 27 | // 28 | //////////////////////////////////////////////////////////////////////////////// 29 | 30 | 31 | dbl_and_line:=function(T,A); 32 | /* 33 | Cost: 9M+5S+7a+1s 34 | Explicit formulas: 35 | X2 := T[1]; XZ := T[2]; Z2 := T[3]; YZ := T[4]; 36 | 37 | ly := (2*YZ)^2; 38 | l0 := 2*YZ*(X2-Z2); 39 | lx := YZ*ly+XZ*l0; 40 | 41 | ly_ := XZ*ly; 42 | l0_ := X2*l0; 43 | v0 := (X2-Z2)^2; 44 | v0_ := XZ*v0; 45 | 46 | X2_ := v0^2; 47 | XZ_ := l0^2; 48 | Z2_ := ly^2; 49 | YZ_ := l0*( v0 + 2*XZ*( 4*XZ + A*(X2+Z2) ) ); 50 | */ 51 | 52 | X2 := T[1]; XZ := T[2]; Z2 := T[3]; YZ := T[4]; 53 | 54 | X2_ := YZ+YZ; 55 | ly := X2_^2; 56 | 57 | l0 := X2-Z2; 58 | v0 := l0^2; 59 | l0 := X2_*l0; 60 | 61 | lx := XZ*l0; 62 | X2_ := YZ*ly; 63 | lx := X2_+lx; 64 | 65 | YZ_ := X2+Z2; 66 | YZ_ := A*YZ_; 67 | X2_ := XZ+XZ; 68 | YZ_ := X2_+YZ_; 69 | YZ_ := X2_+YZ_; 70 | YZ_ := X2_*YZ_; 71 | 72 | X2_ := v0^2; 73 | XZ_ := l0^2; 74 | Z2_ := ly^2; 75 | YZ_ := v0+YZ_; 76 | YZ_ := l0*YZ_; 77 | 78 | ly := XZ*ly; 79 | l0 := X2*l0; 80 | v0 := XZ*v0; 81 | 82 | return [X2_,XZ_,Z2_,YZ_],[lx,ly,l0],[v0]; 83 | end function; 84 | 85 | triple_and_parabola:=function(T,A) 86 | /* 87 | Cost: 19M+6S+15a+6s 88 | Explicit formulas: 89 | X2 := T[1]; XZ := T[2]; Z2 := T[3]; YZ := T[4]; 90 | 91 | tYZ := YZ+YZ; 92 | tYZ2 := tYZ^2; S +:= 1; 93 | X2mZ22 := (X2-Z2)^2; S +:= 1; 94 | X2pZ22 := (X2+Z2)^2; S +:= 1; 95 | AXZ := A*XZ; M +:= 1; 96 | 97 | ly := tYZ*tYZ2; M +:= 1; 98 | lx2 := 2*X2*( X2+X2+AXZ+AXZ+Z2+Z2 ) - X2mZ22; M +:= 1; 99 | lx1 := X2mZ22 + 2*( X2pZ22 + AXZ*( X2+X2+AXZ+AXZ+Z2+Z2+X2+Z2) ); M +:= 1; 100 | lx0 := X2pZ22 - 2*( X2mZ22 - Z2*( 2*(AXZ+Z2) ) ); M +:= 1; 101 | 102 | lx2_ := Z2*lx2; M +:= 1; 103 | lx1_ := 2*XZ*lx1; M +:= 1; 104 | lx0_ := X2*lx0; M +:= 1; 105 | 106 | lx02 := lx0^2; S +:= 1; 107 | lx22 := lx2^2; S +:= 1; 108 | lx04 := lx02^2; S +:= 1; 109 | lx0lx1 := lx0*lx1; M +:= 1; 110 | lx0_lx2 := lx0_*lx2; M +:= 1; 111 | lylx22 := ly*lx22; M +:= 1; 112 | X2lx04 := X2*lx04; M +:= 1; 113 | 114 | X2_ := ly * X2lx04; M +:= 1; 115 | XZ_ := XZ * lylx22 * lx02; M +:= 2; 116 | Z2_ := Z2 * lylx22 * lx22; M +:= 2; 117 | YZ_ := - lx2_ * ( X2lx04 + lx0_lx2 * ( 2*lx0lx1 + lx22 ) ); M +:= 2; 118 | 119 | vx:=Z2_; 120 | v0:=-XZ_; 121 | */ 122 | 123 | X2 := T[1]; XZ := T[2]; Z2 := T[3]; YZ := T[4]; 124 | 125 | ly := YZ+YZ; 126 | lx2 := ly^2; 127 | ly := ly*lx2; 128 | 129 | AXZ := A*XZ; 130 | t0 := AXZ+Z2; 131 | t0 := t0+t0; 132 | t1 := X2+Z2; 133 | t2 := X2+X2; 134 | t3 := X2-Z2; 135 | t3 := t3^2; 136 | t4 := t2+t0; 137 | lx2 := t2*t4; 138 | lx2 := lx2-t3; 139 | 140 | lx1 := t4+t1; 141 | t1 := t1^2; 142 | lx1 := AXZ*lx1; 143 | lx1 := t1+lx1; 144 | lx1 := lx1+lx1; 145 | lx1 := t3+lx1; 146 | 147 | lx0 := Z2*t0; 148 | lx0 := t3-lx0; 149 | lx0 := lx0+lx0; 150 | lx0 := t1-lx0; 151 | 152 | lx2_ := Z2*lx2; 153 | lx1_ := XZ*lx1; 154 | lx1_ := lx1_+lx1_; 155 | lx0_ := X2*lx0; 156 | // lx2_, lx1_, lx0_ done 157 | 158 | t3 := lx2^2; 159 | t2 := ly*t3; 160 | 161 | t4 := lx0^2; 162 | t0 := t4^2; 163 | t0 := X2*t0; 164 | 165 | X2_ := ly*t0; 166 | XZ_ := XZ*t2; 167 | XZ_ := XZ_*t4; 168 | Z2_ := Z2*t2; 169 | Z2_ := Z2_*t3; 170 | t2 := lx0*lx1; 171 | YZ_ := t2+t2; 172 | YZ_ := YZ_+t3; 173 | t2 := lx0_*lx2; 174 | YZ_ := t2*YZ_; 175 | YZ_ := t0+YZ_; 176 | YZ_ := lx2_*YZ_; 177 | YZ_ := -YZ_; 178 | // X2_,XZ_,Z2_,YZ_ done 179 | 180 | vx:=Z2_; 181 | v0:=-XZ_; 182 | // vx,v0 done 183 | 184 | return [X2_,XZ_,Z2_,YZ_],[ly,lx2_,lx1_,lx0_],[vx,v0]; 185 | end function; 186 | 187 | square_and_absorb_line:=function(n,d,L,V,x,y) //vx=ly 188 | /* 189 | Cost: 5M+2S+1a+2s 190 | Explicit formulas: 191 | lx := L[1]; ly := L[2]; l0 := L[3]; v0 := V[1]; 192 | n := n^2*(ly*y-lx*x+l0); 193 | d := d^2*(ly*x-v0); 194 | */ 195 | 196 | lx := L[1]; ly := L[2]; l0 := L[3]; v0 := V[1]; 197 | 198 | n:=n^2; 199 | d:=d^2; 200 | l:=lx*x; 201 | v:=ly*y; 202 | l:=v-l; 203 | l:=l+l0; 204 | v:=ly*x; 205 | v:=v-v0; 206 | n:=n*l; 207 | d:=d*v; 208 | 209 | return n,d; 210 | 211 | end function; 212 | 213 | cube_and_absorb_parab:=function(n,d,L,V,x,y) 214 | /* 215 | Cost: 10M+2S+4a 216 | Explicit formulas: 217 | ly := L[1]; lx2 := L[2]; lx1 := L[3]; lx0 := L[4]; 218 | vx := V[1]; v0 := V[2]; 219 | 220 | n := n^3; 221 | d := d^3; 222 | ln := (ly*y + lx2 + lx1*x + lx0*x^2)*v0; 223 | ld := (vx + v0*x)*lx0*x; 224 | n := n*ln; 225 | d := d*ld; 226 | */ 227 | 228 | ly := L[1]; lx2 := L[2]; lx1 := L[3]; lx0 := L[4]; 229 | vx := V[1]; v0 := V[2]; 230 | 231 | ln := n^2; 232 | n := n*ln; 233 | ld := d^2; 234 | d := d*ld; 235 | 236 | ln := lx0*x; 237 | ld := v0*x; 238 | ld := vx+ld; 239 | ld := ld*ln; 240 | 241 | ln := lx1+ln; 242 | ln := x*ln; 243 | t := ly*y; 244 | ln := lx2+ln; 245 | ln := t+ln; 246 | ln := ln*v0; 247 | 248 | n := n*ln; 249 | d := d*ld; 250 | 251 | return n,d; 252 | 253 | end function; 254 | 255 | final_dbl_iteration:=function(n,d,X,Z,x) 256 | /* 257 | Cost: 7M+3S+2a 258 | Explicit formulas: 259 | n:=n^2*(Z*x-X); 260 | d:=d^2*Z; 261 | */ 262 | 263 | n:=n^2; 264 | d:=d^2; 265 | d:=d*Z; 266 | l:=Z*x; 267 | l:=l-X; 268 | n:=n*l; 269 | 270 | return n,d; 271 | 272 | end function; 273 | 274 | final_tpl_iteration:=function(n,d,lambda,mu,D,x,y); 275 | /* 276 | Cost: 7M+3S+2a 277 | Explicit formulas: 278 | n:=n^3; d:=d^3; 279 | ln:=(D*y+lambda*x+mu*x^2); ld:=mu*x^2; 280 | n:=n*ln; d:=d*ld; 281 | */ 282 | 283 | ln := n^2; 284 | n := n*ln; 285 | ld := d^2; 286 | d := d*ld; 287 | 288 | ld := x^2; 289 | ld := mu*ld; 290 | t := lambda*x; 291 | ln := t+ld; 292 | t := D*y; 293 | ln := t+ln; 294 | 295 | n := n*ln; 296 | d := d*ld; 297 | 298 | return n,d; 299 | 300 | end function; 301 | 302 | /////////////////////////// 303 | 304 | final_triple:=function(P,A) 305 | /* 306 | Cost: 4M+3S+7a+1s 307 | Explicit formulas: 308 | X := P[2]; Y := P[4]; Z := P[3]; 309 | lambda := 2*Y*Z*(3*X^2+2*A*X*Z+Z^2); 310 | mu := 2*X*Y*(Z^2-X^2); 311 | D := (2*Y*Z)^2; 312 | */ 313 | 314 | X := P[2]; Y := P[4]; Z := P[3]; 315 | 316 | X2 := X^2; 317 | tX2 := X2+X2; 318 | AX2 := A*X2; 319 | XZ := X*Z; 320 | Y2 := Y^2; 321 | tXZ := XZ+XZ; 322 | tAXZ := A*tXZ; 323 | Z2 := Z^2; 324 | YZ := Y*Z; 325 | 326 | lambda := X2+Z2; 327 | lambda := lambda+tX2; 328 | lambda := lambda+tAXZ; 329 | mu := tXZ-Y2; 330 | mu := mu+AX2; 331 | D := YZ+YZ; 332 | 333 | return lambda,mu,D; 334 | 335 | end function; 336 | 337 | final_exponentiation_2_torsion:=function(n,d,n_inv,d_inv) 338 | 339 | n:=n*d_inv; 340 | //n:=n^p; //just call conjugation function 341 | n:=inv_Fp2_cycl(n); 342 | d:=d*n_inv; 343 | n:=n*d; 344 | 345 | for j:=1 to 239 do 346 | n:=cube_Fp2_cycl(n); 347 | end for; 348 | 349 | return n; 350 | 351 | end function; 352 | 353 | final_exponentiation_3_torsion:=function(n,d,n_inv,d_inv) 354 | 355 | n:=n*d_inv; 356 | //n:=n^p; //just call conjugation function 357 | n:=inv_Fp2_cycl(n); 358 | d:=d*n_inv; 359 | n:=n*d; 360 | 361 | for j:=1 to 372 do 362 | n:=sqr_Fp2_cycl(n); 363 | end for; 364 | 365 | return n; 366 | 367 | end function; 368 | 369 | Tate_pairings_2_torsion:=function(R1,R2,P,Q,A) 370 | 371 | x1:=R1[1]; y1:=R1[2]; z1 := R1[3]; 372 | x2:=R2[1]; y2:=R2[2]; z2 := R2[3]; 373 | xP:=P[1]; yP:=P[2]; 374 | xQ:=Q[1]; yQ:=Q[2]; 375 | 376 | T1 := [x1^2,x1*z1,z1^2,y1*z1]; 377 | T2 := [x2^2,x2*z2,z2^2,y2*z2]; 378 | x2 := x2/z2; y2 := y2/z2; 379 | 380 | n1:=1; d1:=1; 381 | n2:=1; d2:=1; 382 | n3:=1; d3:=1; 383 | n4:=1; d4:=1; 384 | n5:=1; d5:=1; 385 | 386 | for iter:=371 to 1 by -1 do 387 | 388 | T1,L1,V1:=dbl_and_line(T1,A); //vx=ly 389 | T2,L2,V2:=dbl_and_line(T2,A); //vx=ly 390 | 391 | n1,d1:=square_and_absorb_line(n1,d1,L1,V1,x2,y2); 392 | n2,d2:=square_and_absorb_line(n2,d2,L1,V1,xP,yP); 393 | n3,d3:=square_and_absorb_line(n3,d3,L1,V1,xQ,yQ); 394 | n4,d4:=square_and_absorb_line(n4,d4,L2,V2,xP,yP); 395 | n5,d5:=square_and_absorb_line(n5,d5,L2,V2,xQ,yQ); 396 | 397 | end for; 398 | 399 | X1 := T1[2]; Z1 := T1[3]; 400 | X2 := T2[2]; Z2 := T2[3]; 401 | 402 | n1,d1:=final_dbl_iteration(n1,d1,X1,Z1,x2); 403 | n2,d2:=final_dbl_iteration(n2,d2,X1,Z1,xP); 404 | n3,d3:=final_dbl_iteration(n3,d3,X1,Z1,xQ); 405 | n4,d4:=final_dbl_iteration(n4,d4,X2,Z2,xP); 406 | n5,d5:=final_dbl_iteration(n5,d5,X2,Z2,xQ); 407 | 408 | invs:=mont_n_way_inv([n1,d1,n2,d2,n3,d3,n4,d4,n5,d5],10); 409 | 410 | n1:=final_exponentiation_2_torsion(n1,d1,invs[1],invs[2]); 411 | n2:=final_exponentiation_2_torsion(n2,d2,invs[3],invs[4]); 412 | n3:=final_exponentiation_2_torsion(n3,d3,invs[5],invs[6]); 413 | n4:=final_exponentiation_2_torsion(n4,d4,invs[7],invs[8]); 414 | n5:=final_exponentiation_2_torsion(n5,d5,invs[9],invs[10]); 415 | 416 | return n1,n2,n3,n4,n5; 417 | 418 | end function; 419 | 420 | Tate_pairings_3_torsion_triple:=function(R1,R2,P,Q,A) //3^e pairing 421 | 422 | e := 239; 423 | 424 | x1:=R1[1]; y1:=R1[2]; 425 | x2:=R2[1]; y2:=R2[2]; 426 | xP:=P[1]; yP:=P[2]; 427 | xQ:=Q[1]; yQ:=Q[2]; 428 | 429 | n1:=1; d1:=1; 430 | n2:=1; d2:=1; 431 | n3:=1; d3:=1; 432 | n4:=1; d4:=1; 433 | n5:=1; d5:=1; 434 | 435 | T1:=[x1^2,x1,1,y1]; 436 | T2:=[x2^2,x2,1,y2]; 437 | 438 | for i:=e to 2 by -1 do 439 | 440 | T1,L1,V1:=triple_and_parabola(T1,A); 441 | T2,L2,V2:=triple_and_parabola(T2,A); 442 | 443 | n1,d1 := cube_and_absorb_parab(n1,d1,L1,V1,x2,y2); 444 | n2,d2 := cube_and_absorb_parab(n2,d2,L1,V1,xP,yP); 445 | n3,d3 := cube_and_absorb_parab(n3,d3,L1,V1,xQ,yQ); 446 | n4,d4 := cube_and_absorb_parab(n4,d4,L2,V2,xP,yP); 447 | n5,d5 := cube_and_absorb_parab(n5,d5,L2,V2,xQ,yQ); 448 | 449 | end for; 450 | 451 | lambda1,mu1,D1:=final_triple(T1,A); 452 | lambda2,mu2,D2:=final_triple(T2,A); 453 | 454 | n1,d1 := final_tpl_iteration(n1,d1,lambda1,mu1,D1,x2,y2); 455 | n2,d2 := final_tpl_iteration(n2,d2,lambda1,mu1,D1,xP,yP); 456 | n3,d3 := final_tpl_iteration(n3,d3,lambda1,mu1,D1,xQ,yQ); 457 | n4,d4 := final_tpl_iteration(n4,d4,lambda2,mu2,D2,xP,yP); 458 | n5,d5 := final_tpl_iteration(n5,d5,lambda2,mu2,D2,xQ,yQ); 459 | 460 | invs:=mont_n_way_inv([n1,d1,n2,d2,n3,d3,n4,d4,n5,d5],10); 461 | 462 | n1:=final_exponentiation_3_torsion(n1,d1,invs[1],invs[2]); 463 | n2:=final_exponentiation_3_torsion(n2,d2,invs[3],invs[4]); 464 | n3:=final_exponentiation_3_torsion(n3,d3,invs[5],invs[6]); 465 | n4:=final_exponentiation_3_torsion(n4,d4,invs[7],invs[8]); 466 | n5:=final_exponentiation_3_torsion(n5,d5,invs[9],invs[10]); 467 | 468 | return n1,n2,n3,n4,n5; 469 | 470 | end function; 471 | -------------------------------------------------------------------------------- /SIDH-Magma/SIDH-parameters.mag: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Code for SIDH key exchange with optional public key compression 4 | // 5 | // (c) 2016 Microsoft Corporation. All rights reserved. 6 | // 7 | //////////////////////////////////////////////////////////////////////////////// 8 | // 9 | // SIDH-parameters.mag 10 | // 11 | // Parameter file "SIDH-parameters.mag" containing the schemes' parameters such 12 | // as finite field and elliptic curve parameters, strategies for isogeny tree 13 | // traversal and auxiliary parameters for public key compression. 14 | // 15 | //////////////////////////////////////////////////////////////////////////////// 16 | // 17 | // References: 18 | // 19 | // Efficient algorithms for supersingular isogeny Diffie-Hellman 20 | // Craig Costello, Patrick Longa, Michael Naehrig, CRYPTO 2016. 21 | // 22 | // Efficient compression of SIDH public keys 23 | // Craig Costello, David Jao, Patrick Longa, Michael Naehrig, Joost Renes, 24 | // David Urbanik, EUROCRYPT 2017. 25 | // 26 | //////////////////////////////////////////////////////////////////////////////// 27 | 28 | 29 | //////////////////////////////////////////////////////////////////////////////// 30 | //////////////////////////// Public parameters ///////////////////////////////// 31 | //////////////////////////////////////////////////////////////////////////////// 32 | 33 | // Paramters defining the prime p = f*lA^eA*lB^eB - 1 34 | f:=1; 35 | lA:=2; 36 | lB:=3; 37 | eA:=372; 38 | eB:=239; 39 | 40 | // Define the prime p 41 | p:=f*lA^eA*lB^eB-1; 42 | assert IsPrime(p: Proof:=false); 43 | 44 | // or, explicitly... 45 | assert p eq 46 | 1035471774176930525297776823786680532142738964554907117011618967905467894068247\ 47 | 8846502882896561066713624553211618840202385203911976522554393044160468771151816\ 48 | 976706840078913334358399730952774926980235086850991501872665651576831; 49 | 50 | // Prime field of order p 51 | Fp:=GF(p); 52 | // The quadratic extension via x^2 + 1 since p = 3 mod 4 53 | Fp2:=ExtensionField; 54 | 55 | // Bitlengths of group orders lA^eA and lB^eB, needed during the ladder 56 | // functions 57 | eAbits:=eA; 58 | eBbits:=379; 59 | 60 | // E0 is the starting curve E0/Fp2: y^2=x^3+x (the A=0 Montgomery curve) 61 | E0:=EllipticCurve([Fp2|1,0]); 62 | assert IsSupersingular(E0); 63 | 64 | // The orders of the points on each side 65 | oA:=lA^eA; 66 | oB:=lB^eB; 67 | 68 | // Identifyers for Alice and Bob 69 | Alice:=0; 70 | Bob:=1; 71 | 72 | // Generator PA for the base field subgroup of order lA^eA 73 | PA:=3^239*E0![11,Sqrt(Fp!11^3+11)]; 74 | // Generator PB for the base field subgroup of order lB^eB 75 | PB:=2^372*E0![6,Sqrt(Fp!6^3+6)]; 76 | 77 | //////////////////////////////////////////////////////////////////////////////// 78 | /////////////////////// Generator point coordinates /////////////////////////// 79 | /////////////////// specified explicitly by 4 Fp elements ////////////////////// 80 | //////////////////////////////////////////////////////////////////////////////// 81 | 82 | XPA:=Fp!57843070331575741623916724745225229838323045112189057077049620587995724\ 83 | 6271947419276998036192253718730996052447524118652730054908853394186541287466114\ 84 | 3122262830946833377212881592965099601886901183961091839303261748866970694633; 85 | 86 | YPA:=Fp!55289417931846173645114523009626950849421654600788978815806665527365554\ 87 | 1827349664589467431477400107235381696676468949309812255666275584200196978168790\ 88 | 9521301233517912821073526079191975713749455487083964491867894271185073160661; 89 | 90 | assert XPA eq PA[1] and YPA eq PA[2]; 91 | 92 | XPB:=Fp!43599173968491012310533367637003008929150967000137042101947814578014127\ 93 | 3164398836738987088688433645324515677545433624919918565425015905192997560085704\ 94 | 7173121187832546031604804277991148436536445770452624367894371450077315674371; 95 | 96 | YPB:=Fp!10686693760744079753638500261776672082694467465027140072103951425088918\ 97 | 6719923133049487966730514682296643039694531052672873754128006844434636819566554\ 98 | 364257913332237123293860767683395958817983684370065598726191088239028762772; 99 | 100 | assert XPB eq PB[1] and YPB eq PB[2]; 101 | 102 | params_Alice:=[XPB,XPA,YPA]; 103 | params_Bob:=[XPA,XPB,YPB]; 104 | 105 | //////////////////////////////////////////////////////////////////////////////// 106 | /////////////////// Strategies for traversing isogeny trees //////////////////// 107 | //////////////////////////////////////////////////////////////////////////////// 108 | 109 | /* 110 | These are optimal strategies with respect to the cost ratios of 111 | scalar multiplication by 4 and 4-isogeny evaluation of 112 | pA/qA = 2*12.1/21.6, 113 | and of point tripling and 3-isogeny evaluation of 114 | pB/qB = 24.3/16.0. 115 | 116 | See the file optimalstrategies.txt for how they are computed. 117 | */ 118 | 119 | splits_Alice := [ 120 | 0, 1, 1, 2, 2, 2, 3, 4, 4, 4, 4, 5, 5, 6, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, 12, 11, 121 | 12, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 17, 17, 18, 18, 17, 21, 17, 18, 21, 122 | 20, 21, 21, 21, 21, 21, 22, 25, 25, 25, 26, 27, 28, 28, 29, 30, 31, 32, 32, 32, 123 | 32, 32, 32, 32, 33, 33, 33, 35, 36, 36, 33, 36, 35, 36, 36, 35, 36, 36, 37, 38, 124 | 38, 39, 40, 41, 42, 38, 39, 40, 41, 42, 40, 46, 42, 43, 46, 46, 46, 46, 48, 48, 125 | 48, 48, 49, 49, 48, 53, 54, 51, 52, 53, 54, 55, 56, 57, 58, 59, 59, 60, 62, 62, 126 | 63, 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65, 65, 66, 67, 65, 66, 67, 66, 127 | 69, 70, 66, 67, 66, 69, 70, 69, 70, 70, 71, 72, 71, 72, 72, 74, 74, 75, 72, 72, 128 | 74, 74, 75, 72, 72, 74, 75, 75, 72, 72, 74, 75, 75, 77, 77, 79, 80, 80, 82 ]; 129 | 130 | splits_Bob := [ 131 | 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 132 | 12, 12, 12, 12, 12, 12, 13, 14, 14, 15, 16, 16, 16, 16, 16, 17, 16, 16, 17, 19, 133 | 19, 20, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 24, 24, 25, 27, 27, 28, 28, 134 | 29, 28, 29, 28, 28, 28, 30, 28, 28, 28, 29, 30, 33, 33, 33, 33, 34, 35, 37, 37, 135 | 37, 37, 38, 38, 37, 38, 38, 38, 38, 38, 39, 43, 38, 38, 38, 38, 43, 40, 41, 42, 136 | 43, 48, 45, 46, 47, 47, 48, 49, 49, 49, 50, 51, 50, 49, 49, 49, 49, 51, 49, 53, 137 | 50, 51, 50, 51, 51, 51, 52, 55, 55, 55, 56, 56, 56, 56, 56, 58, 58, 61, 61, 61, 138 | 63, 63, 63, 64, 65, 65, 65, 65, 66, 66, 65, 65, 66, 66, 66, 66, 66, 66, 66, 71, 139 | 66, 73, 66, 66, 71, 66, 73, 66, 66, 71, 66, 73, 68, 68, 71, 71, 73, 73, 73, 75, 140 | 75, 78, 78, 78, 80, 80, 80, 81, 81, 82, 83, 84, 85, 86, 86, 86, 86, 86, 87, 86, 141 | 88, 86, 86, 86, 86, 88, 86, 88, 86, 86, 86, 88, 88, 86, 86, 86, 93, 90, 90, 92, 142 | 92, 92, 93, 93, 93, 93, 93, 97, 97, 97, 97, 97, 97 ]; 143 | 144 | MAX_Alice:=185; 145 | MAX_Bob:=239; 146 | 147 | 148 | 149 | //////////////////////////////////////////////////////////////////////////////// 150 | /////////////////// Hardcoded parameters for compression /////////////////////// 151 | //////////////////////////////////////////////////////////////////////////////// 152 | 153 | //sqrt17 needs to be hardcoded 154 | sqrt17:=Fp!1483538965666804829947069469909104059154140781635831028330640820709265337955392648044549164145551021689748496013107072560229759910814321769438913101160612783079068256317507381028230709001284064164607572283647211914550735845927; 155 | 156 | /* 157 | This is a list of Fp2 values (coming in pairs of 2 Fp values) that are used 158 | in the elligator part of generating the 3-torsion basis. It is unclear how many 159 | of them actually need to be included. This list contains 10 pairs and was 160 | sufficient for all our experiments so far. 161 | */ 162 | 163 | list:=[ 164 | 8363425868352131165866658961353958144229814713712711329709230125390317605935848299098482339530092345619831440153678625003433928904114370855920283455545930313711955524679122308520245936538779748714805262456570059204845333965902, 165 | 9956459367085870435555546382564235885987874659181799202034797768321806673733152737022002785154871840023608857325807886908849915362040917685619385066126107516323756576998955129190768972069975891327149121972107213339101588054645 166 | , 167 | 6144930856590964756685167380504563157961827953588137317347640432488186518896815315465645259926403525134570922304951070923678387107378958508658993589664191734009127665751748568914329020663777907486631313836162169963778632575103, 168 | 7536876520238641856265785405922723873301247545284897704150144618852913851906591160405377059136251837457871517965188606326279568717337728115592798767433428535635504650811536918778900787775462405867580948462033158740104179180513 169 | , 170 | 3649145355892493092601130737620646564999583523362465770985774431722028233578445993491705627684624200456652890439467133392302895875864155375755562758304867985155239445020913595763546387942667577715103537504039074108229067555697, 171 | 3406345077809626624600272723767218026428182662708211688376153432351090934279684420539224235627330222344077159960128811405339493801931902376194527271450923735653716663943201145164797704596188717358325611329602031995352769518723 172 | , 173 | 998267811748346322090246792849466614339797439606605388415575528085610645475302580158278377887610091561215574072604098957912985934804227515687363830062293591817437481569759107440934765403168660668480597527254704041283544182368, 174 | 6299254756541648319486140641915847200671962547147236779677914096206885693439062114609876986392650716657114941948886050368682406616380380110564244909143084100218367071201766960379602246502402243014532659396519266704951253335961 175 | , 176 | 9039574854744291884896812083509992341844657264001872494805847834541453045297442044919522100073770691895959024848481318376368203592288440935586584203801603161116465577829836497600335844932077945214317550880170024404079352766731, 177 | 5313177263581054007047062863601524437514238821450682648253781051833432617355548678396777617808675927783520514552249891395696261872305818368128608110476976569675374699486270420502578099523615806334306845322118768973088647192804 178 | , 179 | 2859481213219210500396709977967429237098625947545561341006056770829848169453286125614612704377152243303693651557660096209954612849929887786332341970767679754484316157978872890685237038734505830827748267342391094374943375131920, 180 | 1138411242251775238152745990579505410097343944723687139978725391891052467202849473111333480944440558901243384315784859847376479547976629563215374301794919876298590501570433821178061598483854203252967918244358816611958313201449 181 | , 182 | 5367316808588549611959672587456268587017968216903026189392184608936835643094356482410776062932320943211212840412279678795203609893969868585047714432744978742112094996625228530338019331542883407309507442131133935246348240313824, 183 | 8851386602506850670872308704570103155979681025085103860948386649455451954463035242071270463410742468353606794120283518792127595418513953496815497229638470396909450421146806115735096998841868535615936457279783490329250009902864 184 | , 185 | 7188443013090000550274508548166825175454104585924265018176320088548672687938897853151391910056849450233961696385929752588921372836392363086801317815771330941328643756283167206927316748142794608941899319827441473735709267505672, 186 | 903722033147219142615010295134657953920856503101452900469759971703938191957489992134730188791030728074838046354416419117573859136364260859565419493760310662535197081402282520962892909728318313535861418514530899913956220955925 187 | , 188 | 5579969524527689275567102658266073446837331226905933874007222354369088971520147421829210289266033980819107236272056980685624788284996978462833907271313354456842447471315232788660234394084377803028810298750081928633804592071001, 189 | 2027913496375781342709202092544270940376528068585729437528950167030737801559327747994534434959292574519503847293579752256122111048046788748770552918005553068750068867624960377134298401661200309492117956725466050020896876890116 190 | , 191 | 4624494142656684527622186866310605773524761035076660546060228364634691625190720012705349560205003073647077848112696936658132795530946054014061987955095884870409424853882937383611296712998217950743726984385808530127744032926811, 192 | 197817600549137552124791176633388479949283507786410028208787576903855465620499461221766306353468426335659142098186050318106570598412146855021358748541286458386045716472254226907403693901668635351880299813202412577271257317552 193 | , 194 | 2376687573372173187082388104863803606689914688520586156889427110064854329629004523727865483902066455992739113122842261239999958200657732612662289575390386558617143244720633294000738727837611339026692156860041836920186210943397, 195 | 571596863167553918317507613300316352758870696217405884151555650801634422565829007267152248774410256621643050466484687438463486660418686787090913150831887879949892011899211783999445332654429272361339208027245506732927558500153]; 196 | 197 | -------------------------------------------------------------------------------- /SIDH-Magma/TestSIDH-kex.mag: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Code for SIDH key exchange with optional public key compression 4 | // 5 | // (c) 2016 Microsoft Corporation. All rights reserved. 6 | // 7 | //////////////////////////////////////////////////////////////////////////////// 8 | // 9 | // TestSIDH-kex.mag 10 | // 11 | // Test file that demonstrates and tests SIDH key exchange without public key 12 | // compression (function kextest) and with public key compression (function 13 | // kextest_compress). 14 | // 15 | // For the 4 stages of SIDH key exchange (i.e. Alice's key generation, Bob's 16 | // key generation, Alice's shared secret and Bob's shared secret computation), 17 | // the isogeny computation/evaluation can be performed using two different 18 | // strategies: 19 | // (1) the slow but simple "scalar-multiplication-based" strategy. 20 | // (2) a fast way to traverse the isogeny tree using an optimal strategy. 21 | // 22 | // The function kextest can be run using the fast computations (2) only by 23 | // setting the input boolean simple:=false. If one sets simple:=true, then the 24 | // computation is done using the simple algorithm (1) and the fast algorithm (2) 25 | // and the results from both are asserted to be equal. 26 | // 27 | //////////////////////////////////////////////////////////////////////////////// 28 | // 29 | // References: 30 | // 31 | // Efficient algorithms for supersingular isogeny Diffie-Hellman 32 | // Craig Costello, Patrick Longa, Michael Naehrig, CRYPTO 2016. 33 | // 34 | // Efficient compression of SIDH public keys 35 | // Craig Costello, David Jao, Patrick Longa, Michael Naehrig, Joost Renes, 36 | // David Urbanik, EUROCRYPT 2017. 37 | // 38 | //////////////////////////////////////////////////////////////////////////////// 39 | 40 | clear; 41 | load "SIDH-parameters.mag"; 42 | load "SIDH-field-arithmetic.mag"; 43 | load "SIDH-curve-and-isogeny-arithmetic.mag"; 44 | load "SIDH.mag"; 45 | load "SIDH-pairings.mag"; 46 | load "SIDH-pohlig-hellman.mag"; 47 | load "SIDH-compression.mag"; 48 | 49 | //////////////////////////////////////////////////////////////////////////////// 50 | ///////////////////////// Key exchange testing ///////////////////////////////// 51 | //////////////////////////////////////////////////////////////////////////////// 52 | 53 | kextest := procedure(n, simple) 54 | for j in [1..n] do 55 | "\n"; 56 | j; 57 | "===================================================================="; 58 | "Generating secret keys..."; 59 | SK_Alice:=Random(1, (oA div lA)-1)*lA; // Random even number between 1 and oA-1 60 | SK_Bob:=Random(1, (oB div lB)-1)*lB; // Random multiple of lB between 1 and oB-1 61 | "Done with secret keys."; 62 | "===================================================================="; 63 | 64 | "Generating Alice's public key... (fast algorithm)."; 65 | PK_Alice:=keygen_Alice_fast(SK_Alice,params_Alice,splits_Alice,MAX_Alice); 66 | if simple then 67 | "Generating Alice's public key... (simple algorithm)."; 68 | PK_Alice_simple:=keygen_Alice_simple(SK_Alice,params_Alice); 69 | equal := PK_Alice eq PK_Alice_simple; 70 | "Result from simple key gen equal to result from fast key gen?", equal; 71 | assert equal; 72 | end if; 73 | "\nDone with Alice's public key."; 74 | "===================================================================="; 75 | 76 | "Generating Bob's public key... (fast algorithm)."; 77 | PK_Bob:=keygen_Bob_fast(SK_Bob,params_Bob,splits_Bob,MAX_Bob); 78 | if simple then 79 | "Generating Bob's public key... (simple algorithm)."; 80 | PK_Bob_simple:=keygen_Bob_simple(SK_Bob,params_Bob); 81 | equal := PK_Bob eq PK_Bob_simple; 82 | "Result from simple key gen equal to result from fast key gen?", equal; 83 | assert equal; 84 | end if; 85 | "\nDone with Bob's public key.\n"; 86 | 87 | "Generating shared secret for Alice... (fast algorithm)."; 88 | secret_Alice:=shared_secret_Alice_fast(SK_Alice,PK_Bob,params_Alice,splits_Alice,MAX_Alice); 89 | if simple then 90 | "Generating shared secret for Alice... (simple algorithm)."; 91 | secret_Alice_simple:=shared_secret_Alice_simple(SK_Alice,PK_Bob); 92 | equal := secret_Alice eq secret_Alice_simple; 93 | "Results from simple and fast algorithms equal?", equal; 94 | assert equal; 95 | end if; 96 | "\nDone with Alice's shared secret computation."; 97 | "===================================================================="; 98 | 99 | "Generating shared secret for Bob... (fast algorithm)."; 100 | secret_Bob:=shared_secret_Bob_fast(SK_Bob,PK_Alice,params_Bob,splits_Bob,MAX_Bob); 101 | if simple then 102 | "Generating shared secret for Bob... (simple algorithm)."; 103 | secret_Bob_simple:=shared_secret_Bob_simple(SK_Bob,PK_Alice); 104 | equal := secret_Bob eq secret_Bob_simple; 105 | "Results from simple and fast algorithms equal?", equal; 106 | assert equal; 107 | end if; 108 | "\nDone with Bob's shared secret computation."; 109 | 110 | "===================================================================="; 111 | "Shared secrets are equal?", secret_Alice eq secret_Bob; 112 | assert secret_Alice eq secret_Bob; 113 | "====================================================================\n"; 114 | end for; 115 | end procedure; 116 | 117 | //////////////////////////////////////////////////////////////////////////////// 118 | ///////////////// Key exchange testing with compression //////////////////////// 119 | //////////////////////////////////////////////////////////////////////////////// 120 | 121 | kextest_compress := procedure(n) 122 | for j in [1..n] do 123 | "\n"; 124 | j; 125 | "===================================================================="; 126 | "Generating secret keys..."; 127 | SK_Alice:=Random(1, (oA div lA)-1)*lA; // Random even number between 1 and oA-1 128 | SK_Bob:=Random(1, (oB div lB)-1)*lB; // Random multiple of lB between 1 and oB-1 129 | "Done with secret keys."; 130 | "===================================================================="; 131 | 132 | "Generating Alice's public key... (fast algorithm)."; 133 | PK_Alice:=keygen_Alice_fast(SK_Alice,params_Alice,splits_Alice,MAX_Alice); 134 | "Compressing Alice's public key."; 135 | PK_Alice_comp_0, PK_Alice_comp_1 := compress_3_torsion(PK_Alice); 136 | 137 | "\nDone with Alice's public key."; 138 | "===================================================================="; 139 | 140 | "Generating Bob's public key... (fast algorithm)."; 141 | PK_Bob:=keygen_Bob_fast(SK_Bob,params_Bob,splits_Bob,MAX_Bob); 142 | "Compressing Bob's public key."; 143 | PK_Bob_comp_0, PK_Bob_comp_1 := compress_2_torsion(PK_Bob); 144 | 145 | "\nDone with Bob's public key.\n"; 146 | 147 | "Decompressing Bob's public key and"; 148 | "generating shared secret for Alice... (fast algorithm)."; 149 | secret_Alice:=shared_secret_Alice_decompression(SK_Alice,PK_Bob_comp_0,PK_Bob_comp_1,params_Alice,splits_Alice,MAX_Alice); 150 | 151 | "Done with Alice's shared secret computation."; 152 | "===================================================================="; 153 | 154 | "Decompressing Alice's public key and"; 155 | "generating shared secret for Bob... (fast algorithm)."; 156 | secret_Bob:=shared_secret_Bob_decompression(SK_Bob,PK_Alice_comp_0,PK_Alice_comp_1,params_Bob,splits_Bob,MAX_Bob); 157 | // secret_Bob:=shared_secret_Bob_fast(SK_Bob,PK_Alice,params_Bob,splits_Bob,MAX_Bob); 158 | "\nDone with Bob's shared secret computation."; 159 | "===================================================================="; 160 | "Shared secrets are equal?", secret_Alice eq secret_Bob; 161 | assert secret_Alice eq secret_Bob; 162 | "====================================================================\n"; 163 | end for; 164 | end procedure; 165 | 166 | 167 | 168 | simple := false; 169 | "\n\n\n"; 170 | "===================================================================="; 171 | "===================================================================="; 172 | "=== Testing SIDH ephemeral key exchange ============================"; 173 | if simple then 174 | "=== Including simple, but slow isogeny tree traversal =============="; 175 | else 176 | "=== Only fast isogeny tree traversal via optimal strategy =========="; 177 | end if; 178 | "===================================================================="; 179 | kextest(10, simple); 180 | 181 | "\n\n\n"; 182 | "===================================================================="; 183 | "===================================================================="; 184 | "=== Testing SIDH ephemeral key exchange with PK compression ========"; 185 | "=== Only fast isogeny tree traversal via optimal strategy =========="; 186 | "===================================================================="; 187 | kextest_compress(10); 188 | 189 | -------------------------------------------------------------------------------- /SIDH-Magma/optimalstrategies.mag: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Code to compute optimal strategies for isogeny tree traversal 4 | // 5 | // Based on the relative cost ratios of scalar multiplications, 6 | // optimal strategies are computed by a dynamic programming approach 7 | // as described in DeFeo, Jao, Plut: Towards quantum-resistant 8 | // cryptosystems from supersingular elliptic curve isogenies, 9 | // J. Math. Crypt., 8(3):209-247, 2014. 10 | // 11 | // (c) 2016 Microsoft Corporation. All rights reserved. 12 | // 13 | //////////////////////////////////////////////////////////////////////////////// 14 | // 15 | // Reference: 16 | // 17 | // Efficient algorithms for supersingular isogeny Diffie-Hellman 18 | // Craig Costello, Patrick Longa, Michael Naehrig, CRYPTO 2016. 19 | // 20 | //////////////////////////////////////////////////////////////////////////////// 21 | 22 | clear; 23 | RR := RealField(10); 24 | Z := Integers(); 25 | ZPQ := PolynomialRing(Z,2); 26 | 27 | //////////////////////////////////////////////////////////////////////////////// 28 | 29 | nA := 185; // Computing 4^nA-isogenies 30 | //pA := RR!(2*12.9); // Linux cost for 2 doublings 31 | //qA := RR!(22.8); // Linux cost for 4-isogeny evaluation 32 | // New op counts 2016-06-15 33 | pA := RR!(2*12.1); // Linux cost for 2 doublings 34 | qA := RR!(21.6); // Linux cost for 4-isogeny evaluation 35 | 36 | nB := 239; // Computing 3^nB-isogenies 37 | pB := RR!24.3; // Linux cost for tripling 38 | qB := RR!16.0; // Linux cost for 3-isogeny evaluation 39 | 40 | //////////////////////////////////////////////////////////////////////////////// 41 | 42 | NextCpq := function(p,q,Cpq,PQcounts) 43 | /* 44 | Computes the cost of an optimal strategy for traversing a tree on n leaves 45 | together with the operation counts in terms of scalar multiplications and 46 | isogeny evaluation, given this information for trees on 1 up to n-1 leaves. 47 | 48 | Input: 49 | - The cost p for a scalar multiplication by \ell, 50 | - the cost q for the evaluation of an \ell-isogeny, 51 | - a list Cpq of length n-1 that contains the cost of an optimal strategy 52 | for traversal of a tree with i leaves in Cpq[i], and 53 | - a list PQcounts of pairs such that the i-th pair contains the number 54 | PQcounts[i][1] of \ell-scalar multiplications and the number 55 | PQcounts[i][2] of \ell-isogeny evaluations in order to traverse a tree 56 | on i leaves using the optimal strategy with cost Cpq[i]. 57 | 58 | Output: 59 | - The cost newCpq of an optimal strategy for traversing a tree on n leaves, 60 | - the corresponding operation counts newPQcount, and 61 | - the splitting newSpq of the n-node strategy into two optimal 62 | sub-strategies. 63 | */ 64 | 65 | pgtq := p gt q; 66 | n := #Cpq + 1; // new index = number of leaves in new strategy 67 | 68 | // Compute all possibilities for the cost of a strategy on n leaves by going 69 | // through all possible splits into two optimal sub-strategies from the 70 | // (n-1) strategies provided in PQcounts. 71 | // Cost = cost of subtree with i leaves + cost of subtree with (n-i) leaves 72 | // + cost of (n-i) scalar mults to get to i-subtree root 73 | // + cost of i isogeny evaluations to get to (n-i) subtree root 74 | newCpqs := [(Cpq[i] + Cpq[n-i] + (n-i)*p + i*q) : i in [1..(n-1)]]; 75 | 76 | newCpq := newCpqs[1]; 77 | m := 1; 78 | // Choose the cheapest strategy. 79 | for i in [2..(n-1)] do 80 | tmpCpq := newCpqs[i]; 81 | if newCpq ge tmpCpq then 82 | // including equality in the condition prefers larger number of isogenies 83 | newCpq := tmpCpq; 84 | m := i; 85 | end if; 86 | end for; 87 | // chosen strategy (m-leave sub-tree on the left, (n-m)-subtree on the right) 88 | newSpq := [m,n-m]; 89 | // updating operation counts 90 | newPQcount := [PQcounts[m][1] + PQcounts[n-m][1] + (n-m), 91 | PQcounts[m][2] + PQcounts[n-m][2] + m]; 92 | 93 | return newCpq, newSpq, newPQcount; 94 | end function; 95 | 96 | //////////////////////////////////////////////////////////////////////////////// 97 | 98 | GetStrategies := function (n,p,q) 99 | /* 100 | Computes a list of optimal strategies for traversing trees with number of 101 | leaves between 1 and n. 102 | 103 | Input: 104 | - The number n of leaves on the tree, 105 | - the cost p for scalar multiplication by \ell, and 106 | - the cost q for \ell-isogeny evaluation. 107 | 108 | Output: 109 | - A list Spq of length n containing the splits into two subtrees for all 110 | optimal strategies on trees with 1<=i<=n leaves. 111 | - A list PQcounts of length n containing operation counts for the above 112 | strategies. 113 | */ 114 | 115 | assert n ge 3; 116 | // Cost for sub-trees with one leaf (=0) and two leaves (p+q) 117 | Cpq := [0, p+q]; 118 | // Splits for these sub-trees 119 | Spq := [[0,0], [1,1]]; 120 | // Operation counts for these sub-trees 121 | PQcounts := [[0,0], [1,1]]; 122 | 123 | // Compute in sequence all optimal strategies for trees with 3<=i<=n leaves. 124 | repeat 125 | newCpq, newSpq, newPQcount := NextCpq(p,q,Cpq,PQcounts); 126 | Append(~Cpq, newCpq); 127 | Append(~Spq, newSpq); 128 | Append(~PQcounts, newPQcount); 129 | until #Cpq eq n; 130 | 131 | return Spq, PQcounts; 132 | end function; 133 | 134 | //////////////////////////////////////////////////////////////////////////////// 135 | 136 | function GetSplits(n,Spq) 137 | /* 138 | Assembles a list of splits by taking the number of leaves in the respective 139 | right subtrees which is equal to the number of scalar multiplications to 140 | reach the root of the next sub-strategy. 141 | 142 | Input: 143 | - The number n of leaves on the tree and 144 | - the list of splits into two sub-trees as above. 145 | 146 | Output: 147 | - A list of length n describing the splits by giving the number of scalar 148 | multiplications by \ell to the root of the next subtree. 149 | */ 150 | 151 | return [Spq[i][2]: i in [1..n]]; 152 | end function; 153 | 154 | //////////////////////////////////////////////////////////////////////////////// 155 | // 156 | // Computing optimal strategies 157 | // 158 | //////////////////////////////////////////////////////////////////////////////// 159 | 160 | ""; 161 | SpqA, PQcountsA := GetStrategies(nA,pA,qA); 162 | "Top Strategy for A:", SpqA[nA]; 163 | PQcountsA[nA][1], "MUL-BY-4 and", PQcountsA[nA][2], "4-ISO-EVAL == ", 164 | PQcountsA[nA][1]*pA + PQcountsA[nA][2]*qA, "total units"; 165 | "Splits for A:", GetSplits(nA,SpqA); 166 | 167 | 168 | ""; 169 | SpqB, PQcountsB := GetStrategies(nB,pB,qB); 170 | "Top Strategy for B:", SpqB[nB]; 171 | PQcountsB[nB][1], "MUL-BY-3 and", PQcountsB[nB][2], "3-ISO-EVAL == ", 172 | PQcountsB[nB][1]*pB + PQcountsB[nB][2]*qB, "total units"; 173 | "Splits for B:", GetSplits(nB,SpqB); 174 | ""; 175 | 176 | //////////////////////////////////////////////////////////////////////////////// 177 | 178 | -------------------------------------------------------------------------------- /SIDH.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************************** 2 | * SIDH: an efficient supersingular isogeny-based cryptography library for ephemeral 3 | * Diffie-Hellman key exchange. 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * 7 | * 8 | * Abstract: supersingular elliptic curve isogeny parameters 9 | * 10 | *********************************************************************************************/ 11 | 12 | #include "SIDH_internal.h" 13 | 14 | 15 | // Encoding of field elements, elements over Z_order, elements over GF(p^2) and elliptic curve points: 16 | // -------------------------------------------------------------------------------------------------- 17 | // Elements over GF(p) and Z_order are encoded with the least significant octet (and digit) located 18 | // at the leftmost position (i.e., little endian format). 19 | // Elements (a+b*i) over GF(p^2), where a and b are defined over GF(p), are encoded as {b, a}, with b 20 | // in the least significant position. 21 | // Elliptic curve points P = (x,y) are encoded as {x, y}, with x in the least significant position. 22 | 23 | // 24 | // Curve isogeny system "SIDHp751". Base curve: Montgomery curve By^2 = Cx^3 + Ax^2 + Cx defined over GF(p751^2), where A=0, B=1 and C=1 25 | // 26 | 27 | CurveIsogenyStaticData CurveIsogeny_SIDHp751 = { 28 | "SIDHp751", 768, 384, // Curve isogeny system ID, smallest multiple of 32 larger than the prime bitlength and smallest multiple of 32 larger than the order bitlength 29 | 751, // Bitlength of the prime 30 | // Prime p751 = 2^372*3^239-1 31 | { 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xEEAFFFFFFFFFFFFF, 32 | 0xE3EC968549F878A8, 0xDA959B1A13F7CC76, 0x084E9867D6EBE876, 0x8562B5045CB25748, 0x0E12909F97BADC66, 0x00006FE5D541F71C }, 33 | // Base curve parameter "A" 34 | { 0 }, 35 | // Base curve parameter "C" 36 | { 1 }, 37 | // Order bitlength for Alice 38 | 372, 39 | // Order of Alice's subgroup 40 | { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0010000000000000 }, 41 | // Order bitlength for Bob 42 | 379, 43 | // Power of Bob's subgroup order 44 | 239, 45 | // Order of Bob's subgroup 46 | { 0xC968549F878A8EEB, 0x59B1A13F7CC76E3E, 0xE9867D6EBE876DA9, 0x2B5045CB25748084, 0x2909F97BADC66856, 0x06FE5D541F71C0E1 }, 47 | // Alice's generator PA = (XPA,YPA), where XPA and YPA are defined over GF(p751) 48 | { 0x4B0346F5CCE233E9, 0x632646086CE3ACD5, 0x5661D14AB7347693, 0xA58A20449AF1F133, 0xB9AC2F40C56D6FA4, 0x8E561E008FA0E3F3, 49 | 0x6CAE096D5DB822C9, 0x83FDB7A4AD3E83E8, 0xB1317AD904386217, 0x3FA23F89F6BE06D2, 0x429C8D36FF46BCC9, 0x00003E82027A38E9, 50 | 0x12E0D620BFB341D5, 0x0F8EEA7370893430, 0x5A99EBEC3B5B8B00, 0x236C7FAC9E69F7FD, 0x0F147EF3BD0CFEC5, 0x8ED5950D80325A8D, 51 | 0x1E911F50BF3F721A, 0x163A7421DFA8378D, 0xC331B043DA010E6A, 0x5E15915A755883B7, 0xB6236F5F598D56EB, 0x00003BBF8DCD4E7E }, 52 | // Bob's generator PB = (XPB,YPB), where XPB and YPB are defined over GF(p751) 53 | { 0x76ED2325DCC93103, 0xD9E1DF566C1D26D3, 0x76AECB94B919AEED, 0xD3785AAAA4D646C5, 0xCB610E30288A7770, 0x9BD3778659023B9E, 54 | 0xD5E69CF26DF23742, 0xA3AD8E17B9F9238C, 0xE145FE2D525160E0, 0xF8D5BCE859ED725D, 0x960A01AB8FF409A2, 0x00002F1D80EF06EF, 55 | 0x91479226A0687894, 0xBBC6BAF5F6BA40BB, 0x15B529122CFE3CA6, 0x7D12754F00E898A3, 0x76EBA0C8419745E9, 0x0A94F06CDFB3EADE, 56 | 0x399A6EDB2EEB2F9B, 0xE302C5129C049EEB, 0xC35892123951D4B6, 0x15445287ED1CC55D, 0x1ACAF351F09AB55A, 0x00000127A46D082A }, 57 | // BigMont's curve parameter A24 = (A+2)/4 58 | 156113, 59 | // BigMont's order, where BigMont is defined by y^2=x^3+A*x^2+x 60 | { 0xA59B73D250E58055, 0xCB063593D0BE10E1, 0xF6515CCB5D076CBB, 0x66880747EDDF5E20, 0xBA515248A6BFD4AB, 0x3B8EF00DDDDC789D, 61 | 0xB8FB25A1527E1E2A, 0xB6A566C684FDF31D, 0x0213A619F5BAFA1D, 0xA158AD41172C95D2, 0x0384A427E5EEB719, 0x00001BF975507DC7 }, 62 | // Montgomery constant Montgomery_R2 = (2^768)^2 mod p751 63 | { 0x233046449DAD4058, 0xDB010161A696452A, 0x5E36941472E3FD8E, 0xF40BFE2082A2E706, 0x4932CCA8904F8751 ,0x1F735F1F1EE7FC81, 64 | 0xA24F4D80C1048E18, 0xB56C383CCDB607C5, 0x441DD47B735F9C90, 0x5673ED2C6A6AC82A, 0x06C905261132294B, 0x000041AD830F1F35 }, 65 | // Montgomery constant -p751^-1 mod 2^768 66 | { 0x0000000000000001, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0xEEB0000000000000, 67 | 0xE3EC968549F878A8, 0xDA959B1A13F7CC76, 0x084E9867D6EBE876, 0x8562B5045CB25748, 0x0E12909F97BADC66, 0x258C28E5D541F71C }, 68 | // Value one in Montgomery representation 69 | { 0x00000000000249ad, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x8310000000000000, 70 | 0x5527b1e4375c6c66, 0x697797bf3f4f24d0, 0xc89db7b2ac5c4e2e, 0x4ca4b439d2076956, 0x10f7926c7512c7e9, 0x00002d5b24bce5e2 } 71 | }; 72 | 73 | 74 | // Fixed parameters for isogeny tree computation 75 | 76 | const unsigned int splits_Alice[MAX_Alice] = { 77 | 0, 1, 1, 2, 2, 2, 3, 4, 4, 4, 4, 5, 5, 6, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, 12, 78 | 11, 12, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 17, 17, 18, 18, 17, 21, 17, 79 | 18, 21, 20, 21, 21, 21, 21, 21, 22, 25, 25, 25, 26, 27, 28, 28, 29, 30, 31, 80 | 32, 32, 32, 32, 32, 32, 32, 33, 33, 33, 35, 36, 36, 33, 36, 35, 36, 36, 35, 81 | 36, 36, 37, 38, 38, 39, 40, 41, 42, 38, 39, 40, 41, 42, 40, 46, 42, 43, 46, 82 | 46, 46, 46, 48, 48, 48, 48, 49, 49, 48, 53, 54, 51, 52, 53, 54, 55, 56, 57, 83 | 58, 59, 59, 60, 62, 62, 63, 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65, 84 | 65, 66, 67, 65, 66, 67, 66, 69, 70, 66, 67, 66, 69, 70, 69, 70, 70, 71, 72, 85 | 71, 72, 72, 74, 74, 75, 72, 72, 74, 74, 75, 72, 72, 74, 75, 75, 72, 72, 74, 86 | 75, 75, 77, 77, 79, 80, 80, 82 }; 87 | 88 | const unsigned int splits_Bob[MAX_Bob] = { 89 | 0, 1, 1, 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 90 | 10, 12, 12, 12, 12, 12, 12, 13, 14, 14, 15, 16, 16, 16, 16, 16, 17, 16, 16, 91 | 17, 19, 19, 20, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 24, 24, 25, 27, 92 | 27, 28, 28, 29, 28, 29, 28, 28, 28, 30, 28, 28, 28, 29, 30, 33, 33, 33, 33, 93 | 34, 35, 37, 37, 37, 37, 38, 38, 37, 38, 38, 38, 38, 38, 39, 43, 38, 38, 38, 94 | 38, 43, 40, 41, 42, 43, 48, 45, 46, 47, 47, 48, 49, 49, 49, 50, 51, 50, 49, 95 | 49, 49, 49, 51, 49, 53, 50, 51, 50, 51, 51, 51, 52, 55, 55, 55, 56, 56, 56, 96 | 56, 56, 58, 58, 61, 61, 61, 63, 63, 63, 64, 65, 65, 65, 65, 66, 66, 65, 65, 97 | 66, 66, 66, 66, 66, 66, 66, 71, 66, 73, 66, 66, 71, 66, 73, 66, 66, 71, 66, 98 | 73, 68, 68, 71, 71, 73, 73, 73, 75, 75, 78, 78, 78, 80, 80, 80, 81, 81, 82, 99 | 83, 84, 85, 86, 86, 86, 86, 86, 87, 86, 88, 86, 86, 86, 86, 88, 86, 88, 86, 100 | 86, 86, 88, 88, 86, 86, 86, 93, 90, 90, 92, 92, 92, 93, 93, 93, 93, 93, 97, 101 | 97, 97, 97, 97, 97 }; 102 | 103 | 104 | const uint64_t LIST[22][NWORDS64_FIELD] = { 105 | { 0xC4EC4EC4EC4EDB72, 0xEC4EC4EC4EC4EC4E, 0x4EC4EC4EC4EC4EC4, 0xC4EC4EC4EC4EC4EC, 0xEC4EC4EC4EC4EC4E, 0x7464EC4EC4EC4EC4, 106 | 0x40E503E18E2D8BE1, 0x4C633882E467773F, 0x998CB725CB703B25, 0x51F8F01043ABC448, 0x70A53813C7A0B43A, 0x00006D56A7157672 }, 107 | { 0x276276276275B6C1, 0x6276276276276276, 0x7627627627627627, 0x2762762762762762, 0x6276276276276276, 0x6377627627627627, 108 | 0x2F25DD32AAF69FE5, 0xC6FBECF3EDD1AA16, 0x29C9664A396A6297, 0x0110D8C47D20DEFD, 0x1322BABB1082C8DD, 0x00000CCBE6DE8350 }, 109 | { 0x093B97EBDB11A7FE, 0x5093B97EBDB11A05, 0x05093B97EBDB11A0, 0xA05093B97EBDB11A, 0x1A05093B97EBDB11, 0x6F005093B97EBDB1, 110 | 0x7204A6634D6196D9, 0x1D6428F62F917BE5, 0x037CE7F8E9689A28, 0x913EC08959C36290, 0x03D1055241F89FDD, 0x000066963FEC58EB }, 111 | { 0x98C2BA559CF4F604, 0xA98C2BA559CF516A, 0x6A98C2BA559CF516, 0x16A98C2BA559CF51, 0x516A98C2BA559CF5, 0x1A56A98C2BA559CF, 112 | 0xDD14E231C3FF5DDC, 0x5AB78BDF0FB0C987, 0x168ED3F1672906EC, 0xAEF17C4BE3A425E0, 0x6F1B34309268385F, 0x0000438BAFFC5E17 }, 113 | { 0xA37CA5409E30BE12, 0x20D6AFD873D163ED, 0xCA5409E30BA70497, 0x6AFD873D163EDA37, 0x409E30BA7049720D, 0x7013D163EDA37CA5, 114 | 0x196C325CFB1D98A8, 0x2A83CC98457F6BB1, 0x157AA4649C505D94, 0x556B2CFA3ED1E977, 0x9C8FB301D3BE27CD, 0x0000659B5D688370 }, 115 | { 0x437158A103E247EB, 0x23A9D7BF076A48BD, 0x158A103E256DD0AF, 0x9D7BF076A48BD437, 0xA103E256DD0AF23A, 0xD3776A48BD437158, 116 | 0xD4F7B332C1F74531, 0x6A60D92C4C627CD9, 0xC8009067FA1223C2, 0x195578D349C85ABC, 0x24DCFD2C3CE56026, 0x00001170D9C4A49E }, 117 | { 0xBBC96234E708BFC3, 0xEE2CE77DBE4CE5A9, 0x21EF6EA93828AD37, 0x66C6ED51865018AE, 0xCB18F74253FB3379, 0x6231B31A5644369D, 118 | 0xF1831316FD5F9AD5, 0xD64412327D9D93D5, 0x2D9659AFA40085D6, 0xB872D3713E1F01AD, 0x96B929E85C90E590, 0x00002A0A122F3E1B }, 119 | { 0x751DE109156C74F6, 0xC86993912AE79AFE, 0x96234E708BDAC04C, 0xCE77DBE4CE5A9BBC, 0xF6EA93828AD37EE2, 0x51B51865018AE21E, 120 | 0x57F8534430BDF5AF, 0xA5BA9F3225E0FA02, 0x05DBA7E2AB49759E, 0xE4706D1BDBA54763, 0xC5316BE14AF60ADD, 0x00002007A8A7A392 }, 121 | { 0x2DEC0AC86E1972FF, 0xD121D09CA2E105D1, 0x258D13A0778EDFB2, 0x25140153000C1B6E, 0xA06B73718D440E30, 0xA46BFDEB49118BC0, 122 | 0x11C799EE82EF46CF, 0xF094D7258BE44445, 0x6B087550522BC899, 0xD4380D82ADEEA2D3, 0x2AFFEB03C6970E0B, 0x00004FF89FD0E867 }, 123 | { 0xF48E11E080A36CD8, 0x75AA967CF316BF89, 0xED69E3E85A6CDEA8, 0x228638171449F794, 0xD4107549BB0BC6AE, 0xB7888349726731CC, 124 | 0x0589577AC89D03A2, 0x79218D005004DCD2, 0xA69CB3C82106FDB8, 0xE54D908CD9B31ED9, 0x2BB46423F8B44F5D, 0x0000158FC37F2F78 }, 125 | { 0xA2B8F30D2D8B2266, 0x37AE9DA734F3D4D4, 0x4BC3AC46B1EE2D59, 0xA541D219D9E660D2, 0xFD629383B8C12367, 0x0E789576DA7C1E23, 126 | 0x2321F1135780B208, 0x059EED9A8BB7694E, 0x3EAC20CCA7C7B679, 0xADED37DC1395BAAB, 0xD701BA16F6CD4328, 0x0000250A355A8E3D }, 127 | { 0x8D08D7B596C87C8E, 0xFC2B5A576AB81FA7, 0x4ED68A1C251D1EAD, 0xA6618E345258FA06, 0xB532F4F490BD3165, 0x0987A5FDBAA88699, 128 | 0x77E908F4AE484907, 0xC85226731C871CED, 0x6F3E5A699F216EC7, 0x70E42ADFCCD68C99, 0x2277864817AA0CAD, 0x000037F521DA6BAC }, 129 | { 0xDB72B65CA8D1D274, 0x286A73457D063FD5, 0x7355642D132BA567, 0x2A970D9461C0DC41, 0x93D2A07ED36F3BCC, 0xFD59A18D2D03447E, 130 | 0xBC047FB33098286A, 0x153E65AE22E4D2F0, 0xBC3F628AF44DDCEB, 0xCF8C49463A2BEC5D, 0x64D31CBF9A0FAE5B, 0x00000E88DF789F48 }, 131 | { 0x7E0E3CF3F602CC03, 0x240AE231C56EB636, 0x1630875FADB3CA47, 0x3FDF66239B9021FE, 0x4FA6BEA94AAE8287, 0x20BD32942BAEF1D9, 132 | 0x3DBE52BE754CD223, 0xD46D6B986A4C461E, 0x31772CCF6AB0EC49, 0x0362808B445792BE, 0xA57068B23D5D4F04, 0x0000233188CFA1F9 }, 133 | { 0x5CFEB9EE80FF8802, 0x641C991F35243E77, 0x109BF7F4D15352D9, 0xF57027C40F2AEC39, 0x78834C224A9E8F4D, 0x3B53C38C5DDA4903, 134 | 0x2472CAD0E4A1DD20, 0x91121637EFEFBFEB, 0x555DDF1E4E875433, 0xD185E0CEBC9A6BF8, 0x247E7766FEA9846A, 0x00004E24131398C0 }, 135 | { 0xAE911D5E41FDE1D5, 0x09FD291EAE9A7528, 0xD94DB04CE76D674F, 0xF269A050B317A36A, 0x1010C2464C5B488A, 0x165E22C0571F72CE, 136 | 0xB649686CDD7FAA40, 0xC65F833CCBC8E854, 0xA1DC607E92B4EC01, 0x6A9F6EA6C5D5598C, 0xB73B45E033D20693, 0x0000126974812437 }, 137 | { 0x7EF889C1569E078D, 0x8B4790D31AFC6D2F, 0x24BAD80FCF2607D2, 0x13C099586804EDD0, 0x0B219830D09F67F8, 0xFEEBDD0A795A4E0D, 138 | 0x2C86D567D8A5A5C6, 0x29EFDB5516CD064B, 0xAFB0A05F0230B35C, 0x73FCFA65EC7C5CB4, 0x245E08DC310C14E1, 0x00001778AC2903DF }, 139 | { 0xF2BF1FF8427C7315, 0x591042D093B90137, 0x23EF8D48782832C9, 0x8DFB39E92296E3D6, 0x0C39FF556BEBDD42, 0x369F6980A4270C5D, 140 | 0x901F9AD6FCBAA761, 0x0E8E81D435F5FC7F, 0x9A795B9A8409D3D3, 0xD29FB9AE4384290F, 0x3B58F53DD7270C90, 0x00001E27D50D0631 }, 141 | { 0x838A7C8B0026C13C, 0xD38CAB350DC1F6BD, 0x426C57FE2436E928, 0xB81B289B8792A253, 0xF8EDB68037D3FB8E, 0x677EE0B4C50C01CD, 142 | 0xF43DCE6FED67139A, 0xF87EFEBF43D77877, 0x3EEA0E8543763A8A, 0x26E5A18357A35379, 0x55867648B9EA7D35, 0x000069DEC7A3C7DA }, 143 | { 0x91CCFD3901F3F3FE, 0x2053992393125D73, 0x2129B3A10D7FF7C0, 0x74C64B3E68087A32, 0xEE46C5739B026DF9, 0x53E7B33F97EC0300, 144 | 0x14672E57801EC044, 0x18610440AA870975, 0xB6B9D9E0E0097AE6, 0x37AD3B922ED0F367, 0xA737A55936D5A8B8, 0x00005A30AF4F51DA }, 145 | { 0xC925488939591E52, 0x8F87728BF0ED44E9, 0xF987EF64E4365147, 0x9338B89963265410, 0x340DA16F22024645, 0x5D295419E474BDC1, 146 | 0xBA0C2E509FC0510B, 0x957E35D641D5DDB5, 0x922F901AA4A236D8, 0xCBFA24C0F7E172E3, 0xB05A32F88CB5B9DC, 0x00001DC7A766A676 }, 147 | { 0x6128F8C2B276D2A1, 0x857530A2A633CE28, 0xEB624F41494C5D1E, 0x3FA62AE33B92CCA8, 0x11BCABB4CC4FBE22, 0x91EA14743FDBAC70, 148 | 0x9876F7DF900DC277, 0x375FD25E09091CBA, 0x580F3084B099A111, 0x58E9B3FB623FB297, 0x957732F791F6C337, 0x00000B070F784B99 } }; -------------------------------------------------------------------------------- /SIDH_api.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************************** 2 | * SIDH: an efficient supersingular isogeny-based cryptography library for ephemeral 3 | * Diffie-Hellman key exchange. 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * 7 | * 8 | * Abstract: API header file 9 | * 10 | *********************************************************************************************/ 11 | 12 | #ifndef __SIDH_API_H__ 13 | #define __SIDH_API_H__ 14 | 15 | 16 | // For C++ 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | 22 | #include "SIDH.h" 23 | 24 | 25 | /*********************** Ephemeral key exchange API ***********************/ 26 | 27 | // SECURITY NOTE: SIDH supports ephemeral Diffie-Hellman key exchange. It is NOT secure to use it with static keys. 28 | // See "On the Security of Supersingular Isogeny Cryptosystems", S.D. Galbraith, C. Petit, B. Shani and Y.B. Ti, in ASIACRYPT 2016, 2016. 29 | // Extended version available at: http://eprint.iacr.org/2016/859 30 | 31 | // Alice's ephemeral key-pair generation 32 | // It produces a private key pPrivateKeyA and computes the public key pPublicKeyA. 33 | // The private key is an even integer in the range [2, oA-2], where oA = 2^372 (i.e., 372 bits in total). 34 | // The public key consists of 3 elements in GF(p751^2), i.e., 564 bytes. 35 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize(). 36 | CRYPTO_STATUS EphemeralKeyGeneration_A(unsigned char* pPrivateKeyA, unsigned char* pPublicKeyA, PCurveIsogenyStruct CurveIsogeny); 37 | 38 | // Bob's ephemeral key-pair generation 39 | // It produces a private key pPrivateKeyB and computes the public key pPublicKeyB. 40 | // The private key is an integer in the range [1, oB-1], where oA = 3^239 (i.e., 379 bits in total). 41 | // The public key consists of 3 elements in GF(p751^2), i.e., 564 bytes. 42 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize(). 43 | CRYPTO_STATUS EphemeralKeyGeneration_B(unsigned char* pPrivateKeyB, unsigned char* pPublicKeyB, PCurveIsogenyStruct CurveIsogeny); 44 | 45 | // Alice's ephemeral shared secret computation 46 | // It produces a shared secret key pSharedSecretA using her secret key pPrivateKeyA and Bob's public key pPublicKeyB 47 | // Inputs: Alice's pPrivateKeyA is an even integer in the range [2, oA-2], where oA = 2^372 (i.e., 372 bits in total). 48 | // Bob's pPublicKeyB consists of 3 elements in GF(p751^2), i.e., 564 bytes. 49 | // Output: a shared secret pSharedSecretA that consists of one element in GF(p751^2), i.e., 1502 bits in total. 50 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize(). 51 | CRYPTO_STATUS EphemeralSecretAgreement_A(const unsigned char* pPrivateKeyA, const unsigned char* pPublicKeyB, unsigned char* pSharedSecretA, PCurveIsogenyStruct CurveIsogeny); 52 | 53 | // Bob's ephemeral shared secret computation 54 | // It produces a shared secret key pSharedSecretB using his secret key pPrivateKeyB and Alice's public key pPublicKeyA 55 | // Inputs: Bob's pPrivateKeyB is an integer in the range [1, oB-1], where oA = 3^239 (i.e., 379 bits in total). 56 | // Alice's pPublicKeyA consists of 3 elements in GF(p751^2), i.e., 564 bytes. 57 | // Output: a shared secret pSharedSecretB that consists of one element in GF(p751^2), i.e., 1502 bits in total. 58 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize(). 59 | CRYPTO_STATUS EphemeralSecretAgreement_B(const unsigned char* pPrivateKeyB, const unsigned char* pPublicKeyA, unsigned char* pSharedSecretB, PCurveIsogenyStruct CurveIsogeny); 60 | 61 | /*********************** Ephemeral key exchange API with compressed public keys ***********************/ 62 | 63 | // Alice's public key compression 64 | // It produces a compressed output that consists of three elements in Z_orderB and one field element 65 | // Input : Alice's public key PublicKeyA, which consists of 3 elements in GF(p751^2). 66 | // Output: a compressed value CompressedPKA that consists of three elements in Z_orderB and one element in GF(p751^2). 67 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize(). 68 | void PublicKeyCompression_A(const unsigned char* PublicKeyA, unsigned char* CompressedPKA, PCurveIsogenyStruct CurveIsogeny); 69 | 70 | // Alice's public key value decompression computed by Bob 71 | // Inputs: Bob's private key SecretKeyB, and 72 | // Alice's compressed public key data CompressedPKA, which consists of three elements in Z_orderB and one element in GF(p751^2), 73 | // Output: a point point_R in coordinates (X:Z) and the curve parameter param_A in GF(p751^2). Outputs are stored in Montgomery representation. 74 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize(). 75 | void PublicKeyADecompression_B(const unsigned char* SecretKeyB, const unsigned char* CompressedPKA, unsigned char* point_R, unsigned char* param_A, PCurveIsogenyStruct CurveIsogeny); 76 | 77 | // Alice's ephemeral shared secret computation 78 | // It produces a shared secret key SharedSecretA using her secret key PrivateKeyA and Bob's public key PublicKeyB 79 | // Inputs: Alice's PrivateKeyA is an even integer in the range [2, oA-2], where oA = 2^372 (i.e., 372 bits in total). 80 | // Bob's PublicKeyB consists of 3 elements in GF(p751^2), i.e., 564 bytes. 81 | // Output: a shared secret SharedSecretA that consists of one element in GF(p751^2), i.e., 1502 bits in total. 82 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize(). 83 | CRYPTO_STATUS EphemeralSecretAgreement_Compression_A(const unsigned char* PrivateKeyA, const unsigned char* point_R, const unsigned char* param_A, unsigned char* SharedSecretA, PCurveIsogenyStruct CurveIsogeny); 84 | 85 | // Bob's public key compression 86 | // It produces a compressed output that consists of three elements in Z_orderA and one field element 87 | // Input : Bob's public key PublicKeyB, which consists of 3 elements in GF(p751^2). 88 | // Output: a compressed value CompressedPKB that consists of three elements in Z_orderA and one element in GF(p751^2). 89 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize(). 90 | void PublicKeyCompression_B(const unsigned char* PublicKeyB, unsigned char* CompressedPKB, PCurveIsogenyStruct CurveIsogeny); 91 | 92 | // Bob's public key value decompression computed by Alice 93 | // Inputs: Alice's private key SecretKeyA, and 94 | // Bob's compressed public key data CompressedPKB, which consists of three elements in Z_orderA and one element in GF(p751^2). 95 | // Output: a point point_R in coordinates (X:Z) and the curve parameter param_A in GF(p751^2). Outputs are stored in Montgomery representation. 96 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize(). 97 | void PublicKeyBDecompression_A(const unsigned char* SecretKeyA, const unsigned char* CompressedPKB, unsigned char* point_R, unsigned char* param_A, PCurveIsogenyStruct CurveIsogeny); 98 | 99 | // Bob's ephemeral shared secret computation 100 | // It produces a shared secret key SharedSecretB using his secret key PrivateKeyB and Alice's decompressed data point_R and param_A 101 | // Inputs: Bob's PrivateKeyB is an integer in the range [1, oB-1], where oB = 3^239. 102 | // Alice's decompressed data consists of point_R in (X:Z) coordinates and the curve paramater param_A in GF(p751^2). 103 | // Output: a shared secret SharedSecretB that consists of one element in GF(p751^2). 104 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize(). 105 | CRYPTO_STATUS EphemeralSecretAgreement_Compression_B(const unsigned char* PrivateKeyB, const unsigned char* point_R, const unsigned char* param_A, unsigned char* SharedSecretB, PCurveIsogenyStruct CurveIsogeny); 106 | 107 | /*********************** Scalar multiplication API using BigMont ***********************/ 108 | 109 | // BigMont's scalar multiplication using the Montgomery ladder 110 | // Inputs: x, the affine x-coordinate of a point P on BigMont: y^2=x^3+A*x^2+x, 111 | // scalar m. 112 | // Output: xout, the affine x-coordinate of m*(x:1) 113 | // CurveIsogeny must be set up in advance using SIDH_curve_initialize(). 114 | CRYPTO_STATUS BigMont_ladder(unsigned char* x, digit_t* m, unsigned char* xout, PCurveIsogenyStruct CurveIsogeny); 115 | 116 | 117 | // Encoding of keys for isogeny system "SIDHp751" (wire format): 118 | // ------------------------------------------------------------ 119 | // Elements over GF(p751) are encoded in 96 octets in little endian format (i.e., the least significant octet located at the leftmost position). 120 | // Elements (a+b*i) over GF(p751^2), where a and b are defined over GF(p751), are encoded as {b, a}, with b in the least significant position. 121 | // Elements over Z_oA and Z_oB are encoded in 48 octets in little endian format. 122 | // 123 | // Private keys pPrivateKeyA and pPrivateKeyB are defined in Z_oA and Z_oB (resp.) and can have values in the range [2, 2^372-2] and [1, 3^239-1], resp. 124 | // In the key exchange API, they are encoded in 48 octets in little endian format. 125 | // Public keys pPublicKeyA and pPublicKeyB consist of four elements in GF(p751^2). In the key exchange API, they are encoded in 768 octets in little 126 | // endian format. 127 | // Shared keys pSharedSecretA and pSharedSecretB consist of one element in GF(p751^2). In the key exchange API, they are encoded in 192 octets in little 128 | // endian format. 129 | 130 | 131 | #ifdef __cplusplus 132 | } 133 | #endif 134 | 135 | 136 | #endif 137 | -------------------------------------------------------------------------------- /SIDH_setup.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************************** 2 | * SIDH: an efficient supersingular isogeny-based cryptography library for ephemeral 3 | * Diffie-Hellman key exchange. 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * 7 | * 8 | * Abstract: functions for initialization and getting randomness 9 | * 10 | *********************************************************************************************/ 11 | 12 | #include "SIDH_internal.h" 13 | #include 14 | 15 | 16 | CRYPTO_STATUS SIDH_curve_initialize(PCurveIsogenyStruct pCurveIsogeny, RandomBytes RandomBytesFunction, PCurveIsogenyStaticData pCurveIsogenyData) 17 | { // Initialize curve isogeny structure pCurveIsogeny with static data extracted from pCurveIsogenyData. 18 | // This needs to be called after allocating memory for "pCurveIsogeny" using SIDH_curve_allocate(). 19 | unsigned int i, pwords, owords; 20 | 21 | if (is_CurveIsogenyStruct_null(pCurveIsogeny)) { 22 | return CRYPTO_ERROR_INVALID_PARAMETER; 23 | } 24 | 25 | for (i = 0; i < 8; i++) { // Copy 8-character identifier 26 | pCurveIsogeny->CurveIsogeny[i] = pCurveIsogenyData->CurveIsogeny[i]; 27 | } 28 | pCurveIsogeny->pwordbits = pCurveIsogenyData->pwordbits; 29 | pCurveIsogeny->owordbits = pCurveIsogenyData->owordbits; 30 | pCurveIsogeny->pbits = pCurveIsogenyData->pbits; 31 | pCurveIsogeny->oAbits = pCurveIsogenyData->oAbits; 32 | pCurveIsogeny->oBbits = pCurveIsogenyData->oBbits; 33 | pCurveIsogeny->eB = pCurveIsogenyData->eB; 34 | pCurveIsogeny->BigMont_A24 = pCurveIsogenyData->BigMont_A24; 35 | pCurveIsogeny->RandomBytesFunction = RandomBytesFunction; 36 | 37 | pwords = (pCurveIsogeny->pwordbits + RADIX - 1)/RADIX; 38 | owords = (pCurveIsogeny->owordbits + RADIX - 1)/RADIX; 39 | copy_words((digit_t*)pCurveIsogenyData->prime, pCurveIsogeny->prime, pwords); 40 | copy_words((digit_t*)pCurveIsogenyData->A, pCurveIsogeny->A, pwords); 41 | copy_words((digit_t*)pCurveIsogenyData->C, pCurveIsogeny->C, pwords); 42 | copy_words((digit_t*)pCurveIsogenyData->Aorder, pCurveIsogeny->Aorder, owords); 43 | copy_words((digit_t*)pCurveIsogenyData->Border, pCurveIsogeny->Border, owords); 44 | copy_words((digit_t*)pCurveIsogenyData->PA, pCurveIsogeny->PA, 2*pwords); 45 | copy_words((digit_t*)pCurveIsogenyData->PB, pCurveIsogeny->PB, 2*pwords); 46 | copy_words((digit_t*)pCurveIsogenyData->BigMont_order, pCurveIsogeny->BigMont_order, pwords); 47 | copy_words((digit_t*)pCurveIsogenyData->Montgomery_R2, pCurveIsogeny->Montgomery_R2, pwords); 48 | copy_words((digit_t*)pCurveIsogenyData->Montgomery_pp, pCurveIsogeny->Montgomery_pp, pwords); 49 | copy_words((digit_t*)pCurveIsogenyData->Montgomery_one, pCurveIsogeny->Montgomery_one, pwords); 50 | 51 | return CRYPTO_SUCCESS; 52 | } 53 | 54 | 55 | PCurveIsogenyStruct SIDH_curve_allocate(PCurveIsogenyStaticData CurveData) 56 | { // Dynamic allocation of memory for curve isogeny structure. 57 | // Returns NULL on error. 58 | digit_t pbytes = (CurveData->pwordbits + 7)/8; 59 | digit_t obytes = (CurveData->owordbits + 7)/8; 60 | PCurveIsogenyStruct pCurveIsogeny = NULL; 61 | 62 | pCurveIsogeny = (PCurveIsogenyStruct)calloc(1, sizeof(CurveIsogenyStruct)); 63 | pCurveIsogeny->prime = (digit_t*)calloc(1, pbytes); 64 | pCurveIsogeny->A = (digit_t*)calloc(1, pbytes); 65 | pCurveIsogeny->C = (digit_t*)calloc(1, pbytes); 66 | pCurveIsogeny->Aorder = (digit_t*)calloc(1, obytes); 67 | pCurveIsogeny->Border = (digit_t*)calloc(1, obytes); 68 | pCurveIsogeny->PA = (digit_t*)calloc(1, 2*pbytes); 69 | pCurveIsogeny->PB = (digit_t*)calloc(1, 2*pbytes); 70 | pCurveIsogeny->BigMont_order = (digit_t*)calloc(1, pbytes); 71 | pCurveIsogeny->Montgomery_R2 = (digit_t*)calloc(1, pbytes); 72 | pCurveIsogeny->Montgomery_pp = (digit_t*)calloc(1, pbytes); 73 | pCurveIsogeny->Montgomery_one = (digit_t*)calloc(1, pbytes); 74 | 75 | if (is_CurveIsogenyStruct_null(pCurveIsogeny)) { 76 | return NULL; 77 | } 78 | return pCurveIsogeny; 79 | } 80 | 81 | 82 | void SIDH_curve_free(PCurveIsogenyStruct pCurveIsogeny) 83 | { // Free memory for curve isogeny structure 84 | 85 | if (pCurveIsogeny != NULL) 86 | { 87 | if (pCurveIsogeny->prime != NULL) 88 | free(pCurveIsogeny->prime); 89 | if (pCurveIsogeny->A != NULL) 90 | free(pCurveIsogeny->A); 91 | if (pCurveIsogeny->C != NULL) 92 | free(pCurveIsogeny->C); 93 | if (pCurveIsogeny->Aorder != NULL) 94 | free(pCurveIsogeny->Aorder); 95 | if (pCurveIsogeny->Border != NULL) 96 | free(pCurveIsogeny->Border); 97 | if (pCurveIsogeny->PA != NULL) 98 | free(pCurveIsogeny->PA); 99 | if (pCurveIsogeny->PB != NULL) 100 | free(pCurveIsogeny->PB); 101 | if (pCurveIsogeny->BigMont_order != NULL) 102 | free(pCurveIsogeny->BigMont_order); 103 | if (pCurveIsogeny->Montgomery_R2 != NULL) 104 | free(pCurveIsogeny->Montgomery_R2); 105 | if (pCurveIsogeny->Montgomery_pp != NULL) 106 | free(pCurveIsogeny->Montgomery_pp); 107 | if (pCurveIsogeny->Montgomery_one != NULL) 108 | free(pCurveIsogeny->Montgomery_one); 109 | 110 | free(pCurveIsogeny); 111 | } 112 | } 113 | 114 | 115 | bool is_CurveIsogenyStruct_null(PCurveIsogenyStruct pCurveIsogeny) 116 | { // Check if curve isogeny structure is NULL 117 | 118 | if (pCurveIsogeny == NULL || pCurveIsogeny->prime == NULL || pCurveIsogeny->A == NULL || pCurveIsogeny->C == NULL || pCurveIsogeny->Aorder == NULL || pCurveIsogeny->Border == NULL || 119 | pCurveIsogeny->PA == NULL || pCurveIsogeny->PB == NULL || pCurveIsogeny->BigMont_order == NULL || pCurveIsogeny->Montgomery_R2 == NULL || pCurveIsogeny->Montgomery_pp == NULL || 120 | pCurveIsogeny->Montgomery_one == NULL) 121 | { 122 | return true; 123 | } 124 | return false; 125 | } 126 | 127 | 128 | const char* SIDH_get_error_message(CRYPTO_STATUS Status) 129 | { // Output error/success message for a given CRYPTO_STATUS 130 | struct error_mapping { 131 | unsigned int index; 132 | char* string; 133 | } mapping[CRYPTO_STATUS_TYPE_SIZE] = { 134 | {CRYPTO_SUCCESS, CRYPTO_MSG_SUCCESS}, 135 | {CRYPTO_ERROR, CRYPTO_MSG_ERROR}, 136 | {CRYPTO_ERROR_DURING_TEST, CRYPTO_MSG_ERROR_DURING_TEST}, 137 | {CRYPTO_ERROR_UNKNOWN, CRYPTO_MSG_ERROR_UNKNOWN}, 138 | {CRYPTO_ERROR_NOT_IMPLEMENTED, CRYPTO_MSG_ERROR_NOT_IMPLEMENTED}, 139 | {CRYPTO_ERROR_NO_MEMORY, CRYPTO_MSG_ERROR_NO_MEMORY}, 140 | {CRYPTO_ERROR_INVALID_PARAMETER, CRYPTO_MSG_ERROR_INVALID_PARAMETER}, 141 | {CRYPTO_ERROR_SHARED_KEY, CRYPTO_MSG_ERROR_SHARED_KEY}, 142 | {CRYPTO_ERROR_PUBLIC_KEY_VALIDATION, CRYPTO_MSG_ERROR_PUBLIC_KEY_VALIDATION}, 143 | {CRYPTO_ERROR_TOO_MANY_ITERATIONS, CRYPTO_MSG_ERROR_TOO_MANY_ITERATIONS} 144 | }; 145 | 146 | if (Status >= CRYPTO_STATUS_TYPE_SIZE || mapping[Status].string == NULL) { 147 | return "Unrecognized CRYPTO_STATUS"; 148 | } else { 149 | return mapping[Status].string; 150 | } 151 | }; 152 | 153 | 154 | const uint64_t Border_div3[NWORDS_ORDER] = { 0xEDCD718A828384F9, 0x733B35BFD4427A14, 0xF88229CF94D7CF38, 0x63C56C990C7C2AD6, 0xB858A87E8F4222C7, 0x254C9C6B525EAF5 }; 155 | 156 | 157 | CRYPTO_STATUS random_mod_order(digit_t* random_digits, unsigned int AliceOrBob, PCurveIsogenyStruct pCurveIsogeny) 158 | { // Output random values in the range [1, order-1] in little endian format that can be used as private keys. 159 | // It makes requests of random values with length "oAbits" (when AliceOrBob = 0) or "oBbits" (when AliceOrBob = 1) to the "random_bytes" function. 160 | // The process repeats until random value is in [0, Aorder-2] ([0, Border-2], resp.). 161 | // If successful, the output is given in "random_digits" in the range [1, Aorder-1] ([1, Border-1], resp.). 162 | // The "random_bytes" function, which is passed through the curve isogeny structure PCurveIsogeny, should be set up in advance using SIDH_curve_initialize(). 163 | // The caller is responsible of providing the "random_bytes" function passing random values as octets. 164 | unsigned int ntry = 0, nbytes, nwords; 165 | digit_t t1[MAXWORDS_ORDER] = {0}, order2[MAXWORDS_ORDER] = {0}; 166 | unsigned char mask; 167 | CRYPTO_STATUS Status = CRYPTO_ERROR_UNKNOWN; 168 | 169 | if (random_digits == NULL || is_CurveIsogenyStruct_null(pCurveIsogeny) || AliceOrBob > 1) { 170 | return CRYPTO_ERROR_INVALID_PARAMETER; 171 | } 172 | 173 | clear_words((void*)random_digits, MAXWORDS_ORDER); 174 | t1[0] = 2; 175 | if (AliceOrBob == ALICE) { 176 | nbytes = (pCurveIsogeny->oAbits+7)/8; // Number of random bytes to be requested 177 | nwords = NBITS_TO_NWORDS(pCurveIsogeny->oAbits); 178 | mask = 0x07; // Value for masking last random byte 179 | copy_words(pCurveIsogeny->Aorder, order2, nwords); 180 | mp_shiftr1(order2, nwords); // order/2 181 | mp_sub(order2, t1, order2, nwords); // order2 = order/2-2 182 | } else { 183 | nbytes = (pCurveIsogeny->oBbits+7)/8; 184 | nwords = NBITS_TO_NWORDS(pCurveIsogeny->oBbits); 185 | mask = 0x03; // Value for masking last random byte 186 | mp_sub((digit_t*)Border_div3, t1, order2, nwords); // order2 = order/3-2 187 | } 188 | 189 | do { 190 | ntry++; 191 | if (ntry > 100) { // Max. 100 iterations to obtain random value in [0, order-2] 192 | return CRYPTO_ERROR_TOO_MANY_ITERATIONS; 193 | } 194 | Status = (pCurveIsogeny->RandomBytesFunction)(nbytes, (unsigned char*)random_digits); 195 | if (Status != CRYPTO_SUCCESS) { 196 | return Status; 197 | } 198 | ((unsigned char*)random_digits)[nbytes-1] &= mask; // Masking last byte 199 | } while (mp_sub(order2, random_digits, t1, nwords) == 1); 200 | 201 | clear_words((void*)t1, MAXWORDS_ORDER); 202 | t1[0] = 1; 203 | mp_add(random_digits, t1, random_digits, nwords); 204 | copy_words(random_digits, t1, nwords); 205 | mp_shiftl1(random_digits, nwords); // Alice's output in the range [2, order-2] 206 | if (AliceOrBob == BOB) { 207 | mp_add(random_digits, t1, random_digits, nwords); // Bob's output in the range [3, order-3] 208 | } 209 | 210 | return Status; 211 | } 212 | 213 | 214 | CRYPTO_STATUS random_BigMont_mod_order(digit_t* random_digits, PCurveIsogenyStruct pCurveIsogeny) 215 | { // Output random values in the range [1, BigMont_order-1] in little endian format that can be used as private keys to compute scalar multiplications 216 | // using the elliptic curve BigMont. 217 | // It makes requests of random values with length "BIGMONT_NBITS_ORDER" to the "random_bytes" function. 218 | // The process repeats until random value is in [0, BigMont_order-2] 219 | // If successful, the output is given in "random_digits" in the range [1, BigMont_order-1]. 220 | // The "random_bytes" function, which is passed through the curve isogeny structure PCurveIsogeny, should be set up in advance using SIDH_curve_initialize(). 221 | // The caller is responsible of providing the "random_bytes" function passing random values as octets. 222 | unsigned int ntry = 0, nbytes = (BIGMONT_NBITS_ORDER+7)/8, nwords = NBITS_TO_NWORDS(BIGMONT_NBITS_ORDER); 223 | digit_t t1[BIGMONT_MAXWORDS_ORDER] = {0}, order2[BIGMONT_MAXWORDS_ORDER] = {0}; 224 | unsigned char mask; 225 | CRYPTO_STATUS Status = CRYPTO_ERROR_UNKNOWN; 226 | 227 | if (random_digits == NULL || is_CurveIsogenyStruct_null(pCurveIsogeny)) { 228 | return CRYPTO_ERROR_INVALID_PARAMETER; 229 | } 230 | 231 | clear_words((void*)random_digits, BIGMONT_MAXWORDS_ORDER); 232 | t1[0] = 2; 233 | mask = (unsigned char)(8*nbytes - BIGMONT_NBITS_ORDER); 234 | mp_sub(pCurveIsogeny->BigMont_order, t1, order2, nwords); // order2 = order-2 235 | mask = ((unsigned char)-1 >> mask); // Value for masking last random byte 236 | 237 | do { 238 | ntry++; 239 | if (ntry > 100) { // Max. 100 iterations to obtain random value in [0, order-2] 240 | return CRYPTO_ERROR_TOO_MANY_ITERATIONS; 241 | } 242 | Status = (pCurveIsogeny->RandomBytesFunction)(nbytes, (unsigned char*)random_digits); 243 | if (Status != CRYPTO_SUCCESS) { 244 | return Status; 245 | } 246 | ((unsigned char*)random_digits)[nbytes-1] &= mask; // Masking last byte 247 | } while (mp_sub(order2, random_digits, t1, nwords) == 1); 248 | 249 | clear_words((void*)t1, BIGMONT_MAXWORDS_ORDER); 250 | t1[0] = 1; 251 | mp_add(random_digits, t1, random_digits, nwords); // Output in the range [1, order-1] 252 | 253 | return Status; 254 | } 255 | 256 | 257 | void clear_words(void* mem, digit_t nwords) 258 | { // Clear digits from memory. "nwords" indicates the number of digits to be zeroed. 259 | // This function uses the volatile type qualifier to inform the compiler not to optimize out the memory clearing. 260 | unsigned int i; 261 | volatile digit_t *v = mem; 262 | 263 | for (i = 0; i < nwords; i++) { 264 | v[i] = 0; 265 | } 266 | } 267 | 268 | 269 | 270 | 271 | 272 | 273 | -------------------------------------------------------------------------------- /Visual Studio/SIDH/SIDH.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}") = "kex_tests", "..\kex_tests\kex_tests.vcxproj", "{98A48FFD-CE31-44B0-B236-D340521E9C0C}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {8283DD76-E88A-4B63-ABDE-33F014178413} = {8283DD76-E88A-4B63-ABDE-33F014178413} 9 | EndProjectSection 10 | EndProject 11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "arith_tests", "..\arith_tests\arith_tests.vcxproj", "{C9639168-C3FF-4427-BC3B-D907FF11DE73}" 12 | ProjectSection(ProjectDependencies) = postProject 13 | {8283DD76-E88A-4B63-ABDE-33F014178413} = {8283DD76-E88A-4B63-ABDE-33F014178413} 14 | EndProjectSection 15 | EndProject 16 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SIDH", "SIDH.vcxproj", "{8283DD76-E88A-4B63-ABDE-33F014178413}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Win32 = Debug|Win32 21 | Debug|x64 = Debug|x64 22 | Generic|Win32 = Generic|Win32 23 | Generic|x64 = Generic|x64 24 | Release|Win32 = Release|Win32 25 | Release|x64 = Release|x64 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Debug|Win32.ActiveCfg = Debug|Win32 29 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Debug|x64.ActiveCfg = Debug|x64 30 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Debug|x64.Build.0 = Debug|x64 31 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Generic|Win32.ActiveCfg = Generic|Win32 32 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Generic|Win32.Build.0 = Generic|Win32 33 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Generic|x64.ActiveCfg = Generic|x64 34 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Generic|x64.Build.0 = Generic|x64 35 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Release|Win32.ActiveCfg = Release|Win32 36 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Release|x64.ActiveCfg = Release|x64 37 | {98A48FFD-CE31-44B0-B236-D340521E9C0C}.Release|x64.Build.0 = Release|x64 38 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Debug|Win32.ActiveCfg = Debug|Win32 39 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Debug|x64.ActiveCfg = Debug|x64 40 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Debug|x64.Build.0 = Debug|x64 41 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Generic|Win32.ActiveCfg = Generic|Win32 42 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Generic|Win32.Build.0 = Generic|Win32 43 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Generic|x64.ActiveCfg = Generic|x64 44 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Generic|x64.Build.0 = Generic|x64 45 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Release|Win32.ActiveCfg = Release|Win32 46 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Release|x64.ActiveCfg = Release|x64 47 | {C9639168-C3FF-4427-BC3B-D907FF11DE73}.Release|x64.Build.0 = Release|x64 48 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Debug|Win32.ActiveCfg = Debug|Win32 49 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Debug|x64.ActiveCfg = Debug|x64 50 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Debug|x64.Build.0 = Debug|x64 51 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Generic|Win32.ActiveCfg = Generic|Win32 52 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Generic|Win32.Build.0 = Generic|Win32 53 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Generic|x64.ActiveCfg = Generic|x64 54 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Generic|x64.Build.0 = Generic|x64 55 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Release|Win32.ActiveCfg = Release|Win32 56 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Release|x64.ActiveCfg = Release|x64 57 | {8283DD76-E88A-4B63-ABDE-33F014178413}.Release|x64.Build.0 = Release|x64 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | EndGlobal 63 | -------------------------------------------------------------------------------- /Visual Studio/SIDH/SIDH.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Generic 14 | Win32 15 | 16 | 17 | Generic 18 | x64 19 | 20 | 21 | Release 22 | Win32 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | {8283DD76-E88A-4B63-ABDE-33F014178413} 31 | Win32Proj 32 | isoECClib 33 | 8.1 34 | 35 | 36 | 37 | StaticLibrary 38 | true 39 | v140 40 | Unicode 41 | 42 | 43 | StaticLibrary 44 | true 45 | v140 46 | Unicode 47 | 48 | 49 | StaticLibrary 50 | false 51 | v140 52 | true 53 | Unicode 54 | 55 | 56 | StaticLibrary 57 | false 58 | v140 59 | true 60 | Unicode 61 | 62 | 63 | StaticLibrary 64 | false 65 | v140 66 | true 67 | Unicode 68 | 69 | 70 | StaticLibrary 71 | false 72 | v140 73 | true 74 | Unicode 75 | 76 | 77 | 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 | Level4 104 | Disabled 105 | __WINDOWS__; _X86_; _GENERIC_; 106 | ProgramDatabase 107 | false 108 | false 109 | false 110 | Default 111 | MultiThreadedDLL 112 | true 113 | 114 | 115 | Windows 116 | true 117 | 118 | 119 | 120 | 121 | 122 | 123 | Level4 124 | Disabled 125 | __WINDOWS__; _AMD64_; 126 | ProgramDatabase 127 | false 128 | false 129 | true 130 | Default 131 | MultiThreadedDLL 132 | 133 | 134 | AdvancedVectorExtensions 135 | 136 | 137 | Windows 138 | true 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | Level4 154 | 155 | 156 | MaxSpeed 157 | true 158 | true 159 | __WINDOWS__; _X86_; _GENERIC_; 160 | MultiThreadedDLL 161 | 162 | 163 | Windows 164 | true 165 | true 166 | true 167 | 168 | 169 | 170 | 171 | Level4 172 | 173 | 174 | MaxSpeed 175 | true 176 | true 177 | __WINDOWS__; _AMD64_; 178 | MultiThreadedDLL 179 | AdvancedVectorExtensions 180 | 181 | 182 | Windows 183 | true 184 | true 185 | true 186 | 187 | 188 | 189 | 190 | Level4 191 | 192 | 193 | MaxSpeed 194 | true 195 | true 196 | __WINDOWS__; _X86_; _GENERIC_; 197 | MultiThreadedDLL 198 | 199 | 200 | Windows 201 | true 202 | true 203 | true 204 | 205 | 206 | 207 | 208 | Level4 209 | 210 | 211 | MaxSpeed 212 | true 213 | true 214 | __WINDOWS__; _AMD64_; _GENERIC_; 215 | MultiThreadedDLL 216 | AdvancedVectorExtensions 217 | 218 | 219 | Windows 220 | true 221 | true 222 | true 223 | 224 | 225 | 226 | 227 | true 228 | true 229 | true 230 | true 231 | 232 | 233 | 234 | 235 | true 236 | true 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | -------------------------------------------------------------------------------- /Visual Studio/SIDH/SIDH.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 | {c12e408e-2171-41d7-8815-33244cd7b1db} 18 | 19 | 20 | {e81738a2-8bd8-449a-8918-07266c29f2b7} 21 | 22 | 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files\generic 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files\x64 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | -------------------------------------------------------------------------------- /Visual Studio/arith_tests/arith_tests.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Generic 14 | Win32 15 | 16 | 17 | Generic 18 | x64 19 | 20 | 21 | Release 22 | Win32 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | {8283dd76-e88a-4b63-abde-33f014178413} 41 | 42 | 43 | 44 | {C9639168-C3FF-4427-BC3B-D907FF11DE73} 45 | Win32Proj 46 | fp_tests 47 | arith_tests 48 | 8.1 49 | 50 | 51 | 52 | Application 53 | true 54 | v140 55 | Unicode 56 | 57 | 58 | Application 59 | true 60 | v140 61 | Unicode 62 | 63 | 64 | Application 65 | false 66 | v140 67 | true 68 | Unicode 69 | 70 | 71 | Application 72 | false 73 | v140 74 | true 75 | Unicode 76 | 77 | 78 | v140 79 | 80 | 81 | v140 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | true 101 | 102 | 103 | true 104 | 105 | 106 | false 107 | 108 | 109 | false 110 | 111 | 112 | 113 | 114 | 115 | Level4 116 | Disabled 117 | __WINDOWS__; _X86_; 118 | false 119 | Default 120 | MultiThreadedDLL 121 | true 122 | ProgramDatabase 123 | 124 | 125 | Console 126 | true 127 | 128 | 129 | 130 | 131 | 132 | 133 | Level4 134 | Disabled 135 | __WINDOWS__; _AMD64_; 136 | false 137 | Default 138 | MultiThreadedDLL 139 | true 140 | ProgramDatabase 141 | AdvancedVectorExtensions 142 | 143 | 144 | Console 145 | true 146 | 147 | 148 | 149 | 150 | Level4 151 | 152 | 153 | MaxSpeed 154 | true 155 | true 156 | __WINDOWS__; _X86_; 157 | MultiThreadedDLL 158 | 159 | 160 | Console 161 | true 162 | true 163 | true 164 | 165 | 166 | 167 | 168 | Level4 169 | 170 | 171 | MaxSpeed 172 | true 173 | true 174 | __WINDOWS__; _AMD64_; 175 | MultiThreadedDLL 176 | AdvancedVectorExtensions 177 | 178 | 179 | Console 180 | true 181 | true 182 | true 183 | 184 | 185 | 186 | 187 | Level4 188 | true 189 | true 190 | __WINDOWS__; _X86_; _GENERIC_; 191 | true 192 | 193 | 194 | UseLinkTimeCodeGeneration 195 | true 196 | 197 | 198 | 199 | 200 | Level4 201 | true 202 | true 203 | __WINDOWS__; _AMD64_; _GENERIC_; 204 | true 205 | AdvancedVectorExtensions 206 | MaxSpeed 207 | 208 | 209 | UseLinkTimeCodeGeneration 210 | true 211 | 212 | 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /Visual Studio/arith_tests/arith_tests.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 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | -------------------------------------------------------------------------------- /Visual Studio/kex_tests/kex_tests.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Generic 14 | Win32 15 | 16 | 17 | Generic 18 | x64 19 | 20 | 21 | Release 22 | Win32 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | {8283dd76-e88a-4b63-abde-33f014178413} 40 | 41 | 42 | 43 | {98A48FFD-CE31-44B0-B236-D340521E9C0C} 44 | Win32Proj 45 | kex_tests 46 | 8.1 47 | 48 | 49 | 50 | Application 51 | true 52 | v140 53 | Unicode 54 | 55 | 56 | Application 57 | true 58 | v140 59 | Unicode 60 | 61 | 62 | Application 63 | false 64 | v140 65 | true 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 | Application 84 | false 85 | v140 86 | true 87 | Unicode 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | true 113 | 114 | 115 | true 116 | 117 | 118 | false 119 | 120 | 121 | false 122 | 123 | 124 | false 125 | 126 | 127 | false 128 | 129 | 130 | 131 | 132 | 133 | Level4 134 | Disabled 135 | __WINDOWS__; _X86_; 136 | AdvancedVectorExtensions 137 | 138 | 139 | Console 140 | true 141 | 142 | 143 | 144 | 145 | 146 | 147 | Level4 148 | Disabled 149 | __WINDOWS__; _AMD64_; 150 | AdvancedVectorExtensions 151 | MultiThreadedDLL 152 | 153 | 154 | Console 155 | true 156 | 157 | 158 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 159 | 160 | 161 | true 162 | 163 | 164 | 165 | 166 | Level4 167 | 168 | 169 | MaxSpeed 170 | true 171 | true 172 | __WINDOWS__; _X86_; 173 | AdvancedVectorExtensions 174 | 175 | 176 | Console 177 | true 178 | true 179 | true 180 | 181 | 182 | 183 | 184 | Level4 185 | 186 | 187 | MaxSpeed 188 | true 189 | true 190 | __WINDOWS__; _X86_; _GENERIC_; 191 | AdvancedVectorExtensions 192 | 193 | 194 | Console 195 | true 196 | true 197 | true 198 | 199 | 200 | 201 | 202 | Level4 203 | 204 | 205 | MaxSpeed 206 | true 207 | true 208 | __WINDOWS__; _AMD64_; 209 | AdvancedVectorExtensions 210 | 211 | 212 | Console 213 | true 214 | true 215 | true 216 | 217 | 218 | 219 | 220 | Level4 221 | 222 | 223 | MaxSpeed 224 | true 225 | true 226 | __WINDOWS__; _AMD64_; _GENERIC_; 227 | AdvancedVectorExtensions 228 | 229 | 230 | Console 231 | true 232 | true 233 | true 234 | 235 | 236 | 237 | 238 | 239 | -------------------------------------------------------------------------------- /Visual Studio/kex_tests/kex_tests.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 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | Header Files 31 | 32 | 33 | -------------------------------------------------------------------------------- /generic/fp_generic.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************************** 2 | * SIDH: an efficient supersingular isogeny-based cryptography library for ephemeral 3 | * Diffie-Hellman key exchange. 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * 7 | * 8 | * Abstract: portable modular arithmetic 9 | * 10 | *********************************************************************************************/ 11 | 12 | #include "../SIDH_internal.h" 13 | 14 | 15 | // Global constants 16 | extern const uint64_t p751[NWORDS_FIELD]; 17 | extern const uint64_t p751p1[NWORDS_FIELD]; 18 | extern const uint64_t p751x2[NWORDS_FIELD]; 19 | 20 | 21 | __inline void fpadd751(const digit_t* a, const digit_t* b, digit_t* c) 22 | { // Modular addition, c = a+b mod p751. 23 | // Inputs: a, b in [0, 2*p751-1] 24 | // Output: c in [0, 2*p751-1] 25 | unsigned int i, carry = 0; 26 | digit_t mask; 27 | 28 | for (i = 0; i < NWORDS_FIELD; i++) { 29 | ADDC(carry, a[i], b[i], carry, c[i]); 30 | } 31 | 32 | carry = 0; 33 | for (i = 0; i < NWORDS_FIELD; i++) { 34 | SUBC(carry, c[i], ((digit_t*)p751x2)[i], carry, c[i]); 35 | } 36 | mask = 0 - (digit_t)carry; 37 | 38 | carry = 0; 39 | for (i = 0; i < NWORDS_FIELD; i++) { 40 | ADDC(carry, c[i], ((digit_t*)p751x2)[i] & mask, carry, c[i]); 41 | } 42 | } 43 | 44 | 45 | __inline void fpsub751(const digit_t* a, const digit_t* b, digit_t* c) 46 | { // Modular subtraction, c = a-b mod p751. 47 | // Inputs: a, b in [0, 2*p751-1] 48 | // Output: c in [0, 2*p751-1] 49 | unsigned int i, borrow = 0; 50 | digit_t mask; 51 | 52 | for (i = 0; i < NWORDS_FIELD; i++) { 53 | SUBC(borrow, a[i], b[i], borrow, c[i]); 54 | } 55 | mask = 0 - (digit_t)borrow; 56 | 57 | borrow = 0; 58 | for (i = 0; i < NWORDS_FIELD; i++) { 59 | ADDC(borrow, c[i], ((digit_t*)p751x2)[i] & mask, borrow, c[i]); 60 | } 61 | } 62 | 63 | 64 | __inline void fpneg751(digit_t* a) 65 | { // Modular negation, a = -a mod p751. 66 | // Input/output: a in [0, 2*p751-1] 67 | unsigned int i, borrow = 0; 68 | 69 | for (i = 0; i < NWORDS_FIELD; i++) { 70 | SUBC(borrow, ((digit_t*)p751x2)[i], a[i], borrow, a[i]); 71 | } 72 | } 73 | 74 | 75 | void fpdiv2_751(const digit_t* a, digit_t* c) 76 | { // Modular division by two, c = a/2 mod p751. 77 | // Input : a in [0, 2*p751-1] 78 | // Output: c in [0, 2*p751-1] 79 | unsigned int i, carry = 0; 80 | digit_t mask; 81 | 82 | mask = 0 - (digit_t)(a[0] & 1); // If a is odd compute a+p751 83 | for (i = 0; i < NWORDS_FIELD; i++) { 84 | ADDC(carry, a[i], ((digit_t*)p751)[i] & mask, carry, c[i]); 85 | } 86 | 87 | mp_shiftr1(c, NWORDS_FIELD); 88 | } 89 | 90 | 91 | void fpcorrection751(digit_t* a) 92 | { // Modular correction to reduce field element a in [0, 2*p751-1] to [0, p751-1]. 93 | unsigned int i, borrow = 0; 94 | digit_t mask; 95 | 96 | for (i = 0; i < NWORDS_FIELD; i++) { 97 | SUBC(borrow, a[i], ((digit_t*)p751)[i], borrow, a[i]); 98 | } 99 | mask = 0 - (digit_t)borrow; 100 | 101 | borrow = 0; 102 | for (i = 0; i < NWORDS_FIELD; i++) { 103 | ADDC(borrow, a[i], ((digit_t*)p751)[i] & mask, borrow, a[i]); 104 | } 105 | } 106 | 107 | 108 | void digit_x_digit(const digit_t a, const digit_t b, digit_t* c) 109 | { // Digit multiplication, digit * digit -> 2-digit result 110 | register digit_t al, ah, bl, bh, temp; 111 | digit_t albl, albh, ahbl, ahbh, res1, res2, res3, carry; 112 | digit_t mask_low = (digit_t)(-1) >> (sizeof(digit_t)*4), mask_high = (digit_t)(-1) << (sizeof(digit_t)*4); 113 | 114 | al = a & mask_low; // Low part 115 | ah = a >> (sizeof(digit_t) * 4); // High part 116 | bl = b & mask_low; 117 | bh = b >> (sizeof(digit_t) * 4); 118 | 119 | albl = al*bl; 120 | albh = al*bh; 121 | ahbl = ah*bl; 122 | ahbh = ah*bh; 123 | c[0] = albl & mask_low; // C00 124 | 125 | res1 = albl >> (sizeof(digit_t) * 4); 126 | res2 = ahbl & mask_low; 127 | res3 = albh & mask_low; 128 | temp = res1 + res2 + res3; 129 | carry = temp >> (sizeof(digit_t) * 4); 130 | c[0] ^= temp << (sizeof(digit_t) * 4); // C01 131 | 132 | res1 = ahbl >> (sizeof(digit_t) * 4); 133 | res2 = albh >> (sizeof(digit_t) * 4); 134 | res3 = ahbh & mask_low; 135 | temp = res1 + res2 + res3 + carry; 136 | c[1] = temp & mask_low; // C10 137 | carry = temp & mask_high; 138 | c[1] ^= (ahbh & mask_high) + carry; // C11 139 | } 140 | 141 | 142 | void mp_mul_schoolbook(const digit_t* a, const digit_t* b, digit_t* c, const unsigned int nwords) 143 | { // Multiprecision schoolbook multiply, c = a*b, where lng(a) = lng(b) = nwords. 144 | unsigned int i, j; 145 | digit_t u, v, UV[2]; 146 | unsigned int carry = 0; 147 | 148 | for (i = 0; i < (2*nwords); i++) c[i] = 0; 149 | 150 | for (i = 0; i < nwords; i++) { 151 | u = 0; 152 | for (j = 0; j < nwords; j++) { 153 | MUL(a[i], b[j], UV+1, UV[0]); 154 | ADDC(0, UV[0], u, carry, v); 155 | u = UV[1] + carry; 156 | ADDC(0, c[i+j], v, carry, v); 157 | u = u + carry; 158 | c[i+j] = v; 159 | } 160 | c[nwords+i] = u; 161 | } 162 | } 163 | 164 | 165 | void mp_mul_comba(const digit_t* a, const digit_t* b, digit_t* c, const unsigned int nwords) 166 | { // Multiprecision comba multiply, c = a*b, where lng(a) = lng(b) = nwords. 167 | unsigned int i, j; 168 | digit_t t = 0, u = 0, v = 0, UV[2]; 169 | unsigned int carry = 0; 170 | 171 | for (i = 0; i < nwords; i++) { 172 | for (j = 0; j <= i; j++) { 173 | MUL(a[j], b[i-j], UV+1, UV[0]); 174 | ADDC(0, UV[0], v, carry, v); 175 | ADDC(carry, UV[1], u, carry, u); 176 | t += carry; 177 | } 178 | c[i] = v; 179 | v = u; 180 | u = t; 181 | t = 0; 182 | } 183 | 184 | for (i = nwords; i < 2*nwords-1; i++) { 185 | for (j = i-nwords+1; j < nwords; j++) { 186 | MUL(a[j], b[i-j], UV+1, UV[0]); 187 | ADDC(0, UV[0], v, carry, v); 188 | ADDC(carry, UV[1], u, carry, u); 189 | t += carry; 190 | } 191 | c[i] = v; 192 | v = u; 193 | u = t; 194 | t = 0; 195 | } 196 | c[2*nwords-1] = v; 197 | } 198 | 199 | 200 | void rdc_mont(const dfelm_t ma, felm_t mc) 201 | { // Efficient Montgomery reduction using comba and exploiting the special form of the prime p751. 202 | // mc = ma*R^-1 mod p751x2, where R = 2^768. 203 | // If ma < 2^768*p751, the output mc is in the range [0, 2*p751-1]. 204 | // ma is assumed to be in Montgomery representation. 205 | unsigned int i, j, carry, count = p751_ZERO_WORDS; 206 | digit_t UV[2], t = 0, u = 0, v = 0; 207 | 208 | for (i = 0; i < NWORDS_FIELD; i++) { 209 | mc[i] = 0; 210 | } 211 | 212 | for (i = 0; i < NWORDS_FIELD; i++) { 213 | for (j = 0; j < i; j++) { 214 | if (j < (i-p751_ZERO_WORDS+1)) { 215 | MUL(mc[j], ((digit_t*)p751p1)[i-j], UV+1, UV[0]); 216 | ADDC(0, UV[0], v, carry, v); 217 | ADDC(carry, UV[1], u, carry, u); 218 | t += carry; 219 | } 220 | } 221 | ADDC(0, v, ma[i], carry, v); 222 | ADDC(carry, u, 0, carry, u); 223 | t += carry; 224 | mc[i] = v; 225 | v = u; 226 | u = t; 227 | t = 0; 228 | } 229 | 230 | for (i = NWORDS_FIELD; i < 2*NWORDS_FIELD-1; i++) { 231 | if (count > 0) { 232 | count -= 1; 233 | } 234 | for (j = i-NWORDS_FIELD+1; j < NWORDS_FIELD; j++) { 235 | if (j < (NWORDS_FIELD-count)) { 236 | MUL(mc[j], ((digit_t*)p751p1)[i-j], UV+1, UV[0]); 237 | ADDC(0, UV[0], v, carry, v); 238 | ADDC(carry, UV[1], u, carry, u); 239 | t += carry; 240 | } 241 | } 242 | ADDC(0, v, ma[i], carry, v); 243 | ADDC(carry, u, 0, carry, u); 244 | t += carry; 245 | mc[i-NWORDS_FIELD] = v; 246 | v = u; 247 | u = t; 248 | t = 0; 249 | } 250 | ADDC(0, v, ma[2*NWORDS_FIELD-1], carry, v); 251 | mc[NWORDS_FIELD-1] = v; 252 | } -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | #### Makefile for compilation on Linux #### 2 | 3 | OPT=-O3 # Optimization option by default 4 | 5 | CC=clang 6 | ifeq "$(CC)" "gcc" 7 | COMPILER=gcc 8 | else ifeq "$(CC)" "clang" 9 | COMPILER=clang 10 | endif 11 | 12 | ifeq "$(ARCH)" "x64" 13 | ARCHITECTURE=_AMD64_ 14 | else ifeq "$(ARCH)" "x86" 15 | ARCHITECTURE=_X86_ 16 | else ifeq "$(ARCH)" "ARM" 17 | ARCHITECTURE=_ARM_ 18 | else ifeq "$(ARCH)" "ARM64" 19 | ARCHITECTURE=_ARM64_ 20 | endif 21 | 22 | ifeq "$(ARCH_EX)" "haswell" 23 | ARCH_EXTRA=__HASWELL__ 24 | else ifeq "$(ARCH_EX)" "skylake" 25 | ARCH_EXTRA=__SKYLAKE__ 26 | else ifeq "$(ARCH_EX)" "native" 27 | ARCH_EXTRA=__NATIVE__ 28 | endif 29 | 30 | ADDITIONAL_SETTINGS= 31 | ifeq "$(SET)" "EXTENDED" 32 | ADDITIONAL_SETTINGS=-fwrapv -fomit-frame-pointer -march=native 33 | endif 34 | 35 | ifeq "$(ARCH_EX)" "haswell" 36 | ADDITIONAL_SETTINGS+= -march=haswell -m64 -mbmi2 37 | else ifeq "$(ARCH_EX)" "skylake" 38 | ADDITIONAL_SETTINGS+= -march=skylake -m64 -mbmi2 -madx 39 | endif 40 | 41 | ifeq "$(GENERIC)" "TRUE" 42 | USE_GENERIC=-D _GENERIC_ 43 | endif 44 | 45 | ifeq "$(ARCH)" "ARM" 46 | ARM_SETTING=-lrt 47 | endif 48 | 49 | ifeq "$(ARCH)" "ARM64" 50 | ARM_SETTING=-lrt 51 | endif 52 | 53 | cc=$(COMPILER) 54 | CFLAGS=-c $(OPT) $(ADDITIONAL_SETTINGS) -D $(ARCHITECTURE) -D __LINUX__ $(USE_GENERIC) -D $(ARCH_EXTRA) 55 | LDFLAGS= 56 | ifeq "$(GENERIC)" "TRUE" 57 | EXTRA_OBJECTS=fp_generic.o 58 | else 59 | ifeq "$(ARCH)" "x64" 60 | EXTRA_OBJECTS=fp_x64.o fp_x64_asm.o 61 | ifeq "$(ARCH_EX)" "haswell" 62 | EXTRA_OBJECTS+= ZREDC_6x4_SH_HW.o 63 | else ifeq "$(ARCH_EX)" "skylake" 64 | EXTRA_OBJECTS+= ZREDC_6x4_SH_SK.o 65 | endif 66 | endif 67 | ifeq "$(ARCH)" "ARM64" 68 | EXTRA_OBJECTS=fp_arm64.o fp_arm64_asm.o 69 | endif 70 | endif 71 | OBJECTS=kex.o ec_isogeny.o SIDH.o SIDH_setup.o fpx.o $(EXTRA_OBJECTS) 72 | OBJECTS_TEST=test_extras.o 73 | OBJECTS_ARITH_TEST=arith_tests.o $(OBJECTS_TEST) $(OBJECTS) 74 | OBJECTS_KEX_TEST=kex_tests.o $(OBJECTS_TEST) $(OBJECTS) 75 | OBJECTS_ALL=$(OBJECTS) $(OBJECTS_ARITH_TEST) $(OBJECTS_KEX_TEST) 76 | 77 | all: arith_test kex_test 78 | 79 | kex_test: $(OBJECTS_KEX_TEST) 80 | $(CC) -o kex_test $(OBJECTS_KEX_TEST) $(ARM_SETTING) 81 | 82 | arith_test: $(OBJECTS_ARITH_TEST) 83 | $(CC) -o arith_test $(OBJECTS_ARITH_TEST) $(ARM_SETTING) 84 | 85 | kex.o: kex.c SIDH_internal.h 86 | $(CC) $(CFLAGS) kex.c 87 | 88 | ec_isogeny.o: ec_isogeny.c SIDH_internal.h 89 | $(CC) $(CFLAGS) ec_isogeny.c 90 | 91 | SIDH.o: SIDH.c SIDH_internal.h 92 | $(CC) $(CFLAGS) SIDH.c 93 | 94 | SIDH_setup.o: SIDH_setup.c SIDH_internal.h 95 | $(CC) $(CFLAGS) SIDH_setup.c 96 | 97 | fpx.o: fpx.c SIDH_internal.h 98 | $(CC) $(CFLAGS) fpx.c 99 | 100 | ifeq "$(GENERIC)" "TRUE" 101 | fp_generic.o: generic/fp_generic.c 102 | $(CC) $(CFLAGS) generic/fp_generic.c 103 | else 104 | ifeq "$(ARCH)" "x64" 105 | fp_x64.o: AMD64/fp_x64.c 106 | $(CC) $(CFLAGS) AMD64/fp_x64.c 107 | 108 | fp_x64_asm.o: AMD64/fp_x64_asm.S 109 | $(CC) $(CFLAGS) AMD64/fp_x64_asm.S 110 | 111 | ifeq "$(ARCH_EX)" "haswell" 112 | 113 | ZREDC_6x4_SH_HW.o: AMD64/ZMULT_HW.h AMD64/ZREDC_6x4_SH_HW.S 114 | $(CC) $(CFLAGS) AMD64/ZREDC_6x4_SH_HW.S 115 | 116 | else ifeq "$(ARCH_EX)" "skylake" 117 | 118 | ZREDC_6x4_SH_SK.o: AMD64/ZMULT_SK.h AMD64/ZREDC_6x4_SH_SK.S 119 | $(CC) $(CFLAGS) AMD64/ZREDC_6x4_SH_SK.S 120 | endif 121 | endif 122 | ifeq "$(ARCH)" "ARM64" 123 | fp_arm64.o: ARM64/fp_arm64.c 124 | $(CC) $(CFLAGS) ARM64/fp_arm64.c 125 | 126 | fp_arm64_asm.o: ARM64/fp_arm64_asm.S 127 | $(CC) $(CFLAGS) ARM64/fp_arm64_asm.S 128 | endif 129 | endif 130 | 131 | test_extras.o: tests/test_extras.c tests/test_extras.h 132 | $(CC) $(CFLAGS) tests/test_extras.c 133 | 134 | arith_tests.o: tests/arith_tests.c SIDH_internal.h 135 | $(CC) $(CFLAGS) tests/arith_tests.c 136 | 137 | kex_tests.o: tests/kex_tests.c SIDH.h 138 | $(CC) $(CFLAGS) tests/kex_tests.c 139 | 140 | .PHONY: clean 141 | 142 | clean: 143 | rm -f arith_test kex_test fp_generic.o fp_x64.o fp_x64_asm.o fp_arm64.o fp_arm64_asm.o ZREDC_6x4_SH_SK.o ZREDC_6x4_SH_HW.o $(OBJECTS_ALL) 144 | 145 | -------------------------------------------------------------------------------- /tests/test/P503_api.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************************** 2 | * SIDH: an efficient supersingular isogeny-based cryptography library 3 | * 4 | * Copyright (c) Microsoft Corporation. All rights reserved. 5 | * 6 | * 7 | * Abstract: API header file for P503 8 | * 9 | *********************************************************************************************/ 10 | 11 | #ifndef __P503_API_H__ 12 | #define __P503_API_H__ 13 | 14 | #include "../config.h" 15 | 16 | 17 | /*********************** Key encapsulation mechanism API ***********************/ 18 | 19 | #define CRYPTO_SECRETKEYBYTES 442 // CRYPTO_BYTES + SECRETKEY_B_BYTES + CRYPTO_PUBLICKEYBYTES bytes 20 | #define CRYPTO_PUBLICKEYBYTES 378 21 | #define CRYPTO_BYTES 32 22 | #define CRYPTO_CIPHERTEXTBYTES 410 // CRYPTO_PUBLICKEYBYTES + CRYPTO_BYTES bytes 23 | 24 | // SIKE's key generation 25 | // It produces a private key sk and computes the public key pk. 26 | // Outputs: secret key sk (CRYPTO_SECRETKEYBYTES = 442 bytes) 27 | // public key pk (CRYPTO_PUBLICKEYBYTES = 378 bytes) 28 | int crypto_kem_keypair(unsigned char *pk, unsigned char *sk); 29 | 30 | // SIKE's encapsulation 31 | // Input: public key pk (CRYPTO_PUBLICKEYBYTES = 378 bytes) 32 | // Outputs: shared secret ss (CRYPTO_BYTES = 32 bytes) 33 | // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = 410 bytes) 34 | int crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); 35 | 36 | // SIKE's decapsulation 37 | // Input: secret key sk (CRYPTO_SECRETKEYBYTES = 442 bytes) 38 | // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = 410 bytes) 39 | // Outputs: shared secret ss (CRYPTO_BYTES = 32 bytes) 40 | int crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); 41 | 42 | 43 | // Encoding of keys for KEM-based isogeny system "SIKEp503" (wire format): 44 | // ---------------------------------------------------------------------- 45 | // Elements over GF(p503) are encoded in 63 octets in little endian format (i.e., the least significant octet is located in the lowest memory address). 46 | // Elements (a+b*i) over GF(p503^2), where a and b are defined over GF(p503), are encoded as {a, b}, with a in the lowest memory portion. 47 | // 48 | // Private keys sk consist of the concatenation of a 32-byte random value and a value in the range [0, 2^252-1]. In the SIDH API, private keys are 49 | // encoded in 64 octets in little endian format (the top 4 bits are zeroes). 50 | // Public keys pk consist of 3 elements in GF(p503^2). In the SIDH API, they are encoded in 378 octets. 51 | // Ciphertexts ct consist of the concatenation of a public key value and a 32-byte value. In the SIDH API, ct is encoded in 378 + 32 = 410 octets. 52 | // Shared keys ss consist of a value of 32 octets. 53 | 54 | 55 | /*********************** Ephemeral key exchange API ***********************/ 56 | 57 | #define SIDH_SECRETKEYBYTES 32 58 | #define SIDH_PUBLICKEYBYTES 378 59 | #define SIDH_BYTES 126 60 | 61 | // SECURITY NOTE: SIDH supports ephemeral Diffie-Hellman key exchange. It is NOT secure to use it with static keys. 62 | // See "On the Security of Supersingular Isogeny Cryptosystems", S.D. Galbraith, C. Petit, B. Shani and Y.B. Ti, in ASIACRYPT 2016, 2016. 63 | // Extended version available at: http://eprint.iacr.org/2016/859 64 | 65 | // Generation of Alice's secret key 66 | // Outputs random value in [0, 2^eA - 1] to be used as Alice's private key 67 | void random_mod_order_A(unsigned char* random_digits); 68 | 69 | // Generation of Bob's secret key 70 | // Outputs random value in [0, 2^Floor(Log(2, oB)) - 1] to be used as Bob's private key 71 | void random_mod_order_B(unsigned char* random_digits); 72 | 73 | // Alice's ephemeral public key generation 74 | // Input: a private key PrivateKeyA in the range [0, oA-1], where oA = 2^250, stored in 32 bytes. 75 | // Output: the public key PublicKeyA consisting of 3 GF(p503^2) elements encoded in 378 bytes. 76 | int EphemeralKeyGeneration_A(const unsigned char* PrivateKeyA, unsigned char* PublicKeyA); 77 | 78 | // Bob's ephemeral key-pair generation 79 | // It produces a private key PrivateKeyB and computes the public key PublicKeyB. 80 | // The private key is an integer in the range [0, 2^Floor(Log(2,oB)) - 1], where oB = 3^159, stored in 32 bytes. 81 | // The public key consists of 3 GF(p503^2) elements encoded in 378 bytes. 82 | int EphemeralKeyGeneration_B(const unsigned char* PrivateKeyB, unsigned char* PublicKeyB); 83 | 84 | // Alice's ephemeral shared secret computation 85 | // It produces a shared secret key SharedSecretA using her secret key PrivateKeyA and Bob's public key PublicKeyB 86 | // Inputs: Alice's PrivateKeyA is an integer in the range [0, oA-1], where oA = 2^250, stored in 32 bytes. 87 | // Bob's PublicKeyB consists of 3 GF(p503^2) elements encoded in 378 bytes. 88 | // Output: a shared secret SharedSecretA that consists of one element in GF(p503^2) encoded in 126 bytes. 89 | int EphemeralSecretAgreement_A(const unsigned char* PrivateKeyA, const unsigned char* PublicKeyB, unsigned char* SharedSecretA); 90 | 91 | // Bob's ephemeral shared secret computation 92 | // It produces a shared secret key SharedSecretB using his secret key PrivateKeyB and Alice's public key PublicKeyA 93 | // Inputs: Bob's PrivateKeyB is an integer in the range [0, 2^Floor(Log(2,oB)) - 1], where oB = 3^159, stored in 32 bytes. 94 | // Alice's PublicKeyA consists of 3 GF(p503^2) elements encoded in 378 bytes. 95 | // Output: a shared secret SharedSecretB that consists of one element in GF(p503^2) encoded in 126 bytes. 96 | int EphemeralSecretAgreement_B(const unsigned char* PrivateKeyB, const unsigned char* PublicKeyA, unsigned char* SharedSecretB); 97 | 98 | 99 | // Encoding of keys for KEX-based isogeny system "SIDHp503" (wire format): 100 | // ---------------------------------------------------------------------- 101 | // Elements over GF(p503) are encoded in 63 octets in little endian format (i.e., the least significant octet is located in the lowest memory address). 102 | // Elements (a+b*i) over GF(p503^2), where a and b are defined over GF(p503), are encoded as {a, b}, with a in the lowest memory portion. 103 | // 104 | // Private keys PrivateKeyA and PrivateKeyB can have values in the range [0, 2^250-1] and [0, 2^252-1], resp. In the SIDH API, private keys are encoded 105 | // in 32 octets in little endian format. 106 | // Public keys PublicKeyA and PublicKeyB consist of 3 elements in GF(p503^2). In the SIDH API, they are encoded in 378 octets. 107 | // Shared keys SharedSecretA and SharedSecretB consist of one element in GF(p503^2). In the SIDH API, they are encoded in 126 octets. 108 | 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /tests/test/P751_api.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************************** 2 | * SIDH: an efficient supersingular isogeny-based cryptography library 3 | * 4 | * Copyright (c) Microsoft Corporation. All rights reserved. 5 | * 6 | * 7 | * Abstract: API header file for P751 8 | * 9 | *********************************************************************************************/ 10 | 11 | #ifndef __P751_API_H__ 12 | #define __P751_API_H__ 13 | 14 | #include "../config.h" 15 | 16 | 17 | /*********************** Key encapsulation mechanism API ***********************/ 18 | 19 | #define CRYPTO_SECRETKEYBYTES 660 // CRYPTO_BYTES + SECRETKEY_B_BYTES + CRYPTO_PUBLICKEYBYTES bytes 20 | #define CRYPTO_PUBLICKEYBYTES 564 21 | #define CRYPTO_BYTES 48 22 | #define CRYPTO_CIPHERTEXTBYTES 612 // CRYPTO_PUBLICKEYBYTES + CRYPTO_BYTES bytes 23 | 24 | // SIKE's key generation 25 | // It produces a private key sk and computes the public key pk. 26 | // Outputs: secret key sk (CRYPTO_SECRETKEYBYTES = 660 bytes) 27 | // public key pk (CRYPTO_PUBLICKEYBYTES = 564 bytes) 28 | int crypto_kem_keypair(unsigned char *pk, unsigned char *sk); 29 | 30 | // SIKE's encapsulation 31 | // Input: public key pk (CRYPTO_PUBLICKEYBYTES = 564 bytes) 32 | // Outputs: shared secret ss (CRYPTO_BYTES = 48 bytes) 33 | // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = 612 bytes) 34 | int crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk); 35 | 36 | // SIKE's decapsulation 37 | // Input: secret key sk (CRYPTO_SECRETKEYBYTES = 660 bytes) 38 | // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = 410 bytes) 39 | // Outputs: shared secret ss (CRYPTO_BYTES = 32 bytes) 40 | int crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); 41 | 42 | 43 | // Encoding of keys for KEM-based isogeny system "SIKEp751" (wire format): 44 | // ---------------------------------------------------------------------- 45 | // Elements over GF(p751) are encoded in 94 octets in little endian format (i.e., the least significant octet is located in the lowest memory address). 46 | // Elements (a+b*i) over GF(p751^2), where a and b are defined over GF(p751), are encoded as {a, b}, with a in the lowest memory portion. 47 | // 48 | // Private keys sk consist of the concatenation of a 48-byte random value and a value in the range [0, 2^378-1]. In the SIDH API, private keys are 49 | // encoded in 96 octets in little endian format (the top 6 bits are zeroes). 50 | // Public keys pk consist of 3 elements in GF(p751^2). In the SIDH API, they are encoded in 564 octets. 51 | // Ciphertexts ct consist of the concatenation of a public key value and a 48-byte value. In the SIDH API, ct is encoded in 564 + 48 = 612 octets. 52 | // Shared keys ss consist of a value of 48 octets. 53 | 54 | 55 | /*********************** Ephemeral key exchange API ***********************/ 56 | 57 | #define SIDH_SECRETKEYBYTES 48 58 | #define SIDH_PUBLICKEYBYTES 564 59 | #define SIDH_BYTES 188 60 | 61 | // SECURITY NOTE: SIDH supports ephemeral Diffie-Hellman key exchange. It is NOT secure to use it with static keys. 62 | // See "On the Security of Supersingular Isogeny Cryptosystems", S.D. Galbraith, C. Petit, B. Shani and Y.B. Ti, in ASIACRYPT 2016, 2016. 63 | // Extended version available at: http://eprint.iacr.org/2016/859 64 | 65 | // Generation of Alice's secret key 66 | // Outputs random value in [0, 2^eA - 1] to be used as Alice's private key 67 | void random_mod_order_A(unsigned char* random_digits); 68 | 69 | // Generation of Bob's secret key 70 | // Outputs random value in [0, 2^Floor(Log(2, oB)) - 1] to be used as Bob's private key 71 | void random_mod_order_B(unsigned char* random_digits); 72 | 73 | // Alice's ephemeral public key generation 74 | // Input: a private key PrivateKeyA in the range [0, oA-1], where oA = 2^372, stored in 47 bytes. 75 | // Output: the public key PublicKeyA consisting of 3 GF(p751^2) elements encoded in 564 bytes. 76 | int EphemeralKeyGeneration_A(const unsigned char* PrivateKeyA, unsigned char* PublicKeyA); 77 | 78 | // Bob's ephemeral key-pair generation 79 | // It produces a private key PrivateKeyB and computes the public key PublicKeyB. 80 | // The private key is an integer in the range [0, 2^Floor(Log(2,oB)) - 1], where oB = 3^239, stored in 48 bytes. 81 | // The public key consists of 3 GF(p751^2) elements encoded in 564 bytes. 82 | int EphemeralKeyGeneration_B(const unsigned char* PrivateKeyB, unsigned char* PublicKeyB); 83 | 84 | // Alice's ephemeral shared secret computation 85 | // It produces a shared secret key SharedSecretA using her secret key PrivateKeyA and Bob's public key PublicKeyB 86 | // Inputs: Alice's PrivateKeyA is an integer in the range [0, oA-1], where oA = 2^372, stored in 47 bytes. 87 | // Bob's PublicKeyB consists of 3 GF(p751^2) elements encoded in 564 bytes. 88 | // Output: a shared secret SharedSecretA that consists of one element in GF(p751^2) encoded in 188 bytes. 89 | int EphemeralSecretAgreement_A(const unsigned char* PrivateKeyA, const unsigned char* PublicKeyB, unsigned char* SharedSecretA); 90 | 91 | // Bob's ephemeral shared secret computation 92 | // It produces a shared secret key SharedSecretB using his secret key PrivateKeyB and Alice's public key PublicKeyA 93 | // Inputs: Bob's PrivateKeyB is an integer in the range [0, 2^Floor(Log(2,oB)) - 1], where oB = 3^239, stored in 48 bytes. 94 | // Alice's PublicKeyA consists of 3 GF(p751^2) elements encoded in 564 bytes. 95 | // Output: a shared secret SharedSecretB that consists of one element in GF(p751^2) encoded in 188 bytes. 96 | int EphemeralSecretAgreement_B(const unsigned char* PrivateKeyB, const unsigned char* PublicKeyA, unsigned char* SharedSecretB); 97 | 98 | 99 | // Encoding of keys for KEX-based isogeny system "SIDHp751" (wire format): 100 | // ---------------------------------------------------------------------- 101 | // Elements over GF(p751) are encoded in 94 octets in little endian format (i.e., the least significant octet is located in the lowest memory address). 102 | // Elements (a+b*i) over GF(p751^2), where a and b are defined over GF(p751), are encoded as {a, b}, with a in the lowest memory portion. 103 | // 104 | // Private keys PrivateKeyA and PrivateKeyB can have values in the range [0, 2^372-1] and [0, 2^378-1], resp. In the SIDH API, private keys are encoded 105 | // in 48 octets in little endian format. 106 | // Public keys PublicKeyA and PublicKeyB consist of 3 elements in GF(p751^2). In the SIDH API, they are encoded in 564 octets. 107 | // Shared keys SharedSecretA and SharedSecretB consist of one element in GF(p751^2). In the SIDH API, they are encoded in 188 octets. 108 | 109 | 110 | #endif 111 | -------------------------------------------------------------------------------- /tests/test/sike.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************************** 2 | * SIDH: an efficient supersingular isogeny-based cryptography library 3 | * 4 | * Copyright (c) Microsoft Corporation. All rights reserved. 5 | * 6 | * 7 | * Abstract: isogeny-based key encapsulation mechanism (KEM) 8 | * 9 | *********************************************************************************************/ 10 | 11 | #include 12 | #include "sha3/fips202.h" 13 | 14 | 15 | int crypto_kem_keypair(unsigned char *pk, unsigned char *sk) 16 | { // SIKE's key generation 17 | // Outputs: secret key sk (CRYPTO_SECRETKEYBYTES = CRYPTO_BYTES + SECRETKEY_B_BYTES + CRYPTO_PUBLICKEYBYTES bytes) 18 | // public key pk (CRYPTO_PUBLICKEYBYTES bytes) 19 | 20 | // Generate lower portion of secret key sk <- s||SK 21 | RandomBytesFunction(sk, CRYPTO_BYTES); 22 | random_mod_order_B(sk + CRYPTO_BYTES); // Get random value in [0, 2^Floor(Log(2,oB))-1] 23 | 24 | // Generate public key pk 25 | EphemeralKeyGeneration_B(sk + CRYPTO_BYTES, pk); 26 | 27 | // Append public key pk to secret key sk 28 | memcpy(&sk[CRYPTO_BYTES + SECRETKEY_B_BYTES], pk, CRYPTO_PUBLICKEYBYTES); 29 | 30 | return 0; 31 | } 32 | 33 | 34 | int crypto_kem_enc(unsigned char *ct, unsigned char *ss, const unsigned char *pk) 35 | { // SIKE's encapsulation 36 | // Input: public key pk (CRYPTO_PUBLICKEYBYTES bytes) 37 | // Outputs: shared secret ss (CRYPTO_BYTES bytes) 38 | // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = CRYPTO_PUBLICKEYBYTES + CRYPTO_BYTES bytes) 39 | const uint16_t G = 0; 40 | const uint16_t H = 1; 41 | const uint16_t P = 2; 42 | unsigned char ephemeralsk[SECRETKEY_A_BYTES]; 43 | unsigned char jinvariant[FP2_ENCODED_BYTES]; 44 | unsigned char h[CRYPTO_BYTES]; 45 | unsigned char message[CRYPTO_BYTES]; 46 | unsigned char temp[SHAKE256_RATE+CRYPTO_CIPHERTEXTBYTES+3]; 47 | unsigned int i; 48 | 49 | // Generate ephemeralsk <- KMAC() mod oA 50 | RandomBytesFunction(message, CRYPTO_BYTES); 51 | kmac256_simple(ephemeralsk, SECRETKEY_A_BYTES, G, pk, (unsigned long long)CRYPTO_PUBLICKEYBYTES, message, CRYPTO_BYTES, temp); 52 | ephemeralsk[SECRETKEY_A_BYTES - 1] &= MASK_ALICE; 53 | 54 | // Encrypt 55 | EphemeralKeyGeneration_A(ephemeralsk, ct); 56 | EphemeralSecretAgreement_A(ephemeralsk, pk, jinvariant); 57 | cshake256_simple(h, CRYPTO_BYTES, P, jinvariant, FP2_ENCODED_BYTES); // TODO: PRF 58 | for (i = 0; i < CRYPTO_BYTES; i++) ct[i + CRYPTO_PUBLICKEYBYTES] = message[i] ^ h[i]; 59 | 60 | // Generate shared secret ss <- KMAC() 61 | kmac256_simple(ss, CRYPTO_BYTES, H, ct, (unsigned long long)CRYPTO_CIPHERTEXTBYTES, message, CRYPTO_BYTES, temp); 62 | 63 | return 0; 64 | } 65 | 66 | 67 | int crypto_kem_dec(unsigned char *ss, const unsigned char *ct, const unsigned char *sk) 68 | { // SIKE's decapsulation 69 | // Input: secret key sk (CRYPTO_SECRETKEYBYTES = CRYPTO_BYTES + SECRETKEY_B_BYTES + CRYPTO_PUBLICKEYBYTES bytes) 70 | // ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = CRYPTO_PUBLICKEYBYTES + CRYPTO_BYTES bytes) 71 | // Outputs: shared secret ss (CRYPTO_BYTES bytes) 72 | const uint16_t G = 0; 73 | const uint16_t H = 1; 74 | const uint16_t P = 2; 75 | unsigned char ephemeralsk_[SECRETKEY_A_BYTES]; 76 | unsigned char jinvariant_[FP2_ENCODED_BYTES]; 77 | unsigned char h_[CRYPTO_BYTES]; 78 | unsigned char message_[CRYPTO_BYTES]; 79 | unsigned char c0_[CRYPTO_PUBLICKEYBYTES]; 80 | unsigned char pk[CRYPTO_PUBLICKEYBYTES]; 81 | unsigned char temp[SHAKE256_RATE+CRYPTO_CIPHERTEXTBYTES+3]; 82 | unsigned int i; 83 | 84 | // Decrypt 85 | EphemeralSecretAgreement_B(sk + CRYPTO_BYTES, ct, jinvariant_); 86 | cshake256_simple(h_, CRYPTO_BYTES, P, jinvariant_, FP2_ENCODED_BYTES); // TODO: PRF 87 | for (i = 0; i < CRYPTO_BYTES; i++) message_[i] = ct[i + CRYPTO_PUBLICKEYBYTES] ^ h_[i]; 88 | 89 | // Generate ephemeralsk_ <- KMAC() mod oA 90 | memcpy(pk, &sk[CRYPTO_BYTES + SECRETKEY_B_BYTES], CRYPTO_PUBLICKEYBYTES); 91 | kmac256_simple(ephemeralsk_, SECRETKEY_A_BYTES, G, pk, (unsigned long long)CRYPTO_PUBLICKEYBYTES, message_, CRYPTO_BYTES, temp); 92 | ephemeralsk_[SECRETKEY_A_BYTES - 1] &= MASK_ALICE; 93 | 94 | EphemeralKeyGeneration_A(ephemeralsk_, c0_); 95 | if (memcmp(c0_, ct, CRYPTO_PUBLICKEYBYTES) == 0) { 96 | kmac256_simple(ss, CRYPTO_BYTES, H, ct, (unsigned long long)CRYPTO_CIPHERTEXTBYTES, message_, CRYPTO_BYTES, temp); 97 | } else { 98 | kmac256_simple(ss, CRYPTO_BYTES, H, ct, (unsigned long long)CRYPTO_CIPHERTEXTBYTES, sk, CRYPTO_BYTES, temp); 99 | } 100 | 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /tests/test_extras.c: -------------------------------------------------------------------------------- 1 | /******************************************************************************************** 2 | * SIDH: an efficient supersingular isogeny-based cryptography library for ephemeral 3 | * Diffie-Hellman key exchange. 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * 7 | * 8 | * Abstract: utility functions for testing and benchmarking 9 | * 10 | *********************************************************************************************/ 11 | 12 | 13 | #include "../SIDH_internal.h" 14 | #include "test_extras.h" 15 | #if (OS_TARGET == OS_WIN) 16 | #include 17 | #include 18 | #endif 19 | #if (OS_TARGET == OS_LINUX) && (TARGET == TARGET_ARM || TARGET == TARGET_ARM64) 20 | #include 21 | #endif 22 | #include 23 | 24 | 25 | // Global constants 26 | extern const uint64_t p751[NWORDS_FIELD]; 27 | extern const uint64_t Montgomery_R2[NWORDS_FIELD]; 28 | 29 | // Montgomery constant -p751^-1 mod 2^768 30 | static uint64_t Montgomery_pp751[NWORDS_FIELD] = { 0x0000000000000001, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0xEEB0000000000000, 31 | 0xE3EC968549F878A8, 0xDA959B1A13F7CC76, 0x084E9867D6EBE876, 0x8562B5045CB25748, 0x0E12909F97BADC66, 0x258C28E5D541F71C }; 32 | 33 | 34 | int64_t cpucycles(void) 35 | { // Access system counter for benchmarking 36 | #if (OS_TARGET == OS_WIN) && (TARGET == TARGET_AMD64 || TARGET == TARGET_x86) 37 | return __rdtsc(); 38 | #elif (OS_TARGET == OS_WIN) && (TARGET == TARGET_ARM) 39 | return __rdpmccntr64(); 40 | #elif (OS_TARGET == OS_LINUX) && (TARGET == TARGET_AMD64 || TARGET == TARGET_x86) 41 | unsigned int hi, lo; 42 | 43 | __asm__ __volatile__ ("rdtsc\n\t" : "=a" (lo), "=d"(hi)); 44 | return ((int64_t)lo) | (((int64_t)hi) << 32); 45 | #elif (OS_TARGET == OS_LINUX) && (TARGET == TARGET_ARM || TARGET == TARGET_ARM64) 46 | struct timespec time; 47 | 48 | clock_gettime(CLOCK_REALTIME, &time); 49 | return (int64_t)(time.tv_sec*1e9 + time.tv_nsec); 50 | #else 51 | return 0; 52 | #endif 53 | } 54 | 55 | 56 | CRYPTO_STATUS random_bytes_test(unsigned int nbytes, unsigned char* random_array) 57 | { // Generate "nbytes" random bytes and output the result to random_array 58 | // Returns CRYPTO_SUCCESS (=1) on success, CRYPTO_ERROR (=0) otherwise. 59 | // SECURITY NOTE: TO BE USED FOR TESTING ONLY. 60 | unsigned int i; 61 | 62 | if (nbytes == 0) { 63 | return CRYPTO_ERROR; 64 | } 65 | 66 | for (i = 0; i < nbytes; i++) { 67 | *(random_array + i) = (unsigned char)rand(); // nbytes of random values 68 | } 69 | 70 | return CRYPTO_SUCCESS; 71 | } 72 | 73 | 74 | int compare_words(digit_t* a, digit_t* b, unsigned int nwords) 75 | { // Comparing "nword" elements, a=b? : (1) a!=b, (0) a=b 76 | // SECURITY NOTE: this function does not have constant-time execution. TO BE USED FOR TESTING ONLY. 77 | unsigned int i; 78 | 79 | for (i = 0; i < nwords; i++) 80 | { 81 | if (a[i] != b[i]) return 1; 82 | } 83 | 84 | return 0; 85 | } 86 | 87 | 88 | 89 | static __inline void sub751_test(felm_t a, felm_t b, felm_t c) 90 | { // 751-bit subtraction without borrow, c = a-b where a>b 91 | // SECURITY NOTE: this function does not have constant-time execution. It is for TESTING ONLY. 92 | unsigned int i; 93 | digit_t res, carry, borrow = 0; 94 | 95 | for (i = 0; i < NWORDS_FIELD; i++) 96 | { 97 | res = a[i] - b[i]; 98 | carry = (a[i] < b[i]); 99 | c[i] = res - borrow; 100 | borrow = carry || (res < borrow); 101 | } 102 | 103 | return; 104 | } 105 | 106 | 107 | void fprandom751_test(felm_t a) 108 | { // Generating a pseudo-random field element in [0, p751-1] 109 | // SECURITY NOTE: distribution is not fully uniform. TO BE USED FOR TESTING ONLY. 110 | unsigned int i; 111 | int diff = 768-751; 112 | unsigned char* string = NULL; 113 | 114 | string = (unsigned char*)a; 115 | for (i = 0; i < sizeof(digit_t)*NWORDS_FIELD; i++) { 116 | *(string + i) = (unsigned char)rand(); // Obtain 768-bit number 117 | } 118 | a[NWORDS_FIELD-1] &= (((digit_t)(-1) << diff) >> diff); 119 | 120 | while (fpcompare751((digit_t*)p751, a) < 1) { // Force it to [0, modulus-1] 121 | sub751_test(a, (digit_t*)p751, a); 122 | } 123 | 124 | return; 125 | } 126 | 127 | 128 | void fp2random751_test(f2elm_t a) 129 | { // Generating a pseudo-random element in GF(p751^2) 130 | // SECURITY NOTE: distribution is not fully uniform. TO BE USED FOR TESTING ONLY. 131 | 132 | fprandom751_test(a[0]); 133 | fprandom751_test(a[1]); 134 | } 135 | 136 | 137 | int fpcompare751(felm_t a, felm_t b) 138 | { // Comparing two field elements, a=b? : (1) a>b, (0) a=b, (-1) a= 0; i--) 143 | { 144 | if (a[i] > b[i]) return 1; 145 | else if (a[i] < b[i]) return -1; 146 | } 147 | 148 | return 0; 149 | } 150 | 151 | 152 | int fp2compare751(f2elm_t a, f2elm_t b) 153 | { // Comparing two quadratic extension field elements, ai=bi? : (1) ai!=bi, (0) ai=bi 154 | // SECURITY NOTE: this function does not have constant-time execution. TO BE USED FOR TESTING ONLY. 155 | 156 | if (fpcompare751(a[0], b[0])!=0 || fpcompare751(a[1], b[1])!=0) return 1; 157 | return 0; 158 | } 159 | 160 | 161 | static __inline void mp_mul_basic(digit_t* a, digit_t* b, digit_t* c, unsigned int nwords) 162 | { // Multiprecision schoolbook multiprecision multiply, c = a*b, where lng(a) = lng(b) = nwords. 163 | unsigned int i, j; 164 | digit_t u, v, UV[2]; 165 | unsigned int carry = 0; 166 | 167 | for (i = 0; i < (2*nwords); i++) c[i] = 0; 168 | 169 | for (i = 0; i < nwords; i++) { 170 | u = 0; 171 | for (j = 0; j < nwords; j++) { 172 | MUL(a[i], b[j], UV+1, UV[0]); 173 | ADDC(0, UV[0], u, carry, v); 174 | u = UV[1] + carry; 175 | ADDC(0, c[i+j], v, carry, v); 176 | u = u + carry; 177 | c[i+j] = v; 178 | } 179 | c[nwords+i] = u; 180 | } 181 | } 182 | 183 | 184 | void fpmul751_mont_basic(felm_t ma, felm_t mb, felm_t mc) 185 | { // Basic Montgomery multiplication, mc = ma*mb*R^-1 mod p751, where ma,mb,mc in [0, p751-1] and R = 2^768. 186 | // ma and mb are assumed to be in Montgomery representation. 187 | // The Montgomery constant pp751 = -p751^(-1) mod R is the global value "Montgomery_pp751". 188 | unsigned int i, bout = 0; 189 | digit_t mask, P[2*NWORDS_FIELD], Q[2*NWORDS_FIELD], temp[2*NWORDS_FIELD]; 190 | 191 | mp_mul_basic(ma, mb, P, NWORDS_FIELD); // P = ma * mb 192 | mp_mul_basic(P, (digit_t*)&Montgomery_pp751, Q, NWORDS_FIELD); // Q = P * pp751 mod R 193 | mp_mul_basic(Q, (digit_t*)&p751, temp, NWORDS_FIELD); // temp = Q * p751 194 | mp_add(P, temp, temp, 2*NWORDS_FIELD); // temp = P + Q * p751 195 | 196 | for (i = 0; i < NWORDS_FIELD; i++) { // mc = (P + Q * p751)/R 197 | mc[i] = temp[NWORDS_FIELD+i]; 198 | } 199 | 200 | // Final, constant-time subtraction 201 | bout = mp_sub(mc, (digit_t*)&p751, mc, NWORDS_FIELD); // (bout, mc) = mc - p751 202 | mask = 0 - (digit_t)bout; // if mc < 0 then mask = 0xFF..F, else if mc >= 0 then mask = 0x00..0 203 | 204 | for (i = 0; i < NWORDS_FIELD; i++) { // temp = mask & p751 205 | temp[i] = (((digit_t*)p751)[i] & mask); 206 | } 207 | mp_add(mc, temp, mc, NWORDS_FIELD); // mc = mc + (mask & p751) 208 | 209 | return; 210 | } 211 | 212 | 213 | void to_mont_basic(felm_t a, felm_t mc) 214 | { // Conversion to Montgomery representation 215 | // mc = a*R^2*R^-1 mod p751 = a*R mod p751, where a in [0, p751-1] 216 | // The Montgomery constant R^2 mod p751 is the global value "Montgomery_R2". 217 | 218 | fpmul751_mont_basic(a, (digit_t*)&Montgomery_R2, mc); 219 | } 220 | 221 | 222 | void from_mont_basic(felm_t ma, felm_t c) 223 | { // Conversion from Montgomery representation to standard representation 224 | // c = ma*R^-1 mod p751 = a mod p751, where ma in [0, p751-1]. 225 | digit_t one[NWORDS_FIELD] = {0}; 226 | 227 | one[0] = 1; 228 | fpmul751_mont_basic(ma, one, c); 229 | } 230 | -------------------------------------------------------------------------------- /tests/test_extras.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************************** 2 | * SIDH: an efficient supersingular isogeny-based cryptography library for ephemeral 3 | * Diffie-Hellman key exchange. 4 | * 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * 7 | * 8 | * Abstract: utility header file for tests 9 | * 10 | *********************************************************************************************/ 11 | 12 | #ifndef __TEST_EXTRAS_H__ 13 | #define __TEST_EXTRAS_H__ 14 | 15 | 16 | // For C++ 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | 22 | #include "../SIDH_internal.h" 23 | 24 | 25 | #if (TARGET == TARGET_ARM || TARGET == TARGET_ARM64) 26 | #define print_unit printf("nsec"); 27 | #else 28 | #define print_unit printf("cycles"); 29 | #endif 30 | 31 | 32 | // Access system counter for benchmarking 33 | int64_t cpucycles(void); 34 | 35 | // Generate "nbytes" random bytes and output the result to random_array 36 | CRYPTO_STATUS random_bytes_test(unsigned int nbytes, unsigned char* random_array); 37 | 38 | // Comparing "nword" elements, a=b? : (1) a!=b, (0) a=b 39 | int compare_words(digit_t* a, digit_t* b, unsigned int nwords); 40 | 41 | // Generating a pseudo-random field element in [0, p751-1] 42 | void fprandom751_test(felm_t a); 43 | 44 | // Generating a pseudo-random element in GF(p751^2) 45 | void fp2random751_test(f2elm_t a); 46 | 47 | // Comparing two field elements, a=b? : (1) a>b, (0) a=b, (-1) a