ecash_core/
crypto.rs

1use num_bigint::{BigInt, BigUint};
2use num_traits::{One, Signed, Zero};
3use rand::thread_rng;
4use rsa::traits::{PrivateKeyParts, PublicKeyParts};
5use rsa::{RsaPrivateKey, RsaPublicKey};
6use sha2::{Digest, Sha256};
7
8use crate::error::{EcashError, Result};
9
10pub struct BlindSigner {
11    private_key: RsaPrivateKey,
12    public_key: RsaPublicKey,
13}
14
15impl BlindSigner {
16    pub fn new(bits: usize) -> Result<Self> {
17        let mut rng = thread_rng();
18        let private_key =
19            RsaPrivateKey::new(&mut rng, bits).map_err(|_| EcashError::CryptoError)?;
20        let public_key = private_key.to_public_key();
21
22        Ok(Self {
23            private_key,
24            public_key,
25        })
26    }
27
28    pub fn from_keys(private_key: RsaPrivateKey) -> Self {
29        let public_key = private_key.to_public_key();
30        Self {
31            private_key,
32            public_key,
33        }
34    }
35
36    pub fn public_key(&self) -> &RsaPublicKey {
37        &self.public_key
38    }
39
40    pub fn sign_blinded(&self, blinded_message: &BigUint) -> Result<BigUint> {
41        let n = self.private_key.n();
42        let n_big = BigUint::from_bytes_be(&n.to_bytes_be());
43        let d = self.private_key.d();
44        let d_big = BigUint::from_bytes_be(&d.to_bytes_be());
45
46        Ok(blinded_message.modpow(&d_big, &n_big))
47    }
48}
49
50pub struct BlindUser {
51    public_key: RsaPublicKey,
52}
53
54impl BlindUser {
55    pub fn new(public_key: RsaPublicKey) -> Self {
56        Self { public_key }
57    }
58
59    pub fn blind_message(&self, message: &[u8]) -> Result<(BigUint, BigUint)> {
60        let n = self.public_key.n();
61        let n_big = BigUint::from_bytes_be(&n.to_bytes_be());
62        let e = self.public_key.e();
63        let e_big = BigUint::from_bytes_be(&e.to_bytes_be());
64
65        let mut hasher = Sha256::new();
66        hasher.update(message);
67        let m = BigUint::from_bytes_be(&hasher.finalize());
68
69        let r = loop {
70            let bytes: Vec<u8> = (0..n.to_bytes_be().len())
71                .map(|_| rand::random::<u8>())
72                .collect();
73            let candidate = BigUint::from_bytes_be(&bytes) % &n_big;
74            if candidate > BigUint::one() && Self::gcd(&candidate, &n_big) == BigUint::one() {
75                break candidate;
76            }
77        };
78
79        let r_e = r.modpow(&e_big, &n_big);
80        let blinded = (&m * &r_e) % &n_big;
81
82        Ok((blinded, r))
83    }
84
85    pub fn unblind_signature(
86        &self,
87        blind_signature: &BigUint,
88        blinding_factor: &BigUint,
89    ) -> Result<BigUint> {
90        let n = self.public_key.n();
91        let n_big = BigUint::from_bytes_be(&n.to_bytes_be());
92
93        let r_inv = Self::mod_inverse(blinding_factor, &n_big).ok_or(EcashError::BlindingFailed)?;
94
95        Ok((blind_signature * r_inv) % &n_big)
96    }
97
98    pub fn verify_signature(&self, message: &[u8], signature: &BigUint) -> bool {
99        let n = self.public_key.n();
100        let n_big = BigUint::from_bytes_be(&n.to_bytes_be());
101        let e = self.public_key.e();
102        let e_big = BigUint::from_bytes_be(&e.to_bytes_be());
103
104        let mut hasher = Sha256::new();
105        hasher.update(message);
106        let m = BigUint::from_bytes_be(&hasher.finalize());
107
108        let verified = signature.modpow(&e_big, &n_big);
109        verified == m
110    }
111
112    fn gcd(a: &BigUint, b: &BigUint) -> BigUint {
113        let mut a = a.clone();
114        let mut b = b.clone();
115        while b != BigUint::zero() {
116            let temp = b.clone();
117            b = &a % &b;
118            a = temp;
119        }
120        a
121    }
122
123    fn mod_inverse(a: &BigUint, n: &BigUint) -> Option<BigUint> {
124        let a_int = BigInt::from_bytes_be(num_bigint::Sign::Plus, &a.to_bytes_be());
125        let n_int = BigInt::from_bytes_be(num_bigint::Sign::Plus, &n.to_bytes_be());
126
127        let (g, x, _) = Self::extended_gcd(&a_int, &n_int);
128
129        if g != BigInt::one() {
130            return None;
131        }
132
133        let result = if x.is_negative() {
134            (x + &n_int) % &n_int
135        } else {
136            x % &n_int
137        };
138
139        Some(BigUint::from_bytes_be(&result.to_bytes_be().1))
140    }
141
142    fn extended_gcd(a: &BigInt, b: &BigInt) -> (BigInt, BigInt, BigInt) {
143        if b.is_zero() {
144            return (a.clone(), BigInt::one(), BigInt::zero());
145        }
146
147        let (g, x1, y1) = Self::extended_gcd(b, &(a % b));
148        let x = y1.clone();
149        let y = x1 - (a / b) * y1;
150
151        (g, x, y)
152    }
153}
154
155#[cfg(test)]
156mod tests {
157    use super::*;
158
159    #[test]
160    fn test_blind_signature_flow() {
161        let signer = BlindSigner::new(2048).unwrap();
162        let user = BlindUser::new(signer.public_key().clone());
163
164        let message = b"test message";
165
166        let (blinded, blinding_factor) = user.blind_message(message).unwrap();
167        let blind_sig = signer.sign_blinded(&blinded).unwrap();
168        let signature = user
169            .unblind_signature(&blind_sig, &blinding_factor)
170            .unwrap();
171
172        assert!(user.verify_signature(message, &signature));
173    }
174}