Repository: dalek-cryptography/curve25519-dalek (language: rust)

Issue:
Pointer width detection in `build.rs`  may break for obscure platforms
[The build.rs file](https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/build.rs) currently uses the `platforms` crate to map the rustc target triples to pointer width. I am the author of the `platforms` crate :wave: 

The `platforms` crate adds and removes targets following the target support in the latest release of rustc. This means that the list of targets it knows about may be different from the list of targets that your local `rustc` knows about.

It would be better to query the Rust compiler directly instead of relying on the `platforms` crate. You can do it with `rustc --print=cfg --target=TRIPLE`, e.g. `rustc --print=cfg --target x86_64-unknown-uefi` will print the pointer width, among other things. By sourcing it from the compiler that performs the build, there is no chance of the pointer width data to be missing.


Discussion / hints:
Thanks - Yeah thought about that but `platforms` was just ergonomic at the time.

I also thought we could expand to `rustc-metadata` but then there was already [rustc-cfg](https://crates.io/crates/rustc-cfg) which we could add and could be suited for the task either with modifications or directly.

But [we've used environment variables](https://github.com/dalek-cryptography/curve25519-dalek/blob/main/curve25519-dalek/build.rs#L39C44-L39C61) for this which even `rustc-cfg` recommends over that create - also saving dep as a bonus.

So I guess we can just read the environment variable `CARGO_CFG_TARGET_POINTER_WIDTH` instead and drop the dep indeed despite it being slightly ergonomic and giving better idea about obscure platforms as you've noted :+1: 

EDIT: One downside is that we need to deal with string match when figuring out whether a platform default override is in future - and it could be helpful to turn this into type proper if / when there is decision to set any wasm/aarch64 target_pointer_width as default 64 over 32 - nonetheless ideally these should be set explciitly via curve25519_dalek_bits

Fix patch:
diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml
index 48dcb977d..f8c7c3a8e 100644
--- a/curve25519-dalek/Cargo.toml
+++ b/curve25519-dalek/Cargo.toml
@@ -38,7 +38,6 @@ rand = "0.8"
 rand_core = { version = "0.6", default-features = false, features = ["getrandom"] }
 
 [build-dependencies]
-platforms = "3.0.2"
 rustc_version = "0.4.0"
 
 [[bench]]
diff --git a/curve25519-dalek/build.rs b/curve25519-dalek/build.rs
index 92d2802cd..97fa28524 100644
--- a/curve25519-dalek/build.rs
+++ b/curve25519-dalek/build.rs
@@ -9,17 +9,31 @@ enum DalekBits {
     Dalek64,
 }
 
+use std::fmt::Formatter;
+
+impl std::fmt::Display for DalekBits {
+    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
+        let w_bits = match self {
+            DalekBits::Dalek32 => "32",
+            DalekBits::Dalek64 => "64",
+        };
+        write!(f, "{}", w_bits)
+    }
+}
+
 fn main() {
+    let target_arch = match std::env::var("CARGO_CFG_TARGET_ARCH") {
+        Ok(arch) => arch,
+        _ => "".to_string(),
+    };
+
     let curve25519_dalek_bits = match std::env::var("CARGO_CFG_CURVE25519_DALEK_BITS").as_deref() {
         Ok("32") => DalekBits::Dalek32,
         Ok("64") => DalekBits::Dalek64,
-        _ => deterministic::determine_curve25519_dalek_bits(),
+        _ => deterministic::determine_curve25519_dalek_bits(&target_arch),
     };
 
-    match curve25519_dalek_bits {
-        DalekBits::Dalek64 => println!("cargo:rustc-cfg=curve25519_dalek_bits=\"64\""),
-        DalekBits::Dalek32 => println!("cargo:rustc-cfg=curve25519_dalek_bits=\"32\""),
-    }
+    println!("cargo:rustc-cfg=curve25519_dalek_bits=\"{curve25519_dalek_bits}\"");
 
     if rustc_version::version_meta()
         .expect("failed to detect rustc version")
@@ -36,11 +50,6 @@ fn main() {
         println!("cargo:rustc-cfg=allow_unused_unsafe");
     }
 
-    let target_arch = match std::env::var("CARGO_CFG_TARGET_ARCH") {
-        Ok(arch) => arch,
-        _ => "".to_string(),
-    };
-
     // Backend overrides / defaults
     let curve25519_dalek_backend =
         match std::env::var("CARGO_CFG_CURVE25519_DALEK_BACKEND").as_deref() {
@@ -74,11 +83,12 @@ mod deterministic {
 
     use super::*;
 
-    // Standard Cargo TARGET environment variable of triplet is required
-    static ERR_MSG_NO_TARGET: &str = "Standard Cargo TARGET environment variable is not set";
+    // Custom Rust non-cargo build tooling needs to set CARGO_CFG_TARGET_POINTER_WIDTH
+    static ERR_MSG_NO_POINTER_WIDTH: &str =
+        "Standard Cargo TARGET_POINTER_WIDTH environment variable is not set.";
 
-    // Custom Non-Rust standard target platforms require explicit settings.
-    static ERR_MSG_NO_PLATFORM: &str = "Unknown Rust target platform.";
+    // When either non-32 or 64 TARGET_POINTER_WIDTH detected
+    static ERR_MSG_UNKNOWN_POINTER_WIDTH: &str = "Unknown TARGET_POINTER_WIDTH detected.";
 
     // Warning when the curve25519_dalek_bits cannot be determined
     fn determine_curve25519_dalek_bits_warning(cause: &str) {
@@ -86,41 +96,30 @@ mod deterministic {
     }
 
     // Determine the curve25519_dalek_bits based on Rust standard TARGET triplet
-    pub(super) fn determine_curve25519_dalek_bits() -> DalekBits {
-        use platforms::target::PointerWidth;
-
-        // TARGET environment is supplied by Cargo
-        // https://doc.rust-lang.org/cargo/reference/environment-variables.html
-        let target_triplet = match std::env::var("TARGET") {
-            Ok(t) => t,
+    pub(super) fn determine_curve25519_dalek_bits(target_arch: &String) -> DalekBits {
+        let target_pointer_width = match std::env::var("CARGO_CFG_TARGET_POINTER_WIDTH") {
+            Ok(pw) => pw,
             Err(_) => {
-                determine_curve25519_dalek_bits_warning(ERR_MSG_NO_TARGET);
-                return DalekBits::Dalek32;
-            }
-        };
-
-        // platforms crate is the source of truth used to determine the platform
-        let platform = match platforms::Platform::find(&target_triplet) {
-            Some(p) => p,
-            None => {
-                determine_curve25519_dalek_bits_warning(ERR_MSG_NO_PLATFORM);
+                determine_curve25519_dalek_bits_warning(ERR_MSG_NO_POINTER_WIDTH);
                 return DalekBits::Dalek32;
             }
         };
 
         #[allow(clippy::match_single_binding)]
-        match platform.target_arch {
+        match &target_arch {
             //Issues: 449 and 456
+            //TODO: When adding arch defaults use proper types not String match
             //TODO(Arm): Needs tests + benchmarks to back this up
-            //platforms::target::Arch::Arm => DalekBits::Dalek64,
             //TODO(Wasm32): Needs tests + benchmarks to back this up
-            //platforms::target::Arch::Wasm32 => DalekBits::Dalek64,
-            _ => match platform.target_pointer_width {
-                PointerWidth::U64 => DalekBits::Dalek64,
-                PointerWidth::U32 => DalekBits::Dalek32,
+            _ => match target_pointer_width.as_ref() {
+                "64" => DalekBits::Dalek64,
+                "32" => DalekBits::Dalek32,
                 // Intended default solely for non-32/64 target pointer widths
                 // Otherwise known target platforms only.
-                _ => DalekBits::Dalek32,
+                _ => {
+                    determine_curve25519_dalek_bits_warning(ERR_MSG_UNKNOWN_POINTER_WIDTH);
+                    DalekBits::Dalek32
+                }
             },
         }
     }


Test patch: