diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,17 @@
 # Changelog
 
+- 0.2.0 (2026-08-01)
+  * Addresses a couple of minor issues detected by an LLM scan:
+
+    * Fixes a bug that could lead shl1_c# to produce a malformed Choice
+      that would behave incorrectly for negation or selection.
+
+    * Each Montgomery domain's 'signum' implementation was broken,
+      producing R^-1 instead of the proper in-domain 'one'. Now these
+      return the appropriate values.
+
+    Also clarifies a few Haddocks, on the suggestions of the same scan.
+
 - 0.1.6 (2026-08-01)
   * The eq_{word,wide,wider}# functions now return a mask, instead of a
     bit, inside the resulting Choice value.
diff --git a/lib/Data/Choice.hs b/lib/Data/Choice.hs
--- a/lib/Data/Choice.hs
+++ b/lib/Data/Choice.hs
@@ -305,6 +305,9 @@
 
 -- | Select an unboxed word without branching, given a 'Choice'.
 --
+--   Returns the second word if the 'Choice' is truthy, and the first
+--   otherwise.
+--
 --   >>> let w = C.select_word# 0## 1## (C.true# ()) in GHC.Word.W# w
 --   1
 select_word# :: Word# -> Word# -> Choice -> Word#
@@ -312,6 +315,9 @@
 {-# INLINE select_word# #-}
 
 -- | Select an unboxed two-limb word without branching, given a 'Choice'.
+--
+--   Returns the second word if the 'Choice' is truthy, and the first
+--   otherwise.
 select_wide#
   :: Limb2
   -> Limb2
@@ -323,6 +329,9 @@
 {-# INLINE select_wide# #-}
 
 -- | Select an unboxed four-limb word without branching, given a 'Choice'.
+--
+--   Returns the second word if the 'Choice' is truthy, and the first
+--   otherwise.
 select_wider#
   :: Limb4
   -> Limb4
diff --git a/lib/Data/Word/Limb.hs b/lib/Data/Word/Limb.hs
--- a/lib/Data/Word/Limb.hs
+++ b/lib/Data/Word/Limb.hs
@@ -143,7 +143,7 @@
 
 -- constant-time selection ----------------------------------------------------
 
--- | Return a if c is truthy, otherwise return b.
+-- | Return b if c is truthy, otherwise return a.
 select#
   :: Limb     -- ^ a
   -> Limb     -- ^ b
@@ -268,6 +268,9 @@
 
 -- | Carrying addition, computing augend + addend + carry, returning
 --   the sum and new carry.
+--
+--   The carry-in must be 0 or 1; this is not checked. The carry-out
+--   is always 0 or 1.
 add_c#
   :: Limb             -- ^ augend
   -> Limb             -- ^ addend
@@ -304,6 +307,11 @@
 
 -- | Borrowing subtraction, computing minuend - (subtrahend + borrow),
 --   returning the difference and new borrow mask.
+--
+--   The borrow-in is interpreted as a mask, of which only the most
+--   significant bit is examined; a full-word mask (as produced by
+--   this function) borrows 1. The borrow-out is 0 or a full-word
+--   mask.
 sub_b#
   :: Limb              -- ^ minuend
   -> Limb              -- ^ subtrahend
diff --git a/lib/Data/Word/Wide.hs b/lib/Data/Word/Wide.hs
--- a/lib/Data/Word/Wide.hs
+++ b/lib/Data/Word/Wide.hs
@@ -159,7 +159,7 @@
 
 -- constant-time selection-----------------------------------------------------
 
--- | Return a if c is truthy, otherwise return b.
+-- | Return b if c is truthy, otherwise return a.
 --
 --   >>> import qualified Data.Choice as C
 --   >>> select 0 1 (C.true# ())
diff --git a/lib/Data/Word/Wider.hs b/lib/Data/Word/Wider.hs
--- a/lib/Data/Word/Wider.hs
+++ b/lib/Data/Word/Wider.hs
@@ -319,7 +319,7 @@
   in  L4 w0 w1 w2 w3
 {-# INLINE select# #-}
 
--- | Return a if c is truthy, otherwise return b.
+-- | Return b if c is truthy, otherwise return a.
 --
 --   >>> import qualified Data.Choice as C
 --   >>> select 0 1 (C.true# ())
@@ -384,7 +384,7 @@
       !r2           = L.or# s2 c1
       !(# s3, c3 #) = (# L.shl# w3 1#, L.shr# w3 s #)
       !r3           = L.or# s3 c2
-      !(Limb w)     = L.shl# c3 s
+      !(Limb w)     = c3
   in  (# (# r0, r1, r2, r3 #), C.from_bit# w #)
 {-# INLINE shl1_c# #-}
 
diff --git a/lib/Numeric/Montgomery/Secp256k1/Curve.hs b/lib/Numeric/Montgomery/Secp256k1/Curve.hs
--- a/lib/Numeric/Montgomery/Secp256k1/Curve.hs
+++ b/lib/Numeric/Montgomery/Secp256k1/Curve.hs
@@ -109,8 +109,9 @@
   signum (Montgomery (# l0, l1, l2, l3 #)) =
     let !(Limb l) = l0 `L.or#` l1 `L.or#` l2 `L.or#` l3
         !n = C.from_word_nonzero# l
-        !b = C.to_word# n
-    in  Montgomery (# Limb b, Limb 0##, Limb 0##, Limb 0## #)
+        !(Montgomery z) = zero
+        !(Montgomery o) = one
+    in  Montgomery (select# z o n)
 
 instance NFData Montgomery where
   rnf (Montgomery a) = case a of (# _, _, _, _ #) -> ()
@@ -761,6 +762,9 @@
 
 -- | Multiplicative inverse in the Montgomery domain.
 --
+--   Note that 'zero' has no multiplicative inverse; 'inv' returns
+--   'zero' when applied to it.
+--
 --   >> inv 2
 --   57896044618658097711785492504343953926634992332820282019728792003954417335832
 --   >> inv 2 * 2
@@ -1354,7 +1358,7 @@
 select# = WW.select#
 {-# INLINE select# #-}
 
--- | Return a if c is truthy, otherwise return b.
+-- | Return b if c is truthy, otherwise return a.
 --
 --   >>> import qualified Data.Choice as C
 --   >>> select 0 1 (C.true# ())
diff --git a/lib/Numeric/Montgomery/Secp256k1/Scalar.hs b/lib/Numeric/Montgomery/Secp256k1/Scalar.hs
--- a/lib/Numeric/Montgomery/Secp256k1/Scalar.hs
+++ b/lib/Numeric/Montgomery/Secp256k1/Scalar.hs
@@ -107,8 +107,9 @@
   signum (Montgomery (# l0, l1, l2, l3 #)) =
     let !(Limb l) = l0 `L.or#` l1 `L.or#` l2 `L.or#` l3
         !n = C.from_word_nonzero# l
-        !b = C.to_word# n
-    in  Montgomery (L4 b 0## 0## 0##)
+        !(Montgomery z) = zero
+        !(Montgomery o) = one
+    in  Montgomery (select# z o n)
 
 instance NFData Montgomery where
   rnf (Montgomery a) = case a of (# _, _, _, _ #) -> ()
@@ -792,6 +793,9 @@
 
 -- | Multiplicative inverse in the Montgomery domain.
 --
+--   Note that 'zero' has no multiplicative inverse; 'inv' returns
+--   'zero' when applied to it.
+--
 --   >> inv 2
 --   57896044618658097711785492504343953926418782139537452191302581570759080747169
 --   >> inv 2 * 2
@@ -856,7 +860,7 @@
 select# = WW.select#
 {-# INLINE select# #-}
 
--- | Return a if c is truthy, otherwise return b.
+-- | Return b if c is truthy, otherwise return a.
 --
 --   >>> import qualified Data.Choice as C
 --   >>> select 0 1 (C.true# ())
diff --git a/ppad-fixed.cabal b/ppad-fixed.cabal
--- a/ppad-fixed.cabal
+++ b/ppad-fixed.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.0
 name:               ppad-fixed
-version:            0.1.6
+version:            0.2.0
 synopsis:           Large fixed-width words and constant-time arithmetic.
 license:            MIT
 license-file:       LICENSE
diff --git a/test/Montgomery/Curve.hs b/test/Montgomery/Curve.hs
--- a/test/Montgomery/Curve.hs
+++ b/test/Montgomery/Curve.hs
@@ -118,6 +118,13 @@
     0x00000000000000000000000000000000000000000000000000000001000003D1
     0x000000000000000000000000000000000000000000000001000007A2000E90A1
 
+signum_correct :: H.Assertion
+signum_correct = do
+  H.assertBool "signum 0 = 0" (C.eq_vartime (signum 0) 0)
+  H.assertBool "signum 5 = 1" (C.eq_vartime (signum 5) 1)
+  H.assertBool "abs 5 * signum 5 = 5"
+    (C.eq_vartime (abs 5 * signum 5) 5)
+
 instance Q.Arbitrary W.Wider where
   arbitrary = fmap W.to_vartime Q.arbitrary
 
@@ -177,6 +184,7 @@
   , H.testCase "add" add
   , H.testCase "sub" sub
   , H.testCase "mul" mul
+  , H.testCase "signum" signum_correct
   , Q.testProperty "a + b mod m ~ ma + mb" $ Q.withMaxSuccess 500 add_matches
   , Q.testProperty "a * b mod m ~ ma * mb" $ Q.withMaxSuccess 500 mul_matches
   , Q.testProperty "a ^ 2 mod m ~ ma ^ 2"  $ Q.withMaxSuccess 500 sqr_matches
diff --git a/test/Montgomery/Scalar.hs b/test/Montgomery/Scalar.hs
--- a/test/Montgomery/Scalar.hs
+++ b/test/Montgomery/Scalar.hs
@@ -118,6 +118,13 @@
     0x000000000000000000000000000000014551231950B75FC4402DA1732FC9BEBF
     0x9D671CD581C69BC5E697F5E45BCD07C6741496C20E7CF878896CF21467D7D140
 
+signum_correct :: H.Assertion
+signum_correct = do
+  H.assertBool "signum 0 = 0" (S.eq_vartime (signum 0) 0)
+  H.assertBool "signum 5 = 1" (S.eq_vartime (signum 5) 1)
+  H.assertBool "abs 5 * signum 5 = 5"
+    (S.eq_vartime (abs 5 * signum 5) 5)
+
 instance Q.Arbitrary W.Wider where
   arbitrary = fmap W.to_vartime Q.arbitrary
 
@@ -173,6 +180,7 @@
   , H.testCase "add" add
   , H.testCase "sub" sub
   , H.testCase "mul" mul
+  , H.testCase "signum" signum_correct
   , Q.testProperty "a + b mod m ~ ma + mb" $ Q.withMaxSuccess 500 add_matches
   , Q.testProperty "a * b mod m ~ ma * mb" $ Q.withMaxSuccess 500 mul_matches
   , Q.testProperty "a ^ 2 mod m ~ ma ^ 2"  $ Q.withMaxSuccess 500 sqr_matches
diff --git a/test/Wider.hs b/test/Wider.hs
--- a/test/Wider.hs
+++ b/test/Wider.hs
@@ -183,6 +183,23 @@
       !e = 0x44acf6b7e36c1342c2c5897204fe09504e1e2efb1a900377dbc4e7a6a133ec56
   H.assertBool mempty (W.eq_vartime o e)
 
+shl1_c :: H.Assertion
+shl1_c = case W.shl1_c (2 ^ (255 :: Word)) of
+  (# r1, c1 #) -> case W.shl1_c 1 of
+    (# r2, c2 #) -> do
+      H.assertBool "value, carry out" (W.eq_vartime r1 0)
+      H.assertBool "carry decides true" (C.decide c1)
+      -- the carry must be a full-word mask, not a bare bit; negating
+      -- or selecting on it is otherwise wrong
+      H.assertBool "negated carry decides false"
+        (not (C.decide (C.not c1)))
+      H.assertBool "select on carry"
+        (W.eq_vartime (W.select 0 1 c1) 1)
+      H.assertBool "value, no carry" (W.eq_vartime r2 2)
+      H.assertBool "no carry decides false" (not (C.decide c2))
+      H.assertBool "select on no carry"
+        (W.eq_vartime (W.select 0 1 c2) 0)
+
 instance Q.Arbitrary W.Wider where
   arbitrary = fmap W.to_vartime Q.arbitrary
 
@@ -216,6 +233,7 @@
   , H.testCase "sqr" sqr
   , H.testCase "mul" mul
   , H.testCase "sub_mod" sub_mod
+  , H.testCase "shl1_c" shl1_c
   , Q.testProperty "odd w ~ odd (from w)" $ Q.withMaxSuccess 500 odd_correct
   , Q.testProperty "lt_vartime a b ~ from a < from b" $
       Q.withMaxSuccess 500 lt_vartime_correct
