Coverage Summary for Class: Secp256k1Service (org.ethereum.crypto.signature)
Class |
Class, %
|
Method, %
|
Line, %
|
Secp256k1Service |
100%
(1/1)
|
100%
(2/2)
|
66.7%
(10/15)
|
1 /*
2 * This file is part of RskJ
3 * Copyright (C) 2020 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.signature;
21
22 import org.ethereum.crypto.ECKey;
23
24 import javax.annotation.Nullable;
25 import java.security.SignatureException;
26
27 /**
28 * Service in charge of the implementations of all the Signature related functionality.
29 * Functions:
30 * - Sign data (future)
31 * - Recover PK from signature
32 * - Verify
33 */
34 public interface Secp256k1Service {
35
36
37 /**
38 * Given a piece of text and a message signature encoded in base64, returns an ECKey
39 * containing the public key that was used to sign it. This can then be compared to the expected public key to
40 * determine if the signature was correct.
41 *
42 * signature.v => from 31 to 34 is compressed
43 * => from 27 to 30 is uncompressed
44 *
45 * @param messageHash a piece of human readable text that was signed
46 * @param signature The message signature
47 * @return -
48 * @throws SignatureException If the public key could not be recovered or if there was a signature format error.
49 */
50 default ECKey signatureToKey(byte[] messageHash, ECDSASignature signature) throws SignatureException {
51 int header = signature.getV() & 0xFF;
52 // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
53 // 0x1D = second key with even y, 0x1E = second key with odd y
54 if (header < 27 || header > 34) {
55 throw new SignatureException("Header byte out of range: " + header);
56 }
57
58 boolean compressed = false;
59 if (header >= 31) {
60 compressed = true;
61 header -= 4;
62 }
63 int recId = header - 27;
64 ECKey key = this.recoverFromSignature(recId, signature, messageHash, compressed);
65 if (key == null) {
66 throw new SignatureException("Could not recover public key from signature");
67 }
68 return key;
69 }
70 /**
71 * <p>Given the components of a signature and a selector value, recover and return the public key
72 * that generated the signature according to the algorithm in SEC1v2 section 4.1.6.</p>
73 *
74 * <p>The recId is an index from 0 to 3 which indicates which of the 4 possible keys is the correct one. Because
75 * the key recovery operation yields multiple potential keys, the correct key must either be stored alongside the
76 * signature, or you must be willing to try each recId in turn until you find one that outputs the key you are
77 * expecting.</p>
78 *
79 * <p>If this method returns null it means recovery was not possible and recId should be iterated.</p>
80 *
81 * <p>Given the above two points, a correct usage of this method is inside a for loop from 0 to 3, and if the
82 * output is null OR a key that is not the one you expect, you try again with the next recId.</p>
83 *
84 * @param recId Which possible key to recover.
85 * @param sig the R and S components of the signature, wrapped.
86 * @param messageHash Hash of the data that was signed.
87 * @param compressed Whether or not the original pubkey was compressed.
88 * @return An ECKey containing only the public part, or null if recovery wasn't possible.
89 */
90 @Nullable
91 ECKey recoverFromSignature(int recId, ECDSASignature sig, byte[] messageHash, boolean compressed);
92
93 /**
94 * <p>Verifies the given ECDSA signature against the message bytes using the public key bytes.</p>
95 *
96 * <p>When using native ECDSA verification, data must be 32 bytes, and no element may be
97 * larger than 520 bytes.</p>
98 *
99 * @param data Hash of the data to verify.
100 * @param signature signature.
101 * @param pub The public key bytes to use.
102 * @return -
103 */
104 boolean verify(byte[] data, ECDSASignature signature, byte[] pub);
105
106 /**
107 * Utility method to check params.
108 *
109 * @param test
110 * @param message
111 */
112 default void check(boolean test, String message) {
113 if (!test) {
114 throw new IllegalArgumentException(message);
115 }
116 }
117
118 }