1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use super::{ExecutableTransaction, Interpreter};
use crate::consts::{MEM_MAX_ACCESS_SIZE, MIN_VM_MAX_RAM_USIZE_MAX, VM_MAX_RAM};
use crate::error::RuntimeError;

use crate::arith::{checked_add_word, checked_sub_word};
use fuel_asm::PanicReason;
use fuel_crypto::{Hasher, Message, PublicKey, Signature};
use fuel_types::{Bytes32, Bytes64, Word};

impl<S, Tx> Interpreter<S, Tx>
where
    Tx: ExecutableTransaction,
{
    pub(crate) fn ecrecover(&mut self, a: Word, b: Word, c: Word) -> Result<(), RuntimeError> {
        let bx = checked_add_word(b, Bytes64::LEN as Word)?;
        let cx = checked_add_word(c, Bytes32::LEN as Word)?;

        if a > checked_sub_word(VM_MAX_RAM, Bytes64::LEN as Word)?
            || bx > MIN_VM_MAX_RAM_USIZE_MAX
            || cx > MIN_VM_MAX_RAM_USIZE_MAX
        {
            return Err(PanicReason::MemoryOverflow.into());
        }

        let (a, b, bx, c, cx) = (a as usize, b as usize, bx as usize, c as usize, cx as usize);

        // Safety: memory bounds are checked
        let signature = unsafe { Signature::as_ref_unchecked(&self.memory[b..bx]) };
        let message = unsafe { Message::as_ref_unchecked(&self.memory[c..cx]) };

        match signature.recover(message) {
            Ok(pub_key) => {
                self.try_mem_write(a, pub_key.as_ref())?;
                self.clear_err();
            }
            Err(_) => {
                self.try_zeroize(a, PublicKey::LEN)?;
                self.set_err();
            }
        }

        self.inc_pc()
    }

    pub(crate) fn keccak256(&mut self, a: Word, b: Word, c: Word) -> Result<(), RuntimeError> {
        use sha3::{Digest, Keccak256};

        let bc = checked_add_word(b, c)?;

        if a > checked_sub_word(VM_MAX_RAM, Bytes32::LEN as Word)?
            || c > MEM_MAX_ACCESS_SIZE
            || bc > MIN_VM_MAX_RAM_USIZE_MAX
        {
            return Err(PanicReason::MemoryOverflow.into());
        }

        let (a, b, bc) = (a as usize, b as usize, bc as usize);

        let mut h = Keccak256::new();

        h.update(&self.memory[b..bc]);

        self.try_mem_write(a, h.finalize().as_slice())?;

        self.inc_pc()
    }

    pub(crate) fn sha256(&mut self, a: Word, b: Word, c: Word) -> Result<(), RuntimeError> {
        let bc = checked_add_word(b, c)?;

        if a > checked_sub_word(VM_MAX_RAM, Bytes32::LEN as Word)?
            || c > MEM_MAX_ACCESS_SIZE
            || bc > MIN_VM_MAX_RAM_USIZE_MAX
        {
            return Err(PanicReason::MemoryOverflow.into());
        }

        let (a, b, bc) = (a as usize, b as usize, bc as usize);

        self.try_mem_write(a, Hasher::hash(&self.memory[b..bc]).as_ref())?;

        self.inc_pc()
    }
}