diff --git a/CHANGES.md b/CHANGES.md
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,11 @@
 See also https://pvp.haskell.org/faq
 
+## Version 1.4.3.0
+
+ * Export `defaultHashWithSalt` and `defaultHash`.
+ * Fix issue of tuples with 0 first component causing all-zero state.
+ * Change `hashInt` to mix bits more.
+
 ## Version 1.4.2.0
 
  * Fix the foreign signature of `getThreadId`
diff --git a/hashable.cabal b/hashable.cabal
--- a/hashable.cabal
+++ b/hashable.cabal
@@ -1,6 +1,6 @@
 cabal-version:      1.12
 name:               hashable
-version:            1.4.2.0
+version:            1.4.3.0
 synopsis:           A class for types that can be converted to a hash value
 description:
   This package defines a class, 'Hashable', for types that
@@ -8,6 +8,8 @@
   exists for the benefit of hashing-based data
   structures.  The package provides instances for
   basic types and a way to combine hash values.
+  .
+  The 'Hashable' 'hash' values are not guaranteed to be stable across library versions, operating systems or architectures. For stable hashing use named hashes: SHA256, CRC32 etc.
 
 homepage:           http://github.com/haskell-unordered-containers/hashable
 
@@ -36,6 +38,7 @@
    || ==9.0.2
    || ==9.2.5
    || ==9.4.4
+   || ==9.6.1
 
 extra-source-files:
   CHANGES.md
@@ -75,7 +78,7 @@
   include-dirs:     include
   hs-source-dirs:   src
   build-depends:
-      base        >=4.10.1.0 && <4.18
+      base        >=4.10.1.0 && <4.19
     , bytestring  >=0.10.8.2 && <0.12
     , containers  >=0.5.10.2 && <0.7
     , deepseq     >=1.4.3.0  && <1.5
@@ -84,7 +87,7 @@
     , text        >=1.2.3.0  && <1.3  || >=2.0 && <2.1
 
   if !impl(ghc >=9.2)
-    build-depends: base-orphans >=0.8.6 && <0.9
+    build-depends: base-orphans >=0.8.6 && <0.10
 
   if !impl(ghc >=9.4)
     build-depends: data-array-byte >=0.1.0.1 && <0.2
diff --git a/src/Data/Hashable.hs b/src/Data/Hashable.hs
--- a/src/Data/Hashable.hs
+++ b/src/Data/Hashable.hs
@@ -60,6 +60,9 @@
     , hashByteArray
     , hashByteArrayWithSalt
 
+    , defaultHashWithSalt
+    , defaultHash
+
     -- * Caching hashes
     , Hashed
     , hashed
diff --git a/src/Data/Hashable/Class.hs b/src/Data/Hashable/Class.hs
--- a/src/Data/Hashable/Class.hs
+++ b/src/Data/Hashable/Class.hs
@@ -50,6 +50,7 @@
     , hashByteArray
     , hashByteArrayWithSalt
     , defaultHashWithSalt
+    , defaultHash
       -- * Higher Rank Functions
     , hashWithSalt1
     , hashWithSalt2
@@ -228,7 +229,7 @@
     -- Instances might want to implement this method to provide a more
     -- efficient implementation than the default implementation.
     hash :: a -> Int
-    hash = hashWithSalt defaultSalt
+    hash = defaultHash
 
     default hashWithSalt :: (Generic a, GHashable Zero (Rep a)) => Int -> a -> Int
     hashWithSalt = genericHashWithSalt
@@ -293,9 +294,19 @@
 -- cannot also provide a default implementation for that method for
 -- the non-generic instance use case. Instead we provide
 -- 'defaultHashWith'.
+--
+-- @since 1.4.3.0
+--
 defaultHashWithSalt :: Hashable a => Int -> a -> Int
 defaultHashWithSalt salt x = salt `hashInt` hash x
 
+-- | Default implementation of 'hash' based on 'hashWithSalt'.
+--
+-- @since 1.4.3.0
+--
+defaultHash :: Hashable a => a -> Int
+defaultHash = hashWithSalt defaultSalt
+
 -- | Transform a value into a 'Hashable' value, then hash the
 -- transformed value using the given salt.
 --
@@ -533,7 +544,6 @@
     liftHashWithSalt2 _ h s (Right b) = s `hashInt` distinguisher `h` b
 
 instance (Hashable a1, Hashable a2) => Hashable (a1, a2) where
-    hash (a1, a2) = hash a1 `hashWithSalt` a2
     hashWithSalt = hashWithSalt1
 
 instance Hashable a1 => Hashable1 ((,) a1) where
@@ -543,7 +553,6 @@
     liftHashWithSalt2 h1 h2 s (a1, a2) = s `h1` a1 `h2` a2
 
 instance (Hashable a1, Hashable a2, Hashable a3) => Hashable (a1, a2, a3) where
-    hash (a1, a2, a3) = hash a1 `hashWithSalt` a2 `hashWithSalt` a3
     hashWithSalt = hashWithSalt1
 
 instance (Hashable a1, Hashable a2) => Hashable1 ((,,) a1 a2) where
@@ -555,8 +564,6 @@
 
 instance (Hashable a1, Hashable a2, Hashable a3, Hashable a4) =>
          Hashable (a1, a2, a3, a4) where
-    hash (a1, a2, a3, a4) = hash a1 `hashWithSalt` a2
-                            `hashWithSalt` a3 `hashWithSalt` a4
     hashWithSalt = hashWithSalt1
 
 instance (Hashable a1, Hashable a2, Hashable a3) => Hashable1 ((,,,) a1 a2 a3) where
@@ -568,9 +575,6 @@
 
 instance (Hashable a1, Hashable a2, Hashable a3, Hashable a4, Hashable a5)
       => Hashable (a1, a2, a3, a4, a5) where
-    hash (a1, a2, a3, a4, a5) =
-        hash a1 `hashWithSalt` a2 `hashWithSalt` a3
-        `hashWithSalt` a4 `hashWithSalt` a5
     hashWithSalt s (a1, a2, a3, a4, a5) =
         s `hashWithSalt` a1 `hashWithSalt` a2 `hashWithSalt` a3
         `hashWithSalt` a4 `hashWithSalt` a5
@@ -589,9 +593,6 @@
 
 instance (Hashable a1, Hashable a2, Hashable a3, Hashable a4, Hashable a5,
           Hashable a6) => Hashable (a1, a2, a3, a4, a5, a6) where
-    hash (a1, a2, a3, a4, a5, a6) =
-        hash a1 `hashWithSalt` a2 `hashWithSalt` a3
-        `hashWithSalt` a4 `hashWithSalt` a5 `hashWithSalt` a6
     hashWithSalt s (a1, a2, a3, a4, a5, a6) =
         s `hashWithSalt` a1 `hashWithSalt` a2 `hashWithSalt` a3
         `hashWithSalt` a4 `hashWithSalt` a5 `hashWithSalt` a6
@@ -611,9 +612,6 @@
 instance (Hashable a1, Hashable a2, Hashable a3, Hashable a4, Hashable a5,
           Hashable a6, Hashable a7) =>
          Hashable (a1, a2, a3, a4, a5, a6, a7) where
-    hash (a1, a2, a3, a4, a5, a6, a7) =
-        hash a1 `hashWithSalt` a2 `hashWithSalt` a3
-        `hashWithSalt` a4 `hashWithSalt` a5 `hashWithSalt` a6 `hashWithSalt` a7
     hashWithSalt s (a1, a2, a3, a4, a5, a6, a7) =
         s `hashWithSalt` a1 `hashWithSalt` a2 `hashWithSalt` a3
         `hashWithSalt` a4 `hashWithSalt` a5 `hashWithSalt` a6 `hashWithSalt` a7
diff --git a/src/Data/Hashable/Imports.hs b/src/Data/Hashable/Imports.hs
--- a/src/Data/Hashable/Imports.hs
+++ b/src/Data/Hashable/Imports.hs
@@ -5,9 +5,10 @@
     Int64, Int32,
     Word64, Word32,
     xor, shiftR, shiftL,
+    (.&.),
 ) where
 
 import Prelude ()
 import Data.Int (Int64, Int32)
 import Data.Word (Word64, Word32)
-import Data.Bits (xor, shiftR, shiftL)
+import Data.Bits (xor, shiftR, shiftL, (.&.))
diff --git a/src/Data/Hashable/LowLevel.hs b/src/Data/Hashable/LowLevel.hs
--- a/src/Data/Hashable/LowLevel.hs
+++ b/src/Data/Hashable/LowLevel.hs
@@ -61,11 +61,31 @@
 -- | Hash 'Int'. First argument is a salt, second argument is an 'Int'.
 -- The result is new salt / hash value.
 hashInt :: Salt -> Int -> Salt
+hashInt s x = s `rnd` x1 `rnd` x2 `rnd` x3 `rnd` x4
+  where
+    {-# INLINE rnd #-}
+    {-# INLINE x1 #-}
+    {-# INLINE x2 #-}
+    {-# INLINE x3 #-}
+    {-# INLINE x4 #-}
 #if WORD_SIZE_IN_BITS == 64
-hashInt s x = (s * 1099511628211) `xor` x
+    -- See https://github.com/haskell-unordered-containers/hashable/issues/270
+    -- FNV-1 is defined to hash byte at the time.
+    -- We used to hash whole Int at once, which provided very bad mixing.
+    -- Current is a performance-quality compromise, we do four rounds per Int (instead of 8 for FNV-1 or 1 for previous hashable).
+    rnd a b = (a * 1099511628211) `xor` b
+    x1 = shiftR x 48 .&. 0xffff
+    x2 = shiftR x 32 .&. 0xffff
+    x3 = shiftR x 16 .&. 0xffff
+    x4 =           x .&. 0xffff
 #else
-hashInt s x = (s * 16777619) `xor` x
+    rnd a b = (a * 16777619) `xor` b
+    x1 = shiftR x 24 .&. 0xff
+    x2 = shiftR x 16 .&. 0xff
+    x3 = shiftR x  8 .&. 0xff
+    x4 =           x .&. 0xff
 #endif
+
 -- Note: FNV-1 hash takes a byte of data at once, here we take an 'Int',
 -- which is 4 or 8 bytes. Whether that's bad or not, I don't know.
 
diff --git a/tests/Regress.hs b/tests/Regress.hs
--- a/tests/Regress.hs
+++ b/tests/Regress.hs
@@ -7,7 +7,8 @@
 import qualified Test.Framework as F
 import Control.Monad (when)
 import Test.Framework.Providers.HUnit (testCase)
-import Test.HUnit (assertFailure, (@=?))
+import Test.HUnit (Assertion, assertFailure, (@?=))
+import Test.Framework.Providers.QuickCheck2 (testProperty)
 import GHC.Generics (Generic)
 import Data.List (nub)
 import Data.Fixed (Pico)
@@ -27,12 +28,17 @@
 
 #include "MachDeps.h"
 
+assertInequal :: Eq a => String -> a -> a -> Assertion
+assertInequal msg x y
+    | x == y    = assertFailure msg
+    | otherwise = return ()
+
 regressions :: [F.Test]
 regressions = [] ++
 #ifdef HAVE_MMAP
     Mmap.regressions ++
     [ testCase "Fixed" $ do
-        (hash (1 :: Pico) == hash (2 :: Pico)) @=? False
+        (hash (1 :: Pico) == hash (2 :: Pico)) @?= False
     ] ++
 #endif
     [ F.testGroup "Generic: sum of nullary constructors"
@@ -42,17 +48,27 @@
         , testCase "3" $ nullaryCase 3 S3
         , testCase "4" $ nullaryCase 4 S4
         ]
+
+    , testCase "Zero tuples: issue 271" $ do
+        assertInequal "Hash of (0,0) != 0" (hash (0 :: Int, 0 :: Int)) 0
+        assertInequal "Hash of (0,0,0) != 0" (hash (0 :: Int, 0 :: Int, 0 :: Int)) 0
+
+    , testProperty "odd, odd: issue 271" $ \x' y' ->
+        let x = if odd x' then x' else x' + 1 :: Int
+            y = if odd y' then y' else y' + 1 :: Int
+        in hash (x, y) /= hash (negate x, negate y)
+
     , testCase "Generic: Peano https://github.com/tibbe/hashable/issues/135" $ do
         let ns = take 20 $ iterate S Z
         let hs = map hash ns
-        hs @=? nub hs
+        hs @?= nub hs
 #if WORD_SIZE_IN_BITS == 64
     , testCase "64 bit Text" $ do
-        hash ("hello world" :: Text) @=?
+        hash ("hello world" :: Text) @?=
 #if MIN_VERSION_text(2,0,0)
-            4078614214911247440
+            2589482369471999198
 #else
-            -3875242662334356092
+            -1955893671357159554
 #endif
 #endif
     , F.testGroup "concatenation"
@@ -103,7 +119,7 @@
         let salt = 42
         let expected = salt `hashWithSalt` n `hashWithSalt` ()
         let actual = hashWithSalt salt s
-        expected @=? actual
+        actual @?= expected
 
 data SumOfNullary = S0 | S1 | S2 | S3 | S4 deriving (Eq, Generic)
 instance Hashable SumOfNullary
