Coverage Summary for Class: HashUtil (org.ethereum.crypto)
Class |
Class, %
|
Method, %
|
Line, %
|
HashUtil |
100%
(1/1)
|
35.7%
(5/14)
|
25.5%
(13/51)
|
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 import co.rsk.core.RskAddress;
23 import org.bouncycastle.crypto.Digest;
24 import org.bouncycastle.crypto.digests.RIPEMD160Digest;
25 import org.bouncycastle.util.encoders.Hex;
26 import org.ethereum.crypto.cryptohash.Keccak256;
27 import org.ethereum.util.ByteUtil;
28 import org.ethereum.util.RLP;
29 import org.ethereum.util.Utils;
30
31 import javax.annotation.Nonnull;
32 import java.math.BigInteger;
33 import java.security.MessageDigest;
34 import java.security.NoSuchAlgorithmException;
35 import java.security.SecureRandom;
36
37 import static java.util.Arrays.copyOfRange;
38 import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;
39
40 public class HashUtil {
41 public static final byte[] EMPTY_TRIE_HASH = keccak256(RLP.encodeElement(EMPTY_BYTE_ARRAY));
42
43 private static final MessageDigest sha256digest;
44
45 static {
46 try {
47 sha256digest = MessageDigest.getInstance("SHA-256");
48 } catch (NoSuchAlgorithmException e) {
49 throw new RuntimeException(e); // Can't happen.
50 }
51 }
52
53 /**
54 * @param input - data for hashing
55 * @return - sha256 hash of the data
56 */
57 public static byte[] sha256(byte[] input) {
58 return sha256digest.digest(input);
59 }
60
61 public static byte[] keccak256(byte[] input) {
62 Keccak256 digest = new Keccak256();
63 digest.update(input);
64 return digest.digest();
65 }
66
67 /**
68 * hashing chunk of the data
69 * @param input - data for hash
70 * @param start - start of hashing chunk
71 * @param length - length of hashing chunk
72 * @return - sha3 hash of the chunk
73 */
74 public static byte[] keccak256(byte[] input, int start, int length) {
75 return Keccak256Helper.keccak256(input, start, length);
76 }
77
78 /**
79 * @param data - message to hash
80 * @return - reipmd160 hash of the message
81 */
82 public static byte[] ripemd160(byte[] data) {
83 Digest digest = new RIPEMD160Digest();
84 if (data != null) {
85 byte[] resBuf = new byte[digest.getDigestSize()];
86 digest.update(data, 0, data.length);
87 digest.doFinal(resBuf, 0);
88 return resBuf;
89 }
90 throw new NullPointerException("Can't hash a NULL value");
91 }
92
93 /**
94 * Calculates RIGTMOST160(KECCAK256(input)). This is used in address calculations.
95 * *
96 * @param input - data
97 * @return - 20 right bytes of the hash sha3 of the data
98 */
99 public static byte[] keccak256Omit12(byte[] input) {
100 byte[] hash = keccak256(input);
101 return copyOfRange(hash, 12, hash.length);
102 }
103
104 /**
105 * The way to calculate new address inside ethereum
106 *
107 * @param addr - creating addres
108 * @param nonce - nonce of creating address
109 * @return new address
110 */
111 public static byte[] calcNewAddr(byte[] addr, byte[] nonce) {
112
113 byte[] encSender = RLP.encodeElement(addr);
114 byte[] encNonce = RLP.encodeBigInteger(new BigInteger(1, nonce));
115
116 return keccak256Omit12(RLP.encodeList(encSender, encNonce));
117 }
118
119 /**
120 * The way to calculate new address inside ethereum for {@link org.ethereum.vm.OpCode#CREATE2}
121 * keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code)))[12:]
122 *
123 * @param senderAddress - creating address
124 * @param initCode - contract init code
125 * @param salt - salt to make different result addresses
126 * @return new address
127 */
128 public static byte[] calcSaltAddr(RskAddress senderAddress, byte[] initCode, byte[] salt) {
129 // 0xff is of length 1
130 // keccak-256 of the address is of length 32
131 // Then we add the lengths of the senderAddress and the salt
132 byte[] data = new byte[1 + 32 + senderAddress.getBytes().length + salt.length];
133
134 data[0] = (byte) 0xff;
135 int currentOffset = 1;
136 System.arraycopy(senderAddress.getBytes(), 0, data, currentOffset, senderAddress.getBytes().length);
137 currentOffset += senderAddress.getBytes().length;
138 System.arraycopy(salt, 0, data, currentOffset, salt.length);
139 currentOffset += salt.length;
140 byte[] keccak256InitCode = keccak256(initCode);
141 System.arraycopy(keccak256InitCode, 0, data, currentOffset, keccak256InitCode.length);
142
143 return keccak256Omit12(data);
144 }
145
146 /**
147 * @see #doubleDigest(byte[], int, int)
148 *
149 * @param input -
150 * @return -
151 */
152 public static byte[] doubleDigest(byte[] input) {
153 return doubleDigest(input, 0, input.length);
154 }
155
156 /**
157 * Calculates the SHA-256 hash of the given byte range, and then hashes the resulting hash again. This is
158 * standard procedure in Bitcoin. The resulting hash is in big endian form.
159 *
160 * @param input -
161 * @param offset -
162 * @param length -
163 * @return -
164 */
165 public static byte[] doubleDigest(byte[] input, int offset, int length) {
166 synchronized (sha256digest) {
167 sha256digest.reset();
168 sha256digest.update(input, offset, length);
169 byte[] first = sha256digest.digest();
170 return sha256digest.digest(first);
171 }
172 }
173
174 /**
175 * @return generates random peer id for the HelloMessage
176 */
177 public static byte[] randomPeerId() {
178 byte[] peerIdBytes = new BigInteger(512, Utils.getRandom()).toByteArray();
179
180 final String peerId;
181 if (peerIdBytes.length > 64) {
182 peerId = ByteUtil.toHexString(peerIdBytes, 1, 64);
183 } else {
184 peerId = ByteUtil.toHexString(peerIdBytes);
185 }
186
187 return Hex.decode(peerId);
188 }
189
190 /**
191 * @return - generate random 32 byte hash
192 */
193 public static byte[] randomHash() {
194 byte[] randomHash = new byte[32];
195 SecureRandom random = new SecureRandom();
196 random.nextBytes(randomHash);
197 return randomHash;
198 }
199
200 /**
201 * Converts {@code hash} in a form of byte array to {@code String}
202 * that's suitable to be printed out in a text form.
203 *
204 * @throws NullPointerException if {@code hash} is {@code null}
205 */
206 @Nonnull
207 public static String toPrintableHash(@Nonnull final byte[] hash) {
208 return ByteUtil.toHexString(hash);
209 }
210 }