new file:   grpcserver/README.md
	new file:   grpcserver/src/CMakeLists.txt
	new file:   grpcserver/src/cmake/FindCppREST.cmake
	new file:   grpcserver/src/cmake/FindGRPC.cmake
	new file:   grpcserver/src/cmake/FindProtobuf.cmake
	new file:   grpcserver/src/dta/dtaserver.cpp
	new file:   grpcserver/src/dta/main.cpp
	new file:   grpcserver/src/dta/secret_proxy.cpp
	new file:   grpcserver/src/dta/utils.cpp
	new file:   grpcserver/src/include/dtaclient.h
	new file:   grpcserver/src/include/dtaserver.h
new file:   grpcserver/src/include/secret_proxy.h
	new file:   grpcserver/src/include/utils.h
	new file:   grpcserver/src/protos/dta.proto
	new file:   grpcserver/src/protos/mpin.proto
	new file:   grpcserver/src/protos/rpa.proto
	new file:   grpcserver/src/protos/rps.proto
	new file:   grpcserver/src/test_server.crt
	new file:   grpcserver/src/test_server.key
diff --git a/grpcserver/README.md b/grpcserver/README.md
new file mode 100644
index 0000000..0f908dd
--- /dev/null
+++ b/grpcserver/README.md
@@ -0,0 +1 @@
+DTA using Apache Milagro AMCL Library.
diff --git a/grpcserver/src/CMakeLists.txt b/grpcserver/src/CMakeLists.txt
new file mode 100644
index 0000000..e2ac5ef
--- /dev/null
+++ b/grpcserver/src/CMakeLists.txt
@@ -0,0 +1,83 @@
+cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
+project(milagro-grpc VERSION 0.1.0 LANGUAGES CXX)
+get_filename_component(PROJECT_ROOT ${CMAKE_CURRENT_LIST_FILE} DIRECTORY)
+list(APPEND CMAKE_PREFIX_PATH "/usr/local" )
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_MODULE_PATH "${PROJECT_ROOT}/cmake")
+set(SERVER_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/include")
+set(CPP_MILAGRO_INCLUDE_DIR "/usr/local/include/amcl")
+set(CPP_MILAGRO_LIB "/usr/lib/amcl")
+set(BSD_ARC_LIB "/usr/lib/x86_64-linux-gnu/libbsd.a")
+# Cmake find modules
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
+find_package(Boost 1.50.0 COMPONENTS system  REQUIRED)
+find_package(Threads REQUIRED)
+find_package(OpenSSL REQUIRED)  
+set(CPP_REST_FOUND False)
+set(protobuf_MODULE_COMPATIBLE TRUE)
+find_package(Protobuf REQUIRED)
+message(STATUS "Using protobuf ${protobuf_VERSION}")
+find_package(GRPC  REQUIRED)
+message(STATUS "Using gRPC ${gRPC_VERSION}")
+
+include_directories(${Protobuf_INCLUDE_DIRS})
+
+set(PROTOS
+    ${CMAKE_CURRENT_SOURCE_DIR}/protos/mpin.proto
+    ${CMAKE_CURRENT_SOURCE_DIR}/protos/dta.proto
+    ${CMAKE_CURRENT_SOURCE_DIR}/protos/rps.proto
+    ${CMAKE_CURRENT_SOURCE_DIR}/protos/rpa.proto
+)
+set(PROTO_SRC_DIR ${CMAKE_CURRENT_BINARY_DIR}/proto-generated)
+set(PROTO_SRC_PYTHON_DIR ${CMAKE_CURRENT_BINARY_DIR}/protopy-generated)
+
+file(MAKE_DIRECTORY ${PROTO_SRC_DIR})
+file(MAKE_DIRECTORY ${PROTO_SRC_PYTHON_DIR})
+
+include_directories(${PROTO_SRC_DIR})
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+include_directories(${Protobuf_INCLUDE_DIRS})
+include_directories(${SERVER_INCLUDE})
+include_directories(SYSTEM ${OPENSSL_INCLUDE_DIR})
+
+protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${PROTO_SRC_DIR} ${PROTOS})
+grpc_generate_cpp(GRPC_SRCS GRPC_HDRS ${PROTO_SRC_DIR} ${PROTOS})
+#protobuf_generate_python(PY_PROTO ${PROTOS})
+#grpc_generate_python(PY_GRPC_SRCS  ${PROTO_SRC_PYTHON_DIR} ${PROTOS})
+
+
+
+if(NOT MSVC)
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1z")
+add_definitions(-DLINUX)
+else()
+add_definitions(-D_WIN32_WINNT=0x600)
+endif()
+
+list(APPEND INCLUDE_EXT_DIRS ${Boost_INCLUDE_DIRS})
+include_directories(SYSTEM ${CPP_MILAGRO_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR} ${PROJECT_ROOT}/include)
+
+file(GLOB DTA_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/dta/*.cpp")
+
+if (UNIX)
+SET(LINK_FLAGS "-lssl -lcrypto -lboost_system -lbsd")
+add_definitions(-Wno-sign-compare -Wno-enum-compare -DBOOST_ALL_DYN_LINK)
+endif()
+
+SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINK_FLAGS}" )
+
+add_executable(dtaservice 
+                ${PROTO_SRCS}
+                ${GRPC_SRCS}
+                ${DTA_SOURCES}
+            )
+
+target_link_libraries(dtaservice PRIVATE 
+                      ${OPENSSL_LIBRARIES} 
+                      ${CMAKE_DL_LIBS} 
+                      ${Boost_SYSTEM_LIBRARY}
+                      ${CPP_MILAGRO_LIB}/amcl.a
+                      ${BSD_ARC_LIB} 
+                      gRPC::grpc++_reflection
+                      protobuf::libprotobuf)
diff --git a/grpcserver/src/cmake/FindCppREST.cmake b/grpcserver/src/cmake/FindCppREST.cmake
new file mode 100644
index 0000000..0007fa7
--- /dev/null
+++ b/grpcserver/src/cmake/FindCppREST.cmake
@@ -0,0 +1,47 @@
+
+IF(UNIX)
+
+    FIND_PATH(CPP_REST_INCLUDE_DIR http_client.h
+      "$ENV{LIB_DIR}/include"
+      "/usr/include/cpprest"
+      "${CMAKE_SOURCE_DIR}/include"
+      "${CMAKE_SOURCE_DIR}/include/cpprest"
+      NO_DEFAULT_PATH
+      )
+
+    SET(CMAKE_FIND_LIBRARY_PREFIXES "" "lib")
+    SET(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a" ".lib")
+    FIND_LIBRARY(CPP_REST_LIBRARY NAMES cpprest PATHS
+      $ENV{LIB}
+      /usr/lib
+      /usr/lib/x86_64-linux-gnu
+      "$ENV{LIB_DIR}/lib"
+      "${CMAKE_SOURCE_DIR}/lib"
+      #mingw
+      c:/msys/local/lib
+      NO_DEFAULT_PATH
+      )
+ELSE()
+    FIND_PATH(CPP_REST_INCLUDE_DIR http_client.h
+        "${PROJECT_ROOT}/include/cpprest"
+      )
+
+    FILE(GLOB CPP_REST_LIBRARY NAMES
+        "${PROJECT_ROOT}/lib/cpprest*.lib"
+        "${PROJECT_ROOT}/lib/cpprest*.a"
+        )
+ENDIF()
+
+
+IF (CPP_REST_INCLUDE_DIR AND CPP_REST_LIBRARY)
+    SET(CPP_REST_FOUND TRUE)
+ENDIF (CPP_REST_INCLUDE_DIR AND CPP_REST_LIBRARY)
+
+MESSAGE(STATUS "C++ REST Include: ${CPP_REST_INCLUDE_DIR}")
+
+
+IF (CPP_REST_FOUND)
+    MESSAGE(STATUS "Found C++ REST: ${CPP_REST_LIBRARY}")
+ELSE (CPP_REST_FOUND)
+        MESSAGE(FATAL_ERROR "Could not find C++ REST")
+ENDIF (CPP_REST_FOUND)
diff --git a/grpcserver/src/cmake/FindGRPC.cmake b/grpcserver/src/cmake/FindGRPC.cmake
new file mode 100644
index 0000000..55ea507
--- /dev/null
+++ b/grpcserver/src/cmake/FindGRPC.cmake
@@ -0,0 +1,126 @@
+#
+# Locate and configure the gRPC library
+#
+# Adds the following targets:
+#
+#  gRPC::grpc - gRPC library
+#  gRPC::grpc++ - gRPC C++ library
+#  gRPC::grpc++_reflection - gRPC C++ reflection library
+#  gRPC::grpc_cpp_plugin - C++ generator plugin for Protocol Buffers
+#
+
+#
+# Generates C++ sources from the .proto files
+#
+# grpc_generate_cpp (<SRCS> <HDRS> <DEST> [<ARGN>...])
+#
+#  SRCS - variable to define with autogenerated source files
+#  HDRS - variable to define with autogenerated header files
+#  DEST - directory where the source files will be created
+#  ARGN - .proto files
+#
+function(GRPC_GENERATE_CPP SRCS HDRS DEST)
+  if(NOT ARGN)
+    message(SEND_ERROR "Error: GRPC_GENERATE_CPP() called without any proto files")
+    return()
+  endif()
+
+  if(GRPC_GENERATE_CPP_APPEND_PATH)
+    # Create an include path for each file specified
+    foreach(FIL ${ARGN})
+      get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
+      get_filename_component(ABS_PATH ${ABS_FIL} PATH)
+      list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
+      if(${_contains_already} EQUAL -1)
+          list(APPEND _protobuf_include_path -I ${ABS_PATH})
+      endif()
+    endforeach()
+  else()
+    set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR})
+  endif()
+
+  if(DEFINED PROTOBUF_IMPORT_DIRS)
+    foreach(DIR ${PROTOBUF_IMPORT_DIRS})
+      get_filename_component(ABS_PATH ${DIR} ABSOLUTE)
+      list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
+      if(${_contains_already} EQUAL -1)
+          list(APPEND _protobuf_include_path -I ${ABS_PATH})
+      endif()
+    endforeach()
+  endif()
+
+  set(${SRCS})
+  set(${HDRS})
+  foreach(FIL ${ARGN})
+    get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
+    get_filename_component(FIL_WE ${FIL} NAME_WE)
+
+    list(APPEND ${SRCS} "${DEST}/${FIL_WE}.grpc.pb.cc")
+    list(APPEND ${HDRS} "${DEST}/${FIL_WE}.grpc.pb.h")
+
+    add_custom_command(
+      OUTPUT "${DEST}/${FIL_WE}.grpc.pb.cc"
+             "${DEST}/${FIL_WE}.grpc.pb.h"
+      COMMAND protobuf::protoc
+      ARGS --grpc_out ${DEST} ${_protobuf_include_path} --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN} ${ABS_FIL}
+      DEPENDS ${ABS_FIL} protobuf::protoc gRPC::grpc_cpp_plugin
+      COMMENT "Running C++ gRPC compiler on ${FIL}"
+      VERBATIM )
+  endforeach()
+
+  set_source_files_properties(${${SRCS}} ${${HDRS}} PROPERTIES GENERATED TRUE)
+  set(${SRCS} ${${SRCS}} PARENT_SCOPE)
+  set(${HDRS} ${${HDRS}} PARENT_SCOPE)
+endfunction()
+
+# By default have GRPC_GENERATE_CPP macro pass -I to protoc
+# for each directory where a proto file is referenced.
+if(NOT DEFINED GRPC_GENERATE_CPP_APPEND_PATH)
+  set(GRPC_GENERATE_CPP_APPEND_PATH TRUE)
+endif()
+
+# Find gRPC include directory
+find_path(GRPC_INCLUDE_DIR grpc/grpc.h)
+mark_as_advanced(GRPC_INCLUDE_DIR)
+
+# Find gRPC library
+find_library(GRPC_LIBRARY NAMES grpc)
+mark_as_advanced(GRPC_LIBRARY)
+add_library(gRPC::grpc UNKNOWN IMPORTED)
+set_target_properties(gRPC::grpc PROPERTIES
+    INTERFACE_INCLUDE_DIRECTORIES ${GRPC_INCLUDE_DIR}
+    INTERFACE_LINK_LIBRARIES "-lpthread;-ldl"
+    IMPORTED_LOCATION ${GRPC_LIBRARY}
+)
+
+# Find gRPC C++ library
+find_library(GRPC_GRPC++_LIBRARY NAMES grpc++)
+mark_as_advanced(GRPC_GRPC++_LIBRARY)
+add_library(gRPC::grpc++ UNKNOWN IMPORTED)
+set_target_properties(gRPC::grpc++ PROPERTIES
+    INTERFACE_INCLUDE_DIRECTORIES ${GRPC_INCLUDE_DIR}
+    INTERFACE_LINK_LIBRARIES gRPC::grpc
+    IMPORTED_LOCATION ${GRPC_GRPC++_LIBRARY}
+)
+
+# Find gRPC C++ reflection library
+find_library(GRPC_GRPC++_REFLECTION_LIBRARY NAMES grpc++_reflection)
+mark_as_advanced(GRPC_GRPC++_REFLECTION_LIBRARY)
+add_library(gRPC::grpc++_reflection UNKNOWN IMPORTED)
+set_target_properties(gRPC::grpc++_reflection PROPERTIES
+    INTERFACE_INCLUDE_DIRECTORIES ${GRPC_INCLUDE_DIR}
+    INTERFACE_LINK_LIBRARIES gRPC::grpc++
+    IMPORTED_LOCATION ${GRPC_GRPC++_REFLECTION_LIBRARY}
+)
+
+# Find gRPC CPP generator
+find_program(GRPC_CPP_PLUGIN NAMES grpc_cpp_plugin)
+mark_as_advanced(GRPC_CPP_PLUGIN)
+add_executable(gRPC::grpc_cpp_plugin IMPORTED)
+set_target_properties(gRPC::grpc_cpp_plugin PROPERTIES
+    IMPORTED_LOCATION ${GRPC_CPP_PLUGIN}
+)
+
+include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(gRPC DEFAULT_MSG
+    GRPC_LIBRARY GRPC_INCLUDE_DIR GRPC_GRPC++_REFLECTION_LIBRARY GRPC_CPP_PLUGIN)
diff --git a/grpcserver/src/cmake/FindProtobuf.cmake b/grpcserver/src/cmake/FindProtobuf.cmake
new file mode 100644
index 0000000..cb2802a
--- /dev/null
+++ b/grpcserver/src/cmake/FindProtobuf.cmake
@@ -0,0 +1,126 @@
+#
+# Locate and configure the Google Protocol Buffers library
+#
+# Adds the following targets:
+#
+#  protobuf::libprotobuf - Protobuf library
+#  protobuf::libprotobuf-lite - Protobuf lite library
+#  protobuf::libprotoc - Protobuf Protoc Library
+#  protobuf::protoc - protoc executable
+#
+
+#
+# Generates C++ sources from the .proto files
+#
+# protobuf_generate_cpp (<SRCS> <HDRS> <DEST> [<ARGN>...])
+#
+#  SRCS - variable to define with autogenerated source files
+#  HDRS - variable to define with autogenerated header files
+#  DEST - directory where the source files will be created
+#  ARGN - .proto files
+#
+function(PROTOBUF_GENERATE_CPP SRCS HDRS DEST)
+  if(NOT ARGN)
+    message(SEND_ERROR "Error: PROTOBUF_GENERATE_CPP() called without any proto files")
+    return()
+  endif()
+
+  if(PROTOBUF_GENERATE_CPP_APPEND_PATH)
+    # Create an include path for each file specified
+    foreach(FIL ${ARGN})
+      get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
+      get_filename_component(ABS_PATH ${ABS_FIL} PATH)
+      list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
+      if(${_contains_already} EQUAL -1)
+          list(APPEND _protobuf_include_path -I ${ABS_PATH})
+      endif()
+    endforeach()
+  else()
+    set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR})
+  endif()
+
+  if(DEFINED PROTOBUF_IMPORT_DIRS)
+    foreach(DIR ${PROTOBUF_IMPORT_DIRS})
+      get_filename_component(ABS_PATH ${DIR} ABSOLUTE)
+      list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
+      if(${_contains_already} EQUAL -1)
+          list(APPEND _protobuf_include_path -I ${ABS_PATH})
+      endif()
+    endforeach()
+  endif()
+
+  set(${SRCS})
+  set(${HDRS})
+  foreach(FIL ${ARGN})
+    get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
+    get_filename_component(FIL_WE ${FIL} NAME_WE)
+
+    list(APPEND ${SRCS} "${DEST}/${FIL_WE}.pb.cc")
+    list(APPEND ${HDRS} "${DEST}/${FIL_WE}.pb.h")
+
+    add_custom_command(
+      OUTPUT "${DEST}/${FIL_WE}.pb.cc"
+             "${DEST}/${FIL_WE}.pb.h"
+      COMMAND protobuf::protoc
+      ARGS --cpp_out ${DEST} ${_protobuf_include_path} ${ABS_FIL}
+      DEPENDS ${ABS_FIL} protobuf::protoc
+      COMMENT "Running C++ protocol buffer compiler on ${FIL}"
+      VERBATIM )
+  endforeach()
+
+  set_source_files_properties(${${SRCS}} ${${HDRS}} PROPERTIES GENERATED TRUE)
+  set(${SRCS} ${${SRCS}} PARENT_SCOPE)
+  set(${HDRS} ${${HDRS}} PARENT_SCOPE)
+endfunction()
+
+# By default have PROTOBUF_GENERATE_CPP macro pass -I to protoc
+# for each directory where a proto file is referenced.
+if(NOT DEFINED PROTOBUF_GENERATE_CPP_APPEND_PATH)
+  set(PROTOBUF_GENERATE_CPP_APPEND_PATH TRUE)
+endif()
+
+# Find the include directory
+find_path(PROTOBUF_INCLUDE_DIR google/protobuf/service.h)
+mark_as_advanced(PROTOBUF_INCLUDE_DIR)
+
+# The Protobuf library
+find_library(PROTOBUF_LIBRARY NAMES protobuf)
+mark_as_advanced(PROTOBUF_LIBRARY)
+add_library(protobuf::libprotobuf UNKNOWN IMPORTED)
+set_target_properties(protobuf::libprotobuf PROPERTIES
+    INTERFACE_INCLUDE_DIRECTORIES ${PROTOBUF_INCLUDE_DIR}
+    INTERFACE_LINK_LIBRARIES pthread
+    IMPORTED_LOCATION ${PROTOBUF_LIBRARY}
+)
+
+# The Protobuf lite library
+find_library(PROTOBUF_LITE_LIBRARY NAMES protobuf-lite)
+mark_as_advanced(PROTOBUF_LITE_LIBRARY)
+add_library(protobuf::libprotobuf-lite UNKNOWN IMPORTED)
+set_target_properties(protobuf::libprotobuf-lite PROPERTIES
+    INTERFACE_INCLUDE_DIRECTORIES ${PROTOBUF_INCLUDE_DIR}
+    INTERFACE_LINK_LIBRARIES pthread
+    IMPORTED_LOCATION ${PROTOBUF_LITE_LIBRARY}
+)
+
+# The Protobuf Protoc Library
+find_library(PROTOBUF_PROTOC_LIBRARY NAMES protoc)
+mark_as_advanced(PROTOBUF_PROTOC_LIBRARY)
+add_library(protobuf::libprotoc UNKNOWN IMPORTED)
+set_target_properties(protobuf::libprotoc PROPERTIES
+    INTERFACE_INCLUDE_DIRECTORIES ${PROTOBUF_INCLUDE_DIR}
+    INTERFACE_LINK_LIBRARIES protobuf::libprotobuf
+    IMPORTED_LOCATION ${PROTOBUF_PROTOC_LIBRARY}
+)
+
+# Find the protoc Executable
+find_program(PROTOBUF_PROTOC_EXECUTABLE NAMES protoc)
+mark_as_advanced(PROTOBUF_PROTOC_EXECUTABLE)
+add_executable(protobuf::protoc IMPORTED)
+set_target_properties(protobuf::protoc PROPERTIES
+    IMPORTED_LOCATION ${PROTOBUF_PROTOC_EXECUTABLE}
+)
+
+
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Protobuf DEFAULT_MSG
+    PROTOBUF_LIBRARY PROTOBUF_INCLUDE_DIR PROTOBUF_PROTOC_EXECUTABLE)
diff --git a/grpcserver/src/dta/dtaserver.cpp b/grpcserver/src/dta/dtaserver.cpp
new file mode 100644
index 0000000..4e51b60
--- /dev/null
+++ b/grpcserver/src/dta/dtaserver.cpp
@@ -0,0 +1,305 @@
+/*
+* Copyright 2019, Giorgio Zoppi
+*
+* 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
+*
+*         http://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 <sstream>
+#include <dtaserver.h>
+#include <utils.h>
+#include <google/protobuf/util/time_util.h>
+
+namespace milagro
+{
+  namespace dta
+  {
+
+    namespace util = milagro::utils;
+    using namespace grpc;
+    using namespace google::protobuf::util;
+
+    ::grpc::Status dta_server::GetClientSecret (ServerContext * context,
+						const
+						AuthClientSecretRequest *
+						request,
+						AuthServerResponse * response)
+    {
+      auto app_id = request->appid ();
+      auto expires = request->expiretime ();
+      auto signature = request->hmacsignature ();
+      auto hash_mpin_hex = request->mpinidhexencoded ();
+      auto hash_user_id = request->hashuserid ();
+      auto provided_signature = request->hmacsignature ();
+      // concat the needed data to verify
+      if ((app_id == 0) || provided_signature.empty ())
+	{
+	  response->set_responsemessage ("Invalid Parameter calls");
+	  return::grpc::Status (StatusCode::INVALID_ARGUMENT,
+				"Signature and appId shall be present");
+	}
+
+      if ((hash_user_id.size () != 0) && (hash_mpin_hex.size () != 64))
+	{
+	  response->set_responsemessage ("Invalid MPIN Parameter");
+	  return::grpc::Status::CANCELLED;
+	}
+      auto key = getCredential (app_id);
+      if (!key.has_value ())
+	{
+	  response->set_statuscode (milagro::dta::ResultCode::PROTOCOL_ERROR);
+	  return::grpc::Status (StatusCode::INVALID_ARGUMENT,
+				"The key associated to the app should be present");
+	}
+
+      client_signature_ctx client_content;
+      client_content.appId = app_id;
+      client_content.hash_mpin_hex = hash_mpin_hex;
+      client_content.hash_user_id = hash_user_id;
+      client_content.expires = expires;
+      auto request_content = make_client_content (client_content);
+
+      if (!hmac_verify (provided_signature, request_content, key).ok ())
+	{
+	  response->
+	    set_statuscode (milagro::dta::ResultCode::INVALID_SIGNATURE);
+	  return::grpc::Status (StatusCode::PERMISSION_DENIED,
+				"Invalid signature");
+	}
+      std::string client_secret;
+      try
+      {
+	client_secret =
+	  util::octet_to_string (_key_store->generate_client_secret
+				 (hash_user_id, hash_mpin_hex));
+      }
+      catch (std::exception & ex)
+      {
+	response->
+	  set_statuscode (milagro::dta::ResultCode::KEY_GENERATION_FAILED);
+	response->set_responsemessage (ex.what ());
+	return::grpc::Status (StatusCode::INTERNAL, ex.what ());
+      }
+
+      client_signature_ctx params;
+      params.appId = app_id;
+      params.client_secret = client_secret;
+      params.hash_mpin_hex = hash_mpin_hex;
+      params.hash_user_id = hash_user_id;
+      params.expires = expires;
+      std::string client_signature;
+      try
+      {
+	client_signature = hmac_client_sign (params, key.value ());
+      }
+      catch (const std::exception & e)
+      {
+	std::cerr << e.what () << '\n';
+      }
+      response->set_statuscode (milagro::dta::ResultCode::SUCCESS);
+      response->set_secret (client_secret);
+      response->set_hmacsignature (client_signature);
+      return::grpc::Status::OK;
+    }
+    ::grpc::Status dta_server::GetStatus (ServerContext * context,
+					  const StatusRequest * request,
+					  StatusResponse * response)
+    {
+    }
+    ::grpc::Status dta_server::GetServerSecret (ServerContext * context,
+						const
+						AuthServerSecretRequest *
+						request,
+						AuthServerResponse * response)
+    {
+      auto appId = request->appid ();
+      auto key = getCredential (appId);
+      auto signature = request->hmacsignature ();
+      if (!key.has_value ())
+	{
+	  response->set_statuscode (milagro::dta::ResultCode::PROTOCOL_ERROR);
+	  return::grpc::Status (StatusCode::INVALID_ARGUMENT,
+				"The application should be registered");
+	}
+      auto request_content = make_server_signature_data (request);
+      if (hmac_verify (signature, request_content, key).ok ())
+	{
+	  response->
+	    set_statuscode (milagro::dta::ResultCode::INVALID_SIGNATURE);
+	  return::grpc::Status (StatusCode::PERMISSION_DENIED,
+				"Invalid signature");
+	}
+      std::string masterHexKey;
+      // success.
+      amcl::octet masterKey;
+      try
+      {
+	masterKey = _key_store->generate_master_secret ();
+	masterHexKey = util::octet_to_string (masterKey);
+      }
+      catch (std::exception & store_ex)
+      {
+	response->
+	  set_statuscode (milagro::dta::ResultCode::KEY_GENERATION_FAILED);
+	response->set_responsemessage (store_ex.what ());
+	return::grpc::Status (StatusCode::ABORTED, "Key generation failed");
+      }
+      auto master_signature =
+	hmac_sign_message (_key_store->server_key_start (),
+			   masterKey, key.value ());
+      response->set_secret (masterHexKey);
+      response->set_hmacsignature (master_signature);
+      return::grpc::Status::OK;
+    }
+    ::grpc::Status dta_server::GetTimePermit (ServerContext * context,
+					      const TimePermitRequest *
+					      request,
+					      TimePermitResponse * response)
+    {
+      auto appId = request->appid ();
+      auto key = getCredential (appId);
+      if (!key.has_value ())
+	{
+	  response->set_statuscode (milagro::dta::ResultCode::PROTOCOL_ERROR);
+	  return::grpc::Status (StatusCode::INVALID_ARGUMENT,
+				"An app identifier shall be registered");
+	}
+      auto hash_mpin_id_hex = request->mpinidhexencoded ();
+      auto provided_signature = request->hmacsignature ();
+      auto app_id = request->appid ();
+      client_signature_ctx client_content;
+      client_content.appId = app_id;
+      client_content.hash_mpin_hex = hash_mpin_id_hex;
+      auto request_content = make_time_content (client_content);
+
+      if (!hmac_verify (provided_signature, request_content, key).ok ())
+	{
+	  response->
+	    set_statuscode (milagro::dta::ResultCode::INVALID_SIGNATURE);
+	  return::grpc::Status (StatusCode::PERMISSION_DENIED,
+				"Invalid signature");
+	}
+      auto timepermit = _key_store->get_time_permits (hash_mpin_id_hex, 1);
+      response->set_timepermit (timepermit[0]);
+      response->set_statuscode (milagro::dta::ResultCode::SUCCESS);
+      return::grpc::Status::OK;
+    }
+
+    ::grpc::Status dta_server::GetTimePermits (ServerContext * context,
+					       const::milagro::
+					       dta::TimePermitsRequest *
+					       request,
+					       TimePermitsResponse * response)
+    {
+
+      auto appId = request->appid ();
+      auto count = request->count ();
+
+      auto key = getCredential (appId);
+      if (!key.has_value ())
+	{
+	  response->set_statuscode (milagro::dta::ResultCode::PROTOCOL_ERROR);
+	  return::grpc::Status (StatusCode::INVALID_ARGUMENT,
+				"Application not registered");
+	}
+      auto hash_mpin_id_hex = request->mpinidhexencoded ();
+      auto provided_signature = request->hmacsignature ();
+      client_signature_ctx time_content;
+      time_content.appId = appId;
+      time_content.hash_mpin_hex = hash_mpin_id_hex;
+      auto request_content = make_time_content (time_content);
+      auto timepermits =
+	_key_store->get_time_permits (hash_mpin_id_hex, count);
+      return::grpc::Status::OK;
+    }
+    std::optional < amcl::octet > dta_server::getCredential (int key) const
+    {
+      return _key_store->search_key (key);
+    }
+    amcl::octet dta_server::make_server_signature_data (const
+							AuthServerSecretRequest
+							* request)
+    {
+      amcl::octet signature;
+      std::ostringstream buffer;
+
+      return signature;
+    }
+    amcl::octet dta_server::make_client_content (const client_signature_ctx &
+						 content)
+    {
+      amcl::octet client_content;
+      return client_content;
+    }
+    std::string dta_server::hmac_client_sign (const client_signature_ctx &
+					      content,
+					      const amcl::octet & key)
+    {
+      amcl::octet data = make_client_content (content);
+      int olen = 32;
+      amcl::octet hmac;
+      /* this is a library design problem. 
+         i would never expect in C++ to do a const_cast
+       */
+      amcl::HMAC (SHA256, &data, const_cast < amcl::octet * >(&key),
+		  olen, &hmac);
+      auto value = util::octet_to_string (hmac);
+      return value;
+    }
+
+    amcl::octet dta_server::make_time_content (const client_signature_ctx &
+					       content)
+    {
+      amcl::octet octect;
+      return octect;
+    }
+
+    std::string dta_server::hmac_sign_message (const boost::
+					       posix_time::ptime & timestamp,
+					       const amcl::octet & secret,
+					       const amcl::octet & key)
+    {
+      std::ostringstream buffer;
+      amcl::octet hmac;
+      amcl::octet inputdata;
+      char input[1024];
+      amcl::octet input_data =
+      {
+      0, sizeof (input), input};
+      int olen = 32;
+      std::strncpy (input, buffer.str ().c_str (), sizeof (input));
+      input[sizeof (input) - 1] = 0;
+      input_data.len = std::strlen (input);
+
+      amcl::HMAC (SHA256,
+		  &input_data,
+		  const_cast < amcl::octet * >(&key), olen, &hmac);
+      return util::octet_to_string (hmac);
+    }
+    ::grpc::Status dta_server::hmac_verify (std::string request_signature,
+					    amcl::octet request_content,
+					    std::optional < amcl::octet > key)
+    {
+
+      int olen = 32;
+      amcl::octet hmac;
+      amcl::HMAC (SHA256, &request_content, &key.value (), olen, &hmac);
+      std::string result = milagro::utils::octet_to_string (hmac);
+
+      if (result.compare (request_signature))
+	{
+	  return::grpc::Status (StatusCode::INVALID_ARGUMENT,
+				"Invalid signature");
+	}
+      return::grpc::Status::OK;
+    }
+  }				// namespace dta
+}				// namespace milagro
diff --git a/grpcserver/src/dta/main.cpp b/grpcserver/src/dta/main.cpp
new file mode 100644
index 0000000..b7b2fcf
--- /dev/null
+++ b/grpcserver/src/dta/main.cpp
@@ -0,0 +1,53 @@
+/*
+* Copyright 2019, Giorgio Zoppi
+*
+* 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
+*
+*         http://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 <dtaserver.h>
+#include <iostream>
+#include <memory>
+#include <string>
+
+#include <grpc++/grpc++.h>
+
+using namespace grpc;
+using
+  grpc::Server;
+using
+  grpc::ServerBuilder;
+using
+  grpc::ServerContext;
+using
+  grpc::Status;
+
+void
+RunServer (const std::string & address)
+{
+  std::string server_address (address);
+  milagro::dta::dta_server dataService;
+  ServerBuilder
+    builder;
+  builder.AddListeningPort (server_address,
+			    grpc::InsecureServerCredentials ());
+  builder.RegisterService (&dataService);
+  std::unique_ptr < Server > server (builder.BuildAndStart ());
+  std::cout << "Server listening on " << server_address << std::endl;
+  server->Wait ();
+}
+
+int
+main ()
+{
+  RunServer ("0.0.0.0:14100");
+  return 0;
+}
diff --git a/grpcserver/src/dta/secret_proxy.cpp b/grpcserver/src/dta/secret_proxy.cpp
new file mode 100644
index 0000000..f4a3a22
--- /dev/null
+++ b/grpcserver/src/dta/secret_proxy.cpp
@@ -0,0 +1,184 @@
+/*
+* Copyright 2019, Giorgio Zoppi
+*
+* 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
+*
+*         http://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 <string>
+#include <vector>
+#include <cstdlib>
+#include <boost/date_time.hpp>
+#include <amcl/mpin_BN254.h>
+#include <bsd/stdlib.h>
+#include <amcl/randapi.h>
+#include <amcl/pbc_support.h>
+#include <amcl/amcl.h>
+#include <utils.h>
+#include <secret_proxy.h>
+
+namespace milagro
+{
+  namespace secure_store
+  {
+
+    using namespace BN254;
+    using namespace boost::local_time;
+
+      secret_proxy::secret_proxy ()
+    {
+      init_state ();
+    }
+    secret_proxy::secret_proxy (const std::string & path)
+    {
+      init_state ();
+
+    }
+    secret_proxy::~secret_proxy ()
+    {
+      KILL_CSPRNG (&_secure_random);
+    }
+    void secret_proxy::init_state ()
+    {
+      char raw[100];
+      // FIXME this works only on linux and bsd
+      arc4random_buf (raw, sizeof raw);
+      amcl::octet row_octet =
+      {
+      0, sizeof (raw), raw};
+      CREATE_CSPRNG (&_secure_random, &row_octet);
+    }
+    /*
+     * Generate the D-TA master secret -
+     * @param type  type of the store, optional parameter.
+     */
+    amcl::octet secret_proxy::generate_master_secret (store_type type)
+    {
+      char secret_chars[PGS_BN254];
+      amcl::octet secret =
+      {
+      0, sizeof (secret_chars), secret_chars};
+      _master_startTime = boost::posix_time::second_clock::local_time ();
+      MPIN_RANDOM_GENERATE (&_secure_random, &secret);
+      return secret;
+    }
+    /*
+     *  Generate the client secret for the MPIN Protocol. 
+     *  One between the user_id or the hash_pin_id shall be present.
+     *  If juse the user_id is present create the hash from the user_id.
+     *  @param user_id optional value for the user identifier
+     *  @param hash_pin_id optional value for the mpin
+     *  @returns An octect to be used as a secret key 
+     */
+    amcl::octet secret_proxy::generate_client_secret (const std::optional <
+						      std::string > &user_id,
+						      const std::optional <
+						      std::string >
+						      &hash_pin_id,
+						      store_type type)
+    {
+      char client_id[256];
+      char idhex[256];
+      char token[2 * PFS_BN254 + 1];
+      char hcid[PFS_BN254];
+      amcl::octet HCID =
+      {
+      0, sizeof (hcid), hcid};
+      amcl::octet CLIENT_ID =
+      {
+      0, sizeof (client_id), client_id};
+      // compute when we shall expire.
+      auto local = local_sec_clock::local_time (time_zone_ptr ());
+      local += boost::gregorian::days (DAYS_CLIENT_SECRET_MAX);
+      _client_expireTime = local.utc_time ();
+      if (!user_id.has_value () && (!hash_pin_id.value ().size () == 64))
+	{
+	  throw std::invalid_argument ("Client identifier too long");
+	}
+      milagro::utils::make_hash_id (hash_pin_id, user_id, HCID);
+      // we have here the hash id anyway.
+      amcl::octet TOKEN =
+      {
+      0, sizeof (token), token};
+      int currentSize = _master_secret.size ();
+      amcl::octet S =
+      {
+      currentSize, currentSize,
+	  const_cast < char *>(_master_secret.c_str ())};
+      MPIN_GET_CLIENT_SECRET (&S, &HCID, &TOKEN);
+      return TOKEN;
+    }
+    /*
+     *  Get the time permits 
+     * @param mash_
+     */
+    std::vector < std::string >
+      secret_proxy::get_time_permits (const
+				      std::optional < std::string >
+				      &mhash_pin_id, int count)
+    {
+      char permit[2 * PFS_BN254 + 1];
+      int day = amcl::today ();
+      std::vector < std::string > tmp;
+      amcl::octet HCID;
+      amcl::octet PERMIT =
+      {
+      0, sizeof (permit), permit};
+      int currentSize = _master_secret.size ();
+      amcl::octet S =
+      {
+      currentSize,
+	  currentSize, const_cast < char *>(_master_secret.c_str ())};
+      milagro::utils::make_hash_id (mhash_pin_id, std::nullopt, HCID);
+      for (int i = 0; i < count; ++count)
+	{
+	  MPIN_GET_CLIENT_PERMIT (HASH_TYPE_BN254, day, &S, &HCID, &PERMIT);
+	  // This encoding makes Time permit look random 
+	  if (MPIN_ENCODING (&_secure_random, &PERMIT) != 0)
+	    {
+	      throw std::runtime_error ("Encoding permit is not possible");
+	    }
+	  std::string str = milagro::utils::octet_to_string (PERMIT);
+	  tmp.push_back (str);
+	  std::memset (&PERMIT, 0, sizeof (amcl::octet));
+	}
+      return tmp;
+    }
+    /*
+     *
+     */
+    boost::posix_time::ptime secret_proxy::client_key_expire ()const
+    {
+      return _client_expireTime;
+    }
+    /*
+     *
+     */
+    boost::posix_time::ptime secret_proxy::server_key_start () const
+    {
+      return _master_startTime;
+    }
+    /*
+     *  
+     */
+    std::optional < amcl::octet > secret_proxy::search_key (int appId)
+    {
+      auto value = _key_store.find (appId);
+      if (value != _key_store.end ())
+	{
+	  return std::make_optional < amcl::octet > (value->second);
+	}
+      return std::nullopt;
+
+    }
+
+  }
+}
diff --git a/grpcserver/src/dta/utils.cpp b/grpcserver/src/dta/utils.cpp
new file mode 100644
index 0000000..04fb0c0
--- /dev/null
+++ b/grpcserver/src/dta/utils.cpp
@@ -0,0 +1,123 @@
+#include <optional>
+#include <cstdlib>
+#include <cstring>
+#include <string>
+#include <sstream>
+#include <iomanip>      // std::setfill, std::setw
+#include <proto-generated/mpin.pb.h>
+#include <amcl/amcl.h>
+#include <amcl/mpin_BN254.h>
+#include <bsd/stdlib.h>
+#include <boost/algorithm/hex.hpp>
+#include <utils.h>
+
+
+namespace milagro
+{
+  namespace utils
+  {
+    std::string octet_to_string (const amcl::octet & y)
+    {
+      std::string s;
+      s.reserve (y.max);
+      int i
+      {
+      0};
+      int j
+      {
+      y.len};
+      for (int i = 0; i < y.max; ++i)
+	{
+	  s[i] = y.val[i];
+	}
+      return s;
+    }
+    std::string tohex (const std::string & s, bool upper)
+    {
+      std::ostringstream ret;
+      unsigned int c;
+      for (std::string::size_type i = 0; i < s.length (); ++i)
+	{
+	  c = (unsigned int) (unsigned char) s[i];
+	  ret << std::hex << std::setfill ('0') <<
+	    std::setw (2)  << c;
+	}
+      return ret.str ();
+    }
+
+    std::string make_mpin_id (const std::string & clientid)
+    {
+      MPinIdentifier mpin_id;
+      char raw[16];
+      arc4random_buf (raw, sizeof raw);
+      std::string salt (raw);
+      google::protobuf::Timestamp *status = new google::protobuf::Timestamp();
+      status->set_seconds(time(NULL));
+      
+      mpin_id.set_allocated_issued (status);
+      mpin_id.set_userid (clientid);
+      mpin_id.set_salt (salt);
+      // now i shall compute the salt
+      std::shared_ptr<std::string> output = std::make_shared<std::string>();
+      output->reserve (512);
+      mpin_id.SerializeToString (output.get());
+      auto outhex =  tohex (*output, false);
+      return outhex;
+    }
+    
+
+  std::string sha256_hash (const std::string & current)
+  {
+    // todo: return an hash
+    return current;
+  }
+  MPinIdentifier decode_mpin (const std::string & mpinSerialized)
+  {
+    MPinIdentifier identifer;
+    // todo this shall be moved values.
+    identifer.set_activatekey ("89289");
+    identifer.set_userid ("jo");
+    // todo more fields to be from the origianl mpinSerialized
+    // that it shall be decoded for real.
+    return identifer;;
+  }
+
+
+  void make_hash_id (const std::optional < std::string > &hash_pin_id,
+		     const std::optional < std::string > &user_id,
+		     amcl::octet & HCID)
+  {
+    char client_id[256];
+    amcl::octet CLIENT_ID =
+    {
+    0, sizeof (client_id), client_id};
+    char hcid[PFS_BN254];
+    amcl::octet tmpHCID =
+    {
+    0, sizeof (hcid), hcid};
+
+    // in case we have the user id we will use it
+    if (user_id.has_value () > 0)
+      {
+	std::memcpy (client_id, user_id.value ().c_str (),
+		     sizeof (client_id));
+	OCT_jstring (&CLIENT_ID,
+		     const_cast < char *>(user_id.value ().c_str ()));
+	HASH_ID (HASH_TYPE_BN254, &CLIENT_ID, &tmpHCID);
+      }
+    else
+      {
+	std::memcpy (hcid, hash_pin_id.value ().c_str (), sizeof (hcid));
+      }
+
+    HCID.max = tmpHCID.max;
+    HCID.val = tmpHCID.val;
+    HCID.len = tmpHCID.len;
+
+  }
+  }
+}
+
+
+
+  // octet
diff --git a/grpcserver/src/include/dtaclient.h b/grpcserver/src/include/dtaclient.h
new file mode 100644
index 0000000..d6140e5
--- /dev/null
+++ b/grpcserver/src/include/dtaclient.h
@@ -0,0 +1,26 @@
+#ifndef DTA_CLIENT_H
+#define DTA_CLIENT_H
+#include <string>
+#include <proto-generated/dta.pb.h>
+
+namespace milagro
+{
+
+  namespace dta
+  {
+
+    class dta_client
+    {
+    public:
+      dta_client (const std::string & dtaEndpoint)
+      {
+      }
+      std::string get_client_secret (const milagro::dta::
+				     AuthClientSecretRequest & request)
+      {
+	return "829392389";
+      }
+    };
+  }
+}
+#endif
diff --git a/grpcserver/src/include/dtaserver.h b/grpcserver/src/include/dtaserver.h
new file mode 100644
index 0000000..be0558f
--- /dev/null
+++ b/grpcserver/src/include/dtaserver.h
@@ -0,0 +1,86 @@
+/*
+* Copyright 2019, Giorgio Zoppi
+*
+* 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
+*
+*         http://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 DTA_SERVER_IMPL
+#define DTA_SERVER_IMPL
+#include <string>
+#include <memory>
+#include <array>
+#include <optional>
+#include <map>
+#include <proto-generated/dta.grpc.pb.h>
+#include <amcl/amcl.h>
+#include <amcl/ecdh_support.h>	// for hmac
+#include <secret_proxy.h>
+
+namespace milagro
+{
+  namespace dta
+  {
+    using namespace grpc;
+
+    struct client_signature_ctx
+    {
+      std::string client_secret;
+      int32_t appId;
+        std::string hash_mpin_hex;
+        std::string hash_user_id;
+        google::protobuf::Timestamp expires;
+    };
+
+    class dta_server final:public DtaService::Service
+    {
+    public:
+      ::grpc::Status GetClientSecret (ServerContext * context,
+				      const AuthClientSecretRequest * request,
+				      AuthServerResponse * response) override;
+      ::grpc::Status GetServerSecret (ServerContext * context,
+				      const AuthServerSecretRequest * request,
+				      AuthServerResponse * response) override;
+      ::grpc::Status GetStatus (ServerContext * context,
+				const StatusRequest * request,
+				StatusResponse * response) override;
+      ::grpc::Status GetTimePermit (ServerContext * context,
+				    const TimePermitRequest * request,
+				    TimePermitResponse * response) override;
+      ::grpc::Status GetTimePermits (ServerContext * context,
+				     const::milagro::dta::TimePermitsRequest *
+				     request,
+				     TimePermitsResponse * response) override;
+    private:
+
+        amcl::
+	octet make_client_content (const client_signature_ctx & content);
+        amcl::
+	octet make_server_signature_data (const AuthServerSecretRequest *
+					  request);
+        amcl::octet make_time_content (const client_signature_ctx & content);
+        std::string hmac_sign_message (const boost::posix_time::ptime &
+				       timestamp,
+				       const amcl::octet & secret,
+				       const amcl::octet & key);
+        std::string hmac_client_sign (const client_signature_ctx & content,
+				      const amcl::octet & key);
+      ::grpc::Status hmac_verify (std::string request_signature,
+				  amcl::octet request_content,
+				  std::optional < amcl::octet > key);
+
+        std::optional < amcl::octet > getCredential (int key) const;
+        std::unique_ptr < milagro::secure_store::secret_proxy > _key_store;
+      csprng _secure_random;
+    };
+  }
+}
+#endif
diff --git a/grpcserver/src/include/secret_proxy.h b/grpcserver/src/include/secret_proxy.h
new file mode 100644
index 0000000..7c212dd
--- /dev/null
+++ b/grpcserver/src/include/secret_proxy.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2019, Giorgio Zoppi
+ *
+ * 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
+ *
+ *         http://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 SECRET_PROXY_H
+#define SECRET_PROXY_H
+#include <amcl/amcl.h>
+#include <string>
+#include <optional>
+#include <vector>
+#include <map>
+#include <boost/date_time.hpp>
+#include <amcl/randapi.h>
+#include <amcl/mpin_BN254.h>
+
+
+namespace milagro
+{
+  using namespace BN254;
+
+  namespace secure_store
+  {
+    // days of live of the client secret
+    // fixme this shall be configurable
+    const int DAYS_CLIENT_SECRET_MAX = 30;
+    const int RNG_ERROR = 30;
+
+    typedef enum store_type
+    {
+      hsm_store = 0x01,
+      json_store = 0x02
+    };
+    class secret_proxy
+    {
+    public:
+      /*
+       * Construct a proxy for the secret retrieval. The idea is that the secret 
+       * location is indipendent from the access. 
+       */
+      secret_proxy ();
+      ~secret_proxy ();
+
+      /*
+       * Construct a proxy for the secret retrieval
+       * @param configuration file parameters.
+       */
+      secret_proxy (const std::string & config);
+      /*
+       *  We dont want copy in case of a secret_proxy.
+       */
+        secret_proxy (const secret_proxy & copy) = delete;
+      const secret_proxy & operator= (const secret_proxy & copy) = delete;
+      /*
+       * Generate the D-TA master secret. Defaule store is json on disk, 
+       * this might change.
+       * @param type  type of the store, std::optional parameter.
+       */
+        amcl::octet generate_master_secret (store_type type =
+					    store_type::json_store);
+      /*
+       *  Generate the client secret for the MPIN Protocol. 
+       *  One between the user_id or the hash_pin_id shall be present.
+       *  If juse the user_id is present create the hash from the user_id.
+       *  @param user_id std::optional value for the user identifier
+       *  @param hash_pin_id std::optional value for the mpin
+       *  @returns An octect to be used as a secret key 
+       */
+        amcl::octet generate_client_secret (const std::optional <
+					    std::string > &user_id,
+					    const std::optional <
+					    std::string > &hash_pin_id,
+					    store_type type =
+					    store_type::json_store);
+
+        std::vector < std::string > get_time_permits (const
+						      std::optional <
+						      std::string >
+						      &mhash_pin_id,
+						      int count = 1);
+        boost::posix_time::ptime client_key_expire () const;
+        boost::posix_time::ptime server_key_start () const;
+        std::optional < amcl::octet > search_key (int appId);
+
+    private:
+      void init_state ();
+        std::string _master_secret;
+      // secure random number generator
+      csprng _secure_random;
+      // time of expiration
+        boost::posix_time::ptime _client_expireTime;
+        boost::posix_time::ptime _master_startTime;
+      // this shall be moved
+        std::map < int32_t, amcl::octet > _key_store;
+
+    };
+  }
+}
+#endif
diff --git a/grpcserver/src/include/utils.h b/grpcserver/src/include/utils.h
new file mode 100644
index 0000000..436a5ba
--- /dev/null
+++ b/grpcserver/src/include/utils.h
@@ -0,0 +1,27 @@
+#ifndef _MILAGRO_OCT_UTILS_H
+#define _MILAGRO_OCT_UTILS_H
+
+#include <amcl/amcl.h>
+#include <string>
+#include <optional>
+#include <proto-generated/mpin.pb.h>
+
+namespace milagro
+{
+  namespace utils
+  {
+    extern std::string octet_to_string (const amcl::octet & y);
+
+    extern void make_hash_id (const std::optional < std::string >
+			      &hash_pin_id,
+			      const std::optional < std::string > &user_id,
+			      amcl::octet & HCID);
+    extern std::string make_mpin_id (const std::string & userId);
+      std::string sha256_hash (const std::string & current);
+
+    extern MPinIdentifier decode_mpin (const std::string & mpinSerialized);
+    extern std::string tohex (const std::string & s, bool upper = false);
+
+  }				// name
+}
+#endif
diff --git a/grpcserver/src/protos/dta.proto b/grpcserver/src/protos/dta.proto
new file mode 100644
index 0000000..a8463a8
--- /dev/null
+++ b/grpcserver/src/protos/dta.proto
@@ -0,0 +1,82 @@
+syntax = "proto3";
+import "google/protobuf/timestamp.proto";
+import "mpin.proto";
+package milagro.dta;
+
+enum ResultCode 
+{
+    SUCCESS = 0;
+    PROTOCOL_ERROR = 1;
+    INVALID_SIGNATURE = 2;
+    KEY_GENERATION_FAILED = 3;
+}
+message AuthClientSecretRequest
+{
+    int32 appId = 1;
+    google.protobuf.Timestamp expireTime = 2;
+    bytes mpinIdHexEncoded = 3;
+    bytes hashUserId = 4;
+    bytes hmacSignature = 5;
+    bool mobile = 6;
+}
+message AuthServerSecretRequest
+{
+    ResultCode statusCode = 1;
+    int32 appId = 2;
+    google.protobuf.Timestamp expireTime = 3;
+    bytes hmacSignature = 4;
+}
+message AuthServerResponse
+{
+   int32 statusCode = 1;
+   string responseMessage = 2;
+   bytes secret = 3;
+   google.protobuf.Timestamp time=4;
+   bytes hmacSignature = 5;
+}
+message TimePermitsRequest
+{
+    int32 appId = 1;
+    bytes mpinIdHexEncoded = 2;
+    bytes hmacSignature = 3;
+    int32 count = 4;
+}
+message TimePermitRequest
+{
+    int32 appId = 1;
+    bytes mpinIdHexEncoded = 2;
+    bytes hmacSignature = 3;
+}
+
+message TimePermitsResponse
+{
+    ResultCode statusCode = 1;
+    repeated bytes timePermit =2;
+}
+
+message TimePermitResponse
+{
+    ResultCode statusCode = 1;
+    bytes timePermit =2;
+}
+message StatusRequest
+{
+    int32 appId = 1;
+    bytes hmacSignature = 2;
+}       
+message StatusResponse
+{
+    ResultCode statusCode = 1;
+    google.protobuf.Timestamp startTime = 2;
+    string serviceName =3; 
+}
+
+// The dta service definition.
+service DtaService {
+  // Sends a greeting
+  rpc GetClientSecret (AuthClientSecretRequest) returns (AuthServerResponse) {}
+  rpc GetServerSecret (AuthServerSecretRequest) returns (AuthServerResponse) {}
+  rpc GetStatus(StatusRequest) returns (StatusResponse) {}
+  rpc GetTimePermit(TimePermitRequest) returns (TimePermitResponse) {}
+  rpc GetTimePermits(TimePermitsRequest) returns (TimePermitsResponse) {}
+}
diff --git a/grpcserver/src/protos/mpin.proto b/grpcserver/src/protos/mpin.proto
new file mode 100644
index 0000000..92e18a3
--- /dev/null
+++ b/grpcserver/src/protos/mpin.proto
@@ -0,0 +1,11 @@
+syntax = "proto3";
+import "google/protobuf/timestamp.proto";
+message MPinIdentifier 
+{
+   int32 appid = 1;
+   google.protobuf.Timestamp issued = 2;
+   string userid = 3;
+   bytes salt = 4;
+   bytes activatekey = 5;
+   bytes regott = 6;
+}
diff --git a/grpcserver/src/protos/rpa.proto b/grpcserver/src/protos/rpa.proto
new file mode 100644
index 0000000..056c2c5
--- /dev/null
+++ b/grpcserver/src/protos/rpa.proto
@@ -0,0 +1,63 @@
+syntax = "proto3";
+package milagro.rpa;
+
+import "google/protobuf/timestamp.proto";
+import "mpin.proto";
+
+message VerifyRequest
+{
+    bytes activateKey = 1;
+    bytes mpinId = 2;
+    bool mobile = 3;
+    string userId = 4;
+    google.protobuf.Timestamp expireTime = 5;
+    bool resend = 6;
+    bytes userData = 7;
+}
+message VerifyResponse
+{
+   int32 status = 1;
+   bool forceActivate = 2;
+}
+message AuthenticateRequest
+{
+    bytes authOTT = 1;
+    string version = 2;
+    string type = 3;   
+}
+message AuthenticateResponse
+{ 
+    int32 status = 1;
+    string message = 2;
+    string userId = 3;
+    bytes mpinId= 4;
+}
+message PermitRequest 
+{
+   bytes mpinId = 1;
+}
+message PermitResponse 
+{
+    int32 status = 2;
+}
+
+/*
+* The RPA is the only part in the system that is strictly specific to each server instance and i
+*   implements the logic of the specific Web Application. 
+*   In order for this Web Application to serve as RPA, 
+*   it should implement the below RESTful endpoints. 
+*   Note that the actual URL's for the endpoints are customizable, 
+*   and therefore example endpoint names are shown in the brackets. 
+*   The actual endpoint URLs should be configured in the RPS.
+*/
+// The RPS service definition.
+service RpaService {
+
+    /*
+  *  This request is made by the RPA when the end-user identity verification 
+  *  is complete.
+  */
+ rpc Verify(VerifyRequest) returns (VerifyResponse) {}
+ rpc Permit(PermitRequest) returns (PermitResponse) {}
+ rpc Authentication (AuthenticateRequest) returns (AuthenticateResponse) {}
+}
\ No newline at end of file
diff --git a/grpcserver/src/protos/rps.proto b/grpcserver/src/protos/rps.proto
new file mode 100644
index 0000000..2e2f4e0
--- /dev/null
+++ b/grpcserver/src/protos/rps.proto
@@ -0,0 +1,353 @@
+syntax = "proto3";
+package milagro.rps;
+import "google/protobuf/timestamp.proto";
+import "mpin.proto";
+
+ enum ResultCode {
+    OK = 0;
+    REGISTRATION_STARTED = 1;
+ }
+
+
+message SetupState
+{
+    ResultCode status = 1;
+    google.protobuf.Timestamp expireTime = 2;
+    bytes mpinHex = 3;
+    bytes regOTT = 4;
+    bool active = 5;
+}
+message SetupRequest
+{ 
+   /*
+   * The encoded mpin hexadecimal value.
+   */
+   bytes mpinHex = 1;
+    /*
+    * User identifier 
+    */
+   string userId = 2;
+  /*
+   * Indicates (1 or 0) whether the flow is carried out 
+   * by the mobile client (1), or not (0).
+   */
+   bool mobile = 3;
+  /*
+  * (Optional) Depending on the server preferences, 
+  * the Client might provide a friendly name describing 
+  * the device from which the request is coming. 
+  * This name will be further forwarded to the RPA so it can attach it to 
+  * the end-user information that it stores.
+  */ 
+
+  /*
+  * Identifier of the device
+  */
+  bytes deviceId = 4;
+ /*
+  * In case an already started setup flow should be re-started, 
+  *  this should be the original <registration-ott> that was returned 
+  *  in the initial response.
+  * 
+  */
+  bytes regOtt = 5;
+  /*
+  * Optional user data to be associated with user. 
+  */ 
+  bytes userData = 6;
+};
+message SetupResponse
+{
+
+ ResultCode statusCode = 1;
+/**
+* Expiration time for the user setup to
+* in case the rps should wait for user verification
+* to be completed.
+*/
+ google.protobuf.Timestamp expireTime = 2;
+ /**
+ * Indicates if the useras been already made active
+ */
+ bool active = 3;
+ /**
+ * A reference number identifing the setup
+ * process for the given mpin. The number is valid
+ * until the flow is complete or expired and
+ * serves as a type of OTT.
+ */
+ bytes regOTT = 4;
+ /*
+ * The current system time.
+ */
+ google.protobuf.Timestamp nowTime = 5;
+ /*
+ * The coded mpin in hexadecimal.
+ */
+ bytes mpinHex = 6;
+}
+
+message UserRequest
+{
+    /*
+    * MPIN identifier to be provided
+    */
+    bytes mpinId = 1;
+  /* 
+  * The string identifying the end-user. 
+  *  It might be the end-user e-mail address or any other system-unique string.
+  */
+    string userId = 2;
+  /*
+  *
+  */
+  bool mobile = 3;
+  /*
+  * (Optional) Depending on the server preferences, 
+  * the Client might provide a friendly name describing 
+  * the device from which the request is coming. 
+  * This name will be further forwarded to the RPA so it can attach it to 
+  * the end-user information that it stores.
+  */ 
+
+   bytes deviceId = 4;
+   /*
+  * In case an already started setup flow should be re-started, 
+  *  this should be the original <registration-ott> that was returned 
+  *  in the initial response.
+  * 
+  */
+  bytes registrationOtt = 5;
+  /*
+  * Optional user data to be associated with user. 
+  */ 
+  bytes userData = 6;
+  bytes salt = 7;
+}
+
+
+message UserResponse
+{
+    google.protobuf.Timestamp expireTime = 1;
+    bool active = 2;
+    bytes regOTT = 3;
+    google.protobuf.Timestamp  nowTime =4;
+    bytes mpinId = 5;
+}
+message UserVerifyRequest
+{
+    bytes mpinIdHex = 1;
+    bytes activateKey = 2;
+}
+message UserVerifyResponse
+{
+    int32 statusCode = 1;
+}
+message MPinExchange1Request
+{
+   bytes mpinHex = 1;
+   bytes mpinU = 2;
+   bytes mpinUT = 3;
+}        
+message MPinExchange1Response
+{
+
+    int32 statusCode = 1;
+    uint32 pass = 2;
+    bytes y = 3;
+    string version = 4;    
+} 
+message MPinExchange2Request
+{
+  bytes v = 1;
+  uint32 pass = 2; 
+  bool mobile = 3;
+}
+message MPinExchange2Response
+{
+    int32 statusCode = 1;
+    uint32 pass = 2;
+    bytes authOTT = 3;
+    string version = 4;
+}
+message SignatureRequest 
+{
+/*
+* Reference OTT registration number
+* provided in response of Setup call.
+*/
+    bytes regOTT = 1;
+    bytes mpinHex = 2;
+}
+message SignatureResponse
+{
+    int32 appid = 1;
+    bytes clientSecret = 2;
+    bytes mpinHex = 3;
+    bytes hashmpin = 4;
+    google.protobuf.Timestamp expireTime = 5;
+    bytes signature = 6;
+}
+message StatusCodeResponse 
+{
+    int32 statusCode = 1;
+}
+
+message TimePermitResponse
+{
+    int32 statusCode = 1;
+    google.protobuf.Timestamp date = 2;
+    string message = 3;
+    string version = 4;
+    bytes timePermit = 5;
+    int32 storageId = 6;
+    bytes signature = 7;  
+}
+message AuthToken
+{
+    google.protobuf.Timestamp expires = 1; 
+    int32 pinError = 2;
+    int32 successCode = 3;
+    bytes mpinId = 4;
+    bool OTP = 5;
+    int32 pinErrorCost = 6;
+}
+message UpdateTokenRequest 
+{
+    AuthToken token = 1;
+    bytes authOTT = 2;
+    bytes signature =3;
+}
+message AuthenticationRequest
+{   
+    bytes authOTT = 1;
+}
+message AuthenticationResponse
+{
+    int32 status = 1;
+    string message = 2;
+    string userId = 3;
+    bytes mpinId= 4;
+}
+message MobileLoginRequest 
+{
+ // return success if the RPA doenst ban the user.
+ bytes authOTT = 2;
+ string logoutURL = 3;
+ bytes logoutData = 4;
+} 
+message MobileLoginResponse
+{
+    // return success if the RPA doenst ban the user.
+    int32 status = 1;
+
+}
+
+message MobileAccessNumberRequest 
+{
+ // return success if the RPA doenst ban the user. 
+} 
+message MobileAccessNumberResponse
+{
+    int32 status = 1;    
+    int64 localTimeStart = 2;
+    int32 ttlSeconds = 3;
+    int64 localTimeEnd = 4;
+    bytes webOTT = 5;
+    int64 accessNumber = 6;
+}
+message MobileAuthenticateRequest
+{
+    bytes authOTT = 1;
+    string version = 2;
+    string type = 3;
+}
+message MobileAuthenticateResponse
+{
+    int32 statusCode = 1;
+}
+
+message MPinHex
+{
+    int32 statusCode = 1;
+    bytes mpinHex = 2;
+};
+// The RPS service definition.
+service RpsService {
+
+    /*
+     * This request is made 
+     * The purpose of the setup is the following:
+     * 1. Verify user identity
+     * 2. Get the two shares of the pin permit and combine them
+     * 3. Extract the user pin code from the client secret to form
+     * MPIN Token
+     * 4. Store the MPIN Token on the client machine.
+     * 5. This request is made by the Client (through a proxy)
+     * to initiate the Setup flow for an end-user, or to restart it.
+     * 6. When the flow is initially started,
+     * the request is made without the optional /<mpin-id>.
+     * In this case the RPS generates a new <mpin-id>
+     * which is returned in the response data.
+     * The <mpin-id> is a hex-encoded JSON structure
+     */
+
+     rpc Setup(SetupRequest) returns (SetupResponse) {}
+
+  /*
+  * The client signal that the setup has been done to the server.
+  * RPS does nothing.
+  */
+  rpc SetupDone(MPinHex) returns (StatusCodeResponse) {}
+  /**
+  * This request is made by the Client (through a proxy) and serves several purposes:
+
+    1. To obtain the server share of the Time Permit. As part of this request the RPS will get the Time Permit share from the server D-TA and will return it in the response.
+    2. To obtain the parameters that should be used to request the cloud share of the Time Permit. Those parameters include a unique signature without which the cloud-hosted D-TA will not fulfill the request.
+    3. To generate obfuscated (hashed) M-Pin ID, which is further used by the cloud-hosted services to identify the end-user.
+
+  */
+  rpc GetSignature(SignatureRequest) returns (SignatureResponse){}
+  
+  /*
+  *
+  * This request is made by the Client (through a proxy) to obtain the server share of the Time Permit for the given <mpin-id>. The RPS makes a request to the server-hosted D-TA Service 
+  * to obtain the Time Permit Share and returns the result to the Client. 
+  * Prior to sending the request to the D-TA, 
+  * the RPS will make a GET /permitUser?mpin_id= request to the RPA, 
+  * which might revoke the access to the service for the specified user. 
+  * The RPA should respond with 200 OK, if the RPS should proceed 
+  *  with the time permit request, or with 403 if the user is revoked. 
+  * The actual RPA endpoint for theGET /permitUser request is configurable. 
+  * If it is not configured, the RPS will not make 
+  * this request and will assume that no user should be revoked by the RPA. 
+  * Additional purpose of this request is to provide the Client with the current date and the location of the cache storage for cloud share of the Time Permit. The Client should use 
+  * those in order to check whether the cloud TP share is stored locally,
+  *  or on the cache storage, or it should be requested from the cloud-hosted D-TA. 
+  * As part of this request the RPS will also generate and return in the response a unique signature which should further be used in the request 
+  * for the second Time Permit Share from the cloud-hosted D-TA Service.
+  */
+  rpc GetTimePermit(MPinHex) returns (TimePermitResponse) {}
+  
+  
+  /*
+  *  This request is maed by the mfa server as a resiult of an authentication 
+  *  attempt. The server passes a token which indicates whether the auteation is 
+  *  successful or not as well a reference number fot hre authentication attempt.
+  *  This reference number is also provided to the client, which it will use it 
+  *  in the AuthenticationRequest. 
+  */
+  rpc UpdateToken(UpdateTokenRequest) returns(StatusCodeResponse) {}
+
+  /*
+  * The request is made by the rpa to validate the successful authentication for 
+  * an end user. The RPA should provide the authentication reference number OTT
+  * in order to the RPS validate the authentication.
+  */
+  rpc NewAutentication(AuthenticationRequest) returns (AuthenticationResponse) {}
+ 
+ /** First pass of the autentication protocol */
+  rpc MPinExchange1 (MPinExchange1Request) returns (MPinExchange1Response) {}
+  rpc MPinExchange2 (MPinExchange2Request) returns (MPinExchange2Response) {}
+ 
+}
diff --git a/grpcserver/src/test_server.crt b/grpcserver/src/test_server.crt
new file mode 100644
index 0000000..e69b0c9
--- /dev/null
+++ b/grpcserver/src/test_server.crt
@@ -0,0 +1,33 @@
+-----BEGIN CERTIFICATE-----
+MIIFxDCCA6wCCQC6IvAmdtzinzANBgkqhkiG9w0BAQsFADCBozELMAkGA1UEBhMC
+VVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxGTAXBgNV
+BAoMEFo0QXNzb2NpYXRlcyBMTEMxETAPBgNVBAsMCFNlY3VyaXR5MRkwFwYDVQQD
+DBB6NGFzc29jaWF0ZXMuY29tMSQwIgYJKoZIhvcNAQkBFhVyb290QHo0YXNzb2Np
+YXRlcy5jb20wHhcNMTkwNTI5MjIyNTEwWhcNMjkwNTI2MjIyNTEwWjCBozELMAkG
+A1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUx
+GTAXBgNVBAoMEFo0QXNzb2NpYXRlcyBMTEMxETAPBgNVBAsMCFNlY3VyaXR5MRkw
+FwYDVQQDDBB6NGFzc29jaWF0ZXMuY29tMSQwIgYJKoZIhvcNAQkBFhVyb290QHo0
+YXNzb2NpYXRlcy5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDE
+gsg5ZwEQX5WyeX2WF2ojHH2MhOTOvQdMwkcDuhc0YDfrWbUVEmkuDZuWF9YAAo0p
+IZ+M58WBcm/hSJcehDw+8HgDUXBhTgfxTMCyoP9vtvIxtF2Vopdat6e34WSY75Hq
+Lo0TMT1oeMHnGqolZfu/CNjjnElpF/tht9AiNa7fD9fNTlM7BcwjIvYa16C48II9
+H+Sz0ip5CmXZpkMI6V0Drs/rTCr/2kp+2hFtvX8JIzN6pRVoJP4GZwoZJX8D6qqF
+PVORYQx003FxCu/zTdvjJs6y5Mbk94S7+ixTv4rZS8i8VmEHCm3um5vSsbVPz4WK
+guZeYxqxhVPG8CEBYtBgRbHsswpP5C1h0puR4VY3PB0+MSlRM1tRlZQ3ajOe/i8P
+JGwWPyyzo0kEY1Vmcd/dgP1RtKlYnYs9ZJn3baQXVR/BS4QFH4P/HqxoF+H+7CES
+08jaUAza33ybYkJ+yAPYhKqFjHdT4cdPkpvwNbRauTtlzdC1ro1xKxJvKpYbKE1S
++RholBTWXlUXG/UdOxWVMVlNpe7RAmhyYWz42NkOng+fI3WSGS5mx4BWui+QR9K/
+Hcv1t5lDdnK1G7oMlaWb8Zi/I0otXyD9tACSppoNVsm5ML34LjzXKOH3oYCXkYbI
+y5d1a31e7ohwlKfCRzRWlX9fY7ZzQnhNe8aHu7nLIQIDAQABMA0GCSqGSIb3DQEB
+CwUAA4ICAQASkimNy/w5PeQbYSEbXiDIKz9Hu1lmqk8mb1n43wORKrudHNwq+m1I
+QT6KDXwg1kTZUojhrR4YBp4eROwJc5nYt67BTxsGQp+DfT5Zef2mvgcqq7vu9Xj1
+v9B3CJyOOdT19KWUlF/TUpZcVV/6rPGvOdzczIGN7pJI+2/p5Py3Tto4dUuExBw0
+40uI7o35UQaizEBBAir84HC5cv2yMOFX5I7rl7mLkF+ubAQn760yCQH34tMzVbSZ
+J6ICUzrIP4BwAvPMoT3ENsnpnIyeX/yFOKI8dmxkKTB9cadId8rZKEW+Fpn/ir/5
+tz84C0E453RmPHuB2Y8wvfwvlWCgklboEhrEDvF/r15bYYhsksOMwHtY1Xzd/p+v
+AUWug3YxaihOZG6jQ/1U7VQPhobjOU3GQwdbA+BdCJMLqmGCKqoqY4BnoHEi2q4X
+nWt2HZrwtTMimQS7LgCfr+MW9d1oJqSZDGIWw49kPp10k9YNrI+WeNGFjK+KQcGh
+vtahCTH2vbSuYU5CJb3srQwMcrmswARJjaJcpCPAa12KWw07sneMRUSvkW4AmGax
+O/dRjGnY56otSrXwPwFd7G8kECQcX0Ba7FcA3Cpm5heuf2x+fZOiLAs48wt36MC8
+EepInNAPbVzHjWpCe73rGW2KGhX4eBLJaBcXxi0viCJEj3qa0AH6VA==
+-----END CERTIFICATE-----
diff --git a/grpcserver/src/test_server.key b/grpcserver/src/test_server.key
new file mode 100644
index 0000000..653be74
--- /dev/null
+++ b/grpcserver/src/test_server.key
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+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
+-----END RSA PRIVATE KEY-----