1use crate::swarm::bmt::{calculate_chunk_address, keccak256};
12use crate::swarm::errors::Error;
13use crate::swarm::keys::PrivateKey;
14use crate::swarm::typed_bytes::{
15 EthAddress, IDENTIFIER_LENGTH, Identifier, Reference, SIGNATURE_LENGTH, SPAN_LENGTH, Signature,
16 Span,
17};
18
19#[derive(Clone, Debug, PartialEq, Eq)]
23pub struct SingleOwnerChunk {
24 pub identifier: Identifier,
26 pub signature: Signature,
28 pub owner: EthAddress,
30 pub span: Span,
32 pub payload: Vec<u8>,
34}
35
36impl SingleOwnerChunk {
37 pub fn address(&self) -> Result<Reference, Error> {
39 calculate_single_owner_chunk_address(&self.identifier, &self.owner)
40 }
41
42 pub fn data(&self) -> Vec<u8> {
46 let mut out = Vec::with_capacity(
47 IDENTIFIER_LENGTH + SIGNATURE_LENGTH + SPAN_LENGTH + self.payload.len(),
48 );
49 out.extend_from_slice(self.identifier.as_bytes());
50 out.extend_from_slice(self.signature.as_bytes());
51 out.extend_from_slice(self.span.as_bytes());
52 out.extend_from_slice(&self.payload);
53 out
54 }
55}
56
57pub fn calculate_single_owner_chunk_address(
61 identifier: &Identifier,
62 owner: &EthAddress,
63) -> Result<Reference, Error> {
64 let mut buf = Vec::with_capacity(identifier.as_bytes().len() + owner.as_bytes().len());
65 buf.extend_from_slice(identifier.as_bytes());
66 buf.extend_from_slice(owner.as_bytes());
67 let addr = keccak256(&buf);
68 Reference::new(&addr)
69}
70
71pub fn make_single_owner_chunk(
75 identifier: &Identifier,
76 payload: &[u8],
77 signer: &PrivateKey,
78) -> Result<SingleOwnerChunk, Error> {
79 if payload.len() > crate::swarm::bmt::MAX_PAYLOAD_SIZE {
80 return Err(Error::argument(format!(
81 "SOC payload too large: {}",
82 payload.len()
83 )));
84 }
85 let span = Span::from_u64(payload.len() as u64);
86
87 let mut full = Vec::with_capacity(SPAN_LENGTH + payload.len());
89 full.extend_from_slice(span.as_bytes());
90 full.extend_from_slice(payload);
91 let cac_addr = calculate_chunk_address(&full)?;
92
93 let mut to_sign = Vec::with_capacity(IDENTIFIER_LENGTH + 32);
95 to_sign.extend_from_slice(identifier.as_bytes());
96 to_sign.extend_from_slice(&cac_addr);
97 let signature = signer.sign(&to_sign)?;
98
99 let owner = signer.public_key()?.address();
100
101 Ok(SingleOwnerChunk {
102 identifier: *identifier,
103 signature,
104 owner,
105 span,
106 payload: payload.to_vec(),
107 })
108}
109
110pub fn unmarshal_single_owner_chunk(
115 data: &[u8],
116 expected_address: &Reference,
117) -> Result<SingleOwnerChunk, Error> {
118 let min_len = IDENTIFIER_LENGTH + SIGNATURE_LENGTH + SPAN_LENGTH;
119 if data.len() < min_len {
120 return Err(Error::argument(format!(
121 "SOC data too short: {}",
122 data.len()
123 )));
124 }
125
126 let identifier = Identifier::new(&data[..IDENTIFIER_LENGTH])?;
127 let sig_start = IDENTIFIER_LENGTH;
128 let span_start = sig_start + SIGNATURE_LENGTH;
129 let payload_start = span_start + SPAN_LENGTH;
130
131 let signature = Signature::new(&data[sig_start..span_start])?;
132 let span = Span::new(&data[span_start..payload_start])?;
133 let payload = data[payload_start..].to_vec();
134
135 let mut cac_data = Vec::with_capacity(SPAN_LENGTH + payload.len());
137 cac_data.extend_from_slice(span.as_bytes());
138 cac_data.extend_from_slice(&payload);
139 let cac_addr = calculate_chunk_address(&cac_data)?;
140
141 let mut signed = Vec::with_capacity(IDENTIFIER_LENGTH + 32);
143 signed.extend_from_slice(identifier.as_bytes());
144 signed.extend_from_slice(&cac_addr);
145 let pub_key = signature.recover_public_key(&signed)?;
146 let owner = pub_key.address();
147
148 let mut soc_input = Vec::with_capacity(IDENTIFIER_LENGTH + owner.as_bytes().len());
150 soc_input.extend_from_slice(identifier.as_bytes());
151 soc_input.extend_from_slice(owner.as_bytes());
152 let computed = keccak256(&soc_input);
153 if computed != expected_address.as_bytes() {
154 return Err(Error::argument("SOC data does not match expected address"));
155 }
156
157 Ok(SingleOwnerChunk {
158 identifier,
159 signature,
160 owner,
161 span,
162 payload,
163 })
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169 use crate::swarm::typed_bytes::PRIVATE_KEY_LENGTH;
170
171 fn signer(byte: u8) -> PrivateKey {
172 PrivateKey::new(&[byte; PRIVATE_KEY_LENGTH]).unwrap()
173 }
174
175 #[test]
176 fn make_and_unmarshal_round_trip() {
177 let id = Identifier::from_string("test-identifier");
178 let pk = signer(0x55);
179 let payload = b"single owner chunk payload";
180
181 let soc = make_single_owner_chunk(&id, payload, &pk).unwrap();
182
183 assert_eq!(soc.owner, pk.public_key().unwrap().address());
185 let v = soc.signature.as_bytes()[64];
187 assert!(v == 27 || v == 28);
188
189 let address = soc.address().unwrap();
190 let parsed = unmarshal_single_owner_chunk(&soc.data(), &address).unwrap();
191 assert_eq!(parsed.identifier, soc.identifier);
192 assert_eq!(parsed.signature, soc.signature);
193 assert_eq!(parsed.owner, soc.owner);
194 assert_eq!(parsed.span, soc.span);
195 assert_eq!(parsed.payload, soc.payload);
196 }
197
198 #[test]
199 fn unmarshal_rejects_wrong_address() {
200 let id = Identifier::from_string("id");
201 let pk = signer(0x66);
202 let soc = make_single_owner_chunk(&id, b"x", &pk).unwrap();
203
204 let wrong = Reference::new(&[0u8; 32]).unwrap();
205 assert!(unmarshal_single_owner_chunk(&soc.data(), &wrong).is_err());
206 }
207
208 #[test]
209 fn unmarshal_rejects_short_data() {
210 let any = Reference::new(&[0u8; 32]).unwrap();
211 assert!(unmarshal_single_owner_chunk(&[0u8; 10], &any).is_err());
212 }
213
214 #[test]
215 fn calculate_address_is_keccak_id_owner() {
216 let id = Identifier::from_string("hello");
217 let owner = EthAddress::from_hex("fb6916095ca1df60bb79ce92ce3ea74c37c5d359").unwrap();
218 let addr = calculate_single_owner_chunk_address(&id, &owner).unwrap();
219
220 let mut input = Vec::new();
221 input.extend_from_slice(id.as_bytes());
222 input.extend_from_slice(owner.as_bytes());
223 let want = crate::swarm::bmt::keccak256(&input);
224 assert_eq!(addr.as_bytes(), want);
225 }
226}