Skip to main content

constellation_sdk/
binary.rs

1//! Binary Encoding
2//!
3//! Functions for encoding data to binary format for signing.
4
5use base64::Engine;
6use serde::Serialize;
7
8use crate::canonicalize::canonicalize_bytes;
9use crate::types::{Result, CONSTELLATION_PREFIX};
10
11/// Convert data to bytes for signing
12///
13/// # Arguments
14/// * `data` - Any serializable data
15/// * `is_data_update` - Whether to encode as a DataUpdate (with Constellation prefix)
16///
17/// # Returns
18/// UTF-8 bytes ready for hashing
19///
20/// # Example
21/// ```
22/// use constellation_sdk::binary::to_bytes;
23/// use serde_json::json;
24///
25/// let data = json!({"id": "test"});
26/// let bytes = to_bytes(&data, false).unwrap();
27/// ```
28pub fn to_bytes<T: Serialize>(data: &T, is_data_update: bool) -> Result<Vec<u8>> {
29    let canonical_json = canonicalize_bytes(data)?;
30
31    if is_data_update {
32        // Add Constellation prefix for DataUpdate
33        let base64_string = base64::engine::general_purpose::STANDARD.encode(&canonical_json);
34        let wrapped_string = format!(
35            "{}{}\n{}",
36            CONSTELLATION_PREFIX,
37            base64_string.len(),
38            base64_string
39        );
40        Ok(wrapped_string.into_bytes())
41    } else {
42        Ok(canonical_json)
43    }
44}
45
46/// Encode data as a DataUpdate (convenience wrapper)
47///
48/// This is equivalent to `to_bytes(data, true)`.
49///
50/// # Arguments
51/// * `data` - Any serializable data
52///
53/// # Returns
54/// UTF-8 bytes with Constellation prefix
55pub fn encode_data_update<T: Serialize>(data: &T) -> Result<Vec<u8>> {
56    to_bytes(data, true)
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use serde_json::json;
63
64    #[test]
65    fn test_to_bytes_regular() {
66        let data = json!({"id": "test", "value": 42});
67        let bytes = to_bytes(&data, false).unwrap();
68        let s = String::from_utf8(bytes).unwrap();
69        assert_eq!(s, r#"{"id":"test","value":42}"#);
70    }
71
72    #[test]
73    fn test_to_bytes_data_update() {
74        let data = json!({"id": "test"});
75        let bytes = to_bytes(&data, true).unwrap();
76        let s = String::from_utf8(bytes).unwrap();
77        assert!(s.starts_with("\x19Constellation Signed Data:\n"));
78        assert!(s.contains('\n'));
79    }
80
81    #[test]
82    fn test_encode_data_update() {
83        let data = json!({"id": "test"});
84        let bytes = encode_data_update(&data).unwrap();
85        let s = String::from_utf8(bytes).unwrap();
86        assert!(s.starts_with("\x19Constellation Signed Data:\n"));
87    }
88}