Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions cryptomite/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
'Raz',
'Toeplitz',
'Trevisan',
'von_neumann'
'von_neumann',

'CompactBoolList'
]

from cryptomite import circulant, dodis, raz, toeplitz, trevisan, utils
Expand All @@ -20,6 +22,6 @@
from cryptomite.raz import Raz
from cryptomite.toeplitz import Toeplitz
from cryptomite.trevisan import Trevisan
from cryptomite.utils import von_neumann
from cryptomite.utils import von_neumann, CompactBoolList

__version__ = '0.3.0'
6 changes: 3 additions & 3 deletions cryptomite/trevisan.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
__all__ = ['Trevisan']

from cryptomite import _cryptomite

from cryptomite.utils import CompactBoolList

class Trevisan:
"""
Expand All @@ -31,7 +31,7 @@ def __init__(self, n: int, k: float, error: float):
self.config = _cryptomite.TrevisanConfig(n, k, error)
self.ext = _cryptomite.Trevisan(self.config)

def extract(self, input1: list[bool], input2: list[bool]) -> list[bool]:
def extract(self, input1: CompactBoolList, input2: CompactBoolList) -> CompactBoolList:
"""
Extract randomness.

Expand All @@ -50,7 +50,7 @@ def extract(self, input1: list[bool], input2: list[bool]) -> list[bool]:
self.ext.load_source(input1, input2)

m = self.config.m
bits = []
bits = CompactBoolList()
for i in range(m):
bit = self.ext.extract_bit(i)
bits.append(bit)
Expand Down
104 changes: 103 additions & 1 deletion cryptomite/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,118 @@
from math import sqrt
from typing import Literal, Sequence

# For the CompactBoolList
from typing import overload

from cryptomite._cryptomite import BigNTT, NTT

__all__ = ['is_prime', 'prime_facto', 'previous_prime', 'next_prime',
'closest_prime', 'previous_na_set', 'next_na_set',
'closest_na_set', 'suggest_extractor', 'von_neumann']
'closest_na_set', 'suggest_extractor', 'von_neumann',

'CompactBoolList'
]


BitT = Literal[0, 1]
BitsT = Sequence[BitT]

class CompactBoolList:
"""
A compact list of booleans using bit-level storage,
designed to interface with functions expecting list[bool].
"""

############ Python native methods ##############
def __init__(self, iterable: BitsT|Sequence[bool]|Sequence|None= None):
self._data = bytearray()
self._length = 0
self._index: int = 0

if iterable is not None:
for item in iterable:
self.append(item)

def __len__(self):
return self._length

def _get_byte_and_bit_index(self, index: int) -> tuple[int, int]:
""" Helper functions for getter """

# Handle negative indexing for convenience
if index < 0:
index += self._length

byte_index = index // 8
bit_index = index % 8
return byte_index, bit_index

def _set_byte_and_bit_index(self, index: int, value: BitT|bool):
""" Helper functions for setter """

byte_idx, bit_idx = self._get_byte_and_bit_index(index)
if value:
self._data[byte_idx] |= (1 << bit_idx)
else:
self._data[byte_idx] &= ~(1 << bit_idx)

### Type check consistency
@overload
def __getitem__(self, index: int) -> bool: ...

@overload
def __getitem__(self, index: slice) -> CompactBoolList: ...

# Actual function signature
def __getitem__(self, index: int|slice) -> bool|CompactBoolList:
# --- Slice Handling ---
if isinstance(index, slice):
start, stop, step = index.indices(self._length)
return self.__class__([self[i] for i in range(start, stop, step)])

# --- Integer Handling ---
# Boundary check for index
if not (-self._length <= index < self._length):
raise IndexError("Index out of range")

byte_idx, bit_idx = self._get_byte_and_bit_index(index)
mask = 1 << bit_idx
return (self._data[byte_idx] & mask) != 0

def __setitem__(self, index: int, value: BitT|bool):
# Boundary check for index
if not (-self._length <= index < self._length):
raise IndexError("Index out of range")

self._set_byte_and_bit_index(index, value)

def __iter__(self):
return self

def __next__(self) -> bool:
if self._index < self._length:
value = self.__getitem__(self._index)
self._index += 1
return value
else:
self._index = 0
raise StopIteration

def append(self, value: BitT|bool):
if self._length % 8 == 0:
self._data.append(0)

self._set_byte_and_bit_index(self._length, value)
self._length += 1

def __repr__(self) -> str:
list_representation = list(self)
return f"{self.__class__.__name__}({list_representation!r})"

############## Custom methods ##############
def to_list(self) -> list[bool]:
"""Converts to a standard list[bool] for functions expecting it."""
return list(self)

def log_2(n: int) -> int:
"""
Expand Down