diff --git a/.gitignore b/.gitignore
index 0c59a1541b9974aaafede7c8c6b5cb584f4fa4fe..4c4a8eefcbf67e936e42ae2b4d60ed4dcb500af1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
 /android-ndk
-/tor-android
+/tor-build
+!/tor-build/Makefile
 /android-ndk.zip
 tor-*.zip
 tor-*.pom
diff --git a/README.md b/README.md
index 5b637372ede7b54295ceb2875d89f944f75df05f..b84565fc96001060d4979468c89dc85b359582be 100644
--- a/README.md
+++ b/README.md
@@ -66,8 +66,13 @@ There should be a tag with the name `[version]` in this repository
 that you could be used to reproduce the old container.
 Note that this will not work if the issue is caused by an updated Debian package.
 
+### Historical changes
+
+The Tor 0.3.x series had a different build system than the 0.4.x series.
+Please use a version of tor-reproducer that starts with 0.3 to reproduce those.
+
 ### Only build Tor
 
 To build a specific version of Tor, run
 
-    docker run briar/tor-reproducer:latest ./build_tor.py [version]
\ No newline at end of file
+    docker run briar/tor-reproducer:latest ./build_tor.py [version]
diff --git a/build_tor_android.py b/build_tor_android.py
index e6e07f3fb05f733e49168bd71e8907d579c7fa17..ffb92bc8e15b2eb9c25382e73d399b5142d5fec7 100755
--- a/build_tor_android.py
+++ b/build_tor_android.py
@@ -4,7 +4,7 @@ from shutil import rmtree, move, copy
 from subprocess import check_call
 
 import utils
-from utils import get_sha256, fail, REPO_DIR, EXT_DIR, reset_time
+from utils import get_sha256, fail, BUILD_DIR, OUTPUT_DIR, reset_time
 
 NDK_DIR = 'android-ndk'
 PLATFORM = "android"
@@ -58,7 +58,12 @@ def setup_android_ndk(versions):
 
 
 def build_android(versions):
-    os.environ.pop("PIEFLAGS", None)  # uses default PIE flags, if not present
+    # apply tor-android patches first
+    apply_tor_patch("6522c8a2ae9b2f9c4c488188f88d38728ee487a7")
+    apply_tor_patch("fbd64bbed2848eb17c559a4c599a6834eb7db33a")
+
+    # use default PIE flags, if not present
+    os.environ.pop("PIEFLAGS", None)
 
     # build arm pie
     env = os.environ.copy()
@@ -87,20 +92,34 @@ def build_android(versions):
 
 def build_android_arch(name, env, versions):
     print("Building %s" % name)
-    check_call(['make', '-C', 'external', 'clean', 'tor'], cwd=REPO_DIR, env=env)
-    copy(os.path.join(EXT_DIR, 'bin', 'tor'), os.path.join(REPO_DIR, 'tor'))
-    check_call(['strip', '-D', 'tor'], cwd=REPO_DIR)
-    tor_path = os.path.join(REPO_DIR, 'tor')
+    # TODO add extra flags to configure?
+    #  '--enable-static-tor',
+    #  '--enable-static-zlib',
+    check_call(['make', 'clean', 'tor'], cwd=BUILD_DIR, env=env)
+    tor_path = os.path.join(OUTPUT_DIR, 'tor')
+    # note: stripping happens in makefile for now
+    copy(os.path.join(BUILD_DIR, 'tor', 'src', 'app', 'tor'), tor_path)
     reset_time(tor_path, versions)
     print("Sha256 hash of tor before zipping %s: %s" % (name, get_sha256(tor_path)))
-    check_call(['zip', '-X', '../' + name, 'tor'], cwd=REPO_DIR)
+    check_call(['zip', '--no-dir-entries', '--junk-paths', '-X', name, 'tor'], cwd=OUTPUT_DIR)
+
+
+def apply_tor_patch(commit):
+    tor_path = os.path.join(BUILD_DIR, 'tor')
+    check_call(['wget', '--no-verbose', 'https://github.com/guardianproject/tor/commit/' + commit + '.patch'],
+               cwd=tor_path)
+    check_call(['git', 'apply', commit + '.patch'], cwd=tor_path)
 
 
 def package_android(versions):
     # zip Android binaries together
-    file_list_android = ['tor_arm_pie.zip', 'tor_arm64_pie.zip',
-                         'tor_x86_pie.zip', 'tor_x86_64_pie.zip',
-                         'geoip.zip']
+    file_list_android = [
+        os.path.join(OUTPUT_DIR, 'tor_arm_pie.zip'),
+        os.path.join(OUTPUT_DIR, 'tor_arm64_pie.zip'),
+        os.path.join(OUTPUT_DIR, 'tor_x86_pie.zip'),
+        os.path.join(OUTPUT_DIR, 'tor_x86_64_pie.zip'),
+        os.path.join(OUTPUT_DIR, 'geoip.zip'),
+    ]
     zip_name_android = utils.pack(versions, file_list_android, PLATFORM)
     pom_name_android = utils.create_pom_file(versions, PLATFORM)
     print("Android:")
diff --git a/build_tor_linux.py b/build_tor_linux.py
index 15164fdc25cd56b8425ce5db40470f45128e1cad..cedbeae0b2b0c8a9de750b7ae63cf95b8e0ef6f5 100755
--- a/build_tor_linux.py
+++ b/build_tor_linux.py
@@ -4,7 +4,8 @@ from shutil import rmtree, copy
 from subprocess import check_call
 
 import utils
-from utils import REPO_DIR, EXT_DIR, reset_time, get_sha256
+from utils import BUILD_DIR, OUTPUT_DIR, TOR_CONFIGURE_FLAGS, OPENSSL_CONFIGURE_FLAGS, REPRODUCIBLE_GCC_CFLAGS, \
+    XZ_CONFIGURE_FLAGS, reset_time, get_sha256, pack, create_pom_file
 
 PLATFORM = "linux"
 
@@ -27,12 +28,12 @@ def build_linux(versions):
 def build_linux_arch(arch, gcc_arch, cc_env, openssl_target, autogen_host, versions):
     name = "tor_linux-%s.zip" % arch
     print("Building %s" % name)
-    prefix_dir = os.path.abspath(os.path.join(REPO_DIR, 'prefix'))
+    prefix_dir = os.path.abspath(os.path.join(BUILD_DIR, 'prefix'))
     lib_dir = os.path.join(prefix_dir, 'lib')
     include_dir = os.path.join(prefix_dir, 'include')
 
     # ensure clean build environment (again here to protect against build reordering)
-    utils.prepare_tor_android_repo(versions)
+    utils.prepare_repos(versions)
     if os.path.exists(prefix_dir):
         rmtree(prefix_dir)
 
@@ -43,61 +44,96 @@ def build_linux_arch(arch, gcc_arch, cc_env, openssl_target, autogen_host, versi
 
     # setup environment
     env = os.environ.copy()
+    env['SOURCE_DATE_EPOCH'] = "1234567890"
     env['LDFLAGS'] = "-L%s" % lib_dir
     env['LD_LIBRARY_PATH'] = lib_dir
-    env['CFLAGS'] = "-fPIC -I%s" % include_dir
+    env['CFLAGS'] = REPRODUCIBLE_GCC_CFLAGS + ' -fPIC -I%s' % include_dir
+    env['PKG_CONFIG_PATH'] = os.path.join(lib_dir, 'pkgconfig')
     env['LIBS'] = "-ldl -L%s" % lib_dir
     env['CC'] = cc_env
 
+    # build lzma
+    xz_dir = os.path.join(BUILD_DIR, 'xz')
+    check_call(['./autogen.sh'], cwd=xz_dir)
+    check_call(['./configure',
+                '--prefix=%s' % prefix_dir,
+                '--host=%s' % autogen_host,
+                ] + XZ_CONFIGURE_FLAGS, cwd=xz_dir, env=env)
+    check_call(['make', '-j', str(os.cpu_count()), 'install'], cwd=xz_dir, env=env)
+
+    # build zstd
+    zstd_dir = os.path.join(BUILD_DIR, 'zstd', "lib")
+    check_call(['make', '-j', str(os.cpu_count()), 'DESTDIR=%s' % prefix_dir, 'PREFIX=""', 'install'],
+               cwd=zstd_dir, env=env)
+
     # build zlib
-    zlib_dir = os.path.join(EXT_DIR, 'zlib')
+    zlib_dir = os.path.join(BUILD_DIR, 'zlib')
     check_call(['./configure', '--prefix=%s' % prefix_dir], cwd=zlib_dir, env=env)
-    check_call(['make', 'install'], cwd=zlib_dir, env=env)
+    check_call(['make', '-j', str(os.cpu_count()), 'install'], cwd=zlib_dir, env=env)
 
     # build openssl
-    openssl_dir = os.path.join(EXT_DIR, 'openssl')
-    check_call(['perl', 'Configure', '--prefix=%s' % prefix_dir,
-                '--openssldir=%s' % prefix_dir, '-march=%s' % gcc_arch,
-                openssl_target, 'shared'], cwd=openssl_dir, env=env)
-    check_call(['make'], cwd=openssl_dir, env=env)
+    openssl_dir = os.path.join(BUILD_DIR, 'openssl')
+    extra_flags = []
+    if autogen_host.endswith("64"):
+        extra_flags = ['enable-ec_nistp_64_gcc_128']
+    check_call(['perl', 'Configure',
+                '--prefix=%s' % prefix_dir,
+                '--openssldir=%s' % prefix_dir,
+                '-march=%s' % gcc_arch,
+                openssl_target,
+                'shared',
+                ] + OPENSSL_CONFIGURE_FLAGS + extra_flags, cwd=openssl_dir, env=env)
+    check_call(['make', '-j', str(os.cpu_count())], cwd=openssl_dir, env=env)
     check_call(['make', 'install_sw'], cwd=openssl_dir, env=env)
 
     # build libevent
-    libevent_dir = os.path.join(EXT_DIR, 'libevent')
+    libevent_dir = os.path.join(BUILD_DIR, 'libevent')
     check_call(['./autogen.sh'], cwd=libevent_dir)
     check_call(['./configure', '--disable-shared', '--prefix=%s' % prefix_dir,
                 '--host=%s' % autogen_host], cwd=libevent_dir, env=env)
-    check_call(['make'], cwd=libevent_dir, env=env)
+    check_call(['make', '-j', str(os.cpu_count())], cwd=libevent_dir, env=env)
     check_call(['make', 'install'], cwd=libevent_dir, env=env)
 
     # build Tor
-    tor_dir = os.path.join(EXT_DIR, 'tor')
+    tor_dir = os.path.join(BUILD_DIR, 'tor')
     check_call(['./autogen.sh'], cwd=tor_dir)
     env['CFLAGS'] += ' -O3'  # needed for FORTIFY_SOURCE
-    check_call(['./configure', '--disable-asciidoc', '--disable-systemd',
-                '--enable-static-zlib', '--with-zlib-dir=%s' % prefix_dir,
-                '--enable-static-libevent', '--with-libevent-dir=%s' % prefix_dir,
-                '--enable-static-openssl', '--with-openssl-dir=%s' % prefix_dir,
-                '--prefix=%s' % prefix_dir, '--host=%s' % autogen_host,
-                '--disable-tool-name-check'], cwd=tor_dir, env=env)
-    check_call(['make', 'install'], cwd=tor_dir, env=env)
+    check_call(['./configure',
+                '--host=%s' % autogen_host,
+                '--prefix=%s' % prefix_dir,
+                '--enable-static-tor',
+                '--enable-lzma',
+                '--enable-zstd',
+                '--enable-static-zlib',
+                '--with-zlib-dir=%s' % prefix_dir,
+                '--enable-static-libevent',
+                '--with-libevent-dir=%s' % prefix_dir,
+                '--enable-static-openssl',
+                '--with-openssl-dir=%s' % prefix_dir,
+                ] + TOR_CONFIGURE_FLAGS, cwd=tor_dir, env=env)
+    check_call(['make', '-j', str(os.cpu_count()), 'install'], cwd=tor_dir, env=env)
 
     # copy and zip built Tor binary
-    tor_path = os.path.join(REPO_DIR, 'tor')
-    copy(os.path.join(prefix_dir, 'bin', 'tor'), tor_path)
-    check_call(['strip', '-D', 'tor'], cwd=REPO_DIR)
+    tor_path = os.path.join(OUTPUT_DIR, 'tor')
+    copy(os.path.join(BUILD_DIR, 'tor', 'src', 'app', 'tor'), tor_path)
+    check_call(['strip', '-D', '--strip-unneeded', '--strip-debug', '-R', '.note*', '-R', '.comment', tor_path])
     reset_time(tor_path, versions)
     print("Sha256 hash of tor before zipping %s: %s" % (name, get_sha256(tor_path)))
-    check_call(['zip', '-X', '../' + name, 'tor'], cwd=REPO_DIR)
+    check_call(['zip', '--no-dir-entries', '--junk-paths', '-X', name, 'tor'], cwd=OUTPUT_DIR)
 
 
 def package_linux(versions, jar_name):
     # zip binaries together
-    file_list = ['tor_linux-aarch64.zip', 'tor_linux-armhf.zip', 'tor_linux-x86_64.zip', 'geoip.zip']
-    zip_name = utils.pack(versions, file_list, PLATFORM)
+    file_list = [
+        os.path.join(OUTPUT_DIR, 'tor_linux-aarch64.zip'),
+        os.path.join(OUTPUT_DIR, 'tor_linux-armhf.zip'),
+        os.path.join(OUTPUT_DIR, 'tor_linux-x86_64.zip'),
+        os.path.join(OUTPUT_DIR, 'geoip.zip'),
+    ]
+    zip_name = pack(versions, file_list, PLATFORM)
 
     # create POM file from template
-    pom_name = utils.create_pom_file(versions, PLATFORM)
+    pom_name = create_pom_file(versions, PLATFORM)
 
     # print hashes for debug purposes
     for file in file_list + [zip_name, jar_name, pom_name]:
diff --git a/build_tor_windows.py b/build_tor_windows.py
index afe652d0c556c31b44f9e8fb69214095da23669b..395df40c1736f991049e6a5ed40b4380d5a5a210 100755
--- a/build_tor_windows.py
+++ b/build_tor_windows.py
@@ -4,7 +4,8 @@ from shutil import rmtree, copy
 from subprocess import check_call
 
 import utils
-from utils import REPO_DIR, EXT_DIR, reset_time
+from utils import BUILD_DIR, OUTPUT_DIR, TOR_CONFIGURE_FLAGS, OPENSSL_CONFIGURE_FLAGS, REPRODUCIBLE_GCC_CFLAGS, \
+    XZ_CONFIGURE_FLAGS, reset_time, get_sha256
 
 PLATFORM = "windows"
 
@@ -25,12 +26,12 @@ def build_windows(versions):
 def build_windows_arch(arch, host, versions):
     name = "tor_windows-%s.zip" % arch
     print("Building %s" % name)
-    prefix_dir = os.path.abspath(os.path.join(REPO_DIR, 'prefix'))
+    prefix_dir = os.path.abspath(os.path.join(BUILD_DIR, 'prefix'))
     lib_dir = os.path.join(prefix_dir, 'lib')
     include_dir = os.path.join(prefix_dir, 'include')
 
     # ensure clean build environment (again here to protect against build reordering)
-    utils.prepare_tor_android_repo(versions)
+    utils.prepare_repos(versions)
     if os.path.exists(prefix_dir):
         rmtree(prefix_dir)
 
@@ -41,66 +42,93 @@ def build_windows_arch(arch, host, versions):
 
     # setup environment
     env = os.environ.copy()
-
-    # build zlib
+    env['SOURCE_DATE_EPOCH'] = "1234567890"
     env['LDFLAGS'] = "-L%s" % prefix_dir
+    env['CFLAGS'] = REPRODUCIBLE_GCC_CFLAGS + ' -fPIC -I%s' % include_dir
+    env['PKG_CONFIG_PATH'] = os.path.join(lib_dir, 'pkgconfig')  # needed to find OpenSSL
     env['CHOST'] = host
 
-    zlib_dir = os.path.join(EXT_DIR, 'zlib')
-    check_call(['make', '-f', 'win32/Makefile.gcc', 'BINARY_PATH=%s/bin' % prefix_dir,
+    # build lzma
+    xz_dir = os.path.join(BUILD_DIR, 'xz')
+    check_call(['./autogen.sh'], cwd=xz_dir)
+    check_call(['./configure',
+                '--prefix=%s' % prefix_dir,
+                '--host=%s' % host,
+                ] + XZ_CONFIGURE_FLAGS, cwd=xz_dir, env=env)
+    check_call(['make', '-j', str(os.cpu_count()), 'install'], cwd=xz_dir, env=env)
+
+    # build zlib
+    zlib_dir = os.path.join(BUILD_DIR, 'zlib')
+    check_call(['make', '-j', str(os.cpu_count()), '-f', 'win32/Makefile.gcc', 'BINARY_PATH=%s/bin' % prefix_dir,
                 'INCLUDE_PATH=%s/include' % prefix_dir, 'LIBRARY_PATH=%s/lib' % prefix_dir,
                 'SHARED_MODE=1', 'PREFIX=%s-' % host, 'install'],
                cwd=zlib_dir, env=env)
 
-    # build libevent
-    libevent_dir = os.path.join(EXT_DIR, 'libevent')
+    # build openssl
+    env['LDFLAGS'] = REPRODUCIBLE_GCC_CFLAGS + " -static -static-libgcc -L%s" % prefix_dir
+
+    openssl_dir = os.path.join(BUILD_DIR, 'openssl')
+    check_call(['perl', 'Configure',
+                'mingw64',
+                '--cross-compile-prefix=%s-' % host,
+                '--prefix=%s' % prefix_dir,
+                '--openssldir=%s' % prefix_dir,
+                # '-static',  # https://github.com/openssl/openssl/issues/14574
+                '-static-libgcc',
+                'no-shared',
+                ] + OPENSSL_CONFIGURE_FLAGS, cwd=openssl_dir, env=env)
+    check_call(['make', '-j', str(os.cpu_count())], cwd=openssl_dir, env=env)
+    check_call(['make', 'install_sw'], cwd=openssl_dir, env=env)
 
+    # build libevent
+    libevent_dir = os.path.join(BUILD_DIR, 'libevent')
     check_call(['./autogen.sh'], cwd=libevent_dir)
-    check_call(['./configure', '--disable-shared', '--prefix=%s' % prefix_dir,
-                '--host=%s' % host, '--enable-static'], cwd=libevent_dir, env=env)
-    check_call(['make'], cwd=libevent_dir, env=env)
+    check_call(['./configure',
+                '--host=%s' % host,
+                '--disable-libevent-regress',
+                '--disable-samples',
+                '--disable-shared',
+                '--prefix=%s' % prefix_dir,
+                ], cwd=libevent_dir, env=env)
+    check_call(['make', '-j', str(os.cpu_count())], cwd=libevent_dir, env=env)
     check_call(['make', 'install'], cwd=libevent_dir, env=env)
 
-    # build openssl
-    env['CFLAGS'] = "-I%s" % include_dir
-    env['LDFLAGS'] = "-static -static-libgcc -L%s" % prefix_dir
-
-    openssl_dir = os.path.join(EXT_DIR, 'openssl')
-    check_call(['perl', 'Configure', '--prefix=%s' % prefix_dir,
-                '--openssldir=%s' % prefix_dir, '-static', '-static-libgcc',
-                '--cross-compile-prefix=%s-' % host, 'mingw64', 'no-shared', 'no-asm'],
-               cwd=openssl_dir, env=env)
-    check_call(['make'], cwd=openssl_dir, env=env)
-    check_call(['make', 'install_sw'], cwd=openssl_dir, env=env)
-
     # build Tor
-    tor_dir = os.path.join(EXT_DIR, 'tor')
+    tor_dir = os.path.join(BUILD_DIR, 'tor')
     check_call(['./autogen.sh'], cwd=tor_dir)
+    env['CFLAGS'] += ' -O3'
     env['LIBS'] = "-lcrypt32"
-    env['LDFLAGS'] = "-static -static-libgcc -L%s" % prefix_dir
-    env['CFLAGS'] = "-I%s" % include_dir
-
-    check_call(['./configure', '--disable-asciidoc', '--disable-systemd',
-                '--enable-static-zlib', '--with-zlib-dir=%s' % prefix_dir,
-                '--enable-static-libevent', '--with-libevent-dir=%s' % prefix_dir,
-                '--enable-static-openssl', '--with-openssl-dir=%s' % prefix_dir,
-                '--prefix=%s' % prefix_dir, '--host=%s' % host,
-                '--disable-tool-name-check'], cwd=tor_dir, env=env)
-    check_call(['make'], cwd=tor_dir, env=env)
+
+    check_call(['./configure',
+                '--host=%s' % host,
+                '--prefix=%s' % prefix_dir,
+                '--enable-lzma',
+                '--enable-static-tor',
+                '--enable-static-zlib',
+                '--with-zlib-dir=%s' % prefix_dir,
+                '--enable-static-libevent',
+                '--with-libevent-dir=%s' % prefix_dir,
+                '--enable-static-openssl',
+                '--with-openssl-dir=%s' % prefix_dir,
+                ] + TOR_CONFIGURE_FLAGS, cwd=tor_dir, env=env)
+    check_call(['make', '-j', str(os.cpu_count())], cwd=tor_dir, env=env)
     check_call(['make', 'install'], cwd=tor_dir, env=env)
 
     # copy and zip built Tor binary
-    tor_path = os.path.join(REPO_DIR, 'tor')
+    tor_path = os.path.join(OUTPUT_DIR, 'tor')
     copy(os.path.join(prefix_dir, 'bin', 'tor.exe'), tor_path)
-    check_call(['strip', '-D', 'tor'], cwd=REPO_DIR)
+    check_call(['strip', '-D', '--strip-unneeded', '--strip-debug', '-R', '.note*', '-R', '.comment', tor_path])
     reset_time(tor_path, versions)
-    print("Sha256 hash of tor before zipping %s: %s" % (name, utils.get_sha256(tor_path)))
-    check_call(['zip', '-X', '../' + name, 'tor'], cwd=REPO_DIR)
+    print("Sha256 hash of tor before zipping %s: %s" % (name, get_sha256(tor_path)))
+    check_call(['zip', '--no-dir-entries', '--junk-paths', '-X', name, 'tor'], cwd=OUTPUT_DIR)
 
 
 def package_windows(versions, jar_name):
     # zip binaries together
-    file_list = ['tor_windows-x86_64.zip', 'geoip.zip']
+    file_list = [
+        os.path.join(OUTPUT_DIR, 'tor_windows-x86_64.zip'),
+        os.path.join(OUTPUT_DIR, 'geoip.zip'),
+    ]
     zip_name = utils.pack(versions, file_list, PLATFORM)
 
     # create POM file from template
diff --git a/install-dependencies.sh b/install-dependencies.sh
index 2677de3ee13772c5d948f252722418a20b4c5880..9e6fd22cff5edd0ec32ad0dce964da02e40e4d7d 100755
--- a/install-dependencies.sh
+++ b/install-dependencies.sh
@@ -10,6 +10,7 @@ apt-get install -y --no-install-recommends \
 	build-essential \
 	make \
 	patch \
+	pkg-config \
 	autopoint \
 	libtool \
 	automake \
diff --git a/tor-build/Makefile b/tor-build/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..f4594e13cd0888cbbc5d962f5bbd283dd1c14a4c
--- /dev/null
+++ b/tor-build/Makefile
@@ -0,0 +1,347 @@
+# Please install the following prerequisites (instructions for each follows):
+# 	Android OS SDK: http://source.android.com/download
+#
+# Install and prepare the Android OS SDK ( http://source.android.com/download )
+# on Debian or Ubuntu
+
+EXTERNAL_ROOT := $(shell pwd)
+
+DEBUG ?= 0
+
+MAKE ?= make -j`nproc`
+
+# Android now has 64-bit and 32-bit versions of the NDK for GNU/Linux.  We
+# assume that the build platform uses the appropriate version, otherwise the
+# user building this will have to manually set NDK_PROCESSOR or NDK_TOOLCHAIN.
+CPU := $(shell uname -m)
+ifeq ($(CPU),x86_64)
+ NDK_PROCESSOR=x86_64
+else
+ NDK_PROCESSOR=x86
+endif
+
+ifeq ($(APP_ABI), )
+ $(error APP_ABI must be set to an NDK-supported ABI/arch for this to run!)
+endif
+
+# matching NDK revisions are required for reproducible builds
+NDK_REVISION := $(shell sed -n 's,^Pkg.Revision *= *\([^ ]*\),\1,p' $(ANDROID_NDK_HOME)/source.properties)
+NDK_REQUIRED_REVISION := 21.4.7075529
+MIN_NDK_VERSION := 19
+ifeq ($(shell test $(MIN_NDK_VERSION) -gt $(firstword $(subst ., ,$(NDK_REVISION))); echo $$?),0)
+ $(error NDK r$(MIN_NDK_VERSION) or newer required! r$(NDK_REVISION) is installed at $(ANDROID_NDK_HOME).)
+endif
+ifneq ($(NDK_REQUIRED_REVISION), $(NDK_REVISION))
+ $(warning WARNING: NDK $(NDK_REQUIRED_REVISION) required for reproducible builds, $(NDK_REVISION) is installed.)
+endif
+
+
+ifneq ($(filter mips%, $(APP_ABI)),)
+ HOST := mipsel-linux-android
+ ALTHOST := $(HOST)
+ GREP_CHECK := MIPS
+ NDK_ABI := mips
+ NDK_BIT := 32
+ NDK_PLATFORM_LEVEL := 16
+ NDK_TOOLCHAIN := $(HOST)-$(NDK_TOOLCHAIN_VERSION)
+endif
+ifneq ($(filter arm64-v8a, $(APP_ABI)),)
+ HOST := aarch64-linux-android
+ ALTHOST := $(HOST)
+ GREP_CHECK := aarch64
+ NDK_ABI := arm64
+ NDK_BIT := 64
+ NDK_PLATFORM_LEVEL := 21
+ NDK_TOOLCHAIN := $(HOST)-$(NDK_TOOLCHAIN_VERSION)
+endif
+ifneq ($(filter armeabi-v7a, $(APP_ABI)),)
+ HOST := armv7a-linux-androideabi
+ ALTHOST := arm-linux-androideabi
+ GREP_CHECK := EABI5
+ NDK_ABI := arm
+ NDK_BIT := 32
+ NDK_PLATFORM_LEVEL := 16
+ NDK_TOOLCHAIN := $(HOST)-$(NDK_TOOLCHAIN_VERSION)
+endif
+ifneq ($(filter x86, $(APP_ABI)),)
+ HOST := i686-linux-android
+ ALTHOST := $(HOST)
+ GREP_CHECK := 80386
+ NDK_ABI := x86
+ NDK_BIT := 32
+ NDK_PLATFORM_LEVEL := 16
+ NDK_TOOLCHAIN := $(NDK_ABI)-$(NDK_TOOLCHAIN_VERSION)
+endif
+ifneq ($(filter x86_64, $(APP_ABI)),)
+ HOST := x86_64-linux-android
+ ALTHOST := $(HOST)
+ GREP_CHECK := x86-64
+ NDK_ABI := x86_64
+ NDK_BIT := 64
+ NDK_PLATFORM_LEVEL := 21
+ NDK_TOOLCHAIN := $(NDK_ABI)-$(NDK_TOOLCHAIN_VERSION)
+endif
+
+NDK_SYSROOT=$(ANDROID_NDK_HOME)/platforms/android-$(NDK_PLATFORM_LEVEL)/arch-$(NDK_ABI)
+NDK_UNAME := $(shell uname -s | tr '[A-Z]' '[a-z]')
+NDK_TOOLCHAIN_BASE=$(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/$(NDK_UNAME)-$(NDK_PROCESSOR)
+
+export CC := $(NDK_TOOLCHAIN_BASE)/bin/$(HOST)$(NDK_PLATFORM_LEVEL)-clang
+
+
+export TZ := UTC
+export LC_ALL := C.UTF-8
+export SOURCE_DATE_EPOCH := 1234567890
+
+REPRODUCIBLE_CFLAGS := \
+  -fbuild-session-timestamp=$(SOURCE_DATE_EPOCH) \
+  -fdebug-compilation-dir . \
+  -no-canonical-prefixes \
+
+
+ALL_CFLAGS := $(REPRODUCIBLE_CFLAGS) $(CFLAGS) -Os
+export CFLAGS := $(ALL_CFLAGS)
+
+
+OUTPUT_FILE := $(EXTERNAL_ROOT)/tor/src/app/tor
+INSTALL_DIR := $(EXTERNAL_ROOT)/lib/$(APP_ABI)
+
+.PHONY = clean showsetup \
+	PREBUILD_SHARED_LIBRARY PREBUILD_SHARED_LIBRARY-clean \
+	openssl-clean \
+	libevent-clean \
+	lzma-clean \
+	zstd-clean \
+	tor tor-clean
+
+all: test-setup PREBUILD_SHARED_LIBRARY
+
+test-setup:
+	test -d $(NDK_SYSROOT)
+	test -x $(CC)
+	printf 'int main() {return 0;}\n' > .test.c
+	$(CC) $(CFLAGS) .test.c
+	rm -f .test.c a.out
+
+
+#------------------------------------------------------------------------------#
+# openssl
+#
+# not all of openssl is needed, only the parts that Tor needs
+# https://trac.torproject.org/projects/tor/ticket/32200
+# https://gitweb.torproject.org/tor.git/tree/src/lib/tls/ciphers.inc
+# https://wiki.openssl.org/index.php/Compilation_and_Installation
+
+PATH := $(ANDROID_NDK_HOME)/toolchains/llvm/prebuilt/linux-x86_64/bin:$(PATH)
+
+
+openssl/Makefile: openssl/Configure $(wildcard openssl/Configurations/*.*)
+	cd openssl && PATH=$(PATH) \
+		./Configure \
+			no-comp no-dtls no-ec2m no-psk no-srp no-ssl2 no-ssl3 \
+			no-camellia no-idea no-md2 no-md4 no-mdc2 no-rc2 no-rc4 no-rc5 no-rmd160 no-whirlpool \
+			no-dso no-hw no-ui-console \
+			no-shared no-unit-test \
+			android-$(NDK_ABI) \
+			-D__ANDROID_API__=$(NDK_PLATFORM_LEVEL) \
+			--prefix=/ \
+			--openssldir=/
+
+openssl-build-stamp: openssl/Makefile
+ifeq ($(V), 0)
+	PATH=$(PATH) make -j`nproc` --silent -C openssl install_dev DESTDIR=$(EXTERNAL_ROOT) ECHO=':'
+else
+	PATH=$(PATH) make -j`nproc` -C openssl install_dev DESTDIR=$(EXTERNAL_ROOT)
+endif
+	touch $@
+
+openssl-clean:
+	-rm openssl-build-stamp
+	-rm lib/libcrypto.a
+	-rm lib/libssl.a
+	-make -C openssl uninstall_dev > /dev/null
+	-make -C openssl clean
+	-cd openssl && \
+		git clean -fdx > /dev/null
+
+
+#------------------------------------------------------------------------------#
+# libevent
+
+libevent/Makefile: libevent/Makefile.am libevent/configure.ac
+	cd libevent && ./autogen.sh
+	cd libevent && ./configure \
+				LDFLAGS="-L../lib" \
+				CFLAGS="-I../include" \
+				--host=$(ALTHOST) \
+				--disable-libevent-regress \
+				--disable-samples \
+				--disable-shared \
+			        --prefix=/
+
+libevent-build-stamp: openssl-build-stamp libevent/Makefile
+	$(MAKE) -C libevent install DESTDIR=$(EXTERNAL_ROOT)
+	touch $@
+
+libevent-clean:
+	-rm -f lib/libevent.a
+	-rm -f libevent-build-stamp
+	-$(MAKE) -C libevent uninstall DESTDIR=$(EXTERNAL_ROOT)
+	-$(MAKE) -C libevent clean
+	-cd libevent && \
+		git clean -fdx > /dev/null
+
+
+#------------------------------------------------------------------------------#
+# lzma
+
+xz/Makefile: xz/configure.ac xz/Makefile.am
+	cd xz && ./autogen.sh
+	cd xz && ./configure \
+			--host=$(HOST) \
+			--enable-static \
+			--disable-doc \
+			--disable-lzma-links \
+			--disable-lzmadec \
+			--disable-lzmainfo \
+			--disable-scripts \
+			--disable-shared \
+			--disable-xz \
+			--disable-xzdec \
+			--prefix=/
+
+lzma-build-stamp: xz/Makefile
+	$(MAKE) -C xz install DESTDIR=$(EXTERNAL_ROOT)
+	touch $@
+
+lzma-clean:
+	-$(MAKE) -C xz uninstall DESTDIR=$(EXTERNAL_ROOT)
+	-$(MAKE) -C xz clean
+	-rm -rf include/lzma
+	-rm -f include/lzma.h
+	-rm -f lib/liblzma.a
+	-rm -f lib/liblzma.la
+	-rm -f lzma-build-stamp
+	-cd xz && \
+		git clean -fdx > /dev/null
+
+
+#------------------------------------------------------------------------------#
+# zstd
+
+zstd-build-stamp:
+	$(MAKE) -C zstd/lib \
+		PREFIX=$(EXTERNAL_ROOT) \
+		libzstd.a-mt
+	$(MAKE) -C zstd/lib \
+		PREFIX=$(EXTERNAL_ROOT) \
+		libzstd.pc
+	test -d lib || mkdir lib
+	test -d lib/pkgconfig || mkdir lib/pkgconfig
+	test -d include || mkdir include
+	cp zstd/lib/libzstd.a lib
+	cp zstd/lib/libzstd.pc lib/pkgconfig
+	cp zstd/lib/zstd.h include
+	cp zstd/lib/common/zstd_errors.h include
+	cp zstd/lib/deprecated/zbuff.h include
+	cp zstd/lib/dictBuilder/zdict.h include
+	touch $@
+
+zstd-clean:
+	-rm -f include/zstd.h include/zstd_errors.h include/zbuff.h include/zdict.h
+	-rm -f lib/libzstd.a
+	-rm -f lib/pkgconfig/libzstd.pc
+	-rm -f zstd-build-stamp
+	-$(MAKE) -C zstd uninstall
+	-$(MAKE) -C zstd clean
+	-cd zstd && \
+		git clean -fdx > /dev/null
+
+
+#------------------------------------------------------------------------------#
+# tor
+
+tor/Makefile: tor/configure.ac tor/Makefile.am
+	@which pkg-config || (echo "ERROR: pkg-config is required! apt-get install pkg-config"; exit 1)
+	cd tor && ./autogen.sh
+	cd tor && \
+			./configure \
+				--host=$(ALTHOST) \
+				--enable-android \
+				--enable-lzma \
+				--enable-pic \
+				--enable-static-libevent --with-libevent-dir=$(EXTERNAL_ROOT) \
+				--enable-static-openssl --with-openssl-dir=$(EXTERNAL_ROOT) \
+				--enable-zstd \
+				--disable-module-dirauth \
+                --disable-module-relay \
+                --disable-unittests \
+                --disable-asciidoc \
+				--prefix=$(EXTERNAL_ROOT)
+	grep -E '^# *define +HAVE_LZMA +1$$' tor/orconfig.h
+	grep -E '^# *define +HAVE_ZSTD +1$$' tor/orconfig.h
+	grep -E '^# *define +ENABLE_OPENSSL +1$$' tor/orconfig.h
+	grep -E '^# *define +HAVE_TLS_METHOD +1$$' tor/orconfig.h
+
+tor-build-stamp: tor/Makefile
+	$(MAKE) -C tor
+	$(NDK_TOOLCHAIN_BASE)/bin/$(ALTHOST)-strip -D --strip-unneeded -R .note -R .comment --strip-debug $(OUTPUT_FILE)
+	touch $@
+
+tor: lzma-build-stamp zstd-build-stamp libevent-build-stamp openssl-build-stamp tor-build-stamp
+
+tor-clean:
+	-rm -f $(OUTPUT_FILE)
+	-rm -f tor-build-stamp
+	-cd tor && \
+		git clean -fdx > /dev/null
+
+
+#------------------------------------------------------------------------------#
+# create and clean libtor.so
+
+PREBUILD_SHARED_LIBRARY: tor
+	file $(OUTPUT_FILE) | grep $(GREP_CHECK)
+	install -d $(EXTERNAL_ROOT)/lib/$(APP_ABI)
+	cp $(OUTPUT_FILE) $(INSTALL_DIR)/libtor.so
+	cp openssl/configdata.pm tor/orconfig.h $(INSTALL_DIR)/
+ifneq ($(DEBUG), 1)
+	ls -l  $(INSTALL_DIR)/libtor.so
+	$(NDK_TOOLCHAIN_BASE)/bin/$(ALTHOST)-strip --strip-unneeded -R .note -R .comment --strip-debug \
+		$(INSTALL_DIR)/libtor.so
+	ls -l  $(INSTALL_DIR)/libtor.so
+endif
+	@echo "check if all the libs got included:"
+	grep "tor_lzma_state_size_precalc" $(INSTALL_DIR)/libtor.so
+	install -d $(EXTERNAL_ROOT)/test/$(APP_ABI)
+	cp tor/src/test/test tor/src/test/test-memwipe tor/src/test/test-slow \
+		$(EXTERNAL_ROOT)/test/$(APP_ABI)
+
+PREBUILD_SHARED_LIBRARY-clean:
+	-rm $(INSTALL_DIR)/libtor.so
+
+
+#------------------------------------------------------------------------------#
+# cleanup, cleanup, put the toys away
+
+clean: openssl-clean libevent-clean lzma-clean zstd-clean tor-clean
+
+
+#------------------------------------------------------------------------------#
+# debugging stuff
+
+showsetup:
+	@echo "ALL_CFLAGS: $(ALL_CFLAGS)"
+	@echo "APP_ABI: $(APP_ABI)"
+	@echo "CC: $$CC"
+	@echo "CFLAGS: $$CFLAGS"
+	@echo "HOST: $(HOST)"
+	@echo "NDK_ABI: $(NDK_ABI)"
+	@echo "NDK_BIT: $(NDK_BIT)"
+	@echo "NDK_PLATFORM_LEVEL: $(NDK_PLATFORM_LEVEL)"
+	@echo "NDK_SYSROOT: $(NDK_SYSROOT)"
+	@echo "NDK_TOOLCHAIN: $(NDK_TOOLCHAIN)"
+	@echo "PATH: $$PATH"
+	@echo "REPRODUCIBLE_CFLAGS: $(REPRODUCIBLE_CFLAGS)"
+	@echo "SOURCE_DATE_EPOCH: $$SOURCE_DATE_EPOCH"
+	@echo "TZ: $$TZ"
diff --git a/tor-versions.json b/tor-versions.json
index a1da4f702d319da1ddf707fe817d382ddd7b3940..8bad0c766ba386d9cf2223eadd45ffaf338654f7 100644
--- a/tor-versions.json
+++ b/tor-versions.json
@@ -1,234 +1,66 @@
 {
-  "0.3.5.17": {
-    "tor": "tor-0.3.5.17",
-    "libevent": "release-2.1.8-stable",
-    "openssl": "OpenSSL_1_0_2u",
-    "xz": "v5.2.5",
-    "zlib": "v1.2.11",
-    "zstd": "v1.3.8",
-    "tor-android": "55791c108d4b732b1c12866e4db3b8b1fd826bf1",
-    "tor_android_repo_url": "https://github.com/n8fr8/tor-android",
-    "ndk": {
-      "url": "https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip",
-      "revision": "15.2.4203891",
-      "sha256": "f01788946733bf6294a36727b99366a18369904eb068a599dde8cca2c1d2ba3c"
+  "0.4.5.12": {
+    "tor": {
+      "url": "https://git.torproject.org/git/tor.git",
+      "commit": "tor-0.4.5.12"
     },
-    "timestamp": "201001010000.00"
-  },
-  "0.3.5.15": {
-    "tor": "tor-0.3.5.15",
-    "libevent": "release-2.1.8-stable",
-    "openssl": "OpenSSL_1_0_2u",
-    "xz": "v5.2.4",
-    "zlib": "v1.2.11",
-    "zstd": "v1.3.8",
-    "tor-android": "55791c108d4b732b1c12866e4db3b8b1fd826bf1",
-    "tor_android_repo_url": "https://github.com/n8fr8/tor-android",
-    "ndk": {
-      "url": "https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip",
-      "revision": "15.2.4203891",
-      "sha256": "f01788946733bf6294a36727b99366a18369904eb068a599dde8cca2c1d2ba3c"
+    "libevent": {
+      "url": "https://github.com/libevent/libevent.git",
+      "commit": "release-2.1.12-stable"
     },
-    "timestamp": "201001010000.00"
-  },
-  "0.3.5.14": {
-    "tor": "tor-0.3.5.14",
-    "libevent": "release-2.1.8-stable",
-    "openssl": "OpenSSL_1_0_2u",
-    "xz": "v5.2.4",
-    "zlib": "v1.2.11",
-    "zstd": "v1.3.8",
-    "tor-android": "55791c108d4b732b1c12866e4db3b8b1fd826bf1",
-    "tor_android_repo_url": "https://github.com/n8fr8/tor-android",
-    "ndk": {
-      "url": "https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip",
-      "revision": "15.2.4203891",
-      "sha256": "f01788946733bf6294a36727b99366a18369904eb068a599dde8cca2c1d2ba3c"
+    "openssl": {
+      "url": "https://github.com/openssl/openssl.git",
+      "commit": "OpenSSL_1_1_1m"
     },
-    "timestamp": "201001010000.00"
-  },
-  "0.3.5.13-1": {
-    "tor": "tor-0.3.5.13",
-    "libevent": "release-2.1.8-stable",
-    "openssl": "OpenSSL_1_0_2u",
-    "xz": "v5.2.4",
-    "zlib": "v1.2.11",
-    "zstd": "v1.3.8",
-    "tor-android": "55791c108d4b732b1c12866e4db3b8b1fd826bf1",
-    "tor_android_repo_url": "https://github.com/n8fr8/tor-android",
-    "ndk": {
-      "url": "https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip",
-      "revision": "15.2.4203891",
-      "sha256": "f01788946733bf6294a36727b99366a18369904eb068a599dde8cca2c1d2ba3c"
+    "xz": {
+      "url": "https://git.tukaani.org/xz.git",
+      "commit": "v5.2.5"
     },
-    "timestamp": "201001010000.00"
-  },
-  "0.3.5.13": {
-    "tor": "tor-0.3.5.13",
-    "libevent": "release-2.1.8-stable",
-    "openssl": "OpenSSL_1_0_2u",
-    "xz": "v5.2.4",
-    "zlib": "v1.2.11",
-    "zstd": "v1.3.8",
-    "tor-android": "55791c108d4b732b1c12866e4db3b8b1fd826bf1",
-    "tor_android_repo_url": "https://github.com/n8fr8/tor-android",
-    "ndk": {
-      "url": "https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip",
-      "revision": "15.2.4203891",
-      "sha256": "f01788946733bf6294a36727b99366a18369904eb068a599dde8cca2c1d2ba3c"
+    "zlib": {
+      "url": "https://github.com/madler/zlib.git",
+      "commit": "v1.2.11"
+    },
+    "zstd": {
+      "url": "https://github.com/facebook/zstd.git",
+      "commit": "v1.4.8"
     },
-    "timestamp": "201001010000.00"
-  },
-  "0.3.5.12": {
-    "tor": "tor-0.3.5.12",
-    "libevent": "release-2.1.8-stable",
-    "openssl": "OpenSSL_1_0_2u",
-    "xz": "v5.2.4",
-    "zlib": "v1.2.11",
-    "zstd": "v1.3.8",
-    "tor-android": "55791c108d4b732b1c12866e4db3b8b1fd826bf1",
-    "tor_android_repo_url": "https://github.com/n8fr8/tor-android",
     "ndk": {
-      "url": "https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip",
-      "revision": "15.2.4203891",
-      "sha256": "f01788946733bf6294a36727b99366a18369904eb068a599dde8cca2c1d2ba3c"
+      "url": "https://dl.google.com/android/repository/android-ndk-r21e-linux-x86_64.zip",
+      "revision": "21.4.7075529",
+      "sha256": "ad7ce5467e18d40050dc51b8e7affc3e635c85bd8c59be62de32352328ed467e"
     },
     "timestamp": "201001010000.00"
   },
-  "0.3.5.11": {
-    "tor": "tor-0.3.5.11",
-    "libevent": "release-2.1.8-stable",
-    "openssl": "OpenSSL_1_0_2u",
-    "xz": "v5.2.4",
-    "zlib": "v1.2.11",
-    "zstd": "v1.3.8",
-    "tor-android": "55791c108d4b732b1c12866e4db3b8b1fd826bf1",
-    "tor_android_repo_url": "https://github.com/n8fr8/tor-android",
+  "0.4.5.10": {
+    "tor": {
+      "url": "https://git.torproject.org/git/tor.git",
+      "commit": "tor-0.4.5.10"
+    },
+    "libevent": {
+      "url": "https://github.com/libevent/libevent.git",
+      "commit": "release-2.1.12-stable"
+    },
+    "openssl": {
+      "url": "https://github.com/openssl/openssl.git",
+      "commit": "OpenSSL_1_1_1k"
+    },
+    "xz": {
+      "url": "https://git.tukaani.org/xz.git",
+      "commit": "v5.2.5"
+    },
+    "zlib": {
+      "url": "https://github.com/madler/zlib.git",
+      "commit": "v1.2.11"
+    },
+    "zstd": {
+      "url": "https://github.com/facebook/zstd.git",
+      "commit": "v1.4.8"
+    },
     "ndk": {
-      "url": "https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip",
-      "revision": "15.2.4203891",
-      "sha256": "f01788946733bf6294a36727b99366a18369904eb068a599dde8cca2c1d2ba3c"
+      "url": "https://dl.google.com/android/repository/android-ndk-r21e-linux-x86_64.zip",
+      "revision": "21.4.7075529",
+      "sha256": "ad7ce5467e18d40050dc51b8e7affc3e635c85bd8c59be62de32352328ed467e"
     },
     "timestamp": "201001010000.00"
-  },
-  "0.3.5.10": {
-    "tor": "tor-0.3.5.10",
-    "libevent": "release-2.1.8-stable",
-    "openssl": "OpenSSL_1_0_2u",
-    "xz": "v5.2.4",
-    "zlib": "v1.2.11",
-    "zstd": "v1.3.8",
-    "tor-android": "55791c108d4b732b1c12866e4db3b8b1fd826bf1",
-    "tor_android_repo_url": "https://github.com/n8fr8/tor-android",
-    "ndk": {
-      "url": "https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip",
-      "revision": "15.2.4203891",
-      "sha256": "f01788946733bf6294a36727b99366a18369904eb068a599dde8cca2c1d2ba3c"
-    }
-  },
-  "0.3.5.9": {
-    "tor": "tor-0.3.5.9",
-    "libevent": "release-2.1.8-stable",
-    "openssl": "OpenSSL_1_0_2q",
-    "xz": "v5.2.4",
-    "zlib": "v1.2.11",
-    "zstd": "v1.3.8",
-    "tor-android": "55791c108d4b732b1c12866e4db3b8b1fd826bf1",
-    "tor_android_repo_url": "https://github.com/n8fr8/tor-android",
-    "ndk": {
-      "url": "https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip",
-      "revision": "15.2.4203891",
-      "sha256": "f01788946733bf6294a36727b99366a18369904eb068a599dde8cca2c1d2ba3c"
-    }
-  },
-  "0.3.5.8-64": {
-    "tor": "tor-0.3.5.8",
-    "libevent": "release-2.1.8-stable",
-    "openssl": "OpenSSL_1_0_2q",
-    "xz": "v5.2.4",
-    "zlib": "v1.2.11",
-    "zstd": "v1.3.8",
-    "tor-android": "55791c108d4b732b1c12866e4db3b8b1fd826bf1",
-    "tor_android_repo_url": "https://github.com/n8fr8/tor-android",
-    "ndk": {
-      "url": "https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip",
-      "revision": "15.2.4203891",
-      "sha256": "f01788946733bf6294a36727b99366a18369904eb068a599dde8cca2c1d2ba3c"
-    }
-  },
-  "0.3.5.8": {
-    "tor": "tor-0.3.5.8",
-    "libevent": "release-2.1.8-stable",
-    "openssl": "OpenSSL_1_0_2q",
-    "xz": "v5.2.4",
-    "zlib": "v1.2.11",
-    "zstd": "v1.3.8",
-    "tor-android": "8eb128aa63b97e139bc845a9426b406245770096",
-    "tor_android_repo_url": "https://github.com/n8fr8/tor-android",
-    "ndk": {
-      "url": "https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip",
-      "revision": "15.2.4203891",
-      "sha256": "f01788946733bf6294a36727b99366a18369904eb068a599dde8cca2c1d2ba3c"
-    }
-  },
-  "0.3.5.7": {
-    "tor": "tor-0.3.5.7",
-    "libevent": "release-2.1.8-stable",
-    "openssl": "OpenSSL_1_0_2q",
-    "xz": "v5.2.4",
-    "zlib": "v1.2.11",
-    "zstd": "v1.3.8",
-    "tor-android": "8eb128aa63b97e139bc845a9426b406245770096",
-    "tor_android_repo_url": "https://github.com/n8fr8/tor-android",
-    "ndk": {
-      "url": "https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip",
-      "revision": "15.2.4203891",
-      "sha256": "f01788946733bf6294a36727b99366a18369904eb068a599dde8cca2c1d2ba3c"
-    }
-  },
-  "0.3.4.8": {
-    "tor": "tor-0.3.4.8",
-    "libevent": "release-2.0.22-stable",
-    "openssl": "OpenSSL_1_0_2p",
-    "xz": "v5.2.4",
-    "zlib": "v1.2.11",
-    "zstd": "v1.3.5",
-    "tor-android": "fa1ed5505d20aae51cb4cceb51bd9c5164066259",
-    "tor_android_repo_url": "https://github.com/n8fr8/tor-android",
-    "ndk": {
-      "url": "https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip",
-      "revision": "15.2.4203891",
-      "sha256": "f01788946733bf6294a36727b99366a18369904eb068a599dde8cca2c1d2ba3c"
-    }
-  },
-  "0.2.9.16": {
-    "tor": "tor-0.2.9.16",
-    "libevent": "release-2.0.22-stable",
-    "openssl": "OpenSSL_1_0_2o",
-    "xz": "v5.2.4",
-    "zlib": "v1.2.11",
-    "zstd": "v1.3.5",
-    "tor-android": "tor-android-binary-0.3.3.5-rc-3",
-    "tor_android_repo_url": "https://github.com/n8fr8/tor-android",
-    "ndk": {
-      "url": "https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip",
-      "revision": "15.2.4203891",
-      "sha256": "f01788946733bf6294a36727b99366a18369904eb068a599dde8cca2c1d2ba3c"
-    }
-  },
-  "0.2.9.15": {
-    "tor": "tor-0.2.9.15",
-    "libevent": "release-2.0.22-stable",
-    "openssl": "OpenSSL_1_0_2o",
-    "xz": "v5.2.3",
-    "zlib": "v1.2.11",
-    "zstd": "v1.3.2",
-    "tor-android": "tor-android-binary-0.3.3.5-rc-3",
-    "tor_android_repo_url": "https://github.com/n8fr8/tor-android",
-    "ndk": {
-      "url": "https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip",
-      "revision": "15.2.4203891",
-      "sha256": "f01788946733bf6294a36727b99366a18369904eb068a599dde8cca2c1d2ba3c"
-    }
   }
 }
diff --git a/utils.py b/utils.py
index a1f8af6768fdbafc48549b2bfa20f0dcc7ab6775..e5857ece23d0cd4e2b67f5dd71388a8b516f2e66 100644
--- a/utils.py
+++ b/utils.py
@@ -5,12 +5,54 @@ import json
 import os
 import sys
 from collections import OrderedDict
-from shutil import copy
+from shutil import copy, rmtree
 from subprocess import check_call
 
-REPO_DIR = 'tor-android'
-ZLIB_REPO_URL = 'https://github.com/madler/zlib.git'
-EXT_DIR = os.path.abspath(os.path.join(REPO_DIR, 'external'))
+BUILD_DIR = 'tor-build'
+OUTPUT_DIR = os.path.abspath(os.path.join(BUILD_DIR, 'output'))
+TOR_CONFIGURE_FLAGS = [
+    '--disable-asciidoc',
+    '--disable-systemd',
+    '--disable-tool-name-check',
+    '--disable-module-relay',
+    '--disable-module-dirauth',
+    '--disable-unittests',
+    '--disable-asciidoc',
+    '--disable-manpage',
+    '--disable-html-manual',
+]
+XZ_CONFIGURE_FLAGS = [
+    '--enable-static',
+    '--disable-doc',
+    '--disable-lzma-links',
+    '--disable-lzmadec',
+    '--disable-lzmainfo',
+    '--disable-scripts',
+    '--disable-shared',
+    '--disable-xz',
+    '--disable-xzdec',
+]
+OPENSSL_CONFIGURE_FLAGS = [
+    'no-unit-test',
+    'no-asm',
+    'no-comp',
+    'no-dtls',
+    'no-err',
+    'no-psk',
+    'no-srp',
+    'no-weak-ssl-ciphers',
+    'no-camellia',
+    'no-idea',
+    'no-md2',
+    'no-md4',
+    'no-rc2',
+    'no-rc4',
+    'no-rc5',
+    'no-rmd160',
+    'no-whirlpool',
+    'no-ui-console',
+]
+REPRODUCIBLE_GCC_CFLAGS = '-fno-guess-branch-probability -frandom-seed="0"'
 
 
 def setup(platform):
@@ -19,10 +61,15 @@ def setup(platform):
 
     # get Tor version and versions of its dependencies
     versions = get_build_versions(version)
-    print("Building Tor %s" % versions['tor'])
+    print("Building Tor %s" % versions['tor']['commit'])
 
-    # clone and checkout tor-android repo based on tor-versions.json
-    prepare_tor_android_repo(versions)
+    # remove output from previous build
+    if os.path.isdir(OUTPUT_DIR):
+        rmtree(OUTPUT_DIR)
+    os.makedirs(OUTPUT_DIR)
+
+    # clone and checkout repos based on tor-versions.json
+    prepare_repos(versions)
 
     # create sources jar before building
     jar_name = create_sources_jar(versions, platform)
@@ -32,46 +79,43 @@ def setup(platform):
 
 def package_geoip(versions):
     # zip geoip database
-    geoip_path = os.path.join(REPO_DIR, 'geoip')
-    copy(os.path.join(EXT_DIR, 'tor', 'src', 'config', 'geoip'), geoip_path)
+    geoip_path = os.path.join(OUTPUT_DIR, 'geoip')
+    copy(os.path.join(BUILD_DIR, 'tor', 'src', 'config', 'geoip'), geoip_path)
     reset_time(geoip_path, versions)
-    check_call(['zip', '-X', '../geoip.zip', 'geoip'], cwd=REPO_DIR)
+    check_call(['zip', '-X', 'geoip.zip', 'geoip'], cwd=OUTPUT_DIR)
+
 
+def prepare_repos(versions):
+    prepare_repo(os.path.join(BUILD_DIR, "tor"), versions['tor']['url'], versions['tor']['commit'])
+    prepare_repo(os.path.join(BUILD_DIR, "libevent"), versions['libevent']['url'], versions['libevent']['commit'])
+    prepare_repo(os.path.join(BUILD_DIR, "openssl"), versions['openssl']['url'], versions['openssl']['commit'])
+    prepare_repo(os.path.join(BUILD_DIR, "xz"), versions['xz']['url'], versions['xz']['commit'])
+    prepare_repo(os.path.join(BUILD_DIR, "zlib"), versions['zlib']['url'], versions['zlib']['commit'])
+    prepare_repo(os.path.join(BUILD_DIR, "zstd"), versions['zstd']['url'], versions['zstd']['commit'])
 
-def prepare_tor_android_repo(versions):
-    if os.path.isdir(REPO_DIR):
+
+def prepare_repo(path, url, version):
+    if os.path.isdir(path):
         # get latest commits and tags from remote
-        check_call(['git', 'fetch', '--recurse-submodules=yes', 'origin'], cwd=REPO_DIR)
+        check_call(['git', 'fetch', '--recurse-submodules=yes', 'origin'], cwd=path)
     else:
         # clone repo
-        url = versions['tor_android_repo_url']
-        check_call(['git', 'clone', url, REPO_DIR])
+        check_call(['git', 'clone', url, path])
 
-    # checkout tor-android version
-    check_call(['git', 'checkout', '-f', versions['tor-android']], cwd=REPO_DIR)
+    # checkout given version
+    check_call(['git', 'checkout', '-f', version], cwd=path)
 
     # initialize and/or update submodules
     # (after checkout, because submodules can point to non-existent commits on master)
-    check_call(['git', 'submodule', 'update', '--init', '--recursive', '-f'], cwd=REPO_DIR)
+    check_call(['git', 'submodule', 'update', '--init', '--recursive', '-f'], cwd=path)
 
     # undo all changes
-    check_call(['git', 'reset', '--hard'], cwd=REPO_DIR)
-    check_call(['git', 'submodule', 'foreach', 'git', 'reset', '--hard'], cwd=REPO_DIR)
+    check_call(['git', 'reset', '--hard'], cwd=path)
+    check_call(['git', 'submodule', 'foreach', 'git', 'reset', '--hard'], cwd=path)
 
     # clean all untracked files and directories (-d) from repo
-    check_call(['git', 'clean', '-dffx'], cwd=REPO_DIR)
-    check_call(['git', 'submodule', 'foreach', 'git', 'clean', '-dffx'], cwd=REPO_DIR)
-
-    # add zlib
-    check_call(['git', 'clone', ZLIB_REPO_URL], cwd=EXT_DIR)
-
-    # check out versions of external dependencies
-    checkout('tor', versions['tor'], 'tor')
-    checkout('libevent', versions['libevent'], 'libevent')
-    checkout('openssl', versions['openssl'], 'openssl')
-    checkout('xz', versions['xz'], 'xz')
-    checkout('zlib', versions['zlib'], 'zlib')
-    checkout('zstd', versions['zstd'], 'zstd')
+    check_call(['git', 'clean', '-dffx'], cwd=path)
+    check_call(['git', 'submodule', 'foreach', 'git', 'clean', '-dffx'], cwd=path)
 
 
 def get_version():
@@ -130,18 +174,12 @@ def get_pom_file_name(versions, platform):
     return 'tor-%s.pom' % get_file_suffix(versions, platform)
 
 
-def checkout(name, tag, path):
-    print("Checking out %s: %s" % (name, tag))
-    repo_path = os.path.join(EXT_DIR, path)
-    check_call(['git', 'checkout', '-f', tag], cwd=repo_path)
-
-
 def pack(versions, file_list, platform):
     # make file times deterministic before zipping
     for filename in file_list:
         reset_time(filename, versions)
     zip_name = get_final_file_name(versions, platform)
-    check_call(['zip', '-D', '-X', zip_name] + file_list)
+    check_call(['zip', '--no-dir-entries', '--junk-paths', '-X', zip_name] + file_list)
     return zip_name
 
 
@@ -155,7 +193,7 @@ def reset_time(filename, versions):
 
 def create_sources_jar(versions, platform):
     jar_files = []
-    for root, dir_names, filenames in os.walk(EXT_DIR):
+    for root, dir_names, filenames in os.walk(BUILD_DIR):
         for f in filenames:
             if '/.git' in root:
                 continue
@@ -164,8 +202,13 @@ def create_sources_jar(versions, platform):
         reset_time(file, versions)
     jar_name = get_sources_file_name(versions, platform)
     jar_path = os.path.abspath(jar_name)
-    rel_paths = [os.path.relpath(f, EXT_DIR) for f in sorted(jar_files)]
-    check_call(['jar', 'cf', jar_path] + rel_paths, cwd=EXT_DIR)
+    rel_paths = [os.path.relpath(f, OUTPUT_DIR) for f in sorted(jar_files)]
+    # create jar archive with first files
+    jar_step = 5000
+    check_call(['jar', 'cf', jar_path] + rel_paths[0:jar_step], cwd=OUTPUT_DIR)
+    # add subsequent files in steps, because the command line can't handle all at once
+    for i in range(jar_step, len(rel_paths), jar_step):
+        check_call(['jar', 'uf', jar_path] + rel_paths[i:i + jar_step], cwd=OUTPUT_DIR)
     return jar_name