packages feed

sd-jwt-0.1.0.0: test/DigestSpec.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module DigestSpec (spec) where

import Test.Hspec
import Test.QuickCheck
import Test.QuickCheck.Property ((==>))
import TestHelpers
import TestKeys
import SDJWT.Internal.Types
import SDJWT.Internal.Utils
import SDJWT.Internal.Digest
import SDJWT.Internal.Disclosure
import SDJWT.Internal.Serialization
import SDJWT.Internal.Issuance
import SDJWT.Internal.Presentation
import SDJWT.Internal.Verification (verifySDJWT, verifySDJWTSignature, verifySDJWTWithoutSignature, verifyKeyBinding, verifyDisclosures, extractHashAlgorithm)
import SDJWT.Internal.KeyBinding
import SDJWT.Internal.JWT
import qualified Data.Vector as V
import qualified Data.Aeson as Aeson
import qualified Data.Aeson.Key as Key
import qualified Data.Aeson.KeyMap as KeyMap
import qualified Data.Text as T
import Data.Text.Encoding (encodeUtf8, decodeUtf8')
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BSL
import qualified Data.Map.Strict as Map
import Data.Int (Int64)
import Data.Maybe (isJust, mapMaybe)
import Data.List (find, nub)
import Control.Monad (replicateM)

spec :: Spec
spec = describe "SDJWT.Digest" $ do
  describe "hashAlgorithmToText" $ do
    it "converts SHA256 to sha-256" $ do
      hashAlgorithmToText SHA256 `shouldBe` "sha-256"
    it "converts SHA384 to sha-384" $ do
      hashAlgorithmToText SHA384 `shouldBe` "sha-384"
    it "converts SHA512 to sha-512" $ do
      hashAlgorithmToText SHA512 `shouldBe` "sha-512"
  
  describe "parseHashAlgorithm" $ do
    it "parses sha-256" $ do
      parseHashAlgorithm "sha-256" `shouldBe` Just SHA256
    it "parses sha-384" $ do
      parseHashAlgorithm "sha-384" `shouldBe` Just SHA384
    it "parses sha-512" $ do
      parseHashAlgorithm "sha-512" `shouldBe` Just SHA512
    it "returns Nothing for invalid algorithm" $ do
      parseHashAlgorithm "invalid" `shouldBe` Nothing
    
    it "returns Nothing for empty string" $ do
      parseHashAlgorithm "" `shouldBe` Nothing
  
  describe "defaultHashAlgorithm" $ do
    it "returns SHA256 as default" $ do
      defaultHashAlgorithm `shouldBe` SHA256
    
    describe "computeDigest" $ do
      it "computes digest for a disclosure with SHA256" $ do
        let disclosure = EncodedDisclosure "WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd"
        let digest = computeDigest SHA256 disclosure
        unDigest digest `shouldBe` "jsu9yVulwQQlhFlM_3JlzMaSFzglhQG0DpfayQwLUK4"
      
      it "computes digest for a disclosure with SHA384" $ do
        let disclosure = EncodedDisclosure "WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd"
        let digest = computeDigest SHA384 disclosure
        -- SHA384 produces different digest than SHA256
        unDigest digest `shouldNotBe` "jsu9yVulwQQlhFlM_3JlzMaSFzglhQG0DpfayQwLUK4"
        -- Digest should be non-empty
        T.length (unDigest digest) `shouldSatisfy` (> 0)
      
      it "computes digest for a disclosure with SHA512" $ do
        let disclosure = EncodedDisclosure "WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd"
        let digest = computeDigest SHA512 disclosure
        -- SHA512 produces different digest than SHA256
        unDigest digest `shouldNotBe` "jsu9yVulwQQlhFlM_3JlzMaSFzglhQG0DpfayQwLUK4"
        -- Digest should be non-empty
        T.length (unDigest digest) `shouldSatisfy` (> 0)
      
      it "produces same digest for same disclosure and algorithm" $ do
        let disclosure = EncodedDisclosure "WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd"
        let digest1 = computeDigest SHA256 disclosure
        let digest2 = computeDigest SHA256 disclosure
        unDigest digest1 `shouldBe` unDigest digest2
    
    describe "verifyDigest" $ do
      it "verifies correct digest for SHA256" $ do
        let disclosure = EncodedDisclosure "WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd"
        let digest = computeDigest SHA256 disclosure
        verifyDigest SHA256 digest disclosure `shouldBe` True
      
      it "verifies correct digest for SHA384" $ do
        let disclosure = EncodedDisclosure "WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd"
        let digest = computeDigest SHA384 disclosure
        verifyDigest SHA384 digest disclosure `shouldBe` True
      
      it "verifies correct digest for SHA512" $ do
        let disclosure = EncodedDisclosure "WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd"
        let digest = computeDigest SHA512 disclosure
        verifyDigest SHA512 digest disclosure `shouldBe` True
      
      it "rejects incorrect digest" $ do
        let disclosure = EncodedDisclosure "WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd"
        let wrongDigest = Digest "wrong-digest-value"
        verifyDigest SHA256 wrongDigest disclosure `shouldBe` False
      
      it "rejects digest computed with different algorithm" $ do
        let disclosure = EncodedDisclosure "WyIyR0xDNDJzS1F2ZUNmR2ZyeU5STjl3IiwgImdpdmVuX25hbWUiLCAiSm9obiJd"
        let sha256Digest = computeDigest SHA256 disclosure
        -- SHA256 digest should not verify with SHA384
        verifyDigest SHA384 sha256Digest disclosure `shouldBe` False