Skip to main content

amaru_uplc/flat/decode/
decoder.rs

1use bumpalo::collections::{String as BumpString, Vec as BumpVec};
2
3use crate::{
4    arena::Arena, builtin::DefaultFunction, constant::Integer, flat::zigzag::ZigZag,
5    machine::PlutusVersion, program::Version,
6};
7
8use super::FlatDecodeError;
9
10pub struct Decoder<'b> {
11    pub buffer: &'b [u8],
12    pub used_bits: usize,
13    pub pos: usize,
14}
15
16pub struct Ctx<'a> {
17    pub arena: &'a Arena,
18    pub version: Option<&'a Version<'a>>,
19    pub plutus_version: Option<PlutusVersion>,
20    pub protocol_version: Option<u32>,
21}
22
23impl<'a> Ctx<'a> {
24    /// Returns true if the given builtin is NOT available under the current
25    /// plutus_version / protocol_version combination.
26    pub fn is_builtin_gated(&self, func: &DefaultFunction) -> bool {
27        match (self.plutus_version, self.protocol_version) {
28            (Some(pv), Some(proto)) => !func.is_available_in(pv, proto),
29            _ => false,
30        }
31    }
32}
33
34impl<'b> Decoder<'b> {
35    pub fn new(bytes: &'b [u8]) -> Decoder<'b> {
36        Decoder {
37            buffer: bytes,
38            pos: 0,
39            used_bits: 0,
40        }
41    }
42
43    /// Decode a word of any size.
44    /// This is byte alignment agnostic.
45    /// First we decode the next 8 bits of the buffer.
46    /// We take the 7 least significant bits as the 7 least significant bits of
47    /// the current unsigned integer. If the most significant bit of the 8
48    /// bits is 1 then we take the next 8 and repeat the process above,
49    /// filling in the next 7 least significant bits of the unsigned integer and
50    /// so on. If the most significant bit was instead 0 we stop decoding
51    /// any more bits.
52    pub fn word(&mut self) -> Result<usize, FlatDecodeError> {
53        let mut leading_bit = 1;
54        let mut final_word: usize = 0;
55        let mut shl: u32 = 0;
56
57        // continue looping if lead bit is 1 which is 128 as a u8 otherwise exit
58        while leading_bit > 0 {
59            let word8 = self.bits8(8)?;
60
61            let word7 = word8 & 127;
62
63            if shl >= usize::BITS {
64                return Err(FlatDecodeError::WordOverflow);
65            }
66
67            let part = (word7 as usize) << shl;
68
69            // Check that no bits were lost in the shift
70            if (part >> shl) != word7 as usize {
71                return Err(FlatDecodeError::WordOverflow);
72            }
73
74            final_word |= part;
75
76            shl += 7;
77
78            leading_bit = word8 & 128;
79        }
80
81        Ok(final_word)
82    }
83
84    /// Decode a list of items with a decoder function.
85    /// This is byte alignment agnostic.
86    /// Decode a bit from the buffer.
87    /// If 0 then stop.
88    /// Otherwise we decode an item in the list with the decoder function passed
89    /// in. Then decode the next bit in the buffer and repeat above.
90    /// Returns a list of items decoded with the decoder function.
91    pub fn list_with<'a, T, F>(
92        &mut self,
93        ctx: &mut Ctx<'a>,
94        decoder_func: F,
95    ) -> Result<BumpVec<'a, T>, FlatDecodeError>
96    where
97        F: Copy + FnOnce(&mut Ctx<'a>, &mut Decoder) -> Result<T, FlatDecodeError>,
98    {
99        let mut vec_array = BumpVec::new_in(ctx.arena.as_bump());
100
101        while self.bit()? {
102            vec_array.push(decoder_func(ctx, self)?)
103        }
104
105        Ok(vec_array)
106    }
107
108    /// Decode up to 8 bits.
109    /// This is byte alignment agnostic.
110    /// If num_bits is greater than the 8 we throw an IncorrectNumBits error.
111    /// First we decode the next num_bits of bits in the buffer.
112    /// If there are less unused bits in the current byte in the buffer than
113    /// num_bits, then we decode the remaining bits from the most
114    /// significant bits in the next byte in the buffer. Otherwise we decode
115    /// the unused bits from the current byte. Returns the decoded value up
116    /// to a byte in size.
117    pub fn bits8(&mut self, num_bits: usize) -> Result<u8, FlatDecodeError> {
118        if num_bits > 8 {
119            return Err(FlatDecodeError::IncorrectNumBits);
120        }
121
122        self.ensure_bits(num_bits)?;
123
124        let unused_bits = 8 - self.used_bits;
125        let leading_zeroes = 8 - num_bits;
126        let r = (self.buffer[self.pos] << self.used_bits) >> leading_zeroes;
127
128        let x = if num_bits > unused_bits {
129            r | (self.buffer[self.pos + 1] >> (unused_bits + leading_zeroes))
130        } else {
131            r
132        };
133
134        self.drop_bits(num_bits);
135
136        Ok(x)
137    }
138
139    /// Ensures the buffer has the required bits passed in by required_bits.
140    /// Throws a NotEnoughBits error if there are less bits remaining in the
141    /// buffer than required_bits.
142    fn ensure_bits(&mut self, required_bits: usize) -> Result<(), FlatDecodeError> {
143        if required_bits > (self.buffer.len() - self.pos) * 8 - self.used_bits {
144            Err(FlatDecodeError::NotEnoughBits(required_bits))
145        } else {
146            Ok(())
147        }
148    }
149
150    /// Increment buffer by num_bits.
151    /// If num_bits + used bits is greater than 8,
152    /// then increment position by (num_bits + used bits) / 8
153    /// Use the left over remainder as the new amount of used bits.
154    fn drop_bits(&mut self, num_bits: usize) {
155        let all_used_bits = num_bits + self.used_bits;
156
157        self.used_bits = all_used_bits % 8;
158
159        self.pos += all_used_bits / 8;
160    }
161
162    /// Decodes a filler of max one byte size.
163    /// Decodes bits until we hit a bit that is 1.
164    /// Expects that the 1 is at the end of the current byte in the buffer.
165    pub fn filler(&mut self) -> Result<(), FlatDecodeError> {
166        while self.zero()? {}
167
168        Ok(())
169    }
170
171    /// Decode the next bit in the buffer.
172    /// If the bit was 0 then return true.
173    /// Otherwise return false.
174    /// Throws EndOfBuffer error if used at the end of the array.
175    fn zero(&mut self) -> Result<bool, FlatDecodeError> {
176        let current_bit = self.bit()?;
177
178        Ok(!current_bit)
179    }
180
181    /// Decode the next bit in the buffer.
182    /// If the bit was 1 then return true.
183    /// Otherwise return false.
184    /// Throws EndOfBuffer error if used at the end of the array.
185    pub fn bit(&mut self) -> Result<bool, FlatDecodeError> {
186        if self.pos >= self.buffer.len() {
187            return Err(FlatDecodeError::EndOfBuffer);
188        }
189
190        let b = self.buffer[self.pos] & (128 >> self.used_bits) > 0;
191
192        self.increment_buffer_by_bit();
193
194        Ok(b)
195    }
196
197    /// Decode an integer of an arbitrary size..
198    ///
199    /// This is byte alignment agnostic.
200    /// First we decode the next 8 bits of the buffer.
201    /// We take the 7 least significant bits as the 7 least significant bits of
202    /// the current unsigned integer. If the most significant bit of the 8
203    /// bits is 1 then we take the next 8 and repeat the process above,
204    /// filling in the next 7 least significant bits of the unsigned integer and
205    /// so on. If the most significant bit was instead 0 we stop decoding
206    /// any more bits. Finally we use zigzag to convert the unsigned integer
207    /// back to a signed integer.
208    pub fn integer(&mut self) -> Result<Integer, FlatDecodeError> {
209        Ok(ZigZag::unzigzag(&self.big_word()?))
210    }
211
212    /// Decode a word of 128 bits size.
213    /// This is byte alignment agnostic.
214    /// First we decode the next 8 bits of the buffer.
215    /// We take the 7 least significant bits as the 7 least significant bits of
216    /// the current unsigned integer. If the most significant bit of the 8
217    /// bits is 1 then we take the next 8 and repeat the process above,
218    /// filling in the next 7 least significant bits of the unsigned integer and
219    /// so on. If the most significant bit was instead 0 we stop decoding
220    /// any more bits.
221    pub fn big_word(&mut self) -> Result<Integer, FlatDecodeError> {
222        let mut leading_bit = 1;
223        let mut final_word = Integer::from(0);
224        let mut shift = 0_u32; // Using u32 for shift as it's more than enough for 128 bits
225
226        // Continue looping if lead bit is 1 (0x80) otherwise exit
227        while leading_bit > 0 {
228            let word8 = self.bits8(8)?;
229            let word7 = word8 & 0x7F; // 127, get 7 least significant bits
230
231            // Create temporary Integer from word7 and shift it
232            let part = Integer::from(word7);
233            let shifted_part = part << shift;
234
235            // OR it with our result
236            final_word |= shifted_part;
237
238            // Increment shift by 7 for next iteration
239            shift += 7;
240
241            // Check if we should continue (MSB set)
242            leading_bit = word8 & 0x80; // 128
243        }
244
245        Ok(final_word)
246    }
247
248    /// Decode a byte array.
249    /// Decodes a filler to byte align the buffer,
250    /// then decodes the next byte to get the array length up to a max of 255.
251    /// We decode bytes equal to the array length to form the byte array.
252    /// If the following byte for array length is not 0 we decode it and repeat
253    /// above to continue decoding the byte array. We stop once we hit a
254    /// byte array length of 0. If array length is 0 for first byte array
255    /// length the we return a empty array.
256    pub fn bytes<'a>(&mut self, arena: &'a Arena) -> Result<BumpVec<'a, u8>, FlatDecodeError> {
257        self.filler()?;
258        self.byte_array(arena)
259    }
260
261    /// Decode a byte array.
262    /// Throws a BufferNotByteAligned error if the buffer is not byte aligned
263    /// Decodes the next byte to get the array length up to a max of 255.
264    /// We decode bytes equal to the array length to form the byte array.
265    /// If the following byte for array length is not 0 we decode it and repeat
266    /// above to continue decoding the byte array. We stop once we hit a
267    /// byte array length of 0. If array length is 0 for first byte array
268    /// length the we return a empty array.
269    fn byte_array<'a>(&mut self, arena: &'a Arena) -> Result<BumpVec<'a, u8>, FlatDecodeError> {
270        if self.used_bits != 0 {
271            return Err(FlatDecodeError::BufferNotByteAligned);
272        }
273
274        self.ensure_bytes(1)?;
275
276        let mut blk_len = self.buffer[self.pos] as usize;
277
278        self.pos += 1;
279
280        let mut blk_array = BumpVec::with_capacity_in(blk_len, arena.as_bump());
281
282        while blk_len != 0 {
283            self.ensure_bytes(blk_len + 1)?;
284
285            let decoded_array = &self.buffer[self.pos..self.pos + blk_len];
286
287            blk_array.extend(decoded_array);
288
289            self.pos += blk_len;
290
291            blk_len = self.buffer[self.pos] as usize;
292
293            self.pos += 1
294        }
295
296        Ok(blk_array)
297    }
298
299    /// Decode a string.
300    /// Convert to byte array and then use byte array decoding.
301    /// Decodes a filler to byte align the buffer,
302    /// then decodes the next byte to get the array length up to a max of 255.
303    /// We decode bytes equal to the array length to form the byte array.
304    /// If the following byte for array length is not 0 we decode it and repeat
305    /// above to continue decoding the byte array. We stop once we hit a
306    /// byte array length of 0. If array length is 0 for first byte array
307    /// length the we return a empty array.
308    pub fn utf8<'a>(&mut self, arena: &'a Arena) -> Result<&'a str, FlatDecodeError> {
309        let b = self.bytes(arena)?;
310
311        let s =
312            BumpString::from_utf8(b).map_err(|e| FlatDecodeError::DecodeUtf8(e.utf8_error()))?;
313        let s = arena.alloc(s);
314
315        Ok(s)
316    }
317
318    /// Increment used bits by 1.
319    /// If all 8 bits are used then increment buffer position by 1.
320    fn increment_buffer_by_bit(&mut self) {
321        if self.used_bits == 7 {
322            self.pos += 1;
323
324            self.used_bits = 0;
325        } else {
326            self.used_bits += 1;
327        }
328    }
329
330    /// Ensures the buffer has the required bytes passed in by required_bytes.
331    /// Throws a NotEnoughBytes error if there are less bytes remaining in the
332    /// buffer than required_bytes.
333    fn ensure_bytes(&mut self, required_bytes: usize) -> Result<(), FlatDecodeError> {
334        if required_bytes > self.buffer.len() - self.pos {
335            Err(FlatDecodeError::NotEnoughBytes(required_bytes))
336        } else {
337            Ok(())
338        }
339    }
340}