diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,15 @@
 # Changelog for ExchangeAlgebra
 
+## 0.5.3.1 - 2026-10-21
+
+### Fixed
+
+- The `Hashable` instance of `MoneyDecimal` now agrees with its `Eq` instance:
+  values that differ only in trailing zeros (`1.0` and `1.00`) have the same
+  hash. The hash previously used the raw number of decimal places and the
+  mantissa, so equal values could land in different `HashMap` or `HashSet`
+  buckets. The `Binary` encoding is unchanged.
+
 ## 0.5.3.0 - 2026-09-26
 
 ### Added
diff --git a/exchangealgebra.cabal b/exchangealgebra.cabal
--- a/exchangealgebra.cabal
+++ b/exchangealgebra.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           exchangealgebra
-version:        0.5.3.0
+version:        0.5.3.1
 synopsis:       Exchange Algebra for bookkeeping and economic simulation
 description:    Please see the README on GitHub at <https://github.com/yakagika/ExchangeAlgebra#readme>
 category:       Accounting, Finance, Math
diff --git a/src/ExchangeAlgebra/Value.hs b/src/ExchangeAlgebra/Value.hs
--- a/src/ExchangeAlgebra/Value.hs
+++ b/src/ExchangeAlgebra/Value.hs
@@ -61,7 +61,7 @@
     ) where
 
 import           ExchangeAlgebra.Algebra (HatVal (..), Nearly (..))
-import           Data.Decimal            (Decimal, DecimalRaw (Decimal), roundTo')
+import           Data.Decimal            (Decimal, DecimalRaw (Decimal), normalizeDecimal, roundTo')
 import           Data.Word               (Word8)
 import           Data.Hashable           (Hashable (..))
 import           Control.DeepSeq         (NFData (..))
@@ -108,7 +108,9 @@
 
 -- 'Binary'/'Hashable' are defined here (not orphan) because 'Data.Decimal' ships
 -- neither, and 'Alg'/t'Journal' serialization and the binary spill path require
--- @Binary v@. Both go through the (places, mantissa) structure of t'Decimal'.
+-- @Binary v@. 'Binary' keeps the (places, mantissa) structure of t'Decimal'.
+-- 'Hashable' hashes the normalized form (trailing zeros removed), so values that
+-- are equal under 'Eq' (@1.0 == 1.00@) have the same hash.
 instance Binary.Binary MoneyDecimal where
     {-# INLINE put #-}
     put (MoneyDecimal (Decimal places mantissa)) = do
@@ -122,8 +124,8 @@
 
 instance Hashable MoneyDecimal where
     {-# INLINE hashWithSalt #-}
-    hashWithSalt s (MoneyDecimal (Decimal places mantissa)) =
-        s `hashWithSalt` places `hashWithSalt` mantissa
+    hashWithSalt s (MoneyDecimal d) = case normalizeDecimal d of
+        Decimal places mantissa -> s `hashWithSalt` places `hashWithSalt` mantissa
 
 instance NFData MoneyDecimal where
     {-# INLINE rnf #-}
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -26,7 +26,7 @@
 import qualified ExchangeAlgebra.Journal  as EJ
 import qualified ExchangeAlgebra.Journal.Transfer as EJT
 import qualified ExchangeAlgebra.Bookkeeping as EB
-import           ExchangeAlgebra.Value    (MoneyDecimal, bankersRound)
+import           ExchangeAlgebra.Value    (MoneyDecimal (..), bankersRound)
 import qualified ExchangeAlgebra.Simulate as ES
 import           ExchangeAlgebra.Simulate
 import qualified ExchangeAlgebra.Simulate.Lite as Lite
@@ -61,6 +61,8 @@
 import qualified Data.Vector.Unboxed as UV
 
 import qualified Data.HashMap.Strict as HM
+import           Data.Hashable           (hash)
+import           Data.Decimal            (DecimalRaw (Decimal))
 import qualified Data.Map.Strict     as M
 import qualified Data.List           as L
 import qualified Data.List.NonEmpty  as NE
@@ -571,6 +573,18 @@
         actual = EA.projNetNorm qs algSample
     assertNear "Alg.projNetNorm == norm . bar . proj (set semantics)" expected actual
 
+-- | 'MoneyDecimal' values equal under 'Eq' have equal hashes, whatever their
+-- number of decimal places (0.5.3.1: the hash used the raw places and mantissa).
+testMoneyDecimalHashMatchesEq :: IO ()
+testMoneyDecimalHashMatchesEq = do
+    let same :: [(MoneyDecimal, MoneyDecimal)]
+        same = [ (MoneyDecimal (Decimal 1 10), MoneyDecimal (Decimal 2 100))
+               , (MoneyDecimal (Decimal 0 0), MoneyDecimal (Decimal 3 0))
+               , (MoneyDecimal (Decimal 1 125), MoneyDecimal (Decimal 3 12500)) ]
+    assertEqual "equal MoneyDecimal values compare equal" True (all (uncurry (==)) same)
+    assertEqual "equal MoneyDecimal values hash equally" True
+        (all (\(a, b) -> hash a == hash b) same)
+
 -- | R7 sentinel (a): a duplicated exact base must project the same as a single
 -- copy (MoneyDecimal exact: no floating tolerance needed).
 testProjDuplicateExact :: IO ()
@@ -6983,6 +6997,7 @@
     testMapMaybePosting
     testProjMultiPatternOnePass
     testProjNormFastPath
+    testMoneyDecimalHashMatchesEq
     testProjDuplicateExact
     testProjExactWildcardOverlap
     testProjNormBarIdentity
