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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//! Internal macros

macro_rules! std_ops_gen {
    ($lty: ident, $class: ident, $rty: ident, $out: ident, $f: ident) => {
        impl<'a> $class<$rty> for &'a $lty {
            type Output = $out;

            fn $f(self, other: $rty) -> Self::Output {
                self.$f(&other)
            }
        }

        impl<'b> $class<&'b $rty> for $lty {
            type Output = $out;

            fn $f(self, other: &'b $rty) -> Self::Output {
                (&self).$f(other)
            }
        }

        impl $class<$rty> for $lty {
            type Output = $out;

            fn $f(self, other: $rty) -> Self::Output {
                (&self).$f(&other)
            }
        }
    };
}

macro_rules! gen_group_tests {
    () => {
        #[cfg(test)]
        mod group_tests {
            use super::*;
            use cryptoxide::blake2b::Blake2b;
            use cryptoxide::digest::Digest;
            use smoke::{
                generator::{self, BoxGenerator},
                Generator,
            };

            fn fe_generator() -> BoxGenerator<Scalar> {
                generator::Array5::new(generator::num::<u8>())
                    .map(|a| {
                        let mut hash = Blake2b::new(64);
                        hash.input(&a);
                        Scalar::hash_to_scalar(&hash)
                    })
                    .into_boxed()
            }

            #[test]
            fn add_zero() {
                let fe = Scalar::from_u64(64);
                let ge = GroupElement::generator() * fe;
                assert_eq!(GroupElement::zero() + &ge, ge);
            }

            #[test]
            fn clone() {
                let fe1 = Scalar::from_bytes(&[1u8; 32]);
                assert_eq!(fe1, fe1.clone());
            }
            #[test]
            fn associative() {
                let fe1 = Scalar::from_u64(124);
                let fe2 = Scalar::from_u64(434);
                let fe3 = Scalar::from_u64(124 + 434);

                let ge1 = GroupElement::generator() * &fe1;
                let ge2 = GroupElement::generator() * &fe2;
                let ge3 = GroupElement::generator() * &fe3;

                let ge3_got = ge1 + ge2;

                assert_eq!(fe3, fe1 + fe2);
                assert_eq!(ge3_got, ge3);
            }

            #[test]
            fn ge_inverse() {
                let fe1 = Scalar::from_u64(124);
                let g = (GroupElement::generator() * &fe1) * fe1.inverse();
                assert_eq!(g, GroupElement::generator())
            }

            #[test]
            fn fe_inverse() {
                let fe1 = Scalar::from_u64(124);
                assert_eq!(&fe1 * fe1.inverse(), Scalar::one())
            }

            #[test]
            fn arithmetic_correct() {
                use smoke::{forall, property, run, Testable};
                run(|ctx| {
                    // add associative
                    forall(fe_generator().and(fe_generator()).and(fe_generator()))
                        .ensure(|((e1, e2), e3)| property::equal((e1 + e2) + e3, e1 + (e2 + e3)))
                        .test(ctx);

                    forall(fe_generator().and(fe_generator()))
                        .ensure(|(e1, e2)| property::equal(e1 + e2, e2 + e1))
                        .test(ctx);

                    forall(fe_generator())
                        .ensure(|e| property::equal(e.clone(), e.clone()))
                        .test(ctx);

                    forall(fe_generator())
                        .ensure(|e| property::equal(e * e.inverse(), Scalar::one()))
                        .test(ctx);

                    forall(fe_generator())
                        .ensure(|e1| property::equal(e1 + e1.negate(), Scalar::zero()))
                        .test(ctx);

                    forall(fe_generator().and(fe_generator()))
                        .ensure(|(e1, e2)| property::equal((e1 - e2) + e2, e1.clone()))
                        .test(ctx);

                    forall(fe_generator().and(fe_generator()).and(fe_generator()))
                        .ensure(|((e1, e2), e3)| property::equal((e1 + e2) * e3, e1 * e3 + e2 * e3))
                        .test(ctx);

                    /*
                    forall(fe_generator())
                        .ensure(|e1| {
                            let g = (GroupElement::generator() * e1) * e1.inverse();
                            property::equal(g, GroupElement::generator())
                        })
                        .test(ctx);
                        */
                })
            }
        }
    };
}