Repository: ergoplatform/sigma-rust (language: rust)

Issue:
[100 SigmaUSD] Eval for SGLOBAL methods
Implement in new `ergotree_interpreter::eval::sglobal` module evaluation (`EvalFn`) for `groupGenerator` and `xor` for byte arrays methods:
- `groupGenerator` should eval to `dlog_group::generator()`.
- `xor` eval should be identical to the existing `Xor` IR node eval - https://github.com/ergoplatform/sigma-rust/blob/0200f346b0aee2952ca82fd5d27cb08e7c228c5e/ergotree-interpreter/src/eval/xor.rs#L17-L34
- add case for `sglobal::TYPE_CODE` in `eval::smethod_eval_fb` - https://github.com/ergoplatform/sigma-rust/blob/0200f346b0aee2952ca82fd5d27cb08e7c228c5e/ergotree-interpreter/src/eval.rs#L211

See `eval::scontext` for examples of how to implement a static `EvalFn` value.


Discussion / hints:
I will take it!

Fix patch:
diff --git a/ergotree-interpreter/src/eval.rs b/ergotree-interpreter/src/eval.rs
index e7ae09fc3..d1079a3d6 100644
--- a/ergotree-interpreter/src/eval.rs
+++ b/ergotree-interpreter/src/eval.rs
@@ -81,6 +81,7 @@ pub(crate) mod sbox;
 pub(crate) mod scoll;
 pub(crate) mod scontext;
 pub(crate) mod select_field;
+pub(crate) mod sglobal;
 pub(crate) mod sgroup_elem;
 pub(crate) mod sheader;
 pub(crate) mod sigma_and;
@@ -327,6 +328,17 @@ fn smethod_eval_fn(method: &SMethod) -> Result<EvalFn, EvalError> {
                 )))
             }
         },
+        sglobal::TYPE_CODE => match method.method_id() {
+            sglobal::GROUP_GENERATOR_METHOD_ID => self::sglobal::GROUP_GENERATOR_EVAL_FN,
+            sglobal::XOR_METHOD_ID => self::sglobal::XOR_EVAL_FN,
+            method_id => {
+                return Err(EvalError::NotFound(format!(
+                    "Eval fn: method {:?} with method id {:?} not found in SGlobal",
+                    method.name(),
+                    method_id,
+                )))
+            }
+        },
         type_id => {
             return Err(EvalError::NotFound(format!(
                 "Eval fn: unknown type id {:?}",
diff --git a/ergotree-interpreter/src/eval/sglobal.rs b/ergotree-interpreter/src/eval/sglobal.rs
new file mode 100644
index 000000000..f5c9ec09d
--- /dev/null
+++ b/ergotree-interpreter/src/eval/sglobal.rs
@@ -0,0 +1,96 @@
+use crate::eval::EvalError;
+
+use ergotree_ir::mir::value::{CollKind, NativeColl, Value};
+
+use ergotree_ir::sigma_protocol::dlog_group::generator;
+
+use super::EvalFn;
+
+fn helper_xor(mut x: Vec<i8>, y: Vec<i8>) -> Vec<i8> {
+    x.iter_mut().zip(y.iter()).for_each(|(x1, x2)| *x1 ^= *x2);
+    x
+}
+
+pub(crate) static GROUP_GENERATOR_EVAL_FN: EvalFn = |_env, _ctx, obj, _args| {
+    if obj != Value::Global {
+        return Err(EvalError::UnexpectedValue(format!(
+            "sglobal.groupGenerator expected obj to be Value::Global, got {:?}",
+            obj
+        )));
+    }
+    Ok(Value::from(generator()))
+};
+
+pub(crate) static XOR_EVAL_FN: EvalFn = |_env, _ctx, obj, args| {
+    if obj != Value::Global {
+        return Err(EvalError::UnexpectedValue(format!(
+            "sglobal.xor expected obj to be Value::Global, got {:?}",
+            obj
+        )));
+    }
+    let right_v = args
+        .get(0)
+        .cloned()
+        .ok_or_else(|| EvalError::NotFound("xor: missing right arg".to_string()))?;
+    let left_v = args
+        .get(1)
+        .cloned()
+        .ok_or_else(|| EvalError::NotFound("xor: missing left arg".to_string()))?;
+
+    match (left_v.clone(), right_v.clone()) {
+        (
+            Value::Coll(CollKind::NativeColl(NativeColl::CollByte(l_byte))),
+            Value::Coll(CollKind::NativeColl(NativeColl::CollByte(r_byte))),
+        ) => {
+            let xor = helper_xor(l_byte, r_byte);
+            Ok(xor.into())
+        }
+        _ => Err(EvalError::UnexpectedValue(format!(
+            "expected Xor input to be byte array, got: {0:?}",
+            (left_v, right_v)
+        ))),
+    }
+};
+
+#[allow(clippy::unwrap_used)]
+#[cfg(test)]
+#[cfg(feature = "arbitrary")]
+mod tests {
+    use ergotree_ir::mir::expr::Expr;
+    use ergotree_ir::mir::method_call::MethodCall;
+    use ergotree_ir::mir::property_call::PropertyCall;
+    use ergotree_ir::sigma_protocol::dlog_group;
+    use ergotree_ir::sigma_protocol::dlog_group::EcPoint;
+    use std::rc::Rc;
+
+    use crate::eval::context::Context;
+    use crate::eval::tests::eval_out;
+    use ergotree_ir::types::sglobal;
+    use sigma_test_util::force_any_val;
+
+    #[test]
+    fn eval_group_generator() {
+        let expr: Expr = PropertyCall::new(Expr::Global, sglobal::GROUP_GENERATOR_METHOD.clone())
+            .unwrap()
+            .into();
+        let ctx = Rc::new(force_any_val::<Context>());
+        assert_eq!(eval_out::<EcPoint>(&expr, ctx), dlog_group::generator());
+    }
+
+    #[test]
+    fn eval_xor() {
+        let left = vec![1_i8, 1, 0, 0];
+        let right = vec![0_i8, 1, 0, 1];
+        let expected_xor = vec![1_i8, 0, 0, 1];
+
+        let expr: Expr = MethodCall::new(
+            Expr::Global,
+            sglobal::XOR_METHOD.clone(),
+            vec![right.into(), left.into()],
+        )
+        .unwrap()
+        .into();
+        let ctx = Rc::new(force_any_val::<Context>());
+        assert_eq!(eval_out::<Vec<i8>>(&expr, ctx), expected_xor);
+    }
+}
diff --git a/ergotree-ir/src/types/sglobal.rs b/ergotree-ir/src/types/sglobal.rs
index 2f3bfe010..143d0bc14 100644
--- a/ergotree-ir/src/types/sglobal.rs
+++ b/ergotree-ir/src/types/sglobal.rs
@@ -4,6 +4,8 @@ use super::sfunc::SFunc;
 use super::smethod::MethodId;
 use super::smethod::SMethodDesc;
 use super::stype::SType;
+use crate::types::smethod::SMethod;
+use crate::types::stype_companion::STypeCompanion;
 use lazy_static::lazy_static;
 
 /// SGlobal type code
@@ -32,6 +34,9 @@ lazy_static! {
             tpe_params: vec![],
         },
     };
+     /// GLOBAL.GroupGenerator
+    pub static ref GROUP_GENERATOR_METHOD: SMethod = SMethod::new(STypeCompanion::Global, GROUP_GENERATOR_METHOD_DESC.clone(),);
+
 }
 
 lazy_static! {
@@ -48,4 +53,7 @@ lazy_static! {
             tpe_params: vec![],
         },
     };
+     /// GLOBAL.xor
+    pub static ref XOR_METHOD: SMethod = SMethod::new(STypeCompanion::Global, XOR_METHOD_DESC.clone(),);
+
 }


Test patch: