-
Notifications
You must be signed in to change notification settings - Fork 96
/
nonces.py
59 lines (48 loc) · 2.32 KB
/
nonces.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# pylint: disable=too-many-ancestors
from typing import Union, Sequence, List, overload
from electionguard.group import ElementModQ, ElementModPOrQ
from electionguard.hash import hash_elems
class Nonces(Sequence[ElementModQ]):
"""
Creates a sequence of random elements in [0,Q), seeded from an initial element in [0,Q).
If you start with the same seed, you'll get exactly the same sequence. Optional string
or ElementModPOrQ "headers" can be included alongside the seed both at construction time
and when asking for the next nonce. This is useful when specifying what a nonce is
being used for, to avoid various kinds of subtle cryptographic attacks.
The Nonces class is a Sequence. It can be iterated, or it can be treated as an array
and indexed. Asking for a nonce is constant time, regardless of the index.
"""
def __init__(self, seed: ElementModQ, *headers: Union[str, ElementModPOrQ]) -> None:
if len(headers) > 0:
self.__seed: ElementModQ = hash_elems(seed, *headers)
else:
self.__seed = seed
# https://github.com/python/mypy/issues/4108
@overload
def __getitem__(self, index: int) -> ElementModQ:
pass
@overload
def __getitem__(self, index: slice) -> List[ElementModQ]:
pass
def __getitem__(
self, index: Union[slice, int]
) -> Union[ElementModQ, List[ElementModQ]]:
if isinstance(index, int):
return self.get_with_headers(index)
if isinstance(index.stop, int):
# Handling slices is a pain: https://stackoverflow.com/a/42731787
indices = range(index.start or 0, index.stop, index.step or 1)
return [self[i] for i in indices]
raise TypeError("Cannot take unbounded slice of Nonces")
def __len__(self) -> int:
raise TypeError("Nonces does not have finite length")
def get_with_headers(self, item: int, *headers: str) -> ElementModQ:
"""
Gets an item from the sequence at any offset. Headers can be included
to optionally help specify what a nonce is being used for.
:param item: Index into the nonces.
:param headers: Optional string headers.
"""
if item < 0:
raise TypeError("Nonces do not support negative indices.")
return hash_elems(self.__seed, item, *headers)