void printCurveParams(const curveParams *p) { const char *pt; const char *ct; switch(p->primeType) { case FPT_Mersenne: pt = "FPT_Mersenne"; break; case FPT_FEE: pt = "FPT_FEE"; break; case FPT_General: pt = "FPT_General"; break; default: pt = "UNKNOWN!"; break; } switch(p->curveType) { case FCT_Montgomery: ct = "FCT_Montgomery"; break; case FCT_Weierstrass: ct = "FCT_Weierstrass"; break; case FCT_General: ct = "FCT_General"; break; default: ct = "UNKNOWN!"; break; } printf(" q %d k %d primeType %s curveType %s\n", p->q, p->k, pt, ct); printf(" minBytes %d maxDigits %d\n", p->minBytes, p->maxDigits); printf(" a : "); printGiant(p->a); printf(" b : "); printGiant(p->b); printf(" c : "); printGiant(p->c); printf(" basePrime : "); printGiant(p->basePrime); printf(" x1Plus : "); printGiant(p->x1Plus); printf(" x1Minus : "); printGiant(p->x1Minus); printf(" cOrderPlus : "); printGiant(p->cOrderPlus); printf(" cOrderMinus : "); printGiant(p->cOrderMinus); printf(" x1OrderPlus : "); printGiant(p->x1OrderPlus); printf(" x1OrderMinus: "); printGiant(p->x1OrderMinus); }
/* * Obtain Pm after feeSigNewWithKey() or feeSigParse() */ unsigned char *feeSigPm(feeSig sig, unsigned *PmLen) { sigInst *sinst = (sigInst*) sig; unsigned char *Pm; if(sinst->PmX == NULL) { dbgLog(("feeSigPm: no PmX!\n")); return NULL; } else { Pm = mem_from_giant(sinst->PmX, PmLen); #if SIG_DEBUG if(sigDebug) { int i; printf("Pm : "); printGiant(sinst->PmX); printf("PmData: "); for(i=0; i<*PmLen; i++) { printf("%x:", Pm[i]); } printf("\n"); } #endif // SIG_DEBUG } return Pm; }
void printPubKey(feePubKey pubKey) { pubKeyInst *pkinst = pubKey; printf("\ncurveParams:\n"); printCurveParams(pkinst->cp); printf("plus:\n"); printKey(pkinst->plus); printf("minus:\n"); printKey(pkinst->minus); if(pkinst->privGiant != NULL) { printf("privGiant : "); printGiant(pkinst->privGiant); } }
/* * FEE_SIG_USING_PROJ true : this is the "no Weierstrass" case * feeSigVerifyNoProj false : this is redefined to feeSigVerify */ feeReturn feeSigVerifyNoProj(feeSig sig, const unsigned char *data, unsigned dataLen, feePubKey pubKey) { giant Q = NULL; giant messageGiant = NULL; giant scratch = NULL; sigInst *sinst = (sigInst*) sig; feeReturn frtn; curveParams *cp; key origKey; // may be plus or minus key if(sinst->PmX == NULL) { dbgLog(("sigVerify without parse!\n")); frtn = FR_IllegalArg; goto out; } cp = feePubKeyCurveParams(pubKey); Q = newGiant(cp->maxDigits); /* * pick a key (+/-) * Q := P1 */ if(SIG_CURVE == CURVE_PLUS) { origKey = feePubKeyPlusCurve(pubKey); gtog(cp->x1Plus, Q); } else { origKey = feePubKeyMinusCurve(pubKey); gtog(cp->x1Minus, Q); } messageGiant = giant_with_data(data, dataLen); // M(ciphertext) /* Q := u 'o' P1 */ elliptic_simple(Q, sinst->u, cp); /* scratch := theirPub */ scratch = newGiant(cp->maxDigits); gtog(origKey->x, scratch); #if SIG_DEBUG if(sigDebug) { printf("verify origKey:\n"); printKey(origKey); printf("messageGiant: "); printGiant(messageGiant); printf("curveParams:\n"); printCurveParams(cp); } #endif // SIG_DEBUG /* scratch := M 'o' theirPub */ elliptic_simple(scratch, messageGiant, cp); #if SIG_DEBUG if(sigDebug) { printf("signature_compare, with\n"); printf("p0 = Q:\n"); printGiant(Q); printf("p1 = Pm:\n"); printGiant(sinst->PmX); printf("p2 = scratch = R:\n"); printGiant(scratch); } #endif // SIG_DEBUG if(signature_compare(Q, sinst->PmX, scratch, cp)) { frtn = FR_InvalidSignature; #if LOG_BAD_SIG printf("***yup, bad sig***\n"); #endif // LOG_BAD_SIG } else { frtn = FR_Success; } out: if(messageGiant != NULL) { freeGiant(messageGiant); } if(Q != NULL) { freeGiant(Q); } if(scratch != NULL) { freeGiant(scratch); } return frtn; }
feeReturn feeSigVerify(feeSig sig, const unsigned char *data, unsigned dataLen, feePubKey pubKey) { pointProjStruct Q; giant messageGiant = NULL; pointProjStruct scratch; sigInst *sinst = (sigInst*) sig; feeReturn frtn; curveParams *cp; key origKey; // may be plus or minus key if(sinst->PmX == NULL) { dbgLog(("sigVerify without parse!\n")); return FR_IllegalArg; } cp = feePubKeyCurveParams(pubKey); if(cp->curveType != FCT_Weierstrass) { return feeSigVerifyNoProj(sig, data, dataLen, pubKey); } borrowPointProj(&Q, cp->maxDigits); borrowPointProj(&scratch, cp->maxDigits); /* * Q := P1 */ gtog(cp->x1Plus, Q.x); gtog(cp->y1Plus, Q.y); int_to_giant(1, Q.z); messageGiant = giant_with_data(data, dataLen); // M(ciphertext) /* Q := u 'o' P1 */ ellMulProjSimple(&Q, sinst->u, cp); /* scratch := theirPub */ origKey = feePubKeyPlusCurve(pubKey); gtog(origKey->x, scratch.x); gtog(origKey->y, scratch.y); int_to_giant(1, scratch.z); #if SIG_DEBUG if(sigDebug) { printf("verify origKey:\n"); printKey(origKey); printf("messageGiant: "); printGiant(messageGiant); printf("curveParams:\n"); printCurveParams(cp); } #endif // SIG_DEBUG /* scratch := M 'o' theirPub */ ellMulProjSimple(&scratch, messageGiant, cp); #if SIG_DEBUG if(sigDebug) { printf("signature_compare, with\n"); printf("p0 = Q:\n"); printGiant(Q.x); printf("p1 = Pm:\n"); printGiant(sinst->PmX); printf("p2 = scratch = R:\n"); printGiant(scratch.x); } #endif // SIG_DEBUG if(signature_compare(Q.x, sinst->PmX, scratch.x, cp)) { frtn = FR_InvalidSignature; #if LOG_BAD_SIG printf("***yup, bad sig***\n"); #endif // LOG_BAD_SIG } else { frtn = FR_Success; } freeGiant(messageGiant); returnPointProj(&Q); returnPointProj(&scratch); return frtn; }
/* * Obtain a feeSig object by parsing an existing signature block. * Note that if Pm is used to salt a hash of the signed data, this must * function must be called prior to hashing. */ feeReturn feeSigParse(const unsigned char *sigData, size_t sigDataLen, feeSig *sig) // RETURNED { sigInst *sinst = NULL; feeReturn frtn; #if !CRYPTKIT_DER_ENABLE int version; int magic; int minVersion; int rtn; #endif sinst = sinstAlloc(); #if CRYPTKIT_DER_ENABLE frtn = feeDERDecodeElGamalSignature(sigData, sigDataLen, &sinst->u, &sinst->PmX); if(frtn) { goto abort; } #else rtn = byteRepToSig(sigData, sigDataLen, FEE_SIG_VERSION, &magic, &version, &minVersion, &sinst->u, &sinst->PmX); if(rtn == 0) { frtn = FR_BadSignatureFormat; goto abort; } switch(magic) { case FEE_ECDSA_MAGIC: frtn = FR_WrongSignatureType; // ECDSA! goto abort; case FEE_SIG_MAGIC: break; // proceed default: frtn = FR_BadSignatureFormat; goto abort; } #endif /* CRYPTKIT_DER_ENABLE */ #if SIG_DEBUG if(sigDebug) { printf("sigParse: \n"); printf("u: "); printGiant(sinst->u); } #endif // SIG_DEBUG *sig = sinst; return FR_Success; abort: if(sinst) { feeSigFree(sinst); } return frtn; }
/* * Sign specified block of data (most likely a hash result) using * specified feePubKey. */ feeReturn feeSigSign(feeSig sig, const unsigned char *data, // data to be signed unsigned dataLen, // in bytes feePubKey pubKey) { sigInst *sinst = (sigInst*) sig; giant messageGiant = NULL; unsigned maxlen; giant privGiant; unsigned privGiantBytes; feeReturn frtn = FR_Success; unsigned randBytesLen; unsigned uDigits; // alloc'd digits in sinst->u curveParams *cp; if(pubKey == NULL) { return FR_BadPubKey; } cp = feePubKeyCurveParams(pubKey); if(cp == NULL) { return FR_BadPubKey; } privGiant = feePubKeyPrivData(pubKey); if(privGiant == NULL) { dbgLog(("Attempt to Sign without private data\n")); frtn = FR_IllegalArg; goto abort; } privGiantBytes = abs(privGiant->sign) * GIANT_BYTES_PER_DIGIT; /* * Note PmX = m 'o' P1. * Get message/digest as giant. May be significantly different * in size from pubKey's basePrime. */ messageGiant = giant_with_data(data, dataLen); // M(text) randBytesLen = feePubKeyBitsize(pubKey) / 8; maxlen = max(randBytesLen, dataLen); /* leave plenty of room.... */ uDigits = (3 * (privGiantBytes + maxlen)) / GIANT_BYTES_PER_DIGIT; sinst->u = newGiant(uDigits); gtog(privGiant, sinst->u); // u := ourPri mulg(messageGiant, sinst->u); // u *= M(text) addg(sinst->randGiant, sinst->u); // u += m /* * Paranoia: we're using the curveParams from the caller's pubKey; * this cp will have a valid x1OrderPlusRecip if pubKey is the same * as the one passed to feeSigNewWithKey() (since feeSigNewWithKey * called x1OrderPlusJustify()). But the caller could conceivably be * using a different instance of their pubKey, in which case * the key's cp->x1OrderPlusRecip may not be valid. */ calcX1OrderPlusRecip(cp); /* u := u mod x1OrderPlus */ #if SIG_DEBUG if(sigDebug) { printf("sigSign:\n"); printf("u pre-modg : "); printGiant(sinst->u); } #endif modg_via_recip(cp->x1OrderPlus, cp->x1OrderPlusRecip, sinst->u); #if SIG_DEBUG if(sigDebug) { printf("privGiant : "); printGiant(privGiant); printf("u : "); printGiant(sinst->u); printf("messageGiant: "); printGiant(messageGiant); printf("curveParams :\n"); printCurveParams(cp); } #endif // SIG_DEBUG abort: if(messageGiant) { freeGiant(messageGiant); } return frtn; }
/* * Decrypt (exactly) a block of data. Caller malloc's plainText. Always * generates feeFEEDPlainBlockSize of plaintext, unless finalBlock is * non-zero (in which case feeFEEDPlainBlockSize or less bytes of plainText are * generated). */ feeReturn feeFEEDDecryptBlock(feeFEED feed, const unsigned char *cipherText, unsigned cipherTextLen, unsigned char *plainText, unsigned *plainTextLen, // RETURNED int finalBlock) { feedInst *finst = (feedInst *) feed; feeReturn frtn = FR_Success; unsigned char clueByte; giant thisClue; // not alloc'd giant thisS; // ditto int parity; if(finst->rsCtext == NULL) { /* * Init'd for encrypt? */ return FR_IllegalArg; } if(cipherTextLen != finst->cipherBlockSize) { dbgLog(("feeFEEDDecryptBlock: bad cipherTextLen\n")); return FR_IllegalArg; } if(finst->rsBlockCount < finst->rsSizeCipherBlocks) { /* * Processing initialRS, FEEDExp-encrypted */ unsigned char *rsPtr = finst->rsCtext + (finst->rsBlockCount * finst->cipherBlockSize); unsigned feedExpCipherSize; if(finalBlock) { dbgLog(("feeFEEDDecryptBlock: incomplete initialRS\n")); return FR_BadCipherText; } bcopy(cipherText, rsPtr, finst->cipherBlockSize); finst->rsBlockCount++; if(finst->rsBlockCount < finst->rsSizeCipherBlocks) { /* * Not done with this yet... */ bprintf(("=== FEED Decrypt: gobbled 0x%x bytes ctext, no ptext (1)\n", cipherTextLen)); *plainTextLen = 0; return FR_Success; } #if FEED_DEBUG if((finst->rsBlockCount * finst->cipherBlockSize) < finst->rsCtextSize) { dbgLog(("feeFEEDDecryptBlock: rsCtextSize underflow!\n")); return FR_Internal; } #endif // FEED_DEBUG /* * OK, we should have the FEEDExp ciphertext for initialRS * in rsCtext. Note the last few bytes are extra; we don't * pass them to FEEDExp. */ feedExpCipherSize = feeFEEDCipherBlockSize(finst->feedExp); frtn = feeFEEDExpDecrypt(finst->feedExp, finst->rsCtext, finst->rsCtextSize, &finst->initialRS, &finst->initialRSSize); if(frtn) { dbgLog(("feeFEEDDecryptBlock: error decrypting " "initialRS (%s)\n", feeReturnString(frtn))); return FR_BadCipherText; } /* * we already know how long this should be... */ if(finst->initialRSSize != finst->initialRSSize) { dbgLog(("feeFEEDDecryptBlock: initialRS sync error\n")); return FR_BadCipherText; } /* * Set up clues */ if(initFromRS(finst)) { dbgLog(("feeFEEDDecryptBlock: bad initialRS\n")); return FR_BadCipherText; } else { /* * Normal completion of last cipherblock containing * initialRS. */ bprintf(("=== FEED Decrypt: gobbled 0x%x bytes ctext, no ptext (2)\n", cipherTextLen)); *plainTextLen = 0; return FR_Success; } } /* * grab xm and clueByte from cipherText */ deserializeGiant(cipherText, finst->xm, finst->cp->minBytes); cipherText += finst->cp->minBytes; clueByte = *cipherText; if((clueByte & CLUE_BIT) == CLUE_PLUS) { thisClue = finst->cluePlus; thisS = finst->sPlus; } else { thisClue = finst->clueMinus; thisS = finst->sMinus; } if((clueByte & PARITY_BIT) == PARITY_PLUS) { parity = SIGN_PLUS; } else { parity = SIGN_MINUS; } /* * recover xp * xp = xm + clue(+/-) w/parity * adjust clue * clue[n+1] = r * clue[n] + (s * P1) */ elliptic_add(thisClue, finst->xm, finst->xp, finst->cp, parity); elliptic_simple(thisClue, finst->r, finst->cp); gtog(thisClue, finst->tmp1); elliptic_add(finst->tmp1, thisS, thisClue, finst->cp, SIGN_PLUS); /* * plaintext in xp */ #if FEED_DEBUG printf("decrypt clue %d\n", clueByte); printf(" xp : "); printGiant(finst->xp); printf(" xm : "); printGiant(finst->xm); printf(" cluePlus :"); printGiant(finst->cluePlus); printf(" clueMinus :"); printGiant(finst->clueMinus); #endif // FEED_DEBUG if(finalBlock) { /* * Snag data from xp in order to find out how much to move to * *plainText */ unsigned char *ptext = (unsigned char*) fmalloc(finst->plainBlockSize); serializeGiant(finst->xp, ptext, finst->plainBlockSize); *plainTextLen = ptext[finst->plainBlockSize - 1]; if(*plainTextLen == RESID_ZERO) { bprintf(("=== FEED Decrypt: RESID_ZERO\n")); *plainTextLen = 0; } else if(*plainTextLen > (finst->plainBlockSize - 1)) { dbgLog(("feeFEEDDecryptBlock: ptext overflow!\n")); bprintf(("feeFEEDDecryptBlock: ptext overflow!\n")); frtn = FR_BadCipherText; } else { bprintf(("=== FEED Decrypt: resid len 0x%x\n", *plainTextLen)); bcopy(ptext, plainText, *plainTextLen); } ffree(ptext); } else { *plainTextLen = finst->plainBlockSize; serializeGiant(finst->xp, plainText, *plainTextLen); } bprintf(("=== FEED decryptBlock ptextLen 0x%x ctextLen 0x%x\n", *plainTextLen, cipherTextLen)); return frtn; }
/* * Encrypt a block or less of data. Caller malloc's cipherText. * Generates up to feeFEEDCipherBufSize() bytes of ciphertext. */ feeReturn feeFEEDEncryptBlock(feeFEED feed, const unsigned char *plainText, unsigned plainTextLen, unsigned char *cipherText, unsigned *cipherTextLen, // RETURNED int finalBlock) { feedInst *finst = (feedInst *) feed; unsigned ctextLen = 0; feeReturn frtn = FR_Success; int whichCurve; giant thisClue; // not alloc'd or freed giant thisS; // ditto unsigned char clueByte; if(plainTextLen > finst->plainBlockSize) { return FR_IllegalArg; } if((plainTextLen < finst->plainBlockSize) && !finalBlock) { return FR_IllegalArg; } if(finst->initialRS == NULL) { /* * Init'd for decrypt? */ return FR_IllegalArg; } /* * First block - encrypt initialRS via FEEDExp */ if(finst->rsBlockCount == 0) { unsigned char *thisCtext; // malloc's by FEEDExp unsigned padLen; if(finst->initialRS == NULL) { /* * init'd for decrypt or reused */ dbgLog(("feeFEEDEncryptBlock: NULL initialRS!\n")); return FR_IllegalArg; } frtn = feeFEEDExpEncrypt(finst->feedExp, finst->initialRS, finst->initialRSSize, &thisCtext, &ctextLen); if(frtn) { /* * Should never happen... */ dbgLog(("feeFEEDEncryptBlock: error writing encrypted" " initialRS (%s)\n", feeReturnString(frtn))); return FR_Internal; } bcopy(thisCtext, cipherText, ctextLen); cipherText += ctextLen; ffree(thisCtext); finst->rsBlockCount = finst->rsSizeCipherBlocks; padLen = finst->cipherBlockSize - (ctextLen % finst->cipherBlockSize); // zeros to write #if 0 /* FEED_DEBUG */ /* * Hard-coded assumptions and tests about initRSSize... * Currently we assume that initRSSize % expBlockSize = 0 */ if((ctextLen / finst->cipherBlockSize) != 5) { dbgLog(("feeFEEDEncryptBlock: cipherblock size screwup (1)\n")); return FR_Internal; } if(padLen != 3) { dbgLog(("feeFEEDEncryptBlock: cipherblock size screwup (2)\n")); return FR_Internal; } #endif // FEED_DEBUG /* * pad to multiple of (our) cipherblock size. */ while(padLen) { *cipherText++ = 0; ctextLen++; padLen--; } } /* * plaintext to giant xp */ if(finalBlock) { unsigned char *ptext = (unsigned char*) fmalloc(finst->plainBlockSize); bzero(ptext, finst->plainBlockSize); if(plainTextLen) { /* * skip for empty block with resid length 0 */ bcopy(plainText, ptext, plainTextLen); } if(plainTextLen < finst->plainBlockSize) { if(plainTextLen == 0) { /* * Special case - resid block with no actual plaintext. * Can't actually write zero here; it screws up * deserializing the giant during decrypt */ ptext[finst->plainBlockSize - 1] = RESID_ZERO; bprintf(("=== FEED encrypt: RESID_ZERO\n")); } else { ptext[finst->plainBlockSize - 1] = plainTextLen; bprintf(("=== FEED encrypt: resid len 0x%x\n", plainTextLen)); } } /* * else handle evenly aligned case (i.e., finalBlock true * and (plainTextLen == plainBlockSize)) below... */ deserializeGiant(ptext, finst->xp, finst->plainBlockSize); ffree(ptext); } else { deserializeGiant(plainText, finst->xp, plainTextLen); } /* * encrypt xp * xm = xp + clue(+/-) * determine parity needed to restore xp * parity = ((xm + clue(+/-) == xp) ? 1 : -1 * and adjust clue * clue[n+1] = r * clue[n] + (s * P1) */ whichCurve = which_curve(finst->xp, finst->cp); if(whichCurve == CURVE_PLUS) { thisClue = finst->cluePlus; thisS = finst->sPlus; clueByte = CLUE_PLUS; } else { thisClue = finst->clueMinus; thisS = finst->sMinus; clueByte = CLUE_MINUS; } // calculate xm elliptic_add(thisClue, finst->xp, finst->xm, finst->cp, SIGN_PLUS); // save xm + clue in tmp1 elliptic_add(finst->xm, thisClue, finst->tmp1, finst->cp, SIGN_PLUS); // Adjust clue elliptic_simple(thisClue, finst->r, finst->cp); gtog(thisClue, finst->tmp2); elliptic_add(finst->tmp2, thisS, thisClue, finst->cp, SIGN_PLUS); /* * Calculate parity */ if(gcompg(finst->tmp1, finst->xp) == 0) { clueByte |= PARITY_PLUS; } /* * Ciphertext = (xm, clueByte) */ serializeGiant(finst->xm, cipherText, finst->cp->minBytes); cipherText += finst->cp->minBytes; ctextLen += finst->cp->minBytes; *cipherText++ = clueByte; ctextLen++; #if FEED_DEBUG printf("encrypt clue %d\n", clueByte); printf(" xp : "); printGiant(finst->xp); printf(" xm : "); printGiant(finst->xm); printf(" cluePlus :"); printGiant(finst->cluePlus); printf(" clueMinus :"); printGiant(finst->clueMinus); #endif // FEED_DEBUG if(finalBlock && (plainTextLen == finst->plainBlockSize)) { /* * Special case: finalBlock true, plainTextLen == blockSize. * In this case we generate one more block of ciphertext, * with a resid length of zero. */ unsigned moreCipher; // additional cipherLen frtn = feeFEEDEncryptBlock(feed, NULL, // plainText not used 0, // resid cipherText, // append... &moreCipher, 1); if(frtn == FR_Success) { ctextLen += moreCipher; } } bprintf(("=== FEED encryptBlock ptextLen 0x%x ctextLen 0x%x\n", plainTextLen, ctextLen)); *cipherTextLen = ctextLen; return frtn; }
/* * cons up: * cluePlus(0) * clueMinus(0) * sPlus * sMinus * r * Assumes: * cluePlus = clueMinus = ourPriv * theirPub * initialRS * initialRSSize * cp * * Called at feeFEEDNewWithPubKey while encrypting, or upon decrypting * first block of data. */ static feeReturn initFromRS(feedInst *finst) { giant s; unsigned rSize = finst->initialRSSize / 2; #if FEED_DEBUG if((finst->initialRS == NULL) || (finst->cp == NULL) || (finst->cluePlus == NULL) || (finst->clueMinus == NULL) || (finst->initialRSSize == 0)) { dbgLog(("initFromRS: resource shortage\n")); return FR_Internal; } #endif // FEED_DEBUG finst->r = giant_with_data(finst->initialRS, rSize); s = giant_with_data(finst->initialRS+rSize, rSize); #if FEED_DEBUG if(isZero(finst->r)) { printf("initFromRS: r = 0! initialRSSize = %d; encr = %s\n", finst->initialRSSize, (finst->rsCtext == NULL) ? "TRUE" : "FALSE"); } if(isZero(s)) { printf("initFromRS: s = 0! initialRSSize = %d; encr = %s\n", finst->initialRSSize, (finst->rsCtext == NULL) ? "TRUE" : "FALSE"); } #endif // FEE_DEBUG /* * Justify r and s to be in [2, minimumX1Order]. */ lesserX1OrderJustify(finst->r, finst->cp); lesserX1OrderJustify(s, finst->cp); /* * sPlus = s * x1Plus * sMinus = s * x1Minus */ finst->sPlus = newGiant(finst->cp->maxDigits); finst->sMinus = newGiant(finst->cp->maxDigits); gtog(finst->cp->x1Plus, finst->sPlus); elliptic_simple(finst->sPlus, s, finst->cp); gtog(finst->cp->x1Minus, finst->sMinus); elliptic_simple(finst->sMinus, s, finst->cp); /* * And finally, the initial clues. They are currently set to * ourPriv * theirPub. */ #if FEED_DEBUG printf("cluePlus : "); printGiant(finst->cluePlus); printf("clueMinus: "); printGiant(finst->clueMinus); #endif // FEED_EEBUG elliptic_simple(finst->cluePlus, finst->r, finst->cp); elliptic_simple(finst->clueMinus, finst->r, finst->cp); #if FEED_DEBUG printf("r : "); printGiant(finst->r); printf("s : "); printGiant(s); printf("sPlus : "); printGiant(finst->sPlus); printf("sMinus : "); printGiant(finst->sMinus); printf("cluePlus : "); printGiant(finst->cluePlus); printf("clueMinus: "); printGiant(finst->clueMinus); #endif // FEED_DEBUG freeGiant(s); return FR_Success; }
void printKey(const key k) { printf(" twist %d\n", k->twist); printf(" x: "); printGiant(k->x); }