#include "ckconfig.h"
#if CRYPTKIT_ECDSA_ENABLE
#include "feeTypes.h"
#include "feePublicKey.h"
#include "feePublicKeyPrivate.h"
#include "giantIntegers.h"
#include "elliptic.h"
#include "feeRandom.h"
#include "curveParams.h"
#include "falloc.h"
#include "ckutilities.h"
#include "feeDebug.h"
#include "platform.h"
#include "byteRep.h"
#include <stdlib.h>
#include "feeECDSA.h"
#include "byteRep.h"
#include "feeDigitalSignature.h"
#include "ECDSA_Profile.h"
#include "ellipticProj.h"
#if CRYPTKIT_DER_ENABLE
#include "CryptKitDER.h"
#endif
#ifndef ECDSA_VERIFY_ONLY
static void ECDSA_encode(giant c,
giant d,
unsigned char **sigData, unsigned *sigDataLen); #endif
static feeReturn ECDSA_decode(const unsigned char *sigData,
size_t sigDataLen,
giant *gs, giant *x0, unsigned *sigVersion);
#define ECDSA_DEBUG 0
#if ECDSA_DEBUG
int ecdsaDebug=1;
#define sigDbg(x) \
if(ecdsaDebug) { \
printf x; \
}
#define sigLogGiant(s, g) \
if(ecdsaDebug) { \
printf(s); \
printGiant(g) ; \
}
#else // ECDSA_DEBUG
#define sigDbg(x)
#define sigLogGiant(s, g)
#endif // ECDSA_DEBUG
#if ECDSA_PROFILE
unsigned signStep1;
unsigned signStep2;
unsigned signStep34;
unsigned signStep5;
unsigned signStep67;
unsigned signStep8;
unsigned vfyStep1;
unsigned vfyStep3;
unsigned vfyStep4;
unsigned vfyStep5;
unsigned vfyStep6;
unsigned vfyStep7;
unsigned vfyStep8;
#endif // ECDSA_PROFILE
#define FEE_ECDSA_VERSION 2
#define FEE_ECDSA_VERSION_MIN 2
#define ECDSA_SIGN_USE_PROJ 1
#ifndef ECDSA_VERIFY_ONLY
feeReturn feeECDSASign(feePubKey pubKey,
const unsigned char *data, unsigned dataLen, feeRandFcn randFcn, void *randRef, unsigned char **sigData, unsigned *sigDataLen) {
curveParams *cp;
giant c; giant d;
giant u; giant s; giant f;
feeReturn frtn = FR_Success;
feeRand frand;
unsigned char *randBytes;
unsigned randBytesLen;
giant privGiant;
#if ECDSA_SIGN_USE_PROJ
pointProjStruct pt; giant pty; giant ptz; #endif
if(pubKey == NULL) {
return FR_BadPubKey;
}
cp = feePubKeyCurveParams(pubKey);
if(cp == NULL) {
return FR_BadPubKey;
}
if(cp->curveType != FCT_Weierstrass) {
return FR_IllegalCurve;
}
CKASSERT(!isZero(cp->x1OrderPlus));
privGiant = feePubKeyPrivData(pubKey);
if(privGiant == NULL) {
dbgLog(("Attempt to Sign without private data\n"));
return FR_IllegalArg;
}
s = borrowGiant(cp->maxDigits);
gtog(privGiant, s);
if(dataLen > (cp->maxDigits * GIANT_BYTES_PER_DIGIT)) {
f = borrowGiant(BYTES_TO_GIANT_DIGITS(dataLen));
}
else {
f = borrowGiant(cp->maxDigits);
}
deserializeGiant(data, f, dataLen);
unsigned hashBits = dataLen * 8;
if(hashBits > cp->q) {
gshiftright(hashBits - cp->q, f);
}
sigDbg(("ECDSA sign:\n"));
sigLogGiant(" s : ", s);
sigLogGiant(" f : ", f);
c = borrowGiant(cp->maxDigits);
d = borrowGiant(cp->maxDigits);
u = borrowGiant(cp->maxDigits);
if(randFcn == NULL) {
frand = feeRandAlloc();
}
else {
frand = NULL;
}
randBytesLen = (feePubKeyBitsize(pubKey) / 8) + 1;
randBytes = (unsigned char*) fmalloc(randBytesLen);
#if ECDSA_SIGN_USE_PROJ
pty = borrowGiant(cp->maxDigits);
ptz = borrowGiant(cp->maxDigits);
pt.x = c;
pt.y = pty;
pt.z = ptz;
#endif
while(1) {
SIGPROF_START;
if(randFcn) {
randFcn(randRef, randBytes, randBytesLen);
}
else {
feeRandBytes(frand, randBytes, randBytesLen);
}
deserializeGiant(randBytes, u, randBytesLen);
x1OrderPlusJustify(u, cp);
SIGPROF_END(signStep1);
sigLogGiant(" u : ", u);
SIGPROF_START;
gtog(cp->x1Plus, c);
#if ECDSA_SIGN_USE_PROJ
gtog(cp->y1Plus, pty);
int_to_giant(1, ptz);
ellMulProjSimple(&pt, u, cp);
#else
elliptic_simple(c, u, cp);
#endif
SIGPROF_END(signStep2);
SIGPROF_START;
x1OrderPlusMod(c, cp);
SIGPROF_END(signStep34);
if(isZero(c)) {
dbgLog(("feeECDSASign: zero modulo (1)\n"));
continue;
}
SIGPROF_START;
gtog(u, d);
binvg_x1OrderPlus(cp, d);
SIGPROF_END(signStep5);
sigLogGiant(" u^(-1) : ", d);
SIGPROF_START;
mulg(c, s); x1OrderPlusMod(s, cp);
addg(f, s); x1OrderPlusMod(s, cp);
mulg(s, d); x1OrderPlusMod(d, cp);
SIGPROF_END(signStep67);
if(isZero(d)) {
dbgLog(("feeECDSASign: zero modulo (2)\n"));
continue;
}
sigLogGiant(" c : ", c);
sigLogGiant(" d : ", d);
break; }
SIGPROF_START;
ECDSA_encode(c, d, sigData, sigDataLen);
SIGPROF_END(signStep8);
if(frand != NULL) {
feeRandFree(frand);
}
ffree(randBytes);
returnGiant(u);
returnGiant(d);
returnGiant(c);
returnGiant(f);
returnGiant(s);
#if ECDSA_SIGN_USE_PROJ
returnGiant(pty);
returnGiant(ptz);
#endif
return frtn;
}
#endif
#define LOG_BAD_SIG 0
feeReturn feeECDSAVerify(const unsigned char *sigData,
size_t sigDataLen,
const unsigned char *data,
unsigned dataLen,
feePubKey pubKey)
{
giant h; giant h1; giant h2; giant littleC; giant littleD; giant c; giant d; giant cPrime = NULL; pointProj h1G = NULL; pointProj h2W = NULL; key W;
unsigned version;
feeReturn frtn;
curveParams *cp = feePubKeyCurveParams(pubKey);
int result;
if(cp == NULL) {
return FR_BadPubKey;
}
frtn = ECDSA_decode(sigData,
sigDataLen,
&littleC,
&littleD,
&version);
if(frtn) {
return frtn;
}
c = borrowGiant(cp->maxDigits);
d = borrowGiant(cp->maxDigits);
gtog(littleC, c);
gtog(littleD, d);
freeGiant(littleC);
freeGiant(littleD);
sigDbg(("ECDSA verify:\n"));
W = feePubKeyPlusCurve(pubKey);
SIGPROF_START;
h = borrowGiant(cp->maxDigits);
gtog(d, h);
binvg_x1OrderPlus(cp, h);
SIGPROF_END(vfyStep1);
if(dataLen > (cp->maxDigits * GIANT_BYTES_PER_DIGIT)) {
h1 = borrowGiant(BYTES_TO_GIANT_DIGITS(dataLen));
}
else {
h1 = borrowGiant(cp->maxDigits);
}
deserializeGiant(data, h1, dataLen);
unsigned hashBits = dataLen * 8;
if(hashBits > cp->q) {
gshiftright(hashBits - cp->q, h1);
}
sigLogGiant(" Wx : ", W->x);
sigLogGiant(" f : ", h1);
sigLogGiant(" c : ", c);
sigLogGiant(" d : ", d);
sigLogGiant(" s^(-1) : ", h);
SIGPROF_START;
mulg(h, h1); x1OrderPlusMod(h1, cp);
SIGPROF_END(vfyStep3);
SIGPROF_START;
h2 = borrowGiant(cp->maxDigits);
gtog(c, h2);
mulg(h, h2); x1OrderPlusMod(h2, cp);
SIGPROF_END(vfyStep4);
CKASSERT((W->y != NULL) && !isZero(W->y));
h2W = newPointProj(cp->maxDigits);
gtog(W->x, h2W->x);
gtog(W->y, h2W->y);
int_to_giant(1, h2W->z);
ellMulProjSimple(h2W, h2, cp);
CKASSERT((cp->y1Plus != NULL) && !isZero(cp->y1Plus));
h1G = newPointProj(cp->maxDigits);
gtog(cp->x1Plus, h1G->x);
gtog(cp->y1Plus, h1G->y);
int_to_giant(1, h1G->z);
ellMulProjSimple(h1G, h1, cp);
ellAddProj(h1G, h2W, cp);
if(isZero(h1G->z)) {
dbgLog(("feeECDSAVerify: h1 * G = point at infinity\n"));
result = 1;
goto vfyDone;
}
normalizeProj(h1G, cp);
cPrime = borrowGiant(cp->maxDigits);
gtog(h1G->x, cPrime);
x1OrderPlusMod(cPrime, cp);
result = gcompg(c, cPrime);
vfyDone:
if(result) {
frtn = FR_InvalidSignature;
#if LOG_BAD_SIG
printf("***yup, bad sig***\n");
#endif }
else {
frtn = FR_Success;
}
returnGiant(c);
returnGiant(d);
returnGiant(h);
returnGiant(h1);
returnGiant(h2);
if(h1G != NULL) {
freePointProj(h1G);
}
if(h2W != NULL) {
freePointProj(h2W);
}
if(cPrime != NULL) {
returnGiant(cPrime);
}
return frtn;
}
#ifndef ECDSA_VERIFY_ONLY
static void ECDSA_encode(giant c,
giant d,
unsigned char **sigData, unsigned *sigDataLen) {
#if CRYPTKIT_DER_ENABLE
feeDEREncodeECDSASignature(c, d, sigData, sigDataLen);
#else
*sigDataLen = lengthOfByteRepSig(c, d);
*sigData = (unsigned char*) fmalloc(*sigDataLen);
sigToByteRep(FEE_ECDSA_MAGIC,
FEE_ECDSA_VERSION,
FEE_ECDSA_VERSION_MIN,
c,
d,
*sigData);
#endif
}
#endif
static feeReturn ECDSA_decode(const unsigned char *sigData,
size_t sigDataLen,
giant *c, giant *d, unsigned *sigVersion) {
#if CRYPTKIT_DER_ENABLE
feeReturn frtn = feeDERDecodeECDSASignature(sigData, sigDataLen, c, d);
if(frtn == FR_Success) {
*sigVersion = FEE_ECDSA_VERSION;
}
return frtn;
#else
int magic;
int minVersion;
int rtn;
rtn = byteRepToSig(sigData,
sigDataLen,
FEE_ECDSA_VERSION,
&magic,
(int *)sigVersion,
&minVersion,
c,
d);
if(rtn == 0) {
return FR_BadSignatureFormat;
}
switch(magic) {
case FEE_ECDSA_MAGIC:
return FR_Success;
case FEE_SIG_MAGIC: return FR_WrongSignatureType;
default:
return FR_BadSignatureFormat;
}
#endif
}
feeReturn feeECDSASigSize(
feePubKey pubKey,
unsigned *maxSigLen)
{
curveParams *cp = feePubKeyCurveParams(pubKey);
if(cp == NULL) {
return FR_BadPubKey;
}
#if CRYPTKIT_DER_ENABLE
*maxSigLen = feeSizeOfDERSig(cp->basePrime, cp->basePrime);
#else
*maxSigLen = (unsigned)lengthOfByteRepSig(cp->basePrime, cp->basePrime);
#endif
return FR_Success;
}
#endif