mirror of
https://github.com/enricobottazzi/zk-fhe.git
synced 2026-01-09 13:18:04 -05:00
chore: modify poly representation => last element = constant term
This commit is contained in:
@@ -29,12 +29,12 @@ use zk_fhe::chips::poly_operations::{poly_add, poly_mul_equal_deg, poly_scalar_m
|
||||
///
|
||||
/// # Fields
|
||||
///
|
||||
/// * `pk0`: Public key 0 polynomial coefficients [a_0, a_1, ..., a_N-1] where a_i is the coefficient of x^i
|
||||
/// * `pk1`: Public key 1 polynomial coefficients [a_0, a_1, ..., a_N-1] where a_i is the coefficient of x^i
|
||||
/// * `m`: Plaintext polynomial coefficients [a_0, a_1, ..., a_N-1] where a_i is the coefficient of x^i. Represents the message to be encrypted
|
||||
/// * `u`: Ephemeral key polynomial coefficients from the distribution ChiKey [a_0, a_1, ..., a_N-1]
|
||||
/// * `e0`: Error polynomial coefficients from the distribution ChiError [a_0, a_1, ..., a_N-1]
|
||||
/// * `e1`: Error polynomial coefficients from the distribution ChiError [a_0, a_1, ..., a_N-1]
|
||||
/// * `pk0`: Public key 0 polynomial coefficients of degree N-1 [a_N-1, a_N-2, ..., a_1, a_0] where a_0 is the constant term
|
||||
/// * `pk1`: Public key 1 polynomial coefficients of degree N-1 [a_N-1, a_N-2, ..., a_1, a_0] where a_0 is the constant term
|
||||
/// * `m`: Plaintext polynomial of degree N-1 [a_N-1, a_N-2, ..., a_1, a_0] where a_0 is the constant term. Represents the message to be encrypted
|
||||
/// * `u`: Ephemeral key polynomial coefficients from the distribution ChiKey [a_N-1, a_N-2, ..., a_1, a_0]
|
||||
/// * `e0`: Error polynomial coefficients from the distribution ChiError [a_N-1, a_N-2, ..., a_1, a_0]
|
||||
/// * `e1`: Error polynomial coefficients from the distribution ChiError [a_N-1, a_N-2, ..., a_1, a_0]
|
||||
|
||||
///
|
||||
/// # Assumes that the following checks have been performed outside the circuit
|
||||
@@ -59,14 +59,14 @@ const B: u64 = 18;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct CircuitInput<const N: u64, const Q: u64, const T: u64, const B: u64> {
|
||||
pub pk0: Vec<u64>, // polynomial coefficients [a_0, a_1, ..., a_N-1] where a_i is the coefficient of x^i. Should live in R_q (to be checked outside the circuit)
|
||||
pub pk1: Vec<u64>, // polynomial coefficients [a_0, a_1, ..., a_N-1] where a_i is the coefficient of x^i. Should live in R_q (to be checked outside the circuit)
|
||||
pub m: Vec<u64>, // polynomial coefficients [a_0, a_1, ..., a_N-1] where a_i is the coefficient of x^i. Should in R_t (checked inside the circuit)
|
||||
pub u: Vec<u64>, // polynomial coefficients [a_0, a_1, ..., a_N-1] where a_i is the coefficient of x^i. Lives in R_q (checked inside the circuit)
|
||||
pub e0: Vec<u64>, // polynomial coefficients [a_0, a_1, ..., a_N-1] where a_i is the coefficient of x^i. Lives in R_q (checked inside the circuit)
|
||||
pub e1: Vec<u64>, // polynomial coefficients [a_0, a_1, ..., a_N-1] where a_i is the coefficient of x^i. Lives in R_q (checked inside the circuit)
|
||||
pub c0: Vec<u64>, // polynomial coefficients [a_0, a_1, ..., a_N-1] where a_i is the coefficient of x^i. It is compared to the ciphertext c0 generated by the circuit
|
||||
pub c1: Vec<u64>, // polynomial coefficients [a_0, a_1, ..., a_N-1] where a_i is the coefficient of x^i. It is compared to the ciphertext c1 generated by the circuit
|
||||
pub pk0: Vec<u64>, // polynomial coefficients [a_N-1, a_N-2, ..., a_1, a_0] where a_0 is the constant term. Should live in R_q (to be checked outside the circuit)
|
||||
pub pk1: Vec<u64>, // polynomial coefficients [a_N-1, a_N-2, ..., a_1, a_0] where a_0 is the constant term. Should live in R_q (to be checked outside the circuit)
|
||||
pub m: Vec<u64>, // polynomial coefficients [a_N-1, a_N-2, ..., a_1, a_0] where a_0 is the constant term. Should in R_t (checked inside the circuit)
|
||||
pub u: Vec<u64>, // polynomial coefficients [a_N-1, a_N-2, ..., a_1, a_0] where a_0 is the constant term. Lives in R_q (checked inside the circuit)
|
||||
pub e0: Vec<u64>, // polynomial coefficients [a_N-1, a_N-2, ..., a_1, a_0] where a_0 is the constant term. Lives in R_q (checked inside the circuit)
|
||||
pub e1: Vec<u64>, // polynomial coefficients [a_N-1, a_N-2, ..., a_1, a_0] where a_0 is the constant term. Lives in R_q (checked inside the circuit)
|
||||
pub c0: Vec<u64>, // polynomial coefficients [a_N-1, a_N-2, ..., a_1, a_0] where a_0 is the constant term. It is compared to the ciphertext c0 generated as output by the circuit
|
||||
pub c1: Vec<u64>, // polynomial coefficients [a_N-1, a_N-2, ..., a_1, a_0] where a_0 is the constant term. It is compared to the ciphertext c1 generated as output by the circuit
|
||||
}
|
||||
|
||||
fn bfv_encryption_circuit<F: ScalarField>(
|
||||
|
||||
@@ -7,11 +7,11 @@ use halo2_base::AssignedValue;
|
||||
use halo2_base::Context;
|
||||
use halo2_base::QuantumCell::Constant;
|
||||
|
||||
/// Enforce that polynomial a of degree N is sampled from the distribution chi error
|
||||
/// Enforce that polynomial a of degree DEG is sampled from the distribution chi error
|
||||
/// Namely, that the coefficients are in the range [0, B] OR [Q-B, Q-1]
|
||||
/// N is the degree of the polynomial
|
||||
/// DEG is the degree of the polynomial
|
||||
pub fn check_poly_from_distribution_chi_error<
|
||||
const N: u64,
|
||||
const DEG: u64,
|
||||
const Q: u64,
|
||||
const B: u64,
|
||||
F: ScalarField,
|
||||
@@ -20,8 +20,8 @@ pub fn check_poly_from_distribution_chi_error<
|
||||
a: Vec<AssignedValue<F>>,
|
||||
range: &RangeChip<F>,
|
||||
) {
|
||||
// assert that the degree of the polynomial a is equal to N
|
||||
assert_eq!(a.len() - 1, N as usize);
|
||||
// assert that the degree of the polynomial a is equal to DEG
|
||||
assert_eq!(a.len() - 1, DEG as usize);
|
||||
|
||||
// The goal is to check that coeff is in the range [0, B] OR [Q-B, Q-1]
|
||||
// We split this check into two checks:
|
||||
@@ -30,7 +30,7 @@ pub fn check_poly_from_distribution_chi_error<
|
||||
// We then perform (`in_partial_range_1` OR `in_partial_range_2`) to check that coeff is in the range [0, B] OR [Q-B, Q-1]
|
||||
// The result of this check is stored in the `in_range` vector.
|
||||
// The bool value of `in_range` is then enforced to be true
|
||||
let mut in_range_vec = Vec::with_capacity((N + 1) as usize);
|
||||
let mut in_range_vec = Vec::with_capacity((DEG + 1) as usize);
|
||||
|
||||
// get the number of bits needed to represent the value of Q
|
||||
let binary_representation = format!("{:b}", Q);
|
||||
@@ -74,16 +74,16 @@ pub fn check_poly_from_distribution_chi_error<
|
||||
}
|
||||
}
|
||||
|
||||
/// Enforce that polynomial a of degree N is sampled from the distribution chi key
|
||||
/// Enforce that polynomial a of degree DEG is sampled from the distribution chi key
|
||||
/// Namely, that the coefficients are in the range [0, 1, Q-1].
|
||||
/// N is the degree of the polynomial
|
||||
pub fn check_poly_from_distribution_chi_key<const N: u64, const Q: u64, F: ScalarField>(
|
||||
/// DEG is the degree of the polynomial
|
||||
pub fn check_poly_from_distribution_chi_key<const DEG: u64, const Q: u64, F: ScalarField>(
|
||||
ctx: &mut Context<F>,
|
||||
a: Vec<AssignedValue<F>>,
|
||||
gate: &GateChip<F>,
|
||||
) {
|
||||
// assert that the degree of the polynomial a is equal to N
|
||||
assert_eq!(a.len() - 1, N as usize);
|
||||
// assert that the degree of the polynomial a is equal to DEG
|
||||
assert_eq!(a.len() - 1, DEG as usize);
|
||||
|
||||
// In order to check that coeff is equal to either 0, 1 or q-1
|
||||
// The constraint that we want to enforce is:
|
||||
|
||||
@@ -6,53 +6,58 @@ use halo2_base::Context;
|
||||
use halo2_base::QuantumCell;
|
||||
|
||||
/// Build the sum of the polynomials a and b as sum of the coefficients
|
||||
/// N is the degree of the polynomials
|
||||
pub fn poly_add<const N: u64, F: ScalarField>(
|
||||
/// DEG is the degree of the input polynomials
|
||||
/// Input polynomials are parsed as a vector of assigned coefficients [a_DEG, a_DEG-1, ..., a_1, a_0] where a_0 is the constant term
|
||||
pub fn poly_add<const DEG: u64, F: ScalarField>(
|
||||
ctx: &mut Context<F>,
|
||||
a: Vec<AssignedValue<F>>,
|
||||
b: Vec<AssignedValue<F>>,
|
||||
gate: &GateChip<F>,
|
||||
) -> Vec<AssignedValue<F>> {
|
||||
// assert that the input polynomials have the same degree and this is equal to N
|
||||
// assert that the input polynomials have the same degree and this is equal to DEG
|
||||
assert_eq!(a.len() - 1, b.len() - 1);
|
||||
assert_eq!(a.len() - 1, N as usize);
|
||||
assert_eq!(a.len() - 1, DEG as usize);
|
||||
|
||||
let c = a
|
||||
let c: Vec<AssignedValue<F>> = a
|
||||
.iter()
|
||||
.zip(b.iter())
|
||||
.take(2 * (N as usize) - 1)
|
||||
.take(2 * (DEG as usize) - 1)
|
||||
.map(|(&a, &b)| gate.add(ctx, a, b))
|
||||
.collect();
|
||||
|
||||
// assert that the sum polynomial has degree DEG
|
||||
assert_eq!(c.len() - 1, DEG as usize);
|
||||
|
||||
c
|
||||
}
|
||||
|
||||
/// Build the product of the polynomials a and b as dot product of the coefficients of a and b
|
||||
/// More efficient implementation for the case where the polynomials have the same degree
|
||||
/// N is the degree of the input polynomials
|
||||
pub fn poly_mul_equal_deg<const N: u64, F: ScalarField>(
|
||||
/// Compared to `poly_mul_diff_deg`, this function assumes that the polynomials have the same degree and therefore optimizes the computation
|
||||
/// DEG is the degree of the input polynomials
|
||||
/// Input polynomials are parsed as a vector of assigned coefficients [a_DEG, a_DEG-1, ..., a_1, a_0] where a_0 is the constant term
|
||||
pub fn poly_mul_equal_deg<const DEG: u64, F: ScalarField>(
|
||||
ctx: &mut Context<F>,
|
||||
a: Vec<AssignedValue<F>>,
|
||||
b: Vec<AssignedValue<F>>,
|
||||
gate: &GateChip<F>,
|
||||
) -> Vec<AssignedValue<F>> {
|
||||
// assert that the input polynomials have the same degree and this is equal to N
|
||||
// assert that the input polynomials have the same degree and this is equal to DEG
|
||||
assert_eq!(a.len() - 1, b.len() - 1);
|
||||
assert_eq!(a.len() - 1, N as usize);
|
||||
assert_eq!(a.len() - 1, DEG as usize);
|
||||
|
||||
let mut c = vec![];
|
||||
|
||||
for i in 0..(2 * N + 1) {
|
||||
for i in 0..(2 * DEG + 1) {
|
||||
let mut coefficient_accumaltor = vec![];
|
||||
|
||||
if i < (N + 1) {
|
||||
if i < (DEG + 1) {
|
||||
for a_idx in 0..=i {
|
||||
let a_coef = a[a_idx as usize];
|
||||
let b_coef = b[(i - a_idx) as usize];
|
||||
coefficient_accumaltor.push(gate.mul(ctx, a_coef, b_coef));
|
||||
}
|
||||
} else {
|
||||
for a_idx in (i - N)..=N {
|
||||
for a_idx in (i - DEG)..=DEG {
|
||||
let a_coef = a[a_idx as usize];
|
||||
let b_coef = b[(i - a_idx) as usize];
|
||||
coefficient_accumaltor.push(gate.mul(ctx, a_coef, b_coef));
|
||||
@@ -66,14 +71,15 @@ pub fn poly_mul_equal_deg<const N: u64, F: ScalarField>(
|
||||
c.push(c_val);
|
||||
}
|
||||
|
||||
// assert that the product polynomial has degree 2N
|
||||
assert_eq!(c.len() - 1, 2 * (N as usize));
|
||||
// assert that the product polynomial has degree 2*DEG
|
||||
assert_eq!(c.len() - 1, 2 * (DEG as usize));
|
||||
|
||||
c
|
||||
}
|
||||
|
||||
/// Build the product of the polynomials a and b as dot product of the coefficients of a and b
|
||||
/// The polynomials have different degrees
|
||||
/// Compared to `poly_mul_equal_deg`, this function doesn't assume that the polynomials have the same degree. Therefore the computation is less efficient.
|
||||
/// Input polynomials are parsed as a vector of assigned coefficients [a_n, a_n-1, ..., a_1, a_0] where a_0 is the constant term and n is the degree of the polynomial
|
||||
pub fn poly_mul_diff_deg<F: ScalarField>(
|
||||
ctx: &mut Context<F>,
|
||||
a: Vec<AssignedValue<F>>,
|
||||
@@ -113,17 +119,21 @@ pub fn poly_mul_diff_deg<F: ScalarField>(
|
||||
}
|
||||
|
||||
/// Build the scalar multiplication of the polynomials a and the scalar k as scalar multiplication of the coefficients of a and k
|
||||
/// N is the degree of the polynomial
|
||||
pub fn poly_scalar_mul<const N: u64, F: ScalarField>(
|
||||
/// DEG is the degree of the polynomial
|
||||
/// Input polynomials is parsed as a vector of assigned coefficients [a_DEG, a_DEG-1, ..., a_1, a_0] where a_0 is the constant term
|
||||
pub fn poly_scalar_mul<const DEG: u64, F: ScalarField>(
|
||||
ctx: &mut Context<F>,
|
||||
a: Vec<AssignedValue<F>>,
|
||||
b: QuantumCell<F>,
|
||||
gate: &GateChip<F>,
|
||||
) -> Vec<AssignedValue<F>> {
|
||||
// assert that the degree of the polynomial a is equal to N
|
||||
assert_eq!(a.len() - 1, N as usize);
|
||||
// assert that the degree of the polynomial a is equal to DEG
|
||||
assert_eq!(a.len() - 1, DEG as usize);
|
||||
|
||||
let c = a.iter().map(|&a| gate.mul(ctx, a, b)).collect();
|
||||
let c: Vec<AssignedValue<F>> = a.iter().map(|&a| gate.mul(ctx, a, b)).collect();
|
||||
|
||||
// assert that the product polynomial has degree DEG
|
||||
assert_eq!(c.len() - 1, DEG as usize);
|
||||
|
||||
c
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user