Exemple #1
0
bool CECKey::SignCompact(const uint256 &hash, unsigned char *p64, int &rec) {
    bool fOk = false;
    ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
    if (sig==NULL)
        return false;
    memset(p64, 0, 64);
    int nBitsR = BN_num_bits(sig->r);
    int nBitsS = BN_num_bits(sig->s);
    if (nBitsR <= 256 && nBitsS <= 256) {
        std::vector<unsigned char> pubkey;
        GetPubKey(pubkey, true);
        for (int i=0; i<4; i++) {
            CECKey keyRec;
            if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1) {
                std::vector<unsigned char> pubkeyRec;
                keyRec.GetPubKey(pubkeyRec, true);
                if (pubkeyRec == pubkey) {
                    rec = i;
                    fOk = true;
                    break;
                }
            }
        }
        assert(fOk);
        BN_bn2bin(sig->r,&p64[32-(nBitsR+7)/8]);
        BN_bn2bin(sig->s,&p64[64-(nBitsS+7)/8]);
    }
    ECDSA_SIG_free(sig);
    return fOk;
}
Exemple #2
0
// reconstruct public key from a compact signature
// This is only slightly more CPU intensive than just verifying it.
// If this function succeeds, the recovered public key is guaranteed to be valid
// (the signature is a valid signature of the given data for that key)
bool CKey::SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig)
{
    if (vchSig.size() != 65)
        return false;
    int nV = vchSig[0];
    if (nV<27 || nV>=35)
        return false;
    ECDSA_SIG *sig = ECDSA_SIG_new();
    BN_bin2bn(&vchSig[1],32,sig->r);
    BN_bin2bn(&vchSig[33],32,sig->s);

    EC_KEY_free(pkey);
    pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
    if (nV >= 31)
    {
        SetCompressedPubKey();
        nV -= 4;
    }
    if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1)
    {
        fSet = true;
        ECDSA_SIG_free(sig);
        return true;
    }
    return false;
}
Exemple #3
0
// create a compact signature (65 bytes), which allows reconstructing the used public key
// The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
//                  0x1D = second key with even y, 0x1E = second key with odd y
bool CKey::SignCompact(uint256 hash, std::vector<unsigned char> &vchSig)
{
	bool fOk = false;
	ECDSA_SIG *sig = ECDSA_do_sign((unsigned char *)&hash, sizeof(hash), pkey);
	if (sig == NULL)
		return false;
	vchSig.clear();
	vchSig.resize(65, 0);
	int nBitsR = BN_num_bits(sig->r);
	int nBitsS = BN_num_bits(sig->s);
	if (nBitsR <= 256 && nBitsS <= 256) {
		int nRecId = -1;
		for (int i = 0; i < 4; i++) {
			CKey keyRec;
			keyRec.fSet = true;
			if (fCompressedPubKey)
				keyRec.SetCompressedPubKey();
			if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char *)&hash, sizeof(hash), i, 1) == 1)
				if (keyRec.GetPubKey() == this->GetPubKey()) {
					nRecId = i;
					break;
				}
		}

		if (nRecId == -1)
			throw key_error("CKey::SignCompact() : unable to construct recoverable key");

		vchSig[0] = nRecId + 27 + (fCompressedPubKey ? 4 : 0);
		BN_bn2bin(sig->r, &vchSig[33 - (nBitsR + 7) / 8]);
		BN_bn2bin(sig->s, &vchSig[65 - (nBitsS + 7) / 8]);
		fOk = true;
	}
	ECDSA_SIG_free(sig);
	return fOk;
}
Exemple #4
0
bool CECKey::Recover(const uint256 &hash, const unsigned char *p64, int rec)
{
    if (rec<0 || rec>=3)
        return false;
    ECDSA_SIG *sig = ECDSA_SIG_new();
    BN_bin2bn(&p64[0],  32, sig->r);
    BN_bin2bn(&p64[32], 32, sig->s);
    bool ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), rec, 0) == 1;
    ECDSA_SIG_free(sig);
    return ret;
}
Exemple #5
0
// create a compact signature (65 bytes), which allows reconstructing the used public key
// The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
//                  0x1D = second key with even y, 0x1E = second key with odd y
bool CKey::SignCompact(uint256 hash, std::vector<unsigned char>& vchSig)
{
    bool fOk = false;
    ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
    if (sig==NULL)
        return false;
    const EC_GROUP *group = EC_KEY_get0_group(pkey);
    CBigNum order, halforder;
    EC_GROUP_get_order(group, &order, NULL);
    BN_rshift1(&halforder, &order);
    // enforce low S values, by negating the value (modulo the order) if above order/2.
    if (BN_cmp(sig->s, &halforder) > 0) {
        BN_sub(sig->s, &order, sig->s);
    }
    vchSig.clear();
    vchSig.resize(65,0);
    int nBitsR = BN_num_bits(sig->r);
    int nBitsS = BN_num_bits(sig->s);
    if (nBitsR <= 256 && nBitsS <= 256)
    {
        int nRecId = -1;
        for (int i=0; i<4; i++)
        {
            CKey keyRec;
            keyRec.fSet = true;
            if (fCompressedPubKey)
                keyRec.SetCompressedPubKey();
            if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1)
                if (keyRec.GetPubKey() == this->GetPubKey())
                {
                    nRecId = i;
                    break;
                }
        }

        if (nRecId == -1)
        {
            ECDSA_SIG_free(sig);
            throw key_error("CKey::SignCompact() : unable to construct recoverable key");
        }

        vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0);
        BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);
        BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]);
        fOk = true;
    }
    ECDSA_SIG_free(sig);
    return fOk;
}
bool CECKey::Recover(const uint256 &hash, const unsigned char *p64, int rec)
{
	if (rec<0 || rec>=3)
		return false;
	ECDSA_SIG *sig = ECDSA_SIG_new();
    // OpenSSL-1.1 compatibility layer:
#if OPENSSL_VERSION_NUMBER > 0x1000ffffL
    BIGNUM *sig_r=BN_new();
    BIGNUM *sig_s=BN_new();
    BN_bin2bn(&p64[0],  32, sig_r);
    BN_bin2bn(&p64[32], 32, sig_s);
    ECDSA_SIG_set0(sig, sig_r, sig_s);
#else
    BN_bin2bn(&p64[0],  32, sig->r);
    BN_bin2bn(&p64[32], 32, sig->s);
#endif
    //
	bool ret = ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), rec, 0) == 1;
	ECDSA_SIG_free(sig);
	return ret;
}
Exemple #7
0
// reconstruct public key from a compact signature
// This is only slightly more CPU intensive than just verifying it.
// If this function succeeds, the recovered public key is guaranteed to be valid
// (the signature is a valid signature of the given data for that key)
bool CKey::SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig)
{
    if (vchSig.size() != 65)
        return false;
    int nV = vchSig[0];
    if (nV<27 || nV>=35)
        return false;
    ECDSA_SIG *sig = ECDSA_SIG_new();
    if (!sig) return false;

    #if OPENSSL_VERSION_NUMBER > 0x1000ffffL
    // sig_r and sig_s are deallocated by ECDSA_SIG_free(sig);
    BIGNUM *sig_r = BN_bin2bn(&vchSig[1],32,BN_new());
    BIGNUM *sig_s = BN_bin2bn(&vchSig[33],32,BN_new());
    if (!sig_r || !sig_s) return false;
    // copy and transfer ownership to sig
    ECDSA_SIG_set0(sig, sig_r, sig_s);
    #else
    BN_bin2bn(&vchSig[1],32,sig->r);
    BN_bin2bn(&vchSig[33],32,sig->s);
    #endif

    EC_KEY_free(pkey);
    pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
    if (nV >= 31)
    {
        SetCompressedPubKey();
        nV -= 4;
    }
    if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1)
    {
        fSet = true;
        ECDSA_SIG_free(sig);
        return true;
    }
    ECDSA_SIG_free(sig);
    return false;
}