decoder.rs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  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. for (opcode, args) in &self.opcodes {
  220. let (_ret, arg_types) = opcode.arg_types();
  221. let variadic = arg_types.iter().any(|t| matches!(t, VarType::BaseArray | VarType::Any));
  222. if variadic {
  223. if args.is_empty() {
  224. return Err(ZkasErr(format!("Opcode {} requires >= 1 argument", opcode.name())))
  225. }
  226. } else if args.len() != arg_types.len() {
  227. return Err(ZkasErr(format!(
  228. "Opcode {} expects {} args, got {}",
  229. opcode.name(),
  230. arg_types.len(),
  231. args.len()
  232. )))
  233. }
  234. }
  235. // Validate all heap references in opcodes
  236. for (op_idx, (opcode, args)) in self.opcodes.iter().enumerate() {
  237. // Calculate heap size at this point in execution
  238. // (constants + witnesses + results from previous opcodes)
  239. let prev_assignments = self.opcodes[..op_idx]
  240. .iter()
  241. .filter(|(op, _)| {
  242. let (ret_types, _) = op.arg_types();
  243. !ret_types.is_empty()
  244. })
  245. .count();
  246. let available_heap = self.constants.len() + self.witnesses.len() + prev_assignments;
  247. for (heap_type, heap_idx) in args {
  248. match heap_type {
  249. HeapType::Var => {
  250. if *heap_idx >= available_heap {
  251. return Err(ZkasErr(format!(
  252. "Opcode {} references heap idx {} but only {} entries available",
  253. opcode.name(),
  254. heap_idx,
  255. available_heap
  256. )));
  257. }
  258. }
  259. HeapType::Lit => {
  260. if *heap_idx >= self.literals.len() {
  261. return Err(ZkasErr(format!(
  262. "Opcode {} references literal idx {} but only {} literals exist",
  263. opcode.name(),
  264. heap_idx,
  265. self.literals.len()
  266. )));
  267. }
  268. }
  269. }
  270. }
  271. }
  272. // Validate debug info consistency if present
  273. if let Some(ref debug) = self.debug_info {
  274. if debug.opcode_locations.len() != self.opcodes.len() {
  275. return Err(ZkasErr(format!(
  276. "Debug info has {} opcode locations but circuit has {} opcodes",
  277. debug.opcode_locations.len(),
  278. self.opcodes.len()
  279. )));
  280. }
  281. if debug.heap_names.len() != heap_size {
  282. return Err(ZkasErr(format!(
  283. "Debug info has {} heap names but heap has {} entries",
  284. debug.heap_names.len(),
  285. heap_size
  286. )));
  287. }
  288. if debug.literal_names.len() != self.literals.len() {
  289. return Err(ZkasErr(format!(
  290. "Debug info has {} literal names but {} literals exist",
  291. debug.literal_names.len(),
  292. self.literals.len()
  293. )));
  294. }
  295. }
  296. Ok(())
  297. }
  298. fn parse_constants(bytes: &[u8]) -> Result<Vec<(VarType, String)>> {
  299. let mut constants = vec![];
  300. let mut offset = 0;
  301. while offset < bytes.len() {
  302. // Check we haven't exceeded the limit
  303. if constants.len() >= MAX_CONSTANTS {
  304. return Err(ZkasErr(format!(
  305. "Too many constants, maximum allowed is {MAX_CONSTANTS}"
  306. )))
  307. }
  308. let c_type = VarType::from_repr(bytes[offset]).ok_or_else(|| {
  309. ZkasErr(format!("Could not decode constant VarType from {}", bytes[offset]))
  310. })?;
  311. offset += 1;
  312. let (name, len) =
  313. deserialize_limited_partial::<String>(&bytes[offset..], MAX_STRING_LEN)?;
  314. offset += len;
  315. constants.push((c_type, name));
  316. }
  317. Ok(constants)
  318. }
  319. fn parse_literals(bytes: &[u8]) -> Result<Vec<(LitType, String)>> {
  320. let mut literals = vec![];
  321. let mut offset = 0;
  322. while offset < bytes.len() {
  323. // Check we haven't exceeded the limit
  324. if literals.len() >= MAX_LITERALS {
  325. return Err(ZkasErr(format!(
  326. "Too many literals, maximum allowed is {MAX_LITERALS}"
  327. )));
  328. }
  329. let l_type = LitType::from_repr(bytes[offset]).ok_or_else(|| {
  330. ZkasErr(format!("Could not decode literal LitType from {}", bytes[offset]))
  331. })?;
  332. offset += 1;
  333. let (name, len) =
  334. deserialize_limited_partial::<String>(&bytes[offset..], MAX_STRING_LEN)?;
  335. offset += len;
  336. literals.push((l_type, name));
  337. }
  338. Ok(literals)
  339. }
  340. fn parse_witnesses(bytes: &[u8]) -> Result<Vec<VarType>> {
  341. // Check vount before allocating
  342. if bytes.len() > MAX_WITNESSES {
  343. return Err(ZkasErr(format!(
  344. "Too many witnesses ({}), maximum allowed is {}",
  345. bytes.len(),
  346. MAX_WITNESSES
  347. )));
  348. }
  349. let mut witnesses = Vec::with_capacity(bytes.len());
  350. for &byte in bytes {
  351. let w_type = VarType::from_repr(byte).ok_or_else(|| {
  352. ZkasErr(format!("Could not decode witness VarType from {}", byte))
  353. })?;
  354. witnesses.push(w_type);
  355. }
  356. Ok(witnesses)
  357. }
  358. #[allow(clippy::type_complexity)]
  359. fn parse_circuit(bytes: &[u8]) -> Result<Vec<(Opcode, Vec<(HeapType, usize)>)>> {
  360. let mut opcodes = vec![];
  361. let mut offset = 0;
  362. while offset < bytes.len() {
  363. // Check opcode count limit
  364. if opcodes.len() >= MAX_OPCODES {
  365. return Err(ZkasErr(format!("Too many opcodes, maximum allowed is {MAX_OPCODES}")))
  366. }
  367. let opcode = Opcode::from_repr(bytes[offset]).ok_or_else(|| {
  368. ZkasErr(format!("Could not decode Opcode from {}", bytes[offset]))
  369. })?;
  370. offset += 1;
  371. // Parse argument count
  372. let (arg_count, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  373. offset += len;
  374. // Validate argument count
  375. let arg_count =
  376. validate_count(arg_count.0, MAX_ARGS_PER_OPCODE, bytes.len() - offset, "Argument")?;
  377. // Parse arguments
  378. let mut args = Vec::with_capacity(arg_count);
  379. for _ in 0..arg_count {
  380. // Check bounds to prevent panics
  381. if offset >= bytes.len() {
  382. return Err(ZkasErr(format!(
  383. "Bad offset for circuit: offset {} is >= circuit len {}",
  384. offset,
  385. bytes.len()
  386. )));
  387. }
  388. let heap_type_byte = bytes[offset];
  389. offset += 1;
  390. if offset >= bytes.len() {
  391. return Err(ZkasErr(format!(
  392. "Bad offset for circuit: offset {} is >= circuit len {}",
  393. offset,
  394. bytes.len()
  395. )));
  396. }
  397. let (heap_index, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  398. offset += len;
  399. let heap_type = HeapType::from_repr(heap_type_byte).ok_or_else(|| {
  400. ZkasErr(format!("Could not decode HeapType from {}", heap_type_byte))
  401. })?;
  402. // Validate heap index is reasonable
  403. let heap_idx = heap_index.0 as usize;
  404. if heap_idx > MAX_HEAP_SIZE {
  405. return Err(ZkasErr(format!(
  406. "Heap index {} exceeds maximum allowed {}",
  407. heap_idx, MAX_HEAP_SIZE
  408. )));
  409. }
  410. args.push((heap_type, heap_index.0 as usize));
  411. }
  412. opcodes.push((opcode, args));
  413. }
  414. Ok(opcodes)
  415. }
  416. fn parse_debug(bytes: &[u8]) -> Result<DebugInfo> {
  417. let mut offset = 0;
  418. // Parse opcode source locations
  419. let (num_opcodes, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  420. offset += len;
  421. let num_opcodes =
  422. validate_count(num_opcodes.0, MAX_OPCODES, bytes.len() - offset, "Debug opcode")?;
  423. let mut opcode_locations = Vec::with_capacity(num_opcodes);
  424. for _ in 0..num_opcodes {
  425. let (line, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  426. offset += len;
  427. let (column, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  428. offset += len;
  429. opcode_locations.push((line.0 as usize, column.0 as usize));
  430. }
  431. // Parse heap var names
  432. let (heap_size, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  433. offset += len;
  434. let heap_size =
  435. validate_count(heap_size.0, MAX_HEAP_SIZE, bytes.len() - offset, "Debug heap")?;
  436. let mut heap_names = Vec::with_capacity(heap_size);
  437. for _ in 0..heap_size {
  438. let (name, len) =
  439. deserialize_limited_partial::<String>(&bytes[offset..], MAX_STRING_LEN)?;
  440. offset += len;
  441. heap_names.push(name);
  442. }
  443. // Parse literal names
  444. let (num_literals, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  445. offset += len;
  446. let num_literals =
  447. validate_count(num_literals.0, MAX_LITERALS, bytes.len() - offset, "Debug literal")?;
  448. let mut literal_names = Vec::with_capacity(num_literals);
  449. for _ in 0..num_literals {
  450. let (name, len) =
  451. deserialize_limited_partial::<String>(&bytes[offset..], MAX_STRING_LEN)?;
  452. offset += len;
  453. literal_names.push(name);
  454. }
  455. Ok(DebugInfo { opcode_locations, heap_names, literal_names })
  456. }
  457. /// Get the source location (line, column) for a given opcode index.
  458. /// Returns `None` if debug info is not present or index is OOB.
  459. pub fn opcode_location(&self, opcode_idx: usize) -> Option<(usize, usize)> {
  460. self.debug_info.as_ref()?.opcode_locations.get(opcode_idx).copied()
  461. }
  462. /// Get the variable name for a given heap index.
  463. /// Returns `None` if debug info is not present or index is OOB.
  464. pub fn heap_name(&self, heap_idx: usize) -> Option<&str> {
  465. self.debug_info.as_ref()?.heap_names.get(heap_idx).map(|s| s.as_str())
  466. }
  467. /// Get the literal name/value for a given literal index.
  468. /// Returns `None` if debug info is not present or index is OOB.
  469. pub fn literal_name(&self, literal_idx: usize) -> Option<&str> {
  470. self.debug_info.as_ref()?.literal_names.get(literal_idx).map(|s| s.as_str())
  471. }
  472. /// Check if debug info is present
  473. pub fn has_debug_info(&self) -> bool {
  474. self.debug_info.is_some()
  475. }
  476. }
  477. #[cfg(test)]
  478. mod tests {
  479. use crate::zkas::ZkBinary;
  480. #[test]
  481. fn panic_regression_001() {
  482. // Out-of-memory panic from string deserialization.
  483. // Read `doc/src/zkas/bincode.md` to understand the input.
  484. let data = vec![11u8, 1, 177, 53, 1, 0, 0, 0, 0, 255, 0, 204, 200, 72, 72, 72, 72, 1];
  485. let _dec = ZkBinary::decode(&data, true);
  486. }
  487. #[test]
  488. fn panic_regression_002() {
  489. // Index out of bounds panic in parse_circuit().
  490. // Read `doc/src/zkas/bincode.md` to understand the input.
  491. let data = vec![
  492. 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,
  493. 109, 112, 108, 101, 46, 99, 111, 110, 115, 116, 97, 110, 116, 3, 18, 86, 65, 76, 85,
  494. 69, 95, 67, 79, 77, 77, 73, 84, 95, 86, 65, 76, 85, 69, 2, 19, 86, 65, 76, 85, 69, 95,
  495. 67, 79, 77, 77, 73, 84, 95, 82, 65, 77, 68, 79, 77, 46, 108, 105, 116, 101, 114, 97,
  496. 108, 46, 119, 105, 116, 110, 101, 115, 115, 16, 18, 46, 99, 105, 114, 99, 117, 105,
  497. 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,
  498. 1, 0, 7, 240, 41, 0, 0, 0, 1, 0, 8,
  499. ];
  500. let _dec = ZkBinary::decode(&data, true);
  501. }
  502. }