Coverage for src\pqlattice\random\_lwe.py: 31%
36 statements
« prev ^ index » next coverage.py v7.11.0, created at 2026-01-10 12:32 +0100
« prev ^ index » next coverage.py v7.11.0, created at 2026-01-10 12:32 +0100
1import numpy as np
3from ..integer._modring import cmodl, mod
4from ..typing import Matrix, Vector
5from ._distribution import DiscreteGaussian, Uniform
8class LWE:
9 def __init__(self, n: int, q: int, sigma: float, secret_distribution: str, seed: int):
10 """
11 Creates LWE sampler with DiscreteGuassianDistribution centered at 0 as noise sampler
13 Parameters
14 ----------
15 n : int
16 length of secret vector
17 q : int
18 modulus
19 sigma : float
20 sigma value for DiscreteGaussianDistribution
21 seed : int
22 seed for random number generator
23 """
24 self.n = n
25 self.q = q
26 self.U = Uniform(0, q - 1, seed=seed)
27 self.D = DiscreteGaussian(sigma, seed=seed)
29 secret = self.U.sample_vector(n)
30 if secret_distribution == "uniform":
31 self._secret = secret
32 elif secret_distribution == "binary":
33 self._secret = mod(secret, 2)
34 elif secret_distribution == "ternary":
35 self._secret = cmodl(secret, 3)
36 else:
37 raise ValueError(f"Unknown distribution {secret_distribution}, expected uniform|binary|ternary")
39 @property
40 def secret(self) -> Vector:
41 """
42 Retrieve underlying secret
44 Returns
45 -------
46 Vector
47 s: n-vector
48 """
49 return self._secret
51 def set_secret(self, secret: Vector) -> None:
52 """
53 Set the underlying secret
55 Parameters
56 ----------
57 secret : Vector
58 secret vector to set
60 Raises
61 ------
62 ValueError
63 when lenght of the provided vector is not correct with the parameter of the LWE sampler
64 """
65 if secret.shape[0] != self.n:
66 raise ValueError(f"expected {self.n} dimension of secret, got {secret.shape[0]}")
68 self._secret = secret
70 def sample_matrix(self, m: int) -> tuple[Matrix, Vector]:
71 """
72 Generates a full matrix system (A, b) with 'm' samples.
74 Parameters
75 ----------
76 m : int
77 how many samples should the resulting matrix have
79 Returns
80 -------
81 tuple[Matrix, Vector]:
83 A (Matrix): m x n matrix (Uniform mod q)
84 b (Vector): m-vector (As + e mod q)
85 """
86 A = self.U.sample_matrix(m, self.n)
87 e = self.D.sample_vector(m)
89 b = mod(A @ self.secret + e, self.q)
91 return A, b
93 def next_sample(self) -> tuple[Vector, int]:
94 """
95 Generates a single sample pair (a, b).
97 Returns
98 -------
99 tuple[Vector, int]
100 a (Vector): n-vector (Uniform mod q)
101 b (int): as + e mod q
102 """
103 a = self.U.sample_vector(self.n)
104 e = self.D.sample_int()
106 _as: int = np.dot(a, self.secret)
107 b = mod(_as + e, self.q)
109 return a, b