ppad-fixed 0.1.5 → 0.1.6
raw patch · 6 files changed
+34/−4 lines, 6 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- CHANGELOG +4/−0
- lib/Data/Choice.hs +3/−3
- ppad-fixed.cabal +1/−1
- test/Limb.hs +5/−0
- test/Wide.hs +15/−0
- test/Wider.hs +6/−0
CHANGELOG view
@@ -1,5 +1,9 @@ # Changelog +- 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.+ - 0.1.5 (2026-06-07) * Improves constant-time modular inverse performance on the Montgomery 'Curve' module by about 2x, and on the 'Scalar' module by about 1.5x.
lib/Data/Choice.hs view
@@ -347,7 +347,7 @@ let !s = case B.finiteBitSize (0 :: Word) of I# m -> m Exts.-# 1# !x = Exts.xor# a b !y = Exts.uncheckedShiftRL# (Exts.or# x (neg_w# x)) s- in Choice (Exts.xor# y 1##)+ in from_bit# (Exts.xor# y 1##) {-# INLINE eq_word# #-} -- | Compare unboxed two-limb words for equality in constant time.@@ -362,7 +362,7 @@ let !s = case B.finiteBitSize (0 :: Word) of I# m -> m Exts.-# 1# !x = Exts.or# (Exts.xor# a0 b0) (Exts.xor# a1 b1) !y = Exts.uncheckedShiftRL# (Exts.or# x (neg_w# x)) s- in Choice (Exts.xor# y 1##)+ in from_bit# (Exts.xor# y 1##) {-# INLINE eq_wide# #-} -- | Compare unboxed four-limb words for equality in constant time.@@ -378,6 +378,6 @@ !x = Exts.or# (Exts.or# (Exts.xor# a0 b0) (Exts.xor# a1 b1)) (Exts.or# (Exts.xor# a2 b2) (Exts.xor# a3 b3)) !y = Exts.uncheckedShiftRL# (Exts.or# x (neg_w# x)) s- in Choice (Exts.xor# y 1##)+ in from_bit# (Exts.xor# y 1##) {-# INLINE eq_wider# #-}
ppad-fixed.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: ppad-fixed-version: 0.1.5+version: 0.1.6 synopsis: Large fixed-width words and constant-time arithmetic. license: MIT license-file: LICENSE
test/Limb.hs view
@@ -84,6 +84,11 @@ H.assertBool mempty (not (C.decide (L.eq# a b))) H.assertBool mempty (not (C.decide (L.eq# b a))) H.assertBool mempty (C.decide (L.eq# b b))+ -- eq# must yield a full-word mask, not a bare bit; negating or+ -- selecting on it is otherwise wrong+ H.assertBool mempty (not (C.decide (L.ne# a a)))+ H.assertBool mempty (C.decide (L.ne# a b))+ H.assertBool mempty (L.eq_vartime# (L.select# a b (L.eq# a a)) b) gt :: H.Assertion gt = do
test/Wide.hs view
@@ -6,6 +6,7 @@ tests ) where +import qualified Data.Choice as C import qualified Data.Word.Wide as W import Test.Tasty import qualified Test.Tasty.HUnit as H@@ -32,11 +33,25 @@ let !r = W.add (2 ^ (128 :: Word) - 1) 1 H.assertBool mempty (W.eq_vartime r 0) +eq :: H.Assertion+eq = do+ let !a = 0 :: W.Wide+ !b = 2 ^ (128 :: Word) - 1+ H.assertBool mempty (C.decide (W.eq a a))+ H.assertBool mempty (not (C.decide (W.eq a b)))+ H.assertBool mempty (C.decide (W.eq b b))+ -- eq must yield a full-word mask, not a bare bit; negating or+ -- selecting on it is otherwise wrong+ H.assertBool mempty (not (C.decide (C.not (W.eq a a))))+ H.assertBool mempty (C.decide (C.not (W.eq a b)))+ H.assertBool mempty (W.eq_vartime (W.select a b (W.eq a a)) b)+ tests :: TestTree tests = testGroup "wide tests" [ H.testCase "overflowing add, no carry" overflowing_add_no_carry , H.testCase "overflowing add, carry" overflowing_add_with_carry , H.testCase "wrapping add, no carry" wrapping_add_no_carry , H.testCase "wrapping add, carry" wrapping_add_with_carry+ , H.testCase "eq" eq ]
test/Wider.hs view
@@ -67,6 +67,12 @@ H.assertBool mempty (not (C.decide (W.eq# a b))) H.assertBool mempty (not (C.decide (W.eq# b a))) H.assertBool mempty (C.decide (W.eq# b b))+ -- eq# must yield a full-word mask, not a bare bit; negating or+ -- selecting on it is otherwise wrong+ H.assertBool mempty (not (C.decide (C.not (W.eq# a a))))+ H.assertBool mempty (C.decide (C.not (W.eq# a b)))+ H.assertBool mempty+ (W.eq_vartime (W.select (W.Wider a) (W.Wider b) (W.eq# a a)) (W.Wider b)) gt :: H.Assertion gt = do