decoder.rs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2026 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use darkfi_serial::{deserialize_limited_partial, deserialize_partial, VarInt};
  19. use super::{
  20. compiler::MAGIC_BYTES,
  21. constants::{
  22. MAX_ARGS_PER_OPCODE, MAX_BIN_SIZE, MAX_CONSTANTS, MAX_HEAP_SIZE, MAX_K, MAX_LITERALS,
  23. MAX_NS_LEN, MAX_OPCODES, MAX_STRING_LEN, MAX_WITNESSES, MIN_BIN_SIZE, SECTION_CIRCUIT,
  24. SECTION_CONSTANT, SECTION_DEBUG, SECTION_LITERAL, SECTION_WITNESS,
  25. },
  26. types::HeapType,
  27. LitType, Opcode, VarType,
  28. };
  29. use crate::{Error::ZkasDecoderError as ZkasErr, Result};
  30. /// A ZkBinary decoded from compiled zkas code.
  31. /// This is used by the zkvm.
  32. ///
  33. /// The binary format consists of:
  34. /// - Header: magic bytes, version, k param, namespace
  35. /// - `.constant` section: constant types and names
  36. /// - `.literal` section: literal types and values
  37. /// - `.witness` section: witness types
  38. /// - `.circuit` section: opcoddes and their arguments
  39. /// - `.debug` section (optional): debug informatioon
  40. #[derive(Clone, Debug)]
  41. // ANCHOR: zkbinary-struct
  42. pub struct ZkBinary {
  43. pub namespace: String,
  44. pub k: u32,
  45. pub constants: Vec<(VarType, String)>,
  46. pub literals: Vec<(LitType, String)>,
  47. pub witnesses: Vec<VarType>,
  48. pub opcodes: Vec<(Opcode, Vec<(HeapType, usize)>)>,
  49. pub debug_info: Option<DebugInfo>,
  50. }
  51. // ANCHOR_END: zkbinary-struct
  52. /// Debug information decoded from the optional .debug section
  53. /// Contains source mappings to help debug circuit failures.
  54. #[derive(Clone, Debug, Default)]
  55. pub struct DebugInfo {
  56. /// Source locations (line, col) for each opcode
  57. pub opcode_locations: Vec<(usize, usize)>,
  58. /// Variable names for each heap entry (constants, witnesses, assigned vars in order)
  59. pub heap_names: Vec<String>,
  60. /// Literal values as strings
  61. pub literal_names: Vec<String>,
  62. }
  63. // https://stackoverflow.com/questions/35901547/how-can-i-find-a-subsequence-in-a-u8-slice
  64. fn find_subslice(haystack: &[u8], needle: &[u8]) -> Option<usize> {
  65. haystack.windows(needle.len()).position(|window| window == needle)
  66. }
  67. fn find_section(bytes: &[u8], section: &[u8]) -> Result<usize> {
  68. find_subslice(bytes, section).ok_or_else(|| {
  69. ZkasErr(format!("Could not find {} section", String::from_utf8_lossy(section)))
  70. })
  71. }
  72. /// Validate that a count is within limits and reasonable for the remaining bytes
  73. fn validate_count(
  74. count: u64,
  75. max: usize,
  76. remaining_bytes: usize,
  77. item_name: &str,
  78. ) -> Result<usize> {
  79. let count = count as usize;
  80. if count > max {
  81. return Err(ZkasErr(format!(
  82. "{} count {} exceeds maximum allowed {}",
  83. item_name, count, max
  84. )));
  85. }
  86. // Sanity check: each item needs at least 1 byte
  87. if count > remaining_bytes {
  88. return Err(ZkasErr(format!(
  89. "{} count {} exceeds remaining bytes {}",
  90. item_name, count, remaining_bytes
  91. )));
  92. }
  93. Ok(count)
  94. }
  95. struct SectionOffsets {
  96. constant: usize,
  97. literal: usize,
  98. witness: usize,
  99. circuit: usize,
  100. debug: usize,
  101. }
  102. impl SectionOffsets {
  103. /// Find all section offsets in the binary and validate their order
  104. fn find(bytes: &[u8]) -> Result<Self> {
  105. let constant = find_section(bytes, SECTION_CONSTANT)?;
  106. let literal = find_section(bytes, SECTION_LITERAL)?;
  107. let witness = find_section(bytes, SECTION_WITNESS)?;
  108. let circuit = find_section(bytes, SECTION_CIRCUIT)?;
  109. // Debug section is optional, so use end of bytes if not present
  110. let debug = find_subslice(bytes, SECTION_DEBUG).unwrap_or(bytes.len());
  111. // Validate section order
  112. let sections = [
  113. (constant, ".constant"),
  114. (literal, ".literal"),
  115. (witness, ".witness"),
  116. (circuit, ".circuit"),
  117. (debug, "debug/EOF"),
  118. ];
  119. for i in 0..sections.len() - 1 {
  120. if sections[i].0 > sections[i + 1].0 {
  121. return Err(ZkasErr(format!(
  122. "{} section appeared before {}",
  123. sections[i + 1].1,
  124. sections[i].1
  125. )));
  126. }
  127. }
  128. Ok(Self { constant, literal, witness, circuit, debug })
  129. }
  130. /// Extract the bytes for the constant section
  131. fn constant_bytes<'a>(&self, bytes: &'a [u8]) -> &'a [u8] {
  132. &bytes[self.constant + SECTION_CONSTANT.len()..self.literal]
  133. }
  134. /// Extract the bytes for the literal section
  135. fn literal_bytes<'a>(&self, bytes: &'a [u8]) -> &'a [u8] {
  136. &bytes[self.literal + SECTION_LITERAL.len()..self.witness]
  137. }
  138. /// Extract the bytes for the witness section
  139. fn witness_bytes<'a>(&self, bytes: &'a [u8]) -> &'a [u8] {
  140. &bytes[self.witness + SECTION_WITNESS.len()..self.circuit]
  141. }
  142. /// Extract the bytes for the circuit section
  143. fn circuit_bytes<'a>(&self, bytes: &'a [u8]) -> &'a [u8] {
  144. &bytes[self.circuit + SECTION_CIRCUIT.len()..self.debug]
  145. }
  146. /// Extract the bytes for the debug section if present
  147. fn debug_bytes<'a>(&self, bytes: &'a [u8]) -> Option<&'a [u8]> {
  148. if self.debug < bytes.len() {
  149. Some(&bytes[self.debug + SECTION_DEBUG.len()..])
  150. } else {
  151. None
  152. }
  153. }
  154. }
  155. impl ZkBinary {
  156. /// Decode a ZkBinary from compiled bytes
  157. pub fn decode(bytes: &[u8], decode_debug_symbols: bool) -> Result<Self> {
  158. // Ensure that bytes is a certain minimum length. Otherwise the code
  159. // below will panic due to an index out of bounds error.
  160. if bytes.len() < MIN_BIN_SIZE {
  161. return Err(ZkasErr("Not enough bytes".to_string()))
  162. }
  163. // Check max size to prevent decoding maliciously large binaries
  164. if bytes.len() > MAX_BIN_SIZE {
  165. return Err(ZkasErr(format!(
  166. "Binary size {} exceeds maximum allowed {}",
  167. bytes.len(),
  168. MAX_BIN_SIZE
  169. )))
  170. }
  171. let magic_bytes = &bytes[0..4];
  172. if magic_bytes != MAGIC_BYTES {
  173. return Err(ZkasErr("Magic bytes are incorrect".to_string()))
  174. }
  175. let _binary_version = &bytes[4];
  176. // Deserialize the k param
  177. let (k, _): (u32, _) = deserialize_partial(&bytes[5..9])?;
  178. // For now, we'll limit k.
  179. if k > MAX_K {
  180. return Err(ZkasErr(format!("k param is too high, max allowed is {MAX_K}")))
  181. }
  182. // After the binary version and k, we're supposed to have the witness namespace
  183. let (namespace, _) = deserialize_limited_partial::<String>(&bytes[9..], MAX_NS_LEN)?;
  184. // ===============
  185. // Section parsing
  186. // ===============
  187. let offsets = SectionOffsets::find(bytes)?;
  188. let constants = Self::parse_constants(offsets.constant_bytes(bytes))?;
  189. let literals = Self::parse_literals(offsets.literal_bytes(bytes))?;
  190. let witnesses = Self::parse_witnesses(offsets.witness_bytes(bytes))?;
  191. let opcodes = Self::parse_circuit(offsets.circuit_bytes(bytes))?;
  192. let mut debug_info = None;
  193. if decode_debug_symbols {
  194. debug_info = match offsets.debug_bytes(bytes) {
  195. Some(debug_bytes) => Some(Self::parse_debug(debug_bytes)?),
  196. None => None,
  197. };
  198. }
  199. let binary = Self { namespace, k, constants, literals, witnesses, opcodes, debug_info };
  200. // Validate cross-references between sections
  201. binary.validate()?;
  202. Ok(binary)
  203. }
  204. /// Validate cross-references and consistency between sections.
  205. /// This catches malicious binaries that pass individual section
  206. /// parsing but have invalid references.
  207. fn validate(&self) -> Result<()> {
  208. // Calculate actual heap size: constants + witnesses + assigned vars
  209. // Each opcode that produces a result adds one entry to the heap
  210. let num_assignments = self
  211. .opcodes
  212. .iter()
  213. .filter(|(op, _)| {
  214. let (ret_types, _) = op.arg_types();
  215. !ret_types.is_empty()
  216. })
  217. .count();
  218. let heap_size = self.constants.len() + self.witnesses.len() + num_assignments;
  219. // Validate all heap references in opcodes
  220. for (op_idx, (opcode, args)) in self.opcodes.iter().enumerate() {
  221. // Calculate heap size at this point in execution
  222. // (constants + witnesses + results from previous opcodes)
  223. let prev_assignments = self.opcodes[..op_idx]
  224. .iter()
  225. .filter(|(op, _)| {
  226. let (ret_types, _) = op.arg_types();
  227. !ret_types.is_empty()
  228. })
  229. .count();
  230. let available_heap = self.constants.len() + self.witnesses.len() + prev_assignments;
  231. for (heap_type, heap_idx) in args {
  232. match heap_type {
  233. HeapType::Var => {
  234. if *heap_idx >= available_heap {
  235. return Err(ZkasErr(format!(
  236. "Opcode {} references heap idx {} but only {} entries available",
  237. opcode.name(),
  238. heap_idx,
  239. available_heap
  240. )));
  241. }
  242. }
  243. HeapType::Lit => {
  244. if *heap_idx >= self.literals.len() {
  245. return Err(ZkasErr(format!(
  246. "Opcode {} references literal idx {} but only {} literals exist",
  247. opcode.name(),
  248. heap_idx,
  249. self.literals.len()
  250. )));
  251. }
  252. }
  253. }
  254. }
  255. }
  256. // Validate debug info consistency if present
  257. if let Some(ref debug) = self.debug_info {
  258. if debug.opcode_locations.len() != self.opcodes.len() {
  259. return Err(ZkasErr(format!(
  260. "Debug info has {} opcode locations but circuit has {} opcodes",
  261. debug.opcode_locations.len(),
  262. self.opcodes.len()
  263. )));
  264. }
  265. if debug.heap_names.len() != heap_size {
  266. return Err(ZkasErr(format!(
  267. "Debug info has {} heap names but heap has {} entries",
  268. debug.heap_names.len(),
  269. heap_size
  270. )));
  271. }
  272. if debug.literal_names.len() != self.literals.len() {
  273. return Err(ZkasErr(format!(
  274. "Debug info has {} literal names but {} literals exist",
  275. debug.literal_names.len(),
  276. self.literals.len()
  277. )));
  278. }
  279. }
  280. Ok(())
  281. }
  282. fn parse_constants(bytes: &[u8]) -> Result<Vec<(VarType, String)>> {
  283. let mut constants = vec![];
  284. let mut offset = 0;
  285. while offset < bytes.len() {
  286. // Check we haven't exceeded the limit
  287. if constants.len() >= MAX_CONSTANTS {
  288. return Err(ZkasErr(format!(
  289. "Too many constants, maximum allowed is {MAX_CONSTANTS}"
  290. )))
  291. }
  292. let c_type = VarType::from_repr(bytes[offset]).ok_or_else(|| {
  293. ZkasErr(format!("Could not decode constant VarType from {}", bytes[offset]))
  294. })?;
  295. offset += 1;
  296. let (name, len) =
  297. deserialize_limited_partial::<String>(&bytes[offset..], MAX_STRING_LEN)?;
  298. offset += len;
  299. constants.push((c_type, name));
  300. }
  301. Ok(constants)
  302. }
  303. fn parse_literals(bytes: &[u8]) -> Result<Vec<(LitType, String)>> {
  304. let mut literals = vec![];
  305. let mut offset = 0;
  306. while offset < bytes.len() {
  307. // Check we haven't exceeded the limit
  308. if literals.len() >= MAX_LITERALS {
  309. return Err(ZkasErr(format!(
  310. "Too many literals, maximum allowed is {MAX_LITERALS}"
  311. )));
  312. }
  313. let l_type = LitType::from_repr(bytes[offset]).ok_or_else(|| {
  314. ZkasErr(format!("Could not decode literal LitType from {}", bytes[offset]))
  315. })?;
  316. offset += 1;
  317. let (name, len) =
  318. deserialize_limited_partial::<String>(&bytes[offset..], MAX_STRING_LEN)?;
  319. offset += len;
  320. literals.push((l_type, name));
  321. }
  322. Ok(literals)
  323. }
  324. fn parse_witnesses(bytes: &[u8]) -> Result<Vec<VarType>> {
  325. // Check vount before allocating
  326. if bytes.len() > MAX_WITNESSES {
  327. return Err(ZkasErr(format!(
  328. "Too many witnesses ({}), maximum allowed is {}",
  329. bytes.len(),
  330. MAX_WITNESSES
  331. )));
  332. }
  333. let mut witnesses = Vec::with_capacity(bytes.len());
  334. for &byte in bytes {
  335. let w_type = VarType::from_repr(byte).ok_or_else(|| {
  336. ZkasErr(format!("Could not decode witness VarType from {}", byte))
  337. })?;
  338. witnesses.push(w_type);
  339. }
  340. Ok(witnesses)
  341. }
  342. #[allow(clippy::type_complexity)]
  343. fn parse_circuit(bytes: &[u8]) -> Result<Vec<(Opcode, Vec<(HeapType, usize)>)>> {
  344. let mut opcodes = vec![];
  345. let mut offset = 0;
  346. while offset < bytes.len() {
  347. // Check opcode count limit
  348. if opcodes.len() >= MAX_OPCODES {
  349. return Err(ZkasErr(format!("Too many opcodes, maximum allowed is {MAX_OPCODES}")))
  350. }
  351. let opcode = Opcode::from_repr(bytes[offset]).ok_or_else(|| {
  352. ZkasErr(format!("Could not decode Opcode from {}", bytes[offset]))
  353. })?;
  354. offset += 1;
  355. // TODO: Check that the types and arg number are correct
  356. // Parse argument count
  357. let (arg_count, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  358. offset += len;
  359. // Validate argument count
  360. let arg_count =
  361. validate_count(arg_count.0, MAX_ARGS_PER_OPCODE, bytes.len() - offset, "Argument")?;
  362. // Parse arguments
  363. let mut args = Vec::with_capacity(arg_count);
  364. for _ in 0..arg_count {
  365. // Check bounds to prevent panics
  366. if offset >= bytes.len() {
  367. return Err(ZkasErr(format!(
  368. "Bad offset for circuit: offset {} is >= circuit len {}",
  369. offset,
  370. bytes.len()
  371. )));
  372. }
  373. let heap_type_byte = bytes[offset];
  374. offset += 1;
  375. if offset >= bytes.len() {
  376. return Err(ZkasErr(format!(
  377. "Bad offset for circuit: offset {} is >= circuit len {}",
  378. offset,
  379. bytes.len()
  380. )));
  381. }
  382. let (heap_index, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  383. offset += len;
  384. let heap_type = HeapType::from_repr(heap_type_byte).ok_or_else(|| {
  385. ZkasErr(format!("Could not decode HeapType from {}", heap_type_byte))
  386. })?;
  387. // Validate heap index is reasonable
  388. let heap_idx = heap_index.0 as usize;
  389. if heap_idx > MAX_HEAP_SIZE {
  390. return Err(ZkasErr(format!(
  391. "Heap index {} exceeds maximum allowed {}",
  392. heap_idx, MAX_HEAP_SIZE
  393. )));
  394. }
  395. args.push((heap_type, heap_index.0 as usize));
  396. }
  397. opcodes.push((opcode, args));
  398. }
  399. Ok(opcodes)
  400. }
  401. fn parse_debug(bytes: &[u8]) -> Result<DebugInfo> {
  402. let mut offset = 0;
  403. // Parse opcode source locations
  404. let (num_opcodes, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  405. offset += len;
  406. let num_opcodes =
  407. validate_count(num_opcodes.0, MAX_OPCODES, bytes.len() - offset, "Debug opcode")?;
  408. let mut opcode_locations = Vec::with_capacity(num_opcodes);
  409. for _ in 0..num_opcodes {
  410. let (line, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  411. offset += len;
  412. let (column, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  413. offset += len;
  414. opcode_locations.push((line.0 as usize, column.0 as usize));
  415. }
  416. // Parse heap var names
  417. let (heap_size, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  418. offset += len;
  419. let heap_size =
  420. validate_count(heap_size.0, MAX_HEAP_SIZE, bytes.len() - offset, "Debug heap")?;
  421. let mut heap_names = Vec::with_capacity(heap_size);
  422. for _ in 0..heap_size {
  423. let (name, len) =
  424. deserialize_limited_partial::<String>(&bytes[offset..], MAX_STRING_LEN)?;
  425. offset += len;
  426. heap_names.push(name);
  427. }
  428. // Parse literal names
  429. let (num_literals, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  430. offset += len;
  431. let num_literals =
  432. validate_count(num_literals.0, MAX_LITERALS, bytes.len() - offset, "Debug literal")?;
  433. let mut literal_names = Vec::with_capacity(num_literals);
  434. for _ in 0..num_literals {
  435. let (name, len) =
  436. deserialize_limited_partial::<String>(&bytes[offset..], MAX_STRING_LEN)?;
  437. offset += len;
  438. literal_names.push(name);
  439. }
  440. Ok(DebugInfo { opcode_locations, heap_names, literal_names })
  441. }
  442. /// Get the source location (line, column) for a given opcode index.
  443. /// Returns `None` if debug info is not present or index is OOB.
  444. pub fn opcode_location(&self, opcode_idx: usize) -> Option<(usize, usize)> {
  445. self.debug_info.as_ref()?.opcode_locations.get(opcode_idx).copied()
  446. }
  447. /// Get the variable name for a given heap index.
  448. /// Returns `None` if debug info is not present or index is OOB.
  449. pub fn heap_name(&self, heap_idx: usize) -> Option<&str> {
  450. self.debug_info.as_ref()?.heap_names.get(heap_idx).map(|s| s.as_str())
  451. }
  452. /// Get the literal name/value for a given literal index.
  453. /// Returns `None` if debug info is not present or index is OOB.
  454. pub fn literal_name(&self, literal_idx: usize) -> Option<&str> {
  455. self.debug_info.as_ref()?.literal_names.get(literal_idx).map(|s| s.as_str())
  456. }
  457. /// Check if debug info is present
  458. pub fn has_debug_info(&self) -> bool {
  459. self.debug_info.is_some()
  460. }
  461. }
  462. #[cfg(test)]
  463. mod tests {
  464. use crate::zkas::ZkBinary;
  465. #[test]
  466. fn panic_regression_001() {
  467. // Out-of-memory panic from string deserialization.
  468. // Read `doc/src/zkas/bincode.md` to understand the input.
  469. let data = vec![11u8, 1, 177, 53, 1, 0, 0, 0, 0, 255, 0, 204, 200, 72, 72, 72, 72, 1];
  470. let _dec = ZkBinary::decode(&data, true);
  471. }
  472. #[test]
  473. fn panic_regression_002() {
  474. // Index out of bounds panic in parse_circuit().
  475. // Read `doc/src/zkas/bincode.md` to understand the input.
  476. let data = vec![
  477. 11u8, 1, 177, 53, 2, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 83, 105,
  478. 109, 112, 108, 101, 46, 99, 111, 110, 115, 116, 97, 110, 116, 3, 18, 86, 65, 76, 85,
  479. 69, 95, 67, 79, 77, 77, 73, 84, 95, 86, 65, 76, 85, 69, 2, 19, 86, 65, 76, 85, 69, 95,
  480. 67, 79, 77, 77, 73, 84, 95, 82, 65, 77, 68, 79, 77, 46, 108, 105, 116, 101, 114, 97,
  481. 108, 46, 119, 105, 116, 110, 101, 115, 115, 16, 18, 46, 99, 105, 114, 99, 117, 105,
  482. 116, 4, 2, 0, 2, 0, 0, 2, 2, 0, 3, 0, 1, 8, 2, 0, 4, 0, 5, 8, 1, 0, 6, 9, 1, 0, 6, 240,
  483. 1, 0, 7, 240, 41, 0, 0, 0, 1, 0, 8,
  484. ];
  485. let _dec = ZkBinary::decode(&data, true);
  486. }
  487. }