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
140
141
142
use crate::{
    ecmult::{ECMultContext, ECMultGenContext},
    field::Field,
    group::{Affine, Jacobian},
    scalar::Scalar,
    Error,
};

const P_MINUS_ORDER: Field = Field::new(0, 0, 0, 1, 0x45512319, 0x50B75FC4, 0x402DA172, 0x2FC9BAEE);

const ORDER_AS_FE: Field = Field::new(
    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xBAAEDCE6, 0xAF48A03B, 0xBFD25E8C, 0xD0364141,
);

impl ECMultContext {
    pub fn verify_raw(
        &self,
        sigr: &Scalar,
        sigs: &Scalar,
        pubkey: &Affine,
        message: &Scalar,
    ) -> bool {
        let c;
        let (sn, u1, u2): (Scalar, Scalar, Scalar);

        if sigr.is_zero() || sigs.is_zero() {
            return false;
        }

        sn = sigs.inv_var();
        u1 = &sn * message;
        u2 = &sn * sigr;
        let mut pubkeyj: Jacobian = Jacobian::default();
        pubkeyj.set_ge(pubkey);
        let mut pr: Jacobian = Jacobian::default();
        self.ecmult(&mut pr, &pubkeyj, &u2, &u1);
        if pr.is_infinity() {
            return false;
        }

        c = sigr.b32();
        let mut xr: Field = Default::default();
        let _ = xr.set_b32(&c);

        if pr.eq_x_var(&xr) {
            return true;
        }
        if xr >= P_MINUS_ORDER {
            return false;
        }
        xr += ORDER_AS_FE;
        if pr.eq_x_var(&xr) {
            return true;
        }
        false
    }

    pub fn recover_raw(
        &self,
        sigr: &Scalar,
        sigs: &Scalar,
        rec_id: u8,
        message: &Scalar,
    ) -> Result<Affine, Error> {
        debug_assert!(rec_id < 4);

        if sigr.is_zero() || sigs.is_zero() {
            return Err(Error::InvalidSignature);
        }

        let brx = sigr.b32();
        let mut fx = Field::default();
        let overflow = fx.set_b32(&brx);
        debug_assert!(overflow);

        if rec_id & 2 > 0 {
            if fx >= P_MINUS_ORDER {
                return Err(Error::InvalidSignature);
            }
            fx += ORDER_AS_FE;
        }
        let mut x = Affine::default();
        if !x.set_xo_var(&fx, rec_id & 1 > 0) {
            return Err(Error::InvalidSignature);
        }
        let mut xj = Jacobian::default();
        xj.set_ge(&x);
        let rn = sigr.inv();
        let mut u1 = &rn * message;
        u1 = -u1;
        let u2 = &rn * sigs;
        let mut qj = Jacobian::default();
        self.ecmult(&mut qj, &xj, &u2, &u1);

        let mut pubkey = Affine::default();
        pubkey.set_gej_var(&qj);

        if pubkey.is_infinity() {
            Err(Error::InvalidSignature)
        } else {
            Ok(pubkey)
        }
    }
}

impl ECMultGenContext {
    pub fn sign_raw(
        &self,
        seckey: &Scalar,
        message: &Scalar,
        nonce: &Scalar,
    ) -> Result<(Scalar, Scalar, u8), Error> {
        let mut rp = Jacobian::default();
        self.ecmult_gen(&mut rp, nonce);
        let mut r = Affine::default();
        r.set_gej(&rp);
        r.x.normalize();
        r.y.normalize();
        let b = r.x.b32();
        let mut sigr = Scalar::default();
        let overflow = bool::from(sigr.set_b32(&b));
        debug_assert!(!sigr.is_zero());
        debug_assert!(!overflow);

        let mut recid = (if overflow { 2 } else { 0 }) | (if r.y.is_odd() { 1 } else { 0 });
        let mut n = &sigr * seckey;
        n += message;
        let mut sigs = nonce.inv();
        sigs *= &n;
        n.clear();
        rp.clear();
        r.clear();
        if sigs.is_zero() {
            return Err(Error::InvalidMessage);
        }
        if sigs.is_high() {
            sigs = -sigs;
            recid ^= 1;
        }
        Ok((sigr, sigs, recid))
    }
}