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
use super::{
    super::sections::{InceptionWitnessConfig, KeyConfig},
    EventData,
};
use crate::{
    error::Error,
    event::{sections::seal::Seal, KeyEvent},
    event_message::{dummy_event::DummyInceptionEvent, msg::KeriEvent, Typeable},
    prefix::IdentifierPrefix,
    state::{EventSemantics, IdentifierState, LastEstablishmentData},
};
use said::version::format::SerializationFormats;
use said::{
    derivation::{HashFunction, HashFunctionCode},
    sad::SAD,
};
use serde::{Deserialize, Serialize};

/// Inception Event
///
/// Describes the inception (icp) event data,
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct InceptionEvent {
    #[serde(flatten)]
    pub key_config: KeyConfig,

    #[serde(flatten)]
    pub witness_config: InceptionWitnessConfig,

    #[serde(rename = "c")]
    pub inception_configuration: Vec<String>,

    #[serde(rename = "a")]
    pub data: Vec<Seal>,
}

impl InceptionEvent {
    pub fn new(
        key_config: KeyConfig,
        witness_config: Option<InceptionWitnessConfig>,
        inception_config: Option<Vec<String>>,
    ) -> Self {
        Self {
            key_config,
            witness_config: witness_config.map_or_else(InceptionWitnessConfig::default, |w| w),
            inception_configuration: inception_config.map_or_else(Vec::new, |c| c),
            data: vec![],
        }
    }

    /// Incept Self Addressing
    ///
    /// Takes the inception data and creates an EventMessage based on it, with
    /// using the given format and deriving a Self Addressing Identifier with the
    /// given derivation method
    pub fn incept_self_addressing(
        self,
        derivation: HashFunction,
        format: SerializationFormats,
    ) -> Result<KeriEvent<KeyEvent>, Error> {
        let code: HashFunctionCode = derivation.into();
        let mut dummy_event =
            DummyInceptionEvent::dummy_inception_data(self.clone(), &code, format)?;
        dummy_event.compute_digest(&code, &format);
        let digest = dummy_event.prefix.unwrap();
        let event = KeyEvent::new(
            IdentifierPrefix::SelfAddressing(digest.clone()),
            0,
            EventData::Icp(self),
        );
        Ok(KeriEvent {
            serialization_info: dummy_event.serialization_info,
            event_type: event.get_type(),
            digest: Some(digest),
            data: event,
        })
    }
}

impl EventSemantics for InceptionEvent {
    fn apply_to(&self, state: IdentifierState) -> Result<IdentifierState, Error> {
        let last_est = LastEstablishmentData {
            sn: state.sn,
            digest: state.last_event_digest.clone(),
            br: vec![],
            ba: vec![],
        };

        Ok(IdentifierState {
            current: self.key_config.clone(),
            witness_config: self.witness_config.clone().into(),
            last_est,
            ..state
        })
    }
}

#[test]
fn test_inception_data_derivation() -> Result<(), Error> {
    use crate::event::sections::{
        key_config::KeyConfig, key_config::NextKeysData, threshold::SignatureThreshold,
    };
    use crate::prefix::BasicPrefix;
    use cesrox::primitives::CesrPrimitive;
    use said::{derivation::HashFunctionCode, SelfAddressingIdentifier};

    let keys: Vec<BasicPrefix> = vec![
        "DErocgXD2RGSyvn3MObcx59jeOsEQhv2TqHirVkzrp0Q"
            .parse()
            .unwrap(),
        "DFXLiTjiRdSBPLL6hLa0rskIxk3dh4XwJLfctkJFLRSS"
            .parse()
            .unwrap(),
        "DE9YgIQVgpLwocTVrG8tidKScsQSMWwLWywNC48fhq4f"
            .parse()
            .unwrap(),
    ];
    let next_keys_hashes: Vec<SelfAddressingIdentifier> = vec![
        "EDJk5EEpC4-tQ7YDwBiKbpaZahh1QCyQOnZRF7p2i8k8"
            .parse()
            .unwrap(),
        "EAXfDjKvUFRj-IEB_o4y-Y_qeJAjYfZtOMD9e7vHNFss"
            .parse()
            .unwrap(),
        "EN8l6yJC2PxribTN0xfri6bLz34Qvj-x3cNwcV3DvT2m"
            .parse()
            .unwrap(),
    ];

    let next_keys_data = NextKeysData {
        threshold: SignatureThreshold::Simple(2),
        next_key_hashes: next_keys_hashes,
    };
    let key_config = KeyConfig::new(keys, next_keys_data, Some(SignatureThreshold::Simple(2)));
    let icp_data = InceptionEvent::new(key_config.clone(), None, None).incept_self_addressing(
        HashFunctionCode::Blake3_256.into(),
        SerializationFormats::JSON,
    )?;

    let icp_digest = icp_data.digest()?;
    assert_eq!(
        "EBfxc4RiVY6saIFmUfEtETs1FcqmktZW88UkbnOg0Qen",
        icp_data.data.get_prefix().to_str()
    );
    assert_eq!(
        "EBfxc4RiVY6saIFmUfEtETs1FcqmktZW88UkbnOg0Qen",
        icp_digest.to_str()
    );

    assert!(icp_digest.verify_binding(&icp_data.to_derivation_data().unwrap()));

    Ok(())
}