Changes for secp256k1

This commit is contained in:
Vinnie Falco
2017-01-26 15:42:24 -05:00
parent fdff943262
commit e05bf0844d
8 changed files with 363 additions and 41 deletions

View File

@@ -3854,6 +3854,10 @@
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\secp256k1\include\secp256k1.h"> <ClInclude Include="..\..\src\secp256k1\include\secp256k1.h">
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\secp256k1\include\secp256k1_ecdh.h">
</ClInclude>
<ClInclude Include="..\..\src\secp256k1\include\secp256k1_recovery.h">
</ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\ecdsa.h"> <ClInclude Include="..\..\src\secp256k1\src\ecdsa.h">
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\ecdsa_impl.h"> <ClInclude Include="..\..\src\secp256k1\src\ecdsa_impl.h">
@@ -3864,6 +3868,10 @@
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\ecmult.h"> <ClInclude Include="..\..\src\secp256k1\src\ecmult.h">
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\ecmult_const.h">
</ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\ecmult_const_impl.h">
</ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\ecmult_gen.h"> <ClInclude Include="..\..\src\secp256k1\src\ecmult_gen.h">
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\ecmult_gen_impl.h"> <ClInclude Include="..\..\src\secp256k1\src\ecmult_gen_impl.h">
@@ -3894,6 +3902,10 @@
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\hash_impl.h"> <ClInclude Include="..\..\src\secp256k1\src\hash_impl.h">
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\modules\ecdh\main_impl.h">
</ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\modules\recovery\main_impl.h">
</ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\num.h"> <ClInclude Include="..\..\src\secp256k1\src\num.h">
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\num_gmp.h"> <ClInclude Include="..\..\src\secp256k1\src\num_gmp.h">
@@ -3914,6 +3926,10 @@
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\scalar_impl.h"> <ClInclude Include="..\..\src\secp256k1\src\scalar_impl.h">
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\scalar_low.h">
</ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\scalar_low_impl.h">
</ClInclude>
<ClCompile Include="..\..\src\secp256k1\src\secp256k1.c"> <ClCompile Include="..\..\src\secp256k1\src\secp256k1.c">
<ExcludedFromBuild>True</ExcludedFromBuild> <ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile> </ClCompile>

View File

@@ -370,6 +370,15 @@
<Filter Include="secp256k1\src"> <Filter Include="secp256k1\src">
<UniqueIdentifier>{E25BE380-48B7-7EA9-DFD6-F38F1E8A22FF}</UniqueIdentifier> <UniqueIdentifier>{E25BE380-48B7-7EA9-DFD6-F38F1E8A22FF}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="secp256k1\src\modules">
<UniqueIdentifier>{6BE34C70-DCAB-96D1-487C-ADC692DA720B}</UniqueIdentifier>
</Filter>
<Filter Include="secp256k1\src\modules\ecdh">
<UniqueIdentifier>{46FCBB68-FE6A-0EB7-98C9-C695B05E6503}</UniqueIdentifier>
</Filter>
<Filter Include="secp256k1\src\modules\recovery">
<UniqueIdentifier>{0B56B4A9-D9BC-B7FB-DD09-ADAF9DDE4895}</UniqueIdentifier>
</Filter>
<Filter Include="snappy"> <Filter Include="snappy">
<UniqueIdentifier>{26306562-F81D-B6CD-B192-22BA51E1A96B}</UniqueIdentifier> <UniqueIdentifier>{26306562-F81D-B6CD-B192-22BA51E1A96B}</UniqueIdentifier>
</Filter> </Filter>
@@ -4521,6 +4530,12 @@
<ClInclude Include="..\..\src\secp256k1\include\secp256k1.h"> <ClInclude Include="..\..\src\secp256k1\include\secp256k1.h">
<Filter>secp256k1\include</Filter> <Filter>secp256k1\include</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\secp256k1\include\secp256k1_ecdh.h">
<Filter>secp256k1\include</Filter>
</ClInclude>
<ClInclude Include="..\..\src\secp256k1\include\secp256k1_recovery.h">
<Filter>secp256k1\include</Filter>
</ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\ecdsa.h"> <ClInclude Include="..\..\src\secp256k1\src\ecdsa.h">
<Filter>secp256k1\src</Filter> <Filter>secp256k1\src</Filter>
</ClInclude> </ClInclude>
@@ -4536,6 +4551,12 @@
<ClInclude Include="..\..\src\secp256k1\src\ecmult.h"> <ClInclude Include="..\..\src\secp256k1\src\ecmult.h">
<Filter>secp256k1\src</Filter> <Filter>secp256k1\src</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\ecmult_const.h">
<Filter>secp256k1\src</Filter>
</ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\ecmult_const_impl.h">
<Filter>secp256k1\src</Filter>
</ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\ecmult_gen.h"> <ClInclude Include="..\..\src\secp256k1\src\ecmult_gen.h">
<Filter>secp256k1\src</Filter> <Filter>secp256k1\src</Filter>
</ClInclude> </ClInclude>
@@ -4581,6 +4602,12 @@
<ClInclude Include="..\..\src\secp256k1\src\hash_impl.h"> <ClInclude Include="..\..\src\secp256k1\src\hash_impl.h">
<Filter>secp256k1\src</Filter> <Filter>secp256k1\src</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\modules\ecdh\main_impl.h">
<Filter>secp256k1\src\modules\ecdh</Filter>
</ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\modules\recovery\main_impl.h">
<Filter>secp256k1\src\modules\recovery</Filter>
</ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\num.h"> <ClInclude Include="..\..\src\secp256k1\src\num.h">
<Filter>secp256k1\src</Filter> <Filter>secp256k1\src</Filter>
</ClInclude> </ClInclude>
@@ -4611,6 +4638,12 @@
<ClInclude Include="..\..\src\secp256k1\src\scalar_impl.h"> <ClInclude Include="..\..\src\secp256k1\src\scalar_impl.h">
<Filter>secp256k1\src</Filter> <Filter>secp256k1\src</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\scalar_low.h">
<Filter>secp256k1\src</Filter>
</ClInclude>
<ClInclude Include="..\..\src\secp256k1\src\scalar_low_impl.h">
<Filter>secp256k1\src</Filter>
</ClInclude>
<ClCompile Include="..\..\src\secp256k1\src\secp256k1.c"> <ClCompile Include="..\..\src\secp256k1\src\secp256k1.c">
<Filter>secp256k1\src</Filter> <Filter>secp256k1\src</Filter>
</ClCompile> </ClCompile>

View File

@@ -29,6 +29,7 @@
#include <algorithm> #include <algorithm>
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <ostream>
#include <utility> #include <utility>
namespace ripple { namespace ripple {
@@ -98,6 +99,11 @@ public:
} }
}; };
/** Print the public key to a stream.
*/
std::ostream&
operator<<(std::ostream& os, PublicKey const& pk);
inline inline
bool bool
operator== (PublicKey const& lhs, operator== (PublicKey const& lhs,

View File

@@ -27,6 +27,7 @@
#include <ripple/protocol/Seed.h> #include <ripple/protocol/Seed.h>
#include <ripple/protocol/tokens.h> #include <ripple/protocol/tokens.h>
#include <array> #include <array>
#include <string>
namespace ripple { namespace ripple {
@@ -57,6 +58,14 @@ public:
{ {
return sizeof(buf_); return sizeof(buf_);
} }
/** Convert the secret key to a hexadecimal string.
@note The operator<< function is deliberately omitted
to avoid accidental exposure of secret key material.
*/
std::string
to_string() const;
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@@ -22,6 +22,7 @@
#include <ripple/protocol/digest.h> #include <ripple/protocol/digest.h>
#include <ripple/protocol/impl/secp256k1.h> #include <ripple/protocol/impl/secp256k1.h>
#include <ripple/basics/contract.h> #include <ripple/basics/contract.h>
#include <ripple/basics/strHex.h>
#include <ripple/beast/core/ByteOrder.h> #include <ripple/beast/core/ByteOrder.h>
#include <boost/multiprecision/cpp_int.hpp> #include <boost/multiprecision/cpp_int.hpp>
#include <ed25519-donna/ed25519.h> #include <ed25519-donna/ed25519.h>
@@ -29,6 +30,13 @@
namespace ripple { namespace ripple {
std::ostream&
operator<<(std::ostream& os, PublicKey const& pk)
{
os << strHex(pk.data(), pk.size());
return os;
}
using uint264 = boost::multiprecision::number< using uint264 = boost::multiprecision::number<
boost::multiprecision::cpp_int_backend< boost::multiprecision::cpp_int_backend<
264, 264, boost::multiprecision::signed_magnitude, 264, 264, boost::multiprecision::signed_magnitude,
@@ -219,17 +227,51 @@ verifyDigest (PublicKey const& publicKey,
{ {
if (publicKeyType(publicKey) != KeyType::secp256k1) if (publicKeyType(publicKey) != KeyType::secp256k1)
LogicError("sign: secp256k1 required for digest signing"); LogicError("sign: secp256k1 required for digest signing");
auto const canonicality = ecdsaCanonicality(sig); auto const canonicality = ecdsaCanonicality(sig);
if (! canonicality) if (! canonicality)
return false; return false;
if (mustBeFullyCanonical && if (mustBeFullyCanonical &&
(*canonicality != ECDSACanonicality::fullyCanonical)) (*canonicality != ECDSACanonicality::fullyCanonical))
return false; return false;
secp256k1_pubkey pubkey_imp;
if(secp256k1_ec_pubkey_parse(
secp256k1Context(),
&pubkey_imp,
reinterpret_cast<unsigned char const*>(
publicKey.data()),
publicKey.size()) != 1)
return false;
secp256k1_ecdsa_signature sig_imp;
if(secp256k1_ecdsa_signature_parse_der(
secp256k1Context(),
&sig_imp,
reinterpret_cast<unsigned char const*>(
sig.data()),
sig.size()) != 1)
return false;
if (*canonicality != ECDSACanonicality::fullyCanonical)
{
secp256k1_ecdsa_signature sig_norm;
if(secp256k1_ecdsa_signature_normalize(
secp256k1Context(),
&sig_norm,
&sig_imp) != 1)
return false;
return secp256k1_ecdsa_verify( return secp256k1_ecdsa_verify(
secp256k1Context(), secpp(digest.data()), secp256k1Context(),
secpp(sig.data()), sig.size(), &sig_norm,
secpp(publicKey.data()), publicKey.size()) == 1; reinterpret_cast<unsigned char const*>(
digest.data()),
&pubkey_imp) == 1;
}
return secp256k1_ecdsa_verify(
secp256k1Context(),
&sig_imp,
reinterpret_cast<unsigned char const*>(
digest.data()),
&pubkey_imp) == 1;
} }
bool bool

View File

@@ -18,6 +18,7 @@
//============================================================================== //==============================================================================
#include <BeastConfig.h> #include <BeastConfig.h>
#include <ripple/basics/strHex.h>
#include <ripple/protocol/SecretKey.h> #include <ripple/protocol/SecretKey.h>
#include <ripple/protocol/digest.h> #include <ripple/protocol/digest.h>
#include <ripple/protocol/impl/secp256k1.h> #include <ripple/protocol/impl/secp256k1.h>
@@ -48,6 +49,12 @@ SecretKey::SecretKey (Slice const& slice)
std::memcpy(buf_, slice.data(), sizeof(buf_)); std::memcpy(buf_, slice.data(), sizeof(buf_));
} }
std::string
SecretKey::to_string() const
{
return strHex(data(), size());
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
Generator::Generator (Seed const& seed) Generator::Generator (Seed const& seed)
@@ -88,16 +95,29 @@ signDigest (PublicKey const& pk, SecretKey const& sk,
if (publicKeyType(pk.slice()) != KeyType::secp256k1) if (publicKeyType(pk.slice()) != KeyType::secp256k1)
LogicError("sign: secp256k1 required for digest signing"); LogicError("sign: secp256k1 required for digest signing");
int siglen = 72; BOOST_ASSERT(sk.size() == 32);
unsigned char sig[72]; secp256k1_ecdsa_signature sig_imp;
auto const result = secp256k1_ecdsa_sign( if(secp256k1_ecdsa_sign(
secp256k1Context(), secp256k1Context(),
digest.data(), sig, &siglen, &sig_imp,
sk.data(), secp256k1_nonce_function_rfc6979, reinterpret_cast<unsigned char const*>(
nullptr); digest.data()),
if (result != 1) reinterpret_cast<unsigned char const*>(
sk.data()),
secp256k1_nonce_function_rfc6979,
nullptr) != 1)
LogicError("sign: secp256k1_ecdsa_sign failed"); LogicError("sign: secp256k1_ecdsa_sign failed");
return Buffer(sig, siglen);
unsigned char sig[72];
size_t len = sizeof(sig);
if(secp256k1_ecdsa_signature_serialize_der(
secp256k1Context(),
sig,
&len,
&sig_imp) != 1)
LogicError("sign: secp256k1_ecdsa_signature_serialize_der failed");
return Buffer{sig, len};
} }
Buffer Buffer
@@ -123,16 +143,29 @@ sign (PublicKey const& pk,
h(m.data(), m.size()); h(m.data(), m.size());
auto const digest = auto const digest =
sha512_half_hasher::result_type(h); sha512_half_hasher::result_type(h);
int siglen = 72;
unsigned char sig[72]; secp256k1_ecdsa_signature sig_imp;
auto const result = secp256k1_ecdsa_sign( if(secp256k1_ecdsa_sign(
secp256k1Context(), secp256k1Context(),
digest.data(), sig, &siglen, &sig_imp,
sk.data(), secp256k1_nonce_function_rfc6979, reinterpret_cast<unsigned char const*>(
nullptr); digest.data()),
if (result != 1) reinterpret_cast<unsigned char const*>(
sk.data()),
secp256k1_nonce_function_rfc6979,
nullptr) != 1)
LogicError("sign: secp256k1_ecdsa_sign failed"); LogicError("sign: secp256k1_ecdsa_sign failed");
return Buffer(sig, siglen);
unsigned char sig[72];
size_t len = sizeof(sig);
if(secp256k1_ecdsa_signature_serialize_der(
secp256k1Context(),
sig,
&len,
&sig_imp) != 1)
LogicError("sign: secp256k1_ecdsa_signature_serialize_der failed");
return Buffer{sig, len};
} }
default: default:
LogicError("sign: invalid type"); LogicError("sign: invalid type");
@@ -184,16 +217,26 @@ derivePublicKey (KeyType type, SecretKey const& sk)
{ {
case KeyType::secp256k1: case KeyType::secp256k1:
{ {
int len; secp256k1_pubkey pubkey_imp;
unsigned char buf[33]; if(secp256k1_ec_pubkey_create(
auto const result =
secp256k1_ec_pubkey_create(
secp256k1Context(), secp256k1Context(),
buf, &len, sk.data(), 1); &pubkey_imp,
if (result != 1) reinterpret_cast<unsigned char const*>(
LogicError("derivePublicKey: failure"); sk.data())) != 1)
return PublicKey(Slice{ buf, LogicError("derivePublicKey: secp256k1_ec_pubkey_create failed");
static_cast<std::size_t>(len) });
unsigned char pubkey[33];
size_t len = sizeof(pubkey);
if(secp256k1_ec_pubkey_serialize(
secp256k1Context(),
pubkey,
&len,
&pubkey_imp,
SECP256K1_EC_COMPRESSED) != 1)
LogicError("derivePublicKey: secp256k1_ec_pubkey_serialize failed");
return PublicKey{Slice{pubkey,
static_cast<std::size_t>(len)}};
} }
case KeyType::ed25519: case KeyType::ed25519:
{ {

View File

@@ -25,15 +25,15 @@
namespace ripple { namespace ripple {
template <class = void> template <class = void>
secp256k1_context_t const* secp256k1_context const*
secp256k1Context() secp256k1Context()
{ {
struct holder struct holder
{ {
secp256k1_context_t* impl; secp256k1_context* impl;
holder() holder()
: impl (secp256k1_context_create( : impl (secp256k1_context_create(
SECP256K1_CONTEXT_VERIFY + SECP256K1_CONTEXT_VERIFY |
SECP256K1_CONTEXT_SIGN)) SECP256K1_CONTEXT_SIGN))
{ {
} }
@@ -47,13 +47,6 @@ secp256k1Context()
return h.impl; return h.impl;
} }
inline
unsigned char const*
secpp(void const* p)
{
return static_cast<unsigned char const*>(p);
}
} // ripple } // ripple
#endif #endif

View File

@@ -28,6 +28,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <ripple/protocol/impl/secp256k1.h>
namespace ripple { namespace ripple {
class SecretKey_test : public beast::unit_test::suite class SecretKey_test : public beast::unit_test::suite
@@ -41,6 +43,183 @@ class SecretKey_test : public beast::unit_test::suite
} }
public: public:
using blob = std::vector<std::uint8_t>;
template <class FwdIter, class Container>
static
void
hex_to_binary (FwdIter first, FwdIter last, Container& out)
{
struct Table
{
int val[256];
Table ()
{
std::fill (val, val+256, 0);
for (int i = 0; i < 10; ++i)
val ['0'+i] = i;
for (int i = 0; i < 6; ++i)
{
val ['A'+i] = 10 + i;
val ['a'+i] = 10 + i;
}
}
int operator[] (int i)
{
return val[i];
}
};
static Table lut;
out.reserve (std::distance (first, last) / 2);
while (first != last)
{
auto const hi (lut[(*first++)]);
auto const lo (lut[(*first++)]);
out.push_back ((hi*16)+lo);
}
}
static
uint256
hex_to_digest(std::string const& s)
{
blob b;
hex_to_binary (s.begin (), s.end (), b);
return uint256::fromVoid(b.data());
}
static
PublicKey
hex_to_pk(std::string const& s)
{
blob b;
hex_to_binary (s.begin (), s.end (), b);
return PublicKey{Slice{b.data(), b.size()}};
}
static
SecretKey
hex_to_sk(std::string const& s)
{
blob b;
hex_to_binary (s.begin (), s.end (), b);
return SecretKey{Slice{b.data(), b.size()}};
}
static
Buffer
hex_to_sig(std::string const& s)
{
blob b;
hex_to_binary (s.begin (), s.end (), b);
return Buffer{Slice{b.data(), b.size()}};
}
// VFALCO We can remove this commented out code
// later, when we have confidence in the vectors.
/*
Buffer
makeNonCanonical(Buffer const& sig)
{
secp256k1_ecdsa_signature sigin;
BEAST_EXPECT(secp256k1_ecdsa_signature_parse_der(
secp256k1Context(),
&sigin,
reinterpret_cast<unsigned char const*>(
sig.data()),
sig.size()) == 1);
secp256k1_ecdsa_signature sigout;
BEAST_EXPECT(secp256k1_ecdsa_signature_denormalize(
secp256k1Context(),
&sigout,
&sigin) == 1);
unsigned char buf[72];
size_t len = sizeof(buf);
BEAST_EXPECT(secp256k1_ecdsa_signature_serialize_der(
secp256k1Context(),
buf,
&len,
&sigout) == 1);
return Buffer{buf, len};
}
void
makeCanonicalityTestVectors()
{
uint256 digest;
beast::rngfill (
digest.data(),
digest.size(),
crypto_prng());
log << "digest " << strHex(digest.data(), digest.size()) << std::endl;
auto const sk = randomSecretKey();
auto const pk = derivePublicKey(KeyType::secp256k1, sk);
log << "public " << pk << std::endl;
log << "secret " << sk.to_string() << std::endl;
auto sig = signDigest(pk, sk, digest);
log << "canonical sig " << strHex(sig) << std::endl;
auto const non = makeNonCanonical(sig);
log << "non-canon sig " << strHex(non) << std::endl;
{
auto const canonicality = ecdsaCanonicality(sig);
BEAST_EXPECT(canonicality);
BEAST_EXPECT(*canonicality == ECDSACanonicality::fullyCanonical);
}
{
auto const canonicality = ecdsaCanonicality(non);
BEAST_EXPECT(canonicality);
BEAST_EXPECT(*canonicality != ECDSACanonicality::fullyCanonical);
}
BEAST_EXPECT(verifyDigest(pk, digest, sig, false));
BEAST_EXPECT(verifyDigest(pk, digest, sig, true));
BEAST_EXPECT(verifyDigest(pk, digest, non, false));
BEAST_EXPECT(! verifyDigest(pk, digest, non, true));
}
*/
// Ensure that verification does the right thing with
// respect to the matrix of canonicality variables.
void
testCanonicality()
{
testcase ("secp256k1 canonicality");
#if 0
makeCanonicalityTestVectors();
#else
auto const digest = hex_to_digest("34C19028C80D21F3F48C9354895F8D5BF0D5EE7FF457647CF655F5530A3022A7");
auto const pk = hex_to_pk("025096EB12D3E924234E7162369C11D8BF877EDA238778E7A31FF0AAC5D0DBCF37");
auto const sk = hex_to_sk("AA921417E7E5C299DA4EEC16D1CAA92F19B19F2A68511F68EC73BBB2F5236F3D");
auto const sig = hex_to_sig("3045022100B49D07F0E934BA468C0EFC78117791408D1FB8B63A6492AD395AC2F360F246600220508739DB0A2EF81676E39F459C8BBB07A09C3E9F9BEB696294D524D479D62740");
auto const non = hex_to_sig("3046022100B49D07F0E934BA468C0EFC78117791408D1FB8B63A6492AD395AC2F360F24660022100AF78C624F5D107E9891C60BA637444F71A129E47135D36D92AFD39B856601A01");
{
auto const canonicality = ecdsaCanonicality(sig);
BEAST_EXPECT(canonicality);
BEAST_EXPECT(*canonicality == ECDSACanonicality::fullyCanonical);
}
{
auto const canonicality = ecdsaCanonicality(non);
BEAST_EXPECT(canonicality);
BEAST_EXPECT(*canonicality != ECDSACanonicality::fullyCanonical);
}
BEAST_EXPECT(verifyDigest(pk, digest, sig, false));
BEAST_EXPECT(verifyDigest(pk, digest, sig, true));
BEAST_EXPECT(verifyDigest(pk, digest, non, false));
BEAST_EXPECT(! verifyDigest(pk, digest, non, true));
#endif
}
void testDigestSigning() void testDigestSigning()
{ {
testcase ("secp256k1 digest"); testcase ("secp256k1 digest");
@@ -279,6 +458,7 @@ public:
testBase58(); testBase58();
testDigestSigning(); testDigestSigning();
testMiscOperations(); testMiscOperations();
testCanonicality();
testcase ("secp256k1"); testcase ("secp256k1");
testSigning(KeyType::secp256k1); testSigning(KeyType::secp256k1);