stoffel-vm 0.1.1

Register-based virtual machine runtime and MPC execution engine for Stoffel programs
Documentation
use super::error::{ValueOpError, ValueOpResult};
use crate::value_conversions::value_to_i64;
use stoffel_vm_types::core_types::{ShareData, ShareType, Value};

pub(crate) struct BorrowedSharePair<'a> {
    pub(crate) share_type: ShareType,
    pub(crate) left_data: &'a ShareData,
    pub(crate) right_data: &'a ShareData,
}

pub(crate) fn matching_share_pair<'a>(
    operation: &'static str,
    left: &'a Value,
    right: &'a Value,
) -> ValueOpResult<Option<BorrowedSharePair<'a>>> {
    let Some((left_type, left_data)) = share_operand(left) else {
        return Ok(None);
    };
    let Some((right_type, right_data)) = share_operand(right) else {
        return Ok(None);
    };

    ensure_same_share_type(operation, &left_type, &right_type)?;
    Ok(Some(BorrowedSharePair {
        share_type: left_type,
        left_data,
        right_data,
    }))
}

pub(super) fn share_scalar_operands<'a>(
    share_value: &'a Value,
    scalar_value: &Value,
) -> ValueOpResult<Option<(ShareType, &'a ShareData, i64)>> {
    let Some((share_type, share_data)) = share_operand(share_value) else {
        return Ok(None);
    };
    let Some(scalar) = integer_scalar(scalar_value)? else {
        return Ok(None);
    };

    Ok(Some((share_type, share_data, scalar)))
}

pub(super) fn contains_share_operand(left: &Value, right: &Value) -> bool {
    share_operand(left).is_some() || share_operand(right).is_some()
}

fn share_operand(value: &Value) -> Option<(ShareType, &ShareData)> {
    match value {
        Value::Share(share_type, data) => Some((*share_type, data)),
        _ => None,
    }
}

fn integer_scalar(value: &Value) -> ValueOpResult<Option<i64>> {
    if matches!(
        value,
        Value::I64(_)
            | Value::I32(_)
            | Value::I16(_)
            | Value::I8(_)
            | Value::U8(_)
            | Value::U16(_)
            | Value::U32(_)
            | Value::U64(_)
    ) {
        value_to_i64(value, "share scalar")
            .map(Some)
            .map_err(Into::into)
    } else {
        Ok(None)
    }
}

fn ensure_same_share_type(
    operation: &'static str,
    left: &ShareType,
    right: &ShareType,
) -> ValueOpResult<()> {
    if left == right {
        Ok(())
    } else {
        Err(ValueOpError::ShareTypeMismatch { operation })
    }
}