trezor_crypto_lib/
lib.rs

1//! A dalek cryptography based reproduction of the ed25519-donna API
2//!
3//! See:
4//!   - https://github.com/ryankurte/rust-dalek-donna
5
6#![cfg_attr(not(feature = "std"), no_std)]
7
8use cty::c_int;
9
10use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE;
11use ed25519_dalek::{Signer, Verifier};
12
13#[cfg(feature = "build_donna")]
14pub mod ffi;
15
16#[cfg(feature = "build_donna")]
17pub mod test;
18
19// Constant lengths
20pub mod consts {
21    pub const PUBLIC_KEY_LENGTH: usize = 32;
22    pub const SECRET_KEY_LENGTH: usize = 32;
23    pub const SIGNATURE_LENGTH: usize = 64;
24    pub const SCALAR_LENGTH: usize = 32;
25
26    // Ensure object sizes used here (and in FFI) match
27    static_assertions::const_assert_eq!(PUBLIC_KEY_LENGTH, ed25519_dalek::PUBLIC_KEY_LENGTH);
28    static_assertions::const_assert_eq!(SECRET_KEY_LENGTH, ed25519_dalek::SECRET_KEY_LENGTH);
29    static_assertions::const_assert_eq!(SIGNATURE_LENGTH, ed25519_dalek::SIGNATURE_LENGTH);
30}
31
32use crate::consts::*;
33
34// Bindgen / cty have some weird behaviours when mapping `size_t` on different platforms.
35// use [`Uint`] in place of `cty::size_t` to avoid this.
36
37/// Alias for size_t on 32-bit platforms where size_t is c_uint
38#[cfg(target_pointer_width = "32")]
39pub type UInt = cty::c_uint;
40
41/// Alias for size_t on 64-bit platforms where size_t is c_ulong
42#[cfg(target_pointer_width = "64")]
43pub type UInt = cty::uint64_t;
44
45/// PublicKey array
46pub type PublicKey = [u8; PUBLIC_KEY_LENGTH];
47
48/// SecretKey array
49pub type SecretKey = [u8; SECRET_KEY_LENGTH];
50
51/// Signature array
52pub type Signature = [u8; SIGNATURE_LENGTH];
53
54/// Scalar array
55pub type Scalar = [u8; SCALAR_LENGTH];
56
57/// Derives a public key from a private key
58///
59/// Compatible with ed25519-donna [ed25519_publickey](https://github.com/floodyberry/ed25519-donna/blob/master/ed25519.c#L45)
60#[no_mangle]
61pub extern "C" fn dalek_ed25519_publickey(sk: *mut SecretKey, pk: *mut PublicKey) {
62    let (sk, pk) = unsafe { (&(*sk), &mut (*pk)) };
63
64    // Parse out secret key
65    let secret_key = match ed25519_dalek::SecretKey::from_bytes(sk) {
66        Ok(v) => v,
67        Err(_e) => {
68            // TODO: how to propagate errors in a function returning void...
69
70            // Ensure public key is zeroed
71            pk.iter_mut().for_each(|v| *v = 0);
72
73            return;
74        }
75    };
76
77    // Generate and write public key
78    let public_key = ed25519_dalek::PublicKey::from(&secret_key);
79    pk.copy_from_slice(public_key.as_bytes());
80}
81
82/// Verifies a signed message
83///
84/// Compatible with ed25519-donna [ed25519_sign_open](https://github.com/floodyberry/ed25519-donna/blob/master/ed25519.c#L94)
85#[no_mangle]
86pub extern "C" fn dalek_ed25519_sign_open(
87    m: *const u8,
88    mlen: UInt,
89    pk: *mut PublicKey,
90    sig: *mut Signature,
91) -> c_int {
92    // Convert pointers into slices
93    let (m, pk, sig) = unsafe {
94        (
95            core::slice::from_raw_parts(m, mlen as usize),
96            &(*pk),
97            &(*sig),
98        )
99    };
100
101    // Parse public key and signature
102    let public_key = match ed25519_dalek::PublicKey::from_bytes(pk) {
103        Ok(v) => v,
104        Err(_e) => {
105            return -1;
106        }
107    };
108    let signature = match ed25519_dalek::Signature::try_from(&sig[..]) {
109        Ok(v) => v,
110        Err(_e) => {
111            return -2;
112        }
113    };
114
115    // Verify signature
116    if let Err(_e) = public_key.verify(m, &signature) {
117        return -3;
118    }
119
120    return 0;
121}
122
123/// Signs a message using the provided secret key
124///
125/// Compatible with ed25519-donna [ed25519_sign](https://github.com/floodyberry/ed25519-donna/blob/master/ed25519.c#L59)
126#[no_mangle]
127pub extern "C" fn dalek_ed25519_sign(
128    m: *const u8,
129    mlen: UInt,
130    sk: *mut SecretKey,
131    pk: *mut PublicKey,
132    sig: *mut Signature,
133) {
134    // Convert pointers into slices
135    let (m, sk, pk, sig) = unsafe {
136        (
137            core::slice::from_raw_parts(m, mlen as usize),
138            &(*sk),
139            &(*pk),
140            &mut (*sig),
141        )
142    };
143
144    // Parse keys
145    let secret_key = match ed25519_dalek::SecretKey::from_bytes(sk) {
146        Ok(v) => v,
147        Err(_e) => return,
148    };
149    let public_key = match ed25519_dalek::PublicKey::from_bytes(pk) {
150        Ok(v) => v,
151        Err(_e) => return,
152    };
153
154    // Generate keypair for signing
155    let keypair = ed25519_dalek::Keypair {
156        public: public_key,
157        secret: secret_key,
158    };
159
160    // Sign message
161    let signature = match keypair.try_sign(m) {
162        Ok(v) => v,
163        Err(_e) => {
164            // Ensure signature is zeroed
165            sig.iter_mut().for_each(|v| *v = 0);
166            return;
167        }
168    };
169
170    // Write signature back
171    sig.copy_from_slice(signature.as_ref());
172}
173
174/// Batch verify signatures, valid[i] == 1 for valid, 0 otherwise
175// TODO(@ryankurte): `ed25519-donna-batchverify.h` has -a lot- going on, presumably for performance reasons (see `cargo bench`)...
176// seems like [`ed25519_dalek::verify_batch`] could substitute but we still need to return the *valid values per message (and run without `std` or `alloc`)
177// TODO(@ryankurte): reverse engineer the error returns from the existing code
178#[no_mangle]
179pub extern "C" fn dalek_ed25519_sign_open_batch(
180    m: *mut *const u8,
181    mlen: *mut UInt,
182    pk: *mut *const u8,
183    rs: *mut *const u8,
184    num: UInt,
185    valid: *mut c_int,
186) -> c_int {
187    // Convert pointers into slices
188    let (m, mlen, pk, rs, valid) = unsafe {
189        (
190            core::slice::from_raw_parts(m, num as usize),
191            core::slice::from_raw_parts(mlen, num as usize),
192            core::slice::from_raw_parts_mut(pk, num as usize),
193            core::slice::from_raw_parts_mut(rs, num as usize),
194            core::slice::from_raw_parts_mut(valid, num as usize),
195        )
196    };
197
198    let mut all_valid = 0;
199
200    // Set all messages to invalid
201    valid.iter_mut().for_each(|v| *v = 1);
202
203    // Check for signature validity
204    for i in 0..num as usize {
205        let v = dalek_ed25519_sign_open(
206            m[i],
207            mlen[i],
208            pk[i] as *mut PublicKey,
209            rs[i] as *mut Signature,
210        );
211        valid[i] = match v {
212            0 => 1,
213            _ => {
214                all_valid = 1;
215                0
216            }
217        };
218    }
219
220    all_valid
221}
222
223/// Generate random bytes using the system RNG
224// TODO(@ryankurte): possible we don't need this
225#[no_mangle]
226pub extern "C" fn dalek_ed25519_randombytes_unsafe(out: *mut u8, count: UInt) {
227    let buff = unsafe { core::slice::from_raw_parts_mut(out, count as usize) };
228    let _ = getrandom::getrandom(buff);
229}
230
231/// Perform scalar multiplication of `e` over the edwards curve point
232///
233/// Compatible with ed25519-donna [curved25519_scalarmult_basepoint](https://github.com/floodyberry/ed25519-donna/blob/master/ed25519.c#L125)
234#[no_mangle]
235pub extern "C" fn dalek_curved25519_scalarmult_basepoint(pk: *mut Scalar, e: *mut Scalar) {
236    let (pk, e) = unsafe { (&mut (*pk), &(*e)) };
237
238    // Copy into editable slice
239    let mut ec = [0u8; 32];
240    ec.copy_from_slice(e);
241
242    // Clamp
243    ec[0] &= 248;
244    ec[31] &= 127;
245    ec[31] |= 64;
246
247    // Expand secret
248    let s = curve25519_dalek::scalar::Scalar::from_bytes_mod_order(ec);
249
250    // scalar * basepoint
251    let p = &ED25519_BASEPOINT_TABLE * &s;
252
253    // convert to montgomery
254    /* u = (y + z) / (z - y) */
255    let u = p.to_montgomery();
256
257    // Write back to pk
258    pk.copy_from_slice(u.as_bytes());
259}
260
261/// Scalar multiplication using the provided basepoint
262#[no_mangle]
263pub extern "C" fn dalek_curve25519_scalarmult(
264    o: *mut PublicKey,
265    e: *mut SecretKey,
266    bp: *mut PublicKey,
267) {
268    let (o, e, bp) = unsafe { (&mut (*o), &(*e), &(*bp)) };
269
270    // Copy secret into editable slice
271    let mut ec = [0u8; 32];
272    ec.copy_from_slice(e);
273
274    // Copy basepoint (public key) into editable slice
275    let mut bpc = [0u8; 32];
276    bpc.copy_from_slice(bp);
277
278    // Clamp secret key
279    ec[0] &= 248;
280    ec[31] &= 127;
281    ec[31] |= 64;
282
283    // Compute DH
284    let p = { x25519_dalek::x25519(ec, bpc) };
285
286    // Write back to pk
287    o.copy_from_slice(&p);
288}
289
290/// Generate a public key using the expanded (sk + sk_ext) form of the secret key
291#[no_mangle]
292pub extern "C" fn dalek_ed25519_publickey_ext(
293    sk: *mut SecretKey,
294    sk_ext: *mut SecretKey,
295    pk: *mut PublicKey,
296) {
297    let (sk, sk_ext, pk) = unsafe { (&(*sk), &(*sk_ext), &mut (*pk)) };
298
299    // Rebuild expanded key
300    let mut sk_full = [0u8; 64];
301    sk_full[..32].copy_from_slice(sk);
302    sk_full[32..].copy_from_slice(sk_ext);
303
304    let expanded = match ed25519_dalek::ExpandedSecretKey::from_bytes(&sk_full) {
305        Ok(v) => v,
306        Err(_e) => return,
307    };
308
309    // Generate public key
310    let public = ed25519_dalek::PublicKey::from(&expanded);
311
312    pk.copy_from_slice(public.as_ref());
313}
314
315/// Generate a signature using the expanded (sk + sk_ext) form of the secret key.
316#[no_mangle]
317pub extern "C" fn dalek_ed25519_sign_ext(
318    m: *const u8,
319    mlen: UInt,
320    sk: *mut SecretKey,
321    sk_ext: *mut SecretKey,
322    pk: *mut PublicKey,
323    sig: *mut Signature,
324) {
325    let (m, sk, sk_ext, pk, sig) = unsafe {
326        (
327            core::slice::from_raw_parts(m, mlen as usize),
328            &(*sk),
329            &(*sk_ext),
330            &(*pk),
331            &mut (*sig),
332        )
333    };
334
335    // Rebuild extended key
336    let mut sk_full = [0u8; 64];
337    sk_full[..32].copy_from_slice(sk);
338    sk_full[32..].copy_from_slice(sk_ext);
339
340    let secret_key = match ed25519_dalek::ExpandedSecretKey::from_bytes(&sk_full) {
341        Ok(k) => k,
342        Err(_e) => return,
343    };
344
345    let public_key = match ed25519_dalek::PublicKey::from_bytes(pk) {
346        Ok(v) => v,
347        Err(_e) => return,
348    };
349
350    // Generate signature
351    let signature = secret_key.sign(m, &public_key);
352
353    // Write to provided buffer
354    sig.copy_from_slice(signature.as_ref());
355}