Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
elliptic_em_impl_pub.cpp
Go to the documentation of this file.
1#include <fc/fwd_impl.hpp>
2#include <boost/config.hpp>
3
5
6/* used by mixed + openssl */
7
8namespace fc { namespace em {
9 namespace detail {
10
12 {
13 _init_lib();
14 }
15
17 {
18 _init_lib();
19 *this = cpy;
20 }
21
23 {
24 _init_lib();
25 *this = cpy;
26 }
27
29 {
30 free_key();
31 }
32
34 {
35 if (pk._key == nullptr)
36 {
37 free_key();
38 } else if ( _key == nullptr ) {
39 _key = EC_KEY_dup( pk._key );
40 } else {
41 EC_KEY_copy( _key, pk._key );
42 }
43 return *this;
44 }
45
47 {
48 if ( this != &pk ) {
49 free_key();
50 _key = pk._key;
51 pk._key = nullptr;
52 }
53 return *this;
54 }
55
56 void public_key_impl::free_key() BOOST_NOEXCEPT
57 {
58 if( _key != nullptr )
59 {
60 EC_KEY_free(_key);
61 _key = nullptr;
62 }
63 }
64
65 // Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields
66 // recid selects which key is recovered
67 // if check is non-zero, additional checks are performed
68 int public_key_impl::ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig,
69 const unsigned char *msg,
70 int msglen, int recid, int check)
71 {
72 if (!eckey) FC_THROW_EXCEPTION( exception, "null key" );
73
74 int ret = 0;
75 BN_CTX *ctx = NULL;
76
77 BIGNUM *x = NULL;
78 BIGNUM *e = NULL;
79 BIGNUM *order = NULL;
80 BIGNUM *sor = NULL;
81 BIGNUM *eor = NULL;
82 BIGNUM *field = NULL;
83 EC_POINT *R = NULL;
84 EC_POINT *O = NULL;
85 EC_POINT *Q = NULL;
86 BIGNUM *rr = NULL;
87 BIGNUM *zero = NULL;
88 int n = 0;
89 int i = recid / 2;
90
91 const EC_GROUP *group = EC_KEY_get0_group(eckey);
92 if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; }
93 BN_CTX_start(ctx);
94 order = BN_CTX_get(ctx);
95 if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; }
96 x = BN_CTX_get(ctx);
97 if (!BN_copy(x, order)) { ret=-1; goto err; }
98 if (!BN_mul_word(x, i)) { ret=-1; goto err; }
99 if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; }
100 field = BN_CTX_get(ctx);
101 if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; }
102 if (BN_cmp(x, field) >= 0) { ret=0; goto err; }
103 if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
104 if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; }
105 if (check)
106 {
107 if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
108 if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; }
109 if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; }
110 }
111 if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
112 n = EC_GROUP_get_degree(group);
113 e = BN_CTX_get(ctx);
114 if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; }
115 if (8*msglen > n) BN_rshift(e, e, 8-(n & 7));
116 zero = BN_CTX_get(ctx);
117 if (!BN_zero(zero)) { ret=-1; goto err; }
118 if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; }
119 rr = BN_CTX_get(ctx);
120 if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; }
121 sor = BN_CTX_get(ctx);
122 if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; }
123 eor = BN_CTX_get(ctx);
124 if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; }
125 if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; }
126 if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; }
127
128 ret = 1;
129
130 err:
131 if (ctx) {
132 BN_CTX_end(ctx);
133 BN_CTX_free(ctx);
134 }
135 if (R != NULL) EC_POINT_free(R);
136 if (O != NULL) EC_POINT_free(O);
137 if (Q != NULL) EC_POINT_free(Q);
138 return ret;
139 }
140 }
141
143
144 public_key::public_key( const public_key& pk ) : my( pk.my ) {}
145
146 public_key::public_key( public_key&& pk ) : my( std::move( pk.my ) ) {}
147
149
150 public_key& public_key::operator=( public_key&& pk )
151 {
152 my = std::move(pk.my);
153 return *this;
154 }
155
156 public_key& public_key::operator=( const public_key& pk )
157 {
158 my = pk.my;
159 return *this;
160 }
161
162 bool public_key::valid()const
163 {
164 return my->_key != nullptr;
165 }
166
167 /* WARNING! This implementation is broken, it is actually equivalent to
168 * public_key::add()!
169 */
170// public_key public_key::mult( const fc::sha256& digest ) const
171// {
172// // get point from this public key
173// const EC_POINT* master_pub = EC_KEY_get0_public_key( my->_key );
174// ec_group group(EC_GROUP_new_by_curve_name(NID_secp256k1));
175//
176// ssl_bignum z;
177// BN_bin2bn((unsigned char*)&digest, sizeof(digest), z);
178//
179// // multiply by digest
180// ssl_bignum one;
181// BN_one(one);
182// bn_ctx ctx(BN_CTX_new());
183//
184// ec_point result(EC_POINT_new(group));
185// EC_POINT_mul(group, result, z, master_pub, one, ctx);
186//
187// public_key rtn;
188// rtn.my->_key = EC_KEY_new_by_curve_name( NID_secp256k1 );
189// EC_KEY_set_public_key(rtn.my->_key,result);
190//
191// return rtn;
192// }
193 public_key public_key::add( const fc::sha256& digest )const
194 {
195 try {
196 ec_group group(EC_GROUP_new_by_curve_name(NID_secp256k1));
197 bn_ctx ctx(BN_CTX_new());
198
199 fc::bigint digest_bi( (char*)&digest, sizeof(digest) );
200
201 ssl_bignum order;
202 EC_GROUP_get_order(group, order, ctx);
203 if( digest_bi > fc::bigint(order) )
204 {
205 FC_THROW_EXCEPTION( exception, "digest > group order" );
206 }
207
208
210 const EC_POINT* digest_point = EC_KEY_get0_public_key( digest_key.my->_key );
211
212 // get point from this public key
213 const EC_POINT* master_pub = EC_KEY_get0_public_key( my->_key );
214
215// ssl_bignum z;
216// BN_bin2bn((unsigned char*)&digest, sizeof(digest), z);
217
218 // multiply by digest
219// ssl_bignum one;
220// BN_one(one);
221
222 ec_point result(EC_POINT_new(group));
223 EC_POINT_add(group, result, digest_point, master_pub, ctx);
224
225 if (EC_POINT_is_at_infinity(group, result))
226 {
227 FC_THROW_EXCEPTION( exception, "point at infinity" );
228 }
229
230
231 public_key rtn;
232 rtn.my->_key = EC_KEY_new_by_curve_name( NID_secp256k1 );
233 EC_KEY_set_public_key(rtn.my->_key,result);
234 return rtn;
235 } FC_RETHROW_EXCEPTIONS( debug, "digest: ${digest}", ("digest",digest) );
236 }
237
238 std::string public_key::to_base58() const
239 {
240 public_key_data key = serialize();
241 return to_base58( key );
242 }
243
244// signature private_key::sign( const fc::sha256& digest )const
245// {
246// unsigned int buf_len = ECDSA_size(my->_key);
248// signature sig;
249// assert( buf_len == sizeof(sig) );
250//
251// if( !ECDSA_sign( 0,
252// (const unsigned char*)&digest, sizeof(digest),
253// (unsigned char*)&sig, &buf_len, my->_key ) )
254// {
255// FC_THROW_EXCEPTION( exception, "signing error" );
256// }
257//
258//
259// return sig;
260// }
261// bool public_key::verify( const fc::sha256& digest, const fc::ecc::signature& sig )
262// {
263// return 1 == ECDSA_verify( 0, (unsigned char*)&digest, sizeof(digest), (unsigned char*)&sig, sizeof(sig), my->_key );
264// }
265
267 {
268 public_key_data dat;
269 if( !my->_key ) return dat;
270 EC_KEY_set_conv_form( my->_key, POINT_CONVERSION_COMPRESSED );
271 /*size_t nbytes = i2o_ECPublicKey( my->_key, nullptr ); */
272 /*assert( nbytes == 33 )*/
273 char* front = &dat.data[0];
274 i2o_ECPublicKey( my->_key, (unsigned char**)&front ); // FIXME: questionable memory handling
275 return dat;
276 /*
277 EC_POINT* pub = EC_KEY_get0_public_key( my->_key );
278 EC_GROUP* group = EC_KEY_get0_group( my->_key );
279 EC_POINT_get_affine_coordinates_GFp( group, pub, self.my->_pub_x.get(), self.my->_pub_y.get(), nullptr );
280 */
281 }
283 {
285 if( !my->_key ) return dat;
286 EC_KEY_set_conv_form( my->_key, POINT_CONVERSION_UNCOMPRESSED );
287 char* front = &dat.data[0];
288 i2o_ECPublicKey( my->_key, (unsigned char**)&front ); // FIXME: questionable memory handling
289 return dat;
290 }
291
293 {
294 const char* front = &dat.data[0];
295 if( *front == 0 ){}
296 else
297 {
298 my->_key = EC_KEY_new_by_curve_name( NID_secp256k1 );
299 my->_key = o2i_ECPublicKey( &my->_key, (const unsigned char**)&front, sizeof(dat) );
300 if( !my->_key )
301 {
302 FC_THROW_EXCEPTION( exception, "error decoding public key", ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
303 }
304 }
305 }
307 {
308 const char* front = &dat.data[0];
309 if( *front == 0 ){}
310 else
311 {
312 my->_key = EC_KEY_new_by_curve_name( NID_secp256k1 );
313 my->_key = o2i_ECPublicKey( &my->_key, (const unsigned char**)&front, sizeof(public_key_data) );
314 if( !my->_key )
315 {
316 FC_THROW_EXCEPTION( exception, "error decoding public key", ("s", ERR_error_string( ERR_get_error(), nullptr) ) );
317 }
318 }
319 }
320
321// bool private_key::verify( const fc::sha256& digest, const fc::ecc::signature& sig )
322// {
323// return 1 == ECDSA_verify( 0, (unsigned char*)&digest, sizeof(digest), (unsigned char*)&sig, sizeof(sig), my->_key );
324// }
325
326 public_key::public_key( const compact_signature& c, const fc::sha256& digest, bool check_canonical )
327 {
328 int nV = c.data[0];
329 if (nV<27 || nV>=35)
330 FC_THROW_EXCEPTION( exception, "unable to reconstruct public key from signature" );
331
332 ECDSA_SIG *sig = ECDSA_SIG_new();
333 BN_bin2bn(&c.data[1],32,sig->r);
334 BN_bin2bn(&c.data[33],32,sig->s);
335
336 if( check_canonical )
337 {
338 FC_ASSERT( is_canonical( c ), "signature is not canonical" );
339 }
340
341 my->_key = EC_KEY_new_by_curve_name(NID_secp256k1);
342
343 if (nV >= 31)
344 {
345 EC_KEY_set_conv_form( my->_key, POINT_CONVERSION_COMPRESSED );
346 nV -= 4;
347// fprintf( stderr, "compressed\n" );
348 }
349
350 if (detail::public_key_impl::ECDSA_SIG_recover_key_GFp(my->_key, sig, (unsigned char*)&digest, sizeof(digest), nV - 27, 0) == 1)
351 {
352 ECDSA_SIG_free(sig);
353 return;
354 }
355 ECDSA_SIG_free(sig);
356 FC_THROW_EXCEPTION( exception, "unable to reconstruct public key from signature" );
357 }
358}}
T data[N]
Definition array.hpp:37
contains only the public point of an elliptic curve key.
public_key_impl & operator=(const public_key_impl &pk) BOOST_NOEXCEPT
static int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check)
public_key get_public_key() const
static private_key regenerate(const fc::sha256 &secret)
std::string to_base58() const
Allows to convert current public key object into base58 number.
public_key & operator=(public_key &&pk)
public_key_point_data serialize_ecc_point() const
public_key_data serialize() const
Used to generate a useful error report when an exception is thrown.
Definition exception.hpp:58
bool debug
#define FC_THROW_EXCEPTION(EXCEPTION, FORMAT,...)
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
#define FC_RETHROW_EXCEPTIONS(LOG_LEVEL, FORMAT,...)
Catchs all exception's, std::exceptions, and ... and rethrows them after appending the provided log m...
ehm field
bignum_st BIGNUM
Definition bigint.hpp:7
fc::array< char, 33 > public_key_data
fc::array< unsigned char, 65 > compact_signature
namespace sysio::chain
Definition authority.cpp:3
std::string to_base58(const char *d, size_t s, const fc::yield_function_t &yield)
Definition base58.cpp:618
fc::sha256 digest(const T &value)
Definition digest.hpp:9
Definition name.hpp:106
#define R
CK_RV ret