about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--tvix/nix-compat/src/derivation/mod.rs8
-rw-r--r--tvix/nix-compat/src/derivation/tests/mod.rs21
-rw-r--r--tvix/nix-compat/src/nixhash/mod.rs24
-rw-r--r--tvix/nix-compat/src/nixhash/with_mode.rs56
-rw-r--r--tvix/nix-compat/src/store_path/utils.rs16
-rw-r--r--tvix/store/src/store_io.rs17
6 files changed, 99 insertions, 43 deletions
diff --git a/tvix/nix-compat/src/derivation/mod.rs b/tvix/nix-compat/src/derivation/mod.rs
index 318f2cc1ae99..0e98e24f43dd 100644
--- a/tvix/nix-compat/src/derivation/mod.rs
+++ b/tvix/nix-compat/src/derivation/mod.rs
@@ -185,7 +185,13 @@ impl Derivation {
 
             hasher.finalize().to_vec()
         });
-        NixHash::new(crate::nixhash::HashAlgo::Sha256, digest.to_vec())
+
+        // We populate the struct directly, as we know the sha256 digest has the
+        // right size.
+        NixHash {
+            algo: crate::nixhash::HashAlgo::Sha256,
+            digest: digest.to_vec(),
+        }
     }
 
     /// This calculates all output paths of a Derivation and updates the struct.
diff --git a/tvix/nix-compat/src/derivation/tests/mod.rs b/tvix/nix-compat/src/derivation/tests/mod.rs
index 1818a08c9bc3..de4ebb6cb20e 100644
--- a/tvix/nix-compat/src/derivation/tests/mod.rs
+++ b/tvix/nix-compat/src/derivation/tests/mod.rs
@@ -1,6 +1,5 @@
 use crate::derivation::output::Output;
 use crate::derivation::Derivation;
-use crate::nixhash::NixHash;
 use crate::store_path::StorePath;
 use bstr::{BStr, BString};
 use std::collections::{BTreeMap, BTreeSet};
@@ -238,15 +237,19 @@ fn output_path_construction() {
         "out".to_string(),
         Output {
             path: "".to_string(), // will be calculated
-            hash_with_mode: Some(crate::nixhash::NixHashWithMode::Recursive(NixHash {
-                digest: data_encoding::HEXLOWER
-                    .decode(
-                        "08813cbee9903c62be4c5027726a418a300da4500b2d369d3af9286f4815ceba"
-                            .as_bytes(),
-                    )
+            hash_with_mode: Some(crate::nixhash::NixHashWithMode::Recursive(
+                (
+                    crate::nixhash::HashAlgo::Sha256,
+                    data_encoding::HEXLOWER
+                        .decode(
+                            "08813cbee9903c62be4c5027726a418a300da4500b2d369d3af9286f4815ceba"
+                                .as_bytes(),
+                        )
+                        .unwrap(),
+                )
+                    .try_into()
                     .unwrap(),
-                algo: crate::nixhash::HashAlgo::Sha256,
-            })),
+            )),
         },
     );
 
diff --git a/tvix/nix-compat/src/nixhash/mod.rs b/tvix/nix-compat/src/nixhash/mod.rs
index 77a9035901d9..2bd24d4ed3db 100644
--- a/tvix/nix-compat/src/nixhash/mod.rs
+++ b/tvix/nix-compat/src/nixhash/mod.rs
@@ -1,6 +1,6 @@
 use crate::nixbase32;
 use data_encoding::{BASE64, BASE64_NOPAD, HEXLOWER};
-use thiserror::Error;
+use thiserror;
 
 mod algos;
 mod with_mode;
@@ -18,11 +18,6 @@ pub struct NixHash {
 }
 
 impl NixHash {
-    /// Constructs a new [NixHash] by specifying [HashAlgo] and digest.
-    pub fn new(algo: HashAlgo, digest: Vec<u8>) -> Self {
-        Self { algo, digest }
-    }
-
     /// Formats a [NixHash] in the Nix default hash format,
     /// which is the algo, followed by a colon, then the lower hex encoded digest.
     pub fn to_nix_hash_string(&self) -> String {
@@ -30,8 +25,23 @@ impl NixHash {
     }
 }
 
+impl TryFrom<(HashAlgo, Vec<u8>)> for NixHash {
+    type Error = Error;
+
+    /// Constructs a new [NixHash] by specifying [HashAlgo] and digest.
+    // It can fail if the passed digest length doesn't match what's expected for
+    // the passed algo.
+    fn try_from(value: (HashAlgo, Vec<u8>)) -> Result<Self, Self::Error> {
+        let (algo, digest) = value;
+        if digest.len() != hash_algo_length(&algo) {
+            return Err(Error::InvalidEncodedDigestLength(digest.len(), algo));
+        }
+        Ok(Self { algo, digest })
+    }
+}
+
 /// Errors related to NixHash construction.
-#[derive(Debug, Error)]
+#[derive(Debug, thiserror::Error)]
 pub enum Error {
     #[error("invalid hash algo: {0}")]
     InvalidAlgo(String),
diff --git a/tvix/nix-compat/src/nixhash/with_mode.rs b/tvix/nix-compat/src/nixhash/with_mode.rs
index 344322046614..caf14331426a 100644
--- a/tvix/nix-compat/src/nixhash/with_mode.rs
+++ b/tvix/nix-compat/src/nixhash/with_mode.rs
@@ -1,5 +1,5 @@
 use crate::nixbase32;
-use crate::nixhash::{HashAlgo, NixHash};
+use crate::nixhash::{self, HashAlgo, NixHash};
 use serde::de::Unexpected;
 use serde::ser::SerializeMap;
 use serde::{Deserialize, Deserializer, Serialize, Serializer};
@@ -102,24 +102,42 @@ impl NixHashWithMode {
         if let Some(v) = map.get("hashAlgo") {
             if let Some(s) = v.as_str() {
                 match s.strip_prefix("r:") {
-                    Some(rest) => Ok(Some(Self::Recursive(NixHash::new(
-                        HashAlgo::try_from(rest).map_err(|e| {
-                            serde::de::Error::invalid_value(
-                                Unexpected::Other(&e.to_string()),
-                                &format!("one of {}", SUPPORTED_ALGOS.join(",")).as_str(),
-                            )
-                        })?,
-                        digest,
-                    )))),
-                    None => Ok(Some(Self::Flat(NixHash::new(
-                        HashAlgo::try_from(s).map_err(|e| {
-                            serde::de::Error::invalid_value(
-                                Unexpected::Other(&e.to_string()),
-                                &format!("one of {}", SUPPORTED_ALGOS.join(",")).as_str(),
-                            )
-                        })?,
-                        digest,
-                    )))),
+                    Some(rest) => Ok(Some(Self::Recursive(
+                        (
+                            HashAlgo::try_from(rest).map_err(|e| {
+                                serde::de::Error::invalid_value(
+                                    Unexpected::Other(&e.to_string()),
+                                    &format!("one of {}", SUPPORTED_ALGOS.join(",")).as_str(),
+                                )
+                            })?,
+                            digest,
+                        )
+                            .try_into()
+                            .map_err(|e: nixhash::Error| {
+                                serde::de::Error::invalid_value(
+                                    Unexpected::Other(&e.to_string()),
+                                    &"a digest with right length",
+                                )
+                            })?,
+                    ))),
+                    None => Ok(Some(Self::Flat(
+                        (
+                            HashAlgo::try_from(s).map_err(|e| {
+                                serde::de::Error::invalid_value(
+                                    Unexpected::Other(&e.to_string()),
+                                    &format!("one of {}", SUPPORTED_ALGOS.join(",")).as_str(),
+                                )
+                            })?,
+                            digest,
+                        )
+                            .try_into()
+                            .map_err(|e: nixhash::Error| {
+                                serde::de::Error::invalid_value(
+                                    Unexpected::Other(&e.to_string()),
+                                    &"a digest with right length",
+                                )
+                            })?,
+                    ))),
                 }
             } else {
                 Err(serde::de::Error::invalid_type(
diff --git a/tvix/nix-compat/src/store_path/utils.rs b/tvix/nix-compat/src/store_path/utils.rs
index 26f6e0085c9d..201d98cce460 100644
--- a/tvix/nix-compat/src/store_path/utils.rs
+++ b/tvix/nix-compat/src/store_path/utils.rs
@@ -54,7 +54,13 @@ pub fn build_text_path<S: AsRef<str>, I: IntoIterator<Item = S>, C: AsRef<[u8]>>
                 let hasher = Sha256::new_with_prefix(content);
                 hasher.finalize()
             };
-            NixHash::new(crate::nixhash::HashAlgo::Sha256, content_digest.to_vec())
+
+            // We populate the struct directly, as we know the sha256 digest has the
+            // right size.
+            NixHash {
+                algo: crate::nixhash::HashAlgo::Sha256,
+                digest: content_digest.to_vec(),
+            }
         },
         name,
     )
@@ -100,7 +106,13 @@ pub fn build_regular_ca_path<S: AsRef<str>, I: IntoIterator<Item = S>>(
                         hasher.update(":");
                         hasher.finalize()
                     };
-                    NixHash::new(crate::nixhash::HashAlgo::Sha256, content_digest.to_vec())
+
+                    // We don't use [NixHash::from_algo_and_digest], as we know [Sha256] has
+                    // the right digest size.
+                    NixHash {
+                        algo: crate::nixhash::HashAlgo::Sha256,
+                        digest: content_digest.to_vec(),
+                    }
                 },
                 name,
             )
diff --git a/tvix/store/src/store_io.rs b/tvix/store/src/store_io.rs
index 1030bbdd337f..615d1f50f4a3 100644
--- a/tvix/store/src/store_io.rs
+++ b/tvix/store/src/store_io.rs
@@ -114,9 +114,12 @@ impl TvixStoreIO {
         )
         .expect("error during nar calculation"); // TODO: handle error
 
-        // For given NAR sha256 digest and name, return the new [StorePath] this would have.
-        let nar_hash_with_mode =
-            NixHashWithMode::Recursive(NixHash::new(HashAlgo::Sha256, nar_sha256.to_vec()));
+        // We populate the struct directly, as we know the sha256 digest has the
+        // right size.
+        let nar_hash_with_mode = NixHashWithMode::Recursive(NixHash {
+            algo: HashAlgo::Sha256,
+            digest: nar_sha256.to_vec(),
+        });
 
         let name = path
             .file_name()
@@ -172,8 +175,12 @@ impl TvixStoreIO {
 /// For given NAR sha256 digest and name, return the new [StorePath] this would have.
 #[instrument(skip(nar_sha256_digest), ret, fields(nar_sha256_digest=BASE64.encode(nar_sha256_digest)))]
 fn calculate_nar_based_store_path(nar_sha256_digest: &[u8; 32], name: &str) -> StorePath {
-    let nar_hash_with_mode =
-        NixHashWithMode::Recursive(NixHash::new(HashAlgo::Sha256, nar_sha256_digest.to_vec()));
+    // We populate the struct directly, as we know the sha256 digest has the
+    // right size.
+    let nar_hash_with_mode = NixHashWithMode::Recursive(NixHash {
+        algo: HashAlgo::Sha256,
+        digest: nar_sha256_digest.to_vec(),
+    });
 
     build_regular_ca_path(name, &nar_hash_with_mode, Vec::<String>::new(), false).unwrap()
 }