Coverage Summary for Class: ECKey (org.ethereum.crypto)
Class |
Method, %
|
Line, %
|
ECKey |
42.9%
(15/35)
|
42.5%
(51/120)
|
ECKey$ECDSASignature |
22.2%
(2/9)
|
24.1%
(7/29)
|
ECKey$MissingPrivateKeyException |
0%
(0/1)
|
0%
(0/1)
|
Total |
37.8%
(17/45)
|
38.7%
(58/150)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2017 RSK Labs Ltd.
4 * (derived from ethereumJ library, Copyright (c) 2016 <ether.camp>)
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 package org.ethereum.crypto;
21 /**
22 * Copyright 2011 Google Inc.
23 *
24 * Licensed under the Apache License, Version 2.0 (the "License");
25 * you may not use this file except in compliance with the License.
26 * You may obtain a copy of the License at
27 *
28 * http://www.apache.org/licenses/LICENSE-2.0
29 *
30 * Unless required by applicable law or agreed to in writing, software
31 * distributed under the License is distributed on an "AS IS" BASIS,
32 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33 * See the License for the specific language governing permissions and
34 * limitations under the License.
35 */
36
37 import org.bouncycastle.asn1.sec.SECNamedCurves;
38 import org.bouncycastle.asn1.x9.X9ECParameters;
39 import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
40 import org.bouncycastle.crypto.digests.SHA256Digest;
41 import org.bouncycastle.crypto.engines.AESEngine;
42 import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
43 import org.bouncycastle.crypto.modes.SICBlockCipher;
44 import org.bouncycastle.crypto.params.*;
45 import org.bouncycastle.crypto.signers.ECDSASigner;
46 import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
47 import org.bouncycastle.math.ec.ECPoint;
48 import org.bouncycastle.util.BigIntegers;
49 import org.ethereum.crypto.signature.Secp256k1;
50 import org.ethereum.util.ByteUtil;
51
52 import javax.annotation.Nullable;
53 import java.math.BigInteger;
54 import java.security.SecureRandom;
55 import java.security.SignatureException;
56 import java.util.Arrays;
57
58 import static org.ethereum.util.ByteUtil.bigIntegerToBytes;
59
60 /**
61 * <p>Represents an elliptic curve public and (optionally) private key, usable for digital signatures but not encryption.
62 * Creating a new ECKey with the empty constructor will generate a new random keypair. Other static methods can be used
63 * when you already have the public or private parts. If you create a key with only the public part, you can check
64 * signatures but not create them.</p>
65 *
66 * <p>The ECDSA algorithm supports <i>key recovery</i> in which a signature plus a couple of discriminator bits can
67 * be reversed to find the public key used to calculate it. This can be convenient when you have a message and a
68 * signature and want to find out who signed it, rather than requiring the user to provide the expected identity.</p>
69 *
70 * <p>A key can be <i>compressed</i> or <i>uncompressed</i>. This refers to whether the public key is represented
71 * when encoded into bytes as an (x, y) coordinate on the elliptic curve, or whether it's represented as just an X
72 * co-ordinate and an extra byte that carries a sign bit. With the latter form the Y coordinate can be calculated
73 * dynamically, however, <b>because the binary serialization is different the address of a key changes if its
74 * compression status is changed</b>. If you deviate from the defaults it's important to understand this: money sent
75 * to a compressed version of the key will have a different address to the same key in uncompressed form. Whether
76 * a public key is compressed or not is recorded in the SEC binary serialisation format, and preserved in a flag in
77 * this class so round-tripping preserves state. Unless you're working with old software or doing unusual things, you
78 * can usually ignore the compressed/uncompressed distinction.</p>
79 *
80 * This code is borrowed from the bitcoinj project and altered to fit Ethereum.<br>
81 * See <a href="https://github.com/bitcoinj/bitcoinj/blob/master/core/src/main/java/com/google/bitcoin/core/ECKey.java">
82 * bitcoinj on GitHub</a>.
83 */
84 public class ECKey {
85
86 /**
87 * The parameters of the secp256k1 curve that Ethereum uses.
88 */
89 public static final ECDomainParameters CURVE;
90
91 /**
92 * Equal to CURVE.getN().shiftRight(1), used for canonicalising the S value of a signature. If you aren't
93 * sure what this is about, you can ignore it.
94 */
95 public static final BigInteger HALF_CURVE_ORDER;
96
97 private static final SecureRandom secureRandom;
98
99 static {
100 // All clients must agree on the curve to use by agreement. Ethereum uses secp256k1.
101 X9ECParameters params = SECNamedCurves.getByName("secp256k1");
102 CURVE = new ECDomainParameters(params.getCurve(), params.getG(), params.getN(), params.getH());
103 HALF_CURVE_ORDER = params.getN().shiftRight(1);
104 secureRandom = new SecureRandom();
105 }
106
107 // The two parts of the key. If "priv" is set, "pub" can always be calculated. If "pub" is set but not "priv", we
108 // can only verify signatures not make them.
109 // TODO: Redesign this class to use consistent internals and more efficient serialization.
110 private final BigInteger priv;
111 private final ECPoint pub;
112
113 // Transient because it's calculated on demand.
114 private byte[] pubKeyHash;
115 private byte[] nodeId;
116
117 /**
118 * Generates an entirely new keypair. Point compression is used so the resulting public key will be 33 bytes
119 * (32 for the co-ordinate and 1 byte to represent the y bit).
120 */
121 public ECKey() {
122 this(secureRandom);
123 }
124
125 /**
126 * Generates an entirely new keypair with the given {@link SecureRandom} object. Point compression is used so the
127 * resulting public key will be 33 bytes (32 for the co-ordinate and 1 byte to represent the y bit).
128 *
129 * @param secureRandom -
130 */
131 public ECKey(SecureRandom secureRandom) {
132 ECKeyPairGenerator generator = new ECKeyPairGenerator();
133 ECKeyGenerationParameters keygenParams = new ECKeyGenerationParameters(CURVE, secureRandom);
134 generator.init(keygenParams);
135 AsymmetricCipherKeyPair keypair = generator.generateKeyPair();
136 ECPrivateKeyParameters privParams = (ECPrivateKeyParameters) keypair.getPrivate();
137 ECPublicKeyParameters pubParams = (ECPublicKeyParameters) keypair.getPublic();
138 priv = privParams.getD();
139 pub = CURVE.getCurve().decodePoint(pubParams.getQ().getEncoded(true));
140 }
141
142 public ECKey(@Nullable BigInteger priv, ECPoint pub) {
143 this.priv = priv;
144 if (pub == null) {
145 throw new IllegalArgumentException("Public key may not be null");
146 }
147 this.pub = pub;
148 }
149
150 /**
151 * Utility for compressing an elliptic curve point. Returns the same point if it's already compressed.
152 * See the ECKey class docs for a discussion of point compression.
153 *
154 * @param uncompressed -
155 *
156 * @return -
157 */
158 public static ECPoint compressPoint(ECPoint uncompressed) {
159 return CURVE.getCurve().decodePoint(uncompressed.getEncoded(true));
160 }
161
162 /**
163 * Utility for decompressing an elliptic curve point. Returns the same point if it's already compressed.
164 * See the ECKey class docs for a discussion of point compression.
165 *
166 * @param compressed -
167 *
168 * @return -
169 */
170 public static ECPoint decompressPoint(ECPoint compressed) {
171 return CURVE.getCurve().decodePoint(compressed.getEncoded(false));
172 }
173
174 /**
175 * Creates an ECKey given the private key only. The public key is calculated from it (this is slow). Note that
176 * the resulting public key is compressed.
177 *
178 * @param privKey -
179 *
180 *
181 * @return -
182 */
183 public static ECKey fromPrivate(BigInteger privKey) {
184 return new ECKey(privKey, compressPoint(CURVE.getG().multiply(privKey)));
185 }
186
187 /**
188 * Creates an ECKey given the private key only. The public key is calculated from it (this is slow). The resulting
189 * public key is compressed.
190 *
191 * @param privKeyBytes -
192 *
193 * @return -
194 */
195 public static ECKey fromPrivate(byte[] privKeyBytes) {
196 return fromPrivate(new BigInteger(1, privKeyBytes));
197 }
198
199 /**
200 * Creates an ECKey that cannot be used for signing, only verifying signatures, from the given point. The
201 * compression state of pub will be preserved.
202 *
203 * @param pub -
204 * @return -
205 */
206 public static ECKey fromPublicOnly(ECPoint pub) {
207 return new ECKey(null, pub);
208 }
209
210 /**
211 * Creates an ECKey that cannot be used for signing, only verifying signatures, from the given encoded point.
212 * The compression state of pub will be preserved.
213 *
214 * @param pub -
215 * @return -
216 */
217 public static ECKey fromPublicOnly(byte[] pub) {
218 return new ECKey(null, CURVE.getCurve().decodePoint(pub));
219 }
220
221 /**
222 * Returns a copy of this key, but with the public point represented in uncompressed form. Normally you would
223 * never need this: it's for specialised scenarios or when backwards compatibility in encoded form is necessary.
224 *
225 * @return -
226 */
227
228 public ECKey decompress() {
229 return new ECKey(priv, decompressPoint(pub));
230 }
231
232 /**
233 * Returns true if this key doesn't have access to private key bytes. This may be because it was never
234 * given any private key bytes to begin with (a watching key).
235 *
236 * @return -
237 */
238 public boolean isPubKeyOnly() {
239 return priv == null;
240 }
241
242 /**
243 * Returns true if this key has access to private key bytes. Does the opposite of
244 * {@link #isPubKeyOnly()}.
245 *
246 * @return -
247 */
248 public boolean hasPrivKey() {
249 return priv != null;
250 }
251
252 /**
253 * Returns public key bytes from the given private key. To convert a byte array into a BigInteger, use <tt>
254 * new BigInteger(1, bytes);</tt>
255 *
256 * @param privKey -
257 * @param compressed -
258 * @return -
259 */
260 public static byte[] publicKeyFromPrivate(BigInteger privKey, boolean compressed) {
261 ECPoint point = CURVE.getG().multiply(privKey);
262 return point.getEncoded(compressed);
263 }
264
265 /**
266 * Gets the hash160 form of the public key (as seen in addresses).
267 *
268 * When we hash the PK to get the address -> Keccak256(PK),
269 * Some things are important:
270 * - 12 bytes are omitted, to get 20bytes for the address.
271 * - first byte of the public key is omitted (generally that byte is the format of the PK - 2/3/4)
272 * - In case of PoI when PK = [0], as the first byte is omitted, we hash an empty byte array.
273 *
274 * @return -
275 */
276 public byte[] getAddress() {
277 if (pubKeyHash == null) {
278 byte[] pubBytes = this.pub.getEncoded(false);
279 pubKeyHash = HashUtil.keccak256Omit12(Arrays.copyOfRange(pubBytes, 1, pubBytes.length));
280 }
281 return pubKeyHash;
282 }
283
284 /**
285 * Generates the NodeID based on this key, that is the public key without first format byte
286 */
287 public byte[] getNodeId() {
288 if (nodeId == null) {
289 byte[] nodeIdWithFormat = getPubKey();
290 nodeId = new byte[nodeIdWithFormat.length - 1];
291 System.arraycopy(nodeIdWithFormat, 1, nodeId, 0, nodeId.length);
292 }
293 return nodeId;
294 }
295
296 /**
297 * Gets the raw public key value. This appears in transaction scriptSigs. Note that this is <b>not</b> the same
298 * as the pubKeyHash/address.
299 *
300 * @return -
301 */
302 public byte[] getPubKey() {
303 return pub.getEncoded(false);
304 }
305
306 public byte[] getPubKey(boolean compressed) {
307 return pub.getEncoded(compressed);
308 }
309
310 /**
311 * Gets the public key in the form of an elliptic curve point object from Bouncy Castle.
312 *
313 * @return -
314 */
315 public ECPoint getPubKeyPoint() {
316 return pub;
317 }
318
319 public boolean equalsPub(ECKey other) {
320 return this.pub.equals(other.pub);
321 }
322
323 /**
324 * Gets the private key in the form of an integer field element. The public key is derived by performing EC
325 * point addition this number of times (i.e. point multiplying).
326 *
327 *
328 * @return -
329 *
330 * @throws java.lang.IllegalStateException if the private key bytes are not available.
331 */
332 public BigInteger getPrivKey() {
333 if (priv == null) {
334 throw new MissingPrivateKeyException();
335 }
336 return priv;
337 }
338
339 public String toString() {
340 StringBuilder b = new StringBuilder();
341 b.append("pub:").append(ByteUtil.toHexString(pub.getEncoded(false)));
342 return b.toString();
343 }
344
345 /**
346 * Groups the two components that make up a signature, and provides a way to encode to Base64 form, which is
347 * how ECDSA signatures are represented when embedded in other data structures in the Ethereum protocol. The raw
348 * components can be useful for doing further EC maths on them.
349 *
350 * @deprecated( in favor of {@link org.ethereum.crypto.signature.ECDSASignature})
351 */
352 @Deprecated
353 public static class ECDSASignature {
354 /**
355 * The two components of the signature.
356 */
357 public final BigInteger r;
358 public final BigInteger s;
359 public byte v;
360
361 /**
362 * Constructs a signature with the given components. Does NOT automatically canonicalise the signature.
363 *
364 * @param r -
365 * @param s -
366 */
367 public ECDSASignature(BigInteger r, BigInteger s) {
368 this.r = r;
369 this.s = s;
370 }
371
372 /**
373 *t
374 * @param r
375 * @param s
376 * @return -
377 */
378 private static ECDSASignature fromComponents(byte[] r, byte[] s) {
379 return new ECDSASignature(new BigInteger(1, r), new BigInteger(1, s));
380 }
381
382 /**
383 *
384 * @param r -
385 * @param s -
386 * @param v -
387 * @return -
388 */
389 public static ECDSASignature fromComponents(byte[] r, byte[] s, byte v) {
390 ECDSASignature signature = fromComponents(r, s);
391 signature.v = v;
392 return signature;
393 }
394
395 /**
396 *
397 * @param r -
398 * @param s -
399 * @param hash - the hash used to compute this signature
400 * @param pub - public key bytes, used to calculate the recovery byte 'v'
401 * @return -
402 */
403 public static ECDSASignature fromComponentsWithRecoveryCalculation(byte[] r, byte[] s, byte[] hash, byte[] pub) {
404 return ECDSASignature.fromSignature(org.ethereum.crypto.signature.ECDSASignature.fromComponentsWithRecoveryCalculation(r, s, hash, pub));
405 }
406
407 /**
408 * Only for compatibility should be removed with the entire deprecated class.
409 * @param sig
410 * @return
411 */
412 private static ECDSASignature fromSignature(org.ethereum.crypto.signature.ECDSASignature sig) {
413 ECDSASignature result = new ECDSASignature(sig.getR(), sig.getS());
414 result.v = sig.getV();
415 return result;
416 }
417
418 public boolean validateComponents() {
419 return org.ethereum.crypto.signature.ECDSASignature.validateComponents(r, s, v);
420 }
421
422 /**
423 * Will automatically adjust the S component to be less than or equal to half the curve order, if necessary.
424 * This is required because for every signature (r,s) the signature (r, -s (mod N)) is a valid signature of
425 * the same message. However, we dislike the ability to modify the bits of a Ethereum transaction after it's
426 * been signed, as that violates various assumed invariants. Thus in future only one of those forms will be
427 * considered legal and the other will be banned.
428 *
429 * @return -
430 */
431 public ECDSASignature toCanonicalised() {
432 if (s.compareTo(HALF_CURVE_ORDER) > 0) {
433 // The order of the curve is the number of valid points that exist on that curve. If S is in the upper
434 // half of the number of valid points, then bring it back to the lower half. Otherwise, imagine that
435 // N = 10
436 // s = 8, so (-8 % 10 == 2) thus both (r, 8) and (r, 2) are valid solutions.
437 // 10 - 8 == 2, giving us always the latter solution, which is canonical.
438 return new ECDSASignature(r, CURVE.getN().subtract(s));
439 } else {
440 return this;
441 }
442 }
443
444 @Override
445 public boolean equals(Object o) {
446 if (this == o) {
447 return true;
448 }
449
450 if (o == null || getClass() != o.getClass()) {
451 return false;
452 }
453
454 ECDSASignature signature = (ECDSASignature) o;
455
456 if (!r.equals(signature.r)) {
457 return false;
458 }
459
460 if (!s.equals(signature.s)) {
461 return false;
462 }
463
464 return true;
465 }
466
467 @Override
468 public int hashCode() {
469 int result = r.hashCode();
470 result = 31 * result + s.hashCode();
471 return result;
472 }
473 }
474
475 /**
476 * Signs the given hash and returns the R and S components as BigIntegers
477 * and put them in ECDSASignature
478 *
479 * @param input to sign
480 * @return ECDSASignature signature that contains the R and S components
481 */
482 public ECDSASignature doSign(byte[] input) {
483 // No decryption of private key required.
484 if (priv == null) {
485 throw new MissingPrivateKeyException();
486 }
487 ECDSASigner signer = new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest()));
488 ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(priv, CURVE);
489 signer.init(true, privKey);
490 BigInteger[] components = signer.generateSignature(input);
491 return new ECDSASignature(components[0], components[1]).toCanonicalised();
492 }
493
494
495 /**
496 * Takes the sha3 hash (32 bytes) of data and returns the ECDSA signature
497 *
498 * @param messageHash -
499 * @return -
500 * @throws IllegalStateException if this ECKey does not have the private part.
501 */
502 public ECDSASignature sign(byte[] messageHash) {
503 if (priv == null) {
504 throw new MissingPrivateKeyException();
505 }
506 ECDSASignature sig = doSign(messageHash);
507 // Now we have to work backwards to figure out the recId needed to recover the signature.
508 int recId = -1;
509 for (int i = 0; i < 4; i++) {
510 ECKey k = Secp256k1.getInstance().recoverFromSignature(i, org.ethereum.crypto.signature.ECDSASignature.fromSignature(sig), messageHash, false);
511 if (k != null && k.pub.equals(pub)) {
512 recId = i;
513 break;
514 }
515 }
516 if (recId == -1) {
517 throw new RuntimeException("Could not construct a recoverable key. This should never happen.");
518 }
519 sig.v = (byte) (recId + 27);
520 return sig;
521 }
522
523
524 /**
525 * Given a piece of text and a message signature encoded in base64, returns an ECKey
526 * containing the public key that was used to sign it. This can then be compared to the expected public key to
527 * determine if the signature was correct.
528 *
529 * @deprecated( in favor of {@link org.ethereum.crypto.signature.Secp256k1Service#signatureToKey(byte[], org.ethereum.crypto.signature.ECDSASignature)} )
530 *
531 * @param messageHash a piece of human readable text that was signed
532 * @param signature The message signature
533 *
534 * @return -
535 * @throws java.security.SignatureException If the public key could not be recovered or if there was a signature format error.
536 */
537 @Deprecated
538 public static ECKey signatureToKey(byte[] messageHash, ECDSASignature signature) throws SignatureException {
539 return Secp256k1.getInstance().signatureToKey(messageHash, org.ethereum.crypto.signature.ECDSASignature.fromSignature(signature));
540 }
541
542 /**
543 * Decrypt cipher by AES in SIC(also know as CTR) mode
544 *
545 * @param cipher -proper cipher
546 * @return decrypted cipher, equal length to the cipher.
547 */
548 public byte[] decryptAES(byte[] cipher){
549
550 if (priv == null) {
551 throw new MissingPrivateKeyException();
552 }
553
554 AESEngine engine = new AESEngine();
555 SICBlockCipher ctrEngine = new SICBlockCipher(engine);
556
557 KeyParameter key = new KeyParameter(BigIntegers.asUnsignedByteArray(priv));
558 ParametersWithIV params = new ParametersWithIV(key, new byte[16]);
559
560 ctrEngine.init(false, params);
561
562 int i = 0;
563 byte[] out = new byte[cipher.length];
564 while(i < cipher.length){
565 ctrEngine.processBlock(cipher, i, out, i);
566 i += engine.getBlockSize();
567 if (cipher.length - i < engine.getBlockSize()) {
568 break;
569 }
570 }
571
572 // process left bytes
573 if (cipher.length - i > 0){
574 byte[] tmpBlock = new byte[16];
575 System.arraycopy(cipher, i, tmpBlock, 0, cipher.length - i);
576 ctrEngine.processBlock(tmpBlock, 0, tmpBlock, 0);
577 System.arraycopy(tmpBlock, 0, out, i, cipher.length - i);
578 }
579
580 return out;
581 }
582
583
584
585 /**
586 * <p>Verifies the given ECDSA signature against the message bytes using the public key bytes.</p>
587 *
588 * <p>When using native ECDSA verification, data must be 32 bytes, and no element may be
589 * larger than 520 bytes.</p>
590 * @deprecated( in favor of {@link org.ethereum.crypto.signature.Secp256k1Service#verify(byte[], org.ethereum.crypto.signature.ECDSASignature, byte[])})
591 *
592 * @param data Hash of the data to verify.
593 * @param signature signature.
594 * @param pub The public key bytes to use.
595 *
596 * @return -
597 */
598 @Deprecated
599 public static boolean verify(byte[] data, ECDSASignature signature, byte[] pub) {
600 return Secp256k1.getInstance().verify(data, org.ethereum.crypto.signature.ECDSASignature.fromSignature(signature), pub);
601 }
602
603 /**
604 * Verifies the given R/S pair (signature) against a hash using the public key.
605 *
606 * @deprecated( in favor of {@link #verify(byte[], org.ethereum.crypto.signature.ECDSASignature)})
607 *
608 * @param sigHash -
609 * @param signature -
610 * @return -
611 */
612 @Deprecated
613 public boolean verify(byte[] sigHash, ECDSASignature signature) {
614 return Secp256k1.getInstance().verify(sigHash, org.ethereum.crypto.signature.ECDSASignature.fromSignature(signature), getPubKey());
615 }
616
617 /**
618 * Verifies the given R/S pair (signature) against a hash using the public key.
619 *
620 * @param sigHash -
621 * @param signature -
622 * @return -
623 */
624 public boolean verify(byte[] sigHash, org.ethereum.crypto.signature.ECDSASignature signature) {
625 return Secp256k1.getInstance().verify(sigHash, signature, getPubKey());
626 }
627
628
629 /**
630 * Returns true if this pubkey is canonical, i.e. the correct length taking into account compression.
631 *
632 * @return -
633 */
634 public boolean isPubKeyCanonical() {
635 return isPubKeyCanonical(pub.getEncoded(false));
636 }
637
638
639 /**
640 * Returns true if the given pubkey is canonical, i.e. the correct length taking into account compression.
641 * @param pubkey -
642 * @return -
643 */
644 public static boolean isPubKeyCanonical(byte[] pubkey) {
645 if (pubkey[0] == 0x04) {
646 // Uncompressed pubkey
647 if (pubkey.length != 65) {
648 return false;
649 }
650 } else if (pubkey[0] == 0x02 || pubkey[0] == 0x03) {
651 // Compressed pubkey
652 if (pubkey.length != 33) {
653 return false;
654 }
655 } else {
656 return false;
657 }
658 return true;
659 }
660
661 /**
662 * <p>Given the components of a signature and a selector value, recover and return the public key
663 * that generated the signature according to the algorithm in SEC1v2 section 4.1.6.</p>
664 *
665 * <p>The recId is an index from 0 to 3 which indicates which of the 4 possible keys is the correct one. Because
666 * the key recovery operation yields multiple potential keys, the correct key must either be stored alongside the
667 * signature, or you must be willing to try each recId in turn until you find one that outputs the key you are
668 * expecting.</p>
669 *
670 * <p>If this method returns null it means recovery was not possible and recId should be iterated.</p>
671 *
672 * <p>Given the above two points, a correct usage of this method is inside a for loop from 0 to 3, and if the
673 * output is null OR a key that is not the one you expect, you try again with the next recId.</p>
674 *
675 * @deprecated (in favor of {@link org.ethereum.crypto.signature.Secp256k1Service#recoverFromSignature(int, org.ethereum.crypto.signature.ECDSASignature, byte[], boolean)}
676 *
677 * @param recId Which possible key to recover.
678 * @param sig the R and S components of the signature, wrapped.
679 * @param messageHash Hash of the data that was signed.
680 * @param compressed Whether or not the original pubkey was compressed.
681 * @return An ECKey containing only the public part, or null if recovery wasn't possible.
682 */
683 @Deprecated
684 @Nullable
685 public static ECKey recoverFromSignature(int recId, ECDSASignature sig, byte[] messageHash, boolean compressed) {
686 return Secp256k1.getInstance().recoverFromSignature(recId, org.ethereum.crypto.signature.ECDSASignature.fromSignature(sig), messageHash, compressed);
687 }
688
689 /**
690 * Returns a 32 byte array containing the private key, or null if the key is encrypted or public only
691 *
692 * @return -
693 */
694 @Nullable
695 public byte[] getPrivKeyBytes() {
696 return bigIntegerToBytes(priv, 32);
697 }
698
699 @Override
700 public boolean equals(Object o) {
701 if (this == o) {
702 return true;
703 }
704
705 if (o == null || !(o instanceof ECKey)) {
706 return false;
707 }
708
709 ECKey ecKey = (ECKey) o;
710
711 if (priv != null && !priv.equals(ecKey.priv)) {
712 return false;
713 }
714
715 if (pub != null && !pub.equals(ecKey.pub)) {
716 return false;
717 }
718
719 return true;
720 }
721
722 @Override
723 public int hashCode() {
724 // Public keys are random already so we can just use a part of them as the hashcode. Read from the start to
725 // avoid picking up the type code (compressed vs uncompressed) which is tacked on the end.
726 byte[] bits = getPubKey(true);
727 return (bits[0] & 0xFF) | ((bits[1] & 0xFF) << 8) | ((bits[2] & 0xFF) << 16) | ((bits[3] & 0xFF) << 24);
728 }
729
730 @SuppressWarnings("serial")
731 public static class MissingPrivateKeyException extends RuntimeException {
732 }
733
734 }