├── tests ├── subtle_eq │ ├── src │ │ └── lib.rs │ ├── checkct │ │ ├── Cargo.toml │ │ ├── rust-toolchain.toml │ │ ├── driver │ │ │ ├── Cargo.toml │ │ │ ├── src │ │ │ │ ├── main.rs │ │ │ │ ├── driver.rs │ │ │ │ └── rng.rs │ │ │ └── .cargo │ │ │ │ └── config.toml │ │ ├── .cargo │ │ │ └── config.toml │ │ └── Cargo.lock │ └── Cargo.toml ├── vulnerable_eq │ ├── checkct │ │ ├── Cargo.toml │ │ ├── rust-toolchain.toml │ │ ├── driver │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ ├── main.rs │ │ │ │ ├── driver.rs │ │ │ │ └── rng.rs │ │ ├── .cargo │ │ │ └── config.toml │ │ └── Cargo.lock │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── subtle_eq.rs └── vulnerable_eq.rs ├── examples ├── dalek │ ├── src │ │ └── lib.rs │ ├── checkct │ │ ├── Cargo.toml │ │ ├── rust-toolchain.toml │ │ ├── driver │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ ├── main.rs │ │ │ │ ├── driver.rs │ │ │ │ └── rng.rs │ │ ├── .cargo │ │ │ └── config.toml │ │ └── Cargo.lock │ └── Cargo.toml ├── chachapoly │ ├── src │ │ └── lib.rs │ ├── checkct │ │ ├── Cargo.toml │ │ ├── rust-toolchain.toml │ │ ├── driver │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ ├── main.rs │ │ │ │ ├── driver.rs │ │ │ │ └── rng.rs │ │ ├── .cargo │ │ │ └── config.toml │ │ └── Cargo.lock │ └── Cargo.toml ├── masked_aes │ ├── .cargo │ │ └── config.toml │ ├── checkct │ │ ├── Cargo.toml │ │ ├── rust-toolchain.toml │ │ ├── driver │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ ├── main.rs │ │ │ │ ├── driver.rs │ │ │ │ └── rng.rs │ │ ├── .cargo │ │ │ └── config.toml │ │ └── Cargo.lock │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ └── lib.rs ├── secp256K1 │ ├── src │ │ └── lib.rs │ ├── checkct │ │ ├── Cargo.toml │ │ ├── rust-toolchain.toml │ │ ├── driver │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ ├── main.rs │ │ │ │ ├── driver.rs │ │ │ │ └── rng.rs │ │ ├── .cargo │ │ │ └── config.toml │ │ └── Cargo.lock │ └── Cargo.toml └── memcmp │ └── checkct │ ├── Cargo.toml │ ├── rust-toolchain.toml │ ├── driver │ ├── Cargo.toml │ └── src │ │ ├── main.rs │ │ └── rng.rs │ ├── .cargo │ └── config.toml │ └── Cargo.lock ├── template ├── Cargo.toml ├── driver │ ├── src │ │ ├── driver.rs │ │ ├── main.rs │ │ └── rng.rs │ └── Cargo.toml ├── rust-toolchain.toml ├── target │ └── driver.binsec └── .cargo │ └── config.toml ├── .gitmodules ├── checkct_macros ├── Cargo.toml ├── src │ └── lib.rs └── examples │ └── attribute.rs ├── .gitignore ├── Cargo.toml ├── .github └── workflows │ ├── lint.yml │ └── test.yml ├── LICENSE-MIT ├── Containerfile ├── src ├── add.rs ├── init.rs ├── main.rs ├── common.rs └── run.rs ├── README.md ├── LICENSE-APACHE └── Cargo.lock /tests/subtle_eq/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | pub use subtle::*; 4 | -------------------------------------------------------------------------------- /examples/dalek/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | pub use x25519_dalek::*; 4 | -------------------------------------------------------------------------------- /examples/chachapoly/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | pub use chacha20poly1305::*; 4 | -------------------------------------------------------------------------------- /examples/masked_aes/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = ["thumbv7em-none-eabihf"] -------------------------------------------------------------------------------- /template/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [{members}] 3 | resolver = "2" 4 | 5 | [profile.release] 6 | debug = true 7 | panic = "abort" 8 | -------------------------------------------------------------------------------- /examples/secp256K1/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | #![no_std] 3 | 4 | pub use secp256k1::*; 5 | pub use secp256k1_sys::types::AlignedType; 6 | -------------------------------------------------------------------------------- /examples/dalek/checkct/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["driver"] 3 | resolver = "2" 4 | 5 | [profile.release] 6 | debug = true 7 | panic = "abort" 8 | -------------------------------------------------------------------------------- /examples/memcmp/checkct/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["driver"] 3 | resolver = "2" 4 | 5 | [profile.release] 6 | debug = true 7 | panic = "abort" 8 | -------------------------------------------------------------------------------- /tests/subtle_eq/checkct/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["driver"] 3 | resolver = "2" 4 | 5 | [profile.release] 6 | debug = true 7 | panic = "abort" 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "examples/masked_aes/better_cortexm"] 2 | path = examples/masked_aes/better_cortexm 3 | url = https://github.com/NicsTr/better_cortexm 4 | -------------------------------------------------------------------------------- /examples/chachapoly/checkct/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["driver"] 3 | resolver = "2" 4 | 5 | [profile.release] 6 | debug = true 7 | panic = "abort" 8 | -------------------------------------------------------------------------------- /examples/masked_aes/checkct/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["driver"] 3 | resolver = "2" 4 | 5 | [profile.release] 6 | debug = true 7 | panic = "abort" 8 | -------------------------------------------------------------------------------- /examples/secp256K1/checkct/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["driver"] 3 | resolver = "2" 4 | 5 | [profile.release] 6 | debug = true 7 | panic = "abort" 8 | -------------------------------------------------------------------------------- /tests/vulnerable_eq/checkct/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["driver"] 3 | resolver = "2" 4 | 5 | [profile.release] 6 | debug = true 7 | panic = "abort" 8 | -------------------------------------------------------------------------------- /examples/masked_aes/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "masked_aes" 3 | version = "0.1.0" 4 | publish = false 5 | edition = "2021" 6 | 7 | [build-dependencies] 8 | cc = "1.0" 9 | -------------------------------------------------------------------------------- /examples/masked_aes/checkct/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" 3 | targets = ["thumbv7em-none-eabihf"] 4 | profile = "minimal" 5 | components = ["rustfmt", "rust-src"] 6 | -------------------------------------------------------------------------------- /tests/subtle_eq/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "subtle_eq" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | subtle = { version = "2.5.0", default-features = false } 8 | -------------------------------------------------------------------------------- /examples/secp256K1/checkct/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" 3 | targets = ["x86_64-unknown-linux-gnu"] 4 | profile = "minimal" 5 | components = ["rustfmt", "rust-src"] 6 | -------------------------------------------------------------------------------- /examples/dalek/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dalek" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2021" 6 | 7 | [dependencies] 8 | x25519-dalek = { version = "2.0.0", default-features = false } -------------------------------------------------------------------------------- /template/driver/src/driver.rs: -------------------------------------------------------------------------------- 1 | use crate::rng::{CryptoRng, PrivateRng, PublicRng, RngCore}; 2 | use checkct_macros::checkct; 3 | 4 | #[checkct] 5 | pub fn checkct() { 6 | // USER CODE GOES HERE 7 | } 8 | -------------------------------------------------------------------------------- /examples/memcmp/checkct/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" 3 | targets = ["thumbv7em-none-eabihf", "riscv32imac-unknown-none-elf"] 4 | profile = "minimal" 5 | components = ["rustfmt", "rust-src"] 6 | -------------------------------------------------------------------------------- /examples/chachapoly/checkct/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" 3 | targets = ["thumbv7em-none-eabihf", "riscv32imac-unknown-none-elf"] 4 | profile = "minimal" 5 | components = ["rustfmt", "rust-src"] 6 | -------------------------------------------------------------------------------- /template/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" 3 | targets = ["thumbv7em-none-eabihf", "riscv32imac-unknown-none-elf", "x86_64-unknown-linux-gnu"] 4 | profile = "minimal" 5 | components = ["rustfmt", "rust-src"] 6 | -------------------------------------------------------------------------------- /examples/dalek/checkct/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" 3 | targets = ["thumbv7em-none-eabihf", "riscv32imac-unknown-none-elf", "x86_64-unknown-linux-gnu"] 4 | profile = "minimal" 5 | components = ["rustfmt", "rust-src"] 6 | -------------------------------------------------------------------------------- /tests/subtle_eq/checkct/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" 3 | targets = ["thumbv7em-none-eabihf", "riscv32imac-unknown-none-elf", "x86_64-unknown-linux-gnu"] 4 | profile = "minimal" 5 | components = ["rustfmt", "rust-src"] 6 | -------------------------------------------------------------------------------- /tests/vulnerable_eq/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "vulnerable_eq" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /tests/vulnerable_eq/checkct/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" 3 | targets = ["thumbv7em-none-eabihf", "riscv32imac-unknown-none-elf", "x86_64-unknown-linux-gnu"] 4 | profile = "minimal" 5 | components = ["rustfmt", "rust-src"] 6 | -------------------------------------------------------------------------------- /examples/memcmp/checkct/driver/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "driver" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2021" 6 | 7 | [dependencies] 8 | rand_core = "0.6.4" 9 | checkct_macros = { path = "../../../../checkct_macros" } 10 | -------------------------------------------------------------------------------- /examples/secp256K1/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "secp256K1" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | secp256k1 = { version = "0.29.0", default-features = false } 8 | secp256k1-sys = { version = "0.10.0", default-features = false } 9 | -------------------------------------------------------------------------------- /tests/vulnerable_eq/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | pub fn eq(left: &[u8], right: &[u8]) -> bool { 4 | for (l, r) in left.iter().zip(right.iter()) { 5 | if l != r { 6 | return false; 7 | } 8 | } 9 | 10 | true 11 | } 12 | -------------------------------------------------------------------------------- /examples/chachapoly/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chachapoly" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2021" 6 | 7 | [dependencies] 8 | chacha20poly1305 = { version = "0.10.1", default-features = false, features = ["rand_core", "heapless", "reduced-round"] } 9 | -------------------------------------------------------------------------------- /template/driver/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "{name}" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2021" 6 | 7 | [dependencies] 8 | rand_core = "0.6.4" 9 | checkct_macros = {{ path = "{checkct_macros_crate_path}" }} 10 | {lib_name} = {{ path = "../.." }} 11 | -------------------------------------------------------------------------------- /tests/subtle_eq/checkct/driver/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "driver" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2021" 6 | 7 | [dependencies] 8 | rand_core = "0.6.4" 9 | checkct_macros = { path = "../../../../checkct_macros" } 10 | subtle_eq = { path = "../.." } 11 | -------------------------------------------------------------------------------- /examples/chachapoly/checkct/driver/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "driver" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2021" 6 | 7 | [dependencies] 8 | rand_core = "0.6.4" 9 | checkct_macros = { path = "../../../../checkct_macros" } 10 | chachapoly = { path = "../.." } 11 | -------------------------------------------------------------------------------- /tests/vulnerable_eq/checkct/driver/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "driver" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2021" 6 | 7 | [dependencies] 8 | rand_core = "0.6.4" 9 | checkct_macros = { path = "../../../../checkct_macros" } 10 | vulnerable_eq = { path = "../.." } 11 | -------------------------------------------------------------------------------- /examples/dalek/checkct/driver/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "driver" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2021" 6 | 7 | [dependencies] 8 | rand_core = "0.6.4" 9 | checkct_macros = { path = "../../../../checkct_macros" } 10 | 11 | [dependencies.dalek] 12 | path = "../.." 13 | -------------------------------------------------------------------------------- /examples/masked_aes/checkct/driver/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "driver" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2021" 6 | 7 | [dependencies] 8 | rand_core = "0.6.4" 9 | checkct_macros = { path = "../../../../checkct_macros" } 10 | 11 | [dependencies.masked_aes] 12 | path = "../.." 13 | -------------------------------------------------------------------------------- /examples/secp256K1/checkct/driver/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "driver" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2021" 6 | 7 | [dependencies] 8 | rand_core = "0.6.4" 9 | checkct_macros = { path = "../../../../checkct_macros" } 10 | 11 | [dependencies.secp256K1] 12 | path = "../.." 13 | -------------------------------------------------------------------------------- /checkct_macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "checkct_macros" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | proc-macro = true 8 | 9 | [dependencies] 10 | proc-macro2 = "1.0.86" 11 | quote = "1.0.37" 12 | syn = { version = "2.0.77", features = ["full"] } 13 | 14 | [dev-dependencies] 15 | rand_core = "0.6.4" 16 | -------------------------------------------------------------------------------- /examples/masked_aes/checkct/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = ["thumbv7em-none-eabihf"] 3 | 4 | [target.'cfg(target_os = "linux")'] 5 | rustflags = ["-C", "link-arg=-nostartfiles"] 6 | 7 | [unstable] 8 | unstable-options = true 9 | build-std = ["core", "panic_abort"] 10 | build-std-features = ["panic_immediate_abort", "compiler-builtins-mem"] 11 | -------------------------------------------------------------------------------- /examples/secp256K1/checkct/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = ["x86_64-unknown-linux-gnu"] 3 | 4 | [target.'cfg(target_os = "linux")'] 5 | rustflags = ["-C", "link-arg=-nostartfiles"] 6 | 7 | [unstable] 8 | unstable-options = true 9 | build-std = ["core", "panic_abort"] 10 | build-std-features = ["panic_immediate_abort", "compiler-builtins-mem"] 11 | -------------------------------------------------------------------------------- /template/driver/src/main.rs: -------------------------------------------------------------------------------- 1 | //----- AUTOGENERATED BY CARGO-CHECKCT: DO NOT MODIFY ----- 2 | // 3 | #![no_std] 4 | #![no_main] 5 | 6 | mod driver; 7 | mod rng; 8 | 9 | #[no_mangle] 10 | pub extern "C" fn _start() -> ! { 11 | panic!() 12 | } 13 | 14 | #[panic_handler] 15 | fn panic(_info: &core::panic::PanicInfo) -> ! { 16 | loop {} 17 | } 18 | -------------------------------------------------------------------------------- /examples/dalek/checkct/driver/src/main.rs: -------------------------------------------------------------------------------- 1 | //----- AUTOGENERATED BY CARGO-CHECKCT: DO NOT MODIFY ----- 2 | // 3 | #![no_std] 4 | #![no_main] 5 | 6 | mod driver; 7 | mod rng; 8 | 9 | #[no_mangle] 10 | pub extern "C" fn _start() -> ! { 11 | panic!() 12 | } 13 | 14 | #[panic_handler] 15 | fn panic(_info: &core::panic::PanicInfo) -> ! { 16 | loop {} 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.DS_Store 2 | /tests/vulnerable_eq/checkct/target 3 | /tests/subtle_eq/checkct/target 4 | /examples/dalek/checkct/target 5 | /examples/chachapoly/checkct/target 6 | /examples/masked_aes/checkct/target 7 | /examples/memcmp/checkct/target 8 | /examples/secp256K1/checkct/target 9 | /unisim_archisec 10 | /binsec 11 | 12 | # Added by cargo 13 | 14 | /target 15 | -------------------------------------------------------------------------------- /examples/chachapoly/checkct/driver/src/main.rs: -------------------------------------------------------------------------------- 1 | //----- AUTOGENERATED BY CARGO-CHECKCT: DO NOT MODIFY ----- 2 | // 3 | #![no_std] 4 | #![no_main] 5 | 6 | mod driver; 7 | mod rng; 8 | 9 | #[no_mangle] 10 | pub extern "C" fn _start() -> ! { 11 | panic!() 12 | } 13 | 14 | #[panic_handler] 15 | fn panic(_info: &core::panic::PanicInfo) -> ! { 16 | loop {} 17 | } 18 | -------------------------------------------------------------------------------- /examples/masked_aes/checkct/driver/src/main.rs: -------------------------------------------------------------------------------- 1 | //----- AUTOGENERATED BY CARGO-CHECKCT: DO NOT MODIFY ----- 2 | // 3 | #![no_std] 4 | #![no_main] 5 | 6 | mod driver; 7 | mod rng; 8 | 9 | #[no_mangle] 10 | pub extern "C" fn _start() -> ! { 11 | panic!() 12 | } 13 | 14 | #[panic_handler] 15 | fn panic(_info: &core::panic::PanicInfo) -> ! { 16 | loop {} 17 | } 18 | -------------------------------------------------------------------------------- /examples/secp256K1/checkct/driver/src/main.rs: -------------------------------------------------------------------------------- 1 | //----- AUTOGENERATED BY CARGO-CHECKCT: DO NOT MODIFY ----- 2 | // 3 | #![no_std] 4 | #![no_main] 5 | 6 | mod driver; 7 | mod rng; 8 | 9 | #[no_mangle] 10 | pub extern "C" fn _start() -> ! { 11 | panic!() 12 | } 13 | 14 | #[panic_handler] 15 | fn panic(_info: &core::panic::PanicInfo) -> ! { 16 | loop {} 17 | } 18 | -------------------------------------------------------------------------------- /tests/subtle_eq/checkct/driver/src/main.rs: -------------------------------------------------------------------------------- 1 | //----- AUTOGENERATED BY CARGO-CHECKCT: DO NOT MODIFY ----- 2 | // 3 | #![no_std] 4 | #![no_main] 5 | 6 | mod driver; 7 | mod rng; 8 | 9 | #[no_mangle] 10 | pub extern "C" fn _start() -> ! { 11 | panic!() 12 | } 13 | 14 | #[panic_handler] 15 | fn panic(_info: &core::panic::PanicInfo) -> ! { 16 | loop {} 17 | } 18 | -------------------------------------------------------------------------------- /tests/vulnerable_eq/checkct/driver/src/main.rs: -------------------------------------------------------------------------------- 1 | //----- AUTOGENERATED BY CARGO-CHECKCT: DO NOT MODIFY ----- 2 | // 3 | #![no_std] 4 | #![no_main] 5 | 6 | mod driver; 7 | mod rng; 8 | 9 | #[no_mangle] 10 | pub extern "C" fn _start() -> ! { 11 | panic!() 12 | } 13 | 14 | #[panic_handler] 15 | fn panic(_info: &core::panic::PanicInfo) -> ! { 16 | loop {} 17 | } 18 | -------------------------------------------------------------------------------- /examples/chachapoly/checkct/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = ["thumbv7em-none-eabihf", "riscv32imac-unknown-none-elf"] 3 | 4 | [target.'cfg(target_os = "linux")'] 5 | rustflags = ["-C", "link-arg=-nostartfiles"] 6 | 7 | [unstable] 8 | unstable-options = true 9 | build-std = ["core", "panic_abort"] 10 | build-std-features = ["panic_immediate_abort", "compiler-builtins-mem"] 11 | -------------------------------------------------------------------------------- /examples/memcmp/checkct/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = ["thumbv7em-none-eabihf", "riscv32imac-unknown-none-elf"] 3 | 4 | [target.'cfg(target_os = "linux")'] 5 | rustflags = ["-C", "link-arg=-nostartfiles"] 6 | 7 | [unstable] 8 | unstable-options = true 9 | build-std = ["core", "panic_abort"] 10 | build-std-features = ["panic_immediate_abort", "compiler-builtins-mem"] 11 | -------------------------------------------------------------------------------- /template/target/driver.binsec: -------------------------------------------------------------------------------- 1 | load sections {sections} from file 2 | starting from <{entrypoint}> 3 | with concrete stack pointer 4 | {lr} := {ret} 5 | replace <__checkct_private_rand>{thumb} () by 6 | res<{size}> := secret 7 | return res 8 | end 9 | replace <__checkct_public_rand>{thumb} () by 10 | res<{size}> := nondet 11 | return res 12 | end 13 | halt at {ret} 14 | explore all 15 | -------------------------------------------------------------------------------- /examples/dalek/checkct/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = ["thumbv7em-none-eabihf", "riscv32imac-unknown-none-elf", "x86_64-unknown-linux-gnu"] 3 | 4 | [target.'cfg(target_os = "linux")'] 5 | rustflags = ["-C", "link-arg=-nostartfiles"] 6 | 7 | [unstable] 8 | unstable-options = true 9 | build-std = ["core", "panic_abort"] 10 | build-std-features = ["panic_immediate_abort", "compiler-builtins-mem"] 11 | -------------------------------------------------------------------------------- /template/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = ["thumbv7em-none-eabihf", "riscv32imac-unknown-none-elf", "x86_64-unknown-linux-gnu"] 3 | 4 | [target.'cfg(target_os = "linux")'] 5 | rustflags = ["-C", "link-arg=-nostartfiles", "-C", "relocation-model=static"] 6 | 7 | [unstable] 8 | unstable-options = true 9 | build-std = ["core", "panic_abort"] 10 | build-std-features = ["panic_immediate_abort", "compiler-builtins-mem"] 11 | -------------------------------------------------------------------------------- /tests/vulnerable_eq/checkct/driver/src/driver.rs: -------------------------------------------------------------------------------- 1 | use crate::rng::{CryptoRng, PrivateRng, PublicRng, RngCore}; 2 | use checkct_macros::checkct; 3 | 4 | #[checkct] 5 | pub fn checkct() { 6 | use vulnerable_eq::eq; 7 | let mut left = [0u8; 32]; 8 | let mut right = [0u8; 32]; 9 | PrivateRng.fill_bytes(&mut left); 10 | PublicRng.fill_bytes(&mut right); 11 | 12 | eq(&left, &right);// USER CODE GOES HERE 13 | } 14 | -------------------------------------------------------------------------------- /tests/subtle_eq/checkct/driver/src/driver.rs: -------------------------------------------------------------------------------- 1 | use crate::rng::{CryptoRng, PrivateRng, PublicRng, RngCore}; 2 | use checkct_macros::checkct; 3 | 4 | #[checkct] 5 | pub fn checkct() { 6 | use subtle_eq::ConstantTimeEq; 7 | let mut left = [0u8; 8]; 8 | let mut right = [0x42u8; 8]; 9 | PrivateRng.fill_bytes(&mut left); 10 | PublicRng.fill_bytes(&mut right); 11 | 12 | left.ct_eq(&right);// USER CODE GOES HERE 13 | } 14 | -------------------------------------------------------------------------------- /tests/subtle_eq/checkct/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = ["thumbv7em-none-eabihf", "riscv32imac-unknown-none-elf", "x86_64-unknown-linux-gnu"] 3 | 4 | [target.'cfg(target_os = "linux")'] 5 | rustflags = ["-C", "link-arg=-nostartfiles", "-C", "relocation-model=static"] 6 | 7 | [unstable] 8 | unstable-options = true 9 | build-std = ["core", "panic_abort"] 10 | build-std-features = ["panic_immediate_abort", "compiler-builtins-mem"] 11 | -------------------------------------------------------------------------------- /tests/vulnerable_eq/checkct/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = ["thumbv7em-none-eabihf", "riscv32imac-unknown-none-elf", "x86_64-unknown-linux-gnu"] 3 | 4 | [target.'cfg(target_os = "linux")'] 5 | rustflags = ["-C", "link-arg=-nostartfiles", "-C", "relocation-model=static"] 6 | 7 | [unstable] 8 | unstable-options = true 9 | build-std = ["core", "panic_abort"] 10 | build-std-features = ["panic_immediate_abort", "compiler-builtins-mem"] 11 | -------------------------------------------------------------------------------- /tests/subtle_eq/checkct/driver/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = ["thumbv7em-none-eabihf", "riscv32im-unknown-none-elf", "x86_64-unknown-linux-gnu"] 3 | 4 | [target.'cfg(target_os = "linux")'] 5 | rustflags = ["-C", "link-arg=-nostartfiles"] 6 | 7 | [target.x86_64-unknown-linux-gnu] 8 | linker = "x86_64-unknown-linux-gnu-gcc" 9 | 10 | [unstable] 11 | unstable-options = true 12 | build-std = ["core", "panic_abort"] 13 | build-std-features = ["panic_immediate_abort", "compiler-builtins-mem"] -------------------------------------------------------------------------------- /examples/masked_aes/checkct/driver/src/driver.rs: -------------------------------------------------------------------------------- 1 | use crate::rng::{CryptoRng, PrivateRng, PublicRng, RngCore}; 2 | use checkct_macros::checkct; 3 | 4 | #[checkct] 5 | pub fn checkct() { 6 | // USER CODE GOES HERE 7 | let mut key = [0u8; 16]; 8 | let mut block = [0u8; 16]; 9 | PrivateRng.fill_bytes(&mut key); 10 | PublicRng.fill_bytes(&mut block); 11 | let mut aes = masked_aes::MaskedAes::new(key, PrivateRng.next_u32()); 12 | core::hint::black_box(aes.encrypt(block)); 13 | } 14 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cargo-checkct" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | anyhow = "1.0.80" 10 | cargo-manifest = "0.19.1" 11 | clap = { version = "4.5.2", features = ["derive"] } 12 | goblin = "0.8.0" 13 | pathdiff = "0.2.1" 14 | toml = "0.8.11" 15 | which = "6.0.1" 16 | 17 | [dev-dependencies] 18 | assert_cmd = "2.0.14" 19 | 20 | [workspace] 21 | members = [ "checkct_macros", "examples/chachapoly", "examples/dalek", "examples/masked_aes", "examples/secp256K1" ] 22 | -------------------------------------------------------------------------------- /examples/dalek/checkct/driver/src/driver.rs: -------------------------------------------------------------------------------- 1 | use crate::rng::{CryptoRng, PrivateRng, PublicRng, RngCore}; 2 | use checkct_macros::checkct; 3 | 4 | #[checkct] 5 | pub fn checkct() { 6 | // USER CODE GOES HERE 7 | use dalek::{EphemeralSecret, PublicKey, SharedSecret}; 8 | let mut public_key_bytes = [0u8; 32]; 9 | PublicRng.fill_bytes(&mut public_key_bytes); 10 | 11 | let public = PublicKey::from(public_key_bytes); 12 | let ephemeral = EphemeralSecret::random_from_rng(PrivateRng); 13 | let shared_secret = ephemeral.diffie_hellman(&public); 14 | core::hint::black_box(shared_secret); 15 | } 16 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: lint 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | push: 7 | branches: [ main ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | RUSTFLAGS: -Dwarnings 12 | 13 | jobs: 14 | lint: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.3 18 | - name: rustup 19 | run: | 20 | rustup update --no-self-update nightly 21 | rustup component add --toolchain nightly rustfmt clippy 22 | rustup default nightly 23 | - name: fmt 24 | run: cargo fmt --all -- --check 25 | - name: clippy 26 | run: cargo clippy --verbose 27 | -------------------------------------------------------------------------------- /examples/secp256K1/checkct/driver/src/driver.rs: -------------------------------------------------------------------------------- 1 | use crate::rng::{CryptoRng, PrivateRng, PublicRng, RngCore}; 2 | use checkct_macros::checkct; 3 | 4 | #[checkct] 5 | pub fn checkct() { 6 | // USER CODE GOES HERE 7 | use secp256K1::{AlignedType, Message, PublicKey, Secp256k1, SecretKey}; 8 | 9 | let mut buf = [AlignedType::zeroed(); 512]; 10 | let Ok(secp) = Secp256k1::preallocated_new(&mut buf) else { 11 | return; 12 | }; 13 | 14 | let mut secret_key = [0u8; 32]; 15 | PrivateRng.fill_bytes(&mut secret_key); 16 | let Ok(secret_key) = SecretKey::from_slice(&secret_key) else { 17 | return; 18 | }; 19 | 20 | let public_key = PublicKey::from_secret_key(&secp, &secret_key); 21 | let mut message = [0u8; 32]; 22 | PublicRng.fill_bytes(&mut message); 23 | let Ok(message) = Message::from_digest_slice(&message) else { 24 | return; 25 | }; 26 | 27 | let sig = secp.sign_ecdsa(&message, &secret_key); 28 | core::hint::black_box(sig); 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Containerfile: -------------------------------------------------------------------------------- 1 | FROM docker.io/library/rust:slim-bullseye 2 | 3 | # Install dependencies and Rust toolchains 4 | RUN export DEBIAN_FRONTEND=noninteractive && \ 5 | apt-get update && \ 6 | apt-get install -y --no-install-recommends --no-install-suggests git libgmp-dev gcc g++ opam pkgconf && \ 7 | apt-get clean && \ 8 | rustup target add thumbv7em-none-eabihf && \ 9 | rustup target add riscv32imac-unknown-none-elf && \ 10 | opam init --disable-sandboxing -y && \ 11 | opam install -y dune dune-site menhir grain_dypgen ocamlgraph zarith toml bitwuzla && \ 12 | echo 'eval $(opam env)' >> /root/.bashrc 13 | 14 | # Install binsec 15 | RUN git clone --depth 1 --branch 0.0.10 https://github.com/binsec/unisim_archisec /opt/unisim_archisec && \ 16 | (cd /opt/unisim_archisec && eval $(opam env) && dune build @install --release && dune install) && \ 17 | git clone --depth 1 --branch 0.10.0 https://github.com/binsec/binsec /opt/binsec && \ 18 | (cd /opt/binsec && eval $(opam env) && dune build @install --release && dune install) 19 | 20 | # Copy cargo-checkct to /src 21 | COPY . /src/ 22 | WORKDIR /src 23 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | push: 7 | branches: [ main ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | linux-amd64: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.3 17 | - name: rustup 18 | run: | 19 | rustup update --no-self-update nightly 20 | rustup component add --toolchain nightly rust-src 21 | rustup default nightly 22 | - name: install binsec 23 | run: | 24 | sudo apt-get update 25 | sudo apt-get install -y libgmp-dev gcc g++ opam 26 | opam init -y 27 | opam install -y dune dune-site menhir grain_dypgen ocamlgraph zarith toml bitwuzla 28 | eval $(opam env) 29 | git clone --branch 0.10.0 https://github.com/binsec/binsec 30 | git clone --branch 0.0.10 https://github.com/binsec/unisim_archisec 31 | pushd unisim_archisec && dune build @install && dune install && popd 32 | pushd binsec && dune build @install && dune install && popd 33 | - name: run tests 34 | run: eval $(opam env) && cargo test 35 | -------------------------------------------------------------------------------- /examples/masked_aes/build.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Ledger 2 | // 3 | // SPDX-License-Identifier: MIT OR Apache-2.0 4 | 5 | fn main() { 6 | let dir = std::path::Path::new("better_cortexm"); 7 | 8 | cc::Build::new() 9 | .file(dir.join("src").join("3").join("bitslicing.s")) 10 | .file(dir.join("src").join("3").join("masked_and.s")) 11 | .file(dir.join("src").join("3").join("masked_xor.s")) 12 | .file(dir.join("src").join("3").join("masked_mixcolumns.s")) 13 | .file(dir.join("src").join("3").join("masked_shiftrows.s")) 14 | .file(dir.join("src").join("3").join("masked_rotword_xorcol.s")) 15 | .file(dir.join("src").join("3").join("masked_sbox_lin.s")) 16 | .file(dir.join("src").join("xoshiro.c")) 17 | .file(dir.join("src").join("masking.c")) 18 | .file(dir.join("src").join("masked_utils.c")) 19 | .file(dir.join("src").join("masked_aes.c")) 20 | .file(dir.join("src").join("masked_aes_sbox.c")) 21 | .file(dir.join("src").join("masked_aes_keyschedule.c")) 22 | .include(dir.join("headers")) 23 | .define("D", "3") 24 | .define("R", "5") 25 | .flag("-mcpu=cortex-m4") 26 | .compile("aes"); 27 | } 28 | -------------------------------------------------------------------------------- /tests/subtle_eq.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | 3 | use assert_cmd::Command; 4 | 5 | #[test] 6 | fn subtle() { 7 | Command::cargo_bin("cargo-checkct") 8 | .unwrap() 9 | .arg("init") 10 | .arg("--dir=tests/subtle_eq") 11 | .assert() 12 | .success(); 13 | 14 | let user_code = r#"use subtle_eq::ConstantTimeEq; 15 | let mut left = [0u8; 8]; 16 | let mut right = [0x42u8; 8]; 17 | PrivateRng.fill_bytes(&mut left); 18 | PublicRng.fill_bytes(&mut right); 19 | 20 | left.ct_eq(&right);"#; 21 | 22 | let driver_path = "tests/subtle_eq/checkct/driver/src/driver.rs"; 23 | let mut driver_file = fs::read_to_string(driver_path).unwrap(); 24 | let idx = driver_file.find("// USER CODE GOES HERE").unwrap(); 25 | driver_file.insert_str(idx, user_code); 26 | fs::write(driver_path, driver_file).unwrap(); 27 | 28 | let output = Command::cargo_bin("cargo-checkct") 29 | .unwrap() 30 | .arg("run") 31 | .arg("--dir=tests/subtle_eq") 32 | .arg("--timeout=60") 33 | .assert() 34 | .success(); 35 | 36 | let output = String::from_utf8_lossy(&output.get_output().stdout); 37 | println!("{output}"); 38 | assert!(!output.contains("INSECURE")); 39 | } 40 | -------------------------------------------------------------------------------- /tests/vulnerable_eq.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | 3 | use assert_cmd::Command; 4 | 5 | #[test] 6 | fn vulnerable() { 7 | Command::cargo_bin("cargo-checkct") 8 | .unwrap() 9 | .arg("init") 10 | .arg("--dir=tests/vulnerable_eq") 11 | .assert() 12 | .success(); 13 | 14 | let user_code = r#"use vulnerable_eq::eq; 15 | let mut left = [0u8; 32]; 16 | let mut right = [0u8; 32]; 17 | PrivateRng.fill_bytes(&mut left); 18 | PublicRng.fill_bytes(&mut right); 19 | 20 | eq(&left, &right);"#; 21 | 22 | let driver_path = "tests/vulnerable_eq/checkct/driver/src/driver.rs"; 23 | let mut driver_file = fs::read_to_string(driver_path).unwrap(); 24 | let idx = driver_file.find("// USER CODE GOES HERE").unwrap(); 25 | driver_file.insert_str(idx, user_code); 26 | fs::write(driver_path, driver_file).unwrap(); 27 | 28 | let output = Command::cargo_bin("cargo-checkct") 29 | .unwrap() 30 | .arg("run") 31 | .arg("--dir=tests/vulnerable_eq") 32 | .arg("--timeout=60") 33 | .assert() 34 | .failure(); 35 | 36 | let output = String::from_utf8_lossy(&output.get_output().stdout); 37 | println!("{output}"); 38 | assert!(output.contains("INSECURE")); 39 | } 40 | -------------------------------------------------------------------------------- /examples/memcmp/checkct/driver/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use checkct_macros::checkct; 5 | 6 | mod rng; 7 | 8 | use crate::rng::{CryptoRng, PrivateRng, PublicRng, RngCore}; 9 | 10 | pub fn memcmp(a: &[u8], b: &[u8]) -> bool { 11 | assert_eq!(a, b); 12 | 13 | for i in 0..a.len() { 14 | if a[i] != b[i] { 15 | return false; 16 | } 17 | } 18 | 19 | true 20 | } 21 | 22 | pub fn memcmp_maybe_ct(a: &[u8], b: &[u8]) -> bool { 23 | assert_eq!(a, b); 24 | 25 | let mut eq = true; 26 | for i in 0..a.len() { 27 | eq = eq && a[i] == b[i]; 28 | } 29 | 30 | eq 31 | } 32 | 33 | #[checkct] 34 | fn checkct_memcmp() { 35 | let mut a = [0u8; 128]; 36 | let mut b = [0u8; 128]; 37 | 38 | PrivateRng.fill_bytes(&mut a); 39 | PublicRng.fill_bytes(&mut b); 40 | 41 | let result = memcmp(&a, &b); 42 | core::hint::black_box(result); 43 | } 44 | 45 | #[checkct] 46 | fn checkct_memcmp_maybe_ct() { 47 | let mut a = [0u8; 128]; 48 | let mut b = [0u8; 128]; 49 | 50 | PrivateRng.fill_bytes(&mut a); 51 | PublicRng.fill_bytes(&mut b); 52 | 53 | let result = memcmp_maybe_ct(&a, &b); 54 | core::hint::black_box(result); 55 | } 56 | 57 | #[no_mangle] 58 | pub extern "C" fn _start() -> ! { 59 | panic!() 60 | } 61 | 62 | #[panic_handler] 63 | fn panic(_info: &core::panic::PanicInfo) -> ! { 64 | loop {} 65 | } 66 | -------------------------------------------------------------------------------- /examples/chachapoly/checkct/driver/src/driver.rs: -------------------------------------------------------------------------------- 1 | use crate::rng::{CryptoRng, PrivateRng, PublicRng, RngCore}; 2 | use checkct_macros::checkct; 3 | 4 | #[checkct] 5 | pub fn checkct_chacha20() { 6 | // USER CODE GOES HERE 7 | use chachapoly::{ 8 | aead::{heapless::Vec, AeadCore, AeadInPlace, KeyInit}, 9 | ChaCha20Poly1305, Nonce, 10 | }; 11 | 12 | let key = ChaCha20Poly1305::generate_key(&mut PrivateRng); 13 | let cipher = ChaCha20Poly1305::new(&key); 14 | let nonce = ChaCha20Poly1305::generate_nonce(&mut PublicRng); 15 | let mut buffer: Vec = Vec::new(); 16 | let mut msg = [0u8; 1008]; 17 | PrivateRng.fill_bytes(&mut msg); 18 | buffer.extend_from_slice(&msg); 19 | cipher.encrypt_in_place(&nonce, b"", &mut buffer).unwrap(); 20 | } 21 | 22 | #[checkct] 23 | pub fn checkct_chacha8() { 24 | // USER CODE GOES HERE 25 | use chachapoly::{ 26 | aead::{heapless::Vec, AeadCore, AeadInPlace, KeyInit}, 27 | ChaCha8Poly1305, Nonce, 28 | }; 29 | 30 | let key = ChaCha8Poly1305::generate_key(&mut PrivateRng); 31 | let cipher = ChaCha8Poly1305::new(&key); 32 | let nonce = ChaCha8Poly1305::generate_nonce(&mut PublicRng); 33 | let mut buffer: Vec = Vec::new(); 34 | let mut msg = [0u8; 1008]; 35 | PrivateRng.fill_bytes(&mut msg); 36 | buffer.extend_from_slice(&msg); 37 | cipher.encrypt_in_place(&nonce, b"", &mut buffer).unwrap(); 38 | } 39 | -------------------------------------------------------------------------------- /src/add.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Ledger 2 | // 3 | // SPDX-License-Identifier: MIT OR Apache-2.0 4 | 5 | use std::{fs, io::Write, path::Path}; 6 | 7 | use anyhow::{Result, bail}; 8 | 9 | use crate::common::{create_driver, get_lib_name, get_workspace_members}; 10 | 11 | pub fn add_driver(path: &Path, name: &str) -> Result<()> { 12 | let name = name.to_owned(); 13 | let workspace_dir = path.join("checkct"); 14 | 15 | // First recover the library name and the members of the checkct workspace 16 | let lib_name = get_lib_name(path)?; 17 | println!("found library name: {lib_name}"); 18 | 19 | let mut members = get_workspace_members(&workspace_dir)?; 20 | if members.contains(&name) { 21 | bail!("Error: the checkct workspace already contains driver {name}") 22 | } 23 | 24 | // Then create the actual driver 25 | create_driver(&workspace_dir, &lib_name, &name)?; 26 | 27 | // Finally, add the newly created driver to the checkct workspace 28 | members.push(name); 29 | let mut cargo_file = fs::File::create(workspace_dir.join("Cargo.toml"))?; 30 | cargo_file.write_all( 31 | format!( 32 | include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/template/Cargo.toml")), 33 | members = members 34 | .into_iter() 35 | .map(|s| format!("\"{s}\"")) 36 | .collect::>() 37 | .join(", ") 38 | ) 39 | .as_bytes(), 40 | )?; 41 | 42 | Ok(()) 43 | } 44 | -------------------------------------------------------------------------------- /examples/memcmp/checkct/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "checkct_macros" 7 | version = "0.1.0" 8 | dependencies = [ 9 | "proc-macro2", 10 | "quote", 11 | "syn", 12 | ] 13 | 14 | [[package]] 15 | name = "driver" 16 | version = "0.0.0" 17 | dependencies = [ 18 | "checkct_macros", 19 | "rand_core", 20 | ] 21 | 22 | [[package]] 23 | name = "proc-macro2" 24 | version = "1.0.86" 25 | source = "registry+https://github.com/rust-lang/crates.io-index" 26 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 27 | dependencies = [ 28 | "unicode-ident", 29 | ] 30 | 31 | [[package]] 32 | name = "quote" 33 | version = "1.0.37" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 36 | dependencies = [ 37 | "proc-macro2", 38 | ] 39 | 40 | [[package]] 41 | name = "rand_core" 42 | version = "0.6.4" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 45 | 46 | [[package]] 47 | name = "syn" 48 | version = "2.0.77" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" 51 | dependencies = [ 52 | "proc-macro2", 53 | "quote", 54 | "unicode-ident", 55 | ] 56 | 57 | [[package]] 58 | name = "unicode-ident" 59 | version = "1.0.12" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 62 | -------------------------------------------------------------------------------- /tests/vulnerable_eq/checkct/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "checkct_macros" 7 | version = "0.1.0" 8 | dependencies = [ 9 | "proc-macro2", 10 | "quote", 11 | "syn", 12 | ] 13 | 14 | [[package]] 15 | name = "driver" 16 | version = "0.0.0" 17 | dependencies = [ 18 | "checkct_macros", 19 | "rand_core", 20 | "vulnerable_eq", 21 | ] 22 | 23 | [[package]] 24 | name = "proc-macro2" 25 | version = "1.0.94" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" 28 | dependencies = [ 29 | "unicode-ident", 30 | ] 31 | 32 | [[package]] 33 | name = "quote" 34 | version = "1.0.40" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 37 | dependencies = [ 38 | "proc-macro2", 39 | ] 40 | 41 | [[package]] 42 | name = "rand_core" 43 | version = "0.6.4" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 46 | 47 | [[package]] 48 | name = "syn" 49 | version = "2.0.100" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" 52 | dependencies = [ 53 | "proc-macro2", 54 | "quote", 55 | "unicode-ident", 56 | ] 57 | 58 | [[package]] 59 | name = "unicode-ident" 60 | version = "1.0.18" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 63 | 64 | [[package]] 65 | name = "vulnerable_eq" 66 | version = "0.1.0" 67 | -------------------------------------------------------------------------------- /src/init.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Ledger 2 | // 3 | // SPDX-License-Identifier: MIT OR Apache-2.0 4 | 5 | use std::{fs, io::Write, path::Path}; 6 | 7 | use anyhow::Result; 8 | 9 | use crate::common::{create_driver, get_lib_name}; 10 | 11 | pub fn init_workspace(path: &Path, name: &str) -> Result<()> { 12 | // First of all, we need to check that the designated path is a proper cargo lib workspace, 13 | // and recover the name of the crate 14 | let lib_name = get_lib_name(path)?; 15 | println!("found library name: {lib_name}"); 16 | 17 | // The workspace directory name is hardcoded to /checkct 18 | let workspace_dir = path.join("checkct"); 19 | fs::create_dir_all(workspace_dir.join(".cargo"))?; 20 | 21 | // Create the rust-toolchain.toml file 22 | let mut toolchain_file = fs::File::create(workspace_dir.join("rust-toolchain.toml"))?; 23 | toolchain_file.write_all( 24 | include_str!(concat!( 25 | env!("CARGO_MANIFEST_DIR"), 26 | "/template/rust-toolchain.toml" 27 | )) 28 | .as_bytes(), 29 | )?; 30 | 31 | // Create the config.toml file 32 | let mut config_file = fs::File::create(workspace_dir.join(".cargo").join("config.toml"))?; 33 | config_file.write_all( 34 | include_str!(concat!( 35 | env!("CARGO_MANIFEST_DIR"), 36 | "/template/.cargo/config.toml" 37 | )) 38 | .as_bytes(), 39 | )?; 40 | 41 | // Create the workspace Cargo.toml file 42 | let mut cargo_file = fs::File::create(workspace_dir.join("Cargo.toml"))?; 43 | cargo_file.write_all( 44 | format!( 45 | include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/template/Cargo.toml")), 46 | members = format_args!("\"{name}\""), 47 | ) 48 | .as_bytes(), 49 | )?; 50 | 51 | create_driver(&workspace_dir, &lib_name, name)?; 52 | 53 | Ok(()) 54 | } 55 | -------------------------------------------------------------------------------- /examples/masked_aes/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Ledger 2 | // 3 | // SPDX-License-Identifier: MIT OR Apache-2.0 4 | 5 | #![no_std] 6 | 7 | use core::ffi::c_int; 8 | 9 | extern "C" { 10 | fn masked_aes_encrypt128( 11 | state: *mut u16, 12 | rkeys: *mut u16, 13 | rng_fill: unsafe extern "C" fn(*mut u8, c_int), 14 | ); 15 | 16 | fn masked_aes_keyschedule128( 17 | key: *mut u16, 18 | rkeys: *mut u16, 19 | rng_fill: unsafe extern "C" fn(*mut u8, c_int), 20 | ); 21 | 22 | fn mask_bitslice_state( 23 | state: *mut u8, 24 | masked_bs_state: *mut u16, 25 | rng_fill: unsafe extern "C" fn(*mut u8, c_int), 26 | ); 27 | 28 | fn unbitslice_unmask_state(masked_bs_state: *mut u16, state: *mut u8); 29 | 30 | fn prng_init(seed: c_int); 31 | 32 | fn prng_fill(dst: *mut u8, size: c_int); 33 | } 34 | 35 | pub struct MaskedAes { 36 | key: [u8; 16], 37 | } 38 | 39 | impl MaskedAes { 40 | pub fn new(key: [u8; 16], seed: u32) -> Self { 41 | unsafe { 42 | prng_init(seed as i32); 43 | } 44 | Self { key } 45 | } 46 | 47 | pub fn encrypt(&mut self, block: [u8; 16]) -> [u8; 16] { 48 | let mut state = block.clone(); 49 | let mut masked_bs_state = [0u16; 4 * 8]; 50 | let mut masked_bs_key = [0u16; 4 * 8]; 51 | let mut rkeys = [0u16; 4 * 8 * 11]; 52 | 53 | unsafe { 54 | mask_bitslice_state(state.as_mut_ptr(), masked_bs_state.as_mut_ptr(), prng_fill); 55 | mask_bitslice_state(self.key.as_mut_ptr(), masked_bs_key.as_mut_ptr(), prng_fill); 56 | masked_aes_keyschedule128(masked_bs_key.as_mut_ptr(), rkeys.as_mut_ptr(), prng_fill); 57 | masked_aes_encrypt128(masked_bs_state.as_mut_ptr(), rkeys.as_mut_ptr(), prng_fill); 58 | unbitslice_unmask_state(masked_bs_state.as_mut_ptr(), state.as_mut_ptr()); 59 | } 60 | 61 | state 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /examples/masked_aes/checkct/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "cc" 7 | version = "1.0.90" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" 10 | 11 | [[package]] 12 | name = "checkct_macros" 13 | version = "0.1.0" 14 | dependencies = [ 15 | "proc-macro2", 16 | "quote", 17 | "syn", 18 | ] 19 | 20 | [[package]] 21 | name = "driver" 22 | version = "0.0.0" 23 | dependencies = [ 24 | "checkct_macros", 25 | "masked_aes", 26 | "rand_core", 27 | ] 28 | 29 | [[package]] 30 | name = "masked_aes" 31 | version = "0.1.0" 32 | dependencies = [ 33 | "cc", 34 | ] 35 | 36 | [[package]] 37 | name = "proc-macro2" 38 | version = "1.0.86" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 41 | dependencies = [ 42 | "unicode-ident", 43 | ] 44 | 45 | [[package]] 46 | name = "quote" 47 | version = "1.0.37" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 50 | dependencies = [ 51 | "proc-macro2", 52 | ] 53 | 54 | [[package]] 55 | name = "rand_core" 56 | version = "0.6.4" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 59 | 60 | [[package]] 61 | name = "syn" 62 | version = "2.0.77" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" 65 | dependencies = [ 66 | "proc-macro2", 67 | "quote", 68 | "unicode-ident", 69 | ] 70 | 71 | [[package]] 72 | name = "unicode-ident" 73 | version = "1.0.13" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" 76 | -------------------------------------------------------------------------------- /tests/subtle_eq/checkct/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "checkct_macros" 7 | version = "0.1.0" 8 | dependencies = [ 9 | "proc-macro2", 10 | "quote", 11 | "syn", 12 | ] 13 | 14 | [[package]] 15 | name = "driver" 16 | version = "0.0.0" 17 | dependencies = [ 18 | "checkct_macros", 19 | "rand_core", 20 | "subtle_eq", 21 | ] 22 | 23 | [[package]] 24 | name = "proc-macro2" 25 | version = "1.0.94" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" 28 | dependencies = [ 29 | "unicode-ident", 30 | ] 31 | 32 | [[package]] 33 | name = "quote" 34 | version = "1.0.40" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 37 | dependencies = [ 38 | "proc-macro2", 39 | ] 40 | 41 | [[package]] 42 | name = "rand_core" 43 | version = "0.6.4" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 46 | 47 | [[package]] 48 | name = "subtle" 49 | version = "2.5.0" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" 52 | 53 | [[package]] 54 | name = "subtle_eq" 55 | version = "0.1.0" 56 | dependencies = [ 57 | "subtle", 58 | ] 59 | 60 | [[package]] 61 | name = "syn" 62 | version = "2.0.100" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" 65 | dependencies = [ 66 | "proc-macro2", 67 | "quote", 68 | "unicode-ident", 69 | ] 70 | 71 | [[package]] 72 | name = "unicode-ident" 73 | version = "1.0.18" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 76 | -------------------------------------------------------------------------------- /template/driver/src/rng.rs: -------------------------------------------------------------------------------- 1 | //----- AUTOGENERATED BY CARGO-CHECKCT: DO NOT MODIFY ----- 2 | // 3 | #[no_mangle] 4 | #[inline(never)] 5 | pub fn __checkct_private_rand() -> u8 { 6 | unsafe { core::ptr::read_volatile(0xcafe as *const u8) } 7 | } 8 | 9 | #[no_mangle] 10 | #[inline(never)] 11 | pub fn __checkct_public_rand() -> u8 { 12 | unsafe { core::ptr::read_volatile(0xf00d as *const u8) } 13 | } 14 | 15 | pub use rand_core::{CryptoRng, RngCore}; 16 | 17 | pub struct PrivateRng; 18 | 19 | impl PrivateRng { 20 | pub const fn new() -> Self { 21 | Self 22 | } 23 | } 24 | 25 | impl RngCore for PrivateRng { 26 | fn next_u32(&mut self) -> u32 { 27 | (__checkct_private_rand() as u32) << 24 28 | | (__checkct_private_rand() as u32) << 16 29 | | (__checkct_private_rand() as u32) << 8 30 | | (__checkct_private_rand() as u32) 31 | } 32 | 33 | fn next_u64(&mut self) -> u64 { 34 | (self.next_u32() as u64) << 32 | (self.next_u32() as u64) 35 | } 36 | 37 | fn fill_bytes(&mut self, dest: &mut [u8]) { 38 | for d in dest { 39 | *d = __checkct_private_rand(); 40 | } 41 | } 42 | 43 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 44 | self.fill_bytes(dest); 45 | Ok(()) 46 | } 47 | } 48 | 49 | impl CryptoRng for PrivateRng {} 50 | 51 | pub struct PublicRng; 52 | 53 | impl PublicRng { 54 | pub const fn new() -> Self { 55 | Self 56 | } 57 | } 58 | 59 | impl RngCore for PublicRng { 60 | fn next_u32(&mut self) -> u32 { 61 | (__checkct_public_rand() as u32) << 24 62 | | (__checkct_public_rand() as u32) << 16 63 | | (__checkct_public_rand() as u32) << 8 64 | | (__checkct_public_rand() as u32) 65 | } 66 | 67 | fn next_u64(&mut self) -> u64 { 68 | (self.next_u32() as u64) << 32 | (self.next_u32() as u64) 69 | } 70 | 71 | fn fill_bytes(&mut self, dest: &mut [u8]) { 72 | for d in dest { 73 | *d = __checkct_public_rand(); 74 | } 75 | } 76 | 77 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 78 | self.fill_bytes(dest); 79 | Ok(()) 80 | } 81 | } 82 | 83 | impl CryptoRng for PublicRng {} 84 | -------------------------------------------------------------------------------- /examples/dalek/checkct/driver/src/rng.rs: -------------------------------------------------------------------------------- 1 | //----- AUTOGENERATED BY CARGO-CHECKCT: DO NOT MODIFY ----- 2 | // 3 | #[no_mangle] 4 | #[inline(never)] 5 | pub fn __checkct_private_rand() -> u8 { 6 | unsafe { core::ptr::read_volatile(0xcafe as *const u8) } 7 | } 8 | 9 | #[no_mangle] 10 | #[inline(never)] 11 | pub fn __checkct_public_rand() -> u8 { 12 | unsafe { core::ptr::read_volatile(0xf00d as *const u8) } 13 | } 14 | 15 | pub use rand_core::{CryptoRng, RngCore}; 16 | 17 | pub struct PrivateRng; 18 | 19 | impl PrivateRng { 20 | pub const fn new() -> Self { 21 | Self 22 | } 23 | } 24 | 25 | impl RngCore for PrivateRng { 26 | fn next_u32(&mut self) -> u32 { 27 | (__checkct_private_rand() as u32) << 24 28 | | (__checkct_private_rand() as u32) << 16 29 | | (__checkct_private_rand() as u32) << 8 30 | | (__checkct_private_rand() as u32) 31 | } 32 | 33 | fn next_u64(&mut self) -> u64 { 34 | (self.next_u32() as u64) << 32 | (self.next_u32() as u64) 35 | } 36 | 37 | fn fill_bytes(&mut self, dest: &mut [u8]) { 38 | for d in dest { 39 | *d = __checkct_private_rand(); 40 | } 41 | } 42 | 43 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 44 | self.fill_bytes(dest); 45 | Ok(()) 46 | } 47 | } 48 | 49 | impl CryptoRng for PrivateRng {} 50 | 51 | pub struct PublicRng; 52 | 53 | impl PublicRng { 54 | pub const fn new() -> Self { 55 | Self 56 | } 57 | } 58 | 59 | impl RngCore for PublicRng { 60 | fn next_u32(&mut self) -> u32 { 61 | (__checkct_public_rand() as u32) << 24 62 | | (__checkct_public_rand() as u32) << 16 63 | | (__checkct_public_rand() as u32) << 8 64 | | (__checkct_public_rand() as u32) 65 | } 66 | 67 | fn next_u64(&mut self) -> u64 { 68 | (self.next_u32() as u64) << 32 | (self.next_u32() as u64) 69 | } 70 | 71 | fn fill_bytes(&mut self, dest: &mut [u8]) { 72 | for d in dest { 73 | *d = __checkct_public_rand(); 74 | } 75 | } 76 | 77 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 78 | self.fill_bytes(dest); 79 | Ok(()) 80 | } 81 | } 82 | 83 | impl CryptoRng for PublicRng {} 84 | -------------------------------------------------------------------------------- /examples/memcmp/checkct/driver/src/rng.rs: -------------------------------------------------------------------------------- 1 | //----- AUTOGENERATED BY CARGO-CHECKCT: DO NOT MODIFY ----- 2 | // 3 | #[no_mangle] 4 | #[inline(never)] 5 | pub fn __checkct_private_rand() -> u8 { 6 | unsafe { core::ptr::read_volatile(0xcafe as *const u8) } 7 | } 8 | 9 | #[no_mangle] 10 | #[inline(never)] 11 | pub fn __checkct_public_rand() -> u8 { 12 | unsafe { core::ptr::read_volatile(0xf00d as *const u8) } 13 | } 14 | 15 | pub use rand_core::{CryptoRng, RngCore}; 16 | 17 | pub struct PrivateRng; 18 | 19 | impl PrivateRng { 20 | pub const fn new() -> Self { 21 | Self 22 | } 23 | } 24 | 25 | impl RngCore for PrivateRng { 26 | fn next_u32(&mut self) -> u32 { 27 | (__checkct_private_rand() as u32) << 24 28 | | (__checkct_private_rand() as u32) << 16 29 | | (__checkct_private_rand() as u32) << 8 30 | | (__checkct_private_rand() as u32) 31 | } 32 | 33 | fn next_u64(&mut self) -> u64 { 34 | (self.next_u32() as u64) << 32 | (self.next_u32() as u64) 35 | } 36 | 37 | fn fill_bytes(&mut self, dest: &mut [u8]) { 38 | for d in dest { 39 | *d = __checkct_private_rand(); 40 | } 41 | } 42 | 43 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 44 | self.fill_bytes(dest); 45 | Ok(()) 46 | } 47 | } 48 | 49 | impl CryptoRng for PrivateRng {} 50 | 51 | pub struct PublicRng; 52 | 53 | impl PublicRng { 54 | pub const fn new() -> Self { 55 | Self 56 | } 57 | } 58 | 59 | impl RngCore for PublicRng { 60 | fn next_u32(&mut self) -> u32 { 61 | (__checkct_public_rand() as u32) << 24 62 | | (__checkct_public_rand() as u32) << 16 63 | | (__checkct_public_rand() as u32) << 8 64 | | (__checkct_public_rand() as u32) 65 | } 66 | 67 | fn next_u64(&mut self) -> u64 { 68 | (self.next_u32() as u64) << 32 | (self.next_u32() as u64) 69 | } 70 | 71 | fn fill_bytes(&mut self, dest: &mut [u8]) { 72 | for d in dest { 73 | *d = __checkct_public_rand(); 74 | } 75 | } 76 | 77 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 78 | self.fill_bytes(dest); 79 | Ok(()) 80 | } 81 | } 82 | 83 | impl CryptoRng for PublicRng {} 84 | -------------------------------------------------------------------------------- /tests/subtle_eq/checkct/driver/src/rng.rs: -------------------------------------------------------------------------------- 1 | //----- AUTOGENERATED BY CARGO-CHECKCT: DO NOT MODIFY ----- 2 | // 3 | #[no_mangle] 4 | #[inline(never)] 5 | pub fn __checkct_private_rand() -> u8 { 6 | unsafe { core::ptr::read_volatile(0xcafe as *const u8) } 7 | } 8 | 9 | #[no_mangle] 10 | #[inline(never)] 11 | pub fn __checkct_public_rand() -> u8 { 12 | unsafe { core::ptr::read_volatile(0xf00d as *const u8) } 13 | } 14 | 15 | pub use rand_core::{CryptoRng, RngCore}; 16 | 17 | pub struct PrivateRng; 18 | 19 | impl PrivateRng { 20 | pub const fn new() -> Self { 21 | Self 22 | } 23 | } 24 | 25 | impl RngCore for PrivateRng { 26 | fn next_u32(&mut self) -> u32 { 27 | (__checkct_private_rand() as u32) << 24 28 | | (__checkct_private_rand() as u32) << 16 29 | | (__checkct_private_rand() as u32) << 8 30 | | (__checkct_private_rand() as u32) 31 | } 32 | 33 | fn next_u64(&mut self) -> u64 { 34 | (self.next_u32() as u64) << 32 | (self.next_u32() as u64) 35 | } 36 | 37 | fn fill_bytes(&mut self, dest: &mut [u8]) { 38 | for d in dest { 39 | *d = __checkct_private_rand(); 40 | } 41 | } 42 | 43 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 44 | self.fill_bytes(dest); 45 | Ok(()) 46 | } 47 | } 48 | 49 | impl CryptoRng for PrivateRng {} 50 | 51 | pub struct PublicRng; 52 | 53 | impl PublicRng { 54 | pub const fn new() -> Self { 55 | Self 56 | } 57 | } 58 | 59 | impl RngCore for PublicRng { 60 | fn next_u32(&mut self) -> u32 { 61 | (__checkct_public_rand() as u32) << 24 62 | | (__checkct_public_rand() as u32) << 16 63 | | (__checkct_public_rand() as u32) << 8 64 | | (__checkct_public_rand() as u32) 65 | } 66 | 67 | fn next_u64(&mut self) -> u64 { 68 | (self.next_u32() as u64) << 32 | (self.next_u32() as u64) 69 | } 70 | 71 | fn fill_bytes(&mut self, dest: &mut [u8]) { 72 | for d in dest { 73 | *d = __checkct_public_rand(); 74 | } 75 | } 76 | 77 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 78 | self.fill_bytes(dest); 79 | Ok(()) 80 | } 81 | } 82 | 83 | impl CryptoRng for PublicRng {} 84 | -------------------------------------------------------------------------------- /examples/chachapoly/checkct/driver/src/rng.rs: -------------------------------------------------------------------------------- 1 | //----- AUTOGENERATED BY CARGO-CHECKCT: DO NOT MODIFY ----- 2 | // 3 | #[no_mangle] 4 | #[inline(never)] 5 | pub fn __checkct_private_rand() -> u8 { 6 | unsafe { core::ptr::read_volatile(0xcafe as *const u8) } 7 | } 8 | 9 | #[no_mangle] 10 | #[inline(never)] 11 | pub fn __checkct_public_rand() -> u8 { 12 | unsafe { core::ptr::read_volatile(0xf00d as *const u8) } 13 | } 14 | 15 | pub use rand_core::{CryptoRng, RngCore}; 16 | 17 | pub struct PrivateRng; 18 | 19 | impl PrivateRng { 20 | pub const fn new() -> Self { 21 | Self 22 | } 23 | } 24 | 25 | impl RngCore for PrivateRng { 26 | fn next_u32(&mut self) -> u32 { 27 | (__checkct_private_rand() as u32) << 24 28 | | (__checkct_private_rand() as u32) << 16 29 | | (__checkct_private_rand() as u32) << 8 30 | | (__checkct_private_rand() as u32) 31 | } 32 | 33 | fn next_u64(&mut self) -> u64 { 34 | (self.next_u32() as u64) << 32 | (self.next_u32() as u64) 35 | } 36 | 37 | fn fill_bytes(&mut self, dest: &mut [u8]) { 38 | for d in dest { 39 | *d = __checkct_private_rand(); 40 | } 41 | } 42 | 43 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 44 | self.fill_bytes(dest); 45 | Ok(()) 46 | } 47 | } 48 | 49 | impl CryptoRng for PrivateRng {} 50 | 51 | pub struct PublicRng; 52 | 53 | impl PublicRng { 54 | pub const fn new() -> Self { 55 | Self 56 | } 57 | } 58 | 59 | impl RngCore for PublicRng { 60 | fn next_u32(&mut self) -> u32 { 61 | (__checkct_public_rand() as u32) << 24 62 | | (__checkct_public_rand() as u32) << 16 63 | | (__checkct_public_rand() as u32) << 8 64 | | (__checkct_public_rand() as u32) 65 | } 66 | 67 | fn next_u64(&mut self) -> u64 { 68 | (self.next_u32() as u64) << 32 | (self.next_u32() as u64) 69 | } 70 | 71 | fn fill_bytes(&mut self, dest: &mut [u8]) { 72 | for d in dest { 73 | *d = __checkct_public_rand(); 74 | } 75 | } 76 | 77 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 78 | self.fill_bytes(dest); 79 | Ok(()) 80 | } 81 | } 82 | 83 | impl CryptoRng for PublicRng {} 84 | -------------------------------------------------------------------------------- /examples/masked_aes/checkct/driver/src/rng.rs: -------------------------------------------------------------------------------- 1 | //----- AUTOGENERATED BY CARGO-CHECKCT: DO NOT MODIFY ----- 2 | // 3 | #[no_mangle] 4 | #[inline(never)] 5 | pub fn __checkct_private_rand() -> u8 { 6 | unsafe { core::ptr::read_volatile(0xcafe as *const u8) } 7 | } 8 | 9 | #[no_mangle] 10 | #[inline(never)] 11 | pub fn __checkct_public_rand() -> u8 { 12 | unsafe { core::ptr::read_volatile(0xf00d as *const u8) } 13 | } 14 | 15 | pub use rand_core::{CryptoRng, RngCore}; 16 | 17 | pub struct PrivateRng; 18 | 19 | impl PrivateRng { 20 | pub const fn new() -> Self { 21 | Self 22 | } 23 | } 24 | 25 | impl RngCore for PrivateRng { 26 | fn next_u32(&mut self) -> u32 { 27 | (__checkct_private_rand() as u32) << 24 28 | | (__checkct_private_rand() as u32) << 16 29 | | (__checkct_private_rand() as u32) << 8 30 | | (__checkct_private_rand() as u32) 31 | } 32 | 33 | fn next_u64(&mut self) -> u64 { 34 | (self.next_u32() as u64) << 32 | (self.next_u32() as u64) 35 | } 36 | 37 | fn fill_bytes(&mut self, dest: &mut [u8]) { 38 | for d in dest { 39 | *d = __checkct_private_rand(); 40 | } 41 | } 42 | 43 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 44 | self.fill_bytes(dest); 45 | Ok(()) 46 | } 47 | } 48 | 49 | impl CryptoRng for PrivateRng {} 50 | 51 | pub struct PublicRng; 52 | 53 | impl PublicRng { 54 | pub const fn new() -> Self { 55 | Self 56 | } 57 | } 58 | 59 | impl RngCore for PublicRng { 60 | fn next_u32(&mut self) -> u32 { 61 | (__checkct_public_rand() as u32) << 24 62 | | (__checkct_public_rand() as u32) << 16 63 | | (__checkct_public_rand() as u32) << 8 64 | | (__checkct_public_rand() as u32) 65 | } 66 | 67 | fn next_u64(&mut self) -> u64 { 68 | (self.next_u32() as u64) << 32 | (self.next_u32() as u64) 69 | } 70 | 71 | fn fill_bytes(&mut self, dest: &mut [u8]) { 72 | for d in dest { 73 | *d = __checkct_public_rand(); 74 | } 75 | } 76 | 77 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 78 | self.fill_bytes(dest); 79 | Ok(()) 80 | } 81 | } 82 | 83 | impl CryptoRng for PublicRng {} 84 | -------------------------------------------------------------------------------- /examples/secp256K1/checkct/driver/src/rng.rs: -------------------------------------------------------------------------------- 1 | //----- AUTOGENERATED BY CARGO-CHECKCT: DO NOT MODIFY ----- 2 | // 3 | #[no_mangle] 4 | #[inline(never)] 5 | pub fn __checkct_private_rand() -> u8 { 6 | unsafe { core::ptr::read_volatile(0xcafe as *const u8) } 7 | } 8 | 9 | #[no_mangle] 10 | #[inline(never)] 11 | pub fn __checkct_public_rand() -> u8 { 12 | unsafe { core::ptr::read_volatile(0xf00d as *const u8) } 13 | } 14 | 15 | pub use rand_core::{CryptoRng, RngCore}; 16 | 17 | pub struct PrivateRng; 18 | 19 | impl PrivateRng { 20 | pub const fn new() -> Self { 21 | Self 22 | } 23 | } 24 | 25 | impl RngCore for PrivateRng { 26 | fn next_u32(&mut self) -> u32 { 27 | (__checkct_private_rand() as u32) << 24 28 | | (__checkct_private_rand() as u32) << 16 29 | | (__checkct_private_rand() as u32) << 8 30 | | (__checkct_private_rand() as u32) 31 | } 32 | 33 | fn next_u64(&mut self) -> u64 { 34 | (self.next_u32() as u64) << 32 | (self.next_u32() as u64) 35 | } 36 | 37 | fn fill_bytes(&mut self, dest: &mut [u8]) { 38 | for d in dest { 39 | *d = __checkct_private_rand(); 40 | } 41 | } 42 | 43 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 44 | self.fill_bytes(dest); 45 | Ok(()) 46 | } 47 | } 48 | 49 | impl CryptoRng for PrivateRng {} 50 | 51 | pub struct PublicRng; 52 | 53 | impl PublicRng { 54 | pub const fn new() -> Self { 55 | Self 56 | } 57 | } 58 | 59 | impl RngCore for PublicRng { 60 | fn next_u32(&mut self) -> u32 { 61 | (__checkct_public_rand() as u32) << 24 62 | | (__checkct_public_rand() as u32) << 16 63 | | (__checkct_public_rand() as u32) << 8 64 | | (__checkct_public_rand() as u32) 65 | } 66 | 67 | fn next_u64(&mut self) -> u64 { 68 | (self.next_u32() as u64) << 32 | (self.next_u32() as u64) 69 | } 70 | 71 | fn fill_bytes(&mut self, dest: &mut [u8]) { 72 | for d in dest { 73 | *d = __checkct_public_rand(); 74 | } 75 | } 76 | 77 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 78 | self.fill_bytes(dest); 79 | Ok(()) 80 | } 81 | } 82 | 83 | impl CryptoRng for PublicRng {} 84 | -------------------------------------------------------------------------------- /tests/vulnerable_eq/checkct/driver/src/rng.rs: -------------------------------------------------------------------------------- 1 | //----- AUTOGENERATED BY CARGO-CHECKCT: DO NOT MODIFY ----- 2 | // 3 | #[no_mangle] 4 | #[inline(never)] 5 | pub fn __checkct_private_rand() -> u8 { 6 | unsafe { core::ptr::read_volatile(0xcafe as *const u8) } 7 | } 8 | 9 | #[no_mangle] 10 | #[inline(never)] 11 | pub fn __checkct_public_rand() -> u8 { 12 | unsafe { core::ptr::read_volatile(0xf00d as *const u8) } 13 | } 14 | 15 | pub use rand_core::{CryptoRng, RngCore}; 16 | 17 | pub struct PrivateRng; 18 | 19 | impl PrivateRng { 20 | pub const fn new() -> Self { 21 | Self 22 | } 23 | } 24 | 25 | impl RngCore for PrivateRng { 26 | fn next_u32(&mut self) -> u32 { 27 | (__checkct_private_rand() as u32) << 24 28 | | (__checkct_private_rand() as u32) << 16 29 | | (__checkct_private_rand() as u32) << 8 30 | | (__checkct_private_rand() as u32) 31 | } 32 | 33 | fn next_u64(&mut self) -> u64 { 34 | (self.next_u32() as u64) << 32 | (self.next_u32() as u64) 35 | } 36 | 37 | fn fill_bytes(&mut self, dest: &mut [u8]) { 38 | for d in dest { 39 | *d = __checkct_private_rand(); 40 | } 41 | } 42 | 43 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 44 | self.fill_bytes(dest); 45 | Ok(()) 46 | } 47 | } 48 | 49 | impl CryptoRng for PrivateRng {} 50 | 51 | pub struct PublicRng; 52 | 53 | impl PublicRng { 54 | pub const fn new() -> Self { 55 | Self 56 | } 57 | } 58 | 59 | impl RngCore for PublicRng { 60 | fn next_u32(&mut self) -> u32 { 61 | (__checkct_public_rand() as u32) << 24 62 | | (__checkct_public_rand() as u32) << 16 63 | | (__checkct_public_rand() as u32) << 8 64 | | (__checkct_public_rand() as u32) 65 | } 66 | 67 | fn next_u64(&mut self) -> u64 { 68 | (self.next_u32() as u64) << 32 | (self.next_u32() as u64) 69 | } 70 | 71 | fn fill_bytes(&mut self, dest: &mut [u8]) { 72 | for d in dest { 73 | *d = __checkct_public_rand(); 74 | } 75 | } 76 | 77 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 78 | self.fill_bytes(dest); 79 | Ok(()) 80 | } 81 | } 82 | 83 | impl CryptoRng for PublicRng {} 84 | -------------------------------------------------------------------------------- /checkct_macros/src/lib.rs: -------------------------------------------------------------------------------- 1 | use proc_macro::TokenStream; 2 | use proc_macro2::{Literal, Span}; 3 | use quote::quote; 4 | use syn::{ 5 | parse::{Parse, ParseStream}, 6 | parse_macro_input, Error, Ident, ItemFn, Result, Token, 7 | }; 8 | 9 | struct AttributeArgs { 10 | descriptor_link_section: Option, 11 | } 12 | 13 | impl Parse for AttributeArgs { 14 | fn parse(input: ParseStream) -> Result { 15 | if input.is_empty() { 16 | return Ok(Self { 17 | descriptor_link_section: None, 18 | }); 19 | } 20 | 21 | let arg_name: Ident = input.parse()?; 22 | if arg_name != "descriptor_link_section" { 23 | return Err(Error::new( 24 | arg_name.span(), 25 | "expected `descriptor_link_section`", 26 | )); 27 | } 28 | input.parse::()?; 29 | let descriptor_link_section: Literal = input.parse()?; 30 | 31 | Ok(Self { 32 | descriptor_link_section: Some(descriptor_link_section.to_string()), 33 | }) 34 | } 35 | } 36 | 37 | #[proc_macro_attribute] 38 | pub fn checkct(args: TokenStream, input: TokenStream) -> TokenStream { 39 | let args = parse_macro_input!(args as AttributeArgs); 40 | // By default the descriptor will be stored in the .note.checkct section 41 | let descriptor_link_section = Literal::string( 42 | args.descriptor_link_section 43 | .as_deref() 44 | .unwrap_or(".note.checkct"), 45 | ); 46 | 47 | let item_fn = parse_macro_input!(input as ItemFn); 48 | let name = &item_fn.sig.ident; 49 | 50 | let entrypoint_descriptor_name = Ident::new( 51 | &format!("__checkct_entrypoint_descriptor__{name}"), 52 | Span::call_site(), 53 | ); 54 | 55 | quote! { 56 | // This variable is used to prevent the compiler from removing the code of the entrypoint 57 | // function if it is unused. Moreover this variable name has a special format which allows 58 | // cargo-checkct to find it. 59 | // Make sure that the descriptor link section is kept by the linker. 60 | #[link_section = #descriptor_link_section] 61 | #[used] 62 | pub static #entrypoint_descriptor_name: fn() = #name; 63 | 64 | #item_fn 65 | } 66 | .into() 67 | } 68 | -------------------------------------------------------------------------------- /examples/secp256K1/checkct/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "cc" 7 | version = "1.0.91" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "1fd97381a8cc6493395a5afc4c691c1084b3768db713b73aa215217aa245d153" 10 | 11 | [[package]] 12 | name = "checkct_macros" 13 | version = "0.1.0" 14 | dependencies = [ 15 | "proc-macro2", 16 | "quote", 17 | "syn", 18 | ] 19 | 20 | [[package]] 21 | name = "driver" 22 | version = "0.0.0" 23 | dependencies = [ 24 | "checkct_macros", 25 | "rand_core", 26 | "secp256K1", 27 | ] 28 | 29 | [[package]] 30 | name = "proc-macro2" 31 | version = "1.0.86" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 34 | dependencies = [ 35 | "unicode-ident", 36 | ] 37 | 38 | [[package]] 39 | name = "quote" 40 | version = "1.0.37" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 43 | dependencies = [ 44 | "proc-macro2", 45 | ] 46 | 47 | [[package]] 48 | name = "rand_core" 49 | version = "0.6.4" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 52 | 53 | [[package]] 54 | name = "secp256K1" 55 | version = "0.1.0" 56 | dependencies = [ 57 | "secp256k1", 58 | "secp256k1-sys", 59 | ] 60 | 61 | [[package]] 62 | name = "secp256k1" 63 | version = "0.29.0" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" 66 | dependencies = [ 67 | "secp256k1-sys", 68 | ] 69 | 70 | [[package]] 71 | name = "secp256k1-sys" 72 | version = "0.10.0" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" 75 | dependencies = [ 76 | "cc", 77 | ] 78 | 79 | [[package]] 80 | name = "syn" 81 | version = "2.0.77" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" 84 | dependencies = [ 85 | "proc-macro2", 86 | "quote", 87 | "unicode-ident", 88 | ] 89 | 90 | [[package]] 91 | name = "unicode-ident" 92 | version = "1.0.13" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" 95 | -------------------------------------------------------------------------------- /checkct_macros/examples/attribute.rs: -------------------------------------------------------------------------------- 1 | use checkct_macros::checkct; 2 | 3 | fn memcmp(a: &[u8], b: &[u8]) -> bool { 4 | assert_eq!(a, b); 5 | 6 | for i in 0..a.len() { 7 | if a[i] != b[i] { 8 | return false; 9 | } 10 | } 11 | 12 | true 13 | } 14 | 15 | #[checkct] 16 | fn checkct_memcmp() { 17 | let mut a = [0u8; 128]; 18 | let mut b = [0u8; 128]; 19 | 20 | PrivateRng.fill_bytes(&mut a); 21 | PublicRng.fill_bytes(&mut b); 22 | 23 | let result = memcmp(&a, &b); 24 | core::hint::black_box(result); 25 | } 26 | 27 | #[checkct(descriptor_link_section = ".rodata")] 28 | fn checkct_memcmp2() { 29 | let mut a = [0u8; 128]; 30 | let mut b = [0u8; 128]; 31 | 32 | PrivateRng.fill_bytes(&mut a); 33 | PublicRng.fill_bytes(&mut b); 34 | 35 | let result = memcmp(&a, &b); 36 | core::hint::black_box(result); 37 | } 38 | 39 | fn main() {} 40 | 41 | #[no_mangle] 42 | #[inline(never)] 43 | pub fn __checkct_private_rand() -> u8 { 44 | unsafe { core::ptr::read_volatile(0xcafe as *const u8) } 45 | } 46 | 47 | #[no_mangle] 48 | #[inline(never)] 49 | pub fn __checkct_public_rand() -> u8 { 50 | unsafe { core::ptr::read_volatile(0xf00d as *const u8) } 51 | } 52 | 53 | pub use rand_core::{CryptoRng, RngCore}; 54 | 55 | pub struct PrivateRng; 56 | 57 | impl PrivateRng { 58 | pub const fn new() -> Self { 59 | Self 60 | } 61 | } 62 | 63 | impl RngCore for PrivateRng { 64 | fn next_u32(&mut self) -> u32 { 65 | (__checkct_private_rand() as u32) << 24 66 | | (__checkct_private_rand() as u32) << 16 67 | | (__checkct_private_rand() as u32) << 8 68 | | (__checkct_private_rand() as u32) 69 | } 70 | 71 | fn next_u64(&mut self) -> u64 { 72 | (self.next_u32() as u64) << 32 | (self.next_u32() as u64) 73 | } 74 | 75 | fn fill_bytes(&mut self, dest: &mut [u8]) { 76 | for d in dest { 77 | *d = __checkct_private_rand(); 78 | } 79 | } 80 | 81 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 82 | self.fill_bytes(dest); 83 | Ok(()) 84 | } 85 | } 86 | 87 | impl CryptoRng for PrivateRng {} 88 | 89 | pub struct PublicRng; 90 | 91 | impl PublicRng { 92 | pub const fn new() -> Self { 93 | Self 94 | } 95 | } 96 | 97 | impl RngCore for PublicRng { 98 | fn next_u32(&mut self) -> u32 { 99 | (__checkct_public_rand() as u32) << 24 100 | | (__checkct_public_rand() as u32) << 16 101 | | (__checkct_public_rand() as u32) << 8 102 | | (__checkct_public_rand() as u32) 103 | } 104 | 105 | fn next_u64(&mut self) -> u64 { 106 | (self.next_u32() as u64) << 32 | (self.next_u32() as u64) 107 | } 108 | 109 | fn fill_bytes(&mut self, dest: &mut [u8]) { 110 | for d in dest { 111 | *d = __checkct_public_rand(); 112 | } 113 | } 114 | 115 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 116 | self.fill_bytes(dest); 117 | Ok(()) 118 | } 119 | } 120 | 121 | impl CryptoRng for PublicRng {} 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cargo-checkct 2 | 3 | cargo-checkct aims to make it easy for cryptography libraries developers and maintainers to formally verify that their code gets compiled down to constant-time machine code, in CI. 4 | 5 | It does so by leveraging [binsec](https://github.com/binsec/binsec), which is developed by the [Binsec team at the CEA](https://binsec.github.io/). 6 | 7 | There are, however, a number of limitations to have in mind if you plan on using cargo-checkct, most notably: 8 | 9 | - As currently designed, cargo-checkct focuses exclusively on `#![no_std]` libraries or features. 10 | - For the moment, only bare-metal `thumb` and `riscv32` are supported, as well as `x86_64-unknown-linux-gnu` (with some caveats, for instance the use of `cpuid` for runtime detection of cpu features, as used in [RustCrypto](https://github.com/RustCrypto/utils/tree/master/cpufeatures), is not supported). This is mainly due to gaps in the architecture coverage of binsec and [unisim_archisec](https://github.com/binsec/unisim_archisec), that may resorb in the future. 11 | - The analysis is predicated on the fact that all instructions have data-independent timing (meaning for instance that even multiplication and division instructions' timing is not dependent on the operands). 12 | - Only Apple-silicon MacOS and amd64 Linux hosts are supported (the only difference being the linker directive passed down to `rustc` for the `x86_64-unknown-linux-gnu` target). 13 | 14 | ## Install 15 | 16 | You will need to install libgmp and gcc/g++ first, as well as opam (see ). 17 | You will also need rust of course (). 18 | 19 | ```console 20 | opam init -y 21 | opam install -y dune dune-site menhir grain_dypgen ocamlgraph zarith toml bitwuzla 22 | eval $(opam env) 23 | git clone --branch 0.10.0 https://github.com/binsec/binsec 24 | git clone --branch 0.0.10 https://github.com/binsec/unisim_archisec 25 | pushd unisim_archisec && dune build @install && dune install && popd 26 | pushd binsec && dune build @install && dune install && popd 27 | ``` 28 | 29 | ## Usage 30 | 31 | Running 32 | 33 | ```console 34 | cargo b --release 35 | ./target/release/cargo-checkct init -d 36 | ``` 37 | 38 | will initialize a `checkct/` workspace at the designated path, and inside it a `driver` crate. 39 | You can then implement your verification harness (which checkct calls a driver) in `checkct/driver/src/driver.rs`. 40 | You can change the rustc targets for which verification will be done by modifying `checkct/.cargo/config.toml` and `checkct/rust-toolchain.toml`. 41 | 42 | At anypoint, you can add an additional verification driver (to verify another function exposed by your library, for instance) with 43 | 44 | ```console 45 | ./target/release/cargo-checkct add -d -n 46 | ``` 47 | 48 | Then running 49 | 50 | ```console 51 | ./target/release/cargo-checkct run -d 52 | ``` 53 | 54 | will build all drivers (for all the respective targets) in `release` mode and run binsec on the resulting binaries. 55 | 56 | ## Examples 57 | 58 | You can find simple examples of the above in `tests`, as well as life-sized examples in `examples`. Of particular interest might be the `masked_aes` example, which shows how to analyse a C or asm library, by simply exposing a thin rust API for the functions to test. 59 | 60 | ## License 61 | 62 | Licensed under the Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or ) or the MIT license ([LICENSE-MIT](LICENSE-MIT) or ), at your option. 63 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Ledger 2 | // 3 | // SPDX-License-Identifier: MIT OR Apache-2.0 4 | 5 | use std::{path::PathBuf, time::Duration}; 6 | 7 | use anyhow::{Result, bail}; 8 | use clap::{Parser, Subcommand}; 9 | 10 | mod add; 11 | mod common; 12 | mod init; 13 | mod run; 14 | 15 | use add::add_driver; 16 | use init::init_workspace; 17 | use run::run_binsec; 18 | 19 | #[derive(Parser)] 20 | #[command(version, about, long_about = None)] 21 | #[command(subcommand_required = true)] 22 | struct Cli { 23 | #[command(subcommand)] 24 | command: Command, 25 | } 26 | 27 | #[derive(Subcommand)] 28 | enum Command { 29 | Init { 30 | /// Set the path to the directory in which to place the checkct workspace, 31 | /// if it is different from the working directory. 32 | #[arg(short, long, value_name = "PATH")] 33 | dir: Option, 34 | 35 | /// Sets the name of the first constant-time verification driver to be created 36 | /// in the newly created chechct workspace. Defaults to "driver" if not set. 37 | #[arg(short, long, value_name = "NAME")] 38 | name: Option, 39 | }, 40 | Run { 41 | /// Set the path to the target workspace (containing the checkct directory), 42 | /// if it is not in the working directory. 43 | #[arg(short, long, value_name = "PATH")] 44 | dir: Option, 45 | 46 | /// Set a timeout in seconds. If not set, defaults to 10 minutes (600 seconds). 47 | #[arg(short, long, value_name = "SECONDS")] 48 | timeout: Option, 49 | 50 | /// Do not raise an error if binsec cannot conclude on the tested implementation. 51 | #[arg(long, action)] 52 | skip_unknown: bool, 53 | }, 54 | Add { 55 | /// Set the path to the checkct workspace, 56 | /// if it is different from the working directory. 57 | #[arg(short, long, value_name = "PATH")] 58 | dir: Option, 59 | 60 | /// Sets the name of the constant-time verification driver to be created. 61 | #[arg(short, long, value_name = "NAME")] 62 | name: String, 63 | }, 64 | } 65 | 66 | fn main() -> Result<()> { 67 | let cli = Cli::parse(); 68 | 69 | match cli.command { 70 | Command::Init { dir, name } => { 71 | let dir = dir.unwrap_or(std::env::current_dir()?); 72 | let name = &name.unwrap_or("driver".to_owned()); 73 | init_workspace(&dir, name) 74 | } 75 | Command::Run { 76 | dir, 77 | timeout, 78 | skip_unknown, 79 | } => { 80 | let dir = dir.unwrap_or(std::env::current_dir()?).join("checkct"); 81 | let timeout = timeout.unwrap_or(600); 82 | match run_binsec(&dir, Duration::from_secs(timeout))? { 83 | run::Status::Secure => { 84 | println!("SECURE"); 85 | Ok(()) 86 | } 87 | run::Status::Insecure => { 88 | println!("INSECURE"); 89 | bail!("Insecure code!") 90 | } 91 | run::Status::Unknown => { 92 | println!("UNKNOWN"); 93 | if skip_unknown { 94 | Ok(()) 95 | } else { 96 | bail!("Unknown status!") 97 | } 98 | } 99 | } 100 | } 101 | Command::Add { dir, name } => { 102 | let dir = dir.unwrap_or(std::env::current_dir()?); 103 | add_driver(&dir, &name) 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/common.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Ledger 2 | // 3 | // SPDX-License-Identifier: MIT OR Apache-2.0 4 | 5 | use std::{fs, io::Write, path::Path}; 6 | 7 | use anyhow::{Context, Result, anyhow}; 8 | use cargo_manifest::Manifest; 9 | 10 | /// Retrieve the name of the rust library at `path` from its cargo manifest. 11 | pub fn get_lib_name(path: &Path) -> Result { 12 | let manifest = Manifest::from_path(path.join("Cargo.toml")) 13 | .with_context(|| format!("Failed to find the cargo manifest at: {path:?}"))?; 14 | 15 | // We recover the package name directly, not the lib.name entry, because 16 | // the latter has dashes '-' replaced with underscores '_', but we need the actual, unaltered name 17 | let lib_name = manifest 18 | .package 19 | .with_context(|| format!("Failed to find package entry in the cargo manifest at {path:?}"))? 20 | .name; 21 | 22 | Ok(lib_name) 23 | } 24 | 25 | /// Retrieve the members of the cargo workspace at `workspace_dir`. 26 | pub fn get_workspace_members(workspace_dir: &Path) -> Result> { 27 | let manifest = Manifest::from_path(workspace_dir.join("Cargo.toml")) 28 | .with_context(|| format!("Failed to find the cargo manifest at: {workspace_dir:?}"))?; 29 | let members = manifest 30 | .workspace 31 | .with_context(|| { 32 | format!("Failed to find [workspace] entry in the cargo manifest at {workspace_dir:?}") 33 | })? 34 | .members; 35 | 36 | Ok(members) 37 | } 38 | 39 | /// Create a driver crate named `name` in the checkct workspace at `workspace_dir`, to test the `lib_name` crate. 40 | pub fn create_driver(workspace_dir: &Path, lib_name: &str, name: &str) -> Result<()> { 41 | // Create the crate's directory structure 42 | let driver_path = workspace_dir.join(name); 43 | fs::create_dir_all(driver_path.join("src"))?; 44 | 45 | // Relative path to checkct_macros 46 | let checkct_macros_crate_path = pathdiff::diff_paths( 47 | Path::new(env!("CARGO_MANIFEST_DIR")).join("checkct_macros"), 48 | driver_path.canonicalize()?, 49 | ) 50 | .context("Failed to compute the relative path between checkct_macros and the driver directory")? 51 | .into_os_string() 52 | .into_string() 53 | .map_err(|_| anyhow!("Failed to convert relative checkct_macros path to string"))?; 54 | 55 | // Create the driver Cargo.toml file 56 | let mut driver_cargo_file = fs::File::create(driver_path.join("Cargo.toml"))?; 57 | driver_cargo_file.write_all( 58 | format!( 59 | include_str!(concat!( 60 | env!("CARGO_MANIFEST_DIR"), 61 | "/template/driver/Cargo.toml" 62 | )), 63 | name = name, 64 | checkct_macros_crate_path = checkct_macros_crate_path, 65 | lib_name = lib_name 66 | ) 67 | .as_bytes(), 68 | )?; 69 | 70 | // Create the driver's rng.rs file 71 | let mut rng_file = fs::File::create(workspace_dir.join(name).join("src").join("rng.rs"))?; 72 | rng_file.write_all( 73 | include_str!(concat!( 74 | env!("CARGO_MANIFEST_DIR"), 75 | "/template/driver/src/rng.rs" 76 | )) 77 | .as_bytes(), 78 | )?; 79 | 80 | // Create the driver's main.rs file 81 | let mut main_file = fs::File::create(workspace_dir.join(name).join("src").join("main.rs"))?; 82 | main_file.write_all( 83 | include_str!(concat!( 84 | env!("CARGO_MANIFEST_DIR"), 85 | "/template/driver/src/main.rs" 86 | )) 87 | .as_bytes(), 88 | )?; 89 | 90 | // Create the driver's driver.rs file 91 | let mut driver_file = fs::File::create(workspace_dir.join(name).join("src").join("driver.rs"))?; 92 | driver_file.write_all( 93 | include_str!(concat!( 94 | env!("CARGO_MANIFEST_DIR"), 95 | "/template/driver/src/driver.rs" 96 | )) 97 | .as_bytes(), 98 | )?; 99 | 100 | Ok(()) 101 | } 102 | -------------------------------------------------------------------------------- /examples/dalek/checkct/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "cfg-if" 7 | version = "1.0.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 10 | 11 | [[package]] 12 | name = "checkct_macros" 13 | version = "0.1.0" 14 | dependencies = [ 15 | "proc-macro2", 16 | "quote", 17 | "syn", 18 | ] 19 | 20 | [[package]] 21 | name = "cpufeatures" 22 | version = "0.2.12" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" 25 | dependencies = [ 26 | "libc", 27 | ] 28 | 29 | [[package]] 30 | name = "curve25519-dalek" 31 | version = "4.1.2" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" 34 | dependencies = [ 35 | "cfg-if", 36 | "cpufeatures", 37 | "curve25519-dalek-derive", 38 | "fiat-crypto", 39 | "platforms", 40 | "rustc_version", 41 | "subtle", 42 | ] 43 | 44 | [[package]] 45 | name = "curve25519-dalek-derive" 46 | version = "0.1.1" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" 49 | dependencies = [ 50 | "proc-macro2", 51 | "quote", 52 | "syn", 53 | ] 54 | 55 | [[package]] 56 | name = "dalek" 57 | version = "0.0.0" 58 | dependencies = [ 59 | "x25519-dalek", 60 | ] 61 | 62 | [[package]] 63 | name = "driver" 64 | version = "0.0.0" 65 | dependencies = [ 66 | "checkct_macros", 67 | "dalek", 68 | "rand_core", 69 | ] 70 | 71 | [[package]] 72 | name = "fiat-crypto" 73 | version = "0.2.7" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "c007b1ae3abe1cb6f85a16305acd418b7ca6343b953633fee2b76d8f108b830f" 76 | 77 | [[package]] 78 | name = "libc" 79 | version = "0.2.153" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" 82 | 83 | [[package]] 84 | name = "platforms" 85 | version = "3.3.0" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "626dec3cac7cc0e1577a2ec3fc496277ec2baa084bebad95bb6fdbfae235f84c" 88 | 89 | [[package]] 90 | name = "proc-macro2" 91 | version = "1.0.86" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 94 | dependencies = [ 95 | "unicode-ident", 96 | ] 97 | 98 | [[package]] 99 | name = "quote" 100 | version = "1.0.37" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 103 | dependencies = [ 104 | "proc-macro2", 105 | ] 106 | 107 | [[package]] 108 | name = "rand_core" 109 | version = "0.6.4" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 112 | 113 | [[package]] 114 | name = "rustc_version" 115 | version = "0.4.0" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 118 | dependencies = [ 119 | "semver", 120 | ] 121 | 122 | [[package]] 123 | name = "semver" 124 | version = "1.0.22" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" 127 | 128 | [[package]] 129 | name = "subtle" 130 | version = "2.5.0" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" 133 | 134 | [[package]] 135 | name = "syn" 136 | version = "2.0.77" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" 139 | dependencies = [ 140 | "proc-macro2", 141 | "quote", 142 | "unicode-ident", 143 | ] 144 | 145 | [[package]] 146 | name = "unicode-ident" 147 | version = "1.0.12" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 150 | 151 | [[package]] 152 | name = "x25519-dalek" 153 | version = "2.0.1" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" 156 | dependencies = [ 157 | "curve25519-dalek", 158 | "rand_core", 159 | ] 160 | -------------------------------------------------------------------------------- /examples/chachapoly/checkct/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "aead" 7 | version = "0.5.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" 10 | dependencies = [ 11 | "crypto-common", 12 | "generic-array", 13 | "heapless", 14 | ] 15 | 16 | [[package]] 17 | name = "atomic-polyfill" 18 | version = "1.0.3" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" 21 | dependencies = [ 22 | "critical-section", 23 | ] 24 | 25 | [[package]] 26 | name = "autocfg" 27 | version = "1.1.0" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 30 | 31 | [[package]] 32 | name = "byteorder" 33 | version = "1.5.0" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 36 | 37 | [[package]] 38 | name = "cfg-if" 39 | version = "1.0.0" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 42 | 43 | [[package]] 44 | name = "chacha20" 45 | version = "0.9.1" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" 48 | dependencies = [ 49 | "cfg-if", 50 | "cipher", 51 | "cpufeatures", 52 | ] 53 | 54 | [[package]] 55 | name = "chacha20poly1305" 56 | version = "0.10.1" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" 59 | dependencies = [ 60 | "aead", 61 | "chacha20", 62 | "cipher", 63 | "poly1305", 64 | "zeroize", 65 | ] 66 | 67 | [[package]] 68 | name = "chachapoly" 69 | version = "0.0.0" 70 | dependencies = [ 71 | "chacha20poly1305", 72 | ] 73 | 74 | [[package]] 75 | name = "checkct_macros" 76 | version = "0.1.0" 77 | dependencies = [ 78 | "proc-macro2", 79 | "quote", 80 | "syn", 81 | ] 82 | 83 | [[package]] 84 | name = "cipher" 85 | version = "0.4.4" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" 88 | dependencies = [ 89 | "crypto-common", 90 | "inout", 91 | "zeroize", 92 | ] 93 | 94 | [[package]] 95 | name = "cpufeatures" 96 | version = "0.2.12" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" 99 | dependencies = [ 100 | "libc", 101 | ] 102 | 103 | [[package]] 104 | name = "critical-section" 105 | version = "1.1.2" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" 108 | 109 | [[package]] 110 | name = "crypto-common" 111 | version = "0.1.6" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 114 | dependencies = [ 115 | "generic-array", 116 | "rand_core", 117 | "typenum", 118 | ] 119 | 120 | [[package]] 121 | name = "driver" 122 | version = "0.0.0" 123 | dependencies = [ 124 | "chachapoly", 125 | "checkct_macros", 126 | "rand_core", 127 | ] 128 | 129 | [[package]] 130 | name = "generic-array" 131 | version = "0.14.7" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 134 | dependencies = [ 135 | "typenum", 136 | "version_check", 137 | ] 138 | 139 | [[package]] 140 | name = "hash32" 141 | version = "0.2.1" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" 144 | dependencies = [ 145 | "byteorder", 146 | ] 147 | 148 | [[package]] 149 | name = "heapless" 150 | version = "0.7.17" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" 153 | dependencies = [ 154 | "atomic-polyfill", 155 | "hash32", 156 | "rustc_version", 157 | "spin", 158 | "stable_deref_trait", 159 | ] 160 | 161 | [[package]] 162 | name = "inout" 163 | version = "0.1.3" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" 166 | dependencies = [ 167 | "generic-array", 168 | ] 169 | 170 | [[package]] 171 | name = "libc" 172 | version = "0.2.153" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" 175 | 176 | [[package]] 177 | name = "lock_api" 178 | version = "0.4.11" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" 181 | dependencies = [ 182 | "autocfg", 183 | "scopeguard", 184 | ] 185 | 186 | [[package]] 187 | name = "opaque-debug" 188 | version = "0.3.1" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" 191 | 192 | [[package]] 193 | name = "poly1305" 194 | version = "0.8.0" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" 197 | dependencies = [ 198 | "cpufeatures", 199 | "opaque-debug", 200 | "universal-hash", 201 | ] 202 | 203 | [[package]] 204 | name = "proc-macro2" 205 | version = "1.0.86" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 208 | dependencies = [ 209 | "unicode-ident", 210 | ] 211 | 212 | [[package]] 213 | name = "quote" 214 | version = "1.0.37" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 217 | dependencies = [ 218 | "proc-macro2", 219 | ] 220 | 221 | [[package]] 222 | name = "rand_core" 223 | version = "0.6.4" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 226 | 227 | [[package]] 228 | name = "rustc_version" 229 | version = "0.4.0" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 232 | dependencies = [ 233 | "semver", 234 | ] 235 | 236 | [[package]] 237 | name = "scopeguard" 238 | version = "1.2.0" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 241 | 242 | [[package]] 243 | name = "semver" 244 | version = "1.0.22" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" 247 | 248 | [[package]] 249 | name = "spin" 250 | version = "0.9.8" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 253 | dependencies = [ 254 | "lock_api", 255 | ] 256 | 257 | [[package]] 258 | name = "stable_deref_trait" 259 | version = "1.2.0" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 262 | 263 | [[package]] 264 | name = "subtle" 265 | version = "2.5.0" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" 268 | 269 | [[package]] 270 | name = "syn" 271 | version = "2.0.77" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" 274 | dependencies = [ 275 | "proc-macro2", 276 | "quote", 277 | "unicode-ident", 278 | ] 279 | 280 | [[package]] 281 | name = "typenum" 282 | version = "1.17.0" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 285 | 286 | [[package]] 287 | name = "unicode-ident" 288 | version = "1.0.13" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" 291 | 292 | [[package]] 293 | name = "universal-hash" 294 | version = "0.5.1" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" 297 | dependencies = [ 298 | "crypto-common", 299 | "subtle", 300 | ] 301 | 302 | [[package]] 303 | name = "version_check" 304 | version = "0.9.4" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 307 | 308 | [[package]] 309 | name = "zeroize" 310 | version = "1.7.0" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" 313 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /src/run.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Ledger 2 | // 3 | // SPDX-License-Identifier: MIT OR Apache-2.0 4 | 5 | use std::{fs, io::Write, path::Path, time::Duration}; 6 | 7 | use anyhow::{Context, Result, bail}; 8 | use goblin::{Object, container::Endian, elf::Elf}; 9 | use which::which; 10 | 11 | use crate::common::get_workspace_members; 12 | 13 | pub enum Status { 14 | Secure, 15 | Insecure, 16 | Unknown, 17 | } 18 | 19 | struct Abi<'a> { 20 | lr: &'a str, 21 | ret: &'a str, 22 | thumb: &'a str, 23 | size: usize, 24 | } 25 | 26 | fn find_checkct_entrypoints<'a>(elf: &'a Elf, binary: &[u8]) -> Result> { 27 | let mut checkct_entrypoints = Vec::new(); 28 | for sym in elf.syms.iter() { 29 | // Find checkct entrypoint descriptors by looking for symbols whose name contains __checkct_entrypoint_descriptor__ 30 | let Some(symbol_name) = elf.strtab.get_at(sym.st_name) else { 31 | continue; 32 | }; 33 | if !symbol_name.contains("__checkct_entrypoint_descriptor__") { 34 | continue; 35 | } 36 | 37 | let section_header = &elf.section_headers[sym.st_shndx]; 38 | let start = sym.st_value - section_header.sh_addr + section_header.sh_offset; 39 | 40 | let entry_addr = match sym.st_size { 41 | 4 => match elf.header.endianness()? { 42 | Endian::Little => u32::from_le_bytes( 43 | binary[start as usize..(start + sym.st_size) as usize].try_into()?, 44 | ) 45 | .into(), 46 | Endian::Big => u32::from_be_bytes( 47 | binary[start as usize..(start + sym.st_size) as usize].try_into()?, 48 | ) 49 | .into(), 50 | }, 51 | 8 => match elf.header.endianness()? { 52 | Endian::Little => u64::from_le_bytes( 53 | binary[start as usize..(start + sym.st_size) as usize].try_into()?, 54 | ), 55 | 56 | Endian::Big => u64::from_be_bytes( 57 | binary[start as usize..(start + sym.st_size) as usize].try_into()?, 58 | ), 59 | }, 60 | _ => todo!(), 61 | }; 62 | 63 | let entry_sym = elf 64 | .syms 65 | .iter() 66 | .find(|s| s.st_value == entry_addr && s.is_function()) 67 | .unwrap(); 68 | checkct_entrypoints.push(elf.strtab.get_at(entry_sym.st_name).unwrap()); 69 | } 70 | 71 | Ok(checkct_entrypoints) 72 | } 73 | 74 | pub fn run_binsec(dir: &Path, timeout: Duration) -> Result { 75 | let cur_dir = std::env::current_dir()?; 76 | 77 | // First we need to actually build the drivers 78 | std::env::set_current_dir(dir) 79 | .with_context(|| format!("Failed to set current directory to {dir:?}"))?; 80 | let cargo_path = which("cargo").context("Failed to find cargo")?; 81 | let mut cmd = std::process::Command::new(cargo_path); 82 | // Enforce -fno-stack-protector since we build with no_std 83 | cmd.env("CFLAGS", "-fno-stack-protector"); 84 | cmd.arg("build").arg("--release"); 85 | 86 | // We need to change the linker for the x86 cross-compilation 87 | #[cfg(all(target_os = "macos", target_arch = "aarch64"))] 88 | cmd.arg("--config") 89 | .arg("target.x86_64-unknown-linux-gnu.linker=\"x86_64-unknown-linux-gnu-gcc\""); 90 | 91 | #[cfg(all(target_os = "linux", target_arch = "x86_64"))] 92 | cmd.arg("--config") 93 | .arg("target.x86_64-unknown-linux-gnu.linker=\"x86_64-linux-gnu-gcc\""); 94 | 95 | let output = cmd.output().context("Failed to build drivers")?; 96 | 97 | if !output.status.success() { 98 | bail!( 99 | "Error while building drivers:\nstdout: {}\nstderr: {}", 100 | String::from_utf8_lossy(&output.stdout), 101 | String::from_utf8_lossy(&output.stderr) 102 | ) 103 | } 104 | std::env::set_current_dir(cur_dir)?; 105 | 106 | // Next we recover the actual name of the drivers 107 | let members = get_workspace_members(dir)?; 108 | if members.is_empty() { 109 | bail!("Error: found empty [workspace.members] key - no drivers to build."); 110 | } 111 | 112 | let mut overall_status = Status::Secure; 113 | 114 | // Now for each driver: 115 | for driver in members { 116 | println!("Driver {driver}:"); 117 | // First we recover the targets from the config toml 118 | let config_path = &dir.join(".cargo").join("config.toml"); 119 | let config = fs::read_to_string(config_path) 120 | .with_context(|| format!("Failed to read the config manifest in: {config_path:?}"))?; 121 | let config_table = config 122 | .parse::() 123 | .with_context(|| format!("Failed to parse the config manifest in: {config_path:?}"))?; 124 | let build_entry = config_table.get("build").with_context(|| { 125 | format!("Failed to find the [build] entry of the config manifest in: {config_path:?}") 126 | })?; 127 | let toml::Value::Table(build_table) = build_entry else { 128 | bail!("[build] entry of the config manifest in: {config_path:?} is not a toml::Table"); 129 | }; 130 | let toml::Value::Array(target_list) = build_table.get("target").with_context(|| { 131 | format!( 132 | "Failed to find the [build.target] entry of the config manifest in: {config_path:?}" 133 | ) 134 | })? 135 | else { 136 | bail!("") 137 | }; 138 | 139 | // Now we can generate and run the binsec script for each targets 140 | for target in target_list { 141 | let toml::Value::String(target) = target else { 142 | bail!("") 143 | }; 144 | 145 | println!(" target: {target}"); 146 | 147 | let abi = match target.split('-').next().unwrap() { 148 | arch if arch.starts_with("thumb") => Abi { 149 | lr: "lr", 150 | ret: "0x8badf00d ^ 1", 151 | thumb: " ^1", 152 | size: 32, 153 | }, 154 | arch if arch.starts_with("riscv") => Abi { 155 | lr: "ra", 156 | ret: "0x8badf00d", 157 | thumb: "", 158 | size: 32, 159 | }, 160 | arch if arch.starts_with("x86_64") => Abi { 161 | lr: "@[rsp, 8]", 162 | ret: "0xffffffff8badf00d", 163 | thumb: "", 164 | size: 64, 165 | }, 166 | _ => panic!("unexpected target: {target}"), 167 | }; 168 | 169 | let binary = fs::read( 170 | dir.join("target") 171 | .join(target) 172 | .join("release") 173 | .join(&driver), 174 | )?; 175 | let obj = Object::parse(&binary)?; 176 | let Object::Elf(elf) = obj else { 177 | bail!("Object format {obj:?} not supported") 178 | }; 179 | 180 | let sections = elf 181 | .section_headers 182 | .iter() 183 | .map(|h| elf.shdr_strtab.get_at(h.sh_name).unwrap()) 184 | .filter(|n| !n.is_empty() && ![".note.gnu.build-id", ".note.checkct"].contains(n)) 185 | .collect::>() 186 | .join(", "); 187 | 188 | let checkct_entrypoints = find_checkct_entrypoints(&elf, &binary)?; 189 | 190 | for entrypoint in checkct_entrypoints { 191 | let mut script = fs::File::create( 192 | dir.join("target") 193 | .join(target) 194 | .join(format!("{driver}.binsec")), 195 | )?; 196 | script.write_all( 197 | format!( 198 | include_str!(concat!( 199 | env!("CARGO_MANIFEST_DIR"), 200 | "/template/target/driver.binsec" 201 | )), 202 | sections = sections, 203 | entrypoint = entrypoint, 204 | lr = abi.lr, 205 | ret = abi.ret, 206 | size = abi.size, 207 | thumb = abi.thumb, 208 | ) 209 | .as_bytes(), 210 | )?; 211 | 212 | let binsec_path = which("binsec").context( 213 | "Failed to find binsec - you might need to run `eval $(opam env)` first", 214 | )?; 215 | let mut binsec_cmd = std::process::Command::new(binsec_path); 216 | binsec_cmd 217 | .arg("-sse") 218 | .arg("-checkct") 219 | .arg("-sse-depth") 220 | .arg("1000000000") 221 | .arg("-sse-jump-enum") 222 | .arg("64") 223 | .arg("-sse-script") 224 | .arg(format!( 225 | "{}", 226 | dir.join("target") 227 | .join(target) 228 | .join(format!("{driver}.binsec")) 229 | .to_string_lossy() 230 | )) 231 | .arg("-sse-timeout") 232 | .arg(format!("{}", timeout.as_secs())) 233 | .arg("-arm-supported-modes") 234 | .arg("thumb") 235 | .arg(format!( 236 | "{}", 237 | dir.join("target") 238 | .join(target) 239 | .join("release") 240 | .join(&driver) 241 | .to_string_lossy() 242 | )); 243 | 244 | println!("{}", format!(" Running: {binsec_cmd:?}").replace('\"', "")); 245 | let output = binsec_cmd.output().context("Failed to run binsec")?; 246 | 247 | let driver_status; 248 | 249 | if !output.status.success() { 250 | bail!( 251 | "Error while running binsec:\nstdout: {}\nstderr: {}", 252 | String::from_utf8_lossy(&output.stdout), 253 | String::from_utf8_lossy(&output.stderr) 254 | ); 255 | } else { 256 | let stdout = String::from_utf8_lossy(&output.stdout); 257 | if stdout.contains("[checkct:result] Program status is : insecure") { 258 | driver_status = Status::Insecure; 259 | } else if stdout.contains("[checkct:result] Program status is : secure") { 260 | driver_status = Status::Secure; 261 | } else { 262 | println!( 263 | "UNEXPECTED:\nstderr: {}", 264 | String::from_utf8_lossy(&output.stderr) 265 | ); 266 | driver_status = Status::Unknown; 267 | } 268 | } 269 | 270 | println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); 271 | 272 | match driver_status { 273 | Status::Secure => {} 274 | // If even one driver is not secure, fail, but still continue 275 | // so that the status of the other drivers can be recovered 276 | // from the logs. 277 | Status::Insecure => { 278 | overall_status = Status::Insecure; 279 | } 280 | Status::Unknown => { 281 | if let Status::Secure = overall_status { 282 | overall_status = Status::Unknown; 283 | } 284 | } 285 | } 286 | } 287 | } 288 | } 289 | 290 | Ok(overall_status) 291 | } 292 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "aead" 7 | version = "0.5.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" 10 | dependencies = [ 11 | "crypto-common", 12 | "generic-array", 13 | "heapless", 14 | ] 15 | 16 | [[package]] 17 | name = "anstream" 18 | version = "0.6.13" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" 21 | dependencies = [ 22 | "anstyle", 23 | "anstyle-parse", 24 | "anstyle-query", 25 | "anstyle-wincon", 26 | "colorchoice", 27 | "utf8parse", 28 | ] 29 | 30 | [[package]] 31 | name = "anstyle" 32 | version = "1.0.6" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" 35 | 36 | [[package]] 37 | name = "anstyle-parse" 38 | version = "0.2.3" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" 41 | dependencies = [ 42 | "utf8parse", 43 | ] 44 | 45 | [[package]] 46 | name = "anstyle-query" 47 | version = "1.0.2" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" 50 | dependencies = [ 51 | "windows-sys", 52 | ] 53 | 54 | [[package]] 55 | name = "anstyle-wincon" 56 | version = "3.0.2" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" 59 | dependencies = [ 60 | "anstyle", 61 | "windows-sys", 62 | ] 63 | 64 | [[package]] 65 | name = "anyhow" 66 | version = "1.0.80" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" 69 | 70 | [[package]] 71 | name = "assert_cmd" 72 | version = "2.0.14" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "ed72493ac66d5804837f480ab3766c72bdfab91a65e565fc54fa9e42db0073a8" 75 | dependencies = [ 76 | "anstyle", 77 | "bstr", 78 | "doc-comment", 79 | "predicates", 80 | "predicates-core", 81 | "predicates-tree", 82 | "wait-timeout", 83 | ] 84 | 85 | [[package]] 86 | name = "atomic-polyfill" 87 | version = "1.0.3" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" 90 | dependencies = [ 91 | "critical-section", 92 | ] 93 | 94 | [[package]] 95 | name = "autocfg" 96 | version = "1.1.0" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 99 | 100 | [[package]] 101 | name = "bitflags" 102 | version = "2.5.0" 103 | source = "registry+https://github.com/rust-lang/crates.io-index" 104 | checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" 105 | 106 | [[package]] 107 | name = "bstr" 108 | version = "1.9.1" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" 111 | dependencies = [ 112 | "memchr", 113 | "regex-automata", 114 | "serde", 115 | ] 116 | 117 | [[package]] 118 | name = "byteorder" 119 | version = "1.5.0" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 122 | 123 | [[package]] 124 | name = "cargo-checkct" 125 | version = "0.1.0" 126 | dependencies = [ 127 | "anyhow", 128 | "assert_cmd", 129 | "cargo-manifest", 130 | "clap", 131 | "goblin", 132 | "pathdiff", 133 | "toml", 134 | "which", 135 | ] 136 | 137 | [[package]] 138 | name = "cargo-manifest" 139 | version = "0.19.1" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "a1d8af896b707212cd0e99c112a78c9497dd32994192a463ed2f7419d29bd8c6" 142 | dependencies = [ 143 | "serde", 144 | "thiserror", 145 | "toml", 146 | ] 147 | 148 | [[package]] 149 | name = "cc" 150 | version = "1.0.90" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" 153 | 154 | [[package]] 155 | name = "cfg-if" 156 | version = "1.0.0" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 159 | 160 | [[package]] 161 | name = "chacha20" 162 | version = "0.9.1" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" 165 | dependencies = [ 166 | "cfg-if", 167 | "cipher", 168 | "cpufeatures", 169 | ] 170 | 171 | [[package]] 172 | name = "chacha20poly1305" 173 | version = "0.10.1" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" 176 | dependencies = [ 177 | "aead", 178 | "chacha20", 179 | "cipher", 180 | "poly1305", 181 | "zeroize", 182 | ] 183 | 184 | [[package]] 185 | name = "chachapoly" 186 | version = "0.0.0" 187 | dependencies = [ 188 | "chacha20poly1305", 189 | ] 190 | 191 | [[package]] 192 | name = "checkct_macros" 193 | version = "0.1.0" 194 | dependencies = [ 195 | "proc-macro2", 196 | "quote", 197 | "rand_core", 198 | "syn", 199 | ] 200 | 201 | [[package]] 202 | name = "cipher" 203 | version = "0.4.4" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" 206 | dependencies = [ 207 | "crypto-common", 208 | "inout", 209 | "zeroize", 210 | ] 211 | 212 | [[package]] 213 | name = "clap" 214 | version = "4.5.2" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651" 217 | dependencies = [ 218 | "clap_builder", 219 | "clap_derive", 220 | ] 221 | 222 | [[package]] 223 | name = "clap_builder" 224 | version = "4.5.2" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" 227 | dependencies = [ 228 | "anstream", 229 | "anstyle", 230 | "clap_lex", 231 | "strsim", 232 | ] 233 | 234 | [[package]] 235 | name = "clap_derive" 236 | version = "4.5.0" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" 239 | dependencies = [ 240 | "heck", 241 | "proc-macro2", 242 | "quote", 243 | "syn", 244 | ] 245 | 246 | [[package]] 247 | name = "clap_lex" 248 | version = "0.7.0" 249 | source = "registry+https://github.com/rust-lang/crates.io-index" 250 | checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" 251 | 252 | [[package]] 253 | name = "colorchoice" 254 | version = "1.0.0" 255 | source = "registry+https://github.com/rust-lang/crates.io-index" 256 | checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" 257 | 258 | [[package]] 259 | name = "cpufeatures" 260 | version = "0.2.12" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" 263 | dependencies = [ 264 | "libc", 265 | ] 266 | 267 | [[package]] 268 | name = "critical-section" 269 | version = "1.1.2" 270 | source = "registry+https://github.com/rust-lang/crates.io-index" 271 | checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" 272 | 273 | [[package]] 274 | name = "crypto-common" 275 | version = "0.1.6" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 278 | dependencies = [ 279 | "generic-array", 280 | "rand_core", 281 | "typenum", 282 | ] 283 | 284 | [[package]] 285 | name = "curve25519-dalek" 286 | version = "4.1.2" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" 289 | dependencies = [ 290 | "cfg-if", 291 | "cpufeatures", 292 | "curve25519-dalek-derive", 293 | "fiat-crypto", 294 | "platforms", 295 | "rustc_version", 296 | "subtle", 297 | ] 298 | 299 | [[package]] 300 | name = "curve25519-dalek-derive" 301 | version = "0.1.1" 302 | source = "registry+https://github.com/rust-lang/crates.io-index" 303 | checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" 304 | dependencies = [ 305 | "proc-macro2", 306 | "quote", 307 | "syn", 308 | ] 309 | 310 | [[package]] 311 | name = "dalek" 312 | version = "0.0.0" 313 | dependencies = [ 314 | "x25519-dalek", 315 | ] 316 | 317 | [[package]] 318 | name = "difflib" 319 | version = "0.4.0" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" 322 | 323 | [[package]] 324 | name = "doc-comment" 325 | version = "0.3.3" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" 328 | 329 | [[package]] 330 | name = "either" 331 | version = "1.10.0" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" 334 | 335 | [[package]] 336 | name = "equivalent" 337 | version = "1.0.1" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 340 | 341 | [[package]] 342 | name = "errno" 343 | version = "0.3.8" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" 346 | dependencies = [ 347 | "libc", 348 | "windows-sys", 349 | ] 350 | 351 | [[package]] 352 | name = "fiat-crypto" 353 | version = "0.2.6" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "1676f435fc1dadde4d03e43f5d62b259e1ce5f40bd4ffb21db2b42ebe59c1382" 356 | 357 | [[package]] 358 | name = "generic-array" 359 | version = "0.14.7" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 362 | dependencies = [ 363 | "typenum", 364 | "version_check", 365 | ] 366 | 367 | [[package]] 368 | name = "goblin" 369 | version = "0.8.0" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "bb07a4ffed2093b118a525b1d8f5204ae274faed5604537caf7135d0f18d9887" 372 | dependencies = [ 373 | "log", 374 | "plain", 375 | "scroll", 376 | ] 377 | 378 | [[package]] 379 | name = "hash32" 380 | version = "0.2.1" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" 383 | dependencies = [ 384 | "byteorder", 385 | ] 386 | 387 | [[package]] 388 | name = "hashbrown" 389 | version = "0.14.3" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" 392 | 393 | [[package]] 394 | name = "heapless" 395 | version = "0.7.17" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" 398 | dependencies = [ 399 | "atomic-polyfill", 400 | "hash32", 401 | "rustc_version", 402 | "spin", 403 | "stable_deref_trait", 404 | ] 405 | 406 | [[package]] 407 | name = "heck" 408 | version = "0.4.1" 409 | source = "registry+https://github.com/rust-lang/crates.io-index" 410 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 411 | 412 | [[package]] 413 | name = "home" 414 | version = "0.5.9" 415 | source = "registry+https://github.com/rust-lang/crates.io-index" 416 | checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" 417 | dependencies = [ 418 | "windows-sys", 419 | ] 420 | 421 | [[package]] 422 | name = "indexmap" 423 | version = "2.2.5" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" 426 | dependencies = [ 427 | "equivalent", 428 | "hashbrown", 429 | ] 430 | 431 | [[package]] 432 | name = "inout" 433 | version = "0.1.3" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" 436 | dependencies = [ 437 | "generic-array", 438 | ] 439 | 440 | [[package]] 441 | name = "libc" 442 | version = "0.2.153" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" 445 | 446 | [[package]] 447 | name = "linux-raw-sys" 448 | version = "0.4.13" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" 451 | 452 | [[package]] 453 | name = "lock_api" 454 | version = "0.4.11" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" 457 | dependencies = [ 458 | "autocfg", 459 | "scopeguard", 460 | ] 461 | 462 | [[package]] 463 | name = "log" 464 | version = "0.4.21" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" 467 | 468 | [[package]] 469 | name = "masked_aes" 470 | version = "0.1.0" 471 | dependencies = [ 472 | "cc", 473 | ] 474 | 475 | [[package]] 476 | name = "memchr" 477 | version = "2.7.1" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" 480 | 481 | [[package]] 482 | name = "opaque-debug" 483 | version = "0.3.1" 484 | source = "registry+https://github.com/rust-lang/crates.io-index" 485 | checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" 486 | 487 | [[package]] 488 | name = "pathdiff" 489 | version = "0.2.1" 490 | source = "registry+https://github.com/rust-lang/crates.io-index" 491 | checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" 492 | 493 | [[package]] 494 | name = "plain" 495 | version = "0.2.3" 496 | source = "registry+https://github.com/rust-lang/crates.io-index" 497 | checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" 498 | 499 | [[package]] 500 | name = "platforms" 501 | version = "3.3.0" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "626dec3cac7cc0e1577a2ec3fc496277ec2baa084bebad95bb6fdbfae235f84c" 504 | 505 | [[package]] 506 | name = "poly1305" 507 | version = "0.8.0" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" 510 | dependencies = [ 511 | "cpufeatures", 512 | "opaque-debug", 513 | "universal-hash", 514 | ] 515 | 516 | [[package]] 517 | name = "predicates" 518 | version = "3.1.0" 519 | source = "registry+https://github.com/rust-lang/crates.io-index" 520 | checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" 521 | dependencies = [ 522 | "anstyle", 523 | "difflib", 524 | "predicates-core", 525 | ] 526 | 527 | [[package]] 528 | name = "predicates-core" 529 | version = "1.0.6" 530 | source = "registry+https://github.com/rust-lang/crates.io-index" 531 | checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" 532 | 533 | [[package]] 534 | name = "predicates-tree" 535 | version = "1.0.9" 536 | source = "registry+https://github.com/rust-lang/crates.io-index" 537 | checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" 538 | dependencies = [ 539 | "predicates-core", 540 | "termtree", 541 | ] 542 | 543 | [[package]] 544 | name = "proc-macro2" 545 | version = "1.0.86" 546 | source = "registry+https://github.com/rust-lang/crates.io-index" 547 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 548 | dependencies = [ 549 | "unicode-ident", 550 | ] 551 | 552 | [[package]] 553 | name = "quote" 554 | version = "1.0.37" 555 | source = "registry+https://github.com/rust-lang/crates.io-index" 556 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 557 | dependencies = [ 558 | "proc-macro2", 559 | ] 560 | 561 | [[package]] 562 | name = "rand_core" 563 | version = "0.6.4" 564 | source = "registry+https://github.com/rust-lang/crates.io-index" 565 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 566 | 567 | [[package]] 568 | name = "regex-automata" 569 | version = "0.4.6" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" 572 | 573 | [[package]] 574 | name = "rustc_version" 575 | version = "0.4.0" 576 | source = "registry+https://github.com/rust-lang/crates.io-index" 577 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 578 | dependencies = [ 579 | "semver", 580 | ] 581 | 582 | [[package]] 583 | name = "rustix" 584 | version = "0.38.32" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" 587 | dependencies = [ 588 | "bitflags", 589 | "errno", 590 | "libc", 591 | "linux-raw-sys", 592 | "windows-sys", 593 | ] 594 | 595 | [[package]] 596 | name = "scopeguard" 597 | version = "1.2.0" 598 | source = "registry+https://github.com/rust-lang/crates.io-index" 599 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 600 | 601 | [[package]] 602 | name = "scroll" 603 | version = "0.12.0" 604 | source = "registry+https://github.com/rust-lang/crates.io-index" 605 | checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" 606 | dependencies = [ 607 | "scroll_derive", 608 | ] 609 | 610 | [[package]] 611 | name = "scroll_derive" 612 | version = "0.12.0" 613 | source = "registry+https://github.com/rust-lang/crates.io-index" 614 | checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" 615 | dependencies = [ 616 | "proc-macro2", 617 | "quote", 618 | "syn", 619 | ] 620 | 621 | [[package]] 622 | name = "secp256K1" 623 | version = "0.1.0" 624 | dependencies = [ 625 | "secp256k1", 626 | "secp256k1-sys", 627 | ] 628 | 629 | [[package]] 630 | name = "secp256k1" 631 | version = "0.29.0" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" 634 | dependencies = [ 635 | "secp256k1-sys", 636 | ] 637 | 638 | [[package]] 639 | name = "secp256k1-sys" 640 | version = "0.10.0" 641 | source = "registry+https://github.com/rust-lang/crates.io-index" 642 | checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" 643 | dependencies = [ 644 | "cc", 645 | ] 646 | 647 | [[package]] 648 | name = "semver" 649 | version = "1.0.22" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" 652 | 653 | [[package]] 654 | name = "serde" 655 | version = "1.0.197" 656 | source = "registry+https://github.com/rust-lang/crates.io-index" 657 | checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" 658 | dependencies = [ 659 | "serde_derive", 660 | ] 661 | 662 | [[package]] 663 | name = "serde_derive" 664 | version = "1.0.197" 665 | source = "registry+https://github.com/rust-lang/crates.io-index" 666 | checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" 667 | dependencies = [ 668 | "proc-macro2", 669 | "quote", 670 | "syn", 671 | ] 672 | 673 | [[package]] 674 | name = "serde_spanned" 675 | version = "0.6.5" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" 678 | dependencies = [ 679 | "serde", 680 | ] 681 | 682 | [[package]] 683 | name = "spin" 684 | version = "0.9.8" 685 | source = "registry+https://github.com/rust-lang/crates.io-index" 686 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 687 | dependencies = [ 688 | "lock_api", 689 | ] 690 | 691 | [[package]] 692 | name = "stable_deref_trait" 693 | version = "1.2.0" 694 | source = "registry+https://github.com/rust-lang/crates.io-index" 695 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 696 | 697 | [[package]] 698 | name = "strsim" 699 | version = "0.11.0" 700 | source = "registry+https://github.com/rust-lang/crates.io-index" 701 | checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" 702 | 703 | [[package]] 704 | name = "subtle" 705 | version = "2.5.0" 706 | source = "registry+https://github.com/rust-lang/crates.io-index" 707 | checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" 708 | 709 | [[package]] 710 | name = "syn" 711 | version = "2.0.87" 712 | source = "registry+https://github.com/rust-lang/crates.io-index" 713 | checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" 714 | dependencies = [ 715 | "proc-macro2", 716 | "quote", 717 | "unicode-ident", 718 | ] 719 | 720 | [[package]] 721 | name = "termtree" 722 | version = "0.4.1" 723 | source = "registry+https://github.com/rust-lang/crates.io-index" 724 | checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" 725 | 726 | [[package]] 727 | name = "thiserror" 728 | version = "2.0.12" 729 | source = "registry+https://github.com/rust-lang/crates.io-index" 730 | checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" 731 | dependencies = [ 732 | "thiserror-impl", 733 | ] 734 | 735 | [[package]] 736 | name = "thiserror-impl" 737 | version = "2.0.12" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" 740 | dependencies = [ 741 | "proc-macro2", 742 | "quote", 743 | "syn", 744 | ] 745 | 746 | [[package]] 747 | name = "toml" 748 | version = "0.8.11" 749 | source = "registry+https://github.com/rust-lang/crates.io-index" 750 | checksum = "af06656561d28735e9c1cd63dfd57132c8155426aa6af24f36a00a351f88c48e" 751 | dependencies = [ 752 | "indexmap", 753 | "serde", 754 | "serde_spanned", 755 | "toml_datetime", 756 | "toml_edit", 757 | ] 758 | 759 | [[package]] 760 | name = "toml_datetime" 761 | version = "0.6.5" 762 | source = "registry+https://github.com/rust-lang/crates.io-index" 763 | checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" 764 | dependencies = [ 765 | "serde", 766 | ] 767 | 768 | [[package]] 769 | name = "toml_edit" 770 | version = "0.22.7" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "18769cd1cec395d70860ceb4d932812a0b4d06b1a4bb336745a4d21b9496e992" 773 | dependencies = [ 774 | "indexmap", 775 | "serde", 776 | "serde_spanned", 777 | "toml_datetime", 778 | "winnow", 779 | ] 780 | 781 | [[package]] 782 | name = "typenum" 783 | version = "1.17.0" 784 | source = "registry+https://github.com/rust-lang/crates.io-index" 785 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 786 | 787 | [[package]] 788 | name = "unicode-ident" 789 | version = "1.0.12" 790 | source = "registry+https://github.com/rust-lang/crates.io-index" 791 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 792 | 793 | [[package]] 794 | name = "universal-hash" 795 | version = "0.5.1" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" 798 | dependencies = [ 799 | "crypto-common", 800 | "subtle", 801 | ] 802 | 803 | [[package]] 804 | name = "utf8parse" 805 | version = "0.2.1" 806 | source = "registry+https://github.com/rust-lang/crates.io-index" 807 | checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" 808 | 809 | [[package]] 810 | name = "version_check" 811 | version = "0.9.4" 812 | source = "registry+https://github.com/rust-lang/crates.io-index" 813 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 814 | 815 | [[package]] 816 | name = "wait-timeout" 817 | version = "0.2.0" 818 | source = "registry+https://github.com/rust-lang/crates.io-index" 819 | checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" 820 | dependencies = [ 821 | "libc", 822 | ] 823 | 824 | [[package]] 825 | name = "which" 826 | version = "6.0.1" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | checksum = "8211e4f58a2b2805adfbefbc07bab82958fc91e3836339b1ab7ae32465dce0d7" 829 | dependencies = [ 830 | "either", 831 | "home", 832 | "rustix", 833 | "winsafe", 834 | ] 835 | 836 | [[package]] 837 | name = "windows-sys" 838 | version = "0.52.0" 839 | source = "registry+https://github.com/rust-lang/crates.io-index" 840 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 841 | dependencies = [ 842 | "windows-targets", 843 | ] 844 | 845 | [[package]] 846 | name = "windows-targets" 847 | version = "0.52.4" 848 | source = "registry+https://github.com/rust-lang/crates.io-index" 849 | checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" 850 | dependencies = [ 851 | "windows_aarch64_gnullvm", 852 | "windows_aarch64_msvc", 853 | "windows_i686_gnu", 854 | "windows_i686_msvc", 855 | "windows_x86_64_gnu", 856 | "windows_x86_64_gnullvm", 857 | "windows_x86_64_msvc", 858 | ] 859 | 860 | [[package]] 861 | name = "windows_aarch64_gnullvm" 862 | version = "0.52.4" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" 865 | 866 | [[package]] 867 | name = "windows_aarch64_msvc" 868 | version = "0.52.4" 869 | source = "registry+https://github.com/rust-lang/crates.io-index" 870 | checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" 871 | 872 | [[package]] 873 | name = "windows_i686_gnu" 874 | version = "0.52.4" 875 | source = "registry+https://github.com/rust-lang/crates.io-index" 876 | checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" 877 | 878 | [[package]] 879 | name = "windows_i686_msvc" 880 | version = "0.52.4" 881 | source = "registry+https://github.com/rust-lang/crates.io-index" 882 | checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" 883 | 884 | [[package]] 885 | name = "windows_x86_64_gnu" 886 | version = "0.52.4" 887 | source = "registry+https://github.com/rust-lang/crates.io-index" 888 | checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" 889 | 890 | [[package]] 891 | name = "windows_x86_64_gnullvm" 892 | version = "0.52.4" 893 | source = "registry+https://github.com/rust-lang/crates.io-index" 894 | checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" 895 | 896 | [[package]] 897 | name = "windows_x86_64_msvc" 898 | version = "0.52.4" 899 | source = "registry+https://github.com/rust-lang/crates.io-index" 900 | checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" 901 | 902 | [[package]] 903 | name = "winnow" 904 | version = "0.6.5" 905 | source = "registry+https://github.com/rust-lang/crates.io-index" 906 | checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" 907 | dependencies = [ 908 | "memchr", 909 | ] 910 | 911 | [[package]] 912 | name = "winsafe" 913 | version = "0.0.19" 914 | source = "registry+https://github.com/rust-lang/crates.io-index" 915 | checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" 916 | 917 | [[package]] 918 | name = "x25519-dalek" 919 | version = "2.0.1" 920 | source = "registry+https://github.com/rust-lang/crates.io-index" 921 | checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" 922 | dependencies = [ 923 | "curve25519-dalek", 924 | "rand_core", 925 | ] 926 | 927 | [[package]] 928 | name = "zeroize" 929 | version = "1.7.0" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" 932 | --------------------------------------------------------------------------------