Merge remote-tracking branch 'upstream/master'

Merge with master after SIDH addition.
This commit is contained in:
Christian Paquin 2016-11-28 11:32:06 -05:00
commit 6119d1e730
23 changed files with 6191 additions and 8 deletions

View File

@ -60,6 +60,7 @@ links:
$(LN) ../../src/kex_rlwe_newhope/kex_rlwe_newhope.h include/oqs
$(LN) ../../src/kex_rlwe_msrln16/kex_rlwe_msrln16.h include/oqs
$(LN) ../../src/kex_lwe_frodo/kex_lwe_frodo.h include/oqs
$(LN) ../../src/kex_sidh_cln16/kex_sidh_cln16.h include/oqs
$(LN) ../../src/rand/rand.h include/oqs
$(LN) ../../src/rand_urandom_chacha20/rand_urandom_chacha20.h include/oqs
$(LN) ../../src/rand_urandom_aesctr/rand_urandom_aesctr.h include/oqs
@ -96,6 +97,11 @@ KEX_LWE_FRODO_OBJS := $(addprefix objs/kex_lwe_frodo/, lwe.o kex_lwe_frodo.o lwe
KEX_LWE_FRODO_HEADERS := $(addprefix src/kex_lwe_frodo/, kex_lwe_frodo.h local.h)
$(KEX_LWE_FRODO_OBJS): $(KEX_LWE_FRODO_HEADERS)
# KEX_SIDH_CLN16
KEX_SIDH_CLN16_OBJS := $(addprefix objs/kex_sidh_cln16/, ec_isogeny.o fpx.o kex_sidh_cln16.o SIDH.o sidh_kex.o SIDH_setup.o validate.o)
KEX_SIDH_CLN16_HEADERS := $(addprefix src/kex_sidh_cln16/, kex_sidh_cln16.h SIDH.h)
$(KEX_SIDH_CLN16_OBJS): $(KEX_SIDH_CLN16_HEADERS)
# AES
AES_OBJS := $(addprefix objs/aes/, aes.o aes_c.o aes_ni.o)
AES_HEADERS := $(addprefix src/aes/, aes.h)
@ -115,7 +121,7 @@ objs/kex/kex.o: src/kex/kex.h
RAND_OBJS := $(RAND_URANDOM_AESCTR_OBJS) $(RAND_URANDOM_CHACHA_OBJS)
lib: $(RAND_OBJS) $(KEX_RLWE_BCNS15_OBJS) $(KEX_RLWE_NEWHOPE_OBJS) $(KEX_LWE_FRODO_OBJS) $(KEX_RLWE_MSRLN16_OBJS) objs/rand/rand.o objs/kex/kex.o $(AES_OBJS) $(COMMON_OBJS)
lib: $(RAND_OBJS) $(KEX_RLWE_BCNS15_OBJS) $(KEX_RLWE_NEWHOPE_OBJS) $(KEX_RLWE_MSRLN16_OBJS) $(KEX_LWE_FRODO_OBJS) $(KEX_SIDH_CLN16_OBJS) objs/rand/rand.o objs/kex/kex.o $(AES_OBJS) $(COMMON_OBJS)
rm -f liboqs.a
$(AR) liboqs.a $^
$(RANLIB) liboqs.a

View File

@ -23,11 +23,11 @@ Contents
liboqs currently contains:
- `rand_urandom_chacha20`: pseudorandom number generator seeded from /dev/urandom and expanded using the ChaCha20 stream cipher
- `kex_rlwe_bcns15`: key exchange from the ring learning with errors problem (Bos, Costello, Naehrig, Stebila, *IEEE Symposium on Security & Privacy 2015*, [https://eprint.iacr.org/2014/599](https://eprint.iacr.org/2014/599))
- `kex_rlwe_newhope`: "NewHope": key exchange from the ring learning with errors problem (Alkim, Ducas, Pöppelmann, Schwabe, *USENIX Security 2016*, [https://eprint.iacr.org/2015/1092](https://eprint.iacr.org/2015/1092)) (using the reference C implementation of NewHope from [https://github.com/tpoeppelmann/newhope](https://github.com/tpoeppelmann/newhope))
- `kex_rlwe_msrln16`: Microsoft Research implementation of Peikert's ring-LWE key exchange (Longa, Naehrig, *CANS 2016*, [https://eprint.iacr.org/2016/504](https://eprint.iacr.org/2016/504)) (based on the implementation of Alkim, Ducas, Pöppelmann, and Schwabe, with improvements from Longa and Naehrig, see [https://www.microsoft.com/en-us/research/project/lattice-cryptography-library/](https://www.microsoft.com/en-us/research/project/lattice-cryptography-library/))
- `kex_lwe_frodo`: key exchange from the learning with errors problem (Bos, Costello, Ducas, Mironov, Naehrig, Nikolaenko, Raghunathan, Stebila, *ACM Conference on Computer and Communications Security 2016*, [http://eprint.iacr.org/2016/659](http://eprint.iacr.org/2016/659))
- `kex_lwe_frodo`: "Frodo": key exchange from the learning with errors problem (Bos, Costello, Ducas, Mironov, Naehrig, Nikolaenko, Raghunathan, Stebila, *ACM Conference on Computer and Communications Security 2016*, [http://eprint.iacr.org/2016/659](http://eprint.iacr.org/2016/659))
- `kex_sidh_cln16`: key exchange from the supersingular isogeny Diffie-Hellman problem (Costello, Naehrig, Longa, *CRYPTO 2016*, [https://eprint.iacr.org/2016/413](https://eprint.iacr.org/2016/413)), using the implementation of Microsoft Research [https://www.microsoft.com/en-us/research/project/sidh-library/](https://www.microsoft.com/en-us/research/project/sidh-library/)
Building and Running
--------------------
@ -93,6 +93,7 @@ Since our initial launch, we have made the following updates:
- Use of travis continuous integration system for testing
- `kex_rlwe_newhope` wrapper
- `kex_rlwe_msrln16` implementation contributed by Christian Paquin (Microsoft Research)
- `kex_sidh_cln16` implementation contributed by Christian Paquin (Microsoft Research)
Our plans for the next few months can be found in [Milestone 1 - Key exchange](https://github.com/open-quantum-safe/liboqs/projects/2).
@ -103,10 +104,12 @@ License
liboqs is licensed under the MIT License; see [LICENSE.txt](https://github.com/open-quantum-safe/liboqs/blob/master/LICENSE.txt) for details. liboqs includes some third party libraries or modules that are licensed differently; the corresponding subfolder contains the license that applies in that case. In particular:
- `src/aes/aes.c`: public domain
- `src/kex_rlwe_bcns15`: public domain ([Unlicense](http://unlicense.org))
- `src/kex_rlwe_msrln16`: MIT License
- `src/kex_rlwe_msrln16/external`: public domain ([CC0](http://creativecommons.org/publicdomain/zero/1.0/))
- `src/kex_rlwe_newhope`: public domain
- `src/kex_sidh_cln16`: MIT License
- `src/rand_urandom_chacha20/external`: public domain
Team

View File

@ -32,6 +32,9 @@
<ClInclude Include="..\..\src\kex_rlwe_msrln16\kex_rlwe_msrln16.h" />
<ClInclude Include="..\..\src\kex_rlwe_msrln16\LatticeCrypto.h" />
<ClInclude Include="..\..\src\kex_rlwe_msrln16\LatticeCrypto_priv.h" />
<ClInclude Include="..\..\src\kex_sidh_cln16\kex_sidh_cln16.h" />
<ClInclude Include="..\..\src\kex_sidh_cln16\SIDH.h" />
<ClInclude Include="..\..\src\kex_sidh_cln16\SIDH_internal.h" />
<ClInclude Include="..\..\src\rand\rand.h" />
<ClInclude Include="..\..\src\rand_urandom_aesctr\rand_urandom_aesctr.h" />
<ClInclude Include="..\..\src\rand_urandom_chacha20\rand_urandom_chacha20.h" />
@ -53,6 +56,13 @@
<ClCompile Include="..\..\src\kex_rlwe_msrln16\kex_rlwe_msrln16.c" />
<ClCompile Include="..\..\src\kex_rlwe_msrln16\LatticeCrypto_kex.c" />
<ClCompile Include="..\..\src\kex_rlwe_msrln16\ntt_constants.c" />
<ClCompile Include="..\..\src\kex_sidh_cln16\ec_isogeny.c" />
<ClCompile Include="..\..\src\kex_sidh_cln16\fpx.c" />
<ClCompile Include="..\..\src\kex_sidh_cln16\kex_sidh_cln16.c" />
<ClCompile Include="..\..\src\kex_sidh_cln16\SIDH.c" />
<ClCompile Include="..\..\src\kex_sidh_cln16\sidh_kex.c" />
<ClCompile Include="..\..\src\kex_sidh_cln16\SIDH_setup.c" />
<ClCompile Include="..\..\src\kex_sidh_cln16\validate.c" />
<ClCompile Include="..\..\src\rand\rand.c" />
<ClCompile Include="..\..\src\rand_urandom_aesctr\rand_urandom_aesctr.c" />
<ClCompile Include="..\..\src\rand_urandom_chacha20\rand_urandom_chacha20.c" />
@ -141,7 +151,8 @@ copy "$(SolutionDir)..\src\aes\aes.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_rlwe_bcns15\kex_rlwe_bcns15.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_rlwe_newhope\kex_rlwe_newhope.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_rlwe_msrln16\kex_rlwe_msrln16.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_lwe_frodo\kex_lwe_frodo.h" "$(SolutionDir)include\oqs\"</Command>
copy "$(SolutionDir)..\src\kex_lwe_frodo\kex_lwe_frodo.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_sidh_cln16\kex_sidh_cln16.h" "$(SolutionDir)include\oqs\"</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -169,7 +180,8 @@ copy "$(SolutionDir)..\src\aes\aes.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_rlwe_bcns15\kex_rlwe_bcns15.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_rlwe_newhope\kex_rlwe_newhope.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_rlwe_msrln16\kex_rlwe_msrln16.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_lwe_frodo\kex_lwe_frodo.h" "$(SolutionDir)include\oqs\"</Command>
copy "$(SolutionDir)..\src\kex_lwe_frodo\kex_lwe_frodo.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_sidh_cln16\kex_sidh_cln16.h" "$(SolutionDir)include\oqs\"</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -201,7 +213,8 @@ copy "$(SolutionDir)..\src\aes\aes.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_rlwe_bcns15\kex_rlwe_bcns15.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_rlwe_newhope\kex_rlwe_newhope.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_rlwe_msrln16\kex_rlwe_msrln16.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_lwe_frodo\kex_lwe_frodo.h" "$(SolutionDir)include\oqs\"</Command>
copy "$(SolutionDir)..\src\kex_lwe_frodo\kex_lwe_frodo.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_sidh_cln16\kex_sidh_cln16.h" "$(SolutionDir)include\oqs\"</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -233,7 +246,8 @@ copy "$(SolutionDir)..\src\aes\aes.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_rlwe_bcns15\kex_rlwe_bcns15.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_rlwe_newhope\kex_rlwe_newhope.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_rlwe_msrln16\kex_rlwe_msrln16.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_lwe_frodo\kex_lwe_frodo.h" "$(SolutionDir)include\oqs\"</Command>
copy "$(SolutionDir)..\src\kex_lwe_frodo\kex_lwe_frodo.h" "$(SolutionDir)include\oqs\"
copy "$(SolutionDir)..\src\kex_sidh_cln16\kex_sidh_cln16.h" "$(SolutionDir)include\oqs\"</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@ -56,6 +56,27 @@
<ClCompile Include="..\..\src\kex_rlwe_bcns15\rlwe_kex.c">
<Filter>BCNS15</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kex_sidh_cln16\ec_isogeny.c">
<Filter>SIDH CLN16</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kex_sidh_cln16\fpx.c">
<Filter>SIDH CLN16</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kex_sidh_cln16\kex_sidh_cln16.c">
<Filter>SIDH CLN16</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kex_sidh_cln16\SIDH.c">
<Filter>SIDH CLN16</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kex_sidh_cln16\sidh_kex.c">
<Filter>SIDH CLN16</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kex_sidh_cln16\SIDH_setup.c">
<Filter>SIDH CLN16</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kex_sidh_cln16\validate.c">
<Filter>SIDH CLN16</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\kex\kex.h" />
@ -104,6 +125,15 @@
<ClInclude Include="..\..\src\kex_rlwe_bcns15\rlwe_a.h">
<Filter>BCNS15</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kex_sidh_cln16\kex_sidh_cln16.h">
<Filter>SIDH CLN16</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kex_sidh_cln16\SIDH.h">
<Filter>SIDH CLN16</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kex_sidh_cln16\SIDH_internal.h">
<Filter>SIDH CLN16</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="AES">
@ -124,5 +154,8 @@
<Filter Include="MSR LN16">
<UniqueIdentifier>{9f5ed87f-ed1e-47b4-b7e7-1d6648cb88fd}</UniqueIdentifier>
</Filter>
<Filter Include="SIDH CLN16">
<UniqueIdentifier>{3e550d03-8fd0-4307-ad38-832effa40102}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

View File

@ -5,6 +5,7 @@
#include <oqs/kex_rlwe_newhope.h>
#include <oqs/kex_rlwe_msrln16.h>
#include <oqs/kex_lwe_frodo.h>
#include <oqs/kex_sidh_cln16.h>
OQS_KEX *OQS_KEX_new(OQS_RAND *rand, enum OQS_KEX_alg_name alg_name, const uint8_t *seed, const size_t seed_len, const char *named_parameters) {
switch (alg_name) {
@ -18,6 +19,8 @@ OQS_KEX *OQS_KEX_new(OQS_RAND *rand, enum OQS_KEX_alg_name alg_name, const uint8
return OQS_KEX_rlwe_newhope_new(rand);
case OQS_KEX_alg_lwe_frodo:
return OQS_KEX_lwe_frodo_new(rand, seed, seed_len, named_parameters);
case OQS_KEX_alg_sidh_cln16:
return OQS_KEX_sidh_cln16_new(rand);
default:
assert(0);
return NULL;

View File

@ -17,6 +17,7 @@ enum OQS_KEX_alg_name {
OQS_KEX_alg_rlwe_newhope,
OQS_KEX_alg_rlwe_msrln16,
OQS_KEX_alg_lwe_frodo,
OQS_KEX_alg_sidh_cln16,
};
typedef struct OQS_KEX OQS_KEX;

View File

@ -23,6 +23,7 @@ struct kex_testcase kex_testcases[] = {
{ OQS_KEX_alg_rlwe_newhope, NULL, 0, NULL, "rlwe_newhope", 0 },
{ OQS_KEX_alg_rlwe_msrln16, NULL, 0, NULL, "rlwe_msrln16", 0 },
{ OQS_KEX_alg_lwe_frodo, (unsigned char *) "01234567890123456", 16, "recommended", "lwe_frodo_recommended", 0 },
{ OQS_KEX_alg_sidh_cln16, NULL, 0, NULL, "sidh_cln16", 0 },
};
#define KEX_TEST_ITERATIONS 100
@ -280,7 +281,12 @@ int main(int argc, char **argv) {
for (size_t i = 0; i < kex_testcases_len; i++) {
if (run_all || kex_testcases[i].run == 1) {
success = kex_test_correctness_wrapper(rand, kex_testcases[i].alg_name, kex_testcases[i].seed, kex_testcases[i].seed_len, kex_testcases[i].named_parameters, KEX_TEST_ITERATIONS);
int num_iter = KEX_TEST_ITERATIONS;
if (kex_testcases[i].alg_name == OQS_KEX_alg_sidh_cln16) {
// SIDH is slower than the other schemes, so we reduce the number of runs
num_iter = KEX_TEST_ITERATIONS / 10;
}
success = kex_test_correctness_wrapper(rand, kex_testcases[i].alg_name, kex_testcases[i].seed, kex_testcases[i].seed_len, kex_testcases[i].named_parameters, num_iter);
}
if (success != 1) {
goto err;

View File

@ -0,0 +1,865 @@
/********************************************************************************************
* SIDH: an efficient supersingular isogeny-based cryptography library for Diffie-Hellman key
* exchange providing 128 bits of quantum security and 192 bits of classical security.
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*
* Abstract: modular arithmetic optimized for x64 platforms
*
*********************************************************************************************/
#include "../SIDH_internal.h"
// Global constants
extern const uint64_t p751[NWORDS_FIELD];
extern const uint64_t p751p1[NWORDS_FIELD];
extern const uint64_t p751x2[NWORDS_FIELD];
__inline void oqs_sidh_cln16_fpadd751(digit_t* a, digit_t* b, digit_t* c)
{ // Modular addition, c = a+b mod p751.
// Inputs: a, b in [0, 2*p751-1]
// Output: c in [0, 2*p751-1]
#if (OS_TARGET == OS_WIN)
unsigned int i, carry = 0;
digit_t mask;
for (i = 0; i < NWORDS_FIELD; i++) {
ADDC(carry, a[i], b[i], carry, c[i]);
}
carry = 0;
for (i = 0; i < NWORDS_FIELD; i++) {
SUBC(carry, c[i], ((digit_t*)p751x2)[i], carry, c[i]);
}
mask = 0 - (digit_t)carry;
carry = 0;
for (i = 0; i < NWORDS_FIELD; i++) {
ADDC(carry, c[i], ((digit_t*)p751x2)[i] & mask, carry, c[i]);
}
#elif (OS_TARGET == OS_LINUX)
oqs_sidh_cln16_fpadd751_asm(a, b, c);
#endif
}
__inline void oqs_sidh_cln16_fpsub751(digit_t* a, digit_t* b, digit_t* c)
{ // Modular subtraction, c = a-b mod p751.
// Inputs: a, b in [0, 2*p751-1]
// Output: c in [0, 2*p751-1]
#if (OS_TARGET == OS_WIN)
unsigned int i, borrow = 0;
digit_t mask;
for (i = 0; i < NWORDS_FIELD; i++) {
SUBC(borrow, a[i], b[i], borrow, c[i]);
}
mask = 0 - (digit_t)borrow;
borrow = 0;
for (i = 0; i < NWORDS_FIELD; i++) {
ADDC(borrow, c[i], ((digit_t*)p751x2)[i] & mask, borrow, c[i]);
}
#elif (OS_TARGET == OS_LINUX)
oqs_sidh_cln16_fpsub751_asm(a, b, c);
#endif
}
__inline void oqs_sidh_cln16_fpneg751(digit_t* a)
{ // Modular negation, a = -a mod p751.
// Input/output: a in [0, 2*p751-1]
unsigned int i, borrow = 0;
for (i = 0; i < NWORDS_FIELD; i++) {
SUBC(borrow, ((digit_t*)p751x2)[i], a[i], borrow, a[i]);
}
}
void oqs_sidh_cln16_fpdiv2_751(digit_t* a, digit_t* c)
{ // Modular division by two, c = a/2 mod p751.
// Input : a in [0, 2*p751-1]
// Output: c in [0, 2*p751-1]
unsigned int i, carry = 0;
digit_t mask;
mask = 0 - (digit_t)(a[0] & 1); // If a is odd compute a+p521
for (i = 0; i < NWORDS_FIELD; i++) {
ADDC(carry, a[i], ((digit_t*)p751)[i] & mask, carry, c[i]);
}
oqs_sidh_cln16_mp_shiftr1(c, NWORDS_FIELD);
}
void oqs_sidh_cln16_fpcorrection751(digit_t* a)
{ // Modular correction to reduce field element a in [0, 2*p751-1] to [0, p751-1].
unsigned int i, borrow = 0;
digit_t mask;
for (i = 0; i < NWORDS_FIELD; i++) {
SUBC(borrow, a[i], ((digit_t*)p751)[i], borrow, a[i]);
}
mask = 0 - (digit_t)borrow;
borrow = 0;
for (i = 0; i < NWORDS_FIELD; i++) {
ADDC(borrow, a[i], ((digit_t*)p751)[i] & mask, borrow, a[i]);
}
}
void oqs_sidh_cln16_mp_mul(digit_t* a, digit_t* b, digit_t* c, unsigned int nwords)
{ // Multiprecision multiply, c = a*b, where lng(a) = lng(b) = nwords.
UNREFERENCED_PARAMETER(nwords);
#if (OS_TARGET == OS_WIN)
digit_t t = 0;
uint128_t uv = {0};
unsigned int carry = 0;
MULADD128(a[0], b[0], uv, carry, uv);
t += carry;
c[0] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[0], b[1], uv, carry, uv);
t += carry;
MULADD128(a[1], b[0], uv, carry, uv);
t += carry;
c[1] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[0], b[2], uv, carry, uv);
t += carry;
MULADD128(a[1], b[1], uv, carry, uv);
t += carry;
MULADD128(a[2], b[0], uv, carry, uv);
t += carry;
c[2] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[0], b[3], uv, carry, uv);
t += carry;
MULADD128(a[2], b[1], uv, carry, uv);
t += carry;
MULADD128(a[1], b[2], uv, carry, uv);
t += carry;
MULADD128(a[3], b[0], uv, carry, uv);
t += carry;
c[3] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[0], b[4], uv, carry, uv);
t += carry;
MULADD128(a[3], b[1], uv, carry, uv);
t += carry;
MULADD128(a[2], b[2], uv, carry, uv);
t += carry;
MULADD128(a[1], b[3], uv, carry, uv);
t += carry;
MULADD128(a[4], b[0], uv, carry, uv);
t += carry;
c[4] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[0], b[5], uv, carry, uv);
t += carry;
MULADD128(a[4], b[1], uv, carry, uv);
t += carry;
MULADD128(a[3], b[2], uv, carry, uv);
t += carry;
MULADD128(a[2], b[3], uv, carry, uv);
t += carry;
MULADD128(a[1], b[4], uv, carry, uv);
t += carry;
MULADD128(a[5], b[0], uv, carry, uv);
t += carry;
c[5] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[0], b[6], uv, carry, uv);
t += carry;
MULADD128(a[5], b[1], uv, carry, uv);
t += carry;
MULADD128(a[4], b[2], uv, carry, uv);
t += carry;
MULADD128(a[3], b[3], uv, carry, uv);
t += carry;
MULADD128(a[2], b[4], uv, carry, uv);
t += carry;
MULADD128(a[1], b[5], uv, carry, uv);
t += carry;
MULADD128(a[6], b[0], uv, carry, uv);
t += carry;
c[6] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[0], b[7], uv, carry, uv);
t += carry;
MULADD128(a[6], b[1], uv, carry, uv);
t += carry;
MULADD128(a[5], b[2], uv, carry, uv);
t += carry;
MULADD128(a[4], b[3], uv, carry, uv);
t += carry;
MULADD128(a[3], b[4], uv, carry, uv);
t += carry;
MULADD128(a[2], b[5], uv, carry, uv);
t += carry;
MULADD128(a[1], b[6], uv, carry, uv);
t += carry;
MULADD128(a[7], b[0], uv, carry, uv);
t += carry;
c[7] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[0], b[8], uv, carry, uv);
t += carry;
MULADD128(a[7], b[1], uv, carry, uv);
t += carry;
MULADD128(a[6], b[2], uv, carry, uv);
t += carry;
MULADD128(a[5], b[3], uv, carry, uv);
t += carry;
MULADD128(a[4], b[4], uv, carry, uv);
t += carry;
MULADD128(a[3], b[5], uv, carry, uv);
t += carry;
MULADD128(a[2], b[6], uv, carry, uv);
t += carry;
MULADD128(a[1], b[7], uv, carry, uv);
t += carry;
MULADD128(a[8], b[0], uv, carry, uv);
t += carry;
c[8] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[0], b[9], uv, carry, uv);
t += carry;
MULADD128(a[8], b[1], uv, carry, uv);
t += carry;
MULADD128(a[7], b[2], uv, carry, uv);
t += carry;
MULADD128(a[6], b[3], uv, carry, uv);
t += carry;
MULADD128(a[5], b[4], uv, carry, uv);
t += carry;
MULADD128(a[4], b[5], uv, carry, uv);
t += carry;
MULADD128(a[3], b[6], uv, carry, uv);
t += carry;
MULADD128(a[2], b[7], uv, carry, uv);
t += carry;
MULADD128(a[1], b[8], uv, carry, uv);
t += carry;
MULADD128(a[9], b[0], uv, carry, uv);
t += carry;
c[9] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[0], b[10], uv, carry, uv);
t += carry;
MULADD128(a[9], b[1], uv, carry, uv);
t += carry;
MULADD128(a[8], b[2], uv, carry, uv);
t += carry;
MULADD128(a[7], b[3], uv, carry, uv);
t += carry;
MULADD128(a[6], b[4], uv, carry, uv);
t += carry;
MULADD128(a[5], b[5], uv, carry, uv);
t += carry;
MULADD128(a[4], b[6], uv, carry, uv);
t += carry;
MULADD128(a[3], b[7], uv, carry, uv);
t += carry;
MULADD128(a[2], b[8], uv, carry, uv);
t += carry;
MULADD128(a[1], b[9], uv, carry, uv);
t += carry;
MULADD128(a[10], b[0], uv, carry, uv);
t += carry;
c[10] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[0], b[11], uv, carry, uv);
t += carry;
MULADD128(a[10], b[1], uv, carry, uv);
t += carry;
MULADD128(a[9], b[2], uv, carry, uv);
t += carry;
MULADD128(a[8], b[3], uv, carry, uv);
t += carry;
MULADD128(a[7], b[4], uv, carry, uv);
t += carry;
MULADD128(a[6], b[5], uv, carry, uv);
t += carry;
MULADD128(a[5], b[6], uv, carry, uv);
t += carry;
MULADD128(a[4], b[7], uv, carry, uv);
t += carry;
MULADD128(a[3], b[8], uv, carry, uv);
t += carry;
MULADD128(a[2], b[9], uv, carry, uv);
t += carry;
MULADD128(a[1], b[10], uv, carry, uv);
t += carry;
MULADD128(a[11], b[0], uv, carry, uv);
t += carry;
c[11] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[1], b[11], uv, carry, uv);
t += carry;
MULADD128(a[10], b[2], uv, carry, uv);
t += carry;
MULADD128(a[9], b[3], uv, carry, uv);
t += carry;
MULADD128(a[8], b[4], uv, carry, uv);
t += carry;
MULADD128(a[7], b[5], uv, carry, uv);
t += carry;
MULADD128(a[6], b[6], uv, carry, uv);
t += carry;
MULADD128(a[5], b[7], uv, carry, uv);
t += carry;
MULADD128(a[4], b[8], uv, carry, uv);
t += carry;
MULADD128(a[3], b[9], uv, carry, uv);
t += carry;
MULADD128(a[2], b[10], uv, carry, uv);
t += carry;
MULADD128(a[11], b[1], uv, carry, uv);
t += carry;
c[12] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[11], b[2], uv, carry, uv);
t += carry;
MULADD128(a[10], b[3], uv, carry, uv);
t += carry;
MULADD128(a[9], b[4], uv, carry, uv);
t += carry;
MULADD128(a[8], b[5], uv, carry, uv);
t += carry;
MULADD128(a[7], b[6], uv, carry, uv);
t += carry;
MULADD128(a[6], b[7], uv, carry, uv);
t += carry;
MULADD128(a[5], b[8], uv, carry, uv);
t += carry;
MULADD128(a[4], b[9], uv, carry, uv);
t += carry;
MULADD128(a[3], b[10], uv, carry, uv);
t += carry;
MULADD128(a[2], b[11], uv, carry, uv);
t += carry;
c[13] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[11], b[3], uv, carry, uv);
t += carry;
MULADD128(a[10], b[4], uv, carry, uv);
t += carry;
MULADD128(a[9], b[5], uv, carry, uv);
t += carry;
MULADD128(a[8], b[6], uv, carry, uv);
t += carry;
MULADD128(a[7], b[7], uv, carry, uv);
t += carry;
MULADD128(a[6], b[8], uv, carry, uv);
t += carry;
MULADD128(a[5], b[9], uv, carry, uv);
t += carry;
MULADD128(a[4], b[10], uv, carry, uv);
t += carry;
MULADD128(a[3], b[11], uv, carry, uv);
t += carry;
c[14] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[11], b[4], uv, carry, uv);
t += carry;
MULADD128(a[10], b[5], uv, carry, uv);
t += carry;
MULADD128(a[9], b[6], uv, carry, uv);
t += carry;
MULADD128(a[8], b[7], uv, carry, uv);
t += carry;
MULADD128(a[7], b[8], uv, carry, uv);
t += carry;
MULADD128(a[6], b[9], uv, carry, uv);
t += carry;
MULADD128(a[5], b[10], uv, carry, uv);
t += carry;
MULADD128(a[4], b[11], uv, carry, uv);
t += carry;
c[15] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[11], b[5], uv, carry, uv);
t += carry;
MULADD128(a[10], b[6], uv, carry, uv);
t += carry;
MULADD128(a[9], b[7], uv, carry, uv);
t += carry;
MULADD128(a[8], b[8], uv, carry, uv);
t += carry;
MULADD128(a[7], b[9], uv, carry, uv);
t += carry;
MULADD128(a[6], b[10], uv, carry, uv);
t += carry;
MULADD128(a[5], b[11], uv, carry, uv);
t += carry;
c[16] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[11], b[6], uv, carry, uv);
t += carry;
MULADD128(a[10], b[7], uv, carry, uv);
t += carry;
MULADD128(a[9], b[8], uv, carry, uv);
t += carry;
MULADD128(a[8], b[9], uv, carry, uv);
t += carry;
MULADD128(a[7], b[10], uv, carry, uv);
t += carry;
MULADD128(a[6], b[11], uv, carry, uv);
t += carry;
c[17] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[11], b[7], uv, carry, uv);
t += carry;
MULADD128(a[10], b[8], uv, carry, uv);
t += carry;
MULADD128(a[9], b[9], uv, carry, uv);
t += carry;
MULADD128(a[8], b[10], uv, carry, uv);
t += carry;
MULADD128(a[7], b[11], uv, carry, uv);
t += carry;
c[18] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[11], b[8], uv, carry, uv);
t += carry;
MULADD128(a[10], b[9], uv, carry, uv);
t += carry;
MULADD128(a[9], b[10], uv, carry, uv);
t += carry;
MULADD128(a[8], b[11], uv, carry, uv);
t += carry;
c[19] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[11], b[9], uv, carry, uv);
t += carry;
MULADD128(a[10], b[10], uv, carry, uv);
t += carry;
MULADD128(a[9], b[11], uv, carry, uv);
t += carry;
c[20] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(a[11], b[10], uv, carry, uv);
t += carry;
MULADD128(a[10], b[11], uv, carry, uv);
t += carry;
c[21] = uv[0];
uv[0] = uv[1];
uv[1] = t;
MULADD128(a[11], b[11], uv, carry, uv);
c[22] = uv[0];
c[23] = uv[1];
#elif (OS_TARGET == OS_LINUX)
oqs_sidh_cln16_mul751_asm(a, b, c);
#endif
}
void oqs_sidh_cln16_rdc_mont(oqs_sidh_cln16_dfelm_t ma, oqs_sidh_cln16_felm_t mc)
{ // Optimized Montgomery reduction using comba and exploiting the special form of the prime p751.
// mc = ma*mb*R^-1 mod p751, where ma,mb,mc in [0, 2*p751-1] and R = 2^768.
// ma and mb are assumed to be in Montgomery representation.
#if (OS_TARGET == OS_WIN)
unsigned int carry;
digit_t t = 0;
uint128_t uv = {0};
mc[0] = ma[0];
mc[1] = ma[1];
mc[2] = ma[2];
mc[3] = ma[3];
mc[4] = ma[4];
MUL128(mc[0], ((digit_t*)p751p1)[5], uv);
ADDC(0, uv[0], ma[5], carry, uv[0]);
ADDC(carry, uv[1], 0, carry, uv[1]);
mc[5] = uv[0];
uv[0] = uv[1];
uv[1] = 0;
MULADD128(mc[0], ((digit_t*)p751p1)[6], uv, carry, uv);
MULADD128(mc[1], ((digit_t*)p751p1)[5], uv, carry, uv);
t += carry;
ADDC(0, uv[0], ma[6], carry, uv[0]);
ADDC(carry, uv[1], 0, carry, uv[1]);
t += carry;
mc[6] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(mc[0], ((digit_t*)p751p1)[7], uv, carry, uv);
t += carry;
MULADD128(mc[1], ((digit_t*)p751p1)[6], uv, carry, uv);
t += carry;
MULADD128(mc[2], ((digit_t*)p751p1)[5], uv, carry, uv);
t += carry;
ADDC(0, uv[0], ma[7], carry, uv[0]);
ADDC(carry, uv[1], 0, carry, uv[1]);
t += carry;
mc[7] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(mc[0], ((digit_t*)p751p1)[8], uv, carry, uv);
t += carry;
MULADD128(mc[1], ((digit_t*)p751p1)[7], uv, carry, uv);
t += carry;
MULADD128(mc[2], ((digit_t*)p751p1)[6], uv, carry, uv);
t += carry;
MULADD128(mc[3], ((digit_t*)p751p1)[5], uv, carry, uv);
t += carry;
ADDC(0, uv[0], ma[8], carry, uv[0]);
ADDC(carry, uv[1], 0, carry, uv[1]);
t += carry;
mc[8] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(mc[0], ((digit_t*)p751p1)[9], uv, carry, uv);
t += carry;
MULADD128(mc[1], ((digit_t*)p751p1)[8], uv, carry, uv);
t += carry;
MULADD128(mc[2], ((digit_t*)p751p1)[7], uv, carry, uv);
t += carry;
MULADD128(mc[3], ((digit_t*)p751p1)[6], uv, carry, uv);
t += carry;
MULADD128(mc[4], ((digit_t*)p751p1)[5], uv, carry, uv);
t += carry;
ADDC(0, uv[0], ma[9], carry, uv[0]);
ADDC(carry, uv[1], 0, carry, uv[1]);
t += carry;
mc[9] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(mc[0], ((digit_t*)p751p1)[10], uv, carry, uv);
t += carry;
MULADD128(mc[1], ((digit_t*)p751p1)[9], uv, carry, uv);
t += carry;
MULADD128(mc[2], ((digit_t*)p751p1)[8], uv, carry, uv);
t += carry;
MULADD128(mc[3], ((digit_t*)p751p1)[7], uv, carry, uv);
t += carry;
MULADD128(mc[4], ((digit_t*)p751p1)[6], uv, carry, uv);
t += carry;
MULADD128(mc[5], ((digit_t*)p751p1)[5], uv, carry, uv);
t += carry;
ADDC(0, uv[0], ma[10], carry, uv[0]);
ADDC(carry, uv[1], 0, carry, uv[1]);
t += carry;
mc[10] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(mc[0], ((digit_t*)p751p1)[11], uv, carry, uv);
t += carry;
MULADD128(mc[1], ((digit_t*)p751p1)[10], uv, carry, uv);
t += carry;
MULADD128(mc[2], ((digit_t*)p751p1)[9], uv, carry, uv);
t += carry;
MULADD128(mc[3], ((digit_t*)p751p1)[8], uv, carry, uv);
t += carry;
MULADD128(mc[4], ((digit_t*)p751p1)[7], uv, carry, uv);
t += carry;
MULADD128(mc[5], ((digit_t*)p751p1)[6], uv, carry, uv);
t += carry;
MULADD128(mc[6], ((digit_t*)p751p1)[5], uv, carry, uv);
t += carry;
ADDC(0, uv[0], ma[11], carry, uv[0]);
ADDC(carry, uv[1], 0, carry, uv[1]);
t += carry;
mc[11] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(mc[1], ((digit_t*)p751p1)[11], uv, carry, uv);
t += carry;
MULADD128(mc[2], ((digit_t*)p751p1)[10], uv, carry, uv);
t += carry;
MULADD128(mc[3], ((digit_t*)p751p1)[9], uv, carry, uv);
t += carry;
MULADD128(mc[4], ((digit_t*)p751p1)[8], uv, carry, uv);
t += carry;
MULADD128(mc[5], ((digit_t*)p751p1)[7], uv, carry, uv);
t += carry;
MULADD128(mc[6], ((digit_t*)p751p1)[6], uv, carry, uv);
t += carry;
MULADD128(mc[7], ((digit_t*)p751p1)[5], uv, carry, uv);
t += carry;
ADDC(0, uv[0], ma[12], carry, uv[0]);
ADDC(carry, uv[1], 0, carry, uv[1]);
t += carry;
mc[0] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(mc[2], ((digit_t*)p751p1)[11], uv, carry, uv);
t += carry;
MULADD128(mc[3], ((digit_t*)p751p1)[10], uv, carry, uv);
t += carry;
MULADD128(mc[4], ((digit_t*)p751p1)[9], uv, carry, uv);
t += carry;
MULADD128(mc[5], ((digit_t*)p751p1)[8], uv, carry, uv);
t += carry;
MULADD128(mc[6], ((digit_t*)p751p1)[7], uv, carry, uv);
t += carry;
MULADD128(mc[7], ((digit_t*)p751p1)[6], uv, carry, uv);
t += carry;
MULADD128(mc[8], ((digit_t*)p751p1)[5], uv, carry, uv);
t += carry;
ADDC(0, uv[0], ma[13], carry, uv[0]);
ADDC(carry, uv[1], 0, carry, uv[1]);
t += carry;
mc[1] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(mc[3], ((digit_t*)p751p1)[11], uv, carry, uv);
t += carry;
MULADD128(mc[4], ((digit_t*)p751p1)[10], uv, carry, uv);
t += carry;
MULADD128(mc[5], ((digit_t*)p751p1)[9], uv, carry, uv);
t += carry;
MULADD128(mc[6], ((digit_t*)p751p1)[8], uv, carry, uv);
t += carry;
MULADD128(mc[7], ((digit_t*)p751p1)[7], uv, carry, uv);
t += carry;
MULADD128(mc[8], ((digit_t*)p751p1)[6], uv, carry, uv);
t += carry;
MULADD128(mc[9], ((digit_t*)p751p1)[5], uv, carry, uv);
t += carry;
ADDC(0, uv[0], ma[14], carry, uv[0]);
ADDC(carry, uv[1], 0, carry, uv[1]);
t += carry;
mc[2] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(mc[4], ((digit_t*)p751p1)[11], uv, carry, uv);
t += carry;
MULADD128(mc[5], ((digit_t*)p751p1)[10], uv, carry, uv);
t += carry;
MULADD128(mc[6], ((digit_t*)p751p1)[9], uv, carry, uv);
t += carry;
MULADD128(mc[7], ((digit_t*)p751p1)[8], uv, carry, uv);
t += carry;
MULADD128(mc[8], ((digit_t*)p751p1)[7], uv, carry, uv);
t += carry;
MULADD128(mc[9], ((digit_t*)p751p1)[6], uv, carry, uv);
t += carry;
MULADD128(mc[10], ((digit_t*)p751p1)[5], uv, carry, uv);
t += carry;
ADDC(0, uv[0], ma[15], carry, uv[0]);
ADDC(carry, uv[1], 0, carry, uv[1]);
t += carry;
mc[3] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(mc[5], ((digit_t*)p751p1)[11], uv, carry, uv);
t += carry;
MULADD128(mc[6], ((digit_t*)p751p1)[10], uv, carry, uv);
t += carry;
MULADD128(mc[7], ((digit_t*)p751p1)[9], uv, carry, uv);
t += carry;
MULADD128(mc[8], ((digit_t*)p751p1)[8], uv, carry, uv);
t += carry;
MULADD128(mc[9], ((digit_t*)p751p1)[7], uv, carry, uv);
t += carry;
MULADD128(mc[10], ((digit_t*)p751p1)[6], uv, carry, uv);
t += carry;
MULADD128(mc[11], ((digit_t*)p751p1)[5], uv, carry, uv);
t += carry;
ADDC(0, uv[0], ma[16], carry, uv[0]);
ADDC(carry, uv[1], 0, carry, uv[1]);
t += carry;
mc[4] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(mc[6], ((digit_t*)p751p1)[11], uv, carry, uv);
t += carry;
MULADD128(mc[7], ((digit_t*)p751p1)[10], uv, carry, uv);
t += carry;
MULADD128(mc[8], ((digit_t*)p751p1)[9], uv, carry, uv);
t += carry;
MULADD128(mc[9], ((digit_t*)p751p1)[8], uv, carry, uv);
t += carry;
MULADD128(mc[10], ((digit_t*)p751p1)[7], uv, carry, uv);
t += carry;
MULADD128(mc[11], ((digit_t*)p751p1)[6], uv, carry, uv);
t += carry;
ADDC(0, uv[0], ma[17], carry, uv[0]);
ADDC(carry, uv[1], 0, carry, uv[1]);
t += carry;
mc[5] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(mc[7], ((digit_t*)p751p1)[11], uv, carry, uv);
t += carry;
MULADD128(mc[8], ((digit_t*)p751p1)[10], uv, carry, uv);
t += carry;
MULADD128(mc[9], ((digit_t*)p751p1)[9], uv, carry, uv);
t += carry;
MULADD128(mc[10], ((digit_t*)p751p1)[8], uv, carry, uv);
t += carry;
MULADD128(mc[11], ((digit_t*)p751p1)[7], uv, carry, uv);
t += carry;
ADDC(0, uv[0], ma[18], carry, uv[0]);
ADDC(carry, uv[1], 0, carry, uv[1]);
t += carry;
mc[6] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(mc[8], ((digit_t*)p751p1)[11], uv, carry, uv);
t += carry;
MULADD128(mc[9], ((digit_t*)p751p1)[10], uv, carry, uv);
t += carry;
MULADD128(mc[10], ((digit_t*)p751p1)[9], uv, carry, uv);
t += carry;
MULADD128(mc[11], ((digit_t*)p751p1)[8], uv, carry, uv);
t += carry;
ADDC(0, uv[0], ma[19], carry, uv[0]);
ADDC(carry, uv[1], 0, carry, uv[1]);
t += carry;
mc[7] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(mc[9], ((digit_t*)p751p1)[11], uv, carry, uv);
t += carry;
MULADD128(mc[10], ((digit_t*)p751p1)[10], uv, carry, uv);
t += carry;
MULADD128(mc[11], ((digit_t*)p751p1)[9], uv, carry, uv);
t += carry;
ADDC(0, uv[0], ma[20], carry, uv[0]);
ADDC(carry, uv[1], 0, carry, uv[1]);
t += carry;
mc[8] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(mc[10], ((digit_t*)p751p1)[11], uv, carry, uv);
t += carry;
MULADD128(mc[11], ((digit_t*)p751p1)[10], uv, carry, uv);
t += carry;
ADDC(0, uv[0], ma[21], carry, uv[0]);
ADDC(carry, uv[1], 0, carry, uv[1]);
t += carry;
mc[9] = uv[0];
uv[0] = uv[1];
uv[1] = t;
t = 0;
MULADD128(mc[11], ((digit_t*)p751p1)[11], uv, carry, uv);
t += carry;
ADDC(0, uv[0], ma[22], carry, mc[10]);
ADDC(carry, uv[1], 0, carry, uv[1]);
ADDC(0, uv[1], ma[23], carry, mc[11]);
#elif (OS_TARGET == OS_LINUX)
oqs_sidh_cln16_rdc751_asm(ma, mc);
#endif
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
SIDH Library
Copyright (c) Microsoft Corporation
All rights reserved.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the ""Software""), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,46 @@
SIDH v1.1 (C Edition)
=======================
The SIDH v1.1 library (C Edition) is a supersingular isogeny-based cryptography library that implements a
new suite of algorithms for a post-quantum resistant Diffie-Hellman key exchange scheme [2]. This scheme
provides approximately 128 bits of quantum security and 192 bits of classical security.
The library was developed by Microsoft Research for experimentation purposes.
*** THE ORIGINAL README HAS BEEN TRIMMED LEAVING ONLY THE INFO RELEVANT FOR THE OQS INTEGRATION ***
1. CONTENTS:
--------
/ - Library C and header files
AMD64/ - Optimized implementation of the field arithmetic for x64 platforms
generic/ - Implementation of the field arithmetic in portable C
README.txt - This readme file
2. MAIN FEATURES:
-------------
- Support key exchange providing 128 bits of quantum security and 192 bits of classical security.
- Support a peace-of-mind hybrid key exchange mode that adds a classical elliptic curve Diffie-Hellman
key exchange on a high-security Montgomery curve providing 384 bits of classical ECDH security.
- Protected against timing and cache-timing attacks through regular, constant-time implementation of
all operations on secret key material.
- Support for public key validation in static key exchange when private keys are used more than once.
- Basic implementation of the underlying arithmetic functions using portable C to enable support on
a wide range of platforms including x64, x86 and ARM.
- Optimized implementation of the underlying arithmetic functions for x64 platforms with optional,
high-performance x64 assembly for Linux.
REFERENCES:
----------
[1] Craig Costello, Patrick Longa, and Michael Naehrig.
Efficient algorithms for supersingular isogeny Diffie-Hellman.
Advances in Cryptology - CRYPTO 2016 (to appear), 2016.
Extended version available at: http://eprint.iacr.org/2016/413.
[2] David Jao and Luca DeFeo.
Towards quantum-resistant cryptosystems from supersingular elliptic curve isogenies.
PQCrypto 2011, LNCS 7071, pp. 19-34, 2011.

117
src/kex_sidh_cln16/SIDH.c Normal file
View File

@ -0,0 +1,117 @@
/********************************************************************************************
* SIDH: an efficient supersingular isogeny-based cryptography library for Diffie-Hellman key
* exchange providing 128 bits of quantum security and 192 bits of classical security.
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*
* Abstract: supersingular elliptic curve isogeny parameters
*
*********************************************************************************************/
#include "SIDH_internal.h"
// Encoding of field elements, elements over Z_order, elements over GF(p^2) and elliptic curve points:
// --------------------------------------------------------------------------------------------------
// Elements over GF(p) and Z_order are encoded with the least significant octet (and digit) located
// at the leftmost position (i.e., little endian format).
// Elements (a+b*i) over GF(p^2), where a and b are defined over GF(p), are encoded as {b, a}, with b
// in the least significant position.
// Elliptic curve points P = (x,y) are encoded as {x, y}, with x in the least significant position.
//
// 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
//
CurveIsogenyStaticData CurveIsogeny_SIDHp751 = {
"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
751, // Bitlength of the prime
// Prime p751 = 2^372*3^239-1
{
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xEEAFFFFFFFFFFFFF,
0xE3EC968549F878A8, 0xDA959B1A13F7CC76, 0x084E9867D6EBE876, 0x8562B5045CB25748, 0x0E12909F97BADC66, 0x00006FE5D541F71C
},
// Base curve parameter "A"
{ 0 },
// Base curve parameter "C"
{ 1 },
// Order bitlength for Alice
372,
// Order of Alice's subgroup
{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0010000000000000 },
// Order bitlength for Bob
379,
// Power of Bob's subgroup order
239,
// Order of Bob's subgroup
{ 0xC968549F878A8EEB, 0x59B1A13F7CC76E3E, 0xE9867D6EBE876DA9, 0x2B5045CB25748084, 0x2909F97BADC66856, 0x06FE5D541F71C0E1 },
// Alice's generator PA = (XPA,YPA), where XPA and YPA are defined over GF(p751)
{
0x4B0346F5CCE233E9, 0x632646086CE3ACD5, 0x5661D14AB7347693, 0xA58A20449AF1F133, 0xB9AC2F40C56D6FA4, 0x8E561E008FA0E3F3,
0x6CAE096D5DB822C9, 0x83FDB7A4AD3E83E8, 0xB1317AD904386217, 0x3FA23F89F6BE06D2, 0x429C8D36FF46BCC9, 0x00003E82027A38E9,
0x12E0D620BFB341D5, 0x0F8EEA7370893430, 0x5A99EBEC3B5B8B00, 0x236C7FAC9E69F7FD, 0x0F147EF3BD0CFEC5, 0x8ED5950D80325A8D,
0x1E911F50BF3F721A, 0x163A7421DFA8378D, 0xC331B043DA010E6A, 0x5E15915A755883B7, 0xB6236F5F598D56EB, 0x00003BBF8DCD4E7E
},
// Bob's generator PB = (XPB,YPB), where XPB and YPB are defined over GF(p751)
{
0x76ED2325DCC93103, 0xD9E1DF566C1D26D3, 0x76AECB94B919AEED, 0xD3785AAAA4D646C5, 0xCB610E30288A7770, 0x9BD3778659023B9E,
0xD5E69CF26DF23742, 0xA3AD8E17B9F9238C, 0xE145FE2D525160E0, 0xF8D5BCE859ED725D, 0x960A01AB8FF409A2, 0x00002F1D80EF06EF,
0x91479226A0687894, 0xBBC6BAF5F6BA40BB, 0x15B529122CFE3CA6, 0x7D12754F00E898A3, 0x76EBA0C8419745E9, 0x0A94F06CDFB3EADE,
0x399A6EDB2EEB2F9B, 0xE302C5129C049EEB, 0xC35892123951D4B6, 0x15445287ED1CC55D, 0x1ACAF351F09AB55A, 0x00000127A46D082A
},
// BigMont's curve parameter A24 = (A+2)/4
156113,
// BigMont's order, where BigMont is defined by y^2=x^3+A*x^2+x
{
0xA59B73D250E58055, 0xCB063593D0BE10E1, 0xF6515CCB5D076CBB, 0x66880747EDDF5E20, 0xBA515248A6BFD4AB, 0x3B8EF00DDDDC789D,
0xB8FB25A1527E1E2A, 0xB6A566C684FDF31D, 0x0213A619F5BAFA1D, 0xA158AD41172C95D2, 0x0384A427E5EEB719, 0x00001BF975507DC7
},
// Montgomery constant Montgomery_R2 = (2^768)^2 mod p751
{
0x233046449DAD4058, 0xDB010161A696452A, 0x5E36941472E3FD8E, 0xF40BFE2082A2E706, 0x4932CCA8904F8751 , 0x1F735F1F1EE7FC81,
0xA24F4D80C1048E18, 0xB56C383CCDB607C5, 0x441DD47B735F9C90, 0x5673ED2C6A6AC82A, 0x06C905261132294B, 0x000041AD830F1F35
},
// Montgomery constant -p751^-1 mod 2^768
{
0x0000000000000001, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0xEEB0000000000000,
0xE3EC968549F878A8, 0xDA959B1A13F7CC76, 0x084E9867D6EBE876, 0x8562B5045CB25748, 0x0E12909F97BADC66, 0x258C28E5D541F71C
},
// Value one in Montgomery representation
{
0x00000000000249ad, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x8310000000000000,
0x5527b1e4375c6c66, 0x697797bf3f4f24d0, 0xc89db7b2ac5c4e2e, 0x4ca4b439d2076956, 0x10f7926c7512c7e9, 0x00002d5b24bce5e2
}
};
// Fixed parameters for isogeny tree computation
const unsigned int splits_Alice[SIDH_MAX_Alice] = {
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, 12, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 17, 17, 18, 18, 17, 21, 17,
18, 21, 20, 21, 21, 21, 21, 21, 22, 25, 25, 25, 26, 27, 28, 28, 29, 30, 31,
32, 32, 32, 32, 32, 32, 32, 33, 33, 33, 35, 36, 36, 33, 36, 35, 36, 36, 35,
36, 36, 37, 38, 38, 39, 40, 41, 42, 38, 39, 40, 41, 42, 40, 46, 42, 43, 46,
46, 46, 46, 48, 48, 48, 48, 49, 49, 48, 53, 54, 51, 52, 53, 54, 55, 56, 57,
58, 59, 59, 60, 62, 62, 63, 64, 64, 64, 64, 64, 64, 64, 64, 65, 65, 65, 65,
65, 66, 67, 65, 66, 67, 66, 69, 70, 66, 67, 66, 69, 70, 69, 70, 70, 71, 72,
71, 72, 72, 74, 74, 75, 72, 72, 74, 74, 75, 72, 72, 74, 75, 75, 72, 72, 74,
75, 75, 77, 77, 79, 80, 80, 82
};
const unsigned int splits_Bob[SIDH_MAX_Bob] = {
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, 12, 12, 12, 12, 12, 12, 13, 14, 14, 15, 16, 16, 16, 16, 16, 17, 16, 16,
17, 19, 19, 20, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 24, 24, 25, 27,
27, 28, 28, 29, 28, 29, 28, 28, 28, 30, 28, 28, 28, 29, 30, 33, 33, 33, 33,
34, 35, 37, 37, 37, 37, 38, 38, 37, 38, 38, 38, 38, 38, 39, 43, 38, 38, 38,
38, 43, 40, 41, 42, 43, 48, 45, 46, 47, 47, 48, 49, 49, 49, 50, 51, 50, 49,
49, 49, 49, 51, 49, 53, 50, 51, 50, 51, 51, 51, 52, 55, 55, 55, 56, 56, 56,
56, 56, 58, 58, 61, 61, 61, 63, 63, 63, 64, 65, 65, 65, 65, 66, 66, 65, 65,
66, 66, 66, 66, 66, 66, 66, 71, 66, 73, 66, 66, 71, 66, 73, 66, 66, 71, 66,
73, 68, 68, 71, 71, 73, 73, 73, 75, 75, 78, 78, 78, 80, 80, 80, 81, 81, 82,
83, 84, 85, 86, 86, 86, 86, 86, 87, 86, 88, 86, 86, 86, 86, 88, 86, 88, 86,
86, 86, 88, 88, 86, 86, 86, 93, 90, 90, 92, 92, 92, 93, 93, 93, 93, 93, 97,
97, 97, 97, 97, 97
};

245
src/kex_sidh_cln16/SIDH.h Normal file
View File

@ -0,0 +1,245 @@
/********************************************************************************************
* SIDH: an efficient supersingular isogeny-based cryptography library for Diffie-Hellman key
* exchange providing 128 bits of quantum security and 192 bits of classical security.
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*
* Abstract: main header file
*
*********************************************************************************************/
#ifndef __SIDH_H__
#define __SIDH_H__
// For C++
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <oqs/rand.h>
// Definition of operating system
#if (defined(__x86_64__) || defined(__x86_64) || defined(__arch64__) || defined(_M_AMD64) || defined(_M_X64) || defined(_WIN64) || !defined(__LP64__))
#define TARGET TARGET_AMD64
#define RADIX 64
typedef uint64_t digit_t; // Unsigned 64-bit digit
typedef int64_t sdigit_t; // Signed 64-bit digit
#define NWORDS_FIELD 12 // Number of words of a 751-bit field element
#define p751_ZERO_WORDS 5 // Number of "0" digits in the least significant part of p751 - 1
#else
#define TARGET TARGET_x86
#define TARGET TARGET_ARM
#define RADIX 32
typedef uint32_t digit_t; // Unsigned 32-bit digit
typedef int32_t sdigit_t; // Signed 32-bit digit
#define NWORDS_FIELD 24
#define p751_ZERO_WORDS 11
#endif
// Extended datatype support
#if defined(SIDH_ASM)
#if (TARGET == TARGET_AMD64 && OS_TARGET == OS_WIN)
#define SCALAR_INTRIN_SUPPORT
typedef uint64_t uint128_t[2];
#elif (TARGET == TARGET_AMD64 && OS_TARGET == OS_LINUX)
#define UINT128_SUPPORT
typedef unsigned uint128_t __attribute__((mode(TI)));
#endif
#else /* generic implementation */
typedef uint64_t uint128_t[2];
#endif
// Basic constants
#define SIDH_NBITS_FIELD 751
#define SIDH_MAXBITS_FIELD 768
#define SIDH_MAXWORDS_FIELD ((SIDH_MAXBITS_FIELD+RADIX-1)/RADIX) // Max. number of words to represent field elements
#define SIDH_NWORDS64_FIELD ((SIDH_NBITS_FIELD+63)/64) // Number of 64-bit words of a 751-bit field element
#define SIDH_NBITS_ORDER 384
#define SIDH_NWORDS_ORDER ((SIDH_NBITS_ORDER+RADIX-1)/RADIX) // Number of words of oA and oB, where oA and oB are the subgroup orders of Alice and Bob, resp.
#define SIDH_MAXBITS_ORDER SIDH_NBITS_ORDER
#define SIDH_MAXWORDS_ORDER ((SIDH_MAXBITS_ORDER+RADIX-1)/RADIX) // Max. number of words to represent elements in [1, oA-1] or [1, oB].
// Basic constants for elliptic curve BigMont
#define BIGMONT_NBITS_ORDER 749
#define BIGMONT_MAXBITS_ORDER 768
#define BIGMONT_NWORDS_ORDER ((BIGMONT_NBITS_ORDER+RADIX-1)/RADIX) // Number of words of BigMont's subgroup order.
#define BIGMONT_MAXWORDS_ORDER ((BIGMONT_MAXBITS_ORDER+RADIX-1)/RADIX) // Max. number of words to represent elements in [1, BigMont_order].
// Size of SIDH secret key = (CurveIsogeny_SIDHp751.owordbits + 7)/8
// Number of bytes in an element in [1, order]
#define SIDH_SECRETKEY_LEN 48
// Number of bytes in a field element
// PBYTES_SIDHp751 ((CurveIsogeny_SIDHp751.pwordbits + 7)/8)
// Size of SIDH public key = 3*2*PBYTES_SIDHp751
#define SIDH_PUBKEY_LEN 576
// Size of SIDH shared key = 2*PBYTES_SIDHp751
#define SIDH_SHAREDKEY_LEN 192
// Definitions of the error-handling type and error codes
typedef enum {
SIDH_CRYPTO_SUCCESS, // 0x00
SIDH_CRYPTO_ERROR, // 0x01
SIDH_CRYPTO_ERROR_INVALID_PARAMETER, // 0x02
SIDH_CRYPTO_ERROR_PUBLIC_KEY_VALIDATION, // 0x03
SIDH_CRYPTO_ERROR_TOO_MANY_ITERATIONS, // 0x04
SIDH_CRYPTO_ERROR_END_OF_LIST
} SIDH_CRYPTO_STATUS;
// Definition of type for curve isogeny system identifiers. Currently valid value is "SIDHp751" (see SIDH.h)
typedef char CurveIsogeny_ID[10];
// Supersingular elliptic curve isogeny structures:
// This data struct contains the static curve isogeny data
typedef struct {
CurveIsogeny_ID CurveIsogeny; // Curve isogeny system identifier, base curve defined over GF(p^2)
unsigned int pwordbits; // Smallest multiple of 32 larger than the prime bitlength
unsigned int owordbits; // Smallest multiple of 32 larger than the order bitlength
unsigned int pbits; // Bitlength of the prime p
uint64_t prime[SIDH_MAXWORDS_FIELD]; // Prime p
uint64_t A[SIDH_MAXWORDS_FIELD]; // Base curve parameter "A"
uint64_t C[SIDH_MAXWORDS_FIELD]; // Base curve parameter "C"
unsigned int oAbits; // Order bitlength for Alice
uint64_t Aorder[SIDH_MAXWORDS_ORDER]; // Order of Alice's (sub)group
unsigned int oBbits; // Order bitlength for Bob
unsigned int eB; // Power of Bob's subgroup order (i.e., oB = 3^eB)
uint64_t Border[SIDH_MAXWORDS_ORDER]; // Order of Bob's (sub)group
uint64_t PA[2 * SIDH_MAXWORDS_FIELD]; // Alice's generator PA = (XPA,YPA), where XPA and YPA are defined over GF(p)
uint64_t PB[2 * SIDH_MAXWORDS_FIELD]; // Bob's generator PB = (XPB,YPB), where XPB and YPB are defined over GF(p)
unsigned int BigMont_A24; // BigMont's curve parameter A24 = (A+2)/4
uint64_t BigMont_order[BIGMONT_MAXWORDS_ORDER]; // BigMont's subgroup order
uint64_t Montgomery_R2[SIDH_MAXWORDS_FIELD]; // Montgomery constant (2^W)^2 mod p, using a suitable value W
uint64_t Montgomery_pp[SIDH_MAXWORDS_FIELD]; // Montgomery constant -p^-1 mod 2^W, using a suitable value W
uint64_t Montgomery_one[SIDH_MAXWORDS_FIELD]; // Value one in Montgomery representation
} CurveIsogenyStaticData, *PCurveIsogenyStaticData;
// This data struct is initialized with the targeted curve isogeny system during setup
typedef struct {
CurveIsogeny_ID CurveIsogeny; // Curve isogeny system identifier, base curve defined over GF(p^2)
unsigned int pwordbits; // Closest multiple of 32 to prime bitlength
unsigned int owordbits; // Closest multiple of 32 to order bitlength
unsigned int pbits; // Bitlength of the prime p
digit_t *prime; // Prime p
digit_t *A; // Base curve parameter "A"
digit_t *C; // Base curve parameter "C"
unsigned int oAbits; // Order bitlength for Alice
digit_t *Aorder; // Order of Alice's (sub)group
unsigned int oBbits; // Order bitlength for Bob
unsigned int eB; // Power of Bob's subgroup order (i.e., oB = 3^eB)
digit_t *Border; // Order of Bob's (sub)group
digit_t *PA; // Alice's generator PA = (XPA,YPA), where XPA and YPA are defined over GF(p)
digit_t *PB; // Bob's generator PB = (XPB,YPB), where XPB and YPB are defined over GF(p)
unsigned int BigMont_A24; // BigMont's curve parameter A24 = (A+2)/4
digit_t *BigMont_order; // BigMont's subgroup order
digit_t *Montgomery_R2; // Montgomery constant (2^W)^2 mod p, using a suitable value W
digit_t *Montgomery_pp; // Montgomery constant -p^-1 mod 2^W, using a suitable value W
digit_t *Montgomery_one; // Value one in Montgomery representation
} CurveIsogenyStruct, *PCurveIsogenyStruct;
// Supported curve isogeny systems:
// "SIDHp751", base curve: supersingular elliptic curve E: y^2 = x^3 + x
extern CurveIsogenyStaticData CurveIsogeny_SIDHp751;
/******************** Function prototypes ***********************/
/*************** Setup/initialization functions *****************/
// Dynamic allocation of memory for curve isogeny structure.
// Returns NULL on error.
PCurveIsogenyStruct oqs_sidh_cln16_curve_allocate(PCurveIsogenyStaticData CurveData);
// Initialize curve isogeny structure pCurveIsogeny with static data extracted from pCurveIsogenyData.
// This needs to be called after allocating memory for "pCurveIsogeny" using oqs_sidh_cln16_curve_allocate().
SIDH_CRYPTO_STATUS oqs_sidh_cln16_curve_initialize(PCurveIsogenyStruct pCurveIsogeny, OQS_RAND *rand, PCurveIsogenyStaticData pCurveIsogenyData);
// Free memory for curve isogeny structure
void oqs_sidh_cln16_curve_free(PCurveIsogenyStruct pCurveIsogeny);
// Output random values in the range [1, order-1] in little endian format that can be used as private keys.
SIDH_CRYPTO_STATUS oqs_sidh_cln16_random_mod_order(digit_t *random_digits, unsigned int AliceOrBob, PCurveIsogenyStruct pCurveIsogeny, OQS_RAND *rand);
// 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 using the elliptic curve BigMont.
SIDH_CRYPTO_STATUS oqs_sidh_cln16_random_BigMont_mod_order(digit_t *random_digits, PCurveIsogenyStruct pCurveIsogeny, OQS_RAND *rand);
// Clear "nwords" digits from memory
void oqs_sidh_cln16_clear_words(void *mem, digit_t nwords);
/*********************** Key exchange API ***********************/
// Alice's key-pair generation
// It produces a private key pPrivateKeyA and computes the public key pPublicKeyA.
// The private key is an even integer in the range [2, oA-2], where oA = 2^372 (i.e., 372 bits in total).
// The public key consists of 3 elements in GF(p751^2), i.e., 564 bytes.
// CurveIsogeny must be set up in advance using oqs_sidh_cln16_curve_initialize().
SIDH_CRYPTO_STATUS oqs_sidh_cln16_KeyGeneration_A(unsigned char *pPrivateKeyA, unsigned char *pPublicKeyA, PCurveIsogenyStruct CurveIsogeny, OQS_RAND *rand);
// Bob's key-pair generation
// It produces a private key pPrivateKeyB and computes the public key pPublicKeyB.
// The private key is an integer in the range [1, oB-1], where oA = 3^239 (i.e., 379 bits in total).
// The public key consists of 3 elements in GF(p751^2), i.e., 564 bytes.
// CurveIsogeny must be set up in advance using oqs_sidh_cln16_curve_initialize().
SIDH_CRYPTO_STATUS oqs_sidh_cln16_KeyGeneration_B(unsigned char *pPrivateKeyB, unsigned char *pPublicKeyB, PCurveIsogenyStruct CurveIsogeny, OQS_RAND *rand);
// Alice's shared secret generation
// It produces a shared secret key pSharedSecretA using her secret key pPrivateKeyA and Bob's public key pPublicKeyB
// Inputs: Alice's pPrivateKeyA is an even integer in the range [2, oA-2], where oA = 2^372 (i.e., 372 bits in total).
// Bob's pPublicKeyB consists of 3 elements in GF(p751^2), i.e., 564 bytes.
// "validate" flag that indicates if Alice must validate Bob's public key.
// Output: a shared secret pSharedSecretA that consists of one element in GF(p751^2), i.e., 1502 bits in total.
// CurveIsogeny must be set up in advance using oqs_sidh_cln16_curve_initialize().
SIDH_CRYPTO_STATUS oqs_sidh_cln16_SecretAgreement_A(unsigned char *pPrivateKeyA, unsigned char *pPublicKeyB, unsigned char *pSharedSecretA, bool validate, PCurveIsogenyStruct CurveIsogeny, OQS_RAND *rand);
// Bob's shared secret generation
// It produces a shared secret key pSharedSecretB using his secret key pPrivateKeyB and Alice's public key pPublicKeyA
// Inputs: Bob's pPrivateKeyB is an integer in the range [1, oB-1], where oA = 3^239 (i.e., 379 bits in total).
// Alice's pPublicKeyA consists of 3 elements in GF(p751^2), i.e., 564 bytes.
// "validate" flag that indicates if Bob must validate Alice's public key.
// Output: a shared secret pSharedSecretB that consists of one element in GF(p751^2), i.e., 1502 bits in total.
// CurveIsogeny must be set up in advance using oqs_sidh_cln16_curve_initialize().
SIDH_CRYPTO_STATUS oqs_sidh_cln16_SecretAgreement_B(unsigned char *pPrivateKeyB, unsigned char *pPublicKeyA, unsigned char *pSharedSecretB, bool validate, PCurveIsogenyStruct CurveIsogeny, OQS_RAND *rand);
/*********************** Scalar multiplication API using BigMont ***********************/
// BigMont's scalar multiplication using the Montgomery ladder
// Inputs: x, the affine x-coordinate of a point P on BigMont: y^2=x^3+A*x^2+x,
// scalar m.
// Output: xout, the affine x-coordinate of m*(x:1)
// CurveIsogeny must be set up in advance using oqs_sidh_cln16_curve_initialize().
SIDH_CRYPTO_STATUS oqs_sidh_cln16_BigMont_ladder(unsigned char *x, digit_t *m, unsigned char *xout, PCurveIsogenyStruct CurveIsogeny);
// Encoding of keys for isogeny system "SIDHp751" (wire format):
// ------------------------------------------------------------
// Elements over GF(p751) are encoded in 96 octets in little endian format (i.e., the least significant octet located at the leftmost position).
// 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.
// Elements over Z_oA and Z_oB are encoded in 48 octets in little endian format.
//
// 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.
// In the key exchange API, they are encoded in 48 octets in little endian format.
// 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
// endian format.
// 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
// endian format.
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,444 @@
/********************************************************************************************
* SIDH: an efficient supersingular isogeny-based cryptography library for Diffie-Hellman key
* exchange providing 128 bits of quantum security and 192 bits of classical security.
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*
* Abstract: internal header file
*
*********************************************************************************************/
#ifndef __SIDH_INTERNAL_H__
#define __SIDH_INTERNAL_H__
// For C++
#ifdef __cplusplus
extern "C" {
#endif
#if defined(WINDOWS)
#define UNUSED
#else
#define UNUSED __attribute__ ((unused))
#endif
#include "SIDH.h"
// Basic constants
#define SIDH_ALICE 0
#define SIDH_BOB 1
#define SIDH_MAX_INT_POINTS_ALICE 8
// Fixed parameters for isogeny tree computation
#define SIDH_MAX_INT_POINTS_BOB 10
#define SIDH_MAX_Alice 185
#define SIDH_MAX_Bob 239
// SIDH's basic element definitions and point representations
typedef digit_t oqs_sidh_cln16_felm_t[NWORDS_FIELD]; // Datatype for representing 751-bit field elements (768-bit max.)
typedef digit_t oqs_sidh_cln16_dfelm_t[2 * NWORDS_FIELD]; // Datatype for representing double-precision 2x751-bit field elements (2x768-bit max.)
typedef oqs_sidh_cln16_felm_t oqs_sidh_cln16_f2elm_t[2]; // Datatype for representing quadratic extension field elements GF(p751^2)
typedef oqs_sidh_cln16_f2elm_t oqs_sidh_cln16_publickey_t[3]; // Datatype for representing public keys equivalent to three GF(p751^2) elements
typedef struct {
oqs_sidh_cln16_f2elm_t x;
oqs_sidh_cln16_f2elm_t y;
} oqs_sidh_cln16_point_affine; // Point representation in affine coordinates on Montgomery curve.
typedef oqs_sidh_cln16_point_affine oqs_sidh_cln16_point_t[1];
typedef struct {
oqs_sidh_cln16_f2elm_t X;
oqs_sidh_cln16_f2elm_t Z;
} oqs_sidh_cln16_point_proj; // Point representation in projective XZ Montgomery coordinates.
typedef oqs_sidh_cln16_point_proj oqs_sidh_cln16_point_proj_t[1];
#define oqs_sidh_cln16_point_proj_t_EMPTY { { { {0}, {0} }, { {0}, {0} } } }
typedef struct {
oqs_sidh_cln16_felm_t x;
oqs_sidh_cln16_felm_t y;
} oqs_sidh_cln16_point_basefield_affine; // Point representation in affine coordinates on Montgomery curve over the base field.
typedef oqs_sidh_cln16_point_basefield_affine oqs_sidh_cln16_point_basefield_t[1];
typedef struct {
oqs_sidh_cln16_felm_t X;
oqs_sidh_cln16_felm_t Z;
} oqs_sidh_cln16_point_basefield_proj; // Point representation in projective XZ Montgomery coordinates over the base field.
typedef oqs_sidh_cln16_point_basefield_proj oqs_sidh_cln16_point_basefield_proj_t[1];
// Macro definitions
#define NBITS_TO_NBYTES(nbits) (((nbits)+7)/8) // Conversion macro from number of bits to number of bytes
#define NBITS_TO_NWORDS(nbits) (((nbits)+(sizeof(digit_t)*8)-1)/(sizeof(digit_t)*8)) // Conversion macro from number of bits to number of computer words
#define NBYTES_TO_NWORDS(nbytes) (((nbytes)+sizeof(digit_t)-1)/sizeof(digit_t)) // Conversion macro from number of bytes to number of computer words
// Macro to avoid compiler warnings when detecting unreferenced parameters
#define UNREFERENCED_PARAMETER(PAR) (PAR)
/********************** Constant-time unsigned comparisons ***********************/
// The following functions return 1 (TRUE) if condition is true, 0 (FALSE) otherwise
// Is x != 0?
#define is_digit_nonzero_ct(x) \
((unsigned int)(((x) | (0 - (x))) >> (RADIX - 1)))
// Is x = 0?
#define is_digit_zero_ct(x) \
((unsigned int)(1 ^ is_digit_nonzero_ct((x))))
// Is x < y?
#define is_digit_lessthan_ct(x, y) \
((unsigned int)(((x) ^ (((x) ^ (y)) | (((x) - (y)) ^ (y)))) >> (RADIX - 1)))
/********************** Macros for platform-dependent operations **********************/
#if !defined(SIDH_ASM)
// Digit multiplication
#define MUL(multiplier, multiplicand, hi, lo) \
oqs_sidh_cln16_digit_x_digit((multiplier), (multiplicand), &(lo));
// Digit addition with carry
#define ADDC(carryIn, addend1, addend2, carryOut, sumOut) \
{ digit_t tempReg = (addend1) + (digit_t)(carryIn); \
(sumOut) = (addend2) + tempReg; \
(carryOut) = (is_digit_lessthan_ct(tempReg, (digit_t)(carryIn)) | is_digit_lessthan_ct((sumOut), tempReg)); }
// Digit subtraction with borrow
#define SUBC(borrowIn, minuend, subtrahend, borrowOut, differenceOut) \
{ digit_t tempReg = (minuend) - (subtrahend); \
unsigned int borrowReg = (is_digit_lessthan_ct((minuend), (subtrahend)) | ((borrowIn) & is_digit_zero_ct(tempReg))); \
(differenceOut) = tempReg - (digit_t)(borrowIn); \
(borrowOut) = borrowReg; }
// Shift right with flexible datatype
#define SHIFTR(highIn, lowIn, shift, shiftOut, DigitSize) \
(shiftOut) = ((lowIn) >> (shift)) ^ ((highIn) << (DigitSize - (shift)));
// Shift left with flexible datatype
#define SHIFTL(highIn, lowIn, shift, shiftOut, DigitSize) \
(shiftOut) = ((highIn) << (shift)) ^ ((lowIn) >> (DigitSize - (shift)));
// 64x64-bit multiplication
#define MUL128(multiplier, multiplicand, product) \
oqs_sidh_cln16_mp_mul((digit_t*)&(multiplier), (digit_t*)&(multiplicand), (digit_t*)&(product), NWORDS_FIELD/2);
// 128-bit addition, inputs < 2^127
#define ADD128(addend1, addend2, addition) \
oqs_sidh_cln16_mp_add((digit_t*)(addend1), (digit_t*)(addend2), (digit_t*)(addition), NWORDS_FIELD);
// 128-bit addition with output carry
#define ADC128(addend1, addend2, carry, addition) \
(carry) = oqs_sidh_cln16_mp_add((digit_t*)(addend1), (digit_t*)(addend2), (digit_t*)(addition), NWORDS_FIELD);
#elif (TARGET == TARGET_AMD64 && defined(WINDOWS))
// Digit multiplication
#define MUL(multiplier, multiplicand, hi, lo) \
(lo) = _umul128((multiplier), (multiplicand), (hi));
// Digit addition with carry
#define ADDC(carryIn, addend1, addend2, carryOut, sumOut) \
(carryOut) = _addcarry_u64((carryIn), (addend1), (addend2), &(sumOut));
// Digit subtraction with borrow
#define SUBC(borrowIn, minuend, subtrahend, borrowOut, differenceOut) \
(borrowOut) = _subborrow_u64((borrowIn), (minuend), (subtrahend), &(differenceOut));
// Digit shift right
#define SHIFTR(highIn, lowIn, shift, shiftOut, DigitSize) \
(shiftOut) = __shiftright128((lowIn), (highIn), (shift));
// Digit shift left
#define SHIFTL(highIn, lowIn, shift, shiftOut, DigitSize) \
(shiftOut) = __shiftleft128((lowIn), (highIn), (shift));
// 64x64-bit multiplication
#define MUL128(multiplier, multiplicand, product) \
(product)[0] = _umul128((multiplier), (multiplicand), &(product)[1]);
// 128-bit addition, inputs < 2^127
#define ADD128(addend1, addend2, addition) \
{ unsigned char carry = _addcarry_u64(0, (addend1)[0], (addend2)[0], &(addition)[0]); \
_addcarry_u64(carry, (addend1)[1], (addend2)[1], &(addition)[1]); }
// 128-bit addition with output carry
#define ADC128(addend1, addend2, carry, addition) \
(carry) = _addcarry_u64(0, (addend1)[0], (addend2)[0], &(addition)[0]); \
(carry) = _addcarry_u64((carry), (addend1)[1], (addend2)[1], &(addition)[1]);
// 128-bit subtraction, subtrahend < 2^127
#define SUB128(minuend, subtrahend, difference) \
{ unsigned char borrow = _subborrow_u64(0, (minuend)[0], (subtrahend)[0], &(difference)[0]); \
_subborrow_u64(borrow, (minuend)[1], (subtrahend)[1], &(difference)[1]); }
// 128-bit right shift, max. shift value is 64
#define SHIFTR128(Input, shift, shiftOut) \
(shiftOut)[0] = __shiftright128((Input)[0], (Input)[1], (shift)); \
(shiftOut)[1] = (Input)[1] >> (shift);
// 128-bit left shift, max. shift value is 64
#define SHIFTL128(Input, shift, shiftOut) \
(shiftOut)[1] = __shiftleft128((Input)[0], (Input)[1], (shift)); \
(shiftOut)[0] = (Input)[0] << (shift);
#define MULADD128(multiplier, multiplicand, addend, carry, result); \
{ uint128_t product; \
MUL128(multiplier, multiplicand, product); \
ADC128(addend, product, carry, result); }
#elif (TARGET == TARGET_AMD64)
// Digit multiplication
#define MUL(multiplier, multiplicand, hi, lo) \
{ uint128_t tempReg = (uint128_t)(multiplier) * (uint128_t)(multiplicand); \
*(hi) = (digit_t)(tempReg >> RADIX); \
(lo) = (digit_t)tempReg; }
// Digit addition with carry
#define ADDC(carryIn, addend1, addend2, carryOut, sumOut) \
{ uint128_t tempReg = (uint128_t)(addend1) + (uint128_t)(addend2) + (uint128_t)(carryIn); \
(carryOut) = (digit_t)(tempReg >> RADIX); \
(sumOut) = (digit_t)tempReg; }
// Digit subtraction with borrow
#define SUBC(borrowIn, minuend, subtrahend, borrowOut, differenceOut) \
{ uint128_t tempReg = (uint128_t)(minuend) - (uint128_t)(subtrahend) - (uint128_t)(borrowIn); \
(borrowOut) = (digit_t)(tempReg >> (sizeof(uint128_t)*8 - 1)); \
(differenceOut) = (digit_t)tempReg; }
// Digit shift right
#define SHIFTR(highIn, lowIn, shift, shiftOut, DigitSize) \
(shiftOut) = ((lowIn) >> (shift)) ^ ((highIn) << (RADIX - (shift)));
// Digit shift left
#define SHIFTL(highIn, lowIn, shift, shiftOut, DigitSize) \
(shiftOut) = ((highIn) << (shift)) ^ ((lowIn) >> (RADIX - (shift)));
#endif
// Multiprecision multiplication selection
#if !defined(SIDH_ASM) && (TARGET == TARGET_AMD64)
#define oqs_sidh_cln16_mp_mul_comba oqs_sidh_cln16_mp_mul
#else
#define oqs_sidh_cln16_mp_mul_schoolbook oqs_sidh_cln16_mp_mul
#endif
/**************** Function prototypes ****************/
/************* Multiprecision functions **************/
// Copy wordsize digits, c = a, where lng(a) = nwords
void oqs_sidh_cln16_copy_words(digit_t *a, digit_t *c, unsigned int nwords);
// Multiprecision addition, c = a+b, where lng(a) = lng(b) = nwords. Returns the carry bit
extern unsigned int oqs_sidh_cln16_mp_add(digit_t *a, digit_t *b, digit_t *c, unsigned int nwords);
// Multiprecision subtraction, c = a-b, where lng(a) = lng(b) = nwords. Returns the borrow bit
extern unsigned int oqs_sidh_cln16_mp_sub(digit_t *a, digit_t *b, digit_t *c, unsigned int nwords);
// Multiprecision right shift by one
void oqs_sidh_cln16_mp_shiftr1(digit_t *x, unsigned int nwords);
// Multiprecision left right shift by one
void oqs_sidh_cln16_mp_shiftl1(digit_t *x, unsigned int nwords);
// Digit multiplication, digit * digit -> 2-digit result
void oqs_sidh_cln16_digit_x_digit(digit_t a, digit_t b, digit_t *c);
// Multiprecision schoolbook multiply, c = a*b, where lng(a) = lng(b) = nwords.
void oqs_sidh_cln16_mp_mul_schoolbook(digit_t *a, digit_t *b, digit_t *c, unsigned int nwords);
// Multiprecision comba multiply, c = a*b, where lng(a) = lng(b) = nwords.
void oqs_sidh_cln16_mp_mul_comba(digit_t *a, digit_t *b, digit_t *c, unsigned int nwords);
/************ Field arithmetic functions *************/
// Copy of a field element, c = a
void oqs_sidh_cln16_fpcopy751(oqs_sidh_cln16_felm_t a, oqs_sidh_cln16_felm_t c);
// Zeroing a field element, a = 0
void oqs_sidh_cln16_fpzero751(oqs_sidh_cln16_felm_t a);
// Modular addition, c = a+b mod p751
extern void oqs_sidh_cln16_fpadd751(digit_t *a, digit_t *b, digit_t *c);
extern void oqs_sidh_cln16_fpadd751_asm(digit_t *a, digit_t *b, digit_t *c);
// Modular subtraction, c = a-b mod p751
extern void oqs_sidh_cln16_fpsub751(digit_t *a, digit_t *b, digit_t *c);
extern void oqs_sidh_cln16_fpsub751_asm(digit_t *a, digit_t *b, digit_t *c);
// Modular negation, a = -a mod p751
extern void oqs_sidh_cln16_fpneg751(digit_t *a);
// Modular division by two, c = a/2 mod p751.
void oqs_sidh_cln16_fpdiv2_751(digit_t *a, digit_t *c);
// Modular correction to reduce field element a in [0, 2*p751-1] to [0, p751-1].
void oqs_sidh_cln16_fpcorrection751(digit_t *a);
// 751-bit Montgomery reduction, c = a mod p
void oqs_sidh_cln16_rdc_mont(digit_t *a, digit_t *c);
// Field multiplication using Montgomery arithmetic, c = a*b*R^-1 mod p751, where R=2^768
void oqs_sidh_cln16_fpmul751_mont(oqs_sidh_cln16_felm_t a, oqs_sidh_cln16_felm_t b, oqs_sidh_cln16_felm_t c);
void oqs_sidh_cln16_mul751_asm(oqs_sidh_cln16_felm_t a, oqs_sidh_cln16_felm_t b, oqs_sidh_cln16_dfelm_t c);
void oqs_sidh_cln16_rdc751_asm(oqs_sidh_cln16_dfelm_t ma, oqs_sidh_cln16_dfelm_t mc);
// Field squaring using Montgomery arithmetic, c = a*b*R^-1 mod p751, where R=2^768
void oqs_sidh_cln16_fpsqr751_mont(oqs_sidh_cln16_felm_t ma, oqs_sidh_cln16_felm_t mc);
// Conversion to Montgomery representation
void oqs_sidh_cln16_to_mont(oqs_sidh_cln16_felm_t a, oqs_sidh_cln16_felm_t mc);
// Conversion from Montgomery representation to standard representation
void oqs_sidh_cln16_from_mont(oqs_sidh_cln16_felm_t ma, oqs_sidh_cln16_felm_t c);
// Field inversion, a = a^-1 in GF(p751)
void oqs_sidh_cln16_fpinv751_mont(oqs_sidh_cln16_felm_t a);
/************ GF(p^2) arithmetic functions *************/
// Copy of a GF(p751^2) element, c = a
void oqs_sidh_cln16_fp2copy751(oqs_sidh_cln16_f2elm_t a, oqs_sidh_cln16_f2elm_t c);
// Zeroing a GF(p751^2) element, a = 0
void oqs_sidh_cln16_fp2zero751(oqs_sidh_cln16_f2elm_t a);
// GF(p751^2) negation, a = -a in GF(p751^2)
void oqs_sidh_cln16_fp2neg751(oqs_sidh_cln16_f2elm_t a);
// GF(p751^2) addition, c = a+b in GF(p751^2)
extern void oqs_sidh_cln16_fp2add751(oqs_sidh_cln16_f2elm_t a, oqs_sidh_cln16_f2elm_t b, oqs_sidh_cln16_f2elm_t c);
// GF(p751^2) subtraction, c = a-b in GF(p751^2)
extern void oqs_sidh_cln16_fp2sub751(oqs_sidh_cln16_f2elm_t a, oqs_sidh_cln16_f2elm_t b, oqs_sidh_cln16_f2elm_t c);
// GF(p751^2) division by two, c = a/2 in GF(p751^2)
void oqs_sidh_cln16_fp2div2_751(oqs_sidh_cln16_f2elm_t a, oqs_sidh_cln16_f2elm_t c);
// Modular correction, a = a in GF(p751^2)
void oqs_sidh_cln16_fp2correction751(oqs_sidh_cln16_f2elm_t a);
// GF(p751^2) squaring using Montgomery arithmetic, c = a^2 in GF(p751^2)
void oqs_sidh_cln16_fp2sqr751_mont(oqs_sidh_cln16_f2elm_t a, oqs_sidh_cln16_f2elm_t c);
// GF(p751^2) multiplication using Montgomery arithmetic, c = a*b in GF(p751^2)
void oqs_sidh_cln16_fp2mul751_mont(oqs_sidh_cln16_f2elm_t a, oqs_sidh_cln16_f2elm_t b, oqs_sidh_cln16_f2elm_t c);
// Conversion of a GF(p751^2) element to Montgomery representation
void oqs_sidh_cln16_to_fp2mont(oqs_sidh_cln16_f2elm_t a, oqs_sidh_cln16_f2elm_t mc);
// Conversion of a GF(p751^2) element from Montgomery representation to standard representation
void oqs_sidh_cln16_from_fp2mont(oqs_sidh_cln16_f2elm_t ma, oqs_sidh_cln16_f2elm_t c);
// GF(p751^2) inversion using Montgomery arithmetic, a = (a0-i*a1)/(a0^2+a1^2)
void oqs_sidh_cln16_fp2inv751_mont(oqs_sidh_cln16_f2elm_t a);
// Select either x or y depending on value of option
void oqs_sidh_cln16_select_f2elm(oqs_sidh_cln16_f2elm_t x, oqs_sidh_cln16_f2elm_t y, oqs_sidh_cln16_f2elm_t z, digit_t option);
/************ Elliptic curve and isogeny functions *************/
// Check if curve isogeny structure is NULL
bool oqs_sidh_cln16_is_CurveIsogenyStruct_null(PCurveIsogenyStruct pCurveIsogeny);
// Swap points over the base field
void oqs_sidh_cln16_swap_points_basefield(oqs_sidh_cln16_point_basefield_proj_t P, oqs_sidh_cln16_point_basefield_proj_t Q, digit_t option);
// Swap points
void oqs_sidh_cln16_swap_points(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_point_proj_t Q, digit_t option);
// Computes the j-invariant of a Montgomery curve with projective constant.
void oqs_sidh_cln16_j_inv(oqs_sidh_cln16_f2elm_t A, oqs_sidh_cln16_f2elm_t C, oqs_sidh_cln16_f2elm_t jinv);
// Simultaneous doubling and differential addition.
void oqs_sidh_cln16_xDBLADD(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_point_proj_t Q, oqs_sidh_cln16_f2elm_t xPQ, oqs_sidh_cln16_f2elm_t A24);
// Doubling of a Montgomery point in projective coordinates (X:Z).
void oqs_sidh_cln16_xDBL(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_point_proj_t Q, oqs_sidh_cln16_f2elm_t A24, oqs_sidh_cln16_f2elm_t C24);
// Computes [2^e](X:Z) on Montgomery curve with projective constant via e repeated doublings.
void oqs_sidh_cln16_xDBLe(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_point_proj_t Q, oqs_sidh_cln16_f2elm_t A, oqs_sidh_cln16_f2elm_t C, int e);
// Computes [2^e](X:Z) on Montgomery curve with projective constant via e repeated doublings and collects a few intermediate multiples.
void oqs_sidh_cln16_xDBLe_collect(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_point_proj_t Q, oqs_sidh_cln16_f2elm_t A, oqs_sidh_cln16_f2elm_t C, unsigned int left_bound, const unsigned int right_bound, const unsigned int *col, oqs_sidh_cln16_point_proj_t *pts, unsigned int *pts_index, unsigned int *npts);
// Differential addition.
void oqs_sidh_cln16_xADD(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_point_proj_t Q, oqs_sidh_cln16_f2elm_t xPQ);
// Doubling of a Montgomery point in projective coordinates (X:Z) over the base field.
void oqs_sidh_cln16_xDBL_basefield(oqs_sidh_cln16_point_basefield_proj_t P, oqs_sidh_cln16_point_basefield_proj_t Q);
// Simultaneous doubling and differential addition over the base field.
void oqs_sidh_cln16_xDBLADD_basefield(oqs_sidh_cln16_point_basefield_proj_t P, oqs_sidh_cln16_point_basefield_proj_t Q, oqs_sidh_cln16_felm_t xPQ, oqs_sidh_cln16_felm_t A24);
// The Montgomery ladder
void oqs_sidh_cln16_ladder(oqs_sidh_cln16_felm_t x, digit_t *m, oqs_sidh_cln16_point_basefield_proj_t P, oqs_sidh_cln16_point_basefield_proj_t Q, oqs_sidh_cln16_felm_t A24, unsigned int order_bits, unsigned int order_fullbits, PCurveIsogenyStruct CurveIsogeny);
// Computes key generation entirely in the base field
SIDH_CRYPTO_STATUS oqs_sidh_cln16_secret_pt(oqs_sidh_cln16_point_basefield_t P, digit_t *m, unsigned int AliceOrBob, oqs_sidh_cln16_point_proj_t R, PCurveIsogenyStruct CurveIsogeny);
// Computes P+[m]Q via x-only arithmetic.
SIDH_CRYPTO_STATUS oqs_sidh_cln16_ladder_3_pt(oqs_sidh_cln16_f2elm_t xP, oqs_sidh_cln16_f2elm_t xQ, oqs_sidh_cln16_f2elm_t xPQ, digit_t *m, unsigned int AliceOrBob, oqs_sidh_cln16_point_proj_t W, oqs_sidh_cln16_f2elm_t A, PCurveIsogenyStruct CurveIsogeny);
// Computes the corresponding 4-isogeny of a projective Montgomery point (X4:Z4) of order 4.
void oqs_sidh_cln16_get_4_isog(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_f2elm_t A, oqs_sidh_cln16_f2elm_t C, oqs_sidh_cln16_f2elm_t *coeff);
// Evaluates the isogeny at the point (X:Z) in the domain of the isogeny
void oqs_sidh_cln16_eval_4_isog(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_f2elm_t *coeff);
// Computes first 4-isogeny computed by Alice.
void oqs_sidh_cln16_first_4_isog(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_f2elm_t A, oqs_sidh_cln16_f2elm_t Aout, oqs_sidh_cln16_f2elm_t Cout, PCurveIsogenyStruct CurveIsogeny);
// Tripling of a Montgomery point in projective coordinates (X:Z).
void oqs_sidh_cln16_xTPL(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_point_proj_t Q, oqs_sidh_cln16_f2elm_t A24, oqs_sidh_cln16_f2elm_t C24);
// Computes [3^e](X:Z) on Montgomery curve with projective constant via e repeated triplings.
void oqs_sidh_cln16_xTPLe(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_point_proj_t Q, oqs_sidh_cln16_f2elm_t A, oqs_sidh_cln16_f2elm_t C, int e);
// Computes [3^e](X:Z) on Montgomery curve with projective constant via e repeated triplings and collects a few intermediate multiples.
void oqs_sidh_cln16_xTPLe_collect(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_point_proj_t Q, oqs_sidh_cln16_f2elm_t A, oqs_sidh_cln16_f2elm_t C, unsigned int left_bound, const unsigned int right_bound, const unsigned int *col, oqs_sidh_cln16_point_proj_t *pts, unsigned int *pts_index, unsigned int *npts);
// Computes the corresponding 3-isogeny of a projective Montgomery point (X3:Z3) of order 3.
void oqs_sidh_cln16_get_3_isog(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_f2elm_t A, oqs_sidh_cln16_f2elm_t C);
// Computes the 3-isogeny R=phi(X:Z), given projective point (X3:Z3) of order 3 on a Montgomery curve and a point P = (X:Z).
void oqs_sidh_cln16_eval_3_isog(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_point_proj_t Q);
// 3-way simultaneous inversion
void oqs_sidh_cln16_inv_3_way(oqs_sidh_cln16_f2elm_t z1, oqs_sidh_cln16_f2elm_t z2, oqs_sidh_cln16_f2elm_t z3);
// Computing the point D = (x(Q-P),z(Q-P))
void oqs_sidh_cln16_distort_and_diff(oqs_sidh_cln16_felm_t xP, oqs_sidh_cln16_point_proj_t d, PCurveIsogenyStruct CurveIsogeny);
// Given the x-coordinates of P, Q, and R, returns the value A corresponding to the Montgomery curve E_A: y^2=x^3+A*x^2+x such that R=Q-P on E_A.
void oqs_sidh_cln16_get_A(oqs_sidh_cln16_f2elm_t xP, oqs_sidh_cln16_f2elm_t xQ, oqs_sidh_cln16_f2elm_t xR, oqs_sidh_cln16_f2elm_t A, PCurveIsogenyStruct CurveIsogeny);
/************ Public key validation functions *************/
// Validation of Alice's public key (ran by Bob)
// CurveIsogeny must be set up in advance using oqs_sidh_cln16_curve_initialize().
SIDH_CRYPTO_STATUS oqs_sidh_cln16_Validate_PKA(oqs_sidh_cln16_f2elm_t A, oqs_sidh_cln16_publickey_t PKA, bool *valid, PCurveIsogenyStruct CurveIsogeny, OQS_RAND *rand);
// Validation of Bob's public key (ran by Alice)
// CurveIsogeny must be set up in advance using oqs_sidh_cln16_curve_initialize().
SIDH_CRYPTO_STATUS oqs_sidh_cln16_Validate_PKB(oqs_sidh_cln16_f2elm_t A, oqs_sidh_cln16_publickey_t PKB, bool *valid, PCurveIsogenyStruct CurveIsogeny, OQS_RAND *rand);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,246 @@
/********************************************************************************************
* SIDH: an efficient supersingular isogeny-based cryptography library for Diffie-Hellman key
* exchange providing 128 bits of quantum security and 192 bits of classical security.
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*
* Abstract: functions for initialization and getting randomness
*
*********************************************************************************************/
#include <stdlib.h>
#include <oqs/rand.h>
#include "SIDH_internal.h"
SIDH_CRYPTO_STATUS oqs_sidh_cln16_curve_initialize(PCurveIsogenyStruct pCurveIsogeny, UNUSED OQS_RAND *rand, PCurveIsogenyStaticData pCurveIsogenyData) {
// Initialize curve isogeny structure pCurveIsogeny with static data extracted from pCurveIsogenyData.
// This needs to be called after allocating memory for "pCurveIsogeny" using oqs_sidh_cln16_curve_allocate().
unsigned int i, pwords, owords;
if (oqs_sidh_cln16_is_CurveIsogenyStruct_null(pCurveIsogeny)) {
return SIDH_CRYPTO_ERROR_INVALID_PARAMETER;
}
for (i = 0; i < 8; i++) { // Copy 8-character identifier
pCurveIsogeny->CurveIsogeny[i] = pCurveIsogenyData->CurveIsogeny[i];
}
pCurveIsogeny->pwordbits = pCurveIsogenyData->pwordbits;
pCurveIsogeny->owordbits = pCurveIsogenyData->owordbits;
pCurveIsogeny->pbits = pCurveIsogenyData->pbits;
pCurveIsogeny->oAbits = pCurveIsogenyData->oAbits;
pCurveIsogeny->oBbits = pCurveIsogenyData->oBbits;
pCurveIsogeny->eB = pCurveIsogenyData->eB;
pCurveIsogeny->BigMont_A24 = pCurveIsogenyData->BigMont_A24;
pwords = (pCurveIsogeny->pwordbits + RADIX - 1) / RADIX;
owords = (pCurveIsogeny->owordbits + RADIX - 1) / RADIX;
oqs_sidh_cln16_copy_words((digit_t *)pCurveIsogenyData->prime, pCurveIsogeny->prime, pwords);
oqs_sidh_cln16_copy_words((digit_t *)pCurveIsogenyData->A, pCurveIsogeny->A, pwords);
oqs_sidh_cln16_copy_words((digit_t *)pCurveIsogenyData->C, pCurveIsogeny->C, pwords);
oqs_sidh_cln16_copy_words((digit_t *)pCurveIsogenyData->Aorder, pCurveIsogeny->Aorder, owords);
oqs_sidh_cln16_copy_words((digit_t *)pCurveIsogenyData->Border, pCurveIsogeny->Border, owords);
oqs_sidh_cln16_copy_words((digit_t *)pCurveIsogenyData->PA, pCurveIsogeny->PA, 2 * pwords);
oqs_sidh_cln16_copy_words((digit_t *)pCurveIsogenyData->PB, pCurveIsogeny->PB, 2 * pwords);
oqs_sidh_cln16_copy_words((digit_t *)pCurveIsogenyData->BigMont_order, pCurveIsogeny->BigMont_order, pwords);
oqs_sidh_cln16_copy_words((digit_t *)pCurveIsogenyData->Montgomery_R2, pCurveIsogeny->Montgomery_R2, pwords);
oqs_sidh_cln16_copy_words((digit_t *)pCurveIsogenyData->Montgomery_pp, pCurveIsogeny->Montgomery_pp, pwords);
oqs_sidh_cln16_copy_words((digit_t *)pCurveIsogenyData->Montgomery_one, pCurveIsogeny->Montgomery_one, pwords);
return SIDH_CRYPTO_SUCCESS;
}
PCurveIsogenyStruct oqs_sidh_cln16_curve_allocate(PCurveIsogenyStaticData CurveData) {
// Dynamic allocation of memory for curve isogeny structure.
// Returns NULL on error.
digit_t pbytes = (CurveData->pwordbits + 7) / 8;
digit_t obytes = (CurveData->owordbits + 7) / 8;
PCurveIsogenyStruct pCurveIsogeny = (PCurveIsogenyStruct)calloc(1, sizeof(CurveIsogenyStruct));
if (!pCurveIsogeny) {
return NULL;
}
pCurveIsogeny->prime = (digit_t *)calloc(1, pbytes);
pCurveIsogeny->A = (digit_t *)calloc(1, pbytes);
pCurveIsogeny->C = (digit_t *)calloc(1, pbytes);
pCurveIsogeny->Aorder = (digit_t *)calloc(1, obytes);
pCurveIsogeny->Border = (digit_t *)calloc(1, obytes);
pCurveIsogeny->PA = (digit_t *)calloc(1, 2 * pbytes);
pCurveIsogeny->PB = (digit_t *)calloc(1, 2 * pbytes);
pCurveIsogeny->BigMont_order = (digit_t *)calloc(1, pbytes);
pCurveIsogeny->Montgomery_R2 = (digit_t *)calloc(1, pbytes);
pCurveIsogeny->Montgomery_pp = (digit_t *)calloc(1, pbytes);
pCurveIsogeny->Montgomery_one = (digit_t *)calloc(1, pbytes);
if (oqs_sidh_cln16_is_CurveIsogenyStruct_null(pCurveIsogeny)) {
oqs_sidh_cln16_curve_free(pCurveIsogeny);
return NULL;
}
return pCurveIsogeny;
}
void oqs_sidh_cln16_curve_free(PCurveIsogenyStruct pCurveIsogeny) {
// Free memory for curve isogeny structure
if (pCurveIsogeny != NULL) {
if (pCurveIsogeny->prime != NULL) {
free(pCurveIsogeny->prime);
}
if (pCurveIsogeny->A != NULL) {
free(pCurveIsogeny->A);
}
if (pCurveIsogeny->C != NULL) {
free(pCurveIsogeny->C);
}
if (pCurveIsogeny->Aorder != NULL) {
free(pCurveIsogeny->Aorder);
}
if (pCurveIsogeny->Border != NULL) {
free(pCurveIsogeny->Border);
}
if (pCurveIsogeny->PA != NULL) {
free(pCurveIsogeny->PA);
}
if (pCurveIsogeny->PB != NULL) {
free(pCurveIsogeny->PB);
}
if (pCurveIsogeny->BigMont_order != NULL) {
free(pCurveIsogeny->BigMont_order);
}
if (pCurveIsogeny->Montgomery_R2 != NULL) {
free(pCurveIsogeny->Montgomery_R2);
}
if (pCurveIsogeny->Montgomery_pp != NULL) {
free(pCurveIsogeny->Montgomery_pp);
}
if (pCurveIsogeny->Montgomery_one != NULL) {
free(pCurveIsogeny->Montgomery_one);
}
free(pCurveIsogeny);
}
}
bool oqs_sidh_cln16_is_CurveIsogenyStruct_null(PCurveIsogenyStruct pCurveIsogeny) {
// Check if curve isogeny structure is NULL
if (pCurveIsogeny == NULL || pCurveIsogeny->prime == NULL || pCurveIsogeny->A == NULL || pCurveIsogeny->C == NULL || pCurveIsogeny->Aorder == NULL || pCurveIsogeny->Border == NULL ||
pCurveIsogeny->PA == NULL || pCurveIsogeny->PB == NULL || pCurveIsogeny->BigMont_order == NULL || pCurveIsogeny->Montgomery_R2 == NULL || pCurveIsogeny->Montgomery_pp == NULL ||
pCurveIsogeny->Montgomery_one == NULL) {
return true;
}
return false;
}
const uint64_t Border_div3[SIDH_NWORDS_ORDER] = { 0xEDCD718A828384F9, 0x733B35BFD4427A14, 0xF88229CF94D7CF38, 0x63C56C990C7C2AD6, 0xB858A87E8F4222C7, 0x254C9C6B525EAF5 };
SIDH_CRYPTO_STATUS oqs_sidh_cln16_random_mod_order(digit_t *random_digits, unsigned int AliceOrBob, PCurveIsogenyStruct pCurveIsogeny, OQS_RAND *rand) {
// Output random values in the range [1, order-1] in little endian format that can be used as private keys.
// It makes requests of random values with length "oAbits" (when AliceOrBob = 0) or "oBbits" (when AliceOrBob = 1).
// The process repeats until random value is in [0, Aorder-2] ([0, Border-2], resp.).
// If successful, the output is given in "random_digits" in the range [1, Aorder-1] ([1, Border-1], resp.).
unsigned int ntry = 0, nbytes, nwords;
digit_t t1[SIDH_MAXWORDS_ORDER] = {0}, order2[SIDH_MAXWORDS_ORDER] = {0};
unsigned char mask;
SIDH_CRYPTO_STATUS Status = SIDH_CRYPTO_SUCCESS;
if (random_digits == NULL || oqs_sidh_cln16_is_CurveIsogenyStruct_null(pCurveIsogeny) || AliceOrBob > 1) {
return SIDH_CRYPTO_ERROR_INVALID_PARAMETER;
}
oqs_sidh_cln16_clear_words((void *)random_digits, SIDH_MAXWORDS_ORDER);
t1[0] = 2;
if (AliceOrBob == SIDH_ALICE) {
nbytes = (pCurveIsogeny->oAbits + 7) / 8; // Number of random bytes to be requested
nwords = NBITS_TO_NWORDS(pCurveIsogeny->oAbits);
mask = 0x07; // Value for masking last random byte
oqs_sidh_cln16_copy_words(pCurveIsogeny->Aorder, order2, nwords);
oqs_sidh_cln16_mp_shiftr1(order2, nwords); // order/2
oqs_sidh_cln16_mp_sub(order2, t1, order2, nwords); // order2 = order/2-2
} else {
nbytes = (pCurveIsogeny->oBbits + 7) / 8;
nwords = NBITS_TO_NWORDS(pCurveIsogeny->oBbits);
mask = 0x03; // Value for masking last random byte
oqs_sidh_cln16_mp_sub((digit_t *)Border_div3, t1, order2, nwords); // order2 = order/3-2
}
do {
ntry++;
if (ntry > 100) { // Max. 100 iterations to obtain random value in [0, order-2]
return SIDH_CRYPTO_ERROR_TOO_MANY_ITERATIONS;
}
rand->rand_n(rand, (uint8_t *) random_digits, nbytes);
((unsigned char *)random_digits)[nbytes - 1] &= mask; // Masking last byte
} while (oqs_sidh_cln16_mp_sub(order2, random_digits, t1, nwords) == 1);
oqs_sidh_cln16_clear_words((void *)t1, SIDH_MAXWORDS_ORDER);
t1[0] = 1;
oqs_sidh_cln16_mp_add(random_digits, t1, random_digits, nwords);
oqs_sidh_cln16_copy_words(random_digits, t1, nwords);
oqs_sidh_cln16_mp_shiftl1(random_digits, nwords); // Alice's output in the range [2, order-2]
if (AliceOrBob == SIDH_BOB) {
oqs_sidh_cln16_mp_add(random_digits, t1, random_digits, nwords); // Bob's output in the range [3, order-3]
}
return Status;
}
SIDH_CRYPTO_STATUS oqs_sidh_cln16_random_BigMont_mod_order(digit_t *random_digits, PCurveIsogenyStruct pCurveIsogeny, OQS_RAND *rand) {
// 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
// using the elliptic curve BigMont.
// It makes requests of random values with length "BIGMONT_NBITS_ORDER".
// The process repeats until random value is in [0, BigMont_order-2]
// If successful, the output is given in "random_digits" in the range [1, BigMont_order-1].
unsigned int ntry = 0, nbytes = (BIGMONT_NBITS_ORDER + 7) / 8, nwords = NBITS_TO_NWORDS(BIGMONT_NBITS_ORDER);
digit_t t1[BIGMONT_MAXWORDS_ORDER] = {0}, order2[BIGMONT_MAXWORDS_ORDER] = {0};
unsigned char mask;
SIDH_CRYPTO_STATUS Status = SIDH_CRYPTO_SUCCESS;
if (random_digits == NULL || oqs_sidh_cln16_is_CurveIsogenyStruct_null(pCurveIsogeny)) {
return SIDH_CRYPTO_ERROR_INVALID_PARAMETER;
}
oqs_sidh_cln16_clear_words((void *)random_digits, BIGMONT_MAXWORDS_ORDER);
t1[0] = 2;
mask = (unsigned char)(8 * nbytes - BIGMONT_NBITS_ORDER);
oqs_sidh_cln16_mp_sub(pCurveIsogeny->BigMont_order, t1, order2, nwords); // order2 = order-2
mask = ((unsigned char) - 1 >> mask); // Value for masking last random byte
do {
ntry++;
if (ntry > 100) { // Max. 100 iterations to obtain random value in [0, order-2]
return SIDH_CRYPTO_ERROR_TOO_MANY_ITERATIONS;
}
rand->rand_n(rand, (uint8_t *)random_digits, nbytes);
((unsigned char *)random_digits)[nbytes - 1] &= mask; // Masking last byte
} while (oqs_sidh_cln16_mp_sub(order2, random_digits, t1, nwords) == 1);
oqs_sidh_cln16_clear_words((void *)t1, BIGMONT_MAXWORDS_ORDER);
t1[0] = 1;
oqs_sidh_cln16_mp_add(random_digits, t1, random_digits, nwords); // Output in the range [1, order-1]
return Status;
}
void oqs_sidh_cln16_clear_words(void *mem, digit_t nwords) {
// Clear digits from memory. "nwords" indicates the number of digits to be zeroed.
// This function uses the volatile type qualifier to inform the compiler not to optimize out the memory clearing.
unsigned int i;
volatile digit_t *v = mem;
for (i = 0; i < nwords; i++) {
v[i] = 0;
}
}

View File

@ -0,0 +1,586 @@
/********************************************************************************************
* SIDH: an efficient supersingular isogeny-based cryptography library for Diffie-Hellman key
* exchange providing 128 bits of quantum security and 192 bits of classical security.
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*
* Abstract: elliptic curve and isogeny functions
*
*********************************************************************************************/
#include "SIDH_internal.h"
void oqs_sidh_cln16_j_inv(oqs_sidh_cln16_f2elm_t A, oqs_sidh_cln16_f2elm_t C, oqs_sidh_cln16_f2elm_t jinv) {
// Computes the j-invariant of a Montgomery curve with projective constant.
// Input: A,C in GF(p^2).
// Output: j=256*(A^2-3*C^2)^3/(C^4*(A^2-4*C^2)), which is j-invariant of Montgomery curve B*y^2=x^3+(A/C)*x^2+x or (equivalently) j-invariant of B'*y^2=C*x^3+A*x^2+C*x.
oqs_sidh_cln16_f2elm_t t0, t1;
oqs_sidh_cln16_fp2sqr751_mont(A, jinv); // jinv = A^2
oqs_sidh_cln16_fp2sqr751_mont(C, t1); // t1 = C^2
oqs_sidh_cln16_fp2add751(t1, t1, t0); // t0 = t1+t1
oqs_sidh_cln16_fp2sub751(jinv, t0, t0); // t0 = jinv-t0
oqs_sidh_cln16_fp2sub751(t0, t1, t0); // t0 = t0-t1
oqs_sidh_cln16_fp2sub751(t0, t1, jinv); // jinv = t0-t1
oqs_sidh_cln16_fp2sqr751_mont(t1, t1); // t1 = t1^2
oqs_sidh_cln16_fp2mul751_mont(jinv, t1, jinv); // jinv = jinv*t1
oqs_sidh_cln16_fp2add751(t0, t0, t0); // t0 = t0+t0
oqs_sidh_cln16_fp2add751(t0, t0, t0); // t0 = t0+t0
oqs_sidh_cln16_fp2sqr751_mont(t0, t1); // t1 = t0^2
oqs_sidh_cln16_fp2mul751_mont(t0, t1, t0); // t0 = t0*t1
oqs_sidh_cln16_fp2add751(t0, t0, t0); // t0 = t0+t0
oqs_sidh_cln16_fp2add751(t0, t0, t0); // t0 = t0+t0
oqs_sidh_cln16_fp2inv751_mont(jinv); // jinv = 1/jinv
oqs_sidh_cln16_fp2mul751_mont(jinv, t0, jinv); // jinv = t0*jinv
}
void oqs_sidh_cln16_xDBLADD(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_point_proj_t Q, oqs_sidh_cln16_f2elm_t xPQ, oqs_sidh_cln16_f2elm_t A24) {
// Simultaneous doubling and differential addition.
// Input: projective Montgomery points P=(XP:ZP) and Q=(XQ:ZQ) such that xP=XP/ZP and xQ=XQ/ZQ, affine difference xPQ=x(P-Q) and Montgomery curve constant A24=(A+2)/4.
// Output: projective Montgomery points P <- 2*P = (X2P:Z2P) such that x(2P)=X2P/Z2P, and Q <- P+Q = (XQP:ZQP) such that = x(Q+P)=XQP/ZQP.
oqs_sidh_cln16_f2elm_t t0, t1, t2;
oqs_sidh_cln16_fp2add751(P->X, P->Z, t0); // t0 = XP+ZP
oqs_sidh_cln16_fp2sub751(P->X, P->Z, t1); // t1 = XP-ZP
oqs_sidh_cln16_fp2sqr751_mont(t0, P->X); // XP = (XP+ZP)^2
oqs_sidh_cln16_fp2sub751(Q->X, Q->Z, t2); // t2 = XQ-ZQ
oqs_sidh_cln16_fp2add751(Q->X, Q->Z, Q->X); // XQ = XQ+ZQ
oqs_sidh_cln16_fp2mul751_mont(t0, t2, t0); // t0 = (XP+ZP)*(XQ-ZQ)
oqs_sidh_cln16_fp2sqr751_mont(t1, P->Z); // ZP = (XP-ZP)^2
oqs_sidh_cln16_fp2mul751_mont(t1, Q->X, t1); // t1 = (XP-ZP)*(XQ+ZQ)
oqs_sidh_cln16_fp2sub751(P->X, P->Z, t2); // t2 = (XP+ZP)^2-(XP-ZP)^2
oqs_sidh_cln16_fp2mul751_mont(P->X, P->Z, P->X); // XP = (XP+ZP)^2*(XP-ZP)^2
oqs_sidh_cln16_fp2mul751_mont(t2, A24, Q->X); // XQ = A24*[(XP+ZP)^2-(XP-ZP)^2]
oqs_sidh_cln16_fp2sub751(t0, t1, Q->Z); // ZQ = (XP+ZP)*(XQ-ZQ)-(XP-ZP)*(XQ+ZQ)
oqs_sidh_cln16_fp2add751(Q->X, P->Z, P->Z); // ZP = A24*[(XP+ZP)^2-(XP-ZP)^2]+(XP-ZP)^2
oqs_sidh_cln16_fp2add751(t0, t1, Q->X); // XQ = (XP+ZP)*(XQ-ZQ)+(XP-ZP)*(XQ+ZQ)
oqs_sidh_cln16_fp2mul751_mont(P->Z, t2, P->Z); // ZP = [A24*[(XP+ZP)^2-(XP-ZP)^2]+(XP-ZP)^2]*[(XP+ZP)^2-(XP-ZP)^2]
oqs_sidh_cln16_fp2sqr751_mont(Q->Z, Q->Z); // ZQ = [(XP+ZP)*(XQ-ZQ)-(XP-ZP)*(XQ+ZQ)]^2
oqs_sidh_cln16_fp2sqr751_mont(Q->X, Q->X); // XQ = [(XP+ZP)*(XQ-ZQ)+(XP-ZP)*(XQ+ZQ)]^2
oqs_sidh_cln16_fp2mul751_mont(Q->Z, xPQ, Q->Z); // ZQ = xPQ*[(XP+ZP)*(XQ-ZQ)-(XP-ZP)*(XQ+ZQ)]^2
}
void oqs_sidh_cln16_xDBL(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_point_proj_t Q, oqs_sidh_cln16_f2elm_t A24, oqs_sidh_cln16_f2elm_t C24) {
// Doubling of a Montgomery point in projective coordinates (X:Z).
// Input: projective Montgomery x-coordinates P = (X1:Z1), where x1=X1/Z1 and Montgomery curve constant A24/C24=(A/C+2)/4.
// Output: projective Montgomery x-coordinates Q = 2*P = (X2:Z2).
oqs_sidh_cln16_f2elm_t t0, t1;
oqs_sidh_cln16_fp2sub751(P->X, P->Z, t0); // t0 = X1-Z1
oqs_sidh_cln16_fp2add751(P->X, P->Z, t1); // t1 = X1+Z1
oqs_sidh_cln16_fp2sqr751_mont(t0, t0); // t0 = (X1-Z1)^2
oqs_sidh_cln16_fp2sqr751_mont(t1, t1); // t1 = (X1+Z1)^2
oqs_sidh_cln16_fp2mul751_mont(C24, t0, Q->Z); // Z2 = C24*(X1-Z1)^2
oqs_sidh_cln16_fp2mul751_mont(t1, Q->Z, Q->X); // X2 = C24*(X1-Z1)^2*(X1+Z1)^2
oqs_sidh_cln16_fp2sub751(t1, t0, t1); // t1 = (X1+Z1)^2-(X1-Z1)^2
oqs_sidh_cln16_fp2mul751_mont(A24, t1, t0); // t0 = A24*[(X1+Z1)^2-(X1-Z1)^2]
oqs_sidh_cln16_fp2add751(Q->Z, t0, Q->Z); // Z2 = A24*[(X1+Z1)^2-(X1-Z1)^2] + C24*(X1-Z1)^2
oqs_sidh_cln16_fp2mul751_mont(Q->Z, t1, Q->Z); // Z2 = [A24*[(X1+Z1)^2-(X1-Z1)^2] + C24*(X1-Z1)^2]*[(X1+Z1)^2-(X1-Z1)^2]
}
void oqs_sidh_cln16_xDBLe(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_point_proj_t Q, oqs_sidh_cln16_f2elm_t A, oqs_sidh_cln16_f2elm_t C, int e) {
// Computes [2^e](X:Z) on Montgomery curve with projective constant via e repeated doublings.
// Input: projective Montgomery x-coordinates P = (XP:ZP), such that xP=XP/ZP and Montgomery curve constant A/C.
// Output: projective Montgomery x-coordinates P <- (2^e)*P.
oqs_sidh_cln16_f2elm_t A24num, A24den;
int i;
oqs_sidh_cln16_fp2add751(C, C, A24num);
oqs_sidh_cln16_fp2add751(A24num, A24num, A24den);
oqs_sidh_cln16_fp2add751(A24num, A, A24num);
oqs_sidh_cln16_copy_words((digit_t *)P, (digit_t *)Q, 2 * 2 * NWORDS_FIELD);
for (i = 0; i < e; i++) {
oqs_sidh_cln16_xDBL(Q, Q, A24num, A24den);
}
}
void oqs_sidh_cln16_xADD(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_point_proj_t Q, oqs_sidh_cln16_f2elm_t xPQ) {
// Differential addition.
// Input: projective Montgomery points P=(XP:ZP) and Q=(XQ:ZQ) such that xP=XP/ZP and xQ=XQ/ZQ, and affine difference xPQ=x(P-Q).
// Output: projective Montgomery point P <- P+Q = (XQP:ZQP) such that = x(Q+P)=XQP/ZQP.
oqs_sidh_cln16_f2elm_t t0, t1;
oqs_sidh_cln16_fp2add751(P->X, P->Z, t0); // t0 = XP+ZP
oqs_sidh_cln16_fp2sub751(P->X, P->Z, t1); // t1 = XP-ZP
oqs_sidh_cln16_fp2sub751(Q->X, Q->Z, P->X); // XP = XQ-ZQ
oqs_sidh_cln16_fp2add751(Q->X, Q->Z, P->Z); // ZP = XQ+ZQ
oqs_sidh_cln16_fp2mul751_mont(t0, P->X, t0); // t0 = (XP+ZP)*(XQ-ZQ)
oqs_sidh_cln16_fp2mul751_mont(t1, P->Z, t1); // t1 = (XP-ZP)*(XQ+ZQ)
oqs_sidh_cln16_fp2sub751(t0, t1, P->Z); // ZP = (XP+ZP)*(XQ-ZQ)-(XP-ZP)*(XQ+ZQ)
oqs_sidh_cln16_fp2add751(t0, t1, P->X); // XP = (XP+ZP)*(XQ-ZQ)+(XP-ZP)*(XQ+ZQ)
oqs_sidh_cln16_fp2sqr751_mont(P->Z, P->Z); // ZP = [(XP+ZP)*(XQ-ZQ)-(XP-ZP)*(XQ+ZQ)]^2
oqs_sidh_cln16_fp2sqr751_mont(P->X, P->X); // XP = [(XP+ZP)*(XQ-ZQ)+(XP-ZP)*(XQ+ZQ)]^2
oqs_sidh_cln16_fp2mul751_mont(P->Z, xPQ, P->Z); // ZP = xPQ*[(XP+ZP)*(XQ-ZQ)-(XP-ZP)*(XQ+ZQ)]^2
}
void oqs_sidh_cln16_xDBL_basefield(oqs_sidh_cln16_point_basefield_proj_t P, oqs_sidh_cln16_point_basefield_proj_t Q) {
// Doubling of a Montgomery point in projective coordinates (X:Z) over the base field.
// Input: projective Montgomery x-coordinates P = (X1:Z1), where x1=X1/Z1 and Montgomery curve constant A24/C24=(A/C+2)/4.
// Output: projective Montgomery x-coordinates Q = 2*P = (X2:Z2).
oqs_sidh_cln16_felm_t t0, t1;
// NOTE: this function is fixed for A24=1, C24=2
oqs_sidh_cln16_fpsub751(P->X, P->Z, t0); // t0 = X1-Z1
oqs_sidh_cln16_fpadd751(P->X, P->Z, t1); // t1 = X1+Z1
oqs_sidh_cln16_fpsqr751_mont(t0, t0); // t0 = (X1-Z1)^2
oqs_sidh_cln16_fpsqr751_mont(t1, t1); // t1 = (X1+Z1)^2
oqs_sidh_cln16_fpadd751(t0, t0, Q->Z); // Z2 = C24*(X1-Z1)^2
oqs_sidh_cln16_fpmul751_mont(t1, Q->Z, Q->X); // X2 = C24*(X1-Z1)^2*(X1+Z1)^2
oqs_sidh_cln16_fpsub751(t1, t0, t1); // t1 = (X1+Z1)^2-(X1-Z1)^2
oqs_sidh_cln16_fpadd751(Q->Z, t1, Q->Z); // Z2 = A24*[(X1+Z1)^2-(X1-Z1)^2] + C24*(X1-Z1)^2
oqs_sidh_cln16_fpmul751_mont(Q->Z, t1, Q->Z); // Z2 = [A24*[(X1+Z1)^2-(X1-Z1)^2] + C24*(X1-Z1)^2]*[(X1+Z1)^2-(X1-Z1)^2]
}
void oqs_sidh_cln16_xDBLADD_basefield(oqs_sidh_cln16_point_basefield_proj_t P, oqs_sidh_cln16_point_basefield_proj_t Q, oqs_sidh_cln16_felm_t xPQ, oqs_sidh_cln16_felm_t A24) {
// Simultaneous doubling and differential addition over the base field.
// Input: projective Montgomery points P=(XP:ZP) and Q=(XQ:ZQ) such that xP=XP/ZP and xQ=XQ/ZQ, affine difference xPQ=x(P-Q) and Montgomery curve constant A24=(A+2)/4.
// Output: projective Montgomery points P <- 2*P = (X2P:Z2P) such that x(2P)=X2P/Z2P, and Q <- P+Q = (XQP:ZQP) such that = x(Q+P)=XQP/ZQP.
oqs_sidh_cln16_felm_t t0, t1, t2;
// NOTE: this function is fixed for C24=2
oqs_sidh_cln16_fpadd751(P->X, P->Z, t0); // t0 = XP+ZP
oqs_sidh_cln16_fpsub751(P->X, P->Z, t1); // t1 = XP-ZP
oqs_sidh_cln16_fpsqr751_mont(t0, P->X); // XP = (XP+ZP)^2
oqs_sidh_cln16_fpsub751(Q->X, Q->Z, t2); // t2 = XQ-ZQ
oqs_sidh_cln16_fpadd751(Q->X, Q->Z, Q->X); // XQ = XQ+ZQ
oqs_sidh_cln16_fpmul751_mont(t0, t2, t0); // t0 = (XP+ZP)*(XQ-ZQ)
oqs_sidh_cln16_fpsqr751_mont(t1, P->Z); // ZP = (XP-ZP)^2
oqs_sidh_cln16_fpmul751_mont(t1, Q->X, t1); // t1 = (XP-ZP)*(XQ+ZQ)
oqs_sidh_cln16_fpsub751(P->X, P->Z, t2); // t2 = (XP+ZP)^2-(XP-ZP)^2
if (A24[0] == 1) {
oqs_sidh_cln16_fpadd751(P->Z, P->Z, P->Z); // ZP = C24*(XP-ZP)^2
oqs_sidh_cln16_fpmul751_mont(P->X, P->Z, P->X); // XP = C24*(XP+ZP)^2*(XP-ZP)^2
oqs_sidh_cln16_fpadd751(t2, P->Z, P->Z); // ZP = A24*[(XP+ZP)^2-(XP-ZP)^2]+C24*(XP-ZP)^2
} else {
oqs_sidh_cln16_fpmul751_mont(P->X, P->Z, P->X); // XP = (XP+ZP)^2*(XP-ZP)^2
oqs_sidh_cln16_fpmul751_mont(A24, t2, Q->X); // XQ = A24*[(XP+ZP)^2-(XP-ZP)^2]
oqs_sidh_cln16_fpadd751(P->Z, Q->X, P->Z); // ZP = A24*[(XP+ZP)^2-(XP-ZP)^2]+C24*(XP-ZP)^2
}
oqs_sidh_cln16_fpsub751(t0, t1, Q->Z); // ZQ = (XP+ZP)*(XQ-ZQ)-(XP-ZP)*(XQ+ZQ)
oqs_sidh_cln16_fpadd751(t0, t1, Q->X); // XQ = (XP+ZP)*(XQ-ZQ)+(XP-ZP)*(XQ+ZQ)
oqs_sidh_cln16_fpmul751_mont(P->Z, t2, P->Z); // ZP = [A24*[(XP+ZP)^2-(XP-ZP)^2]+C24*(XP-ZP)^2]*[(XP+ZP)^2-(XP-ZP)^2]
oqs_sidh_cln16_fpsqr751_mont(Q->Z, Q->Z); // ZQ = [(XP+ZP)*(XQ-ZQ)-(XP-ZP)*(XQ+ZQ)]^2
oqs_sidh_cln16_fpsqr751_mont(Q->X, Q->X); // XQ = [(XP+ZP)*(XQ-ZQ)+(XP-ZP)*(XQ+ZQ)]^2
oqs_sidh_cln16_fpmul751_mont(Q->Z, xPQ, Q->Z); // ZQ = xPQ*[(XP+ZP)*(XQ-ZQ)-(XP-ZP)*(XQ+ZQ)]^2
}
void oqs_sidh_cln16_ladder(oqs_sidh_cln16_felm_t x, digit_t *m, oqs_sidh_cln16_point_basefield_proj_t P, oqs_sidh_cln16_point_basefield_proj_t Q, oqs_sidh_cln16_felm_t A24, unsigned int order_bits, unsigned int order_fullbits, PCurveIsogenyStruct CurveIsogeny) {
// The Montgomery ladder
// Inputs: the affine x-coordinate of a point P on E: B*y^2=x^3+A*x^2+x,
// scalar m
// curve constant A24 = (A+2)/4
// order_bits = subgroup order bitlength
// order_fullbits = smallest multiple of 32 larger than the order bitlength
// Output: Q = m*(x:1)
// CurveIsogeny must be set up in advance using oqs_sidh_cln16_curve_initialize().
unsigned int bit = 0, owords = NBITS_TO_NWORDS(order_fullbits);
digit_t mask;
int i;
// Initializing with the points (1:0) and (x:1)
oqs_sidh_cln16_fpcopy751((digit_t *)CurveIsogeny->Montgomery_one, (digit_t *)P->X);
oqs_sidh_cln16_fpzero751(P->Z);
oqs_sidh_cln16_fpcopy751(x, Q->X);
oqs_sidh_cln16_fpcopy751((digit_t *)CurveIsogeny->Montgomery_one, (digit_t *)Q->Z);
for (i = order_fullbits - order_bits; i > 0; i--) {
oqs_sidh_cln16_mp_shiftl1(m, owords);
}
for (i = order_bits; i > 0; i--) {
bit = (unsigned int)(m[owords - 1] >> (RADIX - 1));
oqs_sidh_cln16_mp_shiftl1(m, owords);
mask = 0 - (digit_t)bit;
oqs_sidh_cln16_swap_points_basefield(P, Q, mask);
oqs_sidh_cln16_xDBLADD_basefield(P, Q, x, A24); // If bit=0 then P <- 2*P and Q <- P+Q,
oqs_sidh_cln16_swap_points_basefield(P, Q, mask); // else if bit=1 then Q <- 2*Q and P <- P+Q
}
}
SIDH_CRYPTO_STATUS oqs_sidh_cln16_BigMont_ladder(unsigned char *x, digit_t *m, unsigned char *xout, PCurveIsogenyStruct CurveIsogeny) {
// BigMont's scalar multiplication using the Montgomery ladder
// Inputs: x, the affine x-coordinate of a point P on BigMont: y^2=x^3+A*x^2+x,
// scalar m.
// Output: xout, the affine x-coordinate of m*(x:1)
// CurveIsogeny must be set up in advance using oqs_sidh_cln16_curve_initialize().
oqs_sidh_cln16_point_basefield_proj_t P1, P2;
digit_t scalar[BIGMONT_NWORDS_ORDER];
oqs_sidh_cln16_felm_t X, A24 = {0};
A24[0] = (digit_t)CurveIsogeny->BigMont_A24;
oqs_sidh_cln16_to_mont(A24, A24); // Conversion to Montgomery representation
oqs_sidh_cln16_to_mont((digit_t *)x, X);
oqs_sidh_cln16_copy_words(m, scalar, BIGMONT_NWORDS_ORDER);
oqs_sidh_cln16_ladder(X, scalar, P1, P2, A24, BIGMONT_NBITS_ORDER, BIGMONT_MAXBITS_ORDER, CurveIsogeny);
oqs_sidh_cln16_fpinv751_mont(P1->Z);
oqs_sidh_cln16_fpmul751_mont(P1->X, P1->Z, (digit_t *)xout);
oqs_sidh_cln16_from_mont((digit_t *)xout, (digit_t *)xout); // Conversion to standard representation
return SIDH_CRYPTO_SUCCESS;
}
SIDH_CRYPTO_STATUS oqs_sidh_cln16_secret_pt(oqs_sidh_cln16_point_basefield_t P, digit_t *m, unsigned int AliceOrBob, oqs_sidh_cln16_point_proj_t R, PCurveIsogenyStruct CurveIsogeny) {
// Computes key generation entirely in the base field by exploiting a 1-dimensional Montgomery ladder in the trace zero subgroup and
// recovering the y-coordinate for the addition. All operations in the base field GF(p).
// Input: The scalar m, point P = (x,y) on E in the base field subgroup and Q = (x1,y1*i) on E in the trace-zero subgroup.
// x,y,x1,y1 are all in the base field.
// Output: R = (RX0+RX1*i)/RZ0 (the x-coordinate of P+[m]Q).
unsigned int nbits;
oqs_sidh_cln16_point_basefield_t Q;
oqs_sidh_cln16_point_basefield_proj_t S, T;
digit_t *X0 = (digit_t *)S->X, *Z0 = (digit_t *)S->Z, *X1 = (digit_t *)T->X, *Z1 = (digit_t *)T->Z;
digit_t *x = (digit_t *)P->x, *y = (digit_t *)P->y, *x1 = (digit_t *)Q->x, *y1 = (digit_t *)Q->y;
digit_t scalar[SIDH_NWORDS_ORDER];
oqs_sidh_cln16_felm_t t0, t1, t2, A24 = {0};
digit_t *RX0 = (digit_t *)R->X[0], *RX1 = (digit_t *)R->X[1], *RZ0 = (digit_t *)R->Z[0], *RZ1 = (digit_t *)R->Z[1];
oqs_sidh_cln16_fpcopy751(P->x, Q->x); // Q = (-XP,YP)
oqs_sidh_cln16_fpcopy751(P->y, Q->y);
oqs_sidh_cln16_fpneg751(Q->x);
if (AliceOrBob == SIDH_ALICE) {
nbits = CurveIsogeny->oAbits;
} else if (AliceOrBob == SIDH_BOB) {
nbits = CurveIsogeny->oBbits;
} else {
return SIDH_CRYPTO_ERROR_INVALID_PARAMETER;
}
// Setting curve constant to one (in standard representation), used in oqs_sidh_cln16_xDBLADD_basefield() in the ladder computation
A24[0] = 1;
oqs_sidh_cln16_copy_words(m, scalar, SIDH_NWORDS_ORDER);
oqs_sidh_cln16_ladder(Q->x, scalar, S, T, A24, nbits, CurveIsogeny->owordbits, CurveIsogeny);
//RX0 := (2*y*y1*Z0^2*Z1 + Z1*(X0*x1+Z0)*(X0+x1*Z0) - X1*(X0-x1*Z0)^2)*(2*y*y1*Z0^2*Z1 - Z1*(X0*x1+Z0)*(X0+x1*Z0) + X1*(X0-x1*Z0)^2) - 4*y1^2*Z0*Z1^2*(X0+x*Z0)*(X0-x*Z0)^2;
//RX1 := 4*y*y1*Z0^2*Z1*(Z1*(X0*x1+Z0)*(X0+x1*Z0) - X1*(X0-x1*Z0)^2);
//RZ0 := 4*y1^2*Z0^2*Z1^2*(X0-x*Z0)^2;
oqs_sidh_cln16_fpmul751_mont(x1, Z0, RX1);
oqs_sidh_cln16_fpmul751_mont(X0, x1, RX0);
oqs_sidh_cln16_fpsub751(X0, RX1, t0);
oqs_sidh_cln16_fpadd751(X0, RX1, RX1);
oqs_sidh_cln16_fpsqr751_mont(t0, t0);
oqs_sidh_cln16_fpadd751(RX0, Z0, RX0);
oqs_sidh_cln16_fpmul751_mont(t0, X1, t0);
oqs_sidh_cln16_fpmul751_mont(RX0, RX1, RX0);
oqs_sidh_cln16_fpmul751_mont(y1, Z1, t2);
oqs_sidh_cln16_fpmul751_mont(y, Z0, t1);
oqs_sidh_cln16_fpadd751(t2, t2, t2);
oqs_sidh_cln16_fpmul751_mont(t2, Z0, RX1);
oqs_sidh_cln16_fpmul751_mont(RX0, Z1, RX0);
oqs_sidh_cln16_fpsub751(RX0, t0, RX0);
oqs_sidh_cln16_fpmul751_mont(t1, RX1, t1);
oqs_sidh_cln16_fpsqr751_mont(RX1, t0);
oqs_sidh_cln16_fpmul751_mont(t2, RX1, t2);
oqs_sidh_cln16_fpmul751_mont(t1, RX0, RX1);
oqs_sidh_cln16_fpadd751(t1, RX0, RZ0);
oqs_sidh_cln16_fpadd751(RX1, RX1, RX1);
oqs_sidh_cln16_fpsub751(t1, RX0, t1);
oqs_sidh_cln16_fpmul751_mont(x, Z0, RX0);
oqs_sidh_cln16_fpmul751_mont(t1, RZ0, t1);
oqs_sidh_cln16_fpsub751(X0, RX0, RZ0);
oqs_sidh_cln16_fpadd751(X0, RX0, RX0);
oqs_sidh_cln16_fpsqr751_mont(RZ0, RZ0);
oqs_sidh_cln16_fpmul751_mont(t2, RX0, t2);
oqs_sidh_cln16_fpmul751_mont(t2, RZ0, t2);
oqs_sidh_cln16_fpmul751_mont(RZ0, t0, RZ0);
oqs_sidh_cln16_fpsub751(t1, t2, RX0);
oqs_sidh_cln16_fpzero751(RZ1);
return SIDH_CRYPTO_SUCCESS;
}
SIDH_CRYPTO_STATUS oqs_sidh_cln16_ladder_3_pt(oqs_sidh_cln16_f2elm_t xP, oqs_sidh_cln16_f2elm_t xQ, oqs_sidh_cln16_f2elm_t xPQ, digit_t *m, unsigned int AliceOrBob, oqs_sidh_cln16_point_proj_t W, oqs_sidh_cln16_f2elm_t A, PCurveIsogenyStruct CurveIsogeny) {
// Computes P+[m]Q via x-only arithmetic. Algorithm by De Feo, Jao and Plut.
// Input: three affine points xP,xQ,xPQ and Montgomery constant A.
// Output: projective Montgomery x-coordinates of x(P+[m]Q)=WX/WZ
oqs_sidh_cln16_point_proj_t U = oqs_sidh_cln16_point_proj_t_EMPTY, V = oqs_sidh_cln16_point_proj_t_EMPTY;
oqs_sidh_cln16_f2elm_t A24, A24num, constant1 = { {0} }, constant2;
oqs_sidh_cln16_felm_t temp_scalar;
unsigned int bit = 0, nbits, fullbits = CurveIsogeny->owordbits;
digit_t mask;
int i;
if (AliceOrBob == SIDH_ALICE) {
nbits = CurveIsogeny->oAbits;
} else if (AliceOrBob == SIDH_BOB) {
nbits = CurveIsogeny->oBbits;
} else {
return SIDH_CRYPTO_ERROR_INVALID_PARAMETER;
}
oqs_sidh_cln16_fpcopy751((digit_t *)CurveIsogeny->Montgomery_one, constant1[0]);
oqs_sidh_cln16_fp2add751(constant1, constant1, constant1); // constant = 2
oqs_sidh_cln16_fp2add751(A, constant1, A24num);
oqs_sidh_cln16_fp2div2_751(A24num, A24);
oqs_sidh_cln16_fp2div2_751(A24, A24);
// Initializing with the points (1:0), (xQ:1) and (xP:1)
oqs_sidh_cln16_fpcopy751((digit_t *)CurveIsogeny->Montgomery_one, (digit_t *)U->X);
oqs_sidh_cln16_fp2copy751(xQ, V->X);
oqs_sidh_cln16_fpcopy751((digit_t *)CurveIsogeny->Montgomery_one, (digit_t *)V->Z);
oqs_sidh_cln16_fp2copy751(xP, W->X);
oqs_sidh_cln16_fpcopy751((digit_t *)CurveIsogeny->Montgomery_one, (digit_t *)W->Z);
oqs_sidh_cln16_fpzero751(W->Z[1]);
oqs_sidh_cln16_fpcopy751(m, temp_scalar);
for (i = fullbits - nbits; i > 0; i--) {
oqs_sidh_cln16_mp_shiftl1(temp_scalar, SIDH_NWORDS_ORDER);
}
for (i = nbits; i > 0; i--) {
bit = (unsigned int)(temp_scalar[SIDH_NWORDS_ORDER - 1] >> (RADIX - 1));
oqs_sidh_cln16_mp_shiftl1(temp_scalar, SIDH_NWORDS_ORDER);
mask = 0 - (digit_t)bit;
oqs_sidh_cln16_swap_points(W, U, mask);
oqs_sidh_cln16_swap_points(U, V, mask);
oqs_sidh_cln16_select_f2elm(xP, xQ, constant1, mask);
oqs_sidh_cln16_select_f2elm(xQ, xPQ, constant2, mask);
oqs_sidh_cln16_xADD(W, U, constant1); // If bit=0 then W <- W+U, U <- 2*U and V <- U+V,
oqs_sidh_cln16_xDBLADD(U, V, constant2, A24); // else if bit=1 then U <- U+V, V <- 2*V and W <- V+W
oqs_sidh_cln16_swap_points(U, V, mask);
oqs_sidh_cln16_swap_points(W, U, mask);
}
return SIDH_CRYPTO_SUCCESS;
}
void oqs_sidh_cln16_get_4_isog(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_f2elm_t A, oqs_sidh_cln16_f2elm_t C, oqs_sidh_cln16_f2elm_t *coeff) {
// Computes the corresponding 4-isogeny of a projective Montgomery point (X4:Z4) of order 4.
// Input: projective point of order four P = (X4:Z4).
// Output: the 4-isogenous Montgomery curve with projective coefficient A/C and the 5 coefficients
// that are used to evaluate the isogeny at a point in oqs_sidh_cln16_eval_4_isog().
oqs_sidh_cln16_fp2add751(P->X, P->Z, coeff[0]); // coeff[0] = X4+Z4
oqs_sidh_cln16_fp2sqr751_mont(P->X, coeff[3]); // coeff[3] = X4^2
oqs_sidh_cln16_fp2sqr751_mont(P->Z, coeff[4]); // coeff[4] = Z4^2
oqs_sidh_cln16_fp2sqr751_mont(coeff[0], coeff[0]); // coeff[0] = (X4+Z4)^2
oqs_sidh_cln16_fp2add751(coeff[3], coeff[4], coeff[1]); // coeff[1] = X4^2+Z4^2
oqs_sidh_cln16_fp2sub751(coeff[3], coeff[4], coeff[2]); // coeff[2] = X4^2-Z4^2
oqs_sidh_cln16_fp2sqr751_mont(coeff[3], coeff[3]); // coeff[3] = X4^4
oqs_sidh_cln16_fp2sqr751_mont(coeff[4], coeff[4]); // coeff[4] = Z4^4
oqs_sidh_cln16_fp2add751(coeff[3], coeff[3], A); // A = 2*X4^4
oqs_sidh_cln16_fp2sub751(coeff[0], coeff[1], coeff[0]); // coeff[0] = 2*X4*Z4 = (X4+Z4)^2 - (X4^2+Z4^2)
oqs_sidh_cln16_fp2sub751(A, coeff[4], A); // A = 2*X4^4-Z4^4
oqs_sidh_cln16_fp2copy751(coeff[4], C); // C = Z4^4
oqs_sidh_cln16_fp2add751(A, A, A); // A = 2(2*X4^4-Z4^4)
}
void oqs_sidh_cln16_eval_4_isog(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_f2elm_t *coeff) {
// Evaluates the isogeny at the point (X:Z) in the domain of the isogeny, given a 4-isogeny phi defined
// by the 5 coefficients in coeff (computed in the function four_isogeny_from_projective_kernel()).
// Inputs: the coefficients defining the isogeny, and the projective point P = (X:Z).
// Output: the projective point P = phi(P) = (X:Z) in the codomain.
oqs_sidh_cln16_f2elm_t t0, t1;
oqs_sidh_cln16_fp2mul751_mont(P->X, coeff[0], P->X); // X = coeff[0]*X
oqs_sidh_cln16_fp2mul751_mont(P->Z, coeff[1], t0); // t0 = coeff[1]*Z
oqs_sidh_cln16_fp2sub751(P->X, t0, P->X); // X = X-t0
oqs_sidh_cln16_fp2mul751_mont(P->Z, coeff[2], P->Z); // Z = coeff[2]*Z
oqs_sidh_cln16_fp2sub751(P->X, P->Z, t0); // t0 = X-Z
oqs_sidh_cln16_fp2mul751_mont(P->Z, P->X, P->Z); // Z = X*Z
oqs_sidh_cln16_fp2sqr751_mont(t0, t0); // t0 = t0^2
oqs_sidh_cln16_fp2add751(P->Z, P->Z, P->Z); // Z = Z+Z
oqs_sidh_cln16_fp2add751(P->Z, P->Z, P->Z); // Z = Z+Z
oqs_sidh_cln16_fp2add751(P->Z, t0, P->X); // X = t0+Z
oqs_sidh_cln16_fp2mul751_mont(P->Z, t0, P->Z); // Z = t0*Z
oqs_sidh_cln16_fp2mul751_mont(P->Z, coeff[4], P->Z); // Z = coeff[4]*Z
oqs_sidh_cln16_fp2mul751_mont(t0, coeff[4], t0); // t0 = t0*coeff[4]
oqs_sidh_cln16_fp2mul751_mont(P->X, coeff[3], t1); // t1 = X*coeff[3]
oqs_sidh_cln16_fp2sub751(t0, t1, t0); // t0 = t0-t1
oqs_sidh_cln16_fp2mul751_mont(P->X, t0, P->X); // X = X*t0
}
void oqs_sidh_cln16_first_4_isog(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_f2elm_t A, oqs_sidh_cln16_f2elm_t Aout, oqs_sidh_cln16_f2elm_t Cout, PCurveIsogenyStruct CurveIsogeny) {
// Computes first 4-isogeny computed by Alice.
// Inputs: projective point P = (X4:Z4) and curve constant A.
// Output: the projective point P = (X4:Z4) in the codomain and isogenous curve constant Aout/Cout.
oqs_sidh_cln16_f2elm_t t0 = { {0} }, t1, t2;
oqs_sidh_cln16_fpcopy751(CurveIsogeny->Montgomery_one, t0[0]);
oqs_sidh_cln16_fpadd751(t0[0], t0[0], t0[0]); // t0 = 2 (in Montgomery domain)
oqs_sidh_cln16_fp2sub751(A, t0, Cout); // Cout = A-2
oqs_sidh_cln16_fpadd751(t0[0], t0[0], t1[0]);
oqs_sidh_cln16_fpadd751(t0[0], t1[0], t0[0]); // t0 = 6 (in Montgomery domain)
oqs_sidh_cln16_fp2add751(P->X, P->Z, t1); // t1 = X+Z
oqs_sidh_cln16_fp2sub751(P->X, P->Z, t2); // t2 = X-Z
oqs_sidh_cln16_fp2sqr751_mont(t1, t1); // t1 = (X+Z)^2
oqs_sidh_cln16_fp2add751(A, t0, Aout); // A = A+6
oqs_sidh_cln16_fp2mul751_mont(P->X, P->Z, P->Z); // Z = X*Z
oqs_sidh_cln16_fp2neg751(P->Z); // Z = -X*Z
oqs_sidh_cln16_fp2sqr751_mont(t2, t2); // t2 = (X-Z)^2
oqs_sidh_cln16_fp2mul751_mont(P->Z, Cout, P->Z); // Z = -C*X*Z
oqs_sidh_cln16_fp2add751(Aout, Aout, Aout); // Aout = 2*A+12
oqs_sidh_cln16_fp2sub751(t1, P->Z, P->X); // X = (X+Z)^2+C*X*Z
oqs_sidh_cln16_fp2mul751_mont(P->Z, t2, P->Z); // Z = -C*X*Z*(X-Z)^2
oqs_sidh_cln16_fp2mul751_mont(P->X, t1, P->X); // X = (X+Z)^2*[(X+Z)^2+C*X*Z]
}
void oqs_sidh_cln16_xTPL(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_point_proj_t Q, oqs_sidh_cln16_f2elm_t A24, oqs_sidh_cln16_f2elm_t C24) {
// Tripling of a Montgomery point in projective coordinates (X:Z).
// Input: projective Montgomery x-coordinates P = (X:Z), where x=X/Z and Montgomery curve constant A/C.
// Output: projective Montgomery x-coordinates Q = 3*P = (X3:Z3).
oqs_sidh_cln16_f2elm_t t0, t1, t2, t3, t4, t5;
oqs_sidh_cln16_fp2sub751(P->X, P->Z, t2); // t2 = X-Z
oqs_sidh_cln16_fp2add751(P->X, P->Z, t3); // t3 = X+Z
oqs_sidh_cln16_fp2sqr751_mont(t2, t0); // t0 = t2^2
oqs_sidh_cln16_fp2sqr751_mont(t3, t1); // t1 = t3^2
oqs_sidh_cln16_fp2mul751_mont(t0, C24, t4); // t4 = C24*t0
oqs_sidh_cln16_fp2mul751_mont(t1, t4, t5); // t5 = t4*t1
oqs_sidh_cln16_fp2sub751(t1, t0, t1); // t1 = t1-t0
oqs_sidh_cln16_fp2mul751_mont(A24, t1, t0); // t0 = A24*t1
oqs_sidh_cln16_fp2add751(t4, t0, t4); // t4 = t4+t0
oqs_sidh_cln16_fp2mul751_mont(t1, t4, t4); // t4 = t4*t1
oqs_sidh_cln16_fp2add751(t5, t4, t0); // t0 = t5+t4
oqs_sidh_cln16_fp2sub751(t5, t4, t1); // t1 = t5-t4
oqs_sidh_cln16_fp2mul751_mont(t0, t2, t0); // t0 = t2*t0
oqs_sidh_cln16_fp2mul751_mont(t1, t3, t1); // t1 = t3*t1
oqs_sidh_cln16_fp2sub751(t0, t1, t4); // t4 = t0-t1
oqs_sidh_cln16_fp2add751(t0, t1, t5); // t5 = t0+t1
oqs_sidh_cln16_fp2sqr751_mont(t4, t4); // t4 = t4^2
oqs_sidh_cln16_fp2sqr751_mont(t5, t5); // t5 = t5^2
oqs_sidh_cln16_fp2mul751_mont(P->X, t4, t4); // t4 = X*t4
oqs_sidh_cln16_fp2mul751_mont(P->Z, t5, Q->X); // X3 = Z*t5
oqs_sidh_cln16_fp2copy751(t4, Q->Z); // Z3 = t4
}
void oqs_sidh_cln16_xTPLe(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_point_proj_t Q, oqs_sidh_cln16_f2elm_t A, oqs_sidh_cln16_f2elm_t C, int e) {
// Computes [3^e](X:Z) on Montgomery curve with projective constant via e repeated triplings.
// Input: projective Montgomery x-coordinates P = (XP:ZP), such that xP=XP/ZP and Montgomery curve constant A/C.
// Output: projective Montgomery x-coordinates P <- (3^e)*P.
oqs_sidh_cln16_f2elm_t A24, C24;
int i;
oqs_sidh_cln16_fp2add751(C, C, A24);
oqs_sidh_cln16_fp2add751(A24, A24, C24);
oqs_sidh_cln16_fp2add751(A24, A, A24);
oqs_sidh_cln16_copy_words((digit_t *)P, (digit_t *)Q, 2 * 2 * NWORDS_FIELD);
for (i = 0; i < e; i++) {
oqs_sidh_cln16_xTPL(Q, Q, A24, C24);
}
}
void oqs_sidh_cln16_get_3_isog(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_f2elm_t A, oqs_sidh_cln16_f2elm_t C) {
// Computes the corresponding 3-isogeny of a projective Montgomery point (X3:Z3) of order 3.
// Input: projective point of order three P = (X3:Z3).
// Output: the 3-isogenous Montgomery curve with projective coefficient A/C.
oqs_sidh_cln16_f2elm_t t0, t1;
oqs_sidh_cln16_fp2sqr751_mont(P->X, t0); // t0 = X^2
oqs_sidh_cln16_fp2add751(t0, t0, t1); // t1 = 2*t0
oqs_sidh_cln16_fp2add751(t0, t1, t0); // t0 = t0+t1
oqs_sidh_cln16_fp2sqr751_mont(P->Z, t1); // t1 = Z^2
oqs_sidh_cln16_fp2sqr751_mont(t1, A); // A = t1^2
oqs_sidh_cln16_fp2add751(t1, t1, t1); // t1 = 2*t1
oqs_sidh_cln16_fp2add751(t1, t1, C); // C = 2*t1
oqs_sidh_cln16_fp2sub751(t0, t1, t1); // t1 = t0-t1
oqs_sidh_cln16_fp2mul751_mont(t0, t1, t1); // t1 = t0*t1
oqs_sidh_cln16_fp2sub751(A, t1, A); // A = A-t1
oqs_sidh_cln16_fp2sub751(A, t1, A); // A = A-t1
oqs_sidh_cln16_fp2sub751(A, t1, A); // A = A-t1
oqs_sidh_cln16_fp2mul751_mont(P->X, P->Z, t1); // t1 = X*Z // ms trade-off possible (1 mul for 1sqr + 1add + 2sub)
oqs_sidh_cln16_fp2mul751_mont(C, t1, C); // C = C*t1
}
void oqs_sidh_cln16_eval_3_isog(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_point_proj_t Q) {
// Computes the 3-isogeny R=phi(X:Z), given projective point (X3:Z3) of order 3 on a Montgomery curve and a point P = (X:Z).
// Inputs: projective points P = (X3:Z3) and Q = (X:Z).
// Output: the projective point R = phi(Q) = (XX:ZZ).
oqs_sidh_cln16_f2elm_t t0, t1, t2;
oqs_sidh_cln16_fp2mul751_mont(P->X, Q->X, t0); // t0 = X3*X
oqs_sidh_cln16_fp2mul751_mont(P->Z, Q->X, t1); // t1 = Z3*X
oqs_sidh_cln16_fp2mul751_mont(P->Z, Q->Z, t2); // t2 = Z3*Z
oqs_sidh_cln16_fp2sub751(t0, t2, t0); // t0 = X3*X-Z3*Z
oqs_sidh_cln16_fp2mul751_mont(P->X, Q->Z, t2); // t2 = X3*Z
oqs_sidh_cln16_fp2sub751(t1, t2, t1); // t1 = Z3*X-X3*Z
oqs_sidh_cln16_fp2sqr751_mont(t0, t0); // t0 = (X3*X-Z3*Z)^2
oqs_sidh_cln16_fp2sqr751_mont(t1, t1); // t1 = (Z3*X-X3*Z)^2
oqs_sidh_cln16_fp2mul751_mont(Q->X, t0, Q->X); // X = X*(X3*X-Z3*Z)^2
oqs_sidh_cln16_fp2mul751_mont(Q->Z, t1, Q->Z); // Z = Z*(Z3*X-X3*Z)^2
}
void oqs_sidh_cln16_inv_3_way(oqs_sidh_cln16_f2elm_t z1, oqs_sidh_cln16_f2elm_t z2, oqs_sidh_cln16_f2elm_t z3) {
// 3-way simultaneous inversion
// Input: z1,z2,z3
// Output: 1/z1,1/z2,1/z3 (override inputs).
oqs_sidh_cln16_f2elm_t t0, t1, t2, t3;
oqs_sidh_cln16_fp2mul751_mont(z1, z2, t0); // t0 = z1*z2
oqs_sidh_cln16_fp2mul751_mont(z3, t0, t1); // t1 = z1*z2*z3
oqs_sidh_cln16_fp2inv751_mont(t1); // t1 = 1/(z1*z2*z3)
oqs_sidh_cln16_fp2mul751_mont(z3, t1, t2); // t2 = 1/(z1*z2)
oqs_sidh_cln16_fp2mul751_mont(t2, z2, t3); // t3 = 1/z1
oqs_sidh_cln16_fp2mul751_mont(t2, z1, z2); // z2 = 1/z2
oqs_sidh_cln16_fp2mul751_mont(t0, t1, z3); // z3 = 1/z3
oqs_sidh_cln16_fp2copy751(t3, z1); // z1 = 1/z1
}
void oqs_sidh_cln16_distort_and_diff(oqs_sidh_cln16_felm_t xP, oqs_sidh_cln16_point_proj_t D, PCurveIsogenyStruct CurveIsogeny) {
// Computing the point (x(Q-P),z(Q-P))
// Input: coordinate xP of point P=(xP,yP)
// Output: the point D = (x(Q-P),z(Q-P)), where Q=tau(P).
oqs_sidh_cln16_felm_t one;
oqs_sidh_cln16_fpcopy751(CurveIsogeny->Montgomery_one, one);
oqs_sidh_cln16_fpsqr751_mont(xP, D->X[0]); // XD = xP^2
oqs_sidh_cln16_fpadd751(D->X[0], one, D->X[0]); // XD = XD+1
oqs_sidh_cln16_fpcopy751(D->X[0], D->X[1]); // XD = XD*i
oqs_sidh_cln16_fpzero751(D->X[0]);
oqs_sidh_cln16_fpadd751(xP, xP, D->Z[0]); // ZD = xP+xP
}
void oqs_sidh_cln16_get_A(oqs_sidh_cln16_f2elm_t xP, oqs_sidh_cln16_f2elm_t xQ, oqs_sidh_cln16_f2elm_t xR, oqs_sidh_cln16_f2elm_t A, PCurveIsogenyStruct CurveIsogeny) {
// Given the x-coordinates of P, Q, and R, returns the value A corresponding to the Montgomery curve E_A: y^2=x^3+A*x^2+x such that R=Q-P on E_A.
// Input: the x-coordinates xP, xQ, and xR of the points P, Q and R.
// Output: the coefficient A corresponding to the curve E_A: y^2=x^3+A*x^2+x.
oqs_sidh_cln16_f2elm_t t0, t1, one = { {0} };
oqs_sidh_cln16_fpcopy751(CurveIsogeny->Montgomery_one, one[0]);
oqs_sidh_cln16_fp2add751(xP, xQ, t1); // t1 = xP+xQ
oqs_sidh_cln16_fp2mul751_mont(xP, xQ, t0); // t0 = xP*xQ
oqs_sidh_cln16_fp2mul751_mont(xR, t1, A); // A = xR*t1
oqs_sidh_cln16_fp2add751(t0, A, A); // A = A+t0
oqs_sidh_cln16_fp2mul751_mont(t0, xR, t0); // t0 = t0*xR
oqs_sidh_cln16_fp2sub751(A, one, A); // A = A-1
oqs_sidh_cln16_fp2add751(t0, t0, t0); // t0 = t0+t0
oqs_sidh_cln16_fp2add751(t1, xR, t1); // t1 = t1+xR
oqs_sidh_cln16_fp2add751(t0, t0, t0); // t0 = t0+t0
oqs_sidh_cln16_fp2sqr751_mont(A, A); // A = A^2
oqs_sidh_cln16_fp2inv751_mont(t0); // t0 = 1/t0
oqs_sidh_cln16_fp2mul751_mont(A, t0, A); // A = A*t0
oqs_sidh_cln16_fp2sub751(A, t1, A); // Afinal = A-t1
}

611
src/kex_sidh_cln16/fpx.c Normal file
View File

@ -0,0 +1,611 @@
/********************************************************************************************
* SIDH: an efficient supersingular isogeny-based cryptography library for Diffie-Hellman key
* exchange providing 128 bits of quantum security and 192 bits of classical security.
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*
* Abstract: core functions over GF(p751^2) and field operations over the prime p751
*
*********************************************************************************************/
#include "SIDH_internal.h"
// Global constants
const uint64_t p751[NWORDS_FIELD] = { 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xEEAFFFFFFFFFFFFF,
0xE3EC968549F878A8, 0xDA959B1A13F7CC76, 0x084E9867D6EBE876, 0x8562B5045CB25748, 0x0E12909F97BADC66, 0x00006FE5D541F71C
};
const uint64_t p751p1[NWORDS_FIELD] = { 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0xEEB0000000000000,
0xE3EC968549F878A8, 0xDA959B1A13F7CC76, 0x084E9867D6EBE876, 0x8562B5045CB25748, 0x0E12909F97BADC66, 0x00006FE5D541F71C
};
const uint64_t p751x2[NWORDS_FIELD] = { 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xDD5FFFFFFFFFFFFF,
0xC7D92D0A93F0F151, 0xB52B363427EF98ED, 0x109D30CFADD7D0ED, 0x0AC56A08B964AE90, 0x1C25213F2F75B8CD, 0x0000DFCBAA83EE38
};
const uint64_t Montgomery_R2[NWORDS_FIELD] = { 0x233046449DAD4058, 0xDB010161A696452A, 0x5E36941472E3FD8E, 0xF40BFE2082A2E706, 0x4932CCA8904F8751 , 0x1F735F1F1EE7FC81,
0xA24F4D80C1048E18, 0xB56C383CCDB607C5, 0x441DD47B735F9C90, 0x5673ED2C6A6AC82A, 0x06C905261132294B, 0x000041AD830F1F35
};
/*******************************************************/
/************* Field arithmetic functions **************/
__inline void oqs_sidh_cln16_fpcopy751(oqs_sidh_cln16_felm_t a, oqs_sidh_cln16_felm_t c) {
// Copy of a field element, c = a
unsigned int i;
for (i = 0; i < NWORDS_FIELD; i++) {
c[i] = a[i];
}
}
__inline void oqs_sidh_cln16_fpzero751(oqs_sidh_cln16_felm_t a) {
// Zeroing a field element, a = 0
unsigned int i;
for (i = 0; i < NWORDS_FIELD; i++) {
a[i] = 0;
}
}
void oqs_sidh_cln16_to_mont(oqs_sidh_cln16_felm_t a, oqs_sidh_cln16_felm_t mc) {
// Conversion to Montgomery representation
// mc = a*R^2*R^-1 mod p751 = a*R mod p751, where a in [0, p751-1]
// The Montgomery constant R^2 mod p751 is the global value "Montgomery_R2".
oqs_sidh_cln16_fpmul751_mont(a, (digit_t *)&Montgomery_R2, mc);
}
void oqs_sidh_cln16_from_mont(oqs_sidh_cln16_felm_t ma, oqs_sidh_cln16_felm_t c) {
// Conversion from Montgomery representation to standard representation
// c = ma*R^-1 mod p751 = a mod p751, where ma in [0, p751-1].
digit_t one[NWORDS_FIELD] = {0};
one[0] = 1;
oqs_sidh_cln16_fpmul751_mont(ma, one, c);
oqs_sidh_cln16_fpcorrection751(c);
}
UNUSED static __inline unsigned int is_felm_zero(oqs_sidh_cln16_felm_t x) {
// Is x = 0? return 1 (TRUE) if condition is true, 0 (FALSE) otherwise
// NOTE: this function does not run in constant-time so it can only be used in functions
// incorporating countermeasures such as projective randomization.
unsigned int i;
for (i = 0; i < NWORDS_FIELD; i++) {
if (x[i] != 0) {
return false;
}
}
return true;
}
UNUSED static __inline unsigned int is_felm_even(oqs_sidh_cln16_felm_t x) {
// Is x even? return 1 (TRUE) if condition is true, 0 (FALSE) otherwise
return (unsigned int)((x[0] & 1) ^ 1);
}
UNUSED static __inline unsigned int is_felm_lt(oqs_sidh_cln16_felm_t x, oqs_sidh_cln16_felm_t y) {
// Is x < y? return 1 (TRUE) if condition is true, 0 (FALSE) otherwise
// NOTE: this function does not run in constant-time so it can only be used in functions
// incorporating countermeasures such as projective randomization.
int i;
for (i = NWORDS_FIELD - 1; i >= 0; i--) {
if (x[i] < y[i]) {
return true;
} else if (x[i] > y[i]) {
return false;
}
}
return false;
}
void oqs_sidh_cln16_copy_words(digit_t *a, digit_t *c, unsigned int nwords) {
// Copy wordsize digits, c = a, where lng(a) = nwords
unsigned int i;
for (i = 0; i < nwords; i++) {
c[i] = a[i];
}
}
__inline unsigned int oqs_sidh_cln16_mp_sub(digit_t *a, digit_t *b, digit_t *c, unsigned int nwords) {
// Multiprecision subtraction, c = a-b, where lng(a) = lng(b) = nwords. Returns the borrow bit
unsigned int i, borrow = 0;
for (i = 0; i < nwords; i++) {
SUBC(borrow, a[i], b[i], borrow, c[i]);
}
return borrow;
}
__inline unsigned int oqs_sidh_cln16_mp_add(digit_t *a, digit_t *b, digit_t *c, unsigned int nwords) {
// Multiprecision addition, c = a+b, where lng(a) = lng(b) = nwords. Returns the carry bit
unsigned int i, carry = 0;
for (i = 0; i < nwords; i++) {
ADDC(carry, a[i], b[i], carry, c[i]);
}
return carry;
}
void oqs_sidh_cln16_mp_shiftr1(digit_t *x, unsigned int nwords) {
// Multiprecision right shift by one
unsigned int i;
for (i = 0; i < nwords - 1; i++) {
SHIFTR(x[i + 1], x[i], 1, x[i], RADIX);
}
x[nwords - 1] >>= 1;
}
void oqs_sidh_cln16_mp_shiftl1(digit_t *x, unsigned int nwords) {
// Multiprecision left right shift by one
int i;
for (i = nwords - 1; i > 0; i--) {
SHIFTL(x[i], x[i - 1], 1, x[i], RADIX);
}
x[0] <<= 1;
}
void oqs_sidh_cln16_fpmul751_mont(oqs_sidh_cln16_felm_t ma, oqs_sidh_cln16_felm_t mb, oqs_sidh_cln16_felm_t mc) {
// 751-bit Comba multi-precision multiplication, c = a*b mod p751
oqs_sidh_cln16_dfelm_t temp = {0};
oqs_sidh_cln16_mp_mul(ma, mb, temp, NWORDS_FIELD);
oqs_sidh_cln16_rdc_mont(temp, mc);
}
void oqs_sidh_cln16_fpsqr751_mont(oqs_sidh_cln16_felm_t ma, oqs_sidh_cln16_felm_t mc) {
// 751-bit Comba multi-precision squaring, c = a^2 mod p751
oqs_sidh_cln16_dfelm_t temp = {0};
oqs_sidh_cln16_mp_mul(ma, ma, temp, NWORDS_FIELD);
oqs_sidh_cln16_rdc_mont(temp, mc);
}
void oqs_sidh_cln16_fpinv751_mont(oqs_sidh_cln16_felm_t a) {
// Field inversion using Montgomery arithmetic, a = a^-1*R mod p751
oqs_sidh_cln16_felm_t t[27], tt;
unsigned int i, j;
// Precomputed table
oqs_sidh_cln16_fpsqr751_mont(a, tt);
oqs_sidh_cln16_fpmul751_mont(a, tt, t[0]);
oqs_sidh_cln16_fpmul751_mont(t[0], tt, t[1]);
oqs_sidh_cln16_fpmul751_mont(t[1], tt, t[2]);
oqs_sidh_cln16_fpmul751_mont(t[2], tt, t[3]);
oqs_sidh_cln16_fpmul751_mont(t[3], tt, t[3]);
for (i = 3; i <= 8; i++) {
oqs_sidh_cln16_fpmul751_mont(t[i], tt, t[i + 1]);
}
oqs_sidh_cln16_fpmul751_mont(t[9], tt, t[9]);
for (i = 9; i <= 20; i++) {
oqs_sidh_cln16_fpmul751_mont(t[i], tt, t[i + 1]);
}
oqs_sidh_cln16_fpmul751_mont(t[21], tt, t[21]);
for (i = 21; i <= 24; i++) {
oqs_sidh_cln16_fpmul751_mont(t[i], tt, t[i + 1]);
}
oqs_sidh_cln16_fpmul751_mont(t[25], tt, t[25]);
oqs_sidh_cln16_fpmul751_mont(t[25], tt, t[26]);
oqs_sidh_cln16_fpcopy751(a, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[20], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[24], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[11], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[8], tt, tt);
for (i = 0; i < 8; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[2], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[23], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[2], tt, tt);
for (i = 0; i < 9; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[2], tt, tt);
for (i = 0; i < 10; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[15], tt, tt);
for (i = 0; i < 8; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[13], tt, tt);
for (i = 0; i < 8; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[26], tt, tt);
for (i = 0; i < 8; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[20], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[11], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[10], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[14], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[4], tt, tt);
for (i = 0; i < 10; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[18], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[1], tt, tt);
for (i = 0; i < 7; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[22], tt, tt);
for (i = 0; i < 10; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[6], tt, tt);
for (i = 0; i < 7; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[24], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[9], tt, tt);
for (i = 0; i < 8; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[18], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[17], tt, tt);
for (i = 0; i < 8; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(a, tt, tt);
for (i = 0; i < 10; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[16], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[7], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[0], tt, tt);
for (i = 0; i < 7; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[12], tt, tt);
for (i = 0; i < 7; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[19], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[22], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[25], tt, tt);
for (i = 0; i < 7; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[2], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[10], tt, tt);
for (i = 0; i < 7; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[22], tt, tt);
for (i = 0; i < 8; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[18], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[4], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[14], tt, tt);
for (i = 0; i < 7; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[13], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[5], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[23], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[21], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[2], tt, tt);
for (i = 0; i < 7; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[23], tt, tt);
for (i = 0; i < 8; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[12], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[9], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[3], tt, tt);
for (i = 0; i < 7; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[13], tt, tt);
for (i = 0; i < 7; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[17], tt, tt);
for (i = 0; i < 8; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[26], tt, tt);
for (i = 0; i < 8; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[5], tt, tt);
for (i = 0; i < 8; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[8], tt, tt);
for (i = 0; i < 8; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[11], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
oqs_sidh_cln16_fpmul751_mont(t[22], tt, tt);
for (i = 0; i < 7; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
for (j = 0; j < 61; j++) {
oqs_sidh_cln16_fpmul751_mont(t[26], tt, tt);
for (i = 0; i < 6; i++) {
oqs_sidh_cln16_fpsqr751_mont(tt, tt);
}
}
oqs_sidh_cln16_fpmul751_mont(t[25], tt, a);
}
/***********************************************/
/************* GF(p^2) FUNCTIONS ***************/
void oqs_sidh_cln16_fp2copy751(oqs_sidh_cln16_f2elm_t a, oqs_sidh_cln16_f2elm_t c) {
// Copy of a GF(p751^2) element, c = a
oqs_sidh_cln16_fpcopy751(a[0], c[0]);
oqs_sidh_cln16_fpcopy751(a[1], c[1]);
}
void oqs_sidh_cln16_fp2zero751(oqs_sidh_cln16_f2elm_t a) {
// Zeroing a GF(p751^2) element, a = 0
oqs_sidh_cln16_fpzero751(a[0]);
oqs_sidh_cln16_fpzero751(a[1]);
}
void oqs_sidh_cln16_fp2neg751(oqs_sidh_cln16_f2elm_t a) {
// GF(p751^2) negation, a = -a in GF(p751^2)
oqs_sidh_cln16_fpneg751(a[0]);
oqs_sidh_cln16_fpneg751(a[1]);
}
__inline void oqs_sidh_cln16_fp2add751(oqs_sidh_cln16_f2elm_t a, oqs_sidh_cln16_f2elm_t b, oqs_sidh_cln16_f2elm_t c) {
// GF(p751^2) addition, c = a+b in GF(p751^2)
oqs_sidh_cln16_fpadd751(a[0], b[0], c[0]);
oqs_sidh_cln16_fpadd751(a[1], b[1], c[1]);
}
__inline void oqs_sidh_cln16_fp2sub751(oqs_sidh_cln16_f2elm_t a, oqs_sidh_cln16_f2elm_t b, oqs_sidh_cln16_f2elm_t c) {
// GF(p751^2) subtraction, c = a-b in GF(p751^2)
oqs_sidh_cln16_fpsub751(a[0], b[0], c[0]);
oqs_sidh_cln16_fpsub751(a[1], b[1], c[1]);
}
void oqs_sidh_cln16_fp2div2_751(oqs_sidh_cln16_f2elm_t a, oqs_sidh_cln16_f2elm_t c) {
// GF(p751^2) division by two, c = a/2 in GF(p751^2)
oqs_sidh_cln16_fpdiv2_751(a[0], c[0]);
oqs_sidh_cln16_fpdiv2_751(a[1], c[1]);
}
void oqs_sidh_cln16_fp2correction751(oqs_sidh_cln16_f2elm_t a) {
// Modular correction, a = a in GF(p751^2)
oqs_sidh_cln16_fpcorrection751(a[0]);
oqs_sidh_cln16_fpcorrection751(a[1]);
}
void oqs_sidh_cln16_fp2sqr751_mont(oqs_sidh_cln16_f2elm_t a, oqs_sidh_cln16_f2elm_t c) {
// GF(p751^2) squaring using Montgomery arithmetic, c = a^2 in GF(p751^2)
oqs_sidh_cln16_felm_t t1, t2, t3;
oqs_sidh_cln16_mp_add(a[0], a[1], t1, NWORDS_FIELD); // t1 = a0+a1
oqs_sidh_cln16_fpsub751(a[0], a[1], t2); // t2 = a0-a1
oqs_sidh_cln16_mp_add(a[0], a[0], t3, NWORDS_FIELD); // t3 = 2a0
oqs_sidh_cln16_fpmul751_mont(t1, t2, c[0]); // c0 = (a0+a1)(a0-a1)
oqs_sidh_cln16_fpmul751_mont(t3, a[1], c[1]); // c1 = 2a0*a1
}
void oqs_sidh_cln16_fp2mul751_mont(oqs_sidh_cln16_f2elm_t a, oqs_sidh_cln16_f2elm_t b, oqs_sidh_cln16_f2elm_t c) {
// GF(p751^2) multiplication using Montgomery arithmetic, c = a*b in GF(p751^2)
oqs_sidh_cln16_felm_t t1, t2;
oqs_sidh_cln16_dfelm_t tt1, tt2, tt3;
digit_t mask;
unsigned int i, borrow;
oqs_sidh_cln16_mp_mul(a[0], b[0], tt1, NWORDS_FIELD); // tt1 = a0*b0
oqs_sidh_cln16_mp_mul(a[1], b[1], tt2, NWORDS_FIELD); // tt2 = a1*b1
oqs_sidh_cln16_mp_add(a[0], a[1], t1, NWORDS_FIELD); // t1 = a0+a1
oqs_sidh_cln16_mp_add(b[0], b[1], t2, NWORDS_FIELD); // t2 = b0+b1
borrow = oqs_sidh_cln16_mp_sub(tt1, tt2, tt3, 2 * NWORDS_FIELD); // tt3 = a0*b0 - a1*b1
mask = 0 - (digit_t)borrow; // if tt3 < 0 then mask = 0xFF..F, else if tt3 >= 0 then mask = 0x00..0
borrow = 0;
for (i = 0; i < NWORDS_FIELD; i++) {
ADDC(borrow, tt3[NWORDS_FIELD + i], ((digit_t *)p751)[i] & mask, borrow, tt3[NWORDS_FIELD + i]);
}
oqs_sidh_cln16_rdc_mont(tt3, c[0]); // c[0] = a0*b0 - a1*b1
oqs_sidh_cln16_mp_add(tt1, tt2, tt1, 2 * NWORDS_FIELD); // tt1 = a0*b0 + a1*b1
oqs_sidh_cln16_mp_mul(t1, t2, tt2, NWORDS_FIELD); // tt2 = (a0+a1)*(b0+b1)
oqs_sidh_cln16_mp_sub(tt2, tt1, tt2, 2 * NWORDS_FIELD); // tt2 = (a0+a1)*(b0+b1) - a0*b0 - a1*b1
oqs_sidh_cln16_rdc_mont(tt2, c[1]); // c[1] = (a0+a1)*(b0+b1) - a0*b0 - a1*b1
}
void oqs_sidh_cln16_to_fp2mont(oqs_sidh_cln16_f2elm_t a, oqs_sidh_cln16_f2elm_t mc) {
// Conversion of a GF(p751^2) element to Montgomery representation
// mc_i = a_i*R^2*R^-1 = a_i*R in GF(p751^2).
oqs_sidh_cln16_to_mont(a[0], mc[0]);
oqs_sidh_cln16_to_mont(a[1], mc[1]);
}
void oqs_sidh_cln16_from_fp2mont(oqs_sidh_cln16_f2elm_t ma, oqs_sidh_cln16_f2elm_t c) {
// Conversion of a GF(p751^2) element from Montgomery representation to standard representation
// c_i = ma_i*R^-1 = a_i in GF(p751^2).
oqs_sidh_cln16_from_mont(ma[0], c[0]);
oqs_sidh_cln16_from_mont(ma[1], c[1]);
}
void oqs_sidh_cln16_fp2inv751_mont(oqs_sidh_cln16_f2elm_t a) {
// GF(p751^2) inversion using Montgomery arithmetic, a = (a0-i*a1)/(a0^2+a1^2)
oqs_sidh_cln16_f2elm_t t1;
oqs_sidh_cln16_fpsqr751_mont(a[0], t1[0]); // t10 = a0^2
oqs_sidh_cln16_fpsqr751_mont(a[1], t1[1]); // t11 = a1^2
oqs_sidh_cln16_fpadd751(t1[0], t1[1], t1[0]); // t10 = a0^2+a1^2
oqs_sidh_cln16_fpinv751_mont(t1[0]); // t10 = (a0^2+a1^2)^-1
oqs_sidh_cln16_fpneg751(a[1]); // a = a0-i*a1
oqs_sidh_cln16_fpmul751_mont(a[0], t1[0], a[0]);
oqs_sidh_cln16_fpmul751_mont(a[1], t1[0], a[1]); // a = (a0-i*a1)*(a0^2+a1^2)^-1
}
void oqs_sidh_cln16_swap_points_basefield(oqs_sidh_cln16_point_basefield_proj_t P, oqs_sidh_cln16_point_basefield_proj_t Q, digit_t option) {
// Swap points over the base field
// If option = 0 then P <- P and Q <- Q, else if option = 0xFF...FF then P <- Q and Q <- P
digit_t temp;
unsigned int i;
for (i = 0; i < NWORDS_FIELD; i++) {
temp = option & (P->X[i] ^ Q->X[i]);
P->X[i] = temp ^ P->X[i];
Q->X[i] = temp ^ Q->X[i];
temp = option & (P->Z[i] ^ Q->Z[i]);
P->Z[i] = temp ^ P->Z[i];
Q->Z[i] = temp ^ Q->Z[i];
}
}
void oqs_sidh_cln16_swap_points(oqs_sidh_cln16_point_proj_t P, oqs_sidh_cln16_point_proj_t Q, digit_t option) {
// Swap points
// If option = 0 then P <- P and Q <- Q, else if option = 0xFF...FF then P <- Q and Q <- P
digit_t temp;
unsigned int i;
for (i = 0; i < NWORDS_FIELD; i++) {
temp = option & (P->X[0][i] ^ Q->X[0][i]);
P->X[0][i] = temp ^ P->X[0][i];
Q->X[0][i] = temp ^ Q->X[0][i];
temp = option & (P->Z[0][i] ^ Q->Z[0][i]);
P->Z[0][i] = temp ^ P->Z[0][i];
Q->Z[0][i] = temp ^ Q->Z[0][i];
temp = option & (P->X[1][i] ^ Q->X[1][i]);
P->X[1][i] = temp ^ P->X[1][i];
Q->X[1][i] = temp ^ Q->X[1][i];
temp = option & (P->Z[1][i] ^ Q->Z[1][i]);
P->Z[1][i] = temp ^ P->Z[1][i];
Q->Z[1][i] = temp ^ Q->Z[1][i];
}
}
void oqs_sidh_cln16_select_f2elm(oqs_sidh_cln16_f2elm_t x, oqs_sidh_cln16_f2elm_t y, oqs_sidh_cln16_f2elm_t z, digit_t option) {
// Select either x or y depending on value of option
// If option = 0 then z <- x, else if option = 0xFF...FF then z <- y
unsigned int i;
for (i = 0; i < NWORDS_FIELD; i++) {
z[0][i] = (option & (x[0][i] ^ y[0][i])) ^ x[0][i];
z[1][i] = (option & (x[1][i] ^ y[1][i])) ^ x[1][i];
}
}

View File

@ -0,0 +1,251 @@
/********************************************************************************************
* SIDH: an efficient supersingular isogeny-based cryptography library for Diffie-Hellman key
* exchange providing 128 bits of quantum security and 192 bits of classical security.
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*
* Abstract: portable modular arithmetic
*
*********************************************************************************************/
#include "../SIDH_internal.h"
// Global constants
extern const uint64_t p751[NWORDS_FIELD];
extern const uint64_t p751p1[NWORDS_FIELD];
extern const uint64_t p751x2[NWORDS_FIELD];
__inline void oqs_sidh_cln16_fpadd751(digit_t* a, digit_t* b, digit_t* c)
{ // Modular addition, c = a+b mod p751.
// Inputs: a, b in [0, 2*p751-1]
// Output: c in [0, 2*p751-1]
unsigned int i, carry = 0;
digit_t mask;
for (i = 0; i < NWORDS_FIELD; i++) {
ADDC(carry, a[i], b[i], carry, c[i]);
}
carry = 0;
for (i = 0; i < NWORDS_FIELD; i++) {
SUBC(carry, c[i], ((digit_t*)p751x2)[i], carry, c[i]);
}
mask = 0 - (digit_t)carry;
carry = 0;
for (i = 0; i < NWORDS_FIELD; i++) {
ADDC(carry, c[i], ((digit_t*)p751x2)[i] & mask, carry, c[i]);
}
}
__inline void oqs_sidh_cln16_fpsub751(digit_t* a, digit_t* b, digit_t* c)
{ // Modular subtraction, c = a-b mod p751.
// Inputs: a, b in [0, 2*p751-1]
// Output: c in [0, 2*p751-1]
unsigned int i, borrow = 0;
digit_t mask;
for (i = 0; i < NWORDS_FIELD; i++) {
SUBC(borrow, a[i], b[i], borrow, c[i]);
}
mask = 0 - (digit_t)borrow;
borrow = 0;
for (i = 0; i < NWORDS_FIELD; i++) {
ADDC(borrow, c[i], ((digit_t*)p751x2)[i] & mask, borrow, c[i]);
}
}
__inline void oqs_sidh_cln16_fpneg751(digit_t* a)
{ // Modular negation, a = -a mod p751.
// Input/output: a in [0, 2*p751-1]
unsigned int i, borrow = 0;
for (i = 0; i < NWORDS_FIELD; i++) {
SUBC(borrow, ((digit_t*)p751x2)[i], a[i], borrow, a[i]);
}
}
void oqs_sidh_cln16_fpdiv2_751(digit_t* a, digit_t* c)
{ // Modular division by two, c = a/2 mod p751.
// Input : a in [0, 2*p751-1]
// Output: c in [0, 2*p751-1]
unsigned int i, carry = 0;
digit_t mask;
mask = 0 - (digit_t)(a[0] & 1); // If a is odd compute a+p521
for (i = 0; i < NWORDS_FIELD; i++) {
ADDC(carry, a[i], ((digit_t*)p751)[i] & mask, carry, c[i]);
}
oqs_sidh_cln16_mp_shiftr1(c, NWORDS_FIELD);
}
void oqs_sidh_cln16_fpcorrection751(digit_t* a)
{ // Modular correction to reduce field element a in [0, 2*p751-1] to [0, p751-1].
unsigned int i, borrow = 0;
digit_t mask;
for (i = 0; i < NWORDS_FIELD; i++) {
SUBC(borrow, a[i], ((digit_t*)p751)[i], borrow, a[i]);
}
mask = 0 - (digit_t)borrow;
borrow = 0;
for (i = 0; i < NWORDS_FIELD; i++) {
ADDC(borrow, a[i], ((digit_t*)p751)[i] & mask, borrow, a[i]);
}
}
void oqs_sidh_cln16_digit_x_digit(digit_t a, digit_t b, digit_t* c)
{ // Digit multiplication, digit * digit -> 2-digit result
register digit_t al, ah, bl, bh, temp;
digit_t albl, albh, ahbl, ahbh, res1, res2, res3, carry;
digit_t mask_low = (digit_t)(-1) >> (sizeof(digit_t)*4), mask_high = (digit_t)(-1) << (sizeof(digit_t)*4);
al = a & mask_low; // Low part
ah = a >> (sizeof(digit_t) * 4); // High part
bl = b & mask_low;
bh = b >> (sizeof(digit_t) * 4);
albl = al*bl;
albh = al*bh;
ahbl = ah*bl;
ahbh = ah*bh;
c[0] = albl & mask_low; // C00
res1 = albl >> (sizeof(digit_t) * 4);
res2 = ahbl & mask_low;
res3 = albh & mask_low;
temp = res1 + res2 + res3;
carry = temp >> (sizeof(digit_t) * 4);
c[0] ^= temp << (sizeof(digit_t) * 4); // C01
res1 = ahbl >> (sizeof(digit_t) * 4);
res2 = albh >> (sizeof(digit_t) * 4);
res3 = ahbh & mask_low;
temp = res1 + res2 + res3 + carry;
c[1] = temp & mask_low; // C10
carry = temp & mask_high;
c[1] ^= (ahbh & mask_high) + carry; // C11
}
void oqs_sidh_cln16_mp_mul_schoolbook(digit_t* a, digit_t* b, digit_t* c, unsigned int nwords)
{ // Multiprecision schoolbook multiply, c = a*b, where lng(a) = lng(b) = nwords.
unsigned int i, j;
digit_t u, v, UV[2];
unsigned int carry = 0;
for (i = 0; i < (2*nwords); i++) c[i] = 0;
for (i = 0; i < nwords; i++) {
u = 0;
for (j = 0; j < nwords; j++) {
MUL(a[i], b[j], UV+1, UV[0]);
ADDC(0, UV[0], u, carry, v);
u = UV[1] + carry;
ADDC(0, c[i+j], v, carry, v);
u = u + carry;
c[i+j] = v;
}
c[nwords+i] = u;
}
}
void oqs_sidh_cln16_mp_mul_comba(digit_t* a, digit_t* b, digit_t* c, unsigned int nwords)
{ // Multiprecision comba multiply, c = a*b, where lng(a) = lng(b) = nwords.
unsigned int i, j;
digit_t t = 0, u = 0, v = 0, UV[2];
unsigned int carry = 0;
for (i = 0; i < nwords; i++) {
for (j = 0; j <= i; j++) {
MUL(a[j], b[i-j], UV+1, UV[0]);
ADDC(0, UV[0], v, carry, v);
ADDC(carry, UV[1], u, carry, u);
t += carry;
}
c[i] = v;
v = u;
u = t;
t = 0;
}
for (i = nwords; i < 2*nwords-1; i++) {
for (j = i-nwords+1; j < nwords; j++) {
MUL(a[j], b[i-j], UV+1, UV[0]);
ADDC(0, UV[0], v, carry, v);
ADDC(carry, UV[1], u, carry, u);
t += carry;
}
c[i] = v;
v = u;
u = t;
t = 0;
}
c[2*nwords-1] = v;
}
void oqs_sidh_cln16_rdc_mont(oqs_sidh_cln16_dfelm_t ma, oqs_sidh_cln16_felm_t mc)
{ // Optimized Montgomery reduction using comba and exploiting the special form of the prime p751.
// mc = ma*mb*R^-1 mod p751, where ma,mb,mc in [0, p751-1] and R = 2^768.
// ma and mb are assumed to be in Montgomery representation.
unsigned int i, j, carry, count = p751_ZERO_WORDS;
digit_t UV[2], t = 0, u = 0, v = 0;
for (i = 0; i < NWORDS_FIELD; i++) {
mc[i] = 0;
}
for (i = 0; i < NWORDS_FIELD; i++) {
for (j = 0; j < i; j++) {
if (j < (i-p751_ZERO_WORDS+1)) {
MUL(mc[j], ((digit_t*)p751p1)[i-j], UV+1, UV[0]);
ADDC(0, UV[0], v, carry, v);
ADDC(carry, UV[1], u, carry, u);
t += carry;
}
}
ADDC(0, v, ma[i], carry, v);
ADDC(carry, u, 0, carry, u);
t += carry;
mc[i] = v;
v = u;
u = t;
t = 0;
}
for (i = NWORDS_FIELD; i < 2*NWORDS_FIELD-1; i++) {
if (count > 0) {
count -= 1;
}
for (j = i-NWORDS_FIELD+1; j < NWORDS_FIELD; j++) {
if (j < (NWORDS_FIELD-count)) {
MUL(mc[j], ((digit_t*)p751p1)[i-j], UV+1, UV[0]);
ADDC(0, UV[0], v, carry, v);
ADDC(carry, UV[1], u, carry, u);
t += carry;
}
}
ADDC(0, v, ma[i], carry, v);
ADDC(carry, u, 0, carry, u);
t += carry;
mc[i-NWORDS_FIELD] = v;
v = u;
u = t;
t = 0;
}
ADDC(0, v, ma[2*NWORDS_FIELD-1], carry, v);
mc[NWORDS_FIELD-1] = v;
}

View File

@ -0,0 +1,185 @@
#if defined(WINDOWS)
#define UNUSED
#else
#define UNUSED __attribute__ ((unused))
#endif
#include <stdlib.h>
#include <string.h>
#if !defined(WINDOWS)
#include <unistd.h>
#include <strings.h>
#endif
#include <oqs/kex.h>
#include <oqs/rand.h>
#include "kex_sidh_cln16.h"
#include "SIDH.h"
OQS_KEX *OQS_KEX_sidh_cln16_new(OQS_RAND *rand) {
OQS_KEX *k = malloc(sizeof(OQS_KEX));
if (k == NULL) {
return NULL;
}
// Curve isogeny system initialization
PCurveIsogenyStruct curveIsogeny = oqs_sidh_cln16_curve_allocate(&CurveIsogeny_SIDHp751);
if (curveIsogeny == NULL) {
free(k);
return NULL;
}
if (oqs_sidh_cln16_curve_initialize(curveIsogeny, rand, &CurveIsogeny_SIDHp751) != SIDH_CRYPTO_SUCCESS) {
free(k);
oqs_sidh_cln16_curve_free(curveIsogeny);
return NULL;
}
k->ctx = curveIsogeny;
k->method_name = strdup("SIDH CLN16");
k->estimated_classical_security = 192;
k->estimated_quantum_security = 128;
k->seed = NULL;
k->seed_len = 0;
k->named_parameters = NULL; // TODO: create param p751 when we have more curves
k->rand = rand;
k->params = NULL;
k->alice_0 = &OQS_KEX_sidh_cln16_alice_0;
k->bob = &OQS_KEX_sidh_cln16_bob;
k->alice_1 = &OQS_KEX_sidh_cln16_alice_1;
k->alice_priv_free = &OQS_KEX_sidh_cln16_alice_priv_free;
k->free = &OQS_KEX_sidh_cln16_free;
return k;
}
int OQS_KEX_sidh_cln16_alice_0(OQS_KEX *k, void **alice_priv, uint8_t **alice_msg, size_t *alice_msg_len) {
int ret;
*alice_priv = NULL;
/* alice_msg is alice's public key */
*alice_msg = NULL;
*alice_msg = malloc(SIDH_PUBKEY_LEN);
if (*alice_msg == NULL) {
goto err;
}
*alice_priv = malloc(SIDH_SECRETKEY_LEN);
if (*alice_priv == NULL) {
goto err;
}
if (oqs_sidh_cln16_KeyGeneration_A((unsigned char *) *alice_priv, (unsigned char *) *alice_msg, k->ctx, k->rand) != SIDH_CRYPTO_SUCCESS) {
goto err;
}
*alice_msg_len = SIDH_PUBKEY_LEN;
ret = 1;
goto cleanup;
err:
ret = 0;
free(*alice_msg);
free(*alice_priv);
cleanup:
return ret;
}
int OQS_KEX_sidh_cln16_bob(OQS_KEX *k, const uint8_t *alice_msg, const size_t alice_msg_len, uint8_t **bob_msg, size_t *bob_msg_len, uint8_t **key, size_t *key_len) {
int ret;
uint8_t *bob_priv = NULL;
*bob_msg = NULL;
*key = NULL;
if (alice_msg_len != SIDH_PUBKEY_LEN) {
goto err;
}
bob_priv = malloc(SIDH_SECRETKEY_LEN);
if (bob_priv == NULL) {
goto err;
}
*bob_msg = malloc(SIDH_PUBKEY_LEN);
if (*bob_msg == NULL) {
goto err;
}
*key = malloc(SIDH_SHAREDKEY_LEN);
if (*key == NULL) {
goto err;
}
if (oqs_sidh_cln16_KeyGeneration_B((unsigned char *) bob_priv, (unsigned char *) *bob_msg, k->ctx, k->rand) != SIDH_CRYPTO_SUCCESS) {
goto err;
}
if (oqs_sidh_cln16_SecretAgreement_B((unsigned char *) bob_priv, (unsigned char *) alice_msg, (unsigned char *) *key, 0, k->ctx, k->rand) != SIDH_CRYPTO_SUCCESS) {
goto err;
}
*key_len = SIDH_SHAREDKEY_LEN;
*bob_msg_len = SIDH_PUBKEY_LEN;
ret = 1;
goto cleanup;
err:
ret = 0;
free(*bob_msg);
free(*key);
cleanup:
free(bob_priv);
return ret;
}
int OQS_KEX_sidh_cln16_alice_1(OQS_KEX *k, const void *alice_priv, const uint8_t *bob_msg, const size_t bob_msg_len, uint8_t **key, size_t *key_len) {
int ret;
*key = NULL;
if (bob_msg_len != SIDH_PUBKEY_LEN) {
goto err;
}
*key = malloc(SIDH_SHAREDKEY_LEN);
if (*key == NULL) {
goto err;
}
if (oqs_sidh_cln16_SecretAgreement_A((unsigned char *) alice_priv, (unsigned char *) bob_msg, (unsigned char *) *key, false, k->ctx, k->rand) != SIDH_CRYPTO_SUCCESS) {
goto err;
}
*key_len = SIDH_SHAREDKEY_LEN;
ret = 1;
goto cleanup;
err:
ret = 0;
free(*key);
cleanup:
return ret;
}
void OQS_KEX_sidh_cln16_alice_priv_free(UNUSED OQS_KEX *k, void *alice_priv) {
if (alice_priv) {
free(alice_priv);
}
}
void OQS_KEX_sidh_cln16_free(OQS_KEX *k) {
if (!k) {
return;
}
oqs_sidh_cln16_curve_free((PCurveIsogenyStruct) k->ctx);
k->ctx = NULL;
free(k->method_name);
k->method_name = NULL;
free(k);
}

View File

@ -0,0 +1,24 @@
/**
* \file kex_sidh_cln16.h
* \brief Header for SIDH key exchange protocol from the Microsoft SIDH library
*/
#ifndef __OQS_KEX_SIDH_CLN16_H
#define __OQS_KEX_SIDH_CLN16_H
#include <stddef.h>
#include <stdint.h>
#include <oqs/kex.h>
#include <oqs/rand.h>
OQS_KEX *OQS_KEX_sidh_cln16_new(OQS_RAND *rand);
int OQS_KEX_sidh_cln16_alice_0(OQS_KEX *k, void **alice_priv, uint8_t **alice_msg, size_t *alice_msg_len);
int OQS_KEX_sidh_cln16_bob(OQS_KEX *k, const uint8_t *alice_msg, const size_t alice_msg_len, uint8_t **bob_msg, size_t *bob_msg_len, uint8_t **key, size_t *key_len);
int OQS_KEX_sidh_cln16_alice_1(OQS_KEX *k, const void *alice_priv, const uint8_t *bob_msg, const size_t bob_msg_len, uint8_t **key, size_t *key_len);
void OQS_KEX_sidh_cln16_alice_priv_free(OQS_KEX *k, void *alice_priv);
void OQS_KEX_sidh_cln16_free(OQS_KEX *k);
#endif

View File

@ -0,0 +1,392 @@
/********************************************************************************************
* SIDH: an efficient supersingular isogeny-based cryptography library for Diffie-Hellman key
* exchange providing 128 bits of quantum security and 192 bits of classical security.
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*
* Abstract: isogeny-based key exchange
*
*********************************************************************************************/
#include "SIDH_internal.h"
extern const unsigned int splits_Alice[SIDH_MAX_Alice];
extern const unsigned int splits_Bob[SIDH_MAX_Bob];
#ifdef SIDH_ASM
#include "AMD64/fp_x64.c"
#else
#include "generic/fp_generic.c"
#endif
SIDH_CRYPTO_STATUS oqs_sidh_cln16_KeyGeneration_A(unsigned char *pPrivateKeyA, unsigned char *pPublicKeyA, PCurveIsogenyStruct CurveIsogeny, OQS_RAND *rand) {
// Alice's key-pair generation
// It produces a private key pPrivateKeyA and computes the public key pPublicKeyA.
// The private key is an even integer in the range [2, oA-2], where oA = 2^372 (i.e., 372 bits in total).
// The public key consists of 3 elements in GF(p751^2), i.e., 564 bytes.
// CurveIsogeny must be set up in advance using oqs_sidh_cln16_curve_initialize().
unsigned int owords = NBITS_TO_NWORDS(CurveIsogeny->owordbits), pwords = NBITS_TO_NWORDS(CurveIsogeny->pwordbits);
oqs_sidh_cln16_point_basefield_t P;
oqs_sidh_cln16_point_proj_t R, phiP = oqs_sidh_cln16_point_proj_t_EMPTY, phiQ = oqs_sidh_cln16_point_proj_t_EMPTY, phiD = oqs_sidh_cln16_point_proj_t_EMPTY, pts[SIDH_MAX_INT_POINTS_ALICE];
oqs_sidh_cln16_publickey_t *PublicKeyA = (oqs_sidh_cln16_publickey_t *)pPublicKeyA;
unsigned int i, row, m, index = 0, pts_index[SIDH_MAX_INT_POINTS_ALICE], npts = 0;
oqs_sidh_cln16_f2elm_t coeff[5], A = { {0} }, C = { {0} }, Aout, Cout;
SIDH_CRYPTO_STATUS Status;
if (pPrivateKeyA == NULL || pPublicKeyA == NULL || oqs_sidh_cln16_is_CurveIsogenyStruct_null(CurveIsogeny)) {
return SIDH_CRYPTO_ERROR_INVALID_PARAMETER;
}
// Choose a random even number in the range [2, oA-2] as secret key for Alice
Status = oqs_sidh_cln16_random_mod_order((digit_t *)pPrivateKeyA, SIDH_ALICE, CurveIsogeny, rand);
if (Status != SIDH_CRYPTO_SUCCESS) {
oqs_sidh_cln16_clear_words((void *)pPrivateKeyA, owords);
return Status;
}
oqs_sidh_cln16_to_mont((digit_t *)CurveIsogeny->PA, (digit_t *)P); // Conversion of Alice's generators to Montgomery representation
oqs_sidh_cln16_to_mont(((digit_t *)CurveIsogeny->PA) + NWORDS_FIELD, ((digit_t *)P) + NWORDS_FIELD);
Status = oqs_sidh_cln16_secret_pt(P, (digit_t *)pPrivateKeyA, SIDH_ALICE, R, CurveIsogeny);
if (Status != SIDH_CRYPTO_SUCCESS) {
oqs_sidh_cln16_clear_words((void *)pPrivateKeyA, owords);
return Status;
}
oqs_sidh_cln16_copy_words((digit_t *)CurveIsogeny->PB, (digit_t *)phiP, pwords); // Copy X-coordinates from Bob's public parameters, set Z <- 1
oqs_sidh_cln16_fpcopy751((digit_t *)CurveIsogeny->Montgomery_one, (digit_t *)phiP->Z);
oqs_sidh_cln16_to_mont((digit_t *)phiP, (digit_t *)phiP);
oqs_sidh_cln16_copy_words((digit_t *)phiP, (digit_t *)phiQ, pwords); // QB = (-XPB:1)
oqs_sidh_cln16_fpneg751(phiQ->X[0]);
oqs_sidh_cln16_fpcopy751((digit_t *)CurveIsogeny->Montgomery_one, (digit_t *)phiQ->Z);
oqs_sidh_cln16_distort_and_diff(phiP->X[0], phiD, CurveIsogeny); // DB = (x(QB-PB),z(QB-PB))
oqs_sidh_cln16_fpcopy751(CurveIsogeny->A, A[0]); // Extracting curve parameters A and C
oqs_sidh_cln16_fpcopy751(CurveIsogeny->C, C[0]);
oqs_sidh_cln16_to_mont(A[0], A[0]);
oqs_sidh_cln16_to_mont(C[0], C[0]);
oqs_sidh_cln16_first_4_isog(phiP, A, Aout, Cout, CurveIsogeny);
oqs_sidh_cln16_first_4_isog(phiQ, A, Aout, Cout, CurveIsogeny);
oqs_sidh_cln16_first_4_isog(phiD, A, Aout, Cout, CurveIsogeny);
oqs_sidh_cln16_first_4_isog(R, A, A, C, CurveIsogeny);
index = 0;
for (row = 1; row < SIDH_MAX_Alice; row++) {
while (index < SIDH_MAX_Alice - row) {
oqs_sidh_cln16_fp2copy751(R->X, pts[npts]->X);
oqs_sidh_cln16_fp2copy751(R->Z, pts[npts]->Z);
pts_index[npts] = index;
npts += 1;
m = splits_Alice[SIDH_MAX_Alice - index - row];
oqs_sidh_cln16_xDBLe(R, R, A, C, (int)(2 * m));
index += m;
}
oqs_sidh_cln16_get_4_isog(R, A, C, coeff);
for (i = 0; i < npts; i++) {
oqs_sidh_cln16_eval_4_isog(pts[i], coeff);
}
oqs_sidh_cln16_eval_4_isog(phiP, coeff);
oqs_sidh_cln16_eval_4_isog(phiQ, coeff);
oqs_sidh_cln16_eval_4_isog(phiD, coeff);
oqs_sidh_cln16_fp2copy751(pts[npts - 1]->X, R->X);
oqs_sidh_cln16_fp2copy751(pts[npts - 1]->Z, R->Z);
index = pts_index[npts - 1];
npts -= 1;
}
oqs_sidh_cln16_get_4_isog(R, A, C, coeff);
oqs_sidh_cln16_eval_4_isog(phiP, coeff);
oqs_sidh_cln16_eval_4_isog(phiQ, coeff);
oqs_sidh_cln16_eval_4_isog(phiD, coeff);
oqs_sidh_cln16_inv_3_way(phiP->Z, phiQ->Z, phiD->Z);
oqs_sidh_cln16_fp2mul751_mont(phiP->X, phiP->Z, phiP->X);
oqs_sidh_cln16_fp2mul751_mont(phiQ->X, phiQ->Z, phiQ->X);
oqs_sidh_cln16_fp2mul751_mont(phiD->X, phiD->Z, phiD->X);
oqs_sidh_cln16_from_fp2mont(phiP->X, ((oqs_sidh_cln16_f2elm_t *)PublicKeyA)[0]); // Converting back to standard representation
oqs_sidh_cln16_from_fp2mont(phiQ->X, ((oqs_sidh_cln16_f2elm_t *)PublicKeyA)[1]);
oqs_sidh_cln16_from_fp2mont(phiD->X, ((oqs_sidh_cln16_f2elm_t *)PublicKeyA)[2]);
// Cleanup:
oqs_sidh_cln16_clear_words((void *)R, 2 * 2 * pwords);
oqs_sidh_cln16_clear_words((void *)phiP, 2 * 2 * pwords);
oqs_sidh_cln16_clear_words((void *)phiQ, 2 * 2 * pwords);
oqs_sidh_cln16_clear_words((void *)phiD, 2 * 2 * pwords);
oqs_sidh_cln16_clear_words((void *)pts, SIDH_MAX_INT_POINTS_ALICE * 2 * 2 * pwords);
oqs_sidh_cln16_clear_words((void *)A, 2 * pwords);
oqs_sidh_cln16_clear_words((void *)C, 2 * pwords);
oqs_sidh_cln16_clear_words((void *)coeff, 5 * 2 * pwords);
return Status;
}
SIDH_CRYPTO_STATUS oqs_sidh_cln16_KeyGeneration_B(unsigned char *pPrivateKeyB, unsigned char *pPublicKeyB, PCurveIsogenyStruct CurveIsogeny, OQS_RAND *rand) {
// Bob's key-pair generation
// It produces a private key pPrivateKeyB and computes the public key pPublicKeyB.
// The private key is an integer in the range [1, oB-1], where oA = 3^239 (i.e., 379 bits in total).
// The public key consists of 3 elements in GF(p751^2), i.e., 564 bytes.
// CurveIsogeny must be set up in advance using oqs_sidh_cln16_curve_initialize().
unsigned int owords = NBITS_TO_NWORDS(CurveIsogeny->owordbits), pwords = NBITS_TO_NWORDS(CurveIsogeny->pwordbits);
oqs_sidh_cln16_point_basefield_t P;
oqs_sidh_cln16_point_proj_t R, phiP = oqs_sidh_cln16_point_proj_t_EMPTY, phiQ = oqs_sidh_cln16_point_proj_t_EMPTY, phiD = oqs_sidh_cln16_point_proj_t_EMPTY, pts[SIDH_MAX_INT_POINTS_BOB];
oqs_sidh_cln16_publickey_t *PublicKeyB = (oqs_sidh_cln16_publickey_t *)pPublicKeyB;
unsigned int i, row, m, index = 0, pts_index[SIDH_MAX_INT_POINTS_BOB], npts = 0;
oqs_sidh_cln16_f2elm_t A = { {0} }, C = { {0} };
SIDH_CRYPTO_STATUS Status;
if (pPrivateKeyB == NULL || pPublicKeyB == NULL || oqs_sidh_cln16_is_CurveIsogenyStruct_null(CurveIsogeny)) {
return SIDH_CRYPTO_ERROR_INVALID_PARAMETER;
}
// Choose a random number equivalent to 0 (mod 3) in the range [3, oB-3] as secret key for Bob
Status = oqs_sidh_cln16_random_mod_order((digit_t *)pPrivateKeyB, SIDH_BOB, CurveIsogeny, rand);
if (Status != SIDH_CRYPTO_SUCCESS) {
oqs_sidh_cln16_clear_words((void *)pPrivateKeyB, owords);
return Status;
}
oqs_sidh_cln16_to_mont((digit_t *)CurveIsogeny->PB, (digit_t *)P); // Conversion of Bob's generators to Montgomery representation
oqs_sidh_cln16_to_mont(((digit_t *)CurveIsogeny->PB) + NWORDS_FIELD, ((digit_t *)P) + NWORDS_FIELD);
Status = oqs_sidh_cln16_secret_pt(P, (digit_t *)pPrivateKeyB, SIDH_BOB, R, CurveIsogeny);
if (Status != SIDH_CRYPTO_SUCCESS) {
oqs_sidh_cln16_clear_words((void *)pPrivateKeyB, owords);
return Status;
}
oqs_sidh_cln16_copy_words((digit_t *)CurveIsogeny->PA, (digit_t *)phiP, pwords); // Copy X-coordinates from Alice's public parameters, set Z <- 1
oqs_sidh_cln16_fpcopy751((digit_t *)CurveIsogeny->Montgomery_one, (digit_t *)phiP->Z);
oqs_sidh_cln16_to_mont((digit_t *)phiP, (digit_t *)phiP); // Conversion to Montgomery representation
oqs_sidh_cln16_copy_words((digit_t *)phiP, (digit_t *)phiQ, pwords); // QA = (-XPA:1)
oqs_sidh_cln16_fpneg751(phiQ->X[0]);
oqs_sidh_cln16_fpcopy751((digit_t *)CurveIsogeny->Montgomery_one, (digit_t *)phiQ->Z);
oqs_sidh_cln16_distort_and_diff(phiP->X[0], phiD, CurveIsogeny); // DA = (x(QA-PA),z(QA-PA))
oqs_sidh_cln16_fpcopy751(CurveIsogeny->A, A[0]); // Extracting curve parameters A and C
oqs_sidh_cln16_fpcopy751(CurveIsogeny->C, C[0]);
oqs_sidh_cln16_to_mont(A[0], A[0]);
oqs_sidh_cln16_to_mont(C[0], C[0]);
index = 0;
for (row = 1; row < SIDH_MAX_Bob; row++) {
while (index < SIDH_MAX_Bob - row) {
oqs_sidh_cln16_fp2copy751(R->X, pts[npts]->X);
oqs_sidh_cln16_fp2copy751(R->Z, pts[npts]->Z);
pts_index[npts] = index;
npts += 1;
m = splits_Bob[SIDH_MAX_Bob - index - row];
oqs_sidh_cln16_xTPLe(R, R, A, C, (int)m);
index += m;
}
oqs_sidh_cln16_get_3_isog(R, A, C);
for (i = 0; i < npts; i++) {
oqs_sidh_cln16_eval_3_isog(R, pts[i]);
}
oqs_sidh_cln16_eval_3_isog(R, phiP);
oqs_sidh_cln16_eval_3_isog(R, phiQ);
oqs_sidh_cln16_eval_3_isog(R, phiD);
oqs_sidh_cln16_fp2copy751(pts[npts - 1]->X, R->X);
oqs_sidh_cln16_fp2copy751(pts[npts - 1]->Z, R->Z);
index = pts_index[npts - 1];
npts -= 1;
}
oqs_sidh_cln16_get_3_isog(R, A, C);
oqs_sidh_cln16_eval_3_isog(R, phiP);
oqs_sidh_cln16_eval_3_isog(R, phiQ);
oqs_sidh_cln16_eval_3_isog(R, phiD);
oqs_sidh_cln16_inv_3_way(phiP->Z, phiQ->Z, phiD->Z);
oqs_sidh_cln16_fp2mul751_mont(phiP->X, phiP->Z, phiP->X);
oqs_sidh_cln16_fp2mul751_mont(phiQ->X, phiQ->Z, phiQ->X);
oqs_sidh_cln16_fp2mul751_mont(phiD->X, phiD->Z, phiD->X);
oqs_sidh_cln16_from_fp2mont(phiP->X, ((oqs_sidh_cln16_f2elm_t *)PublicKeyB)[0]); // Converting back to standard representation
oqs_sidh_cln16_from_fp2mont(phiQ->X, ((oqs_sidh_cln16_f2elm_t *)PublicKeyB)[1]);
oqs_sidh_cln16_from_fp2mont(phiD->X, ((oqs_sidh_cln16_f2elm_t *)PublicKeyB)[2]);
// Cleanup:
oqs_sidh_cln16_clear_words((void *)R, 2 * 2 * pwords);
oqs_sidh_cln16_clear_words((void *)phiP, 2 * 2 * pwords);
oqs_sidh_cln16_clear_words((void *)phiQ, 2 * 2 * pwords);
oqs_sidh_cln16_clear_words((void *)phiD, 2 * 2 * pwords);
oqs_sidh_cln16_clear_words((void *)pts, SIDH_MAX_INT_POINTS_BOB * 2 * 2 * pwords);
oqs_sidh_cln16_clear_words((void *)A, 2 * pwords);
oqs_sidh_cln16_clear_words((void *)C, 2 * pwords);
return Status;
}
SIDH_CRYPTO_STATUS oqs_sidh_cln16_SecretAgreement_A(unsigned char *pPrivateKeyA, unsigned char *pPublicKeyB, unsigned char *pSharedSecretA, bool validate, PCurveIsogenyStruct CurveIsogeny, OQS_RAND *rand) {
// Alice's shared secret generation
// It produces a shared secret key pSharedSecretA using her secret key pPrivateKeyA and Bob's public key pPublicKeyB
// Inputs: Alice's pPrivateKeyA is an even integer in the range [2, oA-2], where oA = 2^372 (i.e., 372 bits in total).
// Bob's pPublicKeyB consists of 3 elements in GF(p751^2), i.e., 564 bytes.
// "validate" flag that indicates if Alice must validate Bob's public key.
// Output: a shared secret pSharedSecretA that consists of one element in GF(p751^2), i.e., 1502 bits in total.
// CurveIsogeny must be set up in advance using oqs_sidh_cln16_curve_initialize().
unsigned int pwords = NBITS_TO_NWORDS(CurveIsogeny->pwordbits);
unsigned int i, row, m, index = 0, pts_index[SIDH_MAX_INT_POINTS_ALICE], npts = 0;
oqs_sidh_cln16_point_proj_t R, pts[SIDH_MAX_INT_POINTS_ALICE];
oqs_sidh_cln16_publickey_t *PublicKeyB = (oqs_sidh_cln16_publickey_t *)pPublicKeyB;
oqs_sidh_cln16_f2elm_t jinv, coeff[5], PKB[3], A, C = { {0} };
bool valid_PublicKey = false;
SIDH_CRYPTO_STATUS Status;
if (pPrivateKeyA == NULL || pPublicKeyB == NULL || pSharedSecretA == NULL || oqs_sidh_cln16_is_CurveIsogenyStruct_null(CurveIsogeny)) {
return SIDH_CRYPTO_ERROR_INVALID_PARAMETER;
}
oqs_sidh_cln16_to_fp2mont(((oqs_sidh_cln16_f2elm_t *)PublicKeyB)[0], PKB[0]); // Extracting and converting Bob's public curve parameters to Montgomery representation
oqs_sidh_cln16_to_fp2mont(((oqs_sidh_cln16_f2elm_t *)PublicKeyB)[1], PKB[1]);
oqs_sidh_cln16_to_fp2mont(((oqs_sidh_cln16_f2elm_t *)PublicKeyB)[2], PKB[2]);
oqs_sidh_cln16_get_A(PKB[0], PKB[1], PKB[2], A, CurveIsogeny);
oqs_sidh_cln16_fpcopy751(CurveIsogeny->C, C[0]);
oqs_sidh_cln16_to_mont(C[0], C[0]);
if (validate == true) { // Alice validating Bob's public key
Status = oqs_sidh_cln16_Validate_PKB(A, &PKB[0], &valid_PublicKey, CurveIsogeny, rand);
if (Status != SIDH_CRYPTO_SUCCESS) {
return Status;
}
if (valid_PublicKey != true) {
Status = SIDH_CRYPTO_ERROR_PUBLIC_KEY_VALIDATION;
return Status;
}
}
Status = oqs_sidh_cln16_ladder_3_pt(PKB[0], PKB[1], PKB[2], (digit_t *)pPrivateKeyA, SIDH_ALICE, R, A, CurveIsogeny);
if (Status != SIDH_CRYPTO_SUCCESS) {
return Status;
}
oqs_sidh_cln16_first_4_isog(R, A, A, C, CurveIsogeny);
index = 0;
for (row = 1; row < SIDH_MAX_Alice; row++) {
while (index < SIDH_MAX_Alice - row) {
oqs_sidh_cln16_fp2copy751(R->X, pts[npts]->X);
oqs_sidh_cln16_fp2copy751(R->Z, pts[npts]->Z);
pts_index[npts] = index;
npts += 1;
m = splits_Alice[SIDH_MAX_Alice - index - row];
oqs_sidh_cln16_xDBLe(R, R, A, C, (int)(2 * m));
index += m;
}
oqs_sidh_cln16_get_4_isog(R, A, C, coeff);
for (i = 0; i < npts; i++) {
oqs_sidh_cln16_eval_4_isog(pts[i], coeff);
}
oqs_sidh_cln16_fp2copy751(pts[npts - 1]->X, R->X);
oqs_sidh_cln16_fp2copy751(pts[npts - 1]->Z, R->Z);
index = pts_index[npts - 1];
npts -= 1;
}
oqs_sidh_cln16_get_4_isog(R, A, C, coeff);
oqs_sidh_cln16_j_inv(A, C, jinv);
oqs_sidh_cln16_from_fp2mont(jinv, (oqs_sidh_cln16_felm_t *)pSharedSecretA); // Converting back to standard representation
// Cleanup:
oqs_sidh_cln16_clear_words((void *)R, 2 * 2 * pwords);
oqs_sidh_cln16_clear_words((void *)pts, SIDH_MAX_INT_POINTS_ALICE * 2 * 2 * pwords);
oqs_sidh_cln16_clear_words((void *)A, 2 * pwords);
oqs_sidh_cln16_clear_words((void *)C, 2 * pwords);
oqs_sidh_cln16_clear_words((void *)jinv, 2 * pwords);
oqs_sidh_cln16_clear_words((void *)coeff, 5 * 2 * pwords);
return Status;
}
SIDH_CRYPTO_STATUS oqs_sidh_cln16_SecretAgreement_B(unsigned char *pPrivateKeyB, unsigned char *pPublicKeyA, unsigned char *pSharedSecretB, bool validate, PCurveIsogenyStruct CurveIsogeny, OQS_RAND *rand) {
// Bob's shared secret generation
// It produces a shared secret key pSharedSecretB using his secret key pPrivateKeyB and Alice's public key pPublicKeyA
// Inputs: Bob's pPrivateKeyB is an integer in the range [1, oB-1], where oA = 3^239 (i.e., 379 bits in total).
// Alice's pPublicKeyA consists of 3 elements in GF(p751^2), i.e., 564 bytes.
// "validate" flag that indicates if Bob must validate Alice's public key.
// Output: a shared secret pSharedSecretB that consists of one element in GF(p751^2), i.e., 1502 bits in total.
// CurveIsogeny must be set up in advance using oqs_sidh_cln16_curve_initialize().
unsigned int pwords = NBITS_TO_NWORDS(CurveIsogeny->pwordbits);
unsigned int i, row, m, index = 0, pts_index[SIDH_MAX_INT_POINTS_BOB], npts = 0;
oqs_sidh_cln16_point_proj_t R, pts[SIDH_MAX_INT_POINTS_BOB];
oqs_sidh_cln16_publickey_t *PublicKeyA = (oqs_sidh_cln16_publickey_t *)pPublicKeyA;
oqs_sidh_cln16_f2elm_t jinv, A, PKA[3], C = { {0} };
bool valid_PublicKey = false;
SIDH_CRYPTO_STATUS Status;
if (pPrivateKeyB == NULL || pPublicKeyA == NULL || pSharedSecretB == NULL || oqs_sidh_cln16_is_CurveIsogenyStruct_null(CurveIsogeny)) {
return SIDH_CRYPTO_ERROR_INVALID_PARAMETER;
}
oqs_sidh_cln16_to_fp2mont(((oqs_sidh_cln16_f2elm_t *)PublicKeyA)[0], PKA[0]); // Extracting and converting Alice's public curve parameters to Montgomery representation
oqs_sidh_cln16_to_fp2mont(((oqs_sidh_cln16_f2elm_t *)PublicKeyA)[1], PKA[1]);
oqs_sidh_cln16_to_fp2mont(((oqs_sidh_cln16_f2elm_t *)PublicKeyA)[2], PKA[2]);
oqs_sidh_cln16_get_A(PKA[0], PKA[1], PKA[2], A, CurveIsogeny);
oqs_sidh_cln16_fpcopy751(CurveIsogeny->C, C[0]);
oqs_sidh_cln16_to_mont(C[0], C[0]);
if (validate == true) { // Bob validating Alice's public key
Status = oqs_sidh_cln16_Validate_PKA(A, &PKA[0], &valid_PublicKey, CurveIsogeny, rand);
if (Status != SIDH_CRYPTO_SUCCESS) {
return Status;
}
if (valid_PublicKey != true) {
Status = SIDH_CRYPTO_ERROR_PUBLIC_KEY_VALIDATION;
return Status;
}
}
Status = oqs_sidh_cln16_ladder_3_pt(PKA[0], PKA[1], PKA[2], (digit_t *)pPrivateKeyB, SIDH_BOB, R, A, CurveIsogeny);
if (Status != SIDH_CRYPTO_SUCCESS) {
return Status;
}
index = 0;
for (row = 1; row < SIDH_MAX_Bob; row++) {
while (index < SIDH_MAX_Bob - row) {
oqs_sidh_cln16_fp2copy751(R->X, pts[npts]->X);
oqs_sidh_cln16_fp2copy751(R->Z, pts[npts]->Z);
pts_index[npts] = index;
npts += 1;
m = splits_Bob[SIDH_MAX_Bob - index - row];
oqs_sidh_cln16_xTPLe(R, R, A, C, (int)m);
index += m;
}
oqs_sidh_cln16_get_3_isog(R, A, C);
for (i = 0; i < npts; i++) {
oqs_sidh_cln16_eval_3_isog(R, pts[i]);
}
oqs_sidh_cln16_fp2copy751(pts[npts - 1]->X, R->X);
oqs_sidh_cln16_fp2copy751(pts[npts - 1]->Z, R->Z);
index = pts_index[npts - 1];
npts -= 1;
}
oqs_sidh_cln16_get_3_isog(R, A, C);
oqs_sidh_cln16_j_inv(A, C, jinv);
oqs_sidh_cln16_from_fp2mont(jinv, (oqs_sidh_cln16_felm_t *)pSharedSecretB); // Converting back to standard representation
// Cleanup:
oqs_sidh_cln16_clear_words((void *)R, 2 * 2 * pwords);
oqs_sidh_cln16_clear_words((void *)pts, SIDH_MAX_INT_POINTS_BOB * 2 * 2 * pwords);
oqs_sidh_cln16_clear_words((void *)A, 2 * pwords);
oqs_sidh_cln16_clear_words((void *)C, 2 * pwords);
oqs_sidh_cln16_clear_words((void *)jinv, 2 * pwords);
return Status;
}

View File

@ -0,0 +1,220 @@
/********************************************************************************************
* SIDH: an efficient supersingular isogeny-based cryptography library for Diffie-Hellman key
* exchange providing 128 bits of quantum security and 192 bits of classical security.
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*
* Abstract: functions for validation of public keys
*
* SECURITY NOTE: these functions run in variable time because it is assumed that they are
* used over public data.
*
*********************************************************************************************/
#include <oqs/rand.h>
#include "SIDH_internal.h"
static bool is_equal_fp(oqs_sidh_cln16_felm_t a, oqs_sidh_cln16_felm_t b) {
// Return true if a = b in GF(p751). Otherwise, return false
unsigned int i;
for (i = 0; i < NWORDS_FIELD; i++) {
if (a[i] != b[i]) {
return false;
}
}
return true;
}
static bool is_equal_fp2(oqs_sidh_cln16_f2elm_t a, oqs_sidh_cln16_f2elm_t b) {
// Return true if a = b in GF(p751^2). Otherwise, return false
return (is_equal_fp(a[0], b[0]) && is_equal_fp(a[1], b[1]));
}
SIDH_CRYPTO_STATUS oqs_sidh_cln16_random_fp2(oqs_sidh_cln16_f2elm_t f2value, PCurveIsogenyStruct pCurveIsogeny, OQS_RAND *rand) {
// Output random value in GF(p751). It makes requests of random values to the "random_bytes" function.
// If successful, the output is given in "f2value".
unsigned int ntry = 0, nbytes;
oqs_sidh_cln16_felm_t t1, p751;
unsigned char mask;
oqs_sidh_cln16_clear_words((void *)f2value, 2 * NWORDS_FIELD);
oqs_sidh_cln16_fpcopy751(pCurveIsogeny->prime, p751);
nbytes = (pCurveIsogeny->pbits + 7) / 8; // Number of random bytes to be requested
mask = (unsigned char)(8 * nbytes - pCurveIsogeny->pbits);
mask = ((unsigned char) - 1 >> mask); // Value for masking last random byte
do {
ntry++;
if (ntry > 100) { // Max. 100 iterations to obtain random value in [0, p751-1]
return SIDH_CRYPTO_ERROR_TOO_MANY_ITERATIONS;
}
rand->rand_n(rand, (uint8_t *)&f2value[0], nbytes);
((unsigned char *)&f2value[0])[nbytes - 1] &= mask; // Masking last byte
} while (oqs_sidh_cln16_mp_sub(p751, f2value[0], t1, NWORDS_FIELD) == 1);
ntry = 0;
do {
ntry++;
if (ntry > 100) { // Max. 100 iterations to obtain random value in [0, p751-1]
return SIDH_CRYPTO_ERROR_TOO_MANY_ITERATIONS;
}
rand->rand_n(rand, (uint8_t *)&f2value[1], nbytes);
((unsigned char *)&f2value[1])[nbytes - 1] &= mask; // Masking last byte
} while (oqs_sidh_cln16_mp_sub(p751, f2value[1], t1, NWORDS_FIELD) == 1);
// Cleanup
oqs_sidh_cln16_clear_words((void *)t1, NWORDS_FIELD);
return SIDH_CRYPTO_SUCCESS;
}
static bool test_curve(oqs_sidh_cln16_f2elm_t A, oqs_sidh_cln16_f2elm_t rvalue, PCurveIsogenyStruct CurveIsogeny) {
// This function checks that the curve is in the correct supersingular isogeny class via Sutherland's Monte Carlo algorithm.
// It also checks that the curve is not a subfield curve. Both Alice and Bob call this same function in their respective validation procedures below.
// Inputs: the curve constant A, corresponding to E_A: y^2=x^3+A*x^2+x,
// a random value "rvalue" in Fp2.
// Output: returns "true" if curve is valid, "false" otherwise.
oqs_sidh_cln16_f2elm_t t0, t1, one = { {0} }, zero = { {0} };
oqs_sidh_cln16_point_proj_t rP, P1;
bool valid_curve;
oqs_sidh_cln16_fpcopy751((digit_t *)CurveIsogeny->Montgomery_one, one[0]);
// Test j invariant in Fp2\Fp
oqs_sidh_cln16_fp2sqr751_mont(A, t0); // t0 = a^2
oqs_sidh_cln16_fp2sub751(t0, one, t0);
oqs_sidh_cln16_fp2sub751(t0, one, t0);
oqs_sidh_cln16_fp2sub751(t0, one, t0); // t0 = t0-3
oqs_sidh_cln16_fp2sqr751_mont(t0, t1); // t1 = t0^2
oqs_sidh_cln16_fp2mul751_mont(t0, t1, t1); // t1 = t1*t0
oqs_sidh_cln16_fp2sub751(t0, one, t0); // t0 = t0-1
oqs_sidh_cln16_fpmul751_mont(t1[0], t0[1], t1[0]);
oqs_sidh_cln16_fpmul751_mont(t1[1], t0[0], t1[1]);
oqs_sidh_cln16_fp2correction751(t1);
valid_curve = !is_equal_fp(t1[0], t1[1]);
// Test supersingular
oqs_sidh_cln16_fp2copy751(rvalue, rP->X);
oqs_sidh_cln16_fp2copy751(one, rP->Z);
oqs_sidh_cln16_xDBLe(rP, rP, A, one, 1);
oqs_sidh_cln16_xDBLe(rP, P1, A, one, 371);
oqs_sidh_cln16_xTPLe(P1, P1, A, one, 239);
oqs_sidh_cln16_fp2mul751_mont(rP->X, P1->Z, rP->X); // X = X*Z1
oqs_sidh_cln16_fp2mul751_mont(rP->Z, P1->X, rP->Z); // Z = Z*X1
oqs_sidh_cln16_fp2sub751(rP->X, rP->Z, rP->X); // X = X-Z
oqs_sidh_cln16_fp2mul751_mont(rP->X, P1->Z, rP->X); // X = X*Z1
oqs_sidh_cln16_fp2correction751(rP->X);
return (valid_curve && is_equal_fp2(rP->X, zero));
}
SIDH_CRYPTO_STATUS oqs_sidh_cln16_Validate_PKA(oqs_sidh_cln16_f2elm_t A, oqs_sidh_cln16_publickey_t PKA, bool *valid, PCurveIsogenyStruct CurveIsogeny, OQS_RAND *rand) {
// Bob validating Alice's public key
// Inputs: Alice's public key [A,xP,xQ,xQP], where xP,xQ and xQP are contained in PKA,
// the exponent eB (=239 for our curve) for Miller's algorithm.
// Output: valid = "true" if key is valid, "false" otherwise.
// CurveIsogeny must be set up in advance using oqs_sidh_cln16_curve_initialize().
unsigned int eB1 = CurveIsogeny->eB - 1; // eB1 = eB-1
oqs_sidh_cln16_f2elm_t t0, t1, rvalue, one = { {0} }, zero = { {0} };
oqs_sidh_cln16_point_proj_t P = oqs_sidh_cln16_point_proj_t_EMPTY, Q = oqs_sidh_cln16_point_proj_t_EMPTY;
SIDH_CRYPTO_STATUS Status;
// Choose a random element in GF(p751^2) for Sutherland's algorithm. Assume that it is in Montgomery representation
Status = oqs_sidh_cln16_random_fp2(rvalue, CurveIsogeny, rand);
if (Status != SIDH_CRYPTO_SUCCESS) {
oqs_sidh_cln16_clear_words((void *)rvalue, 2 * NWORDS_FIELD);
return Status;
}
oqs_sidh_cln16_fpcopy751((digit_t *)CurveIsogeny->Montgomery_one, one[0]);
oqs_sidh_cln16_fp2copy751(PKA[0], P->X);
oqs_sidh_cln16_fpcopy751((digit_t *)CurveIsogeny->Montgomery_one, P->Z[0]);
oqs_sidh_cln16_fp2copy751(PKA[1], Q->X);
oqs_sidh_cln16_fpcopy751((digit_t *)CurveIsogeny->Montgomery_one, Q->Z[0]);
oqs_sidh_cln16_xTPLe(P, P, A, one, eB1);
oqs_sidh_cln16_xTPLe(Q, Q, A, one, eB1);
oqs_sidh_cln16_fp2mul751_mont(P->X, Q->Z, t0); // t0 = XP*ZQ
oqs_sidh_cln16_fp2mul751_mont(Q->X, P->Z, t1); // t1 = XQ*ZP
oqs_sidh_cln16_fp2sub751(t0, t1, t0); // t0 = t0-t1
oqs_sidh_cln16_fp2mul751_mont(P->Z, t0, t0); // t0 = ZP*t0
oqs_sidh_cln16_fp2mul751_mont(Q->Z, t0, t0); // t0 = ZQ*t0
oqs_sidh_cln16_fp2correction751(t0);
*valid = !is_equal_fp2(t0, zero); // Checks that ZP*ZQ*(XQ*ZP-XP*ZQ) != 0, i.e., that 3^(e-1)*P != 3^(e-1)*Q and neither P nor Q has order 3^(e-1)
oqs_sidh_cln16_xTPLe(P, P, A, one, 1);
oqs_sidh_cln16_xTPLe(Q, Q, A, one, 1);
oqs_sidh_cln16_fp2correction751(P->Z);
oqs_sidh_cln16_fp2correction751(Q->Z);
*valid = *valid & is_equal_fp2(P->Z, zero); // Checks that 3^e*P = 0
*valid = *valid & is_equal_fp2(Q->Z, zero); // Checks that 3^e*Q = 0
*valid = *valid & test_curve(A, rvalue, CurveIsogeny); // Tests curve via Sutherland's algorithm
return SIDH_CRYPTO_SUCCESS;
}
SIDH_CRYPTO_STATUS oqs_sidh_cln16_Validate_PKB(oqs_sidh_cln16_f2elm_t A, oqs_sidh_cln16_publickey_t PKB, bool *valid, PCurveIsogenyStruct CurveIsogeny, OQS_RAND *rand) {
// Alice validating Bob's public key
// Inputs: Bob's public key [A,xP,xQ,xQP], where xP,xQ and xQP are contained in PKB,
// the exponent eA (=372 for our curve) for Miller's algorithm.
// Output: valid = "true" if key is valid, "false" otherwise.
// CurveIsogeny must be set up in advance using oqs_sidh_cln16_curve_initialize().
unsigned int oAbits2 = CurveIsogeny->oAbits - 2; // oAbits2 = oAbits-2
oqs_sidh_cln16_f2elm_t t0, t1, two, four, rvalue, one = { {0} }, zero = { {0} };
oqs_sidh_cln16_point_proj_t P = oqs_sidh_cln16_point_proj_t_EMPTY, Q = oqs_sidh_cln16_point_proj_t_EMPTY;
SIDH_CRYPTO_STATUS Status;
// Choose a random element in GF(p751^2) for Sutherland's algorithm. Assume that it is in Montgomery representation
Status = oqs_sidh_cln16_random_fp2(rvalue, CurveIsogeny, rand);
if (Status != SIDH_CRYPTO_SUCCESS) {
oqs_sidh_cln16_clear_words((void *)rvalue, 2 * NWORDS_FIELD);
return Status;
}
oqs_sidh_cln16_fpcopy751((digit_t *)CurveIsogeny->Montgomery_one, one[0]);
oqs_sidh_cln16_fp2copy751(PKB[0], P->X);
oqs_sidh_cln16_fpcopy751((digit_t *)CurveIsogeny->Montgomery_one, P->Z[0]);
oqs_sidh_cln16_fp2copy751(PKB[1], Q->X);
oqs_sidh_cln16_fpcopy751((digit_t *)CurveIsogeny->Montgomery_one, Q->Z[0]);
oqs_sidh_cln16_fp2add751(one, one, two);
oqs_sidh_cln16_fp2add751(two, two, four); // four = 4
oqs_sidh_cln16_xDBLe(P, P, A, one, oAbits2);
oqs_sidh_cln16_xDBLe(Q, Q, A, one, oAbits2);
oqs_sidh_cln16_fp2mul751_mont(P->X, Q->Z, t0); // t0 = XP*ZQ
oqs_sidh_cln16_fp2mul751_mont(Q->X, P->Z, t1); // t1 = XQ*ZP
oqs_sidh_cln16_fp2sub751(t0, t1, t0); // t0 = t0-t1
oqs_sidh_cln16_fp2mul751_mont(P->Z, t0, t0); // t0 = ZP*t0
oqs_sidh_cln16_fp2mul751_mont(Q->Z, t0, t0); // t0 = ZQ*t0
oqs_sidh_cln16_fp2correction751(t0);
*valid = !is_equal_fp2(t0, zero); // Checks that ZP*ZQ*(XQ*ZP-XP*ZQ) != 0, i.e., that 2^(e-2)*P != 2^(e-2)*Q and neither P nor Q has order 2^(e-2)
oqs_sidh_cln16_fp2add751(A, two, t0); // t0 = A+2
oqs_sidh_cln16_xDBL(P, P, t0, four);
oqs_sidh_cln16_xDBL(Q, Q, t0, four);
oqs_sidh_cln16_fp2mul751_mont(P->Z, Q->Z, t0); // t0 = ZP*ZQ
oqs_sidh_cln16_fp2correction751(t0);
*valid = *valid & !is_equal_fp2(t0, zero); // Checks that 2^(e-1)*P != 0 and 2^(e-1)*Q != 0
oqs_sidh_cln16_xDBL(P, P, t0, four);
oqs_sidh_cln16_xDBL(Q, Q, t0, four);
oqs_sidh_cln16_fp2correction751(P->Z);
oqs_sidh_cln16_fp2correction751(Q->Z);
*valid = *valid & is_equal_fp2(P->Z, zero); // Checks that 2^e*P = 0
*valid = *valid & is_equal_fp2(Q->Z, zero); // Checks that 2^e*Q = 0
*valid = *valid & test_curve(A, rvalue, CurveIsogeny); // Tests curve via Sutherland's algorithm
return SIDH_CRYPTO_SUCCESS;
}