diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 6d57bf2b2..f4caa5027 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -152,17 +152,18 @@ inline h256 kFromMessage(h256 _msg, h256 _priv) return _msg ^ _priv; } -Signature dev::sign(Secret _k, h256 _message) +Signature dev::sign(Secret _k, h256 _hash) { int v = 0; secp256k1_start(); SignatureStruct ret; - h256 nonce = kFromMessage(_message, _k); + h256 nonce = kFromMessage(_hash, _k); - if (!secp256k1_ecdsa_sign_compact(_message.data(), 32, ret.r.data(), _k.data(), nonce.data(), &v)) + if (!secp256k1_ecdsa_sign_compact(_hash.data(), 32, ret.r.data(), _k.data(), nonce.data(), &v)) return Signature(); + #if ETH_ADDRESS_DEBUG cout << "---- SIGN -------------------------------" << endl; cout << "MSG: " << _message << endl; @@ -174,3 +175,21 @@ Signature dev::sign(Secret _k, h256 _message) ret.v = v; return *(Signature const*)&ret; } + +bool dev::verify(Public _p, Signature _s, h256 _hash) +{ + secp256k1_start(); + + // sig_t +// secp256k1_ecdsa_sig_t s; + int sz = sizeof(_s)-1; +// secp256k1_ecdsa_sig_serialize(_s.data()+1, &sz, &s); + + // pubk_t + byte pubkey[65] = {0x04}; + memcpy(&pubkey[1], _p.data(), 64); + +// int result = secp256k1_ecdsa_verify(_hash.data(), sizeof(_hash), &s, sizeof(s), pubkey, 65); + return 0; +} + diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 7f2a8192e..bd9a4fbd4 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -59,7 +59,7 @@ Address toAddress(Secret _secret); /// Encrypts plain text using Public key. void encrypt(Public _k, bytesConstRef _plain, bytes& o_cipher); - + /// Decrypts cipher using Secret key. bool decrypt(Secret _k, bytesConstRef _cipher, bytes& o_plaintext); @@ -67,7 +67,10 @@ bool decrypt(Secret _k, bytesConstRef _cipher, bytes& o_plaintext); Public recover(Signature _sig, h256 _message); /// Returns siganture of message hash. -Signature sign(Secret _k, h256 _message); +Signature sign(Secret _k, h256 _hash); + +/// Verify signature. +bool verify(Public _k, Signature _s, h256 _hash); /// Simple class that represents a "key pair". /// All of the data of the class can be regenerated from the secret key (m_secret) alone. diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index cabcfd45a..fa45e6242 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -25,12 +25,62 @@ using namespace dev; using namespace dev::crypto; using namespace CryptoPP; -ECP::Point pp::PointFromPublic(Public const& _p) +/// Conversion from bytes to cryptopp point +inline ECP::Point publicToPoint(Public const& _p); + +/// Conversion from bytes to cryptopp exponent +inline Integer secretToExponent(Secret const& _s); + +/// Conversion from cryptopp exponent Integer to bytes +inline void exponentToPublic(Integer const& _e, Public& _p); + +void pp::initializeSigner(Secret const& _s, ECDSA::Signer& _signer) +{ + _signer.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); + _signer.AccessKey().SetPrivateExponent(secretToExponent(_s)); +} + +void pp::initializeVerifier(Public const& _p, ECDSA::Verifier& _verifier) +{ + _verifier.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); + _verifier.AccessKey().SetPublicElement(publicToPoint(_p)); +} + +void pp::initializeEncryptor(Public const& _p, CryptoPP::ECIES::Encryptor& _encryptor) +{ + _encryptor.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); + _encryptor.AccessKey().SetPublicElement(publicToPoint(_p)); +} + +void pp::initializeDecryptor(Secret const& _s, CryptoPP::ECIES::Decryptor& _decryptor) +{ + _decryptor.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); + _decryptor.AccessKey().SetPrivateExponent(secretToExponent(_s)); +} + +void pp::exportPublicKey(CryptoPP::DL_PublicKey_EC const& _k, Public& _p) +{ + bytes prefixedKey(_k.GetGroupParameters().GetEncodedElementSize(true)); + _k.GetGroupParameters().GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false); + + static_assert(Public::size == 64, "Public key must be 64 bytes."); + assert(Public::size + 1 == _k.GetGroupParameters().GetEncodedElementSize(true)); + memcpy(_p.data(), &prefixedKey[1], Public::size); +} + +void pp::exportPrivateKey(CryptoPP::DL_PrivateKey_EC const& _k, Secret& _s) +{ + _k.GetPrivateExponent().Encode(_s.data(), Secret::size); +} + +/// Integer and Point Conversion: + +inline ECP::Point publicToPoint(Public const& _p) { ECP::Point p; CryptoPP::DL_PublicKey_EC pub; - pub.AccessGroupParameters().Initialize(pp::secp256k1()); - + pub.AccessGroupParameters().Initialize(pp::secp256k1Curve); + bytes prefixedKey(pub.GetGroupParameters().GetEncodedElementSize(true)); prefixedKey[0] = 0x04; assert(Public::size == prefixedKey.size() - 1); @@ -40,35 +90,20 @@ ECP::Point pp::PointFromPublic(Public const& _p) return std::move(p); } -Integer pp::ExponentFromSecret(Secret const& _s) +inline Integer secretToExponent(Secret const& _s) { static_assert(Secret::size == 32, "Secret key must be 32 bytes."); return std::move(Integer(_s.data(), Secret::size)); } -void pp::PublicFromExponent(Integer const& _e, Public& _p) +inline void exponentToPublic(Integer const& _e, Public& _p) { CryptoPP::DL_PrivateKey_EC k; - k.AccessGroupParameters().Initialize(secp256k1()); + k.AccessGroupParameters().Initialize(pp::secp256k1Curve); k.SetPrivateExponent(_e); - + CryptoPP::DL_PublicKey_EC p; - p.AccessGroupParameters().Initialize(secp256k1()); + p.AccessGroupParameters().Initialize(pp::secp256k1Curve); k.MakePublicKey(p); - pp::PublicFromDL_PublicKey_EC(p, _p); -} - -void pp::PublicFromDL_PublicKey_EC(CryptoPP::DL_PublicKey_EC const& _k, Public& _p) -{ - bytes prefixedKey(_k.GetGroupParameters().GetEncodedElementSize(true)); - _k.GetGroupParameters().GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false); - - static_assert(Public::size == 64, "Public key must be 64 bytes."); - assert(Public::size + 1 == _k.GetGroupParameters().GetEncodedElementSize(true)); - memcpy(_p.data(), &prefixedKey[1], Public::size); -} - -void pp::SecretFromDL_PrivateKey_EC(CryptoPP::DL_PrivateKey_EC const& _k, Secret& _s) -{ - _k.GetPrivateExponent().Encode(_s.data(), Secret::size); + pp::exportPublicKey(p, _p); } diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index d7e4181ee..87334b847 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -23,8 +23,6 @@ #pragma once -// need to leave this one disabled -//#pragma GCC diagnostic ignored "-Wunused-function" #pragma warning(push) #pragma warning(disable:4100 4244) #pragma GCC diagnostic push @@ -58,27 +56,31 @@ namespace crypto namespace pp { -/// RNG used by CryptoPP -inline CryptoPP::AutoSeededRandomPool& PRNG() { static CryptoPP::AutoSeededRandomPool prng; return prng; } -/// EC curve used by CryptoPP -inline CryptoPP::OID const& secp256k1() { static CryptoPP::OID curve = CryptoPP::ASN1::secp256k1(); return curve; } - -/// Conversion from bytes to cryptopp point -CryptoPP::ECP::Point PointFromPublic(Public const& _p); +/// CryptoPP random number pool +static CryptoPP::AutoSeededRandomPool PRNG; + +/// CryptoPP EC Cruve +static const CryptoPP::OID secp256k1Curve = CryptoPP::ASN1::secp256k1(); -/// Conversion from bytes to cryptopp exponent -CryptoPP::Integer ExponentFromSecret(Secret const& _s); +/// Initialize signer +void initializeSigner(Secret const& _s, CryptoPP::ECDSA::Signer& out_signer); + +/// Initialize verifier +void initializeVerifier(Public const& _p, CryptoPP::ECDSA::Verifier& _verifier); -/// Conversion from cryptopp exponent Integer to bytes -void PublicFromExponent(CryptoPP::Integer const& _k, Public& _s); +/// Conversion from Public key to cryptopp encryptor +void initializeEncryptor(Public const& _p, CryptoPP::ECIES::Encryptor& out_encryptor); +/// Conversion from Secret key to cryptopp decryptor +void initializeDecryptor(Secret const& _s, CryptoPP::ECIES::Decryptor& out_decryptor); + /// Conversion from cryptopp public key to bytes -void PublicFromDL_PublicKey_EC(CryptoPP::DL_PublicKey_EC const& _k, Public& _p); +void exportPublicKey(CryptoPP::DL_PublicKey_EC const& _k, Public& out_p); /// Conversion from cryptopp private key to bytes -void SecretFromDL_PrivateKey_EC(CryptoPP::DL_PrivateKey_EC const& _k, Secret& _s); - +void exportPrivateKey(CryptoPP::DL_PrivateKey_EC const& _k, Secret& out_s); + } } } diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index b38703ac3..d3c9d9c9f 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -42,32 +42,58 @@ using namespace dev; using namespace dev::crypto; using namespace CryptoPP; -void dev::crypto::encrypt(Public const& _key, bytes& io_cipher) +void crypto::encrypt(Public const& _key, bytes& io_cipher) { ECIES::Encryptor e; - e.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1()); - e.AccessKey().SetPublicElement(pp::PointFromPublic(_key)); + pp::initializeEncryptor(_key, e); size_t plen = io_cipher.size(); bytes c; c.resize(e.CiphertextLength(plen)); // todo: use StringSource with _plain as input and output. - e.Encrypt(pp::PRNG(), io_cipher.data(), plen, c.data()); + e.Encrypt(pp::PRNG, io_cipher.data(), plen, c.data()); bzero(io_cipher.data(), io_cipher.size()); io_cipher = std::move(c); } -void dev::crypto::decrypt(Secret const& _k, bytes& io_text) +void crypto::decrypt(Secret const& _k, bytes& io_text) { CryptoPP::ECIES::Decryptor d; - d.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1()); - d.AccessKey().SetPrivateExponent(pp::ExponentFromSecret(_k)); + pp::initializeDecryptor(_k, d); size_t clen = io_text.size(); bytes p; p.resize(d.MaxPlaintextLength(io_text.size())); // todo: use StringSource with _c as input and output. - DecodingResult r = d.Decrypt(pp::PRNG(), io_text.data(), clen, p.data()); + DecodingResult r = d.Decrypt(pp::PRNG, io_text.data(), clen, p.data()); assert(r.messageLength); io_text.resize(r.messageLength); io_text = std::move(p); } +Signature crypto::sign(Secret const& _k, bytesConstRef _message) +{ + ECDSA::Signer signer; + pp::initializeSigner(_k, signer); + + string sigstr; + StringSource s(_message.toString(), true, new SignerFilter(pp::PRNG, signer, new StringSink(sigstr))); + FixedHash retsig((byte const*)sigstr.data(), Signature::ConstructFromPointer); + + /// eth signature: 65 bytes: r: [0, 32), s: [32, 64), v: 64. + return std::move(retsig); +} + +//Public crypto::recover(Signature _sig, bytesConstRef _message) +//{ +// +//} + +bool crypto::verify(Public _p, Signature _sig, bytesConstRef _message) +{ + ECDSA::Verifier verifier; + pp::initializeVerifier(_p, verifier); + // cryptopp signatures are 64 bytes + static_assert(sizeof(Signature) == 65, "Expected 65-byte signature."); + return verifier.VerifyMessage(_message.data(), _message.size(), _sig.data(), sizeof(Signature) - 1); +} + + diff --git a/libdevcrypto/EC.h b/libdevcrypto/EC.h index cf6714faf..c7ce01ed0 100644 --- a/libdevcrypto/EC.h +++ b/libdevcrypto/EC.h @@ -35,7 +35,16 @@ void encrypt(Public const& _k, bytes& io_cipher); /// Decrypts text (in place). void decrypt(Secret const& _k, bytes& io_text); + +/// Returns siganture of message hash. +Signature sign(Secret const& _k, bytesConstRef _message); +/// Recovers Public key from signed message. +//Public recover(Signature _sig, bytesConstRef _message); + +/// Verify signature +bool verify(Public _p, Signature _sig, bytesConstRef _message); + } } diff --git a/libdevcrypto/SHA3MAC.cpp b/libdevcrypto/SHA3MAC.cpp index 5c74edd7e..1fa370ca1 100644 --- a/libdevcrypto/SHA3MAC.cpp +++ b/libdevcrypto/SHA3MAC.cpp @@ -28,10 +28,11 @@ using namespace dev; using namespace dev::crypto; using namespace CryptoPP; -void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) +void crypto::sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) { CryptoPP::SHA3_256 ctx; - ctx.Update((byte*)_secret.data(), _secret.size()); + if (_secret.size() > 0) + ctx.Update((byte*)_secret.data(), _secret.size()); ctx.Update((byte*)_plain.data(), _plain.size()); assert(_output.size() >= 32); ctx.Final(_output.data()); diff --git a/test/crypto.cpp b/test/crypto.cpp index 0d3b6202f..187ca6c79 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "TestHelperCrypto.h" using namespace std; @@ -57,96 +58,81 @@ BOOST_AUTO_TEST_CASE(common_encrypt_decrypt) BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) { - ECIES::Decryptor d(pp::PRNG(), pp::secp256k1()); + ECIES::Decryptor d(pp::PRNG, pp::secp256k1Curve); ECIES::Encryptor e(d.GetKey()); Secret s; - pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s); + pp::exportPrivateKey(d.GetKey(), s); Public p; - pp::PublicFromDL_PublicKey_EC(e.GetKey(), p); + pp::exportPublicKey(e.GetKey(), p); assert(dev::toAddress(s) == right160(dev::sha3(p.ref()))); Secret previous = s; for (auto i = 0; i < 30; i++) { - ECIES::Decryptor d(pp::PRNG(), pp::secp256k1()); + ECIES::Decryptor d(pp::PRNG, pp::secp256k1Curve); ECIES::Encryptor e(d.GetKey()); Secret s; - pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s); + pp::exportPrivateKey(d.GetKey(), s); assert(s != previous); Public p; - pp::PublicFromDL_PublicKey_EC(e.GetKey(), p); + pp::exportPublicKey(e.GetKey(), p); assert(dev::toAddress(s) == right160(dev::sha3(p.ref()))); } } -BOOST_AUTO_TEST_CASE(cryptopp_keys_cryptor_sipaseckp256k1) +BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) { KeyPair k = KeyPair::create(); Secret s = k.sec(); - - // Convert secret to exponent used by pp - Integer e = pp::ExponentFromSecret(s); - // Test that exported DL_EC private is same as exponent from Secret - CryptoPP::DL_PrivateKey_EC privatek; - privatek.AccessGroupParameters().Initialize(pp::secp256k1()); - privatek.SetPrivateExponent(e); - assert(e == privatek.GetPrivateExponent()); + string emptystr(""), msgstr("test"); + bytesConstRef empty(emptystr), msg(msgstr); - // Test that exported secret is same as decryptor(privatek) secret - ECIES::Decryptor d; - d.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1()); - d.AccessKey().SetPrivateExponent(e); - assert(d.AccessKey().GetPrivateExponent() == e); + // sha3 output of strings are the same + h256 hashpp; + sha3mac(empty, msg, hashpp.ref()); + assert(sha3(msg) == hashpp); + + // cryptopp sign and verify + Signature sigpp = crypto::sign(s, msg); + cout << std::hex << sigpp << endl; + + ECDSA::Verifier verifier; + pp::initializeVerifier(k.pub(), verifier); + assert(verifier.VerifyMessage(msg.data(), msgstr.size(), sigpp.data(), sizeof(Signature))); + + // seckp256k1lib sign and verify + h256 hashed(sha3(h256().asBytes())); + Signature sig = dev::sign(s, hashed); + Public recoveredp = dev::recover(sig, hashed); + bool result = dev::verify(k.pub(), sig, hashed); +// assert(result); + - // Test that decryptor->encryptor->public == private->makepublic->public - CryptoPP::DL_PublicKey_EC pubk; - pubk.AccessGroupParameters().Initialize(pp::secp256k1()); - privatek.MakePublicKey(pubk); - ECIES::Encryptor enc(d); - assert(pubk.GetPublicElement() == enc.AccessKey().GetPublicElement()); - // Test against sipa/seckp256k1 - Public p; - pp::PublicFromExponent(pp::ExponentFromSecret(s), p); - assert(toAddress(s) == dev::right160(dev::sha3(p.ref()))); - assert(k.pub() == p); } BOOST_AUTO_TEST_CASE(cryptopp_public_export_import) { - ECIES::Decryptor d(pp::PRNG(), pp::secp256k1()); + ECIES::Decryptor d(pp::PRNG, pp::secp256k1Curve); ECIES::Encryptor e(d.GetKey()); Secret s; - pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s); + pp::exportPrivateKey(d.GetKey(), s); Public p; - pp::PublicFromDL_PublicKey_EC(e.GetKey(), p); + pp::exportPublicKey(e.GetKey(), p); Address addr = right160(dev::sha3(p.ref())); assert(toAddress(s) == addr); KeyPair l(s); assert(l.address() == addr); - - DL_PublicKey_EC pub; - pub.Initialize(pp::secp256k1(), pp::PointFromPublic(p)); - assert(pub.GetPublicElement() == e.GetKey().GetPublicElement()); - - KeyPair k = KeyPair::create(); - Public p2; - pp::PublicFromExponent(pp::ExponentFromSecret(k.sec()), p2); - assert(k.pub() == p2); - - Address a = k.address(); - Address a2 = toAddress(k.sec()); - assert(a2 == a); } BOOST_AUTO_TEST_CASE(ecies_eckeypair) @@ -172,9 +158,6 @@ BOOST_AUTO_TEST_CASE(ecdhe_aes128_ctr_sha3mac) // All connections should share seed for PRF (or PRNG) for nonces - - - } BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) @@ -183,7 +166,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) string const message("Now is the time for all good persons to come to the aide of humanity."); - ECIES::Decryptor localDecryptor(pp::PRNG(), pp::secp256k1()); + ECIES::Decryptor localDecryptor(pp::PRNG, pp::secp256k1Curve); SavePrivateKey(localDecryptor.GetPrivateKey()); ECIES::Encryptor localEncryptor(localDecryptor); @@ -191,31 +174,31 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) ECIES::Decryptor futureDecryptor; LoadPrivateKey(futureDecryptor.AccessPrivateKey()); - futureDecryptor.GetPrivateKey().ThrowIfInvalid(pp::PRNG(), 3); + futureDecryptor.GetPrivateKey().ThrowIfInvalid(pp::PRNG, 3); ECIES::Encryptor futureEncryptor; LoadPublicKey(futureEncryptor.AccessPublicKey()); - futureEncryptor.GetPublicKey().ThrowIfInvalid(pp::PRNG(), 3); + futureEncryptor.GetPublicKey().ThrowIfInvalid(pp::PRNG, 3); // encrypt/decrypt with local string cipherLocal; - StringSource ss1 (message, true, new PK_EncryptorFilter(pp::PRNG(), localEncryptor, new StringSink(cipherLocal) ) ); + StringSource ss1 (message, true, new PK_EncryptorFilter(pp::PRNG, localEncryptor, new StringSink(cipherLocal) ) ); string plainLocal; - StringSource ss2 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG(), localDecryptor, new StringSink(plainLocal) ) ); + StringSource ss2 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG, localDecryptor, new StringSink(plainLocal) ) ); // encrypt/decrypt with future string cipherFuture; - StringSource ss3 (message, true, new PK_EncryptorFilter(pp::PRNG(), futureEncryptor, new StringSink(cipherFuture) ) ); + StringSource ss3 (message, true, new PK_EncryptorFilter(pp::PRNG, futureEncryptor, new StringSink(cipherFuture) ) ); string plainFuture; - StringSource ss4 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG(), futureDecryptor, new StringSink(plainFuture) ) ); + StringSource ss4 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG, futureDecryptor, new StringSink(plainFuture) ) ); // decrypt local w/future string plainFutureFromLocal; - StringSource ss5 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG(), futureDecryptor, new StringSink(plainFutureFromLocal) ) ); + StringSource ss5 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG, futureDecryptor, new StringSink(plainFutureFromLocal) ) ); // decrypt future w/local string plainLocalFromFuture; - StringSource ss6 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG(), localDecryptor, new StringSink(plainLocalFromFuture) ) ); + StringSource ss6 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG, localDecryptor, new StringSink(plainLocalFromFuture) ) ); assert(plainLocal == message);