interveil_sdk/intent/
sign.rs1use crate::error::VeilError;
2use crate::intent::intent::Intent;
3use crate::signer::Signer;
4
5#[derive(Debug, Clone)]
7pub struct SignedIntent {
8 pub intent: Intent,
9 pub pubkey: Vec<u8>,
10 pub signature: Vec<u8>,
11}
12
13impl SignedIntent {
14 pub fn to_json(&self) -> Result<String, VeilError> {
22 let intent_b64 = base64_encode(&self.intent.to_bytes()?);
23 let pubkey_hex = hex_encode(&self.pubkey);
24 let sig_hex = hex_encode(&self.signature);
25
26 Ok(format!(
28 r#"{{"intent":"{}","pubkey":"{}","signature":"{}"}}"#,
29 intent_b64, pubkey_hex, sig_hex
30 ))
31 }
32}
33
34impl Intent {
35 pub fn sign(&self, signer: &dyn Signer) -> Result<SignedIntent, VeilError> {
45 let intent_bytes = self.to_bytes()?;
46 let hash = blake3::hash(&intent_bytes);
47 let signature = signer.sign(hash.as_bytes())?;
48 let pubkey = signer.public_key();
49
50 Ok(SignedIntent {
51 intent: self.clone(),
52 pubkey,
53 signature,
54 })
55 }
56}
57
58fn base64_encode(data: &[u8]) -> String {
61 const CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
63 let mut result = String::new();
64 for chunk in data.chunks(3) {
65 let b0 = chunk[0] as u32;
66 let b1 = if chunk.len() > 1 { chunk[1] as u32 } else { 0 };
67 let b2 = if chunk.len() > 2 { chunk[2] as u32 } else { 0 };
68 let triple = (b0 << 16) | (b1 << 8) | b2;
69
70 result.push(CHARS[((triple >> 18) & 0x3F) as usize] as char);
71 result.push(CHARS[((triple >> 12) & 0x3F) as usize] as char);
72 if chunk.len() > 1 {
73 result.push(CHARS[((triple >> 6) & 0x3F) as usize] as char);
74 } else {
75 result.push('=');
76 }
77 if chunk.len() > 2 {
78 result.push(CHARS[(triple & 0x3F) as usize] as char);
79 } else {
80 result.push('=');
81 }
82 }
83 result
84}
85
86fn hex_encode(data: &[u8]) -> String {
87 data.iter().map(|b| format!("{:02x}", b)).collect()
88}