diff --git a/cryptomite/circulant.py b/cryptomite/circulant.py new file mode 100644 index 0000000..ff1cb7a --- /dev/null +++ b/cryptomite/circulant.py @@ -0,0 +1,130 @@ +""" +Circulant is a seeded extractor that takes an input of +n - 1 bits and a seed of n bits, where n is prime, to +produce some error-perfect random bits. +""" +from __future__ import annotations + +from math import floor, log2 +from typing import cast + +from cryptomite.utils import BitsT, closest_prime, conv, log_2 + +__all__ = ['Circulant'] + + +class Circulant: + """ Circulant extractor based on [Foreman23]_. """ + def __init__(self, n: int, m: int): + """Create a Circulant Extractor. + + Parameters + ---------- + n : int + The length of the input bits. + *** n + 1 should be prime. *** + m : int + The length of the output bits. + """ + self.n, self.m = n, m + + def extract(self, input1: BitsT, input2: BitsT) -> BitsT: + """ Extract randomness. + + Parameters + ---------- + input1 : list of bits + The first list of bits, the 'input'. + input2 : list of bits + The second list of bits, the '(weak) seed'. + + Returns + ------- + list of bits + The extracted output. + """ + n, m = self.n, self.m + assert len(input1) == len(input2) - 1 == n + assert n >= m + n = n + 1 + l = log_2(2 * n - 2) + L = 1 << l + input1 = input1 + [0] + input1, input2 = list(input1), list(input2) + input1 = input1[0:1] + input1[1:][::-1] + [0] * (L - n) + input2 = input2 + [0] * (L - len(input2)) + conv_output = conv(l, input1, input2) + output: BitsT = cast(BitsT, [ + (conv_output[i] + conv_output[i + n]) & 1 for i in range(m)]) + return output + + @staticmethod + def from_params( + min_entropy1: float, + min_entropy2: float, + log2_error: float, + input_length1: int, + input_length2: int, + markov_q_proof: bool, + verbose: bool = True) -> Circulant: + """ + Calculate a valid input and output size for this extractor, + given the initial lengths and min-entropies of the input sources + and generate the associated extractor. + + The input_length2 must be prime, else the code will chose a + valid input_length2 choice and adjust the other parameters + accordingly. + The min_entropy inputs are a lower bound on the + :term:`min-entropy` of the related input string. + + Parameters + ---------- + min_entropy1 : float + The min-entropy of input source 1, the 'input'. + min_entropy2 : float + The min-entropy of input source 2, the '(weak) seed'. + log2_error : float + The acceptable maximum extractor error, in the + form error = b where extractor error = :math:`2 ^ b`. + input_length1 : int + The initial length of input source. + input_length2 : int + The initial length of the (weak) seed. + markov_q_proof : bool + Boolean indicator of whether the extractor parameters + should be calculated to account for being quantum-proof + in the Markov model or not. + + Returns + ------- + Circulant + The Circulant extractor. + """ + if log2_error >= 0: + raise Exception("""Cannot extract with these parameters. + log2_error must be < 0.""") + input_length = closest_prime((input_length1 + input_length2)//2) + if input_length1 > input_length - 1: + min_entropy1 -= input_length1 - input_length + if input_length2 > input_length: + min_entropy2 -= input_length2 - input_length + output_length = floor(min_entropy1 + min_entropy2 + - input_length + 2 * log2_error) + if markov_q_proof: + output_length = floor(0.2 * (min_entropy1 + min_entropy2 + - input_length + 8 * log2_error + + 8 - 4 * log2(3))) + if output_length <= 0: + raise Exception("""Cannot extract with these parameters. + Increase min_entropy1 and/or min_entropy2 + and/or log2_error.""") + if verbose: + print('Min entropy1: ', min_entropy1, + 'Min entropy2: ', min_entropy2, + 'Log error: ', log2_error, + 'Input length1: ', input_length - 1, + 'Input length2: ', input_length, + 'Output length: ', output_length) + print('Adjust length of the input and (weak) seed accordingly') + return Circulant(n=input_length, m=output_length) diff --git a/cryptomite/dodis.py b/cryptomite/dodis.py index 80cbac6..454b5a6 100644 --- a/cryptomite/dodis.py +++ b/cryptomite/dodis.py @@ -7,13 +7,13 @@ from math import floor, log2 from typing import cast -from cryptomite.utils import BitsT, conv, log_2, na_set +from cryptomite.utils import BitsT, closest_na_set, conv, log_2 __all__ = ['Dodis'] class Dodis: - """ Dodis extractor based on [Dodis20]_. """ + """ Dodis extractor based on [Dodis2004]_. """ def __init__(self, n: int, m: int): """Create a Dodis Extractor. @@ -21,6 +21,7 @@ def __init__(self, n: int, m: int): ---------- n : int The length of the two input bits. + *** This should be prime with primitive root 2. *** m : int The length of the output bits. """ @@ -32,9 +33,9 @@ def extract(self, input1: BitsT, input2: BitsT) -> BitsT: Parameters ---------- input1 : list of bits - The first list of bits. + The first list of bits, the 'input'. input2 : list of bits - The second list of bits. + The second list of bits, the '(weak) seed'. Returns ------- @@ -56,55 +57,71 @@ def extract(self, input1: BitsT, input2: BitsT) -> BitsT: @staticmethod def from_params( + min_entropy1: float, + min_entropy2: float, + log2_error: float, input_length1: int, input_length2: int, - entropy1: int, - entropy2: int, - error: int, - q_proof: bool) -> Dodis: + markov_q_proof: bool, + verbose: bool = True) -> Dodis: """ - Calculate the input size and output size for this 2-source - extractor. + Calculate a valid input and output size for this extractor, + given the initial lengths and min-entropies of the input sources + and generate the associated extractor. - The input_length -1 must be in :py:func:`~.na_set`. - The entropy inputs are a lower bound on the :term:`min-entropy` - of the related input string. + The input_length must be prime with primitive root 2, else + the code will chose a valid input_length choice and adjust the + other parameters accordingly. + The min entropy inputs are a lower bound on the + :term:`min-entropy` of the related input string. Parameters ---------- - input_length1 : int - The initial length of input source 1. - input_length2 : int - The initial length of input source 2. - entropy1 : int - The min-entropy of input source 1. - entropy2 : int - The min-entropy of input source 2. - error : int + min_entropy1 : float + The min-entropy of input source 1, the 'input'. + min_entropy2 : float + The min-entropy of input source 2, the '(weak) seed'. + log2_error : float The acceptable maximum extractor error, in the form error = b where extractor error = :math:`2 ^ b`. - q_proof : bool + input_length1 : int + The initial length of input source. + input_length2 : int + The initial length of the (weak) seed. + markov_q_proof : bool Boolean indicator of whether the extractor parameters - should be calculated to account for quantum side - information or not. + should be calculated to account for being quantum-proof + in the Markov model or not. Returns ------- Dodis The Dodis extractor. """ - if error > 0: - raise Exception('Cannot extract with these parameters.' - 'Error must be < 0.') - input_length = na_set(min(input_length1, input_length2) - 1) + 1 - entropy1 -= input_length1 - input_length - entropy2 -= input_length2 - input_length - output_length = floor( - entropy1 + entropy2 - input_length + 1 + 2 * error) - if q_proof: - output_length = floor(0.2 * (entropy1 + entropy2 - input_length) - + 8 * error + 9 - 4 * log2(3)) + if log2_error >= 0: + raise Exception("""Cannot extract with these parameters. + log2_error must be < 0.""") + input_length = closest_na_set((input_length1 + input_length2)//2) + if input_length1 > input_length: + min_entropy1 -= input_length1 - input_length + if input_length2 > input_length: + min_entropy2 -= input_length2 - input_length + output_length = floor(min_entropy1 + min_entropy2 + - input_length + 1 + 2 * log2_error) + if markov_q_proof: + output_length = floor(0.2 * (min_entropy1 + min_entropy2 + - input_length + 8 * log2_error + + 9 - 4 * log2(3))) if output_length <= 0: - raise Exception('Cannot extract with these parameters. ' - 'Increase entropy1 and/or entropy2.') + raise Exception("""Cannot extract with these parameters. + Increase min_entropy1 and/or min_entropy2 + and/or log2_error.""") + if verbose: + print('Min entropy1: ', min_entropy1, + 'Min entropy2: ', min_entropy2, + 'Log error: ', log2_error, + 'Input length1: ', input_length, + 'Input length2: ', input_length, + 'Output length: ', output_length) + print('Adjust length of the input and (weak) seed accordingly') return Dodis(n=input_length, m=output_length) diff --git a/cryptomite/toeplitz.py b/cryptomite/toeplitz.py index 49fb894..49fb329 100644 --- a/cryptomite/toeplitz.py +++ b/cryptomite/toeplitz.py @@ -4,7 +4,7 @@ """ from __future__ import annotations -from math import floor +from math import floor, log2 from typing import cast from cryptomite.utils import BitT, BitsT, conv, log_2 @@ -15,14 +15,14 @@ class Toeplitz: """Toeplitz extractor""" def __init__(self, n: int, m: int): - """ Create a Toeplitz Extractor. + """Create a Circulant Extractor. Parameters ---------- n : int - The input size (the number of columns in the matrix). + The length of the input bits. m : int - The output size (the number of rows in the matrix). + The length of the output bits. """ self.n, self.m = n, m @@ -32,9 +32,9 @@ def extract(self, input1: BitsT, input2: BitsT) -> BitsT: Parameters ---------- input1 : list of bits - The first list of bits. + The first list of bits, the 'input'. input2 : list of bits - The second list of bits. + The second list of bits, the '(weak) seed'. Returns ------- @@ -56,68 +56,93 @@ def extract(self, input1: BitsT, input2: BitsT) -> BitsT: @staticmethod def from_params( - seed_length: int, - input_length: int, - seed_entropy: int, - input_entropy: int, - error: int) -> Toeplitz: + min_entropy1: float, + min_entropy2: float, + log2_error: float, + input_length1: int, + input_length2: int, + markov_q_proof: bool, + verbose: bool = True) -> Toeplitz: """ - Calculate the input size and output size for this extractor. + Calculate a valid input and output size for this extractor, + given the initial lengths and min-entropies of the input sources + and generate the associated extractor. - The entropy input is a lower bound on the min-entropy of the - related input string. - This function defines the input size and output size for this - seeded extractor. + The min entropy inputs are a lower bound on the + :term:`min-entropy` of the related input string. Parameters ---------- - seed_length : int - The initial length of the seed. - input_length : int - The initial length of second input source. - seed_entropy : int - The min-entropy of the seed. - If the seed is uniform, this should equal - seed_length. - input_entropy : int - The min-entropy of second input source. - error : int - The acceptable maximum extractor error, in the form - error = b where extractor error = 2 ^ b. + min_entropy1 : float + The min-entropy of input source 1, the 'input'. + min_entropy2 : float + The min-entropy of input source 2, the '(weak) seed'. + log2_error : float + The acceptable maximum extractor error, in the + form error = b where extractor error = :math:`2 ^ b`. + input_length1 : int + The initial length of input source. + input_length2 : int + The initial length of the (weak) seed. + markov_q_proof : bool + Boolean indicator of whether the extractor parameters + should be calculated to account for being quantum-proof + in the Markov model or not. Returns ------- Toeplitz The Toeplitz extractor. """ - if error > 0: - raise Exception('Cannot extract with these parameters. ' - 'Error must be < 0.') - if seed_length <= input_length: - raise Exception('Cannot extract with these parameters. ' - 'Increase the seed length. ' - 'The seed must be longer than the input.') - if seed_entropy >= seed_length: - output_length = input_entropy + 2 * error - assert output_length >= 0 - if seed_length > output_length + input_length - 1: - seed_length = output_length + input_length - 1 - if seed_length < output_length + input_length - 1: - output_length = seed_length - input_length + 1 - if seed_entropy < seed_length: - output_length = floor( - 1/3 * (input_entropy - 2 * (input_length - 1 - - seed_entropy) + 2 * error)) - if seed_length > output_length + input_length - 1: - if seed_length > output_length + input_length - 1: - penalty = 3*(seed_length - output_length - - input_length + 1) - output_length = floor(output_length - penalty * 2/3) - seed_length = seed_length - penalty - if seed_length < output_length + input_length - 1: - seed_length = seed_length - input_length + 1 - assert seed_length == output_length + input_length - 1 + if log2_error > 0: + raise Exception("""Cannot extract with these parameters. + log2_error must be < 0.""") + if input_length2 <= input_length1: + raise Exception("""Cannot extract with these parameters. + Increase the seed length (input_length2). + The seed must be longer than the input.""") + if min_entropy2 >= input_length2: + output_length = min_entropy1 + 2 * log2_error + if input_length2 >= output_length + input_length1 - 1: + input_length2 = output_length + input_length1 - 1 + while input_length2 < output_length + input_length1 - 1: + input_length1 -= 1 + min_entropy1 -= 1 + output_length = min_entropy1 + 2 * log2_error + if min_entropy2 < input_length2: + output_length = floor(1/2 * (min_entropy1 + min_entropy2 + - input_length1 + 1 + + 2 * log2_error)) + while input_length2 > output_length + input_length1 - 1: + input_length2 -= 1 + min_entropy2 -= 1 + output_length = floor(1/2 * (min_entropy1 + min_entropy2 + - input_length1 + 1 + + 2 * log2_error)) + if input_length2 < output_length + input_length1 - 1: + output_length = input_length2 - input_length1 + 1 + if markov_q_proof: + output_length = floor((1/6) * (min_entropy1 + min_entropy2 + - input_length1 + 8 * log2_error + + 9 - 4 * log2(3))) + while input_length2 > output_length + input_length1 - 1: + input_length2 -= 1 + min_entropy2 -= 1 + output_length = floor((1/6) * (min_entropy1 + min_entropy2 + - input_length1 + 8 * log2_error + + 9 - 4 * log2(3))) + if input_length2 < output_length + input_length1 - 1: + output_length = input_length2 - input_length1 + 1 if output_length <= 0: - raise Exception('Cannot extract with these parameters. ' - 'Increase input_entropy and/or seed_entropy.') - return Toeplitz(n=input_length, m=output_length) + raise Exception("""Cannot extract with these parameters. + Increase min_entropy1 and/or min_entropy2 + and/or log2_error.""") + if verbose: + print('Min entropy1: ', min_entropy1, + 'Min entropy2: ', min_entropy2, + 'Log error: ', log2_error, + 'Input length1: ', input_length1, + 'Input length2: ', input_length2, + 'Output length: ', output_length) + print('Adjust length of the input and (weak) seed accordingly') + return Toeplitz(n=input_length1, m=output_length) diff --git a/cryptomite/trevisan.py b/cryptomite/trevisan.py index 77a892c..91e2a9b 100644 --- a/cryptomite/trevisan.py +++ b/cryptomite/trevisan.py @@ -5,7 +5,7 @@ __all__ = ['Trevisan'] -from math import ceil, log, log2 +from math import ceil, exp, floor, log, log2 from cryptomite import _cryptomite @@ -19,8 +19,7 @@ def __init__(self, n: int, k: float, max_eps: float): seed bits and outputs `m` bits with total worst case error of `max_eps`. The parameters for the weak designs and 1-bit extractors are computed from `n`, `k`, and `max_eps`. To use - the Trevisan extractor, provide `n`, `k` and `max_eps` and call - the method `get_seed_length()` to get the required seed length. + the Trevisan extractor, provide `n`, `k` and `max_eps`. Parameters ---------- @@ -34,23 +33,23 @@ def __init__(self, n: int, k: float, max_eps: float): self.config = _cryptomite.TrevisanConfig(n, k, max_eps) self.ext = _cryptomite.Trevisan(self.config) - def extract(self, source: list[bool], seed: list[bool]) -> list[bool]: + def extract(self, input1: list[bool], input2: list[bool]) -> list[bool]: """ Load the source and the seed. Parameters ---------- - source : list of bool - The input bits. - seed : list of bool - The seed bits. + input1 : list of bits + The first list of bits, the 'input'. + input2 : list of bits + The second list of bits, the '(weak) seed'. Returns ------- list of bool The output bits from the extractor. """ - self.ext.load_source(source, seed) + self.ext.load_source(input1, input2) m = self.config.m bits = [] @@ -61,63 +60,80 @@ def extract(self, source: list[bool], seed: list[bool]) -> list[bool]: @staticmethod def from_params( - seed_length: int, - input_length: int, - seed_entropy: int, - input_entropy: int, - error: int) -> Trevisan: + min_entropy1: float, + min_entropy2: float, + log2_error: float, + input_length1: int, + input_length2: int, + markov_q_proof: bool, + verbose: bool = True) -> Trevisan: """ - Calculate the input size and output size for this extractor. + Calculate a valid input and output size for this extractor, + given the initial lengths and min-entropies of the input sources + and generate the associated extractor. - The entropy input is a lower bound on the min-entropy of the - related input string. - This function defines the input size and output size for this - seeded extractor. + *** Note: at present, this function (for Trevisan) only supports + when input_length2 = min_entropy2, i.e. when the seed is + uniform. *** + The min entropy inputs are a lower bound on the + :term:`min-entropy` of the related input string. Parameters ---------- - seed_length : int - The initial length of the seed. - input_length : int - The initial length of second input source. - seed_entropy : int - The min-entropy of the seed. - If the seed is uniform, this should equal - seed_length. - input_entropy : int - The min-entropy of second input source. - error : int - The acceptable maximum extractor error, in the form - error = b where extractor error = 2 ^ b. + min_entropy1 : float + The min-entropy of input source 1, the 'input'. + min_entropy2 : float + The min-entropy of input source 2, the '(weak) seed'. + log_error : float + The acceptable maximum extractor error, in the + form error = b where extractor error = :math:`2 ^ b`. + input_length1 : int + The initial length of input source. + input_length2 : int + The initial length of the (weak) seed. + markov_q_proof : bool + Boolean indicator of whether the extractor parameters + should be calculated to account for being quantum-proof + in the Markov model or not. Returns ------- Trevisan The Trevisan extractor. """ - if error > 0: - raise Exception('Cannot extract with these parameters. ' - 'Error must be < 0.') - t = 2 * ceil(log2(input_length) + 1 - - 2 * error) - r = 1 - if seed_length <= seed_entropy: - output_length = input_entropy + 4 * error - 6 - l = max(1, ceil((log(output_length - r) - log(t - r)) + if log2_error > 0: + raise Exception("""Cannot extract with these parameters. + log2_error must be < 0.""") + if min_entropy2 != input_length2: + raise Exception("""Cannot calcuate with these parameters. + Set min_entropy2 = input_length2.""") + r = 2 * exp(1) + m = min_entropy1 + 4 * log2_error - 6 + output_length = floor(min_entropy1 + 4 * log2_error + - 4 * log2(m) - 6) + t = 2 * ceil(log2(input_length1) + 1 + - 2 * log2_error + 2 * log2(2 * output_length)) + a = max(1, ceil((log(output_length - r) - log(t - r)) + / (log(r) - log(r-1)))) + if markov_q_proof: + m = (1/7) * (min_entropy1 + 6 - 6 * log2(3) + + 12 * log2_error) + output_length = floor((1/7) * (min_entropy1 + 6 - 6 * log2(3) + + 12 * log2_error - 12 * log2(m))) + t = 2 * ceil(log2(input_length1) + 1 + - 2 * log2_error + 2 * log2(2 * output_length)) + a = max(1, ceil((log(output_length - r) - log(t - r)) / (log(r) - log(r-1)))) - if seed_length > (l + 1) * t**2: - seed_length = (l + 1) * t**2 - if seed_length < (l + 1) * t**2: - raise Exception('Cannot extract with these parameters. ' - 'Increase seed length.') - if seed_length > seed_entropy: - diff = seed_length - seed_entropy - output_length = input_entropy + 4 * error - 6 - 4 * diff - l = max(1, ceil((log(output_length - r) - log(t - r)) - / (log(r) - log(r-1)))) - if seed_length > (l + 1) * t**2: - seed_length = (l + 1) * t**2 - if seed_length < (l + 1) * t**2: - raise Exception('Cannot extract with these parameters. ' - 'Increase seed length.') - return Trevisan(n=input_length, m=output_length) + if input_length2 < 4 * a * t**2: + raise Exception("""Cannot extract with these parameters. + Increase input_length2.""") + input_length2 = 4 * a * t**2 + if verbose: + print('Min entropy1: ', min_entropy1, + 'Min entropy2: ', min_entropy2, + 'Log error: ', log2_error, + 'Input length1: ', input_length1, + 'Input length2: ', input_length2, + 'Output length: ', output_length) + print('Adjust length of the input and seed accordingly') + return Trevisan(n=input_length1, m=output_length) diff --git a/cryptomite/utils.py b/cryptomite/utils.py index d3bfc5f..8b53d9b 100644 --- a/cryptomite/utils.py +++ b/cryptomite/utils.py @@ -8,7 +8,9 @@ from cryptomite._cryptomite import NTT, mul_vec -__all__ = ['is_prime', 'prime_facto', 'na_set', 'von_neumann'] +__all__ = ['is_prime', 'prime_facto', 'previous_prime', 'next_prime', + 'closest_prime', 'previous_na_set', 'next_na_set', + 'closest_na_set', 'von_neumann'] BitT = Literal[0, 1] @@ -31,11 +33,11 @@ def conv(l: int, source1: Sequence[int], source2: Sequence[int]) -> list[int]: Parameters ---------- l : int - log_2 of the size of the convolution + log_2 of the size of the convolution. source1: list of int - first vector + first vector. source2: list of int - second vector + second vector. Returns ------- @@ -58,7 +60,7 @@ def is_prime(n: int) -> bool: Parameters ---------- n : int - integer to check for primality + integer to check for primality. Returns ------- @@ -79,7 +81,7 @@ def prime_facto(n: int) -> tuple[list[int], list[int]]: Parameters ---------- n : int - number to check + number to check. Returns ------- @@ -113,22 +115,99 @@ def prime_facto(n: int) -> tuple[list[int], list[int]]: return factors2, powers -def na_set(k: int) -> int: +def previous_prime(k: int) -> int: """ - Ensure the number of runs falls within the correct set: - i.e. that we run enough times. + Finds the largest integer smaller than or equal to the input + that is prime. Parameters ---------- k : int - number to check is in the set. + number to check is prime. Returns ------- int : - This number +1 is in na_set. + prime. """ + k -= 1 + if k % 2 != 0: + k = k - 1 + stop = False + while not stop: + stop = True + while not is_prime(k + 1): + k = k - 2 + return k + 1 + +def next_prime(k: int) -> int: + """ + Finds the smallest integer larger than or equal to the input + that is prime. + + Parameters + ---------- + k : int + number to check is prime. + + Returns + ------- + int : + prime. + """ + k -= 1 + if k % 2 != 0: + k = k + 1 + stop = False + while not stop: + stop = True + while not is_prime(k + 1): + k = k + 2 + return k + 1 + + +def closest_prime(k: int) -> int: + """ + Finds the closest integer to the input that is prime. + If both directions are equidistant, outputs the prime less + than the input. + + Parameters + ---------- + k : int + number to check is prime. + + Returns + ------- + int : + prime. + """ + next_p = next_prime(k) + previous_p = previous_prime(k) + if next_p - k >= k - previous_p: + out = previous_p + else: + out = next_p + return out + + +def previous_na_set(k: int) -> int: + """ + Finds the largest integer smaller than the input that is prime + with primitive root 2. + + Parameters + ---------- + k : int + number to check is prime with primitive root 2. + + Returns + ------- + int : + prime with primitive root 2. + """ + k -= 1 if k % 2 != 0: k = k - 1 stop = False @@ -142,7 +221,65 @@ def na_set(k: int) -> int: stop = False k = k - 2 break - return k + return k + 1 + + +def next_na_set(k: int) -> int: + """ + Finds the smallest integer larger than the input that is prime + with primitive root 2. + + Parameters + ---------- + k : int + number to check is prime with primitive root 2. + + Returns + ------- + int : + prime with primitive root 2. + """ + k -= 1 + if k % 2 != 0: + k = k + 1 + stop = False + while not stop: + stop = True + while not is_prime(k + 1): + k = k + 2 + primes, _ = prime_facto(k) + for prime in primes: + if pow(2, k // prime, k + 1) == 1: + stop = False + k = k + 2 + break + return k + 1 + + +def closest_na_set(k: int) -> int: + """ + Finds the closest integer to the input that is prime with + primitive root 2. + If both directions are equidistant, outputs the prime with + primitive root 2 less than the input. + + Parameters + ---------- + k : int + number to check is prime with primitive root 2. + + Returns + ------- + int : + prime with primitive root 2. + """ + next_p = next_na_set(k) + previous_p = previous_na_set(k) + if next_p - k >= k - previous_p: + out = previous_p + else: + out = next_p + return out def von_neumann(bits: BitsT) -> BitsT: diff --git a/docs/_static/.DS_Store b/docs/_static/.DS_Store new file mode 100644 index 0000000..ebdd677 Binary files /dev/null and b/docs/_static/.DS_Store differ diff --git a/docs/_static/images/.DS_Store b/docs/_static/images/.DS_Store new file mode 100644 index 0000000..b51e8ee Binary files /dev/null and b/docs/_static/images/.DS_Store differ diff --git a/docs/_static/images/cryptomite_logo_blur.png b/docs/_static/images/cryptomite_logo_blur.png new file mode 100644 index 0000000..23fec66 Binary files /dev/null and b/docs/_static/images/cryptomite_logo_blur.png differ diff --git a/docs/_static/images/cryptomite_logo_full_blur.png b/docs/_static/images/cryptomite_logo_full_blur.png new file mode 100644 index 0000000..3a3ee2b Binary files /dev/null and b/docs/_static/images/cryptomite_logo_full_blur.png differ diff --git a/docs/_static/images/favicon.png b/docs/_static/images/favicon.png new file mode 100644 index 0000000..2e9c66e Binary files /dev/null and b/docs/_static/images/favicon.png differ diff --git a/docs/bibliography.rst b/docs/bibliography.rst index 8e075ff..7edd9a9 100644 --- a/docs/bibliography.rst +++ b/docs/bibliography.rst @@ -15,4 +15,4 @@ Bibliography .. [Mauer2012] W. Mauerer, C. Portmann, and V. B. Scholz, `A modular framework for randomness extraction based on Trevisan’s construction `_, Pre-print (2012) -.. [Dodis20] Y. Dodis, A. Elbaz, R. Oliveira, and R. Raz, `Improved randomness extraction from two independent sources `_ in Proceedings RANDOM, vol. 3122, pp. 334–344 (2004) +.. [Dodis2004] Y. Dodis, A. Elbaz, R. Oliveira, and R. Raz, `Improved randomness extraction from two independent sources `_ in Proceedings RANDOM, vol. 3122, pp. 334–344 (2004) diff --git a/docs/conf.py b/docs/conf.py index 25ed598..66d96e5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -75,7 +75,7 @@ # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] -html_logo = '_static/images/logo.png' -html_favicon = '_static/images/favicon.ico' +html_logo = '_static/images/cryptomite_logo_blur.png' +html_favicon = '_static/images/favicon.png' numfig = True diff --git a/docs/cryptomite.rst b/docs/cryptomite.rst index c5bae58..6bc2224 100644 --- a/docs/cryptomite.rst +++ b/docs/cryptomite.rst @@ -4,6 +4,14 @@ API Reference Submodules ---------- +cryptomite.circulant module +----------------------- + +.. automodule:: cryptomite.circulant + :members: + :undoc-members: + :show-inheritance: + cryptomite.dodis module ----------------------- diff --git a/docs/figures/performance.png b/docs/figures/performance.png index d371c25..d3a3b0e 100644 Binary files a/docs/figures/performance.png and b/docs/figures/performance.png differ diff --git a/docs/gettingstarted.rst b/docs/gettingstarted.rst index a1ffc75..1fe95cc 100644 --- a/docs/gettingstarted.rst +++ b/docs/gettingstarted.rst @@ -4,6 +4,17 @@ In the following, we use the notation :math:`n_1, n_2` to denote the length and any first or second input string respectively. Additionally, :math:`m` denotes the length of an output string, :math:`\epsilon` the extractor error and :math:`O(.)` denotes the asymptotic behaviour of a function. +:py:class:`.Circulant` +------------------ +The Circulant extractor is a :term:`seeded randomness extractor`, meaning that it requires two independent bit +strings of randomness, where one is already (near-)perfectly random (called a seed). +It requires the weak input to be of length :math:`n_1 = n_2 - 1`, where the length of the seed :math:`n_2` is prime +and outputs approximately :math:`m \approx k_1 + k_2 - n_1` when considering classical side information or in the quantum product-source model +and :math:`m \approx \frac{1}{5}(k_1 + k_2 - n_1)`. +Our implementation of this extractor has near-linear computational complexity. + +This extractor is best suited to scenarios where a seeded extractor is required in both the classical and quantum side information setting. + :py:class:`.Dodis` ------------------ The Dodis extractor is a :term:`2-source randomness extractor`, meaning that it requires two independent bit diff --git a/docs/performance.rst b/docs/performance.rst index e98b635..dd3e5ad 100644 --- a/docs/performance.rst +++ b/docs/performance.rst @@ -10,6 +10,6 @@ The varying degrees of computational efficiency for the extractors of :py:mod:`c Some observations performance observations are: * The :py:func:`.von_neumann` extractor is able to output at speeds above 7Mbit/s. -* The :py:class:`.Dodis` and :py:class:`.Toeplitz` extractors are able to output at speeds of up to 1Mbit/s. The generation speed is faster for shorter input lengths. +* The :py:class:`.Circulant`, :py:class:`.Dodis` and :py:class:`.Toeplitz` extractors are able to output at speeds of up to 1Mbit/s. The generation speed is faster for shorter input lengths. * The :py:class:`.Trevisan` extractor can generate output at speeds comparable to the :py:class:`.Toeplitz` and :py:class:`.Dodis` extractors only when the input size is extremely short. * The :py:class:`.Trevisan` extractor unable to generate a non-vanishing bits/second rate for input lengths greater than approximately 30,000. diff --git a/test/test_circulant.py b/test/test_circulant.py new file mode 100644 index 0000000..b02915d --- /dev/null +++ b/test/test_circulant.py @@ -0,0 +1,22 @@ +import pytest +from cryptomite.circulant import Circulant + + +circulant_testcases = [ + (2, 1, [0, 1], [1, 1, 1], [1]), + (2, 2, [1, 0], [1, 1, 0], [1, 1]), + (2, 2, [0, 1], [0, 0, 0], [0, 0]), + (5, 5, [1, 0, 1, 0, 0], [1, 1, 1, 0, 1, 0], [0, 1, 0, 0, 0]), + ( + 8, + 8, + [0, 0, 1, 1, 0, 0, 0, 1], + [1, 1, 1, 0, 1, 1, 1, 1, 0], + [0, 1, 1, 1, 1, 1, 0, 1], + ), +] + + +@pytest.mark.parametrize("n,m,x,y,z", circulant_testcases) +def test_circulant(n, m, x, y, z): + assert Circulant(n, m).extract(x, y) == z