diff --git a/.gitignore b/.gitignore
index 76ce2ef23af4beaf5bd2329255f7f0bc38ed6804..d17f34632adb1768d2551edb1a9907862d6a8122 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,5 +8,7 @@
 /obfs4proxy*.zip
 /obfs4proxy*.pom
 /obfs4proxy*.jar
-/obfs4
+/snowflake*.zip
+/snowflake*.pom
+/snowflake*.jar
 /reference
\ No newline at end of file
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 6b8aab0e1737a7c2128a4d0e004fcaa9c816ae1c..61a92d7dfaf7bb5a4c4e6b29e79b06837adfd978 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -21,15 +21,29 @@ build:
     - docker build -t ${TEST_IMAGE} .
     - docker push $TEST_IMAGE
 
-test:
+test_obfs4proxy:
   stage: test
   script:
-    - docker run -v `pwd`:/opt/go-reproducer ${TEST_IMAGE} /bin/bash -c "./build-obfs4proxy.py && ./verify-obfs4proxy.py"
+    - docker run -v `pwd`:/opt/go-reproducer ${TEST_IMAGE} /bin/bash -c "./build-binary.py obfs4proxy && ./verify-binary.py obfs4proxy"
   allow_failure: true
   artifacts:
     paths:
-    - obfs4proxy-*.jar
-    - obfs4proxy-*.pom
+      - obfs4proxy-*.jar
+      - obfs4proxy-*.pom
+    expire_in: 1 week
+    when: always
+  except:
+    - tags
+
+test_snowflake:
+  stage: test
+  script:
+    - docker run -v `pwd`:/opt/go-reproducer ${TEST_IMAGE} /bin/bash -c "./build-binary.py snowflake && ./verify-binary.py snowflake"
+  allow_failure: true
+  artifacts:
+    paths:
+      - snowflake-*.jar
+      - snowflake-*.pom
     expire_in: 1 week
     when: always
   except:
@@ -38,12 +52,16 @@ test:
 test_tag:
   stage: test
   script:
-    - docker run -v `pwd`:/opt/go-reproducer ${TEST_IMAGE} /bin/bash -c "./verify-obfs4proxy.py ${CI_BUILD_REF_NAME}"
+    - docker run -v `pwd`:/opt/go-reproducer ${TEST_IMAGE} /bin/bash -c "./verify-binary.py obfs4proxy ${CI_BUILD_REF_NAME}"
+    - docker run -v `pwd`:/opt/go-reproducer ${TEST_IMAGE} /bin/bash -c "./verify-binary.py snowflake ${CI_BUILD_REF_NAME}"
   artifacts:
     paths:
     - obfs4proxy-*.zip
     - obfs4proxy-*.pom
     - obfs4proxy-*-sources.jar
+    - snowflake-*.zip
+    - snowflake-*.pom
+    - snowflake-*-sources.jar
     expire_in: 1 week
     when: always
   only:
diff --git a/Dockerfile b/Dockerfile
index 1ed32f355d89efc3664139eb21f8ffb862f9d5ae..833334334b0b20cdab4351bacf1f2e840f705dc7 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -6,14 +6,14 @@ ENV DEBIAN_FRONTEND=noninteractive
 
 WORKDIR /opt/go-reproducer
 
-ADD build-obfs4proxy.py ./
+ADD build-binary.py ./
 ADD install*.py ./
 ADD install*.sh ./
 ADD versions.json ./
 ADD utils.py ./
 ADD template-*.pom ./
-ADD verify-obfs4proxy.py ./
+ADD verify-binary.py ./
 
 RUN ./install.sh
 
-CMD ./verify-obfs4proxy.py
+CMD ./verify-binary.py obfs4proxy
diff --git a/README.md b/README.md
index 3899be0e42009f536d3c2be305baa56f6dbb9f97..f9a2a6f4b878d30a7476580e8189d7a1735c0fce 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,18 @@
 # Go Reproducer
 
 This is a tool you can use to verify that golang binaries
-used by [Briar](https://briar.app) (such as obfs4proxy)
+used by [Briar](https://briarproject.org) (such as obfs4proxy and snowflake)
 were built exactly from the public source code
 and no modifications (such as backdoors) were added.
 
 Current packages:
 
-* https://bintray.com/briarproject/org.briarproject/obfs4proxy
-* https://bintray.com/briarproject/org.briarproject/obfs4proxy-android
+* https://mvnrepository.com/artifact/org.briarproject/obfs4proxy-android
+* https://mvnrepository.com/artifact/org.briarproject/obfs4proxy-linux
+* https://mvnrepository.com/artifact/org.briarproject/obfs4proxy-windows
+* https://mvnrepository.com/artifact/org.briarproject/snowflake-android
+* https://mvnrepository.com/artifact/org.briarproject/snowflake-linux
+* https://mvnrepository.com/artifact/org.briarproject/snowflake-windows
 
 More information about these so called reproducible builds is available at
 [reproducible-builds.org](https://reproducible-builds.org/).
@@ -61,15 +65,17 @@ which inject outdated vulnerable packages.
 
 ### Run the verification
 
-To verify a specific version of obfs4proxy, run
+To verify a specific version of a binary, run
 
-    docker run briar/go-reproducer:latest ./verify-obfs4proxy.py [version]
+    docker run briar/go-reproducer:latest ./verify-binary.py <binary> [version]
 
-Where `[version]` is the version of obfs4proxy you want to test, for example `0.3.3.6`.
+Where `<binary>` is either `obfs4proxy` or `snowflake` and `[version]` is the version of the binary
+you want to test, for example `0.0.14-tor1`.
 
-You can find a list of versions in obfs4proxy's
-[source code repository](https://gitweb.torproject.org/pluggable-transports/obfs4.git/refs/).
-Just remove the `obfs4proxy-` from `obfs4proxy-0.0.7`.
+You can find a list of versions in `versions.json`. These are based on tags in the source code
+repositories for
+[obfs4proxy](https://gitweb.torproject.org/pluggable-transports/obfs4.git/refs) and
+[snowflake](https://gitweb.torproject.org/pluggable-transports/snowflake.git/refs).
 
 If you leave out `[version]` it will build the latest version
 that was registered in `versions.json`.
@@ -78,14 +84,14 @@ In case there is an issue with the verification of an old build,
 this *might* be caused by an update of the container.
 You can try to use the original container by running:
 
-    docker run briar/go-reproducer:[version] ./verify-obfs4proxy.py [version]
+    docker run briar/go-reproducer:[version] ./verify-binary.py <binary> [version]
 
 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.
 
-### Only build obfs4proxy
+### Only build the binary
 
-To build a specific version of obfs4proxy, run
+To build a specific version of a binary without verifying it, run
 
-    docker run briar/go-reproducer:latest ./build-obfs4proxy.py [version]
\ No newline at end of file
+    docker run briar/go-reproducer:latest ./build-binary.py <binary> [version]
diff --git a/build-binary.py b/build-binary.py
new file mode 100755
index 0000000000000000000000000000000000000000..38db13eab3728af61f5e86cc2ae438ea8dfa34c6
--- /dev/null
+++ b/build-binary.py
@@ -0,0 +1,216 @@
+#!/usr/bin/env python3
+import os
+from glob import glob
+from subprocess import check_call
+
+from utils import get_build_versions, ex, get_sha256, zip_files, get_final_file_name, \
+    get_sources_file_name, get_pom_file_name, reset_time, get_version_number, check_go_version, \
+    get_version_and_tool, GO_PATH, GO_ROOT, NDK_DIR
+
+
+def main():
+    # get version from command line or show usage information
+    tool, command_line_version = get_version_and_tool()
+
+    # Get the latest versions for building
+    tool_version, versions = get_build_versions(tool, command_line_version)
+    print("Building %s %s" % (tool, tool_version))
+
+    # Install Go
+    install_go(tool, tool_version, versions)
+
+    # Install Android NDK
+    install_android_ndk(tool, tool_version)
+
+    # Checkout source at specific version
+    checkout_source_repo(tool, versions)
+
+    # Build and package for various platforms and architectures
+    build_android(tool, versions)
+    package_android(tool, versions)
+
+    build_linux(tool, versions)
+    package_linux(tool, versions)
+
+    build_windows(tool, versions)
+    package_windows(tool, versions)
+
+
+def get_repo_dir(versions):
+    # This needs to be always the same path, otherwise it breaks reproducibility
+    return '/tmp/%s' % versions['repo_dir']
+
+
+def install_go(tool, tool_version, versions):
+    ex(['./install-go.py', tool, tool_version])
+    go_bin_path = os.path.join(GO_ROOT, 'bin')
+    os.environ['GOPATH'] = GO_PATH
+    os.environ['PATH'] = go_bin_path + os.pathsep + os.getenv('PATH')
+    os.environ['GO111MODULE'] = 'on'
+    check_go_version(versions)
+
+
+def install_android_ndk(tool, tool_version):
+    ex(['./install-android-ndk.py', tool, tool_version])
+    os.environ['ANDROID_NDK_HOME'] = os.path.abspath(NDK_DIR)
+
+
+def checkout_source_repo(tool, versions):
+    repo_dir = get_repo_dir(versions)
+    if os.path.isdir(repo_dir):
+        # get latest commits and tags from remote
+        check_call(['git', 'fetch', 'origin'], cwd=repo_dir)
+    else:
+        # clone repo
+        check_call(['git', 'clone', versions['repo_url'], repo_dir])
+
+    # checkout version
+    print("Checking out %s" % versions['revision'])
+    check_call(['git', 'checkout', '-f', versions['revision']], cwd=repo_dir)
+
+    # undo all changes
+    check_call(['git', 'reset', '--hard'], cwd=repo_dir)
+
+    # clean all untracked files and directories (-d) from repo
+    check_call(['git', 'clean', '-dffx'], cwd=repo_dir)
+
+
+def build_android(tool, versions):
+    env = os.environ.copy()
+    env['GOARCH'] = "arm"
+    env['GOARM'] = "7"
+    build_android_arch(tool, versions, env, "arm-linux-androideabi", "arm")
+
+    env = os.environ.copy()
+    env['GOARCH'] = "arm64"
+    build_android_arch(tool, versions, env, "aarch64-linux-android", "arm64")
+
+    env = os.environ.copy()
+    env['GOARCH'] = "386"
+    build_android_arch(tool, versions, env, "i686-linux-android", "x86")
+
+    env = os.environ.copy()
+    env['GOARCH'] = "amd64"
+    build_android_arch(tool, versions, env, "x86_64-linux-android", "x86_64")
+
+
+def build_android_arch(tool, versions, env, clang_arch, ndk_arch):
+    toolchain = os.path.join("toolchain", ndk_arch)
+    if not os.path.isdir(toolchain):
+        toolchain_maker = os.path.join(NDK_DIR, "build", "tools", "make-standalone-toolchain.sh")
+        ex([toolchain_maker, "--arch=%s" % ndk_arch, "--install-dir=%s" % toolchain])
+
+    env['CC'] = "%s/bin/%s-clang" % (os.path.abspath(toolchain), clang_arch)
+    env['CGO_ENABLED'] = "1"
+    env['CGO_CFLAGS'] = "-O2"  # removes -g
+    env['GOOS'] = "android"
+
+    build_mode = "pie"
+    extldflags = " -extldflags=-pie"
+
+    filename = "%s_%s_pie.zip" % (tool, ndk_arch)
+    print("Building %s" % filename)
+
+    output_file = os.path.abspath(os.path.join(os.path.curdir, tool))
+    go_flags = ['-asmflags', '-trimpath', '-o', output_file]
+    repo_dir = get_repo_dir(versions)
+    ex(['go', 'build', '-buildmode=%s' % build_mode, '-ldflags', '-w -s' + extldflags] + go_flags +
+       [os.path.join('.', versions['build_path'])], env=env, cwd=repo_dir)
+
+    zip_files([tool], filename, versions)
+    os.remove(tool)
+
+
+def build_linux(tool, versions):
+    build_desktop_arch(tool, versions, 'linux', 'armhf', 'arm', '7')
+    build_desktop_arch(tool, versions, 'linux', 'aarch64', 'arm64')
+    build_desktop_arch(tool, versions, 'linux', 'x86_64', 'amd64')
+
+
+def build_windows(tool, versions):
+    build_desktop_arch(tool, versions, 'windows', 'x86_64', 'amd64')
+
+
+def build_desktop_arch(tool, versions, goos, arch, goarch, goarm=None):
+    env = os.environ.copy()
+    env['CGO_ENABLED'] = "0"
+    env['GOOS'] = goos
+    env['GOARCH'] = goarch
+    if goarm: env['GOARM'] = goarm
+    build_path = os.path.join('.', versions['build_path'])
+    filename = "%s_%s-%s.zip" % (tool, goos, arch)
+    print("Building %s" % filename)
+    output_file = os.path.abspath(os.path.join(os.path.curdir, tool))
+    go_flags = ['-asmflags', '-trimpath', '-o', output_file]
+    repo_dir = get_repo_dir(versions)
+    ex(['go', 'build', '-ldflags', '-w -s'] + go_flags + [build_path], env=env, cwd=repo_dir)
+    zip_files([tool], filename, versions)
+    os.remove(tool)
+
+
+def package_android(tool, versions):
+    file_list = [
+        '%s_arm_pie.zip' % tool,
+        '%s_arm64_pie.zip' % tool,
+        '%s_x86_pie.zip' % tool,
+        '%s_x86_64_pie.zip' % tool
+    ]
+    package(tool, versions, file_list, 'android')
+
+
+def package_linux(tool, versions):
+    file_list = [
+        '%s_linux-armhf.zip' % tool,
+        '%s_linux-aarch64.zip' % tool,
+        '%s_linux-x86_64.zip' % tool
+    ]
+    package(tool, versions, file_list, 'linux')
+
+
+def package_windows(tool, versions):
+    file_list = ['%s_windows-x86_64.zip' % tool]
+    package(tool, versions, file_list, 'windows')
+
+
+def package(tool, versions, file_list, platform):
+    zip_file = get_final_file_name(tool, versions, platform)
+    zip_files(file_list, zip_file, versions)
+    create_sources_jar(tool, versions, platform)
+    create_pom_file(tool, versions, platform)
+
+    # print hashes for debug purposes
+    for file in file_list + [zip_file]:
+        sha256hash = get_sha256(file)
+        prefix = '->' if file == zip_file else ''
+        print("%s %s: %s" % (prefix, file, sha256hash))
+
+
+def create_sources_jar(tool, versions, platform):
+    repo_dir = get_repo_dir(versions)
+    # clean all untracked files and directories (-d) from repo
+    check_call(['git', 'clean', '-dffx'], cwd=repo_dir)
+    # vendorize dependencies
+    ex(['go', 'mod', 'vendor'], cwd=repo_dir)
+    jar_files = []
+    for file in glob(os.path.join(repo_dir, '*')):
+        reset_time(file, versions)
+        jar_files.append(os.path.relpath(file, repo_dir))
+    jar_file = get_sources_file_name(tool, versions, platform)
+    jar_path = os.path.abspath(jar_file)
+    check_call(['jar', 'cf', jar_path] + jar_files, cwd=repo_dir)
+    return jar_file
+
+
+def create_pom_file(tool, versions, platform):
+    tool_version = get_version_number(versions)
+    pom_file = get_pom_file_name(tool, versions, platform)
+    template = 'template-%s-%s.pom' % (tool, platform)
+    with open(template, 'rt') as infile:
+        with open(pom_file, 'wt') as outfile:
+            for line in infile:
+                outfile.write(line.replace('VERSION', tool_version))
+    return pom_file
+
+
+if __name__ == "__main__":
+    main()
diff --git a/build-obfs4proxy.py b/build-obfs4proxy.py
deleted file mode 100755
index 3b22dceffe9d3f1ddf78870a073c10f3b9188965..0000000000000000000000000000000000000000
--- a/build-obfs4proxy.py
+++ /dev/null
@@ -1,207 +0,0 @@
-#!/usr/bin/env python3
-import os
-from glob import glob
-from subprocess import check_call
-
-from utils import get_build_versions, ex, get_sha256, zip_files, get_final_file_name, \
-    get_sources_file_name, get_pom_file_name, reset_time, get_obfs4_version, check_go_version, \
-    get_version, GO_PATH, GO_ROOT, NDK_DIR
-
-REPO_DIR = '/tmp/obfs4'  # This needs to be always the same path, otherwise breaks reproducibility
-OUTPUT_FILE = os.path.abspath(os.path.join(os.path.curdir, 'obfs4proxy'))
-GO_FLAGS = ['-asmflags', '-trimpath', '-o', OUTPUT_FILE]
-
-
-def main():
-    # get version from command line or show usage information
-    command_line_version = get_version()
-
-    # Get the latest versions for building
-    tool_version, versions = get_build_versions('obfs4proxy', command_line_version)
-    print("Building obfs4proxy %s" % tool_version)
-
-    # Install Go
-    install_go(tool_version, versions)
-
-    # Install Android NDK
-    install_android_ndk(tool_version)
-
-    # Checkout source at specific version
-    checkout_source_repo(versions)
-
-    # Build and package for various platforms and architectures
-    build_android(versions)
-    package_android(versions)
-
-    build_linux(versions)
-    package_linux(versions)
-
-    build_windows(versions)
-    package_windows(versions)
-
-
-def install_go(tool_version, versions):
-    ex(['./install-go.py', 'obfs4proxy', tool_version])
-    go_bin_path = os.path.join(GO_ROOT, 'bin')
-    os.environ['GOPATH'] = GO_PATH
-    os.environ['PATH'] = go_bin_path + os.pathsep + os.getenv('PATH')
-    os.environ['GO111MODULE'] = 'on'
-    check_go_version(versions)
-
-
-def install_android_ndk(tool_version):
-    ex(['./install-android-ndk.py', 'obfs4proxy', tool_version])
-    os.environ['ANDROID_NDK_HOME'] = os.path.abspath(NDK_DIR)
-
-
-def checkout_source_repo(versions):
-    if os.path.isdir(REPO_DIR):
-        # get latest commits and tags from remote
-        check_call(['git', 'fetch', 'origin'], cwd=REPO_DIR)
-    else:
-        # clone repo
-        check_call(['git', 'clone', versions['repo_url'], REPO_DIR])
-
-    # checkout version
-    print("Checking out %s" % versions['revision'])
-    check_call(['git', 'checkout', '-f', versions['revision']], cwd=REPO_DIR)
-
-    # undo all changes
-    check_call(['git', 'reset', '--hard'], cwd=REPO_DIR)
-
-    # clean all untracked files and directories (-d) from repo
-    check_call(['git', 'clean', '-dffx'], cwd=REPO_DIR)
-
-
-def build_android(versions):
-    env = os.environ.copy()
-    env['GOARCH'] = "arm"
-    env['GOARM'] = "7"
-    build_android_arch(versions, env, "arm-linux-androideabi", ndk_arch="arm")
-
-    env = os.environ.copy()
-    env['GOARCH'] = "arm64"
-    build_android_arch(versions, env, "aarch64-linux-android", ndk_arch="arm64")
-
-    env = os.environ.copy()
-    env['GOARCH'] = "386"
-    build_android_arch(versions, env, "i686-linux-android", ndk_arch="x86")
-
-    env = os.environ.copy()
-    env['GOARCH'] = "amd64"
-    build_android_arch(versions, env, "x86_64-linux-android", ndk_arch="x86_64")
-
-
-def build_android_arch(versions, env, tool, ndk_arch):
-    toolchain = os.path.join("toolchain", ndk_arch)
-    if not os.path.isdir(toolchain):
-        toolchain_maker = os.path.join(NDK_DIR, "build", "tools", "make-standalone-toolchain.sh")
-        ex([toolchain_maker, "--arch=%s" % ndk_arch, "--install-dir=%s" % toolchain])
-
-    env['CC'] = "%s/bin/%s-clang" % (os.path.abspath(toolchain), tool)
-    env['CGO_ENABLED'] = "1"
-    env['CGO_CFLAGS'] = "-O2"  # removes -g
-    env['GOOS'] = "android"
-
-    build_mode = "pie"
-    extldflags = " -extldflags=-pie"
-
-    filename = "obfs4proxy_%s_pie.zip" % ndk_arch
-    print("Building %s" % filename)
-
-    ex(['go', 'build', '-buildmode=%s' % build_mode, '-ldflags', '-w -s' + extldflags] + GO_FLAGS +
-       [os.path.join('.', versions['build_path'])], env=env, cwd=REPO_DIR)
-
-    zip_files(['obfs4proxy'], filename, versions)
-    os.remove('obfs4proxy')
-
-
-def build_linux(versions):
-    build_desktop_arch(versions, 'linux', 'armhf', 'arm', '7')
-    build_desktop_arch(versions, 'linux', 'aarch64', 'arm64')
-    build_desktop_arch(versions, 'linux', 'x86_64', 'amd64')
-
-
-def build_windows(versions):
-    build_desktop_arch(versions, 'windows', 'x86_64', 'amd64')
-
-
-def build_desktop_arch(versions, goos, arch, goarch, goarm=None):
-    env = os.environ.copy()
-    env['CGO_ENABLED'] = "0"
-    env['GOOS'] = goos
-    env['GOARCH'] = goarch
-    if goarm: env['GOARM'] = goarm
-    build_path = os.path.join('.', versions['build_path'])
-    filename = "obfs4proxy_%s-%s.zip" % (goos, arch)
-    print("Building %s" % filename)
-    ex(['go', 'build', '-ldflags', '-w -s'] + GO_FLAGS + [build_path], env=env, cwd=REPO_DIR)
-    zip_files(['obfs4proxy'], filename, versions)
-    os.remove('obfs4proxy')
-
-
-def package_android(versions):
-    file_list = [
-        'obfs4proxy_arm_pie.zip',
-        'obfs4proxy_arm64_pie.zip',
-        'obfs4proxy_x86_pie.zip',
-        'obfs4proxy_x86_64_pie.zip'
-    ]
-    package(versions, file_list, 'android')
-
-
-def package_linux(versions):
-    file_list = [
-        'obfs4proxy_linux-armhf.zip',
-        'obfs4proxy_linux-aarch64.zip',
-        'obfs4proxy_linux-x86_64.zip'
-    ]
-    package(versions, file_list, 'linux')
-
-
-def package_windows(versions):
-    file_list = ['obfs4proxy_windows-x86_64.zip']
-    package(versions, file_list, 'windows')
-
-
-def package(versions, file_list, platform):
-    zip_file = get_final_file_name(versions, platform)
-    zip_files(file_list, zip_file, versions)
-    create_sources_jar(versions, platform)
-    create_pom_file(versions, platform)
-
-    # print hashes for debug purposes
-    for file in file_list + [zip_file]:
-        sha256hash = get_sha256(file)
-        prefix = '->' if file == zip_file else ''
-        print("%s %s: %s" % (prefix, file, sha256hash))
-
-
-def create_sources_jar(versions, platform):
-    # clean all untracked files and directories (-d) from repo
-    check_call(['git', 'clean', '-dffx'], cwd=REPO_DIR)
-    # vendorize dependencies
-    ex(['go', 'mod', 'vendor'], cwd=REPO_DIR)
-    jar_files = []
-    for file in glob(os.path.join(REPO_DIR, '*')):
-        reset_time(file, versions)
-        jar_files.append(os.path.relpath(file, REPO_DIR))
-    jar_file = get_sources_file_name(versions, platform)
-    jar_path = os.path.abspath(jar_file)
-    check_call(['jar', 'cf', jar_path] + jar_files, cwd=REPO_DIR)
-    return jar_file
-
-
-def create_pom_file(versions, platform):
-    tor_version = get_obfs4_version(versions)
-    pom_file = get_pom_file_name(versions, platform)
-    template = 'template-%s.pom' % platform
-    with open(template, 'rt') as infile:
-        with open(pom_file, 'wt') as outfile:
-            for line in infile:
-                outfile.write(line.replace('VERSION', tor_version))
-    return pom_file
-
-
-if __name__ == "__main__":
-    main()
diff --git a/install.sh b/install.sh
index 57aee0f6333c83218f851b39e8d9001acd4dd6ea..dd3504b18c7e9b3ec0ee9c4a4a5e26099919e402 100755
--- a/install.sh
+++ b/install.sh
@@ -3,9 +3,10 @@ set -e
 set -x
 
 # use snapshot repos for deterministic package versions
-DATE="20220922T000000Z"
+DATE="20221108T000000Z"
 cat << EOF > /etc/apt/sources.list
 deb http://snapshot.debian.org/archive/debian/${DATE}/ bullseye main
+deb http://snapshot.debian.org/archive/debian/${DATE}/ bullseye-updates main
 EOF
 
 # ignore expired package releases if env variable is set
diff --git a/template-android.pom b/template-obfs4proxy-android.pom
similarity index 100%
rename from template-android.pom
rename to template-obfs4proxy-android.pom
diff --git a/template-linux.pom b/template-obfs4proxy-linux.pom
similarity index 100%
rename from template-linux.pom
rename to template-obfs4proxy-linux.pom
diff --git a/template-windows.pom b/template-obfs4proxy-windows.pom
similarity index 100%
rename from template-windows.pom
rename to template-obfs4proxy-windows.pom
diff --git a/template-snowflake-android.pom b/template-snowflake-android.pom
new file mode 100644
index 0000000000000000000000000000000000000000..874baba8fedd43f3965434bcdea4e0f85a8e3fea
--- /dev/null
+++ b/template-snowflake-android.pom
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.briarproject</groupId>
+  <artifactId>snowflake-android</artifactId>
+  <name>snowflake-android</name>
+  <version>VERSION</version>
+  <url>https://torproject.org</url>
+  <description>Repo for building snowflake for Android.</description>
+  <licenses>
+   <license>
+     <name>BSD-3-clause</name>
+     <url>https://gitweb.torproject.org/pluggable-transports/snowflake.git/tree/LICENSE</url>
+   </license>
+  </licenses>
+  <developers>
+    <developer>
+      <id>torproject</id>
+      <name>Tor Project</name>
+      <email>frontdesk@rt.torproject.org</email>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:https://git.torproject.org/pluggable-transports/snowflake.git</connection>
+    <developerConnection>scm:git@gitweb.torproject.org/pluggable-transports/snowflake.git</developerConnection>
+    <url>scm:https://gitweb.torproject.org/pluggable-transports/snowflake.git</url>
+  </scm>
+</project>
diff --git a/template-snowflake-linux.pom b/template-snowflake-linux.pom
new file mode 100644
index 0000000000000000000000000000000000000000..4d2b1c7d9dfab0d18b270e305564c4aa2114e60f
--- /dev/null
+++ b/template-snowflake-linux.pom
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.briarproject</groupId>
+  <artifactId>snowflake-linux</artifactId>
+  <name>snowflake-linux</name>
+  <version>VERSION</version>
+  <url>https://torproject.org</url>
+  <description>Repo for building snowflake for Linux.</description>
+  <licenses>
+   <license>
+     <name>BSD-3-clause</name>
+     <url>https://gitweb.torproject.org/pluggable-transports/snowflake.git/tree/LICENSE</url>
+   </license>
+  </licenses>
+  <developers>
+    <developer>
+      <id>torproject</id>
+      <name>Tor Project</name>
+      <email>frontdesk@rt.torproject.org</email>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:https://git.torproject.org/pluggable-transports/snowflake.git</connection>
+    <developerConnection>scm:git@gitweb.torproject.org/pluggable-transports/snowflake.git</developerConnection>
+    <url>scm:https://gitweb.torproject.org/pluggable-transports/snowflake.git</url>
+  </scm>
+</project>
diff --git a/template-snowflake-windows.pom b/template-snowflake-windows.pom
new file mode 100644
index 0000000000000000000000000000000000000000..5bb59acafe9a055878113be761f1c02c9b080931
--- /dev/null
+++ b/template-snowflake-windows.pom
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.briarproject</groupId>
+  <artifactId>snowflake-windows</artifactId>
+  <name>snowflake-windows</name>
+  <version>VERSION</version>
+  <url>https://torproject.org</url>
+  <description>Repo for building snowflake for Windows.</description>
+  <licenses>
+   <license>
+     <name>BSD-3-clause</name>
+     <url>https://gitweb.torproject.org/pluggable-transports/snowflake.git/tree/LICENSE</url>
+   </license>
+  </licenses>
+  <developers>
+    <developer>
+      <id>torproject</id>
+      <name>Tor Project</name>
+      <email>frontdesk@rt.torproject.org</email>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:https://git.torproject.org/pluggable-transports/snowflake.git</connection>
+    <developerConnection>scm:git@gitweb.torproject.org/pluggable-transports/snowflake.git</developerConnection>
+    <url>scm:https://gitweb.torproject.org/pluggable-transports/snowflake.git</url>
+  </scm>
+</project>
diff --git a/utils.py b/utils.py
index 1d032c603c8165be1c727036b10a3acc89394bc6..d096cb6d2ebdfc6221192f9f7f06da5021018c73 100644
--- a/utils.py
+++ b/utils.py
@@ -12,15 +12,9 @@ GO_PATH = '/tmp/go-path'
 NDK_DIR = 'android-ndk'
 
 
-def get_version():
-    if len(sys.argv) > 2:
-        fail("Usage: %s [version tag]" % sys.argv[0])
-    return sys.argv[1] if len(sys.argv) > 1 else None
-
-
 def get_version_and_tool():
     if len(sys.argv) < 2 or len(sys.argv) > 3:
-        fail("Usage: %s tool [version tag]" % sys.argv[0])
+        fail("Usage: %s <binary> [version]" % sys.argv[0])
     tool = sys.argv[1]
     command_line_version = sys.argv[2] if len(sys.argv) > 2 else None
     return tool, command_line_version
@@ -78,22 +72,22 @@ def zip_files(files, zip_name, versions):
     ex(['zip', '-D', '-X', zip_name] + files)
 
 
-def get_obfs4_version(versions):
+def get_version_number(versions):
     return versions['tag']
 
 
 def get_file_suffix(versions, platform):
-    version = get_obfs4_version(versions)
+    version = get_version_number(versions)
     return "%s-%s" % (platform, version)
 
 
-def get_final_file_name(versions, platform):
-    return 'obfs4proxy-%s.jar' % get_file_suffix(versions, platform)
+def get_final_file_name(tool, versions, platform):
+    return '%s-%s.jar' % (tool, get_file_suffix(versions, platform))
 
 
-def get_sources_file_name(versions, platform):
-    return 'obfs4proxy-%s-sources.jar' % get_file_suffix(versions, platform)
+def get_sources_file_name(tool, versions, platform):
+    return '%s-%s-sources.jar' % (tool, get_file_suffix(versions, platform))
 
 
-def get_pom_file_name(versions, platform):
-    return 'obfs4proxy-%s.pom' % get_file_suffix(versions, platform)
+def get_pom_file_name(tool, versions, platform):
+    return '%s-%s.pom' % (tool, get_file_suffix(versions, platform))
diff --git a/verify-obfs4proxy.py b/verify-binary.py
similarity index 52%
rename from verify-obfs4proxy.py
rename to verify-binary.py
index 5113b4650e4c1b63c26773e3bdf890740c378b04..7c69ebfef212103b4e6d9f6786c0b47eaf281821 100755
--- a/verify-obfs4proxy.py
+++ b/verify-binary.py
@@ -4,41 +4,41 @@ import sys
 from subprocess import check_call, CalledProcessError
 
 from utils import get_sha256, fail, get_build_versions, get_final_file_name, \
-    get_version, get_obfs4_version
+    get_version_and_tool, get_version_number
 
 
 def main():
     # get version from command or show usage information
-    version = get_version()
+    tool, command_line_version = get_version_and_tool()
 
-    verified_android = verify(version, 'android')
-    verified_linux = verify(version, 'linux')
-    verified_windows = verify(version, 'windows')
+    verified_android = verify(tool, command_line_version, 'android')
+    verified_linux = verify(tool, command_line_version, 'linux')
+    verified_windows = verify(tool, command_line_version, 'windows')
     if verified_android and verified_linux and verified_windows:
         sys.exit(0)
     else:
         sys.exit(1)
 
 
-def verify(version, platform):
+def verify(tool, command_line_version, platform):
     # get version and versions of its dependencies
-    tool_version, versions = get_build_versions('obfs4proxy', version)
+    tool_version, versions = get_build_versions(tool, command_line_version)
 
     # download reference binary
-    file_name = get_final_file_name(versions, platform)
+    file_name = get_final_file_name(tool, versions, platform)
     os.makedirs('reference', exist_ok=True)
     reference_file_name = os.path.join('reference', file_name)
     # try downloading from maven central
-    check_call(['wget', '--no-verbose', get_url(versions, platform), '-O',
+    check_call(['wget', '--no-verbose', get_url(tool, versions, platform), '-O',
                 reference_file_name])
 
     # check if it was already build
     if not os.path.isfile(file_name):
         # build it first
-        if version is None:
-            check_call(['./build-obfs4proxy.py'])
+        if command_line_version is None:
+            check_call(['./build-binary.py', tool])
         else:
-            check_call(['./build-obfs4proxy.py', version])
+            check_call(['./build-binary.py', tool, command_line_version])
 
     # calculate hashes for both files
     reference_hash = get_sha256(reference_file_name)
@@ -48,17 +48,17 @@ def verify(version, platform):
 
     # compare hashes
     if reference_hash == build_hash:
-        print("obfs4proxy-%s version %s was successfully verified! \o/" % (platform, tool_version))
+        print("%s-%s version %s was successfully verified! \o/" % (tool, platform, tool_version))
         return True
     else:
-        print("Hashes for obfs4proxy-%s version %s do not match! :(" % (platform, tool_version))
+        print("Hashes for %s-%s version %s do not match! :(" % (tool, platform, tool_version))
         return False
 
 
-def get_url(versions, platform):
-    version = get_obfs4_version(versions)
-    directory = "obfs4proxy-%s" % platform
-    file = get_final_file_name(versions, platform)
+def get_url(tool, versions, platform):
+    version = get_version_number(versions)
+    directory = "%s-%s" % (tool, platform)
+    file = get_final_file_name(tool, versions, platform)
     return "https://repo.maven.apache.org/maven2/org/briarproject/%s/%s/%s" % (directory, version, file)
 
 
diff --git a/versions.json b/versions.json
index c57ec7c53a478e02626215403993a45ba3c012c1..1b012845be1fd9e422a525030fc003f13f07df7f 100644
--- a/versions.json
+++ b/versions.json
@@ -4,6 +4,7 @@
       "repo_url": "https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/obfs4.git",
       "revision": "ed46c23917b55c4b274d6986daeaf6bec7963115",
       "build_path": "obfs4proxy",
+      "repo_dir": "obfs4",
       "go": {
         "version": "go1.16",
         "sha256": "7688063d55656105898f323d90a79a39c378d86fe89ae192eb3b7fc46347c95a"
@@ -19,6 +20,7 @@
       "repo_url": "https://git.torproject.org/pluggable-transports/obfs4.git",
       "revision": "336a71d6e4cfd2d33e9c57797828007ad74975e9",
       "build_path": "obfs4proxy",
+      "repo_dir": "obfs4",
       "go": {
         "version": "go1.16",
         "sha256": "7688063d55656105898f323d90a79a39c378d86fe89ae192eb3b7fc46347c95a"
@@ -34,6 +36,7 @@
       "repo_url": "https://git.torproject.org/pluggable-transports/obfs4.git",
       "revision": "a564bc3840bc788605e1a8155f4b95ce0d70c6db",
       "build_path": "obfs4proxy",
+      "repo_dir": "obfs4",
       "go": {
         "version": "go1.16",
         "sha256": "7688063d55656105898f323d90a79a39c378d86fe89ae192eb3b7fc46347c95a"
@@ -49,6 +52,7 @@
       "repo_url": "https://git.torproject.org/pluggable-transports/obfs4.git",
       "revision": "40245c4a",
       "build_path": "obfs4proxy",
+      "repo_dir": "obfs4",
       "go": {
         "version": "go1.13.1",
         "sha256": "81f154e69544b9fa92b1475ff5f11e64270260d46e7e36c34aafc8bc96209358"
@@ -64,6 +68,7 @@
       "repo_url": "https://git.torproject.org/pluggable-transports/obfs4.git",
       "revision": "obfs4proxy-0.0.11",
       "build_path": "obfs4proxy",
+      "repo_dir": "obfs4",
       "go": {
         "version": "go1.13.1",
         "sha256": "81f154e69544b9fa92b1475ff5f11e64270260d46e7e36c34aafc8bc96209358"
@@ -79,6 +84,7 @@
       "repo_url": "https://git.torproject.org/pluggable-transports/obfs4.git",
       "revision": "obfs4proxy-0.0.11",
       "build_path": "obfs4proxy",
+      "repo_dir": "obfs4",
       "go": {
         "version": "go1.13.1",
         "sha256": "81f154e69544b9fa92b1475ff5f11e64270260d46e7e36c34aafc8bc96209358"
@@ -93,6 +99,7 @@
       "repo_url": "https://git.torproject.org/pluggable-transports/obfs4.git",
       "revision": "obfs4proxy-0.0.9",
       "build_path": "obfs4proxy",
+      "repo_dir": "obfs4",
       "go": {
         "version": "go1.11.5",
         "sha256": "bc1ef02bb1668835db1390a2e478dcbccb5dd16911691af9d75184bbe5aa943e"
@@ -103,5 +110,23 @@
         "sha256": "c413dd014edc37f822d0dc88fabc05b64232d07d5c6e9345224e47073fdf140b"
       }
     }
+  },
+  "snowflake": {
+    "2.3.1": {
+      "repo_url": "https://git.torproject.org/pluggable-transports/snowflake.git",
+      "revision": "36f03dfd4483922b3e7400dedc71df9cf2f30b6b",
+      "build_path": "client",
+      "repo_dir": "snowflake",
+      "go": {
+        "version": "go1.16",
+        "sha256": "7688063d55656105898f323d90a79a39c378d86fe89ae192eb3b7fc46347c95a"
+      },
+      "ndk": {
+        "url": "https://dl.google.com/android/repository/android-ndk-r18-linux-x86_64.zip",
+        "revision": "18.0.5002713",
+        "sha256": "c413dd014edc37f822d0dc88fabc05b64232d07d5c6e9345224e47073fdf140b"
+      },
+      "timestamp": "201001010000.00"
+    }
   }
 }