420 lines
14 KiB
C
420 lines
14 KiB
C
|
/* 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);
|
||
|
}
|