diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,15 @@
 # Changelog
 
+## 0.1.3 (2026-01-04)
+
+* Performance improvements:
+  - Cache `KeyAggContext` in `SessionContext` to avoid redundant EC operations
+  - Replace lazy `foldl` with strict `foldl'` to prevent space leaks
+  - Add strictness annotations to `SessionContext` fields
+  - Replace O(n) list indexing with O(log n) `Seq.lookup` in `partialSigVerify`
+  - Optimize `integerToBytes32` to eliminate intermediate list allocation
+  - Fix `NFData` instances in benchmarks for accurate measurements
+
 ## 0.1.2 (2025-12-30)
 
 * Fix Hackage build failure by implementing `modQ` locally to support `ppad-secp256k1` 0.5.0+.
diff --git a/bench/Main.hs b/bench/Main.hs
--- a/bench/Main.hs
+++ b/bench/Main.hs
@@ -14,8 +14,8 @@
   PubNonce (..),
   SecKey (..),
   SecNonce (..),
-  SecNonceGenParams,
-  SessionContext,
+  SecNonceGenParams (..),
+  SessionContext (..),
   Tweak (..),
  )
 import qualified Crypto.Curve.Secp256k1.MuSig2 as M
@@ -45,10 +45,12 @@
   rnf ctx = rnf (M.aggregatedPubkey ctx)
 
 instance NFData SessionContext where
-  rnf _ = () -- SessionContext contains multiple fields, but we'll keep it simple
+  rnf (SessionContext an ps ts m kc) =
+    rnf an `seq` rnf ps `seq` rnf ts `seq` rnf m `seq` rnf kc
 
 instance NFData SecNonceGenParams where
-  rnf _ = () -- SecNonceGenParams contains multiple fields, but we'll keep it simple
+  rnf (SecNonceGenParams pk sk apk mg ei) =
+    rnf pk `seq` rnf sk `seq` rnf apk `seq` rnf mg `seq` rnf ei
 
 -- | Main benchmark function.
 main :: IO ()
diff --git a/lib/Crypto/Curve/Secp256k1/MuSig2.hs b/lib/Crypto/Curve/Secp256k1/MuSig2.hs
--- a/lib/Crypto/Curve/Secp256k1/MuSig2.hs
+++ b/lib/Crypto/Curve/Secp256k1/MuSig2.hs
@@ -82,7 +82,7 @@
   partialSigVerify,
   aggPartials,
   -- MuSig2 Session
-  SessionContext,
+  SessionContext (..),
   mkSessionContext,
   -- Key aggregation
   KeyAggContext,
@@ -115,7 +115,7 @@
 import Data.ByteString (ByteString)
 import qualified Data.ByteString as BS
 import qualified Data.ByteString.Lazy as LBS
-import Data.Foldable (toList)
+import Data.Foldable (foldl', toList)
 import Data.List (isPrefixOf)
 import Data.Maybe (fromJust, fromMaybe)
 import Data.Sequence (Seq)
@@ -136,11 +136,9 @@
   ByteString
 aggPartials partials ctx =
   let
-    publicKeys = pks ctx
-    tweaks' = tweaks ctx
     nonce = getSigningNonce ctx
     e = bytesToInteger $ getSigningHash ctx
-    keyCtx = if Seq.null tweaks' then mkKeyAggContext publicKeys Nothing else foldl applyTweak (mkKeyAggContext publicKeys Nothing) tweaks'
+    keyCtx = cachedKeyAggCtx ctx
     aggPk = q keyCtx
     taccVal = maybe 0 getTweak $ tacc keyCtx
     gaccVal = gacc keyCtx
@@ -174,10 +172,9 @@
 sign secnonce sk ctx =
   let
     publicKeys = pks ctx
-    tweaks' = tweaks ctx
     nonce = getSigningNonce ctx
     e = bytesToInteger $ getSigningHash ctx
-    keyCtx = if Seq.null tweaks' then mkKeyAggContext publicKeys Nothing else foldl applyTweak (mkKeyAggContext publicKeys Nothing) tweaks'
+    keyCtx = cachedKeyAggCtx ctx
     aggPk = q keyCtx
     oddAggPk = not $ isEvenPub aggPk
     gaccVal = gacc keyCtx
@@ -229,9 +226,14 @@
 partialSigVerify partial nonces pks tweaks msg idx =
   let aggNonce = fromJust $ aggNonces nonces
       ctx = mkSessionContext aggNonce pks tweaks msg
-      noncesList = toList nonces
-      pk = if idx < length pks then toList pks !! idx else error "musig2 (partialSigVerify): signer index out of range of the list of public keys"
-      pubnonce = if idx < length noncesList then noncesList !! idx else error "musig2 (partialSigVerify): signer index out of range of the list of public nonces"
+      noncesSeq = Seq.fromList (toList nonces)
+      pksSeq = Seq.fromList (toList pks)
+      pk = case Seq.lookup idx pksSeq of
+        Just p -> p
+        Nothing -> error "musig2 (partialSigVerify): signer index out of range of the list of public keys"
+      pubnonce = case Seq.lookup idx noncesSeq of
+        Just n -> n
+        Nothing -> error "musig2 (partialSigVerify): signer index out of range of the list of public nonces"
    in partialSigVerifyInternal partial pubnonce pk ctx
 
 {- | Verifies a 'PartialSignature'.
@@ -254,8 +256,7 @@
 partialSigVerifyInternal partial pubnonce pk ctx =
   let
     publicKeys = pks ctx
-    tweaks' = tweaks ctx
-    keyCtx = if Seq.null tweaks' then mkKeyAggContext publicKeys Nothing else foldl applyTweak (mkKeyAggContext publicKeys Nothing) tweaks'
+    keyCtx = cachedKeyAggCtx ctx
     aggPk = q keyCtx
     oddAggPk = not $ isEvenPub aggPk
     gaccVal = gacc keyCtx
@@ -342,14 +343,16 @@
 
 -- | Session aggregation context that holds the relevant context for a MuSig2 signing session.
 data SessionContext = SessionContext
-  { aggNonce :: PubNonce
+  { aggNonce :: !PubNonce
   -- ^ Aggregated 'PubNonce'.
-  , pks :: Seq Pub
+  , pks :: !(Seq Pub)
   -- ^ Ordered 'Seq' of 'Pub'keys.
-  , tweaks :: Seq Tweak
+  , tweaks :: !(Seq Tweak)
   -- ^ 'Seq' of 'Tweak's.
-  , msg :: ByteString
+  , msg :: !ByteString
   -- ^ Message to be signed.
+  , cachedKeyAggCtx :: !KeyAggContext
+  -- ^ Cached 'KeyAggContext' to avoid recomputation.
   }
 
 {- | Creates a 'SessionContext'.
@@ -390,12 +393,16 @@
       Nothing -> error "musig2 (mkSessionContext): failed to aggregate public keys"
       Just aggPk
         | aggPk == _CURVE_ZERO -> error "musig2 (mkSessionContext): aggregated public key is point at infinity"
-        | otherwise -> SessionContext aggNonce pks' tweaks' msg
+        | otherwise -> SessionContext aggNonce pks' tweaks' msg keyCtx
  where
   pks' = Seq.fromList (toList pks)
   tweaks' = Seq.fromList (toList tweaks)
   checkNeg = (< 0) . getTweak
   checkOrder = (>= curveOrder) . getTweak
+  -- Compute and cache the KeyAggContext once
+  keyCtx =
+    let baseCtx = mkKeyAggContext pks' Nothing
+     in if Seq.null tweaks' then baseCtx else foldl' applyTweak baseCtx tweaks'
 
 {- | Gets the signing nonce as a 'Projective' following
 [BIP-0327 algorithm and recommendations](https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki#dealing-with-infinity-in-nonce-aggregation).
@@ -419,12 +426,7 @@
   let
     aggNonce = ctx.aggNonce
     aggNonce' = if aggNonce.r1 == _CURVE_ZERO then PubNonce _CURVE_G aggNonce.r2 else aggNonce
-    -- Apply tweaks to get the correct aggregate public key
-    keyCtx =
-      if Seq.null (tweaks ctx)
-        then mkKeyAggContext (pks ctx) Nothing
-        else foldl applyTweak (mkKeyAggContext (pks ctx) Nothing) (tweaks ctx)
-    aggPubKey = q keyCtx
+    aggPubKey = q (cachedKeyAggCtx ctx)
     msg = ctx.msg
     nonceBytes = serialize_point aggNonce'.r1 <> serialize_point aggNonce'.r2
     qBytes = xBytes aggPubKey
@@ -442,12 +444,7 @@
 getSigningHash :: SessionContext -> ByteString
 getSigningHash ctx =
   let
-    -- Apply tweaks to get the correct aggregate public key
-    keyCtx =
-      if Seq.null (tweaks ctx)
-        then mkKeyAggContext (pks ctx) Nothing
-        else foldl applyTweak (mkKeyAggContext (pks ctx) Nothing) (tweaks ctx)
-    aggPubKey = q keyCtx
+    aggPubKey = q (cachedKeyAggCtx ctx)
     qBytes = xBytes aggPubKey
     msg = ctx.msg
     nonce = getSigningNonce ctx
@@ -708,6 +705,8 @@
 aggNonces :: (Traversable t) => t PubNonce -> Maybe PubNonce
 aggNonces nonces
   | Seq.null noncesSeq = Nothing
-  | otherwise = Just $ foldl1 (<>) noncesSeq
+  | otherwise = case Seq.viewl noncesSeq of
+      Seq.EmptyL -> Nothing
+      x Seq.:< xs -> Just $! foldl' (<>) x xs
  where
   noncesSeq = Seq.fromList (toList nonces)
diff --git a/lib/Crypto/Curve/Secp256k1/MuSig2/Internal.hs b/lib/Crypto/Curve/Secp256k1/MuSig2/Internal.hs
--- a/lib/Crypto/Curve/Secp256k1/MuSig2/Internal.hs
+++ b/lib/Crypto/Curve/Secp256k1/MuSig2/Internal.hs
@@ -134,7 +134,7 @@
 
 -- | Converts an 'Integer' to a 32-byte big-endian 'ByteString'.
 integerToBytes32 :: Integer -> ByteString
-integerToBytes32 i = BS.pack $ reverse [fromInteger (i `shiftR` (8 * j)) .&. 0xff | j <- [0 .. 31]]
+integerToBytes32 i = BS.pack [fromInteger ((i `shiftR` (8 * (31 - j))) .&. 0xff) | j <- [0 .. 31]]
 
 -- | @XOR@s two 'ByteString's of same length.
 xorByteStrings :: ByteString -> ByteString -> ByteString
diff --git a/musig2.cabal b/musig2.cabal
--- a/musig2.cabal
+++ b/musig2.cabal
@@ -1,6 +1,6 @@
 cabal-version:   3.0
 name:            musig2
-version:         0.1.2
+version:         0.1.3
 synopsis:        MuSig2 library
 license:         MIT
 license-file:    LICENSE
