ethereum.crypto.blake2
The Blake2 Implementation ^^^^^^^^^^^^^^^^^^^^^^^^^^
1""" 2The Blake2 Implementation 3^^^^^^^^^^^^^^^^^^^^^^^^^^ 4""" 5import struct 6from dataclasses import dataclass 7from typing import List, Tuple 8 9from ethereum.base_types import Uint 10 11 12def spit_le_to_uint(data: bytes, start: int, num_words: int) -> List[Uint]: 13 """ 14 Extracts 8 byte words from a given data. 15 16 Parameters 17 ---------- 18 data : 19 The data in bytes from which the words need to be extracted 20 start : 21 Position to start the extraction 22 num_words: 23 The number of words to be extracted 24 """ 25 words = [] 26 for i in range(num_words): 27 start_position = start + (i * 8) 28 words.append( 29 Uint.from_le_bytes(data[start_position : start_position + 8]) 30 ) 31 32 return words 33 34 35@dataclass 36class Blake2: 37 """ 38 Implementation of the BLAKE2 cryptographic hashing algorithm. 39 40 Please refer the following document for details: 41 https://datatracker.ietf.org/doc/html/rfc7693 42 """ 43 44 w: int 45 mask_bits: int 46 word_format: str 47 48 R1: int 49 R2: int 50 R3: int 51 R4: int 52 53 @property 54 def max_word(self) -> int: 55 """ 56 Largest value for a given Blake2 flavor. 57 """ 58 return 2**self.w 59 60 @property 61 def w_R1(self) -> int: 62 """ 63 (w - R1) value for a given Blake2 flavor. 64 Used in the function G 65 """ 66 return self.w - self.R1 67 68 @property 69 def w_R2(self) -> int: 70 """ 71 (w - R2) value for a given Blake2 flavor. 72 Used in the function G 73 """ 74 return self.w - self.R2 75 76 @property 77 def w_R3(self) -> int: 78 """ 79 (w - R3) value for a given Blake2 flavor. 80 Used in the function G 81 """ 82 return self.w - self.R3 83 84 @property 85 def w_R4(self) -> int: 86 """ 87 (w - R4) value for a given Blake2 flavor. 88 Used in the function G 89 """ 90 return self.w - self.R4 91 92 sigma: Tuple = ( 93 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), 94 (14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3), 95 (11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4), 96 (7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8), 97 (9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13), 98 (2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9), 99 (12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11), 100 (13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10), 101 (6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5), 102 (10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0), 103 ) 104 105 IV: Tuple = ( 106 0x6A09E667F3BCC908, 107 0xBB67AE8584CAA73B, 108 0x3C6EF372FE94F82B, 109 0xA54FF53A5F1D36F1, 110 0x510E527FADE682D1, 111 0x9B05688C2B3E6C1F, 112 0x1F83D9ABFB41BD6B, 113 0x5BE0CD19137E2179, 114 ) 115 116 @property 117 def sigma_len(self) -> int: 118 """ 119 Length of the sigma parameter. 120 """ 121 return len(self.sigma) 122 123 def get_blake2_parameters(self, data: bytes) -> Tuple: 124 """ 125 Extract the parameters required in the Blake2 compression function 126 from the provided bytes data. 127 128 Parameters 129 ---------- 130 data : 131 The bytes data that has been passed in the message. 132 """ 133 rounds = Uint.from_be_bytes(data[:4]) 134 h = spit_le_to_uint(data, 4, 8) 135 m = spit_le_to_uint(data, 68, 16) 136 t_0, t_1 = spit_le_to_uint(data, 196, 2) 137 f = Uint.from_be_bytes(data[212:]) 138 139 return (rounds, h, m, t_0, t_1, f) 140 141 def G( 142 self, v: List, a: int, b: int, c: int, d: int, x: int, y: int 143 ) -> List: 144 """ 145 The mixing function used in Blake2 146 https://datatracker.ietf.org/doc/html/rfc7693#section-3.1 147 148 Parameters 149 ---------- 150 v : 151 The working vector to be mixed. 152 a, b, c, d : 153 Indexes within v of the words to be mixed. 154 x, y : 155 The two input words for the mixing. 156 """ 157 v[a] = (v[a] + v[b] + x) % self.max_word 158 v[d] = ((v[d] ^ v[a]) >> self.R1) ^ ( 159 (v[d] ^ v[a]) << self.w_R1 160 ) % self.max_word 161 162 v[c] = (v[c] + v[d]) % self.max_word 163 v[b] = ((v[b] ^ v[c]) >> self.R2) ^ ( 164 (v[b] ^ v[c]) << self.w_R2 165 ) % self.max_word 166 167 v[a] = (v[a] + v[b] + y) % self.max_word 168 v[d] = ((v[d] ^ v[a]) >> self.R3) ^ ( 169 (v[d] ^ v[a]) << self.w_R3 170 ) % self.max_word 171 172 v[c] = (v[c] + v[d]) % self.max_word 173 v[b] = ((v[b] ^ v[c]) >> self.R4) ^ ( 174 (v[b] ^ v[c]) << self.w_R4 175 ) % self.max_word 176 177 return v 178 179 def compress( 180 self, 181 num_rounds: Uint, 182 h: List[Uint], 183 m: List[Uint], 184 t_0: Uint, 185 t_1: Uint, 186 f: bool, 187 ) -> bytes: 188 """ 189 'F Compression' from section 3.2 of RFC 7693: 190 https://tools.ietf.org/html/rfc7693#section-3.2 191 192 Parameters 193 ---------- 194 num_rounds : 195 The number of rounds. A 32-bit unsigned big-endian word 196 h : 197 The state vector. 8 unsigned 64-bit little-endian words 198 m : 199 The message block vector. 16 unsigned 64-bit little-endian words 200 t_0, t_1 : 201 Offset counters. 2 unsigned 64-bit little-endian words 202 f: 203 The final block indicator flag. An 8-bit word 204 """ 205 # Initialize local work vector v[0..15] 206 v = [0] * 16 207 v[0:8] = h # First half from state 208 v[8:15] = self.IV # Second half from IV 209 210 v[12] = t_0 ^ self.IV[4] # Low word of the offset 211 v[13] = t_1 ^ self.IV[5] # High word of the offset 212 213 if f: 214 v[14] = v[14] ^ self.mask_bits # Invert all bits for last block 215 216 # Mixing 217 for r in range(num_rounds): 218 # for more than sigma_len rounds, the schedule 219 # wraps around to the beginning 220 s = self.sigma[r % self.sigma_len] 221 222 v = self.G(v, 0, 4, 8, 12, m[s[0]], m[s[1]]) 223 v = self.G(v, 1, 5, 9, 13, m[s[2]], m[s[3]]) 224 v = self.G(v, 2, 6, 10, 14, m[s[4]], m[s[5]]) 225 v = self.G(v, 3, 7, 11, 15, m[s[6]], m[s[7]]) 226 v = self.G(v, 0, 5, 10, 15, m[s[8]], m[s[9]]) 227 v = self.G(v, 1, 6, 11, 12, m[s[10]], m[s[11]]) 228 v = self.G(v, 2, 7, 8, 13, m[s[12]], m[s[13]]) 229 v = self.G(v, 3, 4, 9, 14, m[s[14]], m[s[15]]) 230 231 result_message_words = (h[i] ^ v[i] ^ v[i + 8] for i in range(8)) 232 return struct.pack("<8%s" % self.word_format, *result_message_words) 233 234 235# Parameters specific to the Blake2b implementation 236@dataclass 237class Blake2b(Blake2): 238 """ 239 The Blake2b flavor (64-bits) of Blake2. 240 This version is used in the pre-compiled contract. 241 """ 242 243 w: int = 64 244 mask_bits: int = 0xFFFFFFFFFFFFFFFF 245 word_format: str = "Q" 246 247 R1: int = 32 248 R2: int = 24 249 R3: int = 16 250 R4: int = 63
13def spit_le_to_uint(data: bytes, start: int, num_words: int) -> List[Uint]: 14 """ 15 Extracts 8 byte words from a given data. 16 17 Parameters 18 ---------- 19 data : 20 The data in bytes from which the words need to be extracted 21 start : 22 Position to start the extraction 23 num_words: 24 The number of words to be extracted 25 """ 26 words = [] 27 for i in range(num_words): 28 start_position = start + (i * 8) 29 words.append( 30 Uint.from_le_bytes(data[start_position : start_position + 8]) 31 ) 32 33 return words
Extracts 8 byte words from a given data.
Parameters
data : The data in bytes from which the words need to be extracted start : Position to start the extraction num_words: The number of words to be extracted
36@dataclass 37class Blake2: 38 """ 39 Implementation of the BLAKE2 cryptographic hashing algorithm. 40 41 Please refer the following document for details: 42 https://datatracker.ietf.org/doc/html/rfc7693 43 """ 44 45 w: int 46 mask_bits: int 47 word_format: str 48 49 R1: int 50 R2: int 51 R3: int 52 R4: int 53 54 @property 55 def max_word(self) -> int: 56 """ 57 Largest value for a given Blake2 flavor. 58 """ 59 return 2**self.w 60 61 @property 62 def w_R1(self) -> int: 63 """ 64 (w - R1) value for a given Blake2 flavor. 65 Used in the function G 66 """ 67 return self.w - self.R1 68 69 @property 70 def w_R2(self) -> int: 71 """ 72 (w - R2) value for a given Blake2 flavor. 73 Used in the function G 74 """ 75 return self.w - self.R2 76 77 @property 78 def w_R3(self) -> int: 79 """ 80 (w - R3) value for a given Blake2 flavor. 81 Used in the function G 82 """ 83 return self.w - self.R3 84 85 @property 86 def w_R4(self) -> int: 87 """ 88 (w - R4) value for a given Blake2 flavor. 89 Used in the function G 90 """ 91 return self.w - self.R4 92 93 sigma: Tuple = ( 94 (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), 95 (14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3), 96 (11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4), 97 (7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8), 98 (9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13), 99 (2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9), 100 (12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11), 101 (13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10), 102 (6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5), 103 (10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0), 104 ) 105 106 IV: Tuple = ( 107 0x6A09E667F3BCC908, 108 0xBB67AE8584CAA73B, 109 0x3C6EF372FE94F82B, 110 0xA54FF53A5F1D36F1, 111 0x510E527FADE682D1, 112 0x9B05688C2B3E6C1F, 113 0x1F83D9ABFB41BD6B, 114 0x5BE0CD19137E2179, 115 ) 116 117 @property 118 def sigma_len(self) -> int: 119 """ 120 Length of the sigma parameter. 121 """ 122 return len(self.sigma) 123 124 def get_blake2_parameters(self, data: bytes) -> Tuple: 125 """ 126 Extract the parameters required in the Blake2 compression function 127 from the provided bytes data. 128 129 Parameters 130 ---------- 131 data : 132 The bytes data that has been passed in the message. 133 """ 134 rounds = Uint.from_be_bytes(data[:4]) 135 h = spit_le_to_uint(data, 4, 8) 136 m = spit_le_to_uint(data, 68, 16) 137 t_0, t_1 = spit_le_to_uint(data, 196, 2) 138 f = Uint.from_be_bytes(data[212:]) 139 140 return (rounds, h, m, t_0, t_1, f) 141 142 def G( 143 self, v: List, a: int, b: int, c: int, d: int, x: int, y: int 144 ) -> List: 145 """ 146 The mixing function used in Blake2 147 https://datatracker.ietf.org/doc/html/rfc7693#section-3.1 148 149 Parameters 150 ---------- 151 v : 152 The working vector to be mixed. 153 a, b, c, d : 154 Indexes within v of the words to be mixed. 155 x, y : 156 The two input words for the mixing. 157 """ 158 v[a] = (v[a] + v[b] + x) % self.max_word 159 v[d] = ((v[d] ^ v[a]) >> self.R1) ^ ( 160 (v[d] ^ v[a]) << self.w_R1 161 ) % self.max_word 162 163 v[c] = (v[c] + v[d]) % self.max_word 164 v[b] = ((v[b] ^ v[c]) >> self.R2) ^ ( 165 (v[b] ^ v[c]) << self.w_R2 166 ) % self.max_word 167 168 v[a] = (v[a] + v[b] + y) % self.max_word 169 v[d] = ((v[d] ^ v[a]) >> self.R3) ^ ( 170 (v[d] ^ v[a]) << self.w_R3 171 ) % self.max_word 172 173 v[c] = (v[c] + v[d]) % self.max_word 174 v[b] = ((v[b] ^ v[c]) >> self.R4) ^ ( 175 (v[b] ^ v[c]) << self.w_R4 176 ) % self.max_word 177 178 return v 179 180 def compress( 181 self, 182 num_rounds: Uint, 183 h: List[Uint], 184 m: List[Uint], 185 t_0: Uint, 186 t_1: Uint, 187 f: bool, 188 ) -> bytes: 189 """ 190 'F Compression' from section 3.2 of RFC 7693: 191 https://tools.ietf.org/html/rfc7693#section-3.2 192 193 Parameters 194 ---------- 195 num_rounds : 196 The number of rounds. A 32-bit unsigned big-endian word 197 h : 198 The state vector. 8 unsigned 64-bit little-endian words 199 m : 200 The message block vector. 16 unsigned 64-bit little-endian words 201 t_0, t_1 : 202 Offset counters. 2 unsigned 64-bit little-endian words 203 f: 204 The final block indicator flag. An 8-bit word 205 """ 206 # Initialize local work vector v[0..15] 207 v = [0] * 16 208 v[0:8] = h # First half from state 209 v[8:15] = self.IV # Second half from IV 210 211 v[12] = t_0 ^ self.IV[4] # Low word of the offset 212 v[13] = t_1 ^ self.IV[5] # High word of the offset 213 214 if f: 215 v[14] = v[14] ^ self.mask_bits # Invert all bits for last block 216 217 # Mixing 218 for r in range(num_rounds): 219 # for more than sigma_len rounds, the schedule 220 # wraps around to the beginning 221 s = self.sigma[r % self.sigma_len] 222 223 v = self.G(v, 0, 4, 8, 12, m[s[0]], m[s[1]]) 224 v = self.G(v, 1, 5, 9, 13, m[s[2]], m[s[3]]) 225 v = self.G(v, 2, 6, 10, 14, m[s[4]], m[s[5]]) 226 v = self.G(v, 3, 7, 11, 15, m[s[6]], m[s[7]]) 227 v = self.G(v, 0, 5, 10, 15, m[s[8]], m[s[9]]) 228 v = self.G(v, 1, 6, 11, 12, m[s[10]], m[s[11]]) 229 v = self.G(v, 2, 7, 8, 13, m[s[12]], m[s[13]]) 230 v = self.G(v, 3, 4, 9, 14, m[s[14]], m[s[15]]) 231 232 result_message_words = (h[i] ^ v[i] ^ v[i + 8] for i in range(8)) 233 return struct.pack("<8%s" % self.word_format, *result_message_words)
Implementation of the BLAKE2 cryptographic hashing algorithm.
Please refer the following document for details: https://datatracker.ietf.org/doc/html/rfc7693
54 @property 55 def max_word(self) -> int: 56 """ 57 Largest value for a given Blake2 flavor. 58 """ 59 return 2**self.w
Largest value for a given Blake2 flavor.
61 @property 62 def w_R1(self) -> int: 63 """ 64 (w - R1) value for a given Blake2 flavor. 65 Used in the function G 66 """ 67 return self.w - self.R1
(w - R1) value for a given Blake2 flavor. Used in the function G
69 @property 70 def w_R2(self) -> int: 71 """ 72 (w - R2) value for a given Blake2 flavor. 73 Used in the function G 74 """ 75 return self.w - self.R2
(w - R2) value for a given Blake2 flavor. Used in the function G
77 @property 78 def w_R3(self) -> int: 79 """ 80 (w - R3) value for a given Blake2 flavor. 81 Used in the function G 82 """ 83 return self.w - self.R3
(w - R3) value for a given Blake2 flavor. Used in the function G
85 @property 86 def w_R4(self) -> int: 87 """ 88 (w - R4) value for a given Blake2 flavor. 89 Used in the function G 90 """ 91 return self.w - self.R4
(w - R4) value for a given Blake2 flavor. Used in the function G
117 @property 118 def sigma_len(self) -> int: 119 """ 120 Length of the sigma parameter. 121 """ 122 return len(self.sigma)
Length of the sigma parameter.
124 def get_blake2_parameters(self, data: bytes) -> Tuple: 125 """ 126 Extract the parameters required in the Blake2 compression function 127 from the provided bytes data. 128 129 Parameters 130 ---------- 131 data : 132 The bytes data that has been passed in the message. 133 """ 134 rounds = Uint.from_be_bytes(data[:4]) 135 h = spit_le_to_uint(data, 4, 8) 136 m = spit_le_to_uint(data, 68, 16) 137 t_0, t_1 = spit_le_to_uint(data, 196, 2) 138 f = Uint.from_be_bytes(data[212:]) 139 140 return (rounds, h, m, t_0, t_1, f)
Extract the parameters required in the Blake2 compression function from the provided bytes data.
Parameters
data : The bytes data that has been passed in the message.
142 def G( 143 self, v: List, a: int, b: int, c: int, d: int, x: int, y: int 144 ) -> List: 145 """ 146 The mixing function used in Blake2 147 https://datatracker.ietf.org/doc/html/rfc7693#section-3.1 148 149 Parameters 150 ---------- 151 v : 152 The working vector to be mixed. 153 a, b, c, d : 154 Indexes within v of the words to be mixed. 155 x, y : 156 The two input words for the mixing. 157 """ 158 v[a] = (v[a] + v[b] + x) % self.max_word 159 v[d] = ((v[d] ^ v[a]) >> self.R1) ^ ( 160 (v[d] ^ v[a]) << self.w_R1 161 ) % self.max_word 162 163 v[c] = (v[c] + v[d]) % self.max_word 164 v[b] = ((v[b] ^ v[c]) >> self.R2) ^ ( 165 (v[b] ^ v[c]) << self.w_R2 166 ) % self.max_word 167 168 v[a] = (v[a] + v[b] + y) % self.max_word 169 v[d] = ((v[d] ^ v[a]) >> self.R3) ^ ( 170 (v[d] ^ v[a]) << self.w_R3 171 ) % self.max_word 172 173 v[c] = (v[c] + v[d]) % self.max_word 174 v[b] = ((v[b] ^ v[c]) >> self.R4) ^ ( 175 (v[b] ^ v[c]) << self.w_R4 176 ) % self.max_word 177 178 return v
The mixing function used in Blake2 https://datatracker.ietf.org/doc/html/rfc7693#section-3.1
Parameters
v : The working vector to be mixed. a, b, c, d : Indexes within v of the words to be mixed. x, y : The two input words for the mixing.
180 def compress( 181 self, 182 num_rounds: Uint, 183 h: List[Uint], 184 m: List[Uint], 185 t_0: Uint, 186 t_1: Uint, 187 f: bool, 188 ) -> bytes: 189 """ 190 'F Compression' from section 3.2 of RFC 7693: 191 https://tools.ietf.org/html/rfc7693#section-3.2 192 193 Parameters 194 ---------- 195 num_rounds : 196 The number of rounds. A 32-bit unsigned big-endian word 197 h : 198 The state vector. 8 unsigned 64-bit little-endian words 199 m : 200 The message block vector. 16 unsigned 64-bit little-endian words 201 t_0, t_1 : 202 Offset counters. 2 unsigned 64-bit little-endian words 203 f: 204 The final block indicator flag. An 8-bit word 205 """ 206 # Initialize local work vector v[0..15] 207 v = [0] * 16 208 v[0:8] = h # First half from state 209 v[8:15] = self.IV # Second half from IV 210 211 v[12] = t_0 ^ self.IV[4] # Low word of the offset 212 v[13] = t_1 ^ self.IV[5] # High word of the offset 213 214 if f: 215 v[14] = v[14] ^ self.mask_bits # Invert all bits for last block 216 217 # Mixing 218 for r in range(num_rounds): 219 # for more than sigma_len rounds, the schedule 220 # wraps around to the beginning 221 s = self.sigma[r % self.sigma_len] 222 223 v = self.G(v, 0, 4, 8, 12, m[s[0]], m[s[1]]) 224 v = self.G(v, 1, 5, 9, 13, m[s[2]], m[s[3]]) 225 v = self.G(v, 2, 6, 10, 14, m[s[4]], m[s[5]]) 226 v = self.G(v, 3, 7, 11, 15, m[s[6]], m[s[7]]) 227 v = self.G(v, 0, 5, 10, 15, m[s[8]], m[s[9]]) 228 v = self.G(v, 1, 6, 11, 12, m[s[10]], m[s[11]]) 229 v = self.G(v, 2, 7, 8, 13, m[s[12]], m[s[13]]) 230 v = self.G(v, 3, 4, 9, 14, m[s[14]], m[s[15]]) 231 232 result_message_words = (h[i] ^ v[i] ^ v[i + 8] for i in range(8)) 233 return struct.pack("<8%s" % self.word_format, *result_message_words)
'F Compression' from section 3.2 of RFC 7693: https://tools.ietf.org/html/rfc7693#section-3.2
Parameters
num_rounds : The number of rounds. A 32-bit unsigned big-endian word h : The state vector. 8 unsigned 64-bit little-endian words m : The message block vector. 16 unsigned 64-bit little-endian words t_0, t_1 : Offset counters. 2 unsigned 64-bit little-endian words f: The final block indicator flag. An 8-bit word
237@dataclass 238class Blake2b(Blake2): 239 """ 240 The Blake2b flavor (64-bits) of Blake2. 241 This version is used in the pre-compiled contract. 242 """ 243 244 w: int = 64 245 mask_bits: int = 0xFFFFFFFFFFFFFFFF 246 word_format: str = "Q" 247 248 R1: int = 32 249 R2: int = 24 250 R3: int = 16 251 R4: int = 63
The Blake2b flavor (64-bits) of Blake2. This version is used in the pre-compiled contract.