Add Curve25519

This commit is contained in:
Kae 2023-07-12 15:13:30 +10:00
parent 70bfb54e55
commit 81343bc06f
20 changed files with 3942 additions and 2 deletions

View File

@ -21,6 +21,7 @@ SET (star_core_HEADERS
StarColor.hpp StarColor.hpp
StarCompression.hpp StarCompression.hpp
StarConfig.hpp StarConfig.hpp
StarCurve25519.hpp
StarDataStream.hpp StarDataStream.hpp
StarDataStreamDevices.hpp StarDataStreamDevices.hpp
StarDataStreamExtra.hpp StarDataStreamExtra.hpp
@ -133,6 +134,7 @@ SET (star_core_SOURCES
StarByteArray.cpp StarByteArray.cpp
StarColor.cpp StarColor.cpp
StarCompression.cpp StarCompression.cpp
StarCurve25519.cpp
StarDataStream.cpp StarDataStream.cpp
StarDataStreamDevices.cpp StarDataStreamDevices.cpp
StarDirectives.cpp StarDirectives.cpp

View File

@ -0,0 +1,50 @@
#include "StarCurve25519.hpp"
#include "StarRandom.hpp"
#include "StarLogging.hpp"
#include "curve25519/include/curve25519_dh.h"
#include "curve25519/include/ed25519_signature.h"
namespace Star::Curve25519 {
struct KeySet {
PrivateKey privateKey;
PublicKey publicKey;
KeySet() {
SecretKey secret;
Random::randBytes(SecretKeySize).copyTo((char*)secret.data());
secret[0] &= 248;
secret[31] &= 127;
secret[31] |= 64;
ed25519_CreateKeyPair(privateKey.data(), publicKey.data(), nullptr, secret.data());
Logger::info("Generated Curve25519 key-pair");
}
};
static KeySet const& staticKeys() {
static KeySet keys;
return keys;
}
PrivateKey const& privateKey() { return staticKeys().privateKey; }
Signature sign(void* data, size_t len) {
Signature signature;
ed25519_SignMessage(signature.data(), privateKey().data(), nullptr, (unsigned char*)data, len);
return signature;
}
bool verify(uint8_t const* signature, uint8_t const* publicKey, void* data, size_t len) {
return ed25519_VerifySignature(signature, publicKey, (unsigned char*)data, len);
}
PublicKey const& publicKey() { return staticKeys().publicKey; }
}

View File

@ -0,0 +1,25 @@
#ifndef STAR_CURVE_25519_HPP
#define STAR_CURVE_25519_HPP
#include "StarEncode.hpp"
#include "StarByteArray.hpp"
#include "StarArray.hpp"
namespace Star::Curve25519 {
constexpr size_t PublicKeySize = 32;
constexpr size_t SecretKeySize = 32;
constexpr size_t PrivateKeySize = 64;
constexpr size_t SignatureSize = 64;
typedef Array<uint8_t, PublicKeySize> PublicKey;
typedef Array<uint8_t, SecretKeySize> SecretKey;
typedef Array<uint8_t, PrivateKeySize> PrivateKey;
typedef Array<uint8_t, SignatureSize> Signature;
PublicKey const& publicKey();
Signature sign(void* data, size_t len);
bool verify(uint8_t const* signature, uint8_t const* publicKey, void* data, size_t len);
}
#endif

View File

@ -3,17 +3,19 @@ SET (OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF)
SET (OPUS_X86_MAY_HAVE_AVX OFF) SET (OPUS_X86_MAY_HAVE_AVX OFF)
SET (OPUS_X86_MAY_HAVE_SSE4_1 OFF) SET (OPUS_X86_MAY_HAVE_SSE4_1 OFF)
SET (OPUS_STACK_PROTECTOR OFF) SET (OPUS_STACK_PROTECTOR OFF)
ADD_SUBDIRECTORY (opus) ADD_SUBDIRECTORY (opus)
INCLUDE_DIRECTORIES ( INCLUDE_DIRECTORIES (
${STAR_EXTERN_INCLUDES} ${STAR_EXTERN_INCLUDES}
opus opus/include
fmt fmt
lua lua
) )
SET (star_extern_HEADERS SET (star_extern_HEADERS
curve25519/include/curve25519_dh.h
curve25519/include/ed25519_signature.h
curve25519/include/external_calls.h
fmt/core.h fmt/core.h
fmt/format.h fmt/format.h
fmt/format-inl.h fmt/format-inl.h
@ -31,6 +33,14 @@ SET (star_extern_HEADERS
) )
SET (star_extern_SOURCES SET (star_extern_SOURCES
curve25519/source/sha512.c
curve25519/source/curve25519_dh.c
curve25519/source/curve25519_mehdi.c
curve25519/source/curve25519_order.c
curve25519/source/curve25519_utils.c
curve25519/source/custom_blind.c
curve25519/source/ed25519_sign.c
curve25519/source/ed25519_verify.c
xxhash.c xxhash.c
fmt/format.cc fmt/format.cc
lua/lapi.c lua/lapi.c

View File

@ -0,0 +1,53 @@
/* The MIT License (MIT)
*
* Copyright (c) 2015 mehdi sotoodeh
*
* 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.
*/
#ifndef __curve25519_dh_key_exchange_h__
#define __curve25519_dh_key_exchange_h__
#ifdef __cplusplus
extern "C" {
#endif
/* Return public key associated with sk */
/* sk will be trimmed on return */
void curve25519_dh_CalculatePublicKey(
unsigned char *pk, /* [32-bytes] OUT: Public key */
unsigned char *sk); /* [32-bytes] IN/OUT: Your secret key */
/* Faster alternative for curve25519_dh_CalculatePublicKey */
/* sk will be trimmed on return */
void curve25519_dh_CalculatePublicKey_fast(
unsigned char *pk, /* [32-bytes] OUT: Public key */
unsigned char *sk); /* [32-bytes] IN/OUT: Your secret key */
/* sk will be trimmed on return */
void curve25519_dh_CreateSharedKey(
unsigned char *shared, /* [32-bytes] OUT: Created shared key */
const unsigned char *pk, /* [32-bytes] IN: Other side's public key */
unsigned char *sk); /* [32-bytes] IN/OUT: Your secret key */
#ifdef __cplusplus
}
#endif
#endif /* __curve25519_dh_key_exchange_h__ */

View File

@ -0,0 +1,98 @@
/* The MIT License (MIT)
*
* Copyright (c) 2015 mehdi sotoodeh
*
* 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.
*/
#ifndef __ed25519_signature_h__
#define __ed25519_signature_h__
#ifdef __cplusplus
extern "C" {
#endif
/* -- ed25519-sign ------------------------------------------------------------- */
#define ed25519_public_key_size 32
#define ed25519_secret_key_size 32
#define ed25519_private_key_size 64
#define ed25519_signature_size 64
/* Generate public key associated with the secret key */
void ed25519_CreateKeyPair(
unsigned char *pubKey, /* OUT: public key */
unsigned char *privKey, /* OUT: private key */
const void *blinding, /* IN: [optional] null or blinding context */
const unsigned char *sk); /* IN: secret key (32 bytes) */
/* Generate message signature */
void ed25519_SignMessage(
unsigned char *signature, /* OUT:[64 bytes] signature (R,S) */
const unsigned char *privKey, /* IN: [64 bytes] private key (sk,pk) */
const void *blinding, /* IN: [optional] null or blinding context */
const unsigned char *msg, /* IN: [msg_size bytes] message to sign */
size_t msg_size); /* IN: size of message */
void *ed25519_Blinding_Init(
void *context, /* IO: null or ptr blinding context */
const unsigned char *seed, /* IN: [size bytes] random blinding seed */
size_t size); /* IN: size of blinding seed */
void ed25519_Blinding_Finish(
void *context); /* IN: blinding context */
/* -- ed25519-verify ----------------------------------------------------------- */
/* Single-phased signature validation.
Returns 1 for SUCCESS and 0 for FAILURE
*/
int ed25519_VerifySignature(
const unsigned char *signature, /* IN: [64 bytes] signature (R,S) */
const unsigned char *publicKey, /* IN: [32 bytes] public key */
const unsigned char *msg, /* IN: [msg_size bytes] message to sign */
size_t msg_size); /* IN: size of message */
/* First part of two-phase signature validation.
This function creates context specifc to a given public key.
Needs to be called once per public key
*/
void * ed25519_Verify_Init(
void *context, /* IO: null or verify context to use */
const unsigned char *publicKey); /* IN: [32 bytes] public key */
/* Second part of two-phase signature validation.
Input context is output of ed25519_Verify_Init() for associated public key.
Call it once for each message/signature pairs
Returns 1 for SUCCESS and 0 for FAILURE
*/
int ed25519_Verify_Check(
const void *context, /* IN: created by ed25519_Verify_Init */
const unsigned char *signature, /* IN: signature (R,S) */
const unsigned char *msg, /* IN: message to sign */
size_t msg_size); /* IN: size of message */
/* Free up context memory */
void ed25519_Verify_Finish(void *ctx);
#ifdef __cplusplus
}
#endif
#endif /* __ed25519_signature_h__ */

View File

@ -0,0 +1,36 @@
/* The MIT License (MIT)
*
* Copyright (c) 2015 mehdi sotoodeh
*
* 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.
*/
#ifndef __external_calls_h__
#define __external_calls_h__
#include <memory.h>
#include <stdlib.h>
#define mem_alloc(size) malloc(size)
#define mem_free(addr) free(addr)
#define mem_clear(addr,size) memset(addr,0,size)
#define mem_fill(addr,data,size) memset(addr,data,size)
#endif /* __external_calls_h__ */

View File

@ -0,0 +1,121 @@
/* The MIT License (MIT)
*
* Copyright (c) 2015 mehdi sotoodeh
*
* 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.
*/
#ifndef __curve25519_base_type_h__
#define __curve25519_base_type_h__
#include <stdint.h>
/* Little-endian as default */
#ifndef ECP_CONFIG_BIG_ENDIAN
#define ECP_CONFIG_LITTLE_ENDIAN
#endif
typedef unsigned char U8;
typedef signed char S8;
#if defined(_MSC_VER)
typedef unsigned __int16 U16;
typedef signed __int16 S16;
typedef unsigned __int32 U32;
typedef signed __int32 S32;
typedef unsigned __int64 U64;
typedef signed __int64 S64;
#else
typedef uint16_t U16;
typedef int16_t S16;
typedef uint32_t U32;
typedef int32_t S32;
typedef uint64_t U64;
typedef int64_t S64;
#endif
typedef unsigned int SZ;
#ifdef ECP_CONFIG_BIG_ENDIAN
typedef union
{
U16 u16;
S16 s16;
U8 bytes[2];
struct { U8 b1, b0; } u8;
struct { S8 b1; U8 b0; } s8;
} M16;
typedef union
{
U32 u32;
S32 s32;
U8 bytes[4];
struct { U16 w1, w0; } u16;
struct { S16 w1; U16 w0; } s16;
struct { U8 b3, b2, b1, b0; } u8;
struct { M16 hi, lo; } m16;
} M32;
typedef union
{
U64 u64;
S64 s64;
U8 bytes[8];
struct { U32 hi, lo; } u32;
struct { S32 hi; U32 lo; } s32;
struct { U16 w3, w2, w1, w0; } u16;
struct { U8 b7, b6, b5, b4, b3, b2, b1, b0; } u8;
struct { M32 hi, lo; } m32;
} M64;
#else
typedef union
{
U16 u16;
S16 s16;
U8 bytes[2];
struct { U8 b0, b1; } u8;
struct { U8 b0; S8 b1; } s8;
} M16;
typedef union
{
U32 u32;
S32 s32;
U8 bytes[4];
struct { U16 w0, w1; } u16;
struct { U16 w0; S16 w1; } s16;
struct { U8 b0, b1, b2, b3; } u8;
struct { M16 lo, hi; } m16;
} M32;
typedef union
{
U64 u64;
S64 s64;
U8 bytes[8];
struct { U32 lo, hi; } u32;
struct { U32 lo; S32 hi; } s32;
struct { U16 w0, w1, w2, w3; } u16;
struct { U8 b0, b1, b2, b3, b4, b5, b6, b7; } u8;
struct { M32 lo, hi; } m32;
} M64;
#endif
#define IN
#define OUT
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,208 @@
/* The MIT License (MIT)
*
* Copyright (c) 2015 mehdi sotoodeh
*
* 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.
*/
#include "../include/external_calls.h"
#include "curve25519_mehdi.h"
typedef struct
{
U_WORD X[K_WORDS]; /* x = X/Z */
U_WORD Z[K_WORDS]; /* */
} XZ_POINT;
extern const U_WORD _w_P[K_WORDS];
extern EDP_BLINDING_CTX edp_custom_blinding;
/* x coordinate of base point */
const U8 ecp_BasePoint[32] = {
9,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0 };
/* Y = X + X */
void ecp_MontDouble(XZ_POINT *Y, const XZ_POINT *X)
{
U_WORD A[K_WORDS], B[K_WORDS];
/* x2 = (x+z)^2 * (x-z)^2 */
/* z2 = ((x+z)^2 - (x-z)^2)*((x+z)^2 + ((A-2)/4)((x+z)^2 - (x-z)^2)) */
ecp_AddReduce(A, X->X, X->Z); /* A = (x+z) */
ecp_SubReduce(B, X->X, X->Z); /* B = (x-z) */
ecp_SqrReduce(A, A); /* A = (x+z)^2 */
ecp_SqrReduce(B, B); /* B = (x-z)^2 */
ecp_MulReduce(Y->X, A, B); /* x2 = (x+z)^2 * (x-z)^2 */
ecp_SubReduce(B, A, B); /* B = (x+z)^2 - (x-z)^2 */
/* (486662-2)/4 = 121665 */
ecp_WordMulAddReduce(A, A, 121665, B);
ecp_MulReduce(Y->Z, A, B); /* z2 = (B)*((x+z)^2 + ((A-2)/4)(B)) */
}
/* return P = P + Q, Q = 2Q */
void ecp_Mont(XZ_POINT *P, XZ_POINT *Q, IN const U_WORD *Base)
{
U_WORD A[K_WORDS], B[K_WORDS], C[K_WORDS], D[K_WORDS], E[K_WORDS];
/* x3 = ((x1-z1)(x2+z2) + (x1+z1)(x2-z2))^2*zb zb=1 */
/* z3 = ((x1-z1)(x2+z2) - (x1+z1)(x2-z2))^2*xb xb=Base */
ecp_SubReduce(A, P->X, P->Z); /* A = x1-z1 */
ecp_AddReduce(B, P->X, P->Z); /* B = x1+z1 */
ecp_SubReduce(C, Q->X, Q->Z); /* C = x2-z2 */
ecp_AddReduce(D, Q->X, Q->Z); /* D = x2+z2 */
ecp_MulReduce(A, A, D); /* A = (x1-z1)(x2+z2) */
ecp_MulReduce(B, B, C); /* B = (x1+z1)(x2-z2) */
ecp_AddReduce(E, A, B); /* E = (x1-z1)(x2+z2) + (x1+z1)(x2-z2) */
ecp_SubReduce(B, A, B); /* B = (x1-z1)(x2+z2) - (x1+z1)(x2-z2) */
ecp_SqrReduce(P->X, E); /* x3 = ((x1-z1)(x2+z2) + (x1+z1)(x2-z2))^2 */
ecp_SqrReduce(A, B); /* A = ((x1-z1)(x2+z2) - (x1+z1)(x2-z2))^2 */
ecp_MulReduce(P->Z, A, Base); /* z3 = ((x1-z1)(x2+z2) - (x1+z1)(x2-z2))^2*Base */
/* x4 = (x2+z2)^2 * (x2-z2)^2 */
/* z4 = ((x2+z2)^2 - (x2-z2)^2)*((x2+z2)^2 + 121665((x2+z2)^2 - (x2-z2)^2)) */
/* C = (x2-z2) */
/* D = (x2+z2) */
ecp_SqrReduce(A, D); /* A = (x2+z2)^2 */
ecp_SqrReduce(B, C); /* B = (x2-z2)^2 */
ecp_MulReduce(Q->X, A, B); /* x4 = (x2+z2)^2 * (x2-z2)^2 */
ecp_SubReduce(B, A, B); /* B = (x2+z2)^2 - (x2-z2)^2 */
ecp_WordMulAddReduce(A, A, 121665, B);
ecp_MulReduce(Q->Z, A, B); /* z4 = B*((x2+z2)^2 + 121665*B) */
}
/* Constant-time measure: */
/* Use different set of parameters for bit=0 or bit=1 with no conditional jump */
/* */
#define ECP_MONT(n) j = (k >> n) & 1; ecp_Mont(PP[j], QP[j], X)
/* -------------------------------------------------------------------------- */
/* Return point Q = k*P */
/* K in a little-endian byte array */
void ecp_PointMultiply(
OUT U8 *PublicKey,
IN const U8 *BasePoint,
IN const U8 *SecretKey,
IN int len)
{
int i, j, k;
U_WORD X[K_WORDS];
XZ_POINT P, Q, *PP[2], *QP[2];
ecp_BytesToWords(X, BasePoint);
/* 1: P = (2k+1)G, Q = (2k+2)G */
/* 0: Q = (2k+1)G, P = (2k)G */
/* Find first non-zero bit */
while (len-- > 0)
{
k = SecretKey[len];
for (i = 0; i < 8; i++, k <<= 1)
{
/* P = kG, Q = (k+1)G */
if (k & 0x80)
{
/* We have first non-zero bit
// This is always bit 254 for keys created according to the spec.
// Start with randomized base point
*/
ecp_Add(P.Z, X, edp_custom_blinding.zr); /* P.Z = random */
ecp_MulReduce(P.X, X, P.Z);
ecp_MontDouble(&Q, &P);
PP[1] = &P; PP[0] = &Q;
QP[1] = &Q; QP[0] = &P;
/* Everything we reference in the below loop are on the stack
// and already touched (cached)
*/
while (++i < 8) { k <<= 1; ECP_MONT(7); }
while (len > 0)
{
k = SecretKey[--len];
ECP_MONT(7);
ECP_MONT(6);
ECP_MONT(5);
ECP_MONT(4);
ECP_MONT(3);
ECP_MONT(2);
ECP_MONT(1);
ECP_MONT(0);
}
ecp_Inverse(Q.Z, P.Z);
ecp_MulMod(X, P.X, Q.Z);
ecp_WordsToBytes(PublicKey, X);
return;
}
}
}
/* K is 0 */
mem_fill(PublicKey, 0, 32);
}
/* -- DH key exchange interfaces ----------------------------------------- */
/* Return R = a*P where P is curve25519 base point */
void x25519_BasePointMultiply(OUT U8 *r, IN const U8 *sk)
{
Ext_POINT S;
U_WORD t[K_WORDS];
ecp_BytesToWords(t, sk);
edp_BasePointMult(&S, t, edp_custom_blinding.zr);
/* Convert ed25519 point to x25519 point */
/* u = (1 + y)/(1 - y) = (Z + Y)/(Z - Y) */
ecp_AddReduce(S.t, S.z, S.y);
ecp_SubReduce(S.z, S.z, S.y);
ecp_Inverse(S.z, S.z);
ecp_MulMod(S.t, S.t, S.z);
ecp_WordsToBytes(r, S.t);
}
/* Return public key associated with sk */
void curve25519_dh_CalculatePublicKey_fast(
unsigned char *pk, /* [32-bytes] OUT: Public key */
unsigned char *sk) /* [32-bytes] IN/OUT: Your secret key */
{
ecp_TrimSecretKey(sk);
/* Use faster method */
x25519_BasePointMultiply(pk, sk);
}
/* Return public key associated with sk */
void curve25519_dh_CalculatePublicKey(
unsigned char *pk, /* [32-bytes] OUT: Public key */
unsigned char *sk) /* [32-bytes] IN/OUT: Your secret key */
{
ecp_TrimSecretKey(sk);
ecp_PointMultiply(pk, ecp_BasePoint, sk, 32);
}
/* Create a shared secret */
void curve25519_dh_CreateSharedKey(
unsigned char *shared, /* [32-bytes] OUT: Created shared key */
const unsigned char *pk, /* [32-bytes] IN: Other side's public key */
unsigned char *sk) /* [32-bytes] IN/OUT: Your secret key */
{
ecp_TrimSecretKey(sk);
ecp_PointMultiply(shared, pk, sk, 32);
}

View File

@ -0,0 +1,410 @@
/* The MIT License (MIT)
*
* Copyright (c) 2015 mehdi sotoodeh
*
* 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.
*/
#include "../include/external_calls.h"
#include "curve25519_mehdi.h"
/*
The curve used is y2 = x^3 + 486662x^2 + x, a Montgomery curve, over
the prime field defined by the prime number 2^255 - 19, and it uses the
base point x = 9.
Protocol uses compressed elliptic point (only X coordinates), so it
allows for efficient use of the Montgomery ladder for ECDH, using only
XZ coordinates.
The curve is birationally equivalent to Ed25519 (Twisted Edwards curve).
b = 256
p = 2**255 - 19
l = 2**252 + 27742317777372353535851937790883648493
This library is a constant-time implementation of field operations
*/
typedef struct
{
U32 X[8]; /* x = X/Z */
U32 Z[8]; /* */
} XZ_POINT;
const U32 _w_P[8] = {
0xFFFFFFED,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0x7FFFFFFF
};
/* Maximum number of prime p that fits into 256-bits */
const U32 _w_maxP[8] = { /* 2*P < 2**256 */
0xFFFFFFDA,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF
};
void ecp_SetValue(U32* X, U32 value)
{
X[0] = value;
X[1] = X[2] = X[3] = X[4] = X[5] = X[6] = X[7] = 0;
}
/* Y = X */
void ecp_Copy(U32* Y, const U32* X)
{
memcpy(Y, X, 8*sizeof(U32));
}
int ecp_CmpNE(const U32* X, const U32* Y)
{
return ((X[0] ^ Y[0]) | (X[1] ^ Y[1]) | (X[2] ^ Y[2]) | (X[3] ^ Y[3]) |
(X[4] ^ Y[4]) | (X[5] ^ Y[5]) | (X[6] ^ Y[6]) | (X[7] ^ Y[7]));
}
int ecp_CmpLT(const U32* X, const U32* Y)
{
U32 T[8];
return ecp_Sub(T, X, Y);
}
#define ECP_ADD_C0(Y,X,V) c.u64 = (U64)(X) + (V); Y = c.u32.lo;
#define ECP_ADD_C1(Y,X) c.u64 = (U64)(X) + c.u32.hi; Y = c.u32.lo;
#define ECP_SUB_C0(Y,X,V) c.s64 = (U64)(X) - (V); Y = c.u32.lo;
#define ECP_SUB_C1(Y,X) c.s64 = (U64)(X) + (S64)c.s32.hi; Y = c.u32.lo;
#define ECP_MULSET_W0(Y,b,X) c.u64 = (U64)(b)*(X); Y = c.u32.lo;
#define ECP_MULSET_W1(Y,b,X) c.u64 = (U64)(b)*(X) + c.u32.hi; Y = c.u32.lo;
#define ECP_MULADD_W0(Z,Y,b,X) c.u64 = (U64)(b)*(X) + (Y); Z = c.u32.lo;
#define ECP_MULADD_W1(Z,Y,b,X) c.u64 = (U64)(b)*(X) + (U64)(Y) + c.u32.hi; Z = c.u32.lo;
#define ECP_ADD32(Z,X,Y) c.u64 = (U64)(X) + (Y); Z = c.u32.lo;
#define ECP_ADC32(Z,X,Y) c.u64 = (U64)(X) + (U64)(Y) + c.u32.hi; Z = c.u32.lo;
#define ECP_SUB32(Z,X,Y) b.s64 = (S64)(X) - (Y); Z = b.s32.lo;
#define ECP_SBC32(Z,X,Y) b.s64 = (S64)(X) - (U64)(Y) + b.s32.hi; Z = b.s32.lo;
/* Computes Z = X+Y */
U32 ecp_Add(U32* Z, const U32* X, const U32* Y)
{
M64 c;
ECP_ADD32(Z[0], X[0], Y[0]);
ECP_ADC32(Z[1], X[1], Y[1]);
ECP_ADC32(Z[2], X[2], Y[2]);
ECP_ADC32(Z[3], X[3], Y[3]);
ECP_ADC32(Z[4], X[4], Y[4]);
ECP_ADC32(Z[5], X[5], Y[5]);
ECP_ADC32(Z[6], X[6], Y[6]);
ECP_ADC32(Z[7], X[7], Y[7]);
return c.u32.hi;
}
/* Computes Z = X-Y */
S32 ecp_Sub(U32* Z, const U32* X, const U32* Y)
{
M64 b;
ECP_SUB32(Z[0], X[0], Y[0]);
ECP_SBC32(Z[1], X[1], Y[1]);
ECP_SBC32(Z[2], X[2], Y[2]);
ECP_SBC32(Z[3], X[3], Y[3]);
ECP_SBC32(Z[4], X[4], Y[4]);
ECP_SBC32(Z[5], X[5], Y[5]);
ECP_SBC32(Z[6], X[6], Y[6]);
ECP_SBC32(Z[7], X[7], Y[7]);
return b.s32.hi;
}
/* Computes Z = X+Y mod P */
void ecp_AddReduce(U32* Z, const U32* X, const U32* Y)
{
M64 c;
c.u32.hi = ecp_Add(Z, X, Y) * 38;
/* Z += c.u32.hi * 38 */
ECP_ADD_C0(Z[0], Z[0], c.u32.hi);
ECP_ADD_C1(Z[1], Z[1]);
ECP_ADD_C1(Z[2], Z[2]);
ECP_ADD_C1(Z[3], Z[3]);
ECP_ADD_C1(Z[4], Z[4]);
ECP_ADD_C1(Z[5], Z[5]);
ECP_ADD_C1(Z[6], Z[6]);
ECP_ADD_C1(Z[7], Z[7]);
/* One more carry at most */
ECP_ADD_C0(Z[0], Z[0], c.u32.hi*38);
ECP_ADD_C1(Z[1], Z[1]);
ECP_ADD_C1(Z[2], Z[2]);
ECP_ADD_C1(Z[3], Z[3]);
ECP_ADD_C1(Z[4], Z[4]);
ECP_ADD_C1(Z[5], Z[5]);
ECP_ADD_C1(Z[6], Z[6]);
ECP_ADD_C1(Z[7], Z[7]);
}
/* Computes Z = X-Y mod P */
void ecp_SubReduce(U32* Z, const U32* X, const U32* Y)
{
M64 c;
c.u32.hi = ecp_Sub(Z, X, Y) & 38;
ECP_SUB_C0(Z[0], Z[0], c.u32.hi);
ECP_SUB_C1(Z[1], Z[1]);
ECP_SUB_C1(Z[2], Z[2]);
ECP_SUB_C1(Z[3], Z[3]);
ECP_SUB_C1(Z[4], Z[4]);
ECP_SUB_C1(Z[5], Z[5]);
ECP_SUB_C1(Z[6], Z[6]);
ECP_SUB_C1(Z[7], Z[7]);
ECP_SUB_C0(Z[0], Z[0], c.u32.hi & 38);
ECP_SUB_C1(Z[1], Z[1]);
ECP_SUB_C1(Z[2], Z[2]);
ECP_SUB_C1(Z[3], Z[3]);
ECP_SUB_C1(Z[4], Z[4]);
ECP_SUB_C1(Z[5], Z[5]);
ECP_SUB_C1(Z[6], Z[6]);
ECP_SUB_C1(Z[7], Z[7]);
}
void ecp_Mod(U32 *X)
{
U32 T[8];
U32 c = (U32)ecp_Sub(X, X, _w_P);
/* set T = 0 if c=0, else T = P */
T[0] = c & 0xFFFFFFED;
T[1] = T[2] = T[3] = T[4] = T[5] = T[6] = c;
T[7] = c >> 1;
ecp_Add(X, X, T); /* X += 0 or P */
/* In case there is another P there */
c = (U32)ecp_Sub(X, X, _w_P);
/* set T = 0 if c=0, else T = P */
T[0] = c & 0xFFFFFFED;
T[1] = T[2] = T[3] = T[4] = T[5] = T[6] = c;
T[7] = c >> 1;
ecp_Add(X, X, T); /* X += 0 or P */
}
/* Computes Y = b*X */
static void ecp_mul_set(U32* Y, U32 b, const U32* X)
{
M64 c;
ECP_MULSET_W0(Y[0], b, X[0]);
ECP_MULSET_W1(Y[1], b, X[1]);
ECP_MULSET_W1(Y[2], b, X[2]);
ECP_MULSET_W1(Y[3], b, X[3]);
ECP_MULSET_W1(Y[4], b, X[4]);
ECP_MULSET_W1(Y[5], b, X[5]);
ECP_MULSET_W1(Y[6], b, X[6]);
ECP_MULSET_W1(Y[7], b, X[7]);
Y[8] = c.u32.hi;
}
/* Computes Y += b*X */
/* Addition is performed on lower 8-words of Y */
static void ecp_mul_add(U32* Y, U32 b, const U32* X)
{
M64 c;
ECP_MULADD_W0(Y[0], Y[0], b, X[0]);
ECP_MULADD_W1(Y[1], Y[1], b, X[1]);
ECP_MULADD_W1(Y[2], Y[2], b, X[2]);
ECP_MULADD_W1(Y[3], Y[3], b, X[3]);
ECP_MULADD_W1(Y[4], Y[4], b, X[4]);
ECP_MULADD_W1(Y[5], Y[5], b, X[5]);
ECP_MULADD_W1(Y[6], Y[6], b, X[6]);
ECP_MULADD_W1(Y[7], Y[7], b, X[7]);
Y[8] = c.u32.hi;
}
/* Computes Z = Y + b*X and return carry */
void ecp_WordMulAddReduce(U32 *Z, const U32* Y, U32 b, const U32* X)
{
M64 c;
ECP_MULADD_W0(Z[0], Y[0], b, X[0]);
ECP_MULADD_W1(Z[1], Y[1], b, X[1]);
ECP_MULADD_W1(Z[2], Y[2], b, X[2]);
ECP_MULADD_W1(Z[3], Y[3], b, X[3]);
ECP_MULADD_W1(Z[4], Y[4], b, X[4]);
ECP_MULADD_W1(Z[5], Y[5], b, X[5]);
ECP_MULADD_W1(Z[6], Y[6], b, X[6]);
ECP_MULADD_W1(Z[7], Y[7], b, X[7]);
/* Z += c.u32.hi * 38 */
ECP_MULADD_W0(Z[0], Z[0], c.u32.hi, 38);
ECP_ADD_C1(Z[1], Z[1]);
ECP_ADD_C1(Z[2], Z[2]);
ECP_ADD_C1(Z[3], Z[3]);
ECP_ADD_C1(Z[4], Z[4]);
ECP_ADD_C1(Z[5], Z[5]);
ECP_ADD_C1(Z[6], Z[6]);
ECP_ADD_C1(Z[7], Z[7]);
/* One more time at most */
ECP_MULADD_W0(Z[0], Z[0], c.u32.hi, 38);
ECP_ADD_C1(Z[1], Z[1]);
ECP_ADD_C1(Z[2], Z[2]);
ECP_ADD_C1(Z[3], Z[3]);
ECP_ADD_C1(Z[4], Z[4]);
ECP_ADD_C1(Z[5], Z[5]);
ECP_ADD_C1(Z[6], Z[6]);
ECP_ADD_C1(Z[7], Z[7]);
}
/* Computes Z = X*Y mod P. */
/* Output fits into 8 words but could be greater than P */
void ecp_MulReduce(U32* Z, const U32* X, const U32* Y)
{
U32 T[16];
ecp_mul_set(T+0, X[0], Y);
ecp_mul_add(T+1, X[1], Y);
ecp_mul_add(T+2, X[2], Y);
ecp_mul_add(T+3, X[3], Y);
ecp_mul_add(T+4, X[4], Y);
ecp_mul_add(T+5, X[5], Y);
ecp_mul_add(T+6, X[6], Y);
ecp_mul_add(T+7, X[7], Y);
/* We have T = X*Y, now do the reduction in size */
ecp_WordMulAddReduce(Z, T, 38, T+8);
}
/* Computes Z = X*Y */
void ecp_Mul(U32* Z, const U32* X, const U32* Y)
{
ecp_mul_set(Z+0, X[0], Y);
ecp_mul_add(Z+1, X[1], Y);
ecp_mul_add(Z+2, X[2], Y);
ecp_mul_add(Z+3, X[3], Y);
ecp_mul_add(Z+4, X[4], Y);
ecp_mul_add(Z+5, X[5], Y);
ecp_mul_add(Z+6, X[6], Y);
ecp_mul_add(Z+7, X[7], Y);
}
/* Computes Z = X*Y mod P. */
void ecp_SqrReduce(U32* Y, const U32* X)
{
/* TBD: Implementation is based on multiply */
/* Optimize for squaring */
U32 T[16];
ecp_mul_set(T+0, X[0], X);
ecp_mul_add(T+1, X[1], X);
ecp_mul_add(T+2, X[2], X);
ecp_mul_add(T+3, X[3], X);
ecp_mul_add(T+4, X[4], X);
ecp_mul_add(T+5, X[5], X);
ecp_mul_add(T+6, X[6], X);
ecp_mul_add(T+7, X[7], X);
/* We have T = X*X, now do the reduction in size */
ecp_WordMulAddReduce(Y, T, 38, T+8);
}
/* Computes Z = X*Y mod P. */
void ecp_MulMod(U32* Z, const U32* X, const U32* Y)
{
ecp_MulReduce(Z, X, Y);
ecp_Mod(Z);
}
/* Courtesy of DJB */
/* Return out = 1/z mod P */
void ecp_Inverse(U32 *out, const U32 *z)
{
int i;
U32 t0[8],t1[8],z2[8],z9[8],z11[8];
U32 z2_5_0[8],z2_10_0[8],z2_20_0[8],z2_50_0[8],z2_100_0[8];
/* 2 */ ecp_SqrReduce(z2,z);
/* 4 */ ecp_SqrReduce(t1,z2);
/* 8 */ ecp_SqrReduce(t0,t1);
/* 9 */ ecp_MulReduce(z9,t0,z);
/* 11 */ ecp_MulReduce(z11,z9,z2);
/* 22 */ ecp_SqrReduce(t0,z11);
/* 2^5 - 2^0 = 31 */ ecp_MulReduce(z2_5_0,t0,z9);
/* 2^6 - 2^1 */ ecp_SqrReduce(t0,z2_5_0);
/* 2^7 - 2^2 */ ecp_SqrReduce(t1,t0);
/* 2^8 - 2^3 */ ecp_SqrReduce(t0,t1);
/* 2^9 - 2^4 */ ecp_SqrReduce(t1,t0);
/* 2^10 - 2^5 */ ecp_SqrReduce(t0,t1);
/* 2^10 - 2^0 */ ecp_MulReduce(z2_10_0,t0,z2_5_0);
/* 2^11 - 2^1 */ ecp_SqrReduce(t0,z2_10_0);
/* 2^12 - 2^2 */ ecp_SqrReduce(t1,t0);
/* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) {
ecp_SqrReduce(t0,t1);
ecp_SqrReduce(t1,t0); }
/* 2^20 - 2^0 */ ecp_MulReduce(z2_20_0,t1,z2_10_0);
/* 2^21 - 2^1 */ ecp_SqrReduce(t0,z2_20_0);
/* 2^22 - 2^2 */ ecp_SqrReduce(t1,t0);
/* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) {
ecp_SqrReduce(t0,t1);
ecp_SqrReduce(t1,t0); }
/* 2^40 - 2^0 */ ecp_MulReduce(t0,t1,z2_20_0);
/* 2^41 - 2^1 */ ecp_SqrReduce(t1,t0);
/* 2^42 - 2^2 */ ecp_SqrReduce(t0,t1);
/* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) {
ecp_SqrReduce(t1,t0);
ecp_SqrReduce(t0,t1); }
/* 2^50 - 2^0 */ ecp_MulReduce(z2_50_0,t0,z2_10_0);
/* 2^51 - 2^1 */ ecp_SqrReduce(t0,z2_50_0);
/* 2^52 - 2^2 */ ecp_SqrReduce(t1,t0);
/* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) {
ecp_SqrReduce(t0,t1);
ecp_SqrReduce(t1,t0); }
/* 2^100 - 2^0 */ ecp_MulReduce(z2_100_0,t1,z2_50_0);
/* 2^101 - 2^1 */ ecp_SqrReduce(t1,z2_100_0);
/* 2^102 - 2^2 */ ecp_SqrReduce(t0,t1);
/* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) {
ecp_SqrReduce(t1,t0);
ecp_SqrReduce(t0,t1); }
/* 2^200 - 2^0 */ ecp_MulReduce(t1,t0,z2_100_0);
/* 2^201 - 2^1 */ ecp_SqrReduce(t0,t1);
/* 2^202 - 2^2 */ ecp_SqrReduce(t1,t0);
/* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) {
ecp_SqrReduce(t0,t1);
ecp_SqrReduce(t1,t0); }
/* 2^250 - 2^0 */ ecp_MulReduce(t0,t1,z2_50_0);
/* 2^251 - 2^1 */ ecp_SqrReduce(t1,t0);
/* 2^252 - 2^2 */ ecp_SqrReduce(t0,t1);
/* 2^253 - 2^3 */ ecp_SqrReduce(t1,t0);
/* 2^254 - 2^4 */ ecp_SqrReduce(t0,t1);
/* 2^255 - 2^5 */ ecp_SqrReduce(t1,t0);
/* 2^255 - 21 */ ecp_MulReduce(out,t1,z11);
}

View File

@ -0,0 +1,175 @@
/* The MIT License (MIT)
*
* Copyright (c) 2015 mehdi sotoodeh
*
* 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.
*/
#ifndef __curve25519_mehdi_h__
#define __curve25519_mehdi_h__
#ifdef __cplusplus
extern "C" {
#endif
#include "BaseTypes.h"
#define ECP_VERSION_STR "1.2.0"
#ifdef USE_ASM_LIB
#define U_WORD U64
#define S_WORD S64
#define WORDSIZE_64
#define W64(lo,hi) ((U64)hi<<32)+lo
#else
#define U_WORD U32
#define S_WORD S32
#define WORDSIZE_32
#define W64(lo,hi) lo,hi
#endif
#define K_BYTES 32
#define K_WORDS (K_BYTES/sizeof(U_WORD))
#define W256(x0,x1,x2,x3,x4,x5,x6,x7) {W64(x0,x1),W64(x2,x3),W64(x4,x5),W64(x6,x7)}
/* Affine coordinates */
typedef struct {
U_WORD x[K_WORDS];
U_WORD y[K_WORDS];
} Affine_POINT;
/* Projective coordinates */
typedef struct {
U_WORD x[K_WORDS]; /* x/z */
U_WORD y[K_WORDS]; /* y/z */
U_WORD z[K_WORDS];
U_WORD t[K_WORDS]; /* xy/z */
} Ext_POINT;
/* pre-computed, extended point */
typedef struct
{
U_WORD YpX[K_WORDS]; /* Y+X */
U_WORD YmX[K_WORDS]; /* Y-X */
U_WORD T2d[K_WORDS]; /* 2d*T */
U_WORD Z2[K_WORDS]; /* 2*Z */
} PE_POINT;
/* pre-computed, Affine point */
typedef struct
{
U_WORD YpX[K_WORDS]; /* Y+X */
U_WORD YmX[K_WORDS]; /* Y-X */
U_WORD T2d[K_WORDS]; /* 2d*T */
} PA_POINT;
typedef struct {
U_WORD bl[K_WORDS];
U_WORD zr[K_WORDS];
PE_POINT BP;
} EDP_BLINDING_CTX;
extern const U8 ecp_BasePoint[K_BYTES];
/* Return point Q = k*P */
void ecp_PointMultiply(OUT U8 *Q, IN const U8 *P, IN const U8 *K, IN int len);
/* Set low and high bits */
void ecp_TrimSecretKey(U8 *X);
/* -- utils ----------------------------------------------------------------- */
/* Convert big-endian byte array to little-endian byte array and vice versa */
U8* ecp_ReverseByteOrder(OUT U8 *Y, IN const U8 *X);
/* Convert little-endian byte array to little-endian word array */
U_WORD* ecp_BytesToWords(OUT U_WORD *Y, IN const U8 *X);
/* Convert little-endian word array to little-endian byte array */
U8* ecp_WordsToBytes(OUT U8 *Y, IN const U_WORD *X);
U8* ecp_EncodeInt(OUT U8 *Y, IN const U_WORD *X, IN U8 parity);
U8 ecp_DecodeInt(OUT U_WORD *Y, IN const U8 *X);
/* -- base point order ------------------------------------------------------ */
/* Z = (X*Y)/R mod BPO */
void eco_MontMul(OUT U_WORD *Z, IN const U_WORD *X, IN const U_WORD *Y);
/* Return Y = X*R mod BPO */
void eco_ToMont(OUT U_WORD *Y, IN const U_WORD *X);
/* Return Y = X/R mod BPO */
void eco_FromMont(OUT U_WORD *Y, IN const U_WORD *X);
/* Calculate Y = X**E mod BPO */
void eco_ExpModBPO(OUT U_WORD *Y, IN const U_WORD *X, IN const U8 *E, IN int bytes);
/* Calculate Y = 1/X mod BPO */
void eco_InvModBPO(OUT U_WORD *Y, IN const U_WORD *X);
/* Z = X*Y mod BPO */
void eco_MulReduce(OUT U_WORD *Z, IN const U_WORD *X, IN const U_WORD *Y);
/* Return Y = D mod BPO where D is 512-bit big-endian byte array (i.e SHA512 digest) */
void eco_DigestToWords( OUT U_WORD *Y, IN const U8 *D);
/* Z = X + Y mod BPO */
void eco_AddReduce(OUT U_WORD *Z, IN const U_WORD *X, IN const U_WORD *Y);
/* X mod BPO */
void eco_Mod(U_WORD *X);
#define ed25519_PackPoint(buff, Y, parity) ecp_EncodeInt(buff, Y, (U8)(parity & 1))
/* -- big-number ------------------------------------------------------------ */
U_WORD ecp_Add(U_WORD* Z, const U_WORD* X, const U_WORD* Y);
S_WORD ecp_Sub(U_WORD* Z, const U_WORD* X, const U_WORD* Y);
void ecp_SetValue(U_WORD* X, U_WORD value);
void ecp_Copy(U_WORD* Y, const U_WORD* X);
void ecp_AddReduce(U_WORD* Z, const U_WORD* X, const U_WORD* Y);
void ecp_SubReduce(U_WORD* Z, const U_WORD* X, const U_WORD* Y);
void ecp_MulReduce(U_WORD* Z, const U_WORD* X, const U_WORD* Y);
void ecp_SqrReduce(U_WORD* Y, const U_WORD* X);
void ecp_ModExp2523(U_WORD *Y, const U_WORD *X);
void ecp_Inverse(U_WORD *out, const U_WORD *z);
void ecp_MulMod(U_WORD* Z, const U_WORD* X, const U_WORD* Y);
void ecp_Mul(U_WORD* Z, const U_WORD* X, const U_WORD* Y);
/* Computes Y = b*X */
void ecp_WordMulSet(U_WORD *Y, U_WORD b, const U_WORD* X);
/* Computes Z = Y + b*X and return carry */
U_WORD ecp_WordMulAdd(U_WORD *Z, const U_WORD* Y, U_WORD b, const U_WORD* X);
/* Computes Z = Y + b*X */
void ecp_WordMulAddReduce(U_WORD *Z, const U_WORD* Y, U_WORD b, const U_WORD* X);
void ecp_Mod(U_WORD* X);
int ecp_CmpNE(const U_WORD* X, const U_WORD* Y);
int ecp_CmpLT(const U_WORD* X, const U_WORD* Y);
/* Calculate: Y = [b:X] mod BPO */
void eco_ReduceHiWord(U_WORD* Y, U_WORD b, const U_WORD* X);
/* -- ed25519 --------------------------------------------------------------- */
void ed25519_UnpackPoint(Affine_POINT *r, const unsigned char *p);
void ed25519_CalculateX(OUT U_WORD *X, IN const U_WORD *Y, U_WORD parity);
void edp_AddAffinePoint(Ext_POINT *p, const PA_POINT *q);
void edp_AddBasePoint(Ext_POINT *p);
void edp_AddPoint(Ext_POINT *r, const Ext_POINT *p, const PE_POINT *q);
void edp_DoublePoint(Ext_POINT *p);
void edp_ComputePermTable(PE_POINT *qtable, Ext_POINT *Q);
void edp_ExtPoint2PE(PE_POINT *r, const Ext_POINT *p);
void edp_BasePointMult(OUT Ext_POINT *S, IN const U_WORD *sk, IN const U_WORD *R);
void edp_BasePointMultiply(OUT Affine_POINT *Q, IN const U_WORD *sk,
IN const void *blinding);
void ecp_4Folds(U8* Y, const U_WORD* X);
void ecp_8Folds(U8* Y, const U_WORD* X);
#ifdef __cplusplus
}
#endif
#endif /* __curve25519_mehdi_h__ */

View File

@ -0,0 +1,155 @@
/* The MIT License (MIT)
*
* Copyright (c) 2015 mehdi sotoodeh
*
* 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.
*/
#include "curve25519_mehdi.h"
/*
This library provides support for mod BPO (Base Point Order) operations
BPO = 2**252 + 27742317777372353535851937790883648493
BPO = 0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED
If you keep adding points together, the result repeats every BPO times.
Based on this, you may use:
public_key = (private_key mod BPO)*BasePoint
Split key example:
k1 = random()
k2 = 1/k1 mod BPO --> k1*k2 = 1 mod BPO
P1 = k1*P0 --> P2 = k2*P1 = k2*k1*P0 = P0
See selftest code for some examples of BPO usage
This library is used for implementation of EdDSA sign/verify.
*/
const U_WORD _w_NxBPO[16][K_WORDS] = { /* n*BPO */
W256(0,0,0,0,0,0,0,0),
W256(0x5CF5D3ED,0x5812631A,0xA2F79CD6,0x14DEF9DE,0,0,0,0x10000000),
W256(0xB9EBA7DA,0xB024C634,0x45EF39AC,0x29BDF3BD,0,0,0,0x20000000),
W256(0x16E17BC7,0x0837294F,0xE8E6D683,0x3E9CED9B,0,0,0,0x30000000),
W256(0x73D74FB4,0x60498C69,0x8BDE7359,0x537BE77A,0,0,0,0x40000000),
W256(0xD0CD23A1,0xB85BEF83,0x2ED6102F,0x685AE159,0,0,0,0x50000000),
W256(0x2DC2F78E,0x106E529E,0xD1CDAD06,0x7D39DB37,0,0,0,0x60000000),
W256(0x8AB8CB7B,0x6880B5B8,0x74C549DC,0x9218D516,0,0,0,0x70000000),
W256(0xE7AE9F68,0xC09318D2,0x17BCE6B2,0xA6F7CEF5,0,0,0,0x80000000),
W256(0x44A47355,0x18A57BED,0xBAB48389,0xBBD6C8D3,0,0,0,0x90000000),
W256(0xA19A4742,0x70B7DF07,0x5DAC205F,0xD0B5C2B2,0,0,0,0xA0000000),
W256(0xFE901B2F,0xC8CA4221,0x00A3BD35,0xE594BC91,0,0,0,0xB0000000),
W256(0x5B85EF1C,0x20DCA53C,0xA39B5A0C,0xFA73B66F,0,0,0,0xC0000000),
W256(0xB87BC309,0x78EF0856,0x4692F6E2,0x0F52B04E,1,0,0,0xD0000000),
W256(0x157196F6,0xD1016B71,0xE98A93B8,0x2431AA2C,1,0,0,0xE0000000),
W256(0x72676AE3,0x2913CE8B,0x8C82308F,0x3910A40B,1,0,0,0xF0000000)
};
#define minusR_0 0xCF5D3ED0
#define minusR_1 0x812631A5
#define minusR_2 0x2F79CD65
#define minusR_3 0x4DEF9DEA
#define minusR_4 1
#define minusR_5 0
#define minusR_6 0
#define minusR_7 0
/* Calculate: Y = [b:X] mod BPO
// For R = 2^256, we calculate Y = b*R + X mod BPO
// Since -R mod BPO is only 129-bits, it reduces number of multiplications if
// we calculate: Y = X - b*(-R) mod BPO instead
// Note that b*(-R) is 161-bits at most and does not need reduction.
*/
void eco_ReduceHiWord(U32* Y, U32 b, const U32* X)
{
M64 c;
U32 T[8];
/* Set T = b*(-R) */
c.u64 = (U64)b*minusR_0;
T[0] = c.u32.lo;
c.u64 = (U64)b*minusR_1 + c.u32.hi;
T[1] = c.u32.lo;
c.u64 = (U64)b*minusR_2 + c.u32.hi;
T[2] = c.u32.lo;
c.u64 = (U64)b*minusR_3 + c.u32.hi;
T[3] = c.u32.lo;
c.u64 = (U64)b + c.u32.hi;
T[4] = c.u32.lo;
T[5] = c.u32.hi;
T[6] = 0;
T[7] = 0;
/* Y = X - T */
c.s32.hi = ecp_Sub(Y, X, T);
/* Add BPO if there is a borrow */
ecp_Add(Y, Y, _w_NxBPO[c.s32.hi & 1]);
}
/* Z = X*Y mod BPO */
void eco_MulReduce(OUT U32 *Z, IN const U32 *X, IN const U32 *Y)
{
U32 T[16];
ecp_Mul(T, X, Y); /* T = X*Y */
eco_ReduceHiWord(T+7, T[15], T+7);
eco_ReduceHiWord(T+6, T[14], T+6);
eco_ReduceHiWord(T+5, T[13], T+5);
eco_ReduceHiWord(T+4, T[12], T+4);
eco_ReduceHiWord(T+3, T[11], T+3);
eco_ReduceHiWord(T+2, T[10], T+2);
eco_ReduceHiWord(T+1, T[9], T+1);
eco_ReduceHiWord(Z, T[8], T+0);
}
/* X mod BPO */
void eco_Mod(U32 *X)
{
S32 c = ecp_Sub(X, X, _w_NxBPO[X[7] >> 28]);
ecp_Add(X, X, _w_NxBPO[c & 1]);
}
/* Z = X + Y mod BPO */
void eco_AddReduce(OUT U32 *Z, IN const U32 *X, IN const U32 *Y)
{
U32 c = ecp_Add(Z, X, Y);
eco_ReduceHiWord(Z, c, Z);
}
/* Return Y = D mod BPO where D is 512-bit message digest (i.e SHA512 digest) */
void eco_DigestToWords( OUT U32 *Y, IN const U8 *md)
{
U32 T[16];
/* We use digest value as little-endian byte array. */
ecp_BytesToWords(T, md);
ecp_BytesToWords(T+8, md+32);
eco_ReduceHiWord(T+7, T[15], T+7);
eco_ReduceHiWord(T+6, T[14], T+6);
eco_ReduceHiWord(T+5, T[13], T+5);
eco_ReduceHiWord(T+4, T[12], T+4);
eco_ReduceHiWord(T+3, T[11], T+3);
eco_ReduceHiWord(T+2, T[10], T+2);
eco_ReduceHiWord(T+1, T[9], T+1);
eco_ReduceHiWord(Y, T[8], T+0);
}

View File

@ -0,0 +1,153 @@
/* The MIT License (MIT)
*
* Copyright (c) 2015 mehdi sotoodeh
*
* 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.
*/
#include "curve25519_mehdi.h"
/* Trim private key */
void ecp_TrimSecretKey(U8 *X)
{
X[0] &= 0xf8;
X[31] = (X[31] | 0x40) & 0x7f;
}
/* Convert big-endian byte array to little-endian byte array and vice versa */
U8* ecp_ReverseByteOrder(OUT U8 *Y, IN const U8 *X)
{
int i;
for (i = 0; i < 32; i++) Y[i] = X[31-i];
return Y;
}
/* Convert little-endian byte array to little-endian word array */
U32* ecp_BytesToWords(OUT U32 *Y, IN const U8 *X)
{
int i;
M32 m;
for (i = 0; i < 8; i++)
{
m.u8.b0 = *X++;
m.u8.b1 = *X++;
m.u8.b2 = *X++;
m.u8.b3 = *X++;
Y[i] = m.u32;
}
return Y;
}
/* Convert little-endian word array to little-endian byte array */
U8* ecp_WordsToBytes(OUT U8 *Y, IN const U32 *X)
{
int i;
M32 m;
for (i = 0; i < 32;)
{
m.u32 = *X++;
Y[i++] = m.u8.b0;
Y[i++] = m.u8.b1;
Y[i++] = m.u8.b2;
Y[i++] = m.u8.b3;
}
return Y;
}
U8* ecp_EncodeInt(OUT U8 *Y, IN const U32 *X, IN U8 parity)
{
int i;
M32 m;
for (i = 0; i < 28;)
{
m.u32 = *X++;
Y[i++] = m.u8.b0;
Y[i++] = m.u8.b1;
Y[i++] = m.u8.b2;
Y[i++] = m.u8.b3;
}
m.u32 = *X;
Y[28] = m.u8.b0;
Y[29] = m.u8.b1;
Y[30] = m.u8.b2;
Y[31] = (U8)((m.u8.b3 & 0x7f) | (parity << 7));
return Y;
}
U8 ecp_DecodeInt(OUT U32 *Y, IN const U8 *X)
{
int i;
M32 m;
for (i = 0; i < 7; i++)
{
m.u8.b0 = *X++;
m.u8.b1 = *X++;
m.u8.b2 = *X++;
m.u8.b3 = *X++;
Y[i] = m.u32;
}
m.u8.b0 = *X++;
m.u8.b1 = *X++;
m.u8.b2 = *X++;
m.u8.b3 = *X & 0x7f;
Y[7] = m.u32;
return (U8)((*X >> 7) & 1);
}
void ecp_4Folds(U8* Y, const U32* X)
{
int i, j;
U8 a, b;
for (i = 32; i-- > 0; Y++)
{
a = 0;
b = 0;
for (j = 8; j > 1;)
{
j -= 2;
a = (a << 1) + ((X[j+1] >> i) & 1);
b = (b << 1) + ((X[j] >> i) & 1);
}
Y[0] = a;
Y[32] = b;
}
}
void ecp_8Folds(U8* Y, const U32* X)
{
int i, j;
U8 a = 0;
for (i = 32; i-- > 0;)
{
for (j = 8; j-- > 0;) a = (a << 1) + ((X[j] >> i) & 1);
*Y++ = a;
}
}

View File

@ -0,0 +1,27 @@
/* The MIT License (MIT)
*
* Copyright (c) 2015 mehdi sotoodeh
*
* 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.
*/
#include "curve25519_mehdi.h"
#include "custom_blind.h"

View File

@ -0,0 +1,11 @@
EDP_BLINDING_CTX edp_custom_blinding =
{
W256(0xDB763B3D,0x2F33DD36,0xF8DC6F74,0x98C50273,0x8216E0D5,0x1AA522E6,0x6BFD2924,0x04BEFBE2),
W256(0x73FF0C54,0x459E8BA8,0x84F9550B,0xDBF5F46A,0x6DB0E537,0x65F44FFD,0x2AED4E78,0x2CF92B82),
{
W256(0xAA6B12E6,0x7E6A2126,0x2E016899,0x80453AE0,0x6F300787,0x7A7E739E,0x264D5BA3,0x4C34AA79),
W256(0x52EA83C8,0xE4156040,0x0792FA4C,0x97CA4A43,0x3C9611E1,0x2198FE81,0x41AEAAE6,0x11919AD1),
W256(0x54A55516,0xCD8ADA8A,0x820A3D65,0xF85C2DB2,0x06667F3B,0xFF1E45F7,0x26BD6148,0x7F4E9D95),
W256(0xA4986374,0x2C1BF6DE,0x57ABC779,0x7C913D04,0xFA1127FA,0x1D7E8692,0xDE0E0680,0xC636320A)
}
};

View File

@ -0,0 +1,419 @@
/* The MIT License (MIT)
*
* Copyright (c) 2015 mehdi sotoodeh
*
* 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.
*/
#include "../include/external_calls.h"
#include "curve25519_mehdi.h"
#include "../include/ed25519_signature.h"
#include "sha512.h"
/*
* Arithmetic on twisted Edwards curve y^2 - x^2 = 1 + dx^2y^2
* with d = -(121665/121666) mod p
* d = 0x52036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978A3
* p = 2**255 - 19
* p = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED
* Base point: y=4/5 mod p
* x = 0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A
* y = 0x6666666666666666666666666666666666666666666666666666666666666658
* Base point order:
* l = 2**252 + 27742317777372353535851937790883648493
* l = 0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED
*/
extern const U_WORD _w_maxP[K_WORDS];
extern const U_WORD _w_NxBPO[16][K_WORDS];
#define _w_BPO _w_NxBPO[1]
/*
// -- custom blind ---------------------------------------------------------
//
// edp_custom_blinding is defined in source/custom_blind.c
// source/custom_blind is created randomly on every new build
//
// -------------------------------------------------------------------------
*/
extern EDP_BLINDING_CTX edp_custom_blinding;
const U_WORD _w_2d[K_WORDS] = /* 2*d */
W256(0x26B2F159,0xEBD69B94,0x8283B156,0x00E0149A,0xEEF3D130,0x198E80F2,0x56DFFCE7,0x2406D9DC);
const U_WORD _w_di[K_WORDS] = /* 1/d */
W256(0xCDC9F843,0x25E0F276,0x4279542E,0x0B5DD698,0xCDB9CF66,0x2B162114,0x14D5CE43,0x40907ED2);
#include "base_folding8.h"
/*
Reference: http://eprint.iacr.org/2008/522
Cost: 7M + 7add
Return: R = P + BasePoint
*/
void edp_AddBasePoint(Ext_POINT *p)
{
U_WORD a[K_WORDS], b[K_WORDS], c[K_WORDS], d[K_WORDS], e[K_WORDS];
ecp_SubReduce(a, p->y, p->x); /* A = (Y1-X1)*(Y2-X2) */
ecp_MulReduce(a, a, _w_base_folding8[1].YmX);
ecp_AddReduce(b, p->y, p->x); /* B = (Y1+X1)*(Y2+X2) */
ecp_MulReduce(b, b, _w_base_folding8[1].YpX);
ecp_MulReduce(c, p->t, _w_base_folding8[1].T2d); /* C = T1*2d*T2 */
ecp_AddReduce(d, p->z, p->z); /* D = 2*Z1 */
ecp_SubReduce(e, b, a); /* E = B-A */
ecp_AddReduce(b, b, a); /* H = B+A */
ecp_SubReduce(a, d, c); /* F = D-C */
ecp_AddReduce(d, d, c); /* G = D+C */
ecp_MulReduce(p->x, e, a); /* E*F */
ecp_MulReduce(p->y, b, d); /* H*G */
ecp_MulReduce(p->t, e, b); /* E*H */
ecp_MulReduce(p->z, d, a); /* G*F */
}
/*
Assumptions: pre-computed q, q->Z=1
Cost: 7M + 7add
Return: P = P + Q
*/
void edp_AddAffinePoint(Ext_POINT *p, const PA_POINT *q)
{
U_WORD a[K_WORDS], b[K_WORDS], c[K_WORDS], d[K_WORDS], e[K_WORDS];
ecp_SubReduce(a, p->y, p->x); /* A = (Y1-X1)*(Y2-X2) */
ecp_MulReduce(a, a, q->YmX);
ecp_AddReduce(b, p->y, p->x); /* B = (Y1+X1)*(Y2+X2) */
ecp_MulReduce(b, b, q->YpX);
ecp_MulReduce(c, p->t, q->T2d); /* C = T1*2d*T2 */
ecp_AddReduce(d, p->z, p->z); /* D = Z1*2*Z2 (Z2=1)*/
ecp_SubReduce(e, b, a); /* E = B-A */
ecp_AddReduce(b, b, a); /* H = B+A */
ecp_SubReduce(a, d, c); /* F = D-C */
ecp_AddReduce(d, d, c); /* G = D+C */
ecp_MulReduce(p->x, e, a); /* E*F */
ecp_MulReduce(p->y, b, d); /* H*G */
ecp_MulReduce(p->t, e, b); /* E*H */
ecp_MulReduce(p->z, d, a); /* G*F */
}
/*
Reference: http://eprint.iacr.org/2008/522
Cost: 4M + 4S + 7add
Return: P = 2*P
*/
void edp_DoublePoint(Ext_POINT *p)
{
U_WORD a[K_WORDS], b[K_WORDS], c[K_WORDS], d[K_WORDS], e[K_WORDS];
ecp_SqrReduce(a, p->x); /* A = X1^2 */
ecp_SqrReduce(b, p->y); /* B = Y1^2 */
ecp_SqrReduce(c, p->z); /* C = 2*Z1^2 */
ecp_AddReduce(c, c, c);
ecp_SubReduce(d, _w_maxP, a); /* D = -A */
ecp_SubReduce(a, d, b); /* H = D-B */
ecp_AddReduce(d, d, b); /* G = D+B */
ecp_SubReduce(b, d, c); /* F = G-C */
ecp_AddReduce(e, p->x, p->y); /* E = (X1+Y1)^2-A-B = (X1+Y1)^2+H */
ecp_SqrReduce(e, e);
ecp_AddReduce(e, e, a);
ecp_MulReduce(p->x, e, b); /* E*F */
ecp_MulReduce(p->y, a, d); /* H*G */
ecp_MulReduce(p->z, d, b); /* G*F */
ecp_MulReduce(p->t, e, a); /* E*H */
}
/* -- FOLDING ---------------------------------------------------------------
//
// The performance boost is achieved by a process that I call it FOLDING.
// Folding can be viewed as an extension of Shamir's trick but it is based
// on break down of the scalar multiplier of a*P into a polynomial of the
// form:
//
// a*P = SUM(a_i*2^(i*w))*P for i = 0,1,2,...n-1
//
// a*P = SUM(a_i*P_i)
//
// where P_i = (2^(i*w))*P
// n = number of folds
// w = bit-length of a_i
//
// For folding of 8, 256-bit multiplier 'a' is chopped into 8 limbs of
// 32-bits each (a_0, a_1,...a_7). P_0 - P_7 can be pre-calculated and
// their 256-different permutations can be cached or hard-coded
// directly into the code.
// This arrangement combined with double-and-add approach reduces the
// number of EC point calculations by a factor of 8. We only need 31
// double & add operations.
//
// +---+---+---+---+---+---+- .... -+---+---+---+---+---+---+
// a = (|255|254|253|252|251|250| | 5 | 4 | 3 | 2 | 1 | 0 |)
// +---+---+---+---+---+---+- .... -+---+---+---+---+---+---+
//
// a_i P_i
// +---+---+---+ .... -+---+---+---+ ----------
// a7 = (|255|254|253| |226|225|224|) * (2**224)*P
// +---+---+---+ .... -+---+---+---+
// a6 = (|225|224|223| |194|193|192|) * (2**192)*P
// +---+---+---+ .... -+---+---+---+
// a5 = (|191|190|189| |162|161|160|) * (2**160)*P
// +---+---+---+ .... -+---+---+---+
// a4 = (|159|158|157| |130|129|128|) * (2**128)*P
// +---+---+---+ .... -+---+---+---+
// a3 = (|127|126|125| | 98| 97| 96|) * (2**96)*P
// +---+---+---+ .... -+---+---+---+
// a2 = (| 95| 94| 93| | 66| 65| 64|) * (2**64)*P
// +---+---+---+ .... -+---+---+---+
// a1 = (| 63| 62| 61| | 34| 33| 32|) * (2**32)*P
// +---+---+---+ .... -+---+---+---+
// a0 = (| 31| 30| 29| | 2 | 1 | 0 |) * (2**0)*P
// +---+---+---+ .... -+---+---+---+
// | | | |
// | +--+ | +--+
// | | | |
// V V slices V V
// +---+ +---+ .... +---+ +---+
// |255| |254| |225| |224| P7
// +---+ +---+ .... +---+ +---+
// |225| |224| |193| |192| P6
// +---+ +---+ .... +---+ +---+
// |191| |190| |161| |160| P5
// +---+ +---+ .... +---+ +---+
// |159| |158| |129| |128| P4
// +---+ +---+ .... +---+ +---+
// |127| |126| | 97| | 96| P3
// +---+ +---+ .... +---+ +---+
// | 95| | 94| | 65| | 64| P2
// +---+ +---+ .... +---+ +---+
// | 63| | 62| | 33| | 32| P1
// +---+ +---+ .... +---+ +---+
// | 31| | 30| | 1 | | 0 | P0
// +---+ +---+ .... +---+ +---+
// cut[]: 0 1 .... 30 31
// --------------------------------------------------------------------------
// Return S = a*P where P is ed25519 base point and R is random
*/
void edp_BasePointMult(
OUT Ext_POINT *S,
IN const U_WORD *sk,
IN const U_WORD *R)
{
int i = 1;
U8 cut[32];
const PA_POINT *p0;
ecp_8Folds(cut, sk);
p0 = &_w_base_folding8[cut[0]];
ecp_SubReduce(S->x, p0->YpX, p0->YmX); /* 2x */
ecp_AddReduce(S->y, p0->YpX, p0->YmX); /* 2y */
ecp_MulReduce(S->t, p0->T2d, _w_di); /* 2xy */
/* Randomize starting point */
ecp_AddReduce(S->z, R, R); /* Z = 2R */
ecp_MulReduce(S->x, S->x, R); /* X = 2xR */
ecp_MulReduce(S->t, S->t, R); /* T = 2xyR */
ecp_MulReduce(S->y, S->y, R); /* Y = 2yR */
do
{
edp_DoublePoint(S);
edp_AddAffinePoint(S, &_w_base_folding8[cut[i]]);
} while (i++ < 31);
}
void edp_BasePointMultiply(
OUT Affine_POINT *R,
IN const U_WORD *sk,
IN const void *blinding)
{
Ext_POINT S;
U_WORD t[K_WORDS];
if (blinding)
{
eco_AddReduce(t, sk, ((EDP_BLINDING_CTX*)blinding)->bl);
edp_BasePointMult(&S, t, ((EDP_BLINDING_CTX*)blinding)->zr);
edp_AddPoint(&S, &S, &((EDP_BLINDING_CTX*)blinding)->BP);
}
else
{
edp_BasePointMult(&S, sk, edp_custom_blinding.zr);
}
ecp_Inverse(S.z, S.z);
ecp_MulMod(R->x, S.x, S.z);
ecp_MulMod(R->y, S.y, S.z);
}
void edp_ExtPoint2PE(PE_POINT *r, const Ext_POINT *p)
{
ecp_AddReduce(r->YpX, p->y, p->x);
ecp_SubReduce(r->YmX, p->y, p->x);
ecp_MulReduce(r->T2d, p->t, _w_2d);
ecp_AddReduce(r->Z2, p->z, p->z);
}
/* -- Blinding -------------------------------------------------------------
//
// Blinding is a measure to protect against side channel attacks.
// Blinding randomizes the scalar multiplier.
//
// Instead of calculating a*P, calculate (a+b mod BPO)*P + B
//
// Where b = random blinding and B = -b*P
//
// -------------------------------------------------------------------------
*/
void *ed25519_Blinding_Init(
void *context, /* IO: null or ptr blinding context */
const unsigned char *seed, /* IN: [size bytes] random blinding seed */
size_t size) /* IN: size of blinding seed */
{
struct {
Ext_POINT T;
U_WORD t[K_WORDS];
SHA512_CTX H;
U8 digest[SHA512_DIGEST_LENGTH];
} d;
EDP_BLINDING_CTX *ctx = (EDP_BLINDING_CTX*)context;
if (ctx == 0)
{
ctx = (EDP_BLINDING_CTX*)mem_alloc(sizeof(EDP_BLINDING_CTX));
if (ctx == 0) return 0;
}
/* Use edp_custom_blinding to protect generation of the new blinder */
SHA512_Init(&d.H);
SHA512_Update(&d.H, edp_custom_blinding.zr, 32);
SHA512_Update(&d.H, seed, size);
SHA512_Final(d.digest, &d.H);
ecp_BytesToWords(ctx->zr, d.digest+32);
ecp_BytesToWords(d.t, d.digest);
eco_Mod(d.t);
ecp_Sub(ctx->bl, _w_BPO, d.t);
eco_AddReduce(d.t, d.t, edp_custom_blinding.bl);
edp_BasePointMult(&d.T, d.t, edp_custom_blinding.zr);
edp_AddPoint(&d.T, &d.T, &edp_custom_blinding.BP);
edp_ExtPoint2PE(&ctx->BP, &d.T);
/* clear potentially sensitive data */
mem_clear (&d, sizeof(d));
return ctx;
}
void ed25519_Blinding_Finish(
void *context) /* IN: blinding context */
{
if (context)
{
mem_clear (context, sizeof(EDP_BLINDING_CTX));
mem_free (context);
}
}
/* Generate public and private key pair associated with the secret key */
void ed25519_CreateKeyPair(
unsigned char *pubKey, /* OUT: public key */
unsigned char *privKey, /* OUT: private key */
const void *blinding, /* IN: [optional] null or blinding context */
const unsigned char *sk) /* IN: secret key (32 bytes) */
{
U8 md[SHA512_DIGEST_LENGTH];
U_WORD t[K_WORDS];
SHA512_CTX H;
Affine_POINT Q;
/* [a:b] = H(sk) */
SHA512_Init(&H);
SHA512_Update(&H, sk, 32);
SHA512_Final(md, &H);
ecp_TrimSecretKey(md);
ecp_BytesToWords(t, md);
edp_BasePointMultiply(&Q, t, blinding);
ed25519_PackPoint(pubKey, Q.y, Q.x[0]);
memcpy(privKey, sk, 32);
memcpy(privKey+32, pubKey, 32);
}
/*
* Generate message signature
*/
void ed25519_SignMessage(
unsigned char *signature, /* OUT: [64 bytes] signature (R,S) */
const unsigned char *privKey, /* IN: [64 bytes] private key (sk,pk) */
const void *blinding, /* IN: [optional] null or blinding context */
const unsigned char *msg, /* IN: [msg_size bytes] message to sign */
size_t msg_size)
{
SHA512_CTX H;
Affine_POINT R;
U_WORD a[K_WORDS], t[K_WORDS], r[K_WORDS];
U8 md[SHA512_DIGEST_LENGTH];
/* [a:b] = H(sk) */
SHA512_Init(&H);
SHA512_Update(&H, privKey, 32);
SHA512_Final(md, &H);
ecp_TrimSecretKey(md); /* a = first 32 bytes */
ecp_BytesToWords(a, md);
/* r = H(b + m) mod BPO */
SHA512_Init(&H);
SHA512_Update(&H, md+32, 32);
SHA512_Update(&H, msg, msg_size);
SHA512_Final(md, &H);
eco_DigestToWords(r, md);
eco_Mod(r); /* r mod BPO */
/* R = r*P */
edp_BasePointMultiply(&R, r, blinding);
ed25519_PackPoint(signature, R.y, R.x[0]); /* R part of signature */
/* S = r + H(encoded(R) + pk + m) * a mod BPO */
SHA512_Init(&H);
SHA512_Update(&H, signature, 32); /* encoded(R) */
SHA512_Update(&H, privKey+32, 32); /* pk */
SHA512_Update(&H, msg, msg_size); /* m */
SHA512_Final(md, &H);
eco_DigestToWords(t, md);
eco_MulReduce(t, t, a); /* h()*a */
eco_AddReduce(t, t, r);
eco_Mod(t);
ecp_WordsToBytes(signature+32, t); /* S part of signature */
/* Clear sensitive data */
ecp_SetValue(a, 0);
ecp_SetValue(r, 0);
}

View File

@ -0,0 +1,313 @@
/* The MIT License (MIT)
*
* Copyright (c) 2015 mehdi sotoodeh
*
* 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.
*/
#include "../include/external_calls.h"
#include "curve25519_mehdi.h"
#include "../include/ed25519_signature.h"
#include "sha512.h"
/*
* Arithmetic on twisted Edwards curve y^2 - x^2 = 1 + dx^2y^2
* with d = -(121665/121666) mod p
* d = 0x52036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978A3
* p = 2**255 - 19
* p = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED
* Base point: y=4/5 mod p
* x = 0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A
* y = 0x6666666666666666666666666666666666666666666666666666666666666658
* Base point order:
* l = 2**252 + 27742317777372353535851937790883648493
* l = 0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED
*/
typedef struct {
unsigned char pk[32];
PE_POINT q_table[16];
} EDP_SIGV_CTX;
extern const U_WORD _w_P[K_WORDS];
extern const U_WORD _w_di[K_WORDS];
extern const PA_POINT _w_base_folding8[256];
extern const U_WORD _w_NxBPO[16][K_WORDS];
#define _w_BPO _w_NxBPO[1]
#define _w_Zero _w_base_folding8[0].T2d
#define _w_One _w_base_folding8[0].YpX
const U_WORD _w_I[K_WORDS] = /* sqrt(-1) */
W256(0x4A0EA0B0,0xC4EE1B27,0xAD2FE478,0x2F431806,0x3DFBD7A7,0x2B4D0099,0x4FC1DF0B,0x2B832480);
static const U_WORD _w_d[K_WORDS] =
W256(0x135978A3,0x75EB4DCA,0x4141D8AB,0x00700A4D,0x7779E898,0x8CC74079,0x2B6FFE73,0x52036CEE);
void ed25519_CalculateX(OUT U_WORD *X, IN const U_WORD *Y, U_WORD parity)
{
U_WORD u[K_WORDS], v[K_WORDS], a[K_WORDS], b[K_WORDS];
/* Calculate sqrt((y^2 - 1)/(d*y^2 + 1)) */
ecp_SqrReduce(u, Y); /* u = y^2 */
ecp_MulReduce(v, u, _w_d); /* v = dy^2 */
ecp_SubReduce(u, u, _w_One); /* u = y^2-1 */
ecp_AddReduce(v, v, _w_One); /* v = dy^2+1 */
/* Calculate: sqrt(u/v) = u*v^3 * (u*v^7)^((p-5)/8) */
ecp_SqrReduce(b, v);
ecp_MulReduce(a, u, b);
ecp_MulReduce(a, a, v); /* a = u*v^3 */
ecp_SqrReduce(b, b); /* b = v^4 */
ecp_MulReduce(b, a, b); /* b = u*v^7 */
ecp_ModExp2523(b, b);
ecp_MulReduce(X, b, a);
/* Check if we have correct sqrt, else, multiply by sqrt(-1) */
ecp_SqrReduce(b, X);
ecp_MulReduce(b, b, v);
ecp_SubReduce(b, b, u);
ecp_Mod(b);
if (ecp_CmpNE(b, _w_Zero)) ecp_MulReduce(X, X, _w_I);
while (ecp_CmpLT(X, _w_P) == 0) ecp_Sub(X, X, _w_P);
/* match parity */
if (((X[0] ^ parity) & 1) != 0)
ecp_Sub(X, _w_P, X);
}
void ed25519_UnpackPoint(Affine_POINT *r, const unsigned char *p)
{
U8 parity = ecp_DecodeInt(r->y, p);
ed25519_CalculateX(r->x, r->y, parity);
}
void ecp_SrqMulReduce(U_WORD *Z, const U_WORD *X, int n, const U_WORD *Y)
{
U_WORD t[K_WORDS];
ecp_SqrReduce(t, X);
while (n-- > 1) ecp_SqrReduce(t, t);
ecp_MulReduce(Z, t, Y);
}
void ecp_ModExp2523(U_WORD *Y, const U_WORD *X)
{
U_WORD x2[K_WORDS], x9[K_WORDS], x11[K_WORDS], x5[K_WORDS], x10[K_WORDS];
U_WORD x20[K_WORDS], x50[K_WORDS], x100[K_WORDS], t[K_WORDS];
ecp_SqrReduce(x2, X); /* 2 */
ecp_SrqMulReduce(x9, x2, 2, X); /* 9 */
ecp_MulReduce(x11, x9, x2); /* 11 */
ecp_SqrReduce(t, x11); /* 22 */
ecp_MulReduce(x5, t, x9); /* 31 = 2^5 - 2^0 */
ecp_SrqMulReduce(x10, x5, 5, x5); /* 2^10 - 2^0 */
ecp_SrqMulReduce(x20, x10, 10, x10); /* 2^20 - 2^0 */
ecp_SrqMulReduce(t, x20, 20, x20); /* 2^40 - 2^0 */
ecp_SrqMulReduce(x50, t, 10, x10); /* 2^50 - 2^0 */
ecp_SrqMulReduce(x100, x50, 50, x50); /* 2^100 - 2^0 */
ecp_SrqMulReduce(t, x100, 100, x100); /* 2^200 - 2^0 */
ecp_SrqMulReduce(t, t, 50, x50); /* 2^250 - 2^0 */
ecp_SqrReduce(t, t); ecp_SqrReduce(t, t); /* 2^252 - 2^2 */
ecp_MulReduce(Y, t, X); /* 2^252 - 3 */
}
/*
Assumptions: pre-computed q
Cost: 8M + 6add
Return: P = P + Q
*/
void edp_AddPoint(Ext_POINT *r, const Ext_POINT *p, const PE_POINT *q)
{
U_WORD a[K_WORDS], b[K_WORDS], c[K_WORDS], d[K_WORDS], e[K_WORDS];
ecp_SubReduce(a, p->y, p->x); /* A = (Y1-X1)*(Y2-X2) */
ecp_MulReduce(a, a, q->YmX);
ecp_AddReduce(b, p->y, p->x); /* B = (Y1+X1)*(Y2+X2) */
ecp_MulReduce(b, b, q->YpX);
ecp_MulReduce(c, p->t, q->T2d); /* C = T1*2d*T2 */
ecp_MulReduce(d, p->z, q->Z2); /* D = Z1*2*Z2 */
ecp_SubReduce(e, b, a); /* E = B-A */
ecp_AddReduce(b, b, a); /* H = B+A */
ecp_SubReduce(a, d, c); /* F = D-C */
ecp_AddReduce(d, d, c); /* G = D+C */
ecp_MulReduce(r->x, e, a); /* E*F */
ecp_MulReduce(r->y, b, d); /* H*G */
ecp_MulReduce(r->t, e, b); /* E*H */
ecp_MulReduce(r->z, d, a); /* G*F */
}
int ed25519_VerifySignature(
const unsigned char *signature, /* IN: signature (R,S) */
const unsigned char *publicKey, /* IN: public key */
const unsigned char *msg, size_t msg_size) /* IN: message to sign */
{
EDP_SIGV_CTX ctx;
ed25519_Verify_Init(&ctx, publicKey);
return ed25519_Verify_Check(&ctx, signature, msg, msg_size);
}
#define QTABLE_SET(d,s) \
edp_AddPoint(&T, &Q, &ctx->q_table[s]); \
edp_ExtPoint2PE(&ctx->q_table[d], &T)
void * ed25519_Verify_Init(
void *context, /* IO: null or context buffer to use */
const unsigned char *publicKey) /* IN: [32 bytes] public key */
{
int i;
Ext_POINT Q, T;
EDP_SIGV_CTX *ctx = (EDP_SIGV_CTX*)context;
if (ctx == 0) ctx = (EDP_SIGV_CTX*)mem_alloc(sizeof(EDP_SIGV_CTX));
if (ctx)
{
memcpy(ctx->pk, publicKey, 32);
i = ecp_DecodeInt(Q.y, publicKey);
ed25519_CalculateX(Q.x, Q.y, ~i); /* Invert parity for -Q */
ecp_MulMod(Q.t, Q.x, Q.y);
ecp_SetValue(Q.z, 1);
/* pre-compute q-table */
/* Calculate: Q0=Q, Q1=(2^64)*Q, Q2=(2^128)*Q, Q3=(2^192)*Q */
ecp_SetValue(ctx->q_table[0].YpX, 1); /* -- -- -- -- */
ecp_SetValue(ctx->q_table[0].YmX, 1);
ecp_SetValue(ctx->q_table[0].T2d, 0);
ecp_SetValue(ctx->q_table[0].Z2, 2);
edp_ExtPoint2PE(&ctx->q_table[1], &Q); /* -- -- -- q0 */
for (i = 0; i < 64; i++) edp_DoublePoint(&Q);
edp_ExtPoint2PE(&ctx->q_table[2], &Q); /* -- -- q1 -- */
QTABLE_SET(3,1); /* -- -- q1 q0 */
do edp_DoublePoint(&Q); while (++i < 128);
edp_ExtPoint2PE(&ctx->q_table[4], &Q); /* -- q2 -- -- */
QTABLE_SET(5, 1); /* -- q2 -- q0 */
QTABLE_SET(6, 2); /* -- q2 q1 -- */
QTABLE_SET(7, 3); /* -- q2 q1 q0 */
do edp_DoublePoint(&Q); while (++i < 192);
edp_ExtPoint2PE(&ctx->q_table[8], &Q); /* q3 -- -- -- */
QTABLE_SET(9, 1); /* q3 -- -- q0 */
QTABLE_SET(10, 2); /* q3 -- q1 -- */
QTABLE_SET(11, 3); /* q3 -- q1 q0 */
QTABLE_SET(12, 4); /* q3 q2 -- -- */
QTABLE_SET(13, 5); /* q3 q2 -- q0 */
QTABLE_SET(14, 6); /* q3 q2 q1 -- */
QTABLE_SET(15, 7); /* q3 q2 q1 q0 */
}
return ctx;
}
void ed25519_Verify_Finish(void *ctx)
{
mem_free(ctx);
}
/*
Assumptions: qtable = pre-computed Q
Calculate: point R = a*P + b*Q where P is base point
*/
static void edp_PolyPointMultiply(
Affine_POINT *r,
const U_WORD *a,
const U_WORD *b,
const PE_POINT *qtable)
{
int i = 1;
Ext_POINT S;
const PE_POINT *q0;
U8 u[32], v[64];
ecp_8Folds(u, a);
ecp_4Folds(v, b);
/* Set initial value of S */
q0 = &qtable[v[0]];
ecp_SubReduce(S.x, q0->YpX, q0->YmX); /* 2x */
ecp_AddReduce(S.y, q0->YpX, q0->YmX); /* 2y */
ecp_MulReduce(S.t, q0->T2d, _w_di); /* 2xy */
ecp_Copy(S.z, q0->Z2); /* 2z */
do
{ /* 31D + 31A */
edp_DoublePoint(&S);
edp_AddPoint(&S, &S, &qtable[v[i]]);
} while (++i < 32);
do
{ /* 32D + 64A */
edp_DoublePoint(&S);
edp_AddAffinePoint(&S, &_w_base_folding8[u[i-32]]);
edp_AddPoint(&S, &S, &qtable[v[i]]);
} while (++i < 64);
ecp_Inverse(S.z, S.z);
ecp_MulMod(r->x, S.x, S.z);
ecp_MulMod(r->y, S.y, S.z);
}
/*
This function can be used for batch verification.
Assumptions: context = ed25519_Verify_Init(pk)
*/
int ed25519_Verify_Check(
const void *context, /* IN: precomputes */
const unsigned char *signature, /* IN: signature (R,S) */
const unsigned char *msg, size_t msg_size) /* IN: message to sign */
{
SHA512_CTX H;
Affine_POINT T;
U_WORD h[K_WORDS], s[K_WORDS];
U8 md[SHA512_DIGEST_LENGTH];
/* h = H(enc(R) + pk + m) mod BPO */
SHA512_Init(&H);
SHA512_Update(&H, signature, 32); /* enc(R) */
SHA512_Update(&H, ((EDP_SIGV_CTX*)context)->pk, 32);
SHA512_Update(&H, msg, msg_size);
SHA512_Final(md, &H);
eco_DigestToWords(h, md);
eco_Mod(h);
/* T = s*P + h*(-Q) = (s - h*a)*P = r*P = R */
ecp_BytesToWords(s, signature+32);
edp_PolyPointMultiply(&T, s, h, ((EDP_SIGV_CTX*)context)->q_table);
ed25519_PackPoint(md, T.y, T.x[0]);
return (memcmp(md, signature, 32) == 0) ? 1 : 0;
}

294
source/extern/curve25519/source/sha512.c vendored Normal file
View File

@ -0,0 +1,294 @@
/* crypto/sha/sha512.c */
/* ====================================================================
* Copyright (c) 2004 The OpenSSL Project. All rights reserved
* according to the OpenSSL license [found in ../../LICENSE].
* ====================================================================
*/
/*
* IMPLEMENTATION NOTES.
*
* As you might have noticed 32-bit hash algorithms:
*
* - permit SHA_LONG to be wider than 32-bit (case on CRAY);
* - optimized versions implement two transform functions: one operating
* on [aligned] data in host byte order and one - on data in input
* stream byte order;
* - share common byte-order neutral collector and padding function
* implementations, ../md32_common.h;
*
* Neither of the above applies to this SHA-512 implementations. Reasons
* [in reverse order] are:
*
* - it's the only 64-bit hash algorithm for the moment of this writing,
* there is no need for common collector/padding implementation [yet];
* - by supporting only one transform function [which operates on
* *aligned* data in input stream byte order, big-endian in this case]
* we minimize burden of maintenance in two ways: a) collector/padding
* function is simpler; b) only one transform function to stare at;
* - SHA_LONG64 is required to be exactly 64-bit in order to be able to
* apply a number of optimizations to mitigate potential performance
* penalties caused by previous design decision;
*
* Caveat lector.
*
* Implementation relies on the fact that "long long" is 64-bit on
* both 32- and 64-bit platforms. If some compiler vendor comes up
* with 128-bit long long, adjustment to sha.h would be required.
* As this implementation relies on 64-bit integer type, it's totally
* inappropriate for platforms which don't support it, most notably
* 16-bit platforms.
* <appro@fy.chalmers.se>
*/
#include <string.h>
#include "../include/external_calls.h"
#include "sha512.h"
#define UINT64(X) X##ULL
void SHA512_Transform (SHA512_CTX *ctx, const void *in);
void SHA512_Init (SHA512_CTX *c)
{
c->h[0]=UINT64(0x6a09e667f3bcc908);
c->h[1]=UINT64(0xbb67ae8584caa73b);
c->h[2]=UINT64(0x3c6ef372fe94f82b);
c->h[3]=UINT64(0xa54ff53a5f1d36f1);
c->h[4]=UINT64(0x510e527fade682d1);
c->h[5]=UINT64(0x9b05688c2b3e6c1f);
c->h[6]=UINT64(0x1f83d9abfb41bd6b);
c->h[7]=UINT64(0x5be0cd19137e2179);
c->Nl=0;
c->Nh=0;
c->num=0;
c->md_len=SHA512_DIGEST_LENGTH;
}
void SHA512_Final (unsigned char *md, SHA512_CTX *c)
{
unsigned char *p=(unsigned char *)c->u.p;
size_t n=c->num;
p[n]=0x80; /* There always is a room for one */
n++;
if (n > (SHA512_CBLOCK-16))
mem_fill (p+n,0,SHA512_CBLOCK-n), n=0,
SHA512_Transform (c,p);
mem_fill (p+n,0,SHA512_CBLOCK-16-n);
#ifdef ECP_CONFIG_BIG_ENDIAN
c->u.d[SHA_LBLOCK-2] = c->Nh;
c->u.d[SHA_LBLOCK-1] = c->Nl;
#else
p[SHA512_CBLOCK-1] = (unsigned char)(c->Nl);
p[SHA512_CBLOCK-2] = (unsigned char)(c->Nl>>8);
p[SHA512_CBLOCK-3] = (unsigned char)(c->Nl>>16);
p[SHA512_CBLOCK-4] = (unsigned char)(c->Nl>>24);
p[SHA512_CBLOCK-5] = (unsigned char)(c->Nl>>32);
p[SHA512_CBLOCK-6] = (unsigned char)(c->Nl>>40);
p[SHA512_CBLOCK-7] = (unsigned char)(c->Nl>>48);
p[SHA512_CBLOCK-8] = (unsigned char)(c->Nl>>56);
p[SHA512_CBLOCK-9] = (unsigned char)(c->Nh);
p[SHA512_CBLOCK-10] = (unsigned char)(c->Nh>>8);
p[SHA512_CBLOCK-11] = (unsigned char)(c->Nh>>16);
p[SHA512_CBLOCK-12] = (unsigned char)(c->Nh>>24);
p[SHA512_CBLOCK-13] = (unsigned char)(c->Nh>>32);
p[SHA512_CBLOCK-14] = (unsigned char)(c->Nh>>40);
p[SHA512_CBLOCK-15] = (unsigned char)(c->Nh>>48);
p[SHA512_CBLOCK-16] = (unsigned char)(c->Nh>>56);
#endif
SHA512_Transform (c,p);
if (md) for (n=0; n < SHA512_DIGEST_LENGTH/8; n++)
{
M64 m;
m.u64 = c->h[n];
*(md++) = m.u8.b7;
*(md++) = m.u8.b6;
*(md++) = m.u8.b5;
*(md++) = m.u8.b4;
*(md++) = m.u8.b3;
*(md++) = m.u8.b2;
*(md++) = m.u8.b1;
*(md++) = m.u8.b0;
}
}
void SHA512_Update (SHA512_CTX *c, const void *_data, size_t len)
{
SHA_LONG64 l;
unsigned char *p=c->u.p;
const unsigned char *data=(const unsigned char *)_data;
if (len==0) return;
l = (c->Nl+(((SHA_LONG64)len)<<3))&UINT64(0xffffffffffffffff);
if (l < c->Nl) c->Nh++;
if (sizeof(len)>=8) c->Nh+=(((SHA_LONG64)len)>>61);
c->Nl=l;
if (c->num != 0)
{
size_t n = SHA512_CBLOCK - c->num;
if (len < n)
{
memcpy (p+c->num,data,len), c->num += (unsigned int)len;
return;
}
else
{
memcpy (p+c->num,data,n), c->num = 0;
len-=n, data+=n;
SHA512_Transform (c,p);
}
}
while (len >= SHA512_CBLOCK)
{
SHA512_Transform (c,data);//,len/SHA512_CBLOCK),
data += SHA512_CBLOCK;
len -= SHA512_CBLOCK;
}
if (len != 0)
memcpy (p,data,len), c->num = (int)len;
}
static const SHA_LONG64 K512[80] =
{
UINT64(0x428a2f98d728ae22),UINT64(0x7137449123ef65cd),
UINT64(0xb5c0fbcfec4d3b2f),UINT64(0xe9b5dba58189dbbc),
UINT64(0x3956c25bf348b538),UINT64(0x59f111f1b605d019),
UINT64(0x923f82a4af194f9b),UINT64(0xab1c5ed5da6d8118),
UINT64(0xd807aa98a3030242),UINT64(0x12835b0145706fbe),
UINT64(0x243185be4ee4b28c),UINT64(0x550c7dc3d5ffb4e2),
UINT64(0x72be5d74f27b896f),UINT64(0x80deb1fe3b1696b1),
UINT64(0x9bdc06a725c71235),UINT64(0xc19bf174cf692694),
UINT64(0xe49b69c19ef14ad2),UINT64(0xefbe4786384f25e3),
UINT64(0x0fc19dc68b8cd5b5),UINT64(0x240ca1cc77ac9c65),
UINT64(0x2de92c6f592b0275),UINT64(0x4a7484aa6ea6e483),
UINT64(0x5cb0a9dcbd41fbd4),UINT64(0x76f988da831153b5),
UINT64(0x983e5152ee66dfab),UINT64(0xa831c66d2db43210),
UINT64(0xb00327c898fb213f),UINT64(0xbf597fc7beef0ee4),
UINT64(0xc6e00bf33da88fc2),UINT64(0xd5a79147930aa725),
UINT64(0x06ca6351e003826f),UINT64(0x142929670a0e6e70),
UINT64(0x27b70a8546d22ffc),UINT64(0x2e1b21385c26c926),
UINT64(0x4d2c6dfc5ac42aed),UINT64(0x53380d139d95b3df),
UINT64(0x650a73548baf63de),UINT64(0x766a0abb3c77b2a8),
UINT64(0x81c2c92e47edaee6),UINT64(0x92722c851482353b),
UINT64(0xa2bfe8a14cf10364),UINT64(0xa81a664bbc423001),
UINT64(0xc24b8b70d0f89791),UINT64(0xc76c51a30654be30),
UINT64(0xd192e819d6ef5218),UINT64(0xd69906245565a910),
UINT64(0xf40e35855771202a),UINT64(0x106aa07032bbd1b8),
UINT64(0x19a4c116b8d2d0c8),UINT64(0x1e376c085141ab53),
UINT64(0x2748774cdf8eeb99),UINT64(0x34b0bcb5e19b48a8),
UINT64(0x391c0cb3c5c95a63),UINT64(0x4ed8aa4ae3418acb),
UINT64(0x5b9cca4f7763e373),UINT64(0x682e6ff3d6b2b8a3),
UINT64(0x748f82ee5defb2fc),UINT64(0x78a5636f43172f60),
UINT64(0x84c87814a1f0ab72),UINT64(0x8cc702081a6439ec),
UINT64(0x90befffa23631e28),UINT64(0xa4506cebde82bde9),
UINT64(0xbef9a3f7b2c67915),UINT64(0xc67178f2e372532b),
UINT64(0xca273eceea26619c),UINT64(0xd186b8c721c0c207),
UINT64(0xeada7dd6cde0eb1e),UINT64(0xf57d4f7fee6ed178),
UINT64(0x06f067aa72176fba),UINT64(0x0a637dc5a2c898a6),
UINT64(0x113f9804bef90dae),UINT64(0x1b710b35131c471b),
UINT64(0x28db77f523047d84),UINT64(0x32caab7b40c72493),
UINT64(0x3c9ebe0a15c9bebc),UINT64(0x431d67c49c100d4c),
UINT64(0x4cc5d4becb3e42b6),UINT64(0x597f299cfc657e2a),
UINT64(0x5fcb6fab3ad6faec),UINT64(0x6c44198c4a475817)
};
#define B(x,j) (((SHA_LONG64)(*(((const unsigned char *)(&x))+j)))<<((7-j)*8))
#define PULL64(x) (B(x,0)|B(x,1)|B(x,2)|B(x,3)|B(x,4)|B(x,5)|B(x,6)|B(x,7))
#define ROTR(x,s) (((x)>>s) | (x)<<(64-s))
#define Sigma0(x) (ROTR((x),28) ^ ROTR((x),34) ^ ROTR((x),39))
#define Sigma1(x) (ROTR((x),14) ^ ROTR((x),18) ^ ROTR((x),41))
#define sigma0(x) (ROTR((x),1) ^ ROTR((x),8) ^ ((x)>>7))
#define sigma1(x) (ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6))
#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define ROUND_00_15(i,a,b,c,d,e,f,g,h) do { \
T1 += h + Sigma1(e) + Ch(e,f,g) + K512[i]; \
h = Sigma0(a) + Maj(a,b,c); \
d += T1; h += T1; } while (0)
#define ROUND_16_80(i,j,a,b,c,d,e,f,g,h,X) do { \
s0 = X[(j+1)&0x0f]; s0 = sigma0(s0); \
s1 = X[(j+14)&0x0f]; s1 = sigma1(s1); \
T1 = X[(j)&0x0f] += s0 + s1 + X[(j+9)&0x0f]; \
ROUND_00_15(i+j,a,b,c,d,e,f,g,h); } while (0)
void SHA512_Transform (SHA512_CTX *ctx, const void *in)
{
const SHA_LONG64 *W = (SHA_LONG64*)in;
SHA_LONG64 a,b,c,d,e,f,g,h,s0,s1,T1;
SHA_LONG64 X[16];
int i;
a = ctx->h[0]; b = ctx->h[1]; c = ctx->h[2]; d = ctx->h[3];
e = ctx->h[4]; f = ctx->h[5]; g = ctx->h[6]; h = ctx->h[7];
#ifdef ECP_CONFIG_BIG_ENDIAN
T1 = X[0] = W[0]; ROUND_00_15(0,a,b,c,d,e,f,g,h);
T1 = X[1] = W[1]; ROUND_00_15(1,h,a,b,c,d,e,f,g);
T1 = X[2] = W[2]; ROUND_00_15(2,g,h,a,b,c,d,e,f);
T1 = X[3] = W[3]; ROUND_00_15(3,f,g,h,a,b,c,d,e);
T1 = X[4] = W[4]; ROUND_00_15(4,e,f,g,h,a,b,c,d);
T1 = X[5] = W[5]; ROUND_00_15(5,d,e,f,g,h,a,b,c);
T1 = X[6] = W[6]; ROUND_00_15(6,c,d,e,f,g,h,a,b);
T1 = X[7] = W[7]; ROUND_00_15(7,b,c,d,e,f,g,h,a);
T1 = X[8] = W[8]; ROUND_00_15(8,a,b,c,d,e,f,g,h);
T1 = X[9] = W[9]; ROUND_00_15(9,h,a,b,c,d,e,f,g);
T1 = X[10] = W[10]; ROUND_00_15(10,g,h,a,b,c,d,e,f);
T1 = X[11] = W[11]; ROUND_00_15(11,f,g,h,a,b,c,d,e);
T1 = X[12] = W[12]; ROUND_00_15(12,e,f,g,h,a,b,c,d);
T1 = X[13] = W[13]; ROUND_00_15(13,d,e,f,g,h,a,b,c);
T1 = X[14] = W[14]; ROUND_00_15(14,c,d,e,f,g,h,a,b);
T1 = X[15] = W[15]; ROUND_00_15(15,b,c,d,e,f,g,h,a);
#else
T1 = X[0] = PULL64(W[0]); ROUND_00_15(0,a,b,c,d,e,f,g,h);
T1 = X[1] = PULL64(W[1]); ROUND_00_15(1,h,a,b,c,d,e,f,g);
T1 = X[2] = PULL64(W[2]); ROUND_00_15(2,g,h,a,b,c,d,e,f);
T1 = X[3] = PULL64(W[3]); ROUND_00_15(3,f,g,h,a,b,c,d,e);
T1 = X[4] = PULL64(W[4]); ROUND_00_15(4,e,f,g,h,a,b,c,d);
T1 = X[5] = PULL64(W[5]); ROUND_00_15(5,d,e,f,g,h,a,b,c);
T1 = X[6] = PULL64(W[6]); ROUND_00_15(6,c,d,e,f,g,h,a,b);
T1 = X[7] = PULL64(W[7]); ROUND_00_15(7,b,c,d,e,f,g,h,a);
T1 = X[8] = PULL64(W[8]); ROUND_00_15(8,a,b,c,d,e,f,g,h);
T1 = X[9] = PULL64(W[9]); ROUND_00_15(9,h,a,b,c,d,e,f,g);
T1 = X[10] = PULL64(W[10]); ROUND_00_15(10,g,h,a,b,c,d,e,f);
T1 = X[11] = PULL64(W[11]); ROUND_00_15(11,f,g,h,a,b,c,d,e);
T1 = X[12] = PULL64(W[12]); ROUND_00_15(12,e,f,g,h,a,b,c,d);
T1 = X[13] = PULL64(W[13]); ROUND_00_15(13,d,e,f,g,h,a,b,c);
T1 = X[14] = PULL64(W[14]); ROUND_00_15(14,c,d,e,f,g,h,a,b);
T1 = X[15] = PULL64(W[15]); ROUND_00_15(15,b,c,d,e,f,g,h,a);
#endif
for (i=16;i<80;i+=16)
{
ROUND_16_80(i, 0,a,b,c,d,e,f,g,h,X);
ROUND_16_80(i, 1,h,a,b,c,d,e,f,g,X);
ROUND_16_80(i, 2,g,h,a,b,c,d,e,f,X);
ROUND_16_80(i, 3,f,g,h,a,b,c,d,e,X);
ROUND_16_80(i, 4,e,f,g,h,a,b,c,d,X);
ROUND_16_80(i, 5,d,e,f,g,h,a,b,c,X);
ROUND_16_80(i, 6,c,d,e,f,g,h,a,b,X);
ROUND_16_80(i, 7,b,c,d,e,f,g,h,a,X);
ROUND_16_80(i, 8,a,b,c,d,e,f,g,h,X);
ROUND_16_80(i, 9,h,a,b,c,d,e,f,g,X);
ROUND_16_80(i,10,g,h,a,b,c,d,e,f,X);
ROUND_16_80(i,11,f,g,h,a,b,c,d,e,X);
ROUND_16_80(i,12,e,f,g,h,a,b,c,d,X);
ROUND_16_80(i,13,d,e,f,g,h,a,b,c,X);
ROUND_16_80(i,14,c,d,e,f,g,h,a,b,X);
ROUND_16_80(i,15,b,c,d,e,f,g,h,a,X);
}
ctx->h[0] += a; ctx->h[1] += b; ctx->h[2] += c; ctx->h[3] += d;
ctx->h[4] += e; ctx->h[5] += f; ctx->h[6] += g; ctx->h[7] += h;
}

View File

@ -0,0 +1,92 @@
/* crypto/sha/sha512.h */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/
#ifndef HEADER_SHA512_H
#define HEADER_SHA512_H
#include "BaseTypes.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SHA512_DIGEST_LENGTH 64
#define SHA512_CBLOCK 128 /* SHA-512 treats input data as a
* contiguous array of 64 bit
* wide big-endian values. */
#define SHA_LONG64 U64
typedef struct SHA512state_st
{
SHA_LONG64 h[8];
SHA_LONG64 Nl,Nh;
union {
SHA_LONG64 d[8];
unsigned char p[SHA512_CBLOCK];
} u;
unsigned int num, md_len;
} SHA512_CTX;
void SHA512_Init(SHA512_CTX *c);
void SHA512_Update(SHA512_CTX *c, const void *data, size_t len);
void SHA512_Final(unsigned char *md, SHA512_CTX *c);
#ifdef __cplusplus
}
#endif
#endif