diff --git a/.gitignore b/.gitignore index e793473..5deb9e2 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,11 @@ Cargo.lock *.pdb # Halo2 artifacts -params/ \ No newline at end of file +params/ + +# Proving and Verifying keys +/data/*.pk +/data/*.vk + +# Snark Proof +/data/*.snark \ No newline at end of file diff --git a/README.md b/README.md index e73f817..32e149c 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,46 @@ Implementation based on [Revisiting Homomorphic Encryption Schemes for Finite Fi The application is not production ready and is only meant to be used for educational purposes. -`LOOKUP_BITS=8 cargo run --example bfv -- --name bfv -k 14 mock` +## Quick Start -The input data is located in the `data` folder. This test vector file can be generated using [rlwe-py](https://github.com/yuriko627/rlwe-py) +**Mock Prover** -### Chips +`LOOKUP_BITS=8 cargo run --example bfv -- --name bfv -k 9 --input bfv.in mock` -- `check_poly_from_distribution_chi_error` - Enforces polynomial to be sampled from the chi distribution +The `MockProver` does not run the cryptographic prover on your circuit, but instead directly checks if constraints are satisfied. This is useful for testing purposes, and runs faster than the actual prover. + +- `LOOKUP_BITS`, in the backend build a lookup table filled with value in the range [0, 2**LOOKUP_BITS) +- `bfv` is the name of the circuit located in `examples/bfv.rs` +- `bfv.in` is the input file for the circuit located in `data/bfv.in`. This test vector file can be generated for different encryption using [bfv-py](https://github.com/yuriko627/bfv-py) +- `-k` is the DEGREE of the circuit as you specify to set the circuit to have `2^k` number of rows. The number of rows is determined by the number of constraints in the circuit. Working with larger data inputs will require a larger degree. + +**Key Generation** + +`LOOKUP_BITS=8 cargo run --example bfv -- --name bfv -k 9 --input bfv.in keygen` + +To generate a random universal trusted setup (for testing only!) and the proving and verifying keys for your circuit. + +For technical reasons (related to [axiom Halo2-scaffold](https://github.com/axiom-crypto/halo2-scaffold)), keygen still requires an input file of the correct format. You can use the same input file as for the prover. But be aware that the actual input data are not encoded in the key generation. + +This will generate a proving key `data/bfv.pk` and a verifying key `data/bfv.vk`. It will also generate a file `configs/bfv.json` which describes (and pins down) the configuration of the circuit. This configuration file is later read by the prover. + +**Proof Generation** + +`LOOKUP_BITS=8 cargo run --example bfv -- --name bfv -k 9 --input bfv.in prove` + +This creates a SNARK proof, stored as a binary file `data/bfv.snark`, using the inputs read (by default) from `data/halbfvo2_lib.in``. You can specify a different input file with the option `--input filename.in`, which would look for a file at `data/filename.in``. + +Using the same proving key, you can generate proofs for the same ZK circuit on different inputs using this command. + +**Proof Verification** + +`LOOKUP_BITS=8 cargo run --example bfv -- --name bfv -k 9 verify` + +Verify the proof generated above + +## Chips + +- `check_poly_coefficients_in_range` - Enforces polynomial coefficients to be within a specified range - `check_poly_from_distribution_chi_key` - Enforces polynomial to be sampled from the chi key - `poly_add` - Enforces polynomial addition - `poly_mul_equal_deg` - Enforces polynomial multiplication between polynomials of equal degree @@ -19,3 +52,4 @@ The input data is located in the `data` folder. This test vector file can be gen - `poly_scalar_mul` - Enforces scalar multiplication of a polynomial - `poly_reduce` - Enforces reduction of polynomial coefficients by a modulus - `poly_divide_by_cyclo` - Enforces the reduction of a polynomial by a cyclotomic polynomial + diff --git a/configs/bfv.json b/configs/bfv.json new file mode 100644 index 0000000..74857aa --- /dev/null +++ b/configs/bfv.json @@ -0,0 +1,22 @@ +{ + "params": { + "degree": 9, + "num_advice": 8, + "num_lookup_advice": 2, + "num_fixed": 1, + "lookup_bits": 8 + }, + "break_points": [ + [ + 501, + 500, + 501, + 502, + 502, + 500, + 501 + ], + [], + [] + ] +} \ No newline at end of file diff --git a/examples/bfv.rs b/examples/bfv.rs index 36460f3..594021c 100644 --- a/examples/bfv.rs +++ b/examples/bfv.rs @@ -13,7 +13,7 @@ use halo2_scaffold::scaffold::cmd::Cli; use halo2_scaffold::scaffold::run; use serde::{Deserialize, Serialize}; use zk_fhe::chips::poly_distribution::{ - check_poly_from_distribution_chi_error, check_poly_from_distribution_chi_key, + check_poly_coefficients_in_range, check_poly_from_distribution_chi_key, }; use zk_fhe::chips::poly_operations::{ poly_add, poly_divide_by_cyclo, poly_mul_equal_deg, poly_reduce, poly_scalar_mul, @@ -178,8 +178,8 @@ fn bfv_encryption_circuit( */ // Assumption for the chip is that B < Q which is satisfied by circuit assumption - check_poly_from_distribution_chi_error::<{ DEG - 1 }, Q, B, F>(ctx, e0.clone(), &range); - check_poly_from_distribution_chi_error::<{ DEG - 1 }, Q, B, F>(ctx, e1.clone(), &range); + check_poly_coefficients_in_range::<{ DEG - 1 }, Q, B, F>(ctx, &e0, &range); + check_poly_coefficients_in_range::<{ DEG - 1 }, Q, B, F>(ctx, &e1, &range); /* constraint on u - u must be a polynomial in the R_q ring => Coefficients must be in the [0, Q-1] range and the degree of u must be DEG - 1 @@ -191,7 +191,7 @@ fn bfv_encryption_circuit( - The assignment for loop above guarantees that the degree of u is DEG - 1 */ - check_poly_from_distribution_chi_key::<{ DEG - 1 }, Q, F>(ctx, u.clone(), range.gate()); + check_poly_from_distribution_chi_key::<{ DEG - 1 }, Q, F>(ctx, &u, range.gate()); /* constraint on m - m must be a polynomial in the R_t ring => Coefficients must be in the [0, T/2] OR [Q - T/2, Q - 1] range and the degree of m must be DEG - 1 @@ -201,6 +201,8 @@ fn bfv_encryption_circuit( - The assignment for loop above guarantees that the degree of m is DEG - 1 */ + check_poly_coefficients_in_range::<{ DEG - 1 }, Q, { T / 2 }, F>(ctx, &m, &range); + // 1. COMPUTE C0 (c0 is the first ciphertext component) // pk0 * u @@ -224,7 +226,7 @@ fn bfv_encryption_circuit( // Q needs to be chosen such that (Q-1) * (Q-1) * DEG < p where p is the prime field of the circuit in order to avoid overflow during the polynomial multiplication. // (Q-1) * (Q-1) * DEG < p according to the assumption of the circuit. - let pk0_u = poly_mul_equal_deg::<{ DEG - 1 }, F>(ctx, pk0.clone(), u.clone(), &range.gate()); + let pk0_u = poly_mul_equal_deg::<{ DEG - 1 }, F>(ctx, &pk0, &u, &range.gate()); // pk0_u is a polynomial of degree (DEG - 1) * 2 = 2*DEG - 2 // pk0_u has coefficients in the [0, (Q-1) * (Q-1) * DEG] range @@ -239,7 +241,7 @@ fn bfv_encryption_circuit( // The coefficients of pk0_u are in the range [0, (Q-1) * (Q-1) * DEG] according to the polynomial multiplication constraint set above. // Therefore the coefficients of pk0_u are known to have <= `num_bits_1` bits, therefore they satisfy the assumption of the `poly_reduce` chip - let pk0_u = poly_reduce::<{ 2 * DEG - 2 }, Q, F>(ctx, pk0_u, &range, num_bits_1); + let pk0_u = poly_reduce::<{ 2 * DEG - 2 }, Q, F>(ctx, &pk0_u, &range, num_bits_1); // pk0_u is a polynomial of degree (DEG - 1) * 2 = 2*DEG - 2 // pk0_u has coefficients in the [0, Q-1] range @@ -253,8 +255,7 @@ fn bfv_encryption_circuit( // - The coefficients of dividend and divisor can be expressed as u64 values as long as Q - 1 is less than 2^64 // - Q is chosen such that (Q-1) * (2 * DEG - 2 - DEG + 1)] + Q-1 < p. Note that this is a subset of the condition (Q-1) * (Q-1) * DEG < p which is an assumption of the circuit. - let pk0_u = - poly_divide_by_cyclo::<{ 2 * DEG - 2 }, DEG, Q, F>(ctx, pk0_u, cyclo.clone(), &range); + let pk0_u = poly_divide_by_cyclo::<{ 2 * DEG - 2 }, DEG, Q, F>(ctx, &pk0_u, &cyclo, &range); // assert that the degree of pk0_u is 2*DEG - 2 @@ -299,7 +300,7 @@ fn bfv_encryption_circuit( // Note that this condition is a subset of the condition (Q-1) * (Q-1) * DEG < p which is an assumption of the circuit. let m_delta = - poly_scalar_mul::<{ DEG - 1 }, F>(ctx, m.clone(), Constant(F::from(DELTA)), range.gate()); + poly_scalar_mul::<{ DEG - 1 }, F>(ctx, &m, &Constant(F::from(DELTA)), range.gate()); // m_delta is a polynomial of degree DEG - 1 // Coefficients of m_delta are in the [0, (Q-1) * (Q/T)] range @@ -307,14 +308,14 @@ fn bfv_encryption_circuit( // Reduce the coefficients of `m_delta` by modulo `Q` // get the number of bits needed to represent the value of (Q-1) * (Q/T) - + let binary_representation = format!("{:b}", ((Q - 1) * (Q / T))); let num_bits_2 = binary_representation.len(); // The coefficients of m_delta are in the range [0, (Q-1) * (Q/T)] according to the polynomial scalar multiplication constraint set above. // Therefore the coefficients of m_delta are known to have <= `num_bits_2` bits, therefore they satisfy the assumption of the `poly_reduce` chip - let m_delta = poly_reduce::<{ DEG - 1 }, Q, F>(ctx, m_delta, &range, num_bits_2); + let m_delta = poly_reduce::<{ DEG - 1 }, Q, F>(ctx, &m_delta, &range, num_bits_2); // Note: Scalar multiplication does not change the degree of the polynomial, therefore we do not need to reduce the coefficients by the cyclotomic polynomial of degree `DEG` => x^DEG + 1 // m_delta is a polynomial in the R_q ring @@ -336,7 +337,7 @@ fn bfv_encryption_circuit( // Note that this condition is a subset of the condition (Q-1) * (Q-1) * DEG < p which is an assumption of the circuit. let pk0_u_trimmed_plus_m_delta = - poly_add::<{ DEG - 1 }, F>(ctx, pk0_u_trimmed, m_delta, range.gate()); + poly_add::<{ DEG - 1 }, F>(ctx, &pk0_u_trimmed, &m_delta, range.gate()); // Reduce the coefficients of `m_delta` by modulo `Q` // Coefficients of pk0_u_trimmed_plus_m_delta are in the [0, 2Q - 2] range @@ -352,7 +353,7 @@ fn bfv_encryption_circuit( // Reduce the coefficients of `pk0_u_trimmed_plus_m_delta` by modulo `Q` let pk0_u_trimmed_plus_m_delta = - poly_reduce::<{ DEG - 1 }, Q, F>(ctx, pk0_u_trimmed_plus_m_delta, &range, num_bits_3); + poly_reduce::<{ DEG - 1 }, Q, F>(ctx, &pk0_u_trimmed_plus_m_delta, &range, num_bits_3); // Note: Addition does not change the degree of the polynomial, therefore we do not need to reduce the coefficients by the cyclotomic polynomial of degree `DEG` => x^DEG + 1 // pk0_u_trimmed_plus_m_delta is a polynomial in the R_q ring @@ -373,14 +374,14 @@ fn bfv_encryption_circuit( // If the condition (Q-1) + (Q-1) < p is satisfied there is no risk of overflow during the polynomial addition. // Note that this condition is a subset of the condition (Q-1) * (Q-1) * DEG < p which is an assumption of the circuit. - let c0 = poly_add::<{ DEG - 1 }, F>(ctx, pk0_u_trimmed_plus_m_delta, e0, range.gate()); + let c0 = poly_add::<{ DEG - 1 }, F>(ctx, &pk0_u_trimmed_plus_m_delta, &e0, range.gate()); // The coefficients of c0 are in the range [0, 2Q - 2] according to the polynomial addition constraint set above. // Therefore the coefficients of c0 are known to have <= `num_bits_3` bits, therefore they satisfy the assumption of the `poly_reduce` chip // Reduce the coefficients of `pk0_u_trimmed_plus_m_delta` by modulo `Q` - let c0 = poly_reduce::<{ DEG - 1 }, Q, F>(ctx, c0, &range, num_bits_3); + let c0 = poly_reduce::<{ DEG - 1 }, Q, F>(ctx, &c0, &range, num_bits_3); // Note: Addition does not change the degree of the polynomial, therefore we do not need to reduce the coefficients by the cyclotomic polynomial of degree `DEG` => x^DEG + 1 // c0 is a polynomial in the R_q ring! @@ -408,7 +409,7 @@ fn bfv_encryption_circuit( // Q needs to be chosen such that (Q-1) * (Q-1) * DEG < p where p is the prime field of the circuit in order to avoid overflow during the polynomial multiplication. // (Q-1) * (Q-1) * DEG < p according to the assumption of the circuit. - let pk1_u = poly_mul_equal_deg::<{ DEG - 1 }, F>(ctx, pk1.clone(), u, range.gate()); + let pk1_u = poly_mul_equal_deg::<{ DEG - 1 }, F>(ctx, &pk1, &u, range.gate()); // pk1_u is a polynomial of degree (DEG - 1) * 2 = 2*DEG - 2 // pk1_u has coefficients in the [0, (Q-1) * (Q-1) * DEG] range @@ -418,7 +419,7 @@ fn bfv_encryption_circuit( // The coefficients of pk1_u are in the range [0, (Q-1) * (Q-1) * DEG] according to the polynomial multiplication constraint set above. // Therefore the coefficients of pk1_u are known to have <= `num_bits_1` bits, therefore they satisfy the assumption of the `poly_reduce` chip - let pk1_u = poly_reduce::<{ 2 * DEG - 2 }, Q, F>(ctx, pk1_u, &range, num_bits_1); + let pk1_u = poly_reduce::<{ 2 * DEG - 2 }, Q, F>(ctx, &pk1_u, &range, num_bits_1); // pk1_u is a polynomial of degree (DEG - 1) * 2 = 2*DEG - 2 // pk1_u has coefficients in the [0, Q-1] range @@ -432,8 +433,7 @@ fn bfv_encryption_circuit( // - The coefficients of dividend and divisor can be expressed as u64 values as long as Q - 1 is less than 2^64 // - Q is chosen such that (Q-1) * (2 * DEG - 2 - DEG + 1)] + Q-1 < p. Note that this is a subset of the condition (Q-1) * (Q-1) * DEG < p which is an assumption of the circuit. - let pk1_u = - poly_divide_by_cyclo::<{ 2 * DEG - 2 }, DEG, Q, F>(ctx, pk1_u, cyclo.clone(), &range); + let pk1_u = poly_divide_by_cyclo::<{ 2 * DEG - 2 }, DEG, Q, F>(ctx, &pk1_u, &cyclo, &range); // assert that the degree of pk1_u is 2*DEG - 2 @@ -479,14 +479,14 @@ fn bfv_encryption_circuit( // Perform the polynomial addition between pk1_u_trimmed and e1. - let c1 = poly_add::<{ DEG - 1 }, F>(ctx, pk1_u_trimmed, e1, range.gate()); + let c1 = poly_add::<{ DEG - 1 }, F>(ctx, &pk1_u_trimmed, &e1, range.gate()); // The coefficients of c1 are in the range [0, 2Q - 2] according to the polynomial addition constraint set above. // Therefore the coefficients of c1 are known to have <= `num_bits_3` bits, therefore they satisfy the assumption of the `poly_reduce` chip // Reduce the coefficients of `c1` by modulo `Q` - let c1 = poly_reduce::<{ DEG - 1 }, Q, F>(ctx, c1, &range, num_bits_3); + let c1 = poly_reduce::<{ DEG - 1 }, Q, F>(ctx, &c1, &range, num_bits_3); // Note: Addition does not change the degree of the polynomial, therefore we do not need to reduce the coefficients by the cyclotomic polynomial of degree `DEG` => x^DEG + 1 // c1 is a polynomial in the R_q ring diff --git a/src/chips/poly_distribution.rs b/src/chips/poly_distribution.rs index 3d774e7..bb126f4 100644 --- a/src/chips/poly_distribution.rs +++ b/src/chips/poly_distribution.rs @@ -7,29 +7,30 @@ use halo2_base::AssignedValue; use halo2_base::Context; use halo2_base::QuantumCell::Constant; -/// Enforce that polynomial a of degree DEG is sampled from the distribution chi error +/// Enforce that polynomial a of degree DEG has coefficients in the range [0, Z] or [Q-Z, Q-1] /// -/// * Namely, that the coefficients are in the range [0, B] OR [Q-B, Q-1] /// * DEG is the degree of the polynomial -/// * Assumes that B < Q -pub fn check_poly_from_distribution_chi_error< +/// * Q is the modulus of the ring R_q (cipher text space) +/// * Z is the constant that defines the range +/// * Assumes that Z < Q +pub fn check_poly_coefficients_in_range< const DEG: usize, const Q: u64, - const B: u64, + const Z: u64, F: ScalarField, >( ctx: &mut Context, - a: Vec>, + a: &Vec>, range: &RangeChip, ) { // assert that the degree of the polynomial a is equal to DEG assert_eq!(a.len() - 1, DEG); - // The goal is to check that coeff is in the range [0, B] OR [Q-B, Q-1] + // The goal is to check that coeff is in the range [0, Z] OR [Q-Z, Q-1] // We split this check into two checks: - // - Check that coeff is in the range [0, B] and store the boolean result in in_partial_range_1_vec - // - Check that coeff is in the range [Q-B, Q-1] and store the boolean result in in_partial_range_2_vec - // 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] + // - Check that coeff is in the range [0, Z] and store the boolean result in in_partial_range_1_vec + // - Check that coeff is in the range [Q-Z, Q-1] and store the boolean result in in_partial_range_2_vec + // We then perform (`in_partial_range_1` OR `in_partial_range_2`) to check that coeff is in the range [0, Z] OR [Q-Z, Q-1] // The result of this check is stored in the `in_range` vector. // All the boolean values in `in_range` are then enforced to be true let mut in_range_vec = Vec::with_capacity(DEG + 1); @@ -38,23 +39,23 @@ pub fn check_poly_from_distribution_chi_error< let binary_representation = format!("{:b}", Q); let q_bits = binary_representation.len(); - for coeff in &a { + for coeff in a { // First of all, enforce that coefficient is in the [0, 2^q_bits] range let bool = range.is_less_than_safe(ctx, *coeff, (1 << q_bits as u64) + 1); range.gate().assert_is_const(ctx, &bool, &F::from(1)); - // Check for the range [0, B] + // Check for the range [0, Z] // coeff is known are known to have <= `q_bits` bits according to the constraint set above - // B + 1 is known to have <= `q_bits` bits according to assumption of the chip + // Z + 1 is known to have <= `q_bits` bits according to assumption of the chip // Therefore it satisfies the assumption of `is_less_than` chip - let in_partial_range_1 = range.is_less_than(ctx, *coeff, Constant(F::from(B + 1)), q_bits); + let in_partial_range_1 = range.is_less_than(ctx, *coeff, Constant(F::from(Z + 1)), q_bits); - // Check for the range [Q-B, Q-1] + // Check for the range [Q-Z, Q-1] // coeff is known are known to have <= `q_bits` bits according to the constraint set above - // Q - B is known to have <= `q_bits` bits according to assumption of the chip + // Q - Z is known to have <= `q_bits` bits according to assumption of the chip // Therefore it satisfies the assumption of `is_less_than` chip let not_in_range_lower_bound = - range.is_less_than(ctx, *coeff, Constant(F::from(Q - B)), q_bits); + range.is_less_than(ctx, *coeff, Constant(F::from(Q - Z)), q_bits); let in_range_lower_bound = range.gate.not(ctx, not_in_range_lower_bound); // coeff is known are known to have <= `q_bits` bits according to the constraint set above @@ -65,7 +66,7 @@ pub fn check_poly_from_distribution_chi_error< .gate .and(ctx, in_range_lower_bound, in_range_upper_bound); - // Combined check for [0, b] OR [q-b, q-1] + // Combined check for [0, Z] OR [Q-Z, Q-1] let in_range = range.gate.or(ctx, in_partial_range_1, in_partial_range_2); in_range_vec.push(in_range); } @@ -81,9 +82,10 @@ pub fn check_poly_from_distribution_chi_error< /// /// * Namely, that the coefficients are in the range [0, 1, Q-1]. /// * DEG is the degree of the polynomial +/// * Q is the modulus of the ring R_q (cipher text space) pub fn check_poly_from_distribution_chi_key( ctx: &mut Context, - a: Vec>, + a: &Vec>, gate: &GateChip, ) { // assert that the degree of the polynomial a is equal to DEG @@ -94,7 +96,7 @@ pub fn check_poly_from_distribution_chi_key( ctx: &mut Context, - a: Vec>, - b: Vec>, + a: &Vec>, + b: &Vec>, gate: &GateChip, ) -> Vec> { // assert that the input polynomials have the same degree and this is equal to DEG @@ -44,8 +44,8 @@ pub fn poly_add( /// * It assumes that the coefficients are constrained such to overflow during the polynomial multiplication pub fn poly_mul_equal_deg( ctx: &mut Context, - a: Vec>, - b: Vec>, + a: &Vec>, + b: &Vec>, gate: &GateChip, ) -> Vec> { // assert that the input polynomials have the same degree and this is equal to DEG @@ -91,8 +91,8 @@ pub fn poly_mul_equal_deg( /// * It assumes that the coefficients are constrained such to overflow during the polynomial multiplication pub fn poly_mul_diff_deg( ctx: &mut Context, - a: Vec>, - b: Vec>, + a: &Vec>, + b: &Vec>, gate: &GateChip, ) -> Vec> { let a_deg = a.len() - 1; @@ -134,8 +134,8 @@ pub fn poly_mul_diff_deg( /// * It assumes that the coefficients are constrained such to overflow during the scalar multiplication pub fn poly_scalar_mul( ctx: &mut Context, - a: Vec>, - b: QuantumCell, + a: &Vec>, + b: &QuantumCell, gate: &GateChip, ) -> Vec> { // assert that the degree of the polynomial a is equal to DEG @@ -144,7 +144,7 @@ pub fn poly_scalar_mul( let mut c = vec![]; for i in 0..=DEG { - let val = gate.mul(ctx, a[i], b); + let val = gate.mul(ctx, a[i], *b); c.push(val); } @@ -161,7 +161,7 @@ pub fn poly_scalar_mul( /// * It assumes that the coefficients of the input polynomial can be expressed in at most num_bits bits pub fn poly_reduce( ctx: &mut Context, - input: Vec>, + input: &Vec>, range: &RangeChip, num_bits: usize, ) -> Vec> { @@ -188,7 +188,7 @@ pub fn poly_reduce( /// /// * DEG_DVD is the degree of the `dividend` polynomial /// * DEG_DVS is the degree of the `divisor` polynomial -/// * Q is the modulus of the Ring +/// * Q is the modulus of the ring R_q (cipher text space) /// * 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 /// * Assumes that the degree of dividend is equal to (2 * DEG_DVS) - 2 /// * Assumes that the coefficients of `dividend` are in the range [0, Q - 1] @@ -202,8 +202,8 @@ pub fn poly_divide_by_cyclo< F: ScalarField, >( ctx: &mut Context, - dividend: Vec>, - divisor: Vec>, + dividend: &Vec>, + divisor: &Vec>, range: &RangeChip, ) -> Vec> { // Assert that degree of dividend polynomial is equal to the constant DEG_DVD @@ -320,7 +320,7 @@ pub fn poly_divide_by_cyclo< // We use a polynomial multiplication algorithm that does not require the input polynomials to be of the same degree - let prod = poly_mul_diff_deg(ctx, quotient, divisor, range.gate()); + let prod = poly_mul_diff_deg(ctx, "ient, divisor, range.gate()); // The degree of prod is DEG_DVD assert_eq!(prod.len() - 1, DEG_DVD); @@ -339,7 +339,7 @@ pub fn poly_divide_by_cyclo< // Q needs to be chosen such that (Q-1) * (DEG_DVD - DEG_DVS + 1)] + Q-1 < p where p is the prime field of the circuit in order to avoid overflow during the addition. // This is true by assumption of the chip. - let sum = poly_add::(ctx, prod, remainder.clone(), range.gate()); + let sum = poly_add::(ctx, &prod, &remainder, range.gate()); // assert that the degree of sum is DEG_DVD assert_eq!(sum.len() - 1, DEG_DVD); @@ -355,7 +355,7 @@ pub fn poly_divide_by_cyclo< // The coefficients of sum are in the range [0, (Q-1) * (DEG_DVD - DEG_DVS + 1)] + Q-1] according to the polynomial addition constraint set above. // Therefore the coefficients of sum are known to have <= `num_bits` bits, therefore they satisfy the assumption of the `poly_reduce` chip - let sum_mod = poly_reduce::(ctx, sum, range, num_bits); + let sum_mod = poly_reduce::(ctx, &sum, range, num_bits); // assert that the degree of sum_mod is DEG_DVD assert_eq!(sum_mod.len() - 1, DEG_DVD);