decoder.rs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. use super::{compiler::MAGIC_BYTES, opcode::Opcode, types::Type};
  2. use crate::{
  3. util::serial::{deserialize_partial, VarInt},
  4. Error::ZkasDecoderError,
  5. Result,
  6. };
  7. #[derive(Debug)]
  8. pub struct ZkBinary {
  9. pub constants: Vec<(Type, String)>,
  10. pub witnesses: Vec<Type>,
  11. pub opcodes: Vec<(Opcode, Vec<usize>)>,
  12. }
  13. impl ZkBinary {
  14. pub fn decode(bytes: &[u8]) -> Result<Self> {
  15. let magic_bytes = &bytes[0..4];
  16. if magic_bytes != MAGIC_BYTES {
  17. return Err(ZkasDecoderError("Magic bytes are incorrect."))
  18. }
  19. let _binary_version = &bytes[4];
  20. let constants_offset = match find_subslice(bytes, b".constant") {
  21. Some(v) => v,
  22. None => return Err(ZkasDecoderError("Could not find .constant section.")),
  23. };
  24. let contract_offset = match find_subslice(bytes, b".contract") {
  25. Some(v) => v,
  26. None => return Err(ZkasDecoderError("Could not find .contract section")),
  27. };
  28. let circuit_offset = match find_subslice(bytes, b".circuit") {
  29. Some(v) => v,
  30. None => return Err(ZkasDecoderError("Could not find .circuit section")),
  31. };
  32. let debug_offset = match find_subslice(bytes, b".debug") {
  33. Some(v) => v,
  34. None => bytes.len(),
  35. };
  36. if constants_offset > contract_offset {
  37. return Err(ZkasDecoderError(".contract appeared before .constant"))
  38. }
  39. if contract_offset > circuit_offset {
  40. return Err(ZkasDecoderError(".contract appeared before .circuit"))
  41. }
  42. if circuit_offset > debug_offset {
  43. return Err(ZkasDecoderError(".circuit appeared before .debug or EOF"))
  44. }
  45. let constants_section = &bytes[constants_offset + b".constant".len()..contract_offset];
  46. let contract_section = &bytes[contract_offset + b".contract".len()..circuit_offset];
  47. let circuit_section = &bytes[circuit_offset + b".circuit".len()..debug_offset];
  48. let constants = ZkBinary::parse_constants(constants_section)?;
  49. let witnesses = ZkBinary::parse_contract(contract_section)?;
  50. let opcodes = ZkBinary::parse_circuit(circuit_section)?;
  51. // TODO: Debug info
  52. Ok(Self { constants, witnesses, opcodes })
  53. }
  54. fn parse_constants(bytes: &[u8]) -> Result<Vec<(Type, String)>> {
  55. let mut constants = vec![];
  56. let mut iter_offset = 0;
  57. while iter_offset < bytes.len() {
  58. let c_type = Type::from_repr(bytes[iter_offset]);
  59. iter_offset += 1;
  60. let (name, offset) = deserialize_partial::<String>(&bytes[iter_offset..])?;
  61. iter_offset += offset;
  62. constants.push((c_type, name));
  63. }
  64. Ok(constants)
  65. }
  66. fn parse_contract(bytes: &[u8]) -> Result<Vec<Type>> {
  67. let mut witnesses = vec![];
  68. let mut iter_offset = 0;
  69. while iter_offset < bytes.len() {
  70. let w_type = Type::from_repr(bytes[iter_offset]);
  71. iter_offset += 1;
  72. witnesses.push(w_type);
  73. }
  74. Ok(witnesses)
  75. }
  76. fn parse_circuit(bytes: &[u8]) -> Result<Vec<(Opcode, Vec<usize>)>> {
  77. let mut opcodes = vec![];
  78. let mut iter_offset = 0;
  79. while iter_offset < bytes.len() {
  80. let opcode = Opcode::from_repr(bytes[iter_offset]);
  81. iter_offset += 1;
  82. let (arg_num, offset) = deserialize_partial::<VarInt>(&bytes[iter_offset..])?;
  83. iter_offset += offset;
  84. let mut args = vec![];
  85. for _ in 0..arg_num.0 {
  86. let (stack_index, offset) = deserialize_partial::<VarInt>(&bytes[iter_offset..])?;
  87. iter_offset += offset;
  88. args.push(stack_index.0 as usize); // FIXME
  89. }
  90. opcodes.push((opcode, args));
  91. }
  92. Ok(opcodes)
  93. }
  94. }
  95. // https://stackoverflow.com/questions/35901547/how-can-i-find-a-subsequence-in-a-u8-slice
  96. fn find_subslice(haystack: &[u8], needle: &[u8]) -> Option<usize> {
  97. haystack.windows(needle.len()).position(|window| window == needle)
  98. }