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:
parent
7de9498a88
commit
7f02881e96
23
LICENSE
23
LICENSE
@ -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
|
||||
-------------------------
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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 */,
|
||||
|
@ -948,4 +948,3 @@ auth_psk 956
|
||||
kx_any 957
|
||||
auth_any 958
|
||||
CECPQ2 959
|
||||
CECPQ2b 960
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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)
|
||||
}
|
@ -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,
|
||||
}
|
||||
}
|
@ -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, ¶ms.C, &t0) // Z2p = C24 * t0
|
||||
mul(x, z, &t1) // X2p = Z2p * t1
|
||||
sub(&t1, &t1, &t0) // t1 = t1 - t0
|
||||
mul(&t0, ¶ms.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, ¶ms.A) // t5 = t3 * A24+
|
||||
mul(&t3, &t3, &t5) // t3 = t5 * t3
|
||||
mul(&t6, &t2, ¶ms.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
|
||||
}
|
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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))) {
|
||||
|
21
third_party/sike/LICENSE
vendored
21
third_party/sike/LICENSE
vendored
@ -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
|
915
third_party/sike/asm/fp-armv8.pl
vendored
915
third_party/sike/asm/fp-armv8.pl
vendored
@ -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;
|
1626
third_party/sike/asm/fp-x86_64.pl
vendored
1626
third_party/sike/asm/fp-x86_64.pl
vendored
File diff suppressed because it is too large
Load Diff
181
third_party/sike/asm/fp_generic.c
vendored
181
third_party/sike/asm/fp_generic.c
vendored
@ -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)
|
128
third_party/sike/curve_params.c
vendored
128
third_party/sike/curve_params.c
vendored
@ -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
283
third_party/sike/fpx.c
vendored
@ -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
113
third_party/sike/fpx.h
vendored
@ -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_
|
260
third_party/sike/isogeny.c
vendored
260
third_party/sike/isogeny.c
vendored
@ -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
|
||||
}
|
49
third_party/sike/isogeny.h
vendored
49
third_party/sike/isogeny.h
vendored
@ -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_
|
531
third_party/sike/sike.c
vendored
531
third_party/sike/sike.c
vendored
@ -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);
|
||||
}
|
64
third_party/sike/sike.h
vendored
64
third_party/sike/sike.h
vendored
@ -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
|
251
third_party/sike/sike_test.cc
vendored
251
third_party/sike/sike_test.cc
vendored
@ -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)
|
145
third_party/sike/utils.h
vendored
145
third_party/sike/utils.h
vendored
@ -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_
|
@ -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) ||
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user