Skip to content

Commit 1582fde

Browse files
Release v0.18.0 (#392)
1 parent 02e29f4 commit 1582fde

File tree

34 files changed

+768
-428
lines changed

34 files changed

+768
-428
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

hydra/garaga/hints/keccak256.py

Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
1+
from copy import deepcopy
2+
from functools import reduce
3+
from math import log
4+
from operator import xor
5+
6+
# The Keccak-f round constants.
7+
RoundConstants = [
8+
0x0000000000000001,
9+
0x0000000000008082,
10+
0x800000000000808A,
11+
0x8000000080008000,
12+
0x000000000000808B,
13+
0x0000000080000001,
14+
0x8000000080008081,
15+
0x8000000000008009,
16+
0x000000000000008A,
17+
0x0000000000000088,
18+
0x0000000080008009,
19+
0x000000008000000A,
20+
0x000000008000808B,
21+
0x800000000000008B,
22+
0x8000000000008089,
23+
0x8000000000008003,
24+
0x8000000000008002,
25+
0x8000000000000080,
26+
0x000000000000800A,
27+
0x800000008000000A,
28+
0x8000000080008081,
29+
0x8000000000008080,
30+
0x0000000080000001,
31+
0x8000000080008008,
32+
]
33+
34+
RotationConstants = [
35+
[0, 1, 62, 28, 27],
36+
[36, 44, 6, 55, 20],
37+
[3, 10, 43, 25, 39],
38+
[41, 45, 15, 21, 8],
39+
[18, 2, 61, 56, 14],
40+
]
41+
42+
Masks = [(1 << i) - 1 for i in range(65)]
43+
44+
45+
def bits2bytes(x):
46+
return (int(x) + 7) // 8
47+
48+
49+
def rol(value, left, bits):
50+
"""
51+
Circularly rotate 'value' to the left,
52+
treating it as a quantity of the given size in bits.
53+
"""
54+
top = value >> (bits - left)
55+
bot = (value & Masks[bits - left]) << left
56+
return bot | top
57+
58+
59+
def multirate_padding(used_bytes, align_bytes):
60+
"""
61+
The Keccak padding function.
62+
"""
63+
padlen = align_bytes - used_bytes
64+
if padlen == 0:
65+
padlen = align_bytes
66+
# note: padding done in 'internal bit ordering', wherein LSB is leftmost
67+
if padlen == 1:
68+
return [0x81]
69+
else:
70+
return [0x01] + ([0x00] * (padlen - 2)) + [0x80]
71+
72+
73+
def keccak_f(state):
74+
"""
75+
This is Keccak-f permutation. It operates on and
76+
mutates the passed-in KeccakState. It returns nothing.
77+
"""
78+
79+
def keccak_round(a, rc):
80+
w, h = state.W, state.H
81+
rangew, rangeh = state.rangeW, state.rangeH
82+
lanew = state.lanew
83+
zero = state.zero
84+
85+
# theta
86+
c = [reduce(xor, a[x]) for x in rangew]
87+
d = [0] * w
88+
for x in rangew:
89+
d[x] = c[(x - 1) % w] ^ rol(c[(x + 1) % w], 1, lanew)
90+
for y in rangeh:
91+
a[x][y] ^= d[x]
92+
93+
# rho and pi
94+
b = zero()
95+
for x in rangew:
96+
for y in rangeh:
97+
b[y % w][(2 * x + 3 * y) % h] = rol(
98+
a[x][y], RotationConstants[y][x], lanew
99+
)
100+
101+
# chi
102+
for x in rangew:
103+
for y in rangeh:
104+
a[x][y] = b[x][y] ^ ((~b[(x + 1) % w][y]) & b[(x + 2) % w][y])
105+
106+
# iota
107+
a[0][0] ^= rc
108+
109+
nr = 12 + 2 * int(log(state.lanew, 2))
110+
111+
for ir in range(nr):
112+
keccak_round(state.s, RoundConstants[ir])
113+
114+
115+
class KeccakState:
116+
"""
117+
A keccak state container.
118+
119+
The state is stored as a 5x5 table of integers.
120+
"""
121+
122+
W = 5
123+
H = 5
124+
125+
rangeW = range(W)
126+
rangeH = range(H)
127+
128+
@staticmethod
129+
def zero():
130+
"""
131+
Returns an zero state table.
132+
"""
133+
return [[0] * KeccakState.W for _ in KeccakState.rangeH]
134+
135+
@staticmethod
136+
def format(st):
137+
"""
138+
Formats the given state as hex, in natural byte order.
139+
"""
140+
rows = []
141+
142+
def fmt(stx):
143+
return "%016x" % stx
144+
145+
for y in KeccakState.rangeH:
146+
row = []
147+
for x in KeccakState.rangeW:
148+
row.append(fmt(st[x][y]))
149+
rows.append(" ".join(row))
150+
return "\n".join(rows)
151+
152+
@staticmethod
153+
def lane2bytes(s, w):
154+
"""
155+
Converts the lane s to a sequence of byte values,
156+
assuming a lane is w bits.
157+
"""
158+
o = []
159+
for b in range(0, w, 8):
160+
o.append((s >> b) & 0xFF)
161+
return o
162+
163+
@staticmethod
164+
def bytes2lane(bb):
165+
"""
166+
Converts a sequence of byte values to a lane.
167+
"""
168+
r = 0
169+
for b in reversed(bb):
170+
r = r << 8 | b
171+
return r
172+
173+
@staticmethod
174+
def ilist2bytes(bb):
175+
"""
176+
Converts a sequence of byte values to a bytestring.
177+
"""
178+
return bytes(bb)
179+
180+
@staticmethod
181+
def bytes2ilist(ss):
182+
"""
183+
Converts a string or bytestring to a sequence of byte values.
184+
"""
185+
return map(ord, ss) if isinstance(ss, str) else list(ss)
186+
187+
def __init__(self, bitrate, b):
188+
self.bitrate = bitrate
189+
self.b = b
190+
191+
# only byte-aligned
192+
assert self.bitrate % 8 == 0
193+
self.bitrate_bytes = bits2bytes(self.bitrate)
194+
195+
assert self.b % 25 == 0
196+
self.lanew = self.b // 25
197+
198+
self.s = KeccakState.zero()
199+
200+
def __str__(self):
201+
return KeccakState.format(self.s)
202+
203+
def absorb(self, bb):
204+
"""
205+
Mixes in the given bitrate-length string to the state.
206+
"""
207+
assert len(bb) == self.bitrate_bytes
208+
209+
bb += [0] * bits2bytes(self.b - self.bitrate)
210+
i = 0
211+
212+
for y in self.rangeH:
213+
for x in self.rangeW:
214+
self.s[x][y] ^= KeccakState.bytes2lane(bb[i : i + 8])
215+
i += 8
216+
217+
def squeeze(self):
218+
"""
219+
Returns the bitrate-length prefix of the state to be output.
220+
"""
221+
return self.get_bytes()[: self.bitrate_bytes]
222+
223+
def get_bytes(self):
224+
"""
225+
Convert whole state to a byte string.
226+
"""
227+
out = [0] * bits2bytes(self.b)
228+
i = 0
229+
for y in self.rangeH:
230+
for x in self.rangeW:
231+
v = KeccakState.lane2bytes(self.s[x][y], self.lanew)
232+
out[i : i + 8] = v
233+
i += 8
234+
return out
235+
236+
def set_bytes(self, bb):
237+
"""
238+
Set whole state from byte string, which is assumed
239+
to be the correct length.
240+
"""
241+
i = 0
242+
for y in self.rangeH:
243+
for x in self.rangeW:
244+
self.s[x][y] = KeccakState.bytes2lane(bb[i : i + 8])
245+
i += 8
246+
247+
248+
class KeccakSponge:
249+
def __init__(self, bitrate, width, padfn, permfn):
250+
self.state = KeccakState(bitrate, width)
251+
self.padfn = padfn
252+
self.permfn = permfn
253+
self.buffer = []
254+
255+
def copy(self):
256+
return deepcopy(self)
257+
258+
def absorb_block(self, bb):
259+
assert len(bb) == self.state.bitrate_bytes
260+
self.state.absorb(bb)
261+
self.permfn(self.state)
262+
263+
def absorb(self, s):
264+
self.buffer += s
265+
266+
while len(self.buffer) >= self.state.bitrate_bytes:
267+
self.absorb_block(self.buffer[: self.state.bitrate_bytes])
268+
self.buffer = self.buffer[self.state.bitrate_bytes :]
269+
270+
def absorb_final(self):
271+
padded = self.buffer + self.padfn(len(self.buffer), self.state.bitrate_bytes)
272+
self.absorb_block(padded)
273+
self.buffer = []
274+
275+
def squeeze_once(self):
276+
rc = self.state.squeeze()
277+
self.permfn(self.state)
278+
return rc
279+
280+
def squeeze(self, l):
281+
z = self.squeeze_once()
282+
while len(z) < l:
283+
z += self.squeeze_once()
284+
return z[:l]
285+
286+
287+
class KeccakHash:
288+
"""
289+
The Keccak hash function, with a hashlib-compatible interface.
290+
"""
291+
292+
def __init__(self, bitrate_bits, capacity_bits, output_bits):
293+
# our in-absorption sponge. this is never given padding
294+
assert bitrate_bits + capacity_bits in (25, 50, 100, 200, 400, 800, 1600)
295+
self.sponge = KeccakSponge(
296+
bitrate_bits, bitrate_bits + capacity_bits, multirate_padding, keccak_f
297+
)
298+
299+
# hashlib interface members
300+
assert output_bits % 8 == 0
301+
self.digest_size = bits2bytes(output_bits)
302+
self.block_size = bits2bytes(bitrate_bits)
303+
304+
def __repr__(self):
305+
inf = (
306+
self.sponge.state.bitrate,
307+
self.sponge.state.b - self.sponge.state.bitrate,
308+
self.digest_size * 8,
309+
)
310+
return "<KeccakHash with r=%d, c=%d, image=%d>" % inf
311+
312+
def copy(self):
313+
return deepcopy(self)
314+
315+
def update(self, s):
316+
self.sponge.absorb(s)
317+
318+
def digest(self):
319+
finalised = self.sponge.copy()
320+
finalised.absorb_final()
321+
digest = finalised.squeeze(self.digest_size)
322+
return KeccakState.ilist2bytes(digest)
323+
324+
def hexdigest(self):
325+
return self.digest().hex()
326+
327+
@staticmethod
328+
def preset(bitrate_bits, capacity_bits, output_bits):
329+
"""
330+
Returns a factory function for the given bitrate, sponge capacity and output length.
331+
The function accepts an optional initial input, ala hashlib.
332+
"""
333+
334+
def create(initial_input=None):
335+
h = KeccakHash(bitrate_bits, capacity_bits, output_bits)
336+
if initial_input is not None:
337+
h.update(initial_input)
338+
return h
339+
340+
return create
341+
342+
343+
# Keccak parameter presets
344+
keccak_256 = KeccakHash.preset(1088, 512, 256)

hydra/garaga/precompiled_circuits/ec.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -951,7 +951,7 @@ def prepare_points_fake_glv(
951951
Q = (Q[0], Q[1])
952952

953953
table_P = [None, None, None]
954-
table_P[0] = (P[0], self.neg(P[0]))
954+
# table_P[0] = (P[0], self.neg(P[0])) # Unused
955955
table_P[1] = P
956956
table_P[2] = self.triple_point(P, A_weirstrass)
957957

0 commit comments

Comments
 (0)