pessimistic_proof_core/aggchain_data/
aggchain_hash.rs

1use agglayer_primitives::{
2    bytes::{BigEndian, ByteOrder as _},
3    keccak::keccak256_combine,
4    Digest,
5};
6use hex_literal::hex;
7
8use crate::aggchain_data::{aggchain_proof::AggchainProof, AggchainData, MultiSignature, Vkey};
9
10struct ConsensusType(u32);
11
12#[derive(Debug)]
13pub enum AggchainHashValues {
14    ConsensusType1 {
15        aggchain_vkey: Option<Vkey>,
16        aggchain_params: Option<Digest>,
17        multisig_hash: Digest,
18    },
19}
20
21impl From<&AggchainHashValues> for ConsensusType {
22    fn from(value: &AggchainHashValues) -> Self {
23        match value {
24            AggchainHashValues::ConsensusType1 { .. } => Self(1),
25        }
26    }
27}
28
29impl AggchainHashValues {
30    /// Value if no multisig.
31    pub const EMPTY_MULTISIG_HASH: Digest = Digest(hex!(
32        // NOTE: value covered in test at the end of this module.
33        "290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563"
34    ));
35
36    /// Value if no aggchain vkey.
37    pub const EMPTY_AGGCHAIN_VKEY_HASH: Digest = Digest::ZERO;
38
39    /// Value if no aggchain params.
40    pub const EMPTY_AGGCHAIN_PARAMS: Digest = Digest::ZERO;
41
42    /// Computes the aggchain hash with the right default values.
43    pub fn hash(&self) -> Digest {
44        let consensus_type: u32 = ConsensusType::from(self).0;
45
46        match self {
47            AggchainHashValues::ConsensusType1 {
48                aggchain_vkey: aggchain_vkey_u32,
49                aggchain_params,
50                multisig_hash,
51            } => {
52                let aggchain_vkey_hash = aggchain_vkey_u32
53                    .map(|vkey| {
54                        let mut aggchain_vkey_hash = [0u8; 32];
55                        BigEndian::write_u32_into(&vkey, &mut aggchain_vkey_hash);
56                        aggchain_vkey_hash
57                    })
58                    .unwrap_or(*Self::EMPTY_AGGCHAIN_VKEY_HASH);
59
60                let aggchain_params = aggchain_params.unwrap_or(Self::EMPTY_AGGCHAIN_PARAMS);
61
62                keccak256_combine([
63                    &consensus_type.to_be_bytes(),
64                    aggchain_vkey_hash.as_slice(),
65                    aggchain_params.as_slice(),
66                    multisig_hash.as_slice(),
67                ])
68            }
69        }
70    }
71}
72
73impl From<&AggchainData> for AggchainHashValues {
74    fn from(value: &AggchainData) -> Self {
75        match value {
76            AggchainData::LegacyEcdsa { signer, signature } => AggchainHashValues::ConsensusType1 {
77                aggchain_vkey: None,
78                aggchain_params: None,
79                multisig_hash: MultiSignature {
80                    signatures: vec![Some(*signature)],
81                    expected_signers: vec![*signer],
82                    threshold: 1,
83                }
84                .multisig_hash(),
85            },
86            AggchainData::MultisigOnly(multisig) => AggchainHashValues::ConsensusType1 {
87                aggchain_vkey: None,
88                aggchain_params: None,
89                multisig_hash: multisig.multisig_hash(),
90            },
91            AggchainData::MultisigAndAggchainProof {
92                multisig,
93                aggchain_proof:
94                    AggchainProof {
95                        aggchain_params,
96                        aggchain_vkey,
97                    },
98            } => AggchainHashValues::ConsensusType1 {
99                aggchain_vkey: Some(*aggchain_vkey),
100                aggchain_params: Some(*aggchain_params),
101                multisig_hash: multisig.multisig_hash(),
102            },
103        }
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use crate::aggchain_data::{AggchainHashValues, MultiSignature};
110
111    #[test]
112    fn nil_set() {
113        let empty = MultiSignature {
114            signatures: vec![], // not involved in the hash
115            expected_signers: vec![],
116            threshold: 0,
117        };
118
119        assert_eq!(
120            empty.multisig_hash(),
121            AggchainHashValues::EMPTY_MULTISIG_HASH
122        );
123    }
124}