-
Notifications
You must be signed in to change notification settings - Fork 274
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
108 changed files
with
2,735 additions
and
1,432 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
150 changes: 91 additions & 59 deletions
150
src/starkware/cairo/common/cairo_keccak/keccak_utils.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,80 +1,112 @@ | ||
from typing import List | ||
# Implementation of Keccak-f[u*u*w], as defined in https://en.wikipedia.org/wiki/SHA-3. | ||
|
||
OFFSETS = list( | ||
zip( | ||
*[ | ||
[0, 1, 62, 28, 27], | ||
[36, 44, 6, 55, 20], | ||
[3, 10, 43, 25, 39], | ||
[41, 45, 15, 21, 8], | ||
[18, 2, 61, 56, 14], | ||
] | ||
) | ||
) | ||
import operator | ||
from functools import reduce | ||
from typing import Iterable, List, Optional | ||
|
||
ROUND_CONSTANTS = [ | ||
0x0000000000000001, | ||
0x0000000000008082, | ||
0x800000000000808A, | ||
0x8000000080008000, | ||
0x000000000000808B, | ||
0x0000000080000001, | ||
0x8000000080008081, | ||
0x8000000000008009, | ||
0x000000000000008A, | ||
0x0000000000000088, | ||
0x0000000080008009, | ||
0x000000008000000A, | ||
0x000000008000808B, | ||
0x800000000000008B, | ||
0x8000000000008089, | ||
0x8000000000008003, | ||
0x8000000000008002, | ||
0x8000000000000080, | ||
0x000000000000800A, | ||
0x800000008000000A, | ||
0x8000000080008081, | ||
0x8000000000008080, | ||
0x0000000080000001, | ||
0x8000000080008008, | ||
] | ||
from starkware.python.math_utils import div_ceil | ||
from starkware.python.utils import from_bytes, to_bytes | ||
|
||
|
||
def rot_left(x, n): | ||
def rot_left(x, n, w): | ||
""" | ||
Rotates a 64-bit number n bits to the left. | ||
Rotates a w-bit number n bits to the left. | ||
""" | ||
return ((x << n) & (2 ** 64 - 1)) | (x >> (64 - n)) | ||
return ((x << n) & (2 ** w - 1)) | (x >> (w - n)) | ||
|
||
|
||
def precompute_offsets(w: int, u: int, alpha: int, beta: int) -> List[List[int]]: | ||
x, y = 1, 0 | ||
xy_pairs = set() | ||
offset = 0 | ||
result = [[0] * u for _ in range(u)] | ||
for t in range(1, u ** 2): | ||
xy_pairs.add((x, y)) | ||
offset = (offset + t) % w | ||
result[x][y] = offset | ||
# The official definition is (alpha, beta) = (3, 2) for u = 5. Any other u has no official | ||
# definition, but the iteration must go over each (x, y) != (0, 0) pair exactly once. | ||
x, y = y, (beta * x + alpha * y) % u | ||
assert len(xy_pairs) == u ** 2 - 1 | ||
return result | ||
|
||
|
||
def keccak_round(a: List[List[int]], rc: int) -> List[List[int]]: | ||
def precompute_rc(ell: int, rounds: Optional[int] = None) -> Iterable[int]: | ||
x = 1 | ||
if rounds is None: | ||
rounds = 12 + 2 * ell | ||
for _ in range(rounds): | ||
rc = 0 | ||
for m in range(ell + 1): | ||
rc += (x & 1) << (2 ** m - 1) | ||
x <<= 1 | ||
x ^= 0x171 * (x >> 8) | ||
yield rc | ||
|
||
|
||
def keccak_round( | ||
a: List[List[int]], offsets: List[List[int]], rc: int, w: int, u: int, alpha: int, beta: int | ||
) -> List[List[int]]: | ||
""" | ||
Performs one keccak round on a matrix of 5x5 64-bit integers. | ||
Performs one keccak round on a matrix of uxu w-bit integers. | ||
rc is the round constant. | ||
""" | ||
c = [a[x][0] ^ a[x][1] ^ a[x][2] ^ a[x][3] ^ a[x][4] for x in range(5)] | ||
d = [c[(x - 1) % 5] ^ rot_left(c[(x + 1) % 5], 1) for x in range(5)] | ||
a = [[a[x][y] ^ d[x] for y in range(5)] for x in range(5)] | ||
b = [[0] * 5 for _ in range(5)] | ||
for x in range(5): | ||
for y in range(5): | ||
b[y][(2 * x + 3 * y) % 5] = rot_left(a[x][y], OFFSETS[x][y]) | ||
|
||
a = [[b[x][y] ^ ((~b[(x + 1) % 5][y]) & b[(x + 2) % 5][y]) for y in range(5)] for x in range(5)] | ||
|
||
c = [reduce(operator.xor, a[x]) for x in range(u)] | ||
d = [c[(x - 1) % u] ^ rot_left(c[(x + 1) % u], 1, w) for x in range(u)] | ||
a = [[a[x][y] ^ d[x] for y in range(u)] for x in range(u)] | ||
b = [a[x][:] for x in range(u)] | ||
for x in range(u): | ||
for y in range(u): | ||
b[y][(beta * x + alpha * y) % u] = rot_left(a[x][y], offsets[x][y], w) | ||
a = [[b[x][y] ^ ((~b[(x + 1) % u][y]) & b[(x + 2) % u][y]) for y in range(u)] for x in range(u)] | ||
a[0][0] ^= rc | ||
return a | ||
|
||
|
||
def keccak_func(values: List[int]) -> List[int]: | ||
def keccak_func( | ||
values: List[int], | ||
ell: int = 6, | ||
u: int = 5, | ||
alpha: int = 3, | ||
beta: int = 2, | ||
rounds: Optional[int] = None, | ||
) -> List[int]: | ||
""" | ||
Computes the keccak block permutation on 25 64-bit integers. | ||
Computes the keccak block permutation on u**2 2**ell-bit integers. | ||
""" | ||
# Reshape values to a matrix. | ||
value_matrix = [[values[5 * y + x] for y in range(5)] for x in range(5)] | ||
for rc in ROUND_CONSTANTS: | ||
value_matrix = keccak_round(value_matrix, rc) | ||
value_matrix = [[values[u * y + x] for y in range(u)] for x in range(u)] | ||
w = 2 ** ell | ||
offsets = precompute_offsets(w, u, alpha, beta) | ||
for rc in precompute_rc(ell, rounds): | ||
value_matrix = keccak_round( | ||
a=value_matrix, offsets=offsets, rc=rc, w=w, u=u, alpha=alpha, beta=beta | ||
) | ||
# Reshape values to a flat list. | ||
values = [value_matrix[y][x] for x in range(5) for y in range(5)] | ||
values = [value_matrix[y][x] for x in range(u) for y in range(u)] | ||
|
||
return values | ||
|
||
|
||
def keccak_f( | ||
message: bytes, | ||
ell: int = 6, | ||
u: int = 5, | ||
alpha: int = 3, | ||
beta: int = 2, | ||
rounds: Optional[int] = None, | ||
) -> bytes: | ||
""" | ||
Computes the keccak block permutation on a u**2*2**ell-bit message (pads with zeros). | ||
""" | ||
w = 2 ** ell | ||
assert len(message) <= div_ceil(u * u * w, 8) | ||
as_bigint = from_bytes(message, byte_order="little") | ||
assert as_bigint < 2 ** (u * u * w) | ||
as_integers = [(as_bigint >> (i * w)) & (2 ** w - 1) for i in range(u ** 2)] | ||
result = keccak_func(values=as_integers, ell=ell, u=u, alpha=alpha, beta=beta, rounds=rounds) | ||
return to_bytes( | ||
sum(x << (i * w) for i, x in enumerate(result)), | ||
length=(u ** 2 * w + 7) // 8, | ||
byte_order="little", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.