fuel-vm 0.35.4

FuelVM interpreter.
Documentation
use super::{
    internal::{
        clear_err,
        inc_pc,
        set_err,
    },
    memory::{
        read_bytes,
        try_mem_write,
        try_zeroize,
        OwnershipRegisters,
    },
    ExecutableTransaction,
    Interpreter,
};
use crate::{
    constraints::reg_key::*,
    consts::*,
    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,
};

#[cfg(test)]
mod tests;

impl<S, Tx> Interpreter<S, Tx>
where
    Tx: ExecutableTransaction,
{
    pub(crate) fn secp256k1_recover(
        &mut self,
        a: Word,
        b: Word,
        c: Word,
    ) -> Result<(), RuntimeError> {
        let owner = self.ownership_registers();
        let (SystemRegisters { err, pc, .. }, _) = split_registers(&mut self.registers);
        secp256k1_recover(&mut self.memory, owner, err, pc, a, b, c)
    }

    pub(crate) fn secp256r1_recover(
        &mut self,
        a: Word,
        b: Word,
        c: Word,
    ) -> Result<(), RuntimeError> {
        let owner = self.ownership_registers();
        let (SystemRegisters { err, pc, .. }, _) = split_registers(&mut self.registers);
        secp256r1_recover(&mut self.memory, owner, err, pc, a, b, c)
    }

    pub(crate) fn ed25519_verify(
        &mut self,
        a: Word,
        b: Word,
        c: Word,
    ) -> Result<(), RuntimeError> {
        let (SystemRegisters { err, pc, .. }, _) = split_registers(&mut self.registers);
        ed25519_verify(&mut self.memory, err, pc, a, b, c)
    }

    pub(crate) fn keccak256(
        &mut self,
        a: Word,
        b: Word,
        c: Word,
    ) -> Result<(), RuntimeError> {
        let owner = self.ownership_registers();
        keccak256(&mut self.memory, owner, self.registers.pc_mut(), a, b, c)
    }

    pub(crate) fn sha256(
        &mut self,
        a: Word,
        b: Word,
        c: Word,
    ) -> Result<(), RuntimeError> {
        let owner = self.ownership_registers();
        sha256(&mut self.memory, owner, self.registers.pc_mut(), a, b, c)
    }
}

pub(crate) fn secp256k1_recover(
    memory: &mut [u8; MEM_SIZE],
    owner: OwnershipRegisters,
    err: RegMut<ERR>,
    pc: RegMut<PC>,
    a: Word,
    b: Word,
    c: Word,
) -> Result<(), RuntimeError> {
    let sig = Bytes64::from(read_bytes(memory, b)?);
    let msg = Bytes32::from(read_bytes(memory, c)?);

    let signature = Signature::from_bytes_ref(&sig);
    let message = Message::from_bytes_ref(&msg);

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

    inc_pc(pc)
}

pub(crate) fn secp256r1_recover(
    memory: &mut [u8; MEM_SIZE],
    owner: OwnershipRegisters,
    err: RegMut<ERR>,
    pc: RegMut<PC>,
    a: Word,
    b: Word,
    c: Word,
) -> Result<(), RuntimeError> {
    let sig = Bytes64::from(read_bytes(memory, b)?);
    let msg = Bytes32::from(read_bytes(memory, c)?);
    let message = Message::from_bytes_ref(&msg);

    match fuel_crypto::secp256r1::recover(&sig, message) {
        Ok(pub_key) => {
            try_mem_write(a, &*pub_key, owner, memory)?;
            clear_err(err);
        }
        Err(_) => {
            try_zeroize(a, Bytes32::LEN, owner, memory)?;
            set_err(err);
        }
    }

    inc_pc(pc)
}

pub(crate) fn ed25519_verify(
    memory: &mut [u8; MEM_SIZE],
    err: RegMut<ERR>,
    pc: RegMut<PC>,
    a: Word,
    b: Word,
    c: Word,
) -> Result<(), RuntimeError> {
    let pub_key = Bytes32::from(read_bytes(memory, a)?);
    let sig = Bytes64::from(read_bytes(memory, b)?);
    let msg = Bytes32::from(read_bytes(memory, c)?);
    let message = Message::from_bytes_ref(&msg);

    if fuel_crypto::ed25519::verify(&pub_key, &sig, message).is_ok() {
        clear_err(err);
    } else {
        set_err(err);
    }

    inc_pc(pc)
}

pub(crate) fn keccak256(
    memory: &mut [u8; MEM_SIZE],
    owner: OwnershipRegisters,
    pc: RegMut<PC>,
    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(&memory[b..bc]);

    try_mem_write(a, h.finalize().as_slice(), owner, memory)?;

    inc_pc(pc)
}

pub(crate) fn sha256(
    memory: &mut [u8; MEM_SIZE],
    owner: OwnershipRegisters,
    pc: RegMut<PC>,
    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);

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

    inc_pc(pc)
}