BitShares-Core  5.0.0
BitShares blockchain implementation and command-line interface software
elliptic_secp256k1.cpp
Go to the documentation of this file.
1 #include <fc/crypto/elliptic.hpp>
2 
3 #include <fc/crypto/base58.hpp>
4 #include <fc/crypto/hmac.hpp>
5 #include <fc/crypto/openssl.hpp>
6 #include <fc/crypto/sha512.hpp>
7 
8 #include <fc/fwd_impl.hpp>
10 #include <fc/log/logger.hpp>
11 
12 #include <assert.h>
13 #include <secp256k1.h>
14 
15 #if _WIN32
16 # include <malloc.h>
17 #endif
18 
19 #include "_elliptic_impl_priv.hpp"
20 
21 namespace fc { namespace ecc {
22  namespace detail
23  {
24  const secp256k1_context_t* _get_context() {
25  static secp256k1_context_t* ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_RANGEPROOF | SECP256K1_CONTEXT_COMMIT );
26  return ctx;
27  }
28 
29  void _init_lib() {
30  static const secp256k1_context_t* ctx = _get_context();
31  (void)ctx;
32  static int init_o = init_openssl();
33  (void)init_o;
34  }
35 
36  class public_key_impl
37  {
38  public:
39  public_key_impl() BOOST_NOEXCEPT
40  {
41  _init_lib();
42  memset( _key.data(), 0, _key.size() );
43  }
44 
45  public_key_impl( const public_key_impl& cpy ) BOOST_NOEXCEPT
46  : _key( cpy._key )
47  {
48  _init_lib();
49  }
50 
52  };
53 
55  chr37 _derive_message( const public_key_data& key, int i );
56  fc::sha256 _left( const fc::sha512& v );
57  fc::sha256 _right( const fc::sha512& v );
58  const ec_group& get_curve();
61  } // detail
62 
63  static const public_key_data empty_pub = detail::public_key_impl()._key;
64  static const private_key_secret empty_priv;
65 
67  {
68  FC_ASSERT( my->_key != empty_priv );
69  FC_ASSERT( other.my->_key != empty_pub );
70  public_key_data pub(other.my->_key);
71  FC_ASSERT( secp256k1_ec_pubkey_tweak_mul( detail::_get_context(), pub.data(), pub.size(),
72  (unsigned char*) my->_key.data() ) );
73  return fc::sha512::hash( (char*) pub.data() + 1, pub.size() - 1 );
74  }
75 
76 
78 
79  public_key::public_key( const public_key &pk ) : my( pk.my ) {}
80 
81  public_key::public_key( public_key &&pk ) : my( std::move( pk.my ) ) {}
82 
84 
86  {
87  my = pk.my;
88  return *this;
89  }
90 
92  {
93  my = pk.my;
94  return *this;
95  }
96 
97  bool public_key::valid()const
98  {
99  return my->_key != empty_pub;
100  }
101 
103  {
104  FC_ASSERT( my->_key != empty_pub );
105  public_key_data new_key;
106  memcpy( new_key.data(), my->_key.data(), new_key.size() );
107  FC_ASSERT( secp256k1_ec_pubkey_tweak_add( detail::_get_context(), new_key.data(), new_key.size(),
108  (unsigned char*) digest.data() ) );
109  return public_key( new_key );
110  }
111 
112  std::string public_key::to_base58() const
113  {
114  FC_ASSERT( my->_key != empty_pub );
115  return to_base58( my->_key );
116  }
117 
119  {
120  FC_ASSERT( my->_key != empty_pub );
121  return my->_key;
122  }
123 
125  {
126  FC_ASSERT( my->_key != empty_pub );
128  unsigned int pk_len = my->_key.size();
129  memcpy( dat.data(), my->_key.data(), pk_len );
130  FC_ASSERT( secp256k1_ec_pubkey_decompress( detail::_get_context(), dat.data(), (int*) &pk_len ) );
131  FC_ASSERT( pk_len == dat.size() );
132  return dat;
133  }
134 
136  {
137  const unsigned char* front = dat.data();
138  if( *front == 0 ){}
139  else
140  {
141  EC_KEY *key = EC_KEY_new_by_curve_name( NID_secp256k1 );
142  key = o2i_ECPublicKey( &key, &front, sizeof(dat) );
143  FC_ASSERT( key );
144  EC_KEY_set_conv_form( key, POINT_CONVERSION_COMPRESSED );
145  unsigned char* buffer = my->_key.data();
146  i2o_ECPublicKey( key, &buffer ); // FIXME: questionable memory handling
147  EC_KEY_free( key );
148  }
149  }
150 
152  {
153  my->_key = dat;
154  }
155 
156  public_key::public_key( const compact_signature& c, const fc::sha256& digest, bool check_canonical )
157  {
158  int nV = c[0];
159  if (nV<27 || nV>=35)
160  FC_THROW_EXCEPTION( exception, "unable to reconstruct public key from signature" );
161 
162  if( check_canonical )
163  {
164  FC_ASSERT( is_canonical( c ), "signature is not canonical" );
165  }
166 
167  unsigned int pk_len;
168  FC_ASSERT( secp256k1_ecdsa_recover_compact( detail::_get_context(), (unsigned char*) digest.data(),
169  c.data() + 1, my->_key.data(), (int*) &pk_len, 1,
170  (*c.data() - 27) & 3 ) );
171  FC_ASSERT( pk_len == my->_key.size() );
172  }
173 
175  int child, int parent, uint8_t depth )
176  : public_key(k), c(c), child_num(child), parent_fp(parent), depth(depth) { }
177 
179  {
180  hmac_sha512 mac;
181  public_key_data key = serialize();
182  const detail::chr37 data = detail::_derive_message( key, i );
183  fc::sha512 l = mac.digest( c.data(), c.data_size(), (const char*) data.data(), data.size() );
184  fc::sha256 left = detail::_left(l);
186  FC_ASSERT( secp256k1_ec_pubkey_tweak_add( detail::_get_context(), key.data(), key.size(),
187  (unsigned char*) left.data() ) > 0 );
188  // FIXME: check validity - if left + key == infinity then invalid
189  extended_public_key result( key, detail::_right(l), i, fingerprint(), depth + 1 );
190  return result;
191  }
192 
194  int child, int parent, uint8_t depth )
195  : private_key(k), c(c), child_num(child), parent_fp(parent), depth(depth) { }
196 
197  extended_private_key extended_private_key::private_derive_rest( const fc::sha512& hash,
198  int i) const
199  {
200  fc::sha256 left = detail::_left(hash);
202  FC_ASSERT( secp256k1_ec_privkey_tweak_add( detail::_get_context(), (unsigned char*) left.data(), (unsigned char*) get_secret().data() ) > 0 );
204  i, fingerprint(), depth + 1 );
205  return result;
206  }
207 
208  commitment_type blind( const blind_factor_type& blind, uint64_t value )
209  {
210  commitment_type result;
211  FC_ASSERT( secp256k1_pedersen_commit( detail::_get_context(), result.data(), (unsigned char*) blind.data(), value ) );
212  return result;
213  }
214 
215  blind_factor_type blind_sum( const std::vector<blind_factor_type>& blinds_in, uint32_t non_neg )
216  {
217  blind_factor_type result;
218  std::vector<const unsigned char*> blinds(blinds_in.size());
219  for( uint32_t i = 0; i < blinds_in.size(); ++i ) blinds[i] = (unsigned char*) blinds_in[i].data();
220  FC_ASSERT( secp256k1_pedersen_blind_sum( detail::_get_context(), (unsigned char*) result.data(), blinds.data(), blinds_in.size(), non_neg ) );
221  return result;
222  }
223 
225  bool verify_sum( const std::vector<commitment_type>& commits_in, const std::vector<commitment_type>& neg_commits_in, int64_t excess )
226  {
227  std::vector<const unsigned char*> commits(commits_in.size());
228  for( uint32_t i = 0; i < commits_in.size(); ++i ) commits[i] = commits_in[i].data();
229  std::vector<const unsigned char*> neg_commits(neg_commits_in.size());
230  for( uint32_t i = 0; i < neg_commits_in.size(); ++i ) neg_commits[i] = neg_commits_in[i].data();
231 
232  return secp256k1_pedersen_verify_tally( detail::_get_context(), commits.data(), commits.size(), neg_commits.data(), neg_commits.size(), excess );
233  }
234 
235  bool verify_range( uint64_t& min_val, uint64_t& max_val, const commitment_type& commit, const std::vector<char>& proof )
236  {
237  return secp256k1_rangeproof_verify( detail::_get_context(), &min_val, &max_val, commit.data(), (const unsigned char*)proof.data(), proof.size() );
238  }
239 
240  std::vector<char> range_proof_sign( uint64_t min_value,
241  const commitment_type& commit,
242  const blind_factor_type& commit_blind,
243  const blind_factor_type& nonce,
244  int8_t base10_exp,
245  uint8_t min_bits,
246  uint64_t actual_value
247  )
248  {
249  int proof_len = 5134;
250  std::vector<char> proof(proof_len);
251 
252  FC_ASSERT( secp256k1_rangeproof_sign( detail::_get_context(),
253  (unsigned char*)proof.data(),
254  &proof_len, min_value,
255  commit.data(),
256  (unsigned char*) commit_blind.data(),
257  (unsigned char*) nonce.data(),
258  base10_exp, min_bits, actual_value ) );
259  proof.resize(proof_len);
260  return proof;
261  }
262 
263 
265  uint64_t& value_out,
266  string& message_out,
267  const blind_factor_type& nonce,
268  uint64_t& min_val,
269  uint64_t& max_val,
270  commitment_type commit,
271  const std::vector<char>& proof )
272  {
273  char msg[4096];
274  int mlen = 0;
275  FC_ASSERT( secp256k1_rangeproof_rewind( detail::_get_context(),
276  (unsigned char*) blind_out.data(),
277  &value_out,
278  (unsigned char*) msg,
279  &mlen,
280  (unsigned char*) nonce.data(),
281  &min_val,
282  &max_val,
283  commit.data(),
284  (const unsigned char*)proof.data(),
285  proof.size() ) );
286 
287  message_out = std::string( msg, mlen );
288  return true;
289  }
290 
291  range_proof_info range_get_info( const std::vector<char>& proof )
292  {
293  range_proof_info result;
294  FC_ASSERT( secp256k1_rangeproof_info( detail::_get_context(),
295  (int*)&result.exp,
296  (int*)&result.mantissa,
297  (uint64_t*)&result.min_value,
298  (uint64_t*)&result.max_value,
299  (const unsigned char*)proof.data(),
300  (int)proof.size() ) );
301 
302  return result;
303  }
304 
305 
306 } }
public_key_data serialize() const
bool verify_range(uint64_t &min_val, uint64_t &max_val, const commitment_type &commit, const range_proof_type &proof)
private_key_secret get_secret() const
const secp256k1_context_t * _get_context()
static constexpr size_t data_size()
Definition: sha256.hpp:21
bool verify_sum(const std::vector< commitment_type > &commits, const std::vector< commitment_type > &neg_commits, int64_t excess)
const ec_group & get_curve()
range_proof_info range_get_info(const range_proof_type &proof)
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 sha512 hash(const char *d, uint32_t dlen)
Definition: sha512.cpp:34
int init_openssl()
Definition: openssl.cpp:61
public_key & operator=(public_key &&pk)
extended_public_key(const public_key &k, const sha256 &c, int child=0, int parent_fp=0, uint8_t depth=0)
fc::sha256 _left(const fc::sha512 &v)
extended_public_key derive_normal_child(int i) const
H digest(const char *c, uint32_t c_len, const char *d, uint32_t d_len)
Definition: hmac.hpp:23
public_key add(const fc::sha256 &offset) const
public_key_impl(const public_key_impl &cpy) BOOST_NOEXCEPT
commitment_type blind(const blind_factor_type &blind, uint64_t value)
fc::sha256 digest(const T &value)
Definition: digest.hpp:9
char * data() const
Definition: sha256.cpp:29
contains only the public point of an elliptic curve key.
Definition: elliptic.hpp:35
fc::sha512 get_shared_secret(const public_key &pub) const
chr37 _derive_message(const public_key_data &key, int i)
#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)
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()
unsigned int fingerprint() const
Definition: elliptic.hpp:139
bool verify_range_proof_rewind(blind_factor_type &blind_out, uint64_t &value_out, string &message_out, const blind_factor_type &nonce, uint64_t &min_val, uint64_t &max_val, commitment_type commit, const range_proof_type &proof)
Defines exception&#39;s used by fc.
zero_initialized_array< unsigned char, 37 > chr37
range_proof_type range_proof_sign(uint64_t min_value, const commitment_type &commit, const blind_factor_type &commit_blind, const blind_factor_type &nonce, int8_t base10_exp, uint8_t min_bits, uint64_t actual_value)
blind_factor_type blind_sum(const std::vector< blind_factor_type > &blinds, uint32_t non_neg)
Definition: api.hpp:15
extended_private_key(const private_key &k, const sha256 &c, int child=0, int parent_fp=0, uint8_t depth=0)
public_key child(const fc::sha256 &offset) const
an elliptic curve private key.
Definition: elliptic.hpp:89
std::string to_base58() const
Allows to convert current public key object into base58 number.
public_key_point_data serialize_ecc_point() const