Skip to main content

p3_security/budget/
report.rs

1//! Labeled soundness breakdown produced by [`super::security_report`].
2//!
3//! Fiat-Shamir security of the compiled argument is the minimum over its rounds: an adversary
4//! needs only one round to break. Keeping the rounds as named terms rather than collapsing them
5//! into a single number means the *binding* round stays visible, which is what tells a reader
6//! whether a parameter change helped the round that actually mattered.
7
8/// Label for the lookup / permutation-argument bus-challenge round.
9pub const LOOKUP_LABEL: &str = "lookup-challenge";
10/// Label for the constraint-batching round.
11pub const COMPOSITION_LABEL: &str = "constraint-composition";
12/// Label for the out-of-domain evaluation round.
13pub const OUT_OF_DOMAIN_LABEL: &str = "out-of-domain";
14/// Label for the DEEP-quotient batching round.
15pub const DEEP_COMPOSITION_LABEL: &str = "deep-composition";
16/// Label for the FRI commit-phase folding rounds.
17pub const FOLDING_LABEL: &str = "fri-folding";
18/// Label for the FRI query round.
19pub const QUERY_LABEL: &str = "fri-query";
20/// Label for the commitment-collision cap.
21pub const COLLISION_LABEL: &str = "commitment-collision";
22
23/// Number of rounds a [`SecurityReport`] carries.
24pub const NUM_TERMS: usize = 7;
25
26/// One round's contribution, as `-log2(error)` in fixed point.
27#[derive(Copy, Clone, Debug, PartialEq, Eq)]
28pub struct SecurityTerm {
29    /// Which round this bounds.
30    pub label: &'static str,
31    /// Attained bits for the round, grinding included, in fixed point.
32    pub bits: u64,
33}
34
35impl SecurityTerm {
36    /// Builds a term from a label and its fixed-point bit count.
37    pub const fn new(label: &'static str, bits: u64) -> Self {
38        Self { label, bits }
39    }
40}
41
42/// The per-round soundness breakdown of one proof configuration.
43#[derive(Copy, Clone, Debug, PartialEq, Eq)]
44pub struct SecurityReport {
45    terms: [SecurityTerm; NUM_TERMS],
46}
47
48impl SecurityReport {
49    /// Builds a report from its rounds.
50    pub const fn new(terms: [SecurityTerm; NUM_TERMS]) -> Self {
51        Self { terms }
52    }
53
54    /// Every round.
55    pub const fn terms(&self) -> &[SecurityTerm; NUM_TERMS] {
56        &self.terms
57    }
58
59    /// The round that binds — the one attaining the minimum.
60    ///
61    /// Ties resolve to the earliest such round, so the reported bottleneck is the one an
62    /// adversary reaches first.
63    pub const fn binding_term(&self) -> SecurityTerm {
64        let mut binding = self.terms[0];
65        let mut index = 1;
66        while index < NUM_TERMS {
67            if self.terms[index].bits < binding.bits {
68                binding = self.terms[index];
69            }
70            index += 1;
71        }
72        binding
73    }
74
75    /// Attained conjectured security, in fixed point.
76    pub const fn attained(&self) -> u64 {
77        self.binding_term().bits
78    }
79
80    /// Attained conjectured security in whole bits, rounded down.
81    pub const fn security_level(&self) -> u32 {
82        crate::fixed::to_bits(self.attained())
83    }
84}