diff --git a/Makefile.am b/Makefile.am
index be1dc7f7ef1a29a83ddc41b95033b4f251ac96e9..b8aa049da104040ed4464a02029ec004b60e62fd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -25,6 +25,12 @@ else
 TESTING_TOR_BINARY=$(top_builddir)/src/or/tor$(EXEEXT)
 endif
 
+if USE_RUST
+rust_ldadd=
+else
+rust_ldadd=
+endif
+
 include src/include.am
 include doc/include.am
 include contrib/include.am
diff --git a/configure.ac b/configure.ac
index ff917354a39219728fb7de6fa5ba5e9f3b67a31b..d281903fcc0a1949b17ede4f0eba3fefa6e2d22c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -55,6 +55,8 @@ AC_ARG_ENABLE(oss-fuzz,
    AS_HELP_STRING(--enable-oss-fuzz, [build extra fuzzers based on 'oss-fuzz' environment]))
 AC_ARG_ENABLE(memory-sentinels,
    AS_HELP_STRING(--disable-memory-sentinels, [disable code that tries to prevent some kinds of memory access bugs. For fuzzing only.]))
+AC_ARG_ENABLE(rust,
+   AS_HELP_STRING(--enable-rust, [enable rust integration]))
 
 if test "x$enable_coverage" != "xyes" -a "x$enable_asserts_in_tests" = "xno" ; then
     AC_MSG_ERROR([Can't disable assertions outside of coverage build])
@@ -65,6 +67,7 @@ AM_CONDITIONAL(COVERAGE_ENABLED, test "x$enable_coverage" = "xyes")
 AM_CONDITIONAL(DISABLE_ASSERTS_IN_UNIT_TESTS, test "x$enable_asserts_in_tests" = "xno")
 AM_CONDITIONAL(LIBFUZZER_ENABLED, test "x$enable_libfuzzer" = "xyes")
 AM_CONDITIONAL(OSS_FUZZ_ENABLED, test "x$enable_oss_fuzz" = "xyes")
+AM_CONDITIONAL(USE_RUST, test "x$enable_rust" = "xyes")
 
 if test "$enable_static_tor" = "yes"; then
   enable_static_libevent="yes";
@@ -249,6 +252,23 @@ if test "x$PYTHON" = "x"; then
 fi
 AM_CONDITIONAL(USEPYTHON, [test "x$PYTHON" != "x"])
 
+
+if test "x$enable_rust" = "xyes"; then
+  AC_ARG_VAR([RUSTC], [path to the rustc binary])
+  AC_CHECK_PROG([RUSTC], [rustc], [rustc],[no])
+  if test "x$RUSTC" = "xno"; then
+    AC_MSG_ERROR([rustc unavailable but rust integration requested.])
+  fi
+
+  AC_ARG_VAR([CARGO], [path to the cargo binary])
+  AC_CHECK_PROG([CARGO], [cargo], [cargo],[no])
+  if test "x$CARGO" = "xno"; then
+    AC_MSG_ERROR([cargo unavailable but rust integration requested.])
+  fi
+
+  AC_DEFINE([HAVE_RUST], 1, [have Rust])
+fi
+
 ifdef([AC_C_FLEXIBLE_ARRAY_MEMBER], [
 AC_C_FLEXIBLE_ARRAY_MEMBER
 ], [
diff --git a/src/include.am b/src/include.am
index f78853f50ff0bb6886981ae502d3b1fe90c91c26..90ecf90d45509205ce7b93aa9acb0254b58ce072 100644
--- a/src/include.am
+++ b/src/include.am
@@ -2,6 +2,7 @@ include src/ext/include.am
 include src/trunnel/include.am
 include src/common/include.am
 include src/or/include.am
+include src/rust/include.am
 include src/test/include.am
 include src/tools/include.am
 include src/win32/include.am
diff --git a/src/or/include.am b/src/or/include.am
index 4c24dd23b3b5438e1256791ac3716d93bd206df6..ff7110ea99b0e1b052aa98bb527e571d98242b39 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -123,7 +123,8 @@ src_or_tor_LDADD = src/or/libtor.a src/common/libor.a src/common/libor-ctime.a \
 	src/trace/libor-trace.a \
 	@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
 	@TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \
-	@TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+	@TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ \
+	$(rust_ldadd)
 
 if COVERAGE_ENABLED
 src_or_tor_cov_SOURCES = src/or/tor_main.c
diff --git a/src/test/fuzz/include.am b/src/test/fuzz/include.am
index 500377f6d77a100bbfd1654c28b5513cd3e6a281..6008238bba25402651f8790edbafaa7731346251 100644
--- a/src/test/fuzz/include.am
+++ b/src/test/fuzz/include.am
@@ -20,7 +20,8 @@ FUZZING_LIBS = \
 	@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
 	@TOR_SYSTEMD_LIBS@ \
 	@TOR_LZMA_LIBS@ \
-	@TOR_ZSTD_LIBS@
+	@TOR_ZSTD_LIBS@ \
+	$(rust_ldadd)
 
 oss-fuzz-prereqs: \
 	src/or/libtor-testing.a \
diff --git a/src/test/include.am b/src/test/include.am
index 230a6c8bad05271a62d71d10ab858fa18f6cc7f2..8a465877d3fec0b0848001522be1fa879b590fad 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -181,7 +181,8 @@ src_test_test_switch_id_LDADD = \
 	src/common/libor-testing.a \
 	src/common/libor-ctime-testing.a \
 	@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
-	@TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+	@TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ \
+	$(rust_ldadd)
 
 src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
         @TOR_LDFLAGS_libevent@
@@ -196,7 +197,8 @@ src_test_test_LDADD = src/or/libtor-testing.a \
 	src/trace/libor-trace.a \
 	@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
 	@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
-	@TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+	@TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ \
+	$(rust_ldadd)
 
 src_test_test_slow_CPPFLAGS = $(src_test_test_CPPFLAGS)
 src_test_test_slow_CFLAGS = $(src_test_test_CFLAGS)
@@ -220,7 +222,8 @@ src_test_bench_LDADD = src/or/libtor.a src/common/libor.a \
 	src/trace/libor-trace.a \
 	@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
 	@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
-	@TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+	@TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ \
+	$(rust_ldadd)
 
 src_test_test_workqueue_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \
         @TOR_LDFLAGS_libevent@
@@ -232,7 +235,8 @@ src_test_test_workqueue_LDADD = src/or/libtor-testing.a \
 	src/trace/libor-trace.a \
 	@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
 	@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
-	@TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@
+	@TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ \
+	$(rust_ldadd)
 
 src_test_test_timers_CPPFLAGS = $(src_test_test_CPPFLAGS)
 src_test_test_timers_CFLAGS = $(src_test_test_CFLAGS)
@@ -243,7 +247,8 @@ src_test_test_timers_LDADD = \
 	src/common/libor-crypto-testing.a $(LIBKECCAK_TINY) $(LIBDONNA) \
 	@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \
 	@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
-	@TOR_LZMA_LIBS@
+	@TOR_LZMA_LIBS@ \
+	$(rust_ldadd)
 src_test_test_timers_LDFLAGS = $(src_test_test_LDFLAGS)
 
 noinst_HEADERS+= \
@@ -270,7 +275,8 @@ src_test_test_ntor_cl_LDADD = src/or/libtor.a src/common/libor.a \
 	src/trace/libor-trace.a \
 	@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \
 	@TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
-	@TOR_LZMA_LIBS@
+	@TOR_LZMA_LIBS@ \
+	$(rust_ldadd)
 src_test_test_ntor_cl_AM_CPPFLAGS =	       \
 	-I"$(top_srcdir)/src/or"
 
@@ -291,7 +297,8 @@ src_test_test_bt_cl_LDADD = src/common/libor-testing.a \
 	src/common/libor-ctime-testing.a \
 	src/trace/libor-trace.a \
 	@TOR_LIB_MATH@ \
-	@TOR_LIB_WS32@ @TOR_LIB_GDI@
+	@TOR_LIB_WS32@ @TOR_LIB_GDI@ \
+	$(rust_ldadd)
 src_test_test_bt_cl_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
 src_test_test_bt_cl_CPPFLAGS= $(src_test_AM_CPPFLAGS) $(TEST_CPPFLAGS)
 
diff --git a/src/tools/include.am b/src/tools/include.am
index 5eadb03a053e9562b464e5bf9c72a084651efef6..717af9e2aebd750fe586430e06bc7f3b345253d7 100644
--- a/src/tools/include.am
+++ b/src/tools/include.am
@@ -8,7 +8,8 @@ src_tools_tor_resolve_SOURCES = src/tools/tor-resolve.c
 src_tools_tor_resolve_LDFLAGS =
 src_tools_tor_resolve_LDADD = src/common/libor.a \
 	src/common/libor-ctime.a \
-	@TOR_LIB_MATH@ @TOR_LIB_WS32@
+	@TOR_LIB_MATH@ @TOR_LIB_WS32@ \
+	$(rust_ldadd)
 
 if COVERAGE_ENABLED
 src_tools_tor_cov_resolve_SOURCES = src/tools/tor-resolve.c
@@ -22,11 +23,12 @@ endif
 src_tools_tor_gencert_SOURCES = src/tools/tor-gencert.c
 src_tools_tor_gencert_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@
 src_tools_tor_gencert_LDADD = src/common/libor.a src/common/libor-crypto.a \
-    src/common/libor-ctime.a \
-    $(LIBKECCAK_TINY) \
-    $(LIBDONNA) \
-    @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \
-    @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+	src/common/libor-ctime.a \
+	$(LIBKECCAK_TINY) \
+	$(LIBDONNA) \
+	@TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \
+	@TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ \
+	$(rust_ldadd)
 
 if COVERAGE_ENABLED
 src_tools_tor_cov_gencert_SOURCES = src/tools/tor-gencert.c