• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ergoplatform / sigma-rust / 15698235808

17 Jun 2025 04:33AM UTC coverage: 78.333% (+0.04%) from 78.291%
15698235808

Pull #804

github

web-flow
Merge ed47dd2dd into 6f12ef8f2
Pull Request #804: Add autolykos 2 validation for custom message

49 of 62 new or added lines in 5 files covered. (79.03%)

5 existing lines in 2 files now uncovered.

11764 of 15018 relevant lines covered (78.33%)

2.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

62.2
/ergotree-interpreter/src/eval/sglobal.rs
1
use crate::eval::EvalError;
2
use alloc::boxed::Box;
3
use alloc::{string::ToString, sync::Arc};
4

5
use ergo_chain_types::autolykos_pow_scheme::{decode_compact_bits, encode_compact_bits};
6
use ergotree_ir::serialization::sigma_byte_writer::SigmaByteWrite;
7
use ergotree_ir::unsignedbigint256::UnsignedBigInt;
8
use ergotree_ir::{
9
    mir::{
10
        constant::{Constant, TryExtractInto},
11
        value::{CollKind, NativeColl, Value},
12
    },
13
    serialization::{
14
        data::DataSerializer,
15
        sigma_byte_reader::{self, SigmaByteRead},
16
        sigma_byte_writer::SigmaByteWriter,
17
    },
18
};
19
use num_bigint::BigInt;
20

21
use super::EvalFn;
22
use crate::eval::Vec;
23
use ergo_chain_types::{autolykos_pow_scheme::AutolykosPowScheme, ec_point::generator};
24
use ergotree_ir::bigint256::BigInt256;
25
use ergotree_ir::types::stype::SType;
26

27
fn helper_xor(x: &[i8], y: &[i8]) -> Arc<[i8]> {
1✔
28
    x.iter().zip(y.iter()).map(|(x1, x2)| *x1 ^ *x2).collect()
3✔
29
}
30

31
pub(crate) static GROUP_GENERATOR_EVAL_FN: EvalFn = |_mc, _env, _ctx, obj, _args| {
1✔
32
    if obj != Value::Global {
2✔
33
        return Err(EvalError::UnexpectedValue(format!(
×
34
            "sglobal.groupGenerator expected obj to be Value::Global, got {:?}",
35
            obj
36
        )));
37
    }
38
    Ok(Value::from(generator()))
2✔
39
};
40

41
pub(crate) static XOR_EVAL_FN: EvalFn = |_mc, _env, _ctx, obj, args| {
1✔
42
    if obj != Value::Global {
2✔
43
        return Err(EvalError::UnexpectedValue(format!(
×
44
            "sglobal.xor expected obj to be Value::Global, got {:?}",
45
            obj
46
        )));
47
    }
48
    let right_v = args
2✔
49
        .first()
50
        .cloned()
51
        .ok_or_else(|| EvalError::NotFound("xor: missing right arg".to_string()))?;
×
52
    let left_v = args
2✔
53
        .get(1)
54
        .cloned()
55
        .ok_or_else(|| EvalError::NotFound("xor: missing left arg".to_string()))?;
×
56

57
    match (left_v.clone(), right_v.clone()) {
3✔
58
        (
59
            Value::Coll(CollKind::NativeColl(NativeColl::CollByte(l_byte))),
1✔
60
            Value::Coll(CollKind::NativeColl(NativeColl::CollByte(r_byte))),
1✔
61
        ) => {
62
            let xor = helper_xor(&l_byte, &r_byte);
2✔
63
            Ok(CollKind::NativeColl(NativeColl::CollByte(xor)).into())
1✔
64
        }
65
        _ => Err(EvalError::UnexpectedValue(format!(
×
66
            "expected Xor input to be byte array, got: {0:?}",
67
            (left_v, right_v)
×
68
        ))),
69
    }
70
};
71

72
pub(crate) static SGLOBAL_FROM_BIGENDIAN_BYTES_EVAL_FN: EvalFn = |mc, _env, _ctx, obj, args| {
1✔
73
    if obj != Value::Global {
2✔
74
        return Err(EvalError::UnexpectedValue(format!(
×
75
            "sglobal.fromBigEndianBytes expected obj to be Value::Global, got {:?}",
76
            obj
77
        )));
78
    }
79

80
    let bytes_val = args
2✔
81
        .first()
82
        .cloned()
83
        .ok_or_else(|| EvalError::NotFound("fromBigEndianBytes: missing bytes arg".to_string()))?;
×
84
    let type_val = mc.tpe().t_range.clone();
2✔
85

86
    let bytes = match bytes_val {
1✔
87
        Value::Coll(CollKind::NativeColl(NativeColl::CollByte(bytes))) => bytes,
1✔
88
        _ => {
89
            return Err(EvalError::UnexpectedValue(format!(
×
90
                "fromBigEndianBytes: expected first argument to be byte array, got {:?}",
91
                bytes_val
92
            )))
93
        }
94
    };
95

96
    match *type_val {
1✔
97
        SType::SByte => {
98
            if bytes.len() != 1 {
2✔
99
                return Err(EvalError::UnexpectedValue(
×
100
                    "To deserialize Byte with fromBigEndianBytes, exactly one byte should be provided".to_string(),
×
101
                ));
102
            }
103
            Ok(Value::Byte(bytes[0]))
2✔
104
        }
105
        SType::SShort => {
106
            if bytes.len() != 2 {
2✔
107
                return Err(EvalError::UnexpectedValue(
×
108
                    "To deserialize Short with fromBigEndianBytes, exactly two bytes should be provided".to_string(),
×
109
                ));
110
            }
111
            let value = bytes
2✔
112
                .iter()
113
                .fold(0i16, |acc, &x| (acc << 8) | (x as u8 as i16));
2✔
114
            Ok(Value::Short(value))
1✔
115
        }
116
        SType::SInt => {
117
            if bytes.len() != 4 {
2✔
118
                return Err(EvalError::UnexpectedValue(
×
119
                    "To deserialize Int with fromBigEndianBytes, exactly four bytes should be provided".to_string(),
×
120
                ));
121
            }
122
            let value = bytes
2✔
123
                .iter()
124
                .fold(0i32, |acc, &x| (acc << 8) | (x as u8 as i32));
2✔
125
            Ok(Value::Int(value))
1✔
126
        }
127
        SType::SLong => {
128
            if bytes.len() != 8 {
2✔
129
                return Err(EvalError::UnexpectedValue(
×
130
                    "To deserialize Long with fromBigEndianBytes, exactly eight bytes should be provided".to_string(),
×
131
                ));
132
            }
133
            let value = bytes
2✔
134
                .iter()
135
                .fold(0i64, |acc, &x| (acc << 8) | (x as u8 as i64));
2✔
136
            Ok(Value::Long(value))
1✔
137
        }
138
        SType::SBigInt => {
139
            if bytes.len() > 32 {
2✔
140
                return Err(EvalError::UnexpectedValue(
×
141
                    "BigInt value doesn't fit into 32 bytes in fromBigEndianBytes".to_string(),
×
142
                ));
143
            }
144
            let bytes_vec: Vec<u8> = bytes.iter().map(|&x| x as u8).collect();
4✔
145
            Ok(Value::BigInt(
1✔
146
                BigInt256::from_be_slice(&bytes_vec).ok_or_else(|| {
2✔
147
                    EvalError::UnexpectedValue("Failed to convert to BigInt256".to_string())
×
148
                })?,
149
            ))
150
        }
151
        _ => Err(EvalError::UnexpectedValue(format!(
×
152
            "Unsupported type provided in fromBigEndianBytes: {:?}",
153
            type_val
154
        ))),
155
    }
156
};
157

158
pub(crate) static DESERIALIZE_EVAL_FN: EvalFn = |mc, _env, ctx, obj, args| {
1✔
159
    if obj != Value::Global {
2✔
160
        return Err(EvalError::UnexpectedValue(format!(
×
161
            "sglobal.deserialize expected obj to be Value::Global, got {:?}",
162
            obj
163
        )));
164
    }
165
    let output_type = &mc.tpe().t_range;
2✔
166
    let bytes = args
1✔
167
        .first()
168
        .ok_or_else(|| EvalError::NotFound("deserialize: missing first arg".into()))?
×
169
        .clone()
170
        .try_extract_into::<Vec<u8>>()?;
×
171
    let mut reader = sigma_byte_reader::from_bytes(&bytes);
1✔
172
    Ok(Value::from(
2✔
173
        reader.with_tree_version(ctx.tree_version(), |reader| {
3✔
174
            DataSerializer::sigma_parse(output_type, reader)
1✔
175
        })?,
176
    ))
177
};
178

179
pub(crate) static SERIALIZE_EVAL_FN: EvalFn = |_mc, _env, ctx, obj, args| {
1✔
180
    if obj != Value::Global {
2✔
181
        return Err(EvalError::UnexpectedValue(format!(
×
182
            "sglobal.groupGenerator expected obj to be Value::Global, got {:?}",
183
            obj
184
        )));
185
    }
186
    let arg: Constant = args
2✔
187
        .first()
188
        .ok_or_else(|| EvalError::NotFound("serialize: missing first arg".into()))?
×
189
        .to_static()
190
        .try_into()
191
        .map_err(EvalError::UnexpectedValue)?;
×
192

193
    let mut buf = vec![];
1✔
194
    let mut writer = SigmaByteWriter::new(&mut buf, None);
1✔
195
    writer.with_tree_version(ctx.tree_version(), |writer| {
3✔
196
        DataSerializer::sigma_serialize(&arg.v, writer)
1✔
197
    })?;
198
    Ok(Value::from(buf))
1✔
199
};
200

201
pub(crate) static SGLOBAL_SOME_EVAL_FN: EvalFn = |_mc, _env, _ctx, obj, args| {
1✔
202
    if obj != Value::Global {
2✔
203
        return Err(EvalError::UnexpectedValue(format!(
×
204
            "sglobal.some expected obj to be Value::Global, got {:?}",
205
            obj
206
        )));
207
    }
208
    let value = args
2✔
209
        .first()
210
        .cloned()
211
        .ok_or_else(|| EvalError::NotFound("some: missing value arg".to_string()))?;
×
212
    Ok(Value::Opt(Some(Box::new(value))))
2✔
213
};
214

215
pub(crate) static SGLOBAL_NONE_EVAL_FN: EvalFn = |_mc, _env, _ctx, obj, _args| {
1✔
216
    if obj != Value::Global {
2✔
217
        return Err(EvalError::UnexpectedValue(format!(
×
218
            "sglobal.none expected obj to be Value::Global, got {:?}",
219
            obj
220
        )));
221
    }
222
    Ok(Value::Opt(None))
1✔
223
};
224

225
pub(crate) static ENCODE_NBITS_EVAL_FN: EvalFn = |_mc, _env, _ctx, _obj, args| {
1✔
226
    let bigint: BigInt = args
2✔
227
        .first()
228
        .cloned()
229
        .ok_or_else(|| EvalError::NotFound("encodeNBits: missing first argument".into()))?
×
230
        .try_extract_into::<BigInt256>()?
×
231
        .into();
232
    Ok(Value::Long(encode_compact_bits(&bigint)))
2✔
233
};
234

235
pub(crate) static DECODE_NBITS_EVAL_FN: EvalFn = |_mc, _env, _ctx, _obj, args| {
1✔
236
    let nbits: i64 = args
2✔
237
        .first()
238
        .cloned()
239
        .ok_or_else(|| EvalError::NotFound("decodeNBits: missing first argument".into()))?
×
240
        .try_extract_into()?;
×
241
    // truncation is safe here, since only bottom 4 bytes are used in decode.
242
    // nbits is only i64 because Scala doesn't have an unsigned 32-bit type
243
    Ok(Value::BigInt(
1✔
244
        decode_compact_bits(nbits as u32)
1✔
245
            .try_into()
246
            .map_err(EvalError::UnexpectedValue)?,
×
247
    ))
248
};
249
pub(crate) static POW_HIT_EVAL_FN: EvalFn = |_mc, _env, _ctx, _obj, mut args| {
1✔
250
    // Pop arguments to avoid cloning
251
    let big_n: u32 = args
2✔
252
        .pop()
NEW
253
        .ok_or_else(|| EvalError::NotFound("powHit: missing N".into()))?
×
NEW
254
        .try_extract_into::<i32>()?
×
255
        .try_into()
NEW
256
        .map_err(|_| EvalError::Misc("N out of bounds".into()))?;
×
257
    let h = args
1✔
258
        .pop()
NEW
259
        .ok_or_else(|| EvalError::NotFound("powHit: missing h".into()))?
×
NEW
260
        .try_extract_into::<Vec<u8>>()?;
×
261
    let nonce = args
2✔
262
        .pop()
NEW
263
        .ok_or_else(|| EvalError::NotFound("powHit: missing nonce".into()))?
×
NEW
264
        .try_extract_into::<Vec<u8>>()?;
×
265
    let msg = args
2✔
266
        .pop()
NEW
267
        .ok_or_else(|| EvalError::NotFound("powHit: missing msg".into()))?
×
NEW
268
        .try_extract_into::<Vec<u8>>()?;
×
269
    let k = args
2✔
270
        .pop()
NEW
271
        .ok_or_else(|| EvalError::NotFound("powHit: missing msg".into()))?
×
NEW
272
        .try_extract_into::<i32>()?;
×
273
    Ok(UnsignedBigInt::try_from(
3✔
274
        AutolykosPowScheme::new(
3✔
275
            k.try_into()
1✔
NEW
276
                .map_err(|_| EvalError::Misc("k out of bounds".into()))?,
×
277
            big_n,
278
        )?
279
        .pow_hit_message_v2(&msg, &nonce, &h, big_n)?,
2✔
280
    )
NEW
281
    .map_err(EvalError::Misc)?
×
282
    .into())
283
};
284

285
#[allow(clippy::unwrap_used)]
286
#[cfg(test)]
287
#[cfg(feature = "arbitrary")]
288
mod tests {
289
    use ergo_chain_types::{EcPoint, Header};
290
    use ergotree_ir::bigint256::BigInt256;
291
    use ergotree_ir::ergo_tree::ErgoTreeVersion;
292
    use ergotree_ir::mir::constant::Constant;
293
    use ergotree_ir::mir::expr::Expr;
294
    use ergotree_ir::mir::long_to_byte_array::LongToByteArray;
295
    use ergotree_ir::mir::method_call::MethodCall;
296
    use ergotree_ir::mir::property_call::PropertyCall;
297
    use ergotree_ir::mir::sigma_prop_bytes::SigmaPropBytes;
298
    use ergotree_ir::mir::unary_op::OneArgOpTryBuild;
299
    use ergotree_ir::mir::value::Value;
300
    use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProp;
301
    use ergotree_ir::types::sgroup_elem::GET_ENCODED_METHOD;
302
    use ergotree_ir::types::stype_param::STypeVar;
303
    use ergotree_ir::unsignedbigint256::UnsignedBigInt;
304
    use num_traits::Num;
305
    use proptest::proptest;
306

307
    use crate::eval::test_util::{eval_out, eval_out_wo_ctx, try_eval_out_with_version};
308
    use ergotree_ir::chain::context::Context;
309
    use ergotree_ir::types::sglobal::{
310
        self, DECODE_NBITS_METHOD, DESERIALIZE_METHOD, ENCODE_NBITS_METHOD, POW_HIT_METHOD,
311
        SERIALIZE_METHOD,
312
    };
313

314
    use ergotree_ir::types::stype::SType;
315
    use sigma_test_util::force_any_val;
316

317
    fn serialize(val: impl Into<Constant>) -> Vec<u8> {
318
        let constant = val.into();
319
        let serialize_node = MethodCall::new(
320
            Expr::Global,
321
            SERIALIZE_METHOD.clone().with_concrete_types(
322
                &[(STypeVar::t(), constant.tpe.clone())]
323
                    .into_iter()
324
                    .collect(),
325
            ),
326
            vec![constant.into()],
327
        )
328
        .unwrap();
329
        let ctx = force_any_val::<Context>();
330
        assert!((0u8..ErgoTreeVersion::V3.into()).all(|version| {
331
            try_eval_out_with_version::<Vec<u8>>(&serialize_node.clone().into(), &ctx, version, 3)
332
                .is_err()
333
        }));
334
        try_eval_out_with_version(&serialize_node.into(), &ctx, ErgoTreeVersion::V3.into(), 3)
335
            .unwrap()
336
    }
337
    fn deserialize(array: &[u8], return_type: SType) -> Constant {
338
        let type_args = [(STypeVar::t(), return_type)].into_iter().collect();
339
        let deserialize_node = MethodCall::with_type_args(
340
            Expr::Global,
341
            DESERIALIZE_METHOD.clone().with_concrete_types(&type_args),
342
            vec![Constant::from(array.to_owned()).into()],
343
            type_args,
344
        )
345
        .unwrap();
346
        let ctx = force_any_val::<Context>();
347
        assert!((0u8..ErgoTreeVersion::V3.into()).all(|version| {
348
            try_eval_out_with_version::<Vec<u8>>(&deserialize_node.clone().into(), &ctx, version, 3)
349
                .is_err()
350
        }));
351
        try_eval_out_with_version::<Value>(
352
            &deserialize_node.into(),
353
            &ctx,
354
            ErgoTreeVersion::V3.into(),
355
            3,
356
        )
357
        .unwrap()
358
        .try_into()
359
        .unwrap()
360
    }
361

362
    fn encode_nbits(bigint: BigInt256) -> i64 {
363
        let mc: Expr = MethodCall::new(
364
            Expr::Global,
365
            ENCODE_NBITS_METHOD.clone(),
366
            vec![bigint.into()],
367
        )
368
        .unwrap()
369
        .into();
370
        eval_out_wo_ctx(&mc)
371
    }
372

373
    fn decode_nbits(nbits: i64) -> BigInt256 {
374
        let mc: Expr = MethodCall::new(
375
            Expr::Global,
376
            DECODE_NBITS_METHOD.clone(),
377
            vec![nbits.into()],
378
        )
379
        .unwrap()
380
        .into();
381
        eval_out_wo_ctx(&mc)
382
    }
383

384
    fn create_some_none_method_call<T>(value: Option<T>, tpe: SType) -> Expr
385
    where
386
        T: Into<Constant>,
387
    {
388
        let type_args = std::iter::once((STypeVar::t(), tpe.clone())).collect();
389
        match value {
390
            Some(v) => MethodCall::new(
391
                Expr::Global,
392
                sglobal::SOME_METHOD.clone().with_concrete_types(&type_args),
393
                vec![Expr::Const(v.into())],
394
            )
395
            .unwrap()
396
            .into(),
397
            None => MethodCall::with_type_args(
398
                Expr::Global,
399
                sglobal::NONE_METHOD.clone().with_concrete_types(&type_args),
400
                vec![],
401
                type_args,
402
            )
403
            .unwrap()
404
            .into(),
405
        }
406
    }
407

408
    fn pow_hit(k: u32, msg: &[u8], nonce: &[u8], h: &[u8], big_n: u32) -> UnsignedBigInt {
409
        let expr: Expr = MethodCall::new(
410
            Expr::Global,
411
            POW_HIT_METHOD.clone(),
412
            vec![
413
                Constant::from(k as i32).into(),
414
                Constant::from(msg.to_owned()).into(),
415
                Constant::from(nonce.to_owned()).into(),
416
                Constant::from(h.to_owned()).into(),
417
                Constant::from(big_n as i32).into(),
418
            ],
419
        )
420
        .unwrap()
421
        .into();
422
        eval_out_wo_ctx(&expr)
423
    }
424

425
    #[test]
426
    fn eval_group_generator() {
427
        let expr: Expr = PropertyCall::new(Expr::Global, sglobal::GROUP_GENERATOR_METHOD.clone())
428
            .unwrap()
429
            .into();
430
        let ctx = force_any_val::<Context>();
431
        assert_eq!(
432
            eval_out::<EcPoint>(&expr, &ctx),
433
            ergo_chain_types::ec_point::generator()
434
        );
435
    }
436

437
    #[test]
438
    fn eval_xor() {
439
        let left = vec![1_i8, 1, 0, 0];
440
        let right = vec![0_i8, 1, 0, 1];
441
        let expected_xor = vec![1_i8, 0, 0, 1];
442

443
        let expr: Expr = MethodCall::new(
444
            Expr::Global,
445
            sglobal::XOR_METHOD.clone(),
446
            vec![right.into(), left.into()],
447
        )
448
        .unwrap()
449
        .into();
450
        let ctx = force_any_val::<Context>();
451
        assert_eq!(
452
            eval_out::<Vec<i8>>(&expr, &ctx).as_slice(),
453
            expected_xor.as_slice()
454
        );
455
    }
456

457
    #[test]
458
    fn test_eval_encode_nbits() {
459
        assert_eq!(
460
            encode_nbits(
461
                BigInt256::from_str_radix("1bc330000000000000000000000000000000000000000000", 16)
462
                    .unwrap()
463
            ),
464
            0x181bc330
465
        );
466

467
        assert_eq!(
468
            encode_nbits(BigInt256::from_str_radix("12345600", 16).unwrap()),
469
            0x04123456
470
        );
471
        assert_eq!(
472
            encode_nbits(BigInt256::from_str_radix("-12345600", 16).unwrap()),
473
            -0x1235
474
        );
475
    }
476

477
    #[test]
478
    fn test_eval_decode_nbits() {
479
        // Following example taken from https://btcinformation.org/en/developer-reference#target-nbits
480
        let n_bits = 0x181bc330;
481
        assert_eq!(
482
            decode_nbits(n_bits),
483
            BigInt256::from_str_radix("1bc330000000000000000000000000000000000000000000", 16)
484
                .unwrap()
485
        );
486

487
        let n_bits = 0x01003456;
488
        assert_eq!(decode_nbits(n_bits), 0x00.into());
489

490
        let n_bits = 0x01123456;
491
        assert_eq!(decode_nbits(n_bits), 0x12.into());
492

493
        let n_bits = 0x04923456;
494
        assert_eq!(decode_nbits(n_bits), (-0x12345600i64).into());
495

496
        let n_bits = 0x04123456;
497
        assert_eq!(decode_nbits(n_bits), 0x12345600.into());
498

499
        let n_bits = 0x05123456;
500
        assert_eq!(decode_nbits(n_bits), 0x1234560000i64.into());
501

502
        let n_bits = 16842752;
503
        assert_eq!(decode_nbits(n_bits), BigInt256::from(1_i8));
504
    }
505

506
    use proptest::prelude::*;
507

508
    proptest! {
509
        #![proptest_config(ProptestConfig::with_cases(64))]
510

511
        #[test]
512
        fn test_bigendian_bytes_roundtrip(
513
            v_byte in any::<i8>(),
514
            v_short in any::<i16>(),
515
            v_int in any::<i32>(),
516
            v_long in any::<i64>()
517
        ) {
518
            {
519
                let bytes = vec![v_byte];
520

521
                let type_args = std::iter::once((STypeVar::t(), SType::SByte)).collect();
522
                let expr: Expr = MethodCall::with_type_args(
523
                    Expr::Global,
524
                    sglobal::FROM_BIGENDIAN_BYTES_METHOD.clone().with_concrete_types(&type_args),
525
                    vec![bytes.into()],
526
                    type_args,
527
                )
528
                .unwrap()
529
                .into();
530
                assert_eq!(eval_out_wo_ctx::<i8>(&expr), v_byte);
531
            }
532

533
            {
534
                let bytes = vec![(v_short >> 8) as i8, v_short as i8];
535

536
                let type_args = std::iter::once((STypeVar::t(), SType::SShort)).collect();
537
                let expr: Expr = MethodCall::with_type_args(
538
                    Expr::Global,
539
                    sglobal::FROM_BIGENDIAN_BYTES_METHOD.clone().with_concrete_types(&type_args),
540
                    vec![bytes.into()],
541
                    type_args,
542
                )
543
                .unwrap()
544
                .into();
545
                assert_eq!(eval_out_wo_ctx::<i16>(&expr), v_short);
546
            }
547

548
            {
549
                let bytes = vec![
550
                    (v_int >> 24) as i8,
551
                    (v_int >> 16) as i8,
552
                    (v_int >> 8) as i8,
553
                    v_int as i8
554
                ];
555

556
                let type_args = std::iter::once((STypeVar::t(), SType::SInt)).collect();
557
                let expr: Expr = MethodCall::with_type_args(
558
                    Expr::Global,
559
                    sglobal::FROM_BIGENDIAN_BYTES_METHOD.clone().with_concrete_types(&type_args),
560
                    vec![bytes.into()],
561
                    type_args,
562
                )
563
                .unwrap()
564
                .into();
565
                assert_eq!(eval_out_wo_ctx::<i32>(&expr), v_int);
566
            }
567

568
            {
569
                let bytes = vec![
570
                    (v_long >> 56) as i8,
571
                    (v_long >> 48) as i8,
572
                    (v_long >> 40) as i8,
573
                    (v_long >> 32) as i8,
574
                    (v_long >> 24) as i8,
575
                    (v_long >> 16) as i8,
576
                    (v_long >> 8) as i8,
577
                    v_long as i8
578
                ];
579

580
                let type_args = std::iter::once((STypeVar::t(), SType::SLong)).collect();
581
                let expr: Expr = MethodCall::with_type_args(
582
                    Expr::Global,
583
                    sglobal::FROM_BIGENDIAN_BYTES_METHOD.clone().with_concrete_types(&type_args),
584
                    vec![bytes.clone().into()],
585
                    type_args,
586
                )
587
                .unwrap()
588
                .into();
589
                assert_eq!(eval_out_wo_ctx::<i64>(&expr), v_long);
590

591
                let original_long = ((bytes[0] as i64) << 56) |
592
                                  (((bytes[1] as i64) & 0xFF) << 48) |
593
                                  (((bytes[2] as i64) & 0xFF) << 40) |
594
                                  (((bytes[3] as i64) & 0xFF) << 32) |
595
                                  (((bytes[4] as i64) & 0xFF) << 24) |
596
                                  (((bytes[5] as i64) & 0xFF) << 16) |
597
                                  (((bytes[6] as i64) & 0xFF) << 8) |
598
                                  ((bytes[7] as i64) & 0xFF);
599
                assert_eq!(original_long, v_long);
600
            }
601
        }
602

603
        #[test]
604
        fn test_bigint_roundtrip(v_long in any::<i64>()) {
605
            let bytes = vec![
606
                (v_long >> 56) as i8,
607
                (v_long >> 48) as i8,
608
                (v_long >> 40) as i8,
609
                (v_long >> 32) as i8,
610
                (v_long >> 24) as i8,
611
                (v_long >> 16) as i8,
612
                (v_long >> 8) as i8,
613
                v_long as i8
614
            ];
615

616
            let type_args = std::iter::once((STypeVar::t(), SType::SBigInt)).collect();
617
            let expr: Expr = MethodCall::with_type_args(
618
                Expr::Global,
619
                sglobal::FROM_BIGENDIAN_BYTES_METHOD.clone().with_concrete_types(&type_args),
620
                vec![bytes.into()],
621
                type_args,
622
            )
623
            .unwrap()
624
            .into();
625
            assert_eq!(eval_out_wo_ctx::<BigInt256>(&expr), BigInt256::from(v_long));
626
        }
627

628
        #[test]
629
        fn test_some_and_none(
630
            byte_val in any::<i8>(),
631
            int_val in any::<i32>(),
632
            long_val in any::<i64>()
633
        ) {
634
            assert_eq!(eval_out_wo_ctx::<Option<i8>>(&create_some_none_method_call(Some(byte_val), SType::SByte)), Some(byte_val));
635
            assert_eq!(eval_out_wo_ctx::<Option<i32>>(&create_some_none_method_call(Some(int_val), SType::SInt)), Some(int_val));
636
            assert_eq!(eval_out_wo_ctx::<Option<i64>>(&create_some_none_method_call(Some(long_val), SType::SLong)), Some(long_val));
637
            assert_eq!(eval_out_wo_ctx::<Option<i8>>(&create_some_none_method_call::<i8>(None, SType::SByte)), None);
638
            assert_eq!(eval_out_wo_ctx::<Option<i64>>(&create_some_none_method_call::<i64>(None, SType::SLong)), None);
639
        }
640

641
    }
642

643
    #[test]
644
    fn serialize_byte() {
645
        assert_eq!(serialize(-128i8), vec![-128i8 as u8]);
646
        assert_eq!(serialize(-1i8), vec![-1i8 as u8]);
647
        assert_eq!(serialize(0i8), vec![0u8]);
648
        assert_eq!(serialize(1i8), vec![1]);
649
        assert_eq!(serialize(127i8), vec![127u8]);
650
    }
651

652
    #[test]
653
    fn serialize_short() {
654
        assert_eq!(serialize(i16::MIN), vec![0xff, 0xff, 0x03]);
655
        assert_eq!(serialize(-1i16), vec![0x01]);
656
        assert_eq!(serialize(0i16), vec![0x00]);
657
        assert_eq!(serialize(1i16), vec![0x02]);
658
        assert_eq!(serialize(i16::MAX), vec![0xfe, 0xff, 0x03]);
659
    }
660

661
    #[test]
662
    fn serialize_byte_array() {
663
        let arr = vec![0xc0, 0xff, 0xee];
664
        let serialized = serialize(arr.clone());
665

666
        assert_eq!(serialized[0], arr.len() as u8);
667
        assert_eq!(&serialized[1..], &arr)
668
    }
669

670
    // test that serialize(long) != longToByteArray()
671
    #[test]
672
    fn serialize_long_ne_tobytearray() {
673
        let num = -1000i64;
674
        let long_to_byte_array = LongToByteArray::try_build(Constant::from(num).into()).unwrap();
675
        let serialized = serialize(num);
676
        assert!(serialized != eval_out_wo_ctx::<Vec<u8>>(&long_to_byte_array.into()))
677
    }
678

679
    // test equivalence between Global.serialize and ge.getEncoded
680
    #[test]
681
    fn serialize_group_element() {
682
        let ec_point = EcPoint::from_base16_str(String::from(
683
            "026930cb9972e01534918a6f6d6b8e35bc398f57140d13eb3623ea31fbd069939b",
684
        ))
685
        .unwrap();
686
        let get_encoded = MethodCall::new(
687
            Constant::from(ec_point.clone()).into(),
688
            GET_ENCODED_METHOD.clone(),
689
            vec![],
690
        )
691
        .unwrap();
692
        assert_eq!(
693
            eval_out_wo_ctx::<Vec<u8>>(&get_encoded.into()),
694
            serialize(ec_point)
695
        );
696
    }
697

698
    #[test]
699
    fn deserialize_group_element() {
700
        let ec_point = EcPoint::from_base16_str(String::from(
701
            "026930cb9972e01534918a6f6d6b8e35bc398f57140d13eb3623ea31fbd069939b",
702
        ))
703
        .unwrap();
704
        let get_encoded = MethodCall::new(
705
            Constant::from(ec_point.clone()).into(),
706
            GET_ENCODED_METHOD.clone(),
707
            vec![],
708
        )
709
        .unwrap();
710
        let encoded = eval_out_wo_ctx::<Vec<u8>>(&get_encoded.into());
711
        assert_eq!(
712
            deserialize(&encoded, SType::SGroupElement),
713
            Constant::from(ec_point)
714
        );
715
    }
716

717
    #[test]
718
    fn pow_hit_eval() {
719
        let msg = base16::decode("0a101b8c6a4f2e").unwrap();
720
        let nonce = base16::decode("000000000000002c").unwrap();
721
        let hbs = base16::decode("00000000").unwrap();
722
        assert_eq!(
723
            pow_hit(32, &msg, &nonce, &hbs, 1024 * 1024),
724
            UnsignedBigInt::from_str_radix(
725
                "326674862673836209462483453386286740270338859283019276168539876024851191344",
726
                10
727
            )
728
            .unwrap()
729
        );
730
    }
731

732
    proptest! {
733
        #[test]
734
        fn serialize_sigmaprop_eq_prop_bytes(sigma_prop: SigmaProp) {
735
            let prop_bytes_op = SigmaPropBytes::try_build(Constant::from(sigma_prop.clone()).into()).unwrap();
736
            let prop_bytes = eval_out_wo_ctx::<Vec<u8>>(&prop_bytes_op.into());
737
            assert_eq!(serialize(sigma_prop.clone()), &prop_bytes[2..]);
738
            assert_eq!(deserialize(&prop_bytes[2..], SType::SSigmaProp), sigma_prop.into());
739
        }
740
        #[test]
741
        fn serialize_roundtrip(v in any::<Constant>()) {
742
            let tpe = v.tpe.clone();
743
            let res = std::panic::catch_unwind(|| assert_eq!(deserialize(&serialize(v.clone()), tpe.clone()), v));
744
            if matches!(tpe, SType::SOption(_)) {
745
                assert!(res.is_err());
746
            }
747
            else {
748
                res.unwrap();
749
            }
750
        }
751
        #[test]
752
        fn serialize_unsigned_bigint(v in any::<UnsignedBigInt>()) {
753
            assert_eq!(deserialize(&serialize(v), SType::SUnsignedBigInt), Constant::from(v));
754
        }
755
        #[test]
756
        fn serialize_header(h in any::<Header>()) {
757
            assert_eq!(deserialize(&serialize(h.clone()), SType::SHeader), Constant::from(h));
758
        }
759
    }
760
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc