fixed

Pure Haskell large fixed-width integers.
git clone git://git.ppad.tech/fixed.git
Log | Files | Refs | README | LICENSE

commit dbf556e634531aba482cbc7aa3f1aad66d033523
parent 09d3cf81230cc16a9aa21da513f2b4aa81ea51fc
Author: Jared Tobin <jared@jtobin.io>
Date:   Sun,  2 Nov 2025 19:16:25 +0400

lib: axe some old wide stuff

Diffstat:
Mlib/Data/Word/Montgomery.hs | 43++++++++++++++++++++-----------------------
Mlib/Data/Word/Wide.hs | 114-------------------------------------------------------------------------------
2 files changed, 20 insertions(+), 137 deletions(-)

diff --git a/lib/Data/Word/Montgomery.hs b/lib/Data/Word/Montgomery.hs @@ -13,13 +13,12 @@ import qualified Data.Word.Wider as W import GHC.Exts import Prelude hiding (div, mod, or, and, not, quot, rem, recip) --- reference 'montgomery_reduction_inner' redc_inner# - :: (# Word#, Word#, Word#, Word# #) -- upper - -> (# Word#, Word#, Word#, Word# #) -- lower - -> (# Word#, Word#, Word#, Word# #) -- modulus - -> Word# -- mod neg inv - -> (# (# Word#, Word#, Word#, Word# #), Word# #) -- upper, meta-carry + :: (# Word#, Word#, Word#, Word# #) -- ^ upper words + -> (# Word#, Word#, Word#, Word# #) -- ^ lower words + -> (# Word#, Word#, Word#, Word# #) -- ^ modulus + -> Word# -- ^ mod neg inv + -> (# (# Word#, Word#, Word#, Word# #), Word# #) -- ^ upper words, meta-carry redc_inner# (# u0, u1, u2, u3 #) (# l0, l1, l2, l3 #) (# m0, m1, m2, m3 #) n = let -- outer loop, i == 0 --------------------------------------------------- !w_0 = L.mul_w# l0 n @@ -74,29 +73,28 @@ redc_inner# (# u0, u1, u2, u3 #) (# l0, l1, l2, l3 #) (# m0, m1, m2, m3 #) n = in (# (# u3_1, u3_2, u3_3, u_3 #), mc_3 #) {-# INLINE redc_inner# #-} +-- | Montgomery reduction. redc# - :: (# Word#, Word#, Word#, Word# #) -- lower - -> (# Word#, Word#, Word#, Word# #) -- upper - -> (# Word#, Word#, Word#, Word# #) -- modulus - -> Word# -- mod neg inv - -> (# Word#, Word#, Word#, Word# #) + :: (# Word#, Word#, Word#, Word# #) -- ^ lower words + -> (# Word#, Word#, Word#, Word# #) -- ^ upper words + -> (# Word#, Word#, Word#, Word# #) -- ^ modulus + -> Word# -- ^ mod neg inv + -> (# Word#, Word#, Word#, Word# #) -- ^ result redc# l u m n = let !(# nu, mc #) = redc_inner# u l m n - in W.sub_mod_c# nu mc m m -- XX shouldn't use Data.Word.Wider version + in W.sub_mod_c# nu mc m m {-# INLINE redc# #-} --- XX here only for testing; should probably be in Data.Word.Wider itself redc :: W.Wider -> W.Wider -> W.Wider -> Word -> W.Wider redc (W.Wider l) (W.Wider u) (W.Wider m) (W# n) = let !res = redc# l u m n in (W.Wider res) --- reference 'montgomery_retrieve_inner' retr_inner# - :: (# Word#, Word#, Word#, Word# #) -- montgomery form - -> (# Word#, Word#, Word#, Word# #) -- modulus - -> Word# -- mod neg inv - -> (# Word#, Word#, Word#, Word# #) + :: (# Word#, Word#, Word#, Word# #) -- ^ value in montgomery form + -> (# Word#, Word#, Word#, Word# #) -- ^ modulus + -> Word# -- ^ mod neg inv + -> (# Word#, Word#, Word#, Word# #) -- ^ retrieved value retr_inner# (# x0, x1, x2, x3 #) (# m0, m1, m2, m3 #) n = let -- outer loop, i == 0 --------------------------------------------------- !u_0 = L.mul_w# x0 n -- out state @@ -141,12 +139,11 @@ retr# retr# f m n = retr_inner# f m n {-# INLINE retr# #-} --- XX ditto retr - :: W.Wider -- montgomery form - -> W.Wider -- modulus - -> Word -- mod neg inv - -> W.Wider + :: W.Wider -- ^ value in montgomery form + -> W.Wider -- ^ modulus + -> Word -- ^ mod neg inv + -> W.Wider -- ^ retrieved value retr (W.Wider f) (W.Wider m) (W# n) = let !res = retr# f m n in (W.Wider res) diff --git a/lib/Data/Word/Wide.hs b/lib/Data/Word/Wide.hs @@ -27,22 +27,17 @@ module Data.Word.Wide ( , and , xor , not - , shr - , unchecked_shr -- * Arithmetic , add , sub , mul - , quotrem_by1 - , _quotrem_by1 , add_w# , mul_w# ) where import Control.DeepSeq -import qualified Data.Choice as C import Data.Bits ((.|.), (.&.), (.<<.), (.>>.)) import qualified Data.Bits as B import qualified Data.Word.Limb as L @@ -150,77 +145,6 @@ not :: Wide -> Wide not (Wide w) = Wide (not_w# w) {-# INLINE not #-} --- overflowing, vartime w/respect to s -shr_of_vartime# :: (# Word#, Word# #) -> Int# -> C.MaybeWide# -shr_of_vartime# (# l, h #) s - | isTrue# (s ># wide_size) = C.none_wide# (# 0##, 0## #) - | otherwise = - let !(# shift_num, rem #) = quotRemInt# s size - !w_1 = case shift_num of - 0# -> - let !h_0 = uncheckedShiftRL# h rem - !car = uncheckedShiftL# h (size -# rem) - !shf = uncheckedShiftRL# l rem - !l_0 = or# shf car - in (# l_0, h_0 #) - 1# -> - let !l_0 = uncheckedShiftRL# h rem - in (# l_0, 0## #) - 2# -> - (# l, h #) - _ -> error "ppad-fixed (shr_of_vartime#): internal error" - in C.some_wide# w_1 - where - !size = case B.finiteBitSize (0 :: Word) of I# m -> m - !wide_size = 2# *# size -{-# INLINE shr_of_vartime# #-} - -shr_of# :: (# Word#, Word# #) -> Int# -> C.MaybeWide# -shr_of# (# l, h #) s = - let !shift_bits = size -# (word2Int# (clz# (int2Word# (wide_size -# 1#)))) - !overflow = C.not_c# - (C.from_word_lt# (int2Word# s) (int2Word# wide_size)) - !shift = remWord# (int2Word# s) (int2Word# wide_size) - loop !j !res - | isTrue# (j <# shift_bits) = - let !bit = C.from_word_lsb# -- XX not inlined - (and# (uncheckedShiftRL# shift j) 1##) - !nres = C.ct_select_wide# -- XX - res - (C.expect_wide# -- XX - (shr_of_vartime# -- XX - res - (word2Int# (uncheckedShiftL# 1## j))) - "shift within range") - bit - in loop (j +# 1#) nres - | otherwise = res - !result = loop 0# (# l, h #) - in C.just_wide# - (C.ct_select_wide# result (# 0##, 0## #) overflow) - (C.not_c# overflow) - where - !size = case B.finiteBitSize (0 :: Word) of I# m -> m - !wide_size = 2# *# size -{-# INLINE shr_of# #-} - -shr# :: (# Word#, Word# #) -> Int# -> (# Word#, Word# #) -shr# w s = C.expect_wide# (shr_of# w s) "invalid shift" -{-# INLINE shr# #-} - --- wrapping -unchecked_shr# :: (# Word#, Word# #) -> Int# -> (# Word#, Word# #) -unchecked_shr# w s = C.expect_wide_or# (shr_of# w s) (# 0##, 0## #) -{-# INLINE unchecked_shr# #-} - --- constant-time shr, ErrorCall on invalid shift -shr :: Wide -> Int -> Wide -shr (Wide w) (I# s) = Wide (shr# w s) - --- constant-time shr, saturating -unchecked_shr :: Wide -> Int -> Wide -unchecked_shr (Wide w) (I# s) = Wide (unchecked_shr# w s) - -- addition, subtraction ------------------------------------------------------ -- wide addition (overflowing) @@ -283,41 +207,3 @@ mul_w# (# a0, a1 #) (# b0, b1 #) = mul :: Wide -> Wide -> Wide mul (Wide a) (Wide b) = Wide (mul_w# a b) --- division ------------------------------------------------------------------- - --- quotient and remainder of wide word (lo, hi), divided by divisor -_quotrem_by1# :: (# Word#, Word# #) -> Word# -> (# Word#, Word# #) -_quotrem_by1# (# l, h #) d = quotRemWord2# h l d -{-# INLINE _quotrem_by1# #-} - --- ~6x slower than quotrem_by1, but useful for testing -_quotrem_by1 :: Wide -> Word -> (Word, Word) -_quotrem_by1 (Wide u) (W# d) = - let !(# q, r #) = _quotrem_by1# u d - in (W# q, W# r) - --- quotient and remainder of wide word (lo, hi) divided using reciprocal -quotrem_by1# :: (# Word#, Word# #) -> L.Reciprocal -> (# Word#, Word# #) -quotrem_by1# (# u0, u1 #) (L.Reciprocal (# d, _, r #)) = - let !(# q0_0, q1_0 #) = L.mul_c# r u1 - !(# q0_1, q1_1 #) = add_w# (# q0_0, q1_0 #) (# u0, u1 #) - !q1_2 = plusWord# q1_1 1## - !r_0 = minusWord# u0 (timesWord# q1_2 d) - -- ct block 1 - !r_gt_q0 = C.from_word_lt# q0_1 r_0 - !q1_3 = C.ct_select_word# q1_2 (minusWord# q1_2 1##) r_gt_q0 - !r_1 = C.ct_select_word# r_0 (plusWord# r_0 d) r_gt_q0 - -- ct block 2 - !r_ge_d = C.from_word_le# d r_1 - !q1_4 = C.ct_select_word# q1_3 (plusWord# q1_3 1##) r_ge_d - !r_2 = C.ct_select_word# r_1 (minusWord# r_1 d) r_ge_d - in (# q1_4, r_2 #) -{-# INLINE quotrem_by1# #-} - --- quotient and remainder of wide word divided by word -quotrem_by1 :: Wide -> Word -> (Word, Word) -quotrem_by1 (Wide (# u0, u1 #)) (W# d) = - let !re = L.recip# d - !(# q, r #) = quotrem_by1# (# u0, u1 #) re - in (W# q, W# r) -