BitShares-Core  5.0.0
BitShares blockchain implementation and command-line interface software
elliptic_common.cpp
Go to the documentation of this file.
1 #include <fc/crypto/base58.hpp>
2 #include <fc/crypto/elliptic.hpp>
3 #include <fc/io/raw.hpp>
4 #include <fc/crypto/hmac.hpp>
5 #include <fc/crypto/openssl.hpp>
7 
8 #ifdef _WIN32
9 # include <malloc.h>
10 #endif
11 
12 /* stuff common to all ecc implementations */
13 
14 #define BTC_EXT_PUB_MAGIC (0x0488B21E)
15 #define BTC_EXT_PRIV_MAGIC (0x0488ADE4)
16 
17 namespace fc { namespace ecc {
18 
19  namespace detail {
21 
23  {
24  fc::sha256 result;
25  memcpy( result.data(), v.data(), 32 );
26  return result;
27  }
28 
30  {
31  fc::sha256 result;
32  memcpy( result.data(), v.data() + 32, 32 );
33  return result;
34  }
35 
36  static void _put( unsigned char** dest, unsigned int i)
37  {
38  *(*dest)++ = (i >> 24) & 0xff;
39  *(*dest)++ = (i >> 16) & 0xff;
40  *(*dest)++ = (i >> 8) & 0xff;
41  *(*dest)++ = i & 0xff;
42  }
43 
44  static unsigned int _get( unsigned char** src )
45  {
46  unsigned int result = *(*src)++ << 24;
47  result |= *(*src)++ << 16;
48  result |= *(*src)++ << 8;
49  result |= *(*src)++;
50  return result;
51  }
52 
53  static chr37 _derive_message( unsigned char first, const unsigned char* key32, int i )
54  {
55  chr37 result;
56  unsigned char* dest = result.data();
57  *dest++ = first;
58  memcpy( dest, key32, 32 ); dest += 32;
59  _put( &dest, i );
60  return result;
61  }
62 
63  chr37 _derive_message( const public_key_data& key, int i )
64  {
65  return _derive_message( *key.data(), key.data() + 1, i );
66  }
67 
68  static chr37 _derive_message( const private_key_secret& key, int i )
69  {
70  return _derive_message( 0, (unsigned char*) key.data(), i );
71  }
72 
73  const ec_group& get_curve()
74  {
75  static const ec_group secp256k1( EC_GROUP_new_by_curve_name( NID_secp256k1 ) );
76  return secp256k1;
77  }
78 
79  static private_key_secret _get_curve_order()
80  {
81  const ec_group& group = get_curve();
82  bn_ctx ctx(BN_CTX_new());
83  ssl_bignum order;
84  FC_ASSERT( EC_GROUP_get_order( group, order, ctx ) );
86  FC_ASSERT( (size_t) BN_num_bytes( order ) == bin.data_size() );
87  FC_ASSERT( (size_t) BN_bn2bin( order, (unsigned char*) bin.data() ) == bin.data_size() );
88  return bin;
89  }
90 
92  {
93  static private_key_secret order = _get_curve_order();
94  return order;
95  }
96 
97  static private_key_secret _get_half_curve_order()
98  {
99  const ec_group& group = get_curve();
100  bn_ctx ctx(BN_CTX_new());
101  ssl_bignum order;
102  FC_ASSERT( EC_GROUP_get_order( group, order, ctx ) );
103  BN_rshift1( order, order );
104  private_key_secret bin;
105  FC_ASSERT( (size_t) BN_num_bytes( order ) == bin.data_size() );
106  FC_ASSERT( (size_t) BN_bn2bin( order, (unsigned char*) bin.data() ) == bin.data_size() );
107  return bin;
108  }
109 
111  {
112  static private_key_secret half_order = _get_half_curve_order();
113  return half_order;
114  }
115  }
116 
117  public_key public_key::from_key_data( const public_key_data &data ) {
118  return public_key(data);
119  }
120 
122  {
124  fc::raw::pack( enc, *this );
125  fc::raw::pack( enc, offset );
126 
127  return add( enc.result() );
128  }
129 
131  {
133  fc::raw::pack( enc, get_public_key() );
134  fc::raw::pack( enc, offset );
135  return generate_from_seed( get_secret(), enc.result() );
136  }
137 
138  std::string public_key::to_base58( const public_key_data &key )
139  {
140  sha256 check = sha256::hash((char*) key.data(), sizeof(key));
141  static_assert(sizeof(key) + 4 == 37, "Elliptic public key size (or its hash) is incorrect");
142  detail::chr37 data;
143  memcpy(data.data(), key.data(), key.size());
144  memcpy(data.data() + key.size(), (const char*)check._hash, 4);
145  return fc::to_base58((char*) data.data(), data.size());
146  }
147 
148  public_key public_key::from_base58( const std::string& b58 )
149  {
150  detail::chr37 data;
151  size_t s = fc::from_base58(b58, (char*)&data, sizeof(data) );
152  FC_ASSERT( s == sizeof(data) );
153 
154  public_key_data key;
155  sha256 check = sha256::hash((char*) data.data(), sizeof(key));
156  FC_ASSERT( memcmp( (char*)check._hash, data.data() + key.size(), 4 ) == 0 );
157  memcpy( (char*)key.data(), data.data(), key.size() );
158  return from_key_data(key);
159  }
160 
161  unsigned int public_key::fingerprint() const
162  {
163  public_key_data key = serialize();
164  ripemd160 hash = ripemd160::hash( sha256::hash( (char*) key.data(), key.size() ) );
165  unsigned char* fp = (unsigned char*) hash._hash;
166  return (fp[0] << 24) | (fp[1] << 16) | (fp[2] << 8) | fp[3];
167  }
168 
169  bool public_key::is_canonical( const compact_signature& c ) {
170  return !(c[1] & 0x80)
171  && !(c[1] == 0 && !(c[2] & 0x80))
172  && !(c[33] & 0x80)
173  && !(c[33] == 0 && !(c[34] & 0x80));
174  }
175 
177  {
178  ssl_bignum z;
179  BN_bin2bn((unsigned char*)&offset, sizeof(offset), z);
180 
181  ec_group group(EC_GROUP_new_by_curve_name(NID_secp256k1));
182  bn_ctx ctx(BN_CTX_new());
183  ssl_bignum order;
184  EC_GROUP_get_order(group, order, ctx);
185 
186  // secexp = (seed + z) % order
187  ssl_bignum secexp;
188  BN_bin2bn((unsigned char*)&seed, sizeof(seed), secexp);
189  BN_add(secexp, secexp, z);
190  BN_mod(secexp, secexp, order, ctx);
191 
192  fc::sha256 secret;
193  FC_ASSERT(BN_num_bytes(secexp) <= int64_t(sizeof(secret)));
194  auto shift = sizeof(secret) - BN_num_bytes(secexp);
195  BN_bn2bin(secexp, ((unsigned char*)&secret)+shift);
196  return regenerate( secret );
197  }
198 
199  fc::sha256 private_key::get_secret( const EC_KEY * const k )
200  {
201  if( !k )
202  {
203  return fc::sha256();
204  }
205 
206  fc::sha256 sec;
207  const BIGNUM* bn = EC_KEY_get0_private_key(k);
208  if( bn == NULL )
209  {
210  FC_THROW_EXCEPTION( exception, "get private key failed" );
211  }
212  int nbytes = BN_num_bytes(bn);
213  BN_bn2bin(bn, &((unsigned char*)&sec)[32-nbytes] );
214  return sec;
215  }
216 
218  {
219  EC_KEY* k = EC_KEY_new_by_curve_name( NID_secp256k1 );
220  if( !k ) FC_THROW_EXCEPTION( exception, "Unable to generate EC key" );
221  if( !EC_KEY_generate_key( k ) )
222  {
223  FC_THROW_EXCEPTION( exception, "ecc key generation error" );
224 
225  }
226 
227  return private_key( k );
228  }
229 
230  static std::string _to_base58( const extended_key_data& key )
231  {
232  char buffer[std::tuple_size<extended_key_data>::value + 4]; // it's a small static array => allocate on stack
233  memcpy( buffer, key.data(), key.size() );
234  fc::sha256 double_hash = fc::sha256::hash( fc::sha256::hash( (char*)key.data(), key.size() ));
235  memcpy( buffer + key.size(), double_hash.data(), 4 );
236  return fc::to_base58( buffer, sizeof(buffer) );
237  }
238 
239  static void _parse_extended_data( unsigned char* buffer, std::string base58 )
240  {
241  memset( buffer, 0, 78 );
242  std::vector<char> decoded = fc::from_base58( base58 );
243  unsigned int i = 0;
244  for ( char c : decoded )
245  {
246  if ( i >= 78 || i > decoded.size() - 4 ) { break; }
247  buffer[i++] = c;
248  }
249  }
250 
252  {
253  FC_ASSERT( !(i&0x80000000), "Can't derive hardened public key!" );
254  return derive_normal_child(i);
255  }
256 
258  {
259  extended_key_data result;
260  unsigned char* dest = (unsigned char*) result.data();
261  detail::_put( &dest, BTC_EXT_PUB_MAGIC );
262  *dest++ = depth;
263  detail::_put( &dest, parent_fp );
264  detail::_put( &dest, child_num );
265  memcpy( dest, c.data(), c.data_size() ); dest += 32;
266  public_key_data key = serialize();
267  memcpy( dest, key.data(), key.size() );
268  return result;
269  }
270 
272  {
273  return from_base58( _to_base58( data ) );
274  }
275 
276  std::string extended_public_key::str() const
277  {
278  return _to_base58( serialize_extended() );
279  }
280 
282  {
283  unsigned char buffer[78];
284  unsigned char* ptr = buffer;
285  _parse_extended_data( buffer, base58 );
286  FC_ASSERT( detail::_get( &ptr ) == BTC_EXT_PUB_MAGIC, "Invalid extended private key" );
287  uint8_t d = *ptr++;
288  int fp = detail::_get( &ptr );
289  int cn = detail::_get( &ptr );
290  fc::sha256 chain;
291  memcpy( chain.data(), ptr, chain.data_size() ); ptr += chain.data_size();
292  public_key_data key;
293  memcpy( key.data(), ptr, key.size() );
294  return extended_public_key( key, chain, cn, fp, d );
295  }
296 
298  {
299  return extended_public_key( get_public_key(), c, child_num, parent_fp, depth );
300  }
301 
303  {
304  return i < 0 ? derive_hardened_child(i) : derive_normal_child(i);
305  }
306 
308  {
309  const detail::chr37 data = detail::_derive_message( get_public_key().serialize(), i );
310  hmac_sha512 mac;
311  fc::sha512 l = mac.digest( c.data(), c.data_size(), (char*) data.data(), data.size() );
312  return private_derive_rest( l, i );
313  }
314 
316  {
317  hmac_sha512 mac;
318  private_key_secret key = get_secret();
319  const detail::chr37 data = detail::_derive_message( key, i );
320  fc::sha512 l = mac.digest( c.data(), c.data_size(), (char*) data.data(), data.size() );
321  return private_derive_rest( l, i );
322  }
323 
325  {
326  extended_key_data result;
327  unsigned char* dest = (unsigned char*) result.data();
328  detail::_put( &dest, BTC_EXT_PRIV_MAGIC );
329  *dest++ = depth;
330  detail::_put( &dest, parent_fp );
331  detail::_put( &dest, child_num );
332  memcpy( dest, c.data(), c.data_size() ); dest += 32;
333  *dest++ = 0;
334  private_key_secret key = get_secret();
335  memcpy( dest, key.data(), key.data_size() );
336  return result;
337  }
338 
340  {
341  return from_base58( _to_base58( data ) );
342  }
343 
344  std::string extended_private_key::str() const
345  {
346  return _to_base58( serialize_extended() );
347  }
348 
350  {
351  unsigned char buffer[78];
352  unsigned char* ptr = buffer;
353  _parse_extended_data( buffer, base58 );
354  FC_ASSERT( detail::_get( &ptr ) == BTC_EXT_PRIV_MAGIC, "Invalid extended private key" );
355  uint8_t d = *ptr++;
356  int fp = detail::_get( &ptr );
357  int cn = detail::_get( &ptr );
358  fc::sha256 chain;
359  memcpy( chain.data(), ptr, chain.data_size() ); ptr += chain.data_size();
360  ptr++;
361  private_key_secret key;
362  memcpy( key.data(), ptr, key.data_size() );
363  return extended_private_key( private_key::regenerate(key), chain, cn, fp, d );
364  }
365 
367  {
368  return generate_master( seed.c_str(), seed.size() );
369  }
370 
371  extended_private_key extended_private_key::generate_master( const char* seed, uint32_t seed_len )
372  {
373  hmac_sha512 mac;
374  fc::sha512 hash = mac.digest( "Bitcoin seed", 12, seed, seed_len );
376  detail::_right(hash) );
377  return result;
378  }
379 }
380 
381 void to_variant( const ecc::private_key& var, variant& vo, uint32_t max_depth )
382 {
383  to_variant( var.get_secret(), vo, max_depth );
384 }
385 
386 void from_variant( const variant& var, ecc::private_key& vo, uint32_t max_depth )
387 {
388  fc::sha256 sec;
389  from_variant( var, sec, max_depth );
391 }
392 
393 void to_variant( const ecc::public_key& var, variant& vo, uint32_t max_depth )
394 {
395  to_variant( var.serialize(), vo, max_depth );
396 }
397 
398 void from_variant( const variant& var, ecc::public_key& vo, uint32_t max_depth )
399 {
401  from_variant( var, dat, max_depth );
402  vo = ecc::public_key(dat);
403 }
404 
405 }
boost::endian::little_uint32_buf_t _hash[5]
Definition: ripemd160.hpp:71
#define BTC_EXT_PRIV_MAGIC
extended_key_data serialize_extended() const
public_key_data serialize() const
static extended_public_key deserialize(const extended_key_data &data)
extended_key_data serialize_extended() const
std::string to_base58(const char *d, size_t s)
Definition: base58.cpp:612
private_key_secret get_secret() const
void pack(Stream &s, const flat_set< T, A... > &value, uint32_t _max_depth)
Definition: flat.hpp:11
static constexpr size_t data_size()
Definition: sha256.hpp:21
const ec_group & get_curve()
extended_private_key derive_normal_child(int i) const
private_key child(const fc::sha256 &offset) const
extended_public_key get_extended_public_key() const
Used to generate a useful error report when an exception is thrown.At each level in the stack where t...
Definition: exception.hpp:56
const private_key_secret & get_half_curve_order()
static ripemd160 hash(const fc::sha512 &h)
Definition: ripemd160.cpp:43
extended_private_key derive_child(int i) const
fc::sha256 _left(const fc::sha512 &v)
sha256 result()
Definition: sha256.cpp:59
extended_public_key derive_child(int i) const
H digest(const char *c, uint32_t c_len, const char *d, uint32_t d_len)
Definition: hmac.hpp:23
static sha256 hash(const char *d, uint32_t dlen)
Definition: sha256.cpp:41
boost::endian::little_uint64_buf_t _hash[4]
Definition: sha256.hpp:71
char * data() const
Definition: sha256.cpp:29
static private_key generate()
void to_variant(const flat_set< T, A... > &var, variant &vo, uint32_t _max_depth)
Definition: flat.hpp:105
contains only the public point of an elliptic curve key.
Definition: elliptic.hpp:35
char * data() const
Definition: sha512.cpp:22
static extended_private_key deserialize(const extended_key_data &data)
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
fc::sha256 _right(const fc::sha512 &v)
static extended_public_key from_base58(const std::string &base58)
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object&#39;s.
Definition: variant.hpp:198
unsigned int fingerprint() const
static private_key regenerate(const fc::sha256 &secret)
#define FC_THROW_EXCEPTION(EXCEPTION, FORMAT,...)
Definition: exception.hpp:378
const private_key_secret & get_curve_order()
at< List, 0 > first
Get the type at the beginning of the list.
Definition: typelist.hpp:190
zero_initialized_array< unsigned char, 37 > chr37
extended_private_key derive_hardened_child(int i) const
static private_key generate_from_seed(const fc::sha256 &seed, const fc::sha256 &offset=fc::sha256())
void from_variant(const variant &var, flat_set< T, A... > &vo, uint32_t _max_depth)
Definition: flat.hpp:116
bignum_st BIGNUM
Definition: bigint.hpp:6
std::vector< char > from_base58(const std::string &base58_str)
Definition: base58.cpp:622
#define BTC_EXT_PUB_MAGIC
Definition: api.hpp:15
static extended_private_key generate_master(const std::string &seed)
static public_key from_base58(const std::string &b58)
public_key child(const fc::sha256 &offset) const
an elliptic curve private key.
Definition: elliptic.hpp:89
static extended_private_key from_base58(const std::string &base58)
std::string to_base58() const
Allows to convert current public key object into base58 number.