Skip to main content

tecdsa_core/
df.rs

1//! Damgård–Fujisaki commitments `∏ base_i^{x_i}` over `Z*_N̂`.
2use alloc::vec::Vec;
3
4use crate::arith::{
5    fixed_base::FixedBase,
6    monty::{Modulus, Residue},
7    multiexp::multiexp_vartime,
8    sbig::SBig,
9};
10use crate::error::Result;
11
12/// DF parameters `(N̂, t, s₁, s₂)` with optional fixed-base tables.
13pub struct DfParams {
14    modulus: Modulus,
15    t: Residue,
16    s1: Residue,
17    s2: Residue,
18    tables: Option<[FixedBase; 3]>,
19}
20
21impl DfParams {
22    pub fn new(modulus: Modulus, t: Residue, s1: Residue, s2: Residue) -> Self {
23        Self {
24            modulus,
25            t,
26            s1,
27            s2,
28            tables: None,
29        }
30    }
31
32    pub fn modulus(&self) -> &Modulus {
33        &self.modulus
34    }
35    pub fn t(&self) -> &Residue {
36        &self.t
37    }
38    pub fn s1(&self) -> &Residue {
39        &self.s1
40    }
41    pub fn s2(&self) -> &Residue {
42        &self.s2
43    }
44
45    /// Builds comb tables for `t, s₁, s₂` for exponents below `2^max_bits`.
46    pub fn with_tables(mut self, max_bits: u32, window: u32) -> Self {
47        let m = &self.modulus;
48        self.tables = Some([
49            FixedBase::new(m, &self.t, max_bits, window),
50            FixedBase::new(m, &self.s1, max_bits, window),
51            FixedBase::new(m, &self.s2, max_bits, window),
52        ]);
53        self
54    }
55
56    /// Like [`Self::with_tables`] with a separate exponent width per base: `[t, s₁, s₂]`.
57    pub fn with_tables_sized(mut self, max_bits: [u32; 3], window: u32) -> Self {
58        let m = &self.modulus;
59        self.tables = Some([
60            FixedBase::new(m, &self.t, max_bits[0], window),
61            FixedBase::new(m, &self.s1, max_bits[1], window),
62            FixedBase::new(m, &self.s2, max_bits[2], window),
63        ]);
64        self
65    }
66
67    /// Memory held by precomputed tables, in bytes.
68    pub fn tables_size_bytes(&self) -> usize {
69        self.tables
70            .as_ref()
71            .map_or(0, |t| t.iter().map(FixedBase::size_bytes).sum())
72    }
73
74    /// `s₁^{a} · s₂^{b} · t^{r}` with secret exponents (prover side).
75    pub fn commit_ct(&self, a: &SBig, b: &SBig, r: &SBig, bits: [u32; 3]) -> Result<Residue> {
76        let (x, y, z) = match &self.tables {
77            Some([_, s1, s2]) if bits[0] <= s1.max_bits() && bits[1] <= s2.max_bits() => {
78                (s1.pow_ct(a)?, s2.pow_ct(b)?, self.pow_t_ct(r, bits[2])?)
79            }
80            _ => (
81                self.modulus.pow_ct(&self.s1, a, bits[0])?,
82                self.modulus.pow_ct(&self.s2, b, bits[1])?,
83                self.modulus.pow_ct(&self.t, r, bits[2])?,
84            ),
85        };
86        Ok(x.mul(&y).mul(&z))
87    }
88
89    fn pow_t_ct(&self, r: &SBig, bits: u32) -> Result<Residue> {
90        match &self.tables {
91            Some([t, _, _]) if bits <= t.max_bits() => t.pow_ct(r),
92            _ => self.modulus.pow_ct(&self.t, r, bits),
93        }
94    }
95
96    /// `s₁^{a} · s₂^{b} · t^{r}` for public exponents (verifier side).
97    pub fn commit_vartime(&self, a: &SBig, b: &SBig, r: &SBig) -> Result<Residue> {
98        multiexp_vartime(&self.modulus, &[(&self.s1, a), (&self.s2, b), (&self.t, r)])
99    }
100
101    /// Residues of the parameters, e.g. for a transcript.
102    pub fn elements(&self) -> Vec<&Residue> {
103        alloc::vec![&self.t, &self.s1, &self.s2]
104    }
105}