1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
//! Types related to transcript commitments.

/// BLAKE3 commitments.
pub mod blake3;
mod builder;

use std::collections::HashMap;

use bimap::BiMap;
use mpz_core::hash::Hash;
use mpz_garble_core::{encoding_state::Full, EncodedValue};
use serde::{Deserialize, Serialize};
use utils::range::RangeSet;

use crate::{
    merkle::{MerkleRoot, MerkleTree},
    Direction,
};

pub use builder::{TranscriptCommitmentBuilder, TranscriptCommitmentBuilderError};

/// A commitment id.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct CommitmentId(u32);

impl CommitmentId {
    /// Creates a new commitment id
    pub(crate) fn new(id: u32) -> Self {
        Self(id)
    }

    /// Returns the inner value
    pub(crate) fn to_inner(self) -> u32 {
        self.0
    }
}

/// Info of a transcript commitment
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct CommitmentInfo {
    pub(crate) kind: CommitmentKind,
    pub(crate) ranges: RangeSet<usize>,
    pub(crate) direction: Direction,
}

impl CommitmentInfo {
    /// Creates new commitment info.
    pub(crate) fn new(kind: CommitmentKind, ranges: RangeSet<usize>, direction: Direction) -> Self {
        Self {
            kind,
            ranges,
            direction,
        }
    }

    /// Returns the kind of this commitment
    pub fn kind(&self) -> CommitmentKind {
        self.kind
    }

    /// Returns the ranges of this commitment
    pub fn ranges(&self) -> &RangeSet<usize> {
        &self.ranges
    }

    /// Returns the direction of this commitment
    pub fn direction(&self) -> &Direction {
        &self.direction
    }
}

/// A commitment to some bytes in a transcript
#[derive(Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub enum Commitment {
    /// A BLAKE3 commitment to encodings of the transcript.
    Blake3(blake3::Blake3Commitment),
}

impl Commitment {
    /// Returns the hash of this commitment
    pub fn hash(&self) -> Hash {
        match self {
            Commitment::Blake3(commitment) => *commitment.hash(),
        }
    }

    /// Returns the kind of this commitment
    pub fn kind(&self) -> CommitmentKind {
        match self {
            Commitment::Blake3(_) => CommitmentKind::Blake3,
        }
    }
}

/// The kind of a [`Commitment`].
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum CommitmentKind {
    /// A BLAKE3 commitment to encodings of the transcript.
    Blake3,
}

/// An opening to a commitment to the transcript.
#[derive(Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub enum CommitmentOpening {
    /// An opening to a BLAKE3 commitment
    Blake3(blake3::Blake3Opening),
}

impl CommitmentOpening {
    /// Returns the kind of this opening
    pub fn kind(&self) -> CommitmentKind {
        match self {
            CommitmentOpening::Blake3(_) => CommitmentKind::Blake3,
        }
    }

    /// Recovers the expected commitment from this opening.
    ///
    /// # Panics
    ///
    /// Implementations may panic if the following conditions are not met:
    ///
    /// - If the number of encodings does not match the number of bytes in the opening.
    /// - If an encoding is not for a u8.
    pub fn recover(&self, encodings: &[EncodedValue<Full>]) -> Commitment {
        match self {
            CommitmentOpening::Blake3(opening) => opening.recover(encodings).into(),
        }
    }

    /// Returns the transcript data corresponding to this opening
    pub fn data(&self) -> &[u8] {
        match self {
            CommitmentOpening::Blake3(opening) => opening.data(),
        }
    }

    /// Returns the transcript data corresponding to this opening
    pub fn into_data(self) -> Vec<u8> {
        match self {
            CommitmentOpening::Blake3(opening) => opening.into_data(),
        }
    }
}

/// A collection of transcript commitments.
#[derive(Clone, Serialize, Deserialize)]
pub struct TranscriptCommitments {
    /// A Merkle tree of commitments. Each commitment's index in the tree matches its `CommitmentId`.
    merkle_tree: MerkleTree,
    commitments: HashMap<CommitmentId, Commitment>,
    /// Information about the above `commitments`.
    commitment_info: BiMap<CommitmentId, CommitmentInfo>,
}

opaque_debug::implement!(TranscriptCommitments);

impl TranscriptCommitments {
    /// Returns the merkle tree of the commitments.
    pub fn merkle_tree(&self) -> &MerkleTree {
        &self.merkle_tree
    }

    /// Returns the merkle root of the commitments.
    pub fn merkle_root(&self) -> MerkleRoot {
        self.merkle_tree.root()
    }

    /// Returns a commitment if it exists.
    pub fn get(&self, id: &CommitmentId) -> Option<&Commitment> {
        self.commitments.get(id)
    }

    /// Returns the commitment id for a commitment with the given info, if it exists.
    pub fn get_id_by_info(
        &self,
        kind: CommitmentKind,
        ranges: &RangeSet<usize>,
        direction: Direction,
    ) -> Option<CommitmentId> {
        self.commitment_info
            .get_by_right(&CommitmentInfo::new(kind, ranges.clone(), direction))
            .copied()
    }

    /// Returns commitment info, if it exists.
    pub fn get_info(&self, id: &CommitmentId) -> Option<&CommitmentInfo> {
        self.commitment_info.get_by_left(id)
    }
}