From 97528038e40b38cdc64df812b73288df88d10829 Mon Sep 17 00:00:00 2001
From: Jean-Paul Calderone <exarkun@twistedmatrix.com>
Date: Thu, 22 Jul 2021 18:46:46 -0400
Subject: [PATCH] Add a tool for extracting the public key from a signing key

---
 PaymentServer.cabal                           |  9 ++++++++
 get-public-key/Main.hs                        | 21 +++++++++++++++++++
 .../PaymentServer.nix                         | 10 +++++++++
 src/PaymentServer/Ristretto.hs                | 12 +++++++++++
 4 files changed, 52 insertions(+)
 create mode 100644 get-public-key/Main.hs

diff --git a/PaymentServer.cabal b/PaymentServer.cabal
index 1a96e00..1b29cf0 100644
--- a/PaymentServer.cabal
+++ b/PaymentServer.cabal
@@ -67,6 +67,15 @@ executable PaymentServer-generate-key
                      , PaymentServer
   default-language:    Haskell2010
 
+executable PaymentServer-get-public-key
+  hs-source-dirs:      get-public-key
+  main-is:             Main.hs
+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N -Wmissing-import-lists -Wunused-imports
+  build-depends:       base
+                     , text
+                     , PaymentServer
+  default-language:    Haskell2010
+
 test-suite PaymentServer-tests
   type:                exitcode-stdio-1.0
   hs-source-dirs:      test
diff --git a/get-public-key/Main.hs b/get-public-key/Main.hs
new file mode 100644
index 0000000..952caef
--- /dev/null
+++ b/get-public-key/Main.hs
@@ -0,0 +1,21 @@
+-- | Extract a public key from Ristretto-flavored PrivacyPass signing key read from stdin.
+module Main
+  ( main
+  ) where
+
+import Prelude hiding
+  ( putStrLn
+  , getLine
+  )
+
+import Data.Text.IO
+  ( putStrLn
+  , getLine
+  )
+
+import PaymentServer.Ristretto
+  ( getPublicKey
+  )
+
+main :: IO ()
+main = getLine >>= getPublicKey >>= putStrLn
diff --git a/nix/materialized.paymentserver/PaymentServer.nix b/nix/materialized.paymentserver/PaymentServer.nix
index e77024c..842157c 100644
--- a/nix/materialized.paymentserver/PaymentServer.nix
+++ b/nix/materialized.paymentserver/PaymentServer.nix
@@ -93,6 +93,16 @@
           hsSourceDirs = [ "generate-key" ];
           mainPath = [ "Main.hs" ];
           };
+        "PaymentServer-get-public-key" = {
+          depends = [
+            (hsPkgs."base" or (errorHandler.buildDepError "base"))
+            (hsPkgs."text" or (errorHandler.buildDepError "text"))
+            (hsPkgs."PaymentServer" or (errorHandler.buildDepError "PaymentServer"))
+            ];
+          buildable = true;
+          hsSourceDirs = [ "get-public-key" ];
+          mainPath = [ "Main.hs" ];
+          };
         };
       tests = {
         "PaymentServer-tests" = {
diff --git a/src/PaymentServer/Ristretto.hs b/src/PaymentServer/Ristretto.hs
index 7c06520..1018eb5 100644
--- a/src/PaymentServer/Ristretto.hs
+++ b/src/PaymentServer/Ristretto.hs
@@ -4,6 +4,7 @@
 module PaymentServer.Ristretto
   ( Issuance(Issuance)
   , randomSigningKey
+  , getPublicKey
   , ristretto
   ) where
 
@@ -159,3 +160,14 @@ randomSigningKey = do
   result <- peekCString cString
   free cString
   return $ pack result
+
+-- | getPublicKey returns the base64 encoded public key corresponding to the
+-- base64 encoded signing key passed to it.
+getPublicKey :: Text -> IO Text
+getPublicKey enc_skey = do
+  enc_cstr_skey <- newCString . unpack $ enc_skey
+  skey <- signing_key_decode_base64 $ enc_cstr_skey
+  pkey <- signing_key_get_public_key skey
+  enc_cstr_pkey <- public_key_encode_base64 pkey
+  enc_pkey <- peekCString enc_cstr_pkey
+  return $ pack enc_pkey
-- 
GitLab