labrador/commitments/
outer_commitments.rs

1use thiserror::Error;
2
3use crate::{
4    commitments::common_instances::AjtaiInstances,
5    ring::{rq_matrix::RqMatrix, rq_vector::RqVector, zq::Zq},
6};
7
8use super::ajtai_commitment::AjtaiScheme;
9
10#[derive(Debug, Error)]
11pub enum DecompositionError {
12    #[error("invalid decomposition base: {0}")]
13    InvalidBase(Zq),
14    #[error("invalid number of parts: {0}")]
15    InvalidPartCount(usize),
16}
17
18/// Parameters for polynomial decomposition in hierarchical commitments
19/// The base parameter controls how coefficients are decomposed
20/// The num_parts parameter determines how many parts each coefficient is split into
21#[derive(Debug, Clone)]
22pub struct DecompositionParameters {
23    base: Zq,
24    num_parts: usize,
25}
26
27impl DecompositionParameters {
28    /// Creates new decomposition parameters with validation
29    /// - base must be greater than 1 for meaningful decomposition
30    /// - num_parts must be positive to ensure decomposition occurs
31    pub fn new(base: Zq, num_parts: usize) -> Result<Self, DecompositionError> {
32        if base <= Zq::ONE {
33            return Err(DecompositionError::InvalidBase(base));
34        }
35        if num_parts == 0 {
36            return Err(DecompositionError::InvalidPartCount(num_parts));
37        }
38
39        Ok(Self { base, num_parts })
40    }
41
42    /// Returns the decomposition base
43    pub fn base(&self) -> Zq {
44        self.base
45    }
46
47    /// Returns the number of decomposition parts
48    pub fn num_parts(&self) -> usize {
49        self.num_parts
50    }
51}
52
53fn decompose_and_commit(
54    commitment_matrix: &AjtaiScheme,
55    input: &RqMatrix,
56    params: &DecompositionParameters,
57) -> RqVector {
58    let decomposed_input = input.decompose_each_cell(params.base, params.num_parts);
59    commitment_matrix
60        .commit(&decomposed_input)
61        .expect("Commitment error in committing to decomposed input")
62}
63
64pub fn compute_u1(
65    crs: &AjtaiInstances,
66    t: &RqMatrix,
67    t_decomposition_params: DecompositionParameters,
68    g: &RqMatrix,
69    g_decomposition_params: DecompositionParameters,
70) -> RqVector {
71    &decompose_and_commit(&crs.commitment_scheme_b, t, &t_decomposition_params)
72        + &decompose_and_commit(&crs.commitment_scheme_c, g, &g_decomposition_params)
73}
74
75pub fn compute_u2(
76    crs: &AjtaiInstances,
77    h: &RqMatrix,
78    h_decomposition_params: DecompositionParameters,
79) -> RqVector {
80    decompose_and_commit(&crs.commitment_scheme_d, h, &h_decomposition_params)
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn test_decomposition_parameters() {
89        assert!(DecompositionParameters::new(Zq::ZERO, 2).is_err());
90        assert!(DecompositionParameters::new(Zq::TWO, 0).is_err());
91        let params = DecompositionParameters::new(Zq::new(8), 3).unwrap();
92        assert_eq!(params.base(), Zq::new(8));
93        assert_eq!(params.num_parts(), 3);
94    }
95}