mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-04-16 06:02:18 +02:00
use EVP interface for DSA sign/verify with OpenSSL 3
This commit is contained in:
parent
a193186935
commit
75d5c6036e
4 changed files with 227 additions and 68 deletions
|
@ -19,6 +19,10 @@
|
||||||
#if OPENSSL_HKDF
|
#if OPENSSL_HKDF
|
||||||
#include <openssl/kdf.h>
|
#include <openssl/kdf.h>
|
||||||
#endif
|
#endif
|
||||||
|
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
|
||||||
|
#include <openssl/param_build.h>
|
||||||
|
#include <openssl/core_names.h>
|
||||||
|
#endif
|
||||||
#include "CPU.h"
|
#include "CPU.h"
|
||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
#include "Ed25519.h"
|
#include "Ed25519.h"
|
||||||
|
@ -146,6 +150,37 @@ namespace crypto
|
||||||
#define dsap GetCryptoConstants ().dsap
|
#define dsap GetCryptoConstants ().dsap
|
||||||
#define dsaq GetCryptoConstants ().dsaq
|
#define dsaq GetCryptoConstants ().dsaq
|
||||||
#define dsag GetCryptoConstants ().dsag
|
#define dsag GetCryptoConstants ().dsag
|
||||||
|
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
|
||||||
|
EVP_PKEY * CreateDSA (BIGNUM * pubKey, BIGNUM * privKey)
|
||||||
|
{
|
||||||
|
EVP_PKEY * pkey = nullptr;
|
||||||
|
int selection = EVP_PKEY_KEY_PARAMETERS;
|
||||||
|
auto bld = OSSL_PARAM_BLD_new();
|
||||||
|
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, dsap);
|
||||||
|
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_Q, dsaq);
|
||||||
|
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, dsag);
|
||||||
|
if (pubKey)
|
||||||
|
{
|
||||||
|
OSSL_PARAM_BLD_push_BN (bld, OSSL_PKEY_PARAM_PUB_KEY, pubKey);
|
||||||
|
selection = EVP_PKEY_PUBLIC_KEY;
|
||||||
|
}
|
||||||
|
if (privKey)
|
||||||
|
{
|
||||||
|
OSSL_PARAM_BLD_push_BN (bld, OSSL_PKEY_PARAM_PRIV_KEY, privKey);
|
||||||
|
selection = EVP_PKEY_KEYPAIR;
|
||||||
|
}
|
||||||
|
auto params = OSSL_PARAM_BLD_to_param(bld);
|
||||||
|
|
||||||
|
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name (NULL, "DSA", NULL);
|
||||||
|
EVP_PKEY_fromdata_init(ctx);
|
||||||
|
EVP_PKEY_fromdata(ctx, &pkey, selection, params);
|
||||||
|
|
||||||
|
EVP_PKEY_CTX_free(ctx);
|
||||||
|
OSSL_PARAM_free(params);
|
||||||
|
OSSL_PARAM_BLD_free(bld);
|
||||||
|
return pkey;
|
||||||
|
}
|
||||||
|
#else
|
||||||
DSA * CreateDSA ()
|
DSA * CreateDSA ()
|
||||||
{
|
{
|
||||||
DSA * dsa = DSA_new ();
|
DSA * dsa = DSA_new ();
|
||||||
|
@ -153,7 +188,8 @@ namespace crypto
|
||||||
DSA_set0_key (dsa, NULL, NULL);
|
DSA_set0_key (dsa, NULL, NULL);
|
||||||
return dsa;
|
return dsa;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// DH/ElGamal
|
// DH/ElGamal
|
||||||
|
|
||||||
#if !IS_X86_64
|
#if !IS_X86_64
|
||||||
|
@ -943,7 +979,6 @@ namespace crypto
|
||||||
}
|
}
|
||||||
|
|
||||||
#if OPENSSL_PQ
|
#if OPENSSL_PQ
|
||||||
#include <openssl/core_names.h>
|
|
||||||
|
|
||||||
MLKEM512Keys::MLKEM512Keys ():
|
MLKEM512Keys::MLKEM512Keys ():
|
||||||
m_Pkey (nullptr)
|
m_Pkey (nullptr)
|
||||||
|
|
|
@ -45,7 +45,11 @@ namespace crypto
|
||||||
bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len);
|
bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len);
|
||||||
|
|
||||||
// DSA
|
// DSA
|
||||||
|
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
|
||||||
|
EVP_PKEY * CreateDSA (BIGNUM * pubKey = nullptr, BIGNUM * privKey = nullptr);
|
||||||
|
#else
|
||||||
DSA * CreateDSA ();
|
DSA * CreateDSA ();
|
||||||
|
#endif
|
||||||
|
|
||||||
// RSA
|
// RSA
|
||||||
const BIGNUM * GetRSAE ();
|
const BIGNUM * GetRSAE ();
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
|
||||||
|
#include <openssl/core_names.h>
|
||||||
|
#endif
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Signature.h"
|
#include "Signature.h"
|
||||||
|
|
||||||
|
@ -14,6 +18,163 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace crypto
|
namespace crypto
|
||||||
{
|
{
|
||||||
|
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
|
||||||
|
DSAVerifier::DSAVerifier ():
|
||||||
|
m_PublicKey (nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DSAVerifier::~DSAVerifier ()
|
||||||
|
{
|
||||||
|
if (m_PublicKey)
|
||||||
|
EVP_PKEY_free (m_PublicKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSAVerifier::SetPublicKey (const uint8_t * signingKey)
|
||||||
|
{
|
||||||
|
if (m_PublicKey)
|
||||||
|
EVP_PKEY_free (m_PublicKey);
|
||||||
|
BIGNUM * pub = BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL);
|
||||||
|
m_PublicKey = CreateDSA (pub);
|
||||||
|
BN_free (pub);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DSAVerifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
||||||
|
{
|
||||||
|
// calculate SHA1 digest
|
||||||
|
uint8_t digest[20], sign[48];
|
||||||
|
SHA1 (buf, len, digest);
|
||||||
|
// signature
|
||||||
|
DSA_SIG * sig = DSA_SIG_new();
|
||||||
|
DSA_SIG_set0 (sig, BN_bin2bn (signature, DSA_SIGNATURE_LENGTH/2, NULL), BN_bin2bn (signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2, NULL));
|
||||||
|
// to DER format
|
||||||
|
uint8_t * s = sign;
|
||||||
|
auto l = i2d_DSA_SIG (sig, &s);
|
||||||
|
DSA_SIG_free(sig);
|
||||||
|
// verify
|
||||||
|
auto ctx = EVP_PKEY_CTX_new (m_PublicKey, NULL);
|
||||||
|
EVP_PKEY_verify_init(ctx);
|
||||||
|
EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha1());
|
||||||
|
bool ret = EVP_PKEY_verify(ctx, sign, l, digest, 20);
|
||||||
|
EVP_PKEY_CTX_free(ctx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
DSASigner::DSASigner (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey)
|
||||||
|
{
|
||||||
|
BIGNUM * priv = BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL);
|
||||||
|
m_PrivateKey = CreateDSA (nullptr, priv);
|
||||||
|
BN_free (priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
DSASigner::~DSASigner ()
|
||||||
|
{
|
||||||
|
if (m_PrivateKey)
|
||||||
|
EVP_PKEY_free (m_PrivateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSASigner::Sign (const uint8_t * buf, int len, uint8_t * signature) const
|
||||||
|
{
|
||||||
|
uint8_t digest[20], sign[48];
|
||||||
|
SHA1 (buf, len, digest);
|
||||||
|
auto ctx = EVP_PKEY_CTX_new (m_PrivateKey, NULL);
|
||||||
|
EVP_PKEY_sign_init(ctx);
|
||||||
|
EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha1());
|
||||||
|
size_t l = 48;
|
||||||
|
EVP_PKEY_sign(ctx, sign, &l, digest, 20);
|
||||||
|
const uint8_t * s1 = sign;
|
||||||
|
DSA_SIG * sig = d2i_DSA_SIG (NULL, &s1, l);
|
||||||
|
const BIGNUM * r, * s;
|
||||||
|
DSA_SIG_get0 (sig, &r, &s);
|
||||||
|
bn2buf (r, signature, DSA_SIGNATURE_LENGTH/2);
|
||||||
|
bn2buf (s, signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2);
|
||||||
|
DSA_SIG_free(sig);
|
||||||
|
EVP_PKEY_CTX_free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateDSARandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
||||||
|
{
|
||||||
|
EVP_PKEY * paramskey = CreateDSA();
|
||||||
|
EVP_PKEY_CTX * ctx = EVP_PKEY_CTX_new_from_pkey(NULL, paramskey, NULL);
|
||||||
|
EVP_PKEY_keygen_init(ctx);
|
||||||
|
EVP_PKEY * pkey = nullptr;
|
||||||
|
EVP_PKEY_keygen(ctx, &pkey);
|
||||||
|
BIGNUM * pub = NULL, * priv = NULL;
|
||||||
|
EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, &pub);
|
||||||
|
bn2buf (pub, signingPublicKey, DSA_PUBLIC_KEY_LENGTH);
|
||||||
|
EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv);
|
||||||
|
bn2buf (priv, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH);
|
||||||
|
BN_free (pub); BN_free (priv);
|
||||||
|
EVP_PKEY_free (pkey);
|
||||||
|
EVP_PKEY_free (paramskey);
|
||||||
|
EVP_PKEY_CTX_free (ctx);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
DSAVerifier::DSAVerifier ()
|
||||||
|
{
|
||||||
|
m_PublicKey = CreateDSA ();
|
||||||
|
}
|
||||||
|
|
||||||
|
DSAVerifier::~DSAVerifier ()
|
||||||
|
{
|
||||||
|
DSA_free (m_PublicKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSAVerifier::SetPublicKey (const uint8_t * signingKey)
|
||||||
|
{
|
||||||
|
DSA_set0_key (m_PublicKey, BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DSAVerifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
||||||
|
{
|
||||||
|
// calculate SHA1 digest
|
||||||
|
uint8_t digest[20];
|
||||||
|
SHA1 (buf, len, digest);
|
||||||
|
// signature
|
||||||
|
DSA_SIG * sig = DSA_SIG_new();
|
||||||
|
DSA_SIG_set0 (sig, BN_bin2bn (signature, DSA_SIGNATURE_LENGTH/2, NULL), BN_bin2bn (signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2, NULL));
|
||||||
|
// DSA verification
|
||||||
|
int ret = DSA_do_verify (digest, 20, sig, m_PublicKey);
|
||||||
|
DSA_SIG_free(sig);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
DSASigner::DSASigner (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey)
|
||||||
|
{
|
||||||
|
m_PrivateKey = CreateDSA ();
|
||||||
|
DSA_set0_key (m_PrivateKey, BN_bin2bn (signingPublicKey, DSA_PUBLIC_KEY_LENGTH, NULL), BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
DSASigner::~DSASigner ()
|
||||||
|
{
|
||||||
|
DSA_free (m_PrivateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSASigner::Sign (const uint8_t * buf, int len, uint8_t * signature) const
|
||||||
|
{
|
||||||
|
uint8_t digest[20];
|
||||||
|
SHA1 (buf, len, digest);
|
||||||
|
DSA_SIG * sig = DSA_do_sign (digest, 20, m_PrivateKey);
|
||||||
|
const BIGNUM * r, * s;
|
||||||
|
DSA_SIG_get0 (sig, &r, &s);
|
||||||
|
bn2buf (r, signature, DSA_SIGNATURE_LENGTH/2);
|
||||||
|
bn2buf (s, signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2);
|
||||||
|
DSA_SIG_free(sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateDSARandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
||||||
|
{
|
||||||
|
DSA * dsa = CreateDSA ();
|
||||||
|
DSA_generate_key (dsa);
|
||||||
|
const BIGNUM * pub_key, * priv_key;
|
||||||
|
DSA_get0_key(dsa, &pub_key, &priv_key);
|
||||||
|
bn2buf (priv_key, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH);
|
||||||
|
bn2buf (pub_key, signingPublicKey, DSA_PUBLIC_KEY_LENGTH);
|
||||||
|
DSA_free (dsa);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if OPENSSL_EDDSA
|
#if OPENSSL_EDDSA
|
||||||
EDDSA25519Verifier::EDDSA25519Verifier ():
|
EDDSA25519Verifier::EDDSA25519Verifier ():
|
||||||
m_Pkey (nullptr)
|
m_Pkey (nullptr)
|
||||||
|
@ -202,8 +363,7 @@ namespace crypto
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if OPENSSL_PQ
|
#if OPENSSL_PQ
|
||||||
#include <openssl/core_names.h>
|
|
||||||
|
|
||||||
MLDSA44Verifier::MLDSA44Verifier ():
|
MLDSA44Verifier::MLDSA44Verifier ():
|
||||||
m_Pkey (nullptr)
|
m_Pkey (nullptr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -43,94 +43,55 @@ namespace crypto
|
||||||
virtual void Sign (const uint8_t * buf, int len, uint8_t * signature) const = 0;
|
virtual void Sign (const uint8_t * buf, int len, uint8_t * signature) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// DSA
|
||||||
const size_t DSA_PUBLIC_KEY_LENGTH = 128;
|
const size_t DSA_PUBLIC_KEY_LENGTH = 128;
|
||||||
const size_t DSA_SIGNATURE_LENGTH = 40;
|
const size_t DSA_SIGNATURE_LENGTH = 40;
|
||||||
const size_t DSA_PRIVATE_KEY_LENGTH = DSA_SIGNATURE_LENGTH/2;
|
const size_t DSA_PRIVATE_KEY_LENGTH = DSA_SIGNATURE_LENGTH/2;
|
||||||
class DSAVerifier: public Verifier
|
class DSAVerifier: public Verifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
DSAVerifier ();
|
||||||
|
~DSAVerifier ();
|
||||||
|
|
||||||
DSAVerifier ()
|
// implements Verifier
|
||||||
{
|
void SetPublicKey (const uint8_t * signingKey) override;
|
||||||
m_PublicKey = CreateDSA ();
|
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const override;
|
||||||
}
|
size_t GetPublicKeyLen () const override { return DSA_PUBLIC_KEY_LENGTH; };
|
||||||
|
size_t GetSignatureLen () const override { return DSA_SIGNATURE_LENGTH; };
|
||||||
void SetPublicKey (const uint8_t * signingKey)
|
|
||||||
{
|
|
||||||
DSA_set0_key (m_PublicKey, BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL), NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
~DSAVerifier ()
|
|
||||||
{
|
|
||||||
DSA_free (m_PublicKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
|
||||||
{
|
|
||||||
// calculate SHA1 digest
|
|
||||||
uint8_t digest[20];
|
|
||||||
SHA1 (buf, len, digest);
|
|
||||||
// signature
|
|
||||||
DSA_SIG * sig = DSA_SIG_new();
|
|
||||||
DSA_SIG_set0 (sig, BN_bin2bn (signature, DSA_SIGNATURE_LENGTH/2, NULL), BN_bin2bn (signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2, NULL));
|
|
||||||
// DSA verification
|
|
||||||
int ret = DSA_do_verify (digest, 20, sig, m_PublicKey);
|
|
||||||
DSA_SIG_free(sig);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t GetPublicKeyLen () const { return DSA_PUBLIC_KEY_LENGTH; };
|
|
||||||
size_t GetSignatureLen () const { return DSA_SIGNATURE_LENGTH; };
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
|
||||||
|
EVP_PKEY * m_PublicKey;
|
||||||
|
#else
|
||||||
DSA * m_PublicKey;
|
DSA * m_PublicKey;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class DSASigner: public Signer
|
class DSASigner: public Signer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DSASigner (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey)
|
DSASigner (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey);
|
||||||
// openssl 1.1 always requires DSA public key even for signing
|
// openssl 1.1 always requires DSA public key even for signing
|
||||||
{
|
~DSASigner ();
|
||||||
m_PrivateKey = CreateDSA ();
|
|
||||||
DSA_set0_key (m_PrivateKey, BN_bin2bn (signingPublicKey, DSA_PUBLIC_KEY_LENGTH, NULL), BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
~DSASigner ()
|
// implements Signer
|
||||||
{
|
void Sign (const uint8_t * buf, int len, uint8_t * signature) const override;
|
||||||
DSA_free (m_PrivateKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const
|
|
||||||
{
|
|
||||||
uint8_t digest[20];
|
|
||||||
SHA1 (buf, len, digest);
|
|
||||||
DSA_SIG * sig = DSA_do_sign (digest, 20, m_PrivateKey);
|
|
||||||
const BIGNUM * r, * s;
|
|
||||||
DSA_SIG_get0 (sig, &r, &s);
|
|
||||||
bn2buf (r, signature, DSA_SIGNATURE_LENGTH/2);
|
|
||||||
bn2buf (s, signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2);
|
|
||||||
DSA_SIG_free(sig);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
#if (OPENSSL_VERSION_NUMBER >= 0x030000000) // since 3.0.0
|
||||||
|
EVP_PKEY * m_PrivateKey;
|
||||||
|
#else
|
||||||
DSA * m_PrivateKey;
|
DSA * m_PrivateKey;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void CreateDSARandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
void CreateDSARandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey);
|
||||||
{
|
|
||||||
DSA * dsa = CreateDSA ();
|
|
||||||
DSA_generate_key (dsa);
|
|
||||||
const BIGNUM * pub_key, * priv_key;
|
|
||||||
DSA_get0_key(dsa, &pub_key, &priv_key);
|
|
||||||
bn2buf (priv_key, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH);
|
|
||||||
bn2buf (pub_key, signingPublicKey, DSA_PUBLIC_KEY_LENGTH);
|
|
||||||
DSA_free (dsa);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// ECDSA
|
||||||
struct SHA256Hash
|
struct SHA256Hash
|
||||||
{
|
{
|
||||||
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
|
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
|
||||||
|
@ -161,7 +122,6 @@ namespace crypto
|
||||||
enum { hashLen = 64 };
|
enum { hashLen = 64 };
|
||||||
};
|
};
|
||||||
|
|
||||||
// EcDSA
|
|
||||||
template<typename Hash, int curve, size_t keyLen>
|
template<typename Hash, int curve, size_t keyLen>
|
||||||
class ECDSAVerifier: public Verifier
|
class ECDSAVerifier: public Verifier
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Reference in a new issue