1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
use poulpy_hal::{
api::ScratchAvailable,
layouts::{Backend, DataMut, Module, Scratch},
source::Source,
};
use crate::{
encryption::{GLWEEncryptSk, GLWEEncryptSkInternal, SIGMA},
layouts::{
GLWECompressedSeedMut, GLWEInfos, GLWEPlaintextToRef, LWEInfos,
compressed::{GLWECompressed, GLWECompressedToMut},
prepared::GLWESecretPreparedToRef,
},
};
impl GLWECompressed<Vec<u8>> {
/// Returns the scratch buffer size in bytes required by [`GLWECompressed::encrypt_sk`].
pub fn encrypt_sk_tmp_bytes<M, A, BE: Backend>(module: &M, infos: &A) -> usize
where
A: GLWEInfos,
M: GLWECompressedEncryptSk<BE>,
{
module.glwe_compressed_encrypt_sk_tmp_bytes(infos)
}
}
impl<D: DataMut> GLWECompressed<D> {
/// Encrypts a plaintext under a secret key, producing a compressed GLWE ciphertext.
///
/// The mask is deterministically generated from `seed_xa` rather than stored explicitly.
/// Only the ciphertext body and the seed are retained in the output.
///
/// - `pt`: the plaintext to encrypt.
/// - `sk`: the GLWE secret key in prepared form.
/// - `seed_xa`: seed for deterministic mask generation.
/// - `source_xe`: PRNG source for sampling encryption noise.
/// - `scratch`: scratch buffer (see [`GLWECompressed::encrypt_sk_tmp_bytes`] for sizing).
#[allow(clippy::too_many_arguments)]
pub fn encrypt_sk<M, P, S, BE: Backend>(
&mut self,
module: &M,
pt: &P,
sk: &S,
seed_xa: [u8; 32],
source_xe: &mut Source,
scratch: &mut Scratch<BE>,
) where
M: GLWECompressedEncryptSk<BE>,
P: GLWEPlaintextToRef,
S: GLWESecretPreparedToRef<BE>,
{
module.glwe_compressed_encrypt_sk(self, pt, sk, seed_xa, source_xe, scratch);
}
}
/// Compressed secret-key encryption of a GLWE ciphertext.
///
/// Produces a [`GLWECompressed`] where the mask is derived from a seed
/// instead of being stored explicitly.
pub trait GLWECompressedEncryptSk<BE: Backend> {
/// Returns the scratch buffer size in bytes required by
/// [`glwe_compressed_encrypt_sk`](Self::glwe_compressed_encrypt_sk).
fn glwe_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize
where
A: GLWEInfos;
/// Encrypts a plaintext under a GLWE secret key into a compressed GLWE ciphertext.
///
/// - `res`: output compressed GLWE ciphertext.
/// - `pt`: the plaintext to encrypt.
/// - `sk`: the GLWE secret key in prepared form.
/// - `seed_xa`: seed for deterministic mask generation.
/// - `source_xe`: PRNG source for sampling encryption noise.
/// - `scratch`: scratch buffer.
fn glwe_compressed_encrypt_sk<R, P, S>(
&self,
res: &mut R,
pt: &P,
sk: &S,
seed_xa: [u8; 32],
source_xe: &mut Source,
scratch: &mut Scratch<BE>,
) where
R: GLWECompressedToMut + GLWECompressedSeedMut,
P: GLWEPlaintextToRef,
S: GLWESecretPreparedToRef<BE>;
}
impl<BE: Backend> GLWECompressedEncryptSk<BE> for Module<BE>
where
Self: GLWEEncryptSkInternal<BE> + GLWEEncryptSk<BE>,
Scratch<BE>: ScratchAvailable,
{
fn glwe_compressed_encrypt_sk_tmp_bytes<A>(&self, infos: &A) -> usize
where
A: GLWEInfos,
{
assert_eq!(self.n() as u32, infos.n());
let lvl_0: usize = self.glwe_encrypt_sk_tmp_bytes(infos);
lvl_0
}
fn glwe_compressed_encrypt_sk<R, P, S>(
&self,
res: &mut R,
pt: &P,
sk: &S,
seed_xa: [u8; 32],
source_xe: &mut Source,
scratch: &mut Scratch<BE>,
) where
R: GLWECompressedToMut + GLWECompressedSeedMut,
P: GLWEPlaintextToRef,
S: GLWESecretPreparedToRef<BE>,
{
{
let res: &mut GLWECompressed<&mut [u8]> = &mut res.to_mut();
let mut source_xa: Source = Source::new(seed_xa);
let cols: usize = (res.rank() + 1).into();
assert!(
scratch.available() >= self.glwe_compressed_encrypt_sk_tmp_bytes(res),
"scratch.available(): {} < GLWECompressedEncryptSk::glwe_compressed_encrypt_sk_tmp_bytes: {}",
scratch.available(),
self.glwe_compressed_encrypt_sk_tmp_bytes(res)
);
self.glwe_encrypt_sk_internal(
res.base2k().into(),
res.k().into(),
&mut res.data,
cols,
true,
Some((pt, 0)),
sk,
&mut source_xa,
source_xe,
SIGMA,
scratch,
);
}
res.seed_mut().copy_from_slice(&seed_xa);
}
}