diff --git a/Sources/ElixxirDAppsSDK/Errors.swift b/Sources/ElixxirDAppsSDK/Errors.swift
new file mode 100644
index 0000000000000000000000000000000000000000..acb286921b3942040e35de91cd173827c50f5c03
--- /dev/null
+++ b/Sources/ElixxirDAppsSDK/Errors.swift
@@ -0,0 +1,3 @@
+public struct BindingsDownloadAndVerifySignedNdfWithUrlUnknownError: Error, Equatable {
+  public init() {}
+}
diff --git a/Sources/ElixxirDAppsSDK/NDFDownloader.swift b/Sources/ElixxirDAppsSDK/NDFDownloader.swift
new file mode 100644
index 0000000000000000000000000000000000000000..c0552b99985d3a9b4c3a52fc554b2fad2a92a61c
--- /dev/null
+++ b/Sources/ElixxirDAppsSDK/NDFDownloader.swift
@@ -0,0 +1,36 @@
+import Bindings
+
+public struct NDFDownloader {
+  public var run: (Environment) throws -> Data
+
+  public func callAsFunction(_ env: Environment) throws -> Data {
+    try run(env)
+  }
+}
+
+extension NDFDownloader {
+  public static let live = NDFDownloader { env in
+    var error: NSError?
+    let data = BindingsDownloadAndVerifySignedNdfWithUrl(
+      env.url.absoluteString,
+      env.cert,
+      &error
+    )
+    if let error = error {
+      throw error
+    }
+    guard let data = data else {
+      throw BindingsDownloadAndVerifySignedNdfWithUrlUnknownError()
+    }
+    return data
+  }
+}
+
+#if DEBUG
+extension NDFDownloader {
+  public static let failing = NDFDownloader { _ in
+    struct NotImplemented: Error {}
+    throw NotImplemented()
+  }
+}
+#endif