Serialize an expression to bytes (iterative to avoid stack overflow).
(e: &Expr, buf: &mut Vec<u8>)
| 131 | // hold is corruption (or a stale format) — reject before allocating. |
| 132 | if n > buf.len() / 32 { |
| 133 | return Err(format!( |
| 134 | "{ctx}: assumption count {n} exceeds remaining buffer — corrupt or \ |
| 135 | pre-bundle-format .ixe" |
| 136 | )); |
| 137 | } |
| 138 | let mut assumptions: Vec<Address> = Vec::with_capacity(n); |
| 139 | for i in 0..n { |
| 140 | let addr = get_address(buf)?; |
| 141 | if let Some(prev) = assumptions.last() |
| 142 | && *prev >= addr |
| 143 | { |
| 144 | return Err(format!( |
| 145 | "{ctx}: assumptions not strictly ascending at idx {i} ({} then {})", |
| 146 | prev.hex(), |
| 147 | addr.hex() |
| 148 | )); |
| 149 | } |
| 150 | assumptions.push(addr); |
| 151 | } |
| 152 | Ok((stored_root, main, assumptions)) |
| 153 | } |
| 154 | |
| 155 | /// Read the §1 blob section, verifying `Address::hash(bytes) == addr` |
| 156 | /// per entry. Without the check a swapped blob would silently change a |
| 157 | /// Nat/String literal's value under an otherwise-valid file (the consts |
| 158 | /// merkle root covers only const addresses). |
| 159 | fn read_blob_section( |
| 160 | buf: &mut &[u8], |
| 161 | ctx: &str, |
| 162 | ) -> Result<Vec<(Address, Vec<u8>)>, String> { |
| 163 | let num_blobs = get_u64(buf)? as usize; |
| 164 | // Each blob entry needs at least addr (32) + a length byte. |
| 165 | if num_blobs > buf.len() / 33 { |
| 166 | return Err(format!( |
| 167 | "{ctx}: blob count {num_blobs} exceeds remaining buffer" |
| 168 | )); |
| 169 | } |
| 170 | let mut blobs = Vec::with_capacity(num_blobs); |
| 171 | for i in 0..num_blobs { |
| 172 | let addr = get_address(buf)?; |
| 173 | let len = get_u64(buf)? as usize; |
| 174 | if buf.len() < len { |
| 175 | return Err(format!( |
| 176 | "{ctx}: need {} bytes for blob, have {}", |
| 177 | len, |
| 178 | buf.len() |
| 179 | )); |
| 180 | } |
| 181 | let (bytes, rest) = buf.split_at(len); |
| 182 | *buf = rest; |
| 183 | let computed = Address::hash(bytes); |
| 184 | if computed != addr { |
| 185 | return Err(format!( |
| 186 | "{ctx}: blob at idx {i} bytes hash to {} but stored under {}", |
| 187 | computed.hex(), |
| 188 | addr.hex() |
| 189 | )); |
| 190 | } |