Snap for 8426163 from cd9c844bd676ff9ff69a74bc49e157149a7f0918 to mainline-tzdata2-release

Change-Id: I02bead3409dc2824a92b88f874dd1f264d9a91f6
diff --git a/.gitignore b/.gitignore
index f53951a..9d4d4f8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
 build/**
 .gradle/**
-.idea/**
+
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index 2624f19..0000000
--- a/.gitmodules
+++ /dev/null
@@ -1,16 +0,0 @@
-[submodule "third_party/secure_message"]
-	path = third_party/secure_message
-	url = https://github.com/google/securemessage
-	branch = master
-[submodule "third_party/gtest"]
-	path = third_party/gtest
-	url = https://github.com/google/googletest
-	branch = master
-[submodule "third_party/protobuf"]
-	path = third_party/protobuf
-	url = https://github.com/protocolbuffers/protobuf
-	branch = master
-[submodule "third_party/absl"]
-	path = third_party/absl
-	url = https://github.com/abseil/abseil-cpp
-	branch = master
diff --git a/Android.bp b/Android.bp
index 1376405..b99ed63 100644
--- a/Android.bp
+++ b/Android.bp
@@ -15,23 +15,6 @@
 // Android build file for building the library in AOSP
 // https://android.googlesource.com/platform/external/ukey2
 
-package {
-    default_applicable_licenses: ["external_ukey2_license"],
-}
-
-// Added automatically by a large-scale-change
-// http://go/android-license-faq
-license {
-    name: "external_ukey2_license",
-    visibility: [":__subpackages__"],
-    license_kinds: [
-        "SPDX-license-identifier-Apache-2.0",
-    ],
-    license_text: [
-        "LICENSE",
-    ],
-}
-
 java_library {
   name: "ukey2",
   proto: {
@@ -40,7 +23,7 @@
   },
   srcs: [
     "**/*.proto",
-    "src/main/java/**/*.java",
+    "**/*.java",
   ],
   libs: [
     "guava",
diff --git a/CMakeLists.txt b/CMakeLists.txt
deleted file mode 100644
index 02ddda2..0000000
--- a/CMakeLists.txt
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright 2020 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-cmake_minimum_required(VERSION 3.0.2)
-
-project(ukey2)
-
-option(ukey2_USE_LOCAL_PROTOBUF
-       "Use local copy of protobuf library and compiler" OFF)
-
-option(ukey2_USE_LOCAL_ABSL
-       "Use local copy of abseil-cpp library" OFF)
-
-include(cmake/proto_defs.cmake)
-include(cmake/local_build_setup.cmake)
-
-if (ukey2_USE_LOCAL_PROTOBUF)
-  include(cmake/local_build_protobuf.cmake)
-endif()
-
-if (ukey2_USE_LOCAL_ABSL)
-  if (NOT TARGET absl::base)
-    add_subdirectory(third_party/absl)
-  endif()
-else()
-  find_package(absl REQUIRED)
-endif()
-
-find_package(Protobuf REQUIRED)
-
-enable_testing()
-
-add_subdirectory(src/main)
-if (NOT TARGET securemessage)
-add_subdirectory(third_party/secure_message)
-endif()
-if (NOT TARGET gtest)
-add_subdirectory(third_party/gtest)
-endif()
diff --git a/METADATA b/METADATA
index d08b2ea..1548a33 100644
--- a/METADATA
+++ b/METADATA
@@ -5,9 +5,8 @@
 third_party {
   url {
     type: ARCHIVE
-    value: "https://github.com/google/ukey2.git"
+    value: "https://user.git.corp.google.com/michalp/ukey2/"
   }
-  version: "0275885d8e6038c39b8a8ca55e75d1d4d1727f47"
-  license_type: NOTICE
-  last_upgrade_date { year: 2021 month: 2 day: 8 }
+  version: "1.0"
+  last_upgrade_date { year: 2018 month: 12 day: 28 }
 }
diff --git a/NOTICE b/NOTICE
new file mode 120000
index 0000000..7a694c9
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1 @@
+LICENSE
\ No newline at end of file
diff --git a/README.md b/README.md
index 87a652d..2f56370 100644
--- a/README.md
+++ b/README.md
@@ -3,9 +3,7 @@
 
 **Coathored by:** Alexei Czeskis, Thai Duong, Eduardo' Vela'' \<Nava\>, and Adam Stubblefield.
 
-**Status:**
-Implemented in Java by Alexei Czeskis (aczeskis@google.com)
-Ported from Java to C++ by Tim Song (tengs@google.com)
+**Status:** Implemented in Java (aczeskis@google.com)
 
 **Design reviewers:** Thai Duong, Bruno Blanchet, Martin Abadi, and Bo Wang
 
@@ -329,64 +327,3 @@
 |`ClientFinished`| 79              |
 
 
-# Checking out source code
-
-```
-git clone https://github.com/google/ukey2
-cd ukey2
-git submodule update --init --recursive
-```
-
-# Building and tesging C++ code
-
-## Build
-```
-cd <source root>
-mkdir build; cd build
-cmake -Dukey2_USE_LOCAL_PROTOBUF=ON -Dukey2_USE_LOCAL_ABSL=ON ..
-make
-```
-## Running C++ tests
-```
-cd <source root>/build
-ctest -V
-```
-
-# Buillding Java library and running Java Tests
-
-NOTE: c++ build must be completed as described above, before running java tests.
-This requirement exists because Java build runs a c++/java compatibility test, and
-this test depends on c++ test helper binary (found in build/src/main/cpp/test/securegcm/ukey2_test).
-Gradle build does not know how to build this artifact. Java test uses a relative
-path to the artifact, and expects tests to be run from <source root> as follows:
-
-Pre-reqs: gradle
-
-1. Create gradle wrapper for a specific gradle version.
-This project was built with Gradle-6.1.1.
-If you have an incompatible version of gradle it is recommended that
-you setup gradle wrapper first.
-1.1. The simplest is to run
-```
-cd <source root>
-gradle wrapper --gradle-version=6.1.1
-
-```
-
-1.2. If this fails, this is likely because current gradle version is unable to parse the build.gradle
-file. In this case, create an empty directory outside your project tree, and create a wrapper there.
-```
-mkdir -p $HOME/scratch/gradle-wrapper-611
-cd $HOME/scratch/gradle-wrapper-611
-gradle wrapper --gradle-version=6.1.1
-cp -a gradle gradlew gradlew.bat <source root>
-```
-
-2. Once you get gradle wrapper installed, run test command
-
-```
-cd <source root>
-./gradlew test -i
-```
-
-This will build and execute all the tests.
diff --git a/build.gradle b/build.gradle
index e319422..bb46e75 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,59 +1,23 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
 apply plugin: 'java'
 apply plugin: 'com.google.protobuf'
 
 repositories {
-    mavenCentral()
+    jcenter()
 }
 
 buildscript {
   repositories {
-    mavenCentral()
+    jcenter()
   }
   dependencies {
-    classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.12'
+    classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.7'
   }
 }
 
 dependencies {
-    compile group: 'com.google.truth.extensions', name: 'truth-java8-extension', version: '0.41'
-    testCompile group: 'com.google.guava', name: 'guava-testlib', version: '29.0-jre'
-    testImplementation 'junit:junit:4.13'
     compile  "com.google.code.findbugs:jsr305:3.0.0"
-    compile "com.google.protobuf:protobuf-java:3.8.0"
-    compile "com.google.guava:guava:19.0"
+    compile "com.google.protobuf:protobuf-java:3.4.0"
+    compile "com.google.guava:guava:r05"
 }
 
-sourceSets {
-    main {
-        java {
-            srcDir 'src/main/java'
-            srcDir 'build/generated/source/proto/main/java'
-        }
-    }
-    test {
-        java {
-            srcDir 'src/main/javatest'
-            srcDir 'build/generated/source/proto/main/java'
-        }
-    }
-}
 
-test {
-    useJUnit()
-
-    maxHeapSize = '1G'
-}
diff --git a/cmake/local_build_protobuf.cmake b/cmake/local_build_protobuf.cmake
deleted file mode 100644
index 3a04d55..0000000
--- a/cmake/local_build_protobuf.cmake
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright 2020 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-if (NOT EXISTS ${TOOLS_INSTALL_PREFIX}/bin/protoc)
-  set(PKG_BUILD_ROOT ${TOOLS_BUILD_ROOT}/protobuf)
-  set(PKG_SRC_ROOT ${CMAKE_SOURCE_DIR}/third_party/protobuf)
-  execute_process(
-    COMMAND mkdir -p ${PKG_BUILD_ROOT}
-  )
-  execute_process(
-    COMMAND cmake ${PKG_SRC_ROOT}/cmake
-    WORKING_DIRECTORY ${PKG_BUILD_ROOT}
-  )
-  execute_process(
-    COMMAND make -j${N_CPUS}
-    WORKING_DIRECTORY ${PKG_BUILD_ROOT}
-  )
-  execute_process(
-    COMMAND make check
-    WORKING_DIRECTORY ${PKG_BUILD_ROOT}
-    RESULT_VARIABLE test_exit_code
-    ERROR_QUIET
-  )
-  if (NOT ${test_exit_code} EQUAL "0")
-    message(FATAL_ERROR "Protobuf tests failed; can't use this protobuf")
-  endif()
-  execute_process(
-    COMMAND /bin/bash -c "DESTDIR=${TOOLS_INSTALL_ROOT} make install"
-    WORKING_DIRECTORY ${PKG_BUILD_ROOT}
-  )
-endif()
diff --git a/cmake/local_build_setup.cmake b/cmake/local_build_setup.cmake
deleted file mode 100644
index a7917fe..0000000
--- a/cmake/local_build_setup.cmake
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright 2020 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-include(ProcessorCount)
-ProcessorCount(N_CPUS)
-
-if (N_CPUS EQUAL 0)
-  set (N_CPUS 1)
-endif()
-
-set (TOOLS_ROOT ${CMAKE_BINARY_DIR}/stage)
-set (TOOLS_BUILD_ROOT ${TOOLS_ROOT}/build)
-set (TOOLS_INSTALL_ROOT ${TOOLS_ROOT}/install)
-set (TOOLS_INSTALL_PREFIX ${TOOLS_INSTALL_ROOT}/usr/local)
-set (CMAKE_FIND_ROOT_PATH ${TOOLS_INSTALL_ROOT})
diff --git a/cmake/proto_defs.cmake b/cmake/proto_defs.cmake
deleted file mode 100644
index aae0ce9..0000000
--- a/cmake/proto_defs.cmake
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright 2020 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-function(add_cc_proto_library NAME)
-  set(single)
-  set(multi_args PROTOS INCS DEPS)
-  cmake_parse_arguments(PARSE_ARGV 1 args "" "${single}" "${multi_args}")
-
-  protobuf_generate(
-    PROTOS ${args_PROTOS}
-    LANGUAGE cpp
-    OUT_VAR ${NAME}_var
-  )
-
-  add_library(${NAME}
-    ${${NAME}_var}
-  )
-
-  target_link_libraries(${NAME}
-    PUBLIC
-      ${Protobuf_LIBRARIES}
-      ${args_DEPS}
-  )
-
-  target_include_directories(${NAME}
-    PUBLIC
-      ${Protobuf_INCLUDE_DIRS}
-      ${args_INCS}
-      ${CMAKE_CURRENT_BINARY_DIR}
-  )
-endfunction()
diff --git a/src/.gradle/3.2.1/taskArtifacts/fileSnapshots.bin b/src/.gradle/3.2.1/taskArtifacts/fileSnapshots.bin
new file mode 100644
index 0000000..f0cc1a8
--- /dev/null
+++ b/src/.gradle/3.2.1/taskArtifacts/fileSnapshots.bin
Binary files differ
diff --git a/src/.gradle/3.2.1/taskArtifacts/taskArtifacts.bin b/src/.gradle/3.2.1/taskArtifacts/taskArtifacts.bin
new file mode 100644
index 0000000..b1f5426
--- /dev/null
+++ b/src/.gradle/3.2.1/taskArtifacts/taskArtifacts.bin
Binary files differ
diff --git a/src/.gradle/3.2.1/taskArtifacts/taskArtifacts.lock b/src/.gradle/3.2.1/taskArtifacts/taskArtifacts.lock
new file mode 100644
index 0000000..6fa2a90
--- /dev/null
+++ b/src/.gradle/3.2.1/taskArtifacts/taskArtifacts.lock
Binary files differ
diff --git a/src/main/CMakeLists.txt b/src/main/CMakeLists.txt
deleted file mode 100644
index 776826c..0000000
--- a/src/main/CMakeLists.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright 2020 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-set(UKEY_SRC_ROOT ${CMAKE_CURRENT_LIST_DIR})
-set(UKEY_BINARY_ROOT ${CMAKE_CURRENT_BINARY_DIR})
-add_subdirectory(cpp)
-add_subdirectory(proto)
diff --git a/src/main/cpp/CMakeLists.txt b/src/main/cpp/CMakeLists.txt
deleted file mode 100644
index 919e096..0000000
--- a/src/main/cpp/CMakeLists.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2020 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
-add_subdirectory(src/securegcm)
-add_subdirectory(test/securegcm)
diff --git a/src/main/cpp/include/securegcm/d2d_connection_context_v1.h b/src/main/cpp/include/securegcm/d2d_connection_context_v1.h
deleted file mode 100644
index 098e654..0000000
--- a/src/main/cpp/include/securegcm/d2d_connection_context_v1.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SECURITY_CRYPTAUTH_LIB_SECUREGCM_D2D_CONNECTION_CONTEXT_V1_H_
-#define SECURITY_CRYPTAUTH_LIB_SECUREGCM_D2D_CONNECTION_CONTEXT_V1_H_
-
-#include <memory>
-#include <string>
-
-#include "securemessage/crypto_ops.h"
-
-namespace securegcm {
-
-// The full context of a secure connection. This class has methods to encode and
-// decode messages that are to be sent to another device.
-//
-// This class should be kept compatible with the Java implementation in
-// java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV1.java
-class D2DConnectionContextV1 {
- public:
-  D2DConnectionContextV1(const securemessage::CryptoOps::SecretKey& encode_key,
-                         const securemessage::CryptoOps::SecretKey& decode_key,
-                         uint32_t encode_sequence_number,
-                         uint32_t decode_sequence_number);
-
-  // Once the initiator and responder have negotiated a secret key, use this
-  // method to encrypt and sign |payload|. Both initiator and responder devices
-  // can use this message.
-  //
-  // On failure, nullptr is returned.
-  std::unique_ptr<string> EncodeMessageToPeer(const string& payload);
-
-  // Once the initiator and responder have negotiated a secret key, use this
-  // method to decrypt and verify a |message| received from the other device.
-  // Both initiator and responder devices can use this message.
-  //
-  // On failure, nullptr is returned.
-  std::unique_ptr<string> DecodeMessageFromPeer(const string& message);
-
-  // Returns a cryptographic digest (SHA256) of the session keys prepended by
-  // the SHA256 hash of the ASCII string "D2D".
-  //
-  // On failure, nullptr is returned.
-  std::unique_ptr<string> GetSessionUnique();
-
-  // Creates a saved session that can be later used for resumption. Note,
-  // this must be stored in a secure location.
-  std::unique_ptr<string> SaveSession();
-
-  // Parse a saved session info and attempt to construct a resumed context.
-  //
-  // The session info passed to this method should be one that was generated
-  // by |SaveSession|.
-  //
-  // On failure, nullptr is returned.
-  static std::unique_ptr<D2DConnectionContextV1> FromSavedSession(
-      const string& savedSessionInfo);
-
- private:
-  // The key used to encode payloads.
-  const securemessage::CryptoOps::SecretKey encode_key_;
-
-  // The key used to decode received messages.
-  const securemessage::CryptoOps::SecretKey decode_key_;
-
-  // The current sequence number for encoding.
-  uint32_t encode_sequence_number_;
-
-  // The current sequence number for decoding.
-  uint32_t decode_sequence_number_;
-
-  // A friend to access private variables for testing.
-  friend class D2DConnectionContextV1Peer;
-};
-
-}  // namespace securegcm
-
-#endif  // SECURITY_CRYPTAUTH_LIB_SECUREGCM_D2D_CONNECTION_CONTEXT_V1_H_
diff --git a/src/main/cpp/include/securegcm/d2d_crypto_ops.h b/src/main/cpp/include/securegcm/d2d_crypto_ops.h
deleted file mode 100644
index eeeeb20..0000000
--- a/src/main/cpp/include/securegcm/d2d_crypto_ops.h
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SECURITY_CRYPTAUTH_LIB_SECUREGCM_D2D_CRYPTO_OPS_H_
-#define SECURITY_CRYPTAUTH_LIB_SECUREGCM_D2D_CRYPTO_OPS_H_
-
-#include <memory>
-#include <string>
-
-#include "proto/securegcm.pb.h"
-#include "securemessage/crypto_ops.h"
-
-namespace securegcm {
-
-// A collection of static utility methods for the Device to Device communication
-// (D2D) library.
-//
-// A class is used here in preference to a namespace to provide a closer
-// correspondence with the Java equivalent class:
-// //java/com/google/security/cryptauth/lib/securegcm/D2DCryptoOps.java
-class D2DCryptoOps {
- public:
-  // Encapsulates a payload type specifier, and a corresponding message as the
-  // raw payload.
-  //
-  // Note: Type is defined in securegcm.proto.
-  class Payload {
-   public:
-    Payload(Type type, const std::string& message);
-
-    Type type() const { return type_; }
-
-    const std::string& message() const { return message_; }
-
-   private:
-    const Type type_;
-    const std::string message_;
-  };
-
-  // The salt, SHA256 of "D2D".
-  static const uint8_t kSalt[];
-  static const size_t kSaltLength;
-
-  // Used by a device to send a secure |Payload| to another device.
-  static std::unique_ptr<std::string> SigncryptPayload(
-      const Payload& payload,
-      const securemessage::CryptoOps::SecretKey& secret_key);
-
-  // Used by a device to recover a secure |Payload| sent by another device.
-  static std::unique_ptr<Payload> VerifyDecryptPayload(
-      const std::string& signcrypted_message,
-      const securemessage::CryptoOps::SecretKey& secret_key);
-
-  // Used to derive a distinct key for each initiator and responder from the
-  // |master_key|. Use a different |purpose| for each role.
-  static std::unique_ptr<securemessage::CryptoOps::SecretKey>
-  DeriveNewKeyForPurpose(const securemessage::CryptoOps::SecretKey& master_key,
-                         const std::string& purpose);
-
- private:
-  // Prevent instantiation.
-  D2DCryptoOps();
-};
-
-}  // namespace securegcm
-
-#endif  // SECURITY_CRYPTAUTH_LIB_SECUREGCM_D2D_CRYPTO_OPS_H_
diff --git a/src/main/cpp/include/securegcm/java_util.h b/src/main/cpp/include/securegcm/java_util.h
deleted file mode 100644
index 8783af4..0000000
--- a/src/main/cpp/include/securegcm/java_util.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Utility functions for Java-compatible operations.
-#ifndef SECURITY_CRYPTAUTH_LIB_SECUREGCM_JAVA_UTIL_H_
-#define SECURITY_CRYPTAUTH_LIB_SECUREGCM_JAVA_UTIL_H_
-
-#include "securemessage/byte_buffer.h"
-
-namespace securegcm {
-namespace java_util {
-
-// Perform multiplication with Java overflow semantics
-// (https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html):
-//   If an integer multiplication overflows, then the result is the low-order
-//   bits of the mathematical product as represented in some sufficiently
-//   large two's-complement format.
-int32_t JavaMultiply(int32_t lhs, int32_t rhs);
-
-// Perform addition with Java overflow semantics:
-// (https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html):
-//   If an integer addition overflows, then the result is the low-order bits of
-//   the mathematical sum as represented in some sufficiently large
-//   two's-complement format.
-int32_t JavaAdd(int32_t lhs, int32_t rhs);
-
-// To be compatible with the Java implementation, we need to use the same
-// algorithm as the Arrays#hashCode(byte[]) function in Java:
-//  "The value returned by this method is the same value that would be obtained
-//  by invoking the hashCode method on a List containing a sequence of Byte
-//  instances representing the elements of a in the same order."
-//
-// According to List#hashCode(), this algorithm is:
-//   int hashCode = 1;
-//   for (Byte b : list) {
-//     hashCode = 31 * hashCode + (b == null ? b : b.hashCode());
-//   }
-//
-// Finally, Byte#hashCode() is defined as "equal to the result of invoking
-// Byte#intValue()".
-int32_t JavaHashCode(const securemessage::ByteBuffer& byte_buffer);
-
-}  // namespace java_util
-}  // namespace securegcm
-
-#endif  // SECURITY_CRYPTAUTH_LIB_SECUREGCM_JAVA_UTIL_H_
diff --git a/src/main/cpp/include/securegcm/ukey2_handshake.h b/src/main/cpp/include/securegcm/ukey2_handshake.h
deleted file mode 100644
index 8455fd7..0000000
--- a/src/main/cpp/include/securegcm/ukey2_handshake.h
+++ /dev/null
@@ -1,263 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SECURITY_CRYPTAUTH_LIB_SECUREGCM_UKEY2_HANDSHAKE_H_
-#define SECURITY_CRYPTAUTH_LIB_SECUREGCM_UKEY2_HANDSHAKE_H_
-
-#include <map>
-#include <memory>
-
-#include "proto/ukey.pb.h"
-#include "securegcm/d2d_connection_context_v1.h"
-#include "securemessage/crypto_ops.h"
-
-namespace securegcm {
-
-// Implements UKEY2 and produces a |D2DConnectionContextV1|.
-// This class should be kept compatible with the Java implementation in
-//     //java/com/google/security/cryptauth/lib/securegcm/Ukey2Handshake.java
-//
-// For usage examples, see ukey2_shell.cc. This file contains a shell exercising
-// both the initiator and responder handshake roles.
-class UKey2Handshake {
- public:
-  // Handshake states:
-  //   kInProgress:
-  //       The handshake is in progress, caller should use
-  //       |GetNextHandshakeMessage()| and |ParseHandshakeMessage()| to continue
-  //       the handshake.
-  //
-  //   kVerificationNeeded:
-  //       The handshake is complete, but pending verification of the
-  //       authentication string. Clients should use |GetVerificationString()|
-  //       to get the verification string and use out-of-band methods to
-  //       authenticate the handshake.
-  //
-  //   kVerificationInProgress:
-  //       The handshake is complete, verification string has been generated,
-  //       but has not been confirmed. After authenticating the handshake
-  //       out-of-band, use |VerifyHandshake()| to mark the handshake as
-  //       verified.
-  //
-  //   kFinished:
-  //       The handshake is finished, and the caller can use
-  //       |ToConnectionContext()| to produce a |D2DConnectionContextV1|.
-  //
-  //   kAlreadyUsed:
-  //       The hanshake has already been used and should be destroyed.
-  //
-  //   kError:
-  //       The handshake produced an error and should be destroyed.
-  enum class State {
-    kInProgress,
-    kVerificationNeeded,
-    kVerificationInProgress,
-    kFinished,
-    kAlreadyUsed,
-    kError,
-  };
-
-  // Currently implemented UKEY2 handshake ciphers. Each cipher is a tuple
-  // consisting of a key negotiation cipher and a hash function used for a
-  // commitment. Currently the ciphers are:
-  //   +-----------------------------------------------------+
-  //   | Enum        | Key negotiation       | Hash function |
-  //   +-------------+-----------------------+---------------+
-  //   | P256_SHA512 | ECDH using NIST P-256 | SHA512        |
-  //   +-----------------------------------------------------+
-  //
-  // Note that these should correspond to values in
-  // device_to_device_messages.proto.
-  enum class HandshakeCipher : int {
-    // TODO(aczeskis): add CURVE25519_SHA512
-
-    P256_SHA512 = securegcm::P256_SHA512,
-  };
-
-  // Creates a |UKey2Handshake| with a particular |cipher| that can be used by
-  // an initiator / client.
-  static std::unique_ptr<UKey2Handshake> ForInitiator(HandshakeCipher cipher);
-
-  // Creates a |UKey2Handshake| with a particular |cipher| that can be used by
-  // a responder / server.
-  static std::unique_ptr<UKey2Handshake> ForResponder(HandshakeCipher cipher);
-
-  // Returns the current state of the handshake.
-  State GetHandshakeState() const;
-
-  // Returns the last error message. Empty string if there was no error.
-  const string& GetLastError() const;
-
-  // Gets the next handshake message suitable for sending on the wire.
-  // If |nullptr| is returned, check |GetLastError()| for the error message.
-  std::unique_ptr<string> GetNextHandshakeMessage();
-
-  // Parses the given |handshake_message|, updating the internal state.
-  struct ParseResult {
-    // True if |handshake_message| is parsed successfully. If |false|, call
-    // |GetLastError()| for the error message.
-    bool success;
-
-    // May be set if parsing fails. This value should be sent to the remote
-    // device before disconnecting.
-    std::unique_ptr<string> alert_to_send;
-  };
-  ParseResult ParseHandshakeMessage(const string& handshake_message);
-
-  // Returns an authentication string suitable for authenticating the handshake
-  // out-of-band. Note that the authentication string can be short (e.g., a 6
-  // digit visual confirmation code).
-  //
-  // Note: This should only be called when the state returned from
-  // |GetHandshakeState()| is |State::VERIFICATION_NEEDED|, which means this can
-  // only be called once.
-  //
-  // |byte_length|: The length of the output. Min length is 1; max length is 32.
-  // If |nullptr| is returned, check |GetLastError()| for the error message.
-  std::unique_ptr<string> GetVerificationString(int byte_length);
-
-  // Invoked to let the handshake state machine know that caller has validated
-  // the authentication string obtained via |GetVerificationString()|.
-  // Note: This should only be called when the state returned by
-  // |GetHandshakeState()| is |State::VERIFICATION_IN_PROGRESS|.
-  //
-  // If |false| is returned, check |GetLastError()| for the error message.
-  bool VerifyHandshake();
-
-  // Can be called to generate a |D2DConnectionContextV1|. Returns nullptr on
-  // failure.
-  // Note: This should only be called when the state returned by
-  // |GetHandshakeState()| is |State::FINISHED|.
-  //
-  // If |nullptr| is returned, check |GetLastError()| for the error message.
-  std::unique_ptr<D2DConnectionContextV1> ToConnectionContext();
-
- private:
-  // Enums for internal state machinery.
-  enum class InternalState : int {
-    CLIENT_START,
-    CLIENT_WAITING_FOR_SERVER_INIT,
-    CLIENT_AFTER_SERVER_INIT,
-
-    // Responder/server state
-    SERVER_START,
-    SERVER_AFTER_CLIENT_INIT,
-    SERVER_WAITING_FOR_CLIENT_FINISHED,
-
-    // Common completion state
-    HANDSHAKE_VERIFICATION_NEEDED,
-    HANDSHAKE_VERIFICATION_IN_PROGRESS,
-    HANDSHAKE_FINISHED,
-    HANDSHAKE_ALREADY_USED,
-    HANDSHAKE_ERROR,
-  };
-
-  // Helps us remember our role in the handshake.
-  enum class HandshakeRole {
-    CLIENT,
-    SERVER
-  };
-
-  // Prevent public instantiation. Callers should use |ForInitiator()| or
-  // |ForResponder()|.
-  UKey2Handshake(InternalState state, HandshakeCipher cipher);
-
-  // Attempts to parse Ukey2ClientInit, wrapped inside a Ukey2Message.
-  // See go/ukey2 for details.
-  ParseResult ParseClientInitUkey2Message(const string& handshake_message);
-
-  // Attempts to parse Ukey2ServerInit, wrapped inside a Ukey2Message.
-  // See go/ukey2 for details.
-  ParseResult ParseServerInitUkey2Message(const string& handshake_message);
-
-  // Attempts to parse Ukey2ClientFinish, wrapped inside a Ukey2Message.
-  // See go/ukey2 for details.
-  ParseResult ParseClientFinishUkey2Message(const string& handshake_message);
-
-  // Convenience function to set |last_error_| and create a ParseResult with a
-  // given alert.
-  ParseResult CreateFailedResultWithAlert(Ukey2Alert::AlertType alert_type,
-                                          const string& error_message);
-
-  // Convenience function to set |last_error_| and create a failed ParseResult
-  // without an alert.
-  ParseResult CreateFailedResultWithoutAlert(const string& error_message);
-
-  // Convenience function to create a successful ParseResult.
-  ParseResult CreateSuccessResult();
-
-  // Verifies that the peer's commitment stored in |peer_commitment_| is the
-  // same as that obtained from |handshake_message|.
-  bool VerifyCommitment(const string& handshake_message);
-
-  // Generates a commitment for the P256_SHA512 cipher.
-  std::unique_ptr<Ukey2ClientInit::CipherCommitment>
-  GenerateP256Sha512Commitment();
-
-  // Creates a serialized Ukey2Message, wrapping an inner ClientInit message.
-  std::unique_ptr<string> MakeClientInitUkey2Message();
-
-  // Creates a serialized Ukey2Message, wrapping an inner ServerInit message.
-  std::unique_ptr<string> MakeServerInitUkey2Message();
-
-  // Creates a serialized Ukey2Message of a given |type|, wrapping |data|.
-  std::unique_ptr<string> MakeUkey2Message(Ukey2Message::Type type,
-                                           const string& data);
-
-  // Called when an error occurs to set |handshake_state_| and |last_error_|.
-  void SetError(const string& error_message);
-
-  // The current state of the handshake.
-  InternalState handshake_state_;
-
-  // The cipher to use for the handshake.
-  const HandshakeCipher handshake_cipher_;
-
-  // The role to perform, i.e. client or server.
-  const HandshakeRole handshake_role_;
-
-  // A newly generated key-pair for this handshake.
-  std::unique_ptr<securemessage::CryptoOps::KeyPair> our_key_pair_;
-
-  // The peer's public key retrieved from a handshake message.
-  std::unique_ptr<securemessage::CryptoOps::PublicKey> their_public_key_;
-
-  // The secret key derived from |our_key_pair_| and |their_public_key_|.
-  std::unique_ptr<securemessage::CryptoOps::SecretKey> derived_secret_key_;
-
-  // The raw bytes of the Ukey2ClientInit, wrapped inside a Ukey2Message.
-  // Empty string if not initialized.
-  string wrapped_client_init_;
-
-  // The raw bytes of the Ukey2ServerInit, wrapped inside a Ukey2Message.
-  // Empty string if not initialized.
-  string wrapped_server_init_;
-
-  // The commitment of the peer retrieved from a handshake message. Empty string
-  // if not initialized.
-  string peer_commitment_;
-
-  // Map from ciphers to the raw bytes of message 3 (which is a wrapped
-  // Ukey2ClientFinished message).
-  // Note: Currently only one cipher is supported, so at most one entry exists
-  // in this map.
-  std::map<HandshakeCipher, string> raw_message3_map_;
-
-  // Contains the last error message.
-  string last_error_;
-};
-
-}  // namespace securegcm
-
-#endif  // SECURITY_CRYPTAUTH_LIB_SECUREGCM_UKEY2_HANDSHAKE_H_
diff --git a/src/main/cpp/src/securegcm/CMakeLists.txt b/src/main/cpp/src/securegcm/CMakeLists.txt
deleted file mode 100644
index b562756..0000000
--- a/src/main/cpp/src/securegcm/CMakeLists.txt
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright 2020 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-add_library(ukey2 STATIC
-  d2d_connection_context_v1.cc
-  d2d_crypto_ops.cc
-  java_util.cc
-  ukey2_handshake.cc
-)
-
-target_include_directories(ukey2
-  PUBLIC
-    ${PROJECT_SOURCE_DIR}/src/main/cpp/include
-)
-
-target_link_libraries(ukey2
-  PUBLIC
-    proto_device_to_device_messages_cc_proto
-    proto_securegcm_cc_proto
-    proto_ukey_cc_proto
-    securemessage
-)
-
-add_executable(ukey2_shell
-  ukey2_shell.cc
-)
-
-target_link_libraries(ukey2_shell
-  PUBLIC
-    securemessage
-    ukey2
-    absl::base
-    absl::container
-    absl::flags
-    absl::flags_parse
-)
diff --git a/src/main/cpp/src/securegcm/d2d_connection_context_v1.cc b/src/main/cpp/src/securegcm/d2d_connection_context_v1.cc
deleted file mode 100644
index 8a9a612..0000000
--- a/src/main/cpp/src/securegcm/d2d_connection_context_v1.cc
+++ /dev/null
@@ -1,228 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "securegcm/d2d_connection_context_v1.h"
-
-#include <limits>
-#include <sstream>
-
-#include "proto/device_to_device_messages.pb.h"
-#include "proto/securegcm.pb.h"
-#include "securegcm/d2d_crypto_ops.h"
-#include "securegcm/java_util.h"
-#include "securemessage/secure_message_builder.h"
-#include "securemessage/util.h"
-
-namespace securegcm {
-
-using securemessage::CryptoOps;
-using securemessage::ByteBuffer;
-using securemessage::Util;
-
-namespace {
-
-// Fields to fill in the GcmMetadata proto.
-const Type kGcmMetadataType = DEVICE_TO_DEVICE_MESSAGE;
-
-// Represents the version of this context.
-const uint8_t kProtocolVersion = 1;
-
-// The following represent the starting positions of the each entry within
-// the string representation of this D2DConnectionContextV1.
-//
-// The saved session has a 1 byte protocol version, two 4 byte sequence numbers,
-// and two 32 byte AES keys: (1 + 4 + 4 + 32 + 32 = 73).
-
-// The two sequence numbers are 4 bytes each.
-const int kSequenceNumberLength = 4;
-
-// 32 byte AES keys.
-const int kAesKeyLength = 32;
-
-// The encode sequence number starts at 1 to account for the 1 byte version
-// number.
-const int kEncodeSequenceStart = 1;
-const int kEncodeSequenceEnd = kEncodeSequenceStart + kSequenceNumberLength;
-
-const int kDecodeSequenceStart = kEncodeSequenceEnd;
-const int kDecodeSequenceEnd = kDecodeSequenceStart + kSequenceNumberLength;
-
-const int kEncodeKeyStart = kDecodeSequenceEnd;
-const int kEncodeKeyEnd = kEncodeKeyStart + kAesKeyLength;
-
-const int kDecodeKeyStart = kEncodeKeyEnd;
-const int kSavedSessionLength = kDecodeKeyStart + kAesKeyLength;
-
-// Convenience function to creates a DeviceToDeviceMessage proto with |payload|
-// and |sequence_number|.
-DeviceToDeviceMessage CreateDeviceToDeviceMessage(const std::string& payload,
-                                                  uint32_t sequence_number) {
-  DeviceToDeviceMessage device_to_device_message;
-  device_to_device_message.set_sequence_number(sequence_number);
-  device_to_device_message.set_message(payload);
-  return device_to_device_message;
-}
-
-// Convert 4 bytes in big-endian representation into an unsigned int.
-uint32_t BytesToUnsignedInt(std::vector<uint8_t> bytes) {
-  return bytes[0] << 24 | bytes[1] << 12 | bytes[2] << 8 | bytes[3];
-}
-
-// Convert an unsigned int into a 4 byte big-endian representation.
-std::vector<uint8_t> UnsignedIntToBytes(uint32_t val) {
-  return {static_cast<uint8_t>(val >> 24), static_cast<uint8_t>(val >> 12),
-          static_cast<uint8_t>(val >> 8), static_cast<uint8_t>(val)};
-}
-
-}  // namespace
-
-D2DConnectionContextV1::D2DConnectionContextV1(
-    const CryptoOps::SecretKey& encode_key,
-    const CryptoOps::SecretKey& decode_key, uint32_t encode_sequence_number,
-    uint32_t decode_sequence_number)
-    : encode_key_(encode_key),
-      decode_key_(decode_key),
-      encode_sequence_number_(encode_sequence_number),
-      decode_sequence_number_(decode_sequence_number) {}
-
-std::unique_ptr<std::string> D2DConnectionContextV1::EncodeMessageToPeer(
-    const std::string& payload) {
-  encode_sequence_number_++;
-  const DeviceToDeviceMessage message =
-      CreateDeviceToDeviceMessage(payload, encode_sequence_number_);
-
-  const D2DCryptoOps::Payload payload_with_type(kGcmMetadataType,
-                                                message.SerializeAsString());
-  return D2DCryptoOps::SigncryptPayload(payload_with_type, encode_key_);
-}
-
-std::unique_ptr<std::string> D2DConnectionContextV1::DecodeMessageFromPeer(
-    const std::string& message) {
-  std::unique_ptr<D2DCryptoOps::Payload> payload =
-      D2DCryptoOps::VerifyDecryptPayload(message, decode_key_);
-  if (!payload) {
-    Util::LogError("DecodeMessageFromPeer: Failed to verify message.");
-    return nullptr;
-  }
-
-  if (kGcmMetadataType != payload->type()) {
-    Util::LogError("DecodeMessageFromPeer: Wrong message type in D2D message.");
-    return nullptr;
-  }
-
-  DeviceToDeviceMessage d2d_message;
-  if (!d2d_message.ParseFromString(payload->message())) {
-    Util::LogError("DecodeMessageFromPeer: Unable to parse D2D message proto.");
-    return nullptr;
-  }
-
-  decode_sequence_number_++;
-  if (d2d_message.sequence_number() != decode_sequence_number_) {
-    std::ostringstream stream;
-    stream << "DecodeMessageFromPeer: Seqno in D2D message ("
-           << d2d_message.sequence_number()
-           << ") does not match expected seqno (" << decode_sequence_number_
-           << ").";
-    Util::LogError(stream.str());
-    return nullptr;
-  }
-
-  return std::unique_ptr<std::string>(d2d_message.release_message());
-}
-
-std::unique_ptr<std::string> D2DConnectionContextV1::GetSessionUnique() {
-  const ByteBuffer encode_key_data = encode_key_.data();
-  const ByteBuffer decode_key_data = decode_key_.data();
-  const int32_t encode_key_hash = java_util::JavaHashCode(encode_key_data);
-  const int32_t decode_key_hash = java_util::JavaHashCode(decode_key_data);
-
-  const ByteBuffer& first_buffer =
-      encode_key_hash < decode_key_hash ? encode_key_data : decode_key_data;
-  const ByteBuffer& second_buffer =
-      encode_key_hash < decode_key_hash ? decode_key_data : encode_key_data;
-
-  ByteBuffer data_to_hash(D2DCryptoOps::kSalt, D2DCryptoOps::kSaltLength);
-  data_to_hash = ByteBuffer::Concat(data_to_hash, first_buffer);
-  data_to_hash = ByteBuffer::Concat(data_to_hash, second_buffer);
-
-  std::unique_ptr<ByteBuffer> hash = CryptoOps::Sha256(data_to_hash);
-  if (!hash) {
-    Util::LogError("GetSessionUnique: SHA-256 hash failed.");
-    return nullptr;
-  }
-
-  return std::unique_ptr<std::string>(new std::string(hash->String()));
-}
-
-// Structure of saved session is:
-//
-// +---------------------------------------------------------------------------+
-// | 1 Byte  |      4 Bytes      |      4 Bytes      |  32 Bytes  |  32 Bytes  |
-// +---------------------------------------------------------------------------+
-// | Version | encode seq number | decode seq number | encode key | decode key |
-// +---------------------------------------------------------------------------+
-//
-// The sequence numbers are represented in big-endian.
-std::unique_ptr<std::string> D2DConnectionContextV1::SaveSession() {
-  ByteBuffer byteBuffer = ByteBuffer(&kProtocolVersion, static_cast<size_t>(1));
-
-  // Append encode sequence number.
-  std::vector<uint8_t> encode_sequence_number_bytes =
-      UnsignedIntToBytes(encode_sequence_number_);
-  for (int i = 0; i < encode_sequence_number_bytes.size(); i++) {
-    byteBuffer.Append(static_cast<size_t>(1), encode_sequence_number_bytes[i]);
-  }
-
-  // Append decode sequence number.
-  std::vector<uint8_t> decode_sequence_number_bytes =
-      UnsignedIntToBytes(decode_sequence_number_);
-  for (int i = 0; i < decode_sequence_number_bytes.size(); i++) {
-    byteBuffer.Append(static_cast<size_t>(1), decode_sequence_number_bytes[i]);
-  }
-
-  // Append encode key.
-  byteBuffer = ByteBuffer::Concat(byteBuffer, encode_key_.data());
-
-  // Append decode key.
-  byteBuffer = ByteBuffer::Concat(byteBuffer, decode_key_.data());
-
-  return std::unique_ptr<std::string>(new std::string(byteBuffer.String()));
-}
-
-// static.
-std::unique_ptr<D2DConnectionContextV1>
-D2DConnectionContextV1::FromSavedSession(const std::string& savedSessionInfo) {
-  ByteBuffer byteBuffer = ByteBuffer(savedSessionInfo);
-
-  if (byteBuffer.size() != kSavedSessionLength) {
-    return nullptr;
-  }
-
-  uint32_t encode_sequence_number = BytesToUnsignedInt(
-      byteBuffer.SubArray(kEncodeSequenceStart, kEncodeSequenceEnd)->Vector());
-  uint32_t decode_sequence_number = BytesToUnsignedInt(
-      byteBuffer.SubArray(kDecodeSequenceStart, kDecodeSequenceEnd)->Vector());
-
-  const CryptoOps::SecretKey encode_key =
-      CryptoOps::SecretKey(*byteBuffer.SubArray(kEncodeKeyStart, kAesKeyLength),
-                           CryptoOps::KeyAlgorithm::AES_256_KEY);
-  const CryptoOps::SecretKey decode_key =
-      CryptoOps::SecretKey(*byteBuffer.SubArray(kDecodeKeyStart, kAesKeyLength),
-                           CryptoOps::KeyAlgorithm::AES_256_KEY);
-
-  return std::unique_ptr<D2DConnectionContextV1>(new D2DConnectionContextV1(
-      encode_key, decode_key, encode_sequence_number, decode_sequence_number));
-}
-
-}  // namespace securegcm
diff --git a/src/main/cpp/src/securegcm/d2d_crypto_ops.cc b/src/main/cpp/src/securegcm/d2d_crypto_ops.cc
deleted file mode 100644
index 49f0b85..0000000
--- a/src/main/cpp/src/securegcm/d2d_crypto_ops.cc
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "securegcm/d2d_crypto_ops.h"
-
-#include <sstream>
-
-#include "securemessage/secure_message_builder.h"
-#include "securemessage/secure_message_parser.h"
-#include "securemessage/util.h"
-
-namespace securegcm {
-
-using securemessage::CryptoOps;
-using securemessage::HeaderAndBody;
-using securemessage::SecureMessage;
-using securemessage::SecureMessageBuilder;
-using securemessage::SecureMessageParser;
-using securemessage::Util;
-
-namespace {
-
-// The current protocol version.
-const int kSecureGcmProtocolVersion = 1;
-
-// The number of bytes in an expected AES256 key.
-const int kAes256KeyLength = 32;
-}
-
-// static.
-const uint8_t D2DCryptoOps::kSalt[] = {
-    0x82, 0xAA, 0x55, 0xA0, 0xD3, 0x97, 0xF8, 0x83, 0x46, 0xCA, 0x1C,
-    0xEE, 0x8D, 0x39, 0x09, 0xB9, 0x5F, 0x13, 0xFA, 0x7D, 0xEB, 0x1D,
-    0x4A, 0xB3, 0x83, 0x76, 0xB8, 0x25, 0x6D, 0xA8, 0x55, 0x10};
-
-// static.
-const size_t D2DCryptoOps::kSaltLength = sizeof(D2DCryptoOps::kSalt);
-
-D2DCryptoOps::Payload::Payload(Type type, const string& message)
-    : type_(type), message_(message) {}
-
-D2DCryptoOps::D2DCryptoOps() {}
-
-// static.
-std::unique_ptr<string> D2DCryptoOps::SigncryptPayload(
-    const Payload& payload, const CryptoOps::SecretKey& secret_key) {
-  GcmMetadata gcm_metadata;
-  gcm_metadata.set_type(payload.type());
-  gcm_metadata.set_version(kSecureGcmProtocolVersion);
-
-  SecureMessageBuilder builder;
-  builder.SetPublicMetadata(gcm_metadata.SerializeAsString());
-
-  std::unique_ptr<SecureMessage> secure_message =
-      builder.BuildSignCryptedMessage(secret_key, CryptoOps::HMAC_SHA256,
-                                      secret_key, CryptoOps::AES_256_CBC,
-                                      payload.message());
-  if (!secure_message) {
-    Util::LogError("Unable to encrypt payload.");
-    return nullptr;
-  }
-
-  return std::unique_ptr<string>(
-      new string(secure_message->SerializeAsString()));
-}
-
-// static.
-std::unique_ptr<D2DCryptoOps::Payload> D2DCryptoOps::VerifyDecryptPayload(
-    const string& signcrypted_message, const CryptoOps::SecretKey& secret_key) {
-  SecureMessage secure_message;
-  if (!secure_message.ParseFromString(signcrypted_message)) {
-    Util::LogError("VerifyDecryptPayload: error parsing SecureMessage.");
-    return nullptr;
-  }
-
-  std::unique_ptr<HeaderAndBody> header_and_body =
-      SecureMessageParser::ParseSignCryptedMessage(
-          secure_message, secret_key, CryptoOps::HMAC_SHA256, secret_key,
-          CryptoOps::AES_256_CBC, string() /* associated_data */);
-  if (!header_and_body) {
-    Util::LogError("VerifyDecryptPayload: error verifying SecureMessage.");
-    return nullptr;
-  }
-
-  if (!header_and_body->header().has_public_metadata()) {
-    Util::LogError("VerifyDecryptPayload: no public metadata in header.");
-    return nullptr;
-  }
-
-  GcmMetadata metadata;
-  if (!metadata.ParseFromString(header_and_body->header().public_metadata())) {
-    Util::LogError("VerifyDecryptPayload: Failed to parse GcmMetadata.");
-    return nullptr;
-  }
-
-  if (metadata.version() != kSecureGcmProtocolVersion) {
-    std::ostringstream stream;
-    stream << "VerifyDecryptPayload: Unsupported protocol version "
-           << metadata.version();
-    Util::LogError(stream.str());
-    return nullptr;
-  }
-
-  return std::unique_ptr<Payload>(
-      new Payload(metadata.type(), header_and_body->body()));
-}
-
-// static.
-std::unique_ptr<CryptoOps::SecretKey> D2DCryptoOps::DeriveNewKeyForPurpose(
-    const securemessage::CryptoOps::SecretKey& master_key,
-    const string& purpose) {
-  if (master_key.data().size() != kAes256KeyLength) {
-    Util::LogError("DeriveNewKeyForPurpose: Invalid master_key length.");
-    return nullptr;
-  }
-
-  if (purpose.empty()) {
-    Util::LogError("DeriveNewKeyForPurpose: purpose is empty.");
-    return nullptr;
-  }
-
-  std::unique_ptr<string> raw_derived_key = CryptoOps::Hkdf(
-      master_key.data().String(),
-      string(reinterpret_cast<const char *>(kSalt), kSaltLength),
-      purpose);
-  if (!raw_derived_key) {
-    Util::LogError("DeriveNewKeyForPurpose: hkdf failed.");
-    return nullptr;
-  }
-
-  if (raw_derived_key->size() != kAes256KeyLength) {
-    Util::LogError("DeriveNewKeyForPurpose: Unexpected size of derived key.");
-    return nullptr;
-  }
-
-  return std::unique_ptr<CryptoOps::SecretKey>(
-      new CryptoOps::SecretKey(*raw_derived_key, CryptoOps::AES_256_KEY));
-}
-
-}  // namespace securegcm
diff --git a/src/main/cpp/src/securegcm/java_util.cc b/src/main/cpp/src/securegcm/java_util.cc
deleted file mode 100644
index 1ce4d7b..0000000
--- a/src/main/cpp/src/securegcm/java_util.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "securegcm/java_util.h"
-
-#include <cstring>
-
-namespace securegcm {
-namespace java_util {
-
-namespace {
-
-// Returns the lower 32-bits of a int64_t |value| as an int32_t.
-int32_t Lower32Bits(int64_t value) {
-  const uint32_t lower_bits = static_cast<uint32_t>(value & 0xFFFFFFFF);
-  int32_t return_value;
-  std::memcpy(&return_value, &lower_bits, sizeof(uint32_t));
-  return return_value;
-}
-
-}  // namespace
-
-int32_t JavaMultiply(int32_t lhs, int32_t rhs) {
-  // Multiplication guaranteed to fit in int64_t, range from [2^63, 2^63 - 1].
-  // Minimum value is (-2^31)^2 = 2^62.
-  const int64_t result = static_cast<int64_t>(lhs) * static_cast<int64_t>(rhs);
-  return Lower32Bits(result);
-}
-
-int32_t JavaAdd(int32_t lhs, int32_t rhs) {
-  const int64_t result = static_cast<int64_t>(lhs) + static_cast<int64_t>(rhs);
-  return Lower32Bits(result);
-}
-
-int32_t JavaHashCode(const securemessage::ByteBuffer& byte_buffer) {
-  const string bytes = byte_buffer.String();
-  int32_t hash_code = 1;
-  for (const int8_t byte : bytes) {
-    int32_t int_value = static_cast<int32_t>(byte);
-    // Java relies on the overflow/underflow behaviour of arithmetic operations,
-    // which is undefined in C++, so we call our own Java-compatible versions of
-    // + and * here.
-    hash_code = JavaAdd(JavaMultiply(31, hash_code), int_value);
-  }
-  return hash_code;
-}
-
-}  // namespace java_util
-}  // namespace securegcm
diff --git a/src/main/cpp/src/securegcm/ukey2_handshake.cc b/src/main/cpp/src/securegcm/ukey2_handshake.cc
deleted file mode 100644
index dc5c131..0000000
--- a/src/main/cpp/src/securegcm/ukey2_handshake.cc
+++ /dev/null
@@ -1,715 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "securegcm/ukey2_handshake.h"
-
-#include <sstream>
-
-#include "securegcm/d2d_crypto_ops.h"
-#include "securemessage/public_key_proto_util.h"
-
-namespace securegcm {
-
-using securemessage::ByteBuffer;
-using securemessage::CryptoOps;
-using securemessage::GenericPublicKey;
-using securemessage::PublicKeyProtoUtil;
-
-namespace {
-
-// Salt value used to derive client and server keys for next protocol.
-const char kUkey2HkdfSalt[] = "UKEY2 v1 next";
-
-// Salt value used to derive verification string.
-const char kUkey2VerificationStringSalt[] = "UKEY2 v1 auth";
-
-// Maximum version of the handshake supported by this class.
-const uint32_t kVersion = 1;
-
-// Random nonce is fixed at 32 bytes (as per go/ukey2).
-const uint32_t kNonceLengthInBytes = 32;
-
-// Currently, we only support one next protocol.
-const char kNextProtocol[] = "AES_256_CBC-HMAC_SHA256";
-
-// Creates the appropriate KeyPair for |cipher|.
-std::unique_ptr<CryptoOps::KeyPair> GenerateKeyPair(
-    UKey2Handshake::HandshakeCipher cipher) {
-  switch (cipher) {
-    case UKey2Handshake::HandshakeCipher::P256_SHA512:
-      return CryptoOps::GenerateEcP256KeyPair();
-    default:
-      return nullptr;
-  }
-}
-
-// Parses a CryptoOps::PublicKey from a serialized GenericPublicKey.
-std::unique_ptr<securemessage::CryptoOps::PublicKey> ParsePublicKey(
-    const string& serialized_generic_public_key) {
-  GenericPublicKey generic_public_key;
-  if (!generic_public_key.ParseFromString(serialized_generic_public_key)) {
-    return nullptr;
-  }
-  return PublicKeyProtoUtil::ParsePublicKey(generic_public_key);
-}
-
-}  // namespace
-
-// static.
-std::unique_ptr<UKey2Handshake> UKey2Handshake::ForInitiator(
-    HandshakeCipher cipher) {
-  return std::unique_ptr<UKey2Handshake>(
-      new UKey2Handshake(InternalState::CLIENT_START, cipher));
-}
-
-// static.
-std::unique_ptr<UKey2Handshake> UKey2Handshake::ForResponder(
-    HandshakeCipher cipher) {
-  return std::unique_ptr<UKey2Handshake>(
-      new UKey2Handshake(InternalState::SERVER_START, cipher));
-}
-
-UKey2Handshake::UKey2Handshake(InternalState state, HandshakeCipher cipher)
-    : handshake_state_(state),
-      handshake_cipher_(cipher),
-      handshake_role_(state == InternalState::CLIENT_START
-                          ? HandshakeRole::CLIENT
-                          : HandshakeRole::SERVER),
-      our_key_pair_(GenerateKeyPair(cipher)) {}
-
-UKey2Handshake::State UKey2Handshake::GetHandshakeState() const {
-  switch (handshake_state_) {
-    case InternalState::CLIENT_START:
-    case InternalState::CLIENT_WAITING_FOR_SERVER_INIT:
-    case InternalState::CLIENT_AFTER_SERVER_INIT:
-    case InternalState::SERVER_START:
-    case InternalState::SERVER_AFTER_CLIENT_INIT:
-    case InternalState::SERVER_WAITING_FOR_CLIENT_FINISHED:
-      // Fallthrough intended -- these are all in-progress states.
-      return State::kInProgress;
-    case InternalState::HANDSHAKE_VERIFICATION_NEEDED:
-      return State::kVerificationNeeded;
-    case InternalState::HANDSHAKE_VERIFICATION_IN_PROGRESS:
-      return State::kVerificationInProgress;
-    case InternalState::HANDSHAKE_FINISHED:
-      return State::kFinished;
-    case InternalState::HANDSHAKE_ALREADY_USED:
-      return State::kAlreadyUsed;
-    case InternalState::HANDSHAKE_ERROR:
-      return State::kError;
-    default:
-      // Unreachable.
-      return State::kError;
-  }
-}
-
-const string& UKey2Handshake::GetLastError() const {
-  return last_error_;
-}
-
-std::unique_ptr<string> UKey2Handshake::GetNextHandshakeMessage() {
-  switch (handshake_state_) {
-    case InternalState::CLIENT_START: {
-      std::unique_ptr<string> client_init = MakeClientInitUkey2Message();
-      if (!client_init) {
-        // |last_error_| is already set.
-        return nullptr;
-      }
-
-      wrapped_client_init_ = *client_init;
-      handshake_state_ = InternalState::CLIENT_WAITING_FOR_SERVER_INIT;
-      return client_init;
-    }
-
-    case InternalState::SERVER_AFTER_CLIENT_INIT: {
-      std::unique_ptr<string> server_init = MakeServerInitUkey2Message();
-      if (!server_init) {
-        // |last_error_| is already set.
-        return nullptr;
-      }
-
-      wrapped_server_init_ = *server_init;
-      handshake_state_ = InternalState::SERVER_WAITING_FOR_CLIENT_FINISHED;
-      return server_init;
-    }
-
-    case InternalState::CLIENT_AFTER_SERVER_INIT: {
-      // Make sure we have a message 3 for the chosen cipher.
-      if (raw_message3_map_.count(handshake_cipher_) == 0) {
-        std::ostringstream stream;
-        stream << "Client state is CLIENT_AFTER_SERVER_INIT, and cipher is "
-               << static_cast<int>(handshake_cipher_)
-               << ", but no corresponding raw "
-               << "[Client Finished] message has been generated.";
-        SetError(stream.str());
-        return nullptr;
-      }
-      handshake_state_ = InternalState::HANDSHAKE_VERIFICATION_NEEDED;
-      return std::unique_ptr<string>(
-          new string(raw_message3_map_[handshake_cipher_]));
-    }
-
-    default: {
-      std::ostringstream stream;
-      stream << "Cannot get next message in state "
-             << static_cast<int>(handshake_state_);
-      SetError(stream.str());
-      return nullptr;
-    }
-  }
-}
-
-UKey2Handshake::ParseResult
-UKey2Handshake::ParseHandshakeMessage(const string& handshake_message) {
-  switch (handshake_state_) {
-    case InternalState::SERVER_START:
-      return ParseClientInitUkey2Message(handshake_message);
-    case InternalState::CLIENT_WAITING_FOR_SERVER_INIT:
-      return ParseServerInitUkey2Message(handshake_message);
-    case InternalState::SERVER_WAITING_FOR_CLIENT_FINISHED:
-      return ParseClientFinishUkey2Message(handshake_message);
-    default:
-      std::ostringstream stream;
-      stream << "Cannot parse message in state "
-             << static_cast<int>(handshake_state_);
-      SetError(stream.str());
-      return {false, nullptr};
-  }
-}
-
-std::unique_ptr<string> UKey2Handshake::GetVerificationString(int byte_length) {
-  if (byte_length < 1 || byte_length > 32) {
-    SetError("Minimum length is 1 byte, max is 32 bytes.");
-    return nullptr;
-  }
-
-  if (handshake_state_ != InternalState::HANDSHAKE_VERIFICATION_NEEDED) {
-    std::ostringstream stream;
-    stream << "Unexpected state: " << static_cast<int>(handshake_state_);
-    SetError(stream.str());
-    return nullptr;
-  }
-
-  if (!our_key_pair_ || !our_key_pair_->private_key || !their_public_key_) {
-    SetError("One of our private key or their public key is null.");
-    return nullptr;
-  }
-
-  switch (handshake_cipher_) {
-    case HandshakeCipher::P256_SHA512:
-      derived_secret_key_ = CryptoOps::KeyAgreementSha256(
-          *(our_key_pair_->private_key), *their_public_key_);
-      break;
-    default:
-      // Unreachable.
-      return nullptr;
-  }
-
-  if (!derived_secret_key_) {
-    SetError("Failed to derive shared secret key.");
-    return nullptr;
-  }
-
-  std::unique_ptr<string> auth_string = CryptoOps::Hkdf(
-      derived_secret_key_->data().String(),
-      string(kUkey2VerificationStringSalt, sizeof(kUkey2VerificationStringSalt)),
-      wrapped_client_init_ + wrapped_server_init_);
-
-  handshake_state_ = InternalState::HANDSHAKE_VERIFICATION_IN_PROGRESS;
-  return auth_string;
-}
-
-bool UKey2Handshake::VerifyHandshake() {
-  if (handshake_state_ != InternalState::HANDSHAKE_VERIFICATION_IN_PROGRESS) {
-    std::ostringstream stream;
-    stream << "Unexpected state: " << static_cast<int>(handshake_state_);
-    SetError(stream.str());
-    return false;
-  }
-
-  handshake_state_ = InternalState::HANDSHAKE_FINISHED;
-  return true;
-}
-
-std::unique_ptr<D2DConnectionContextV1> UKey2Handshake::ToConnectionContext() {
-  if (InternalState::HANDSHAKE_FINISHED != handshake_state_) {
-    std::ostringstream stream;
-    stream << "ToConnectionContext can only be called when handshake is "
-           << "completed, but current state is "
-           << static_cast<int>(handshake_state_);
-    SetError(stream.str());
-    return nullptr;
-  }
-
-  if (!derived_secret_key_) {
-    SetError("Derived key is null.");
-    return nullptr;
-  }
-
-  string info = wrapped_client_init_ + wrapped_server_init_;
-  std::unique_ptr<string> master_key_data = CryptoOps::Hkdf(
-      derived_secret_key_->data().String(), kUkey2HkdfSalt, info);
-
-  if (!master_key_data) {
-    SetError("Failed to create master key.");
-    return nullptr;
-  }
-
-  // Derive separate encode keys for both client and server.
-  CryptoOps::SecretKey master_key(*master_key_data, CryptoOps::AES_256_KEY);
-  std::unique_ptr<CryptoOps::SecretKey> client_key =
-      D2DCryptoOps::DeriveNewKeyForPurpose(master_key, "client");
-  std::unique_ptr<CryptoOps::SecretKey> server_key =
-      D2DCryptoOps::DeriveNewKeyForPurpose(master_key, "server");
-  if (!client_key || !server_key) {
-    SetError("Failed to derive client or server key.");
-    return nullptr;
-  }
-
-  handshake_state_ = InternalState::HANDSHAKE_ALREADY_USED;
-
-  return std::unique_ptr<D2DConnectionContextV1>(new D2DConnectionContextV1(
-      handshake_role_ == HandshakeRole::CLIENT ? *client_key : *server_key,
-      handshake_role_ == HandshakeRole::CLIENT ? *server_key : *client_key,
-      0 /* initial encode sequence number */,
-      0 /* initial decode sequence number */));
-}
-
-UKey2Handshake::ParseResult UKey2Handshake::ParseClientInitUkey2Message(
-    const string& handshake_message) {
-  // Deserialize the protobuf.
-  Ukey2Message message;
-  if (!message.ParseFromString(handshake_message)) {
-    return CreateFailedResultWithAlert(Ukey2Alert::BAD_MESSAGE,
-                                       "Can't parse message 1.");
-  }
-
-  // Verify that message_type == CLIENT_INIT.
-  if (!message.has_message_type() ||
-      message.message_type() != Ukey2Message::CLIENT_INIT) {
-    return CreateFailedResultWithAlert(
-        Ukey2Alert::BAD_MESSAGE,
-        "Expected, but did not find ClientInit message type.");
-  }
-
-  // Derserialize message_data as a ClientInit message.
-  if (!message.has_message_data()) {
-    return CreateFailedResultWithAlert(
-        Ukey2Alert::BAD_MESSAGE_DATA,
-        "Expected message data, but did not find it.");
-  }
-
-  Ukey2ClientInit client_init;
-  if (!client_init.ParseFromString(message.message_data())) {
-    return CreateFailedResultWithAlert(
-        Ukey2Alert::BAD_MESSAGE_DATA,
-        "Can't parse message data into ClientInit.");
-  }
-
-  // Check that version == VERSION.
-  if (!client_init.has_version()) {
-    return CreateFailedResultWithAlert(Ukey2Alert::BAD_VERSION,
-                                       "ClientInit missing version.");
-  }
-  if (client_init.version() != kVersion) {
-    return CreateFailedResultWithAlert(Ukey2Alert::BAD_VERSION,
-                                       "ClientInit version mismatch.");
-  }
-
-  // Check that random is exactly kNonceLengthInBytes.
-  if (!client_init.has_random()) {
-    return CreateFailedResultWithAlert(Ukey2Alert::BAD_RANDOM,
-                                       "ClientInit missing random.");
-  }
-  if (client_init.random().length() != kNonceLengthInBytes) {
-    return CreateFailedResultWithAlert(
-        Ukey2Alert::BAD_RANDOM, "ClientInit has incorrect nonce length.");
-  }
-
-  // Check to see if any of the handshake_cipher in handshake_cipher_commitment
-  // are acceptable. Servers should select the first ahdnshake_cipher that it
-  // finds acceptable to support clients signalling deprecated but supported
-  // HandshakeCiphers. If no handshake_cipher is acceptable (or there are no
-  // HandshakeCiphers in the message), the server sends a BAD_HANDSHAKE_CIPHER
-  // alert message.
-  if (client_init.cipher_commitments_size() == 0) {
-    return CreateFailedResultWithAlert(
-        Ukey2Alert::BAD_HANDSHAKE_CIPHER,
-        "ClientInit is missing cipher commitments.");
-  }
-
-  for (const Ukey2ClientInit::CipherCommitment& commitment :
-       client_init.cipher_commitments()) {
-    if (!commitment.has_handshake_cipher() || !commitment.has_commitment() ||
-        commitment.commitment().empty()) {
-      return CreateFailedResultWithAlert(
-          Ukey2Alert::BAD_HANDSHAKE_CIPHER,
-          "ClientInit has improperly formatted cipher commitment.");
-    }
-
-    // TODO(aczeskis): for now we only support one cipher, eventually support
-    // more.
-    if (commitment.handshake_cipher() == static_cast<int>(handshake_cipher_)) {
-      peer_commitment_ = commitment.commitment();
-    }
-  }
-
-  if (peer_commitment_.empty()) {
-    return CreateFailedResultWithAlert(Ukey2Alert::BAD_HANDSHAKE_CIPHER,
-                                       "No acceptable commitments found");
-  }
-
-  // Checks that next_protocol contains a protocol that the server supports. We
-  // currently only support one protocol.
-  if (!client_init.has_next_protocol() ||
-      client_init.next_protocol() != kNextProtocol) {
-    return CreateFailedResultWithAlert(Ukey2Alert::BAD_NEXT_PROTOCOL,
-                                       "Incorrect next protocol.");
-  }
-
-  // Store raw message for AUTH_STRING computation.
-  wrapped_client_init_ = handshake_message;
-  handshake_state_ = InternalState::SERVER_AFTER_CLIENT_INIT;
-  return CreateSuccessResult();
-}
-
-UKey2Handshake::ParseResult UKey2Handshake::ParseServerInitUkey2Message(
-    const string& handshake_message) {
-  // Deserialize the protobuf.
-  Ukey2Message message;
-  if (!message.ParseFromString(handshake_message)) {
-    return CreateFailedResultWithAlert(Ukey2Alert::BAD_MESSAGE,
-                                       "Can't parse message 2.");
-  }
-
-  // Verify that message_type == SERVER_INIT.
-  if (!message.has_message_type() ||
-      message.message_type() != Ukey2Message::SERVER_INIT) {
-    return CreateFailedResultWithAlert(
-        Ukey2Alert::BAD_MESSAGE,
-        "Expected, but did not find SERVER_INIT message type.");
-  }
-
-  // Derserialize message_data as a ServerInit message.
-  if (!message.has_message_data()) {
-    return CreateFailedResultWithAlert(
-        Ukey2Alert::BAD_MESSAGE_DATA,
-        "Expected message data, but did not find it.");
-  }
-
-  Ukey2ServerInit server_init;
-  if (!server_init.ParseFromString(message.message_data())) {
-    return CreateFailedResultWithAlert(
-        Ukey2Alert::BAD_MESSAGE_DATA,
-        "Can't parse message data into ServerInit.");
-  }
-
-  // Check that version == VERSION.
-  if (!server_init.has_version()) {
-    return CreateFailedResultWithAlert(Ukey2Alert::BAD_VERSION,
-                                       "ServerInit missing version.");
-  }
-  if (server_init.version() != kVersion) {
-    return CreateFailedResultWithAlert(Ukey2Alert::BAD_VERSION,
-                                       "ServerInit version mismatch.");
-  }
-
-  // Check that random is exactly kNonceLengthInBytes.
-  if (!server_init.has_random()) {
-    return CreateFailedResultWithAlert(Ukey2Alert::BAD_RANDOM,
-                                       "ServerInit missing random.");
-  }
-  if (server_init.random().length() != kNonceLengthInBytes) {
-    return CreateFailedResultWithAlert(
-        Ukey2Alert::BAD_RANDOM, "ServerInit has incorrect nonce length.");
-  }
-
-  // Check that the handshake_cipher matches a handshake cipher that was sent in
-  // ClientInit::cipher_commitments().
-  if (!server_init.has_handshake_cipher()) {
-    return CreateFailedResultWithAlert(Ukey2Alert::BAD_HANDSHAKE_CIPHER,
-                                       "No handshake cipher found.");
-  }
-
-  Ukey2HandshakeCipher cipher = server_init.handshake_cipher();
-  HandshakeCipher server_cipher;
-  switch (static_cast<HandshakeCipher>(cipher)) {
-    case HandshakeCipher::P256_SHA512:
-      server_cipher = static_cast<HandshakeCipher>(cipher);
-      break;
-    default:
-      return CreateFailedResultWithAlert(Ukey2Alert::BAD_HANDSHAKE_CIPHER,
-                                         "No acceptable handshake found.");
-  }
-
-  // Check that public_key parses into a correct public key structure.
-  if (!server_init.has_public_key()) {
-    return CreateFailedResultWithAlert(Ukey2Alert::BAD_PUBLIC_KEY,
-                                       "No public key found in ServerInit.");
-  }
-
-  their_public_key_ = ParsePublicKey(server_init.public_key());
-  if (!their_public_key_) {
-    return CreateFailedResultWithAlert(Ukey2Alert::BAD_PUBLIC_KEY,
-                                       "Failed to parse public key.");
-  }
-
-  // Store raw message for AUTH_STRING computation.
-  wrapped_server_init_ = handshake_message;
-  handshake_state_ = InternalState::CLIENT_AFTER_SERVER_INIT;
-  return CreateSuccessResult();
-}
-
-UKey2Handshake::ParseResult UKey2Handshake::ParseClientFinishUkey2Message(
-    const string& handshake_message) {
-  // Deserialize the protobuf.
-  Ukey2Message message;
-  if (!message.ParseFromString(handshake_message)) {
-    return CreateFailedResultWithoutAlert("Can't parse message 3.");
-  }
-
-  // Verify that message_type == CLIENT_FINISH.
-  if (!message.has_message_type() ||
-      message.message_type() != Ukey2Message::CLIENT_FINISH) {
-    return CreateFailedResultWithoutAlert(
-        "Expected, but did not find CLIENT_FINISH message type.");
-  }
-
-  // Verify that the hash of the CLientFinished message matches the expected
-  // commitment from ClientInit.
-  if (!VerifyCommitment(handshake_message)) {
-    return CreateFailedResultWithoutAlert(last_error_);
-  }
-
-  // Deserialize message_data as a ClientFinished message.
-  if (!message.has_message_data()) {
-    return CreateFailedResultWithoutAlert(
-        "Expected message data, but didn't find it.");
-  }
-
-  Ukey2ClientFinished client_finished;
-  if (!client_finished.ParseFromString(message.message_data())) {
-    return CreateFailedResultWithoutAlert("Failed to parse ClientFinished.");
-  }
-
-  // Check that public_key parses into a correct public key structure.
-  if (!client_finished.has_public_key()) {
-    return CreateFailedResultWithoutAlert(
-        "No public key found in ClientFinished.");
-  }
-
-  their_public_key_ = ParsePublicKey(client_finished.public_key());
-  if (!their_public_key_) {
-    return CreateFailedResultWithoutAlert("Failed to parse public key.");
-  }
-
-  handshake_state_ = InternalState::HANDSHAKE_VERIFICATION_NEEDED;
-  return CreateSuccessResult();
-}
-
-UKey2Handshake::ParseResult UKey2Handshake::CreateFailedResultWithAlert(
-    Ukey2Alert::AlertType alert_type, const string& error_message) {
-  if (!Ukey2Alert_AlertType_IsValid(alert_type)) {
-    std::ostringstream stream;
-    stream << "Unknown alert type: " << static_cast<int>(alert_type);
-    SetError(stream.str());
-    return {false, nullptr};
-  }
-
-  Ukey2Alert alert;
-  alert.set_type(alert_type);
-  if (!error_message.empty()) {
-    alert.set_error_message(error_message);
-  }
-
-  std::unique_ptr<string> alert_message =
-      MakeUkey2Message(Ukey2Message::ALERT, alert.SerializeAsString());
-
-  SetError(error_message);
-  ParseResult result{false, std::move(alert_message)};
-  return result;
-}
-
-UKey2Handshake::ParseResult
-UKey2Handshake::CreateFailedResultWithoutAlert(const string& error_message) {
-  SetError(error_message);
-  return {false, nullptr};
-}
-
-UKey2Handshake::ParseResult UKey2Handshake::CreateSuccessResult() {
-  return {true, nullptr};
-}
-
-bool UKey2Handshake::VerifyCommitment(const string& handshake_message) {
-  std::unique_ptr<ByteBuffer> actual_client_finish_hash;
-  switch (handshake_cipher_) {
-    case HandshakeCipher::P256_SHA512:
-      actual_client_finish_hash =
-          CryptoOps::Sha512(ByteBuffer(handshake_message));
-      break;
-    default:
-      // Unreachable.
-      return false;
-  }
-
-  if (!actual_client_finish_hash) {
-    SetError("Failed to hash ClientFinish message.");
-    return false;
-  }
-
-  // Note: Equals() is a time constant comparison operation.
-  if (!actual_client_finish_hash->Equals(peer_commitment_)) {
-    SetError("Failed to verify commitment.");
-    return false;
-  }
-
-  return true;
-}
-
-std::unique_ptr<Ukey2ClientInit::CipherCommitment>
-UKey2Handshake::GenerateP256Sha512Commitment() {
-  // Generate the corresponding ClientFinished message if it's not done yet.
-  if (raw_message3_map_.count(HandshakeCipher::P256_SHA512) == 0) {
-    if (!our_key_pair_ || !our_key_pair_->public_key) {
-      SetError("Invalid public key.");
-      return nullptr;
-    }
-
-    std::unique_ptr<GenericPublicKey> generic_public_key =
-        PublicKeyProtoUtil::EncodePublicKey(*(our_key_pair_->public_key));
-    if (!generic_public_key) {
-      SetError("Failed to encode generic public key.");
-      return nullptr;
-    }
-
-    Ukey2ClientFinished client_finished;
-    client_finished.set_public_key(generic_public_key->SerializeAsString());
-    std::unique_ptr<string> serialized_ukey2_message = MakeUkey2Message(
-        Ukey2Message::CLIENT_FINISH, client_finished.SerializeAsString());
-    if (!serialized_ukey2_message) {
-      SetError("Failed to serialized Ukey2Message.");
-      return nullptr;
-    }
-
-    raw_message3_map_[HandshakeCipher::P256_SHA512] = *serialized_ukey2_message;
-  }
-
-  // Create the SHA512 commitment from raw message 3.
-  std::unique_ptr<ByteBuffer> commitment = CryptoOps::Sha512(
-      ByteBuffer(raw_message3_map_[HandshakeCipher::P256_SHA512]));
-  if (!commitment) {
-    SetError("Failed to hash message for commitment.");
-    return nullptr;
-  }
-
-  // Wrap the commitment in a proto.
-  std::unique_ptr<Ukey2ClientInit::CipherCommitment>
-      handshake_cipher_commitment(new Ukey2ClientInit::CipherCommitment());
-  handshake_cipher_commitment->set_handshake_cipher(P256_SHA512);
-  handshake_cipher_commitment->set_commitment(commitment->String());
-
-  return handshake_cipher_commitment;
-}
-
-std::unique_ptr<string> UKey2Handshake::MakeClientInitUkey2Message() {
-  std::unique_ptr<ByteBuffer> nonce =
-      CryptoOps::SecureRandom(kNonceLengthInBytes);
-  if (!nonce) {
-    SetError("Failed to generate nonce.");
-    return nullptr;
-  }
-
-  Ukey2ClientInit client_init;
-  client_init.set_version(kVersion);
-  client_init.set_random(nonce->String());
-  client_init.set_next_protocol(kNextProtocol);
-
-  // At the moment, we only support one cipher.
-  std::unique_ptr<Ukey2ClientInit::CipherCommitment>
-      handshake_cipher_commitment = GenerateP256Sha512Commitment();
-  if (!handshake_cipher_commitment) {
-    // |last_error_| already set.
-    return nullptr;
-  }
-  *(client_init.add_cipher_commitments()) = *handshake_cipher_commitment;
-
-  return MakeUkey2Message(Ukey2Message::CLIENT_INIT,
-                          client_init.SerializeAsString());
-}
-
-std::unique_ptr<string> UKey2Handshake::MakeServerInitUkey2Message() {
-  std::unique_ptr<ByteBuffer> nonce =
-      CryptoOps::SecureRandom(kNonceLengthInBytes);
-  if (!nonce) {
-    SetError("Failed to generate nonce.");
-    return nullptr;
-  }
-
-  if (!our_key_pair_ || !our_key_pair_->public_key) {
-    SetError("Invalid key pair.");
-    return nullptr;
-  }
-
-  std::unique_ptr<GenericPublicKey> public_key =
-      PublicKeyProtoUtil::EncodePublicKey(*(our_key_pair_->public_key));
-  if (!public_key) {
-    SetError("Failed to encode public key.");
-    return nullptr;
-  }
-
-  Ukey2ServerInit server_init;
-  server_init.set_version(kVersion);
-  server_init.set_random(nonce->String());
-  server_init.set_handshake_cipher(
-      static_cast<Ukey2HandshakeCipher>(handshake_cipher_));
-  server_init.set_public_key(public_key->SerializeAsString());
-
-  return MakeUkey2Message(Ukey2Message::SERVER_INIT,
-                          server_init.SerializeAsString());
-}
-
-// Generates the serialized representation of a Ukey2Message based on the
-// provided |type| and |data|. On error, returns nullptr and writes error
-// message to |out_error|.
-std::unique_ptr<string> UKey2Handshake::MakeUkey2Message(
-    Ukey2Message::Type type, const string& data) {
-  Ukey2Message message;
-  if (!Ukey2Message::Type_IsValid(type)) {
-    std::ostringstream stream;
-    stream << "Invalid message type: " << type;
-    SetError(stream.str());
-    return nullptr;
-  }
-  message.set_message_type(type);
-
-  // Only ALERT messages can have a blank data field.
-  if (type != Ukey2Message::ALERT) {
-    if (data.length() == 0) {
-      SetError("Cannot send empty message data for non-alert messages");
-      return nullptr;
-    }
-  }
-  message.set_message_data(data);
-
-  std::unique_ptr<string> serialized(new string());
-  message.SerializeToString(serialized.get());
-  return serialized;
-}
-
-void UKey2Handshake::SetError(const string& error_message) {
-  handshake_state_ = InternalState::HANDSHAKE_ERROR;
-  last_error_ = error_message;
-}
-
-}  // namespace securegcm
diff --git a/src/main/cpp/src/securegcm/ukey2_shell.cc b/src/main/cpp/src/securegcm/ukey2_shell.cc
deleted file mode 100644
index 99a35a8..0000000
--- a/src/main/cpp/src/securegcm/ukey2_shell.cc
+++ /dev/null
@@ -1,297 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// The ukey2_shell binary is a command-line based wrapper, exercising the
-// UKey2Handshake class. Its main use is to be run in a Java test, testing the
-// compatibility of the Java and C++ implementations.
-//
-// This program can be run in two modes, initiator or responder (default is
-// initiator):
-//   ukey2_shell --mode=initiator --verification_string_length=32
-//   ukey2_shell --mode=responder --verification_string_length=32
-//
-// In initiator mode, the program performs the initiator handshake, and in
-// responder mode, it performs the responder handshake.
-//
-// After the handshake is done, the program establishes a secure connection and
-// enters a loop in which it processes the following commands:
-//    * encrypt <payload>: encrypts the payload and prints it.
-//    * decrypt <message>: decrypts the message and prints the payload.
-//    * session_unique:    prints the session unique value.
-//
-// IO is performed on stdin and stdout. To provide frame control, all frames
-// will have the following simple format:
-//   [ length | bytes ]
-// where |length| is a 4 byte big-endian encoded unsigned integer.
-#include <cassert>
-#include <cstdio>
-#include <iostream>
-#include <memory>
-
-#include "securegcm/ukey2_handshake.h"
-#include "absl/container/fixed_array.h"
-#include "absl/flags/flag.h"
-#include "absl/flags/parse.h"
-
-#define LOG(ERROR) std::cerr
-#define CHECK_EQ(a, b) do { if ((a) != (b)) abort(); } while(0)
-
-ABSL_FLAG(
-    int, verification_string_length, 32,
-    "The length in bytes of the verification string. Must be a value between 1"
-    "and 32.");
-ABSL_FLAG(string, mode, "initiator",
-          "The mode to run as: one of [initiator, responder]");
-
-namespace securegcm {
-
-namespace {
-
-// Writes |message| to stdout in the frame format.
-void WriteFrame(const string& message) {
-  // Write length of |message| in little-endian.
-  const uint32_t length = message.length();
-  fputc((length >> (3 * 8)) & 0xFF, stdout);
-  fputc((length >> (2 * 8)) & 0xFF, stdout);
-  fputc((length >> (1 * 8)) & 0xFF, stdout);
-  fputc((length >> (0 * 8)) & 0xFF, stdout);
-
-  // Write message to stdout.
-  CHECK_EQ(message.length(),
-           fwrite(message.c_str(), 1, message.length(), stdout));
-  CHECK_EQ(0, fflush(stdout));
-}
-
-// Returns a message read from stdin after parsing it from the frame format.
-string ReadFrame() {
-  // Read length of the frame from the stream.
-  uint8_t length_data[sizeof(uint32_t)];
-  CHECK_EQ(sizeof(uint32_t), fread(&length_data, 1, sizeof(uint32_t), stdin));
-
-  uint32_t length = 0;
-  length |= static_cast<uint32_t>(length_data[0]) << (3 * 8);
-  length |= static_cast<uint32_t>(length_data[1]) << (2 * 8);
-  length |= static_cast<uint32_t>(length_data[2]) << (1 * 8);
-  length |= static_cast<uint32_t>(length_data[3]) << (0 * 8);
-
-  // Read |length| bytes from the stream.
-  absl::FixedArray<char> buffer(length);
-  CHECK_EQ(length, fread(buffer.data(), 1, length, stdin));
-
-  return string(buffer.data(), length);
-}
-
-}  // namespace
-
-// Handles the runtime of the program in initiator or responder mode.
-class UKey2Shell {
- public:
-  explicit UKey2Shell(int verification_string_length);
-  ~UKey2Shell();
-
-  // Runs the shell, performing the initiator handshake for authentication.
-  bool RunAsInitiator();
-
-  // Runs the shell, performing the responder handshake for authentication.
-  bool RunAsResponder();
-
- private:
-  // Writes the next handshake message obtained from |ukey2_handshake_| to
-  // stdout.
-  // If an error occurs, |tag| is logged.
-  bool WriteNextHandshakeMessage(const string& tag);
-
-  // Reads the next handshake message from stdin and parses it using
-  // |ukey2_handshake_|.
-  // If an error occurs, |tag| is logged.
-  bool ReadNextHandshakeMessage(const string& tag);
-
-  // Writes the verification string to stdout and waits for a confirmation from
-  // stdin.
-  bool ConfirmVerificationString();
-
-  // After authentication is completed, this function runs the loop handing the
-  // secure connection.
-  bool RunSecureConnectionLoop();
-
-  std::unique_ptr<UKey2Handshake> ukey2_handshake_;
-  const int verification_string_length_;
-};
-
-UKey2Shell::UKey2Shell(int verification_string_length)
-    : verification_string_length_(verification_string_length) {}
-
-UKey2Shell::~UKey2Shell() {}
-
-bool UKey2Shell::WriteNextHandshakeMessage(const string& tag) {
-  const std::unique_ptr<string> message =
-      ukey2_handshake_->GetNextHandshakeMessage();
-  if (!message) {
-    LOG(ERROR) << "Failed to create [" << tag
-               << "] message: " << ukey2_handshake_->GetLastError();
-    return false;
-  }
-  WriteFrame(*message);
-  return true;
-}
-
-bool UKey2Shell::ReadNextHandshakeMessage(const string& tag) {
-  const string message = ReadFrame();
-  const UKey2Handshake::ParseResult result =
-      ukey2_handshake_->ParseHandshakeMessage(message);
-  if (!result.success) {
-    LOG(ERROR) << "Failed to parse [" << tag
-               << "] message: " << ukey2_handshake_->GetLastError();
-    if (result.alert_to_send) {
-      WriteFrame(*result.alert_to_send);
-    }
-    return false;
-  }
-  return true;
-}
-
-bool UKey2Shell::ConfirmVerificationString() {
-  const std::unique_ptr<string> auth_string =
-      ukey2_handshake_->GetVerificationString(verification_string_length_);
-  if (!auth_string) {
-    LOG(ERROR) << "Failed to get verification string: "
-               << ukey2_handshake_->GetLastError();
-    return false;
-  }
-  WriteFrame(*auth_string);
-
-  // Wait for ack message.
-  const string message = ReadFrame();
-  if (message != "ok") {
-    LOG(ERROR) << "Expected string 'ok'";
-    return false;
-  }
-  ukey2_handshake_->VerifyHandshake();
-  return true;
-}
-
-bool UKey2Shell::RunSecureConnectionLoop() {
-  const std::unique_ptr<D2DConnectionContextV1> connection_context =
-      ukey2_handshake_->ToConnectionContext();
-  if (!connection_context) {
-    LOG(ERROR) << "Failed to create connection context: "
-               << ukey2_handshake_->GetLastError();
-    return false;
-  }
-
-  for (;;) {
-    // Parse the next expression.
-    const string expression = ReadFrame();
-    const size_t pos = expression.find(" ");
-    if (pos == std::string::npos) {
-      LOG(ERROR) << "Invalid command in connection loop.";
-      return false;
-    }
-    const string command = expression.substr(0, pos);
-
-    if (command == "encrypt") {
-      const string payload = expression.substr(pos + 1, expression.length());
-      std::unique_ptr<string> encoded_message =
-          connection_context->EncodeMessageToPeer(payload);
-      if (!encoded_message) {
-        LOG(ERROR) << "Failed to encode payload of size " << payload.length();
-        return false;
-      }
-      WriteFrame(*encoded_message);
-    } else if (command == "decrypt") {
-      const string message = expression.substr(pos + 1, expression.length());
-      std::unique_ptr<string> decoded_payload =
-          connection_context->DecodeMessageFromPeer(message);
-      if (!decoded_payload) {
-        LOG(ERROR) << "Failed to decode message of size " << message.length();
-        return false;
-      }
-      WriteFrame(*decoded_payload);
-    } else if (command == "session_unique") {
-      std::unique_ptr<string> session_unique =
-          connection_context->GetSessionUnique();
-      if (!session_unique) {
-        LOG(ERROR) << "Failed to get session unique.";
-        return false;
-      }
-      WriteFrame(*session_unique);
-    } else {
-      LOG(ERROR) << "Unrecognized command: " << command;
-      return false;
-    }
-  }
-}
-
-bool UKey2Shell::RunAsInitiator() {
-  ukey2_handshake_ = UKey2Handshake::ForInitiator(
-      UKey2Handshake::HandshakeCipher::P256_SHA512);
-  if (!ukey2_handshake_) {
-    LOG(ERROR) << "Unable to create UKey2Handshake";
-    return false;
-  }
-
-  // Perform handshake.
-  if (!WriteNextHandshakeMessage("Initiator Init")) return false;
-  if (!ReadNextHandshakeMessage("Responder Init")) return false;
-  if (!WriteNextHandshakeMessage("Initiator Finish")) return false;
-  if (!ConfirmVerificationString()) return false;
-
-  // Create a connection context.
-  return RunSecureConnectionLoop();
-}
-
-bool UKey2Shell::RunAsResponder() {
-  ukey2_handshake_ = UKey2Handshake::ForResponder(
-      UKey2Handshake::HandshakeCipher::P256_SHA512);
-  if (!ukey2_handshake_) {
-    LOG(ERROR) << "Unable to create UKey2Handshake";
-    return false;
-  }
-
-  // Perform handshake.
-  if (!ReadNextHandshakeMessage("Initiator Init")) return false;
-  if (!WriteNextHandshakeMessage("Responder Init")) return false;
-  if (!ReadNextHandshakeMessage("Initiator Finish")) return false;
-  if (!ConfirmVerificationString()) return false;
-
-  // Create a connection context.
-  return RunSecureConnectionLoop();
-}
-
-}  // namespace securegcm
-
-int main(int argc, char** argv) {
-  absl::ParseCommandLine(argc, argv);
-
-  const int verification_string_length =
-      absl::GetFlag(FLAGS_verification_string_length);
-  if (verification_string_length < 1 || verification_string_length > 32) {
-    LOG(ERROR) << "Invalid flag value, verification_string_length: "
-               << verification_string_length;
-    return 1;
-  }
-
-  securegcm::UKey2Shell shell(verification_string_length);
-  int exit_code = 0;
-  const string mode = absl::GetFlag(FLAGS_mode);
-  if (mode == "initiator") {
-    exit_code = !shell.RunAsInitiator();
-  } else if (mode == "responder") {
-    exit_code = !shell.RunAsResponder();
-  } else {
-    LOG(ERROR) << "Invalid flag value, mode: " << mode;
-    exit_code = 1;
-  }
-  return exit_code;
-}
diff --git a/src/main/cpp/test/securegcm/CMakeLists.txt b/src/main/cpp/test/securegcm/CMakeLists.txt
deleted file mode 100644
index 272f919..0000000
--- a/src/main/cpp/test/securegcm/CMakeLists.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright 2020 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-add_executable(ukey2_test
-  d2d_connection_context_v1_test.cc
-  d2d_crypto_ops_test.cc
-  java_util_test.cc
-)
-
-target_link_libraries(ukey2_test
-  PUBLIC
-    ukey2
-    gtest
-    gtest_main
-)
-
-add_test(
-  NAME ukey2_test
-  COMMAND ukey2_test
-)
diff --git a/src/main/cpp/test/securegcm/d2d_connection_context_v1_test.cc b/src/main/cpp/test/securegcm/d2d_connection_context_v1_test.cc
deleted file mode 100644
index daf69d1..0000000
--- a/src/main/cpp/test/securegcm/d2d_connection_context_v1_test.cc
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "securegcm/d2d_connection_context_v1.h"
-
-#include "securegcm/d2d_crypto_ops.h"
-#include "gtest/gtest.h"
-
-namespace securegcm {
-
-using securemessage::CryptoOps;
-
-namespace {
-
-// The encode and decode keys should be 32 bytes.
-const char kEncodeKeyData[] = "initiator_encode_key_for_aes_256";
-const char kDecodeKeyData[] = "initiator_decode_key_for_aes_256";
-
-}  // namespace
-
-// A friend to access the private variables of D2DConnectionContextV1.
-class D2DConnectionContextV1Peer {
- public:
-  explicit D2DConnectionContextV1Peer(const std::string& savedSessionInfo) {
-    context_ = D2DConnectionContextV1::FromSavedSession(savedSessionInfo);
-  }
-
-  D2DConnectionContextV1* GetContext() { return context_.get(); }
-
-  uint32_t GetEncodeSequenceNumber() {
-    return context_->encode_sequence_number_;
-  }
-
-  uint32_t GetDecodeSequenceNumber() {
-    return context_->decode_sequence_number_;
-  }
-
- private:
-  std::unique_ptr<D2DConnectionContextV1> context_;
-};
-
-TEST(D2DConnectionContextionV1Test, SaveSession) {
-  CryptoOps::SecretKey encodeKey = CryptoOps::SecretKey(
-      kEncodeKeyData, CryptoOps::KeyAlgorithm::AES_256_KEY);
-  CryptoOps::SecretKey decodeKey = CryptoOps::SecretKey(
-      kDecodeKeyData, CryptoOps::KeyAlgorithm::AES_256_KEY);
-
-  D2DConnectionContextV1 initiator =
-      D2DConnectionContextV1(encodeKey, decodeKey, 0, 1);
-  D2DConnectionContextV1 responder =
-      D2DConnectionContextV1(decodeKey, encodeKey, 1, 0);
-
-  std::unique_ptr<std::string> initiatorSavedSessionState =
-      initiator.SaveSession();
-  std::unique_ptr<std::string> responderSavedSessionState =
-      responder.SaveSession();
-
-  D2DConnectionContextV1Peer restoredInitiator =
-      D2DConnectionContextV1Peer(*initiatorSavedSessionState);
-  D2DConnectionContextV1Peer restoredResponder =
-      D2DConnectionContextV1Peer(*responderSavedSessionState);
-
-  // Verify internal state matches initialization.
-  EXPECT_EQ(0, restoredInitiator.GetEncodeSequenceNumber());
-  EXPECT_EQ(1, restoredInitiator.GetDecodeSequenceNumber());
-  EXPECT_EQ(1, restoredResponder.GetEncodeSequenceNumber());
-  EXPECT_EQ(0, restoredResponder.GetDecodeSequenceNumber());
-
-  EXPECT_EQ(*restoredInitiator.GetContext()->GetSessionUnique(),
-            *restoredResponder.GetContext()->GetSessionUnique());
-
-  const std::string message = "ping";
-
-  // Ensure that they can still talk to one another.
-  std::string encodedMessage =
-      *restoredInitiator.GetContext()->EncodeMessageToPeer(message);
-  std::string decodedMessage =
-      *restoredResponder.GetContext()->DecodeMessageFromPeer(encodedMessage);
-
-  EXPECT_EQ(message, decodedMessage);
-
-  encodedMessage =
-      *restoredResponder.GetContext()->EncodeMessageToPeer(message);
-  decodedMessage =
-      *restoredInitiator.GetContext()->DecodeMessageFromPeer(encodedMessage);
-
-  EXPECT_EQ(message, decodedMessage);
-}
-
-TEST(D2DConnectionContextionV1Test, SaveSession_TooShort) {
-  CryptoOps::SecretKey encodeKey = CryptoOps::SecretKey(
-      kEncodeKeyData, CryptoOps::KeyAlgorithm::AES_256_KEY);
-  CryptoOps::SecretKey decodeKey = CryptoOps::SecretKey(
-      kDecodeKeyData, CryptoOps::KeyAlgorithm::AES_256_KEY);
-
-  D2DConnectionContextV1 initiator =
-      D2DConnectionContextV1(encodeKey, decodeKey, 0, 1);
-
-  std::unique_ptr<std::string> initiatorSavedSessionState =
-      initiator.SaveSession();
-
-  // Try to rebuild the context with a shorter session state.
-  std::string shortSessionState = initiatorSavedSessionState->substr(
-      0, initiatorSavedSessionState->size() - 1);
-
-  D2DConnectionContextV1Peer restoredInitiator =
-      D2DConnectionContextV1Peer(shortSessionState);
-
-  // nullptr is returned on error. It should not crash.
-  EXPECT_EQ(restoredInitiator.GetContext(), nullptr);
-}
-
-}  // namespace securegcm
diff --git a/src/main/cpp/test/securegcm/d2d_crypto_ops_test.cc b/src/main/cpp/test/securegcm/d2d_crypto_ops_test.cc
deleted file mode 100644
index 5acbb89..0000000
--- a/src/main/cpp/test/securegcm/d2d_crypto_ops_test.cc
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "securegcm/d2d_crypto_ops.h"
-
-#include "gtest/gtest.h"
-#include "securemessage/crypto_ops.h"
-#include "securemessage/secure_message_builder.h"
-
-namespace securegcm {
-
-using securemessage::CryptoOps;
-using securemessage::HeaderAndBody;
-using securemessage::SecureMessage;
-
-namespace {
-
-const char kPayloadData[] = "Test payload";
-const char kSecretKeyData[] = "secret key must be 32 bytes long";
-const char kOtherSecretKeyData[] = "other secret key****************";
-const char kInvalidSigncryptedMessage[] = "Not a protobuf";
-const int kSupportedProtocolVersion = 1;
-const int kUnsupportedProtocolVersion = 2;
-
-}  // namespace
-
-class D2DCryptoOpsTest : public testing::Test {
- public:
-  D2DCryptoOpsTest()
-      : payload_(DEVICE_TO_DEVICE_MESSAGE, kPayloadData),
-        secret_key_(kSecretKeyData, CryptoOps::AES_256_KEY) {}
-
- protected:
-  const D2DCryptoOps::Payload payload_;
-  const CryptoOps::SecretKey secret_key_;
-};
-
-TEST_F(D2DCryptoOpsTest, Signcrypt_EmptyPayload) {
-  // Signcrypting an empty payload should fail.
-  D2DCryptoOps::Payload empty_payload(DEVICE_TO_DEVICE_MESSAGE, string());
-  EXPECT_FALSE(D2DCryptoOps::SigncryptPayload(empty_payload, secret_key_));
-}
-
-TEST_F(D2DCryptoOpsTest, VerifyDecrypt_InvalidMessage) {
-  // VerifyDecrypting an invalid payload should fail.
-  EXPECT_FALSE(D2DCryptoOps::VerifyDecryptPayload(kInvalidSigncryptedMessage,
-                                                  secret_key_));
-}
-
-TEST_F(D2DCryptoOpsTest, VerifyDecrypt_NoPublicMetadata) {
-  std::unique_ptr<string> signcrypted_message =
-      D2DCryptoOps::SigncryptPayload(payload_, secret_key_);
-
-  // Clear metadata field in header.
-  SecureMessage secure_message;
-  ASSERT_TRUE(secure_message.ParseFromString(*signcrypted_message));
-  HeaderAndBody header_and_body;
-  ASSERT_TRUE(
-      header_and_body.ParseFromString(secure_message.header_and_body()));
-  header_and_body.mutable_header()->clear_public_metadata();
-  secure_message.set_header_and_body(header_and_body.SerializeAsString());
-
-  // Decrypting the message should now fail.
-  EXPECT_FALSE(D2DCryptoOps::VerifyDecryptPayload(
-      secure_message.SerializeAsString(), secret_key_));
-}
-
-TEST_F(D2DCryptoOpsTest, VerifyDecrypt_ProtocolVersionNotSupported) {
-  std::unique_ptr<string> signcrypted_message =
-      D2DCryptoOps::SigncryptPayload(payload_, secret_key_);
-
-  // Change version in metadata field in header to an unsupported version.
-  SecureMessage secure_message;
-  ASSERT_TRUE(secure_message.ParseFromString(*signcrypted_message));
-  HeaderAndBody header_and_body;
-  ASSERT_TRUE(
-      header_and_body.ParseFromString(secure_message.header_and_body()));
-  GcmMetadata metadata;
-  ASSERT_TRUE(
-      metadata.ParseFromString(header_and_body.header().public_metadata()));
-  EXPECT_EQ(kSupportedProtocolVersion, metadata.version());
-  metadata.set_version(kUnsupportedProtocolVersion);
-  header_and_body.mutable_header()->set_public_metadata(
-      metadata.SerializeAsString());
-  secure_message.set_header_and_body(header_and_body.SerializeAsString());
-
-  // Decrypting the message should now fail.
-  EXPECT_FALSE(D2DCryptoOps::VerifyDecryptPayload(
-      secure_message.SerializeAsString(), secret_key_));
-}
-
-TEST_F(D2DCryptoOpsTest, SigncryptThenVerifyDecrypt_SuccessWithSameKey) {
-  // Signcrypt the payload.
-  std::unique_ptr<string> signcrypted_message =
-      D2DCryptoOps::SigncryptPayload(payload_, secret_key_);
-  ASSERT_TRUE(signcrypted_message);
-
-  // Decrypt the signcrypted message.
-  std::unique_ptr<D2DCryptoOps::Payload> decrypted_payload =
-      D2DCryptoOps::VerifyDecryptPayload(*signcrypted_message, secret_key_);
-  ASSERT_TRUE(decrypted_payload);
-
-  // Check that decrypted payload is the same.
-  EXPECT_EQ(payload_.type(), decrypted_payload->type());
-  EXPECT_EQ(payload_.message(), decrypted_payload->message());
-}
-
-TEST_F(D2DCryptoOpsTest, SigncryptThenVerifyDecrypt_FailsWithDifferentKey) {
-  CryptoOps::SecretKey other_secret_key(kOtherSecretKeyData,
-                                        CryptoOps::AES_256_KEY);
-
-  // Signcrypt the payload with first secret key.
-  std::unique_ptr<string> signcrypted_message =
-      D2DCryptoOps::SigncryptPayload(payload_, secret_key_);
-  ASSERT_TRUE(signcrypted_message);
-
-  // Decrypting the signcrypted message with the other secret key should fail.
-  EXPECT_FALSE(D2DCryptoOps::VerifyDecryptPayload(*signcrypted_message,
-                                                  other_secret_key));
-}
-
-TEST_F(D2DCryptoOpsTest, DeriveNewKeyForPurpose_ClientServer) {
-  CryptoOps::SecretKey master_key(kSecretKeyData, CryptoOps::AES_256_KEY);
-
-  std::unique_ptr<CryptoOps::SecretKey> derived_key1 =
-      D2DCryptoOps::DeriveNewKeyForPurpose(master_key, "client");
-  std::unique_ptr<CryptoOps::SecretKey> derived_key2 =
-      D2DCryptoOps::DeriveNewKeyForPurpose(master_key, "server");
-
-  ASSERT_TRUE(derived_key1);
-  ASSERT_TRUE(derived_key2);
-  EXPECT_EQ(CryptoOps::AES_256_KEY, derived_key1->algorithm());
-  EXPECT_EQ(CryptoOps::AES_256_KEY, derived_key2->algorithm());
-  EXPECT_NE(derived_key1->data().String(), derived_key2->data().String());
-}
-
-TEST_F(D2DCryptoOpsTest, DeriveNewKeyForPurpose_InvalidMasterKeySize) {
-  CryptoOps::SecretKey master_key("Invalid Size", CryptoOps::AES_256_KEY);
-  EXPECT_FALSE(D2DCryptoOps::DeriveNewKeyForPurpose(master_key, "purpose"));
-}
-
-TEST_F(D2DCryptoOpsTest, DeriveNewKeyForPurpose_PurposeEmpty) {
-  CryptoOps::SecretKey master_key(kSecretKeyData, CryptoOps::AES_256_KEY);
-  EXPECT_FALSE(D2DCryptoOps::DeriveNewKeyForPurpose(master_key, string()));
-}
-
-}  // namespace securegcm
diff --git a/src/main/cpp/test/securegcm/java_util_test.cc b/src/main/cpp/test/securegcm/java_util_test.cc
deleted file mode 100644
index 20928fa..0000000
--- a/src/main/cpp/test/securegcm/java_util_test.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "securegcm/java_util.h"
-
-#include <limits>
-
-#include "gtest/gtest.h"
-
-namespace securegcm {
-
-using securemessage::ByteBuffer;
-
-namespace {
-
-int32_t kMinInt32 = std::numeric_limits<int32_t>::min();
-int32_t kMaxInt32 = std::numeric_limits<int32_t>::max();
-
-}  // namespace
-
-
-TEST(JavaUtilTest, TestJavaAdd_InRange) {
-  EXPECT_EQ(2, java_util::JavaAdd(1, 1));
-}
-
-TEST(JavaUtilTest, TestJavaAdd_Underflow) {
-  EXPECT_EQ(kMaxInt32, java_util::JavaAdd(kMinInt32, -1));
-  EXPECT_EQ(kMaxInt32 - 1, java_util::JavaAdd(kMinInt32, -2));
-  EXPECT_EQ(1, java_util::JavaAdd(kMinInt32, -kMaxInt32));
-}
-
-TEST(JavaUtilTest, TestJavaAdd_Overflow) {
-  EXPECT_EQ(kMinInt32, java_util::JavaAdd(kMaxInt32, 1));
-  EXPECT_EQ(kMinInt32 + 1, java_util::JavaAdd(kMaxInt32, 2));
-  EXPECT_EQ(-2, java_util::JavaAdd(kMaxInt32, kMaxInt32));
-}
-
-TEST(JavaUtilTest, TestJavaMultiply_InRange) {
-  EXPECT_EQ(4, java_util::JavaAdd(2, 2));
-}
-
-TEST(JavaUtilTest, TestJavaMultiply_Underflow) {
-  EXPECT_EQ(0, java_util::JavaMultiply(kMinInt32, 2));
-  EXPECT_EQ(-(kMinInt32 / 2), java_util::JavaMultiply(kMinInt32 / 2, 3));
-  EXPECT_EQ(kMinInt32, java_util::JavaMultiply(kMinInt32, kMaxInt32));
-}
-
-TEST(JavaUtilTest, TestJavaMultiply_Overflow) {
-  EXPECT_EQ(-2, java_util::JavaMultiply(kMaxInt32, 2));
-  EXPECT_EQ(kMaxInt32 - 2, java_util::JavaMultiply(kMaxInt32, 3));
-  EXPECT_EQ(1, java_util::JavaMultiply(kMaxInt32, kMaxInt32));
-}
-
-TEST(JavaUtilTest, TestJavaHashCode_EmptyBytes) {
-  EXPECT_EQ(1, java_util::JavaHashCode(ByteBuffer()));
-}
-
-TEST(JavaUtilTest, TestJavaHashCode_LongByteArray) {
-  const uint8_t kBytes[] = {
-      0x93, 0x75, 0xE1, 0x2E, 0x26, 0x28, 0x54, 0x8C, 0xD9, 0x5C, 0x48, 0x7A,
-      0x07, 0x53, 0x4E, 0xED, 0x28, 0x52, 0x5D, 0x41, 0xE3, 0x18, 0x84, 0x84,
-      0x5F, 0xF6, 0x89, 0x98, 0x25, 0x1E, 0xD9, 0x6C, 0x85, 0xF3, 0x5A, 0x83,
-      0x39, 0x37, 0x4E, 0x77, 0x95, 0xB5, 0x58, 0x7C, 0xD2, 0x55, 0xA0, 0x86,
-      0x13, 0x3F, 0xBF, 0x85, 0xD3, 0xE0, 0x28, 0x90, 0x17, 0x3D, 0x2E, 0xD4,
-      0x4D, 0x95, 0x9C, 0xAE, 0xAD, 0x8A, 0x05, 0x91, 0x5D, 0xC6, 0x4B, 0x09,
-      0xB2, 0xD9, 0x34, 0x64, 0x07, 0x7B, 0x07, 0x8C, 0xA6, 0xC7, 0x1C, 0x10,
-      0x34, 0xD4, 0x30, 0x80, 0x03, 0x4F, 0x2C, 0x70};
-  const int32_t kExpectedHashCode = 1983685004;
-  EXPECT_EQ(kExpectedHashCode,
-            java_util::JavaHashCode(ByteBuffer(kBytes, sizeof(kBytes))));
-}
-
-}  // namespace securegcm
diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContext.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContext.java
index fb4af63..09023a5 100644
--- a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContext.java
+++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContext.java
@@ -1,17 +1,17 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.security.cryptauth.lib.securegcm;
 
 import com.google.common.annotations.VisibleForTesting;
diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV0.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV0.java
index d0efa44..92aa02d 100644
--- a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV0.java
+++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV0.java
@@ -1,17 +1,17 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.security.cryptauth.lib.securegcm;
 
 import java.io.ByteArrayOutputStream;
diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV1.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV1.java
index 1566849..4b5fb5e 100644
--- a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV1.java
+++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV1.java
@@ -1,17 +1,17 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.security.cryptauth.lib.securegcm;
 
 import java.io.ByteArrayOutputStream;
diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DCryptoOps.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DCryptoOps.java
index a7203d1..48dc52f 100644
--- a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DCryptoOps.java
+++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DCryptoOps.java
@@ -1,17 +1,17 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.security.cryptauth.lib.securegcm;
 
 import com.google.common.annotations.VisibleForTesting;
@@ -55,11 +55,6 @@
     (byte) 0x6D, (byte) 0xA8, (byte) 0x55, (byte) 0x10
   };
 
-  // Data passed to hkdf to create the key used by the initiator to encode messages.
-  static final String INITIATOR_PURPOSE = "initiator";
-  // Data passed to hkdf to create the key used by the responder to encode messages.
-  static final String RESPONDER_PURPOSE = "responder";
-
   // Don't instantiate
   private D2DCryptoOps() { }
 
@@ -201,7 +196,7 @@
 
   /**
    * Used to derive a distinct key for each initiator and responder.
-   *
+   * 
    * @param masterKey the source key used to derive the new key.
    * @param purpose a string to make the new key different for each purpose.
    * @return the derived {@link SecretKey}.
diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DDiffieHellmanKeyExchangeHandshake.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DDiffieHellmanKeyExchangeHandshake.java
index f929a3a..ae43d90 100644
--- a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DDiffieHellmanKeyExchangeHandshake.java
+++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DDiffieHellmanKeyExchangeHandshake.java
@@ -1,17 +1,17 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.security.cryptauth.lib.securegcm;
 
 import com.google.protobuf.InvalidProtocolBufferException;
@@ -64,6 +64,11 @@
  * </pre>
  */
 public class D2DDiffieHellmanKeyExchangeHandshake implements D2DHandshakeContext {
+  // Data passed to hkdf to create the key used by the initiator to encode messages.
+  private static final String INITIATOR_PURPOSE = "initiator";
+  // Data passed to hkdf to create the key used by the responder to encode messages.
+  private static final String RESPONDER_PURPOSE = "responder";
+
   private KeyPair ourKeyPair;
   private PublicKey theirPublicKey;
   private SecretKey initiatorEncodeKey;
@@ -171,10 +176,8 @@
           responderEncodeKey = masterKey;
           break;
         case D2DConnectionContextV1.PROTOCOL_VERSION:
-          initiatorEncodeKey = D2DCryptoOps.deriveNewKeyForPurpose(masterKey,
-              D2DCryptoOps.INITIATOR_PURPOSE);
-          responderEncodeKey = D2DCryptoOps.deriveNewKeyForPurpose(masterKey,
-              D2DCryptoOps.RESPONDER_PURPOSE);
+          initiatorEncodeKey = D2DCryptoOps.deriveNewKeyForPurpose(masterKey, INITIATOR_PURPOSE);
+          responderEncodeKey = D2DCryptoOps.deriveNewKeyForPurpose(masterKey, RESPONDER_PURPOSE);
           break;
         default:
           throw new IllegalStateException("Unexpected protocol version: " + protocolVersionToUse);
@@ -235,10 +238,8 @@
           initiatorEncodeKey = masterKey;
           responderEncodeKey = masterKey;
         } else {
-          initiatorEncodeKey = D2DCryptoOps.deriveNewKeyForPurpose(masterKey,
-              D2DCryptoOps.INITIATOR_PURPOSE);
-          responderEncodeKey = D2DCryptoOps.deriveNewKeyForPurpose(masterKey,
-              D2DCryptoOps.RESPONDER_PURPOSE);
+          initiatorEncodeKey = D2DCryptoOps.deriveNewKeyForPurpose(masterKey, INITIATOR_PURPOSE);
+          responderEncodeKey = D2DCryptoOps.deriveNewKeyForPurpose(masterKey, RESPONDER_PURPOSE);
         }
 
         DeviceToDeviceMessage message =
diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DHandshakeContext.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DHandshakeContext.java
index 5fc1d7b..8c35d22 100644
--- a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DHandshakeContext.java
+++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DHandshakeContext.java
@@ -1,17 +1,17 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.security.cryptauth.lib.securegcm;
 
 /**
diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DSpakeEd25519Handshake.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DSpakeEd25519Handshake.java
new file mode 100644
index 0000000..da5abf1
--- /dev/null
+++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DSpakeEd25519Handshake.java
@@ -0,0 +1,648 @@
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.security.cryptauth.lib.securegcm;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.security.cryptauth.lib.securegcm.DeviceToDeviceMessagesProto.DeviceToDeviceMessage;
+import com.google.security.cryptauth.lib.securegcm.DeviceToDeviceMessagesProto.EcPoint;
+import com.google.security.cryptauth.lib.securegcm.DeviceToDeviceMessagesProto.SpakeHandshakeMessage;
+import com.google.security.cryptauth.lib.securegcm.Ed25519.Ed25519Exception;
+import com.google.security.cryptauth.lib.securegcm.TransportCryptoOps.Payload;
+import com.google.security.cryptauth.lib.securegcm.TransportCryptoOps.PayloadType;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * Implements a {@link D2DHandshakeContext} by using SPAKE2 (Simple Password-Based Encrypted Key
+ * Exchange Protocol) on top of the Ed25519 curve.
+ * SPAKE2: http://www.di.ens.fr/~mabdalla/papers/AbPo05a-letter.pdf
+ * Ed25519: http://ed25519.cr.yp.to/
+ *
+ * <p>Usage:
+ * {@code
+ *   // initiator:
+ *   D2DHandshakeContext initiatorHandshakeContext =
+ *       D2DSpakeEd25519Handshake.forInitiator(PASSWORD);
+ *   byte[] initiatorMsg = initiatorHandshakeContext.getNextHandshakeMessage();
+ *   // (send initiatorMsg to responder)
+ *
+ *   // responder:
+ *   D2DHandshakeContext responderHandshakeContext =
+ *       D2DSpakeEd25519Handshake.forResponder(PASSWORD);
+ *   responderHandshakeContext.parseHandshakeMessage(initiatorMsg);
+ *   byte[] responderMsg = responderHandshakeContext.getNextHandshakeMessage();
+ *   // (send responderMsg to initiator)
+ *
+ *   // initiator:
+ *   initiatorHandshakeContext.parseHandshakeMessage(responderMsg);
+ *   initiatorMsg = initiatorHandshakeContext.getNextHandshakeMessage();
+ *   // (send initiatorMsg to responder)
+ *
+ *   // responder:
+ *   responderHandshakeContext.parseHandshakeMessage(initiatorMsg);
+ *   responderMsg = responderHandshakeContext.getNextHandshakeMessage();
+ *   D2DConnectionContext responderCtx = responderHandshakeContext.toConnectionContext();
+ *   // (send responderMsg to initiator)
+ *
+ *   // initiator:
+ *   initiatorHandshakeContext.parseHandshakeMessage(responderMsg);
+ *   D2DConnectionContext initiatorCtx = initiatorHandshakeContext.toConnectionContext();
+ * }
+ *
+ * <p>The initial computation is:
+ *   Initiator                                              Responder
+ *    has KM (pre-agreed point)                              has KM (pre-agreed point)
+ *    has KN (pre-agreed point)                              has KN (pre-agreed point)
+ *    has Password (pre-agreed)                              has Password (pre-agreed)
+ *    picks random scalar Xi (private key)                   picks random scalar Xr (private key)
+ *    computes the public key Pxi = G*Xi                     computes the public key Pxr = G*Xr
+ *    computes commitment:                                   computes commitment:
+ *      Ci = KM * password + Pxi                               Cr = KN * password + Pxr
+ *
+ * <p>The flow is:
+ *   Initiator                                              Responder
+ *              ----- Ci --------------------------------->
+ *              <--------------------------------- Cr -----
+ *   computes shared key K:                                 computes shared key K:
+ *    (Cr - KN*password) * Xi                                (Ci - KM*password) * Xr
+ *   computes hash:                                         computes hash:
+ *    Hi = sha256(0|Cr|Ci|K)                                 Hr = sha256(1|Ci|Cr|K)
+ *              ----- Hi --------------------------------->
+ *                                                          Verify Hi
+ *              <-------------- Hr (optional payload) -----
+ *   Verify Hr
+ */
+public class D2DSpakeEd25519Handshake implements D2DHandshakeContext {
+  // Minimum length password that is acceptable for the handshake
+  public static final int MIN_PASSWORD_LENGTH = 4;
+  /**
+   * Creates a new SPAKE handshake object for the initiator.
+   *
+   * @param password the password that should be used in the handshake.  Note that this should be
+   *     at least {@value #MIN_PASSWORD_LENGTH} bytes long
+   */
+  public static D2DSpakeEd25519Handshake forInitiator(byte[] password) throws HandshakeException {
+    return new D2DSpakeEd25519Handshake(State.INITIATOR_START, password);
+  }
+
+  /**
+   * Creates a new SPAKE handshake object for the responder.
+   *
+   * @param password the password that should be used in the handshake.  Note that this should be
+   *     at least {@value #MIN_PASSWORD_LENGTH} bytes long
+   */
+  public static D2DSpakeEd25519Handshake forResponder(byte[] password) throws HandshakeException {
+    return new D2DSpakeEd25519Handshake(State.RESPONDER_START, password);
+  }
+
+  //
+  // The protocol requires two verifiable, randomly generated group point. They were generated
+  // using the python code below. The algorithm is to first pick a random y in the group and solve
+  // the elliptic curve equation for a value of x, if possible. We then use (x, y) as the random
+  // point.
+  // Source of ed25519 is here: http://ed25519.cr.yp.to/python/ed25519.py
+  // import ed25519
+  // import hashlib
+  //
+  // # Seeds
+  // seed1 = 'D2D Ed25519 point generation seed (M)'
+  // seed2 = 'D2D Ed25519 point generation seed (N)'
+  //
+  // def find_seed(seed):
+  //   # generate a random scalar for the y coordinate
+  //   y = hashlib.sha256(seed).hexdigest()
+  //
+  //   P = ed25519.scalarmult(ed25519.B, int(y, 16) % ed25519.q)
+  //   if (not ed25519.isoncurve(P)):
+  //       print 'Wat? P should be on curve!'
+  //
+  //   print '  x: ' + hex(P[0])
+  //   print '  y: ' + hex(P[1])
+  //   print
+  //
+  // find_seed(seed1)
+  // find_seed(seed2)
+  //
+  // Output is:
+  //   x: 0x1981fb43f103290ecf9772022db8b19bfaf389057ed91e8486eb368763435925L
+  //   y: 0xa714c34f3b588aac92fd2587884a20964fd351a1f147d5c4bbf5c2f37a77c36L
+  //
+  //   x: 0x201a184f47d9a7973891d148e3d1c864d8084547131c2c1cefb7eebd26c63567L
+  //   y: 0x6da2d3b18ec4f9aa3b08e39c997cd8bf6e9948ffd4feffecaf8dd0b3d648b7e8L
+  //
+  // To get extended representation X, Y, Z, T, do: Z = 1, T = X*Y mod P
+  @VisibleForTesting
+  static final BigInteger[] KM = new BigInteger[] {
+    new BigInteger(new byte[] {(byte) 0x19, (byte) 0x81, (byte) 0xFB, (byte) 0x43,
+        (byte) 0xF1, (byte) 0x03, (byte) 0x29, (byte) 0x0E, (byte) 0xCF, (byte) 0x97,
+        (byte) 0x72, (byte) 0x02, (byte) 0x2D, (byte) 0xB8, (byte) 0xB1, (byte) 0x9B,
+        (byte) 0xFA, (byte) 0xF3, (byte) 0x89, (byte) 0x05, (byte) 0x7E, (byte) 0xD9,
+        (byte) 0x1E, (byte) 0x84, (byte) 0x86, (byte) 0xEB, (byte) 0x36, (byte) 0x87,
+        (byte) 0x63, (byte) 0x43, (byte) 0x59, (byte) 0x25}),
+    new BigInteger(new byte[] {(byte) 0x0A, (byte) 0x71, (byte) 0x4C, (byte) 0x34,
+        (byte) 0xF3, (byte) 0xB5, (byte) 0x88, (byte) 0xAA, (byte) 0xC9, (byte) 0x2F,
+        (byte) 0xD2, (byte) 0x58, (byte) 0x78, (byte) 0x84, (byte) 0xA2, (byte) 0x09,
+        (byte) 0x64, (byte) 0xFD, (byte) 0x35, (byte) 0x1A, (byte) 0x1F, (byte) 0x14,
+        (byte) 0x7D, (byte) 0x5C, (byte) 0x4B, (byte) 0xBF, (byte) 0x5C, (byte) 0x2F,
+        (byte) 0x37, (byte) 0xA7, (byte) 0x7C, (byte) 0x36}),
+    BigInteger.ONE,
+    new BigInteger(new byte[] {(byte) 0x04, (byte) 0x8F, (byte) 0xC1, (byte) 0xCE,
+        (byte) 0xE5, (byte) 0x83, (byte) 0x99, (byte) 0x25, (byte) 0xE5, (byte) 0x9B,
+        (byte) 0x80, (byte) 0xEA, (byte) 0xAD, (byte) 0x82, (byte) 0xAC, (byte) 0x0A,
+        (byte) 0x3C, (byte) 0xFE, (byte) 0xC5, (byte) 0x60, (byte) 0x93, (byte) 0x59,
+        (byte) 0x8B, (byte) 0x48, (byte) 0x44, (byte) 0xDD, (byte) 0x2A, (byte) 0x3E,
+        (byte) 0x24, (byte) 0x5D, (byte) 0x88, (byte) 0x33})};
+
+  @VisibleForTesting
+  static final BigInteger[] KN = new BigInteger[] {
+    new BigInteger(new byte[] {(byte) 0x20, (byte) 0x1A, (byte) 0x18, (byte) 0x4F,
+        (byte) 0x47, (byte) 0xD9, (byte) 0xA7, (byte) 0x97, (byte) 0x38, (byte) 0x91,
+        (byte) 0xD1, (byte) 0x48, (byte) 0xE3, (byte) 0xD1, (byte) 0xC8, (byte) 0x64,
+        (byte) 0xD8, (byte) 0x08, (byte) 0x45, (byte) 0x47, (byte) 0x13, (byte) 0x1C,
+        (byte) 0x2C, (byte) 0x1C, (byte) 0xEF, (byte) 0xB7, (byte) 0xEE, (byte) 0xBD,
+        (byte) 0x26, (byte) 0xC6, (byte) 0x35, (byte) 0x67}),
+    new BigInteger(new byte[] {(byte) 0x6D, (byte) 0xA2, (byte) 0xD3, (byte) 0xB1,
+        (byte) 0x8E, (byte) 0xC4, (byte) 0xF9, (byte) 0xAA, (byte) 0x3B, (byte) 0x08,
+        (byte) 0xE3, (byte) 0x9C, (byte) 0x99, (byte) 0x7C, (byte) 0xD8, (byte) 0xBF,
+        (byte) 0x6E, (byte) 0x99, (byte) 0x48, (byte) 0xFF, (byte) 0xD4, (byte) 0xFE,
+        (byte) 0xFF, (byte) 0xEC, (byte) 0xAF, (byte) 0x8D, (byte) 0xD0, (byte) 0xB3,
+        (byte) 0xD6, (byte) 0x48, (byte) 0xB7, (byte) 0xE8}),
+    BigInteger.ONE,
+    new BigInteger(new byte[] {(byte) 0x16, (byte) 0x40, (byte) 0xED, (byte) 0x5A,
+        (byte) 0x54, (byte) 0xFA, (byte) 0x0B, (byte) 0x07, (byte) 0x22, (byte) 0x86,
+        (byte) 0xE9, (byte) 0xD2, (byte) 0x2F, (byte) 0x46, (byte) 0x47, (byte) 0x63,
+        (byte) 0xFB, (byte) 0xF6, (byte) 0x0D, (byte) 0x79, (byte) 0x1D, (byte) 0x37,
+        (byte) 0xB9, (byte) 0x09, (byte) 0x3B, (byte) 0x58, (byte) 0x4D, (byte) 0xF4,
+        (byte) 0xC9, (byte) 0x95, (byte) 0xF7, (byte) 0x81})};
+
+  // Base point B as per ed25519.cr.yp.to
+  @VisibleForTesting
+  /* package */ static final BigInteger[] B = new BigInteger[] {
+    new BigInteger(new byte[] {(byte) 0x21, (byte) 0x69, (byte) 0x36, (byte) 0xD3,
+        (byte) 0xCD, (byte) 0x6E, (byte) 0x53, (byte) 0xFE, (byte) 0xC0, (byte) 0xA4,
+        (byte) 0xE2, (byte) 0x31, (byte) 0xFD, (byte) 0xD6, (byte) 0xDC, (byte) 0x5C,
+        (byte) 0x69, (byte) 0x2C, (byte) 0xC7, (byte) 0x60, (byte) 0x95, (byte) 0x25,
+        (byte) 0xA7, (byte) 0xB2, (byte) 0xC9, (byte) 0x56, (byte) 0x2D, (byte) 0x60,
+        (byte) 0x8F, (byte) 0x25, (byte) 0xD5, (byte) 0x1A}),
+    new BigInteger(new byte[] {(byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66,
+        (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66,
+        (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66,
+        (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66,
+        (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66,
+        (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x58}),
+    BigInteger.ONE,
+    new BigInteger(new byte[] {(byte) 0x67, (byte) 0x87, (byte) 0x5F, (byte) 0x0F,
+        (byte) 0xD7, (byte) 0x8B, (byte) 0x76, (byte) 0x65, (byte) 0x66, (byte) 0xEA,
+        (byte) 0x4E, (byte) 0x8E, (byte) 0x64, (byte) 0xAB, (byte) 0xE3, (byte) 0x7D,
+        (byte) 0x20, (byte) 0xF0, (byte) 0x9F, (byte) 0x80, (byte) 0x77, (byte) 0x51,
+        (byte) 0x52, (byte) 0xF5, (byte) 0x6D, (byte) 0xDE, (byte) 0x8A, (byte) 0xB3,
+        (byte) 0xA5, (byte) 0xB7, (byte) 0xDD, (byte) 0xA3})};
+
+  // Number of bits needed to represent a point
+  private static final int POINT_SIZE_BITS = 256;
+
+  // Java Message Digest name for SHA 256
+  private static final String SHA256 = "SHA-256";
+
+  // Pre-shared password hash represented as an integer
+  private BigInteger passwordHash;
+
+  // Current state of the handshake
+  private State handshakeState;
+
+  // Derived shared key
+  private byte[] sharedKey;
+
+  // Private key (random scalar)
+  private BigInteger valueX;
+
+  // Public key (random point, in extended notation, based on valueX)
+  private BigInteger[] pointX;
+
+  // Commitment we've received from the other party (their password-authenticated public key)
+  private BigInteger[] theirCommitmentPointAffine;
+  private BigInteger[] theirCommitmentPointExtended;
+
+  // Commitment we've sent to the other party (our password-authenticated public key)
+  private BigInteger[] ourCommitmentPointAffine;
+  private BigInteger[] ourCommitmentPointExtended;
+
+  private enum State {
+    // Initiator state
+    INITIATOR_START,
+    INITIATOR_WAITING_FOR_RESPONDER_COMMITMENT,
+    INITIATOR_AFTER_RESPONDER_COMMITMENT,
+    INITIATOR_WAITING_FOR_RESPONDER_HASH,
+
+    // Responder state
+    RESPONDER_START,
+    RESPONDER_AFTER_INITIATOR_COMMITMENT,
+    RESPONDER_WAITING_FOR_INITIATOR_HASH,
+    RESPONDER_AFTER_INITIATOR_HASH,
+
+    // Common completion state
+    HANDSHAKE_FINISHED,
+    HANDSHAKE_ALREADY_USED
+  }
+
+  @VisibleForTesting
+  D2DSpakeEd25519Handshake(State state, byte[] password) throws HandshakeException {
+    if (password == null || password.length < MIN_PASSWORD_LENGTH) {
+      throw new HandshakeException("Passwords must be at least " + MIN_PASSWORD_LENGTH + " bytes");
+    }
+
+    handshakeState = state;
+    passwordHash = new BigInteger(1 /* positive */, hash(password));
+
+    do {
+      valueX = new BigInteger(POINT_SIZE_BITS, new SecureRandom());
+    } while (valueX.equals(BigInteger.ZERO));
+
+    try {
+      pointX = Ed25519.scalarMultiplyExtendedPoint(B, valueX);
+    } catch (Ed25519Exception e) {
+      throw new HandshakeException("Could not make public key point", e);
+    }
+  }
+
+  @Override
+  public boolean isHandshakeComplete() {
+    switch (handshakeState) {
+      case HANDSHAKE_FINISHED:
+        // fall-through intentional
+      case HANDSHAKE_ALREADY_USED:
+        return true;
+
+      default:
+        return false;
+    }
+  }
+
+  @Override
+  public byte[] getNextHandshakeMessage() throws HandshakeException {
+    byte[] nextMessage;
+
+    switch(handshakeState) {
+      case INITIATOR_START:
+        nextMessage = makeCommitmentPointMessage(true /* is initiator */);
+        handshakeState = State.INITIATOR_WAITING_FOR_RESPONDER_COMMITMENT;
+        break;
+
+      case RESPONDER_AFTER_INITIATOR_COMMITMENT:
+        nextMessage = makeCommitmentPointMessage(false /* is initiator */);
+        handshakeState = State.RESPONDER_WAITING_FOR_INITIATOR_HASH;
+        break;
+
+      case INITIATOR_AFTER_RESPONDER_COMMITMENT:
+        nextMessage = makeSharedKeyHashMessage(true /* is initiator */, null /* no payload */);
+        handshakeState = State.INITIATOR_WAITING_FOR_RESPONDER_HASH;
+        break;
+
+      case RESPONDER_AFTER_INITIATOR_HASH:
+        nextMessage = makeSharedKeyHashMessage(false /* is initiator */, null /* no payload */);
+        handshakeState = State.HANDSHAKE_FINISHED;
+        break;
+
+      default:
+        throw new HandshakeException("Cannot get next message in state: " + handshakeState);
+    }
+
+    return nextMessage;
+  }
+
+  @Override
+  public byte[] getNextHandshakeMessage(byte[] payload) throws HandshakeException {
+    byte[] nextMessage;
+
+    switch (handshakeState) {
+      case RESPONDER_AFTER_INITIATOR_HASH:
+        nextMessage = makeSharedKeyHashMessage(false /* is initiator */, payload);
+        handshakeState = State.HANDSHAKE_FINISHED;
+        break;
+
+      default:
+        throw new HandshakeException(
+            "Cannot send handshake message with payload in state: " + handshakeState);
+    }
+
+    return nextMessage;
+  }
+
+  private byte[] makeCommitmentPointMessage(boolean isInitiator) throws HandshakeException {
+    try {
+      ourCommitmentPointExtended =
+          Ed25519.scalarMultiplyExtendedPoint(isInitiator ? KM : KN, passwordHash);
+      ourCommitmentPointExtended = Ed25519.addExtendedPoints(ourCommitmentPointExtended, pointX);
+      ourCommitmentPointAffine = Ed25519.toAffine(ourCommitmentPointExtended);
+
+      return SpakeHandshakeMessage.newBuilder()
+          .setEcPoint(
+              EcPoint.newBuilder()
+                .setCurve(DeviceToDeviceMessagesProto.Curve.ED_25519)
+                .setX(ByteString.copyFrom(ourCommitmentPointAffine[0].toByteArray()))
+                .setY(ByteString.copyFrom(ourCommitmentPointAffine[1].toByteArray()))
+                .build())
+          .setFlowNumber(isInitiator ? 1 : 2 /* first or second message */)
+          .build()
+          .toByteArray();
+    } catch (Ed25519Exception e) {
+      throw new HandshakeException("Could not make commitment point message", e);
+    }
+  }
+
+  private void makeSharedKey(boolean isInitiator) throws HandshakeException {
+
+    if (handshakeState != State.RESPONDER_START
+        && handshakeState != State.INITIATOR_WAITING_FOR_RESPONDER_COMMITMENT) {
+      throw new HandshakeException("Cannot make shared key in state: " + handshakeState);
+    }
+
+    try {
+      BigInteger[] kNMP = Ed25519.scalarMultiplyExtendedPoint(isInitiator ? KN : KM, passwordHash);
+
+      // TheirPublicKey = TheirCommitment - kNMP = (TheirPublicKey + kNMP) - kNMP
+      BigInteger[] theirPublicKey =
+          Ed25519.subtractExtendedPoints(theirCommitmentPointExtended, kNMP);
+
+      BigInteger[] sharedKeyPoint = Ed25519.scalarMultiplyExtendedPoint(theirPublicKey, valueX);
+      sharedKey = hash(pointToByteArray(Ed25519.toAffine(sharedKeyPoint)));
+    } catch (Ed25519Exception e) {
+      throw new HandshakeException("Error computing shared key", e);
+    }
+  }
+
+  private byte[] makeSharedKeyHashMessage(boolean isInitiator, byte[] payload)
+      throws HandshakeException {
+    SpakeHandshakeMessage.Builder handshakeMessage = SpakeHandshakeMessage.newBuilder()
+        .setHashValue(ByteString.copyFrom(computeOurKeyHash(isInitiator)))
+        .setFlowNumber(isInitiator ? 3 : 4 /* third or fourth message */);
+
+    if (canSendPayloadInHandshakeMessage() && payload != null) {
+      DeviceToDeviceMessage deviceToDeviceMessage =
+          D2DConnectionContext.createDeviceToDeviceMessage(payload, 1 /* sequence number */);
+      try {
+        handshakeMessage.setPayload(ByteString.copyFrom(
+            D2DCryptoOps.signcryptPayload(
+              new Payload(PayloadType.DEVICE_TO_DEVICE_RESPONDER_HELLO_PAYLOAD,
+                  deviceToDeviceMessage.toByteArray()),
+              new SecretKeySpec(sharedKey, "AES"))));
+      } catch (InvalidKeyException | NoSuchAlgorithmException e) {
+        throw new HandshakeException("Cannot set payload", e);
+      }
+    }
+
+    return handshakeMessage.build().toByteArray();
+  }
+
+  private byte[] computeOurKeyHash(boolean isInitiator) throws HandshakeException {
+    return hash(concat(
+        new byte[] { (byte) (isInitiator ? 0 : 1) },
+        pointToByteArray(theirCommitmentPointAffine),
+        pointToByteArray(ourCommitmentPointAffine),
+        sharedKey));
+  }
+
+  private byte[] computeTheirKeyHash(boolean isInitiator) throws HandshakeException {
+    return hash(concat(
+        new byte[] { (byte) (isInitiator ? 1 : 0) },
+        pointToByteArray(ourCommitmentPointAffine),
+        pointToByteArray(theirCommitmentPointAffine),
+        sharedKey));
+  }
+
+  private byte[] pointToByteArray(BigInteger[] p) {
+    return concat(p[0].toByteArray(), p[1].toByteArray());
+  }
+
+  @Override
+  public boolean canSendPayloadInHandshakeMessage() {
+    return handshakeState == State.RESPONDER_AFTER_INITIATOR_HASH;
+  }
+
+  @Override
+  public byte[] parseHandshakeMessage(byte[] handshakeMessage) throws HandshakeException {
+    if (handshakeMessage == null || handshakeMessage.length == 0) {
+      throw new HandshakeException("Handshake message too short");
+    }
+
+    byte[] payload = new byte[0];
+
+    switch(handshakeState) {
+      case RESPONDER_START:
+        // no payload can be sent in this message
+        parseCommitmentMessage(handshakeMessage, false /* is initiator */);
+        makeSharedKey(false /* is initiator */);
+        handshakeState = State.RESPONDER_AFTER_INITIATOR_COMMITMENT;
+        break;
+
+      case INITIATOR_WAITING_FOR_RESPONDER_COMMITMENT:
+        // no payload can be sent in this message
+        parseCommitmentMessage(handshakeMessage, true /* is initiator */);
+        makeSharedKey(true /* is initiator */);
+        handshakeState = State.INITIATOR_AFTER_RESPONDER_COMMITMENT;
+        break;
+
+      case RESPONDER_WAITING_FOR_INITIATOR_HASH:
+        // no payload can be sent in this message
+        parseHashMessage(handshakeMessage, false /* is initiator */);
+        handshakeState = State.RESPONDER_AFTER_INITIATOR_HASH;
+        break;
+
+      case INITIATOR_WAITING_FOR_RESPONDER_HASH:
+        payload = parseHashMessage(handshakeMessage, true /* is initiator */);
+        handshakeState = State.HANDSHAKE_FINISHED;
+        break;
+
+      default:
+        throw new HandshakeException("Cannot parse message in state: " + handshakeState);
+    }
+
+    return payload;
+  }
+
+  private byte[] parseHashMessage(byte[] handshakeMessage, boolean isInitiator)
+      throws HandshakeException {
+    SpakeHandshakeMessage hashMessage;
+
+    // Parse the message
+    try {
+      hashMessage = SpakeHandshakeMessage.parseFrom(handshakeMessage);
+    } catch (InvalidProtocolBufferException e) {
+      throw new HandshakeException("Could not parse hash message", e);
+    }
+
+    // Check flow number
+    if (!hashMessage.hasFlowNumber()) {
+      throw new HandshakeException("Hash message missing flow number");
+    }
+    int expectedFlowNumber = isInitiator ? 4 : 3;
+    int actualFlowNumber = hashMessage.getFlowNumber();
+    if (actualFlowNumber != expectedFlowNumber) {
+      throw new HandshakeException("Hash message has flow number " + actualFlowNumber
+          + ", but expected flow number " + expectedFlowNumber);
+    }
+
+    // Check and extract hash
+    if (!hashMessage.hasHashValue()) {
+      throw new HandshakeException("Hash message missing hash value");
+    }
+
+    byte[] theirHash = hashMessage.getHashValue().toByteArray();
+    byte[] theirCorrectHash = computeTheirKeyHash(isInitiator);
+
+    if (!constantTimeArrayEquals(theirCorrectHash, theirHash)) {
+      throw new HandshakeException("Hash message had incorrect hash value");
+    }
+
+    if (isInitiator && hashMessage.hasPayload()) {
+      try {
+        DeviceToDeviceMessage message = D2DCryptoOps.decryptResponderHelloMessage(
+            new SecretKeySpec(sharedKey, "AES"),
+            hashMessage.getPayload().toByteArray());
+
+        if (message.getSequenceNumber() != 1) {
+          throw new HandshakeException("Incorrect sequence number in responder hello");
+        }
+
+        return message.getMessage().toByteArray();
+
+      } catch (SignatureException e) {
+        throw new HandshakeException("Error recovering payload from hash message", e);
+      }
+    }
+
+    // empty/no payload
+    return new byte[0];
+  }
+
+  private void parseCommitmentMessage(byte[] handshakeMessage, boolean isInitiator)
+      throws HandshakeException {
+    SpakeHandshakeMessage commitmentMessage;
+
+    // Parse the message
+    try {
+      commitmentMessage = SpakeHandshakeMessage.parseFrom(handshakeMessage);
+    } catch (InvalidProtocolBufferException e) {
+      throw new HandshakeException("Could not parse commitment message", e);
+    }
+
+    // Check flow number
+    if (!commitmentMessage.hasFlowNumber()) {
+      throw new HandshakeException("Commitment message missing flow number");
+    }
+    if (commitmentMessage.getFlowNumber() != (isInitiator ? 2 : 1)) {
+      throw new HandshakeException("Commitment message has wrong flow number");
+    }
+
+    // Check point and curve; and extract point
+    if (!commitmentMessage.hasEcPoint()) {
+      throw new HandshakeException("Commitment message missing point");
+    }
+    EcPoint commitmentPoint = commitmentMessage.getEcPoint();
+    if (!commitmentPoint.hasCurve()
+        || commitmentPoint.getCurve() != DeviceToDeviceMessagesProto.Curve.ED_25519) {
+      throw new HandshakeException("Commitment message has wrong curve");
+    }
+
+    if (!commitmentPoint.hasX()) {
+      throw new HandshakeException("Commitment point missing x coordinate");
+    }
+
+    if (!commitmentPoint.hasY()) {
+      throw new HandshakeException("Commitment point missing y coordinate");
+    }
+
+    // Build the point
+    theirCommitmentPointAffine = new BigInteger[] {
+        new BigInteger(commitmentPoint.getX().toByteArray()),
+        new BigInteger(commitmentPoint.getY().toByteArray())
+    };
+
+    // Validate the point to be sure
+    try {
+      Ed25519.validateAffinePoint(theirCommitmentPointAffine);
+      theirCommitmentPointExtended = Ed25519.toExtended(theirCommitmentPointAffine);
+    } catch (Ed25519Exception e) {
+      throw new HandshakeException("Error validating their commitment point", e);
+    }
+  }
+
+  @Override
+  public D2DConnectionContext toConnectionContext() throws HandshakeException {
+    if (handshakeState == State.HANDSHAKE_ALREADY_USED) {
+      throw new HandshakeException("Cannot reuse handshake context; is has already been used");
+    }
+
+    if (!isHandshakeComplete()) {
+      throw new HandshakeException("Handshake is not complete; cannot create connection context");
+    }
+
+    handshakeState = State.HANDSHAKE_ALREADY_USED;
+
+    // Both sides start with an initial sequence number of 1 because the last message of the
+    // handshake had an optional payload with sequence number 1.  D2DConnectionContext remembers
+    // the last sequence number used.
+    return new D2DConnectionContextV0(
+        new SecretKeySpec(sharedKey, "AES"), 1 /* initialSequenceNumber */);
+  }
+
+  /**
+   * Implementation of byte array concatenation copied from Guava.
+   */
+  private static byte[] concat(byte[]... arrays) {
+    int length = 0;
+    for (byte[] array : arrays) {
+      length += array.length;
+    }
+
+    byte[] result = new byte[length];
+    int pos = 0;
+    for (byte[] array : arrays) {
+      System.arraycopy(array, 0, result, pos, array.length);
+      pos += array.length;
+    }
+
+    return result;
+  }
+
+  private static byte[] hash(byte[] message) throws HandshakeException {
+    try {
+      return MessageDigest.getInstance(SHA256).digest(message);
+    } catch (NoSuchAlgorithmException e) {
+      throw new HandshakeException("Error performing hash", e);
+    }
+  }
+
+  private static boolean constantTimeArrayEquals(byte[] a, byte[] b) {
+    if (a == null || b == null) {
+      return (a == b);
+    }
+    if (a.length != b.length) {
+      return false;
+    }
+    byte result = 0;
+    for (int i = 0; i < b.length; i++) {
+      result = (byte) (result | (a[i] ^ b[i]));
+    }
+    return (result == 0);
+  }
+}
diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/Ed25519.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/Ed25519.java
index 454b942..2ea2563 100644
--- a/src/main/java/com/google/security/cryptauth/lib/securegcm/Ed25519.java
+++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/Ed25519.java
@@ -1,23 +1,24 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.security.cryptauth.lib.securegcm;
 
 import static java.math.BigInteger.ONE;
 import static java.math.BigInteger.ZERO;
 
 import com.google.common.annotations.VisibleForTesting;
+
 import java.math.BigInteger;
 
 /**
@@ -207,20 +208,20 @@
     };
   }
 
-  /** Converts a point in affine representation to extended representation */
-  // TODO(b/120887495): This @VisibleForTesting annotation was being ignored by prod code.
-  // Please check that removing it is correct, and remove this comment along with it.
-  // @VisibleForTesting
+  /**
+   * Converts a point in affine representation to extended representation
+   */
+  @VisibleForTesting
   static BigInteger[] toExtended(BigInteger[] p) throws Ed25519Exception {
     checkPointIsInAffineRepresentation(p);
 
     return new BigInteger[] {p[X], p[Y], ONE, p[X].multiply(p[Y]).mod(Ed25519_P)}; // x, y, 1, x*y
   }
 
-  /** Converts a point in extended representation to affine representation */
-  // TODO(b/120887495): This @VisibleForTesting annotation was being ignored by prod code.
-  // Please check that removing it is correct, and remove this comment along with it.
-  // @VisibleForTesting
+  /**
+   * Converts a point in extended representation to affine representation
+   */
+  @VisibleForTesting
   static BigInteger[] toAffine(BigInteger[] p) throws Ed25519Exception {
     checkPointIsInExtendedRepresentation(p);
 
diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/EnrollmentCryptoOps.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/EnrollmentCryptoOps.java
index 450c806..328cb53 100644
--- a/src/main/java/com/google/security/cryptauth/lib/securegcm/EnrollmentCryptoOps.java
+++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/EnrollmentCryptoOps.java
@@ -1,17 +1,17 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.security.cryptauth.lib.securegcm;
 
 import com.google.protobuf.InvalidProtocolBufferException;
diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/HandshakeException.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/HandshakeException.java
index b717eb6..bb5fffc 100644
--- a/src/main/java/com/google/security/cryptauth/lib/securegcm/HandshakeException.java
+++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/HandshakeException.java
@@ -1,17 +1,17 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.security.cryptauth.lib.securegcm;
 
 /**
diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/KeyEncoding.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/KeyEncoding.java
index 67e4ace..9690a89 100644
--- a/src/main/java/com/google/security/cryptauth/lib/securegcm/KeyEncoding.java
+++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/KeyEncoding.java
@@ -1,17 +1,17 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.security.cryptauth.lib.securegcm;
 
 import com.google.protobuf.InvalidProtocolBufferException;
@@ -58,10 +58,6 @@
     return sk.getEncoded();
   }
 
-  public static byte[] encodeDeviceSyncGroupPublicKey(PublicKey pk) {
-    return PublicKeyProtoUtil.encodePaddedEcPublicKey(pk).toByteArray();
-  }
-
   public static PrivateKey parseUserPrivateKey(byte[] encodedPrivateKey, boolean isLegacy)
       throws InvalidKeySpecException {
     PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
@@ -75,11 +71,6 @@
     return parsePublicKey(keyBytes);
   }
 
-  public static PublicKey parseDeviceSyncGroupPublicKey(byte[] keyBytes)
-      throws InvalidKeySpecException {
-    return parsePublicKey(keyBytes);
-  }
-
   public static byte[] encodeKeyAgreementPublicKey(PublicKey pk) {
     return encodePublicKey(pk);
   }
diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/SecureGcmConstants.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/SecureGcmConstants.java
index a69431f..8482628 100644
--- a/src/main/java/com/google/security/cryptauth/lib/securegcm/SecureGcmConstants.java
+++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/SecureGcmConstants.java
@@ -1,17 +1,17 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.security.cryptauth.lib.securegcm;
 
 /**
diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/TransportCryptoOps.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/TransportCryptoOps.java
index b053bf4..a22edc4 100644
--- a/src/main/java/com/google/security/cryptauth/lib/securegcm/TransportCryptoOps.java
+++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/TransportCryptoOps.java
@@ -1,17 +1,17 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.security.cryptauth.lib.securegcm;
 
 import com.google.protobuf.InvalidProtocolBufferException;
diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/Ukey2Handshake.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/Ukey2Handshake.java
index 8e00ea9..0d01c9a 100644
--- a/src/main/java/com/google/security/cryptauth/lib/securegcm/Ukey2Handshake.java
+++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/Ukey2Handshake.java
@@ -1,17 +1,17 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.security.cryptauth.lib.securegcm;
 
 import com.google.protobuf.ByteString;
diff --git a/src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java b/src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java
index 876bd93..1e3b196 100644
--- a/src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java
+++ b/src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java
@@ -1,17 +1,17 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.security.cryptauth.lib.securemessage;
 
 import com.google.security.annotations.SuppressInsecureCipherModeCheckerReviewed;
@@ -132,6 +132,7 @@
    * A salt value specific to this library, generated as SHA-256("SecureMessage")
    */
   private static final byte[] SALT = sha256("SecureMessage");
+  private static final byte[] CONSTANT_01 = { 0x01 };  // For convenience
 
   /**
    * Signs {@code data} using the algorithm specified by {@code sigType} with {@code signingKey}.
@@ -411,31 +412,10 @@
    */
   public static byte[] hkdf(SecretKey inputKeyMaterial, byte[] salt, byte[] info)
       throws NoSuchAlgorithmException, InvalidKeyException {
-    return hkdf(inputKeyMaterial, salt, info, /* length= */ 32);
-  }
-
-  /**
-   * Implements HKDF (RFC 5869) with the SHA-256 hash.
-   *
-   * <p>Please make sure to select a salt that is fixed and unique for your codebase, and use the
-   * {@code info} parameter to specify any additional bits that should influence the derived key.
-   *
-   * @param inputKeyMaterial master key from which to derive sub-keys
-   * @param salt a (public) randomly generated 256-bit input that can be re-used
-   * @param info arbitrary information that is bound to the derived key (i.e., used in its creation)
-   * @param length length of returned key material
-   * @return raw derived key bytes = HKDF-SHA256(inputKeyMaterial, salt, info)
-   * @throws InvalidKeyException if the encoded form of {@code inputKeyMaterial} cannot be accessed
-   */
-  public static byte[] hkdf(SecretKey inputKeyMaterial, byte[] salt, byte[] info, int length)
-      throws NoSuchAlgorithmException, InvalidKeyException {
     if ((inputKeyMaterial == null) || (salt == null) || (info == null)) {
       throw new NullPointerException();
     }
-    if (length < 0) {
-      throw new IllegalArgumentException("Length must be positive");
-    }
-    return hkdfSha256Expand(hkdfSha256Extract(inputKeyMaterial, salt), info, length);
+    return hkdfSha256Expand(hkdfSha256Extract(inputKeyMaterial, salt), info);
   }
 
   /**
@@ -484,12 +464,12 @@
   }
 
   /**
-   * The HKDF (RFC 5869) extraction function, using the SHA-256 hash function. This function is used
-   * to pre-process the inputKeyMaterial and mix it with the salt, producing output suitable for use
-   * with HKDF expansion function (which produces the actual derived key).
+   * The HKDF (RFC 5869) extraction function, using the SHA-256 hash function. This function is
+   * used to pre-process the inputKeyMaterial and mix it with the salt, producing output suitable
+   * for use with HKDF expansion function (which produces the actual derived key).
    *
-   * @see #hkdfSha256Expand(byte[], byte[], int)
-   * @return HMAC-SHA256(salt, inputKeyMaterial) (salt is the "key" for the HMAC)
+   * @see #hkdfSha256Expand(byte[], byte[])
+   * @return HMAC-SHA256(salt, inputKeyMaterial)  (salt is the "key" for the HMAC)
    * @throws InvalidKeyException if the encoded form of {@code inputKeyMaterial} cannot be accessed
    * @throws NoSuchAlgorithmException if the HmacSHA256 or AES algorithms are unavailable
    */
@@ -511,15 +491,15 @@
   }
 
   /**
-   * HKDF (RFC 5869) expansion function, using the SHA-256 hash function.
+   * Special case of HKDF (RFC 5869) expansion function, using the SHA-256 hash function and
+   * allowing for a maximum output length of 256 bits.
    *
-   * @param pseudoRandomKey should be generated by {@link #hkdfSha256Extract(SecretKey, byte[])}
+   * @param pseudoRandomKey should be generated by {@link #hkdfSha256Expand(byte[], byte[])}
    * @param info arbitrary information the derived key should be bound to
-   * @param length length of the output key material in bytes
    * @return raw derived key bytes = HMAC-SHA256(pseudoRandomKey, info | 0x01)
    * @throws NoSuchAlgorithmException if the HmacSHA256 or AES algorithms are unavailable
    */
-  private static byte[] hkdfSha256Expand(byte[] pseudoRandomKey, byte[] info, int length)
+  private static byte[] hkdfSha256Expand(byte[] pseudoRandomKey, byte[] info)
       throws NoSuchAlgorithmException {
     Mac macScheme = Mac.getInstance("HmacSHA256");
     try {
@@ -527,38 +507,11 @@
     } catch (InvalidKeyException e) {
       throw new AssertionError(e);  // This should never happen
     }
-
-    // Number of blocks N = ceil(hash length / output length).
-    int blocks = length / 32;
-    if (length % 32 > 0) {
-      blocks += 1;
-    }
-
-    // The counter used to generate the blocks according to the RFC is only one byte long,
-    // which puts a limit on the number of blocks possible.
-    if (blocks > 0xFF) {
-      throw new IllegalArgumentException("Maximum HKDF output length exceeded.");
-    }
-
-    byte[] outputBlock = new byte[32];
-    byte[] counter = new byte[1];
-    byte[] output = new byte[32 * blocks];
-    for (int i = 0; i < blocks; ++i) {
-      macScheme.reset();
-      if (i > 0) {
-        // Previous block
-        macScheme.update(outputBlock);
-      }
-      // Arbitrary info
-      macScheme.update(info);
-      // Counter
-      counter[0] = (byte) (i + 1);
-      outputBlock = macScheme.doFinal(counter);
-
-      System.arraycopy(outputBlock, 0, output, 32 * i, 32);
-    }
-
-    return subarray(output, 0, length);
+    // Arbitrary "info" to be included in the MAC.
+    macScheme.update(info);
+    // Note that RFC 5869 computes number of blocks N = ceil(hash length / output length), but
+    // here we only deal with a 256 bit hash up to a 256 bit output, yielding N=1.
+    return macScheme.doFinal(CONSTANT_01);
   }
 
 }
diff --git a/src/main/java/com/google/security/cryptauth/lib/securemessage/PublicKeyProtoUtil.java b/src/main/java/com/google/security/cryptauth/lib/securemessage/PublicKeyProtoUtil.java
index 0c593fe..ab97cca 100644
--- a/src/main/java/com/google/security/cryptauth/lib/securemessage/PublicKeyProtoUtil.java
+++ b/src/main/java/com/google/security/cryptauth/lib/securemessage/PublicKeyProtoUtil.java
@@ -1,20 +1,19 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.security.cryptauth.lib.securemessage;
 
-import com.google.common.collect.Lists;
 import com.google.protobuf.ByteString;
 import com.google.security.annotations.SuppressInsecureCipherModeCheckerPendingReview;
 import com.google.security.cryptauth.lib.securemessage.SecureMessageProto.DhPublicKey;
@@ -195,37 +194,6 @@
   }
 
   /**
-   * Encodes an {@link ECPublicKey} to an {@link GenericPublicKey} proto message. The returned key
-   * has a null-byte padded to the front in order to match the C++ implementation.
-   */
-  public static GenericPublicKey encodePaddedEcPublicKey(PublicKey pk) {
-    if (pk == null) {
-      throw new NullPointerException();
-    }
-    if (!(pk instanceof ECPublicKey)) {
-      throw new IllegalArgumentException("Expected ECPublicKey PublicKey type");
-    }
-
-    ECPublicKey epk = pkToECPublicKey(pk);
-    ByteString nullByteString = ByteString.copyFrom(new byte[] {0});
-    ByteString xByteString = extractX(epk);
-    if (xByteString.size() < MAX_P256_ENCODING_BYTES) {
-      xByteString = ByteString.copyFrom(Lists.newArrayList(nullByteString, xByteString));
-    }
-    ByteString yByteString = extractY(epk);
-    if (yByteString.size() < MAX_P256_ENCODING_BYTES) {
-      yByteString = ByteString.copyFrom(Lists.newArrayList(nullByteString, yByteString));
-    }
-    EcP256PublicKey newKey =
-        EcP256PublicKey.newBuilder().setX(xByteString).setY(yByteString).build();
-
-    return GenericPublicKey.newBuilder()
-        .setType(SecureMessageProto.PublicKeyType.EC_P256)
-        .setEcP256PublicKey(newKey)
-        .build();
-  }
-
-  /**
    * Encodes an {@link ECPublicKey} to an {@link EcP256PublicKey} proto message.
    */
   public static EcP256PublicKey encodeEcPublicKey(PublicKey pk) {
diff --git a/src/main/java/com/google/security/cryptauth/lib/securemessage/SecureMessageBuilder.java b/src/main/java/com/google/security/cryptauth/lib/securemessage/SecureMessageBuilder.java
index f1a9464..f59ce4e 100644
--- a/src/main/java/com/google/security/cryptauth/lib/securemessage/SecureMessageBuilder.java
+++ b/src/main/java/com/google/security/cryptauth/lib/securemessage/SecureMessageBuilder.java
@@ -1,17 +1,17 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.security.cryptauth.lib.securemessage;
 
 import com.google.protobuf.ByteString;
diff --git a/src/main/java/com/google/security/cryptauth/lib/securemessage/SecureMessageParser.java b/src/main/java/com/google/security/cryptauth/lib/securemessage/SecureMessageParser.java
index d634d40..e1c60e3 100644
--- a/src/main/java/com/google/security/cryptauth/lib/securemessage/SecureMessageParser.java
+++ b/src/main/java/com/google/security/cryptauth/lib/securemessage/SecureMessageParser.java
@@ -1,17 +1,17 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.google.security.cryptauth.lib.securemessage;
 
 import com.google.protobuf.ByteString;
diff --git a/src/main/javatest/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextTest.java b/src/main/javatest/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextTest.java
deleted file mode 100644
index e671e8c..0000000
--- a/src/main/javatest/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextTest.java
+++ /dev/null
@@ -1,568 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.security.cryptauth.lib.securegcm;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.security.SignatureException;
-import java.util.Arrays;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-/**
- * Base class for Android compatible tests for {@link D2DConnectionContext} subclasses.
- * Note: We would use a Parameterized test runner to test different versions, but this
- * functionality is not supported by Android tests.
- */
-@RunWith(JUnit4.class)
-public class D2DConnectionContextTest {
-  private static final String PING = "ping";
-  private static final String PONG = "pong";
-
-  // Key is: "initiator_encode_key_for_aes_256"
-  private static final SecretKey INITIATOR_ENCODE_KEY = new SecretKeySpec(
-      new byte[] {
-          (byte) 0x69, (byte) 0x6e, (byte) 0x69, (byte) 0x74, (byte) 0x69, (byte) 0x61, (byte) 0x74,
-          (byte) 0x6f, (byte) 0x72, (byte) 0x5f, (byte) 0x65, (byte) 0x6e, (byte) 0x63, (byte) 0x6f,
-          (byte) 0x64, (byte) 0x65, (byte) 0x5f, (byte) 0x6b, (byte) 0x65, (byte) 0x79, (byte) 0x5f,
-          (byte) 0x66, (byte) 0x6f, (byte) 0x72, (byte) 0x5f, (byte) 0x61, (byte) 0x65, (byte) 0x73,
-          (byte) 0x5f, (byte) 0x32, (byte) 0x35, (byte) 0x36
-      },
-      "AES");
-
-  // Key is: "initiator_decode_key_for_aes_256"
-  private static final SecretKey INITIATOR_DECODE_KEY = new SecretKeySpec(
-      new byte[] {
-          (byte) 0x69, (byte) 0x6e, (byte) 0x69, (byte) 0x74, (byte) 0x69, (byte) 0x61, (byte) 0x74,
-          (byte) 0x6f, (byte) 0x72, (byte) 0x5f, (byte) 0x64, (byte) 0x65, (byte) 0x63, (byte) 0x6f,
-          (byte) 0x64, (byte) 0x65, (byte) 0x5f, (byte) 0x6b, (byte) 0x65, (byte) 0x79, (byte) 0x5f,
-          (byte) 0x66, (byte) 0x6f, (byte) 0x72, (byte) 0x5f, (byte) 0x61, (byte) 0x65, (byte) 0x73,
-          (byte) 0x5f, (byte) 0x32, (byte) 0x35, (byte) 0x36
-      },
-      "AES");
-
-  private D2DConnectionContext initiatorCtx;
-  private D2DConnectionContext responderCtx;
-
-  @Before
-  public void setUp() throws Exception {
-    KeyEncodingTest.installSunEcSecurityProviderIfNecessary();
-  }
-
-  protected void testPeerToPeerProtocol(int protocolVersion) throws Exception {
-
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    initiatorCtx = createConnectionContext(protocolVersion, true /** isInitiator */);
-    responderCtx = createConnectionContext(protocolVersion, false /** isInitiator */);
-
-    byte[] pingMessage = initiatorCtx.encodeMessageToPeer(PING);
-    // (send message to responder)
-
-    // responder
-    String messageStr = responderCtx.decodeMessageFromPeerAsString(pingMessage);
-    assertEquals(PING, messageStr);
-
-    byte[] pongMessage = responderCtx.encodeMessageToPeer(PONG);
-    // (send message to initiator)
-
-    // initiator
-    messageStr = initiatorCtx.decodeMessageFromPeerAsString(pongMessage);
-    assertEquals(PONG, messageStr);
-
-    // let's make sure there is actually some crypto involved.
-    pingMessage = initiatorCtx.encodeMessageToPeer("can you see this?");
-    pingMessage[2] = (byte) (pingMessage[2] + 1); // twiddle with the message
-    try {
-      responderCtx.decodeMessageFromPeerAsString(pingMessage);
-      fail("expected exception, but didn't get it");
-    } catch (SignatureException expected) {
-      assertTrue(expected.getMessage().contains("failed verification"));
-    }
-
-    // Try and replay the previous encoded message to the initiator (replays should not work).
-    try {
-      initiatorCtx.decodeMessageFromPeerAsString(pongMessage);
-      fail("expected exception, but didn't get it");
-    } catch (SignatureException expected) {
-      assertTrue(expected.getMessage().contains("sequence"));
-    }
-
-    assertEquals(protocolVersion, initiatorCtx.getProtocolVersion());
-    assertEquals(protocolVersion, responderCtx.getProtocolVersion());
-  }
-
-  @Test
-  public void testPeerToPeerProtocol_V0() throws Exception {
-    testPeerToPeerProtocol(D2DConnectionContextV0.PROTOCOL_VERSION);
-  }
-
-  @Test
-  public void testPeerToPeerProtocol_V1() throws Exception {
-    testPeerToPeerProtocol(D2DConnectionContextV1.PROTOCOL_VERSION);
-  }
-
-  protected void testResponderSendsFirst(int protocolVersion) throws Exception {
-
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    initiatorCtx = createConnectionContext(protocolVersion, true /** isInitiator */);
-    responderCtx = createConnectionContext(protocolVersion, false /** isInitiator */);
-
-    byte[] pongMessage = responderCtx.encodeMessageToPeer(PONG);
-    assertEquals(PONG, initiatorCtx.decodeMessageFromPeerAsString(pongMessage));
-
-    pongMessage = responderCtx.encodeMessageToPeer(PONG);
-    assertEquals(PONG, initiatorCtx.decodeMessageFromPeerAsString(pongMessage));
-
-    // for good measure, if the initiator now responds, it should also work:
-    byte[] pingMessage = initiatorCtx.encodeMessageToPeer(PING);
-    assertEquals(PING, responderCtx.decodeMessageFromPeerAsString(pingMessage));
-
-    pingMessage = initiatorCtx.encodeMessageToPeer(PING);
-    assertEquals(PING, responderCtx.decodeMessageFromPeerAsString(pingMessage));
-
-    pingMessage = initiatorCtx.encodeMessageToPeer(PING);
-    assertEquals(PING, responderCtx.decodeMessageFromPeerAsString(pingMessage));
-  }
-
-  @Test
-  public void testResponderSendsFirst_V0() throws Exception {
-    testResponderSendsFirst(D2DConnectionContextV0.PROTOCOL_VERSION);
-  }
-
-  @Test
-  public void testResponderSendsFirst_V1() throws Exception {
-    testResponderSendsFirst(D2DConnectionContextV1.PROTOCOL_VERSION);
-  }
-
-  protected void testAssymmetricFlows(int protocolVersion) throws Exception {
-
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    initiatorCtx = createConnectionContext(protocolVersion, true /** isInitiator */);
-    responderCtx = createConnectionContext(protocolVersion, false /** isInitiator */);
-
-    // Let's test that this still works if one side sends a few messages in a row.
-    byte[] pingMessage = initiatorCtx.encodeMessageToPeer(PING);
-    assertEquals(PING, responderCtx.decodeMessageFromPeerAsString(pingMessage));
-
-    pingMessage = initiatorCtx.encodeMessageToPeer(PING);
-    assertEquals(PING, responderCtx.decodeMessageFromPeerAsString(pingMessage));
-
-    pingMessage = initiatorCtx.encodeMessageToPeer(PING);
-    assertEquals(PING, responderCtx.decodeMessageFromPeerAsString(pingMessage));
-
-
-    byte[] pongMessage = responderCtx.encodeMessageToPeer(PONG);
-    assertEquals(PONG, initiatorCtx.decodeMessageFromPeerAsString(pongMessage));
-
-    pongMessage = responderCtx.encodeMessageToPeer(PONG);
-    assertEquals(PONG, initiatorCtx.decodeMessageFromPeerAsString(pongMessage));
-  }
-
-  @Test
-  public void testAssymmetricFlows_V0() throws Exception {
-    testAssymmetricFlows(D2DConnectionContextV0.PROTOCOL_VERSION);
-  }
-
-  @Test
-  public void testAssymmetricFlows_V1() throws Exception {
-    testAssymmetricFlows(D2DConnectionContextV1.PROTOCOL_VERSION);
-  }
-
-  public void testErrorWhenResponderResendsMessage(int protocolVersion) throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    initiatorCtx = createConnectionContext(protocolVersion, true /** isInitiator */);
-    responderCtx = createConnectionContext(protocolVersion, false /** isInitiator */);
-
-    byte[] pongMessage = responderCtx.encodeMessageToPeer(PONG);
-    assertEquals(PONG, initiatorCtx.decodeMessageFromPeerAsString(pongMessage));
-
-    try {
-      // send pongMessage again to the initiator
-      initiatorCtx.decodeMessageFromPeerAsString(pongMessage);
-      fail("expected exception, but didn't get it");
-    } catch (SignatureException expected) {
-      assertTrue(expected.getMessage().contains("sequence"));
-    }
-  }
-
-  @Test
-  public void testErrorWhenResponderResendsMessage_V0() throws Exception {
-    testErrorWhenResponderResendsMessage(D2DConnectionContextV0.PROTOCOL_VERSION);
-  }
-
-  @Test
-  public void testErrorWhenResponderResendsMessage_V1() throws Exception {
-    testErrorWhenResponderResendsMessage(D2DConnectionContextV1.PROTOCOL_VERSION);
-  }
-
-  protected void testErrorWhenResponderEchoesInitiatorMessage(
-      int protocolVersion) throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      return;
-    }
-
-    initiatorCtx = createConnectionContext(protocolVersion, true /** isInitiator */);
-    responderCtx = createConnectionContext(protocolVersion, false /** isInitiator */);
-
-    byte[] pingMessage = initiatorCtx.encodeMessageToPeer(PING);
-    assertEquals(PING, responderCtx.decodeMessageFromPeerAsString(pingMessage));
-
-    try {
-      initiatorCtx.decodeMessageFromPeerAsString(pingMessage);
-      fail("expected exception, but didn't get it");
-    } catch (SignatureException expected) {
-    }
-  }
-
-  @Test
-  public void testErrorWhenResponderEchoesInitiatorMessage_V0() throws Exception {
-    testErrorWhenResponderEchoesInitiatorMessage(D2DConnectionContextV0.PROTOCOL_VERSION);
-  }
-
-  @Test
-  public void testErrorWhenResponderEchoesInitiatorMessage_V1() throws Exception {
-    testErrorWhenResponderEchoesInitiatorMessage(D2DConnectionContextV1.PROTOCOL_VERSION);
-  }
-
-  @Test
-  public void testErrorUsingV1InitiatorWithV0Responder() throws SignatureException {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    initiatorCtx = new D2DConnectionContextV1(INITIATOR_ENCODE_KEY, INITIATOR_DECODE_KEY, 1, 1);
-    responderCtx = new D2DConnectionContextV0(INITIATOR_DECODE_KEY, 1);
-
-    // Decoding the responder's message should succeed, because the decode key and sequence numbers
-    // match.
-    initiatorCtx.decodeMessageFromPeer(responderCtx.encodeMessageToPeer(PING));
-
-    // Responder fails to decodes initiator's encoded message because keys do not match.
-    try {
-      responderCtx.decodeMessageFromPeer(initiatorCtx.encodeMessageToPeer(PONG));
-      fail("Expected verification to fail.");
-    } catch (SignatureException e) {
-      // Exception expected.
-    }
-  }
-
-  @Test
-  public void testErrorWithV0InitiatorV1Responder() throws SignatureException {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    initiatorCtx = new D2DConnectionContextV0(INITIATOR_ENCODE_KEY, 1);
-    responderCtx = new D2DConnectionContextV1(INITIATOR_DECODE_KEY, INITIATOR_ENCODE_KEY, 1, 1);
-
-    // Decoding the initiator's message should succeed, because the decode key and sequence numbers
-    // match.
-    responderCtx.decodeMessageFromPeer(initiatorCtx.encodeMessageToPeer(PING));
-
-    // Initiator fails to decodes responder's encoded message because keys do not match.
-    try {
-      initiatorCtx.decodeMessageFromPeer(responderCtx.encodeMessageToPeer(PONG));
-      fail("Expected verification to fail.");
-    } catch (SignatureException e) {
-      // Exception expected.
-    }
-  }
-
-  protected void testSessionUnique(int protocolVersion) throws Exception {
-    // Should be the same (we set them up with the same key and sequence number)
-    initiatorCtx = createConnectionContext(protocolVersion, true /** isInitiator */);
-    responderCtx = createConnectionContext(protocolVersion, false /** isInitiator */);
-    Assert.assertArrayEquals(initiatorCtx.getSessionUnique(), responderCtx.getSessionUnique());
-
-    // Change just the key (should not match)
-    SecretKey wrongKey = new SecretKeySpec("wrong".getBytes("UTF8"), "AES");
-    responderCtx = createConnectionContext(protocolVersion, false, wrongKey, wrongKey, 0, 1);
-    assertFalse(Arrays.equals(initiatorCtx.getSessionUnique(), responderCtx.getSessionUnique()));
-
-    // Change just the sequence number (should still match)
-    responderCtx = createConnectionContext(
-        protocolVersion, false, INITIATOR_ENCODE_KEY, INITIATOR_DECODE_KEY, 2, 2);
-    Assert.assertArrayEquals(initiatorCtx.getSessionUnique(), responderCtx.getSessionUnique());
-  }
-
-  @Test
-  public void testSessionUnique_V0() throws Exception {
-    testSessionUnique(D2DConnectionContextV0.PROTOCOL_VERSION);
-  }
-
-  @Test
-  public void testSessionUnique_V1() throws Exception {
-    testSessionUnique(D2DConnectionContextV1.PROTOCOL_VERSION);
-  }
-
-  @Test
-  public void testSessionUniqueValues_V0() throws Exception {
-    // The key and the session unique value should match ones in the equivalent test in
-    // @link {cs/Nearby/D2DCrypto/Tests/D2DConnectionContextTest.m}
-    byte[] key =
-        new byte[] {
-          (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07,
-          (byte) 0x08, (byte) 0x09, (byte) 0x0a, (byte) 0x0b, (byte) 0x0c, (byte) 0x0d, (byte) 0x0e,
-          (byte) 0x0f, (byte) 0x10, (byte) 0x11, (byte) 0x12, (byte) 0x13, (byte) 0x14, (byte) 0x15,
-          (byte) 0x16, (byte) 0x17, (byte) 0x18, (byte) 0x19, (byte) 0x1a, (byte) 0x1b, (byte) 0x1c,
-          (byte) 0x1d, (byte) 0x1e, (byte) 0x1f, (byte) 0x20
-        };
-    byte[] sessionUnique =
-        new byte[] {
-          (byte) 0x70, (byte) 0x7a, (byte) 0x17, (byte) 0x27, (byte) 0xa3, (byte) 0x0e, (byte) 0x68,
-          (byte) 0x63, (byte) 0x38, (byte) 0xdf, (byte) 0x72, (byte) 0x62, (byte) 0xf4, (byte) 0xb0,
-          (byte) 0x41, (byte) 0xac, (byte) 0x75, (byte) 0x8b, (byte) 0xca, (byte) 0x3b, (byte) 0x11,
-          (byte) 0xd4, (byte) 0x09, (byte) 0x64, (byte) 0x96, (byte) 0x54, (byte) 0xb4, (byte) 0x9b,
-          (byte) 0x43, (byte) 0xe6, (byte) 0x9b, (byte) 0xce
-        };
-
-    SecretKey secretKey = new SecretKeySpec(key, "AES");
-    D2DConnectionContext context = new D2DConnectionContextV0(secretKey, 1);
-
-    Assert.assertArrayEquals(context.getSessionUnique(), sessionUnique);
-  }
-
-  @Test
-  public void testSessionUniqueValues_V1_Initiator() throws Exception {
-    // The key and the session unique value should match ones in the equivalent test in
-    // @link {cs/Nearby/D2DCrypto/Tests/D2DConnectionContextTest.m}
-    byte[] sessionUnique =
-        new byte[] {
-          (byte) 0x91, (byte) 0xc7, (byte) 0xc9, (byte) 0x26, (byte) 0x2c, (byte) 0x17, (byte) 0x8a,
-          (byte) 0xa0, (byte) 0x36, (byte) 0x9f, (byte) 0xf2, (byte) 0x05, (byte) 0x20, (byte) 0x98,
-          (byte) 0x38, (byte) 0x53, (byte) 0xa5, (byte) 0x46, (byte) 0xab, (byte) 0x3a, (byte) 0x21,
-          (byte) 0x3b, (byte) 0x76, (byte) 0x58, (byte) 0x59, (byte) 0x4e, (byte) 0xe7, (byte) 0xe3,
-          (byte) 0xc1, (byte) 0x69, (byte) 0x87, (byte) 0xfa
-        };
-
-    D2DConnectionContext initiatorContext = new D2DConnectionContextV1(
-        INITIATOR_ENCODE_KEY, INITIATOR_DECODE_KEY, 0, 1);
-    D2DConnectionContext responderContext = new D2DConnectionContextV1(
-        INITIATOR_DECODE_KEY, INITIATOR_ENCODE_KEY, 1, 0);
-
-    // Both the initiator and responder must be the same.
-    Assert.assertArrayEquals(initiatorContext.getSessionUnique(), sessionUnique);
-    Assert.assertArrayEquals(responderContext.getSessionUnique(), sessionUnique);
-  }
-
-  @Test
-  public void testSaveSessionV0() throws Exception {
-    D2DConnectionContext initiatorCtx = new D2DConnectionContextV0(INITIATOR_ENCODE_KEY, 1);
-    D2DConnectionContext responderCtx = new D2DConnectionContextV0(INITIATOR_ENCODE_KEY, 1);
-
-    // Save the state
-    byte[] initiatorSavedSessionState = initiatorCtx.saveSession();
-    byte[] responderSavedSessionState = responderCtx.saveSession();
-
-    // Try to rebuild the context
-    initiatorCtx = D2DConnectionContext.fromSavedSession(initiatorSavedSessionState);
-    responderCtx = D2DConnectionContext.fromSavedSession(responderSavedSessionState);
-
-    // Sanity check
-    assertEquals(1, initiatorCtx.getSequenceNumberForDecoding());
-    assertEquals(1, responderCtx.getSequenceNumberForDecoding());
-    Assert.assertArrayEquals(initiatorCtx.getSessionUnique(), responderCtx.getSessionUnique());
-
-    // Make sure they can still talk to one another
-    assertEquals(PING,
-        responderCtx.decodeMessageFromPeerAsString(initiatorCtx.encodeMessageToPeer(PING)));
-    assertEquals(PONG,
-        initiatorCtx.decodeMessageFromPeerAsString(responderCtx.encodeMessageToPeer(PONG)));
-  }
-
-  @Test
-  public void testSaveSessionV0_negativeSeqNumber() throws Exception {
-    D2DConnectionContext initiatorCtx = new D2DConnectionContextV0(INITIATOR_ENCODE_KEY, -5);
-
-    // Save the state
-    byte[] initiatorSavedSessionState = initiatorCtx.saveSession();
-
-    // Try to rebuild the context
-    initiatorCtx = D2DConnectionContext.fromSavedSession(initiatorSavedSessionState);
-
-    // Sanity check
-    assertEquals(-5, initiatorCtx.getSequenceNumberForDecoding());
-  }
-
-  @Test
-  public void testSaveSessionV0_shortKey() throws Exception {
-    D2DConnectionContext initiatorCtx = new D2DConnectionContextV0(INITIATOR_ENCODE_KEY, -5);
-
-    // Save the state
-    byte[] initiatorSavedSessionState = initiatorCtx.saveSession();
-
-    // Try to rebuild the context
-    try {
-      D2DConnectionContext.fromSavedSession(Arrays.copyOf(initiatorSavedSessionState,
-          initiatorSavedSessionState.length - 1));
-      fail("Expected failure as key is too short");
-    } catch (IllegalArgumentException e) {
-      // expected
-    }
-  }
-
-  @Test
-  public void testSaveSession_unknownProtocolVersion() throws Exception {
-    D2DConnectionContext initiatorCtx = new D2DConnectionContextV0(INITIATOR_ENCODE_KEY, -5);
-
-    // Save the state
-    byte[] initiatorSavedSessionState = initiatorCtx.saveSession();
-
-    // Mess with the protocol version
-    initiatorSavedSessionState[0] = (byte) 0xff;
-
-    // Try to rebuild the context
-    try {
-      D2DConnectionContext.fromSavedSession(initiatorSavedSessionState);
-      fail("Expected failure as 0xff is not a valid protocol version");
-    } catch (IllegalArgumentException e) {
-      // expected
-    }
-
-    // Mess with the protocol version in the other direction
-    initiatorSavedSessionState[0] = 2;
-
-    // Try to rebuild the context
-    try {
-      D2DConnectionContext.fromSavedSession(initiatorSavedSessionState);
-      fail("Expected failure as 2 is not a valid protocol version");
-    } catch (IllegalArgumentException e) {
-      // expected
-    }
-  }
-
-  @Test
-  public void testSaveSessionV1() throws Exception {
-    D2DConnectionContext initiatorCtx = new D2DConnectionContextV1(INITIATOR_ENCODE_KEY,
-        INITIATOR_DECODE_KEY, 0, 1);
-    D2DConnectionContext responderCtx = new D2DConnectionContextV1(INITIATOR_DECODE_KEY,
-        INITIATOR_ENCODE_KEY, 1, 0);
-
-    // Save the state
-    byte[] initiatorSavedSessionState = initiatorCtx.saveSession();
-    byte[] responderSavedSessionState = responderCtx.saveSession();
-
-    // Try to rebuild the context
-    initiatorCtx = D2DConnectionContext.fromSavedSession(initiatorSavedSessionState);
-    responderCtx = D2DConnectionContext.fromSavedSession(responderSavedSessionState);
-
-    // Sanity check
-    assertEquals(1, initiatorCtx.getSequenceNumberForDecoding());
-    assertEquals(0, initiatorCtx.getSequenceNumberForEncoding());
-    assertEquals(0, responderCtx.getSequenceNumberForDecoding());
-    assertEquals(1, responderCtx.getSequenceNumberForEncoding());
-    Assert.assertArrayEquals(initiatorCtx.getSessionUnique(), responderCtx.getSessionUnique());
-
-    // Make sure they can still talk to one another
-    assertEquals(PING,
-        responderCtx.decodeMessageFromPeerAsString(initiatorCtx.encodeMessageToPeer(PING)));
-    assertEquals(PONG,
-        initiatorCtx.decodeMessageFromPeerAsString(responderCtx.encodeMessageToPeer(PONG)));
-  }
-
-  @Test
-  public void testSaveSessionV1_negativeSeqNumbers() throws Exception {
-    D2DConnectionContext initiatorCtx = new D2DConnectionContextV1(INITIATOR_ENCODE_KEY,
-        INITIATOR_DECODE_KEY, -8, -10);
-
-    // Save the state
-    byte[] initiatorSavedSessionState = initiatorCtx.saveSession();
-
-    // Try to rebuild the context
-    initiatorCtx = D2DConnectionContext.fromSavedSession(initiatorSavedSessionState);
-
-    // Sanity check
-    assertEquals(-10, initiatorCtx.getSequenceNumberForDecoding());
-    assertEquals(-8, initiatorCtx.getSequenceNumberForEncoding());
-  }
-
-  @Test
-  public void testSaveSessionV1_tooShort() throws Exception {
-    D2DConnectionContext initiatorCtx = new D2DConnectionContextV1(INITIATOR_ENCODE_KEY,
-        INITIATOR_DECODE_KEY, -8, -10);
-
-    // Save the state
-    byte[] initiatorSavedSessionState = initiatorCtx.saveSession();
-
-    // Try to rebuild the context
-    try {
-      D2DConnectionContext.fromSavedSession(
-          Arrays.copyOf(initiatorSavedSessionState, initiatorSavedSessionState.length - 1));
-      fail("Expected error as saved session is too short");
-    } catch (IllegalArgumentException e) {
-      // expected
-    }
-
-    // Sanity check
-    assertEquals(-10, initiatorCtx.getSequenceNumberForDecoding());
-    assertEquals(-8, initiatorCtx.getSequenceNumberForEncoding());
-  }
-
-  D2DConnectionContext createConnectionContext(int protocolVersion, boolean isInitiator) {
-    return createConnectionContext(
-        protocolVersion, isInitiator, INITIATOR_ENCODE_KEY, INITIATOR_DECODE_KEY, 0, 1);
-  }
-
-  D2DConnectionContext createConnectionContext(
-      int protocolVersion, boolean isInitiator,
-      SecretKey initiatorEncodeKey, SecretKey initiatorDecodeKey,
-      int initiatorSequenceNumber, int responderSequenceNumber) {
-    if (protocolVersion == D2DConnectionContextV0.PROTOCOL_VERSION) {
-      return new D2DConnectionContextV0(initiatorEncodeKey, responderSequenceNumber);
-    } else if (protocolVersion == D2DConnectionContextV1.PROTOCOL_VERSION) {
-      return isInitiator
-          ? new D2DConnectionContextV1(
-              initiatorEncodeKey, initiatorDecodeKey,
-              initiatorSequenceNumber, responderSequenceNumber)
-          : new D2DConnectionContextV1(
-              initiatorDecodeKey, initiatorEncodeKey,
-              responderSequenceNumber, initiatorSequenceNumber);
-    } else {
-      throw new IllegalArgumentException("Unknown version: " + protocolVersion);
-    }
-  }
-}
diff --git a/src/main/javatest/com/google/security/cryptauth/lib/securegcm/D2DDiffieHellmanKeyExchangeHandshakeTest.java b/src/main/javatest/com/google/security/cryptauth/lib/securegcm/D2DDiffieHellmanKeyExchangeHandshakeTest.java
deleted file mode 100644
index 4de794a..0000000
--- a/src/main/javatest/com/google/security/cryptauth/lib/securegcm/D2DDiffieHellmanKeyExchangeHandshakeTest.java
+++ /dev/null
@@ -1,432 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.security.cryptauth.lib.securegcm;
-
-import com.google.security.cryptauth.lib.securegcm.DeviceToDeviceMessagesProto.InitiatorHello;
-import com.google.security.cryptauth.lib.securegcm.DeviceToDeviceMessagesProto.ResponderHello;
-import com.google.security.cryptauth.lib.securegcm.TransportCryptoOps.Payload;
-import com.google.security.cryptauth.lib.securegcm.TransportCryptoOps.PayloadType;
-import com.google.security.cryptauth.lib.securemessage.PublicKeyProtoUtil;
-import java.nio.charset.Charset;
-import java.security.KeyPair;
-import java.security.PublicKey;
-import java.security.SignatureException;
-import javax.crypto.SecretKey;
-import junit.framework.TestCase;
-import org.junit.Assert;
-
-/**
- * Android compatible tests for the {@link D2DDiffieHellmanKeyExchangeHandshake} class.
- */
-public class D2DDiffieHellmanKeyExchangeHandshakeTest extends TestCase {
-
-  private static final byte[] RESPONDER_HELLO_MESSAGE =
-      "first payload".getBytes(Charset.forName("UTF-8"));
-
-  private static final String PING = "ping";
-
-  @Override
-  protected void setUp() throws Exception {
-    KeyEncodingTest.installSunEcSecurityProviderIfNecessary();
-    super.setUp();
-  }
-
-  public void testHandshakeWithPayload() throws Exception {
-
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // initiator:
-    D2DHandshakeContext initiatorHandshakeContext =
-        D2DDiffieHellmanKeyExchangeHandshake.forInitiator();
-    assertFalse(initiatorHandshakeContext.canSendPayloadInHandshakeMessage());
-    assertFalse(initiatorHandshakeContext.isHandshakeComplete());
-    byte[] initiatorHello = initiatorHandshakeContext.getNextHandshakeMessage();
-    assertFalse(initiatorHandshakeContext.isHandshakeComplete());
-    // (send initiatorHello to responder)
-
-    // responder:
-    D2DHandshakeContext responderHandshakeContext =
-        D2DDiffieHellmanKeyExchangeHandshake.forResponder();
-    byte[] payload = responderHandshakeContext.parseHandshakeMessage(initiatorHello);
-    assertEquals(0, payload.length);
-    assertTrue(responderHandshakeContext.canSendPayloadInHandshakeMessage());
-    assertFalse(responderHandshakeContext.isHandshakeComplete());
-    byte[] responderHelloAndPayload = responderHandshakeContext.getNextHandshakeMessage(
-        RESPONDER_HELLO_MESSAGE);
-    assertTrue(responderHandshakeContext.isHandshakeComplete());
-    D2DConnectionContext responderCtx = responderHandshakeContext.toConnectionContext();
-    // (send responderHelloAndPayload to initiator)
-
-    // initiator
-    byte[] messageFromPayload =
-        initiatorHandshakeContext.parseHandshakeMessage(responderHelloAndPayload);
-    Assert.assertArrayEquals(RESPONDER_HELLO_MESSAGE, messageFromPayload);
-    assertTrue(initiatorHandshakeContext.isHandshakeComplete());
-    D2DConnectionContextV1 initiatorCtx =
-        (D2DConnectionContextV1) initiatorHandshakeContext.toConnectionContext();
-
-    // Test that that initiator and responder contexts are initialized correctly.
-    checkInitializedConnectionContexts(initiatorCtx, responderCtx);
-  }
-
-  public void testHandshakeWithoutPayload() throws Exception {
-
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // initiator:
-    D2DHandshakeContext initiatorHandshakeContext =
-        D2DDiffieHellmanKeyExchangeHandshake.forInitiator();
-    byte[] initiatorHello = initiatorHandshakeContext.getNextHandshakeMessage();
-    // (send initiatorHello to responder)
-
-    // responder:
-    D2DHandshakeContext responderHandshakeContext =
-        D2DDiffieHellmanKeyExchangeHandshake.forResponder();
-    responderHandshakeContext.parseHandshakeMessage(initiatorHello);
-    byte[] responderHelloAndPayload = responderHandshakeContext.getNextHandshakeMessage();
-    assertTrue(responderHandshakeContext.isHandshakeComplete());
-    D2DConnectionContext responderCtx = responderHandshakeContext.toConnectionContext();
-    // (send responderHelloAndPayload to initiator)
-
-    // initiator
-    byte[] messageFromPayload =
-        initiatorHandshakeContext.parseHandshakeMessage(responderHelloAndPayload);
-    assertEquals(0, messageFromPayload.length);
-    assertTrue(initiatorHandshakeContext.isHandshakeComplete());
-    D2DConnectionContext initiatorCtx = initiatorHandshakeContext.toConnectionContext();
-
-    // Test that that initiator and responder contexts are initialized correctly.
-    checkInitializedConnectionContexts(initiatorCtx, responderCtx);
-  }
-
-  public void testErrorWhenInitiatorOrResponderSendTwice() throws Exception {
-
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // initiator:
-    D2DHandshakeContext initiatorHandshakeContext =
-        D2DDiffieHellmanKeyExchangeHandshake.forInitiator();
-    byte[] initiatorHello = initiatorHandshakeContext.getNextHandshakeMessage();
-    try {
-      initiatorHandshakeContext.getNextHandshakeMessage();
-      fail("Expected error as initiator has no more initiator messages to send");
-    } catch (HandshakeException expected) {
-      assertTrue(expected.getMessage().contains("Cannot get next message"));
-    }
-    // (send initiatorHello to responder)
-
-    // responder:
-    D2DHandshakeContext responderHandshakeContext =
-        D2DDiffieHellmanKeyExchangeHandshake.forResponder();
-    responderHandshakeContext.parseHandshakeMessage(initiatorHello);
-    responderHandshakeContext.getNextHandshakeMessage();
-    try {
-      responderHandshakeContext.getNextHandshakeMessage();
-      fail("Expected error as initiator has no more responder messages to send");
-    } catch (HandshakeException expected) {
-      assertTrue(expected.getMessage().contains("Cannot get"));
-    }
-  }
-
-  public void testInitiatorOrResponderFailOnEmptyMessage() throws Exception {
-
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    D2DHandshakeContext handshakeContext =
-        D2DDiffieHellmanKeyExchangeHandshake.forInitiator();
-    try {
-      handshakeContext.parseHandshakeMessage(null);
-      fail("Expected to crash on null message");
-    } catch (HandshakeException expected) {
-      assertTrue(expected.getMessage().contains("short"));
-    }
-    try {
-      handshakeContext.parseHandshakeMessage(new byte[0]);
-      fail("Expected to crash on empty message");
-    } catch (HandshakeException expected) {
-      assertTrue(expected.getMessage().contains("short"));
-    }
-  }
-
-  public void testPrematureConversionToConnection() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // initiator:
-    D2DHandshakeContext initiatorHandshakeContext =
-        D2DDiffieHellmanKeyExchangeHandshake.forInitiator();
-    try {
-      initiatorHandshakeContext.toConnectionContext();
-      fail("Expected to crash: initiator hasn't done anything to deserve full connection");
-    } catch (HandshakeException expected) {
-      assertTrue(expected.getMessage().contains("not complete"));
-    }
-
-    byte[] initiatorHello = initiatorHandshakeContext.getNextHandshakeMessage();
-    try {
-      initiatorHandshakeContext.toConnectionContext();
-      fail("Expected to crash: initiator hasn't yet received responder's key");
-    } catch (HandshakeException expected) {
-      assertTrue(expected.getMessage().contains("not complete"));
-    }
-    // (send initiatorHello to responder)
-
-    // responder:
-    D2DHandshakeContext responderHandshakeContext =
-        D2DDiffieHellmanKeyExchangeHandshake.forResponder();
-    responderHandshakeContext.parseHandshakeMessage(initiatorHello);
-    try {
-      initiatorHandshakeContext.toConnectionContext();
-      fail("Expected to crash: responder hasn't yet send their key");
-    } catch (HandshakeException expected) {
-      assertTrue(expected.getMessage().contains("not complete"));
-    }
-  }
-
-  public void testCannotReuseHandshakeContext() throws Exception {
-
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // initiator:
-    D2DHandshakeContext initiatorHandshakeContext =
-        D2DDiffieHellmanKeyExchangeHandshake.forInitiator();
-    byte[] initiatorHello = initiatorHandshakeContext.getNextHandshakeMessage();
-    // (send initiatorHello to responder)
-
-    // responder:
-    D2DHandshakeContext responderHandshakeContext =
-        D2DDiffieHellmanKeyExchangeHandshake.forResponder();
-    responderHandshakeContext.parseHandshakeMessage(initiatorHello);
-    byte[] responderHelloAndPayload = responderHandshakeContext.getNextHandshakeMessage();
-    D2DConnectionContext responderCtx = responderHandshakeContext.toConnectionContext();
-    // (send responderHelloAndPayload to initiator)
-
-    // initiator
-    initiatorHandshakeContext.parseHandshakeMessage(responderHelloAndPayload);
-    D2DConnectionContext initiatorCtx = initiatorHandshakeContext.toConnectionContext();
-
-    // Test that that initiator and responder contexts are initialized correctly.
-    checkInitializedConnectionContexts(initiatorCtx, responderCtx);
-
-    // Try to get another full context
-    try {
-      initiatorHandshakeContext.toConnectionContext();
-      fail("Expected crash: initiator context has already been used");
-    } catch (HandshakeException expected) {
-      assertTrue(expected.getMessage().contains("used"));
-    }
-    try {
-      responderHandshakeContext.toConnectionContext();
-      fail("Expected crash: responder context has already been used");
-    } catch (HandshakeException expected) {
-      assertTrue(expected.getMessage().contains("used"));
-    }
-  }
-
-  public void testErrorWhenInitiatorEchosResponderHello() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // Initiator echoing back responder's first packet:
-    D2DDiffieHellmanKeyExchangeHandshake partialInitiatorContext =
-        D2DDiffieHellmanKeyExchangeHandshake.forInitiator();
-    byte[] initiatorHello = partialInitiatorContext.getNextHandshakeMessage();
-
-    D2DDiffieHellmanKeyExchangeHandshake partialResponderCtx =
-        D2DDiffieHellmanKeyExchangeHandshake.forResponder();
-    partialResponderCtx.parseHandshakeMessage(initiatorHello);
-    byte[] responderHelloAndPayload =
-        partialResponderCtx.getNextHandshakeMessage(RESPONDER_HELLO_MESSAGE);
-    D2DConnectionContext responderCtx = partialResponderCtx.toConnectionContext();
-
-    try {
-      // initiator sends responderHelloAndPayload to responder
-      responderCtx.decodeMessageFromPeerAsString(responderHelloAndPayload);
-      fail("expected exception, but didn't get it");
-    } catch (SignatureException expected) {
-      assertTrue(expected.getMessage().contains("Signature failed verification"));
-    }
-  }
-
-  public void testErrorWhenInitiatorResendsMessage() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // Initiator repeating the same packet twice
-    D2DDiffieHellmanKeyExchangeHandshake partialInitiatorContext =
-        D2DDiffieHellmanKeyExchangeHandshake.forInitiator();
-    byte[] initiatorHello = partialInitiatorContext.getNextHandshakeMessage();
-
-    D2DDiffieHellmanKeyExchangeHandshake partialResponderCtx =
-        D2DDiffieHellmanKeyExchangeHandshake.forResponder();
-    partialResponderCtx.parseHandshakeMessage(initiatorHello);
-    byte[] responderHelloAndPayload =
-        partialResponderCtx.getNextHandshakeMessage(RESPONDER_HELLO_MESSAGE);
-    D2DConnectionContext responderCtx = partialResponderCtx.toConnectionContext();
-
-    partialInitiatorContext.parseHandshakeMessage(responderHelloAndPayload);
-    D2DConnectionContext initiatorCtx = partialInitiatorContext.toConnectionContext();
-
-    byte[] pingMessage = initiatorCtx.encodeMessageToPeer(PING);
-    assertEquals(PING, responderCtx.decodeMessageFromPeerAsString(pingMessage));
-
-    try {
-      // send pingMessage to responder again
-      responderCtx.decodeMessageFromPeerAsString(pingMessage);
-      fail("expected exception, but didn't get it");
-    } catch (SignatureException expected) {
-      assertTrue(expected.getMessage().contains("sequence"));
-    }
-  }
-
-  public void testErrorWhenResponderResendsFirstMessage() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    D2DDiffieHellmanKeyExchangeHandshake partialInitiatorContext =
-        D2DDiffieHellmanKeyExchangeHandshake.forInitiator();
-    byte[] initiatorHello = partialInitiatorContext.getNextHandshakeMessage();
-
-    D2DDiffieHellmanKeyExchangeHandshake partialResponderCtx =
-        D2DDiffieHellmanKeyExchangeHandshake.forResponder();
-    partialResponderCtx.parseHandshakeMessage(initiatorHello);
-    byte[] responderHelloAndPayload =
-        partialResponderCtx.getNextHandshakeMessage(RESPONDER_HELLO_MESSAGE);
-
-    partialInitiatorContext.parseHandshakeMessage(responderHelloAndPayload);
-    D2DConnectionContext initiatorCtx = partialInitiatorContext.toConnectionContext();
-
-    try {
-      // Send the responderHelloAndPayload again. This time, the initiator will
-      // process it as a normal message.
-      initiatorCtx.decodeMessageFromPeerAsString(responderHelloAndPayload);
-      fail("expected exception, but didn't get it");
-    } catch (SignatureException expected) {
-      assertTrue(expected.getMessage().contains("wrong message type"));
-    }
-  }
-
-  public void testHandshakeWithInitiatorV1AndResponderV0() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // Initialize initiator side.
-    D2DHandshakeContext initiatorHandshakeContext =
-        D2DDiffieHellmanKeyExchangeHandshake.forInitiator();
-    byte[] initiatorHello = initiatorHandshakeContext.getNextHandshakeMessage();
-
-    // Set up keys used by the responder.
-    PublicKey initiatorPublicKey = PublicKeyProtoUtil.parsePublicKey(
-        InitiatorHello.parseFrom(initiatorHello).getPublicDhKey());
-    KeyPair responderKeyPair = PublicKeyProtoUtil.generateEcP256KeyPair();
-    SecretKey sharedKey =
-        EnrollmentCryptoOps.doKeyAgreement(responderKeyPair.getPrivate(), initiatorPublicKey);
-
-    // Construct a responder hello message without the version field, whose payload is encrypted
-    // with the shared key.
-    byte[] responderHello = D2DCryptoOps.signcryptPayload(
-          new Payload(
-              PayloadType.DEVICE_TO_DEVICE_RESPONDER_HELLO_PAYLOAD,
-              D2DConnectionContext.createDeviceToDeviceMessage(new byte[] {}, 1).toByteArray()),
-          sharedKey,
-          ResponderHello.newBuilder()
-              .setPublicDhKey(
-                  PublicKeyProtoUtil.encodePublicKey(responderKeyPair.getPublic()))
-              .build().toByteArray());
-
-    // Handle V0 responder hello message.
-    initiatorHandshakeContext.parseHandshakeMessage(responderHello);
-    D2DConnectionContext initiatorCtx = initiatorHandshakeContext.toConnectionContext();
-
-    assertEquals(D2DConnectionContextV0.PROTOCOL_VERSION, initiatorCtx.getProtocolVersion());
-    assertEquals(1, initiatorCtx.getSequenceNumberForEncoding());
-    assertEquals(1, initiatorCtx.getSequenceNumberForDecoding());
-  }
-
-  public void testHandshakeWithInitiatorV0AndResponderV1() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // Construct an initiator hello message without the version field.
-    byte[] initiatorHello = InitiatorHello.newBuilder()
-        .setPublicDhKey(PublicKeyProtoUtil.encodePublicKey(
-            PublicKeyProtoUtil.generateEcP256KeyPair().getPublic()))
-        .build()
-        .toByteArray();
-
-    // Handle V0 initiator hello message.
-    D2DHandshakeContext responderHandshakeContext =
-        D2DDiffieHellmanKeyExchangeHandshake.forResponder();
-    responderHandshakeContext.parseHandshakeMessage(initiatorHello);
-    responderHandshakeContext.getNextHandshakeMessage();
-    D2DConnectionContext responderCtx = responderHandshakeContext.toConnectionContext();
-
-    assertEquals(D2DConnectionContextV0.PROTOCOL_VERSION, responderCtx.getProtocolVersion());
-    assertEquals(1, responderCtx.getSequenceNumberForEncoding());
-    assertEquals(1, responderCtx.getSequenceNumberForDecoding());
-  }
-
-  private void checkInitializedConnectionContexts(
-      D2DConnectionContext initiatorCtx, D2DConnectionContext responderCtx) {
-    assertNotNull(initiatorCtx);
-    assertNotNull(responderCtx);
-    assertEquals(D2DConnectionContextV1.PROTOCOL_VERSION, initiatorCtx.getProtocolVersion());
-    assertEquals(D2DConnectionContextV1.PROTOCOL_VERSION, responderCtx.getProtocolVersion());
-    assertEquals(initiatorCtx.getEncodeKey(), responderCtx.getDecodeKey());
-    assertEquals(initiatorCtx.getDecodeKey(), responderCtx.getEncodeKey());
-    assertEquals(0, initiatorCtx.getSequenceNumberForEncoding());
-    assertEquals(1, initiatorCtx.getSequenceNumberForDecoding());
-    assertEquals(1, responderCtx.getSequenceNumberForEncoding());
-    assertEquals(0, responderCtx.getSequenceNumberForDecoding());
-  }
-}
diff --git a/src/main/javatest/com/google/security/cryptauth/lib/securegcm/Ed25519Test.java b/src/main/javatest/com/google/security/cryptauth/lib/securegcm/Ed25519Test.java
deleted file mode 100644
index 6ae95d8..0000000
--- a/src/main/javatest/com/google/security/cryptauth/lib/securegcm/Ed25519Test.java
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.security.cryptauth.lib.securegcm;
-
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertThat;
-
-import com.google.security.cryptauth.lib.securegcm.Ed25519.Ed25519Exception;
-import java.math.BigInteger;
-import junit.framework.TestCase;
-
-/**
- * Android compatible tests for the {@link Ed25519} class.
- */
-public class Ed25519Test extends TestCase {
-
-  // Points on the curve
-  private static final int HEX_RADIX = 16;
-  private static final BigInteger[] KM = new BigInteger[] {
-    new BigInteger("1981FB43F103290ECF9772022DB8B19BFAF389057ED91E8486EB368763435925", HEX_RADIX),
-    new BigInteger("A714C34F3B588AAC92FD2587884A20964FD351A1F147D5C4BBF5C2F37A77C36", HEX_RADIX)};
-  private static final BigInteger[] KN = new BigInteger[] {
-    new BigInteger("201A184F47D9A7973891D148E3D1C864D8084547131C2C1CEFB7EEBD26C63567", HEX_RADIX),
-    new BigInteger("6DA2D3B18EC4F9AA3B08E39C997CD8BF6E9948FFD4FEFFECAF8DD0B3D648B7E8", HEX_RADIX)};
-
-  // Curve prime P
-  private static final BigInteger P =
-      new BigInteger("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED", HEX_RADIX);
-
-  // Test vectors obtain by multiplying KM by k by manually using the official implementation
-  // see: http://ed25519.cr.yp.to/python/ed25519.py
-  // k = 2
-  private static final BigInteger[] KM_2 = new BigInteger[] {
-    new BigInteger("718079972e63c2d62caf0ee93ec6f00337ceaff4e283181c04c4082b1d5e1ecf", HEX_RADIX),
-    new BigInteger("143d18d393a8058c8614335bf36bf59364cc7c451db74726b322ce9d0b826d51", HEX_RADIX)
-  };
-  // k = 3
-  private static final BigInteger[] KM_3 = new BigInteger[] {
-    new BigInteger("39DA3C92EFC0577586B4D58F4A5C0BF65A6CC8F6BF358F38D70B2E6C28A31E8E", HEX_RADIX),
-    new BigInteger("6D194F054B3FC2BE217F6A360BBEC747D2937FCEBD74B67FC3B20ED638ADD670", HEX_RADIX)
-  };
-  // k = 317698
-  private static final BigInteger[] KM_317698 = new BigInteger[] {
-    new BigInteger("7945D0ADEB568B16495476E81ADF281F4515439AE835914FBF6CEEAFEB9CD7E8", HEX_RADIX),
-    new BigInteger("3631503DCDEBC0BF9BB1FFC3984A8CB52A34FFC2E77E9C19FD896DC6EE64A530", HEX_RADIX)
-  };
-  // k = P
-  private static final BigInteger[] KM_HUGE = new BigInteger[] {
-    new BigInteger("530162B05F440E00E219DFD3188524821C860C41FD87B9AC6AF2A283FDD585A1", HEX_RADIX),
-    new BigInteger("48385A7D2BB858F3DB7F72E7CDFE218B9CA84DDA8BD64C3775AA43551D974F60", HEX_RADIX)
-  };
-  // k = P + 10000
-  private static final BigInteger[] KM_XRAHUGE = new BigInteger[] {
-    new BigInteger("16377E9F5EE2C0F4C70E17AC298EF670700A7CB186EEB0DA10CDD59635000AF8", HEX_RADIX),
-    new BigInteger("5BD7921EEE662ACBAC3A96D8B6039D2356F154859FAF41FD2F0D99DF06CD2EAE", HEX_RADIX)
-  };
-
-  // Helpful constants
-  private static final BigInteger ONE = BigInteger.ONE;
-  private static final BigInteger ZERO = BigInteger.ZERO;
-
-  // Identity element of the group (the zero) in affine and extended representations
-  private static final BigInteger[] ID = new BigInteger[] {ZERO, ONE};
-  private static final BigInteger[] ID_EX = new BigInteger[] {ZERO, ONE, ONE, ZERO};
-
-  public void testValidPoints() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // We've got a couple of valid points
-    Ed25519.validateAffinePoint(KM);
-    Ed25519.validateAffinePoint(KN);
-    
-    // And a bunch of invalid ones
-    try {
-      Ed25519.validateAffinePoint(new BigInteger[] {ZERO, ONE});
-      fail("Validate point not catching zero x coordinates");
-    } catch (Ed25519Exception e) {
-      assertThat(e.getMessage(), containsString("positive"));
-    }
-    
-    try {
-      Ed25519.validateAffinePoint(new BigInteger[] {ONE, ZERO});
-      fail("Validate point not catching zero y coordinates");
-    } catch (Ed25519Exception e) {
-      assertThat(e.getMessage(), containsString("positive"));
-    }
-    
-    try {
-      Ed25519.validateAffinePoint(new BigInteger[] {new BigInteger("-1"), ONE});
-      fail("Validate point not catching negative x coordinates");
-    } catch (Ed25519Exception e) {
-      assertThat(e.getMessage(), containsString("positive"));
-    }
-    
-    try {
-      Ed25519.validateAffinePoint(new BigInteger[] {ONE, new BigInteger("-1")});
-      fail("Validate point not catching negative y coordinates");
-    } catch (Ed25519Exception e) {
-      assertThat(e.getMessage(), containsString("positive"));
-    }
-    
-    try {
-      Ed25519.validateAffinePoint(new BigInteger[] {ONE, ONE});
-      fail("Validate point not catching points that are not on curve");
-    } catch (Ed25519Exception e) {
-      assertThat(e.getMessage(), containsString("expected curve"));
-    }
-  }
-
-  public void testAffineExtendedConversion() throws Exception {
-    BigInteger[] km1 = Ed25519.toAffine(Ed25519.toExtended(KM));
-    BigInteger[] kn1 = Ed25519.toAffine(Ed25519.toExtended(KN));
-
-    assertArrayEquals(KM, km1);
-    assertArrayEquals(KN, kn1);
-
-    assertArrayEquals(ID, Ed25519.toAffine(ID_EX));
-    assertArrayEquals(ID_EX, Ed25519.toExtended(ID));
-  }
-
-  public void testRepresentationCheck() throws Exception {
-    Ed25519.checkPointIsInAffineRepresentation(KM);
-    Ed25519.checkPointIsInExtendedRepresentation(ID_EX);
-
-    try {
-      Ed25519.checkPointIsInExtendedRepresentation(KM);
-      fail("Point is not really in extended representation, expected failure");
-    } catch (Ed25519Exception e) {      
-      assertThat(e.getMessage(), containsString("not in extended"));
-    }
-
-    try {
-      Ed25519.checkPointIsInAffineRepresentation(Ed25519.toExtended(KM));
-      fail("Point is not really in affine representation, expected failure");
-    } catch (Ed25519Exception e) {     
-      assertThat(e.getMessage(), containsString("not in affine"));
-    }
-  }
-
-  public void testAddSubtractExtendedPoints() throws Exception {
-    // Adding/subtracting identity to/from itself should yield the identity point
-    assertArrayEquals(ID, Ed25519.addAffinePoints(ID, ID));
-    assertArrayEquals(ID, Ed25519.subtractAffinePoints(ID, ID));
-
-    // In fact adding/subtracting the identity point to/from any point should yield that point
-    assertArrayEquals(KM, Ed25519.addAffinePoints(KM, ID));
-    assertArrayEquals(KM, Ed25519.subtractAffinePoints(KM, ID));
-
-    // Subtracting a point from itself should yield the identity element
-    assertArrayEquals(ID, Ed25519.subtractAffinePoints(KM, KM));
-    assertArrayEquals(ID, Ed25519.subtractAffinePoints(KN, KN));
-
-    // Adding and subtracting should yield the same point
-    assertArrayEquals(KM, Ed25519.subtractAffinePoints(Ed25519.addAffinePoints(KM, KN), KN));
-    assertArrayEquals(KN, Ed25519.subtractAffinePoints(Ed25519.addAffinePoints(KN, KM), KM));
-  }
-
-  public void testScalarMultiplyExtendedPoints() throws Exception {
-    // A point times one is the point itself
-    assertArrayEquals(KM, Ed25519.scalarMultiplyAffinePoint(KM, ONE));
-    assertArrayEquals(KN, Ed25519.scalarMultiplyAffinePoint(KN, ONE));
-
-    // A point times zero is the identity point
-    assertArrayEquals(ID, Ed25519.scalarMultiplyAffinePoint(KM, ZERO));
-    assertArrayEquals(ID, Ed25519.scalarMultiplyAffinePoint(KN, ZERO));
-
-    // The identity times a scalar is the identity
-    assertArrayEquals(ID, Ed25519.scalarMultiplyAffinePoint(ID, BigInteger.valueOf(317698)));
-
-    // Use test vectors
-    assertArrayEquals(KM_2, Ed25519.scalarMultiplyAffinePoint(KM, BigInteger.valueOf(2)));
-    assertArrayEquals(KM_3, Ed25519.scalarMultiplyAffinePoint(KM, BigInteger.valueOf(3)));
-    assertArrayEquals(KM_317698, Ed25519.scalarMultiplyAffinePoint(KM, BigInteger.valueOf(317698)));
-    assertArrayEquals(KM_HUGE, Ed25519.scalarMultiplyAffinePoint(KM, P));
-    assertArrayEquals(KM_XRAHUGE,
-        Ed25519.scalarMultiplyAffinePoint(KM, P.add(BigInteger.valueOf(10000))));
-  }
-}
diff --git a/src/main/javatest/com/google/security/cryptauth/lib/securegcm/EnrollmentCryptoOpsTest.java b/src/main/javatest/com/google/security/cryptauth/lib/securegcm/EnrollmentCryptoOpsTest.java
deleted file mode 100644
index 4437045..0000000
--- a/src/main/javatest/com/google/security/cryptauth/lib/securegcm/EnrollmentCryptoOpsTest.java
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.security.cryptauth.lib.securegcm;
-
-import com.google.protobuf.ByteString;
-import com.google.security.cryptauth.lib.securegcm.SecureGcmProto.GcmDeviceInfo;
-import com.google.security.cryptauth.lib.securemessage.PublicKeyProtoUtil;
-import com.google.security.cryptauth.lib.securemessage.SecureMessageProto.GenericPublicKey;
-import java.security.KeyPair;
-import java.security.PublicKey;
-import java.util.Arrays;
-import javax.crypto.SecretKey;
-import junit.framework.TestCase;
-
-/**
- * Android compatible tests for the {@link EnrollmentCryptoOps} class.
- */
-public class EnrollmentCryptoOpsTest extends TestCase {
-
-  private static final long DEVICE_ID = 1234567890L;
-  private static final byte[] GCM_REGISTRATION_ID = { -0x80, 0, -0x80, 0, -0x80, 0 };
-  private static final String DEVICE_MODEL = "TEST DEVICE";
-  private static final String LOCALE = "en";
-  private static final byte[] SESSION_ID = { 5, 5, 4, 4, 3, 3, 2, 2, 1, 1 };
-  private static final String OAUTH_TOKEN = "1/23456etc";
-
-  @Override
-  protected void setUp() throws Exception {
-    KeyEncodingTest.installSunEcSecurityProviderIfNecessary();
-    assertEquals(
-        PublicKeyProtoUtil.isLegacyCryptoRequired(), KeyEncoding.isLegacyCryptoRequired());
-    super.setUp();
-  }
-
-  @Override
-  protected void tearDown() throws Exception {
-    KeyEncoding.setSimulateLegacyCrypto(false);
-    super.tearDown();
-  }
-
-
-  public void testSimulatedEnrollment() throws Exception {
-    boolean isLegacy = KeyEncoding.isLegacyCryptoRequired();
-    // Step 1: Server generates an ephemeral DH key pair, saves the private key, and sends
-    //         the public key to the client as server_ephemeral_key.
-    KeyPair serverEphemeralKeyPair =
-        EnrollmentCryptoOps.generateEnrollmentKeyAgreementKeyPair(isLegacy);
-    byte[] savedServerPrivateKey =
-        KeyEncoding.encodeKeyAgreementPrivateKey(serverEphemeralKeyPair.getPrivate());
-    byte[] serverEphemeralKey = KeyEncoding.encodeKeyAgreementPublicKey(
-        serverEphemeralKeyPair.getPublic());
-
-    // Step 2a: Client generates an ephemeral DH key pair, and completes the DH key exchange
-    //          to derive the master key.
-    KeyPair clientEphemeralKeyPair =
-        EnrollmentCryptoOps.generateEnrollmentKeyAgreementKeyPair(isLegacy);
-    byte[] clientEphemeralKey = KeyEncoding.encodeKeyAgreementPublicKey(
-        clientEphemeralKeyPair.getPublic());
-    SecretKey clientMasterKey = EnrollmentCryptoOps.doKeyAgreement(
-        clientEphemeralKeyPair.getPrivate(),
-        KeyEncoding.parseKeyAgreementPublicKey(serverEphemeralKey));
-
-    // Step 2b: Client generates its user key pair, and fills in a GcmDeviceInfo message containing
-    //          the enrollment request (which includes the user public key).
-    KeyPair userKeyPair = isLegacy ? PublicKeyProtoUtil.generateRSA2048KeyPair()
-        : PublicKeyProtoUtil.generateEcP256KeyPair();
-    GcmDeviceInfo clientInfo = createGcmDeviceInfo(userKeyPair.getPublic(), clientMasterKey);
-
-    // Step 2c: Client signcrypts the enrollment request to the server, using a combination of the
-    //          master key and its user signing key.
-    byte[] enrollmentMessage = EnrollmentCryptoOps.encryptEnrollmentMessage(
-        clientInfo, clientMasterKey, userKeyPair.getPrivate());
-
-
-    // Step 3a: Server receives the client's DH public key and completes the key exchange using
-    //          the saved DH private key.
-    SecretKey serverMasterKey = EnrollmentCryptoOps.doKeyAgreement(
-        KeyEncoding.parseKeyAgreementPrivateKey(savedServerPrivateKey, isLegacy),
-        KeyEncoding.parseKeyAgreementPublicKey(clientEphemeralKey));
-
-    // Step 3b: Server uses the exchanged master key to de-signcrypt the enrollment request
-    //          (which also provides the user public key in the clear).
-    GcmDeviceInfo serverInfo = EnrollmentCryptoOps.decryptEnrollmentMessage(
-        enrollmentMessage, serverMasterKey, isLegacy);
-
-    // Verify that the server sees the client's original enrollment request
-    assertTrue(Arrays.equals(clientInfo.toByteArray(), serverInfo.toByteArray()));
-
-    // Confirm that the server can recover a valid user PublicKey from the enrollment
-    PublicKey serverUserPublicKey = KeyEncoding.parseUserPublicKey(
-        serverInfo.getUserPublicKey().toByteArray());
-    assertTrue(serverUserPublicKey.equals(userKeyPair.getPublic()));
-  }
-
-  public void testSimulatedEnrollmentWithForcedLegacy() throws Exception {
-    if (PublicKeyProtoUtil.isLegacyCryptoRequired()) {
-      // We already test with legacy in this case
-      return;
-    }
-    KeyEncoding.setSimulateLegacyCrypto(true);
-    testSimulatedEnrollment();
-  }
-
-  private GcmDeviceInfo createGcmDeviceInfo(PublicKey userPublicKey, SecretKey masterKey) {
-    // One possible method of generating a key handle:
-    GenericPublicKey encodedUserPublicKey = PublicKeyProtoUtil.encodePublicKey(userPublicKey);
-    byte[] keyHandle = EnrollmentCryptoOps.sha256(encodedUserPublicKey.toByteArray());
-
-    return GcmDeviceInfo.newBuilder()
-        .setAndroidDeviceId(DEVICE_ID)
-        .setGcmRegistrationId(ByteString.copyFrom(GCM_REGISTRATION_ID))
-        .setDeviceMasterKeyHash(
-            ByteString.copyFrom(EnrollmentCryptoOps.getMasterKeyHash(masterKey)))
-        .setUserPublicKey(ByteString.copyFrom(KeyEncoding.encodeUserPublicKey(userPublicKey)))
-        .setDeviceModel(DEVICE_MODEL)
-        .setLocale(LOCALE)
-        .setKeyHandle(ByteString.copyFrom(keyHandle))
-        .setEnrollmentSessionId(ByteString.copyFrom(SESSION_ID))
-        .setOauthToken(OAUTH_TOKEN)
-        .build();
-  }
-}
diff --git a/src/main/javatest/com/google/security/cryptauth/lib/securegcm/KeyEncodingTest.java b/src/main/javatest/com/google/security/cryptauth/lib/securegcm/KeyEncodingTest.java
deleted file mode 100644
index 7012eae..0000000
--- a/src/main/javatest/com/google/security/cryptauth/lib/securegcm/KeyEncodingTest.java
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.security.cryptauth.lib.securegcm;
-
-import com.google.security.cryptauth.lib.securemessage.PublicKeyProtoUtil;
-import java.security.Key;
-import java.security.KeyPair;
-import java.security.PrivateKey;
-import java.security.Provider;
-import java.security.PublicKey;
-import java.security.Security;
-import java.security.interfaces.ECPrivateKey;
-import java.security.interfaces.ECPublicKey;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.interfaces.RSAPublicKey;
-import java.security.spec.InvalidKeySpecException;
-import java.util.Arrays;
-import javax.crypto.interfaces.DHPrivateKey;
-import javax.crypto.interfaces.DHPublicKey;
-import junit.framework.TestCase;
-
-/**
- * Android compatible tests for the {@link KeyEncoding} class.
- */
-public class KeyEncodingTest extends TestCase {
-  private static final byte[] RAW_KEY_BYTES = {
-      1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
-      1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
-      1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
-      1, 2};
-
-  private Boolean isLegacy;
-  private KeyPair userKeyPair;
-
-  @Override
-  protected void setUp() throws Exception {
-    installSunEcSecurityProviderIfNecessary();
-    isLegacy = PublicKeyProtoUtil.isLegacyCryptoRequired();
-    setUserKeyPair();
-    super.setUp();
-  }
-
-  @Override
-  protected void tearDown() throws Exception {
-    KeyEncoding.setSimulateLegacyCrypto(false);
-    isLegacy = PublicKeyProtoUtil.isLegacyCryptoRequired();
-    super.tearDown();
-  }
-
-  private void setUserKeyPair() {
-    userKeyPair = isLegacy ? PublicKeyProtoUtil.generateRSA2048KeyPair()
-        : PublicKeyProtoUtil.generateEcP256KeyPair();
-  }
-
-  public void testSimulateLegacyCrypto() {
-    if (isLegacy) {
-      return;  // Nothing to test if we are already stuck in a legacy platform
-    }
-    assertFalse(KeyEncoding.isLegacyCryptoRequired());
-    KeyEncoding.setSimulateLegacyCrypto(true);
-    assertTrue(KeyEncoding.isLegacyCryptoRequired());
-  }
-
-  public void testMasterKeyEncoding() {
-    // Require that master keys are encoded/decoded as raw byte arrays
-    assertTrue(Arrays.equals(
-        RAW_KEY_BYTES,
-        KeyEncoding.encodeMasterKey(KeyEncoding.parseMasterKey(RAW_KEY_BYTES))));
-  }
-
-  public void testUserPublicKeyEncoding() throws InvalidKeySpecException {
-    PublicKey pk = userKeyPair.getPublic();
-    byte[] encodedPk = KeyEncoding.encodeUserPublicKey(pk);
-    PublicKey decodedPk = KeyEncoding.parseUserPublicKey(encodedPk);
-    assertKeysEqual(pk, decodedPk);
-  }
-
-  public void testUserPrivateKeyEncoding() throws InvalidKeySpecException {
-    PrivateKey sk = userKeyPair.getPrivate();
-    byte[] encodedSk = KeyEncoding.encodeUserPrivateKey(sk);
-    PrivateKey decodedSk = KeyEncoding.parseUserPrivateKey(encodedSk, isLegacy);
-    assertKeysEqual(sk, decodedSk);
-  }
-
-  public void testKeyAgreementPublicKeyEncoding() throws InvalidKeySpecException {
-    KeyPair clientKeyPair = EnrollmentCryptoOps.generateEnrollmentKeyAgreementKeyPair(isLegacy);
-    PublicKey pk = clientKeyPair.getPublic();
-    byte[] encodedPk = KeyEncoding.encodeKeyAgreementPublicKey(pk);
-    PublicKey decodedPk = KeyEncoding.parseKeyAgreementPublicKey(encodedPk);
-    assertKeysEqual(pk, decodedPk);
-  }
-
-  public void testKeyAgreementPrivateKeyEncoding() throws InvalidKeySpecException {
-    KeyPair clientKeyPair = EnrollmentCryptoOps.generateEnrollmentKeyAgreementKeyPair(isLegacy);
-    PrivateKey sk = clientKeyPair.getPrivate();
-    byte[] encodedSk = KeyEncoding.encodeKeyAgreementPrivateKey(sk);
-    PrivateKey decodedSk = KeyEncoding.parseKeyAgreementPrivateKey(encodedSk, isLegacy);
-    assertKeysEqual(sk, decodedSk);
-  }
-
-  public void testEncodingsWithForcedLegacy() throws InvalidKeySpecException {
-    if (PublicKeyProtoUtil.isLegacyCryptoRequired()) {
-      // We already test with legacy in this case
-      return;
-    }
-    KeyEncoding.setSimulateLegacyCrypto(true);
-    isLegacy = true;
-    setUserKeyPair();
-    testUserPublicKeyEncoding();
-    testUserPrivateKeyEncoding();
-    testKeyAgreementPublicKeyEncoding();
-    testKeyAgreementPrivateKeyEncoding();
-  }
-
-  public void testSigningPublicKeyEncoding() throws InvalidKeySpecException {
-    KeyPair keyPair = PublicKeyProtoUtil.generateEcP256KeyPair();
-    PublicKey pk = keyPair.getPublic();
-    byte[] encodedPk = KeyEncoding.encodeSigningPublicKey(pk);
-    PublicKey decodedPk = KeyEncoding.parseSigningPublicKey(encodedPk);
-    assertKeysEqual(pk, decodedPk);
-  }
-
-  public void testSigningPrivateKeyEncoding() throws InvalidKeySpecException {
-    KeyPair keyPair = PublicKeyProtoUtil.generateEcP256KeyPair();
-    PrivateKey sk = keyPair.getPrivate();
-    byte[] encodedSk = KeyEncoding.encodeSigningPrivateKey(sk);
-    PrivateKey decodedSk = KeyEncoding.parseSigningPrivateKey(encodedSk);
-    assertKeysEqual(sk, decodedSk);
-  }
-
-  public void testDeviceSyncPublicKeyEncoding() throws InvalidKeySpecException {
-    KeyPair keyPair = PublicKeyProtoUtil.generateEcP256KeyPair();
-    PublicKey pk = keyPair.getPublic();
-    byte[] encodedPk = KeyEncoding.encodeDeviceSyncGroupPublicKey(pk);
-    PublicKey decodedPk = KeyEncoding.parseDeviceSyncGroupPublicKey(encodedPk);
-    assertKeysEqual(pk, decodedPk);
-  }
-
-  void assertKeysEqual(Key a, Key b) {
-    if ((a instanceof ECPublicKey)
-        || (a instanceof ECPrivateKey)
-        || (a instanceof RSAPublicKey)
-        || (a instanceof RSAPrivateKey)) {
-      assertNotNull(a.getEncoded());
-      assertTrue(Arrays.equals(a.getEncoded(), b.getEncoded()));
-    }
-    if (a instanceof DHPublicKey) {
-      DHPublicKey ya = (DHPublicKey) a;
-      DHPublicKey yb = (DHPublicKey) b;
-      assertEquals(ya.getY(), yb.getY());
-      assertEquals(ya.getParams().getG(), yb.getParams().getG());
-      assertEquals(ya.getParams().getP(), yb.getParams().getP());
-    }
-    if (a instanceof DHPrivateKey) {
-      DHPrivateKey xa = (DHPrivateKey) a;
-      DHPrivateKey xb = (DHPrivateKey) b;
-      assertEquals(xa.getX(), xb.getX());
-      assertEquals(xa.getParams().getG(), xb.getParams().getG());
-      assertEquals(xa.getParams().getP(), xb.getParams().getP());
-    }
-  }
-
-  /**
-   * Registers the SunEC security provider if no EC security providers are currently registered.
-   */
-  // TODO(shabsi): Remove this method when b/7891565 is fixed
-  static void installSunEcSecurityProviderIfNecessary() {
-    if (Security.getProviders("KeyPairGenerator.EC") == null) {
-      try {
-        Class<?> providerClass = Class.forName("sun.security.ec.SunEC");
-        Security.addProvider((Provider) providerClass.newInstance());
-      } catch (Exception e) {
-        // SunEC is not available, nothing we can do
-      }
-    }
-  }
-}
diff --git a/src/main/javatest/com/google/security/cryptauth/lib/securegcm/TransportCryptoOpsTest.java b/src/main/javatest/com/google/security/cryptauth/lib/securegcm/TransportCryptoOpsTest.java
deleted file mode 100644
index 9e45c0a..0000000
--- a/src/main/javatest/com/google/security/cryptauth/lib/securegcm/TransportCryptoOpsTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.security.cryptauth.lib.securegcm;
-
-import com.google.security.cryptauth.lib.securegcm.SecureGcmProto.Tickle;
-import com.google.security.cryptauth.lib.securegcm.TransportCryptoOps.Payload;
-import com.google.security.cryptauth.lib.securegcm.TransportCryptoOps.PayloadType;
-import com.google.security.cryptauth.lib.securemessage.PublicKeyProtoUtil;
-import java.security.KeyPair;
-import java.security.PublicKey;
-import java.util.Arrays;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
-import junit.framework.TestCase;
-
-/**
- * Android compatible tests for the {@link TransportCryptoOps} class.
- */
-public class TransportCryptoOpsTest extends TestCase {
-  private static final byte[] KEY_BYTES = {
-      1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
-      1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
-      1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
-      1, 2
-  };
-  private static final byte[] KEY_HANDLE = { 9 };
-
-  private SecretKey masterKey;
-
-  @Override
-  protected void setUp() throws Exception {
-    KeyEncodingTest.installSunEcSecurityProviderIfNecessary();
-    masterKey = new SecretKeySpec(KEY_BYTES, "AES");
-    super.setUp();
-  }
-
-  public void testServerMessage() throws Exception {
-    long tickleExpiry = 12345L;
-    Tickle tickle = Tickle.newBuilder()
-        .setExpiryTime(tickleExpiry)
-        .build();
-
-    // Simulate sending a message
-    byte[] signcryptedMessage = TransportCryptoOps.signcryptServerMessage(
-        new Payload(PayloadType.TICKLE, tickle.toByteArray()),
-        masterKey,
-        KEY_HANDLE);
-
-    // Simulate the process of receiving the message
-    assertTrue(Arrays.equals(KEY_HANDLE, TransportCryptoOps.getKeyHandleFor(signcryptedMessage)));
-    Payload received = TransportCryptoOps.verifydecryptServerMessage(signcryptedMessage, masterKey);
-    assertEquals(PayloadType.TICKLE, received.getPayloadType());
-    Tickle receivedTickle = Tickle.parseFrom(received.getMessage());
-    assertEquals(tickleExpiry, receivedTickle.getExpiryTime());
-  }
-
-  public void testClientMessage() throws Exception {
-    if (PublicKeyProtoUtil.isLegacyCryptoRequired()) {
-      return;  // This test isn't for legacy crypto
-    }
-    KeyPair userKeyPair = PublicKeyProtoUtil.generateEcP256KeyPair();
-    doTestClientMessageWith(userKeyPair);
-  }
-
-  public void testClientMessageWithLegacyCrypto() throws Exception {
-    KeyPair userKeyPair = PublicKeyProtoUtil.generateRSA2048KeyPair();
-    doTestClientMessageWith(userKeyPair);
-  }
-
-  private void doTestClientMessageWith(KeyPair userKeyPair) throws Exception {
-    PublicKey userPublicKey = userKeyPair.getPublic();
-    // Will use a Tickle for the test message, even though that would normally
-    // only be sent from the server to the client
-    long tickleExpiry = 12345L;
-    Tickle tickle = Tickle.newBuilder()
-        .setExpiryTime(tickleExpiry)
-        .build();
-
-    // Simulate sending a message
-    byte[] signcryptedMessage = TransportCryptoOps.signcryptClientMessage(
-        new Payload(PayloadType.TICKLE, tickle.toByteArray()),
-        userKeyPair,
-        masterKey);
-
-    // Simulate the process of receiving the message
-    byte[] encodedUserPublicKey = TransportCryptoOps.getEncodedUserPublicKeyFor(signcryptedMessage);
-    assertTrue(Arrays.equals(KeyEncoding.encodeUserPublicKey(userPublicKey), encodedUserPublicKey));
-    userPublicKey = KeyEncoding.parseUserPublicKey(encodedUserPublicKey);
-    // At this point the server would have looked up the masterKey for this userPublicKey
-
-    Payload received = TransportCryptoOps.verifydecryptClientMessage(
-        signcryptedMessage, userPublicKey, masterKey);
-
-    assertEquals(PayloadType.TICKLE, received.getPayloadType());
-    Tickle receivedTickle = Tickle.parseFrom(received.getMessage());
-    assertEquals(tickleExpiry, receivedTickle.getExpiryTime());
-  }
-}
diff --git a/src/main/javatest/com/google/security/cryptauth/lib/securegcm/Ukey2CppCompatibilityTest.java b/src/main/javatest/com/google/security/cryptauth/lib/securegcm/Ukey2CppCompatibilityTest.java
deleted file mode 100644
index db319e0..0000000
--- a/src/main/javatest/com/google/security/cryptauth/lib/securegcm/Ukey2CppCompatibilityTest.java
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.security.cryptauth.lib.securegcm;
-
-import com.google.security.cryptauth.lib.securegcm.Ukey2Handshake.HandshakeCipher;
-import com.google.security.cryptauth.lib.securegcm.Ukey2ShellCppWrapper.Mode;
-import java.util.Arrays;
-import junit.framework.TestCase;
-
-/**
- * Tests the compatibility between the Java and C++ implementations of the UKEY2 protocol. This
- * integration test executes and talks to a compiled binary exposing the C++ implementation (wrapped
- * by {@link Ukey2ShellCppWrapper}).
- *
- * <p>The C++ implementation is located in //security/cryptauth/lib/securegcm.
- */
-public class Ukey2CppCompatibilityTest extends TestCase {
-  private static final int VERIFICATION_STRING_LENGTH = 32;
-
-  private static final byte[] sPayload1 = "payload to encrypt1".getBytes();
-  private static final byte[] sPayload2 = "payload to encrypt2".getBytes();
-
-  /** Tests full handshake with C++ client and Java server. */
-  public void testCppClientJavaServer() throws Exception {
-    Ukey2ShellCppWrapper cppUkey2Shell =
-        new Ukey2ShellCppWrapper(Mode.INITIATOR, VERIFICATION_STRING_LENGTH);
-    cppUkey2Shell.startShell();
-    Ukey2Handshake javaUkey2Handshake = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-
-    // ClientInit:
-    byte[] clientInit = cppUkey2Shell.readHandshakeMessage();
-    javaUkey2Handshake.parseHandshakeMessage(clientInit);
-
-    // ServerInit:
-    byte[] serverInit = javaUkey2Handshake.getNextHandshakeMessage();
-    cppUkey2Shell.writeHandshakeMessage(serverInit);
-
-    // ClientFinished:
-    byte[] clientFinished = cppUkey2Shell.readHandshakeMessage();
-    javaUkey2Handshake.parseHandshakeMessage(clientFinished);
-
-    // Verification String:
-    cppUkey2Shell.confirmAuthString(
-        javaUkey2Handshake.getVerificationString(VERIFICATION_STRING_LENGTH));
-    javaUkey2Handshake.verifyHandshake();
-
-    // Secure channel:
-    D2DConnectionContext javaSecureContext = javaUkey2Handshake.toConnectionContext();
-
-    // ukey2_shell encodes data:
-    byte[] encodedData = cppUkey2Shell.sendEncryptCommand(sPayload1);
-    byte[] decodedData = javaSecureContext.decodeMessageFromPeer(encodedData);
-    assertTrue(Arrays.equals(sPayload1, decodedData));
-
-    // ukey2_shell decodes data:
-    encodedData = javaSecureContext.encodeMessageToPeer(sPayload2);
-    decodedData = cppUkey2Shell.sendDecryptCommand(encodedData);
-    assertTrue(Arrays.equals(sPayload2, decodedData));
-
-    // ukey2_shell session unique:
-    byte[] localSessionUnique = javaSecureContext.getSessionUnique();
-    byte[] remoteSessionUnique = cppUkey2Shell.sendSessionUniqueCommand();
-    assertTrue(Arrays.equals(localSessionUnique, remoteSessionUnique));
-
-    cppUkey2Shell.stopShell();
-  }
-
-  /** Tests full handshake with C++ server and Java client. */
-  public void testCppServerJavaClient() throws Exception {
-    Ukey2ShellCppWrapper cppUkey2Shell =
-        new Ukey2ShellCppWrapper(Mode.RESPONDER, VERIFICATION_STRING_LENGTH);
-    cppUkey2Shell.startShell();
-    Ukey2Handshake javaUkey2Handshake = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-
-    // ClientInit:
-    byte[] clientInit = javaUkey2Handshake.getNextHandshakeMessage();
-    cppUkey2Shell.writeHandshakeMessage(clientInit);
-
-    // ServerInit:
-    byte[] serverInit = cppUkey2Shell.readHandshakeMessage();
-    javaUkey2Handshake.parseHandshakeMessage(serverInit);
-
-    // ClientFinished:
-    byte[] clientFinished = javaUkey2Handshake.getNextHandshakeMessage();
-    cppUkey2Shell.writeHandshakeMessage(clientFinished);
-
-    // Verification String:
-    cppUkey2Shell.confirmAuthString(
-        javaUkey2Handshake.getVerificationString(VERIFICATION_STRING_LENGTH));
-    javaUkey2Handshake.verifyHandshake();
-
-    // Secure channel:
-    D2DConnectionContext javaSecureContext = javaUkey2Handshake.toConnectionContext();
-
-    // ukey2_shell encodes data:
-    byte[] encodedData = cppUkey2Shell.sendEncryptCommand(sPayload1);
-    byte[] decodedData = javaSecureContext.decodeMessageFromPeer(encodedData);
-    assertTrue(Arrays.equals(sPayload1, decodedData));
-
-    // ukey2_shell decodes data:
-    encodedData = javaSecureContext.encodeMessageToPeer(sPayload2);
-    decodedData = cppUkey2Shell.sendDecryptCommand(encodedData);
-    assertTrue(Arrays.equals(sPayload2, decodedData));
-
-    // ukey2_shell session unique:
-    byte[] localSessionUnique = javaSecureContext.getSessionUnique();
-    byte[] remoteSessionUnique = cppUkey2Shell.sendSessionUniqueCommand();
-    assertTrue(Arrays.equals(localSessionUnique, remoteSessionUnique));
-
-    cppUkey2Shell.stopShell();
-  }
-}
diff --git a/src/main/javatest/com/google/security/cryptauth/lib/securegcm/Ukey2HandshakeTest.java b/src/main/javatest/com/google/security/cryptauth/lib/securegcm/Ukey2HandshakeTest.java
deleted file mode 100644
index f5d0e1a..0000000
--- a/src/main/javatest/com/google/security/cryptauth/lib/securegcm/Ukey2HandshakeTest.java
+++ /dev/null
@@ -1,818 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.security.cryptauth.lib.securegcm;
-
-import com.google.protobuf.ByteString;
-import com.google.security.cryptauth.lib.securegcm.Ukey2Handshake.AlertException;
-import com.google.security.cryptauth.lib.securegcm.Ukey2Handshake.HandshakeCipher;
-import com.google.security.cryptauth.lib.securegcm.Ukey2Handshake.State;
-import com.google.security.cryptauth.lib.securegcm.UkeyProto.Ukey2ClientFinished;
-import com.google.security.cryptauth.lib.securegcm.UkeyProto.Ukey2ClientInit;
-import com.google.security.cryptauth.lib.securegcm.UkeyProto.Ukey2ClientInit.CipherCommitment;
-import com.google.security.cryptauth.lib.securegcm.UkeyProto.Ukey2Message;
-import com.google.security.cryptauth.lib.securegcm.UkeyProto.Ukey2ServerInit;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-import junit.framework.TestCase;
-import org.junit.Assert;
-
-/**
- * Android compatible tests for the {@link Ukey2Handshake} class.
- */
-public class Ukey2HandshakeTest extends TestCase {
-
-  private static final int MAX_AUTH_STRING_LENGTH = 32;
-
-  @Override
-  protected void setUp() throws Exception {
-    KeyEncodingTest.installSunEcSecurityProviderIfNecessary();
-    super.setUp();
-  }
-
-  /**
-   * Tests correct use
-   */
-  public void testHandshake() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    Ukey2Handshake client = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    Ukey2Handshake server = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    byte[] handshakeMessage;
-
-    assertEquals(State.IN_PROGRESS, client.getHandshakeState());
-    assertEquals(State.IN_PROGRESS, server.getHandshakeState());
-
-    // Message 1 (Client Init)
-    handshakeMessage = client.getNextHandshakeMessage();
-    server.parseHandshakeMessage(handshakeMessage);
-    assertEquals(State.IN_PROGRESS, client.getHandshakeState());
-    assertEquals(State.IN_PROGRESS, server.getHandshakeState());
-
-    // Message 2 (Server Init)
-    handshakeMessage = server.getNextHandshakeMessage();
-    client.parseHandshakeMessage(handshakeMessage);
-    assertEquals(State.IN_PROGRESS, client.getHandshakeState());
-    assertEquals(State.IN_PROGRESS, server.getHandshakeState());
-
-    // Message 3 (Client Finish)
-    handshakeMessage = client.getNextHandshakeMessage();
-    server.parseHandshakeMessage(handshakeMessage);
-    assertEquals(State.VERIFICATION_NEEDED, client.getHandshakeState());
-    assertEquals(State.VERIFICATION_NEEDED, server.getHandshakeState());
-
-    // Get the auth string
-    byte[] clientAuthString = client.getVerificationString(MAX_AUTH_STRING_LENGTH);
-    byte[] serverAuthString = server.getVerificationString(MAX_AUTH_STRING_LENGTH);
-    Assert.assertArrayEquals(clientAuthString, serverAuthString);
-    assertEquals(State.VERIFICATION_IN_PROGRESS, client.getHandshakeState());
-    assertEquals(State.VERIFICATION_IN_PROGRESS, server.getHandshakeState());
-
-    // Verify the auth string
-    client.verifyHandshake();
-    server.verifyHandshake();
-    assertEquals(State.FINISHED, client.getHandshakeState());
-    assertEquals(State.FINISHED, server.getHandshakeState());
-
-    // Make a context
-    D2DConnectionContext clientContext = client.toConnectionContext();
-    D2DConnectionContext serverContext = server.toConnectionContext();
-    assertContextsCompatible(clientContext, serverContext);
-    assertEquals(State.ALREADY_USED, client.getHandshakeState());
-    assertEquals(State.ALREADY_USED, server.getHandshakeState());
-  }
-
-  /**
-   * Verify enums for ciphers match the proto values
-   */
-  public void testCipherEnumValuesCorrect() {
-    assertEquals(
-        "You added a cipher, but forgot to change the test", 1, HandshakeCipher.values().length);
-
-    assertEquals(UkeyProto.Ukey2HandshakeCipher.P256_SHA512,
-        HandshakeCipher.P256_SHA512.getValue());
-  }
-
-  /**
-   * Tests incorrect use by callers (client and servers accidentally sending the wrong message at
-   * the wrong time)
-   */
-  public void testHandshakeClientAndServerSendRepeatedOutOfOrderMessages() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // Client sends ClientInit (again) instead of ClientFinished
-    Ukey2Handshake client = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    Ukey2Handshake server = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    byte[] handshakeMessage = client.getNextHandshakeMessage();
-    server.parseHandshakeMessage(handshakeMessage);
-    server.getNextHandshakeMessage(); // do this to avoid illegal state
-    try {
-      server.parseHandshakeMessage(handshakeMessage);
-      fail("Expected Alert for client sending ClientInit twice");
-    } catch (HandshakeException e) {
-      // success
-    }
-    assertEquals(State.ERROR, server.getHandshakeState());
-
-    // Server sends ClientInit back to client instead of ServerInit
-    client = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    server = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    handshakeMessage = client.getNextHandshakeMessage();
-    try {
-      client.parseHandshakeMessage(handshakeMessage);
-      fail("Expected Alert for server sending ClientInit back to client");
-    } catch (AlertException e) {
-      // success
-    }
-    assertEquals(State.ERROR, client.getHandshakeState());
-
-    // Clients sends ServerInit back to client instead of ClientFinished
-    client = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    server = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    handshakeMessage = client.getNextHandshakeMessage();
-    server.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = server.getNextHandshakeMessage();
-    try {
-      server.parseHandshakeMessage(handshakeMessage);
-      fail("Expected Alert for client sending ServerInit back to server");
-    } catch (HandshakeException e) {
-      // success
-    }
-    assertEquals(State.ERROR, server.getHandshakeState());
-  }
-
-  /**
-   * Tests that verification codes are different for different handshake runs. Also tests a full
-   * man-in-the-middle attack.
-   */
-  public void testVerificationCodeUniqueToSession() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // Client 1 and Server 1
-    Ukey2Handshake client1 = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    Ukey2Handshake server1 = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    byte[] handshakeMessage = client1.getNextHandshakeMessage();
-    server1.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = server1.getNextHandshakeMessage();
-    client1.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = client1.getNextHandshakeMessage();
-    server1.parseHandshakeMessage(handshakeMessage);
-    byte[] client1AuthString = client1.getVerificationString(MAX_AUTH_STRING_LENGTH);
-    byte[] server1AuthString = server1.getVerificationString(MAX_AUTH_STRING_LENGTH);
-    Assert.assertArrayEquals(client1AuthString, server1AuthString);
-
-    // Client 2 and Server 2
-    Ukey2Handshake client2 = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    Ukey2Handshake server2 = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    handshakeMessage = client2.getNextHandshakeMessage();
-    server2.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = server2.getNextHandshakeMessage();
-    client2.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = client2.getNextHandshakeMessage();
-    server2.parseHandshakeMessage(handshakeMessage);
-    byte[] client2AuthString = client2.getVerificationString(MAX_AUTH_STRING_LENGTH);
-    byte[] server2AuthString = server2.getVerificationString(MAX_AUTH_STRING_LENGTH);
-    Assert.assertArrayEquals(client2AuthString, server2AuthString);
-
-    // Make sure the verification strings differ
-    assertFalse(Arrays.equals(client1AuthString, client2AuthString));
-  }
-
-  /**
-   * Test an attack where the adversary swaps out the public key in the final message (i.e.,
-   * commitment doesn't match public key)
-   */
-  public void testPublicKeyDoesntMatchCommitment() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // Run handshake as usual, but stop before sending client finished
-    Ukey2Handshake client1 = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    Ukey2Handshake server1 = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    byte[] handshakeMessage = client1.getNextHandshakeMessage();
-    server1.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = server1.getNextHandshakeMessage();
-
-    // Run another handshake and get the final client finished
-    Ukey2Handshake client2 = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    Ukey2Handshake server2 = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    handshakeMessage = client2.getNextHandshakeMessage();
-    server2.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = server2.getNextHandshakeMessage();
-    client2.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = client2.getNextHandshakeMessage();
-
-    // Now use the client finished from second handshake in first handshake (simulates where an
-    // attacker switches out the last message).
-    try {
-      server1.parseHandshakeMessage(handshakeMessage);
-      fail("Expected server to catch mismatched ClientFinished");
-    } catch (HandshakeException e) {
-      // success
-    }
-    assertEquals(State.ERROR, server1.getHandshakeState());
-
-    // Make sure caller can't actually do anything with the server now that an error has occurred
-    try {
-      server1.getVerificationString(MAX_AUTH_STRING_LENGTH);
-      fail("Server allows operations post error");
-    } catch (IllegalStateException e) {
-      // success
-    }
-    try {
-      server1.verifyHandshake();
-      fail("Server allows operations post error");
-    } catch (IllegalStateException e) {
-      // success
-    }
-    try {
-      server1.toConnectionContext();
-      fail("Server allows operations post error");
-    } catch (IllegalStateException e) {
-      // success
-    }
-  }
-
-  /**
-   * Test commitment having unsupported version
-   */
-  public void testClientInitUnsupportedVersion() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // Get ClientInit and modify the version to be too big
-    Ukey2Handshake client = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    Ukey2Handshake server = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    byte[] handshakeMessage = client.getNextHandshakeMessage();
-
-    Ukey2Message.Builder message = Ukey2Message.newBuilder(
-        Ukey2Message.parseFrom(handshakeMessage));
-    Ukey2ClientInit.Builder clientInit =
-        Ukey2ClientInit.newBuilder(Ukey2ClientInit.parseFrom(message.getMessageData()));
-    clientInit.setVersion(Ukey2Handshake.VERSION + 1);
-    message.setMessageData(ByteString.copyFrom(clientInit.build().toByteArray()));
-    handshakeMessage = message.build().toByteArray();
-
-    try {
-      server.parseHandshakeMessage(handshakeMessage);
-      fail("Server did not catch unsupported version (too big) in ClientInit");
-    } catch (AlertException e) {
-      // success
-    }
-    assertEquals(State.ERROR, server.getHandshakeState());
-
-    // Get ClientInit and modify the version to be too big
-    client = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    server = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    handshakeMessage = client.getNextHandshakeMessage();
-
-    message = Ukey2Message.newBuilder(
-        Ukey2Message.parseFrom(handshakeMessage));
-    clientInit = Ukey2ClientInit.newBuilder(Ukey2ClientInit.parseFrom(message.getMessageData()));
-    clientInit.setVersion(0 /* minimum version is 1 */);
-    message.setMessageData(ByteString.copyFrom(clientInit.build().toByteArray()));
-    handshakeMessage = message.build().toByteArray();
-
-    try {
-      server.parseHandshakeMessage(handshakeMessage);
-      fail("Server did not catch unsupported version (too small) in ClientInit");
-    } catch (AlertException e) {
-      // success
-    }
-    assertEquals(State.ERROR, server.getHandshakeState());
-  }
-
-  /**
-   * Tests that server catches wrong number of random bytes in ClientInit
-   */
-  public void testWrongNonceLengthInClientInit() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // Get ClientInit and modify the nonce
-    Ukey2Handshake client = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    Ukey2Handshake server = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    byte[] handshakeMessage = client.getNextHandshakeMessage();
-
-    Ukey2Message.Builder message = Ukey2Message.newBuilder(
-        Ukey2Message.parseFrom(handshakeMessage));
-    Ukey2ClientInit.Builder clientInit =
-        Ukey2ClientInit.newBuilder(Ukey2ClientInit.parseFrom(message.getMessageData()));
-    clientInit.setRandom(
-        ByteString.copyFrom(
-            Arrays.copyOf(
-                clientInit.getRandom().toByteArray(),
-                31 /* as per go/ukey2, nonces must be 32 bytes long */)));
-    message.setMessageData(ByteString.copyFrom(clientInit.build().toByteArray()));
-    handshakeMessage = message.build().toByteArray();
-
-    try {
-      server.parseHandshakeMessage(handshakeMessage);
-      fail("Server did not catch nonce being too short in ClientInit");
-    } catch (AlertException e) {
-      // success
-    }
-    assertEquals(State.ERROR, server.getHandshakeState());
-  }
-
-  /**
-   * Test that server catches missing commitment in ClientInit message
-   */
-  public void testServerCatchesMissingCommitmentInClientInit() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // Get ClientInit and modify the commitment
-    Ukey2Handshake client = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    Ukey2Handshake server = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    byte[] handshakeMessage = client.getNextHandshakeMessage();
-
-    Ukey2Message.Builder message = Ukey2Message.newBuilder(
-        Ukey2Message.parseFrom(handshakeMessage));
-    Ukey2ClientInit clientInit =
-        Ukey2ClientInit.newBuilder(Ukey2ClientInit.parseFrom(message.getMessageData()))
-        .build();
-    Ukey2ClientInit.Builder badClientInit = Ukey2ClientInit.newBuilder()
-        .setVersion(clientInit.getVersion())
-        .setRandom(clientInit.getRandom());
-    for (CipherCommitment commitment : clientInit.getCipherCommitmentsList()) {
-      badClientInit.addCipherCommitments(commitment);
-    }
-
-    message.setMessageData(ByteString.copyFrom(badClientInit.build().toByteArray()));
-    handshakeMessage = message.build().toByteArray();
-
-    try {
-      server.parseHandshakeMessage(handshakeMessage);
-      fail("Server did not catch missing commitment in ClientInit");
-    } catch (AlertException e) {
-      // success
-    }
-  }
-
-  /**
-   * Test that client catches invalid version in ServerInit
-   */
-  public void testServerInitUnsupportedVersion() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // Get ServerInit and modify the version to be too big
-    Ukey2Handshake client = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    Ukey2Handshake server = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    byte[] handshakeMessage = client.getNextHandshakeMessage();
-    server.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = server.getNextHandshakeMessage();
-
-    Ukey2Message.Builder message = Ukey2Message.newBuilder(
-        Ukey2Message.parseFrom(handshakeMessage));
-    Ukey2ServerInit serverInit =
-        Ukey2ServerInit.newBuilder(Ukey2ServerInit.parseFrom(message.getMessageData()))
-            .setVersion(Ukey2Handshake.VERSION + 1)
-            .build();
-    message.setMessageData(ByteString.copyFrom(serverInit.toByteArray()));
-    handshakeMessage = message.build().toByteArray();
-
-    try {
-      client.parseHandshakeMessage(handshakeMessage);
-      fail("Client did not catch unsupported version (too big) in ServerInit");
-    } catch (AlertException e) {
-      // success
-    }
-    assertEquals(State.ERROR, client.getHandshakeState());
-
-    // Get ServerInit and modify the version to be too big
-    client = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    server = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    handshakeMessage = client.getNextHandshakeMessage();
-    server.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = server.getNextHandshakeMessage();
-
-    message = Ukey2Message.newBuilder(Ukey2Message.parseFrom(handshakeMessage));
-    serverInit =
-        Ukey2ServerInit.newBuilder(Ukey2ServerInit.parseFrom(message.getMessageData()))
-            .setVersion(0 /* minimum version is 1 */)
-            .build();
-    message.setMessageData(ByteString.copyFrom(serverInit.toByteArray()));
-    handshakeMessage = message.build().toByteArray();
-
-    try {
-      client.parseHandshakeMessage(handshakeMessage);
-      fail("Client did not catch unsupported version (too small) in ServerInit");
-    } catch (AlertException e) {
-      // success
-    }
-    assertEquals(State.ERROR, client.getHandshakeState());
-  }
-
-  /**
-   * Tests that client catches wrong number of random bytes in ServerInit
-   */
-  public void testWrongNonceLengthInServerInit() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // Get ServerInit and modify the nonce
-    Ukey2Handshake client = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    Ukey2Handshake server = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    byte[] handshakeMessage = client.getNextHandshakeMessage();
-    server.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = server.getNextHandshakeMessage();
-
-    Ukey2Message.Builder message = Ukey2Message.newBuilder(
-        Ukey2Message.parseFrom(handshakeMessage));
-    Ukey2ServerInit.Builder serverInitBuilder =
-        Ukey2ServerInit.newBuilder(Ukey2ServerInit.parseFrom(message.getMessageData()));
-    Ukey2ServerInit serverInit = serverInitBuilder.setRandom(ByteString.copyFrom(Arrays.copyOf(
-            serverInitBuilder.getRandom().toByteArray(),
-            31 /* as per go/ukey2, nonces must be 32 bytes long */)))
-        .build();
-    message.setMessageData(ByteString.copyFrom(serverInit.toByteArray()));
-    handshakeMessage = message.build().toByteArray();
-
-    try {
-      client.parseHandshakeMessage(handshakeMessage);
-      fail("Client did not catch nonce being too short in ServerInit");
-    } catch (AlertException e) {
-      // success
-    }
-    assertEquals(State.ERROR, client.getHandshakeState());
-  }
-
-  /**
-   * Test that client catches missing or incorrect handshake cipher in serverInit
-   */
-  public void testMissingOrIncorrectHandshakeCipherInServerInit() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // Get ServerInit
-    Ukey2Handshake client = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    Ukey2Handshake server = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    byte[] handshakeMessage = client.getNextHandshakeMessage();
-    server.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = server.getNextHandshakeMessage();
-    Ukey2Message.Builder message = Ukey2Message.newBuilder(
-        Ukey2Message.parseFrom(handshakeMessage));
-    Ukey2ServerInit serverInit = Ukey2ServerInit.parseFrom(message.getMessageData());
-
-    // remove handshake cipher
-    Ukey2ServerInit badServerInit = Ukey2ServerInit.newBuilder()
-        .setPublicKey(serverInit.getPublicKey())
-        .setRandom(serverInit.getRandom())
-        .setVersion(serverInit.getVersion())
-        .build();
-
-    message.setMessageData(ByteString.copyFrom(badServerInit.toByteArray()));
-    handshakeMessage = message.build().toByteArray();
-
-    try {
-      client.parseHandshakeMessage(handshakeMessage);
-      fail("Client did not catch missing handshake cipher in ServerInit");
-    } catch (AlertException e) {
-      // success
-    }
-    assertEquals(State.ERROR, client.getHandshakeState());
-
-    // Get ServerInit
-    client = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    server = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    handshakeMessage = client.getNextHandshakeMessage();
-    server.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = server.getNextHandshakeMessage();
-    message = Ukey2Message.newBuilder(Ukey2Message.parseFrom(handshakeMessage));
-    serverInit = Ukey2ServerInit.parseFrom(message.getMessageData());
-
-    // put in a bad handshake cipher
-    badServerInit = Ukey2ServerInit.newBuilder()
-        .setPublicKey(serverInit.getPublicKey())
-        .setRandom(serverInit.getRandom())
-        .setVersion(serverInit.getVersion())
-        .setHandshakeCipher(UkeyProto.Ukey2HandshakeCipher.RESERVED)
-        .build();
-
-    message.setMessageData(ByteString.copyFrom(badServerInit.toByteArray()));
-    handshakeMessage = message.build().toByteArray();
-
-    try {
-      client.parseHandshakeMessage(handshakeMessage);
-      fail("Client did not catch bad handshake cipher in ServerInit");
-    } catch (AlertException e) {
-      // success
-    }
-    assertEquals(State.ERROR, client.getHandshakeState());
-  }
-
-  /**
-   * Test that client catches missing or incorrect public key in serverInit
-   */
-  public void testMissingOrIncorrectPublicKeyInServerInit() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // Get ServerInit
-    Ukey2Handshake client = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    Ukey2Handshake server = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    byte[] handshakeMessage = client.getNextHandshakeMessage();
-    server.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = server.getNextHandshakeMessage();
-    Ukey2Message.Builder message = Ukey2Message.newBuilder(
-        Ukey2Message.parseFrom(handshakeMessage));
-    Ukey2ServerInit serverInit = Ukey2ServerInit.parseFrom(message.getMessageData());
-
-    // remove public key
-    Ukey2ServerInit badServerInit = Ukey2ServerInit.newBuilder()
-        .setRandom(serverInit.getRandom())
-        .setVersion(serverInit.getVersion())
-        .setHandshakeCipher(serverInit.getHandshakeCipher())
-        .build();
-
-    message.setMessageData(ByteString.copyFrom(badServerInit.toByteArray()));
-    handshakeMessage = message.build().toByteArray();
-
-    try {
-      client.parseHandshakeMessage(handshakeMessage);
-      fail("Client did not catch missing public key in ServerInit");
-    } catch (AlertException e) {
-      // success
-    }
-    assertEquals(State.ERROR, client.getHandshakeState());
-
-    // Get ServerInit
-    client = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    server = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    handshakeMessage = client.getNextHandshakeMessage();
-    server.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = server.getNextHandshakeMessage();
-    message = Ukey2Message.newBuilder(
-        Ukey2Message.parseFrom(handshakeMessage));
-    serverInit = Ukey2ServerInit.parseFrom(message.getMessageData());
-
-    // put in a bad public key
-    badServerInit = Ukey2ServerInit.newBuilder()
-        .setPublicKey(ByteString.copyFrom(new byte[] {42, 12, 1}))
-        .setRandom(serverInit.getRandom())
-        .setVersion(serverInit.getVersion())
-        .setHandshakeCipher(serverInit.getHandshakeCipher())
-        .build();
-
-    message.setMessageData(ByteString.copyFrom(badServerInit.toByteArray()));
-    handshakeMessage = message.build().toByteArray();
-
-    try {
-      client.parseHandshakeMessage(handshakeMessage);
-      fail("Client did not catch bad public key in ServerInit");
-    } catch (AlertException e) {
-      // success
-    }
-    assertEquals(State.ERROR, client.getHandshakeState());
-  }
-
-  /**
-   * Test that client catches missing or incorrect public key in clientFinished
-   */
-  public void testMissingOrIncorrectPublicKeyInClientFinished() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // Get ClientFinished
-    Ukey2Handshake client = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    Ukey2Handshake server = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    byte[] handshakeMessage = client.getNextHandshakeMessage();
-    server.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = server.getNextHandshakeMessage();
-    client.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = client.getNextHandshakeMessage();
-    Ukey2Message.Builder message = Ukey2Message.newBuilder(
-        Ukey2Message.parseFrom(handshakeMessage));
-
-    // remove public key
-    Ukey2ClientFinished.Builder badClientFinished = Ukey2ClientFinished.newBuilder();
-
-    message.setMessageData(ByteString.copyFrom(badClientFinished.build().toByteArray()));
-    handshakeMessage = message.build().toByteArray();
-
-    try {
-      server.parseHandshakeMessage(handshakeMessage);
-      fail("Server did not catch missing public key in ClientFinished");
-    } catch (HandshakeException e) {
-      // success
-    }
-    assertEquals(State.ERROR, server.getHandshakeState());
-
-    // Get ClientFinished
-    client = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    server = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    handshakeMessage = client.getNextHandshakeMessage();
-    server.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = server.getNextHandshakeMessage();
-    client.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = client.getNextHandshakeMessage();
-    message = Ukey2Message.newBuilder(Ukey2Message.parseFrom(handshakeMessage));
-
-    // remove public key
-    badClientFinished = Ukey2ClientFinished.newBuilder()
-        .setPublicKey(ByteString.copyFrom(new byte[] {42, 12, 1}));
-
-    message.setMessageData(ByteString.copyFrom(badClientFinished.build().toByteArray()));
-    handshakeMessage = message.build().toByteArray();
-
-    try {
-      server.parseHandshakeMessage(handshakeMessage);
-      fail("Server did not catch bad public key in ClientFinished");
-    } catch (HandshakeException e) {
-      // success
-    }
-    assertEquals(State.ERROR, server.getHandshakeState());
-  }
-
-  /**
-   * Tests that items (nonces, commitments, public keys) that should be random are at least
-   * different on every run.
-   */
-  public void testRandomItemsDifferentOnEveryRun() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    int numberOfRuns = 50;
-
-    // Search for collisions
-    Set<Integer> commitments = new HashSet<>(numberOfRuns);
-    Set<Integer> clientNonces = new HashSet<>(numberOfRuns);
-    Set<Integer> serverNonces = new HashSet<>(numberOfRuns);
-    Set<Integer> serverPublicKeys = new HashSet<>(numberOfRuns);
-    Set<Integer> clientPublicKeys = new HashSet<>(numberOfRuns);
-
-    for (int i = 0; i < numberOfRuns; i++) {
-      Ukey2Handshake client = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-      Ukey2Handshake server = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-      byte[] handshakeMessage = client.getNextHandshakeMessage();
-      Ukey2Message message = Ukey2Message.parseFrom(handshakeMessage);
-      Ukey2ClientInit clientInit = Ukey2ClientInit.parseFrom(message.getMessageData());
-
-      server.parseHandshakeMessage(handshakeMessage);
-      handshakeMessage = server.getNextHandshakeMessage();
-      message = Ukey2Message.parseFrom(handshakeMessage);
-      Ukey2ServerInit serverInit = Ukey2ServerInit.parseFrom(message.getMessageData());
-
-      client.parseHandshakeMessage(handshakeMessage);
-      handshakeMessage = client.getNextHandshakeMessage();
-      message = Ukey2Message.parseFrom(handshakeMessage);
-      Ukey2ClientFinished clientFinished = Ukey2ClientFinished.parseFrom(message.getMessageData());
-
-      // Clean up to save some memory (b/32054837)
-      client = null;
-      server = null;
-      handshakeMessage = null;
-      message = null;
-      System.gc();
-
-      // ClientInit randomness
-      Integer nonceHash = Integer.valueOf(Arrays.hashCode(clientInit.getRandom().toByteArray()));
-      if (clientNonces.contains(nonceHash) || serverNonces.contains(nonceHash)) {
-        fail("Nonce in ClientINit has repeated!");
-      }
-      clientNonces.add(nonceHash);
-
-      Integer commitmentHash = 0;
-      for (CipherCommitment commitement : clientInit.getCipherCommitmentsList()) {
-        commitmentHash += Arrays.hashCode(commitement.toByteArray());
-      }
-      if (commitments.contains(nonceHash)) {
-        fail("Commitment has repeated!");
-      }
-      commitments.add(commitmentHash);
-
-      // ServerInit randomness
-      nonceHash = Integer.valueOf(Arrays.hashCode(serverInit.getRandom().toByteArray()));
-      if (serverNonces.contains(nonceHash) || clientNonces.contains(nonceHash)) {
-        fail("Nonce in ServerInit repeated!");
-      }
-      serverNonces.add(nonceHash);
-
-      Integer publicKeyHash =
-          Integer.valueOf(Arrays.hashCode(serverInit.getPublicKey().toByteArray()));
-      if (serverPublicKeys.contains(publicKeyHash) || clientPublicKeys.contains(publicKeyHash)) {
-        fail("Public Key in ServerInit repeated!");
-      }
-      serverPublicKeys.add(publicKeyHash);
-
-      // Client Finished randomness
-      publicKeyHash = Integer.valueOf(Arrays.hashCode(clientFinished.getPublicKey().toByteArray()));
-      if (serverPublicKeys.contains(publicKeyHash) || clientPublicKeys.contains(publicKeyHash)) {
-        fail("Public Key in ClientFinished repeated!");
-      }
-      clientPublicKeys.add(publicKeyHash);
-    }
-  }
-
-  /**
-   * Tests that {@link Ukey2Handshake#getVerificationString(int)} enforces sane verification string
-   * lengths.
-   */
-  public void testGetVerificationEnforcesSaneLengths() throws Exception {
-    if (KeyEncoding.isLegacyCryptoRequired()) {
-      // this means we're running on an old SDK, which doesn't support the
-      // necessary crypto. Let's not test anything in this case.
-      return;
-    }
-
-    // Run the protocol
-    Ukey2Handshake client = Ukey2Handshake.forInitiator(HandshakeCipher.P256_SHA512);
-    Ukey2Handshake server = Ukey2Handshake.forResponder(HandshakeCipher.P256_SHA512);
-    byte[] handshakeMessage = client.getNextHandshakeMessage();
-    server.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = server.getNextHandshakeMessage();
-    client.parseHandshakeMessage(handshakeMessage);
-    handshakeMessage = client.getNextHandshakeMessage();
-    server.parseHandshakeMessage(handshakeMessage);
-
-    // Try to get too short verification string
-    try {
-      client.getVerificationString(0);
-      fail("Too short verification string allowed");
-    } catch (IllegalArgumentException e) {
-      // success
-    }
-
-    // Try to get too long verification string
-    try {
-      server.getVerificationString(MAX_AUTH_STRING_LENGTH + 1);
-      fail("Too long verification string allowed");
-    } catch (IllegalArgumentException e) {
-      // success
-    }
-  }
-
-  /**
-   * Asserts that the given client and server contexts are compatible
-   */
-  private void assertContextsCompatible(
-      D2DConnectionContext clientContext, D2DConnectionContext serverContext) {
-    assertNotNull(clientContext);
-    assertNotNull(serverContext);
-    assertEquals(D2DConnectionContextV1.PROTOCOL_VERSION, clientContext.getProtocolVersion());
-    assertEquals(D2DConnectionContextV1.PROTOCOL_VERSION, serverContext.getProtocolVersion());
-    assertEquals(clientContext.getEncodeKey(), serverContext.getDecodeKey());
-    assertEquals(clientContext.getDecodeKey(), serverContext.getEncodeKey());
-    assertFalse(clientContext.getEncodeKey().equals(clientContext.getDecodeKey()));
-    assertEquals(0, clientContext.getSequenceNumberForEncoding());
-    assertEquals(0, clientContext.getSequenceNumberForDecoding());
-    assertEquals(0, serverContext.getSequenceNumberForEncoding());
-    assertEquals(0, serverContext.getSequenceNumberForDecoding());
-  }
-}
diff --git a/src/main/javatest/com/google/security/cryptauth/lib/securegcm/Ukey2ShellCppWrapper.java b/src/main/javatest/com/google/security/cryptauth/lib/securegcm/Ukey2ShellCppWrapper.java
deleted file mode 100644
index 2b73653..0000000
--- a/src/main/javatest/com/google/security/cryptauth/lib/securegcm/Ukey2ShellCppWrapper.java
+++ /dev/null
@@ -1,342 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.security.cryptauth.lib.securegcm;
-
-import com.google.common.io.BaseEncoding;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.ProcessBuilder.Redirect;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Arrays;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import javax.annotation.Nullable;
-
-/**
- * A wrapper to execute and interact with the //security/cryptauth/lib/securegcm:ukey2_shell binary.
- *
- * <p>This binary is a shell over the C++ implementation of the UKEY2 protocol, so this wrapper is
- * used to test compatibility between the C++ and Java implementations.
- *
- * <p>The ukey2_shell is invoked as follows:
- *
- * <pre>{@code
- * ukey2_shell --mode=<mode> --verification_string_length=<length>
- * }</pre>
- *
- * where {@code mode={initiator, responder}} and {@code verification_string_length} is a positive
- * integer.
- */
-public class Ukey2ShellCppWrapper {
-  // The path the the ukey2_shell binary.
-  private static final String BINARY_PATH = "build/src/main/cpp/src/securegcm/ukey2_shell";
-
-  // The time to wait before timing out a read or write operation to the shell.
-  @SuppressWarnings("GoodTime") // TODO(b/147378611): store a java.time.Duration instead
-  private static final long IO_TIMEOUT_MILLIS = 5000;
-
-  public enum Mode {
-    INITIATOR,
-    RESPONDER
-  }
-
-  private final Mode mode;
-  private final int verificationStringLength;
-  private final ExecutorService executorService;
-
-  @Nullable private Process shellProcess;
-  private boolean secureContextEstablished;
-
-  /**
-   * @param mode The mode to run the shell in (initiator or responder).
-   * @param verificationStringLength The length of the verification string used in the handshake.
-   */
-  public Ukey2ShellCppWrapper(Mode mode, int verificationStringLength) {
-    this.mode = mode;
-    this.verificationStringLength = verificationStringLength;
-    this.executorService = Executors.newSingleThreadExecutor();
-  }
-
-  /**
-   * Begins execution of the ukey2_shell binary.
-   *
-   * @throws IOException
-   */
-  public void startShell() throws IOException {
-    if (shellProcess != null) {
-      throw new IllegalStateException("Shell already started.");
-    }
-
-    String modeArg = "--mode=" + getModeString();
-    String verificationStringLengthArg = "--verification_string_length=" + verificationStringLength;
-
-    final ProcessBuilder builder =
-        new ProcessBuilder(BINARY_PATH, modeArg, verificationStringLengthArg);
-
-    // Merge the shell's stderr with the stderr of the current process.
-    builder.redirectError(Redirect.INHERIT);
-
-    shellProcess = builder.start();
-  }
-
-  /**
-   * Stops execution of the ukey2_shell binary.
-   *
-   * @throws IOException
-   */
-  public void stopShell() {
-    if (shellProcess == null) {
-      throw new IllegalStateException("Shell not started.");
-    }
-    shellProcess.destroy();
-  }
-
-  /**
-   * @return the handshake message read from the shell.
-   * @throws IOException
-   */
-  public byte[] readHandshakeMessage() throws IOException {
-    return readFrameWithTimeout();
-  }
-
-  /**
-   * Sends the handshake message to the shell.
-   *
-   * @param message
-   * @throws IOException
-   */
-  public void writeHandshakeMessage(byte[] message) throws IOException {
-    writeFrameWithTimeout(message);
-  }
-
-  /**
-   * Reads the auth string from the shell and compares it with {@code authString}. If verification
-   * succeeds, then write "ok" back as a confirmation.
-   *
-   * @param authString the auth string to compare to.
-   * @throws IOException
-   */
-  public void confirmAuthString(byte[] authString) throws IOException {
-    byte[] shellAuthString = readFrameWithTimeout();
-    if (!Arrays.equals(authString, shellAuthString)) {
-      throw new IOException(
-          String.format(
-              "Unable to verify auth string: 0x%s != 0x%s",
-              BaseEncoding.base16().encode(authString),
-              BaseEncoding.base16().encode(shellAuthString)));
-    }
-    writeFrameWithTimeout("ok".getBytes());
-    secureContextEstablished = true;
-  }
-
-  /**
-   * Sends {@code payload} to be encrypted by the shell. This function can only be called after a
-   * handshake is performed and a secure context established.
-   *
-   * @param payload the data to be encrypted.
-   * @return the encrypted message returned by the shell.
-   * @throws IOException
-   */
-  public byte[] sendEncryptCommand(byte[] payload) throws IOException {
-    writeFrameWithTimeout(createExpression("encrypt", payload));
-    return readFrameWithTimeout();
-  }
-
-  /**
-   * Sends {@code message} to be decrypted by the shell. This function can only be called after a
-   * handshake is performed and a secure context established.
-   *
-   * @param message the data to be decrypted.
-   * @return the decrypted payload returned by the shell.
-   * @throws IOException
-   */
-  public byte[] sendDecryptCommand(byte[] message) throws IOException {
-    writeFrameWithTimeout(createExpression("decrypt", message));
-    return readFrameWithTimeout();
-  }
-
-  /**
-   * Requests the session unique value from the shell. This function can only be called after a
-   * handshake is performed and a secure context established.
-   *
-   * @return the session unique value returned by the shell.
-   * @throws IOException
-   */
-  public byte[] sendSessionUniqueCommand() throws IOException {
-    writeFrameWithTimeout(createExpression("session_unique", null));
-    return readFrameWithTimeout();
-  }
-
-  /**
-   * Reads a frame from the shell's stdout with a timeout.
-   *
-   * @return The contents of the frame.
-   * @throws IOException
-   */
-  private byte[] readFrameWithTimeout() throws IOException {
-    Future<byte[]> future =
-        executorService.submit(
-            new Callable<byte[]>() {
-              @Override
-              public byte[] call() throws Exception {
-                return readFrame();
-              }
-            });
-
-    try {
-      return future.get(IO_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
-    } catch (InterruptedException | ExecutionException | TimeoutException e) {
-      throw new IOException(e);
-    }
-  }
-
-  /**
-   * Writes a frame to the shell's stdin with a timeout.
-   *
-   * @param contents the contents of the frame.
-   * @throws IOException
-   */
-  private void writeFrameWithTimeout(final byte[] contents) throws IOException {
-    Future<?> future =
-        executorService.submit(
-            new Runnable() {
-              @Override
-              public void run() {
-                try {
-                  writeFrame(contents);
-                } catch (IOException e) {
-                  throw new RuntimeException(e);
-                }
-              }
-            });
-
-    try {
-      future.get(IO_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
-    } catch (InterruptedException | ExecutionException | TimeoutException e) {
-      throw new IOException(e);
-    }
-  }
-
-  /**
-   * Reads a frame from the shell's stdout, which has the format:
-   *
-   * <pre>{@code
-   * +---------------------+-----------------+
-   * | 4-bytes             | |length| bytes  |
-   * +---------------------+-----------------+
-   * | (unsigned) length   |     contents    |
-   * +---------------------+-----------------+
-   * }</pre>
-   *
-   * @return the contents that were read
-   * @throws IOException
-   */
-  private byte[] readFrame() throws IOException {
-    if (shellProcess == null) {
-      throw new IllegalStateException("Shell not started.");
-    }
-
-    InputStream inputStream = shellProcess.getInputStream();
-    byte[] lengthBytes = new byte[4];
-    if (inputStream.read(lengthBytes) != lengthBytes.length) {
-      throw new IOException("Failed to read length.");
-    }
-
-    int length = ByteBuffer.wrap(lengthBytes).order(ByteOrder.BIG_ENDIAN).getInt();
-    if (length < 0) {
-      throw new IOException("Length too large: " + Arrays.toString(lengthBytes));
-    }
-
-    byte[] contents = new byte[length];
-    int bytesRead = inputStream.read(contents);
-    if (bytesRead != length) {
-      throw new IOException("Failed to read entire contents: " + bytesRead + " != " + length);
-    }
-
-    return contents;
-  }
-
-  /**
-   * Writes a frame to the shell's stdin, which has the format:
-   *
-   * <pre>{@code
-   * +---------------------+-----------------+
-   * | 4-bytes             | |length| bytes  |
-   * +---------------------+-----------------+
-   * | (unsigned) length   |     contents    |
-   * +---------------------+-----------------+
-   * }</pre>
-   *
-   * @param contents the contents to send.
-   * @throws IOException
-   */
-  private void writeFrame(byte[] contents) throws IOException {
-    if (shellProcess == null) {
-      throw new IllegalStateException("Shell not started.");
-    }
-
-    // The length is big-endian encoded, network byte order.
-    long length = contents.length;
-    byte[] lengthBytes = new byte[4];
-    lengthBytes[0] = (byte) (length >> 32 & 0xFF);
-    lengthBytes[1] = (byte) (length >> 16 & 0xFF);
-    lengthBytes[2] = (byte) (length >> 8 & 0xFF);
-    lengthBytes[3] = (byte) (length >> 0 & 0xFF);
-
-    OutputStream outputStream = shellProcess.getOutputStream();
-    outputStream.write(lengthBytes);
-    outputStream.write(contents);
-    outputStream.flush();
-  }
-
-  /**
-   * Creates an expression to be processed when a secure connection is established, after the
-   * handshake is done.
-   *
-   * @param command The command to send.
-   * @param argument The argument of the command. Can be null.
-   * @return the expression that can be sent to the shell.
-   * @throws IOException.
-   */
-  private byte[] createExpression(String command, @Nullable byte[] argument) throws IOException {
-    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-    outputStream.write(command.getBytes());
-    outputStream.write(" ".getBytes());
-    if (argument != null) {
-      outputStream.write(argument);
-    }
-    return outputStream.toByteArray();
-  }
-
-  /** @return the mode string to use in the argument to start the ukey2_shell process. */
-  private String getModeString() {
-    switch (mode) {
-      case INITIATOR:
-        return "initiator";
-      case RESPONDER:
-        return "responder";
-      default:
-        throw new IllegalArgumentException("Uknown mode " + mode);
-    }
-  }
-}
diff --git a/src/main/javatest/com/google/security/cryptauth/lib/securemessage/CryptoOpsTest.java b/src/main/javatest/com/google/security/cryptauth/lib/securemessage/CryptoOpsTest.java
deleted file mode 100644
index 65fa094..0000000
--- a/src/main/javatest/com/google/security/cryptauth/lib/securemessage/CryptoOpsTest.java
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.security.cryptauth.lib.securemessage;
-
-import static org.junit.Assert.assertThrows;
-
-import com.google.security.cryptauth.lib.securemessage.CryptoOps.EncType;
-import com.google.security.cryptauth.lib.securemessage.CryptoOps.SigType;
-import java.util.Arrays;
-import javax.crypto.KeyGenerator;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
-import junit.framework.TestCase;
-
-/**
- * Unit tests for the CryptoOps class
- */
-public class CryptoOpsTest extends TestCase {
-
-  /** HKDF Test Case 1 IKM from RFC 5869 */
-  private static final byte[] HKDF_CASE1_IKM = {
-    0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
-    0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
-    0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
-    0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
-    0x0b, 0x0b
-  };
-
-  /** HKDF Test Case 1 salt from RFC 5869 */
-  private static final byte[] HKDF_CASE1_SALT = {
-    0x00, 0x01, 0x02, 0x03, 0x04,
-    0x05, 0x06, 0x07, 0x08, 0x09,
-    0x0a, 0x0b, 0x0c
-  };
-
-  /** HKDF Test Case 1 info from RFC 5869 */
-  private static final byte[] HKDF_CASE1_INFO = {
-    (byte) 0xf0, (byte) 0xf1, (byte) 0xf2, (byte) 0xf3, (byte) 0xf4,
-    (byte) 0xf5, (byte) 0xf6, (byte) 0xf7, (byte) 0xf8, (byte) 0xf9
-  };
-
-  /** First 32 bytes of HKDF Test Case 1 OKM (output) from RFC 5869 */
-  private static final byte[] HKDF_CASE1_OKM = {
-    (byte) 0x3c, (byte) 0xb2, (byte) 0x5f, (byte) 0x25, (byte) 0xfa,
-    (byte) 0xac, (byte) 0xd5, (byte) 0x7a, (byte) 0x90, (byte) 0x43,
-    (byte) 0x4f, (byte) 0x64, (byte) 0xd0, (byte) 0x36, (byte) 0x2f,
-    (byte) 0x2a, (byte) 0x2d, (byte) 0x2d, (byte) 0x0a, (byte) 0x90,
-    (byte) 0xcf, (byte) 0x1a, (byte) 0x5a, (byte) 0x4c, (byte) 0x5d,
-    (byte) 0xb0, (byte) 0x2d, (byte) 0x56, (byte) 0xec, (byte) 0xc4,
-    (byte) 0xc5, (byte) 0xbf, (byte) 0x34, (byte) 0x00, (byte) 0x72,
-    (byte) 0x08, (byte) 0xd5, (byte) 0xb8, (byte) 0x87, (byte) 0x18,
-    (byte) 0x58, (byte) 0x65
-  };
-
-  private SecretKey aesKey1;
-  private SecretKey aesKey2;
-
-  @Override
-  protected void setUp() throws Exception {
-    KeyGenerator aesKeygen = KeyGenerator.getInstance("AES");
-    aesKeygen.init(256);
-    aesKey1 = aesKeygen.generateKey();
-    aesKey2 = aesKeygen.generateKey();
-    super.setUp();
-  }
-
-  public void testNoPurposeConflicts() {
-    // Ensure that signature algorithms and encryption algorithms are not given identical purposes
-    // (this prevents confusion of derived keys).
-    for (SigType sigType : SigType.values()) {
-      for (EncType encType : EncType.values()) {
-        assertFalse(CryptoOps.getPurpose(sigType).equals(CryptoOps.getPurpose(encType)));
-      }
-    }
-  }
-
-  public void testDeriveAes256KeyFor() throws Exception {
-    // Test that deriving with the same key and purpose twice is deterministic
-    assertTrue(Arrays.equals(CryptoOps.deriveAes256KeyFor(aesKey1, "A").getEncoded(),
-                             CryptoOps.deriveAes256KeyFor(aesKey1, "A").getEncoded()));
-    // Test that derived keys with different purposes differ
-    assertFalse(Arrays.equals(CryptoOps.deriveAes256KeyFor(aesKey1, "A").getEncoded(),
-                              CryptoOps.deriveAes256KeyFor(aesKey1, "B").getEncoded()));
-    // Test that derived keys with the same purpose but different master keys differ
-    assertFalse(Arrays.equals(CryptoOps.deriveAes256KeyFor(aesKey1, "A").getEncoded(),
-                              CryptoOps.deriveAes256KeyFor(aesKey2, "A").getEncoded()));
-  }
-
-  public void testHkdf() throws Exception {
-    SecretKey inputKey = new SecretKeySpec(HKDF_CASE1_IKM, "AES");
-    byte[] result = CryptoOps.hkdf(inputKey, HKDF_CASE1_SALT, HKDF_CASE1_INFO);
-    byte[] expectedResult = Arrays.copyOf(HKDF_CASE1_OKM, 32);
-    assertTrue(Arrays.equals(result, expectedResult));
-  }
-
-  public void testHkdfLongOutput() throws Exception {
-    SecretKey inputKey = new SecretKeySpec(HKDF_CASE1_IKM, "AES");
-    byte[] result = CryptoOps.hkdf(inputKey, HKDF_CASE1_SALT, HKDF_CASE1_INFO, 42);
-    byte[] expectedResult = Arrays.copyOf(HKDF_CASE1_OKM, 42);
-    assertTrue(Arrays.equals(result, expectedResult));
-  }
-
-  public void testHkdfShortOutput() throws Exception {
-    SecretKey inputKey = new SecretKeySpec(HKDF_CASE1_IKM, "AES");
-    byte[] result = CryptoOps.hkdf(inputKey, HKDF_CASE1_SALT, HKDF_CASE1_INFO, 12);
-    byte[] expectedResult = Arrays.copyOf(HKDF_CASE1_OKM, 12);
-    assertTrue(Arrays.equals(result, expectedResult));
-  }
-
-  public void testHkdfInvalidLengths() throws Exception {
-    SecretKey inputKey = new SecretKeySpec(HKDF_CASE1_IKM, "AES");
-
-    // Negative length
-    assertThrows(
-        IllegalArgumentException.class,
-        () -> CryptoOps.hkdf(inputKey, HKDF_CASE1_SALT, HKDF_CASE1_INFO, -5));
-
-    // Too long, would be more than 256 blocks
-    assertThrows(
-        IllegalArgumentException.class,
-        () -> CryptoOps.hkdf(inputKey, HKDF_CASE1_SALT, HKDF_CASE1_INFO, 32 * 256 + 1));
-  }
-
-  public void testConcat() {
-    byte[] a = { 1, 2, 3, 4};
-    byte[] b = { 5 , 6 };
-    byte[] expectedResult = { 1, 2, 3, 4, 5, 6 };
-    byte[] result = CryptoOps.concat(a, b);
-    assertEquals(a.length + b.length, result.length);
-    assertTrue(Arrays.equals(expectedResult, result));
-
-    byte[] empty =  { };
-    assertEquals(0, CryptoOps.concat(empty, empty).length);
-    assertTrue(Arrays.equals(a, CryptoOps.concat(a, empty)));
-    assertTrue(Arrays.equals(a, CryptoOps.concat(empty, a)));
-
-    assertEquals(0, CryptoOps.concat(null, null).length);
-    assertTrue(Arrays.equals(a, CryptoOps.concat(a, null)));
-    assertTrue(Arrays.equals(a, CryptoOps.concat(null, a)));
-  }
-
-  public void testSubarray() {
-    byte[] in = { 1, 2, 3, 4, 5, 6, 7 };
-    assertTrue(Arrays.equals(in, CryptoOps.subarray(in, 0, in.length)));
-    assertEquals(0, CryptoOps.subarray(in, 0, 0).length);
-    byte[] expectedResult1 = { 1 };
-    assertTrue(Arrays.equals(expectedResult1, CryptoOps.subarray(in, 0, 1)));
-    byte[] expectedResult34 = { 3, 4 };
-    assertTrue(Arrays.equals(expectedResult34, CryptoOps.subarray(in, 2, 4)));
-    assertThrows(IndexOutOfBoundsException.class, () -> CryptoOps.subarray(in, 0, in.length + 1));
-    assertThrows(IndexOutOfBoundsException.class, () -> CryptoOps.subarray(in, -1, in.length));
-    assertThrows(
-        IndexOutOfBoundsException.class, () -> CryptoOps.subarray(in, in.length, in.length));
-    assertThrows(
-        IndexOutOfBoundsException.class,
-        () -> CryptoOps.subarray(in, Integer.MIN_VALUE, in.length));
-    assertThrows(
-        IndexOutOfBoundsException.class, () -> CryptoOps.subarray(in, 1, Integer.MIN_VALUE));
-  }
-}
diff --git a/src/main/javatest/com/google/security/cryptauth/lib/securemessage/NullsGoogle3Test.java b/src/main/javatest/com/google/security/cryptauth/lib/securemessage/NullsGoogle3Test.java
deleted file mode 100644
index c28d2f9..0000000
--- a/src/main/javatest/com/google/security/cryptauth/lib/securemessage/NullsGoogle3Test.java
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.security.cryptauth.lib.securemessage;
-
-import com.google.common.testing.NullPointerTester;
-import com.google.security.cryptauth.lib.securemessage.SecureMessageProto.SecureMessage;
-import junit.framework.TestCase;
-
-/**
- * Non-portable Google3-based test to check null pointer behavior.
- */
-public class NullsGoogle3Test extends TestCase {
-
-  /**
-   *  We test all of the classes in one place to avoid a proliferation of similar test cases,
-   * noting that {@link NullPointerTester} emits the name of the class where the breakge occurs.
-   */
-  public void testNulls() {
-    final NullPointerTester tester = new NullPointerTester();
-    tester.testAllPublicStaticMethods(CryptoOps.class);
-    tester.testAllPublicStaticMethods(PublicKeyProtoUtil.class);
-
-    tester.setDefault(SecureMessage.class, SecureMessage.getDefaultInstance());
-    tester.testAllPublicStaticMethods(SecureMessageParser.class);
-
-    tester.testAllPublicStaticMethods(SecureMessageBuilder.class);
-    tester.testAllPublicConstructors(SecureMessageBuilder.class);
-    tester.testAllPublicInstanceMethods(new SecureMessageBuilder());
-  }
-}
diff --git a/src/main/javatest/com/google/security/cryptauth/lib/securemessage/PublicKeyProtoUtilTest.java b/src/main/javatest/com/google/security/cryptauth/lib/securemessage/PublicKeyProtoUtilTest.java
deleted file mode 100644
index 8581622..0000000
--- a/src/main/javatest/com/google/security/cryptauth/lib/securemessage/PublicKeyProtoUtilTest.java
+++ /dev/null
@@ -1,412 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.security.cryptauth.lib.securemessage;
-
-import com.google.common.io.BaseEncoding;
-import com.google.protobuf.ByteString;
-import com.google.security.annotations.SuppressInsecureCipherModeCheckerNoReview;
-import com.google.security.cryptauth.lib.securemessage.SecureMessageProto.DhPublicKey;
-import com.google.security.cryptauth.lib.securemessage.SecureMessageProto.EcP256PublicKey;
-import com.google.security.cryptauth.lib.securemessage.SecureMessageProto.GenericPublicKey;
-import com.google.security.cryptauth.lib.securemessage.SecureMessageProto.SimpleRsaPublicKey;
-import java.math.BigInteger;
-import java.security.KeyFactory;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.interfaces.ECPublicKey;
-import java.security.spec.ECPoint;
-import java.security.spec.ECPublicKeySpec;
-import java.security.spec.InvalidKeySpecException;
-import java.util.Arrays;
-import javax.crypto.KeyAgreement;
-import javax.crypto.interfaces.DHPrivateKey;
-import javax.crypto.interfaces.DHPublicKey;
-import junit.framework.TestCase;
-
-/** Tests for the PublicKeyProtoUtil class. */
-public class PublicKeyProtoUtilTest extends TestCase {
-
-  private static final byte[] ZERO_BYTE = {0};
-  private PublicKey ecPublicKey;
-  private PublicKey rsaPublicKey;
-
-  /**
-   * Diffie Hellman {@link PublicKey}s require special treatment, so we store them specifically as a
-   * {@link DHPublicKey} to minimize casting.
-   */
-  private DHPublicKey dhPublicKey;
-
-  @Override
-  public void setUp() {
-    if (!isAndroidOsWithoutEcSupport()) {
-      ecPublicKey = PublicKeyProtoUtil.generateEcP256KeyPair().getPublic();
-    }
-    rsaPublicKey = PublicKeyProtoUtil.generateRSA2048KeyPair().getPublic();
-    dhPublicKey = (DHPublicKey) PublicKeyProtoUtil.generateDh2048KeyPair().getPublic();
-  }
-
-  public void testPublicKeyProtoSpecificEncodeParse() throws Exception {
-    if (!isAndroidOsWithoutEcSupport()) {
-      assertEquals(
-          ecPublicKey,
-          PublicKeyProtoUtil.parseEcPublicKey(PublicKeyProtoUtil.encodeEcPublicKey(ecPublicKey)));
-    }
-
-    assertEquals(
-        rsaPublicKey,
-        PublicKeyProtoUtil.parseRsa2048PublicKey(
-            PublicKeyProtoUtil.encodeRsa2048PublicKey(rsaPublicKey)));
-
-    // DHPublicKey objects don't seem to properly implement equals(), so we have to test that
-    // the individual y and p values match (it is safe to assume g = 2 is used if p is correct).
-    DHPublicKey parsedDHPublicKey =
-        PublicKeyProtoUtil.parseDh2048PublicKey(
-            PublicKeyProtoUtil.encodeDh2048PublicKey(dhPublicKey));
-    assertEquals(dhPublicKey.getY(), parsedDHPublicKey.getY());
-    assertEquals(dhPublicKey.getParams().getP(), parsedDHPublicKey.getParams().getP());
-    assertEquals(dhPublicKey.getParams().getG(), parsedDHPublicKey.getParams().getG());
-  }
-
-  public void testPublicKeyProtoGenericEncodeParse() throws Exception {
-    if (!isAndroidOsWithoutEcSupport()) {
-      assertEquals(
-          ecPublicKey,
-          PublicKeyProtoUtil.parsePublicKey(
-              PublicKeyProtoUtil.encodePaddedEcPublicKey(ecPublicKey)));
-      assertEquals(
-          ecPublicKey,
-          PublicKeyProtoUtil.parsePublicKey(PublicKeyProtoUtil.encodePublicKey(ecPublicKey)));
-    }
-
-    assertEquals(
-        rsaPublicKey,
-        PublicKeyProtoUtil.parsePublicKey(PublicKeyProtoUtil.encodePublicKey(rsaPublicKey)));
-
-    // See above explanation for why we treat DHPublicKey objects differently.
-    DHPublicKey parsedDHPublicKey =
-        PublicKeyProtoUtil.parseDh2048PublicKey(
-            PublicKeyProtoUtil.encodeDh2048PublicKey(dhPublicKey));
-    assertEquals(dhPublicKey.getY(), parsedDHPublicKey.getY());
-    assertEquals(dhPublicKey.getParams().getP(), parsedDHPublicKey.getParams().getP());
-    assertEquals(dhPublicKey.getParams().getG(), parsedDHPublicKey.getParams().getG());
-  }
-
-  public void testPaddedECPublicKeyEncodeHasPaddedNullByte() throws Exception {
-    if (isAndroidOsWithoutEcSupport()) {
-      return;
-    }
-
-    // Key where the x coordinate is 33 bytes, y coordinate is 32 bytes
-    ECPublicKey maxXByteLengthKey =
-        buildEcPublicKey(
-            BaseEncoding.base64().decode("AM730WQL7ZAmvyAJX4euNdr3+nAIueGlYYGXE6p732h6"),
-            BaseEncoding.base64().decode("JEnmaDpKn0fH4/0kKGb97qUSwI2uT+ta0GLe3V7REfk="));
-    // Key where both coordinates are 33 bytes
-    ECPublicKey maxByteLengthKey =
-        buildEcPublicKey(
-            BaseEncoding.base64().decode("AOg9TQCxFfVdXv7lO/6UVDyiPsu8XDkEWQIPUfqX6UHP"),
-            BaseEncoding.base64().decode("AP/RW8uVyu6QImpbza51CqG1mtBTh5c9pjv9CUwOuB7E"));
-    // Key where both coordinates are 32 bytes
-    ECPublicKey notMaxByteLengthKey =
-        buildEcPublicKey(
-            BaseEncoding.base64().decode("M35bxV8HKr0e8v7f4zuXgw6TYFawvikFdI71u9S1ONI="),
-            BaseEncoding.base64().decode("OXR+xCpD8AR0VR8TeBXA00eIr3rWE6sV6KrOM6MoWsc="));
-    GenericPublicKey encodedMaxXByteLengthKey =
-        PublicKeyProtoUtil.encodePublicKey(maxXByteLengthKey);
-    GenericPublicKey paddedEncodedMaxXByteLengthKey =
-        PublicKeyProtoUtil.encodePaddedEcPublicKey(maxXByteLengthKey);
-    GenericPublicKey encodedMaxByteLengthKey = PublicKeyProtoUtil.encodePublicKey(maxByteLengthKey);
-    GenericPublicKey paddedEncodedMaxByteLengthKey =
-        PublicKeyProtoUtil.encodePaddedEcPublicKey(maxByteLengthKey);
-    GenericPublicKey encodedNotMaxByteLengthKey =
-        PublicKeyProtoUtil.encodePublicKey(notMaxByteLengthKey);
-    GenericPublicKey paddedEncodedNotMaxByteLengthKey =
-        PublicKeyProtoUtil.encodePaddedEcPublicKey(notMaxByteLengthKey);
-
-    assertEquals(maxXByteLengthKey, PublicKeyProtoUtil.parsePublicKey(encodedMaxXByteLengthKey));
-    assertEquals(
-        maxXByteLengthKey, PublicKeyProtoUtil.parsePublicKey(paddedEncodedMaxXByteLengthKey));
-    assertEquals(maxByteLengthKey, PublicKeyProtoUtil.parsePublicKey(encodedMaxByteLengthKey));
-    assertEquals(
-        maxByteLengthKey, PublicKeyProtoUtil.parsePublicKey(paddedEncodedMaxByteLengthKey));
-    assertEquals(
-        notMaxByteLengthKey, PublicKeyProtoUtil.parsePublicKey(paddedEncodedNotMaxByteLengthKey));
-    assertEquals(
-        notMaxByteLengthKey, PublicKeyProtoUtil.parsePublicKey(encodedNotMaxByteLengthKey));
-
-    assertEquals(33, paddedEncodedMaxXByteLengthKey.getEcP256PublicKey().getX().size());
-    assertEquals(33, paddedEncodedMaxXByteLengthKey.getEcP256PublicKey().getY().size());
-    assertEquals(0, paddedEncodedMaxXByteLengthKey.getEcP256PublicKey().getX().byteAt(0));
-    assertEquals(0, paddedEncodedMaxXByteLengthKey.getEcP256PublicKey().getY().byteAt(0));
-    assertEquals(33, encodedMaxXByteLengthKey.getEcP256PublicKey().getX().size());
-    assertEquals(32, encodedMaxXByteLengthKey.getEcP256PublicKey().getY().size());
-
-    assertEquals(33, paddedEncodedMaxByteLengthKey.getEcP256PublicKey().getX().size());
-    assertEquals(33, paddedEncodedMaxByteLengthKey.getEcP256PublicKey().getY().size());
-    assertEquals(0, paddedEncodedMaxByteLengthKey.getEcP256PublicKey().getX().byteAt(0));
-    assertEquals(0, paddedEncodedMaxByteLengthKey.getEcP256PublicKey().getY().byteAt(0));
-    assertEquals(33, encodedMaxByteLengthKey.getEcP256PublicKey().getX().size());
-    assertEquals(33, encodedMaxByteLengthKey.getEcP256PublicKey().getY().size());
-
-    assertEquals(32, encodedNotMaxByteLengthKey.getEcP256PublicKey().getX().size());
-    assertEquals(32, encodedNotMaxByteLengthKey.getEcP256PublicKey().getY().size());
-    assertEquals(0, paddedEncodedNotMaxByteLengthKey.getEcP256PublicKey().getX().byteAt(0));
-    assertEquals(0, paddedEncodedNotMaxByteLengthKey.getEcP256PublicKey().getY().byteAt(0));
-    assertEquals(33, paddedEncodedNotMaxByteLengthKey.getEcP256PublicKey().getX().size());
-    assertEquals(33, paddedEncodedNotMaxByteLengthKey.getEcP256PublicKey().getY().size());
-  }
-
-  @SuppressInsecureCipherModeCheckerNoReview
-  public void testWrongPublicKeyType() throws Exception {
-    KeyPairGenerator dsaGen = KeyPairGenerator.getInstance("DSA");
-    dsaGen.initialize(512);
-    PublicKey pk = dsaGen.generateKeyPair().getPublic();
-
-    if (!isAndroidOsWithoutEcSupport()) {
-      // Try to encode it as EC
-      try {
-        PublicKeyProtoUtil.encodeEcPublicKey(pk);
-        fail();
-      } catch (IllegalArgumentException expected) {
-      }
-
-      try {
-        PublicKeyProtoUtil.encodePaddedEcPublicKey(pk);
-        fail();
-      } catch (IllegalArgumentException expected) {
-      }
-    }
-
-    // Try to encode it as RSA
-    try {
-      PublicKeyProtoUtil.encodeRsa2048PublicKey(pk);
-      fail();
-    } catch (IllegalArgumentException expected) {
-    }
-
-    // Try to encode it as DH
-    try {
-      PublicKeyProtoUtil.encodeDh2048PublicKey(pk);
-      fail();
-    } catch (IllegalArgumentException expected) {
-    }
-
-    // Try to encode it as Generic
-    try {
-      PublicKeyProtoUtil.encodePublicKey(pk);
-      fail();
-    } catch (IllegalArgumentException expected) {
-    }
-  }
-
-  public void testEcPublicKeyProtoInvalidEncoding() throws Exception {
-    if (isAndroidOsWithoutEcSupport()) {
-      return;
-    }
-
-    EcP256PublicKey validProto = PublicKeyProtoUtil.encodeEcPublicKey(ecPublicKey);
-    EcP256PublicKey.Builder invalidProto = EcP256PublicKey.newBuilder(validProto);
-
-    // Mess up the X coordinate by repeating it twice
-    byte[] newX =
-        CryptoOps.concat(validProto.getX().toByteArray(), validProto.getX().toByteArray());
-    checkParsingFailsFor(invalidProto.setX(ByteString.copyFrom(newX)).build());
-
-    // Mess up the Y coordinate by erasing it
-    invalidProto = EcP256PublicKey.newBuilder(validProto);
-    checkParsingFailsFor(invalidProto.setY(ByteString.EMPTY).build());
-
-    // Pick a point that is likely not on the curve by copying X over Y
-    invalidProto = EcP256PublicKey.newBuilder(validProto);
-    checkParsingFailsFor(invalidProto.setY(validProto.getX()).build());
-
-    // Try the point (0, 0)
-    invalidProto = EcP256PublicKey.newBuilder(validProto);
-    checkParsingFailsFor(
-        invalidProto
-            .setX(ByteString.copyFrom(ZERO_BYTE))
-            .setY(ByteString.copyFrom(ZERO_BYTE))
-            .build());
-  }
-
-  private void checkParsingFailsFor(EcP256PublicKey invalid) {
-    try {
-      // Should fail to decode
-      PublicKeyProtoUtil.parseEcPublicKey(invalid);
-      fail();
-    } catch (InvalidKeySpecException expected) {
-    }
-  }
-
-  public void testSimpleRsaPublicKeyProtoInvalidEncoding() throws Exception {
-    SimpleRsaPublicKey validProto = PublicKeyProtoUtil.encodeRsa2048PublicKey(rsaPublicKey);
-    SimpleRsaPublicKey.Builder invalidProto;
-
-    // Double the number of bits in the modulus
-    invalidProto = SimpleRsaPublicKey.newBuilder(validProto);
-    byte[] newN =
-        CryptoOps.concat(validProto.getN().toByteArray(), validProto.getN().toByteArray());
-    checkParsingFailsFor(invalidProto.setN(ByteString.copyFrom(newN)).build());
-
-    // Set the modulus to 0
-    invalidProto = SimpleRsaPublicKey.newBuilder(validProto);
-    checkParsingFailsFor(invalidProto.setN(ByteString.copyFrom(ZERO_BYTE)).build());
-
-    // Set the modulus to 65537 (way too small)
-    invalidProto = SimpleRsaPublicKey.newBuilder(validProto);
-    checkParsingFailsFor(
-        invalidProto.setN(ByteString.copyFrom(BigInteger.valueOf(65537).toByteArray())).build());
-  }
-
-  private static void checkParsingFailsFor(SimpleRsaPublicKey invalid) {
-    try {
-      // Should fail to decode
-      PublicKeyProtoUtil.parseRsa2048PublicKey(invalid);
-      fail();
-    } catch (InvalidKeySpecException expected) {
-    }
-  }
-
-  public void testSimpleDhPublicKeyProtoInvalidEncoding() throws Exception {
-    DhPublicKey validProto = PublicKeyProtoUtil.encodeDh2048PublicKey(dhPublicKey);
-    DhPublicKey.Builder invalidProto;
-
-    // Double the number of bits in the public element encoding
-    invalidProto = DhPublicKey.newBuilder(validProto);
-    byte[] newY =
-        CryptoOps.concat(validProto.getY().toByteArray(), validProto.getY().toByteArray());
-    checkParsingFailsFor(invalidProto.setY(ByteString.copyFrom(newY)).build());
-
-    // Set the public element to 0
-    invalidProto = DhPublicKey.newBuilder(validProto);
-    checkParsingFailsFor(invalidProto.setY(ByteString.copyFrom(ZERO_BYTE)).build());
-  }
-
-  private static void checkParsingFailsFor(DhPublicKey invalid) {
-    try {
-      // Should fail to decode
-      PublicKeyProtoUtil.parseDh2048PublicKey(invalid);
-      fail();
-    } catch (InvalidKeySpecException expected) {
-    }
-  }
-
-  public void testDhKeyAgreementWorks() throws Exception {
-    int minExpectedSecretLength = (PublicKeyProtoUtil.DH_P.bitLength() / 8) - 4;
-
-    KeyPair clientKeyPair = PublicKeyProtoUtil.generateDh2048KeyPair();
-    KeyPair serverKeyPair = PublicKeyProtoUtil.generateDh2048KeyPair();
-    BigInteger clientY = ((DHPublicKey) clientKeyPair.getPublic()).getY();
-    BigInteger serverY = ((DHPublicKey) serverKeyPair.getPublic()).getY();
-    assertFalse(clientY.equals(serverY)); // DHPublicKeys should not be equal
-
-    // Run client side of the key exchange
-    byte[] clientSecret = doDhAgreement(clientKeyPair.getPrivate(), serverKeyPair.getPublic());
-    assert (clientSecret.length >= minExpectedSecretLength);
-
-    // Run the server side of the key exchange
-    byte[] serverSecret = doDhAgreement(serverKeyPair.getPrivate(), clientKeyPair.getPublic());
-    assert (serverSecret.length >= minExpectedSecretLength);
-
-    assertTrue(Arrays.equals(clientSecret, serverSecret));
-  }
-
-  public void testDh2048PrivateKeyEncoding() throws Exception {
-    KeyPair testPair = PublicKeyProtoUtil.generateDh2048KeyPair();
-    DHPrivateKey sk = (DHPrivateKey) testPair.getPrivate();
-    DHPrivateKey skParsed =
-        PublicKeyProtoUtil.parseDh2048PrivateKey(PublicKeyProtoUtil.encodeDh2048PrivateKey(sk));
-    assertEquals(sk.getX(), skParsed.getX());
-    assertEquals(sk.getParams().getP(), skParsed.getParams().getP());
-    assertEquals(sk.getParams().getG(), skParsed.getParams().getG());
-  }
-
-  public void testParseEcPublicKeyOnLegacyPlatform() {
-    if (!PublicKeyProtoUtil.isLegacyCryptoRequired()) {
-      return; // This test only runs on legacy platforms
-    }
-    byte[] pointBytes = {
-      1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
-      1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
-      1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
-      1, 2
-    };
-
-    try {
-      PublicKeyProtoUtil.parseEcPublicKey(
-          EcP256PublicKey.newBuilder()
-              .setX(ByteString.copyFrom(pointBytes))
-              .setY(ByteString.copyFrom(pointBytes))
-              .build());
-      fail();
-    } catch (InvalidKeySpecException expected) {
-      // Should get this specific exception when EC doesn't work
-    }
-  }
-
-  public void testIsLegacyCryptoRequired() {
-    assertEquals(isAndroidOsWithoutEcSupport(), PublicKeyProtoUtil.isLegacyCryptoRequired());
-  }
-
-  /** @return true if running on an Android OS that doesn't support Elliptic Curve algorithms */
-  public static boolean isAndroidOsWithoutEcSupport() {
-    try {
-      Class<?> clazz = ClassLoader.getSystemClassLoader().loadClass("android.os.Build$VERSION");
-      int sdkVersion = clazz.getField("SDK_INT").getInt(null);
-      if (sdkVersion < PublicKeyProtoUtil.ANDROID_HONEYCOMB_SDK_INT) {
-        return true;
-      }
-    } catch (ClassNotFoundException e) {
-      // Not running on Android
-      return false;
-    } catch (SecurityException e) {
-      throw new AssertionError(e);
-    } catch (NoSuchFieldException e) {
-      throw new AssertionError(e);
-    } catch (IllegalArgumentException e) {
-      throw new AssertionError(e);
-    } catch (IllegalAccessException e) {
-      throw new AssertionError(e);
-    }
-    return false;
-  }
-
-  @SuppressInsecureCipherModeCheckerNoReview
-  private static byte[] doDhAgreement(PrivateKey secretKey, PublicKey peerKey) throws Exception {
-    KeyAgreement agreement = KeyAgreement.getInstance("DH");
-    agreement.init(secretKey);
-    agreement.doPhase(peerKey, true);
-    return agreement.generateSecret();
-  }
-
-  private static ECPublicKey buildEcPublicKey(byte[] encodedX, byte[] encodedY) throws Exception {
-    try {
-      BigInteger wX = new BigInteger(encodedX);
-      BigInteger wY = new BigInteger(encodedY);
-      return (ECPublicKey)
-          KeyFactory.getInstance("EC")
-              .generatePublic(
-                  new ECPublicKeySpec(
-                      new ECPoint(wX, wY),
-                      ((ECPublicKey) PublicKeyProtoUtil.generateEcP256KeyPair().getPublic())
-                          .getParams()));
-    } catch (NoSuchAlgorithmException e) {
-      throw new RuntimeException(e);
-    }
-  }
-}
diff --git a/src/main/javatest/com/google/security/cryptauth/lib/securemessage/SecureMessageSimpleTestVectorTest.java b/src/main/javatest/com/google/security/cryptauth/lib/securemessage/SecureMessageSimpleTestVectorTest.java
deleted file mode 100644
index 285b259..0000000
--- a/src/main/javatest/com/google/security/cryptauth/lib/securemessage/SecureMessageSimpleTestVectorTest.java
+++ /dev/null
@@ -1,403 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.security.cryptauth.lib.securemessage;
-
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.security.cryptauth.lib.securemessage.CryptoOps.EncType;
-import com.google.security.cryptauth.lib.securemessage.CryptoOps.SigType;
-import com.google.security.cryptauth.lib.securemessage.SecureMessageProto.GenericPublicKey;
-import com.google.security.cryptauth.lib.securemessage.SecureMessageProto.Header;
-import com.google.security.cryptauth.lib.securemessage.SecureMessageProto.HeaderAndBody;
-import com.google.security.cryptauth.lib.securemessage.SecureMessageProto.SecureMessage;
-import java.security.KeyFactory;
-import java.security.KeyPair;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.util.Arrays;
-import javax.crypto.KeyGenerator;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
-import junit.framework.TestCase;
-
-/**
- * Tests the library against some very basic test vectors, to help ensure wire-format
- * compatibility is not broken.
- */
-public class SecureMessageSimpleTestVectorTest extends TestCase {
-
-  private static final KeyFactory EC_KEY_FACTORY;
-  static {
-    try {
-      if (PublicKeyProtoUtil.isLegacyCryptoRequired()) {
-        EC_KEY_FACTORY = null;
-      } else {
-        EC_KEY_FACTORY = KeyFactory.getInstance("EC");
-      }
-    } catch (Exception e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-  private static final byte[] TEST_ASSOCIATED_DATA = {
-    11, 22, 33, 44, 55
-  };
-  private static final byte[] TEST_METADATA = {
-    10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28
-  };
-  private static final byte[] TEST_VKID  = {
-    0, 0, 1
-  };
-  private static final byte[] TEST_DKID = {
-    -1, -1, 0,
-  };
-  private static final byte[] TEST_MESSAGE = {
-    0, 99, 1, 98, 2, 97, 3, 96, 4, 95, 5, 94, 6, 93, 7, 92, 8, 91, 9, 90
-  };
-
-  // The following fields are initialized below, in a static block that contains auto-generated test
-  // vectors. Initialization can't just be done inline due to code that throws checked exceptions.
-  private static final PublicKey TEST_EC_PUBLIC_KEY;
-  private static final PrivateKey TEST_EC_PRIVATE_KEY;
-  private static final SecretKey TEST_KEY1;
-  private static final SecretKey TEST_KEY2;
-  private static final byte[] TEST_VECTOR_ECDSA_ONLY;
-  private static final byte[] TEST_VECTOR_ECDSA_AND_AES;
-  private static final byte[] TEST_VECTOR_HMAC_AND_AES_SAME_KEYS;
-  private static final byte[] TEST_VECTOR_HMAC_AND_AES_DIFFERENT_KEYS;
-
-  public void testEcdsaOnly() throws Exception {
-   if (PublicKeyProtoUtil.isLegacyCryptoRequired()) {
-      // On older Android platforms we can't run this test.
-      return;
-    }
-    SecureMessage testVector = SecureMessage.parseFrom(TEST_VECTOR_ECDSA_ONLY);
-    Header unverifiedHeader = SecureMessageParser.getUnverifiedHeader(testVector);
-    HeaderAndBody headerAndBody = SecureMessageParser.parseSignedCleartextMessage(
-        testVector, TEST_EC_PUBLIC_KEY, SigType.ECDSA_P256_SHA256, TEST_ASSOCIATED_DATA);
-    assertTrue(Arrays.equals(
-        unverifiedHeader.toByteArray(),
-        headerAndBody.getHeader().toByteArray()));
-    assertTrue(Arrays.equals(TEST_MESSAGE, headerAndBody.getBody().toByteArray()));
-    assertEquals(TEST_ASSOCIATED_DATA.length, unverifiedHeader.getAssociatedDataLength());
-    assertTrue(Arrays.equals(TEST_METADATA, unverifiedHeader.getPublicMetadata().toByteArray()));
-    assertTrue(Arrays.equals(TEST_VKID, unverifiedHeader.getVerificationKeyId().toByteArray()));
-    assertFalse(unverifiedHeader.hasDecryptionKeyId());
-  }
-
-  public void testEcdsaAndAes() throws Exception {
-   if (PublicKeyProtoUtil.isLegacyCryptoRequired()) {
-      // On older Android platforms we can't run this test.
-      return;
-    }
-    SecureMessage testVector = SecureMessage.parseFrom(TEST_VECTOR_ECDSA_AND_AES);
-    Header unverifiedHeader = SecureMessageParser.getUnverifiedHeader(testVector);
-    HeaderAndBody headerAndBody = SecureMessageParser.parseSignCryptedMessage(
-        testVector,
-        TEST_EC_PUBLIC_KEY,
-        SigType.ECDSA_P256_SHA256,
-        TEST_KEY1,
-        EncType.AES_256_CBC,
-        TEST_ASSOCIATED_DATA);
-    assertTrue(Arrays.equals(
-        unverifiedHeader.toByteArray(),
-        headerAndBody.getHeader().toByteArray()));
-    assertTrue(Arrays.equals(TEST_MESSAGE, headerAndBody.getBody().toByteArray()));
-    assertEquals(TEST_ASSOCIATED_DATA.length, unverifiedHeader.getAssociatedDataLength());
-    assertTrue(Arrays.equals(TEST_METADATA, unverifiedHeader.getPublicMetadata().toByteArray()));
-    assertTrue(Arrays.equals(TEST_VKID, unverifiedHeader.getVerificationKeyId().toByteArray()));
-    assertTrue(Arrays.equals(TEST_DKID, unverifiedHeader.getDecryptionKeyId().toByteArray()));
-  }
-
-  public void testHmacAndAesSameKeys() throws Exception {
-    SecureMessage testVector = SecureMessage.parseFrom(TEST_VECTOR_HMAC_AND_AES_SAME_KEYS);
-    Header unverifiedHeader = SecureMessageParser.getUnverifiedHeader(testVector);
-
-    HeaderAndBody headerAndBody = SecureMessageParser.parseSignCryptedMessage(
-        testVector,
-        TEST_KEY1,
-        SigType.HMAC_SHA256,
-        TEST_KEY1,
-        EncType.AES_256_CBC,
-        TEST_ASSOCIATED_DATA);
-    assertTrue(Arrays.equals(
-        unverifiedHeader.toByteArray(),
-        headerAndBody.getHeader().toByteArray()));
-    assertTrue(Arrays.equals(TEST_MESSAGE, headerAndBody.getBody().toByteArray()));
-    assertEquals(TEST_ASSOCIATED_DATA.length, unverifiedHeader.getAssociatedDataLength());
-    assertTrue(Arrays.equals(TEST_METADATA, unverifiedHeader.getPublicMetadata().toByteArray()));
-    assertTrue(Arrays.equals(TEST_VKID, unverifiedHeader.getVerificationKeyId().toByteArray()));
-    assertTrue(Arrays.equals(TEST_DKID, unverifiedHeader.getDecryptionKeyId().toByteArray()));
-  }
-
-  public void testHmacAndAesDifferentKeys() throws Exception {
-    SecureMessage testVector = SecureMessage.parseFrom(TEST_VECTOR_HMAC_AND_AES_DIFFERENT_KEYS);
-    Header unverifiedHeader = SecureMessageParser.getUnverifiedHeader(testVector);
-    HeaderAndBody headerAndBody = SecureMessageParser.parseSignCryptedMessage(
-        testVector,
-        TEST_KEY1,
-        SigType.HMAC_SHA256,
-        TEST_KEY2,
-        EncType.AES_256_CBC,
-        TEST_ASSOCIATED_DATA);
-    assertTrue(Arrays.equals(
-        unverifiedHeader.toByteArray(),
-        headerAndBody.getHeader().toByteArray()));
-    assertTrue(Arrays.equals(TEST_MESSAGE, headerAndBody.getBody().toByteArray()));
-    assertEquals(TEST_ASSOCIATED_DATA.length, unverifiedHeader.getAssociatedDataLength());
-    assertTrue(Arrays.equals(TEST_METADATA, unverifiedHeader.getPublicMetadata().toByteArray()));
-    assertTrue(Arrays.equals(TEST_VKID, unverifiedHeader.getVerificationKeyId().toByteArray()));
-    assertTrue(Arrays.equals(TEST_DKID, unverifiedHeader.getDecryptionKeyId().toByteArray()));
-  }
-
-  /**
-   * This code emits the test vectors to {@code System.out}. It will not generate fresh test
-   * vectors unless an existing test vector is set to {@code null}, but it contains all of the code
-   * used to the generate the test vector values. Ideally, existing test vectors should never be
-   * regenerated, but having this code available should make it easier to add new test vectors.
-   */
-  public void testGenerateTestVectorsPseudoTest() throws Exception {
-   if (PublicKeyProtoUtil.isLegacyCryptoRequired()) {
-      // On older Android platforms we can't run this test.
-      return;
-    }
-    System.out.printf("  static {\n    try {\n");
-    String indent = "      ";
-    PublicKey testEcPublicKey = TEST_EC_PUBLIC_KEY;
-    PrivateKey testEcPrivateKey = TEST_EC_PRIVATE_KEY;
-    if (testEcPublicKey == null) {
-      KeyPair testEcKeyPair = PublicKeyProtoUtil.generateEcP256KeyPair();
-      testEcPublicKey = testEcKeyPair.getPublic();
-      testEcPrivateKey = testEcKeyPair.getPrivate();
-    }
-    System.out.printf("%s%s = parsePublicKey(new byte[] %s);\n",
-        indent,
-        "TEST_EC_PUBLIC_KEY",
-        byteArrayToJavaCode(indent, encodePublicKey(testEcPublicKey)));
-    System.out.printf("%s%s = parseEcPrivateKey(new byte[] %s);\n",
-        indent,
-        "TEST_EC_PRIVATE_KEY",
-        byteArrayToJavaCode(indent, encodeEcPrivateKey(testEcPrivateKey)));
-
-    SecretKey testKey1 = TEST_KEY1;
-    if (testKey1 == null) {
-      testKey1 = makeAesKey();
-    }
-    System.out.printf("%s%s = new SecretKeySpec(new byte[] %s, \"AES\");\n",
-        indent,
-        "TEST_KEY1",
-        byteArrayToJavaCode(indent, testKey1.getEncoded()));
-
-    SecretKey testKey2 = TEST_KEY2;
-    if (testKey2 == null) {
-      testKey2 = makeAesKey();
-    }
-    System.out.printf("%s%s = new SecretKeySpec(new byte[] %s, \"AES\");\n",
-        indent,
-        "TEST_KEY2",
-        byteArrayToJavaCode(indent, testKey2.getEncoded()));
-
-    byte[] testVectorEcdsaOnly = TEST_VECTOR_ECDSA_ONLY;
-    if (testVectorEcdsaOnly == null) {
-      testVectorEcdsaOnly = new SecureMessageBuilder()
-          .setAssociatedData(TEST_ASSOCIATED_DATA)
-          .setPublicMetadata(TEST_METADATA)
-          .setVerificationKeyId(TEST_VKID)
-          .buildSignedCleartextMessage(
-              testEcPrivateKey, SigType.ECDSA_P256_SHA256, TEST_MESSAGE).toByteArray();
-    }
-    printInitializerFor(indent, "TEST_VECTOR_ECDSA_ONLY", testVectorEcdsaOnly);
-
-    byte[] testVectorEcdsaAndAes = TEST_VECTOR_ECDSA_AND_AES;
-    if (testVectorEcdsaAndAes == null) {
-      testVectorEcdsaAndAes = new SecureMessageBuilder()
-          .setAssociatedData(TEST_ASSOCIATED_DATA)
-          .setDecryptionKeyId(TEST_DKID)
-          .setPublicMetadata(TEST_METADATA)
-          .setVerificationKeyId(TEST_VKID)
-          .buildSignCryptedMessage(
-              testEcPrivateKey,
-              SigType.ECDSA_P256_SHA256,
-              testKey1,
-              EncType.AES_256_CBC,
-              TEST_MESSAGE).toByteArray();
-    }
-    printInitializerFor(indent, "TEST_VECTOR_ECDSA_AND_AES", testVectorEcdsaAndAes);
-
-    byte[] testVectorHmacAndAesSameKeys = TEST_VECTOR_HMAC_AND_AES_SAME_KEYS;
-    if (testVectorHmacAndAesSameKeys == null) {
-      testVectorHmacAndAesSameKeys = new SecureMessageBuilder()
-          .setAssociatedData(TEST_ASSOCIATED_DATA)
-          .setDecryptionKeyId(TEST_DKID)
-          .setPublicMetadata(TEST_METADATA)
-          .setVerificationKeyId(TEST_VKID)
-          .buildSignCryptedMessage(
-              testKey1,
-              SigType.HMAC_SHA256,
-              testKey1,
-              EncType.AES_256_CBC,
-              TEST_MESSAGE).toByteArray();
-    }
-    printInitializerFor(indent, "TEST_VECTOR_HMAC_AND_AES_SAME_KEYS", testVectorHmacAndAesSameKeys);
-
-    byte[] testVectorHmacAndAesDifferentKeys = TEST_VECTOR_HMAC_AND_AES_DIFFERENT_KEYS;
-    if (testVectorHmacAndAesDifferentKeys == null) {
-      testVectorHmacAndAesDifferentKeys = new SecureMessageBuilder()
-          .setAssociatedData(TEST_ASSOCIATED_DATA)
-          .setDecryptionKeyId(TEST_DKID)
-          .setPublicMetadata(TEST_METADATA)
-          .setVerificationKeyId(TEST_VKID)
-          .buildSignCryptedMessage(
-              testKey1,
-              SigType.HMAC_SHA256,
-              testKey2,
-              EncType.AES_256_CBC,
-              TEST_MESSAGE).toByteArray();
-    }
-    printInitializerFor(
-        indent, "TEST_VECTOR_HMAC_AND_AES_DIFFERENT_KEYS", testVectorHmacAndAesDifferentKeys);
-
-    System.out.printf(
-        "    } catch (Exception e) {\n      throw new RuntimeException(e);\n    }\n  }\n");
-  }
-
-  private SecretKey makeAesKey() throws NoSuchAlgorithmException {
-    KeyGenerator aesKeygen = KeyGenerator.getInstance("AES");
-    aesKeygen.init(256);
-    return aesKeygen.generateKey();
-  }
-
-  private void printInitializerFor(String indent, String name, byte[] value) {
-    System.out.printf("%s%s = new byte[] %s;\n",
-        indent,
-        name,
-        byteArrayToJavaCode(indent, value));
-  }
-
-  private static String byteArrayToJavaCode(String lineIndent, byte[] array) {
-    String newline = "\n" + lineIndent + "    ";
-    String unwrappedArray = Arrays.toString(array).replace("[", "").replace("]", "");
-    int wrapAfter = 16;
-    int count = wrapAfter;
-    StringBuilder result = new StringBuilder("{");
-    for (String entry : unwrappedArray.split(" ")) {
-      if (++count > wrapAfter) {
-        result.append(newline);
-        count = 0;
-      } else {
-        result.append(" ");
-      }
-      result.append(entry);
-    }
-    result.append(" }");
-    return result.toString();
-  }
-
-  private static byte[] encodePublicKey(PublicKey pk) {
-    return PublicKeyProtoUtil.encodePublicKey(pk).toByteArray();
-  }
-
-  private static PublicKey parsePublicKey(byte[] encodedPk)
-      throws InvalidKeySpecException, InvalidProtocolBufferException {
-    GenericPublicKey gpk = GenericPublicKey.parseFrom(encodedPk);
-    if (PublicKeyProtoUtil.isLegacyCryptoRequired()
-        && gpk.getType() == SecureMessageProto.PublicKeyType.EC_P256) {
-      return null;
-    }
-    return PublicKeyProtoUtil.parsePublicKey(gpk);
-  }
-
-  private static byte[] encodeEcPrivateKey(PrivateKey sk) {
-    return sk.getEncoded();
-  }
-
-  private static PrivateKey parseEcPrivateKey(byte[] sk) throws InvalidKeySpecException {
-    if (PublicKeyProtoUtil.isLegacyCryptoRequired()) {
-      return null;
-    }
-    return EC_KEY_FACTORY.generatePrivate(new PKCS8EncodedKeySpec(sk));
-  }
-
-  // The following block of code was automatically generated by cut and pasting the output of the
-  // generateTestVectorsPseudoTest, which should reliably emit this same test vectors. Please
-  // DO NOT DELETE any of these existing test vectors unless you _really_ know what you are doing.
-  //
-  // --- AUTO GENERATED CODE BEGINS HERE ---
-  static {
-    try {
-      TEST_EC_PUBLIC_KEY = parsePublicKey(new byte[] {
-          8, 1, 18, 70, 10, 33, 0, -109, 9, 5, 8, -89, -3, -68, -86, -19, 17,
-          -126, -11, -95, 35, 101, 102, -57, -84, -118, 73, 83, 66, -62, -49, -91, 71, -19,
-          52, 123, 113, 119, 45, 18, 33, 0, -65, -19, 83, -66, -12, 62, 102, -67, 116,
-          64, 42, 55, -84, -101, 90, -106, 113, -89, -30, 57, -112, 96, -99, -126, 14, 83,
-          41, 95, -24, -114, 23, -5 });
-      TEST_EC_PRIVATE_KEY = parseEcPrivateKey(new byte[] {
-          48, 65, 2, 1, 0, 48, 19, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6,
-          8, 42, -122, 72, -50, 61, 3, 1, 7, 4, 39, 48, 37, 2, 1, 1, 4,
-          32, 26, -82, -61, -86, -59, -8, 2, -62, -17, -20, 122, 3, 85, -102, -76, 81,
-          51, 39, -9, 12, 99, -117, 127, 19, 121, 109, -31, -49, 110, 121, 76, -107 });
-      TEST_KEY1 = new SecretKeySpec(new byte[] {
-          -89, 105, 62, -41, -75, 78, 70, 110, -62, -58, -80, -81, -99, -62, 39, 38, 37,
-          -7, -112, -83, 81, 23, 125, -72, -100, 103, -34, -23, -68, 21, -46, -104 }, "AES");
-      TEST_KEY2 = new SecretKeySpec(new byte[] {
-          -6, 48, 107, 61, -99, -89, 111, 33, 70, 54, -13, 111, 81, -120, 50, 89, -119,
-          -113, -114, 63, 12, -68, 40, 42, -77, -58, -49, 18, 69, 91, -20, -65 }, "AES");
-      TEST_VECTOR_ECDSA_ONLY = new byte[] {
-          10, 56, 10, 32, 8, 2, 16, 1, 26, 3, 0, 0, 1, 50, 19, 10, 11,
-          12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
-          56, 5, 18, 20, 0, 99, 1, 98, 2, 97, 3, 96, 4, 95, 5, 94, 6,
-          93, 7, 92, 8, 91, 9, 90, 18, 72, 48, 70, 2, 33, 0, -79, 59, 50,
-          21, 54, 61, -92, 77, -34, -77, -45, -105, 107, -28, -19, 91, -78, 120, 68, 33,
-          11, -76, -1, 50, 64, -127, -78, 6, 108, 115, -13, 126, 2, 33, 0, -72, -44,
-          52, 93, 105, 109, -127, -111, 11, 33, -111, 97, -114, 9, 117, -68, -45, 64, 63,
-          43, 60, -44, -89, -107, -59, -45, 56, 100, -66, -40, 46, -60 };
-      TEST_VECTOR_ECDSA_AND_AES = new byte[] {
-          10, 107, 10, 55, 8, 2, 16, 2, 26, 3, 0, 0, 1, 34, 3, -1, -1,
-          0, 42, 16, -86, 16, 55, -8, -85, -47, -77, -36, -127, 44, -10, -44, -63, 115,
-          -111, 26, 50, 19, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
-          23, 24, 25, 26, 27, 28, 56, 5, 18, 48, -110, 23, -67, 122, -118, 96, -4,
-          32, -113, -104, -107, -16, 76, 37, -61, -67, -63, 90, 38, 96, -47, -105, 56, -34,
-          50, -30, 82, 25, 100, 36, 69, 50, 68, 60, 38, 96, -108, -49, -73, -10, -62,
-          -76, -45, -105, -86, 93, 28, 34, 18, 70, 48, 68, 2, 33, 0, -87, -103, 11,
-          -70, 34, 33, -41, 90, -83, -74, 19, -13, 127, -43, -116, -32, 88, -13, 125, -122,
-          56, -21, 79, 47, 101, 89, -80, -43, 102, 92, 4, -15, 2, 31, 109, -69, 35,
-          21, 44, -27, -77, 32, 17, -90, -68, 113, 55, -24, -122, 40, 81, 51, 0, -84,
-          -29, -12, -26, 73, 105, -32, 116, -28, 84, -116, -117 };
-      TEST_VECTOR_HMAC_AND_AES_SAME_KEYS = new byte[] {
-          10, 91, 10, 55, 8, 1, 16, 2, 26, 3, 0, 0, 1, 34, 3, -1, -1,
-          0, 42, 16, -110, 48, 67, 67, -31, 24, -42, 13, -44, -109, 6, 113, 34, -70,
-          121, 6, 50, 19, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
-          23, 24, 25, 26, 27, 28, 56, 5, 18, 32, -44, -102, -16, 123, 113, -75, 88,
-          -33, 118, 25, 60, -65, 109, 26, -70, -123, 58, -114, 126, 8, 106, -28, 65, -38,
-          -4, 68, -78, -91, 49, -13, 22, -122, 18, 32, 20, -120, -113, -76, 85, -35, -53,
-          37, -18, 66, -38, 32, 10, 30, 89, 112, -39, -27, 24, 93, -36, -100, -127, -79,
-          94, -7, -19, -41, -47, -29, 1, 12 };
-      TEST_VECTOR_HMAC_AND_AES_DIFFERENT_KEYS = new byte[] {
-          10, 107, 10, 55, 8, 1, 16, 2, 26, 3, 0, 0, 1, 34, 3, -1, -1,
-          0, 42, 16, -96, -7, 39, 79, -37, 40, 1, -30, 97, 0, 123, -7, -124, -75,
-          -127, -18, 50, 19, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
-          23, 24, 25, 26, 27, 28, 56, 5, 18, 48, 90, 40, -48, -113, 84, -32, 47,
-          98, 54, -128, 127, 115, 32, 87, -86, 4, -26, 99, 9, -88, 13, 77, 127, 114,
-          -48, -117, -94, 96, -86, -105, -123, 11, 116, -69, -83, -110, 3, -10, 0, -34, 72,
-          10, -58, 3, -119, -94, 23, -114, 18, 32, -25, -126, 95, 125, -110, -62, -36, -78,
-          97, 72, -54, -114, 97, -68, -46, 107, 53, 55, -57, 88, 127, -20, -23, 80, -9,
-          -91, 115, 42, 24, 49, -76, -111 };
-    } catch (Exception e) {
-      throw new RuntimeException(e);
-    }
-  }
-}
diff --git a/src/main/javatest/com/google/security/cryptauth/lib/securemessage/SecureMessageTest.java b/src/main/javatest/com/google/security/cryptauth/lib/securemessage/SecureMessageTest.java
deleted file mode 100644
index 40e5091..0000000
--- a/src/main/javatest/com/google/security/cryptauth/lib/securemessage/SecureMessageTest.java
+++ /dev/null
@@ -1,766 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.security.cryptauth.lib.securemessage;
-
-import com.google.protobuf.ByteString;
-import com.google.protobuf.InvalidProtocolBufferException;
-import com.google.protobuf.UninitializedMessageException;
-import com.google.security.cryptauth.lib.securemessage.CryptoOps.EncType;
-import com.google.security.cryptauth.lib.securemessage.CryptoOps.SigType;
-import com.google.security.cryptauth.lib.securemessage.SecureMessageProto.EcP256PublicKey;
-import com.google.security.cryptauth.lib.securemessage.SecureMessageProto.GenericPublicKey;
-import com.google.security.cryptauth.lib.securemessage.SecureMessageProto.Header;
-import com.google.security.cryptauth.lib.securemessage.SecureMessageProto.HeaderAndBody;
-import com.google.security.cryptauth.lib.securemessage.SecureMessageProto.SecureMessage;
-import com.google.security.cryptauth.lib.securemessage.SecureMessageProto.SimpleRsaPublicKey;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.KeyPair;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.SecureRandom;
-import java.security.SignatureException;
-import java.security.spec.InvalidKeySpecException;
-import java.util.Arrays;
-import java.util.List;
-import javax.crypto.KeyGenerator;
-import javax.crypto.SecretKey;
-import junit.framework.TestCase;
-
-/**
- * Tests for the SecureMessageBuilder and SecureMessageParser classes.
- */
-public class SecureMessageTest extends TestCase {
-  // Not to be used when generating cross-platform test vectors (due to default charset encoding)
-  public static final byte[] TEST_MESSAGE =
-      "Testing 1 2 3... Testing 1 2 3... Testing 1 2 3...".getBytes();
-
-  private static final byte[] TEST_KEY_ID =
-    { 0, 1, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
-  // Not to be used when generating cross-platform test vectors (due to default charset encoding)
-  private static final byte[] TEST_METADATA = "Some protocol metadata string goes here".getBytes();
-  private static final byte[] TEST_ASSOCIATED_DATA = {
-    1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11 };
-  private static final byte[] ZERO_BYTE = { 0 };
-  private static final byte[] EMPTY_BYTES = { };
-
-  private static final List<byte[]> MESSAGE_VALUES = Arrays.asList(
-      EMPTY_BYTES,
-      TEST_MESSAGE
-      );
-
-  private static final List<byte[]> KEY_ID_VALUES = Arrays.asList(
-      null,
-      EMPTY_BYTES,
-      TEST_KEY_ID);
-
-  private static final List<byte[]> METADATA_VALUES = Arrays.asList(
-      null,
-      EMPTY_BYTES,
-      TEST_METADATA
-      );
-
-  private static final List<byte[]> ASSOCIATED_DATA_VALUES = Arrays.asList(
-      null,
-      ZERO_BYTE,
-      TEST_ASSOCIATED_DATA);
-
-  private byte[] message;
-  private byte[] metadata;
-  private byte[] verificationKeyId;
-  private byte[] decryptionKeyId;
-  private byte[] associatedData;
-  private PublicKey ecPublicKey;
-  private PrivateKey ecPrivateKey;
-  private PublicKey rsaPublicKey;
-  private PrivateKey rsaPrivateKey;
-  private SecretKey aesEncryptionKey;
-  private SecretKey hmacKey;
-  private SecureMessageBuilder secureMessageBuilder = new SecureMessageBuilder();
-  private SecureRandom rng = new SecureRandom();
-
-  @Override
-  public void setUp() {
-    message = TEST_MESSAGE;
-    metadata = null;
-    verificationKeyId = null;
-    decryptionKeyId = null;
-    associatedData = null;
-    if (!PublicKeyProtoUtil.isLegacyCryptoRequired()) {
-      KeyPair ecKeyPair = PublicKeyProtoUtil.generateEcP256KeyPair();
-      ecPublicKey = ecKeyPair.getPublic();
-      ecPrivateKey = ecKeyPair.getPrivate();
-    }
-    KeyPair rsaKeyPair = PublicKeyProtoUtil.generateRSA2048KeyPair();
-    rsaPublicKey = rsaKeyPair.getPublic();
-    rsaPrivateKey = rsaKeyPair.getPrivate();
-    try {
-      aesEncryptionKey = makeAesKey();
-      hmacKey = makeAesKey();
-    } catch (NoSuchAlgorithmException e) {
-      e.printStackTrace();
-      fail();
-    }
-    secureMessageBuilder.reset();
-  }
-
-  private SecureMessage sign(SigType sigType) throws NoSuchAlgorithmException, InvalidKeyException {
-    return getPreconfiguredBuilder().buildSignedCleartextMessage(
-        getSigningKeyFor(sigType), sigType, message);
-  }
-
-  private SecureMessage signCrypt(SigType sigType, EncType encType)
-      throws NoSuchAlgorithmException, InvalidKeyException {
-    return getPreconfiguredBuilder().buildSignCryptedMessage(
-        getSigningKeyFor(sigType), sigType, aesEncryptionKey, encType, message);
-  }
-
-  private void verify(SecureMessage signed, SigType sigType)
-      throws NoSuchAlgorithmException, InvalidKeyException, SignatureException,
-      InvalidProtocolBufferException {
-    HeaderAndBody headerAndBody = SecureMessageParser.parseSignedCleartextMessage(
-        signed,
-        getVerificationKeyFor(sigType),
-        sigType,
-        associatedData);
-    consistencyCheck(signed, headerAndBody, sigType, EncType.NONE);
-  }
-
-  private void verifyDecrypt(SecureMessage encryptedAndSigned, SigType sigType, EncType encType)
-      throws InvalidProtocolBufferException, InvalidKeyException, NoSuchAlgorithmException,
-      SignatureException {
-    HeaderAndBody headerAndBody = SecureMessageParser.parseSignCryptedMessage(
-        encryptedAndSigned,
-        getVerificationKeyFor(sigType),
-        sigType,
-        aesEncryptionKey,
-        encType,
-        associatedData);
-    consistencyCheck(encryptedAndSigned, headerAndBody, sigType, encType);
-  }
-
-  // A collection of different kinds of "alterations" that can be made to SecureMessage protos.
-  enum Alteration {
-    DECRYPTION_KEY_ID,
-    ENCTYPE,
-    HEADER_AND_BODY_PROTO,
-    MESSAGE,
-    METADATA,
-    RESIGNCRYPTION_ATTACK,
-    SIGTYPE,
-    VERIFICATION_KEY_ID,
-    ASSOCIATED_DATA_LENGTH,
-  }
-
-  private void doSignAndVerify(SigType sigType) throws Exception {
-    System.out.println("BEGIN_TEST -- Testing SigType: " + sigType + " with:");
-    System.out.println("VerificationKeyId: " + Arrays.toString(verificationKeyId));
-    System.out.println("Metadata: " + Arrays.toString(metadata));
-    System.out.println("AssociatedData: " + Arrays.toString(associatedData));
-    System.out.println("Message: " + Arrays.toString(message));
-    // Positive test cases
-    SecureMessage signed = sign(sigType);
-    verify(signed, sigType);
-
-    // Negative test cases
-    for (Alteration altType : getAlterationsToTest()) {
-      System.out.println("Testing alteration: " + altType.toString());
-      SecureMessage modified = modifyMessage(signed, altType);
-      try {
-        verify(modified, sigType);
-        fail(altType.toString());
-      } catch (SignatureException e) {
-        // We expect this
-      }
-    }
-
-    // Try verifying with the wrong associated data
-    if ((associatedData == null) || (associatedData.length == 0)) {
-      associatedData = ZERO_BYTE;
-    } else {
-      associatedData = null;
-    }
-    try {
-      verify(signed, sigType);
-      fail("Expected verification to fail due to incorrect associatedData");
-    } catch (SignatureException e) {
-      // We expect this
-    }
-
-    System.out.println("PASS_TEST -- Testing SigType: " + sigType);
-  }
-
-  private List<Alteration> getAlterationsToTest() {
-    if (isRunningInAndroid()) {
-      // Android is very slow. Only try one alteration attack, intead of all of them.
-      int randomAlteration = Math.abs(rng.nextInt()) % Alteration.values().length;
-      return Arrays.asList(Alteration.values()[randomAlteration]);
-    } else {
-      // Just try all of them
-      return Arrays.asList(Alteration.values());
-    }
-  }
-
-  private void doSignCryptAndVerifyDecrypt(SigType sigType) throws Exception {
-    // For now, EncType is always AES_256_CBC
-    EncType encType = EncType.AES_256_CBC;
-    System.out.println("BEGIN_TEST -- Testing SigType: " + sigType
-        + " EncType: " + encType + " with:");
-    System.out.println("DecryptionKeyId: " + Arrays.toString(decryptionKeyId));
-    System.out.println("VerificationKeyId: " + Arrays.toString(verificationKeyId));
-    System.out.println("Metadata: " + Arrays.toString(metadata));
-    System.out.println("AssociatedData: " + Arrays.toString(associatedData));
-    System.out.println("Message: " + Arrays.toString(message));
-    SecureMessage encryptedAndSigned = null;
-    encryptedAndSigned = signCrypt(sigType, encType);
-    verifyDecrypt(encryptedAndSigned, sigType, encType);
-
-    // Negative test cases
-    for (Alteration altType : getAlterationsToTest()) {
-      if (skipAlterationTestFor(altType, sigType)) {
-        System.out.println("Skipping alteration test: " + altType.toString());
-        continue;
-      }
-
-      System.out.println("Testing alteration: " + altType.toString());
-      SecureMessage modified = modifyMessage(encryptedAndSigned, altType);
-      try {
-        verifyDecrypt(modified, sigType, encType);
-        fail();
-      } catch (SignatureException e) {
-        // We expect this
-      }
-    }
-    System.out.println("PASS_TEST -- Testing SigType: " + sigType + " EncType: " + encType);
-  }
-
-  private boolean skipAlterationTestFor(Alteration altType, SigType sigType) {
-    // The RESIGNCRYPTION_ATTACK may be allowed to succeed iff the same symmetric key
-    // is being reused for both signature and encryption.
-    return (altType == Alteration.RESIGNCRYPTION_ATTACK)
-        // Intentionally testing equality of object address here
-        && (getVerificationKeyFor(sigType) == aesEncryptionKey);
-  }
-
-  private SecureMessage modifyMessage(SecureMessage original, Alteration altType) throws Exception {
-    ByteString bogus = ByteString.copyFromUtf8("BOGUS");
-    HeaderAndBody origHAB = HeaderAndBody.parseFrom(original.getHeaderAndBody());
-    HeaderAndBody.Builder newHAB = HeaderAndBody.newBuilder(origHAB);
-    Header.Builder newHeader = Header.newBuilder(origHAB.getHeader());
-    Header origHeader = origHAB.getHeader();
-    SecureMessage.Builder result = SecureMessage.newBuilder(original);
-    switch (altType) {
-      case DECRYPTION_KEY_ID:
-        if (origHeader.hasDecryptionKeyId()) {
-          newHeader.clearDecryptionKeyId();
-        } else {
-          newHeader.setDecryptionKeyId(ByteString.copyFrom(TEST_KEY_ID));
-        }
-        break;
-      case ENCTYPE:
-        if (origHeader.getEncryptionScheme() == SecureMessageProto.EncScheme.NONE) {
-          newHeader.setEncryptionScheme(SecureMessageProto.EncScheme.AES_256_CBC);
-        } else {
-          newHeader.setEncryptionScheme(SecureMessageProto.EncScheme.NONE);
-        }
-        break;
-      case HEADER_AND_BODY_PROTO:
-        // Substitute a junk byte string instead of the HeeaderAndBody proto message
-        return result.setHeaderAndBody(bogus).build();
-      case MESSAGE:
-        byte[] origBody = origHAB.getBody().toByteArray();
-        if (origBody.length > 0) {
-          // Lop off trailing byte of the body
-          byte[] truncatedBody = CryptoOps.subarray(origBody, 0, origBody.length - 1);
-          newHAB.setBody(ByteString.copyFrom(truncatedBody));
-        } else {
-          newHAB.setBody(bogus);
-        }
-        break;
-      case METADATA:
-        if (origHeader.hasPublicMetadata()) {
-          newHeader.clearPublicMetadata();
-        } else {
-          newHeader.setPublicMetadata(bogus);
-        }
-        break;
-      case RESIGNCRYPTION_ATTACK:
-        // Simulate stripping a signature, and re-signing a message to see if it will be decrypted.
-        newHeader
-            .setVerificationKeyId(bogus)
-            // In case original was cleartext
-            .setEncryptionScheme(SecureMessageProto.EncScheme.AES_256_CBC);
-
-        // Now that we've mildly changed the header, compute a new signature for it.
-        newHAB.setHeader(newHeader.build());
-        byte[] headerAndBodyBytes = newHAB.build().toByteArray();
-        result.setHeaderAndBody(ByteString.copyFrom(headerAndBodyBytes));
-        SigType sigType = SigType.valueOf(origHeader.getSignatureScheme());
-        // Note that in all cases where this attack applies, the associatedData is not normally
-        // used directly inside the signature (but rather inside the inner ciphertext).
-        result.setSignature(ByteString.copyFrom(CryptoOps.sign(
-            sigType, getSigningKeyFor(sigType), rng, headerAndBodyBytes)));
-        return result.build();
-      case SIGTYPE:
-        if (origHeader.getSignatureScheme() == SecureMessageProto.SigScheme.ECDSA_P256_SHA256) {
-          newHeader
-              .setSignatureScheme(SecureMessageProto.SigScheme.HMAC_SHA256);
-        } else {
-          newHeader
-              .setSignatureScheme(SecureMessageProto.SigScheme.ECDSA_P256_SHA256);
-        }
-        break;
-      case VERIFICATION_KEY_ID:
-        if (origHeader.hasVerificationKeyId()) {
-          newHeader.clearVerificationKeyId();
-        } else {
-          newHeader.setVerificationKeyId(
-              ByteString.copyFrom(TEST_KEY_ID));
-        }
-        break;
-      case ASSOCIATED_DATA_LENGTH:
-        int adLength = origHeader.getAssociatedDataLength();
-        switch (adLength) {
-          case 0:
-            newHeader.setAssociatedDataLength(1);
-            break;
-          case 1:
-            newHeader.setAssociatedDataLength(0);
-            break;
-          default:
-            newHeader.setAssociatedDataLength(adLength - 1);
-        }
-        break;
-      default:
-        fail("Forgot to implement an alteration attack: " + altType);
-        break;
-    }
-    // Set the header.
-    newHAB.setHeader(newHeader.build());
-
-    return result.setHeaderAndBody(ByteString.copyFrom(newHAB.build().toByteArray()))
-        .build();
-  }
-
-  public void testEcDsaSignedOnly() throws Exception {
-    doTestSignedOnly(SigType.ECDSA_P256_SHA256);
-  }
-
-  public void testRsaSignedOnly() throws Exception {
-    doTestSignedOnly(SigType.RSA2048_SHA256);
-  }
-
-  public void testHmacSignedOnly() throws Exception {
-    doTestSignedOnly(SigType.HMAC_SHA256);
-  }
-
-  private void doTestSignedOnly(SigType sigType) throws Exception {
-    if (isUnsupported(sigType)) {
-      return;
-    }
-
-    // decryptionKeyId must be left null for signature-only operation
-    for (byte[] vkId : KEY_ID_VALUES) {
-      verificationKeyId = vkId;
-      for (byte[] md : METADATA_VALUES) {
-        metadata = md;
-        for (byte[] ad : ASSOCIATED_DATA_VALUES) {
-          associatedData = ad;
-          for (byte[] msg : MESSAGE_VALUES) {
-            message = msg;
-            doSignAndVerify(sigType);
-          }
-        }
-      }
-    }
-
-    // Test that use of a DecryptionKeyId is not allowed for signature-only
-    try {
-      decryptionKeyId = TEST_KEY_ID;  // Should trigger a failure
-      doSignAndVerify(sigType);
-      fail();
-    } catch (IllegalStateException expected) {
-    }
-}
-
-  public void testEncryptedAndMACed() throws Exception {
-    for (byte[] dkId : KEY_ID_VALUES) {
-      decryptionKeyId = dkId;
-      for (byte[] vkId : KEY_ID_VALUES) {
-        verificationKeyId = vkId;
-        for (byte[] md : METADATA_VALUES) {
-          metadata = md;
-          for (byte[] ad : ASSOCIATED_DATA_VALUES) {
-            associatedData = ad;
-            for (byte[] msg : MESSAGE_VALUES) {
-              message = msg;
-              doSignCryptAndVerifyDecrypt(SigType.HMAC_SHA256);
-            }
-          }
-        }
-      }
-    }
-  }
-
-  public void testEncryptedAndMACedWithSameKey() throws Exception {
-    hmacKey = aesEncryptionKey; // Re-use the same key for both
-    testEncryptedAndMACed();
-  }
-
-  public void testEncryptedAndEcdsaSigned() throws Exception {
-    doTestEncryptedAndSigned(SigType.ECDSA_P256_SHA256);
-  }
-
-  public void testEncryptedAndRsaSigned() throws Exception {
-    doTestEncryptedAndSigned(SigType.RSA2048_SHA256);
-  }
-
-  public void doTestEncryptedAndSigned(SigType sigType) throws Exception {
-    if (isUnsupported(sigType)) {
-      return;  // EC operations aren't supported on older Android releases
-    }
-
-    for (byte[] dkId : KEY_ID_VALUES) {
-      decryptionKeyId = dkId;
-      for (byte[] vkId : KEY_ID_VALUES) {
-        verificationKeyId = vkId;
-        if ((verificationKeyId == null) && sigType.isPublicKeyScheme()) {
-          continue;  // Null verificationKeyId is not allowed with public key signcryption
-        }
-        for (byte[] md : METADATA_VALUES) {
-          metadata = md;
-          for (byte[] ad : ASSOCIATED_DATA_VALUES) {
-            associatedData = ad;
-            for (byte[] msg : MESSAGE_VALUES) {
-              message = msg;
-              doSignCryptAndVerifyDecrypt(sigType);
-            }
-          }
-        }
-      }
-    }
-
-    // Verify that a missing verificationKeyId is not allowed here
-    try {
-      verificationKeyId = null;  // Should trigger a failure
-      signCrypt(sigType, EncType.AES_256_CBC);
-      fail();
-    } catch (IllegalStateException expected) {
-    }
-  }
-
-  public void testSignCryptionRequiresEncryption() throws Exception {
-    try {
-      signCrypt(SigType.RSA2048_SHA256, EncType.NONE);
-    } catch (IllegalArgumentException expected) {
-    }
-  }
-
-  public void testAssociatedData() throws Exception {
-    // How much extra room might the encoding of AssociatedDataLength take up?
-    int maxAssociatedDataOverheadBytes = 4;
-    // How many bytes might normally vary in the encoding length for SecureMessages generated with
-    // fresh randomness but identical contents (e.g., due to MSBs being 0)
-    int maxJitter = 2;
-    verificationKeyId = TEST_KEY_ID;  // So that public key signcryption will work
-    message = TEST_MESSAGE;
-
-    for (SigType sigType : SigType.values()) {
-      if (isUnsupported(sigType)) {
-        continue;
-      }
-      associatedData = null;
-      SecureMessage signed = sign(sigType);
-      int signedLength = signed.toByteArray().length;
-      associatedData = EMPTY_BYTES;
-      // Check that EMPTY_BYTES is equivalent to null associated data under verification
-      verify(signed, sigType);
-      // We already tested that incorrect associated data fails elsewhere in negative test cases
-      associatedData = TEST_ASSOCIATED_DATA;
-      SecureMessage signedWithAssociatedData = sign(sigType);
-      int signedWithAssociatedDataLength = signedWithAssociatedData.toByteArray().length;
-      String logInfo = "Testing associated data overhead for signature using: " + sigType
-          + " signedLength=" + signedLength
-          + " signedWithAssociatedDataLength=" + signedWithAssociatedDataLength;
-      System.out.println(logInfo);
-      assertTrue(logInfo,
-          signedWithAssociatedData.toByteArray().length
-          <= signed.toByteArray().length + maxAssociatedDataOverheadBytes + maxJitter);
-    }
-
-    for (SigType sigType : SigType.values()) {
-      if (isUnsupported(sigType)) {
-        continue;
-      }
-      associatedData = null;
-      SecureMessage signCrypted = signCrypt(sigType, EncType.AES_256_CBC);
-      int signCryptedLength = signCrypted.toByteArray().length;
-      // Check that EMPTY_BYTES is equivalent to null associated data under verification
-      associatedData = EMPTY_BYTES;
-      verifyDecrypt(signCrypted, sigType, EncType.AES_256_CBC);
-      // We already tested that incorrect associated data fails elsewhere in negative test cases
-      associatedData = TEST_ASSOCIATED_DATA;
-      SecureMessage signCryptedWithAssociatedData = signCrypt(sigType, EncType.AES_256_CBC);
-      int signCryptedWithAssociatedDataLength = signCryptedWithAssociatedData.toByteArray().length;
-      String logInfo = "Testing associated data overhead for signcryption using: " + sigType
-          + " signCryptedLength=" + signCryptedLength
-          + " signCryptedWithAssociatedDataLength=" + signCryptedWithAssociatedDataLength;
-      System.out.println(logInfo);
-      assertTrue(logInfo,
-          signCryptedWithAssociatedData.toByteArray().length
-          <= signCrypted.toByteArray().length + maxAssociatedDataOverheadBytes + maxJitter);
-    }
-  }
-
-  public void testEncryptedAndEcdsaSignedUsingPublicKeyProto() throws Exception {
-    if (isUnsupported(SigType.ECDSA_P256_SHA256)) {
-      return;
-    }
-
-    // Safest usage of SignCryption is to set the VerificationKeyId to an actual representation of
-    // the verification key.
-    verificationKeyId = PublicKeyProtoUtil.encodeEcPublicKey(ecPublicKey).toByteArray();
-    SecureMessage encryptedAndSigned = signCrypt(SigType.ECDSA_P256_SHA256, EncType.AES_256_CBC);
-
-    // Simulate extracting the verification key ID from the SecureMessage (non-standard usage)
-    ecPublicKey =
-        PublicKeyProtoUtil.parseEcPublicKey(
-            EcP256PublicKey.parseFrom(
-                SecureMessageParser.getUnverifiedHeader(encryptedAndSigned)
-                    .getVerificationKeyId()));
-
-    // Note that this verification uses the encoded/decoded ecPublicKey value
-    verifyDecrypt(encryptedAndSigned, SigType.ECDSA_P256_SHA256, EncType.AES_256_CBC);
-  }
-
-  public void testEncryptedAndRsaSignedUsingPublicKeyProto() throws Exception {
-    // Safest usage of SignCryption is to set the VerificationKeyId to an actual representation of
-    // the verification key.
-    verificationKeyId = PublicKeyProtoUtil.encodeRsa2048PublicKey(rsaPublicKey).toByteArray();
-    SecureMessage encryptedAndSigned = signCrypt(SigType.RSA2048_SHA256, EncType.AES_256_CBC);
-
-    // Simulate extracting the verification key ID from the SecureMessage (non-standard usage)
-    rsaPublicKey =
-        PublicKeyProtoUtil.parseRsa2048PublicKey(
-            SimpleRsaPublicKey.parseFrom(
-                SecureMessageParser.getUnverifiedHeader(encryptedAndSigned)
-                    .getVerificationKeyId()));
-
-    // Note that this verification uses the encoded/decoded SimpleRsaPublicKey value
-    verifyDecrypt(encryptedAndSigned, SigType.RSA2048_SHA256, EncType.AES_256_CBC);
-  }
-
-  // TODO(shabsi): The test was only corrupting header but wasn't setting the body. With protolite,
-  // not setting a required field causes problems. Modify the SecureMessageParser test and
-  // enable/remove this test.
-  /*
-  public void testCorruptUnverifiedHeader() throws Exception {
-    // Create a sample message
-    SecureMessage original = signCrypt(SigType.HMAC_SHA256, EncType.AES_256_CBC);
-    HeaderAndBody originalHAB = HeaderAndBody.parseFrom(original.getHeaderAndBody().toByteArray());
-    for (CorruptHeaderType corruptionType : CorruptHeaderType.values()) {
-      // Mess with the HeaderAndBody field
-      HeaderAndBody.Builder corruptHAB = HeaderAndBody.newBuilder(originalHAB);
-      try {
-        corruptHeaderWith(corruptionType, corruptHAB);
-        // Construct the corrupted message using the modified HeaderAndBody
-        SecureMessage.Builder corrupt = SecureMessage.newBuilder(original);
-          corrupt.setHeaderAndBody(ByteString.copyFrom(corruptHAB.build().toByteArray())).build();
-          SecureMessageParser.getUnverifiedHeader(corrupt.build());
-          fail("Corrupt header type " + corruptionType + " parsed without error");
-      } catch (InvalidProtocolBufferException expected) {
-      }
-    }
-  }
-  */
-
-  public void testParseEmptyMessage() throws Exception {
-    byte[] bogusData = new byte[0];
-
-    try {
-      SecureMessageParser.parseSignedCleartextMessage(
-          SecureMessage.parseFrom(bogusData),
-          aesEncryptionKey,
-          SigType.HMAC_SHA256);
-      fail("Empty message verified without error");
-    } catch (SignatureException | UninitializedMessageException
-        | InvalidProtocolBufferException expected) {
-    }
-  }
-
-  public void testParseKeyInvalidInputs() throws Exception {
-    GenericPublicKey[] badKeys = new GenericPublicKey[] {
-        GenericPublicKey.newBuilder().setType(SecureMessageProto.PublicKeyType.EC_P256).build(),
-        GenericPublicKey.newBuilder().setType(SecureMessageProto.PublicKeyType.RSA2048).build(),
-        GenericPublicKey.newBuilder().setType(SecureMessageProto.PublicKeyType.DH2048_MODP).build(),
-    };
-    for (int i = 0; i < badKeys.length; i++) {
-      GenericPublicKey key = badKeys[i];
-      try {
-        PublicKeyProtoUtil.parsePublicKey(key);
-        fail(String.format("%sth key was parsed without exceptions", i));
-      } catch (InvalidKeySpecException expected) {
-      }
-    }
-  }
-
-  enum CorruptHeaderType {
-    EMPTY,
-    // TODO(shabsi): Remove these test cases and modify code in SecureMessageParser appropriately.
-    // UNSET,
-    // JUNK,
-  }
-
-  private void corruptHeaderWith(CorruptHeaderType corruptionType,
-      HeaderAndBody.Builder protoToModify) {
-    switch (corruptionType) {
-      case EMPTY:
-        protoToModify.setHeader(Header.getDefaultInstance());
-        break;
-      /*
-      case JUNK:
-        Header.Builder junk = Header.newBuilder();
-        junk.setDecryptionKeyId(ByteString.copyFromUtf8("fooooo"));
-        junk.setIv(ByteString.copyFromUtf8("bar"));
-        // Don't set signature scheme.
-        junk.setVerificationKeyId(ByteString.copyFromUtf8("bazzzzz"));
-        protoToModify.setHeader(junk.build());
-        break;
-      case UNSET:
-        protoToModify.clearHeader();
-        break;
-      */
-      default:
-        throw new RuntimeException("Broken test code");
-    }
-  }
-
-  private void consistencyCheck(
-      SecureMessage secmsg, HeaderAndBody headerAndBody, SigType sigType, EncType encType)
-      throws InvalidProtocolBufferException {
-    Header header = SecureMessageParser.getUnverifiedHeader(secmsg);
-    checkHeader(header, sigType, encType);  // Checks that the "unverified header" looks right
-    checkHeaderAndBody(header, headerAndBody);  // Matches header vs. the "verified" headerAndBody
-  }
-
-  private Header checkHeader(Header header, SigType sigType, EncType encType) {
-    assertEquals(sigType.getSigScheme(), header.getSignatureScheme());
-    assertEquals(encType.getEncScheme(), header.getEncryptionScheme());
-    checkKeyIdsAndMetadata(verificationKeyId, decryptionKeyId, metadata, associatedData, header);
-    return header;
-  }
-
-  private void checkHeaderAndBody(Header header, HeaderAndBody headerAndBody) {
-    assertTrue(header.equals(headerAndBody.getHeader()));
-    assertTrue(Arrays.equals(message, headerAndBody.getBody().toByteArray()));
-  }
-
-  private void checkKeyIdsAndMetadata(byte[] verificationKeyId, byte[] decryptionKeyId,
-      byte[] metadata, byte[] associatedData, Header header) {
-    if (verificationKeyId == null) {
-      assertFalse(header.hasVerificationKeyId());
-    } else {
-      assertTrue(Arrays.equals(verificationKeyId, header.getVerificationKeyId().toByteArray()));
-    }
-    if (decryptionKeyId == null) {
-      assertFalse(header.hasDecryptionKeyId());
-    } else {
-      assertTrue(Arrays.equals(decryptionKeyId, header.getDecryptionKeyId().toByteArray()));
-    }
-    if (metadata == null) {
-      assertFalse(header.hasPublicMetadata());
-    } else {
-      assertTrue(Arrays.equals(metadata, header.getPublicMetadata().toByteArray()));
-    }
-    if (associatedData == null) {
-      assertFalse(header.hasAssociatedDataLength());
-    } else {
-      assertEquals(associatedData.length, header.getAssociatedDataLength());
-    }
-  }
-
-  private SecretKey makeAesKey() throws NoSuchAlgorithmException {
-    KeyGenerator aesKeygen = KeyGenerator.getInstance("AES");
-    aesKeygen.init(256);
-    return aesKeygen.generateKey();
-  }
-
-  private Key getSigningKeyFor(SigType sigType) {
-    if (sigType == SigType.ECDSA_P256_SHA256) {
-      return ecPrivateKey;
-    }
-    if (sigType == SigType.RSA2048_SHA256) {
-      return rsaPrivateKey;
-    }
-    if (sigType == SigType.HMAC_SHA256) {
-      return hmacKey;
-    }
-    return null;  // This should not happen
-  }
-
-  private Key getVerificationKeyFor(SigType sigType) {
-    try {
-      if (sigType == SigType.ECDSA_P256_SHA256) {
-        return PublicKeyProtoUtil.parseEcPublicKey(
-            PublicKeyProtoUtil.encodeEcPublicKey(ecPublicKey));
-      }
-      if (sigType == SigType.RSA2048_SHA256) {
-        return PublicKeyProtoUtil.parseRsa2048PublicKey(
-            PublicKeyProtoUtil.encodeRsa2048PublicKey(rsaPublicKey));
-      }
-    } catch (InvalidKeySpecException e) {
-      throw new AssertionError(e);
-    }
-
-    assertFalse(sigType.isPublicKeyScheme());
-    // For symmetric key schemes
-    return getSigningKeyFor(sigType);
-  }
-
-  private SecureMessageBuilder getPreconfiguredBuilder() {
-    // Re-use a single instance of SecureMessageBuilder for efficiency.
-    SecureMessageBuilder builder = secureMessageBuilder.reset();
-    if (verificationKeyId != null) {
-      builder.setVerificationKeyId(verificationKeyId);
-    }
-    if (decryptionKeyId != null) {
-      builder.setDecryptionKeyId(decryptionKeyId);
-    }
-    if (metadata != null) {
-      builder.setPublicMetadata(metadata);
-    }
-    if (associatedData != null) {
-      builder.setAssociatedData(associatedData);
-    }
-    return builder;
-  }
-
-  private static boolean isUnsupported(SigType sigType) {
-    // EC operations aren't supported on older Android releases
-    return PublicKeyProtoUtil.isLegacyCryptoRequired()
-        && (sigType == SigType.ECDSA_P256_SHA256);
-  }
-
-  private static boolean isRunningInAndroid() {
-    try {
-      ClassLoader.getSystemClassLoader().loadClass("android.os.Build$VERSION");
-      return true;
-    } catch (ClassNotFoundException e) {
-      // Not running on Android
-      return false;
-    }
-  }
-}
diff --git a/src/main/proto/CMakeLists.txt b/src/main/proto/CMakeLists.txt
deleted file mode 100644
index cd94f3f..0000000
--- a/src/main/proto/CMakeLists.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright 2020 Google LLC
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-add_cc_proto_library(
-  proto_device_to_device_messages_cc_proto
-  PROTOS device_to_device_messages.proto
-  DEPS proto_securemessage_cc_proto
-  INCS ${CMAKE_CURRENT_BINARY_DIR}/..
-)
-
-add_cc_proto_library(
-  proto_securegcm_cc_proto
-  PROTOS securegcm.proto
-  INCS ${CMAKE_CURRENT_BINARY_DIR}/..
-)
-
-add_cc_proto_library(
-  proto_ukey_cc_proto
-  PROTOS ukey.proto
-  INCS ${CMAKE_CURRENT_BINARY_DIR}/..
-)
diff --git a/src/main/proto/device_to_device_messages.proto b/src/main/proto/device_to_device_messages.proto
index 5600373..c3bd2cf 100644
--- a/src/main/proto/device_to_device_messages.proto
+++ b/src/main/proto/device_to_device_messages.proto
@@ -1,28 +1,27 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 syntax = "proto2";
 
 package securegcm;
 
-import "securemessage.proto";
-
-option optimize_for = LITE_RUNTIME;
 option java_package = "com.google.security.cryptauth.lib.securegcm";
 option java_outer_classname = "DeviceToDeviceMessagesProto";
 option objc_class_prefix = "SGCM";
 
+import "securemessage.proto";
+
 // Used by protocols between devices
 message DeviceToDeviceMessage {
   // the payload of the message
@@ -53,7 +52,9 @@
 }
 
 // Type of curve
-enum Curve { ED_25519 = 1; }
+enum Curve {
+  ED_25519 = 1;
+}
 
 // A convenience proto for encoding curve points in affine representation
 message EcPoint {
@@ -79,3 +80,4 @@
   // since the key exchange is already complete on the sender's side.
   optional bytes payload = 4;
 }
+
diff --git a/src/main/proto/passwordless_auth_payloads.proto b/src/main/proto/passwordless_auth_payloads.proto
index 69c2784..054d91c 100644
--- a/src/main/proto/passwordless_auth_payloads.proto
+++ b/src/main/proto/passwordless_auth_payloads.proto
@@ -1,27 +1,28 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 syntax = "proto2";
 
 package securegcm;
 
-option optimize_for = LITE_RUNTIME;
 option java_package = "com.google.security.cryptauth.lib.securegcm";
 option java_outer_classname = "SecureGcmPasswordlessAuthProto";
 option objc_class_prefix = "SGCM";
 
+
 message IdentityAssertion {
+
   // Browser data contains the challenge, origin, etc.
   optional bytes browser_data_hash = 1;
 
diff --git a/src/main/proto/proximity_payloads.proto b/src/main/proto/proximity_payloads.proto
index d7a4956..9c2f1ec 100644
--- a/src/main/proto/proximity_payloads.proto
+++ b/src/main/proto/proximity_payloads.proto
@@ -1,34 +1,33 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 syntax = "proto2";
 
-package securegcm;
-
 import "securegcm.proto";
 
-option optimize_for = LITE_RUNTIME;
+package securegcm;
+
 option java_package = "com.google.security.cryptauth.lib.securegcm";
 option java_outer_classname = "SecureGcmProximityAuthProto";
 option objc_class_prefix = "SGCM";
 
-// Message used when one device wants to initiate a Proximity Auth pairing with
-// another device DEPRECATED. DO NOT USE
+// Message used when one device wants to initiate a Proximity Auth pairing with another device
+// DEPRECATED. DO NOT USE
 message CloudToDeviceProximityAuthPairing {
-  // The name or description of the device that wants to pair with another
-  // personal device of the user.  This is a string that may be shown to the
-  // user or may be kept in logs.
+// The name or description of the device that wants to pair with another
+// personal device of the user.  This is a string that may be shown to the
+// user or may be kept in logs.
   optional string initiating_device_name = 1;
 
   // The original device's Bluetooth address in human readable form
diff --git a/src/main/proto/securegcm.proto b/src/main/proto/securegcm.proto
index 0325f06..b7dae25 100644
--- a/src/main/proto/securegcm.proto
+++ b/src/main/proto/securegcm.proto
@@ -1,22 +1,21 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 syntax = "proto2";
 
 package securegcm;
 
-option optimize_for = LITE_RUNTIME;
 option java_package = "com.google.security.cryptauth.lib.securegcm";
 option java_outer_classname = "SecureGcmProto";
 option objc_class_prefix = "SGCM";
@@ -37,7 +36,7 @@
   optional bytes apn_registration_id = 202;
 
   // Does the user have notifications enabled for the given device address.
-  optional bool notification_enabled = 203 [default = true];
+  optional bool notification_enabled = 203 [ default = true ];
 
   // Used for device_address of DeviceInfo field 2, a Bluetooth Mac address for
   // the device (e.g., to be used with EasyUnlock)
@@ -105,45 +104,45 @@
   optional string device_manufacturer = 31;
 
   // Used to indicate which type of device this is.
-  optional DeviceType device_type = 32 [default = ANDROID];
+  optional DeviceType device_type = 32 [ default = ANDROID ];
 
   // Fields corresponding to screenlock type/features and hardware features
   // should be numbered in the 400 range.
 
   // Is this device using  a secure screenlock (e.g., pattern or pin unlock)
-  optional bool using_secure_screenlock = 400 [default = false];
+  optional bool using_secure_screenlock = 400 [ default = false ];
 
   // Is auto-unlocking the screenlock (e.g., when at "home") supported?
-  optional bool auto_unlock_screenlock_supported = 401 [default = false];
+  optional bool auto_unlock_screenlock_supported = 401 [ default = false ];
 
   // Is auto-unlocking the screenlock (e.g., when at "home") enabled?
-  optional bool auto_unlock_screenlock_enabled = 402 [default = false];
+  optional bool auto_unlock_screenlock_enabled = 402 [ default = false ];
 
   // Does the device have a Bluetooth (classic) radio?
-  optional bool bluetooth_radio_supported = 403 [default = false];
+  optional bool bluetooth_radio_supported = 403 [ default = false ];
 
   // Is the Bluetooth (classic) radio on?
-  optional bool bluetooth_radio_enabled = 404 [default = false];
+  optional bool bluetooth_radio_enabled = 404 [ default = false ];
 
   // Does the device hardware support a mobile data connection?
-  optional bool mobile_data_supported = 405 [default = false];
+  optional bool mobile_data_supported = 405 [ default = false ];
 
   // Does the device support tethering?
-  optional bool tethering_supported = 406 [default = false];
+  optional bool tethering_supported = 406 [ default = false ];
 
   // Does the device have a BLE radio?
-  optional bool ble_radio_supported = 407 [default = false];
+  optional bool ble_radio_supported = 407 [ default = false ];
 
   // Is the device a "Pixel Experience" Android device?
-  optional bool pixel_experience = 408 [default = false];
+  optional bool pixel_experience = 408 [ default = false ];
 
   // Is the device running in the ARC++ container on a chromebook?
-  optional bool arc_plus_plus = 409 [default = false];
+  optional bool arc_plus_plus = 409 [ default = false ];
 
   // Is the value set in |using_secure_screenlock| reliable? On some Android
   // devices, the platform API to get the screenlock state is not trustworthy.
   // See b/32212161.
-  optional bool is_screenlock_state_flaky = 410 [default = false];
+  optional bool is_screenlock_state_flaky = 410 [ default = false ];
 
   // A list of multi-device software features supported by the device.
   repeated SoftwareFeature supported_software_features = 411;
@@ -179,7 +178,7 @@
   OSX = 5;
 }
 
-// MultiDevice features which may be supported and enabled on a device. See
+// MultiDevice features which may be supported and enabled on a device.
 enum SoftwareFeature {
   UNKNOWN_FEATURE = 0;
   BETTER_TOGETHER_HOST = 1;
diff --git a/src/main/proto/securemessage.proto b/src/main/proto/securemessage.proto
index 5118d35..062e425 100644
--- a/src/main/proto/securemessage.proto
+++ b/src/main/proto/securemessage.proto
@@ -1,24 +1,22 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // Proto definitions for SecureMessage format
 
 syntax = "proto2";
 
 package securemessage;
-
-option optimize_for = LITE_RUNTIME;
 option java_package = "com.google.security.cryptauth.lib.securemessage";
 option java_outer_classname = "SecureMessageProto";
 option objc_class_prefix = "SMSG";
@@ -58,7 +56,7 @@
   optional bytes public_metadata = 6;
   // The length of some associated data this is not sent in this SecureMessage,
   // but which will be bound to the signature.
-  optional uint32 associated_data_length = 7 [default = 0];
+  optional uint32 associated_data_length = 7 [ default = 0 ];
 }
 
 message HeaderAndBody {
diff --git a/src/main/proto/ukey.proto b/src/main/proto/ukey.proto
index 327d8d3..155b279 100644
--- a/src/main/proto/ukey.proto
+++ b/src/main/proto/ukey.proto
@@ -1,22 +1,21 @@
-// Copyright 2020 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
+/* Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 syntax = "proto2";
 
 package securegcm;
 
-option optimize_for = LITE_RUNTIME;
 option java_package = "com.google.security.cryptauth.lib.securegcm";
 option java_outer_classname = "UkeyProto";
 
@@ -37,12 +36,12 @@
 message Ukey2Alert {
   enum AlertType {
     // Framing errors
-    BAD_MESSAGE = 1;        // The message could not be deserialized
-    BAD_MESSAGE_TYPE = 2;   // message_type has an undefined value
-    INCORRECT_MESSAGE = 3;  // message_type received does not correspond to
-                            // expected type at this stage of the protocol
-    BAD_MESSAGE_DATA = 4;   // Could not deserialize message_data as per
-                            //  value inmessage_type
+    BAD_MESSAGE = 1;             // The message could not be deserialized
+    BAD_MESSAGE_TYPE = 2;        // message_type has an undefined value
+    INCORRECT_MESSAGE = 3;       // message_type received does not correspond to
+                                 // expected type at this stage of the protocol
+    BAD_MESSAGE_DATA = 4;        // Could not deserialize message_data as per
+                                 //  value inmessage_type
 
     // ClientInit and ServerInit errors
     BAD_VERSION = 100;           // version is invalid; server cannot find
@@ -55,9 +54,9 @@
     BAD_PUBLIC_KEY = 104;        // The public key could not be parsed
 
     // Other errors
-    INTERNAL_ERROR = 200;  // An internal error has occurred. error_message
-                           // may contain additional details for logging
-                           // and debugging.
+    INTERNAL_ERROR = 200;       // An internal error has occurred. error_message
+                                // may contain additional details for logging
+                                // and debugging.
   }
 
   optional AlertType type = 1;
diff --git a/third_party/absl b/third_party/absl
deleted file mode 160000
index 62f05b1..0000000
--- a/third_party/absl
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 62f05b1f57ad660e9c09e02ce7d591dcc4d0ca08
diff --git a/third_party/gtest b/third_party/gtest
deleted file mode 160000
index 703bd9c..0000000
--- a/third_party/gtest
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 703bd9caab50b139428cea1aaff9974ebee5742e
diff --git a/third_party/protobuf b/third_party/protobuf
deleted file mode 160000
index d0bfd52..0000000
--- a/third_party/protobuf
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit d0bfd5221182da1a7cc280f3337b5e41a89539cf
diff --git a/third_party/secure_message b/third_party/secure_message
deleted file mode 160000
index e7b6988..0000000
--- a/third_party/secure_message
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit e7b6988454bc94601616fbbf0db3559f73a1ebdf