private_key.cpp 5.3 KB
Newer Older
1 2
#include <fc/crypto/private_key.hpp>
#include <fc/utility.hpp>
B
Bart Wyatt 已提交
3
#include <fc/exception/exception.hpp>
4 5

namespace fc { namespace crypto {
B
Bart Wyatt 已提交
6 7 8
   using namespace std;

   struct public_key_visitor : visitor<public_key::storage_type> {
9
      template<typename KeyType>
B
Bart Wyatt 已提交
10
      public_key::storage_type operator()(const KeyType& key) const
11
      {
B
Bart Wyatt 已提交
12
         return public_key::storage_type(key.get_public_key());
13 14 15 16 17
      }
   };

   public_key private_key::get_public_key() const
   {
B
Bart Wyatt 已提交
18
      return public_key(_storage.visit(public_key_visitor()));
19 20
   }

B
Bart Wyatt 已提交
21
   struct sign_visitor : visitor<signature::storage_type> {
22 23 24 25 26 27
      sign_visitor( const sha256& digest, bool require_canonical )
      :_digest(digest)
      ,_require_canonical(require_canonical)
      {}

      template<typename KeyType>
B
Bart Wyatt 已提交
28
      signature::storage_type operator()(const KeyType& key) const
29
      {
B
Bart Wyatt 已提交
30
         return signature::storage_type(key.sign(_digest, _require_canonical));
31 32 33 34 35 36 37 38
      }

      const sha256&  _digest;
      bool           _require_canonical;
   };

   signature private_key::sign( const sha256& digest, bool require_canonical ) const
   {
B
Bart Wyatt 已提交
39
      return signature(_storage.visit(sign_visitor(digest, require_canonical)));
40 41 42
   }

   struct generate_shared_secret_visitor : visitor<sha512> {
B
Bart Wyatt 已提交
43 44
      generate_shared_secret_visitor( const public_key::storage_type& pub_storage )
      :_pub_storage(pub_storage)
45 46 47
      {}

      template<typename KeyType>
B
Bart Wyatt 已提交
48
      sha512 operator()(const KeyType& key) const
49
      {
B
Bart Wyatt 已提交
50 51
         using PublicKeyType = typename KeyType::public_key_type;
         return key.generate_shared_secret(_pub_storage.template get<PublicKeyType>());
52 53
      }

B
Bart Wyatt 已提交
54
      const public_key::storage_type&  _pub_storage;
55 56 57 58
   };

   sha512 private_key::generate_shared_secret( const public_key& pub ) const
   {
B
Bart Wyatt 已提交
59
      return _storage.visit(generate_shared_secret_visitor(pub._storage));
60 61 62 63 64
   }

   template<typename Data>
   string to_wif( const Data& secret )
   {
B
Bart Wyatt 已提交
65
      const size_t size_of_data_to_hash = sizeof(typename Data::data_type) + 1;
66 67 68
      const size_t size_of_hash_bytes = 4;
      char data[size_of_data_to_hash + size_of_hash_bytes];
      data[0] = (char)0x80; // this is the Bitcoin MainNet code
B
Bart Wyatt 已提交
69
      memcpy(&data[1], (const char*)&secret.serialize(), sizeof(typename Data::data_type));
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
      sha256 digest = sha256::hash(data, size_of_data_to_hash);
      digest = sha256::hash(digest);
      memcpy(data + size_of_data_to_hash, (char*)&digest, size_of_hash_bytes);
      return to_base58(data, sizeof(data));
   }

   template<typename Data>
   Data from_wif( const string& wif_key )
   {
      auto wif_bytes = from_base58(wif_key);
      FC_ASSERT(wif_bytes.size() >= 5);
      auto key_bytes = vector<char>(wif_bytes.begin() + 1, wif_bytes.end() - 4);
      fc::sha256 check = fc::sha256::hash(wif_bytes.data(), wif_bytes.size() - 4);
      fc::sha256 check2 = fc::sha256::hash(check);

      FC_ASSERT(memcmp( (char*)&check, wif_bytes.data() + wif_bytes.size() - 4, 4 ) == 0 ||
                memcmp( (char*)&check2, wif_bytes.data() + wif_bytes.size() - 4, 4 ) == 0 );

B
Bart Wyatt 已提交
88
      return Data(fc::variant(key_bytes).as<typename Data::data_type>());
89 90 91 92
   }

   static private_key::storage_type parse_base58(const string& base58str)
   {
93
      if (base58str.find('_') == std::string::npos) {
94
         // wif import
B
Bart Wyatt 已提交
95 96
         using default_type = private_key::storage_type::template type_at<0>;
         return private_key::storage_type(from_wif<default_type>(base58str));
97 98 99
      } else {
         constexpr auto prefix = config::private_key_base_prefix;

100
         const auto pivot = base58str.find('_');
101
         FC_ASSERT(pivot != std::string::npos, "No delimiter in string, cannot determine type: ${str}", ("str", base58str));
102

103 104 105 106 107 108 109
         const auto prefix_str = base58str.substr(0, pivot);
         FC_ASSERT(prefix == prefix_str, "Private Key has invalid prefix: ${str}", ("str", base58str)("prefix_str", prefix_str));

         auto data_str = base58str.substr(pivot + 1);
         FC_ASSERT(!data_str.empty(), "Private Key has no data: ${str}", ("str", base58str));
         return base58_str_parser<private_key::storage_type, config::private_key_prefix>::apply(data_str);
      }
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
   }

   private_key::private_key(const std::string& base58str)
   :_storage(parse_base58(base58str))
   {}

   private_key::operator std::string() const
   {
      auto which = _storage.which();

      if (which == 0) {
         using default_type = storage_type::template type_at<0>;
         return to_wif(_storage.template get<default_type>());
      }

      auto data_str = _storage.visit(base58str_visitor<storage_type, config::private_key_prefix>());
126
      return std::string(config::private_key_base_prefix) + "_" + data_str;
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
   }

   std::ostream& operator<<(std::ostream& s, const private_key& k) {
      s << "private_key(" << std::string(k) << ')';
      return s;
   }

   bool operator == ( const private_key& p1, const private_key& p2) {
      return eq_comparator<private_key::storage_type>::apply(p1._storage, p2._storage);
   }

   bool operator < ( const private_key& p1, const private_key& p2)
   {
      return less_comparator<private_key::storage_type>::apply(p1._storage, p2._storage);
   }
} } // fc::crypto

namespace fc
{
   void to_variant(const fc::crypto::private_key& var, variant& vo)
   {
      vo = string(var);
   }

   void from_variant(const variant& var, fc::crypto::private_key& vo)
   {
      vo = fc::crypto::private_key(var.as_string());
   }

} // fc