Esempio n. 1
0
static int hashToEC(const uint8_t *p, uint32_t len, BIGNUM *bnTmp, EC_POINT *ptRet)
{
    // - bn(hash(data)) * (G + bn1)
    uint256 pkHash = Hash(p, p + len);

    if (!bnTmp || !BN_bin2bn(pkHash.begin(), EC_SECRET_SIZE, bnTmp))
        return errorN(1, "%s: BN_bin2bn failed.", __func__);

    if (Params().IsProtocolV3(pindexBest->nHeight))
    {
        if(!EC_POINT_mul(ecGrpKi, ptRet, bnTmp, NULL, NULL, bnCtx))
            return errorN(1, "%s: EC_POINT_mul failed.", __func__);
    } else
    if (!EC_POINT_mul(ecGrp, ptRet, bnTmp, NULL, NULL, bnCtx))
        return errorN(1, "%s: EC_POINT_mul failed.", __func__);

    return 0;
};
Esempio n. 2
0
ast::Node *parseFunction(TokenIt &it, const TokenIt &end, bool sub)
{
  Token *current = nextToken(it, end);
  EXPECT_TOKEN_N(current, Token::IDENTIFIER, "Expected function identifier");

  std::string name = current->value;
  
  current = nextToken(it, end);
  EXPECT_TOKEN_N(current, Token::LPAREN, "Expected '('");

  std::vector<std::string> args;
  while(1)
  {
    current = nextToken(it, end);
    if(current && current->type == Token::IDENTIFIER)
    {
      args.push_back(current->value);
      current = nextToken(it, end);
      if(current->type == Token::RPAREN)
        break;
      EXPECT_TOKEN_N(current, Token::COMMA, "Expected ',' in arg list");
    }
    else break;
  }

  EXPECT_TOKEN_N(current, Token::RPAREN, "Expected ')'");
  current = nextToken(it, end);
  std::vector<ast::Node *> body;
  while(1)
  {
    current = currentToken(it, end);
    EXPECT_ANY_TOKEN(current, errorN, "Statement or function end expected");

    if(current->type == Token::END)
      break;

    if(ast::Node *stmt = parseStatement(it, end))
      body.push_back(stmt);
    else return errorN("Statement or function end expected");
  }

  current = nextToken(it, end);
  EXPECT_TOKEN_N(current, (sub ? Token::SUB : Token::FUNCTION),
                 "Function end expected");

  nextToken(it, end);
  
  return new ast::Function(name, args, body, sub);
}
Esempio n. 3
0
int compile()
{
	int i;
	printf("start compilation\n");
	initSource();				/* getSourceの初期設定 */
	token = nextToken();			/* 最初のトークン */
	blockBegin(FIRSTADDR);		/* これ以後の宣言は新しいブロックのもの */
	block(0);					/* 0 はダミー(主ブロックの関数名はない) */
	finalSource();
	i = errorN();				/* エラーメッセージの個数 */
	if (i!=0)
		printf("%d errors\n", i);
/*	listCode();	*/			/* 目的コードのリスト(必要なら) */
	return i<MINERROR;		/* エラーメッセージの個数が少ないかどうかの判定 */
}
Esempio n. 4
0
int getOldKeyImage(CPubKey &publicKey, ec_point &keyImage)
{
    // - PublicKey * Hash(PublicKey)
    if (publicKey.size() != EC_COMPRESSED_SIZE)
        return errorN(1, "%s: Invalid publicKey.", __func__);

    int rv = 0;

    uint256 pkHash = publicKey.GetHash();

    BN_CTX_start(bnCtx);
    BIGNUM *bnTmp = BN_CTX_get(bnCtx);
    EC_POINT *ptPk = NULL;

    // Hash to BIGNUM
    if (!BN_bin2bn(pkHash.begin(), EC_SECRET_SIZE, bnTmp)
    && (rv = errorN(1, "%s: BN_bin2bn failed.", __func__)))
        goto End;

    // PublicKey point
    if (!(ptPk = EC_POINT_new(ecGrp))
    && (rv = errorN(1, "%s: EC_POINT_new failed.", __func__)))
        goto End;

    if(!EC_POINT_oct2point(ecGrp, ptPk, publicKey.begin(), EC_COMPRESSED_SIZE, bnCtx)
    && (rv = errorN(1, "%s: EC_POINT_oct2point failed.", __func__)))
        goto End;

    // PublicKey * Hash(PublicKey)
    if (!EC_POINT_mul(ecGrp, ptPk, NULL, ptPk, bnTmp, bnCtx)
    && (rv = errorN(1, "%s: EC_POINT_mul failed.", __func__)))
        goto End;

    try { keyImage.resize(EC_COMPRESSED_SIZE); } catch (std::exception& e)
    {
        LogPrintf("%s: keyImage.resize threw: %s.\n", __func__, e.what());
        rv = 1; goto End;
    }

    // Point to BIGNUM to bin
    if (!(EC_POINT_point2bn(ecGrp, ptPk, POINT_CONVERSION_COMPRESSED, bnTmp, bnCtx))
     ||BN_num_bytes(bnTmp) != (int) EC_COMPRESSED_SIZE
     ||BN_bn2bin(bnTmp, &keyImage[0]) != (int) EC_COMPRESSED_SIZE)
        rv = errorN(1, "%s: point -> keyImage failed.", __func__);

    End:
    EC_POINT_free(ptPk);
    BN_CTX_end(bnCtx);

    return 0;
}
Esempio n. 5
0
ast::Node *parseDim(TokenIt &it, const TokenIt &end)
{
  Token *current = nextToken(it, end);
  EXPECT_TOKEN_N(current, Token::IDENTIFIER, "Expected identifier");

  std::string name = current->value;

  current = nextToken(it, end);
  //FIXME: Dim foo 5
  if(!current || current->type != Token::EQUALS)
    return new ast::Dim(name, NULL);

  nextToken(it, end);
  ast::Expr *val = parseExpr(it, end);
  if(!val)
    return errorN("Expected expression");
  
  return new ast::Dim(name, val);
}
Esempio n. 6
0
int generateKeyImage(ec_point &publicKey, ec_secret secret, ec_point &keyImage)
{
    // - keyImage = secret * hash(publicKey) * G

    if (publicKey.size() != EC_COMPRESSED_SIZE)
        return errorN(1, "%s: Invalid publicKey.", __func__);

    BN_CTX_start(bnCtx);
    int rv = 0;
    BIGNUM *bnTmp = BN_CTX_get(bnCtx);
    BIGNUM *bnSec = BN_CTX_get(bnCtx);
    EC_POINT *hG    = NULL;

    if (!(hG = EC_POINT_new(ecGrp))
    && (rv = errorN(1, "%s: EC_POINT_new failed.", __func__)))
        goto End;

    if (hashToEC(&publicKey[0], publicKey.size(), bnTmp, hG)
    && (rv = errorN(1, "%s: hashToEC failed.", __func__)))
        goto End;

    if (!(BN_bin2bn(&secret.e[0], EC_SECRET_SIZE, bnSec))
    && (rv = errorN(1, "%s: BN_bin2bn failed.", __func__)))
        goto End;

    if (!EC_POINT_mul(ecGrp, hG, NULL, hG, bnSec, bnCtx)
    && (rv = errorN(1, "%s: kimg EC_POINT_mul failed.", __func__)))
        goto End;

    try { keyImage.resize(EC_COMPRESSED_SIZE); } catch (std::exception& e)
    {
        LogPrintf("%s: keyImage.resize threw: %s.\n", __func__, e.what());
        rv = 1; goto End;
    }

    if ((!(EC_POINT_point2bn(ecGrp, hG, POINT_CONVERSION_COMPRESSED, bnTmp, bnCtx))
        || BN_num_bytes(bnTmp) != (int) EC_COMPRESSED_SIZE
        || BN_bn2bin(bnTmp, &keyImage[0]) != (int) EC_COMPRESSED_SIZE)
    && (rv = errorN(1, "%s: point -> keyImage failed.", __func__)))
        goto End;

    if (fDebugRingSig)
        LogPrintf("keyImage %s\n", HexStr(keyImage).c_str());

    End:
    EC_POINT_free(hG);
    BN_CTX_end(bnCtx);

    return rv;
};
Esempio n. 7
0
ast::Expr *errorE(const char *str)
{
  errorN(str);
  return NULL;
}
Esempio n. 8
0
int generateRingSignatureAB(data_chunk &keyImage, uint256 &txnHash, int nRingSize, int nSecretOffset, ec_secret secret, const uint8_t *pPubkeys, data_chunk &sigC, uint8_t *pSigS)
{
    // https://bitcointalk.org/index.php?topic=972541.msg10619684

    if (fDebugRingSig)
        LogPrintf("%s: Ring size %d.\n", __func__, nRingSize);

    assert(nRingSize < 200);

    RandAddSeedPerfmon();

    memset(pSigS, 0, EC_SECRET_SIZE * nRingSize);

    int rv = 0;
    int nBytes;

    uint256 tmpPkHash;
    uint256 tmpHash;

    uint8_t tempData[66]; // hold raw point data to hash
    ec_secret sAlpha;

    if (0 != GenerateRandomSecret(sAlpha))
        return errorN(1, "%s: GenerateRandomSecret failed.", __func__);

    CHashWriter ssPkHash(SER_GETHASH, PROTOCOL_VERSION);
    CHashWriter ssCjHash(SER_GETHASH, PROTOCOL_VERSION);

    uint256 test;
    for (int i = 0; i < nRingSize; ++i)
    {
        ssPkHash.write((const char*)&pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE);

        if (i == nSecretOffset)
            continue;

        int k;
        // NOTE: necessary to clamp?
        for (k = 0; k < 32; ++k)
        {
            if (1 != RAND_bytes(&pSigS[i * EC_SECRET_SIZE], 32))
                return errorN(1, "%s: RAND_bytes ERR_get_error %u.", __func__, ERR_get_error());

            memcpy(test.begin(), &pSigS[i * EC_SECRET_SIZE], 32);
            if (test > MIN_SECRET && test < MAX_SECRET)
                break;
        };

        if (k > 31)
            return errorN(1, "%s: Failed to generate a valid key.", __func__);
    };

    tmpPkHash = ssPkHash.GetHash();

    BN_CTX_start(bnCtx);
    BIGNUM   *bnT  = BN_CTX_get(bnCtx);
    BIGNUM   *bnT2 = BN_CTX_get(bnCtx);
    BIGNUM   *bnS  = BN_CTX_get(bnCtx);
    BIGNUM   *bnC  = BN_CTX_get(bnCtx);
    BIGNUM   *bnCj = BN_CTX_get(bnCtx);
    BIGNUM   *bnA  = BN_CTX_get(bnCtx);
    EC_POINT *ptKi = NULL;
    EC_POINT *ptPk = NULL;
    EC_POINT *ptT1 = NULL;
    EC_POINT *ptT2 = NULL;
    EC_POINT *ptT3 = NULL;
    EC_POINT *ptT4 = NULL;

    if (   !(ptKi = EC_POINT_new(ecGrp))
        || !(ptPk = EC_POINT_new(ecGrp))
        || !(ptT1 = EC_POINT_new(ecGrp))
        || !(ptT2 = EC_POINT_new(ecGrp))
        || !(ptT3 = EC_POINT_new(ecGrp))
        || !(ptT4 = EC_POINT_new(ecGrp)))
    {
        LogPrintf("%s: EC_POINT_new failed.\n", __func__);
        rv = 1; goto End;
    };

    // get keyimage as point
    if (!EC_POINT_oct2point(ecGrp, ptKi, &keyImage[0], EC_COMPRESSED_SIZE, bnCtx))
    {
        LogPrintf("%s: extract ptKi failed.\n", __func__);
        rv = 1; goto End;
    };

    // c_{j+1} = h(P_1,...,P_n,alpha*G,alpha*H(P_j))
    if (!bnA || !(BN_bin2bn(&sAlpha.e[0], EC_SECRET_SIZE, bnA)))
    {
        LogPrintf("%s: BN_bin2bn failed.\n", __func__);
        rv = 1; goto End;
    };

    // ptT1 = alpha * G
    if (!EC_POINT_mul(ecGrp, ptT1, bnA, NULL, NULL, bnCtx))
    {
        LogPrintf("%s: EC_POINT_mul failed.\n", __func__);
        rv = 1; goto End;
    };

    // ptT3 = H(Pj)

    if (hashToEC(&pPubkeys[nSecretOffset * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnT2, ptT3) != 0)
    {
        LogPrintf("%s: hashToEC failed.\n", __func__);
        rv = 1; goto End;
    };

    ssCjHash.write((const char*)tmpPkHash.begin(), 32);

    // ptT2 = alpha * H(P_j)
    // ptT2 = alpha * ptT3
    if (!EC_POINT_mul(ecGrp, ptT2, NULL, ptT3, bnA, bnCtx))
    {
        LogPrintf("%s: EC_POINT_mul failed.\n", __func__);
        rv = 1; goto End;
    };

    if (   !(EC_POINT_point2oct(ecGrp, ptT1, POINT_CONVERSION_COMPRESSED, &tempData[0],  33, bnCtx) == (int) EC_COMPRESSED_SIZE)
        || !(EC_POINT_point2oct(ecGrp, ptT2, POINT_CONVERSION_COMPRESSED, &tempData[33], 33, bnCtx) == (int) EC_COMPRESSED_SIZE))
    {
        LogPrintf("%s: extract ptL and ptR failed.\n", __func__);
        rv = 1; goto End;
    };

    ssCjHash.write((const char*)&tempData[0], 66);
    tmpHash = ssCjHash.GetHash();

    if (!bnC || !(BN_bin2bn(tmpHash.begin(), EC_SECRET_SIZE, bnC)) // bnC lags i by 1
        || !BN_mod(bnC, bnC, bnOrder, bnCtx))
    {
        LogPrintf("%s: hash -> bnC failed.\n", __func__);
        rv = 1; goto End;
    };


    // c_{j+2} = h(P_1,...,P_n,s_{j+1}*G+c_{j+1}*P_{j+1},s_{j+1}*H(P_{j+1})+c_{j+1}*I_j)
    for (int k = 0, ib = (nSecretOffset + 1) % nRingSize, i = (nSecretOffset + 2) % nRingSize;
        k < nRingSize;
        ++k, ib=i, i=(i+1) % nRingSize)
    {
        if (k == nRingSize - 1)
        {
            // s_j = alpha - c_j*x_j mod n.
            if (!bnT || !BN_bin2bn(&secret.e[0], EC_SECRET_SIZE, bnT))
            {
                LogPrintf("%s: BN_bin2bn failed.\n", __func__);
                rv = 1; goto End;
            };

            if (!BN_mul(bnT2, bnCj, bnT, bnCtx))
            {
                LogPrintf("%s: BN_mul failed.\n", __func__);
                rv = 1; goto End;
            };

            if (!BN_mod_sub(bnS, bnA, bnT2, bnOrder, bnCtx))
            {
                LogPrintf("%s: BN_mod_sub failed.\n", __func__);
                rv = 1; goto End;
            };

            if (!bnS || (nBytes = BN_num_bytes(bnS)) > (int) EC_SECRET_SIZE
                || BN_bn2bin(bnS, &pSigS[nSecretOffset * EC_SECRET_SIZE + (EC_SECRET_SIZE-nBytes)]) != nBytes)
            {
                LogPrintf("%s: bnS -> pSigS failed.\n", __func__);
                rv = 1; goto End;
            };

            if (nSecretOffset != nRingSize - 1)
                break;
        };

        if (!bnS || !(BN_bin2bn(&pSigS[ib * EC_SECRET_SIZE], EC_SECRET_SIZE, bnS)))
        {
            LogPrintf("%s: BN_bin2bn failed.\n", __func__);
            rv = 1; goto End;
        };

        // bnC is from last round (ib)
        if (!EC_POINT_oct2point(ecGrp, ptPk, &pPubkeys[ib * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnCtx))
        {
            LogPrintf("%s: EC_POINT_oct2point failed.\n", __func__);
            rv = 1; goto End;
        };

        // ptT1 = s_{j+1}*G+c_{j+1}*P_{j+1}
        if (!EC_POINT_mul(ecGrp, ptT1, bnS, ptPk, bnC, bnCtx))
        {
            LogPrintf("%s: EC_POINT_mul failed.\n", __func__);
            rv = 1; goto End;
        };

        //s_{j+1}*H(P_{j+1})+c_{j+1}*I_j

        if (hashToEC(&pPubkeys[ib * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnT2, ptT2) != 0)
        {
            LogPrintf("%s: hashToEC failed.\n", __func__);
            rv = 1; goto End;
        };

        // ptT3 = s_{j+1}*H(P_{j+1})
        if (!EC_POINT_mul(ecGrp, ptT3, NULL, ptT2, bnS, bnCtx))
        {
            LogPrintf("%s: EC_POINT_mul failed.\n", __func__);
            rv = 1; goto End;
        };

        // ptT4 = c_{j+1}*I_j
        if (!EC_POINT_mul(ecGrp, ptT4, NULL, ptKi, bnC, bnCtx))
        {
            LogPrintf("%s: EC_POINT_mul failed.\n", __func__);
            rv = 1; goto End;
        };

        // ptT2 = ptT3 + ptT4
        if (!EC_POINT_add(ecGrp, ptT2, ptT3, ptT4, bnCtx))
        {
            LogPrintf("%s: EC_POINT_add failed.\n", __func__);
            rv = 1; goto End;
        };

        if (   !(EC_POINT_point2oct(ecGrp, ptT1, POINT_CONVERSION_COMPRESSED, &tempData[0],  33, bnCtx) == (int) EC_COMPRESSED_SIZE)
            || !(EC_POINT_point2oct(ecGrp, ptT2, POINT_CONVERSION_COMPRESSED, &tempData[33], 33, bnCtx) == (int) EC_COMPRESSED_SIZE))
        {
            LogPrintf("%s: extract ptL and ptR failed.\n", __func__);
            rv = 1; goto End;
        };

        CHashWriter ssCHash(SER_GETHASH, PROTOCOL_VERSION);
        ssCHash.write((const char*)tmpPkHash.begin(), 32);
        ssCHash.write((const char*)&tempData[0], 66);
        tmpHash = ssCHash.GetHash();

        if (!bnC || !(BN_bin2bn(tmpHash.begin(), EC_SECRET_SIZE, bnC)) // bnC lags i by 1
            || !BN_mod(bnC, bnC, bnOrder, bnCtx))
        {
            LogPrintf("%s: hash -> bnC failed.\n", __func__);
            rv = 1; goto End;
        };

        if (i == nSecretOffset
            && !BN_copy(bnCj, bnC))
        {
            LogPrintf("%s: BN_copy failed.\n", __func__);
            rv = 1; goto End;
        };

        if (i == 0)
        {
            memset(tempData, 0, EC_SECRET_SIZE);
            if ((nBytes = BN_num_bytes(bnC)) > (int) EC_SECRET_SIZE
                || BN_bn2bin(bnC, &tempData[0 + (EC_SECRET_SIZE-nBytes)]) != nBytes)
            {
                LogPrintf("%s: bnC -> sigC failed.\n", __func__);
                rv = 1; goto End;
            };
            try { sigC.resize(32); } catch (std::exception& e)
            {
                LogPrintf("%s: sigC.resize failed.\n", __func__);
                rv = 1; goto End;
            };
            memcpy(&sigC[0], tempData, EC_SECRET_SIZE);
        };
    };

    End:
    EC_POINT_free(ptKi);
    EC_POINT_free(ptPk);
    EC_POINT_free(ptT1);
    EC_POINT_free(ptT2);
    EC_POINT_free(ptT3);
    EC_POINT_free(ptT4);

    BN_CTX_end(bnCtx);

    return rv;
};
Esempio n. 9
0
int verifyRingSignature(data_chunk &keyImage, uint256 &txnHash, int nRingSize, const uint8_t *pPubkeys, const uint8_t *pSigc, const uint8_t *pSigr)
{
    if (fDebugRingSig)
    {
        // LogPrintf("%s size %d\n", __func__, nRingSize); // happens often
    };

    int rv = 0;

    BN_CTX_start(bnCtx);

    BIGNUM   *bnT   = BN_CTX_get(bnCtx);
    BIGNUM   *bnH   = BN_CTX_get(bnCtx);
    BIGNUM   *bnC   = BN_CTX_get(bnCtx);
    BIGNUM   *bnR   = BN_CTX_get(bnCtx);
    BIGNUM   *bnSum = BN_CTX_get(bnCtx);
    EC_POINT *ptT1  = NULL;
    EC_POINT *ptT2  = NULL;
    EC_POINT *ptT3  = NULL;
    EC_POINT *ptPk  = NULL;
    EC_POINT *ptKi  = NULL;
    EC_POINT *ptL   = NULL;
    EC_POINT *ptR   = NULL;
    EC_POINT *ptSi  = NULL;

    uint8_t tempData[66]; // hold raw point data to hash
    uint256 commitHash;
    CHashWriter ssCommitHash(SER_GETHASH, PROTOCOL_VERSION);

    ssCommitHash << txnHash;

    // zero sum
    if (!bnSum || !(BN_zero(bnSum)))
    {
        LogPrintf("%s: BN_zero failed.\n", __func__);
        rv = 1; goto End;
    };

    if (   !(ptT1 = EC_POINT_new(ecGrp))
        || !(ptT2 = EC_POINT_new(ecGrp))
        || !(ptT3 = EC_POINT_new(ecGrp))
        || !(ptPk = EC_POINT_new(ecGrp))
        || !(ptKi = EC_POINT_new(ecGrp))
        || !(ptL  = EC_POINT_new(ecGrp))
        || !(ptSi = EC_POINT_new(ecGrp))
        || !(ptR  = EC_POINT_new(ecGrp)))
    {
        LogPrintf("%s: EC_POINT_new failed.\n", __func__);
        rv = 1; goto End;
    };

    // get keyimage as point
    if (!(bnT = BN_bin2bn(&keyImage[0], EC_COMPRESSED_SIZE, bnT))
        || !(ptKi) || !(ptKi = EC_POINT_bn2point(ecGrp, bnT, ptKi, bnCtx)))
    {
        LogPrintf("%s: extract ptKi failed.\n", __func__);
        rv = 1; goto End;
    };

    for (int i = 0; i < nRingSize; ++i)
    {
        // Li = ci * Pi + ri * G
        // Ri = ci * I + ri * Hp(Pi)

        if (   !bnC || !(bnC = BN_bin2bn(&pSigc[i * EC_SECRET_SIZE], EC_SECRET_SIZE, bnC))
            || !bnR || !(bnR = BN_bin2bn(&pSigr[i * EC_SECRET_SIZE], EC_SECRET_SIZE, bnR)))
        {
            LogPrintf("%s: extract bnC and bnR failed.\n", __func__);
            rv = 1; goto End;
        };

        // get Pk i as point
        if (!(bnT = BN_bin2bn(&pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnT))
            || !(ptPk) || !(ptPk = EC_POINT_bn2point(ecGrp, bnT, ptPk, bnCtx)))
        {
            LogPrintf("%s: extract ptPk failed.\n", __func__);
            rv = 1; goto End;
        };

        // ptT1 = ci * Pi
        if (!EC_POINT_mul(ecGrp, ptT1, NULL, ptPk, bnC, bnCtx))
        {
            LogPrintf("%s: EC_POINT_mul failed.\n", __func__);
            rv = 1; goto End;
        };

        // ptT2 = ri * G
        if (!EC_POINT_mul(ecGrp, ptT2, bnR, NULL, NULL, bnCtx))
        {
            LogPrintf("%s: EC_POINT_mul failed.\n", __func__);
            rv = 1; goto End;
        };

        // ptL = ptT1 + ptT2
        if (!EC_POINT_add(ecGrp, ptL, ptT1, ptT2, bnCtx))
        {
            LogPrintf("%s: EC_POINT_add failed.\n", __func__);
            rv = 1; goto End;
        };

        // ptT3 = Hp(Pi)
        if (hashToEC(&pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnT, ptT3) != 0)
        {
            LogPrintf("%s: hashToEC failed.\n", __func__);
            rv = 1; goto End;
        };

        // DEBUGGING: ------- check if we can find the signer...
        // ptSi = Pi * bnT
        if ((!EC_POINT_mul(ecGrp, ptSi, NULL, ptPk, bnT, bnCtx)
           || false)
        && (rv = errorN(1, "%s: EC_POINT_mul failed.1", __func__)))
            goto End;

        if (0 == EC_POINT_cmp(ecGrp, ptSi, ptKi, bnCtx) )
            LogPrintf("signer is index %d\n", i);
        // DEBUGGING: - End - check if we can find the signer...

        // ptT1 = k1 * I
        if (!EC_POINT_mul(ecGrp, ptT1, NULL, ptKi, bnC, bnCtx))
        {
            LogPrintf("%s: EC_POINT_mul failed.\n", __func__);
            rv = 1; goto End;
        };

        // ptT2 = k2 * ptT3
        if (!EC_POINT_mul(ecGrp, ptT2, NULL, ptT3, bnR, bnCtx))
        {
            LogPrintf("%s: EC_POINT_mul failed.\n", __func__);
            rv = 1; goto End;
        };

        // ptR = ptT1 + ptT2
        if (!EC_POINT_add(ecGrp, ptR, ptT1, ptT2, bnCtx))
        {
            LogPrintf("%s: EC_POINT_add failed.\n", __func__);
            rv = 1; goto End;
        };

        // sum = (sum + ci) % N
        if (!BN_mod_add(bnSum, bnSum, bnC, bnOrder, bnCtx))
        {
            LogPrintf("%s: BN_mod_add failed.\n", __func__);
            rv = 1; goto End;
        };

        // -- add ptL and ptR to hash
        if (   !(EC_POINT_point2oct(ecGrp, ptL, POINT_CONVERSION_COMPRESSED, &tempData[0],  33, bnCtx) == (int) EC_COMPRESSED_SIZE)
            || !(EC_POINT_point2oct(ecGrp, ptR, POINT_CONVERSION_COMPRESSED, &tempData[33], 33, bnCtx) == (int) EC_COMPRESSED_SIZE))
        {
            LogPrintf("%s: extract ptL and ptR failed.\n", __func__);
            rv = 1; goto End;
        };

        ssCommitHash.write((const char*)&tempData[0], 66);
    };

    commitHash = ssCommitHash.GetHash();

    if (!(bnH) || !(bnH = BN_bin2bn(commitHash.begin(), EC_SECRET_SIZE, bnH)))
    {
        LogPrintf("%s: commitHash -> bnH failed.\n", __func__);
        rv = 1; goto End;
    };

    if (!BN_mod(bnH, bnH, bnOrder, bnCtx))
    {
        LogPrintf("%s: BN_mod failed.\n", __func__);
        rv = 1; goto End;
    };

    // bnT = (bnH - bnSum) % N
    if (!BN_mod_sub(bnT, bnH, bnSum, bnOrder, bnCtx))
    {
        LogPrintf("%s: BN_mod_sub failed.\n", __func__);
        rv = 1; goto End;
    };

    // test bnT == 0  (bnSum == bnH)
    if (!BN_is_zero(bnT))
    {
        LogPrintf("%s: signature does not verify.\n", __func__);
        rv = 2;
    };

    End:

    EC_POINT_free(ptT1);
    EC_POINT_free(ptT2);
    EC_POINT_free(ptT3);
    EC_POINT_free(ptPk);
    EC_POINT_free(ptKi);
    EC_POINT_free(ptL);
    EC_POINT_free(ptR);
    EC_POINT_free(ptSi);

    BN_CTX_end(bnCtx);

    return rv;
};
Esempio n. 10
0
int generateRingSignature(data_chunk &keyImage, uint256 &txnHash, int nRingSize, int nSecretOffset, ec_secret secret, const uint8_t *pPubkeys, uint8_t *pSigc, uint8_t *pSigr)
{
    if (fDebugRingSig)
        LogPrintf("%s: Ring size %d.\n", __func__, nRingSize);

    int rv = 0;
    int nBytes;

    BN_CTX_start(bnCtx);

    BIGNUM   *bnKS  = BN_CTX_get(bnCtx);
    BIGNUM   *bnK1  = BN_CTX_get(bnCtx);
    BIGNUM   *bnK2  = BN_CTX_get(bnCtx);
    BIGNUM   *bnT   = BN_CTX_get(bnCtx);
    BIGNUM   *bnH   = BN_CTX_get(bnCtx);
    BIGNUM   *bnSum = BN_CTX_get(bnCtx);
    EC_POINT *ptT1  = NULL;
    EC_POINT *ptT2  = NULL;
    EC_POINT *ptT3  = NULL;
    EC_POINT *ptPk  = NULL;
    EC_POINT *ptKi  = NULL;
    EC_POINT *ptL   = NULL;
    EC_POINT *ptR   = NULL;

    uint8_t tempData[66]; // hold raw point data to hash
    uint256 commitHash;
    ec_secret scData1, scData2;

    CHashWriter ssCommitHash(SER_GETHASH, PROTOCOL_VERSION);

    ssCommitHash << txnHash;

    // zero signature
    memset(pSigc, 0, EC_SECRET_SIZE * nRingSize);
    memset(pSigr, 0, EC_SECRET_SIZE * nRingSize);


    // ks = random 256 bit int mod P
    if (GenerateRandomSecret(scData1)
    && (rv = errorN(1, "%s: GenerateRandomSecret failed.", __func__)))
        goto End;

    if (!bnKS || !(BN_bin2bn(&scData1.e[0], EC_SECRET_SIZE, bnKS)))
    {
        LogPrintf("%s: BN_bin2bn failed.\n", __func__);
        rv = 1; goto End;
    };

    // zero sum
    if (!bnSum || !(BN_zero(bnSum)))
    {
        LogPrintf("%s: BN_zero failed.\n", __func__);
        rv = 1; goto End;
    };

    if (   !(ptT1 = EC_POINT_new(ecGrp))
        || !(ptT2 = EC_POINT_new(ecGrp))
        || !(ptT3 = EC_POINT_new(ecGrp))
        || !(ptPk = EC_POINT_new(ecGrp))
        || !(ptKi = EC_POINT_new(ecGrp))
        || !(ptL  = EC_POINT_new(ecGrp))
        || !(ptR  = EC_POINT_new(ecGrp)))
    {
        LogPrintf("%s: EC_POINT_new failed.\n", __func__);
        rv = 1; goto End;
    };

    // get keyimage as point
    if (!(bnT = BN_bin2bn(&keyImage[0], EC_COMPRESSED_SIZE, bnT))
        || !(ptKi) || !(ptKi = EC_POINT_bn2point(ecGrp, bnT, ptKi, bnCtx)))
    {
        LogPrintf("%s: extract ptKi failed.\n", __func__);
        rv = 1; goto End;
    };

    for (int i = 0; i < nRingSize; ++i)
    {
        if (i == nSecretOffset)
        {
            // k = random 256 bit int mod P
            // L = k * G
            // R = k * HashToEC(PKi)

            if (!EC_POINT_mul(ecGrp, ptL, bnKS, NULL, NULL, bnCtx))
            {
                LogPrintf("%s: EC_POINT_mul failed.\n", __func__);
                rv = 1; goto End;
            };

            if (hashToEC(&pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnT, ptT1) != 0)
            {
                LogPrintf("%s: hashToEC failed.\n", __func__);
                rv = 1; goto End;
            };

            if (!EC_POINT_mul(ecGrp, ptR, NULL, ptT1, bnKS, bnCtx))
            {
                LogPrintf("%s: EC_POINT_mul failed.\n", __func__);
                rv = 1; goto End;
            };

        } else
        {
            // k1 = random 256 bit int mod P
            // k2 = random 256 bit int mod P
            // Li = k1 * Pi + k2 * G
            // Ri = k1 * I + k2 * Hp(Pi)
            // ci = k1
            // ri = k2

            if (GenerateRandomSecret(scData1) != 0
                || !bnK1 || !(BN_bin2bn(&scData1.e[0], EC_SECRET_SIZE, bnK1))
                || GenerateRandomSecret(scData2) != 0
                || !bnK2 || !(BN_bin2bn(&scData2.e[0], EC_SECRET_SIZE, bnK2)))
            {
                LogPrintf("%s: k1 and k2 failed.\n", __func__);
                rv = 1; goto End;
            };

            // get Pk i as point
            if (!(bnT = BN_bin2bn(&pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnT))
                || !(ptPk) || !(ptPk = EC_POINT_bn2point(ecGrp, bnT, ptPk, bnCtx)))
            {
                LogPrintf("%s: extract ptPk failed.\n", __func__);
                rv = 1; goto End;
            };

            // ptT1 = k1 * Pi
            if (!EC_POINT_mul(ecGrp, ptT1, NULL, ptPk, bnK1, bnCtx))
            {
                LogPrintf("%s: EC_POINT_mul failed.\n", __func__);
                rv = 1; goto End;
            };

            // ptT2 = k2 * G
            if (!EC_POINT_mul(ecGrp, ptT2, bnK2, NULL, NULL, bnCtx))
            {
                LogPrintf("%s: EC_POINT_mul failed.\n", __func__);
                rv = 1; goto End;
            };

            // ptL = ptT1 + ptT2
            if (!EC_POINT_add(ecGrp, ptL, ptT1, ptT2, bnCtx))
            {
                LogPrintf("%s: EC_POINT_add failed.\n", __func__);
                rv = 1; goto End;
            };

            // ptT3 = Hp(Pi)
            if (hashToEC(&pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnT, ptT3) != 0)
            {
                LogPrintf("%s: hashToEC failed.\n", __func__);
                rv = 1; goto End;
            };

            // ptT1 = k1 * I
            if (!EC_POINT_mul(ecGrp, ptT1, NULL, ptKi, bnK1, bnCtx))
            {
                LogPrintf("%s: EC_POINT_mul failed.\n", __func__);
                rv = 1; goto End;
            };

            // ptT2 = k2 * ptT3
            if (!EC_POINT_mul(ecGrp, ptT2, NULL, ptT3, bnK2, bnCtx))
            {
                LogPrintf("%s: EC_POINT_mul failed.\n", __func__);
                rv = 1; goto End;
            };

            // ptR = ptT1 + ptT2
            if (!EC_POINT_add(ecGrp, ptR, ptT1, ptT2, bnCtx))
            {
                LogPrintf("%s: EC_POINT_add failed.\n", __func__);
                rv = 1; goto End;
            };

            memcpy(&pSigc[i * EC_SECRET_SIZE], &scData1.e[0], EC_SECRET_SIZE);
            memcpy(&pSigr[i * EC_SECRET_SIZE], &scData2.e[0], EC_SECRET_SIZE);

            // sum = (sum + sigc) % N , sigc == bnK1
            if (!BN_mod_add(bnSum, bnSum, bnK1, bnOrder, bnCtx))
            {
                LogPrintf("%s: BN_mod_add failed.\n", __func__);
                rv = 1; goto End;
            };
        };

        // -- add ptL and ptR to hash
        if (   !(EC_POINT_point2oct(ecGrp, ptL, POINT_CONVERSION_COMPRESSED, &tempData[0],  33, bnCtx) == (int) EC_COMPRESSED_SIZE)
            || !(EC_POINT_point2oct(ecGrp, ptR, POINT_CONVERSION_COMPRESSED, &tempData[33], 33, bnCtx) == (int) EC_COMPRESSED_SIZE))
        {
            LogPrintf("%s: extract ptL and ptR failed.\n", __func__);
            rv = 1; goto End;
        };

        ssCommitHash.write((const char*)&tempData[0], 66);
    };

    commitHash = ssCommitHash.GetHash();

    if (!(bnH) || !(bnH = BN_bin2bn(commitHash.begin(), EC_SECRET_SIZE, bnH)))
    {
        LogPrintf("%s: commitHash -> bnH failed.\n", __func__);
        rv = 1; goto End;
    };


    if (!BN_mod(bnH, bnH, bnOrder, bnCtx)) // this is necessary
    {
        LogPrintf("%s: BN_mod failed.\n", __func__);
        rv = 1; goto End;
    };

    // sigc[nSecretOffset] = (bnH - bnSum) % N
    if (!BN_mod_sub(bnT, bnH, bnSum, bnOrder, bnCtx))
    {
        LogPrintf("%s: BN_mod_sub failed.\n", __func__);
        rv = 1; goto End;
    };

    if ((nBytes = BN_num_bytes(bnT)) > (int)EC_SECRET_SIZE
        || BN_bn2bin(bnT, &pSigc[nSecretOffset * EC_SECRET_SIZE + (EC_SECRET_SIZE-nBytes)]) != nBytes)
    {
        LogPrintf("%s: bnT -> pSigc failed.\n", __func__);
        rv = 1; goto End;
    };

    // sigr[nSecretOffset] = (bnKS - sigc[nSecretOffset] * bnSecret) % N
    // reuse bnH for bnSecret
    if (!bnH || !(BN_bin2bn(&secret.e[0], EC_SECRET_SIZE, bnH)))
    {
        LogPrintf("%s: BN_bin2bn failed.\n", __func__);
        rv = 1; goto End;
    };

    // bnT = sigc[nSecretOffset] * bnSecret , TODO: mod N ?
    if (!BN_mul(bnT, bnT, bnH, bnCtx))
    {
        LogPrintf("%s: BN_mul failed.\n", __func__);
        rv = 1; goto End;
    };

    if (!BN_mod_sub(bnT, bnKS, bnT, bnOrder, bnCtx))
    {
        LogPrintf("%s: BN_mod_sub failed.\n", __func__);
        rv = 1; goto End;
    };

    if ((nBytes = BN_num_bytes(bnT)) > (int) EC_SECRET_SIZE
        || BN_bn2bin(bnT, &pSigr[nSecretOffset * EC_SECRET_SIZE + (EC_SECRET_SIZE-nBytes)]) != nBytes)
    {
        LogPrintf("%s: bnT -> pSigr failed.\n", __func__);
        rv = 1; goto End;
    };

    End:
    EC_POINT_free(ptT1);
    EC_POINT_free(ptT2);
    EC_POINT_free(ptT3);
    EC_POINT_free(ptPk);
    EC_POINT_free(ptKi);
    EC_POINT_free(ptL);
    EC_POINT_free(ptR);

    BN_CTX_end(bnCtx);

    return rv;
};
Esempio n. 11
0
int initialiseRingSigs()
{
    if (fDebugRingSig)
        LogPrintf("initialiseRingSigs()\n");

    if (!(ecGrp = EC_GROUP_new_by_curve_name(NID_secp256k1)))
        return errorN(1, "initialiseRingSigs(): EC_GROUP_new_by_curve_name failed.");

    if (!(bnCtx = BN_CTX_new()))
        return errorN(1, "initialiseRingSigs(): BN_CTX_new failed.");

    BN_CTX_start(bnCtx);

    //Create a new EC group for the keyImage with all of the characteristics of ecGrp.
    if(!(ecGrpKi = EC_GROUP_dup(ecGrp))){
	return errorN(1, "initialiseRingSigs(): EC_GROUP_dup failed.");
    }

    // get order and cofactor
    bnOrder = BN_new();
    if(!EC_GROUP_get_order(ecGrp, bnOrder, bnCtx)){
        return errorN(1, "initialiseRingSigs(): EC_GROUP_get_order failed.");
    }

    BIGNUM *bnCofactor = BN_CTX_get(bnCtx);
    if(!EC_GROUP_get_cofactor(ecGrp, bnCofactor, bnCtx)){
    	return errorN(1, "initialiseRingSigs(): EC_GROUP_get_cofactor failed.");
    }

    // get the original generator
    EC_POINT *ptBase = const_cast<EC_POINT*>(EC_GROUP_get0_generator(ecGrp)); //PS: never clear this point

    // create key image basepoint variable
    EC_POINT *ptBaseKi = EC_POINT_new(ecGrpKi);
    BIGNUM *bnBaseKi = BN_CTX_get(bnCtx);

    // get original basepoint in BIG NUMS.
    EC_POINT_point2bn(ecGrp, ptBase, POINT_CONVERSION_COMPRESSED, bnBaseKi, bnCtx);

    //create "1" in BIG NUMS
    BIGNUM *bnBaseKiAdd = BN_CTX_get(bnCtx);
    std::string num_str = "1";
    BN_dec2bn(&bnBaseKiAdd, num_str.c_str());

    // add 1 to original base point and store in key image basepoint (BIG NUMS)
    BN_add(bnBaseKi, bnBaseKi, bnBaseKiAdd);

    // key image basepoint from bignum to point in ptBaseKi
    if(!EC_POINT_bn2point(ecGrp, bnBaseKi, ptBaseKi, bnCtx))
       return errorN(1, "initialiseRingSigs(): EC_POINT_bn2point failed.");

    // set generator of ecGrpKi
    if(!EC_GROUP_set_generator(ecGrpKi, ptBaseKi, bnOrder, bnCofactor)){
	 return errorN(1, "initialiseRingSigs(): EC_GROUP_set_generator failed.");
    }

    if (fDebugRingSig)
    {
        // Debugging...
        const EC_POINT *generator = EC_GROUP_get0_generator(ecGrp);
        const EC_POINT *generatorKi = EC_GROUP_get0_generator(ecGrpKi);
        char *genPoint = EC_POINT_point2hex(ecGrp, generator, POINT_CONVERSION_UNCOMPRESSED, bnCtx);
        char *genPointKi = EC_POINT_point2hex(ecGrpKi, generatorKi, POINT_CONVERSION_UNCOMPRESSED, bnCtx);

        LogPrintf("generator ecGrp:   %s\ngenerator ecGrpKi: %s\n", genPoint, genPointKi);
    }

    EC_POINT_free(ptBaseKi);
    BN_CTX_end(bnCtx);
    return 0;
};
Esempio n. 12
0
int verifyRingSignatureAB(data_chunk &keyImage, uint256 &txnHash, int nRingSize, const uint8_t *pPubkeys, const data_chunk &sigC, const uint8_t *pSigS)
{
    // https://bitcointalk.org/index.php?topic=972541.msg10619684

    // forall_{i=1..n} compute e_i=s_i*G+c_i*P_i and E_i=s_i*H(P_i)+c_i*I_j and c_{i+1}=h(P_1,...,P_n,e_i,E_i)
    // check c_{n+1}=c_1

    if (fDebugRingSig)
    {
        //LogPrintf("%s size %d\n", __func__, nRingSize); // happens often
    };

    if (sigC.size() != EC_SECRET_SIZE)
        return errorN(1, "%s: sigC size !=  EC_SECRET_SIZE.", __func__);
    if (keyImage.size() != EC_COMPRESSED_SIZE)
        return errorN(1, "%s: keyImage size !=  EC_COMPRESSED_SIZE.", __func__);

    int rv = 0;

    uint256 tmpPkHash;
    uint256 tmpHash;

    uint8_t tempData[66]; // hold raw point data to hash
    CHashWriter ssPkHash(SER_GETHASH, PROTOCOL_VERSION);
    CHashWriter ssCjHash(SER_GETHASH, PROTOCOL_VERSION);

    for (int i = 0; i < nRingSize; ++i)
    {
        ssPkHash.write((const char*)&pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE);
    };

    tmpPkHash = ssPkHash.GetHash();

    BN_CTX_start(bnCtx);

    BIGNUM   *bnC  = BN_CTX_get(bnCtx);
    BIGNUM   *bnC1 = BN_CTX_get(bnCtx);
    BIGNUM   *bnT  = BN_CTX_get(bnCtx);
    BIGNUM   *bnS  = BN_CTX_get(bnCtx);
    EC_POINT *ptKi = NULL;
    EC_POINT *ptT1 = NULL;
    EC_POINT *ptT2 = NULL;
    EC_POINT *ptT3 = NULL;
    EC_POINT *ptPk = NULL;
    EC_POINT *ptSi = NULL;

    if (   !(ptKi = EC_POINT_new(ecGrp))
        || !(ptT1 = EC_POINT_new(ecGrp))
        || !(ptT2 = EC_POINT_new(ecGrp))
        || !(ptT3 = EC_POINT_new(ecGrp))
        || !(ptPk = EC_POINT_new(ecGrp))
        || !(ptSi = EC_POINT_new(ecGrp)))
    {
        LogPrintf("%s: EC_POINT_new failed.\n", __func__);
        rv = 1; goto End;
    };

    // get keyimage as point
    if (!EC_POINT_oct2point(ecGrp, ptKi, &keyImage[0], EC_COMPRESSED_SIZE, bnCtx))
    {
        LogPrintf("%s: extract ptKi failed.\n", __func__);
        rv = 1; goto End;
    };

    if (!bnC1 || !BN_bin2bn(&sigC[0], EC_SECRET_SIZE, bnC1))
    {
        LogPrintf("%s: BN_bin2bn failed.\n", __func__);
        rv = 1; goto End;
    };

    if (!BN_copy(bnC, bnC1))
    {
        LogPrintf("%s: BN_copy failed.\n", __func__);
        rv = 1; goto End;
    };

    for (int i = 0; i < nRingSize; ++i)
    {
        if (!bnS || !(BN_bin2bn(&pSigS[i * EC_SECRET_SIZE], EC_SECRET_SIZE, bnS)))
        {
            LogPrintf("%s: BN_bin2bn failed.\n", __func__);
            rv = 1; goto End;
        };

        // ptT2 <- pk
        if (!EC_POINT_oct2point(ecGrp, ptPk, &pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnCtx))
        {
            LogPrintf("%s: EC_POINT_oct2point failed.\n", __func__);
            rv = 1; goto End;
        };

        // ptT1 = e_i=s_i*G+c_i*P_i
        if (!EC_POINT_mul(ecGrp, ptT1, bnS, ptPk, bnC, bnCtx))
        {
            LogPrintf("%s: EC_POINT_mul failed.\n", __func__);
            rv = 1; goto End;
        };

        if (!(EC_POINT_point2oct(ecGrp, ptT1, POINT_CONVERSION_COMPRESSED, &tempData[0],  33, bnCtx) == (int) EC_COMPRESSED_SIZE))
        {
            LogPrintf("%s: extract ptT1 failed.\n", __func__);
            rv = 1; goto End;
        };

        // ptT2 =E_i=s_i*H(P_i)+c_i*I_j

        // ptT2 =H(P_i)
        if (hashToEC(&pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnT, ptT2) != 0)
        {
            LogPrintf("%s: hashToEC failed.\n", __func__);
            rv = 1; goto End;
        };

        // DEBUGGING: ------- check if we can find the signer...
        // ptSi = Pi * bnT
        if ((!EC_POINT_mul(ecGrp, ptSi, NULL, ptPk, bnT, bnCtx)
           || false)
        && (rv = errorN(1, "%s: EC_POINT_mul failed.", __func__)))
            goto End;

        if (0 == EC_POINT_cmp(ecGrp, ptSi, ptKi, bnCtx) )
            LogPrintf("signer is index %d\n", i);
        // DEBUGGING: - End - check if we can find the signer...

        // ptT3 = s_i*ptT2
        if (!EC_POINT_mul(ecGrp, ptT3, NULL, ptT2, bnS, bnCtx))
        {
            LogPrintf("%s: EC_POINT_mul failed.\n", __func__);
            rv = 1; goto End;
        };

        // ptT1 = c_i*I_j
        if (!EC_POINT_mul(ecGrp, ptT1, NULL, ptKi, bnC, bnCtx))
        {
            LogPrintf("%s: EC_POINT_mul failed.\n", __func__);
            rv = 1; goto End;
        };

        // ptT2 = ptT3 + ptT1
        if (!EC_POINT_add(ecGrp, ptT2, ptT3, ptT1, bnCtx))
        {
            LogPrintf("%s: EC_POINT_add failed.\n", __func__);
            rv = 1; goto End;
        };

        if (!(EC_POINT_point2oct(ecGrp, ptT2, POINT_CONVERSION_COMPRESSED, &tempData[33], 33, bnCtx) == (int) EC_COMPRESSED_SIZE))
        {
            LogPrintf("%s: extract ptT2 failed.\n", __func__);
            rv = 1; goto End;
        };

        CHashWriter ssCHash(SER_GETHASH, PROTOCOL_VERSION);
        ssCHash.write((const char*)tmpPkHash.begin(), 32);
        ssCHash.write((const char*)&tempData[0], 66);
        tmpHash = ssCHash.GetHash();

        if (!bnC || !(BN_bin2bn(tmpHash.begin(), EC_SECRET_SIZE, bnC))
            || !BN_mod(bnC, bnC, bnOrder, bnCtx))
        {
            LogPrintf("%s: tmpHash -> bnC failed.\n", __func__);
            rv = 1; goto End;
        };
    };

    // bnT = (bnC - bnC1) % N
    if (!BN_mod_sub(bnT, bnC, bnC1, bnOrder, bnCtx))
    {
        LogPrintf("%s: BN_mod_sub failed.\n", __func__);
        rv = 1; goto End;
    };

    // test bnT == 0  (bnC == bnC1)
    if (!BN_is_zero(bnT))
    {
        LogPrintf("%s: signature does not verify.\n", __func__);
        rv = 2;
    };

    End:

    BN_CTX_end(bnCtx);

    EC_POINT_free(ptKi);
    EC_POINT_free(ptT1);
    EC_POINT_free(ptT2);
    EC_POINT_free(ptT3);
    EC_POINT_free(ptPk);
    EC_POINT_free(ptSi);

    return rv;
};