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
def spit_le_to_uint( data: bytes, start: int, num_words: int) -> List[ethereum.base_types.Uint]:
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

@dataclass
class Blake2:
 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

max_word: int
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.

w_R1: int
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

w_R2: int
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

w_R3: int
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

w_R4: int
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

sigma_len: int
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.

def get_blake2_parameters(self, data: bytes) -> Tuple:
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.

def G(self, v: List, a: int, b: int, c: int, d: int, x: int, y: int) -> List:
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.

def compress( self, num_rounds: ethereum.base_types.Uint, h: List[ethereum.base_types.Uint], m: List[ethereum.base_types.Uint], t_0: ethereum.base_types.Uint, t_1: ethereum.base_types.Uint, f: bool) -> bytes:
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

@dataclass
class Blake2b(Blake2):
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.