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

1import numpy as np 

2 

3from ..integer._modring import cmodl, mod 

4from ..typing import Matrix, Vector 

5from ._distribution import DiscreteGaussian, Uniform 

6 

7 

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 

12 

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) 

28 

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") 

38 

39 @property 

40 def secret(self) -> Vector: 

41 """ 

42 Retrieve underlying secret 

43 

44 Returns 

45 ------- 

46 Vector 

47 s: n-vector 

48 """ 

49 return self._secret 

50 

51 def set_secret(self, secret: Vector) -> None: 

52 """ 

53 Set the underlying secret 

54 

55 Parameters 

56 ---------- 

57 secret : Vector 

58 secret vector to set 

59 

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]}") 

67 

68 self._secret = secret 

69 

70 def sample_matrix(self, m: int) -> tuple[Matrix, Vector]: 

71 """ 

72 Generates a full matrix system (A, b) with 'm' samples. 

73 

74 Parameters 

75 ---------- 

76 m : int 

77 how many samples should the resulting matrix have 

78 

79 Returns 

80 ------- 

81 tuple[Matrix, Vector]: 

82 

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) 

88 

89 b = mod(A @ self.secret + e, self.q) 

90 

91 return A, b 

92 

93 def next_sample(self) -> tuple[Vector, int]: 

94 """ 

95 Generates a single sample pair (a, b). 

96 

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() 

105 

106 _as: int = np.dot(a, self.secret) 

107 b = mod(_as + e, self.q) 

108 

109 return a, b