From c9cb29e9b787dd8e4309808d3a5a1709c2a27cd4 Mon Sep 17 00:00:00 2001 From: Mathwizard1 Date: Sun, 26 Oct 2025 01:07:44 +0530 Subject: [PATCH] CompactBoolList solution --- cryptomite/__init__.py | 6 ++- cryptomite/trevisan.py | 6 +-- cryptomite/utils.py | 104 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 110 insertions(+), 6 deletions(-) diff --git a/cryptomite/__init__.py b/cryptomite/__init__.py index e147c9b..23c060f 100644 --- a/cryptomite/__init__.py +++ b/cryptomite/__init__.py @@ -11,7 +11,9 @@ 'Raz', 'Toeplitz', 'Trevisan', - 'von_neumann' + 'von_neumann', + + 'CompactBoolList' ] from cryptomite import circulant, dodis, raz, toeplitz, trevisan, utils @@ -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' diff --git a/cryptomite/trevisan.py b/cryptomite/trevisan.py index cdc6aeb..ca8fb36 100644 --- a/cryptomite/trevisan.py +++ b/cryptomite/trevisan.py @@ -9,7 +9,7 @@ __all__ = ['Trevisan'] from cryptomite import _cryptomite - +from cryptomite.utils import CompactBoolList class Trevisan: """ @@ -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. @@ -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) diff --git a/cryptomite/utils.py b/cryptomite/utils.py index 479e0c1..2ff9eda 100644 --- a/cryptomite/utils.py +++ b/cryptomite/utils.py @@ -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: """