-
Notifications
You must be signed in to change notification settings - Fork 181
Ns/feat/atomic patterns #2024
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ns/feat/atomic patterns #2024
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we foresee that the ServerKeyAtomicPattern
is going to have a dynamic variant ServerKeyAtomicPattern::Dynamic(Box<dyn AtomicPattern>)
if yes, should the ServerKey just store a Box directly ?
Reviewed 9 of 45 files at r1, all commit messages.
Reviewable status: 9 of 45 files reviewed, 4 unresolved discussions (waiting on @nsarlin-zama)
tfhe/src/high_level_api/backward_compatibility/integers.rs
line 76 at r1 (raw file):
.as_view() .try_into() .map(|sk| old_sk_decompress(sk, a))
We could have let key = sk.key.key.key.as_view().try_into()?;
at the beginning of the fn, and use the key in the par_iter.map
Code quote:
.try_into()
.map(|sk| old_sk_decompress(sk, a))
tfhe/src/high_level_api/backward_compatibility/integers.rs
line 122 at r1 (raw file):
.as_view() .try_into() .map(|sk| old_sk_decompress(sk, a))
Same here, we could do`let key = sk.key.key.key.as_view().try_into()?;
Code quote:
sk.key
.key
.key
.as_view()
.try_into()
.map(|sk| old_sk_decompress(sk, a))
tfhe/src/shortint/atomic_pattern.rs
line 50 at r1 (raw file):
} pub trait AtomicPatternMutOperations {
I would have pub trait AtomicPatternMutOperations: AtomicPatternOperations
so that having the mut version also gives all the non mul ops
tfhe/src/shortint/server_key/mod.rs
line 406 at r1 (raw file):
impl<AP: Clone> GenericServerKey<&AP> { pub fn into_owned(&self) -> GenericServerKey<AP> {
Generally into_
method take self
, so I think a better name would be to_owned
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes the dynamic one is in progress
enum dispatch is supposedly more performant than vtable lookups, and some things are easier to do with enums, like serialization
Reviewable status: 9 of 45 files reviewed, 4 unresolved discussions (waiting on @tmontaigu)
tfhe/src/high_level_api/backward_compatibility/integers.rs
line 76 at r1 (raw file):
Previously, tmontaigu (tmontaigu) wrote…
We could have
let key = sk.key.key.key.as_view().try_into()?;
at the beginning of the fn, and use the key in the par_iter.map
good idea !
tfhe/src/shortint/atomic_pattern.rs
line 50 at r1 (raw file):
Previously, tmontaigu (tmontaigu) wrote…
I would have
pub trait AtomicPatternMutOperations: AtomicPatternOperations
so that having the mut version also gives all the non mul ops
ok I will do that!
tfhe/src/shortint/server_key/mod.rs
line 406 at r1 (raw file):
Previously, tmontaigu (tmontaigu) wrote…
Generally
into_
method takeself
, so I think a better name would beto_owned
ok, but to_owned is generally associated with the ToOwned
trait, so maybe there is a third option that is less confusing ?
41c1d18
to
a413178
Compare
b11e47a
to
1fc1441
Compare
14a920c
to
600a1b7
Compare
20843dd
to
4a759f6
Compare
4a759f6
to
74d237b
Compare
74d237b
to
7707a5b
Compare
Since only one kind is used at a time we don't need do allocate both
This allows to call it without having to define a max_noise_level
3a39fe0
to
ef7fe37
Compare
ef7fe37
to
ff11aa8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After discussing I agree, no need to have a special handling for the new generic parameter as it's "just" a result of "contamination" from an inner member that handles its own upgrade automatically
Just one thing around a parameter alias that I would prefer not done this way, otherwise, this is the last round for this PR
Reviewed 1 of 1 files at r9, 11 of 14 files at r10, 9 of 10 files at r11, 2 of 2 files at r12, 1 of 1 files at r13, all commit messages.
Reviewable status: all files reviewed, 13 unresolved discussions (waiting on @mayeul-zama and @nsarlin-zama)
tfhe/src/shortint/atomic_pattern/ks32.rs
line 66 at r6 (raw file):
Previously, nsarlin-zama (Nicolas Sarlin) wrote…
The problem here is that the client key is not generic, it stores its keys using u64 Scalar.
I think at some point we would have to make the ClientKey an enum with AP specific variants like the ServerKey, this is a workaround to avoid that.
understood but having additional copies of the secret key in memory is something we don't want, please have a follow up issues, this can either be managed as you say or making the core APIs even more flexible with a scalar only tied to the ciphertext modulus and compatible scalars for both input and output keys
tfhe/src/shortint/atomic_pattern/mod.rs
line 547 at r6 (raw file):
Previously, nsarlin-zama (Nicolas Sarlin) wrote…
done ! I forgot to update this match case
do we want a wildcard for all other cases or rather a properly exhaustive code so that this is not forgotten later ? follow up issue or in the compressed key follow up
tfhe/src/shortint/server_key/modulus_switched_compression.rs
line 33 at r6 (raw file):
Previously, nsarlin-zama (Nicolas Sarlin) wrote…
If I revert this this lint triggers: https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else. For me it's more a question of habit so I don't have any strong opinion.
Just that I would keep the compression which is common to both after the application of MS noise reduction or not
tfhe/src/shortint/atomic_pattern/classical.rs
line 33 at r6 (raw file):
Previously, nsarlin-zama (Nicolas Sarlin) wrote…
this was pub when it was in the server key so I simply reused the previous pattern. Do you think I should make them private ?
long term yes, but it will do for now
tfhe/src/shortint/atomic_pattern/mod.rs
line 557 at r13 (raw file):
#[cfg(test)] mod test { use crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128;
create a test_params alias instead please, for now we are not adverstising KS32 until it's prod ready
in shortint::parameters::test_params I believe
tfhe/src/shortint/parameters/aliases.rs
line 174 at r13 (raw file):
// KS32 AP pub const PARAM_MESSAGE_2_CARRY_2_KS32_PBS_TUNIFORM_2M128: KeySwitch32PBSParameters =
as said elsewhere I would prefer a test_params alias
tfhe/src/core_crypto/entities/compressed_modulus_switched_multi_bit_lwe_ciphertext.rs
line 193 at r12 (raw file):
) -> Self { assert_eq!( packed_mask.initial_len() % grouping_factor.0,
careful if grouping factor == 0 (which should not happen, but you know), let's add it as a follow up in the compressed server key PR as a separate commit to avoid delaying this one more
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: all files reviewed, 10 unresolved discussions (waiting on @IceTDrinker and @mayeul-zama)
tfhe/src/core_crypto/entities/compressed_modulus_switched_multi_bit_lwe_ciphertext.rs
line 193 at r12 (raw file):
Previously, IceTDrinker (Arthur Meyre) wrote…
careful if grouping factor == 0 (which should not happen, but you know), let's add it as a follow up in the compressed server key PR as a separate commit to avoid delaying this one more
done
Added an assert_ne!(grouping_factor, 0)
tfhe/src/shortint/atomic_pattern/ks32.rs
line 66 at r6 (raw file):
Previously, IceTDrinker (Arthur Meyre) wrote…
understood but having additional copies of the secret key in memory is something we don't want, please have a follow up issues, this can either be managed as you say or making the core APIs even more flexible with a scalar only tied to the ciphertext modulus and compatible scalars for both input and output keys
https://github.com/zama-ai/tfhe-rs-internal/issues/1007#issue-3028543196
tfhe/src/shortint/atomic_pattern/mod.rs
line 547 at r6 (raw file):
Previously, IceTDrinker (Arthur Meyre) wrote…
do we want a wildcard for all other cases or rather a properly exhaustive code so that this is not forgotten later ? follow up issue or in the compressed key follow up
the problem is that having all the other cases exhaustively handled does not scale well as we need to catch all possible combinations.
tfhe/src/shortint/atomic_pattern/mod.rs
line 557 at r13 (raw file):
Previously, IceTDrinker (Arthur Meyre) wrote…
create a test_params alias instead please, for now we are not adverstising KS32 until it's prod ready
in shortint::parameters::test_params I believe
done
tfhe/src/shortint/parameters/aliases.rs
line 174 at r13 (raw file):
Previously, IceTDrinker (Arthur Meyre) wrote…
as said elsewhere I would prefer a test_params alias
done
tfhe/src/shortint/server_key/modulus_switched_compression.rs
line 33 at r6 (raw file):
Previously, IceTDrinker (Arthur Meyre) wrote…
Just that I would keep the compression which is common to both after the application of MS noise reduction or not
The problem here is that in one branch I have LweCiphertext<&[Scalar]>
and in the other one LweCiphertext<Vec<Scalar>>
so I cannot return them both in the branches.
I cannot declare the input_improved_before_ms
uninitialized before the block because of the closure. I need to intialize it with an empty ciphertext which feels weird.
I think I here the 2 options are to disable the lint or keep it like that
ff11aa8
to
8579504
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huge effort on your part @nsarlin-zama a big big thank you for this work, I know this has not been easy (and a long time coming) and the reviews were thorough
Let's go!
Reviewed 4 of 4 files at r14, all commit messages.
Reviewable status: all files reviewed, 9 unresolved discussions (waiting on @mayeul-zama and @nsarlin-zama)
tfhe/src/shortint/atomic_pattern/mod.rs
line 547 at r6 (raw file):
Previously, nsarlin-zama (Nicolas Sarlin) wrote…
the problem is that having all the other cases exhaustively handled does not scale well as we need to catch all possible combinations.
ah right, misread this :/
tfhe/src/shortint/server_key/modulus_switched_compression.rs
line 33 at r6 (raw file):
Previously, nsarlin-zama (Nicolas Sarlin) wrote…
The problem here is that in one branch I have
LweCiphertext<&[Scalar]>
and in the other oneLweCiphertext<Vec<Scalar>>
so I cannot return them both in the branches.I cannot declare the
input_improved_before_ms
uninitialized before the block because of the closure. I need to intialize it with an empty ciphertext which feels weird.I think I here the 2 options are to disable the lint or keep it like that
Potential solutions (but let's go ahead with the code as it is now): .as_view to have the same return type (that's what was done before the change), as for the unitialized variable I know you can do some "forward declarations" with "just" a let x;
and then as long as the compiler can prove that x is initialized in the branch where it is used it does not bother you, but I really don't know how that behaves with closures
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: all files reviewed, 9 unresolved discussions (waiting on @IceTDrinker and @mayeul-zama)
tfhe/src/shortint/server_key/modulus_switched_compression.rs
line 33 at r6 (raw file):
Previously, IceTDrinker (Arthur Meyre) wrote…
Potential solutions (but let's go ahead with the code as it is now): .as_view to have the same return type (that's what was done before the change), as for the unitialized variable I know you can do some "forward declarations" with "just" a
let x;
and then as long as the compiler can prove that x is initialized in the branch where it is used it does not bother you, but I really don't know how that behaves with closures
No that's what I was trying but it does not work with the closure, here it needs to be initialized
closes: https://github.com/zama-ai/tfhe-rs-internal/issues/643
PR content/description
This PR adds the notion of Atomic Pattern to the shortint layer. This is currently a draft to be able to discuss on the design.
Atomic Pattern
An atomic pattern is a sequence of homomorphic operations that can be executed indefinitely. In TFHE, the standard atomic pattern is the chain of 5 linear operations + KS + PBS. In TFHE-rs, this is implemented at the shortint level by the
ServerKey::apply_lookup_table
(to be precise this is only the KS/PBS part). The goal of the PR is to add a genericity layer to be able to easily switch atomic pattern without having to rewrite higher level operations.Implementation
(The names of the trait and types are not definitive)
Currently the shortint
ServerKey
is represented by this structure:We can split these fields in 2 parts:
To do that, this PR first adds a trait
AtomicPattern
. This trait defines the operations that should be supported by all the atomic patterns. It is dyn compatible to allows having atomic patterns as trait objects:This trait is first implemented for the "classical" (CJP) atomic pattern:
From there we have an enum of atomic pattern specific keys that all implement this trait:
The enum also implements
AtomicPattern
(the "enum dispatch" design pattern).Finally, we have the "GenericServerKey" (name not definitive) defined as follow:
Some type aliases are defined to make it more usable:
ServerKey
is the one that is used in the upper layers, this reduces the breaking changes. Every methods that use the ServerKey for lookup tables and the shortint encoding are usable without (almost) any modification.However some features (such as the WoPBS) don't fit well in the atomic pattern concept (as I understand it)
For these features, this design allows to create impl blocks that only work for one specific atomic pattern, by using the
ClassicalServerKey
type. To go from one type to the other,ClassicalServerKey
implementsTryFrom<ServerKey>
.To make this more efficient, we have 2 "View" types that allow conversions without having to clone the keys:
In the future, it should be easy to extend the set of supported AP for a feature.
For example we can have an
OprfServerKeyAtomicPattern
enum with only the subset of ap that support the oprf, and define a typeOprfServerKey = GenericServerKey<OprfServerKeyAtomicPattern>;
Dynamic AP
The
GenericServerKey
enum has a last specific variant:This allows to create a server key for an AP defined by the user. the trait
DynamicAtomicPattern
is sealed but automatically impl for most of the types that implement AtomicPattern. This trait allows to implClone
andPartialEq
for the dynamic case.KS32
This PR also implements the
DP-KS-PBS-AP-with-32-bit-KS-modulus
atomic pattern to have an example of what can be done using this structures.Check-list:
This change is