commit 140b0a32804a0b23068c3656f90dcc89fa8317fc
parent c7feb7f5551d91b7f0962d1aaa9a8065d3be478f
Author: Jared Tobin <jared@jtobin.io>
Date: Fri, 14 Mar 2025 14:04:08 +0400
test: test actual ecdh function
Diffstat:
3 files changed, 42 insertions(+), 22 deletions(-)
diff --git a/ppad-secp256k1.cabal b/ppad-secp256k1.cabal
@@ -53,6 +53,7 @@ test-suite secp256k1-tests
, base16-bytestring
, bytestring
, ppad-secp256k1
+ , ppad-sha256
, tasty
, tasty-hunit
, text
diff --git a/test/Main.hs b/test/Main.hs
@@ -44,11 +44,11 @@ main = do
Nothing -> error "couldn't parse wycheproof vectors"
Just (w0, w1, w2, no, ip) -> defaultMain $ testGroup "ppad-secp256k1" [
units
- -- , wycheproof_ecdsa_verify_tests tex "(ecdsa, sha256)" Unrestricted w0
- -- , wycheproof_ecdsa_verify_tests tex "(ecdsa, sha256, low-s)" LowS w1
+ , wycheproof_ecdsa_verify_tests tex "(ecdsa, sha256)" Unrestricted w0
+ , wycheproof_ecdsa_verify_tests tex "(ecdsa, sha256, low-s)" LowS w1
, wycheproof_ecdh_tests "(ecdh)" w2
- -- , N.execute_ecdsa tex no
- -- , testGroup "bip0340 vectors (schnorr)" (fmap (BIP340.execute tex) ip)
+ , N.execute_ecdsa tex no
+ , testGroup "bip0340 vectors (schnorr)" (fmap (BIP340.execute tex) ip)
]
wycheproof_ecdsa_verify_tests
diff --git a/test/WycheproofEcdh.hs b/test/WycheproofEcdh.hs
@@ -9,15 +9,15 @@ module WycheproofEcdh (
) where
import Crypto.Curve.Secp256k1
+import qualified Crypto.Hash.SHA256 as SHA256
import Data.Aeson ((.:))
import qualified Data.Aeson as A
import qualified Data.Attoparsec.ByteString as AT
-import Data.Bits ((.<<.), (.|.))
+import Data.Bits ((.<<.), (.>>.), (.|.))
import qualified Data.ByteString as BS
import qualified Data.ByteString.Base16 as B16
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
-import qualified GHC.Num.Integer as I
import Test.Tasty (TestTree, testGroup)
import qualified Test.Tasty.HUnit as H (assertBool, assertEqual, testCase)
@@ -42,10 +42,11 @@ execute EcdhTest {..} = H.testCase report $ do
--
H.assertBool "invalid" (t_result `elem` ["invalid", "acceptable"])
Right pub -> do
- let sec = parse_bigint t_private
- sar = parse_bigint t_shared
- Affine x_out _ = affine (mul_unsafe pub sec) -- faster
- H.assertEqual mempty sar x_out
+ let sec = parse_bigint t_private
+ sar = parse_bigint t_shared
+ h_sar = SHA256.hash (unroll32 sar)
+ out = ecdh pub sec
+ H.assertEqual mempty h_sar out
where
report = "wycheproof ecdh " <> show t_tcId
@@ -61,14 +62,14 @@ execute EcdhTest {..} = H.testCase report $ do
parse_der_pub :: AT.Parser Projective
parse_der_pub = do
_ <- AT.word8 0x30 -- SEQUENCE
- len <- fmap fi AT.anyWord8
+ _ <- AT.anyWord8
_ <- parse_der_algo
parse_der_subjectpubkey
parse_der_algo :: AT.Parser ()
parse_der_algo = do
_ <- AT.word8 0x30 -- SEQUENCE
- _ <- fmap fi AT.anyWord8 -- XX check
+ _ <- AT.anyWord8
_ <- parse_der_ecpubkey
_ <- parse_der_secp256k1
pure ()
@@ -127,6 +128,34 @@ parse_der_subjectpubkey = do
Nothing -> fail "invalid content"
Just pt -> pure pt
+der_to_pub :: T.Text -> Either String Projective
+der_to_pub (B16.decodeLenient . TE.encodeUtf8 -> bs) =
+ AT.parseOnly parse_der_pub bs
+
+parse_bigint :: T.Text -> Integer
+parse_bigint (B16.decodeLenient . TE.encodeUtf8 -> bs) = roll bs where
+ roll :: BS.ByteString -> Integer
+ roll = BS.foldl' alg 0 where
+ alg !a (fi -> !b) = (a .<<. 8) .|. b
+
+-- big-endian bytestring encoding
+unroll :: Integer -> BS.ByteString
+unroll i = case i of
+ 0 -> BS.singleton 0
+ _ -> BS.reverse $ BS.unfoldr step i
+ where
+ step 0 = Nothing
+ step m = Just (fi m, m .>>. 8)
+
+-- big-endian bytestring encoding for 256-bit ints, left-padding with
+-- zeros if necessary. the size of the integer is not checked.
+unroll32 :: Integer -> BS.ByteString
+unroll32 (unroll -> u)
+ | l < 32 = BS.replicate (32 - l) 0 <> u
+ | otherwise = u
+ where
+ l = BS.length u
+
data Wycheproof = Wycheproof {
wp_testGroups :: ![EcdhTestGroup]
} deriving Show
@@ -143,16 +172,6 @@ instance A.FromJSON EcdhTestGroup where
parseJSON = A.withObject "EcdhTestGroup" $ \m -> EcdhTestGroup
<$> m .: "tests"
-der_to_pub :: T.Text -> Either String Projective
-der_to_pub (B16.decodeLenient . TE.encodeUtf8 -> bs) =
- AT.parseOnly parse_der_pub bs
-
-parse_bigint :: T.Text -> Integer
-parse_bigint (B16.decodeLenient . TE.encodeUtf8 -> bs) = roll bs where
- roll :: BS.ByteString -> Integer
- roll = BS.foldl' alg 0 where
- alg !a (fi -> !b) = (a .<<. 8) .|. b
-
data EcdhTest = EcdhTest {
t_tcId :: !Int
, t_public :: !T.Text