Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 6 additions & 10 deletions circuits/lib/src/core/dkg/share_computation.nr
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::math::commitments::{
compute_share_computation_e_sm_commitment, compute_share_computation_sk_commitment,
compute_share_encryption_commitment_from_message,
};
use crate::math::modulo::U128::ModU128;
use crate::math::modulo::U64::ModU64;
use crate::math::polynomial::Polynomial;

/// Cryptographic parameters for Threshold secret share verification circuit.
Expand Down Expand Up @@ -194,11 +194,8 @@ impl<let N: u32, let L: u32, let N_PARTIES: u32, let T: u32, let BIT_SECRET: u32
// Reverse: position i gets the coefficient from N-1-i.
let c = self.e_sm_secret[j].coefficients[N - 1 - i];
// Center: shift [0, q) to [-(q-1)/2, (q-1)/2].
let centered = if (c as u128) > (half as u128) {
c - q
} else {
c
};
// c = e_sm_secret coeff in [0, q) < 2^62; half < 2^61: u64 saves 22 gates.
let centered = if (c as u64) > (half as u64) { c - q } else { c };
Comment thread
0xjei marked this conversation as resolved.
coeffs[i] = centered;
}
normalized[j] = Polynomial::new(coeffs);
Expand Down Expand Up @@ -294,10 +291,9 @@ pub fn verify_parity_check<let N: u32, let L: u32, let N_PARTIES: u32, let T: u3
sum = sum + h[mod_idx][row][col] * y[coeff_idx][mod_idx][col];
}

// Reduce mod q_j and verify == 0
let m = ModU128::new(q_j);
let result = m.reduce_mod(sum);
assert(result == 0, "Parity check failed");
// Assert sum divisible by q_j: ~12 gates vs reduce_mod's ~24 gates.
// Safe: sum < (N_PARTIES+1)*max(h)*q_j < 2^122 << field prime, no Field wrap.
ModU64::new(q_j as u64).assert_zero_mod(sum);
}
}
}
Expand Down
8 changes: 5 additions & 3 deletions circuits/lib/src/core/dkg/share_decryption.nr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use crate::math::commitments::{
compute_aggregated_shares_commitment, compute_share_encryption_commitment_from_message,
};
use crate::math::modulo::U128::ModU128;
use crate::math::modulo::U64::ModU64;
use crate::math::polynomial::Polynomial;

/// DKG share decryption and aggregation (C4a / C4b).
Expand Down Expand Up @@ -152,9 +152,11 @@ fn normalize_aggregated<let N: u32, let L: u32>(
for i in 0..N {
// Reverse: position i gets the coefficient from N-1-i.
let c = poly.coefficients[N - 1 - i];
let reduced = ModU128::new(q).reduce_mod(c);
// c < H*q_l (sum of H shares); quotient < H (small) -- safe for ModU64.
let reduced = ModU64::new(q as u64).reduce_mod(c);
// Center: shift to [-(q-1)/2, (q-1)/2].
let centered = if (reduced as u128) > (half as u128) {
// reduced < q < 2^62 and half < 2^61: u64 cast is sufficient, saves 22 gates.
let centered = if (reduced as u64) > (half as u64) {
Comment thread
0xjei marked this conversation as resolved.
reduced - q
} else {
reduced
Expand Down
11 changes: 6 additions & 5 deletions circuits/lib/src/core/dkg/share_encryption.nr
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::math::commitments::{
};
use crate::math::commitments::compute_dkg_pk_commitment;
use crate::math::helpers::flatten;
use crate::math::modulo::U128::ModU128;
use crate::math::modulo::U64::ModU64;
use crate::math::polynomial::Polynomial;

/// Parameters for DKG share encryption (C3).
Expand Down Expand Up @@ -204,19 +204,20 @@ impl<let N: u32, let L: u32, let BIT_PK: u32, let BIT_CT: u32, let BIT_U: u32, l
/// then centered to [-t/2, t/2) to produce the BFV plaintext encoding.
fn compute_scaled_message(self) -> Polynomial<N> {
let t = self.configs.t;
let t_mod = ModU128::new(t);
// t < 2^62 (plaintext modulus); q_mod_t, msg_i < t: all safe for ModU64.
let t_mod = ModU64::new(t as u64);
let q_mod_t: Field = self.configs.q_mod_t;
let mut k1_coeffs: [Field; N] = [0; N];

// Integer division for t_half
let t_half: u128 = (t as u128) / 2;
// Integer division for t_half; t < 2^62 so u64 is sufficient.
let t_half: u64 = (t as u64) / 2;

for i in 0..N {
let msg_i: Field = self.message.coefficients[i];
let q_times_m_mod_t = t_mod.mul_mod(q_mod_t, msg_i);

// Check if centering is needed (value > t/2 means negative in centered form)
let needs_centering = (q_times_m_mod_t as u128) > t_half;
let needs_centering = (q_times_m_mod_t as u64) > t_half;
Comment thread
0xjei marked this conversation as resolved.

k1_coeffs[i] = if needs_centering {
// Value is in (t/2, t), negative in centered form
Expand Down
11 changes: 7 additions & 4 deletions circuits/lib/src/core/threshold/decrypted_shares_aggregation.nr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// or FITNESS FOR A PARTICULAR PURPOSE.

use crate::math::commitments::compute_threshold_decryption_share_commitment;
use crate::math::modulo::U128::ModU128;
use crate::math::modulo::U64::ModU64;
use crate::math::polynomial::Polynomial;
use dep::bignum::BigNum;
use dep::bignum::bignum::to_field;
Expand Down Expand Up @@ -132,7 +132,8 @@ impl<let MAX_MSG_NON_ZERO_COEFFS: u32, let L: u32, let T: u32, let BIT_NOISE: u3
let t_bn_mod_q = t_bn.umod(q_bn);
let t_times_u_bn_q = (t_bn_mod_q * u_bn_mod_q).umod(q_bn);

let m = ModU128::new(self.configs.plaintext_modulus);
// t ~ 1000; all inputs < t; quotient < t << 2^64: safe for ModU64.
let m = ModU64::new(self.configs.plaintext_modulus as u64);
Comment thread
0xjei marked this conversation as resolved.

// Check if centering is needed
let needs_centering = t_times_u_bn_q > q_half_bn;
Expand Down Expand Up @@ -189,7 +190,8 @@ pub fn compute_all_lagrange_coeffs<let T: u32, let L: u32>(
// Step 3: For each CRT basis, compute Lagrange coefficients
for basis_idx in 0..L {
let q_l = qis[basis_idx];
let m = ModU128::new(q_l);
// party_ids are small (1-indexed, <= T+1); quotient < T+1 << 2^64: safe for ModU64.
let m = ModU64::new(q_l as u64);

// Compute product of all party IDs: PRODUCT(j=0..T) x_j mod q_l
let mut product_x = 1 as Field;
Expand Down Expand Up @@ -243,7 +245,8 @@ pub fn compute_crt_components<let MAX_MSG_NON_ZERO_COEFFS: u32, let L: u32, let

for basis_idx in 0..L {
let q_l = qis[basis_idx];
let m = ModU128::new(q_l);
// d_coeff < 2^59 (BIT_D_NATIVE=59), l_i_0 < q_l < 2^62; quotient < 2^59: safe for ModU64.
let m = ModU64::new(q_l as u64);
let mut u_coeffs = [0 as Field; MAX_MSG_NON_ZERO_COEFFS];

// For each coefficient position
Expand Down
5 changes: 3 additions & 2 deletions circuits/lib/src/core/threshold/pk_aggregation.nr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// or FITNESS FOR A PARTICULAR PURPOSE.

use crate::math::commitments::{compute_pk_aggregation_commitment, compute_threshold_pk_commitment};
use crate::math::modulo::U128::ModU128;
use crate::math::modulo::U64::ModU64;
use crate::math::polynomial::Polynomial;

/// Parameters for threshold public key aggregation (C5).
Expand Down Expand Up @@ -100,7 +100,8 @@ impl<let N: u32, let H: u32, let L: u32, let BIT_PK: u32> PkAggregation<N, H, L,
basis_idx: u32,
) {
let q_l = self.configs.qis[basis_idx];
let mod_q_l = ModU128::new(q_l);
// sum_shifted < H*2*q_l; quotient < 2H (small) -- safe for ModU64.
let mod_q_l = ModU64::new(q_l as u64);
Comment thread
0xjei marked this conversation as resolved.

let half_qi: Field = (q_l - 1) / 2;
let h_half_qi: Field = H as Field * half_qi;
Expand Down
16 changes: 10 additions & 6 deletions circuits/lib/src/core/threshold/share_decryption.nr
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,11 @@ impl<let N: u32, let MAX_MSG_NON_ZERO_COEFFS: u32, let L: u32, let BIT_CT: u32,
// Step 5: Generate Fiat-Shamir challenge from the transcript
let gamma = self.generate_challenge();

// Step 6: Verify decryption share computation for each CRT basis
// Step 6: Verify decryption share computation for each CRT basis.
// cyclo_at_gamma is identical across all bases (same gamma, same N); compute once.
let cyclo_at_gamma = gamma.pow_32(N as Field) + 1;
for i in 0..L {
self.verify_decryption_share_computation(i, gamma);
self.verify_decryption_share_computation(i, gamma, cyclo_at_gamma);
}

d_commitment
Expand Down Expand Up @@ -309,7 +311,12 @@ impl<let N: u32, let MAX_MSG_NON_ZERO_COEFFS: u32, let L: u32, let BIT_CT: u32,
///
/// # Panics
/// The circuit will fail if the decryption share computation formula doesn't hold for the specified basis.
fn verify_decryption_share_computation(self, basis_idx: u32, gamma: Field) {
fn verify_decryption_share_computation(
self,
basis_idx: u32,
gamma: Field,
cyclo_at_gamma: Field,
) {
Comment thread
0xjei marked this conversation as resolved.
// Evaluate ciphertext components at gamma
let c_0_at_gamma = self.ct0[basis_idx].eval(gamma);
let c_1_at_gamma = self.ct1[basis_idx].eval(gamma);
Expand All @@ -322,9 +329,6 @@ impl<let N: u32, let MAX_MSG_NON_ZERO_COEFFS: u32, let L: u32, let BIT_CT: u32,
let r_1_at_gamma = self.r1[basis_idx].eval(gamma);
let r_2_at_gamma = self.r2[basis_idx].eval(gamma);

// Evaluate cyclotomic polynomial X^N + 1 at gamma
let cyclo_at_gamma = gamma.pow_32(N as Field) + 1;

// Compute expected decryption share using the lifted formula:
// d_i = c_0i + c_1i * sk_i + e_sm_i + r_2i * (X^N + 1) + r_1i * q_i
let expected_decryption_share = c_0_at_gamma
Expand Down
2 changes: 1 addition & 1 deletion circuits/lib/src/lib.nr
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//! - **`core`**: DKG and threshold TrBFV circuit logic (PV-TBFV / publicly verifiable
//! threshold BFV).
//! - **`math`**: Polynomials, SAFE sponge (Poseidon2 + Keccak per `safe.nr`), helpers,
//! `ModU128`, commitments.
//! `ModU128` / `ModU64`, commitments.
//! - **`configs`**: Parameter presets (default -> secure / insecure / committee) for DKG
//! and threshold packages under `circuits/bin/`.

Expand Down
Loading
Loading