Skip to main content

auths_id/identity/
events.rs

1//! Event structures for KERI identity operations.
2//!
3//! This module provides high-level event types that abstract over the
4//! low-level KERI event formats.
5
6use chrono::{DateTime, Utc};
7use serde::{Deserialize, Serialize};
8
9/// Represents a key rotation event in the KERI Key Event Log (KEL).
10///
11/// This is a high-level representation of a key rotation that can be
12/// serialized to JSON for storage and transmission. The actual KERI
13/// event format (CESR) is handled at the storage layer.
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
15pub struct KeyRotationEvent {
16    /// Sequence number in the KEL (incrementing from 0)
17    pub sequence: u64,
18
19    /// Hash of the previous event for backward chain verification.
20    /// Empty string for inception events (sequence 0).
21    pub previous_hash: String,
22
23    /// Old public key being rotated from (32 bytes for Ed25519).
24    #[serde(with = "base64_bytes")]
25    pub old_public_key: Vec<u8>,
26
27    /// New public key being rotated to (32 bytes for Ed25519).
28    #[serde(with = "base64_bytes")]
29    pub new_public_key: Vec<u8>,
30
31    /// ISO 8601 timestamp of the rotation event.
32    pub timestamp: DateTime<Utc>,
33
34    /// Signature proving authority to rotate (signed by the old key).
35    /// This proves the holder of the old key authorized the rotation.
36    #[serde(with = "base64_bytes")]
37    pub rotation_signature: Vec<u8>,
38}
39
40impl KeyRotationEvent {
41    /// Creates a new KeyRotationEvent.
42    pub fn new(
43        sequence: u64,
44        previous_hash: String,
45        old_public_key: Vec<u8>,
46        new_public_key: Vec<u8>,
47        timestamp: DateTime<Utc>,
48        rotation_signature: Vec<u8>,
49    ) -> Self {
50        Self {
51            sequence,
52            previous_hash,
53            old_public_key,
54            new_public_key,
55            timestamp,
56            rotation_signature,
57        }
58    }
59
60    /// Returns the canonical bytes for signing this event.
61    ///
62    /// The canonical form includes all fields except the rotation_signature,
63    /// serialized deterministically.
64    pub fn canonical_bytes_for_signing(&self) -> Vec<u8> {
65        // Create a deterministic representation for signing
66        let mut data = Vec::new();
67        data.extend_from_slice(&self.sequence.to_be_bytes());
68        data.extend_from_slice(self.previous_hash.as_bytes());
69        data.extend_from_slice(&self.old_public_key);
70        data.extend_from_slice(&self.new_public_key);
71        data.extend_from_slice(self.timestamp.to_rfc3339().as_bytes());
72        data
73    }
74}
75
76/// Base64 serialization helper for `Vec<u8>` fields.
77mod base64_bytes {
78    use base64::{Engine as _, engine::general_purpose::STANDARD};
79    use serde::{Deserialize, Deserializer, Serializer};
80
81    pub fn serialize<S>(bytes: &Vec<u8>, serializer: S) -> Result<S::Ok, S::Error>
82    where
83        S: Serializer,
84    {
85        serializer.serialize_str(&STANDARD.encode(bytes))
86    }
87
88    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
89    where
90        D: Deserializer<'de>,
91    {
92        let s = String::deserialize(deserializer)?;
93        STANDARD.decode(&s).map_err(serde::de::Error::custom)
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100    use chrono::TimeZone;
101
102    #[test]
103    fn test_key_rotation_event_serialization() {
104        let timestamp = Utc.with_ymd_and_hms(2026, 1, 15, 12, 0, 0).unwrap();
105        let event = KeyRotationEvent::new(
106            1,
107            "abc123hash".to_string(),
108            vec![1u8; 32], // old public key
109            vec![2u8; 32], // new public key
110            timestamp,
111            vec![3u8; 64], // signature
112        );
113
114        let json = serde_json::to_string(&event).expect("Failed to serialize");
115        let deserialized: KeyRotationEvent =
116            serde_json::from_str(&json).expect("Failed to deserialize");
117
118        assert_eq!(event, deserialized);
119        assert_eq!(deserialized.sequence, 1);
120        assert_eq!(deserialized.previous_hash, "abc123hash");
121        assert_eq!(deserialized.old_public_key, vec![1u8; 32]);
122        assert_eq!(deserialized.new_public_key, vec![2u8; 32]);
123        assert_eq!(deserialized.rotation_signature, vec![3u8; 64]);
124    }
125
126    #[test]
127    fn test_canonical_bytes_for_signing() {
128        let timestamp = Utc.with_ymd_and_hms(2026, 1, 15, 12, 0, 0).unwrap();
129        let event = KeyRotationEvent::new(
130            1,
131            "prevhash".to_string(),
132            vec![0u8; 32],
133            vec![1u8; 32],
134            timestamp,
135            vec![],
136        );
137
138        let bytes = event.canonical_bytes_for_signing();
139        assert!(!bytes.is_empty());
140
141        // Verify determinism - same event produces same bytes
142        let bytes2 = event.canonical_bytes_for_signing();
143        assert_eq!(bytes, bytes2);
144    }
145}