Drop CECPQ2b code.

The experiment which motivated CECPQ2b has concluded (although the
results haven't been published yet) and the SIKE code is causing some
issues for gRPC in gprc/grpc#20100. Also, this is code size that takes
up space in Android etc.

Change-Id: I43b0b8c420f236c0fe9b40bf2517d2fde98495d5
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/38384
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
This commit is contained in:
Adam Langley 2019-10-18 14:48:11 -07:00 committed by CQ bot account: commit-bot@chromium.org
parent 7de9498a88
commit 7f02881e96
35 changed files with 12 additions and 7557 deletions

23
LICENSE
View File

@ -181,29 +181,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
The code in third_party/sike also carries the MIT license:
Copyright (c) Microsoft Corporation. All rights reserved.
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
Licenses for support code
-------------------------

View File

@ -115,7 +115,6 @@ if(${ARCH} STREQUAL "aarch64")
chacha/chacha-armv8.${ASM_EXT}
test/trampoline-armv8.${ASM_EXT}
third_party/sike/asm/fp-armv8.${ASM_EXT}
)
endif()
@ -137,7 +136,6 @@ if(${ARCH} STREQUAL "x86_64")
cipher_extra/chacha20_poly1305_x86_64.${ASM_EXT}
hrss/asm/poly_rq_mul.S
test/trampoline-x86_64.${ASM_EXT}
third_party/sike/asm/fp-x86_64.${ASM_EXT}
)
endif()
@ -147,8 +145,6 @@ perlasm(chacha/chacha-x86.${ASM_EXT} chacha/asm/chacha-x86.pl)
perlasm(chacha/chacha-x86_64.${ASM_EXT} chacha/asm/chacha-x86_64.pl)
perlasm(cipher_extra/aes128gcmsiv-x86_64.${ASM_EXT} cipher_extra/asm/aes128gcmsiv-x86_64.pl)
perlasm(cipher_extra/chacha20_poly1305_x86_64.${ASM_EXT} cipher_extra/asm/chacha20_poly1305_x86_64.pl)
perlasm(third_party/sike/asm/fp-x86_64.${ASM_EXT} ../third_party/sike/asm/fp-x86_64.pl)
perlasm(third_party/sike/asm/fp-armv8.${ASM_EXT} ../third_party/sike/asm/fp-armv8.pl)
perlasm(test/trampoline-armv4.${ASM_EXT} test/asm/trampoline-armv4.pl)
perlasm(test/trampoline-armv8.${ASM_EXT} test/asm/trampoline-armv8.pl)
perlasm(test/trampoline-x86.${ASM_EXT} test/asm/trampoline-x86.pl)
@ -412,11 +408,6 @@ add_library(
x509v3/v3_sxnet.c
x509v3/v3_utl.c
../third_party/fiat/curve25519.c
../third_party/sike/fpx.c
../third_party/sike/isogeny.c
../third_party/sike/curve_params.c
../third_party/sike/sike.c
../third_party/sike/asm/fp_generic.c
$<TARGET_OBJECTS:fipsmodule>
@ -537,7 +528,6 @@ add_executable(
x509/x509_time_test.cc
x509v3/tab_test.cc
x509v3/v3name_test.cc
../third_party/sike/sike_test.cc
$<TARGET_OBJECTS:crypto_test_data>
$<TARGET_OBJECTS:boringssl_gtest_main>

View File

@ -57,7 +57,7 @@
/* This file is generated by crypto/obj/objects.go. */
#define NUM_NID 961
#define NUM_NID 960
static const uint8_t kObjectData[] = {
/* NID_rsadsi */
@ -8756,7 +8756,6 @@ static const ASN1_OBJECT kObjects[NUM_NID] = {
{"KxANY", "kx-any", NID_kx_any, 0, NULL, 0},
{"AuthANY", "auth-any", NID_auth_any, 0, NULL, 0},
{"CECPQ2", "CECPQ2", NID_CECPQ2, 0, NULL, 0},
{"CECPQ2b", "CECPQ2b", NID_CECPQ2b, 0, NULL, 0},
};
static const unsigned kNIDsInShortNameOrder[] = {
@ -8819,7 +8818,6 @@ static const unsigned kNIDsInShortNameOrder[] = {
109 /* CAST5-ECB */,
111 /* CAST5-OFB */,
959 /* CECPQ2 */,
960 /* CECPQ2b */,
894 /* CMAC */,
13 /* CN */,
141 /* CRLReason */,
@ -9725,7 +9723,6 @@ static const unsigned kNIDsInLongNameOrder[] = {
179 /* CA Issuers */,
785 /* CA Repository */,
959 /* CECPQ2 */,
960 /* CECPQ2b */,
131 /* Code Signing */,
783 /* Diffie-Hellman based MAC */,
382 /* Directory */,

View File

@ -948,4 +948,3 @@ auth_psk 956
kx_any 957
auth_any 958
CECPQ2 959
CECPQ2b 960

View File

@ -1337,9 +1337,6 @@ secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme
# NID for CECPQ2 (no corresponding OID).
: CECPQ2
# NID for CECPQ2 (no corresponding OID).
: CECPQ2b
# See RFC 8410.
1 3 101 112 : ED25519

View File

@ -4237,9 +4237,6 @@ extern "C" {
#define SN_CECPQ2 "CECPQ2"
#define NID_CECPQ2 959
#define SN_CECPQ2b "CECPQ2b"
#define NID_CECPQ2b 960
#if defined(__cplusplus)
} /* extern C */

View File

@ -2231,7 +2231,6 @@ OPENSSL_EXPORT int SSL_set1_curves_list(SSL *ssl, const char *curves);
#define SSL_CURVE_SECP521R1 25
#define SSL_CURVE_X25519 29
#define SSL_CURVE_CECPQ2 16696
#define SSL_CURVE_CECPQ2b 65074
// SSL_get_curve_id returns the ID of the curve used by |ssl|'s most recently
// completed handshake or 0 if not applicable.

View File

@ -660,8 +660,7 @@ class CipherScorer {
public:
CipherScorer(uint16_t group_id)
: aes_is_fine_(EVP_has_aes_hardware()),
security_128_is_fine_(group_id != SSL_CURVE_CECPQ2 &&
group_id != SSL_CURVE_CECPQ2b) {}
security_128_is_fine_(group_id != SSL_CURVE_CECPQ2) {}
typedef std::tuple<bool, bool, bool> Score;

View File

@ -31,7 +31,6 @@
#include "internal.h"
#include "../crypto/internal.h"
#include "../third_party/sike/sike.h"
BSSL_NAMESPACE_BEGIN
@ -300,87 +299,6 @@ class CECPQ2KeyShare : public SSLKeyShare {
HRSS_private_key hrss_private_key_;
};
class CECPQ2bKeyShare : public SSLKeyShare {
public:
uint16_t GroupID() const override { return SSL_CURVE_CECPQ2b; }
bool Offer(CBB *out) override {
uint8_t public_x25519[32] = {0};
X25519_keypair(public_x25519, private_x25519_);
if (!SIKE_keypair(private_sike_, public_sike_)) {
return false;
}
return CBB_add_bytes(out, public_x25519, sizeof(public_x25519)) &&
CBB_add_bytes(out, public_sike_, sizeof(public_sike_));
}
bool Accept(CBB *out_public_key, Array<uint8_t> *out_secret,
uint8_t *out_alert, Span<const uint8_t> peer_key) override {
uint8_t public_x25519[32];
uint8_t private_x25519[32];
uint8_t sike_ciphertext[SIKE_CT_BYTESZ] = {0};
*out_alert = SSL_AD_INTERNAL_ERROR;
if (peer_key.size() != sizeof(public_x25519) + SIKE_PUB_BYTESZ) {
*out_alert = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
return false;
}
Array<uint8_t> secret;
if (!secret.Init(sizeof(private_x25519_) + SIKE_SS_BYTESZ)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return false;
}
X25519_keypair(public_x25519, private_x25519);
if (!X25519(secret.data(), private_x25519, peer_key.data())) {
*out_alert = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
return false;
}
SIKE_encaps(secret.data() + sizeof(private_x25519_), sike_ciphertext,
peer_key.data() + sizeof(public_x25519));
*out_secret = std::move(secret);
return CBB_add_bytes(out_public_key, public_x25519,
sizeof(public_x25519)) &&
CBB_add_bytes(out_public_key, sike_ciphertext,
sizeof(sike_ciphertext));
}
bool Finish(Array<uint8_t> *out_secret, uint8_t *out_alert,
Span<const uint8_t> peer_key) override {
*out_alert = SSL_AD_INTERNAL_ERROR;
Array<uint8_t> secret;
if (!secret.Init(sizeof(private_x25519_) + SIKE_SS_BYTESZ)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return false;
}
if (peer_key.size() != 32 + SIKE_CT_BYTESZ ||
!X25519(secret.data(), private_x25519_, peer_key.data())) {
*out_alert = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
return false;
}
SIKE_decaps(secret.data() + sizeof(private_x25519_), peer_key.data() + 32,
public_sike_, private_sike_);
*out_secret = std::move(secret);
return true;
}
private:
uint8_t private_x25519_[32];
uint8_t private_sike_[SIKE_PRV_BYTESZ];
uint8_t public_sike_[SIKE_PUB_BYTESZ];
};
CONSTEXPR_ARRAY NamedGroup kNamedGroups[] = {
{NID_secp224r1, SSL_CURVE_SECP224R1, "P-224", "secp224r1"},
{NID_X9_62_prime256v1, SSL_CURVE_SECP256R1, "P-256", "prime256v1"},
@ -388,7 +306,6 @@ CONSTEXPR_ARRAY NamedGroup kNamedGroups[] = {
{NID_secp521r1, SSL_CURVE_SECP521R1, "P-521", "secp521r1"},
{NID_X25519, SSL_CURVE_X25519, "X25519", "x25519"},
{NID_CECPQ2, SSL_CURVE_CECPQ2, "CECPQ2", "CECPQ2"},
{NID_CECPQ2b, SSL_CURVE_CECPQ2b, "CECPQ2b", "CECPQ2b"},
};
} // namespace
@ -415,8 +332,6 @@ UniquePtr<SSLKeyShare> SSLKeyShare::Create(uint16_t group_id) {
return UniquePtr<SSLKeyShare>(New<X25519KeyShare>());
case SSL_CURVE_CECPQ2:
return UniquePtr<SSLKeyShare>(New<CECPQ2KeyShare>());
case SSL_CURVE_CECPQ2b:
return UniquePtr<SSLKeyShare>(New<CECPQ2bKeyShare>());
default:
return nullptr;
}

View File

@ -200,7 +200,7 @@ static bool tls1_check_duplicate_extensions(const CBS *cbs) {
}
static bool is_post_quantum_group(uint16_t id) {
return id == SSL_CURVE_CECPQ2 || id == SSL_CURVE_CECPQ2b;
return id == SSL_CURVE_CECPQ2;
}
bool ssl_client_hello_init(const SSL *ssl, SSL_CLIENT_HELLO *out,

View File

@ -151,7 +151,6 @@ const (
CurveP521 CurveID = 25
CurveX25519 CurveID = 29
CurveCECPQ2 CurveID = 16696
CurveCECPQ2b CurveID = 65074
)
// TLS Elliptic Curve Point Formats
@ -1732,7 +1731,7 @@ func (c *Config) maxVersion(isDTLS bool) uint16 {
return ret
}
var defaultCurvePreferences = []CurveID{CurveCECPQ2b, CurveCECPQ2, CurveX25519, CurveP256, CurveP384, CurveP521}
var defaultCurvePreferences = []CurveID{CurveCECPQ2, CurveX25519, CurveP256, CurveP384, CurveP521}
func (c *Config) curvePreferences() []CurveID {
if c == nil || len(c.CurvePreferences) == 0 {

View File

@ -210,7 +210,7 @@ func (hs *serverHandshakeState) readClientHello() error {
if config.Bugs.FailIfCECPQ2Offered {
for _, offeredCurve := range hs.clientHello.supportedCurves {
if isPqGroup(offeredCurve) {
return errors.New("tls: CECPQ2 or CECPQ2b was offered")
return errors.New("tls: CECPQ2 was offered")
}
}
}
@ -1227,7 +1227,7 @@ func (hs *serverHandshakeState) processClientHello() (isResume bool, err error)
Curves:
for _, curve := range hs.clientHello.supportedCurves {
if isPqGroup(curve) && c.vers < VersionTLS13 {
// CECPQ2 and CECPQ2b is TLS 1.3-only.
// CECPQ2 is TLS 1.3-only.
continue
}

View File

@ -19,7 +19,6 @@ import (
"boringssl.googlesource.com/boringssl/ssl/test/runner/curve25519"
"boringssl.googlesource.com/boringssl/ssl/test/runner/hrss"
"boringssl.googlesource.com/boringssl/ssl/test/runner/sike"
)
type keyType int
@ -434,98 +433,6 @@ func (e *cecpq2Curve) finish(peerKey []byte) (preMasterSecret []byte, err error)
return preMasterSecret, nil
}
// cecpq2BCurve implements CECPQ2b, which is SIKE combined with X25519.
type cecpq2BCurve struct {
// Both public key and shared secret size
x25519PrivateKey [32]byte
sikePrivateKey *sike.PrivateKey
}
func (e *cecpq2BCurve) offer(rand io.Reader) (publicKey []byte, err error) {
if _, err = io.ReadFull(rand, e.x25519PrivateKey[:]); err != nil {
return nil, err
}
var x25519Public [32]byte
curve25519.ScalarBaseMult(&x25519Public, &e.x25519PrivateKey)
e.sikePrivateKey = sike.NewPrivateKey(sike.KeyVariant_SIKE)
if err = e.sikePrivateKey.Generate(rand); err != nil {
return nil, err
}
sikePublic := e.sikePrivateKey.GeneratePublicKey().Export()
var ret []byte
ret = append(ret, x25519Public[:]...)
ret = append(ret, sikePublic...)
return ret, nil
}
func (e *cecpq2BCurve) accept(rand io.Reader, peerKey []byte) (publicKey []byte, preMasterSecret []byte, err error) {
if len(peerKey) != 32+sike.Params.PublicKeySize {
return nil, nil, errors.New("tls: bad length CECPQ2b offer")
}
if _, err = io.ReadFull(rand, e.x25519PrivateKey[:]); err != nil {
return nil, nil, err
}
var x25519Shared, x25519PeerKey, x25519Public [32]byte
copy(x25519PeerKey[:], peerKey)
curve25519.ScalarBaseMult(&x25519Public, &e.x25519PrivateKey)
curve25519.ScalarMult(&x25519Shared, &e.x25519PrivateKey, &x25519PeerKey)
// Per RFC 7748, reject the all-zero value in constant time.
var zeros [32]byte
if subtle.ConstantTimeCompare(zeros[:], x25519Shared[:]) == 1 {
return nil, nil, errors.New("tls: X25519 value with wrong order")
}
var sikePubKey = sike.NewPublicKey(sike.KeyVariant_SIKE)
if err = sikePubKey.Import(peerKey[32:]); err != nil {
// should never happen as size was already checked
return nil, nil, errors.New("tls: implementation error")
}
sikeCiphertext, sikeShared, err := sike.Encapsulate(rand, sikePubKey)
if err != nil {
return nil, nil, err
}
publicKey = append(publicKey, x25519Public[:]...)
publicKey = append(publicKey, sikeCiphertext...)
preMasterSecret = append(preMasterSecret, x25519Shared[:]...)
preMasterSecret = append(preMasterSecret, sikeShared...)
return publicKey, preMasterSecret, nil
}
func (e *cecpq2BCurve) finish(peerKey []byte) (preMasterSecret []byte, err error) {
if len(peerKey) != 32+(sike.Params.PublicKeySize+sike.Params.MsgLen) {
return nil, errors.New("tls: bad length CECPQ2b reply")
}
var x25519Shared, x25519PeerKey [32]byte
copy(x25519PeerKey[:], peerKey)
curve25519.ScalarMult(&x25519Shared, &e.x25519PrivateKey, &x25519PeerKey)
// Per RFC 7748, reject the all-zero value in constant time.
var zeros [32]byte
if subtle.ConstantTimeCompare(zeros[:], x25519Shared[:]) == 1 {
return nil, errors.New("tls: X25519 value with wrong order")
}
var sikePubKey = e.sikePrivateKey.GeneratePublicKey()
sikeShared, err := sike.Decapsulate(e.sikePrivateKey, sikePubKey, peerKey[32:])
if err != nil {
return nil, errors.New("tls: invalid SIKE ciphertext")
}
preMasterSecret = append(preMasterSecret, x25519Shared[:]...)
preMasterSecret = append(preMasterSecret, sikeShared...)
return preMasterSecret, nil
}
func curveForCurveID(id CurveID, config *Config) (ecdhCurve, bool) {
switch id {
case CurveP224:
@ -540,8 +447,6 @@ func curveForCurveID(id CurveID, config *Config) (ecdhCurve, bool) {
return &x25519ECDHCurve{setHighBit: config.Bugs.SetX25519HighBit}, true
case CurveCECPQ2:
return &cecpq2Curve{}, true
case CurveCECPQ2b:
return &cecpq2BCurve{}, true
default:
return nil, false
}
@ -690,7 +595,7 @@ func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Cer
NextCandidate:
for _, candidate := range preferredCurves {
if isPqGroup(candidate) && version < VersionTLS13 {
// CECPQ2 and CECPQ2b is TLS 1.3-only.
// CECPQ2 is TLS 1.3-only.
continue
}

View File

@ -10449,13 +10449,12 @@ var testCurves = []struct {
{"P-521", CurveP521},
{"X25519", CurveX25519},
{"CECPQ2", CurveCECPQ2},
{"CECPQ2b", CurveCECPQ2b},
}
const bogusCurve = 0x1234
func isPqGroup(r CurveID) bool {
return r == CurveCECPQ2 || r == CurveCECPQ2b
return r == CurveCECPQ2
}
func addCurveTests() {
@ -10928,21 +10927,6 @@ func addCurveTests() {
},
})
// CECPQ2b should not be offered by a TLS < 1.3 client.
testCases = append(testCases, testCase{
name: "CECPQ2bNotInTLS12",
config: Config{
Bugs: ProtocolBugs{
FailIfCECPQ2Offered: true,
},
},
flags: []string{
"-max-version", strconv.Itoa(VersionTLS12),
"-curves", strconv.Itoa(int(CurveCECPQ2b)),
"-curves", strconv.Itoa(int(CurveX25519)),
},
})
// CECPQ2 should not crash a TLS < 1.3 client if the server mistakenly
// selects it.
testCases = append(testCases, testCase{
@ -10961,24 +10945,6 @@ func addCurveTests() {
expectedError: ":WRONG_CURVE:",
})
// CECPQ2b should not crash a TLS < 1.3 client if the server mistakenly
// selects it.
testCases = append(testCases, testCase{
name: "CECPQ2bNotAcceptedByTLS12Client",
config: Config{
Bugs: ProtocolBugs{
SendCurve: CurveCECPQ2b,
},
},
flags: []string{
"-max-version", strconv.Itoa(VersionTLS12),
"-curves", strconv.Itoa(int(CurveCECPQ2b)),
"-curves", strconv.Itoa(int(CurveX25519)),
},
shouldFail: true,
expectedError: ":WRONG_CURVE:",
})
// CECPQ2 should not be offered by default as a client.
testCases = append(testCases, testCase{
name: "CECPQ2NotEnabledByDefaultInClients",
@ -10990,17 +10956,6 @@ func addCurveTests() {
},
})
// CECPQ2b should not be offered by default as a client.
testCases = append(testCases, testCase{
name: "CECPQ2bNotEnabledByDefaultInClients",
config: Config{
MinVersion: VersionTLS13,
Bugs: ProtocolBugs{
FailIfCECPQ2Offered: true,
},
},
})
// If CECPQ2 is offered, both X25519 and CECPQ2 should have a key-share.
testCases = append(testCases, testCase{
name: "NotJustCECPQ2KeyShare",
@ -11033,38 +10988,6 @@ func addCurveTests() {
},
})
// If CECPQ2b is offered, both X25519 and CECPQ2b should have a key-share.
testCases = append(testCases, testCase{
name: "NotJustCECPQ2bKeyShare",
config: Config{
MinVersion: VersionTLS13,
Bugs: ProtocolBugs{
ExpectedKeyShares: []CurveID{CurveCECPQ2b, CurveX25519},
},
},
flags: []string{
"-curves", strconv.Itoa(int(CurveCECPQ2b)),
"-curves", strconv.Itoa(int(CurveX25519)),
"-expect-curve-id", strconv.Itoa(int(CurveCECPQ2b)),
},
})
// ... but only if CECPQ2b is listed first.
testCases = append(testCases, testCase{
name: "CECPQ2bKeyShareNotIncludedSecond",
config: Config{
MinVersion: VersionTLS13,
Bugs: ProtocolBugs{
ExpectedKeyShares: []CurveID{CurveX25519},
},
},
flags: []string{
"-curves", strconv.Itoa(int(CurveX25519)),
"-curves", strconv.Itoa(int(CurveCECPQ2b)),
"-expect-curve-id", strconv.Itoa(int(CurveX25519)),
},
})
// If CECPQ2 is the only configured curve, the key share is sent.
testCases = append(testCases, testCase{
name: "JustConfiguringCECPQ2Works",
@ -11080,21 +11003,6 @@ func addCurveTests() {
},
})
// If CECPQ2b is the only configured curve, the key share is sent.
testCases = append(testCases, testCase{
name: "JustConfiguringCECPQ2bWorks",
config: Config{
MinVersion: VersionTLS13,
Bugs: ProtocolBugs{
ExpectedKeyShares: []CurveID{CurveCECPQ2b},
},
},
flags: []string{
"-curves", strconv.Itoa(int(CurveCECPQ2b)),
"-expect-curve-id", strconv.Itoa(int(CurveCECPQ2b)),
},
})
// As a server, CECPQ2 is not yet supported by default.
testCases = append(testCases, testCase{
testType: serverTest,
@ -11109,21 +11017,6 @@ func addCurveTests() {
"-expect-curve-id", strconv.Itoa(int(CurveX25519)),
},
})
// As a server, CECPQ2b is not yet supported by default.
testCases = append(testCases, testCase{
testType: serverTest,
name: "CECPQ2bNotEnabledByDefaultForAServer",
config: Config{
MinVersion: VersionTLS13,
CurvePreferences: []CurveID{CurveCECPQ2b, CurveX25519},
DefaultCurves: []CurveID{CurveCECPQ2b},
},
flags: []string{
"-server-preference",
"-expect-curve-id", strconv.Itoa(int(CurveX25519)),
},
})
}
func addTLS13RecordTests() {
@ -14049,21 +13942,6 @@ func addTLS13CipherPreferenceTests() {
},
})
// CECPQ2b prefers 256-bit ciphers but will use AES-128 if there's nothing else.
testCases = append(testCases, testCase{
testType: serverTest,
name: "TLS13-CipherPreference-CECPQ2b-AES128Only",
config: Config{
MaxVersion: VersionTLS13,
CipherSuites: []uint16{
TLS_AES_128_GCM_SHA256,
},
},
flags: []string{
"-curves", strconv.Itoa(int(CurveCECPQ2b)),
},
})
// When a 256-bit cipher is offered, even if not in first place, it should be
// picked.
testCases = append(testCases, testCase{
@ -14098,40 +13976,6 @@ func addTLS13CipherPreferenceTests() {
expectedCipher: TLS_AES_128_GCM_SHA256,
})
// When a 256-bit cipher is offered, even if not in first place, it should be
// picked.
testCases = append(testCases, testCase{
testType: serverTest,
name: "TLS13-CipherPreference-CECPQ2b-AES256Preferred",
config: Config{
MaxVersion: VersionTLS13,
CipherSuites: []uint16{
TLS_AES_128_GCM_SHA256,
TLS_AES_256_GCM_SHA384,
},
},
flags: []string{
"-curves", strconv.Itoa(int(CurveCECPQ2b)),
},
expectedCipher: TLS_AES_256_GCM_SHA384,
})
// ... but when CECPQ2b isn't being used, the client's preference controls.
testCases = append(testCases, testCase{
testType: serverTest,
name: "TLS13-CipherPreference-CECPQ2b-AES128PreferredOtherwise",
config: Config{
MaxVersion: VersionTLS13,
CipherSuites: []uint16{
TLS_AES_128_GCM_SHA256,
TLS_AES_256_GCM_SHA384,
},
},
flags: []string{
"-curves", strconv.Itoa(int(CurveX25519)),
},
expectedCipher: TLS_AES_128_GCM_SHA256,
})
// Test that CECPQ2 continues to honor AES vs ChaCha20 logic.
testCases = append(testCases, testCase{
testType: serverTest,
@ -14167,42 +14011,6 @@ func addTLS13CipherPreferenceTests() {
"-expect-cipher-no-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
},
})
// Test that CECPQ2b continues to honor AES vs ChaCha20 logic.
testCases = append(testCases, testCase{
testType: serverTest,
name: "TLS13-CipherPreference-CECPQ2b-AES128-ChaCha20-AES256",
config: Config{
MaxVersion: VersionTLS13,
CipherSuites: []uint16{
TLS_AES_128_GCM_SHA256,
TLS_CHACHA20_POLY1305_SHA256,
TLS_AES_256_GCM_SHA384,
},
},
flags: []string{
"-curves", strconv.Itoa(int(CurveCECPQ2b)),
"-expect-cipher-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
"-expect-cipher-no-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
},
})
testCases = append(testCases, testCase{
testType: serverTest,
name: "TLS13-CipherPreference-CECPQ2b-AES128-AES256-ChaCha20",
config: Config{
MaxVersion: VersionTLS13,
CipherSuites: []uint16{
TLS_AES_128_GCM_SHA256,
TLS_AES_256_GCM_SHA384,
TLS_CHACHA20_POLY1305_SHA256,
},
},
flags: []string{
"-curves", strconv.Itoa(int(CurveCECPQ2b)),
"-expect-cipher-aes", strconv.Itoa(int(TLS_AES_256_GCM_SHA384)),
"-expect-cipher-no-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
},
})
}
func addPeekTests() {

View File

@ -1,374 +0,0 @@
// Copyright (c) 2019, Cloudflare Inc.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package sike
import (
"math/bits"
)
// Compute z = x + y (mod 2*p).
func fpAddRdc(z, x, y *Fp) {
var carry uint64
// z=x+y % p
for i := 0; i < FP_WORDS; i++ {
z[i], carry = bits.Add64(x[i], y[i], carry)
}
// z = z - pX2
carry = 0
for i := 0; i < FP_WORDS; i++ {
z[i], carry = bits.Sub64(z[i], pX2[i], carry)
}
// if z<0 add pX2 back
mask := uint64(0 - carry)
carry = 0
for i := 0; i < FP_WORDS; i++ {
z[i], carry = bits.Add64(z[i], pX2[i]&mask, carry)
}
}
// Compute z = x - y (mod 2*p).
func fpSubRdc(z, x, y *Fp) {
var borrow uint64
// z = z - pX2
for i := 0; i < FP_WORDS; i++ {
z[i], borrow = bits.Sub64(x[i], y[i], borrow)
}
// if z<0 add pX2 back
mask := uint64(0 - borrow)
borrow = 0
for i := 0; i < FP_WORDS; i++ {
z[i], borrow = bits.Add64(z[i], pX2[i]&mask, borrow)
}
}
// Reduce a field element in [0, 2*p) to one in [0,p).
func fpRdcP(x *Fp) {
var borrow, mask uint64
for i := 0; i < FP_WORDS; i++ {
x[i], borrow = bits.Sub64(x[i], p[i], borrow)
}
// Sets all bits if borrow = 1
mask = 0 - borrow
borrow = 0
for i := 0; i < FP_WORDS; i++ {
x[i], borrow = bits.Add64(x[i], p[i]&mask, borrow)
}
}
// Implementation doesn't actually depend on a prime field.
func fpSwapCond(x, y *Fp, mask uint8) {
if mask != 0 {
var tmp Fp
copy(tmp[:], y[:])
copy(y[:], x[:])
copy(x[:], tmp[:])
}
}
// Compute z = x * y.
func fpMul(z *FpX2, x, y *Fp) {
var carry, t, u, v uint64
var hi, lo uint64
for i := uint64(0); i < FP_WORDS; i++ {
for j := uint64(0); j <= i; j++ {
hi, lo = bits.Mul64(x[j], y[i-j])
v, carry = bits.Add64(lo, v, 0)
u, carry = bits.Add64(hi, u, carry)
t += carry
}
z[i] = v
v = u
u = t
t = 0
}
for i := FP_WORDS; i < (2*FP_WORDS)-1; i++ {
for j := i - FP_WORDS + 1; j < FP_WORDS; j++ {
hi, lo = bits.Mul64(x[j], y[i-j])
v, carry = bits.Add64(lo, v, 0)
u, carry = bits.Add64(hi, u, carry)
t += carry
}
z[i] = v
v = u
u = t
t = 0
}
z[2*FP_WORDS-1] = v
}
// Perform Montgomery reduction: set z = x R^{-1} (mod 2*p)
// with R=2^512. Destroys the input value.
func fpMontRdc(z *Fp, x *FpX2) {
var carry, t, u, v uint64
var hi, lo uint64
var count int
count = 3 // number of 0 digits in the least significat part of p + 1
for i := 0; i < FP_WORDS; i++ {
for j := 0; j < i; j++ {
if j < (i - count + 1) {
hi, lo = bits.Mul64(z[j], p1[i-j])
v, carry = bits.Add64(lo, v, 0)
u, carry = bits.Add64(hi, u, carry)
t += carry
}
}
v, carry = bits.Add64(v, x[i], 0)
u, carry = bits.Add64(u, 0, carry)
t += carry
z[i] = v
v = u
u = t
t = 0
}
for i := FP_WORDS; i < 2*FP_WORDS-1; i++ {
if count > 0 {
count--
}
for j := i - FP_WORDS + 1; j < FP_WORDS; j++ {
if j < (FP_WORDS - count) {
hi, lo = bits.Mul64(z[j], p1[i-j])
v, carry = bits.Add64(lo, v, 0)
u, carry = bits.Add64(hi, u, carry)
t += carry
}
}
v, carry = bits.Add64(v, x[i], 0)
u, carry = bits.Add64(u, 0, carry)
t += carry
z[i-FP_WORDS] = v
v = u
u = t
t = 0
}
v, carry = bits.Add64(v, x[2*FP_WORDS-1], 0)
z[FP_WORDS-1] = v
}
// Compute z = x + y, without reducing mod p.
func fp2Add(z, x, y *FpX2) {
var carry uint64
for i := 0; i < 2*FP_WORDS; i++ {
z[i], carry = bits.Add64(x[i], y[i], carry)
}
}
// Compute z = x - y, without reducing mod p.
func fp2Sub(z, x, y *FpX2) {
var borrow, mask uint64
for i := 0; i < 2*FP_WORDS; i++ {
z[i], borrow = bits.Sub64(x[i], y[i], borrow)
}
// Sets all bits if borrow = 1
mask = 0 - borrow
borrow = 0
for i := FP_WORDS; i < 2*FP_WORDS; i++ {
z[i], borrow = bits.Add64(z[i], p[i-FP_WORDS]&mask, borrow)
}
}
// Montgomery multiplication. Input values must be already
// in Montgomery domain.
func fpMulRdc(dest, lhs, rhs *Fp) {
a := lhs // = a*R
b := rhs // = b*R
var ab FpX2
fpMul(&ab, a, b) // = a*b*R*R
fpMontRdc(dest, &ab) // = a*b*R mod p
}
// Set dest = x^((p-3)/4). If x is square, this is 1/sqrt(x).
// Uses variation of sliding-window algorithm from with window size
// of 5 and least to most significant bit sliding (left-to-right)
// See HAC 14.85 for general description.
//
// Allowed to overlap x with dest.
// All values in Montgomery domains
// Set dest = x^(2^k), for k >= 1, by repeated squarings.
func p34(dest, x *Fp) {
var lookup [16]Fp
// This performs sum(powStrategy) + 1 squarings and len(lookup) + len(mulStrategy)
// multiplications.
powStrategy := []uint8{
0x03, 0x0A, 0x07, 0x05, 0x06, 0x05, 0x03, 0x08, 0x04, 0x07,
0x05, 0x06, 0x04, 0x05, 0x09, 0x06, 0x03, 0x0B, 0x05, 0x05,
0x02, 0x08, 0x04, 0x07, 0x07, 0x08, 0x05, 0x06, 0x04, 0x08,
0x05, 0x02, 0x0A, 0x06, 0x05, 0x04, 0x08, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x01}
mulStrategy := []uint8{
0x02, 0x0F, 0x09, 0x08, 0x0E, 0x0C, 0x02, 0x08, 0x05, 0x0F,
0x08, 0x0F, 0x06, 0x06, 0x03, 0x02, 0x00, 0x0A, 0x09, 0x0D,
0x01, 0x0C, 0x03, 0x07, 0x01, 0x0A, 0x08, 0x0B, 0x02, 0x0F,
0x0E, 0x01, 0x0B, 0x0C, 0x0E, 0x03, 0x0B, 0x0F, 0x0F, 0x0F,
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00}
initialMul := uint8(8)
// Precompute lookup table of odd multiples of x for window
// size k=5.
var xx Fp
fpMulRdc(&xx, x, x)
lookup[0] = *x
for i := 1; i < 16; i++ {
fpMulRdc(&lookup[i], &lookup[i-1], &xx)
}
// Now lookup = {x, x^3, x^5, ... }
// so that lookup[i] = x^{2*i + 1}
// so that lookup[k/2] = x^k, for odd k
*dest = lookup[initialMul]
for i := uint8(0); i < uint8(len(powStrategy)); i++ {
fpMulRdc(dest, dest, dest)
for j := uint8(1); j < powStrategy[i]; j++ {
fpMulRdc(dest, dest, dest)
}
fpMulRdc(dest, dest, &lookup[mulStrategy[i]])
}
}
func add(dest, lhs, rhs *Fp2) {
fpAddRdc(&dest.A, &lhs.A, &rhs.A)
fpAddRdc(&dest.B, &lhs.B, &rhs.B)
}
func sub(dest, lhs, rhs *Fp2) {
fpSubRdc(&dest.A, &lhs.A, &rhs.A)
fpSubRdc(&dest.B, &lhs.B, &rhs.B)
}
func mul(dest, lhs, rhs *Fp2) {
// Let (a,b,c,d) = (lhs.a,lhs.b,rhs.a,rhs.b).
a := &lhs.A
b := &lhs.B
c := &rhs.A
d := &rhs.B
// We want to compute
//
// (a + bi)*(c + di) = (a*c - b*d) + (a*d + b*c)i
//
// Use Karatsuba's trick: note that
//
// (b - a)*(c - d) = (b*c + a*d) - a*c - b*d
//
// so (a*d + b*c) = (b-a)*(c-d) + a*c + b*d.
var ac, bd FpX2
fpMul(&ac, a, c) // = a*c*R*R
fpMul(&bd, b, d) // = b*d*R*R
var b_minus_a, c_minus_d Fp
fpSubRdc(&b_minus_a, b, a) // = (b-a)*R
fpSubRdc(&c_minus_d, c, d) // = (c-d)*R
var ad_plus_bc FpX2
fpMul(&ad_plus_bc, &b_minus_a, &c_minus_d) // = (b-a)*(c-d)*R*R
fp2Add(&ad_plus_bc, &ad_plus_bc, &ac) // = ((b-a)*(c-d) + a*c)*R*R
fp2Add(&ad_plus_bc, &ad_plus_bc, &bd) // = ((b-a)*(c-d) + a*c + b*d)*R*R
fpMontRdc(&dest.B, &ad_plus_bc) // = (a*d + b*c)*R mod p
var ac_minus_bd FpX2
fp2Sub(&ac_minus_bd, &ac, &bd) // = (a*c - b*d)*R*R
fpMontRdc(&dest.A, &ac_minus_bd) // = (a*c - b*d)*R mod p
}
func inv(dest, x *Fp2) {
var a2PlusB2 Fp
var asq, bsq FpX2
var ac FpX2
var minusB Fp
var minusBC FpX2
a := &x.A
b := &x.B
// We want to compute
//
// 1 1 (a - bi) (a - bi)
// -------- = -------- -------- = -----------
// (a + bi) (a + bi) (a - bi) (a^2 + b^2)
//
// Letting c = 1/(a^2 + b^2), this is
//
// 1/(a+bi) = a*c - b*ci.
fpMul(&asq, a, a) // = a*a*R*R
fpMul(&bsq, b, b) // = b*b*R*R
fp2Add(&asq, &asq, &bsq) // = (a^2 + b^2)*R*R
fpMontRdc(&a2PlusB2, &asq) // = (a^2 + b^2)*R mod p
// Now a2PlusB2 = a^2 + b^2
inv := a2PlusB2
fpMulRdc(&inv, &a2PlusB2, &a2PlusB2)
p34(&inv, &inv)
fpMulRdc(&inv, &inv, &inv)
fpMulRdc(&inv, &inv, &a2PlusB2)
fpMul(&ac, a, &inv)
fpMontRdc(&dest.A, &ac)
fpSubRdc(&minusB, &minusB, b)
fpMul(&minusBC, &minusB, &inv)
fpMontRdc(&dest.B, &minusBC)
}
func sqr(dest, x *Fp2) {
var a2, aPlusB, aMinusB Fp
var a2MinB2, ab2 FpX2
a := &x.A
b := &x.B
// (a + bi)*(a + bi) = (a^2 - b^2) + 2abi.
fpAddRdc(&a2, a, a) // = a*R + a*R = 2*a*R
fpAddRdc(&aPlusB, a, b) // = a*R + b*R = (a+b)*R
fpSubRdc(&aMinusB, a, b) // = a*R - b*R = (a-b)*R
fpMul(&a2MinB2, &aPlusB, &aMinusB) // = (a+b)*(a-b)*R*R = (a^2 - b^2)*R*R
fpMul(&ab2, &a2, b) // = 2*a*b*R*R
fpMontRdc(&dest.A, &a2MinB2) // = (a^2 - b^2)*R mod p
fpMontRdc(&dest.B, &ab2) // = 2*a*b*R mod p
}
// In case choice == 1, performs following swap in constant time:
// xPx <-> xQx
// xPz <-> xQz
// Otherwise returns xPx, xPz, xQx, xQz unchanged
func condSwap(xPx, xPz, xQx, xQz *Fp2, choice uint8) {
fpSwapCond(&xPx.A, &xQx.A, choice)
fpSwapCond(&xPx.B, &xQx.B, choice)
fpSwapCond(&xPz.A, &xQz.A, choice)
fpSwapCond(&xPz.B, &xQz.B, choice)
}

View File

@ -1,317 +0,0 @@
// Copyright (c) 2019, Cloudflare Inc.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package sike
// I keep it bool in order to be able to apply logical NOT
type KeyVariant uint
// Representation of an element of the base field F_p.
//
// No particular meaning is assigned to the representation -- it could represent
// an element in Montgomery form, or not. Tracking the meaning of the field
// element is left to higher types.
type Fp [FP_WORDS]uint64
// Represents an intermediate product of two elements of the base field F_p.
type FpX2 [2 * FP_WORDS]uint64
// Represents an element of the extended field Fp^2 = Fp(x+i)
type Fp2 struct {
A Fp
B Fp
}
type DomainParams struct {
// P, Q and R=P-Q base points
Affine_P, Affine_Q, Affine_R Fp2
// Size of a compuatation strategy for x-torsion group
IsogenyStrategy []uint32
// Max size of secret key for x-torsion group
SecretBitLen uint
// Max size of secret key for x-torsion group
SecretByteLen uint
}
type SidhParams struct {
Id uint8
// Bytelen of P
Bytelen int
// The public key size, in bytes.
PublicKeySize int
// The shared secret size, in bytes.
SharedSecretSize int
// Defines A,C constant for starting curve Cy^2 = x^3 + Ax^2 + x
InitCurve ProjectiveCurveParameters
// 2- and 3-torsion group parameter definitions
A, B DomainParams
// Precomputed 1/2 in the Fp2 in Montgomery domain
HalfFp2 Fp2
// Precomputed identity element in the Fp2 in Montgomery domain
OneFp2 Fp2
// Length of SIKE secret message. Must be one of {24,32,40},
// depending on size of prime field used (see [SIKE], 1.4 and 5.1)
MsgLen int
// Length of SIKE ephemeral KEM key (see [SIKE], 1.4 and 5.1)
KemSize int
// Size of a ciphertext returned by encapsulation in bytes
CiphertextSize int
}
// Stores curve projective parameters equivalent to A/C. Meaning of the
// values depends on the context. When working with isogenies over
// subgroup that are powers of:
// * three then (A:C) ~ (A+2C:A-2C)
// * four then (A:C) ~ (A+2C: 4C)
// See Appendix A of SIKE for more details
type CurveCoefficientsEquiv struct {
A Fp2
C Fp2
}
// A point on the projective line P^1(F_{p^2}).
//
// This represents a point on the Kummer line of a Montgomery curve. The
// curve is specified by a ProjectiveCurveParameters struct.
type ProjectivePoint struct {
X Fp2
Z Fp2
}
// Base type for public and private key. Used mainly to carry domain
// parameters.
type key struct {
// Domain parameters of the algorithm to be used with a key
params *SidhParams
// Flag indicates whether corresponds to 2-, 3-torsion group or SIKE
keyVariant KeyVariant
}
// Defines operations on private key
type PrivateKey struct {
key
// Secret key
Scalar []byte
// Used only by KEM
S []byte
}
// Defines operations on public key
type PublicKey struct {
key
affine_xP Fp2
affine_xQ Fp2
affine_xQmP Fp2
}
// A point on the projective line P^1(F_{p^2}).
//
// This is used to work projectively with the curve coefficients.
type ProjectiveCurveParameters struct {
A Fp2
C Fp2
}
const (
// First 2 bits identify SIDH variant third bit indicates
// whether key is a SIKE variant (set) or SIDH (not set)
// 001 - SIDH: corresponds to 2-torsion group
KeyVariant_SIDH_A KeyVariant = 1 << 0
// 010 - SIDH: corresponds to 3-torsion group
KeyVariant_SIDH_B = 1 << 1
// 110 - SIKE
KeyVariant_SIKE = 1<<2 | KeyVariant_SIDH_B
// Number of uint64 limbs used to store field element
FP_WORDS = 7
)
// Used internally by this package
// -------------------------------
var (
p = Fp{
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFDC1767AE2FFFFFF,
0x7BC65C783158AEA3, 0x6CFC5FD681C52056, 0x2341F27177344,
}
// 2*p434
pX2 = Fp{
0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFB82ECF5C5FFFFFF,
0xF78CB8F062B15D47, 0xD9F8BFAD038A40AC, 0x4683E4E2EE688,
}
// p434 + 1
p1 = Fp{
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0xFDC1767AE3000000,
0x7BC65C783158AEA3, 0x6CFC5FD681C52056, 0x0002341F27177344,
}
// R^2=(2^448)^2 mod p
R2 = Fp{
0x28E55B65DCD69B30, 0xACEC7367768798C2, 0xAB27973F8311688D, 0x175CC6AF8D6C7C0B,
0xABCD92BF2DDE347E, 0x69E16A61C7686D9A, 0x000025A89BCDD12A,
}
// 1/2 * R mod p
half = Fp2{
A: Fp{
0x0000000000003A16, 0x0000000000000000, 0x0000000000000000, 0x5C87FA027E000000,
0x6C00D27DAACFD66A, 0x74992A2A2FBBA086, 0x0000767753DE976D},
}
// 1*R mod p
one = Fp2{
A: Fp{
0x000000000000742C, 0x0000000000000000, 0x0000000000000000, 0xB90FF404FC000000,
0xD801A4FB559FACD4, 0xE93254545F77410C, 0x0000ECEEA7BD2EDA},
}
// 6*R mod p
six = Fp2{
A: Fp{
0x000000000002B90A, 0x0000000000000000, 0x0000000000000000, 0x5ADCCB2822000000,
0x187D24F39F0CAFB4, 0x9D353A4D394145A0, 0x00012559A0403298},
}
Params SidhParams
)
func init() {
Params = SidhParams{
// SIDH public key byte size.
PublicKeySize: 330,
// SIDH shared secret byte size.
SharedSecretSize: 110,
InitCurve: ProjectiveCurveParameters{
A: six,
C: one,
},
A: DomainParams{
// The x-coordinate of PA
Affine_P: Fp2{
A: Fp{
0x05ADF455C5C345BF, 0x91935C5CC767AC2B, 0xAFE4E879951F0257, 0x70E792DC89FA27B1,
0xF797F526BB48C8CD, 0x2181DB6131AF621F, 0x00000A1C08B1ECC4,
},
B: Fp{
0x74840EB87CDA7788, 0x2971AA0ECF9F9D0B, 0xCB5732BDF41715D5, 0x8CD8E51F7AACFFAA,
0xA7F424730D7E419F, 0xD671EB919A179E8C, 0x0000FFA26C5A924A,
},
},
// The x-coordinate of QA
Affine_Q: Fp2{
A: Fp{
0xFEC6E64588B7273B, 0xD2A626D74CBBF1C6, 0xF8F58F07A78098C7, 0xE23941F470841B03,
0x1B63EDA2045538DD, 0x735CFEB0FFD49215, 0x0001C4CB77542876,
},
B: Fp{
0xADB0F733C17FFDD6, 0x6AFFBD037DA0A050, 0x680EC43DB144E02F, 0x1E2E5D5FF524E374,
0xE2DDA115260E2995, 0xA6E4B552E2EDE508, 0x00018ECCDDF4B53E,
},
},
// The x-coordinate of RA = PA-QA
Affine_R: Fp2{
A: Fp{
0x01BA4DB518CD6C7D, 0x2CB0251FE3CC0611, 0x259B0C6949A9121B, 0x60E17AC16D2F82AD,
0x3AA41F1CE175D92D, 0x413FBE6A9B9BC4F3, 0x00022A81D8D55643,
},
B: Fp{
0xB8ADBC70FC82E54A, 0xEF9CDDB0D5FADDED, 0x5820C734C80096A0, 0x7799994BAA96E0E4,
0x044961599E379AF8, 0xDB2B94FBF09F27E2, 0x0000B87FC716C0C6,
},
},
// Max size of secret key for 2-torsion group, corresponds to 2^e2 - 1
SecretBitLen: 216,
// SecretBitLen in bytes.
SecretByteLen: 27,
// 2-torsion group computation strategy
IsogenyStrategy: []uint32{
0x30, 0x1C, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01,
0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x08, 0x04,
0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01,
0x02, 0x01, 0x01, 0x0D, 0x07, 0x04, 0x02, 0x01, 0x01, 0x02,
0x01, 0x01, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x05, 0x04,
0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
0x15, 0x0C, 0x07, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x05, 0x03, 0x02, 0x01,
0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x09, 0x05, 0x03,
0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x04,
0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01},
},
B: DomainParams{
// The x-coordinate of PB
Affine_P: Fp2{
A: Fp{
0x6E5497556EDD48A3, 0x2A61B501546F1C05, 0xEB919446D049887D, 0x5864A4A69D450C4F,
0xB883F276A6490D2B, 0x22CC287022D5F5B9, 0x0001BED4772E551F,
},
B: Fp{
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
},
},
// The x-coordinate of QB
Affine_Q: Fp2{
A: Fp{
0xFAE2A3F93D8B6B8E, 0x494871F51700FE1C, 0xEF1A94228413C27C, 0x498FF4A4AF60BD62,
0xB00AD2A708267E8A, 0xF4328294E017837F, 0x000034080181D8AE,
},
B: Fp{
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
},
},
// The x-coordinate of RB = PB - QB
Affine_R: Fp2{
A: Fp{
0x283B34FAFEFDC8E4, 0x9208F44977C3E647, 0x7DEAE962816F4E9A, 0x68A2BA8AA262EC9D,
0x8176F112EA43F45B, 0x02106D022634F504, 0x00007E8A50F02E37,
},
B: Fp{
0xB378B7C1DA22CCB1, 0x6D089C99AD1D9230, 0xEBE15711813E2369, 0x2B35A68239D48A53,
0x445F6FD138407C93, 0xBEF93B29A3F6B54B, 0x000173FA910377D3,
},
},
// Size of secret key for 3-torsion group, corresponds to log_2(3^e3) - 1.
SecretBitLen: 217,
// SecretBitLen in bytes.
SecretByteLen: 28,
// 3-torsion group computation strategy
IsogenyStrategy: []uint32{
0x42, 0x21, 0x11, 0x09, 0x05, 0x03, 0x02, 0x01, 0x01, 0x01,
0x01, 0x02, 0x01, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x01,
0x02, 0x01, 0x01, 0x08, 0x04, 0x02, 0x01, 0x01, 0x01, 0x02,
0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x10,
0x08, 0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04,
0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x08, 0x04, 0x02, 0x01,
0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01,
0x01, 0x20, 0x10, 0x08, 0x04, 0x03, 0x01, 0x01, 0x01, 0x01,
0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02,
0x01, 0x01, 0x02, 0x01, 0x01, 0x10, 0x08, 0x04, 0x02, 0x01,
0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01,
0x01, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04,
0x02, 0x01, 0x01, 0x02, 0x01, 0x01},
},
OneFp2: one,
HalfFp2: half,
MsgLen: 16,
// SIKEp434 provides 128 bit of classical security ([SIKE], 5.1)
KemSize: 16,
// ceil(434+7/8)
Bytelen: 55,
CiphertextSize: 16 + 330,
}
}

View File

@ -1,422 +0,0 @@
// Copyright (c) 2019, Cloudflare Inc.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package sike
// Interface for working with isogenies.
type isogeny interface {
// Given a torsion point on a curve computes isogenous curve.
// Returns curve coefficients (A:C), so that E_(A/C) = E_(A/C)/<P>,
// where P is a provided projective point. Sets also isogeny constants
// that are needed for isogeny evaluation.
GenerateCurve(*ProjectivePoint) CurveCoefficientsEquiv
// Evaluates isogeny at caller provided point. Requires isogeny curve constants
// to be earlier computed by GenerateCurve.
EvaluatePoint(*ProjectivePoint) ProjectivePoint
}
// Stores isogeny 3 curve constants
type isogeny3 struct {
K1 Fp2
K2 Fp2
}
// Stores isogeny 4 curve constants
type isogeny4 struct {
isogeny3
K3 Fp2
}
// Constructs isogeny3 objects
func NewIsogeny3() isogeny {
return &isogeny3{}
}
// Constructs isogeny4 objects
func NewIsogeny4() isogeny {
return &isogeny4{}
}
// Helper function for RightToLeftLadder(). Returns A+2C / 4.
func calcAplus2Over4(cparams *ProjectiveCurveParameters) (ret Fp2) {
var tmp Fp2
// 2C
add(&tmp, &cparams.C, &cparams.C)
// A+2C
add(&ret, &cparams.A, &tmp)
// 1/4C
add(&tmp, &tmp, &tmp)
inv(&tmp, &tmp)
// A+2C/4C
mul(&ret, &ret, &tmp)
return
}
// Converts values in x.A and x.B to Montgomery domain
// x.A = x.A * R mod p
// x.B = x.B * R mod p
// Performs v = v*R^2*R^(-1) mod p, for both x.A and x.B
func toMontDomain(x *Fp2) {
var aRR FpX2
// convert to montgomery domain
fpMul(&aRR, &x.A, &R2) // = a*R*R
fpMontRdc(&x.A, &aRR) // = a*R mod p
fpMul(&aRR, &x.B, &R2)
fpMontRdc(&x.B, &aRR)
}
// Converts values in x.A and x.B from Montgomery domain
// a = x.A mod p
// b = x.B mod p
//
// After returning from the call x is not modified.
func fromMontDomain(x *Fp2, out *Fp2) {
var aR FpX2
// convert from montgomery domain
copy(aR[:], x.A[:])
fpMontRdc(&out.A, &aR) // = a mod p in [0, 2p)
fpRdcP(&out.A) // = a mod p in [0, p)
for i := range aR {
aR[i] = 0
}
copy(aR[:], x.B[:])
fpMontRdc(&out.B, &aR)
fpRdcP(&out.B)
}
// Computes j-invariant for a curve y2=x3+A/Cx+x with A,C in F_(p^2). Result
// is returned in 'j'. Implementation corresponds to Algorithm 9 from SIKE.
func Jinvariant(cparams *ProjectiveCurveParameters, j *Fp2) {
var t0, t1 Fp2
sqr(j, &cparams.A) // j = A^2
sqr(&t1, &cparams.C) // t1 = C^2
add(&t0, &t1, &t1) // t0 = t1 + t1
sub(&t0, j, &t0) // t0 = j - t0
sub(&t0, &t0, &t1) // t0 = t0 - t1
sub(j, &t0, &t1) // t0 = t0 - t1
sqr(&t1, &t1) // t1 = t1^2
mul(j, j, &t1) // j = j * t1
add(&t0, &t0, &t0) // t0 = t0 + t0
add(&t0, &t0, &t0) // t0 = t0 + t0
sqr(&t1, &t0) // t1 = t0^2
mul(&t0, &t0, &t1) // t0 = t0 * t1
add(&t0, &t0, &t0) // t0 = t0 + t0
add(&t0, &t0, &t0) // t0 = t0 + t0
inv(j, j) // j = 1/j
mul(j, &t0, j) // j = t0 * j
}
// Given affine points x(P), x(Q) and x(Q-P) in a extension field F_{p^2}, function
// recorvers projective coordinate A of a curve. This is Algorithm 10 from SIKE.
func RecoverCoordinateA(curve *ProjectiveCurveParameters, xp, xq, xr *Fp2) {
var t0, t1 Fp2
add(&t1, xp, xq) // t1 = Xp + Xq
mul(&t0, xp, xq) // t0 = Xp * Xq
mul(&curve.A, xr, &t1) // A = X(q-p) * t1
add(&curve.A, &curve.A, &t0) // A = A + t0
mul(&t0, &t0, xr) // t0 = t0 * X(q-p)
sub(&curve.A, &curve.A, &Params.OneFp2) // A = A - 1
add(&t0, &t0, &t0) // t0 = t0 + t0
add(&t1, &t1, xr) // t1 = t1 + X(q-p)
add(&t0, &t0, &t0) // t0 = t0 + t0
sqr(&curve.A, &curve.A) // A = A^2
inv(&t0, &t0) // t0 = 1/t0
mul(&curve.A, &curve.A, &t0) // A = A * t0
sub(&curve.A, &curve.A, &t1) // A = A - t1
}
// Computes equivalence (A:C) ~ (A+2C : A-2C)
func CalcCurveParamsEquiv3(cparams *ProjectiveCurveParameters) CurveCoefficientsEquiv {
var coef CurveCoefficientsEquiv
var c2 Fp2
add(&c2, &cparams.C, &cparams.C)
// A24p = A+2*C
add(&coef.A, &cparams.A, &c2)
// A24m = A-2*C
sub(&coef.C, &cparams.A, &c2)
return coef
}
// Computes equivalence (A:C) ~ (A+2C : 4C)
func CalcCurveParamsEquiv4(cparams *ProjectiveCurveParameters) CurveCoefficientsEquiv {
var coefEq CurveCoefficientsEquiv
add(&coefEq.C, &cparams.C, &cparams.C)
// A24p = A+2C
add(&coefEq.A, &cparams.A, &coefEq.C)
// C24 = 4*C
add(&coefEq.C, &coefEq.C, &coefEq.C)
return coefEq
}
// Recovers (A:C) curve parameters from projectively equivalent (A+2C:A-2C).
func RecoverCurveCoefficients3(cparams *ProjectiveCurveParameters, coefEq *CurveCoefficientsEquiv) {
add(&cparams.A, &coefEq.A, &coefEq.C)
// cparams.A = 2*(A+2C+A-2C) = 4A
add(&cparams.A, &cparams.A, &cparams.A)
// cparams.C = (A+2C-A+2C) = 4C
sub(&cparams.C, &coefEq.A, &coefEq.C)
return
}
// Recovers (A:C) curve parameters from projectively equivalent (A+2C:4C).
func RecoverCurveCoefficients4(cparams *ProjectiveCurveParameters, coefEq *CurveCoefficientsEquiv) {
// cparams.C = (4C)*1/2=2C
mul(&cparams.C, &coefEq.C, &Params.HalfFp2)
// cparams.A = A+2C - 2C = A
sub(&cparams.A, &coefEq.A, &cparams.C)
// cparams.C = 2C * 1/2 = C
mul(&cparams.C, &cparams.C, &Params.HalfFp2)
return
}
// Combined coordinate doubling and differential addition. Takes projective points
// P,Q,Q-P and (A+2C)/4C curve E coefficient. Returns 2*P and P+Q calculated on E.
// Function is used only by RightToLeftLadder. Corresponds to Algorithm 5 of SIKE
func xDbladd(P, Q, QmP *ProjectivePoint, a24 *Fp2) (dblP, PaQ ProjectivePoint) {
var t0, t1, t2 Fp2
xQmP, zQmP := &QmP.X, &QmP.Z
xPaQ, zPaQ := &PaQ.X, &PaQ.Z
x2P, z2P := &dblP.X, &dblP.Z
xP, zP := &P.X, &P.Z
xQ, zQ := &Q.X, &Q.Z
add(&t0, xP, zP) // t0 = Xp+Zp
sub(&t1, xP, zP) // t1 = Xp-Zp
sqr(x2P, &t0) // 2P.X = t0^2
sub(&t2, xQ, zQ) // t2 = Xq-Zq
add(xPaQ, xQ, zQ) // Xp+q = Xq+Zq
mul(&t0, &t0, &t2) // t0 = t0 * t2
mul(z2P, &t1, &t1) // 2P.Z = t1 * t1
mul(&t1, &t1, xPaQ) // t1 = t1 * Xp+q
sub(&t2, x2P, z2P) // t2 = 2P.X - 2P.Z
mul(x2P, x2P, z2P) // 2P.X = 2P.X * 2P.Z
mul(xPaQ, a24, &t2) // Xp+q = A24 * t2
sub(zPaQ, &t0, &t1) // Zp+q = t0 - t1
add(z2P, xPaQ, z2P) // 2P.Z = Xp+q + 2P.Z
add(xPaQ, &t0, &t1) // Xp+q = t0 + t1
mul(z2P, z2P, &t2) // 2P.Z = 2P.Z * t2
sqr(zPaQ, zPaQ) // Zp+q = Zp+q ^ 2
sqr(xPaQ, xPaQ) // Xp+q = Xp+q ^ 2
mul(zPaQ, xQmP, zPaQ) // Zp+q = Xq-p * Zp+q
mul(xPaQ, zQmP, xPaQ) // Xp+q = Zq-p * Xp+q
return
}
// Given the curve parameters, xP = x(P), computes xP = x([2^k]P)
// Safe to overlap xP, x2P.
func Pow2k(xP *ProjectivePoint, params *CurveCoefficientsEquiv, k uint32) {
var t0, t1 Fp2
x, z := &xP.X, &xP.Z
for i := uint32(0); i < k; i++ {
sub(&t0, x, z) // t0 = Xp - Zp
add(&t1, x, z) // t1 = Xp + Zp
sqr(&t0, &t0) // t0 = t0 ^ 2
sqr(&t1, &t1) // t1 = t1 ^ 2
mul(z, &params.C, &t0) // Z2p = C24 * t0
mul(x, z, &t1) // X2p = Z2p * t1
sub(&t1, &t1, &t0) // t1 = t1 - t0
mul(&t0, &params.A, &t1) // t0 = A24+ * t1
add(z, z, &t0) // Z2p = Z2p + t0
mul(z, z, &t1) // Zp = Z2p * t1
}
}
// Given the curve parameters, xP = x(P), and k >= 0, compute xP = x([3^k]P).
//
// Safe to overlap xP, xR.
func Pow3k(xP *ProjectivePoint, params *CurveCoefficientsEquiv, k uint32) {
var t0, t1, t2, t3, t4, t5, t6 Fp2
x, z := &xP.X, &xP.Z
for i := uint32(0); i < k; i++ {
sub(&t0, x, z) // t0 = Xp - Zp
sqr(&t2, &t0) // t2 = t0^2
add(&t1, x, z) // t1 = Xp + Zp
sqr(&t3, &t1) // t3 = t1^2
add(&t4, &t1, &t0) // t4 = t1 + t0
sub(&t0, &t1, &t0) // t0 = t1 - t0
sqr(&t1, &t4) // t1 = t4^2
sub(&t1, &t1, &t3) // t1 = t1 - t3
sub(&t1, &t1, &t2) // t1 = t1 - t2
mul(&t5, &t3, &params.A) // t5 = t3 * A24+
mul(&t3, &t3, &t5) // t3 = t5 * t3
mul(&t6, &t2, &params.C) // t6 = t2 * A24-
mul(&t2, &t2, &t6) // t2 = t2 * t6
sub(&t3, &t2, &t3) // t3 = t2 - t3
sub(&t2, &t5, &t6) // t2 = t5 - t6
mul(&t1, &t2, &t1) // t1 = t2 * t1
add(&t2, &t3, &t1) // t2 = t3 + t1
sqr(&t2, &t2) // t2 = t2^2
mul(x, &t2, &t4) // X3p = t2 * t4
sub(&t1, &t3, &t1) // t1 = t3 - t1
sqr(&t1, &t1) // t1 = t1^2
mul(z, &t1, &t0) // Z3p = t1 * t0
}
}
// Set (y1, y2, y3) = (1/x1, 1/x2, 1/x3).
//
// All xi, yi must be distinct.
func Fp2Batch3Inv(x1, x2, x3, y1, y2, y3 *Fp2) {
var x1x2, t Fp2
mul(&x1x2, x1, x2) // x1*x2
mul(&t, &x1x2, x3) // 1/(x1*x2*x3)
inv(&t, &t)
mul(y1, &t, x2) // 1/x1
mul(y1, y1, x3)
mul(y2, &t, x1) // 1/x2
mul(y2, y2, x3)
mul(y3, &t, &x1x2) // 1/x3
}
// ScalarMul3Pt is a right-to-left point multiplication that given the
// x-coordinate of P, Q and P-Q calculates the x-coordinate of R=Q+[scalar]P.
// nbits must be smaller or equal to len(scalar).
func ScalarMul3Pt(cparams *ProjectiveCurveParameters, P, Q, PmQ *ProjectivePoint, nbits uint, scalar []uint8) ProjectivePoint {
var R0, R2, R1 ProjectivePoint
aPlus2Over4 := calcAplus2Over4(cparams)
R1 = *P
R2 = *PmQ
R0 = *Q
// Iterate over the bits of the scalar, bottom to top
prevBit := uint8(0)
for i := uint(0); i < nbits; i++ {
bit := (scalar[i>>3] >> (i & 7) & 1)
swap := prevBit ^ bit
prevBit = bit
condSwap(&R1.X, &R1.Z, &R2.X, &R2.Z, swap)
R0, R2 = xDbladd(&R0, &R2, &R1, &aPlus2Over4)
}
condSwap(&R1.X, &R1.Z, &R2.X, &R2.Z, prevBit)
return R1
}
// Given a three-torsion point p = x(PB) on the curve E_(A:C), construct the
// three-isogeny phi : E_(A:C) -> E_(A:C)/<P_3> = E_(A':C').
//
// Input: (XP_3: ZP_3), where P_3 has exact order 3 on E_A/C
// Output: * Curve coordinates (A' + 2C', A' - 2C') corresponding to E_A'/C' = A_E/C/<P3>
// * isogeny phi with constants in F_p^2
func (phi *isogeny3) GenerateCurve(p *ProjectivePoint) CurveCoefficientsEquiv {
var t0, t1, t2, t3, t4 Fp2
var coefEq CurveCoefficientsEquiv
var K1, K2 = &phi.K1, &phi.K2
sub(K1, &p.X, &p.Z) // K1 = XP3 - ZP3
sqr(&t0, K1) // t0 = K1^2
add(K2, &p.X, &p.Z) // K2 = XP3 + ZP3
sqr(&t1, K2) // t1 = K2^2
add(&t2, &t0, &t1) // t2 = t0 + t1
add(&t3, K1, K2) // t3 = K1 + K2
sqr(&t3, &t3) // t3 = t3^2
sub(&t3, &t3, &t2) // t3 = t3 - t2
add(&t2, &t1, &t3) // t2 = t1 + t3
add(&t3, &t3, &t0) // t3 = t3 + t0
add(&t4, &t3, &t0) // t4 = t3 + t0
add(&t4, &t4, &t4) // t4 = t4 + t4
add(&t4, &t1, &t4) // t4 = t1 + t4
mul(&coefEq.C, &t2, &t4) // A24m = t2 * t4
add(&t4, &t1, &t2) // t4 = t1 + t2
add(&t4, &t4, &t4) // t4 = t4 + t4
add(&t4, &t0, &t4) // t4 = t0 + t4
mul(&t4, &t3, &t4) // t4 = t3 * t4
sub(&t0, &t4, &coefEq.C) // t0 = t4 - A24m
add(&coefEq.A, &coefEq.C, &t0) // A24p = A24m + t0
return coefEq
}
// Given a 3-isogeny phi and a point pB = x(PB), compute x(QB), the x-coordinate
// of the image QB = phi(PB) of PB under phi : E_(A:C) -> E_(A':C').
//
// The output xQ = x(Q) is then a point on the curve E_(A':C'); the curve
// parameters are returned by the GenerateCurve function used to construct phi.
func (phi *isogeny3) EvaluatePoint(p *ProjectivePoint) ProjectivePoint {
var t0, t1, t2 Fp2
var q ProjectivePoint
var K1, K2 = &phi.K1, &phi.K2
var px, pz = &p.X, &p.Z
add(&t0, px, pz) // t0 = XQ + ZQ
sub(&t1, px, pz) // t1 = XQ - ZQ
mul(&t0, K1, &t0) // t2 = K1 * t0
mul(&t1, K2, &t1) // t1 = K2 * t1
add(&t2, &t0, &t1) // t2 = t0 + t1
sub(&t0, &t1, &t0) // t0 = t1 - t0
sqr(&t2, &t2) // t2 = t2 ^ 2
sqr(&t0, &t0) // t0 = t0 ^ 2
mul(&q.X, px, &t2) // XQ'= XQ * t2
mul(&q.Z, pz, &t0) // ZQ'= ZQ * t0
return q
}
// Given a four-torsion point p = x(PB) on the curve E_(A:C), construct the
// four-isogeny phi : E_(A:C) -> E_(A:C)/<P_4> = E_(A':C').
//
// Input: (XP_4: ZP_4), where P_4 has exact order 4 on E_A/C
// Output: * Curve coordinates (A' + 2C', 4C') corresponding to E_A'/C' = A_E/C/<P4>
// * isogeny phi with constants in F_p^2
func (phi *isogeny4) GenerateCurve(p *ProjectivePoint) CurveCoefficientsEquiv {
var coefEq CurveCoefficientsEquiv
var xp4, zp4 = &p.X, &p.Z
var K1, K2, K3 = &phi.K1, &phi.K2, &phi.K3
sub(K2, xp4, zp4)
add(K3, xp4, zp4)
sqr(K1, zp4)
add(K1, K1, K1)
sqr(&coefEq.C, K1)
add(K1, K1, K1)
sqr(&coefEq.A, xp4)
add(&coefEq.A, &coefEq.A, &coefEq.A)
sqr(&coefEq.A, &coefEq.A)
return coefEq
}
// Given a 4-isogeny phi and a point xP = x(P), compute x(Q), the x-coordinate
// of the image Q = phi(P) of P under phi : E_(A:C) -> E_(A':C').
//
// Input: isogeny returned by GenerateCurve and point q=(Qx,Qz) from E0_A/C
// Output: Corresponding point q from E1_A'/C', where E1 is 4-isogenous to E0
func (phi *isogeny4) EvaluatePoint(p *ProjectivePoint) ProjectivePoint {
var t0, t1 Fp2
var q = *p
var xq, zq = &q.X, &q.Z
var K1, K2, K3 = &phi.K1, &phi.K2, &phi.K3
add(&t0, xq, zq)
sub(&t1, xq, zq)
mul(xq, &t0, K2)
mul(zq, &t1, K3)
mul(&t0, &t0, &t1)
mul(&t0, &t0, K1)
add(&t1, xq, zq)
sub(zq, xq, zq)
sqr(&t1, &t1)
sqr(zq, zq)
add(xq, &t0, &t1)
sub(&t0, zq, &t0)
mul(xq, xq, &t1)
mul(zq, zq, &t0)
return q
}

View File

@ -1,683 +0,0 @@
// Copyright (c) 2019, Cloudflare Inc.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package sike
import (
"crypto/sha256"
"crypto/subtle"
"errors"
"io"
)
// Zeroize Fp2
func zeroize(fp *Fp2) {
// Zeroizing in 2 separated loops tells compiler to
// use fast runtime.memclr()
for i := range fp.A {
fp.A[i] = 0
}
for i := range fp.B {
fp.B[i] = 0
}
}
// Convert the input to wire format.
//
// The output byte slice must be at least 2*bytelen(p) bytes long.
func convFp2ToBytes(output []byte, fp2 *Fp2) {
if len(output) < 2*Params.Bytelen {
panic("output byte slice too short")
}
var a Fp2
fromMontDomain(fp2, &a)
// convert to bytes in little endian form
for i := 0; i < Params.Bytelen; i++ {
// set i = j*8 + k
tmp := i / 8
k := uint64(i % 8)
output[i] = byte(a.A[tmp] >> (8 * k))
output[i+Params.Bytelen] = byte(a.B[tmp] >> (8 * k))
}
}
// Read 2*bytelen(p) bytes into the given ExtensionFieldElement.
//
// It is an error to call this function if the input byte slice is less than 2*bytelen(p) bytes long.
func convBytesToFp2(fp2 *Fp2, input []byte) {
if len(input) < 2*Params.Bytelen {
panic("input byte slice too short")
}
for i := 0; i < Params.Bytelen; i++ {
j := i / 8
k := uint64(i % 8)
fp2.A[j] |= uint64(input[i]) << (8 * k)
fp2.B[j] |= uint64(input[i+Params.Bytelen]) << (8 * k)
}
toMontDomain(fp2)
}
// -----------------------------------------------------------------------------
// Functions for traversing isogeny trees acoording to strategy. Key type 'A' is
//
// Traverses isogeny tree in order to compute xR, xP, xQ and xQmP needed
// for public key generation.
func traverseTreePublicKeyA(curve *ProjectiveCurveParameters, xR, phiP, phiQ, phiR *ProjectivePoint, pub *PublicKey) {
var points = make([]ProjectivePoint, 0, 8)
var indices = make([]int, 0, 8)
var i, sidx int
cparam := CalcCurveParamsEquiv4(curve)
phi := NewIsogeny4()
strat := pub.params.A.IsogenyStrategy
stratSz := len(strat)
for j := 1; j <= stratSz; j++ {
for i <= stratSz-j {
points = append(points, *xR)
indices = append(indices, i)
k := strat[sidx]
sidx++
Pow2k(xR, &cparam, 2*k)
i += int(k)
}
cparam = phi.GenerateCurve(xR)
for k := 0; k < len(points); k++ {
points[k] = phi.EvaluatePoint(&points[k])
}
*phiP = phi.EvaluatePoint(phiP)
*phiQ = phi.EvaluatePoint(phiQ)
*phiR = phi.EvaluatePoint(phiR)
// pop xR from points
*xR, points = points[len(points)-1], points[:len(points)-1]
i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
}
}
// Traverses isogeny tree in order to compute xR needed
// for public key generation.
func traverseTreeSharedKeyA(curve *ProjectiveCurveParameters, xR *ProjectivePoint, pub *PublicKey) {
var points = make([]ProjectivePoint, 0, 8)
var indices = make([]int, 0, 8)
var i, sidx int
cparam := CalcCurveParamsEquiv4(curve)
phi := NewIsogeny4()
strat := pub.params.A.IsogenyStrategy
stratSz := len(strat)
for j := 1; j <= stratSz; j++ {
for i <= stratSz-j {
points = append(points, *xR)
indices = append(indices, i)
k := strat[sidx]
sidx++
Pow2k(xR, &cparam, 2*k)
i += int(k)
}
cparam = phi.GenerateCurve(xR)
for k := 0; k < len(points); k++ {
points[k] = phi.EvaluatePoint(&points[k])
}
// pop xR from points
*xR, points = points[len(points)-1], points[:len(points)-1]
i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
}
}
// Traverses isogeny tree in order to compute xR, xP, xQ and xQmP needed
// for public key generation.
func traverseTreePublicKeyB(curve *ProjectiveCurveParameters, xR, phiP, phiQ, phiR *ProjectivePoint, pub *PublicKey) {
var points = make([]ProjectivePoint, 0, 8)
var indices = make([]int, 0, 8)
var i, sidx int
cparam := CalcCurveParamsEquiv3(curve)
phi := NewIsogeny3()
strat := pub.params.B.IsogenyStrategy
stratSz := len(strat)
for j := 1; j <= stratSz; j++ {
for i <= stratSz-j {
points = append(points, *xR)
indices = append(indices, i)
k := strat[sidx]
sidx++
Pow3k(xR, &cparam, k)
i += int(k)
}
cparam = phi.GenerateCurve(xR)
for k := 0; k < len(points); k++ {
points[k] = phi.EvaluatePoint(&points[k])
}
*phiP = phi.EvaluatePoint(phiP)
*phiQ = phi.EvaluatePoint(phiQ)
*phiR = phi.EvaluatePoint(phiR)
// pop xR from points
*xR, points = points[len(points)-1], points[:len(points)-1]
i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
}
}
// Traverses isogeny tree in order to compute xR, xP, xQ and xQmP needed
// for public key generation.
func traverseTreeSharedKeyB(curve *ProjectiveCurveParameters, xR *ProjectivePoint, pub *PublicKey) {
var points = make([]ProjectivePoint, 0, 8)
var indices = make([]int, 0, 8)
var i, sidx int
cparam := CalcCurveParamsEquiv3(curve)
phi := NewIsogeny3()
strat := pub.params.B.IsogenyStrategy
stratSz := len(strat)
for j := 1; j <= stratSz; j++ {
for i <= stratSz-j {
points = append(points, *xR)
indices = append(indices, i)
k := strat[sidx]
sidx++
Pow3k(xR, &cparam, k)
i += int(k)
}
cparam = phi.GenerateCurve(xR)
for k := 0; k < len(points); k++ {
points[k] = phi.EvaluatePoint(&points[k])
}
// pop xR from points
*xR, points = points[len(points)-1], points[:len(points)-1]
i, indices = int(indices[len(indices)-1]), indices[:len(indices)-1]
}
}
// Generate a public key in the 2-torsion group
func publicKeyGenA(prv *PrivateKey) (pub *PublicKey) {
var xPA, xQA, xRA ProjectivePoint
var xPB, xQB, xRB, xK ProjectivePoint
var invZP, invZQ, invZR Fp2
pub = NewPublicKey(KeyVariant_SIDH_A)
var phi = NewIsogeny4()
// Load points for A
xPA = ProjectivePoint{X: prv.params.A.Affine_P, Z: prv.params.OneFp2}
xQA = ProjectivePoint{X: prv.params.A.Affine_Q, Z: prv.params.OneFp2}
xRA = ProjectivePoint{X: prv.params.A.Affine_R, Z: prv.params.OneFp2}
// Load points for B
xRB = ProjectivePoint{X: prv.params.B.Affine_R, Z: prv.params.OneFp2}
xQB = ProjectivePoint{X: prv.params.B.Affine_Q, Z: prv.params.OneFp2}
xPB = ProjectivePoint{X: prv.params.B.Affine_P, Z: prv.params.OneFp2}
// Find isogeny kernel
xK = ScalarMul3Pt(&pub.params.InitCurve, &xPA, &xQA, &xRA, prv.params.A.SecretBitLen, prv.Scalar)
traverseTreePublicKeyA(&pub.params.InitCurve, &xK, &xPB, &xQB, &xRB, pub)
// Secret isogeny
phi.GenerateCurve(&xK)
xPA = phi.EvaluatePoint(&xPB)
xQA = phi.EvaluatePoint(&xQB)
xRA = phi.EvaluatePoint(&xRB)
Fp2Batch3Inv(&xPA.Z, &xQA.Z, &xRA.Z, &invZP, &invZQ, &invZR)
mul(&pub.affine_xP, &xPA.X, &invZP)
mul(&pub.affine_xQ, &xQA.X, &invZQ)
mul(&pub.affine_xQmP, &xRA.X, &invZR)
return
}
// Generate a public key in the 3-torsion group
func publicKeyGenB(prv *PrivateKey) (pub *PublicKey) {
var xPB, xQB, xRB, xK ProjectivePoint
var xPA, xQA, xRA ProjectivePoint
var invZP, invZQ, invZR Fp2
pub = NewPublicKey(prv.keyVariant)
var phi = NewIsogeny3()
// Load points for B
xRB = ProjectivePoint{X: prv.params.B.Affine_R, Z: prv.params.OneFp2}
xQB = ProjectivePoint{X: prv.params.B.Affine_Q, Z: prv.params.OneFp2}
xPB = ProjectivePoint{X: prv.params.B.Affine_P, Z: prv.params.OneFp2}
// Load points for A
xPA = ProjectivePoint{X: prv.params.A.Affine_P, Z: prv.params.OneFp2}
xQA = ProjectivePoint{X: prv.params.A.Affine_Q, Z: prv.params.OneFp2}
xRA = ProjectivePoint{X: prv.params.A.Affine_R, Z: prv.params.OneFp2}
xK = ScalarMul3Pt(&pub.params.InitCurve, &xPB, &xQB, &xRB, prv.params.B.SecretBitLen, prv.Scalar)
traverseTreePublicKeyB(&pub.params.InitCurve, &xK, &xPA, &xQA, &xRA, pub)
phi.GenerateCurve(&xK)
xPB = phi.EvaluatePoint(&xPA)
xQB = phi.EvaluatePoint(&xQA)
xRB = phi.EvaluatePoint(&xRA)
Fp2Batch3Inv(&xPB.Z, &xQB.Z, &xRB.Z, &invZP, &invZQ, &invZR)
mul(&pub.affine_xP, &xPB.X, &invZP)
mul(&pub.affine_xQ, &xQB.X, &invZQ)
mul(&pub.affine_xQmP, &xRB.X, &invZR)
return
}
// -----------------------------------------------------------------------------
// Key agreement functions
//
// Establishing shared keys in in 2-torsion group
func deriveSecretA(prv *PrivateKey, pub *PublicKey) []byte {
var sharedSecret = make([]byte, pub.params.SharedSecretSize)
var xP, xQ, xQmP ProjectivePoint
var xK ProjectivePoint
var cparam ProjectiveCurveParameters
var phi = NewIsogeny4()
var jInv Fp2
// Recover curve coefficients
RecoverCoordinateA(&cparam, &pub.affine_xP, &pub.affine_xQ, &pub.affine_xQmP)
// C=1
cparam.C = Params.OneFp2
// Find kernel of the morphism
xP = ProjectivePoint{X: pub.affine_xP, Z: pub.params.OneFp2}
xQ = ProjectivePoint{X: pub.affine_xQ, Z: pub.params.OneFp2}
xQmP = ProjectivePoint{X: pub.affine_xQmP, Z: pub.params.OneFp2}
xK = ScalarMul3Pt(&cparam, &xP, &xQ, &xQmP, pub.params.A.SecretBitLen, prv.Scalar)
// Traverse isogeny tree
traverseTreeSharedKeyA(&cparam, &xK, pub)
// Calculate j-invariant on isogeneus curve
c := phi.GenerateCurve(&xK)
RecoverCurveCoefficients4(&cparam, &c)
Jinvariant(&cparam, &jInv)
convFp2ToBytes(sharedSecret, &jInv)
return sharedSecret
}
// Establishing shared keys in in 3-torsion group
func deriveSecretB(prv *PrivateKey, pub *PublicKey) []byte {
var sharedSecret = make([]byte, pub.params.SharedSecretSize)
var xP, xQ, xQmP ProjectivePoint
var xK ProjectivePoint
var cparam ProjectiveCurveParameters
var phi = NewIsogeny3()
var jInv Fp2
// Recover curve A coefficient
RecoverCoordinateA(&cparam, &pub.affine_xP, &pub.affine_xQ, &pub.affine_xQmP)
// C=1
cparam.C = Params.OneFp2
// Find kernel of the morphism
xP = ProjectivePoint{X: pub.affine_xP, Z: pub.params.OneFp2}
xQ = ProjectivePoint{X: pub.affine_xQ, Z: pub.params.OneFp2}
xQmP = ProjectivePoint{X: pub.affine_xQmP, Z: pub.params.OneFp2}
xK = ScalarMul3Pt(&cparam, &xP, &xQ, &xQmP, pub.params.B.SecretBitLen, prv.Scalar)
// Traverse isogeny tree
traverseTreeSharedKeyB(&cparam, &xK, pub)
// Calculate j-invariant on isogeneus curve
c := phi.GenerateCurve(&xK)
RecoverCurveCoefficients3(&cparam, &c)
Jinvariant(&cparam, &jInv)
convFp2ToBytes(sharedSecret, &jInv)
return sharedSecret
}
func encrypt(skA *PrivateKey, pkA, pkB *PublicKey, ptext []byte) ([]byte, error) {
if pkB.keyVariant != KeyVariant_SIKE {
return nil, errors.New("wrong key type")
}
j, err := DeriveSecret(skA, pkB)
if err != nil {
return nil, err
}
if len(ptext) != pkA.params.KemSize {
panic("Implementation error")
}
digest := sha256.Sum256(j)
// Uses truncated digest (first 16-bytes)
for i, _ := range ptext {
digest[i] ^= ptext[i]
}
ret := make([]byte, pkA.Size()+len(ptext))
copy(ret, pkA.Export())
copy(ret[pkA.Size():], digest[:pkA.params.KemSize])
return ret, nil
}
// NewPrivateKey initializes private key.
// Usage of this function guarantees that the object is correctly initialized.
func NewPrivateKey(v KeyVariant) *PrivateKey {
prv := &PrivateKey{key: key{params: &Params, keyVariant: v}}
if (v & KeyVariant_SIDH_A) == KeyVariant_SIDH_A {
prv.Scalar = make([]byte, prv.params.A.SecretByteLen)
} else {
prv.Scalar = make([]byte, prv.params.B.SecretByteLen)
}
if v == KeyVariant_SIKE {
prv.S = make([]byte, prv.params.MsgLen)
}
return prv
}
// NewPublicKey initializes public key.
// Usage of this function guarantees that the object is correctly initialized.
func NewPublicKey(v KeyVariant) *PublicKey {
return &PublicKey{key: key{params: &Params, keyVariant: v}}
}
// Import clears content of the public key currently stored in the structure
// and imports key stored in the byte string. Returns error in case byte string
// size is wrong. Doesn't perform any validation.
func (pub *PublicKey) Import(input []byte) error {
if len(input) != pub.Size() {
return errors.New("sidh: input to short")
}
ssSz := pub.params.SharedSecretSize
convBytesToFp2(&pub.affine_xP, input[0:ssSz])
convBytesToFp2(&pub.affine_xQ, input[ssSz:2*ssSz])
convBytesToFp2(&pub.affine_xQmP, input[2*ssSz:3*ssSz])
return nil
}
// Exports currently stored key. In case structure hasn't been filled with key data
// returned byte string is filled with zeros.
func (pub *PublicKey) Export() []byte {
output := make([]byte, pub.params.PublicKeySize)
ssSz := pub.params.SharedSecretSize
convFp2ToBytes(output[0:ssSz], &pub.affine_xP)
convFp2ToBytes(output[ssSz:2*ssSz], &pub.affine_xQ)
convFp2ToBytes(output[2*ssSz:3*ssSz], &pub.affine_xQmP)
return output
}
// Size returns size of the public key in bytes
func (pub *PublicKey) Size() int {
return pub.params.PublicKeySize
}
// Exports currently stored key. In case structure hasn't been filled with key data
// returned byte string is filled with zeros.
func (prv *PrivateKey) Export() []byte {
ret := make([]byte, len(prv.Scalar)+len(prv.S))
copy(ret, prv.S)
copy(ret[len(prv.S):], prv.Scalar)
return ret
}
// Size returns size of the private key in bytes
func (prv *PrivateKey) Size() int {
tmp := len(prv.Scalar)
if prv.keyVariant == KeyVariant_SIKE {
tmp += int(prv.params.MsgLen)
}
return tmp
}
// Import clears content of the private key currently stored in the structure
// and imports key from octet string. In case of SIKE, the random value 'S'
// must be prepended to the value of actual private key (see SIKE spec for details).
// Function doesn't import public key value to PrivateKey object.
func (prv *PrivateKey) Import(input []byte) error {
if len(input) != prv.Size() {
return errors.New("sidh: input to short")
}
copy(prv.S, input[:len(prv.S)])
copy(prv.Scalar, input[len(prv.S):])
return nil
}
// Generates random private key for SIDH or SIKE. Generated value is
// formed as little-endian integer from key-space <2^(e2-1)..2^e2 - 1>
// for KeyVariant_A or <2^(s-1)..2^s - 1>, where s = floor(log_2(3^e3)),
// for KeyVariant_B.
//
// Returns error in case user provided RNG fails.
func (prv *PrivateKey) Generate(rand io.Reader) error {
var err error
var dp *DomainParams
if (prv.keyVariant & KeyVariant_SIDH_A) == KeyVariant_SIDH_A {
dp = &prv.params.A
} else {
dp = &prv.params.B
}
if prv.keyVariant == KeyVariant_SIKE {
_, err = io.ReadFull(rand, prv.S)
}
// Private key generation takes advantage of the fact that keyspace for secret
// key is (0, 2^x - 1), for some possitivite value of 'x' (see SIKE, 1.3.8).
// It means that all bytes in the secret key, but the last one, can take any
// value between <0x00,0xFF>. Similarily for the last byte, but generation
// needs to chop off some bits, to make sure generated value is an element of
// a key-space.
_, err = io.ReadFull(rand, prv.Scalar)
if err != nil {
return err
}
prv.Scalar[len(prv.Scalar)-1] &= (1 << (dp.SecretBitLen % 8)) - 1
// Make sure scalar is SecretBitLen long. SIKE spec says that key
// space starts from 0, but I'm not confortable with having low
// value scalars used for private keys. It is still secrure as per
// table 5.1 in [SIKE].
prv.Scalar[len(prv.Scalar)-1] |= 1 << ((dp.SecretBitLen % 8) - 1)
return err
}
// Generates public key.
//
// Constant time.
func (prv *PrivateKey) GeneratePublicKey() *PublicKey {
if (prv.keyVariant & KeyVariant_SIDH_A) == KeyVariant_SIDH_A {
return publicKeyGenA(prv)
}
return publicKeyGenB(prv)
}
// Computes a shared secret which is a j-invariant. Function requires that pub has
// different KeyVariant than prv. Length of returned output is 2*ceil(log_2 P)/8),
// where P is a prime defining finite field.
//
// It's important to notice that each keypair must not be used more than once
// to calculate shared secret.
//
// Function may return error. This happens only in case provided input is invalid.
// Constant time for properly initialized private and public key.
func DeriveSecret(prv *PrivateKey, pub *PublicKey) ([]byte, error) {
if (pub == nil) || (prv == nil) {
return nil, errors.New("sidh: invalid arguments")
}
if (pub.keyVariant == prv.keyVariant) || (pub.params.Id != prv.params.Id) {
return nil, errors.New("sidh: public and private are incompatbile")
}
if (prv.keyVariant & KeyVariant_SIDH_A) == KeyVariant_SIDH_A {
return deriveSecretA(prv, pub), nil
} else {
return deriveSecretB(prv, pub), nil
}
}
// Uses SIKE public key to encrypt plaintext. Requires cryptographically secure PRNG
// Returns ciphertext in case encryption succeeds. Returns error in case PRNG fails
// or wrongly formatted input was provided.
func Encrypt(rng io.Reader, pub *PublicKey, ptext []byte) ([]byte, error) {
var ptextLen = len(ptext)
// c1 must be security level + 64 bits (see [SIKE] 1.4 and 4.3.3)
if ptextLen != pub.params.KemSize {
return nil, errors.New("Unsupported message length")
}
skA := NewPrivateKey(KeyVariant_SIDH_A)
err := skA.Generate(rng)
if err != nil {
return nil, err
}
pkA := skA.GeneratePublicKey()
return encrypt(skA, pkA, pub, ptext)
}
// Uses SIKE private key to decrypt ciphertext. Returns plaintext in case
// decryption succeeds or error in case unexptected input was provided.
// Constant time
func Decrypt(prv *PrivateKey, ctext []byte) ([]byte, error) {
var c1_len int
n := make([]byte, prv.params.KemSize)
pk_len := prv.params.PublicKeySize
if prv.keyVariant != KeyVariant_SIKE {
return nil, errors.New("wrong key type")
}
// ctext is a concatenation of (pubkey_A || c1=ciphertext)
// it must be security level + 64 bits (see [SIKE] 1.4 and 4.3.3)
c1_len = len(ctext) - pk_len
if c1_len != int(prv.params.KemSize) {
return nil, errors.New("wrong size of cipher text")
}
c0 := NewPublicKey(KeyVariant_SIDH_A)
err := c0.Import(ctext[:pk_len])
if err != nil {
return nil, err
}
j, err := DeriveSecret(prv, c0)
if err != nil {
return nil, err
}
digest := sha256.Sum256(j)
copy(n, digest[:])
for i, _ := range n {
n[i] ^= ctext[pk_len+i]
}
return n[:c1_len], nil
}
// Encapsulation receives the public key and generates SIKE ciphertext and shared secret.
// The generated ciphertext is used for authentication.
// The rng must be cryptographically secure PRNG.
// Error is returned in case PRNG fails or wrongly formatted input was provided.
func Encapsulate(rng io.Reader, pub *PublicKey) (ctext []byte, secret []byte, err error) {
// Buffer for random, secret message
ptext := make([]byte, pub.params.MsgLen)
// SHA256 hash context object
d := sha256.New()
// Generate ephemeral value
_, err = io.ReadFull(rng, ptext)
if err != nil {
return nil, nil, err
}
// Implementation uses first 28-bytes of secret
d.Write(ptext)
d.Write(pub.Export())
digest := d.Sum(nil)
// r = G(ptext||pub)
r := digest[:pub.params.A.SecretByteLen]
// (c0 || c1) = Enc(pkA, ptext; r)
skA := NewPrivateKey(KeyVariant_SIDH_A)
err = skA.Import(r)
if err != nil {
return nil, nil, err
}
pkA := skA.GeneratePublicKey()
ctext, err = encrypt(skA, pkA, pub, ptext)
if err != nil {
return nil, nil, err
}
// K = H(ptext||(c0||c1))
d.Reset()
d.Write(ptext)
d.Write(ctext)
digest = d.Sum(digest[:0])
return ctext, digest[:pub.params.KemSize], nil
}
// Decapsulate given the keypair and ciphertext as inputs, Decapsulate outputs a shared
// secret if plaintext verifies correctly, otherwise function outputs random value.
// Decapsulation may fail in case input is wrongly formatted.
// Constant time for properly initialized input.
func Decapsulate(prv *PrivateKey, pub *PublicKey, ctext []byte) ([]byte, error) {
var skA = NewPrivateKey(KeyVariant_SIDH_A)
// SHA256 hash context object
d := sha256.New()
m, err := Decrypt(prv, ctext)
if err != nil {
return nil, err
}
// r' = G(m'||pub)
d.Write(m)
d.Write(pub.Export())
digest := d.Sum(nil)
// Never fails
skA.Import(digest[:pub.params.A.SecretByteLen])
// Never fails
pkA := skA.GeneratePublicKey()
c0 := pkA.Export()
d.Reset()
if subtle.ConstantTimeCompare(c0, ctext[:len(c0)]) == 1 {
d.Write(m)
} else {
// S is chosen at random when generating a key and is unknown to the other party. It
// may seem weird, but it's correct. It is important that S is unpredictable
// to other party. Without this check, it is possible to recover a secret, by
// providing series of invalid ciphertexts. It is also important that in case
//
// See more details in "On the security of supersingular isogeny cryptosystems"
// (S. Galbraith, et al., 2016, ePrint #859).
d.Write(prv.S)
}
d.Write(ctext)
digest = d.Sum(digest[:0])
return digest[:pub.params.KemSize], nil
}

View File

@ -1,698 +0,0 @@
// Copyright (c) 2019, Cloudflare Inc.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package sike
import (
"bufio"
"bytes"
"crypto/rand"
"encoding/hex"
"math/big"
"strings"
"testing"
)
var tdata = struct {
name string
PrB_sidh string
PkB_sidh string
PrA_sidh string
PkA_sidh string
PkB_sike string
PrB_sike string
}{
name: "P-434",
PrA_sidh: "3A727E04EA9B7E2A766A6F846489E7E7B915263BCEED308BB10FC9",
PkA_sidh: "9E668D1E6750ED4B91EE052C32839CA9DD2E56D52BC24DECC950AA" +
"AD24CEED3F9049C77FE80F0B9B01E7F8DAD7833EEC2286544D6380" +
"009C379CDD3E7517CEF5E20EB01F8231D52FC30DC61D2F63FB357F" +
"85DC6396E8A95DB9740BD3A972C8DB7901B31F074CD3E45345CA78" +
"F900817130E688A29A7CF0073B5C00FF2C65FBE776918EF9BD8E75" +
"B29EF7FAB791969B60B0C5B37A8992EDEF95FA7BAC40A95DAFE02E" +
"237301FEE9A7A43FD0B73477E8035DD12B73FAFEF18D39904DDE36" +
"53A754F36BE1888F6607C6A7951349A414352CF31A29F2C40302DB" +
"406C48018C905EB9DC46AFBF42A9187A9BB9E51B587622A2862DC7" +
"D5CC598BF38ED6320FB51D8697AD3D7A72ABCC32A393F0133DA8DF" +
"5E253D9E00B760B2DF342FCE974DCFE946CFE4727783531882800F" +
"9E5DD594D6D5A6275EEFEF9713ED838F4A06BB34D7B8D46E0B385A" +
"AEA1C7963601",
PrB_sidh: "E37BFE55B43B32448F375903D8D226EC94ADBFEA1D2B3536EB987001",
PkB_sidh: "C9F73E4497AAA3FDF9EB688135866A8A83934BA10E273B8CC3808C" +
"F0C1F5FAB3E9BB295885881B73DEBC875670C0F51C4BB40DF5FEDE" +
"01B8AF32D1BF10508B8C17B2734EB93B2B7F5D84A4A0F2F816E9E2" +
"C32AC253C0B6025B124D05A87A9E2A8567930F44BAA14219B941B6" +
"B400B4AED1D796DA12A5A9F0B8F3F5EE9DD43F64CB24A3B1719DF2" +
"78ADF56B5F3395187829DA2319DEABF6BBD6EDA244DE2B62CC5AC2" +
"50C1009DD1CD4712B0B37406612AD002B5E51A62B51AC9C0374D14" +
"3ABBBD58275FAFC4A5E959C54838C2D6D9FB43B7B2609061267B6A" +
"2E6C6D01D295C4223E0D3D7A4CDCFB28A7818A737935279751A6DD" +
"8290FD498D1F6AD5F4FFF6BDFA536713F509DCE8047252F1E7D0DD" +
"9FCC414C0070B5DCCE3665A21A032D7FBE749181032183AFAD240B" +
"7E671E87FBBEC3A8CA4C11AA7A9A23AC69AE2ACF54B664DECD2775" +
"3D63508F1B02",
PrB_sike: "4B622DE1350119C45A9F2E2EF3DC5DF56A27FCDFCDDAF58CD69B90" +
"3752D68C200934E160B234E49EDE247601",
PkB_sike: "1BD0A2E81307B6F96461317DDF535ACC0E59C742627BAE60D27605" +
"E10FAF722D22A73E184CB572A12E79DCD58C6B54FB01442114CBE9" +
"010B6CAEC25D04C16C5E42540C1524C545B8C67614ED4183C9FA5B" +
"D0BE45A7F89FBC770EE8E7E5E391C7EE6F35F74C29E6D9E35B1663" +
"DA01E48E9DEB2347512D366FDE505161677055E3EF23054D276E81" +
"7E2C57025DA1C10D2461F68617F2D11256EEE4E2D7DBDF6C8E34F3" +
"A0FD00C625428CB41857002159DAB94267ABE42D630C6AAA91AF83" +
"7C7A6740754EA6634C45454C51B0BB4D44C3CCCCE4B32C00901CF6" +
"9C008D013348379B2F9837F428A01B6173584691F2A6F3A3C4CF48" +
"7D20D261B36C8CDB1BC158E2A5162A9DA4F7A97AA0879B9897E2B6" +
"891B672201F9AEFBF799C27B2587120AC586A511360926FB7DA8EB" +
"F5CB5272F396AE06608422BE9792E2CE9BEF21BF55B7EFF8DC7EC8" +
"C99910D3F800",
}
/* -------------------------------------------------------------------------
Helpers
-------------------------------------------------------------------------*/
// Fail if err !=nil. Display msg as an error message
func checkErr(t testing.TB, err error, msg string) {
t.Helper()
if err != nil {
t.Error(msg)
}
}
// Utility used for running same test with all registered prime fields
type MultiIdTestingFunc func(testing.TB)
// Converts string to private key
func convToPrv(s string, v KeyVariant) *PrivateKey {
key := NewPrivateKey(v)
hex, e := hex.DecodeString(s)
if e != nil {
panic("non-hex number provided")
}
e = key.Import(hex)
if e != nil {
panic("Can't import private key")
}
return key
}
// Converts string to public key
func convToPub(s string, v KeyVariant) *PublicKey {
key := NewPublicKey(v)
hex, e := hex.DecodeString(s)
if e != nil {
panic("non-hex number provided")
}
e = key.Import(hex)
if e != nil {
panic("Can't import public key")
}
return key
}
/* -------------------------------------------------------------------------
Unit tests
-------------------------------------------------------------------------*/
func TestKeygen(t *testing.T) {
alicePrivate := convToPrv(tdata.PrA_sidh, KeyVariant_SIDH_A)
bobPrivate := convToPrv(tdata.PrB_sidh, KeyVariant_SIDH_B)
expPubA := convToPub(tdata.PkA_sidh, KeyVariant_SIDH_A)
expPubB := convToPub(tdata.PkB_sidh, KeyVariant_SIDH_B)
pubA := alicePrivate.GeneratePublicKey()
pubB := bobPrivate.GeneratePublicKey()
if !bytes.Equal(pubA.Export(), expPubA.Export()) {
t.Fatalf("unexpected value of public key A")
}
if !bytes.Equal(pubB.Export(), expPubB.Export()) {
t.Fatalf("unexpected value of public key B")
}
}
func TestImportExport(t *testing.T) {
var err error
a := NewPublicKey(KeyVariant_SIDH_A)
b := NewPublicKey(KeyVariant_SIDH_B)
// Import keys
a_hex, err := hex.DecodeString(tdata.PkA_sidh)
checkErr(t, err, "invalid hex-number provided")
err = a.Import(a_hex)
checkErr(t, err, "import failed")
b_hex, err := hex.DecodeString(tdata.PkB_sike)
checkErr(t, err, "invalid hex-number provided")
err = b.Import(b_hex)
checkErr(t, err, "import failed")
// Export and check if same
if !bytes.Equal(b.Export(), b_hex) || !bytes.Equal(a.Export(), a_hex) {
t.Fatalf("export/import failed")
}
if (len(b.Export()) != b.Size()) || (len(a.Export()) != a.Size()) {
t.Fatalf("wrong size of exported keys")
}
}
func testPrivateKeyBelowMax(t testing.TB) {
for variant, keySz := range map[KeyVariant]*DomainParams{
KeyVariant_SIDH_A: &Params.A,
KeyVariant_SIDH_B: &Params.B} {
func(v KeyVariant, dp *DomainParams) {
var blen = int(dp.SecretByteLen)
var prv = NewPrivateKey(v)
// Calculate either (2^e2 - 1) or (2^s - 1); where s=ceil(log_2(3^e3)))
maxSecertVal := big.NewInt(int64(dp.SecretBitLen))
maxSecertVal.Exp(big.NewInt(int64(2)), maxSecertVal, nil)
maxSecertVal.Sub(maxSecertVal, big.NewInt(1))
// Do same test 1000 times
for i := 0; i < 1000; i++ {
err := prv.Generate(rand.Reader)
checkErr(t, err, "Private key generation")
// Convert to big-endian, as that's what expected by (*Int)SetBytes()
secretBytes := prv.Export()
for i := 0; i < int(blen/2); i++ {
tmp := secretBytes[i] ^ secretBytes[blen-i-1]
secretBytes[i] = tmp ^ secretBytes[i]
secretBytes[blen-i-1] = tmp ^ secretBytes[blen-i-1]
}
prvBig := new(big.Int).SetBytes(secretBytes)
// Check if generated key is bigger than acceptable
if prvBig.Cmp(maxSecertVal) == 1 {
t.Error("Generated private key is wrong")
}
}
}(variant, keySz)
}
}
func testKeyAgreement(t *testing.T, pkA, prA, pkB, prB string) {
var e error
// KeyPairs
alicePublic := convToPub(pkA, KeyVariant_SIDH_A)
bobPublic := convToPub(pkB, KeyVariant_SIDH_B)
alicePrivate := convToPrv(prA, KeyVariant_SIDH_A)
bobPrivate := convToPrv(prB, KeyVariant_SIDH_B)
// Do actual test
s1, e := DeriveSecret(bobPrivate, alicePublic)
checkErr(t, e, "derivation s1")
s2, e := DeriveSecret(alicePrivate, bobPublic)
checkErr(t, e, "derivation s1")
if !bytes.Equal(s1[:], s2[:]) {
t.Fatalf("two shared keys: %d, %d do not match", s1, s2)
}
// Negative case
dec, e := hex.DecodeString(tdata.PkA_sidh)
if e != nil {
t.FailNow()
}
dec[0] = ^dec[0]
e = alicePublic.Import(dec)
if e != nil {
t.FailNow()
}
s1, e = DeriveSecret(bobPrivate, alicePublic)
checkErr(t, e, "derivation of s1 failed")
s2, e = DeriveSecret(alicePrivate, bobPublic)
checkErr(t, e, "derivation of s2 failed")
if bytes.Equal(s1[:], s2[:]) {
t.Fatalf("The two shared keys: %d, %d match", s1, s2)
}
}
func TestDerivationRoundTrip(t *testing.T) {
var err error
prvA := NewPrivateKey(KeyVariant_SIDH_A)
prvB := NewPrivateKey(KeyVariant_SIDH_B)
// Generate private keys
err = prvA.Generate(rand.Reader)
checkErr(t, err, "key generation failed")
err = prvB.Generate(rand.Reader)
checkErr(t, err, "key generation failed")
// Generate public keys
pubA := prvA.GeneratePublicKey()
pubB := prvB.GeneratePublicKey()
// Derive shared secret
s1, err := DeriveSecret(prvB, pubA)
checkErr(t, err, "")
s2, err := DeriveSecret(prvA, pubB)
checkErr(t, err, "")
if !bytes.Equal(s1[:], s2[:]) {
t.Fatalf("Two shared keys: \n%X, \n%X do not match", s1, s2)
}
}
// Encrypt, Decrypt, check if input/output plaintext is the same
func testPKERoundTrip(t testing.TB, id uint8) {
// Message to be encrypted
var msg = make([]byte, Params.MsgLen)
for i, _ := range msg {
msg[i] = byte(i)
}
// Import keys
pkB := NewPublicKey(KeyVariant_SIKE)
skB := NewPrivateKey(KeyVariant_SIKE)
pk_hex, err := hex.DecodeString(tdata.PkB_sike)
if err != nil {
t.Fatal(err)
}
sk_hex, err := hex.DecodeString(tdata.PrB_sike)
if err != nil {
t.Fatal(err)
}
if pkB.Import(pk_hex) != nil || skB.Import(sk_hex) != nil {
t.Error("Import")
}
ct, err := Encrypt(rand.Reader, pkB, msg[:])
if err != nil {
t.Fatal(err)
}
pt, err := Decrypt(skB, ct)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(pt[:], msg[:]) {
t.Errorf("Decryption failed \n got : %X\n exp : %X", pt, msg)
}
}
// Generate key and check if can encrypt
func TestPKEKeyGeneration(t *testing.T) {
// Message to be encrypted
var msg = make([]byte, Params.MsgLen)
var err error
for i, _ := range msg {
msg[i] = byte(i)
}
sk := NewPrivateKey(KeyVariant_SIKE)
err = sk.Generate(rand.Reader)
checkErr(t, err, "PEK key generation")
pk := sk.GeneratePublicKey()
// Try to encrypt
ct, err := Encrypt(rand.Reader, pk, msg[:])
checkErr(t, err, "PEK encryption")
pt, err := Decrypt(sk, ct)
checkErr(t, err, "PEK key decryption")
if !bytes.Equal(pt[:], msg[:]) {
t.Fatalf("Decryption failed \n got : %X\n exp : %X", pt, msg)
}
}
func TestNegativePKE(t *testing.T) {
var msg [40]byte
var err error
// Generate key
sk := NewPrivateKey(KeyVariant_SIKE)
err = sk.Generate(rand.Reader)
checkErr(t, err, "key generation")
pk := sk.GeneratePublicKey()
// bytelen(msg) - 1
ct, err := Encrypt(rand.Reader, pk, msg[:Params.KemSize+8-1])
if err == nil {
t.Fatal("Error hasn't been returned")
}
if ct != nil {
t.Fatal("Ciphertext must be nil")
}
// KemSize - 1
pt, err := Decrypt(sk, msg[:Params.KemSize+8-1])
if err == nil {
t.Fatal("Error hasn't been returned")
}
if pt != nil {
t.Fatal("Ciphertext must be nil")
}
}
func testKEMRoundTrip(t *testing.T, pkB, skB []byte) {
// Import keys
pk := NewPublicKey(KeyVariant_SIKE)
sk := NewPrivateKey(KeyVariant_SIKE)
if pk.Import(pkB) != nil || sk.Import(skB) != nil {
t.Error("Import failed")
}
ct, ss_e, err := Encapsulate(rand.Reader, pk)
if err != nil {
t.Error("Encapsulate failed")
}
ss_d, err := Decapsulate(sk, pk, ct)
if err != nil {
t.Error("Decapsulate failed")
}
if !bytes.Equal(ss_e, ss_d) {
t.Error("Shared secrets from decapsulation and encapsulation differ")
}
}
func TestKEMRoundTrip(t *testing.T) {
pk, err := hex.DecodeString(tdata.PkB_sike)
checkErr(t, err, "public key B not a number")
sk, err := hex.DecodeString(tdata.PrB_sike)
checkErr(t, err, "private key B not a number")
testKEMRoundTrip(t, pk, sk)
}
func TestKEMKeyGeneration(t *testing.T) {
// Generate key
sk := NewPrivateKey(KeyVariant_SIKE)
checkErr(t, sk.Generate(rand.Reader), "error: key generation")
pk := sk.GeneratePublicKey()
// calculated shared secret
ct, ss_e, err := Encapsulate(rand.Reader, pk)
checkErr(t, err, "encapsulation failed")
ss_d, err := Decapsulate(sk, pk, ct)
checkErr(t, err, "decapsulation failed")
if !bytes.Equal(ss_e, ss_d) {
t.Fatalf("KEM failed \n encapsulated: %X\n decapsulated: %X", ss_d, ss_e)
}
}
func TestNegativeKEM(t *testing.T) {
sk := NewPrivateKey(KeyVariant_SIKE)
checkErr(t, sk.Generate(rand.Reader), "error: key generation")
pk := sk.GeneratePublicKey()
ct, ss_e, err := Encapsulate(rand.Reader, pk)
checkErr(t, err, "pre-requisite for a test failed")
ct[0] = ct[0] - 1
ss_d, err := Decapsulate(sk, pk, ct)
checkErr(t, err, "decapsulation returns error when invalid ciphertext provided")
if bytes.Equal(ss_e, ss_d) {
// no idea how this could ever happen, but it would be very bad
t.Error("critical error")
}
// Try encapsulating with SIDH key
pkSidh := NewPublicKey(KeyVariant_SIDH_B)
prSidh := NewPrivateKey(KeyVariant_SIDH_B)
_, _, err = Encapsulate(rand.Reader, pkSidh)
if err == nil {
t.Error("encapsulation accepts SIDH public key")
}
// Try decapsulating with SIDH key
_, err = Decapsulate(prSidh, pk, ct)
if err == nil {
t.Error("decapsulation accepts SIDH private key key")
}
}
// In case invalid ciphertext is provided, SIKE's decapsulation must
// return same (but unpredictable) result for a given key.
func TestNegativeKEMSameWrongResult(t *testing.T) {
sk := NewPrivateKey(KeyVariant_SIKE)
checkErr(t, sk.Generate(rand.Reader), "error: key generation")
pk := sk.GeneratePublicKey()
ct, encSs, err := Encapsulate(rand.Reader, pk)
checkErr(t, err, "pre-requisite for a test failed")
// make ciphertext wrong
ct[0] = ct[0] - 1
decSs1, err := Decapsulate(sk, pk, ct)
checkErr(t, err, "pre-requisite for a test failed")
// second decapsulation must be done with same, but imported private key
expSk := sk.Export()
// creat new private key
sk = NewPrivateKey(KeyVariant_SIKE)
err = sk.Import(expSk)
checkErr(t, err, "import failed")
// try decapsulating again. ss2 must be same as ss1 and different than
// original plaintext
decSs2, err := Decapsulate(sk, pk, ct)
checkErr(t, err, "pre-requisite for a test failed")
if !bytes.Equal(decSs1, decSs2) {
t.Error("decapsulation is insecure")
}
if bytes.Equal(encSs, decSs1) || bytes.Equal(encSs, decSs2) {
// this test requires that decapsulation returns wrong result
t.Errorf("test implementation error")
}
}
func readAndCheckLine(r *bufio.Reader) []byte {
// Read next line from buffer
line, isPrefix, err := r.ReadLine()
if err != nil || isPrefix {
panic("Wrong format of input file")
}
// Function expects that line is in format "KEY = HEX_VALUE". Get
// value, which should be a hex string
hexst := strings.Split(string(line), "=")[1]
hexst = strings.TrimSpace(hexst)
// Convert value to byte string
ret, err := hex.DecodeString(hexst)
if err != nil {
panic("Wrong format of input file")
}
return ret
}
func testKeygenSIKE(pk, sk []byte, id uint8) bool {
// Import provided private key
var prvKey = NewPrivateKey(KeyVariant_SIKE)
if prvKey.Import(sk) != nil {
panic("sike test: can't load KAT")
}
// Generate public key
pubKey := prvKey.GeneratePublicKey()
return bytes.Equal(pubKey.Export(), pk)
}
func testDecapsulation(pk, sk, ct, ssExpected []byte, id uint8) bool {
var pubKey = NewPublicKey(KeyVariant_SIKE)
var prvKey = NewPrivateKey(KeyVariant_SIKE)
if pubKey.Import(pk) != nil || prvKey.Import(sk) != nil {
panic("sike test: can't load KAT")
}
ssGot, err := Decapsulate(prvKey, pubKey, ct)
if err != nil {
panic("sike test: can't perform degcapsulation KAT")
}
return bytes.Equal(ssGot, ssExpected)
}
func TestKeyAgreement(t *testing.T) {
testKeyAgreement(t, tdata.PkA_sidh, tdata.PrA_sidh, tdata.PkB_sidh, tdata.PrB_sidh)
}
// Same values as in sike_test.cc
func TestDecapsulation(t *testing.T) {
var sk = [16 + 28]byte{
0x04, 0x5E, 0x01, 0x42, 0xB8, 0x2F, 0xE1, 0x9A, 0x38, 0x25,
0x92, 0xE7, 0xDC, 0xBA, 0xF7, 0x1B, 0xB1, 0xFD, 0x34, 0x42,
0xDB, 0x02, 0xBC, 0x9D, 0x4C, 0xD0, 0x72, 0x34, 0x4D, 0xBD,
0x06, 0xDF, 0x1C, 0x7D, 0x0A, 0x88, 0xB2, 0x50, 0xC4, 0xF6,
0xAE, 0xE8, 0x25, 0x01,
}
var pk = [330]byte{
0x6D, 0x8D, 0xF5, 0x7B, 0xCD, 0x47, 0xCA, 0xCB, 0x7A, 0x38,
0xB7, 0xA6, 0x90, 0xB7, 0x37, 0x03, 0xD4, 0x6F, 0x27, 0x73,
0x74, 0x17, 0x5A, 0xA4, 0x0D, 0xC6, 0x81, 0xAD, 0xDB, 0xF7,
0x18, 0xB2, 0x3C, 0x30, 0xCF, 0xAA, 0x08, 0x11, 0x91, 0xCC,
0x27, 0x4E, 0xF1, 0xA6, 0xB7, 0xDA, 0xD2, 0xCF, 0x99, 0x7F,
0xF7, 0xE1, 0xD0, 0xCE, 0x00, 0xD2, 0x4B, 0xA4, 0x33, 0xB4,
0x87, 0x01, 0x3F, 0x02, 0xF7, 0xF9, 0xDE, 0xC3, 0x60, 0x62,
0xDA, 0x3F, 0x74, 0xA9, 0x44, 0xBE, 0x19, 0xD5, 0x03, 0x2A,
0x79, 0x8C, 0xA7, 0xFF, 0xEA, 0xB3, 0xBB, 0xB5, 0xD4, 0x1D,
0x8F, 0x92, 0xCE, 0x62, 0x6E, 0x99, 0x24, 0xD7, 0x57, 0xFA,
0xCD, 0xB6, 0xE2, 0x8E, 0xFD, 0x22, 0x0E, 0x31, 0x21, 0x01,
0x8D, 0x79, 0xF8, 0x3E, 0x27, 0xEC, 0x43, 0x40, 0xDB, 0x82,
0xE5, 0xEB, 0x6C, 0x97, 0x66, 0x29, 0x15, 0x68, 0xB7, 0x4D,
0x84, 0xD1, 0x8A, 0x0B, 0x12, 0x36, 0x2C, 0x0C, 0x0A, 0x6E,
0x4E, 0xDE, 0xA5, 0x8A, 0xDE, 0x77, 0xDD, 0x70, 0x49, 0x73,
0xAC, 0x27, 0x6D, 0x8D, 0x25, 0x9A, 0xE4, 0x25, 0xE8, 0x95,
0x8F, 0xFE, 0x90, 0x3B, 0x00, 0x69, 0x20, 0xE8, 0x7C, 0xA5,
0xF5, 0x79, 0xC0, 0x61, 0x51, 0x91, 0x35, 0x25, 0x3F, 0x17,
0x2F, 0x70, 0x73, 0xF0, 0x89, 0xB5, 0xC8, 0x25, 0xB8, 0xE5,
0x7E, 0x34, 0xDD, 0x11, 0xE5, 0xD6, 0xC3, 0xD5, 0x29, 0x89,
0xC6, 0x2C, 0x99, 0x53, 0x1D, 0x2C, 0x77, 0xB0, 0xB6, 0xA1,
0xBD, 0x79, 0xFB, 0x4A, 0xC2, 0x48, 0x4C, 0x62, 0x51, 0x00,
0xE3, 0x91, 0x2A, 0xCB, 0x84, 0x03, 0x5D, 0x2D, 0xC8, 0x33,
0xE9, 0x14, 0xBF, 0x74, 0x21, 0xBC, 0xF4, 0x76, 0xE5, 0x42,
0xB8, 0xBD, 0xE2, 0xE7, 0x20, 0x95, 0x54, 0xF2, 0xED, 0xC0,
0x79, 0x38, 0x1E, 0xD2, 0xEA, 0x1A, 0x63, 0x85, 0xE7, 0x3A,
0xDA, 0xAD, 0xAB, 0x1B, 0x1E, 0x19, 0x9E, 0x73, 0xD0, 0x10,
0x2E, 0x38, 0xAC, 0x8B, 0x00, 0x6A, 0x30, 0x2C, 0x3D, 0x70,
0x8E, 0x39, 0x6D, 0xC0, 0x12, 0x61, 0x7D, 0x2A, 0x0A, 0x04,
0x95, 0x8E, 0x09, 0x3C, 0x7B, 0xEC, 0x2E, 0xBC, 0xE8, 0xE8,
0xE8, 0x37, 0x29, 0xC4, 0x7E, 0x76, 0x48, 0xB9, 0x3B, 0x72,
0xE5, 0x99, 0x9B, 0xF9, 0xE3, 0x99, 0x72, 0x3F, 0x35, 0x29,
0x85, 0xE0, 0xC8, 0xBF, 0xB1, 0x6B, 0xB1, 0x6E, 0x72, 0x00,
}
var ct = [330 + 16]byte{
0xFF, 0xEB, 0xEF, 0x4A, 0xC0, 0x57, 0x0F, 0x26, 0xAC, 0x76,
0xA8, 0xB0, 0xA3, 0x5D, 0x9C, 0xD9, 0x25, 0xD1, 0x7F, 0x92,
0x5D, 0xF4, 0x23, 0x34, 0xC3, 0x03, 0x10, 0xE1, 0xB0, 0x24,
0x9B, 0x44, 0x58, 0x26, 0x13, 0x56, 0x83, 0x43, 0x72, 0x69,
0x28, 0x0D, 0x55, 0x07, 0x1F, 0xDB, 0xC0, 0x23, 0x34, 0x83,
0x1A, 0x09, 0x9B, 0x80, 0x00, 0x64, 0x56, 0xDC, 0x79, 0x7A,
0xD2, 0xCE, 0x23, 0xC9, 0x72, 0x27, 0xFC, 0x8D, 0xAB, 0xBF,
0xD3, 0x17, 0xF6, 0x91, 0x7B, 0x15, 0x93, 0x83, 0x8A, 0x4F,
0x6C, 0xCA, 0x4A, 0x94, 0xDA, 0xC7, 0x9D, 0xB6, 0xD6, 0xBA,
0xBD, 0x81, 0x9A, 0x78, 0xE5, 0xE5, 0xBE, 0x17, 0xBC, 0xCB,
0xC8, 0x23, 0x80, 0x5F, 0x75, 0xF8, 0xDB, 0x51, 0x55, 0x00,
0x25, 0x33, 0x52, 0x64, 0xB2, 0xD6, 0xD8, 0x9A, 0x2A, 0x9E,
0x29, 0x99, 0x13, 0x33, 0xE2, 0xA7, 0x98, 0xAC, 0xD7, 0x79,
0x5C, 0x2F, 0xBA, 0x07, 0xC3, 0x03, 0x37, 0xD6, 0xE6, 0xB5,
0xA1, 0xF5, 0x29, 0xB6, 0xF6, 0xC0, 0x5C, 0x44, 0x68, 0x2B,
0x0B, 0xF5, 0x00, 0x01, 0x44, 0xD5, 0xCC, 0x23, 0xB5, 0x27,
0x4F, 0xCA, 0xB4, 0x05, 0x01, 0xF9, 0xD4, 0x41, 0xE0, 0xE1,
0x1E, 0xCF, 0xA9, 0xBC, 0x79, 0xD7, 0xD5, 0xF5, 0x3C, 0xE6,
0x93, 0xF4, 0x6C, 0x84, 0x5A, 0x2C, 0x4B, 0xE4, 0x91, 0xB2,
0xB2, 0xB8, 0xAD, 0x74, 0x9A, 0x69, 0x79, 0x4C, 0x84, 0xB7,
0xBF, 0xF1, 0x68, 0x4B, 0xAE, 0x0F, 0x7F, 0x45, 0x3B, 0x18,
0x3F, 0xFA, 0x00, 0x48, 0xE0, 0x3A, 0xE2, 0xC0, 0xAE, 0x00,
0xCE, 0x90, 0x28, 0xA4, 0x1B, 0xBE, 0xCA, 0x0C, 0x21, 0x29,
0x64, 0x30, 0x5E, 0x35, 0xAD, 0xFD, 0x83, 0x47, 0x40, 0x6D,
0x15, 0x56, 0xFC, 0xF8, 0x5F, 0xAB, 0x81, 0xFE, 0x6B, 0xE9,
0x6B, 0xED, 0x27, 0x35, 0x7C, 0xD8, 0x2C, 0xD4, 0xF2, 0x11,
0xE6, 0xAF, 0xDF, 0xB8, 0x91, 0x96, 0xEB, 0xF7, 0x4C, 0x8D,
0x70, 0x77, 0x90, 0x81, 0x00, 0x09, 0x19, 0x27, 0x8A, 0x9E,
0xB6, 0x1A, 0xE9, 0xAC, 0x6C, 0xC9, 0xF8, 0xEA, 0xA2, 0x34,
0xB8, 0xAC, 0xB3, 0xB3, 0x68, 0xA1, 0xB7, 0x29, 0x55, 0xCA,
0x40, 0x23, 0x92, 0x5C, 0x0C, 0x79, 0x6B, 0xD6, 0x9F, 0x5B,
0xD2, 0xE6, 0xAE, 0x04, 0xCB, 0xEC, 0xC7, 0x88, 0x18, 0xDB,
0x7A, 0xE6, 0xD6, 0xC9, 0x39, 0xFD, 0x93, 0x9B, 0xC8, 0x01,
0x6F, 0x3E, 0x6C, 0x90, 0x3E, 0x73, 0x76, 0x99, 0x7C, 0x48,
0xDA, 0x68, 0x48, 0x80, 0x2B, 0x63,
}
var ssExp = [16]byte{
0xA1, 0xF9, 0x5A, 0x67, 0xB9, 0x3D, 0x1E, 0x72, 0xE8, 0xC5,
0x71, 0xF1, 0x4C, 0xB2, 0xAA, 0x6D,
}
var prvObj = NewPrivateKey(KeyVariant_SIKE)
var pubObj = NewPublicKey(KeyVariant_SIKE)
if pubObj.Import(pk[:]) != nil || prvObj.Import(sk[:]) != nil {
t.Error("Can't import one of the keys")
}
res, _ := Decapsulate(prvObj, pubObj, ct[:])
if !bytes.Equal(ssExp[:], res) {
t.Error("Wrong decapsulation result")
}
}
/* -------------------------------------------------------------------------
Benchmarking
-------------------------------------------------------------------------*/
func BenchmarkSidhKeyAgreement(b *testing.B) {
// KeyPairs
alicePublic := convToPub(tdata.PkA_sidh, KeyVariant_SIDH_A)
alicePrivate := convToPrv(tdata.PrA_sidh, KeyVariant_SIDH_A)
bobPublic := convToPub(tdata.PkB_sidh, KeyVariant_SIDH_B)
bobPrivate := convToPrv(tdata.PrB_sidh, KeyVariant_SIDH_B)
for i := 0; i < b.N; i++ {
// Derive shared secret
DeriveSecret(bobPrivate, alicePublic)
DeriveSecret(alicePrivate, bobPublic)
}
}
func BenchmarkAliceKeyGenPrv(b *testing.B) {
prv := NewPrivateKey(KeyVariant_SIDH_A)
for n := 0; n < b.N; n++ {
prv.Generate(rand.Reader)
}
}
func BenchmarkBobKeyGenPrv(b *testing.B) {
prv := NewPrivateKey(KeyVariant_SIDH_B)
for n := 0; n < b.N; n++ {
prv.Generate(rand.Reader)
}
}
func BenchmarkAliceKeyGenPub(b *testing.B) {
prv := NewPrivateKey(KeyVariant_SIDH_A)
prv.Generate(rand.Reader)
for n := 0; n < b.N; n++ {
prv.GeneratePublicKey()
}
}
func BenchmarkBobKeyGenPub(b *testing.B) {
prv := NewPrivateKey(KeyVariant_SIDH_B)
prv.Generate(rand.Reader)
for n := 0; n < b.N; n++ {
prv.GeneratePublicKey()
}
}
func BenchmarkSharedSecretAlice(b *testing.B) {
aPr := convToPrv(tdata.PrA_sidh, KeyVariant_SIDH_A)
bPk := convToPub(tdata.PkB_sike, KeyVariant_SIDH_B)
for n := 0; n < b.N; n++ {
DeriveSecret(aPr, bPk)
}
}
func BenchmarkSharedSecretBob(b *testing.B) {
// m_B = 3*randint(0,3^238)
aPk := convToPub(tdata.PkA_sidh, KeyVariant_SIDH_A)
bPr := convToPrv(tdata.PrB_sidh, KeyVariant_SIDH_B)
for n := 0; n < b.N; n++ {
DeriveSecret(bPr, aPk)
}
}

View File

@ -1611,9 +1611,6 @@ bssl::UniquePtr<SSL> TestConfig::NewSSL(
case SSL_CURVE_CECPQ2:
nids.push_back(NID_CECPQ2);
break;
case SSL_CURVE_CECPQ2b:
nids.push_back(NID_CECPQ2b);
break;
}
if (!SSL_set1_curves(ssl.get(), &nids[0], nids.size())) {
return nullptr;
@ -1622,8 +1619,8 @@ bssl::UniquePtr<SSL> TestConfig::NewSSL(
}
if (enable_all_curves) {
static const int kAllCurves[] = {
NID_secp224r1, NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1,
NID_X25519, NID_CECPQ2, NID_CECPQ2b,
NID_secp224r1, NID_X9_62_prime256v1, NID_secp384r1,
NID_secp521r1, NID_X25519, NID_CECPQ2,
};
if (!SSL_set1_curves(ssl.get(), kAllCurves,
OPENSSL_ARRAY_SIZE(kAllCurves))) {

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) Microsoft Corporation. All rights reserved.
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

@ -1,915 +0,0 @@
#! /usr/bin/env perl
#
# April 2019
#
# Abstract: field arithmetic in aarch64 assembly for SIDH/p434
$flavour = shift;
$output = shift;
if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
( $xlate="${dir}../../../crypto/perlasm/arm-xlate.pl" and -f $xlate) or
die "can't locate arm-xlate.pl";
open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
*STDOUT=*OUT;
$PREFIX="sike";
$code.=<<___;
.section .rodata
# p434 x 2
.Lp434x2:
.quad 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF
.quad 0xFB82ECF5C5FFFFFF, 0xF78CB8F062B15D47
.quad 0xD9F8BFAD038A40AC, 0x0004683E4E2EE688
# p434 + 1
.Lp434p1:
.quad 0xFDC1767AE3000000, 0x7BC65C783158AEA3
.quad 0x6CFC5FD681C52056, 0x0002341F27177344
.text
___
# Computes C0-C2 = A0 * (B0-B1)
# Inputs remain intact
sub mul64x128 {
my ($A0,$B0,$B1,$C0,$C1,$C2,$T0,$T1)=@_;
my $body=<<___;
mul $T1, $A0, $B0
umulh $B0, $A0, $B0
adds $C0, $C0, $C2
adc $C1, $C1, xzr
mul $T0, $A0, $B1
umulh $B1, $A0, $B1
adds $C0, $C0, $T1
adcs $C1, $C1, $B0
adc $C2, xzr, xzr
adds $C1, $C1, $T0
adc $C2, $C2, $B1
___
return $body;
}
# Computes C0-C4 = A0 * (B0-B3)
# Inputs remain intact
sub mul64x256 {
my ($A0,$B0,$B1,$B2,$B3,$C0,$C1,$C2,$C3,$C4,$T0,$T1,$T2)=@_;
my $body=<<___;
mul $C0, $A0, $B0 // C0
umulh $T0, $A0, $B0
mul $C1, $A0, $B1
umulh $T1, $A0, $B1
adds $C1, $C1, $T0 // C1
adc $T0, xzr, xzr
mul $C2, $A0, $B2
umulh $T2, $A0, $B2
adds $T1, $T0, $T1
adcs $C2, $C2, $T1 // C2
adc $T0, xzr, xzr
mul $C3, $A0, $B3
umulh $C4, $A0, $B3
adds $T2, $T0, $T2
adcs $C3, $C3, $T2 // C3
adc $C4, $C4, xzr // C4
___
return $body;
}
# Computes C0-C4 = (A0-A1) * (B0-B3)
# Inputs remain intact
sub mul128x256 {
my ($A0,$A1,$B0,$B1,$B2,$B3,$C0,$C1,$C2,$C3,$C4,$C5,$T0,$T1,$T2,$T3)=@_;
my $body=<<___;
mul $C0, $A0, $B0 // C0
umulh $C3, $A0, $B0
mul $C1, $A0, $B1
umulh $C2, $A0, $B1
mul $T0, $A1, $B0
umulh $T1, $A1, $B0
adds $C1, $C1, $C3
adc $C2, $C2, xzr
mul $T2, $A0, $B2
umulh $T3, $A0, $B2
adds $C1, $C1, $T0 // C1
adcs $C2, $C2, $T1
adc $C3, xzr, xzr
mul $T0, $A1, $B1
umulh $T1, $A1, $B1
adds $C2, $C2, $T2
adcs $C3, $C3, $T3
adc $C4, xzr, xzr
mul $T2, $A0, $B3
umulh $T3, $A0, $B3
adds $C2, $C2, $T0 // C2
adcs $C3, $C3, $T1
adc $C4, $C4, xzr
mul $T0, $A1, $B2
umulh $T1, $A1, $B2
adds $C3, $C3, $T2
adcs $C4, $C4, $T3
adc $C5, xzr, xzr
mul $T2, $A1, $B3
umulh $T3, $A1, $B3
adds $C3, $C3, $T0 // C3
adcs $C4, $C4, $T1
adc $C5, $C5, xzr
adds $C4, $C4, $T2 // C4
adc $C5, $C5, $T3 // C5
___
return $body;
}
# Computes C0-C5 = (A0-A2) * (B0-B2)
# Inputs remain intact
sub mul192 {
my ($A0,$A1,$A2,$B0,$B1,$B2,$C0,$C1,$C2,$C3,$C4,$C5,$T0,$T1,$T2,$T3)=@_;
my $body=<<___;
// A0 * B0
mul $C0, $A0, $B0 // C0
umulh $C3, $A0, $B0
// A0 * B1
mul $C1, $A0, $B1
umulh $C2, $A0, $B1
// A1 * B0
mul $T0, $A1, $B0
umulh $T1, $A1, $B0
adds $C1, $C1, $C3
adc $C2, $C2, xzr
// A0 * B2
mul $T2, $A0, $B2
umulh $T3, $A0, $B2
adds $C1, $C1, $T0 // C1
adcs $C2, $C2, $T1
adc $C3, xzr, xzr
// A2 * B0
mul $T0, $A2, $B0
umulh $C4, $A2, $B0
adds $C2, $C2, $T2
adcs $C3, $C3, $C4
adc $C4, xzr, xzr
// A1 * B1
mul $T2, $A1, $B1
umulh $T1, $A1, $B1
adds $C2, $C2, $T0
adcs $C3, $C3, $T3
adc $C4, $C4, xzr
// A1 * B2
mul $T0, $A1, $B2
umulh $T3, $A1, $B2
adds $C2, $C2, $T2 // C2
adcs $C3, $C3, $T1
adc $C4, $C4, xzr
// A2 * B1
mul $T2, $A2, $B1
umulh $T1, $A2, $B1
adds $C3, $C3, $T0
adcs $C4, $C4, $T3
adc $C5, xzr, xzr
// A2 * B2
mul $T0, $A2, $B2
umulh $T3, $A2, $B2
adds $C3, $C3, $T2 // C3
adcs $C4, $C4, $T1
adc $C5, $C5, xzr
adds $C4, $C4, $T0 // C4
adc $C5, $C5, $T3 // C5
___
return $body;
}
sub mul256_karatsuba {
my ($M,$A0,$A1,$A2,$A3,$B0,$B1,$B2,$B3,$C0,$C1,$C2,$C3,$C4,$C5,$C6,$C7,$T0,$T1)=@_;
# (AH+AL) x (BH+BL), low part
my $mul_low=&mul64x128($A1, $C6, $T1, $C3, $C4, $C5, $C7, $A0);
# AL x BL
my $mul_albl=&mul64x128($A1, $B0, $B1, $C1, $T1, $C7, $C6, $A0);
# AH x BH
my $mul_ahbh=&mul64x128($A3, $B2, $B3, $A1, $C6, $B0, $B1, $A2);
my $body=<<___;
// A0-A1 <- AH + AL, T0 <- mask
adds $A0, $A0, $A2
adcs $A1, $A1, $A3
adc $T0, xzr, xzr
// C6, T1 <- BH + BL, C7 <- mask
adds $C6, $B0, $B2
adcs $T1, $B1, $B3
adc $C7, xzr, xzr
// C0-C1 <- masked (BH + BL)
sub $C2, xzr, $T0
sub $C3, xzr, $C7
and $C0, $C6, $C2
and $C1, $T1, $C2
// C4-C5 <- masked (AH + AL), T0 <- combined carry
and $C4, $A0, $C3
and $C5, $A1, $C3
mul $C2, $A0, $C6
mul $C3, $A0, $T1
and $T0, $T0, $C7
// C0-C1, T0 <- (AH+AL) x (BH+BL), part 1
adds $C0, $C4, $C0
umulh $C4, $A0, $T1
adcs $C1, $C5, $C1
umulh $C5, $A0, $C6
adc $T0, $T0, xzr
// C2-C5 <- (AH+AL) x (BH+BL), low part
$mul_low
ldp $A0, $A1, [$M,#0]
// C2-C5, T0 <- (AH+AL) x (BH+BL), final part
adds $C4, $C0, $C4
umulh $C7, $A0, $B0
umulh $T1, $A0, $B1
adcs $C5, $C1, $C5
mul $C0, $A0, $B0
mul $C1, $A0, $B1
adc $T0, $T0, xzr
// C0-C1, T1, C7 <- AL x BL
$mul_albl
// C2-C5, T0 <- (AH+AL) x (BH+BL) - ALxBL
mul $A0, $A2, $B2
umulh $B0, $A2, $B2
subs $C2, $C2, $C0
sbcs $C3, $C3, $C1
sbcs $C4, $C4, $T1
mul $A1, $A2, $B3
umulh $C6, $A2, $B3
sbcs $C5, $C5, $C7
sbc $T0, $T0, xzr
// A0, A1, C6, B0 <- AH x BH
$mul_ahbh
// C2-C5, T0 <- (AH+AL) x (BH+BL) - ALxBL - AHxBH
subs $C2, $C2, $A0
sbcs $C3, $C3, $A1
sbcs $C4, $C4, $C6
sbcs $C5, $C5, $B0
sbc $T0, $T0, xzr
adds $C2, $C2, $T1
adcs $C3, $C3, $C7
adcs $C4, $C4, $A0
adcs $C5, $C5, $A1
adcs $C6, $T0, $C6
adc $C7, $B0, xzr
___
return $body;
}
# 512-bit integer multiplication using Karatsuba (two levels),
# Comba (lower level).
# Operation: c [x2] = a [x0] * b [x1]
sub mul {
# (AH+AL) x (BH+BL), low part
my $mul_kc_low=&mul256_karatsuba(
"x2", # M0
"x3","x4","x5","x6", # A0-A3
"x10","x11","x12","x13", # B0-B3
"x8","x9","x19","x20","x21","x22","x23","x24", # C0-C7
"x25","x26"); # TMP
# AL x BL
my $mul_albl=&mul256_karatsuba(
"x0", # M0f
"x3","x4","x5","x6", # A0-A3
"x10","x11","x12","x13", # B0-B3
"x21","x22","x23","x24","x25","x26","x27","x28",# C0-C7
"x8","x9"); # TMP
# AH x BH
my $mul_ahbh=&mul192(
"x3","x4","x5", # A0-A2
"x10","x11","x12", # B0-B2
"x21","x22","x23","x24","x25","x26", # C0-C5
"x8","x9","x27","x28"); # TMP
my $body=<<___;
.global ${PREFIX}_mpmul
.align 4
${PREFIX}_mpmul:
stp x29, x30, [sp,#-96]!
add x29, sp, #0
stp x19, x20, [sp,#16]
stp x21, x22, [sp,#32]
stp x23, x24, [sp,#48]
stp x25, x26, [sp,#64]
stp x27, x28, [sp,#80]
ldp x3, x4, [x0]
ldp x5, x6, [x0,#16]
ldp x7, x8, [x0,#32]
ldr x9, [x0,#48]
ldp x10, x11, [x1,#0]
ldp x12, x13, [x1,#16]
ldp x14, x15, [x1,#32]
ldr x16, [x1,#48]
// x3-x7 <- AH + AL, x7 <- carry
adds x3, x3, x7
adcs x4, x4, x8
adcs x5, x5, x9
adcs x6, x6, xzr
adc x7, xzr, xzr
// x10-x13 <- BH + BL, x8 <- carry
adds x10, x10, x14
adcs x11, x11, x15
adcs x12, x12, x16
adcs x13, x13, xzr
adc x8, xzr, xzr
// x9 <- combined carry
and x9, x7, x8
// x7-x8 <- mask
sub x7, xzr, x7
sub x8, xzr, x8
// x15-x19 <- masked (BH + BL)
and x14, x10, x7
and x15, x11, x7
and x16, x12, x7
and x17, x13, x7
// x20-x23 <- masked (AH + AL)
and x20, x3, x8
and x21, x4, x8
and x22, x5, x8
and x23, x6, x8
// x15-x19, x7 <- masked (AH+AL) + masked (BH+BL), step 1
adds x14, x14, x20
adcs x15, x15, x21
adcs x16, x16, x22
adcs x17, x17, x23
adc x7, x9, xzr
// x8-x9,x19,x20-x24 <- (AH+AL) x (BH+BL), low part
stp x3, x4, [x2,#0]
$mul_kc_low
// x15-x19, x7 <- (AH+AL) x (BH+BL), final step
adds x14, x14, x21
adcs x15, x15, x22
adcs x16, x16, x23
adcs x17, x17, x24
adc x7, x7, xzr
// Load AL
ldp x3, x4, [x0]
ldp x5, x6, [x0,#16]
// Load BL
ldp x10, x11, [x1,#0]
ldp x12, x13, [x1,#16]
// Temporarily store x8 in x2
stp x8, x9, [x2,#0]
// x21-x28 <- AL x BL
$mul_albl
// Restore x8
ldp x8, x9, [x2,#0]
// x8-x10,x20,x15-x17,x19 <- maskd (AH+AL) x (BH+BL) - ALxBL
subs x8, x8, x21
sbcs x9, x9, x22
sbcs x19, x19, x23
sbcs x20, x20, x24
sbcs x14, x14, x25
sbcs x15, x15, x26
sbcs x16, x16, x27
sbcs x17, x17, x28
sbc x7, x7, xzr
// Store ALxBL, low
stp x21, x22, [x2]
stp x23, x24, [x2,#16]
// Load AH
ldp x3, x4, [x0,#32]
ldr x5, [x0,#48]
// Load BH
ldp x10, x11, [x1,#32]
ldr x12, [x1,#48]
adds x8, x8, x25
adcs x9, x9, x26
adcs x19, x19, x27
adcs x20, x20, x28
adc x1, xzr, xzr
add x0, x0, #32
// Temporarily store x8,x9 in x2
stp x8,x9, [x2,#32]
// x21-x28 <- AH x BH
$mul_ahbh
// Restore x8,x9
ldp x8,x9, [x2,#32]
neg x1, x1
// x8-x9,x19,x20,x14-x17 <- (AH+AL) x (BH+BL) - ALxBL - AHxBH
subs x8, x8, x21
sbcs x9, x9, x22
sbcs x19, x19, x23
sbcs x20, x20, x24
sbcs x14, x14, x25
sbcs x15, x15, x26
sbcs x16, x16, xzr
sbcs x17, x17, xzr
sbc x7, x7, xzr
// Store (AH+AL) x (BH+BL) - ALxBL - AHxBH, low
stp x8, x9, [x2,#32]
stp x19, x20, [x2,#48]
adds x1, x1, #1
adcs x14, x14, x21
adcs x15, x15, x22
adcs x16, x16, x23
adcs x17, x17, x24
adcs x25, x7, x25
adc x26, x26, xzr
stp x14, x15, [x2,#64]
stp x16, x17, [x2,#80]
stp x25, x26, [x2,#96]
ldp x19, x20, [x29,#16]
ldp x21, x22, [x29,#32]
ldp x23, x24, [x29,#48]
ldp x25, x26, [x29,#64]
ldp x27, x28, [x29,#80]
ldp x29, x30, [sp],#96
ret
___
return $body;
}
$code.=&mul();
# Montgomery reduction
# Based on method described in Faz-Hernandez et al. https://eprint.iacr.org/2017/1015
# Operation: mc [x1] = ma [x0]
# NOTE: ma=mc is not allowed
sub rdc {
my $mul01=&mul128x256(
"x2","x3", # A0-A1
"x23","x24","x25","x26", # B0-B3
"x4","x5","x6","x7","x8","x9", # C0-C5
"x10","x11","x27","x28"); # TMP
my $mul23=&mul128x256(
"x2","x10", # A0-A1
"x23","x24","x25","x26", # B0-B3
"x4","x5","x6","x7","x8","x9", # C0-C5
"x0","x3","x27","x28"); # TMP
my $mul45=&mul128x256(
"x11","x12", # A0-A1
"x23","x24","x25","x26", # B0-B3
"x4","x5","x6","x7","x8","x9", # C0-C5
"x10","x3","x27","x28"); # TMP
my $mul67=&mul64x256(
"x13", # A0
"x23","x24","x25","x26", # B0-B3
"x4","x5","x6","x7","x8", # C0-C4
"x10","x27","x28"); # TMP
my $body=<<___;
.global ${PREFIX}_fprdc
.align 4
${PREFIX}_fprdc:
stp x29, x30, [sp, #-96]!
add x29, sp, xzr
stp x19, x20, [sp,#16]
stp x21, x22, [sp,#32]
stp x23, x24, [sp,#48]
stp x25, x26, [sp,#64]
stp x27, x28, [sp,#80]
ldp x2, x3, [x0,#0] // a[0-1]
// Load the prime constant
adrp x26, :pg_hi21:.Lp434p1
add x26, x26, :lo12:.Lp434p1
ldp x23, x24, [x26, #0x0]
ldp x25, x26, [x26,#0x10]
// a[0-1] * p434+1
$mul01
ldp x10, x11, [x0, #0x18]
ldp x12, x13, [x0, #0x28]
ldp x14, x15, [x0, #0x38]
ldp x16, x17, [x0, #0x48]
ldp x19, x20, [x0, #0x58]
ldr x21, [x0, #0x68]
adds x10, x10, x4
adcs x11, x11, x5
adcs x12, x12, x6
adcs x13, x13, x7
adcs x14, x14, x8
adcs x15, x15, x9
adcs x22, x16, xzr
adcs x17, x17, xzr
adcs x19, x19, xzr
adcs x20, x20, xzr
adc x21, x21, xzr
ldr x2, [x0,#0x10] // a[2]
// a[2-3] * p434+1
$mul23
adds x12, x12, x4
adcs x13, x13, x5
adcs x14, x14, x6
adcs x15, x15, x7
adcs x16, x22, x8
adcs x17, x17, x9
adcs x22, x19, xzr
adcs x20, x20, xzr
adc x21, x21, xzr
$mul45
adds x14, x14, x4
adcs x15, x15, x5
adcs x16, x16, x6
adcs x17, x17, x7
adcs x19, x22, x8
adcs x20, x20, x9
adc x22, x21, xzr
stp x14, x15, [x1, #0x0] // C0, C1
$mul67
adds x16, x16, x4
adcs x17, x17, x5
adcs x19, x19, x6
adcs x20, x20, x7
adc x21, x22, x8
str x16, [x1, #0x10]
stp x17, x19, [x1, #0x18]
stp x20, x21, [x1, #0x28]
ldp x19, x20, [x29,#16]
ldp x21, x22, [x29,#32]
ldp x23, x24, [x29,#48]
ldp x25, x26, [x29,#64]
ldp x27, x28, [x29,#80]
ldp x29, x30, [sp],#96
ret
___
}
$code.=&rdc();
# Field addition
# Operation: c [x2] = a [x0] + b [x1]
$code.=<<___;
.global ${PREFIX}_fpadd
.align 4
${PREFIX}_fpadd:
stp x29,x30, [sp,#-16]!
add x29, sp, #0
ldp x3, x4, [x0,#0]
ldp x5, x6, [x0,#16]
ldp x7, x8, [x0,#32]
ldr x9, [x0,#48]
ldp x11, x12, [x1,#0]
ldp x13, x14, [x1,#16]
ldp x15, x16, [x1,#32]
ldr x17, [x1,#48]
// Add a + b
adds x3, x3, x11
adcs x4, x4, x12
adcs x5, x5, x13
adcs x6, x6, x14
adcs x7, x7, x15
adcs x8, x8, x16
adc x9, x9, x17
// Subtract 2xp434
adrp x17, :pg_hi21:.Lp434x2
add x17, x17, :lo12:.Lp434x2
ldp x11, x12, [x17, #0]
ldp x13, x14, [x17, #16]
ldp x15, x16, [x17, #32]
subs x3, x3, x11
sbcs x4, x4, x12
sbcs x5, x5, x12
sbcs x6, x6, x13
sbcs x7, x7, x14
sbcs x8, x8, x15
sbcs x9, x9, x16
sbc x0, xzr, xzr // x0 can be reused now
// Add 2xp434 anded with the mask in x0
and x11, x11, x0
and x12, x12, x0
and x13, x13, x0
and x14, x14, x0
and x15, x15, x0
and x16, x16, x0
adds x3, x3, x11
adcs x4, x4, x12
adcs x5, x5, x12
adcs x6, x6, x13
adcs x7, x7, x14
adcs x8, x8, x15
adc x9, x9, x16
stp x3, x4, [x2,#0]
stp x5, x6, [x2,#16]
stp x7, x8, [x2,#32]
str x9, [x2,#48]
ldp x29, x30, [sp],#16
ret
___
# Field subtraction
# Operation: c [x2] = a [x0] - b [x1]
$code.=<<___;
.global ${PREFIX}_fpsub
.align 4
${PREFIX}_fpsub:
stp x29, x30, [sp,#-16]!
add x29, sp, #0
ldp x3, x4, [x0,#0]
ldp x5, x6, [x0,#16]
ldp x7, x8, [x0,#32]
ldr x9, [x0,#48]
ldp x11, x12, [x1,#0]
ldp x13, x14, [x1,#16]
ldp x15, x16, [x1,#32]
ldr x17, [x1,#48]
// Subtract a - b
subs x3, x3, x11
sbcs x4, x4, x12
sbcs x5, x5, x13
sbcs x6, x6, x14
sbcs x7, x7, x15
sbcs x8, x8, x16
sbcs x9, x9, x17
sbc x0, xzr, xzr
// Add 2xp434 anded with the mask in x0
adrp x17, :pg_hi21:.Lp434x2
add x17, x17, :lo12:.Lp434x2
// First half
ldp x11, x12, [x17, #0]
ldp x13, x14, [x17, #16]
ldp x15, x16, [x17, #32]
// Add 2xp434 anded with the mask in x0
and x11, x11, x0
and x12, x12, x0
and x13, x13, x0
and x14, x14, x0
and x15, x15, x0
and x16, x16, x0
adds x3, x3, x11
adcs x4, x4, x12
adcs x5, x5, x12
adcs x6, x6, x13
adcs x7, x7, x14
adcs x8, x8, x15
adc x9, x9, x16
stp x3, x4, [x2,#0]
stp x5, x6, [x2,#16]
stp x7, x8, [x2,#32]
str x9, [x2,#48]
ldp x29, x30, [sp],#16
ret
___
# 434-bit multiprecision addition
# Operation: c [x2] = a [x0] + b [x1]
$code.=<<___;
.global ${PREFIX}_mpadd_asm
.align 4
${PREFIX}_mpadd_asm:
stp x29, x30, [sp,#-16]!
add x29, sp, #0
ldp x3, x4, [x0,#0]
ldp x5, x6, [x0,#16]
ldp x7, x8, [x0,#32]
ldr x9, [x0,#48]
ldp x11, x12, [x1,#0]
ldp x13, x14, [x1,#16]
ldp x15, x16, [x1,#32]
ldr x17, [x1,#48]
adds x3, x3, x11
adcs x4, x4, x12
adcs x5, x5, x13
adcs x6, x6, x14
adcs x7, x7, x15
adcs x8, x8, x16
adc x9, x9, x17
stp x3, x4, [x2,#0]
stp x5, x6, [x2,#16]
stp x7, x8, [x2,#32]
str x9, [x2,#48]
ldp x29, x30, [sp],#16
ret
___
# 2x434-bit multiprecision subtraction
# Operation: c [x2] = a [x0] - b [x1].
# Returns borrow mask
$code.=<<___;
.global ${PREFIX}_mpsubx2_asm
.align 4
${PREFIX}_mpsubx2_asm:
stp x29, x30, [sp,#-16]!
add x29, sp, #0
ldp x3, x4, [x0,#0]
ldp x5, x6, [x0,#16]
ldp x11, x12, [x1,#0]
ldp x13, x14, [x1,#16]
subs x3, x3, x11
sbcs x4, x4, x12
sbcs x5, x5, x13
sbcs x6, x6, x14
ldp x7, x8, [x0,#32]
ldp x9, x10, [x0,#48]
ldp x11, x12, [x1,#32]
ldp x13, x14, [x1,#48]
sbcs x7, x7, x11
sbcs x8, x8, x12
sbcs x9, x9, x13
sbcs x10, x10, x14
stp x3, x4, [x2,#0]
stp x5, x6, [x2,#16]
stp x7, x8, [x2,#32]
stp x9, x10, [x2,#48]
ldp x3, x4, [x0,#64]
ldp x5, x6, [x0,#80]
ldp x11, x12, [x1,#64]
ldp x13, x14, [x1,#80]
sbcs x3, x3, x11
sbcs x4, x4, x12
sbcs x5, x5, x13
sbcs x6, x6, x14
ldp x7, x8, [x0,#96]
ldp x11, x12, [x1,#96]
sbcs x7, x7, x11
sbcs x8, x8, x12
sbc x0, xzr, xzr
stp x3, x4, [x2,#64]
stp x5, x6, [x2,#80]
stp x7, x8, [x2,#96]
ldp x29, x30, [sp],#16
ret
___
# Double 2x434-bit multiprecision subtraction
# Operation: c [x2] = c [x2] - a [x0] - b [x1]
$code.=<<___;
.global ${PREFIX}_mpdblsubx2_asm
.align 4
${PREFIX}_mpdblsubx2_asm:
stp x29, x30, [sp, #-16]!
add x29, sp, #0
ldp x3, x4, [x2, #0]
ldp x5, x6, [x2,#16]
ldp x7, x8, [x2,#32]
ldp x11, x12, [x0, #0]
ldp x13, x14, [x0,#16]
ldp x15, x16, [x0,#32]
subs x3, x3, x11
sbcs x4, x4, x12
sbcs x5, x5, x13
sbcs x6, x6, x14
sbcs x7, x7, x15
sbcs x8, x8, x16
// x9 stores carry
adc x9, xzr, xzr
ldp x11, x12, [x1, #0]
ldp x13, x14, [x1,#16]
ldp x15, x16, [x1,#32]
subs x3, x3, x11
sbcs x4, x4, x12
sbcs x5, x5, x13
sbcs x6, x6, x14
sbcs x7, x7, x15
sbcs x8, x8, x16
adc x9, x9, xzr
stp x3, x4, [x2, #0]
stp x5, x6, [x2,#16]
stp x7, x8, [x2,#32]
ldp x3, x4, [x2,#48]
ldp x5, x6, [x2,#64]
ldp x7, x8, [x2,#80]
ldp x11, x12, [x0,#48]
ldp x13, x14, [x0,#64]
ldp x15, x16, [x0,#80]
// x9 = 2 - x9
neg x9, x9
add x9, x9, #2
subs x3, x3, x9
sbcs x3, x3, x11
sbcs x4, x4, x12
sbcs x5, x5, x13
sbcs x6, x6, x14
sbcs x7, x7, x15
sbcs x8, x8, x16
adc x9, xzr, xzr
ldp x11, x12, [x1,#48]
ldp x13, x14, [x1,#64]
ldp x15, x16, [x1,#80]
subs x3, x3, x11
sbcs x4, x4, x12
sbcs x5, x5, x13
sbcs x6, x6, x14
sbcs x7, x7, x15
sbcs x8, x8, x16
adc x9, x9, xzr
stp x3, x4, [x2,#48]
stp x5, x6, [x2,#64]
stp x7, x8, [x2,#80]
ldp x3, x4, [x2,#96]
ldp x11, x12, [x0,#96]
ldp x13, x14, [x1,#96]
// x9 = 2 - x9
neg x9, x9
add x9, x9, #2
subs x3, x3, x9
sbcs x3, x3, x11
sbcs x4, x4, x12
subs x3, x3, x13
sbc x4, x4, x14
stp x3, x4, [x2,#96]
ldp x29, x30, [sp],#16
ret
___
foreach (split("\n",$code)) {
s/\`([^\`]*)\`/eval($1)/ge;
print $_,"\n";
}
close STDOUT;

File diff suppressed because it is too large Load Diff

View File

@ -1,181 +0,0 @@
/********************************************************************************************
* SIDH: an efficient supersingular isogeny cryptography library
*
* Abstract: portable modular arithmetic for P503
*********************************************************************************************/
#include <openssl/base.h>
#if defined(OPENSSL_NO_ASM) || \
(!defined(OPENSSL_X86_64) && !defined(OPENSSL_AARCH64))
#include "../utils.h"
#include "../fpx.h"
// Global constants
extern const struct params_t sike_params;
static void digit_x_digit(const crypto_word_t a, const crypto_word_t b, crypto_word_t* c)
{ // Digit multiplication, digit * digit -> 2-digit result
crypto_word_t al, ah, bl, bh, temp;
crypto_word_t albl, albh, ahbl, ahbh, res1, res2, res3, carry;
crypto_word_t mask_low = (crypto_word_t)(-1) >> (sizeof(crypto_word_t)*4);
crypto_word_t mask_high = (crypto_word_t)(-1) << (sizeof(crypto_word_t)*4);
al = a & mask_low; // Low part
ah = a >> (sizeof(crypto_word_t) * 4); // High part
bl = b & mask_low;
bh = b >> (sizeof(crypto_word_t) * 4);
albl = al*bl;
albh = al*bh;
ahbl = ah*bl;
ahbh = ah*bh;
c[0] = albl & mask_low; // C00
res1 = albl >> (sizeof(crypto_word_t) * 4);
res2 = ahbl & mask_low;
res3 = albh & mask_low;
temp = res1 + res2 + res3;
carry = temp >> (sizeof(crypto_word_t) * 4);
c[0] ^= temp << (sizeof(crypto_word_t) * 4); // C01
res1 = ahbl >> (sizeof(crypto_word_t) * 4);
res2 = albh >> (sizeof(crypto_word_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 sike_fpadd(const felm_t a, const felm_t b, felm_t c)
{ // Modular addition, c = a+b mod p434.
// Inputs: a, b in [0, 2*p434-1]
// Output: c in [0, 2*p434-1]
unsigned int i, carry = 0;
crypto_word_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], sike_params.prime_x2[i], carry, c[i]);
}
mask = 0 - (crypto_word_t)carry;
carry = 0;
for (i = 0; i < NWORDS_FIELD; i++) {
ADDC(carry, c[i], sike_params.prime_x2[i] & mask, carry, c[i]);
}
}
void sike_fpsub(const felm_t a, const felm_t b, felm_t c)
{ // Modular subtraction, c = a-b mod p434.
// Inputs: a, b in [0, 2*p434-1]
// Output: c in [0, 2*p434-1]
unsigned int i, borrow = 0;
crypto_word_t mask;
for (i = 0; i < NWORDS_FIELD; i++) {
SUBC(borrow, a[i], b[i], borrow, c[i]);
}
mask = 0 - (crypto_word_t)borrow;
borrow = 0;
for (i = 0; i < NWORDS_FIELD; i++) {
ADDC(borrow, c[i], sike_params.prime_x2[i] & mask, borrow, c[i]);
}
}
void sike_mpmul(const felm_t a, const felm_t b, dfelm_t c)
{ // Multiprecision comba multiply, c = a*b, where lng(a) = lng(b) = NWORDS_FIELD.
unsigned int i, j;
crypto_word_t t = 0, u = 0, v = 0, UV[2];
unsigned int carry = 0;
for (i = 0; i < NWORDS_FIELD; 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_FIELD; i < 2*NWORDS_FIELD-1; i++) {
for (j = i-NWORDS_FIELD+1; j < NWORDS_FIELD; 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_FIELD-1] = v;
}
void sike_fprdc(felm_t ma, felm_t mc)
{ // Efficient Montgomery reduction using comba and exploiting the special form of the prime p434.
// mc = ma*R^-1 mod p434x2, where R = 2^448.
// If ma < 2^448*p434, the output mc is in the range [0, 2*p434-1].
// ma is assumed to be in Montgomery representation.
unsigned int i, j, carry, count = ZERO_WORDS;
crypto_word_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-ZERO_WORDS+1)) {
MUL(mc[j], sike_params.prime_p1[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], sike_params.prime_p1[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;
}
#endif // NO_ASM || (!X86_64 && !AARCH64)

View File

@ -1,128 +0,0 @@
/********************************************************************************************
* SIDH: an efficient supersingular isogeny cryptography library
*
* Abstract: supersingular isogeny parameters and generation of functions for P434
*********************************************************************************************/
#include "utils.h"
// Parameters for isogeny system "SIKE"
const struct params_t sike_params = {
.prime = {
U64_TO_WORDS(0xFFFFFFFFFFFFFFFF), U64_TO_WORDS(0xFFFFFFFFFFFFFFFF),
U64_TO_WORDS(0xFFFFFFFFFFFFFFFF), U64_TO_WORDS(0xFDC1767AE2FFFFFF),
U64_TO_WORDS(0x7BC65C783158AEA3), U64_TO_WORDS(0x6CFC5FD681C52056),
U64_TO_WORDS(0x0002341F27177344)
},
.prime_p1 = {
U64_TO_WORDS(0x0000000000000000), U64_TO_WORDS(0x0000000000000000),
U64_TO_WORDS(0x0000000000000000), U64_TO_WORDS(0xFDC1767AE3000000),
U64_TO_WORDS(0x7BC65C783158AEA3), U64_TO_WORDS(0x6CFC5FD681C52056),
U64_TO_WORDS(0x0002341F27177344)
},
.prime_x2 = {
U64_TO_WORDS(0xFFFFFFFFFFFFFFFE), U64_TO_WORDS(0xFFFFFFFFFFFFFFFF),
U64_TO_WORDS(0xFFFFFFFFFFFFFFFF), U64_TO_WORDS(0xFB82ECF5C5FFFFFF),
U64_TO_WORDS(0xF78CB8F062B15D47), U64_TO_WORDS(0xD9F8BFAD038A40AC),
U64_TO_WORDS(0x0004683E4E2EE688)
},
.A_gen = {
U64_TO_WORDS(0x05ADF455C5C345BF), U64_TO_WORDS(0x91935C5CC767AC2B),
U64_TO_WORDS(0xAFE4E879951F0257), U64_TO_WORDS(0x70E792DC89FA27B1),
U64_TO_WORDS(0xF797F526BB48C8CD), U64_TO_WORDS(0x2181DB6131AF621F),
U64_TO_WORDS(0x00000A1C08B1ECC4), // XPA0
U64_TO_WORDS(0x74840EB87CDA7788), U64_TO_WORDS(0x2971AA0ECF9F9D0B),
U64_TO_WORDS(0xCB5732BDF41715D5), U64_TO_WORDS(0x8CD8E51F7AACFFAA),
U64_TO_WORDS(0xA7F424730D7E419F), U64_TO_WORDS(0xD671EB919A179E8C),
U64_TO_WORDS(0x0000FFA26C5A924A), // XPA1
U64_TO_WORDS(0xFEC6E64588B7273B), U64_TO_WORDS(0xD2A626D74CBBF1C6),
U64_TO_WORDS(0xF8F58F07A78098C7), U64_TO_WORDS(0xE23941F470841B03),
U64_TO_WORDS(0x1B63EDA2045538DD), U64_TO_WORDS(0x735CFEB0FFD49215),
U64_TO_WORDS(0x0001C4CB77542876), // XQA0
U64_TO_WORDS(0xADB0F733C17FFDD6), U64_TO_WORDS(0x6AFFBD037DA0A050),
U64_TO_WORDS(0x680EC43DB144E02F), U64_TO_WORDS(0x1E2E5D5FF524E374),
U64_TO_WORDS(0xE2DDA115260E2995), U64_TO_WORDS(0xA6E4B552E2EDE508),
U64_TO_WORDS(0x00018ECCDDF4B53E), // XQA1
U64_TO_WORDS(0x01BA4DB518CD6C7D), U64_TO_WORDS(0x2CB0251FE3CC0611),
U64_TO_WORDS(0x259B0C6949A9121B), U64_TO_WORDS(0x60E17AC16D2F82AD),
U64_TO_WORDS(0x3AA41F1CE175D92D), U64_TO_WORDS(0x413FBE6A9B9BC4F3),
U64_TO_WORDS(0x00022A81D8D55643), // XRA0
U64_TO_WORDS(0xB8ADBC70FC82E54A), U64_TO_WORDS(0xEF9CDDB0D5FADDED),
U64_TO_WORDS(0x5820C734C80096A0), U64_TO_WORDS(0x7799994BAA96E0E4),
U64_TO_WORDS(0x044961599E379AF8), U64_TO_WORDS(0xDB2B94FBF09F27E2),
U64_TO_WORDS(0x0000B87FC716C0C6) // XRA1
},
.B_gen = {
U64_TO_WORDS(0x6E5497556EDD48A3), U64_TO_WORDS(0x2A61B501546F1C05),
U64_TO_WORDS(0xEB919446D049887D), U64_TO_WORDS(0x5864A4A69D450C4F),
U64_TO_WORDS(0xB883F276A6490D2B), U64_TO_WORDS(0x22CC287022D5F5B9),
U64_TO_WORDS(0x0001BED4772E551F), // XPB0
U64_TO_WORDS(0x0000000000000000), U64_TO_WORDS(0x0000000000000000),
U64_TO_WORDS(0x0000000000000000), U64_TO_WORDS(0x0000000000000000),
U64_TO_WORDS(0x0000000000000000), U64_TO_WORDS(0x0000000000000000),
U64_TO_WORDS(0x0000000000000000), // XPB1
U64_TO_WORDS(0xFAE2A3F93D8B6B8E), U64_TO_WORDS(0x494871F51700FE1C),
U64_TO_WORDS(0xEF1A94228413C27C), U64_TO_WORDS(0x498FF4A4AF60BD62),
U64_TO_WORDS(0xB00AD2A708267E8A), U64_TO_WORDS(0xF4328294E017837F),
U64_TO_WORDS(0x000034080181D8AE), // XQB0
U64_TO_WORDS(0x0000000000000000), U64_TO_WORDS(0x0000000000000000),
U64_TO_WORDS(0x0000000000000000), U64_TO_WORDS(0x0000000000000000),
U64_TO_WORDS(0x0000000000000000), U64_TO_WORDS(0x0000000000000000),
U64_TO_WORDS(0x0000000000000000), // XQB1
U64_TO_WORDS(0x283B34FAFEFDC8E4), U64_TO_WORDS(0x9208F44977C3E647),
U64_TO_WORDS(0x7DEAE962816F4E9A), U64_TO_WORDS(0x68A2BA8AA262EC9D),
U64_TO_WORDS(0x8176F112EA43F45B), U64_TO_WORDS(0x02106D022634F504),
U64_TO_WORDS(0x00007E8A50F02E37), // XRB0
U64_TO_WORDS(0xB378B7C1DA22CCB1), U64_TO_WORDS(0x6D089C99AD1D9230),
U64_TO_WORDS(0xEBE15711813E2369), U64_TO_WORDS(0x2B35A68239D48A53),
U64_TO_WORDS(0x445F6FD138407C93), U64_TO_WORDS(0xBEF93B29A3F6B54B),
U64_TO_WORDS(0x000173FA910377D3) // XRB1
},
.mont_R2 = {
U64_TO_WORDS(0x28E55B65DCD69B30), U64_TO_WORDS(0xACEC7367768798C2),
U64_TO_WORDS(0xAB27973F8311688D), U64_TO_WORDS(0x175CC6AF8D6C7C0B),
U64_TO_WORDS(0xABCD92BF2DDE347E), U64_TO_WORDS(0x69E16A61C7686D9A),
U64_TO_WORDS(0x000025A89BCDD12A)
},
.mont_one = {
U64_TO_WORDS(0x000000000000742C), U64_TO_WORDS(0x0000000000000000),
U64_TO_WORDS(0x0000000000000000), U64_TO_WORDS(0xB90FF404FC000000),
U64_TO_WORDS(0xD801A4FB559FACD4), U64_TO_WORDS(0xE93254545F77410C),
U64_TO_WORDS(0x0000ECEEA7BD2EDA)
},
.mont_six = {
U64_TO_WORDS(0x000000000002B90A), U64_TO_WORDS(0x0000000000000000),
U64_TO_WORDS(0x0000000000000000), U64_TO_WORDS(0x5ADCCB2822000000),
U64_TO_WORDS(0x187D24F39F0CAFB4), U64_TO_WORDS(0x9D353A4D394145A0),
U64_TO_WORDS(0x00012559A0403298)
},
.A_strat = {
0x30, 0x1C, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01,
0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x08, 0x04,
0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01,
0x02, 0x01, 0x01, 0x0D, 0x07, 0x04, 0x02, 0x01, 0x01, 0x02,
0x01, 0x01, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x05, 0x04,
0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
0x15, 0x0C, 0x07, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x05, 0x03, 0x02, 0x01,
0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x09, 0x05, 0x03,
0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x04,
0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01
},
.B_strat = {
0x42, 0x21, 0x11, 0x09, 0x05, 0x03, 0x02, 0x01, 0x01, 0x01,
0x01, 0x02, 0x01, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x01,
0x02, 0x01, 0x01, 0x08, 0x04, 0x02, 0x01, 0x01, 0x01, 0x02,
0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x10,
0x08, 0x04, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04,
0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x08, 0x04, 0x02, 0x01,
0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01,
0x01, 0x20, 0x10, 0x08, 0x04, 0x03, 0x01, 0x01, 0x01, 0x01,
0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01,
0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04, 0x02,
0x01, 0x01, 0x02, 0x01, 0x01, 0x10, 0x08, 0x04, 0x02, 0x01,
0x01, 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01,
0x01, 0x08, 0x04, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x04,
0x02, 0x01, 0x01, 0x02, 0x01, 0x01
}
};

283
third_party/sike/fpx.c vendored
View File

@ -1,283 +0,0 @@
/********************************************************************************************
* SIDH: an efficient supersingular isogeny cryptography library
*
* Abstract: core functions over GF(p) and GF(p^2)
*********************************************************************************************/
#include <openssl/base.h>
#include "utils.h"
#include "fpx.h"
extern const struct params_t sike_params;
// Multiprecision squaring, c = a^2 mod p.
static void fpsqr_mont(const felm_t ma, felm_t mc)
{
dfelm_t temp = {0};
sike_mpmul(ma, ma, temp);
sike_fprdc(temp, mc);
}
// Chain to compute a^(p-3)/4 using Montgomery arithmetic.
static void fpinv_chain_mont(felm_t a)
{
unsigned int i, j;
felm_t t[31], tt;
// Precomputed table
fpsqr_mont(a, tt);
sike_fpmul_mont(a, tt, t[0]);
for (i = 0; i <= 29; i++) sike_fpmul_mont(t[i], tt, t[i+1]);
sike_fpcopy(a, tt);
for (i = 0; i < 7; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[5], tt, tt);
for (i = 0; i < 10; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[14], tt, tt);
for (i = 0; i < 6; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[3], tt, tt);
for (i = 0; i < 6; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[23], tt, tt);
for (i = 0; i < 6; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[13], tt, tt);
for (i = 0; i < 6; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[24], tt, tt);
for (i = 0; i < 6; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[7], tt, tt);
for (i = 0; i < 8; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[12], tt, tt);
for (i = 0; i < 8; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[30], tt, tt);
for (i = 0; i < 6; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[1], tt, tt);
for (i = 0; i < 6; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[30], tt, tt);
for (i = 0; i < 7; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[21], tt, tt);
for (i = 0; i < 9; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[2], tt, tt);
for (i = 0; i < 9; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[19], tt, tt);
for (i = 0; i < 9; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[1], tt, tt);
for (i = 0; i < 7; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[24], tt, tt);
for (i = 0; i < 6; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[26], tt, tt);
for (i = 0; i < 6; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[16], tt, tt);
for (i = 0; i < 7; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[10], tt, tt);
for (i = 0; i < 7; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[6], tt, tt);
for (i = 0; i < 7; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[0], tt, tt);
for (i = 0; i < 9; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[20], tt, tt);
for (i = 0; i < 8; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[9], tt, tt);
for (i = 0; i < 6; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[25], tt, tt);
for (i = 0; i < 9; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[30], tt, tt);
for (i = 0; i < 6; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[26], tt, tt);
for (i = 0; i < 6; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(a, tt, tt);
for (i = 0; i < 7; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[28], tt, tt);
for (i = 0; i < 6; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[6], tt, tt);
for (i = 0; i < 6; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[10], tt, tt);
for (i = 0; i < 9; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[22], tt, tt);
for (j = 0; j < 35; j++) {
for (i = 0; i < 6; i++) fpsqr_mont(tt, tt);
sike_fpmul_mont(t[30], tt, tt);
}
sike_fpcopy(tt, a);
}
// Field inversion using Montgomery arithmetic, a = a^(-1)*R mod p.
static void fpinv_mont(felm_t a)
{
felm_t tt = {0};
sike_fpcopy(a, tt);
fpinv_chain_mont(tt);
fpsqr_mont(tt, tt);
fpsqr_mont(tt, tt);
sike_fpmul_mont(a, tt, a);
}
// Multiprecision addition, c = a+b, where lng(a) = lng(b) = nwords. Returns the carry bit.
#if defined(OPENSSL_NO_ASM) || (!defined(OPENSSL_X86_64) && !defined(OPENSSL_AARCH64))
inline static unsigned int mp_add(const felm_t a, const felm_t b, felm_t c, const unsigned int nwords) {
uint8_t carry = 0;
for (size_t i = 0; i < nwords; i++) {
ADDC(carry, a[i], b[i], carry, c[i]);
}
return carry;
}
// Multiprecision subtraction, c = a-b, where lng(a) = lng(b) = nwords. Returns the borrow bit.
inline static unsigned int mp_sub(const felm_t a, const felm_t b, felm_t c, const unsigned int nwords) {
uint32_t borrow = 0;
for (size_t i = 0; i < nwords; i++) {
SUBC(borrow, a[i], b[i], borrow, c[i]);
}
return borrow;
}
#endif
// Multiprecision addition, c = a+b.
inline static void mp_addfast(const felm_t a, const felm_t b, felm_t c)
{
#if defined(OPENSSL_NO_ASM) || (!defined(OPENSSL_X86_64) && !defined(OPENSSL_AARCH64))
mp_add(a, b, c, NWORDS_FIELD);
#else
sike_mpadd_asm(a, b, c);
#endif
}
// Multiprecision subtraction, c = a-b, where lng(a) = lng(b) = 2*NWORDS_FIELD.
// If c < 0 then returns mask = 0xFF..F, else mask = 0x00..0
inline static crypto_word_t mp_subfast(const dfelm_t a, const dfelm_t b, dfelm_t c) {
#if defined(OPENSSL_NO_ASM) || (!defined(OPENSSL_X86_64) && !defined(OPENSSL_AARCH64))
return (0 - (crypto_word_t)mp_sub(a, b, c, 2*NWORDS_FIELD));
#else
return sike_mpsubx2_asm(a, b, c);
#endif
}
// Multiprecision subtraction, c = c-a-b, where lng(a) = lng(b) = 2*NWORDS_FIELD.
// Inputs should be s.t. c > a and c > b
inline static void mp_dblsubfast(const dfelm_t a, const dfelm_t b, dfelm_t c) {
#if defined(OPENSSL_NO_ASM) || (!defined(OPENSSL_X86_64) && !defined(OPENSSL_AARCH64))
mp_sub(c, a, c, 2*NWORDS_FIELD);
mp_sub(c, b, c, 2*NWORDS_FIELD);
#else
sike_mpdblsubx2_asm(a, b, c);
#endif
}
// Copy a field element, c = a.
void sike_fpcopy(const felm_t a, felm_t c) {
for (size_t i = 0; i < NWORDS_FIELD; i++) {
c[i] = a[i];
}
}
// Field multiplication using Montgomery arithmetic, c = a*b*R^-1 mod prime, where R=2^768
void sike_fpmul_mont(const felm_t ma, const felm_t mb, felm_t mc)
{
dfelm_t temp = {0};
sike_mpmul(ma, mb, temp);
sike_fprdc(temp, mc);
}
// Conversion from Montgomery representation to standard representation,
// c = ma*R^(-1) mod p = a mod p, where ma in [0, p-1].
void sike_from_mont(const felm_t ma, felm_t c)
{
felm_t one = {0};
one[0] = 1;
sike_fpmul_mont(ma, one, c);
sike_fpcorrection(c);
}
// GF(p^2) squaring using Montgomery arithmetic, c = a^2 in GF(p^2).
// Inputs: a = a0+a1*i, where a0, a1 are in [0, 2*p-1]
// Output: c = c0+c1*i, where c0, c1 are in [0, 2*p-1]
void sike_fp2sqr_mont(const f2elm_t a, f2elm_t c) {
felm_t t1, t2, t3;
mp_addfast(a->c0, a->c1, t1); // t1 = a0+a1
sike_fpsub(a->c0, a->c1, t2); // t2 = a0-a1
mp_addfast(a->c0, a->c0, t3); // t3 = 2a0
sike_fpmul_mont(t1, t2, c->c0); // c0 = (a0+a1)(a0-a1)
sike_fpmul_mont(t3, a->c1, c->c1); // c1 = 2a0*a1
}
// Modular negation, a = -a mod p503.
// Input/output: a in [0, 2*p503-1]
void sike_fpneg(felm_t a) {
uint32_t borrow = 0;
for (size_t i = 0; i < NWORDS_FIELD; i++) {
SUBC(borrow, sike_params.prime_x2[i], a[i], borrow, a[i]);
}
}
// Modular division by two, c = a/2 mod p503.
// Input : a in [0, 2*p503-1]
// Output: c in [0, 2*p503-1]
void sike_fpdiv2(const felm_t a, felm_t c) {
uint32_t carry = 0;
crypto_word_t mask;
mask = 0 - (crypto_word_t)(a[0] & 1); // If a is odd compute a+p503
for (size_t i = 0; i < NWORDS_FIELD; i++) {
ADDC(carry, a[i], sike_params.prime[i] & mask, carry, c[i]);
}
// Multiprecision right shift by one.
for (size_t i = 0; i < NWORDS_FIELD-1; i++) {
c[i] = (c[i] >> 1) ^ (c[i+1] << (RADIX - 1));
}
c[NWORDS_FIELD-1] >>= 1;
}
// Modular correction to reduce field element a in [0, 2*p503-1] to [0, p503-1].
void sike_fpcorrection(felm_t a) {
uint32_t borrow = 0;
crypto_word_t mask;
for (size_t i = 0; i < NWORDS_FIELD; i++) {
SUBC(borrow, a[i], sike_params.prime[i], borrow, a[i]);
}
mask = 0 - (crypto_word_t)borrow;
borrow = 0;
for (size_t i = 0; i < NWORDS_FIELD; i++) {
ADDC(borrow, a[i], sike_params.prime[i] & mask, borrow, a[i]);
}
}
// GF(p^2) multiplication using Montgomery arithmetic, c = a*b in GF(p^2).
// Inputs: a = a0+a1*i and b = b0+b1*i, where a0, a1, b0, b1 are in [0, 2*p-1]
// Output: c = c0+c1*i, where c0, c1 are in [0, 2*p-1]
void sike_fp2mul_mont(const f2elm_t a, const f2elm_t b, f2elm_t c) {
felm_t t1, t2;
dfelm_t tt1, tt2, tt3;
crypto_word_t mask;
mp_addfast(a->c0, a->c1, t1); // t1 = a0+a1
mp_addfast(b->c0, b->c1, t2); // t2 = b0+b1
sike_mpmul(a->c0, b->c0, tt1); // tt1 = a0*b0
sike_mpmul(a->c1, b->c1, tt2); // tt2 = a1*b1
sike_mpmul(t1, t2, tt3); // tt3 = (a0+a1)*(b0+b1)
mp_dblsubfast(tt1, tt2, tt3); // tt3 = (a0+a1)*(b0+b1) - a0*b0 - a1*b1
mask = mp_subfast(tt1, tt2, tt1); // tt1 = a0*b0 - a1*b1. If tt1 < 0 then mask = 0xFF..F, else if tt1 >= 0 then mask = 0x00..0
for (size_t i = 0; i < NWORDS_FIELD; i++) {
t1[i] = sike_params.prime[i] & mask;
}
sike_fprdc(tt3, c->c1); // c[1] = (a0+a1)*(b0+b1) - a0*b0 - a1*b1
mp_addfast(&tt1[NWORDS_FIELD], t1, &tt1[NWORDS_FIELD]);
sike_fprdc(tt1, c->c0); // c[0] = a0*b0 - a1*b1
}
// GF(p^2) inversion using Montgomery arithmetic, a = (a0-i*a1)/(a0^2+a1^2).
void sike_fp2inv_mont(f2elm_t a) {
f2elm_t t1;
fpsqr_mont(a->c0, t1->c0); // t10 = a0^2
fpsqr_mont(a->c1, t1->c1); // t11 = a1^2
sike_fpadd(t1->c0, t1->c1, t1->c0); // t10 = a0^2+a1^2
fpinv_mont(t1->c0); // t10 = (a0^2+a1^2)^-1
sike_fpneg(a->c1); // a = a0-i*a1
sike_fpmul_mont(a->c0, t1->c0, a->c0);
sike_fpmul_mont(a->c1, t1->c0, a->c1); // a = (a0-i*a1)*(a0^2+a1^2)^-1
}

113
third_party/sike/fpx.h vendored
View File

@ -1,113 +0,0 @@
#ifndef FPX_H_
#define FPX_H_
#include "utils.h"
#if defined(__cplusplus)
extern "C" {
#endif
// Modular addition, c = a+b mod p.
void sike_fpadd(const felm_t a, const felm_t b, felm_t c);
// Modular subtraction, c = a-b mod p.
void sike_fpsub(const felm_t a, const felm_t b, felm_t c);
// Modular division by two, c = a/2 mod p.
void sike_fpdiv2(const felm_t a, felm_t c);
// Modular correction to reduce field element a in [0, 2*p-1] to [0, p-1].
void sike_fpcorrection(felm_t a);
// Multiprecision multiply, c = a*b, where lng(a) = lng(b) = nwords.
void sike_mpmul(const felm_t a, const felm_t b, dfelm_t c);
// 443-bit Montgomery reduction, c = a mod p. Buffer 'a' is modified after
// call returns.
void sike_fprdc(dfelm_t a, felm_t c);
// Double 2x443-bit multiprecision subtraction, c = c-a-b
void sike_mpdblsubx2_asm(const felm_t a, const felm_t b, felm_t c);
// Multiprecision subtraction, c = a-b
crypto_word_t sike_mpsubx2_asm(const dfelm_t a, const dfelm_t b, dfelm_t c);
// 443-bit multiprecision addition, c = a+b
void sike_mpadd_asm(const felm_t a, const felm_t b, felm_t c);
// Modular negation, a = -a mod p.
void sike_fpneg(felm_t a);
// Copy of a field element, c = a
void sike_fpcopy(const felm_t a, felm_t c);
// Copy a field element, c = a.
void sike_fpzero(felm_t a);
// If option = 0xFF...FF x=y; y=x, otherwise swap doesn't happen. Constant time.
void sike_cswap_asm(point_proj_t x, point_proj_t y, const crypto_word_t option);
// Conversion from Montgomery representation to standard representation,
// c = ma*R^(-1) mod p = a mod p, where ma in [0, p-1].
void sike_from_mont(const felm_t ma, felm_t c);
// Field multiplication using Montgomery arithmetic, c = a*b*R^-1 mod p443, where R=2^768
void sike_fpmul_mont(const felm_t ma, const felm_t mb, felm_t mc);
// GF(p443^2) multiplication using Montgomery arithmetic, c = a*b in GF(p443^2)
void sike_fp2mul_mont(const f2elm_t a, const f2elm_t b, f2elm_t c);
// GF(p443^2) inversion using Montgomery arithmetic, a = (a0-i*a1)/(a0^2+a1^2)
void sike_fp2inv_mont(f2elm_t a);
// GF(p^2) squaring using Montgomery arithmetic, c = a^2 in GF(p^2).
void sike_fp2sqr_mont(const f2elm_t a, f2elm_t c);
// Modular correction, a = a in GF(p^2).
void sike_fp2correction(f2elm_t a);
#if defined(__cplusplus)
} // extern C
#endif
// GF(p^2) addition, c = a+b in GF(p^2).
#define sike_fp2add(a, b, c) \
do { \
sike_fpadd(a->c0, b->c0, c->c0); \
sike_fpadd(a->c1, b->c1, c->c1); \
} while(0)
// GF(p^2) subtraction, c = a-b in GF(p^2).
#define sike_fp2sub(a,b,c) \
do { \
sike_fpsub(a->c0, b->c0, c->c0); \
sike_fpsub(a->c1, b->c1, c->c1); \
} while(0)
// Copy a GF(p^2) element, c = a.
#define sike_fp2copy(a, c) \
do { \
sike_fpcopy(a->c0, c->c0); \
sike_fpcopy(a->c1, c->c1); \
} while(0)
// GF(p^2) negation, a = -a in GF(p^2).
#define sike_fp2neg(a) \
do { \
sike_fpneg(a->c0); \
sike_fpneg(a->c1); \
} while(0)
// GF(p^2) division by two, c = a/2 in GF(p^2).
#define sike_fp2div2(a, c) \
do { \
sike_fpdiv2(a->c0, c->c0); \
sike_fpdiv2(a->c1, c->c1); \
} while(0)
// Modular correction, a = a in GF(p^2).
#define sike_fp2correction(a) \
do { \
sike_fpcorrection(a->c0); \
sike_fpcorrection(a->c1); \
} while(0)
// Conversion of a GF(p^2) element to Montgomery representation,
// mc_i = a_i*R^2*R^(-1) = a_i*R in GF(p^2).
#define sike_to_fp2mont(a, mc) \
do { \
sike_fpmul_mont(a->c0, sike_params.mont_R2, mc->c0); \
sike_fpmul_mont(a->c1, sike_params.mont_R2, mc->c1); \
} while (0)
// Conversion of a GF(p^2) element from Montgomery representation to standard representation,
// c_i = ma_i*R^(-1) = a_i in GF(p^2).
#define sike_from_fp2mont(ma, c) \
do { \
sike_from_mont(ma->c0, c->c0); \
sike_from_mont(ma->c1, c->c1); \
} while(0)
#endif // FPX_H_

View File

@ -1,260 +0,0 @@
/********************************************************************************************
* SIDH: an efficient supersingular isogeny cryptography library
*
* Abstract: elliptic curve and isogeny functions
*********************************************************************************************/
#include "utils.h"
#include "isogeny.h"
#include "fpx.h"
static void xDBL(const point_proj_t P, point_proj_t Q, const f2elm_t A24plus, const 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 constants A+2C and 4C.
// Output: projective Montgomery x-coordinates Q = 2*P = (X2:Z2).
f2elm_t t0, t1;
sike_fp2sub(P->X, P->Z, t0); // t0 = X1-Z1
sike_fp2add(P->X, P->Z, t1); // t1 = X1+Z1
sike_fp2sqr_mont(t0, t0); // t0 = (X1-Z1)^2
sike_fp2sqr_mont(t1, t1); // t1 = (X1+Z1)^2
sike_fp2mul_mont(C24, t0, Q->Z); // Z2 = C24*(X1-Z1)^2
sike_fp2mul_mont(t1, Q->Z, Q->X); // X2 = C24*(X1-Z1)^2*(X1+Z1)^2
sike_fp2sub(t1, t0, t1); // t1 = (X1+Z1)^2-(X1-Z1)^2
sike_fp2mul_mont(A24plus, t1, t0); // t0 = A24plus*[(X1+Z1)^2-(X1-Z1)^2]
sike_fp2add(Q->Z, t0, Q->Z); // Z2 = A24plus*[(X1+Z1)^2-(X1-Z1)^2] + C24*(X1-Z1)^2
sike_fp2mul_mont(Q->Z, t1, Q->Z); // Z2 = [A24plus*[(X1+Z1)^2-(X1-Z1)^2] + C24*(X1-Z1)^2]*[(X1+Z1)^2-(X1-Z1)^2]
}
void sike_xDBLe(const point_proj_t P, point_proj_t Q, const f2elm_t A24plus, const f2elm_t C24, size_t 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 constants A+2C and 4C.
// Output: projective Montgomery x-coordinates Q <- (2^e)*P.
memmove(Q, P, sizeof(*P));
for (size_t i = 0; i < e; i++) {
xDBL(Q, Q, A24plus, C24);
}
}
void sike_get_4_isog(const point_proj_t P, f2elm_t A24plus, f2elm_t C24, 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 coefficients A+2C/4C and the 3 coefficients
// that are used to evaluate the isogeny at a point in eval_4_isog().
sike_fp2sub(P->X, P->Z, coeff[1]); // coeff[1] = X4-Z4
sike_fp2add(P->X, P->Z, coeff[2]); // coeff[2] = X4+Z4
sike_fp2sqr_mont(P->Z, coeff[0]); // coeff[0] = Z4^2
sike_fp2add(coeff[0], coeff[0], coeff[0]); // coeff[0] = 2*Z4^2
sike_fp2sqr_mont(coeff[0], C24); // C24 = 4*Z4^4
sike_fp2add(coeff[0], coeff[0], coeff[0]); // coeff[0] = 4*Z4^2
sike_fp2sqr_mont(P->X, A24plus); // A24plus = X4^2
sike_fp2add(A24plus, A24plus, A24plus); // A24plus = 2*X4^2
sike_fp2sqr_mont(A24plus, A24plus); // A24plus = 4*X4^4
}
void sike_eval_4_isog(point_proj_t P, 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 3 coefficients in coeff (computed in the function get_4_isog()).
// 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.
f2elm_t t0, t1;
sike_fp2add(P->X, P->Z, t0); // t0 = X+Z
sike_fp2sub(P->X, P->Z, t1); // t1 = X-Z
sike_fp2mul_mont(t0, coeff[1], P->X); // X = (X+Z)*coeff[1]
sike_fp2mul_mont(t1, coeff[2], P->Z); // Z = (X-Z)*coeff[2]
sike_fp2mul_mont(t0, t1, t0); // t0 = (X+Z)*(X-Z)
sike_fp2mul_mont(t0, coeff[0], t0); // t0 = coeff[0]*(X+Z)*(X-Z)
sike_fp2add(P->X, P->Z, t1); // t1 = (X-Z)*coeff[2] + (X+Z)*coeff[1]
sike_fp2sub(P->X, P->Z, P->Z); // Z = (X-Z)*coeff[2] - (X+Z)*coeff[1]
sike_fp2sqr_mont(t1, t1); // t1 = [(X-Z)*coeff[2] + (X+Z)*coeff[1]]^2
sike_fp2sqr_mont(P->Z, P->Z); // Z = [(X-Z)*coeff[2] - (X+Z)*coeff[1]]^2
sike_fp2add(t1, t0, P->X); // X = coeff[0]*(X+Z)*(X-Z) + [(X-Z)*coeff[2] + (X+Z)*coeff[1]]^2
sike_fp2sub(P->Z, t0, t0); // t0 = [(X-Z)*coeff[2] - (X+Z)*coeff[1]]^2 - coeff[0]*(X+Z)*(X-Z)
sike_fp2mul_mont(P->X, t1, P->X); // Xfinal
sike_fp2mul_mont(P->Z, t0, P->Z); // Zfinal
}
void sike_xTPL(const point_proj_t P, point_proj_t Q, const f2elm_t A24minus, const f2elm_t A24plus)
{ // 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 constants A24plus = A+2C and A24minus = A-2C.
// Output: projective Montgomery x-coordinates Q = 3*P = (X3:Z3).
f2elm_t t0, t1, t2, t3, t4, t5, t6;
sike_fp2sub(P->X, P->Z, t0); // t0 = X-Z
sike_fp2sqr_mont(t0, t2); // t2 = (X-Z)^2
sike_fp2add(P->X, P->Z, t1); // t1 = X+Z
sike_fp2sqr_mont(t1, t3); // t3 = (X+Z)^2
sike_fp2add(t0, t1, t4); // t4 = 2*X
sike_fp2sub(t1, t0, t0); // t0 = 2*Z
sike_fp2sqr_mont(t4, t1); // t1 = 4*X^2
sike_fp2sub(t1, t3, t1); // t1 = 4*X^2 - (X+Z)^2
sike_fp2sub(t1, t2, t1); // t1 = 4*X^2 - (X+Z)^2 - (X-Z)^2
sike_fp2mul_mont(t3, A24plus, t5); // t5 = A24plus*(X+Z)^2
sike_fp2mul_mont(t3, t5, t3); // t3 = A24plus*(X+Z)^3
sike_fp2mul_mont(A24minus, t2, t6); // t6 = A24minus*(X-Z)^2
sike_fp2mul_mont(t2, t6, t2); // t2 = A24minus*(X-Z)^3
sike_fp2sub(t2, t3, t3); // t3 = A24minus*(X-Z)^3 - coeff*(X+Z)^3
sike_fp2sub(t5, t6, t2); // t2 = A24plus*(X+Z)^2 - A24minus*(X-Z)^2
sike_fp2mul_mont(t1, t2, t1); // t1 = [4*X^2 - (X+Z)^2 - (X-Z)^2]*[A24plus*(X+Z)^2 - A24minus*(X-Z)^2]
sike_fp2add(t3, t1, t2); // t2 = [4*X^2 - (X+Z)^2 - (X-Z)^2]*[A24plus*(X+Z)^2 - A24minus*(X-Z)^2] + A24minus*(X-Z)^3 - coeff*(X+Z)^3
sike_fp2sqr_mont(t2, t2); // t2 = t2^2
sike_fp2mul_mont(t4, t2, Q->X); // X3 = 2*X*t2
sike_fp2sub(t3, t1, t1); // t1 = A24minus*(X-Z)^3 - A24plus*(X+Z)^3 - [4*X^2 - (X+Z)^2 - (X-Z)^2]*[A24plus*(X+Z)^2 - A24minus*(X-Z)^2]
sike_fp2sqr_mont(t1, t1); // t1 = t1^2
sike_fp2mul_mont(t0, t1, Q->Z); // Z3 = 2*Z*t1
}
void sike_xTPLe(const point_proj_t P, point_proj_t Q, const f2elm_t A24minus, const f2elm_t A24plus, size_t 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 constants A24plus = A+2C and A24minus = A-2C.
// Output: projective Montgomery x-coordinates Q <- (3^e)*P.
memmove(Q, P, sizeof(*P));
for (size_t i = 0; i < e; i++) {
sike_xTPL(Q, Q, A24minus, A24plus);
}
}
void sike_get_3_isog(const point_proj_t P, f2elm_t A24minus, f2elm_t A24plus, f2elm_t* coeff)
{ // 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.
f2elm_t t0, t1, t2, t3, t4;
sike_fp2sub(P->X, P->Z, coeff[0]); // coeff0 = X-Z
sike_fp2sqr_mont(coeff[0], t0); // t0 = (X-Z)^2
sike_fp2add(P->X, P->Z, coeff[1]); // coeff1 = X+Z
sike_fp2sqr_mont(coeff[1], t1); // t1 = (X+Z)^2
sike_fp2add(t0, t1, t2); // t2 = (X+Z)^2 + (X-Z)^2
sike_fp2add(coeff[0], coeff[1], t3); // t3 = 2*X
sike_fp2sqr_mont(t3, t3); // t3 = 4*X^2
sike_fp2sub(t3, t2, t3); // t3 = 4*X^2 - (X+Z)^2 - (X-Z)^2
sike_fp2add(t1, t3, t2); // t2 = 4*X^2 - (X-Z)^2
sike_fp2add(t3, t0, t3); // t3 = 4*X^2 - (X+Z)^2
sike_fp2add(t0, t3, t4); // t4 = 4*X^2 - (X+Z)^2 + (X-Z)^2
sike_fp2add(t4, t4, t4); // t4 = 2(4*X^2 - (X+Z)^2 + (X-Z)^2)
sike_fp2add(t1, t4, t4); // t4 = 8*X^2 - (X+Z)^2 + 2*(X-Z)^2
sike_fp2mul_mont(t2, t4, A24minus); // A24minus = [4*X^2 - (X-Z)^2]*[8*X^2 - (X+Z)^2 + 2*(X-Z)^2]
sike_fp2add(t1, t2, t4); // t4 = 4*X^2 + (X+Z)^2 - (X-Z)^2
sike_fp2add(t4, t4, t4); // t4 = 2(4*X^2 + (X+Z)^2 - (X-Z)^2)
sike_fp2add(t0, t4, t4); // t4 = 8*X^2 + 2*(X+Z)^2 - (X-Z)^2
sike_fp2mul_mont(t3, t4, t4); // t4 = [4*X^2 - (X+Z)^2]*[8*X^2 + 2*(X+Z)^2 - (X-Z)^2]
sike_fp2sub(t4, A24minus, t0); // t0 = [4*X^2 - (X+Z)^2]*[8*X^2 + 2*(X+Z)^2 - (X-Z)^2] - [4*X^2 - (X-Z)^2]*[8*X^2 - (X+Z)^2 + 2*(X-Z)^2]
sike_fp2add(A24minus, t0, A24plus); // A24plus = 8*X^2 - (X+Z)^2 + 2*(X-Z)^2
}
void sike_eval_3_isog(point_proj_t Q, f2elm_t* coeff)
{ // Computes the 3-isogeny R=phi(X:Z), given projective point (X3:Z3) of order 3 on a Montgomery curve and
// a point P with 2 coefficients in coeff (computed in the function get_3_isog()).
// Inputs: projective points P = (X3:Z3) and Q = (X:Z).
// Output: the projective point Q <- phi(Q) = (X3:Z3).
f2elm_t t0, t1, t2;
sike_fp2add(Q->X, Q->Z, t0); // t0 = X+Z
sike_fp2sub(Q->X, Q->Z, t1); // t1 = X-Z
sike_fp2mul_mont(t0, coeff[0], t0); // t0 = coeff0*(X+Z)
sike_fp2mul_mont(t1, coeff[1], t1); // t1 = coeff1*(X-Z)
sike_fp2add(t0, t1, t2); // t2 = coeff0*(X+Z) + coeff1*(X-Z)
sike_fp2sub(t1, t0, t0); // t0 = coeff1*(X-Z) - coeff0*(X+Z)
sike_fp2sqr_mont(t2, t2); // t2 = [coeff0*(X+Z) + coeff1*(X-Z)]^2
sike_fp2sqr_mont(t0, t0); // t0 = [coeff1*(X-Z) - coeff0*(X+Z)]^2
sike_fp2mul_mont(Q->X, t2, Q->X); // X3final = X*[coeff0*(X+Z) + coeff1*(X-Z)]^2
sike_fp2mul_mont(Q->Z, t0, Q->Z); // Z3final = Z*[coeff1*(X-Z) - coeff0*(X+Z)]^2
}
void sike_inv_3_way(f2elm_t z1, f2elm_t z2, f2elm_t z3)
{ // 3-way simultaneous inversion
// Input: z1,z2,z3
// Output: 1/z1,1/z2,1/z3 (override inputs).
f2elm_t t0, t1, t2, t3;
sike_fp2mul_mont(z1, z2, t0); // t0 = z1*z2
sike_fp2mul_mont(z3, t0, t1); // t1 = z1*z2*z3
sike_fp2inv_mont(t1); // t1 = 1/(z1*z2*z3)
sike_fp2mul_mont(z3, t1, t2); // t2 = 1/(z1*z2)
sike_fp2mul_mont(t2, z2, t3); // t3 = 1/z1
sike_fp2mul_mont(t2, z1, z2); // z2 = 1/z2
sike_fp2mul_mont(t0, t1, z3); // z3 = 1/z3
sike_fp2copy(t3, z1); // z1 = 1/z1
}
void sike_get_A(const f2elm_t xP, const f2elm_t xQ, const f2elm_t xR, f2elm_t A)
{ // 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.
f2elm_t t0, t1, one = F2ELM_INIT;
extern const struct params_t sike_params;
sike_fpcopy(sike_params.mont_one, one->c0);
sike_fp2add(xP, xQ, t1); // t1 = xP+xQ
sike_fp2mul_mont(xP, xQ, t0); // t0 = xP*xQ
sike_fp2mul_mont(xR, t1, A); // A = xR*t1
sike_fp2add(t0, A, A); // A = A+t0
sike_fp2mul_mont(t0, xR, t0); // t0 = t0*xR
sike_fp2sub(A, one, A); // A = A-1
sike_fp2add(t0, t0, t0); // t0 = t0+t0
sike_fp2add(t1, xR, t1); // t1 = t1+xR
sike_fp2add(t0, t0, t0); // t0 = t0+t0
sike_fp2sqr_mont(A, A); // A = A^2
sike_fp2inv_mont(t0); // t0 = 1/t0
sike_fp2mul_mont(A, t0, A); // A = A*t0
sike_fp2sub(A, t1, A); // Afinal = A-t1
}
void sike_j_inv(const f2elm_t A, const f2elm_t C, 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 the j-invariant of the 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.
f2elm_t t0, t1;
sike_fp2sqr_mont(A, jinv); // jinv = A^2
sike_fp2sqr_mont(C, t1); // t1 = C^2
sike_fp2add(t1, t1, t0); // t0 = t1+t1
sike_fp2sub(jinv, t0, t0); // t0 = jinv-t0
sike_fp2sub(t0, t1, t0); // t0 = t0-t1
sike_fp2sub(t0, t1, jinv); // jinv = t0-t1
sike_fp2sqr_mont(t1, t1); // t1 = t1^2
sike_fp2mul_mont(jinv, t1, jinv); // jinv = jinv*t1
sike_fp2add(t0, t0, t0); // t0 = t0+t0
sike_fp2add(t0, t0, t0); // t0 = t0+t0
sike_fp2sqr_mont(t0, t1); // t1 = t0^2
sike_fp2mul_mont(t0, t1, t0); // t0 = t0*t1
sike_fp2add(t0, t0, t0); // t0 = t0+t0
sike_fp2add(t0, t0, t0); // t0 = t0+t0
sike_fp2inv_mont(jinv); // jinv = 1/jinv
sike_fp2mul_mont(jinv, t0, jinv); // jinv = t0*jinv
}
void sike_xDBLADD(point_proj_t P, point_proj_t Q, const f2elm_t xPQ, const 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.
f2elm_t t0, t1, t2;
sike_fp2add(P->X, P->Z, t0); // t0 = XP+ZP
sike_fp2sub(P->X, P->Z, t1); // t1 = XP-ZP
sike_fp2sqr_mont(t0, P->X); // XP = (XP+ZP)^2
sike_fp2sub(Q->X, Q->Z, t2); // t2 = XQ-ZQ
sike_fp2correction(t2);
sike_fp2add(Q->X, Q->Z, Q->X); // XQ = XQ+ZQ
sike_fp2mul_mont(t0, t2, t0); // t0 = (XP+ZP)*(XQ-ZQ)
sike_fp2sqr_mont(t1, P->Z); // ZP = (XP-ZP)^2
sike_fp2mul_mont(t1, Q->X, t1); // t1 = (XP-ZP)*(XQ+ZQ)
sike_fp2sub(P->X, P->Z, t2); // t2 = (XP+ZP)^2-(XP-ZP)^2
sike_fp2mul_mont(P->X, P->Z, P->X); // XP = (XP+ZP)^2*(XP-ZP)^2
sike_fp2mul_mont(t2, A24, Q->X); // XQ = A24*[(XP+ZP)^2-(XP-ZP)^2]
sike_fp2sub(t0, t1, Q->Z); // ZQ = (XP+ZP)*(XQ-ZQ)-(XP-ZP)*(XQ+ZQ)
sike_fp2add(Q->X, P->Z, P->Z); // ZP = A24*[(XP+ZP)^2-(XP-ZP)^2]+(XP-ZP)^2
sike_fp2add(t0, t1, Q->X); // XQ = (XP+ZP)*(XQ-ZQ)+(XP-ZP)*(XQ+ZQ)
sike_fp2mul_mont(P->Z, t2, P->Z); // ZP = [A24*[(XP+ZP)^2-(XP-ZP)^2]+(XP-ZP)^2]*[(XP+ZP)^2-(XP-ZP)^2]
sike_fp2sqr_mont(Q->Z, Q->Z); // ZQ = [(XP+ZP)*(XQ-ZQ)-(XP-ZP)*(XQ+ZQ)]^2
sike_fp2sqr_mont(Q->X, Q->X); // XQ = [(XP+ZP)*(XQ-ZQ)+(XP-ZP)*(XQ+ZQ)]^2
sike_fp2mul_mont(Q->Z, xPQ, Q->Z); // ZQ = xPQ*[(XP+ZP)*(XQ-ZQ)-(XP-ZP)*(XQ+ZQ)]^2
}

View File

@ -1,49 +0,0 @@
#ifndef ISOGENY_H_
#define ISOGENY_H_
// Computes [2^e](X:Z) on Montgomery curve with projective
// constant via e repeated doublings.
void sike_xDBLe(
const point_proj_t P, point_proj_t Q, const f2elm_t A24plus,
const f2elm_t C24, size_t e);
// Simultaneous doubling and differential addition.
void sike_xDBLADD(
point_proj_t P, point_proj_t Q, const f2elm_t xPQ,
const f2elm_t A24);
// Tripling of a Montgomery point in projective coordinates (X:Z).
void sike_xTPL(
const point_proj_t P, point_proj_t Q, const f2elm_t A24minus,
const f2elm_t A24plus);
// Computes [3^e](X:Z) on Montgomery curve with projective constant
// via e repeated triplings.
void sike_xTPLe(
const point_proj_t P, point_proj_t Q, const f2elm_t A24minus,
const f2elm_t A24plus, size_t e);
// 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 sike_get_A(
const f2elm_t xP, const f2elm_t xQ, const f2elm_t xR, f2elm_t A);
// Computes the j-invariant of a Montgomery curve with projective constant.
void sike_j_inv(
const f2elm_t A, const f2elm_t C, f2elm_t jinv);
// Computes the corresponding 4-isogeny of a projective Montgomery
// point (X4:Z4) of order 4.
void sike_get_4_isog(
const point_proj_t P, f2elm_t A24plus, f2elm_t C24, f2elm_t* coeff);
// Computes the corresponding 3-isogeny of a projective Montgomery
// point (X3:Z3) of order 3.
void sike_get_3_isog(
const point_proj_t P, f2elm_t A24minus, f2elm_t A24plus,
f2elm_t* coeff);
// Computes the 3-isogeny R=phi(X:Z), given projective point (X3:Z3)
// of order 3 on a Montgomery curve and a point P with coefficients given in coeff.
void sike_eval_3_isog(
point_proj_t Q, f2elm_t* coeff);
// Evaluates the isogeny at the point (X:Z) in the domain of the isogeny.
void sike_eval_4_isog(
point_proj_t P, f2elm_t* coeff);
// 3-way simultaneous inversion
void sike_inv_3_way(
f2elm_t z1, f2elm_t z2, f2elm_t z3);
#endif // ISOGENY_H_

View File

@ -1,531 +0,0 @@
/********************************************************************************************
* SIDH: an efficient supersingular isogeny cryptography library
*
* Abstract: supersingular isogeny key encapsulation (SIKE) protocol
*********************************************************************************************/
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <openssl/bn.h>
#include <openssl/base.h>
#include <openssl/rand.h>
#include <openssl/mem.h>
#include <openssl/sha.h>
#include "utils.h"
#include "isogeny.h"
#include "fpx.h"
extern const struct params_t sike_params;
// SIDH_JINV_BYTESZ is a number of bytes used for encoding j-invariant.
#define SIDH_JINV_BYTESZ 110U
// SIDH_PRV_A_BITSZ is a number of bits of SIDH private key (2-isogeny)
#define SIDH_PRV_A_BITSZ 216U
// SIDH_PRV_A_BITSZ is a number of bits of SIDH private key (3-isogeny)
#define SIDH_PRV_B_BITSZ 217U
// MAX_INT_POINTS_ALICE is a number of points used in 2-isogeny tree computation
#define MAX_INT_POINTS_ALICE 7U
// MAX_INT_POINTS_ALICE is a number of points used in 3-isogeny tree computation
#define MAX_INT_POINTS_BOB 8U
// Swap points.
// If option = 0 then P <- P and Q <- Q, else if option = 0xFF...FF then P <- Q and Q <- P
#if !defined(OPENSSL_X86_64) || defined(OPENSSL_NO_ASM)
static void sike_cswap(point_proj_t P, point_proj_t Q, const crypto_word_t option)
{
crypto_word_t temp;
for (size_t i = 0; i < NWORDS_FIELD; i++) {
temp = option & (P->X->c0[i] ^ Q->X->c0[i]);
P->X->c0[i] = temp ^ P->X->c0[i];
Q->X->c0[i] = temp ^ Q->X->c0[i];
temp = option & (P->Z->c0[i] ^ Q->Z->c0[i]);
P->Z->c0[i] = temp ^ P->Z->c0[i];
Q->Z->c0[i] = temp ^ Q->Z->c0[i];
temp = option & (P->X->c1[i] ^ Q->X->c1[i]);
P->X->c1[i] = temp ^ P->X->c1[i];
Q->X->c1[i] = temp ^ Q->X->c1[i];
temp = option & (P->Z->c1[i] ^ Q->Z->c1[i]);
P->Z->c1[i] = temp ^ P->Z->c1[i];
Q->Z->c1[i] = temp ^ Q->Z->c1[i];
}
}
#endif
// Swap points.
// If option = 0 then P <- P and Q <- Q, else if option = 0xFF...FF then P <- Q and Q <- P
static inline void sike_fp2cswap(point_proj_t P, point_proj_t Q, const crypto_word_t option)
{
#if defined(OPENSSL_X86_64) && !defined(OPENSSL_NO_ASM)
sike_cswap_asm(P, Q, option);
#else
sike_cswap(P, Q, option);
#endif
}
static void ladder3Pt(
const f2elm_t xP, const f2elm_t xQ, const f2elm_t xPQ, const uint8_t* m,
int is_A, point_proj_t R, const f2elm_t A) {
point_proj_t R0 = POINT_PROJ_INIT, R2 = POINT_PROJ_INIT;
f2elm_t A24 = F2ELM_INIT;
crypto_word_t mask;
int bit, swap, prevbit = 0;
const size_t nbits = is_A?SIDH_PRV_A_BITSZ:SIDH_PRV_B_BITSZ;
// Initializing constant
sike_fpcopy(sike_params.mont_one, A24[0].c0);
sike_fp2add(A24, A24, A24);
sike_fp2add(A, A24, A24);
sike_fp2div2(A24, A24);
sike_fp2div2(A24, A24); // A24 = (A+2)/4
// Initializing points
sike_fp2copy(xQ, R0->X);
sike_fpcopy(sike_params.mont_one, R0->Z[0].c0);
sike_fp2copy(xPQ, R2->X);
sike_fpcopy(sike_params.mont_one, R2->Z[0].c0);
sike_fp2copy(xP, R->X);
sike_fpcopy(sike_params.mont_one, R->Z[0].c0);
memset(R->Z->c1, 0, sizeof(R->Z->c1));
// Main loop
for (size_t i = 0; i < nbits; i++) {
bit = (m[i >> 3] >> (i & 7)) & 1;
swap = bit ^ prevbit;
prevbit = bit;
mask = 0 - (crypto_word_t)swap;
sike_fp2cswap(R, R2, mask);
sike_xDBLADD(R0, R2, R->X, A24);
sike_fp2mul_mont(R2->X, R->Z, R2->X);
}
mask = 0 - (crypto_word_t)prevbit;
sike_fp2cswap(R, R2, mask);
}
// Initialization of basis points
static inline void sike_init_basis(const crypto_word_t *gen, f2elm_t XP, f2elm_t XQ, f2elm_t XR) {
sike_fpcopy(gen, XP->c0);
sike_fpcopy(gen + NWORDS_FIELD, XP->c1);
sike_fpcopy(gen + 2*NWORDS_FIELD, XQ->c0);
sike_fpcopy(gen + 3*NWORDS_FIELD, XQ->c1);
sike_fpcopy(gen + 4*NWORDS_FIELD, XR->c0);
sike_fpcopy(gen + 5*NWORDS_FIELD, XR->c1);
}
// Conversion of GF(p^2) element from Montgomery to standard representation.
static inline void sike_fp2_encode(const f2elm_t x, uint8_t *enc) {
f2elm_t t;
sike_from_fp2mont(x, t);
// convert to bytes in little endian form
for (size_t i=0; i<FIELD_BYTESZ; i++) {
enc[i+ 0] = (t[0].c0[i/LSZ] >> (8*(i%LSZ))) & 0xFF;
enc[i+FIELD_BYTESZ] = (t[0].c1[i/LSZ] >> (8*(i%LSZ))) & 0xFF;
}
}
// Parse byte sequence back into GF(p^2) element, and conversion to Montgomery representation.
// Elements over GF(p503) are encoded in 63 octets in little endian format
// (i.e., the least significant octet is located in the lowest memory address).
static inline void fp2_decode(const uint8_t *enc, f2elm_t t) {
memset(t[0].c0, 0, sizeof(t[0].c0));
memset(t[0].c1, 0, sizeof(t[0].c1));
// convert bytes in little endian form to f2elm_t
for (size_t i = 0; i < FIELD_BYTESZ; i++) {
t[0].c0[i/LSZ] |= ((crypto_word_t)enc[i+ 0]) << (8*(i%LSZ));
t[0].c1[i/LSZ] |= ((crypto_word_t)enc[i+FIELD_BYTESZ]) << (8*(i%LSZ));
}
sike_to_fp2mont(t, t);
}
// Alice's ephemeral public key generation
// Input: a private key prA in the range [0, 2^250 - 1], stored in 32 bytes.
// Output: the public key pkA consisting of 3 GF(p503^2) elements encoded in 378 bytes.
static void gen_iso_A(const uint8_t* skA, uint8_t* pkA)
{
point_proj_t R, pts[MAX_INT_POINTS_ALICE];
point_proj_t phiP = POINT_PROJ_INIT;
point_proj_t phiQ = POINT_PROJ_INIT;
point_proj_t phiR = POINT_PROJ_INIT;
f2elm_t XPA, XQA, XRA, coeff[3];
f2elm_t A24plus = F2ELM_INIT;
f2elm_t C24 = F2ELM_INIT;
f2elm_t A = F2ELM_INIT;
unsigned int m, index = 0, pts_index[MAX_INT_POINTS_ALICE], npts = 0, ii = 0;
// Initialize basis points
sike_init_basis(sike_params.A_gen, XPA, XQA, XRA);
sike_init_basis(sike_params.B_gen, phiP->X, phiQ->X, phiR->X);
sike_fpcopy(sike_params.mont_one, (phiP->Z)->c0);
sike_fpcopy(sike_params.mont_one, (phiQ->Z)->c0);
sike_fpcopy(sike_params.mont_one, (phiR->Z)->c0);
// Initialize constants: A24plus = A+2C, C24 = 4C, where A=6, C=1
sike_fpcopy(sike_params.mont_one, A24plus->c0);
sike_fp2add(A24plus, A24plus, A24plus);
sike_fp2add(A24plus, A24plus, C24);
sike_fp2add(A24plus, C24, A);
sike_fp2add(C24, C24, A24plus);
// Retrieve kernel point
ladder3Pt(XPA, XQA, XRA, skA, 1, R, A);
// Traverse tree
index = 0;
for (size_t row = 1; row < A_max; row++) {
while (index < A_max-row) {
sike_fp2copy(R->X, pts[npts]->X);
sike_fp2copy(R->Z, pts[npts]->Z);
pts_index[npts++] = index;
m = sike_params.A_strat[ii++];
sike_xDBLe(R, R, A24plus, C24, (2*m));
index += m;
}
sike_get_4_isog(R, A24plus, C24, coeff);
for (size_t i = 0; i < npts; i++) {
sike_eval_4_isog(pts[i], coeff);
}
sike_eval_4_isog(phiP, coeff);
sike_eval_4_isog(phiQ, coeff);
sike_eval_4_isog(phiR, coeff);
sike_fp2copy(pts[npts-1]->X, R->X);
sike_fp2copy(pts[npts-1]->Z, R->Z);
index = pts_index[npts-1];
npts -= 1;
}
sike_get_4_isog(R, A24plus, C24, coeff);
sike_eval_4_isog(phiP, coeff);
sike_eval_4_isog(phiQ, coeff);
sike_eval_4_isog(phiR, coeff);
sike_inv_3_way(phiP->Z, phiQ->Z, phiR->Z);
sike_fp2mul_mont(phiP->X, phiP->Z, phiP->X);
sike_fp2mul_mont(phiQ->X, phiQ->Z, phiQ->X);
sike_fp2mul_mont(phiR->X, phiR->Z, phiR->X);
// Format public key
sike_fp2_encode(phiP->X, pkA);
sike_fp2_encode(phiQ->X, pkA + SIDH_JINV_BYTESZ);
sike_fp2_encode(phiR->X, pkA + 2*SIDH_JINV_BYTESZ);
}
// Bob's ephemeral key-pair generation
// It produces a private key skB and computes the public key pkB.
// The private key is an integer in the range [0, 2^Floor(Log(2,3^159)) - 1], stored in 32 bytes.
// The public key consists of 3 GF(p503^2) elements encoded in 378 bytes.
static void gen_iso_B(const uint8_t* skB, uint8_t* pkB)
{
point_proj_t R, pts[MAX_INT_POINTS_BOB];
point_proj_t phiP = POINT_PROJ_INIT;
point_proj_t phiQ = POINT_PROJ_INIT;
point_proj_t phiR = POINT_PROJ_INIT;
f2elm_t XPB, XQB, XRB, coeff[3];
f2elm_t A24plus = F2ELM_INIT;
f2elm_t A24minus = F2ELM_INIT;
f2elm_t A = F2ELM_INIT;
unsigned int m, index = 0, pts_index[MAX_INT_POINTS_BOB], npts = 0, ii = 0;
// Initialize basis points
sike_init_basis(sike_params.B_gen, XPB, XQB, XRB);
sike_init_basis(sike_params.A_gen, phiP->X, phiQ->X, phiR->X);
sike_fpcopy(sike_params.mont_one, (phiP->Z)->c0);
sike_fpcopy(sike_params.mont_one, (phiQ->Z)->c0);
sike_fpcopy(sike_params.mont_one, (phiR->Z)->c0);
// Initialize constants: A24minus = A-2C, A24plus = A+2C, where A=6, C=1
sike_fpcopy(sike_params.mont_one, A24plus->c0);
sike_fp2add(A24plus, A24plus, A24plus);
sike_fp2add(A24plus, A24plus, A24minus);
sike_fp2add(A24plus, A24minus, A);
sike_fp2add(A24minus, A24minus, A24plus);
// Retrieve kernel point
ladder3Pt(XPB, XQB, XRB, skB, 0, R, A);
// Traverse tree
index = 0;
for (size_t row = 1; row < B_max; row++) {
while (index < B_max-row) {
sike_fp2copy(R->X, pts[npts]->X);
sike_fp2copy(R->Z, pts[npts]->Z);
pts_index[npts++] = index;
m = sike_params.B_strat[ii++];
sike_xTPLe(R, R, A24minus, A24plus, m);
index += m;
}
sike_get_3_isog(R, A24minus, A24plus, coeff);
for (size_t i = 0; i < npts; i++) {
sike_eval_3_isog(pts[i], coeff);
}
sike_eval_3_isog(phiP, coeff);
sike_eval_3_isog(phiQ, coeff);
sike_eval_3_isog(phiR, coeff);
sike_fp2copy(pts[npts-1]->X, R->X);
sike_fp2copy(pts[npts-1]->Z, R->Z);
index = pts_index[npts-1];
npts -= 1;
}
sike_get_3_isog(R, A24minus, A24plus, coeff);
sike_eval_3_isog(phiP, coeff);
sike_eval_3_isog(phiQ, coeff);
sike_eval_3_isog(phiR, coeff);
sike_inv_3_way(phiP->Z, phiQ->Z, phiR->Z);
sike_fp2mul_mont(phiP->X, phiP->Z, phiP->X);
sike_fp2mul_mont(phiQ->X, phiQ->Z, phiQ->X);
sike_fp2mul_mont(phiR->X, phiR->Z, phiR->X);
// Format public key
sike_fp2_encode(phiP->X, pkB);
sike_fp2_encode(phiQ->X, pkB + SIDH_JINV_BYTESZ);
sike_fp2_encode(phiR->X, pkB + 2*SIDH_JINV_BYTESZ);
}
// Alice's ephemeral shared secret computation
// It produces a shared secret key ssA using her secret key skA and Bob's public key pkB
// Inputs: Alice's skA is an integer in the range [0, 2^250 - 1], stored in 32 bytes.
// Bob's pkB consists of 3 GF(p503^2) elements encoded in 378 bytes.
// Output: a shared secret ssA that consists of one element in GF(p503^2) encoded in 126 bytes.
static void ex_iso_A(const uint8_t* skA, const uint8_t* pkB, uint8_t* ssA)
{
point_proj_t R, pts[MAX_INT_POINTS_ALICE];
f2elm_t coeff[3], PKB[3], jinv;
f2elm_t A24plus = F2ELM_INIT;
f2elm_t C24 = F2ELM_INIT;
f2elm_t A = F2ELM_INIT;
unsigned int m, index = 0, pts_index[MAX_INT_POINTS_ALICE], npts = 0, ii = 0;
// Initialize images of Bob's basis
fp2_decode(pkB, PKB[0]);
fp2_decode(pkB + SIDH_JINV_BYTESZ, PKB[1]);
fp2_decode(pkB + 2*SIDH_JINV_BYTESZ, PKB[2]);
// Initialize constants
sike_get_A(PKB[0], PKB[1], PKB[2], A);
sike_fpadd(sike_params.mont_one, sike_params.mont_one, C24->c0);
sike_fp2add(A, C24, A24plus);
sike_fpadd(C24->c0, C24->c0, C24->c0);
// Retrieve kernel point
ladder3Pt(PKB[0], PKB[1], PKB[2], skA, 1, R, A);
// Traverse tree
index = 0;
for (size_t row = 1; row < A_max; row++) {
while (index < A_max-row) {
sike_fp2copy(R->X, pts[npts]->X);
sike_fp2copy(R->Z, pts[npts]->Z);
pts_index[npts++] = index;
m = sike_params.A_strat[ii++];
sike_xDBLe(R, R, A24plus, C24, (2*m));
index += m;
}
sike_get_4_isog(R, A24plus, C24, coeff);
for (size_t i = 0; i < npts; i++) {
sike_eval_4_isog(pts[i], coeff);
}
sike_fp2copy(pts[npts-1]->X, R->X);
sike_fp2copy(pts[npts-1]->Z, R->Z);
index = pts_index[npts-1];
npts -= 1;
}
sike_get_4_isog(R, A24plus, C24, coeff);
sike_fp2add(A24plus, A24plus, A24plus);
sike_fp2sub(A24plus, C24, A24plus);
sike_fp2add(A24plus, A24plus, A24plus);
sike_j_inv(A24plus, C24, jinv);
sike_fp2_encode(jinv, ssA);
}
// Bob's ephemeral shared secret computation
// It produces a shared secret key ssB using his secret key skB and Alice's public key pkA
// Inputs: Bob's skB is an integer in the range [0, 2^Floor(Log(2,3^159)) - 1], stored in 32 bytes.
// Alice's pkA consists of 3 GF(p503^2) elements encoded in 378 bytes.
// Output: a shared secret ssB that consists of one element in GF(p503^2) encoded in 126 bytes.
static void ex_iso_B(const uint8_t* skB, const uint8_t* pkA, uint8_t* ssB)
{
point_proj_t R, pts[MAX_INT_POINTS_BOB];
f2elm_t coeff[3], PKB[3], jinv;
f2elm_t A24plus = F2ELM_INIT;
f2elm_t A24minus = F2ELM_INIT;
f2elm_t A = F2ELM_INIT;
unsigned int m, index = 0, pts_index[MAX_INT_POINTS_BOB], npts = 0, ii = 0;
// Initialize images of Alice's basis
fp2_decode(pkA, PKB[0]);
fp2_decode(pkA + SIDH_JINV_BYTESZ, PKB[1]);
fp2_decode(pkA + 2*SIDH_JINV_BYTESZ, PKB[2]);
// Initialize constants
sike_get_A(PKB[0], PKB[1], PKB[2], A);
sike_fpadd(sike_params.mont_one, sike_params.mont_one, A24minus->c0);
sike_fp2add(A, A24minus, A24plus);
sike_fp2sub(A, A24minus, A24minus);
// Retrieve kernel point
ladder3Pt(PKB[0], PKB[1], PKB[2], skB, 0, R, A);
// Traverse tree
index = 0;
for (size_t row = 1; row < B_max; row++) {
while (index < B_max-row) {
sike_fp2copy(R->X, pts[npts]->X);
sike_fp2copy(R->Z, pts[npts]->Z);
pts_index[npts++] = index;
m = sike_params.B_strat[ii++];
sike_xTPLe(R, R, A24minus, A24plus, m);
index += m;
}
sike_get_3_isog(R, A24minus, A24plus, coeff);
for (size_t i = 0; i < npts; i++) {
sike_eval_3_isog(pts[i], coeff);
}
sike_fp2copy(pts[npts-1]->X, R->X);
sike_fp2copy(pts[npts-1]->Z, R->Z);
index = pts_index[npts-1];
npts -= 1;
}
sike_get_3_isog(R, A24minus, A24plus, coeff);
sike_fp2add(A24plus, A24minus, A);
sike_fp2add(A, A, A);
sike_fp2sub(A24plus, A24minus, A24plus);
sike_j_inv(A, A24plus, jinv);
sike_fp2_encode(jinv, ssB);
}
int SIKE_keypair(uint8_t out_priv[SIKE_PRV_BYTESZ],
uint8_t out_pub[SIKE_PUB_BYTESZ]) {
int ret = 0;
// Calculate private key for Alice. Needs to be in range [0, 2^0xFA - 1] and <
// 253 bits
BIGNUM *bn_sidh_prv = BN_new();
if (!bn_sidh_prv ||
!BN_rand(bn_sidh_prv, SIDH_PRV_B_BITSZ, BN_RAND_TOP_ONE,
BN_RAND_BOTTOM_ANY) ||
!BN_bn2le_padded(out_priv, BITS_TO_BYTES(SIDH_PRV_B_BITSZ),
bn_sidh_prv)) {
goto end;
}
gen_iso_B(out_priv, out_pub);
ret = 1;
end:
BN_free(bn_sidh_prv);
return ret;
}
void SIKE_encaps(uint8_t out_shared_key[SIKE_SS_BYTESZ],
uint8_t out_ciphertext[SIKE_CT_BYTESZ],
const uint8_t pub_key[SIKE_PUB_BYTESZ]) {
// Secret buffer is reused by the function to store some ephemeral
// secret data. It's size must be maximum of SHA256_CBLOCK,
// SIKE_MSG_BYTESZ and SIDH_PRV_A_BITSZ in bytes.
uint8_t secret[SHA256_CBLOCK];
uint8_t j[SIDH_JINV_BYTESZ];
uint8_t temp[SIKE_MSG_BYTESZ + SIKE_CT_BYTESZ];
SHA256_CTX ctx;
// Generate secret key for A
// secret key A = SHA256({0,1}^n || pub_key)) mod SIDH_PRV_A_BITSZ
RAND_bytes(temp, SIKE_MSG_BYTESZ);
SHA256_Init(&ctx);
SHA256_Update(&ctx, temp, SIKE_MSG_BYTESZ);
SHA256_Update(&ctx, pub_key, SIKE_PUB_BYTESZ);
SHA256_Final(secret, &ctx);
// Generate public key for A - first part of the ciphertext
gen_iso_A(secret, out_ciphertext);
// Generate c1:
// h = SHA256(j-invariant)
// c1 = h ^ m
ex_iso_A(secret, pub_key, j);
SHA256_Init(&ctx);
SHA256_Update(&ctx, j, sizeof(j));
SHA256_Final(secret, &ctx);
// c1 = h ^ m
uint8_t *c1 = &out_ciphertext[SIKE_PUB_BYTESZ];
for (size_t i = 0; i < SIKE_MSG_BYTESZ; i++) {
c1[i] = temp[i] ^ secret[i];
}
SHA256_Init(&ctx);
SHA256_Update(&ctx, temp, SIKE_MSG_BYTESZ);
SHA256_Update(&ctx, out_ciphertext, SIKE_CT_BYTESZ);
SHA256_Final(secret, &ctx);
// Generate shared secret out_shared_key = SHA256(m||out_ciphertext)
memcpy(out_shared_key, secret, SIKE_SS_BYTESZ);
}
void SIKE_decaps(uint8_t out_shared_key[SIKE_SS_BYTESZ],
const uint8_t ciphertext[SIKE_CT_BYTESZ],
const uint8_t pub_key[SIKE_PUB_BYTESZ],
const uint8_t priv_key[SIKE_PRV_BYTESZ]) {
// Secret buffer is reused by the function to store some ephemeral
// secret data. It's size must be maximum of SHA256_CBLOCK,
// SIKE_MSG_BYTESZ and SIDH_PRV_A_BITSZ in bytes.
uint8_t secret[SHA256_CBLOCK];
uint8_t j[SIDH_JINV_BYTESZ];
uint8_t c0[SIKE_PUB_BYTESZ];
uint8_t temp[SIKE_MSG_BYTESZ];
uint8_t shared_nok[SIKE_MSG_BYTESZ];
SHA256_CTX ctx;
// This is OK as we are only using ephemeral keys in BoringSSL
RAND_bytes(shared_nok, SIKE_MSG_BYTESZ);
// Recover m
// Let ciphertext = c0 || c1 - both have fixed sizes
// m = F(j-invariant(c0, priv_key)) ^ c1
ex_iso_B(priv_key, ciphertext, j);
SHA256_Init(&ctx);
SHA256_Update(&ctx, j, sizeof(j));
SHA256_Final(secret, &ctx);
const uint8_t *c1 = &ciphertext[sizeof(c0)];
for (size_t i = 0; i < SIKE_MSG_BYTESZ; i++) {
temp[i] = c1[i] ^ secret[i];
}
SHA256_Init(&ctx);
SHA256_Update(&ctx, temp, SIKE_MSG_BYTESZ);
SHA256_Update(&ctx, pub_key, SIKE_PUB_BYTESZ);
SHA256_Final(secret, &ctx);
// Recover c0 = public key A
gen_iso_A(secret, c0);
crypto_word_t ok = constant_time_is_zero_w(
CRYPTO_memcmp(c0, ciphertext, SIKE_PUB_BYTESZ));
for (size_t i = 0; i < SIKE_MSG_BYTESZ; i++) {
temp[i] = constant_time_select_8(ok, temp[i], shared_nok[i]);
}
SHA256_Init(&ctx);
SHA256_Update(&ctx, temp, SIKE_MSG_BYTESZ);
SHA256_Update(&ctx, ciphertext, SIKE_CT_BYTESZ);
SHA256_Final(secret, &ctx);
// Generate shared secret out_shared_key = SHA256(m||ciphertext)
memcpy(out_shared_key, secret, SIKE_SS_BYTESZ);
}

View File

@ -1,64 +0,0 @@
/********************************************************************************************
* SIDH: an efficient supersingular isogeny cryptography library
*
* Abstract: API header file for SIKE
*********************************************************************************************/
#ifndef SIKE_H_
#define SIKE_H_
#include <stdint.h>
#include <openssl/base.h>
#if defined(__cplusplus)
extern "C" {
#endif
/* SIKE
*
* SIKE is a isogeny based post-quantum key encapsulation mechanism. Description of the
* algorithm is provided in [SIKE]. This implementation uses 434-bit field size. The code
* is based on "Additional_Implementations" from PQC NIST submission package which can
* be found here:
* https://csrc.nist.gov/CSRC/media/Projects/Post-Quantum-Cryptography/documents/round-1/submissions/SIKE.zip
*
* [SIKE] https://sike.org/files/SIDH-spec.pdf
*/
// SIKE_PUB_BYTESZ is the number of bytes in a public key.
#define SIKE_PUB_BYTESZ 330
// SIKE_PRV_BYTESZ is the number of bytes in a private key.
#define SIKE_PRV_BYTESZ 28
// SIKE_SS_BYTESZ is the number of bytes in a shared key.
#define SIKE_SS_BYTESZ 16
// SIKE_MSG_BYTESZ is the number of bytes in a random bit string concatenated
// with the public key (see 1.4 of SIKE).
#define SIKE_MSG_BYTESZ 16
// SIKE_SS_BYTESZ is the number of bytes in a ciphertext.
#define SIKE_CT_BYTESZ (SIKE_PUB_BYTESZ + SIKE_MSG_BYTESZ)
// SIKE_keypair outputs a public and secret key. Internally it uses BN_rand() as
// an entropy source. In case of success function returns 1, otherwise 0.
OPENSSL_EXPORT int SIKE_keypair(
uint8_t out_priv[SIKE_PRV_BYTESZ],
uint8_t out_pub[SIKE_PUB_BYTESZ]);
// SIKE_encaps generates and encrypts a random session key, writing those values to
// |out_shared_key| and |out_ciphertext|, respectively.
OPENSSL_EXPORT void SIKE_encaps(
uint8_t out_shared_key[SIKE_SS_BYTESZ],
uint8_t out_ciphertext[SIKE_CT_BYTESZ],
const uint8_t pub_key[SIKE_PUB_BYTESZ]);
// SIKE_decaps outputs a random session key, writing it to |out_shared_key|.
OPENSSL_EXPORT void SIKE_decaps(
uint8_t out_shared_key[SIKE_SS_BYTESZ],
const uint8_t ciphertext[SIKE_CT_BYTESZ],
const uint8_t pub_key[SIKE_PUB_BYTESZ],
const uint8_t priv_key[SIKE_PRV_BYTESZ]);
#if defined(__cplusplus)
}
#endif
#endif

View File

@ -1,251 +0,0 @@
/* Copyright (c) 2018, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#include <gtest/gtest.h>
#include <stdint.h>
#include "sike.h"
#include "fpx.h"
#include "../../crypto/test/abi_test.h"
TEST(SIKE, RoundTrip) {
uint8_t sk[SIKE_PRV_BYTESZ] = {0};
uint8_t pk[SIKE_PUB_BYTESZ] = {0};
uint8_t ct[SIKE_CT_BYTESZ] = {0};
uint8_t ss_enc[SIKE_SS_BYTESZ] = {0};
uint8_t ss_dec[SIKE_SS_BYTESZ] = {0};
for (size_t i = 0; i < 30; i++) {
EXPECT_EQ(SIKE_keypair(sk, pk), 1);
SIKE_encaps(ss_enc, ct, pk);
SIKE_decaps(ss_dec, ct, pk, sk);
EXPECT_EQ(memcmp(ss_enc, ss_dec, SIKE_SS_BYTESZ), 0);
}
}
TEST(SIKE, Decapsulation) {
const uint8_t sk[SIKE_PRV_BYTESZ] = {
0xB1, 0xFD, 0x34, 0x42, 0xDB, 0x02, 0xBC, 0x9D, 0x4C, 0xD0,
0x72, 0x34, 0x4D, 0xBD, 0x06, 0xDF, 0x1C, 0x7D, 0x0A, 0x88,
0xB2, 0x50, 0xC4, 0xF6, 0xAE, 0xE8, 0x25, 0x01};
const uint8_t pk[SIKE_PUB_BYTESZ] = {
0x6D, 0x8D, 0xF5, 0x7B, 0xCD, 0x47, 0xCA, 0xCB, 0x7A, 0x38, 0xB7, 0xA6,
0x90, 0xB7, 0x37, 0x03, 0xD4, 0x6F, 0x27, 0x73, 0x74, 0x17, 0x5A, 0xA4,
0x0D, 0xC6, 0x81, 0xAD, 0xDB, 0xF7, 0x18, 0xB2, 0x3C, 0x30, 0xCF, 0xAA,
0x08, 0x11, 0x91, 0xCC, 0x27, 0x4E, 0xF1, 0xA6, 0xB7, 0xDA, 0xD2, 0xCF,
0x99, 0x7F, 0xF7, 0xE1, 0xD0, 0xCE, 0x00, 0xD2, 0x4B, 0xA4, 0x33, 0xB4,
0x87, 0x01, 0x3F, 0x02, 0xF7, 0xF9, 0xDE, 0xC3, 0x60, 0x62, 0xDA, 0x3F,
0x74, 0xA9, 0x44, 0xBE, 0x19, 0xD5, 0x03, 0x2A, 0x79, 0x8C, 0xA7, 0xFF,
0xEA, 0xB3, 0xBB, 0xB5, 0xD4, 0x1D, 0x8F, 0x92, 0xCE, 0x62, 0x6E, 0x99,
0x24, 0xD7, 0x57, 0xFA, 0xCD, 0xB6, 0xE2, 0x8E, 0xFD, 0x22, 0x0E, 0x31,
0x21, 0x01, 0x8D, 0x79, 0xF8, 0x3E, 0x27, 0xEC, 0x43, 0x40, 0xDB, 0x82,
0xE5, 0xEB, 0x6C, 0x97, 0x66, 0x29, 0x15, 0x68, 0xB7, 0x4D, 0x84, 0xD1,
0x8A, 0x0B, 0x12, 0x36, 0x2C, 0x0C, 0x0A, 0x6E, 0x4E, 0xDE, 0xA5, 0x8A,
0xDE, 0x77, 0xDD, 0x70, 0x49, 0x73, 0xAC, 0x27, 0x6D, 0x8D, 0x25, 0x9A,
0xE4, 0x25, 0xE8, 0x95, 0x8F, 0xFE, 0x90, 0x3B, 0x00, 0x69, 0x20, 0xE8,
0x7C, 0xA5, 0xF5, 0x79, 0xC0, 0x61, 0x51, 0x91, 0x35, 0x25, 0x3F, 0x17,
0x2F, 0x70, 0x73, 0xF0, 0x89, 0xB5, 0xC8, 0x25, 0xB8, 0xE5, 0x7E, 0x34,
0xDD, 0x11, 0xE5, 0xD6, 0xC3, 0xD5, 0x29, 0x89, 0xC6, 0x2C, 0x99, 0x53,
0x1D, 0x2C, 0x77, 0xB0, 0xB6, 0xA1, 0xBD, 0x79, 0xFB, 0x4A, 0xC2, 0x48,
0x4C, 0x62, 0x51, 0x00, 0xE3, 0x91, 0x2A, 0xCB, 0x84, 0x03, 0x5D, 0x2D,
0xC8, 0x33, 0xE9, 0x14, 0xBF, 0x74, 0x21, 0xBC, 0xF4, 0x76, 0xE5, 0x42,
0xB8, 0xBD, 0xE2, 0xE7, 0x20, 0x95, 0x54, 0xF2, 0xED, 0xC0, 0x79, 0x38,
0x1E, 0xD2, 0xEA, 0x1A, 0x63, 0x85, 0xE7, 0x3A, 0xDA, 0xAD, 0xAB, 0x1B,
0x1E, 0x19, 0x9E, 0x73, 0xD0, 0x10, 0x2E, 0x38, 0xAC, 0x8B, 0x00, 0x6A,
0x30, 0x2C, 0x3D, 0x70, 0x8E, 0x39, 0x6D, 0xC0, 0x12, 0x61, 0x7D, 0x2A,
0x0A, 0x04, 0x95, 0x8E, 0x09, 0x3C, 0x7B, 0xEC, 0x2E, 0xBC, 0xE8, 0xE8,
0xE8, 0x37, 0x29, 0xC4, 0x7E, 0x76, 0x48, 0xB9, 0x3B, 0x72, 0xE5, 0x99,
0x9B, 0xF9, 0xE3, 0x99, 0x72, 0x3F, 0x35, 0x29, 0x85, 0xE0, 0xC8, 0xBF,
0xB1, 0x6B, 0xB1, 0x6E, 0x72, 0x00};
const uint8_t ct[SIKE_CT_BYTESZ] = {
0xFF, 0xEB, 0xEF, 0x4A, 0xC0, 0x57, 0x0F, 0x26, 0xAC, 0x76, 0xA8, 0xB0,
0xA3, 0x5D, 0x9C, 0xD9, 0x25, 0xD1, 0x7F, 0x92, 0x5D, 0xF4, 0x23, 0x34,
0xC3, 0x03, 0x10, 0xE1, 0xB0, 0x24, 0x9B, 0x44, 0x58, 0x26, 0x13, 0x56,
0x83, 0x43, 0x72, 0x69, 0x28, 0x0D, 0x55, 0x07, 0x1F, 0xDB, 0xC0, 0x23,
0x34, 0x83, 0x1A, 0x09, 0x9B, 0x80, 0x00, 0x64, 0x56, 0xDC, 0x79, 0x7A,
0xD2, 0xCE, 0x23, 0xC9, 0x72, 0x27, 0xFC, 0x8D, 0xAB, 0xBF, 0xD3, 0x17,
0xF6, 0x91, 0x7B, 0x15, 0x93, 0x83, 0x8A, 0x4F, 0x6C, 0xCA, 0x4A, 0x94,
0xDA, 0xC7, 0x9D, 0xB6, 0xD6, 0xBA, 0xBD, 0x81, 0x9A, 0x78, 0xE5, 0xE5,
0xBE, 0x17, 0xBC, 0xCB, 0xC8, 0x23, 0x80, 0x5F, 0x75, 0xF8, 0xDB, 0x51,
0x55, 0x00, 0x25, 0x33, 0x52, 0x64, 0xB2, 0xD6, 0xD8, 0x9A, 0x2A, 0x9E,
0x29, 0x99, 0x13, 0x33, 0xE2, 0xA7, 0x98, 0xAC, 0xD7, 0x79, 0x5C, 0x2F,
0xBA, 0x07, 0xC3, 0x03, 0x37, 0xD6, 0xE6, 0xB5, 0xA1, 0xF5, 0x29, 0xB6,
0xF6, 0xC0, 0x5C, 0x44, 0x68, 0x2B, 0x0B, 0xF5, 0x00, 0x01, 0x44, 0xD5,
0xCC, 0x23, 0xB5, 0x27, 0x4F, 0xCA, 0xB4, 0x05, 0x01, 0xF9, 0xD4, 0x41,
0xE0, 0xE1, 0x1E, 0xCF, 0xA9, 0xBC, 0x79, 0xD7, 0xD5, 0xF5, 0x3C, 0xE6,
0x93, 0xF4, 0x6C, 0x84, 0x5A, 0x2C, 0x4B, 0xE4, 0x91, 0xB2, 0xB2, 0xB8,
0xAD, 0x74, 0x9A, 0x69, 0x79, 0x4C, 0x84, 0xB7, 0xBF, 0xF1, 0x68, 0x4B,
0xAE, 0x0F, 0x7F, 0x45, 0x3B, 0x18, 0x3F, 0xFA, 0x00, 0x48, 0xE0, 0x3A,
0xE2, 0xC0, 0xAE, 0x00, 0xCE, 0x90, 0x28, 0xA4, 0x1B, 0xBE, 0xCA, 0x0C,
0x21, 0x29, 0x64, 0x30, 0x5E, 0x35, 0xAD, 0xFD, 0x83, 0x47, 0x40, 0x6D,
0x15, 0x56, 0xFC, 0xF8, 0x5F, 0xAB, 0x81, 0xFE, 0x6B, 0xE9, 0x6B, 0xED,
0x27, 0x35, 0x7C, 0xD8, 0x2C, 0xD4, 0xF2, 0x11, 0xE6, 0xAF, 0xDF, 0xB8,
0x91, 0x96, 0xEB, 0xF7, 0x4C, 0x8D, 0x70, 0x77, 0x90, 0x81, 0x00, 0x09,
0x19, 0x27, 0x8A, 0x9E, 0xB6, 0x1A, 0xE9, 0xAC, 0x6C, 0xC9, 0xF8, 0xEA,
0xA2, 0x34, 0xB8, 0xAC, 0xB3, 0xB3, 0x68, 0xA1, 0xB7, 0x29, 0x55, 0xCA,
0x40, 0x23, 0x92, 0x5C, 0x0C, 0x79, 0x6B, 0xD6, 0x9F, 0x5B, 0xD2, 0xE6,
0xAE, 0x04, 0xCB, 0xEC, 0xC7, 0x88, 0x18, 0xDB, 0x7A, 0xE6, 0xD6, 0xC9,
0x39, 0xFD, 0x93, 0x9B, 0xC8, 0x01, 0x6F, 0x3E, 0x6C, 0x90, 0x3E, 0x73,
0x76, 0x99, 0x7C, 0x48, 0xDA, 0x68, 0x48, 0x80, 0x2B, 0x63};
const uint8_t ss_exp[SIKE_SS_BYTESZ] = {0xA1, 0xF9, 0x5A, 0x67, 0xB9, 0x3D,
0x1E, 0x72, 0xE8, 0xC5, 0x71, 0xF1,
0x4C, 0xB2, 0xAA, 0x6D};
uint8_t ss_dec[SIKE_SS_BYTESZ] = {0};
SIKE_decaps(ss_dec, ct, pk, sk);
EXPECT_EQ(memcmp(ss_dec, ss_exp, sizeof(ss_exp)), 0);
}
// SIKE_encaps and SIKE_keypair doesn't return zeros.
TEST(SIKE, NonZero) {
uint8_t sk[SIKE_PRV_BYTESZ] = {0};
uint8_t pk[SIKE_PUB_BYTESZ] = {0};
uint8_t ct[SIKE_CT_BYTESZ] = {0};
uint8_t ss[SIKE_SS_BYTESZ] = {0};
// Check secret and public key returned by SIKE_keypair
EXPECT_EQ(SIKE_keypair(sk, pk), 1);
uint8_t tmp = 0;
for (size_t i = 0; i < sizeof(sk); i++) {
tmp |= sk[i];
}
EXPECT_NE(tmp, 0);
tmp = 0;
for (size_t i = 0; i < sizeof(pk); i++) {
tmp |= pk[i];
}
EXPECT_NE(tmp, 0);
// Check shared secret and ciphertext returned by SIKE_encaps
SIKE_encaps(ss, ct, pk);
tmp = 0;
for (size_t i = 0; i < sizeof(ct); i++) {
tmp |= ct[i];
}
EXPECT_NE(tmp, 0);
tmp = 0;
for (size_t i = 0; i < sizeof(ss); i++) {
tmp |= ss[i];
}
EXPECT_NE(tmp, 0);
}
TEST(SIKE, Negative) {
uint8_t sk[SIKE_PRV_BYTESZ] = {0};
uint8_t pk[SIKE_PUB_BYTESZ] = {0};
uint8_t ct[SIKE_CT_BYTESZ] = {0};
uint8_t ss_enc[SIKE_SS_BYTESZ] = {0};
uint8_t ss_dec[SIKE_SS_BYTESZ] = {0};
EXPECT_EQ(SIKE_keypair(sk, pk), 1);
SIKE_encaps(ss_enc, ct, pk);
// Change cipertext
uint8_t ct_tmp[SIKE_CT_BYTESZ] = {0};
memcpy(ct_tmp, ct, sizeof(ct));
ct_tmp[0] = ~ct_tmp[0];
SIKE_decaps(ss_dec, ct_tmp, pk, sk);
EXPECT_NE(memcmp(ss_enc, ss_dec, SIKE_SS_BYTESZ), 0);
// Change secret key
uint8_t sk_tmp[SIKE_PRV_BYTESZ] = {0};
memcpy(sk_tmp, sk, sizeof(sk));
sk_tmp[0] = ~sk_tmp[0];
SIKE_decaps(ss_dec, ct, pk, sk_tmp);
EXPECT_NE(memcmp(ss_enc, ss_dec, SIKE_SS_BYTESZ), 0);
// Change public key
uint8_t pk_tmp[SIKE_PUB_BYTESZ] = {0};
memcpy(pk_tmp, pk, sizeof(pk));
pk_tmp[0] = ~pk_tmp[0];
SIKE_decaps(ss_dec, ct, pk_tmp, sk);
EXPECT_NE(memcmp(ss_enc, ss_dec, SIKE_SS_BYTESZ), 0);
}
TEST(SIKE, Unaligned) {
alignas(4) uint8_t priv[SIKE_PRV_BYTESZ + 1];
alignas(4) uint8_t pub[SIKE_PUB_BYTESZ + 1];
alignas(4) uint8_t shared_key1[SIKE_SS_BYTESZ + 1];
alignas(4) uint8_t ciphertext[SIKE_CT_BYTESZ + 1];
alignas(4) uint8_t shared_key2[SIKE_SS_BYTESZ + 1];
ASSERT_TRUE(SIKE_keypair(priv + 1, pub + 1));
SIKE_encaps(shared_key1 + 1, ciphertext + 1, pub + 1);
SIKE_decaps(shared_key2 + 1, ciphertext + 1, pub + 1, priv + 1);
EXPECT_EQ(memcmp(shared_key1 + 1, shared_key2 + 1, SIKE_SS_BYTESZ), 0);
}
#if defined(SUPPORTS_ABI_TEST) && \
(defined(OPENSSL_X86_64) || defined(OPENSSL_AARCH64))
TEST(SIKE, ABI) {
felm_t a, b, c;
dfelm_t d, e, f;
CHECK_ABI(sike_fpadd, a, b, c);
CHECK_ABI(sike_fpsub, a, b, c);
CHECK_ABI(sike_mpmul, a, b, d);
CHECK_ABI(sike_fprdc, d, a);
CHECK_ABI(sike_mpadd_asm, a, b, c);
CHECK_ABI(sike_mpsubx2_asm, d, e, f);
CHECK_ABI(sike_mpdblsubx2_asm, d, e, f);
}
// Additional tests for checking if assembly implementation
// of MUL and REDC handles carry chains correctly.
TEST(SIKE, CarryChains) {
// Expected results
const dfelm_t exp_mul = {
0x0000000000000001, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
};
const felm_t exp_redc = {
0x93AA0C8C2D3235BE, 0xA8CD35DDDE399B46, 0xB9BBA5469509CA65,
0x6B2FB3A5A2FB86E4, 0x585591BA6DBE862C, 0xD92D3FF5FE0938F2,
0x0001E1F0EE75A1E1
};
// Input
dfelm_t in14 = {
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF
};
felm_t in7 = {
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
0xFFFFFFFFFFFFFFFF
};
dfelm_t res;
sike_mpmul(in7, in7, res);
EXPECT_EQ(memcmp(exp_mul, res, sizeof(exp_mul)), 0);
// modifies in14 and in7
sike_fprdc(in14, in7);
EXPECT_EQ(memcmp(exp_redc, in7, sizeof(exp_redc)), 0);
}
#endif // SUPPORTS_ABI_TEST && (X86_64 || AARCH64)

View File

@ -1,145 +0,0 @@
/********************************************************************************************
* SIDH: an efficient supersingular isogeny cryptography library
*
* Abstract: internal header file for P434
*********************************************************************************************/
#ifndef UTILS_H_
#define UTILS_H_
#include <openssl/base.h>
#include "../../crypto/internal.h"
#include "sike.h"
// Conversion macro from number of bits to number of bytes
#define BITS_TO_BYTES(nbits) (((nbits)+7)/8)
// Bit size of the field
#define BITS_FIELD 434
// Byte size of the field
#define FIELD_BYTESZ BITS_TO_BYTES(BITS_FIELD)
// Number of 64-bit words of a 224-bit element
#define NBITS_ORDER 224
#define NWORDS64_ORDER ((NBITS_ORDER+63)/64)
// Number of elements in Alice's strategy
#define A_max 108
// Number of elements in Bob's strategy
#define B_max 137
// Word size size
#define RADIX sizeof(crypto_word_t)*8
// Byte size of a limb
#define LSZ sizeof(crypto_word_t)
#if defined(OPENSSL_64_BIT)
// Number of words of a 434-bit field element
#define NWORDS_FIELD 7
// Number of "0" digits in the least significant part of p434 + 1
#define ZERO_WORDS 3
// U64_TO_WORDS expands |x| for a |crypto_word_t| array literal.
#define U64_TO_WORDS(x) UINT64_C(x)
#else
// Number of words of a 434-bit field element
#define NWORDS_FIELD 14
// Number of "0" digits in the least significant part of p434 + 1
#define ZERO_WORDS 6
// U64_TO_WORDS expands |x| for a |crypto_word_t| array literal.
#define U64_TO_WORDS(x) \
(uint32_t)(UINT64_C(x) & 0xffffffff), (uint32_t)(UINT64_C(x) >> 32)
#endif
// Extended datatype support
#if !defined(BORINGSSL_HAS_UINT128)
typedef uint64_t uint128_t[2];
#endif
// The following functions return 1 (TRUE) if condition is true, 0 (FALSE) otherwise
// Digit multiplication
#define MUL(multiplier, multiplicand, hi, lo) digit_x_digit((multiplier), (multiplicand), &(lo));
// If mask |x|==0xff.ff set |x| to 1, otherwise 0
#define M2B(x) ((x)>>(RADIX-1))
// Digit addition with carry
#define ADDC(carryIn, addend1, addend2, carryOut, sumOut) \
do { \
crypto_word_t tempReg = (addend1) + (crypto_word_t)(carryIn); \
(sumOut) = (addend2) + tempReg; \
(carryOut) = M2B(constant_time_lt_w(tempReg, (crypto_word_t)(carryIn)) | \
constant_time_lt_w((sumOut), tempReg)); \
} while(0)
// Digit subtraction with borrow
#define SUBC(borrowIn, minuend, subtrahend, borrowOut, differenceOut) \
do { \
crypto_word_t tempReg = (minuend) - (subtrahend); \
crypto_word_t borrowReg = M2B(constant_time_lt_w((minuend), (subtrahend))); \
borrowReg |= ((borrowIn) & constant_time_is_zero_w(tempReg)); \
(differenceOut) = tempReg - (crypto_word_t)(borrowIn); \
(borrowOut) = borrowReg; \
} while(0)
/* Old GCC 4.9 (jessie) doesn't implement {0} initialization properly,
which violates C11 as described in 6.7.9, 21 (similarily C99, 6.7.8).
Defines below are used to work around the bug, and provide a way
to initialize f2elem_t and point_proj_t structs.
Bug has been fixed in GCC6 (debian stretch).
*/
#define F2ELM_INIT {{ {0}, {0} }}
#define POINT_PROJ_INIT {{ F2ELM_INIT, F2ELM_INIT }}
// Datatype for representing 434-bit field elements (448-bit max.)
// Elements over GF(p434) are encoded in 63 octets in little endian format
// (i.e., the least significant octet is located in the lowest memory address).
typedef crypto_word_t felm_t[NWORDS_FIELD];
// An element in F_{p^2}, is composed of two coefficients from F_p, * i.e.
// Fp2 element = c0 + c1*i in F_{p^2}
// Datatype for representing double-precision 2x434-bit field elements (448-bit max.)
// Elements (a+b*i) over GF(p434^2), where a and b are defined over GF(p434), are
// encoded as {a, b}, with a in the lowest memory portion.
typedef struct {
felm_t c0;
felm_t c1;
} fp2;
// Our F_{p^2} element type is a pointer to the struct.
typedef fp2 f2elm_t[1];
// Datatype for representing double-precision 2x434-bit
// field elements in contiguous memory.
typedef crypto_word_t dfelm_t[2*NWORDS_FIELD];
// Constants used during SIKE computation.
struct params_t {
// Stores a prime
const crypto_word_t prime[NWORDS_FIELD];
// Stores prime + 1
const crypto_word_t prime_p1[NWORDS_FIELD];
// Stores prime * 2
const crypto_word_t prime_x2[NWORDS_FIELD];
// Alice's generator values {XPA0 + XPA1*i, XQA0 + XQA1*i, XRA0 + XRA1*i}
// in GF(prime^2), expressed in Montgomery representation
const crypto_word_t A_gen[6*NWORDS_FIELD];
// Bob's generator values {XPB0 + XPB1*i, XQB0 + XQB1*i, XRB0 + XRB1*i}
// in GF(prime^2), expressed in Montgomery representation
const crypto_word_t B_gen[6*NWORDS_FIELD];
// Montgomery constant mont_R2 = (2^448)^2 mod prime
const crypto_word_t mont_R2[NWORDS_FIELD];
// Value 'one' in Montgomery representation
const crypto_word_t mont_one[NWORDS_FIELD];
// Value '6' in Montgomery representation
const crypto_word_t mont_six[NWORDS_FIELD];
// Fixed parameters for isogeny tree computation
const unsigned int A_strat[A_max-1];
const unsigned int B_strat[B_max-1];
};
// Point representation in projective XZ Montgomery coordinates.
typedef struct {
f2elm_t X;
f2elm_t Z;
} point_proj;
typedef point_proj point_proj_t[1];
#endif // UTILS_H_

View File

@ -52,8 +52,6 @@ OPENSSL_MSVC_PRAGMA(warning(pop))
#include "../crypto/internal.h"
#include "internal.h"
#include "../third_party/sike/sike.h"
// g_print_json is true if printed output is JSON formatted.
static bool g_print_json = false;
@ -338,64 +336,6 @@ static bool SpeedRSAKeyGen(const std::string &selected) {
return true;
}
static bool SpeedSIKEP434(const std::string &selected) {
if (!selected.empty() && selected.find("SIKE") == std::string::npos) {
return true;
}
// speed generation
uint8_t public_SIKE[SIKE_PUB_BYTESZ];
uint8_t private_SIKE[SIKE_PRV_BYTESZ];
uint8_t ct[SIKE_CT_BYTESZ];
bool res;
{
TimeResults results;
res = TimeFunction(&results,
[&private_SIKE, &public_SIKE]() -> bool {
return (SIKE_keypair(private_SIKE, public_SIKE) == 1);
});
results.Print("SIKE/P434 generate");
}
if (!res) {
fprintf(stderr, "Failed to time SIKE_keypair.\n");
return false;
}
{
TimeResults results;
TimeFunction(&results,
[&ct, &public_SIKE]() -> bool {
uint8_t ss[SIKE_SS_BYTESZ];
SIKE_encaps(ss, ct, public_SIKE);
return true;
});
results.Print("SIKE/P434 encap");
}
if (!res) {
fprintf(stderr, "Failed to time SIKE_encaps.\n");
return false;
}
{
TimeResults results;
TimeFunction(&results,
[&ct, &public_SIKE, &private_SIKE]() -> bool {
uint8_t ss[SIKE_SS_BYTESZ];
SIKE_decaps(ss, ct, public_SIKE, private_SIKE);
return true;
});
results.Print("SIKE/P434 decap");
}
if (!res) {
fprintf(stderr, "Failed to time SIKE_decaps.\n");
return false;
}
return true;
}
static uint8_t *align(uint8_t *in, unsigned alignment) {
return reinterpret_cast<uint8_t *>(
(reinterpret_cast<uintptr_t>(in) + alignment) &
@ -1128,7 +1068,6 @@ bool Speed(const std::vector<std::string> &args) {
!SpeedECDH(selected) ||
!SpeedECDSA(selected) ||
!Speed25519(selected) ||
!SpeedSIKEP434(selected) ||
!SpeedSPAKE2(selected) ||
!SpeedScrypt(selected) ||
!SpeedRSAKeyGen(selected) ||

View File

@ -640,8 +640,7 @@ def ExtractVariablesFromCMakeFile(cmakefile):
def main(platforms):
cmake = ExtractVariablesFromCMakeFile(os.path.join('src', 'sources.cmake'))
crypto_c_files = (FindCFiles(os.path.join('src', 'crypto'), NoTestsNorFIPSFragments) +
FindCFiles(os.path.join('src', 'third_party', 'fiat'), NoTestsNorFIPSFragments) +
FindCFiles(os.path.join('src', 'third_party', 'sike'), NoTestsNorFIPSFragments))
FindCFiles(os.path.join('src', 'third_party', 'fiat'), NoTestsNorFIPSFragments))
fips_fragments = FindCFiles(os.path.join('src', 'crypto', 'fipsmodule'), OnlyFIPSFragments)
ssl_source_files = FindCFiles(os.path.join('src', 'ssl'), NoTests)
tool_c_files = FindCFiles(os.path.join('src', 'tool'), NoTests)
@ -721,8 +720,7 @@ def main(platforms):
ssl_internal_h_files = FindHeaderFiles(os.path.join('src', 'ssl'), NoTests)
crypto_internal_h_files = (
FindHeaderFiles(os.path.join('src', 'crypto'), NoTests) +
FindHeaderFiles(os.path.join('src', 'third_party', 'fiat'), NoTests) +
FindHeaderFiles(os.path.join('src', 'third_party', 'sike'), NoTests))
FindHeaderFiles(os.path.join('src', 'third_party', 'fiat'), NoTests))
files = {
'bcm_crypto': bcm_crypto_c_files,