decoder.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  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_partial, VarInt};
  19. use super::{
  20. compiler::MAGIC_BYTES,
  21. constants::{
  22. MAX_K, MAX_NS_LEN, MIN_BIN_SIZE, SECTION_CIRCUIT, SECTION_CONSTANT, SECTION_DEBUG,
  23. SECTION_LITERAL, SECTION_WITNESS,
  24. },
  25. types::HeapType,
  26. LitType, Opcode, VarType,
  27. };
  28. use crate::{Error::ZkasDecoderError as ZkasErr, Result};
  29. /// A ZkBinary decoded from compiled zkas code.
  30. /// This is used by the zkvm.
  31. ///
  32. /// The binary format consists of:
  33. /// - Header: magic bytes, version, k param, namespace
  34. /// - `.constant` section: constant types and names
  35. /// - `.literal` section: literal types and values
  36. /// - `.witness` section: witness types
  37. /// - `.circuit` section: opcoddes and their arguments
  38. /// - `.debug` section (optional): debug informatioon
  39. #[derive(Clone, Debug)]
  40. // ANCHOR: zkbinary-struct
  41. pub struct ZkBinary {
  42. pub namespace: String,
  43. pub k: u32,
  44. pub constants: Vec<(VarType, String)>,
  45. pub literals: Vec<(LitType, String)>,
  46. pub witnesses: Vec<VarType>,
  47. pub opcodes: Vec<(Opcode, Vec<(HeapType, usize)>)>,
  48. pub debug_info: Option<DebugInfo>,
  49. }
  50. // ANCHOR_END: zkbinary-struct
  51. /// Debug information decoded from the optional .debug section
  52. /// Contains source mappings to help debug circuit failures.
  53. #[derive(Clone, Debug, Default)]
  54. pub struct DebugInfo {
  55. /// Source locations (line, col) for each opcode
  56. pub opcode_locations: Vec<(usize, usize)>,
  57. /// Variable names for each heap entry (constants, witnesses, assigned vars in order)
  58. pub heap_names: Vec<String>,
  59. /// Literal values as strings
  60. pub literal_names: Vec<String>,
  61. }
  62. // https://stackoverflow.com/questions/35901547/how-can-i-find-a-subsequence-in-a-u8-slice
  63. fn find_subslice(haystack: &[u8], needle: &[u8]) -> Option<usize> {
  64. haystack.windows(needle.len()).position(|window| window == needle)
  65. }
  66. fn find_section(bytes: &[u8], section: &[u8]) -> Result<usize> {
  67. find_subslice(bytes, section).ok_or_else(|| {
  68. ZkasErr(format!("Could not find {} section", String::from_utf8_lossy(section)))
  69. })
  70. }
  71. struct SectionOffsets {
  72. constant: usize,
  73. literal: usize,
  74. witness: usize,
  75. circuit: usize,
  76. debug: usize,
  77. }
  78. impl SectionOffsets {
  79. /// Find all section offsets in the binary and validate their order
  80. fn find(bytes: &[u8]) -> Result<Self> {
  81. let constant = find_section(bytes, SECTION_CONSTANT)?;
  82. let literal = find_section(bytes, SECTION_LITERAL)?;
  83. let witness = find_section(bytes, SECTION_WITNESS)?;
  84. let circuit = find_section(bytes, SECTION_CIRCUIT)?;
  85. // Debug section is optional, so use end of bytes if not present
  86. let debug = find_subslice(bytes, SECTION_DEBUG).unwrap_or(bytes.len());
  87. // Validate section order
  88. let sections = [
  89. (constant, ".constant"),
  90. (literal, ".literal"),
  91. (witness, ".witness"),
  92. (circuit, ".circuit"),
  93. (debug, "debug/EOF"),
  94. ];
  95. for i in 0..sections.len() - 1 {
  96. if sections[i].0 > sections[i + 1].0 {
  97. return Err(ZkasErr(format!(
  98. "{} section appeared before {}",
  99. sections[i + 1].1,
  100. sections[i].1
  101. )));
  102. }
  103. }
  104. Ok(Self { constant, literal, witness, circuit, debug })
  105. }
  106. /// Extract the bytes for the constant section
  107. fn constant_bytes<'a>(&self, bytes: &'a [u8]) -> &'a [u8] {
  108. &bytes[self.constant + SECTION_CONSTANT.len()..self.literal]
  109. }
  110. /// Extract the bytes for the literal section
  111. fn literal_bytes<'a>(&self, bytes: &'a [u8]) -> &'a [u8] {
  112. &bytes[self.literal + SECTION_LITERAL.len()..self.witness]
  113. }
  114. /// Extract the bytes for the witness section
  115. fn witness_bytes<'a>(&self, bytes: &'a [u8]) -> &'a [u8] {
  116. &bytes[self.witness + SECTION_WITNESS.len()..self.circuit]
  117. }
  118. /// Extract the bytes for the circuit section
  119. fn circuit_bytes<'a>(&self, bytes: &'a [u8]) -> &'a [u8] {
  120. &bytes[self.circuit + SECTION_CIRCUIT.len()..self.debug]
  121. }
  122. /// Extract the bytes for the debug section if present
  123. fn debug_bytes<'a>(&self, bytes: &'a [u8]) -> Option<&'a [u8]> {
  124. if self.debug < bytes.len() {
  125. Some(&bytes[self.debug + SECTION_DEBUG.len()..])
  126. } else {
  127. None
  128. }
  129. }
  130. }
  131. impl ZkBinary {
  132. /// Decode a ZkBinary from compiled bytes
  133. pub fn decode(bytes: &[u8], decode_debug_symbols: bool) -> Result<Self> {
  134. // Ensure that bytes is a certain minimum length. Otherwise the code
  135. // below will panic due to an index out of bounds error.
  136. if bytes.len() < MIN_BIN_SIZE {
  137. return Err(ZkasErr("Not enough bytes".to_string()))
  138. }
  139. let magic_bytes = &bytes[0..4];
  140. if magic_bytes != MAGIC_BYTES {
  141. return Err(ZkasErr("Magic bytes are incorrect".to_string()))
  142. }
  143. let _binary_version = &bytes[4];
  144. // Deserialize the k param
  145. let (k, _): (u32, _) = deserialize_partial(&bytes[5..9])?;
  146. // For now, we'll limit k.
  147. if k > MAX_K {
  148. return Err(ZkasErr(format!("k param is too high, max allowed is {MAX_K}")))
  149. }
  150. // After the binary version and k, we're supposed to have the witness namespace
  151. let (namespace, _): (String, _) = deserialize_partial(&bytes[9..])?;
  152. // Enforce a limit on the namespace string length
  153. if namespace.len() > MAX_NS_LEN {
  154. return Err(ZkasErr("Namespace too long".to_string()))
  155. }
  156. // ===============
  157. // Section parsing
  158. // ===============
  159. let offsets = SectionOffsets::find(bytes)?;
  160. let constants = Self::parse_constants(offsets.constant_bytes(bytes))?;
  161. let literals = Self::parse_literals(offsets.literal_bytes(bytes))?;
  162. let witnesses = Self::parse_witnesses(offsets.witness_bytes(bytes))?;
  163. let opcodes = Self::parse_circuit(offsets.circuit_bytes(bytes))?;
  164. let mut debug_info = None;
  165. if decode_debug_symbols {
  166. debug_info = match offsets.debug_bytes(bytes) {
  167. Some(debug_bytes) => Some(Self::parse_debug(debug_bytes)?),
  168. None => None,
  169. };
  170. }
  171. Ok(Self { namespace, k, constants, literals, witnesses, opcodes, debug_info })
  172. }
  173. fn parse_constants(bytes: &[u8]) -> Result<Vec<(VarType, String)>> {
  174. let mut constants = vec![];
  175. let mut offset = 0;
  176. while offset < bytes.len() {
  177. let c_type = VarType::from_repr(bytes[offset]).ok_or_else(|| {
  178. ZkasErr(format!("Could not decode constant VarType from {}", bytes[offset]))
  179. })?;
  180. offset += 1;
  181. let (name, len) = deserialize_partial::<String>(&bytes[offset..])?;
  182. offset += len;
  183. constants.push((c_type, name));
  184. }
  185. Ok(constants)
  186. }
  187. fn parse_literals(bytes: &[u8]) -> Result<Vec<(LitType, String)>> {
  188. let mut literals = vec![];
  189. let mut offset = 0;
  190. while offset < bytes.len() {
  191. let l_type = LitType::from_repr(bytes[offset]).ok_or_else(|| {
  192. ZkasErr(format!("Could not decode literal LitType from {}", bytes[offset]))
  193. })?;
  194. offset += 1;
  195. let (name, len) = deserialize_partial::<String>(&bytes[offset..])?;
  196. offset += len;
  197. literals.push((l_type, name));
  198. }
  199. Ok(literals)
  200. }
  201. fn parse_witnesses(bytes: &[u8]) -> Result<Vec<VarType>> {
  202. let mut witnesses = vec![];
  203. for &byte in bytes {
  204. let w_type = VarType::from_repr(byte).ok_or_else(|| {
  205. ZkasErr(format!("Could not decode witness VarType from {}", byte))
  206. })?;
  207. witnesses.push(w_type);
  208. }
  209. Ok(witnesses)
  210. }
  211. #[allow(clippy::type_complexity)]
  212. fn parse_circuit(bytes: &[u8]) -> Result<Vec<(Opcode, Vec<(HeapType, usize)>)>> {
  213. let mut opcodes = vec![];
  214. let mut offset = 0;
  215. while offset < bytes.len() {
  216. let opcode = Opcode::from_repr(bytes[offset]).ok_or_else(|| {
  217. ZkasErr(format!("Could not decode Opcode from {}", bytes[offset]))
  218. })?;
  219. offset += 1;
  220. // TODO: Check that the types and arg number are correct
  221. // Parse argument count
  222. let (arg_count, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  223. offset += len;
  224. // Parse arguments
  225. let mut args = vec![];
  226. for _ in 0..arg_count.0 {
  227. // Check bounds to prevent panics
  228. if offset >= bytes.len() {
  229. return Err(ZkasErr(format!(
  230. "Bad offset for circuit: offset {} is >= circuit len {}",
  231. offset,
  232. bytes.len()
  233. )));
  234. }
  235. let heap_type_byte = bytes[offset];
  236. offset += 1;
  237. if offset >= bytes.len() {
  238. return Err(ZkasErr(format!(
  239. "Bad offset for circuit: offset {} is >= circuit len {}",
  240. offset,
  241. bytes.len()
  242. )));
  243. }
  244. let (heap_index, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  245. offset += len;
  246. let heap_type = HeapType::from_repr(heap_type_byte).ok_or_else(|| {
  247. ZkasErr(format!("Could not decode HeapType from {}", heap_type_byte))
  248. })?;
  249. args.push((heap_type, heap_index.0 as usize));
  250. }
  251. opcodes.push((opcode, args));
  252. }
  253. Ok(opcodes)
  254. }
  255. fn parse_debug(bytes: &[u8]) -> Result<DebugInfo> {
  256. let mut offset = 0;
  257. // Parse opcode source locations
  258. let (num_opcodes, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  259. offset += len;
  260. let mut opcode_locations = Vec::with_capacity(num_opcodes.0 as usize);
  261. for _ in 0..num_opcodes.0 {
  262. let (line, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  263. offset += len;
  264. let (column, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  265. offset += len;
  266. opcode_locations.push((line.0 as usize, column.0 as usize));
  267. }
  268. // Parse heap var names
  269. let (heap_size, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  270. offset += len;
  271. let mut heap_names = Vec::with_capacity(heap_size.0 as usize);
  272. for _ in 0..heap_size.0 {
  273. let (name, len) = deserialize_partial::<String>(&bytes[offset..])?;
  274. offset += len;
  275. heap_names.push(name);
  276. }
  277. // Parse literal names
  278. let (num_literals, len) = deserialize_partial::<VarInt>(&bytes[offset..])?;
  279. offset += len;
  280. let mut literal_names = Vec::with_capacity(num_literals.0 as usize);
  281. for _ in 0..num_literals.0 {
  282. let (name, len) = deserialize_partial::<String>(&bytes[offset..])?;
  283. offset += len;
  284. literal_names.push(name);
  285. }
  286. Ok(DebugInfo { opcode_locations, heap_names, literal_names })
  287. }
  288. /// Get the source location (line, column) for a given opcode index.
  289. /// Returns `None` if debug info is not present or index is OOB.
  290. pub fn opcode_location(&self, opcode_idx: usize) -> Option<(usize, usize)> {
  291. self.debug_info.as_ref()?.opcode_locations.get(opcode_idx).copied()
  292. }
  293. /// Get the variable name for a given heap index.
  294. /// Returns `None` if debug info is not present or index is OOB.
  295. pub fn heap_name(&self, heap_idx: usize) -> Option<&str> {
  296. self.debug_info.as_ref()?.heap_names.get(heap_idx).map(|s| s.as_str())
  297. }
  298. /// Get the literal name/value for a given literal index.
  299. /// Returns `None` if debug info is not present or index is OOB.
  300. pub fn literal_name(&self, literal_idx: usize) -> Option<&str> {
  301. self.debug_info.as_ref()?.literal_names.get(literal_idx).map(|s| s.as_str())
  302. }
  303. /// Check if debug info is present
  304. pub fn has_debug_info(&self) -> bool {
  305. self.debug_info.is_some()
  306. }
  307. }
  308. #[cfg(test)]
  309. mod tests {
  310. use crate::zkas::ZkBinary;
  311. #[test]
  312. fn panic_regression_001() {
  313. // Out-of-memory panic from string deserialization.
  314. // Read `doc/src/zkas/bincode.md` to understand the input.
  315. let data = vec![11u8, 1, 177, 53, 1, 0, 0, 0, 0, 255, 0, 204, 200, 72, 72, 72, 72, 1];
  316. let _dec = ZkBinary::decode(&data, true);
  317. }
  318. #[test]
  319. fn panic_regression_002() {
  320. // Index out of bounds panic in parse_circuit().
  321. // Read `doc/src/zkas/bincode.md` to understand the input.
  322. let data = vec![
  323. 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,
  324. 109, 112, 108, 101, 46, 99, 111, 110, 115, 116, 97, 110, 116, 3, 18, 86, 65, 76, 85,
  325. 69, 95, 67, 79, 77, 77, 73, 84, 95, 86, 65, 76, 85, 69, 2, 19, 86, 65, 76, 85, 69, 95,
  326. 67, 79, 77, 77, 73, 84, 95, 82, 65, 77, 68, 79, 77, 46, 108, 105, 116, 101, 114, 97,
  327. 108, 46, 119, 105, 116, 110, 101, 115, 115, 16, 18, 46, 99, 105, 114, 99, 117, 105,
  328. 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,
  329. 1, 0, 7, 240, 41, 0, 0, 0, 1, 0, 8,
  330. ];
  331. let _dec = ZkBinary::decode(&data, true);
  332. }
  333. }