-
Notifications
You must be signed in to change notification settings - Fork 22
refactor: polynomial conversions [skip-line-limit] #1231
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
Merged
Merged
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
28d8369
docs(polynomial): explain descending coefficient order for circuit Ho…
cedoor 75dbb59
refactor: add CRT polynomial
cedoor 2ec0484
chore: update crisp lockfile
cedoor 2e164a5
fix(polynomial): enable serde "rc" for Arc<CrtContext>
cedoor f1d805b
refactor: update ciphertext addition logic with new poly struct
cedoor 240825a
chore: update lockfile
cedoor c8a75eb
chore: fix lint issues
cedoor 82e7be8
chore: add rand feature to num-bigint
cedoor bc273f6
refactor(polynomial): add reduce functions
cedoor 38074b4
refactor: remove unused function
cedoor 2d54241
fix(polynomial): enable num-bigint rand feature for fhe-math
cedoor 71b00a2
chore: remove unused rand feature from global num-bigint
cedoor 7521dbe
docs(zk-inputs): clarify first-in-slot prev_ct_commitment comment
cedoor 1241491
fix(zk-inputs): validate exact division remainder in ciphertext addition
cedoor a9686ac
refactor(polynomial): remove from_ascending_coefficients and to_ascen…
cedoor ab22b31
refactor: remove redundant reduce and center functions
cedoor b88ffaa
chore: remove .git from fhe-math dependency
cedoor 0dac129
chore: update scripts to lint circuits
cedoor 36bf62c
docs: remove polynomial representation from README
cedoor 522eb82
fix: update param set name in ciphertext addition
cedoor File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,169 @@ | ||
| // SPDX-License-Identifier: LGPL-3.0-only | ||
| // | ||
| // This file is provided WITHOUT ANY WARRANTY; | ||
| // without even the implied warranty of MERCHANTABILITY | ||
| // or FITNESS FOR A PARTICULAR PURPOSE. | ||
|
|
||
| //! CRT (Chinese Remainder Theorem) polynomial representation. | ||
|
|
||
| use crate::polynomial::Polynomial; | ||
| use fhe_math::rq::{Poly, Representation}; | ||
| use num_bigint::BigInt; | ||
| #[cfg(feature = "serde")] | ||
| use serde::{Deserialize, Serialize}; | ||
| use thiserror::Error; | ||
|
|
||
| /// Errors that can occur during CRT polynomial operations. | ||
| #[derive(Debug, Error)] | ||
| pub enum CrtPolynomialError { | ||
| /// Moduli slice length does not match number of limbs. | ||
| #[error("moduli length ({moduli_len}) must match limbs length ({limbs_len})")] | ||
| ModuliLengthMismatch { limbs_len: usize, moduli_len: usize }, | ||
| } | ||
|
|
||
| /// A polynomial in CRT form: one limb polynomial per modulus. | ||
| /// | ||
| /// Each limb is a `Polynomial` whose coefficients are expected to be reduced/centered | ||
| /// modulo the corresponding `ctx.moduli[i]` as required by the caller. | ||
| #[derive(Clone, Debug, PartialEq)] | ||
| #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||
| pub struct CrtPolynomial { | ||
| pub limbs: Vec<Polynomial>, | ||
| } | ||
|
|
||
| impl CrtPolynomial { | ||
| /// Builds a `CrtPolynomial` from a vector of polynomials. | ||
| /// | ||
| /// # Arguments | ||
| /// | ||
| /// * `limbs` - Vector of polynomials. | ||
| pub fn new(limbs: Vec<Polynomial>) -> Self { | ||
| Self { limbs } | ||
| } | ||
|
|
||
| /// Builds a `CrtPolynomial` from coefficient vectors (one `Vec<BigInt>` per modulus). | ||
| /// | ||
| /// # Arguments | ||
| /// | ||
| /// * `limbs` - Vector of coefficient vectors. | ||
| pub fn from_bigint_vectors(limbs: Vec<Vec<BigInt>>) -> Self { | ||
| let limbs = limbs.into_iter().map(Polynomial::new).collect::<Vec<_>>(); | ||
|
|
||
| Self { limbs } | ||
| } | ||
|
|
||
| /// Builds a `CrtPolynomial` from an fhe-math `Poly` in PowerBasis representation. | ||
| /// | ||
| /// Used to prepare inputs for ZK circuits by converting FHE BFV ciphertext polynomials | ||
| /// into CRT limb format. If `p` is in NTT form, it is converted to PowerBasis first. | ||
| /// | ||
| /// # Arguments | ||
| /// | ||
| /// * `p` - An fhe-math polynomial (PowerBasis or Ntt). | ||
| pub fn from_fhe_polynomial(p: &Poly) -> Self { | ||
| let mut p = p.clone(); | ||
|
|
||
| if *p.representation() == Representation::Ntt { | ||
| p.change_representation(Representation::PowerBasis); | ||
| } | ||
|
|
||
| let limbs = p | ||
| .coefficients() | ||
| .outer_iter() | ||
| .map(|row| Polynomial::from_u64_vector(row.to_vec())) | ||
| .collect(); | ||
|
|
||
| Self { limbs } | ||
| } | ||
|
cedoor marked this conversation as resolved.
|
||
|
|
||
| /// Reverses the coefficient order of every limb in-place. | ||
| /// | ||
| /// For each limb, converts between descending degree (a_n, …, a_0) and ascending | ||
| /// degree (a_0, …, a_n). Calling this twice restores the original order. | ||
| pub fn reverse(&mut self) { | ||
| for limb in &mut self.limbs { | ||
| limb.reverse(); | ||
| } | ||
| } | ||
|
|
||
| /// Centers each limb's coefficients (already in [0, q_i)) into (-q_i/2, q_i/2] in-place. | ||
| /// | ||
| /// # Arguments | ||
| /// | ||
| /// * `moduli` - One modulus per limb; `moduli[i]` is used for `self.limbs[i]`. | ||
| /// | ||
| /// # Errors | ||
| /// | ||
| /// Returns [`CrtPolynomialError::ModuliLengthMismatch`] if `moduli.len() != self.limbs.len()`. | ||
| pub fn center(&mut self, moduli: &[u64]) -> Result<(), CrtPolynomialError> { | ||
| if self.limbs.len() != moduli.len() { | ||
| return Err(CrtPolynomialError::ModuliLengthMismatch { | ||
| limbs_len: self.limbs.len(), | ||
| moduli_len: moduli.len(), | ||
| }); | ||
| } | ||
|
|
||
| for (limb, qi) in self.limbs.iter_mut().zip(moduli.iter()) { | ||
| limb.center(&BigInt::from(*qi)); | ||
| } | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| /// Reduces each limb's coefficients modulo the corresponding modulus in-place (range [0, qi)). | ||
| /// | ||
| /// # Arguments | ||
| /// | ||
| /// * `moduli` - One modulus per limb; `moduli[i]` is used for `self.limbs[i]`. | ||
| /// | ||
| /// # Errors | ||
| /// | ||
| /// Returns [`CrtPolynomialError::ModuliLengthMismatch`] if `moduli.len() != self.limbs.len()`. | ||
| pub fn reduce(&mut self, moduli: &[u64]) -> Result<(), CrtPolynomialError> { | ||
| if self.limbs.len() != moduli.len() { | ||
| return Err(CrtPolynomialError::ModuliLengthMismatch { | ||
| limbs_len: self.limbs.len(), | ||
| moduli_len: moduli.len(), | ||
| }); | ||
| } | ||
|
|
||
| for (limb, qi) in self.limbs.iter_mut().zip(moduli.iter()) { | ||
| limb.reduce(&BigInt::from(*qi)); | ||
| } | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| /// Reduces each limb's coefficients modulo the same modulus in-place. | ||
| /// | ||
| /// Every limb uses the same `modulus`; coefficients are reduced into the range `[0, modulus)`. | ||
| /// Use this when all limbs should be reduced by one common modulus (e.g. a single prime) | ||
| /// instead of per-limb moduli as in [`reduce`](Self::reduce). | ||
| /// | ||
| /// # Arguments | ||
| /// | ||
| /// * `modulus` - The modulus applied to every limb. | ||
| pub fn reduce_uniform(&mut self, modulus: &BigInt) { | ||
| for limb in &mut self.limbs { | ||
| limb.reduce(&modulus); | ||
| } | ||
| } | ||
|
|
||
| /// Returns a reference to the limb polynomial at the given index. | ||
| /// | ||
| /// # Arguments | ||
| /// | ||
| /// * `i` - Limb index; must be in range `0..self.limbs.len()`. | ||
| /// | ||
| /// # Returns | ||
| /// | ||
| /// A reference to the polynomial for modulus `i`. Coefficients are expected to be | ||
| /// reduced/centered modulo the corresponding modulus as required by the caller. | ||
| /// | ||
| /// # Panics | ||
| /// | ||
| /// Panics if `i >= self.limbs.len()`. | ||
| pub fn limb(&self, i: usize) -> &Polynomial { | ||
| &self.limbs[i] | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.