fixed

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

commit fd2afa29f19d2707f79ce8e6fa6191773403a4db
parent f6a91648f522f5611e408661bcd3e46ab4764f05
Author: Jared Tobin <jared@jtobin.io>
Date:   Sat,  6 Dec 2025 18:18:41 +0400

lib: basic montgomery docs

Diffstat:
Mlib/Numeric/Montgomery/Secp256k1/Curve.hs | 88++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Mlib/Numeric/Montgomery/Secp256k1/Scalar.hs | 116++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 176 insertions(+), 28 deletions(-)

diff --git a/lib/Numeric/Montgomery/Secp256k1/Curve.hs b/lib/Numeric/Montgomery/Secp256k1/Curve.hs @@ -58,8 +58,21 @@ import Prelude hiding (div, mod, or, and, not, quot, rem, recip) -- montgomery arithmetic, specialized to the secp256k1 field prime modulus -- 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F +-- | Montgomery-form 'Wider' words, on the Montgomery domain defined by +-- the secp256k1 scalar group order. +-- +-- >>> let one = 1 :: Montgomery +-- >>> one +-- 1 +-- >>> putStrLn (render one) +-- (4294968273, 0, 0, 0) data Montgomery = Montgomery !(# Limb, Limb, Limb, Limb #) +-- | Render a 'Montgomery' value as a 'String', showing its individual +-- 'Limb's. +-- +-- >>> putStrLn (render 1) +-- (4294968273, 0, 0, 0) render :: Montgomery -> String render (Montgomery (# Limb a, Limb b, Limb c, Limb d #)) = "(" <> show (W# a) <> ", " <> show (W# b) <> ", " @@ -155,7 +168,14 @@ redc# l u = in WW.sub_mod_c# nu mc m m {-# INLINE redc# #-} -redc :: Montgomery -> Montgomery -> Montgomery +-- | Montgomery reduction. +-- +-- The first argument represents the low words, and the second the +-- high words, of an extra-large eight-limb word in Montgomery form. +redc + :: Montgomery -- ^ low wider-word, Montgomery form + -> Montgomery -- ^ high wider-word, Montgomery form + -> Montgomery -- ^ reduced value redc (Montgomery l) (Montgomery u) = let !res = redc# l u in (Montgomery res) @@ -197,6 +217,8 @@ retr# retr# f = retr_inner# f {-# INLINE retr# #-} +-- | Retrieve a 'Montgomery' value from the Montgomery domain, producing +-- a 'Wider' word. retr :: Montgomery -- ^ value in montgomery form -> Wider -- ^ retrieved value @@ -285,7 +307,6 @@ mul_inner# (# x0, x1, x2, x3 #) (# y0, y1, y2, y3 #) = in (# (# o3, p3, q3, r3 #), mc3 #) {-# INLINE mul_inner# #-} --- | Montgomery multiplication, with conditional subtract. mul# :: (# Limb, Limb, Limb, Limb #) -> (# Limb, Limb, Limb, Limb #) @@ -298,9 +319,16 @@ mul# a b = in WW.sub_mod_c# nu mc m m {-# NOINLINE mul# #-} -- cannot be inlined without exploding comp time +-- | Multiplication in the Montgomery domain. +-- +-- Note that 'Montgomery' is an instance of 'Num', so you can use '*' +-- to apply this function. +-- +-- >>> 1 * 1 :: Montgomery +-- 1 mul - :: Montgomery -- ^ lhs in montgomery form - -> Montgomery -- ^ rhs in montgomery form + :: Montgomery -- ^ multiplicand in montgomery form + -> Montgomery -- ^ multiplier in montgomery form -> Montgomery -- ^ montgomery product mul (Montgomery a) (Montgomery b) = Montgomery (mul# a b) @@ -313,13 +341,16 @@ to# x = in mul# x r2 {-# INLINE to# #-} +-- | Convert a 'Wider' word to the Montgomery domain. to :: Wider -> Montgomery to (Wider x) = Montgomery (to# x) +-- | Retrieve a 'Montgomery' word from the Montgomery domain. +-- +-- This function is a synonym for 'retr'. from :: Montgomery -> Wider from = retr --- | Addition in the Montgomery domain. add# :: (# Limb, Limb, Limb, Limb #) -- ^ augend -> (# Limb, Limb, Limb, Limb #) -- ^ addend @@ -331,10 +362,16 @@ add# a b = in WW.add_mod# a b m {-# INLINE add# #-} +-- | Addition in the Montgomery domain. +-- +-- Note that 'Montgomery' is an instance of 'Num', so you can use '+' +-- to apply this function. +-- +-- >>> 1 + 1 :: Montgomery +-- 2 add :: Montgomery -> Montgomery -> Montgomery add (Montgomery a) (Montgomery b) = Montgomery (add# a b) --- | Subtraction in the Montgomery domain. sub# :: (# Limb, Limb, Limb, Limb #) -- ^ minuend -> (# Limb, Limb, Limb, Limb #) -- ^ subtrahend @@ -346,16 +383,31 @@ sub# a b = in WW.sub_mod# a b m {-# INLINE sub# #-} +-- | Subtraction in the Montgomery domain. +-- +-- Note that 'Montgomery' is an instance of 'Num', so you can use '-' +-- to apply this function. +-- +-- >>> 1 - 1 :: Montgomery +-- 0 sub :: Montgomery -> Montgomery -> Montgomery sub (Montgomery a) (Montgomery b) = Montgomery (sub# a b) --- | Modular negation in the Montgomery domain. neg# :: (# Limb, Limb, Limb, Limb #) -- ^ argument -> (# Limb, Limb, Limb, Limb #) -- ^ modular negation neg# a = sub# (# Limb 0##, Limb 0##, Limb 0##, Limb 0## #) a {-# INLINE neg# #-} +-- | Additive inverse in the Montgomery domain. +-- +-- Note that 'Montgomery' is an instance of 'Num', so you can use 'negate' +-- to apply this function. +-- +-- >>> negate 1 :: Montgomery +-- 115792089237316195423570985008687907853269984665640564039457584007908834671662 +-- >>> (negate 1 :: Montgomery) + 1 +-- 0 neg :: Montgomery -> Montgomery neg (Montgomery a) = Montgomery (neg# a) @@ -365,15 +417,25 @@ sqr# a = in redc# l h {-# NOINLINE sqr# #-} -- cannot be inlined without exploding comp time +-- | Squaring in the Montgomery domain. +-- +-- >>> sqr 1 +-- 1 +-- >>> sqr 2 +-- 4 +-- >>> sqr (negate 2) +-- 4 sqr :: Montgomery -> Montgomery sqr (Montgomery a) = Montgomery (mul# a a) -one :: Montgomery -one = Montgomery (# Limb 0x1000003D1##, Limb 0##, Limb 0##, Limb 0## #) - +-- | Zero (the additive unit) in the Montgomery domain. zero :: Montgomery zero = Montgomery (# Limb 0##, Limb 0##, Limb 0##, Limb 0## #) +-- | One (the multiplicative unit) in the Montgomery domain. +one :: Montgomery +one = Montgomery (# Limb 0x1000003D1##, Limb 0##, Limb 0##, Limb 0## #) + -- generated by etc/generate_inv.sh inv# :: (# Limb, Limb, Limb, Limb #) @@ -890,5 +952,11 @@ inv# a = in r {-# INLINE inv# #-} +-- | Multiplicative inverse in the Montgomery domain. +-- +-- >> inv 2 +-- 57896044618658097711785492504343953926634992332820282019728792003954417335832 +-- >> inv 2 * 2 +-- 1 inv :: Montgomery -> Montgomery inv (Montgomery w) = Montgomery (inv# w) diff --git a/lib/Numeric/Montgomery/Secp256k1/Scalar.hs b/lib/Numeric/Montgomery/Secp256k1/Scalar.hs @@ -55,14 +55,29 @@ import qualified Data.Word.Wider as WW import GHC.Exts (Word(..)) import Prelude hiding (div, mod, or, and, not, quot, rem, recip) +-- XX fix examples for scalar + -- montgomery arithmetic, specialized to the secp256k1 scalar group order -- 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 +-- | Montgomery-form 'Wider' words, on the Montgomery domain defined by +-- the secp256k1 scalar group order. +-- +-- >>> let one = 1 :: Montgomery +-- >>> one +-- 1 +-- >>> putStrLn (render one) +-- (4624529908474429119, 4994812053365940164, 1, 0) data Montgomery = Montgomery !(# Limb, Limb, Limb, Limb #) instance Show Montgomery where show = show . from +-- | Render a 'Montgomery' value as a 'String', showing its individual +-- 'Limb's. +-- +-- >>> putStrLn (render 1) +-- (4624529908474429119, 4994812053365940164, 1, 0) render :: Montgomery -> String render (Montgomery (# Limb a, Limb b, Limb c, Limb d #)) = "(" <> show (W# a) <> ", " <> show (W# b) <> ", " @@ -143,7 +158,6 @@ redc_inner# (# u0, u1, u2, u3 #) (# l0, l1, l2, l3 #) = in (# (# u3_1, u3_2, u3_3, u_3 #), mc_3 #) {-# INLINE redc_inner# #-} --- | Montgomery reduction. redc# :: (# Limb, Limb, Limb, Limb #) -- ^ lower limbs -> (# Limb, Limb, Limb, Limb #) -- ^ upper limbs @@ -156,7 +170,14 @@ redc# l u = in WW.sub_mod_c# nu mc m m {-# INLINE redc# #-} -redc :: Montgomery -> Montgomery -> Montgomery +-- | Montgomery reduction. +-- +-- The first argument represents the low words, and the second the +-- high words, of an extra-large eight-limb word in Montgomery form. +redc + :: Montgomery -- ^ low wider-word, Montgomery form + -> Montgomery -- ^ high wider-word, Montgomery form + -> Montgomery -- ^ reduced value redc (Montgomery l) (Montgomery u) = let !res = redc# l u in (Montgomery res) @@ -193,13 +214,15 @@ retr_inner# (# x0, x1, x2, x3 #) = {-# INLINE retr_inner# #-} retr# - :: (# Limb, Limb, Limb, Limb #) -- montgomery form + :: (# Limb, Limb, Limb, Limb #) -> (# Limb, Limb, Limb, Limb #) retr# f = retr_inner# f {-# INLINE retr# #-} +-- | Retrieve a 'Montgomery' value from the Montgomery domain, producing +-- a 'Wider' word. retr - :: Montgomery -- ^ value in montgomery form + :: Montgomery -- ^ value in Montgomery form -> Wider -- ^ retrieved value retr (Montgomery f) = let !res = retr# f @@ -286,7 +309,6 @@ mul_inner# (# x0, x1, x2, x3 #) (# y0, y1, y2, y3 #) = in (# (# o3, p3, q3, r3 #), mc3 #) {-# INLINE mul_inner# #-} --- | Montgomery multiplication, with conditional subtract. mul# :: (# Limb, Limb, Limb, Limb #) -> (# Limb, Limb, Limb, Limb #) @@ -299,9 +321,16 @@ mul# a b = in WW.sub_mod_c# nu mc m m {-# NOINLINE mul# #-} -- cannot be inlined without exploding comp time +-- | Multiplication in the Montgomery domain. +-- +-- Note that 'Montgomery' is an instance of 'Num', so you can use '*' +-- to apply this function. +-- +-- >>> 1 * 1 :: Montgomery +-- 1 mul - :: Montgomery -- ^ lhs in montgomery form - -> Montgomery -- ^ rhs in montgomery form + :: Montgomery -- ^ multiplicand in montgomery form + -> Montgomery -- ^ multiplier in montgomery form -> Montgomery -- ^ montgomery product mul (Montgomery a) (Montgomery b) = Montgomery (mul# a b) @@ -315,13 +344,16 @@ to# x = in mul# x r2 {-# INLINE to# #-} +-- | Convert a 'Wider' word to the Montgomery domain. to :: Wider -> Montgomery to (Wider x) = Montgomery (to# x) +-- | Retrieve a 'Montgomery' word from the Montgomery domain. +-- +-- This function is a synonym for 'retr'. from :: Montgomery -> Wider from = retr --- | Addition in the Montgomery domain. add# :: (# Limb, Limb, Limb, Limb #) -- ^ augend -> (# Limb, Limb, Limb, Limb #) -- ^ addend @@ -333,10 +365,19 @@ add# a b = in WW.add_mod# a b m {-# INLINE add# #-} -add :: Montgomery -> Montgomery -> Montgomery +-- | Addition in the Montgomery domain. +-- +-- Note that 'Montgomery' is an instance of 'Num', so you can use '+' +-- to apply this function. +-- +-- >>> 1 + 1 :: Montgomery +-- 2 +add + :: Montgomery -- ^ augend + -> Montgomery -- ^ addend + -> Montgomery -- ^ sum add (Montgomery a) (Montgomery b) = Montgomery (add# a b) --- | Subtraction in the Montgomery domain. sub# :: (# Limb, Limb, Limb, Limb #) -- ^ minuend -> (# Limb, Limb, Limb, Limb #) -- ^ subtrahend @@ -347,16 +388,34 @@ sub# a b = in WW.sub_mod# a b m {-# INLINE sub# #-} -sub :: Montgomery -> Montgomery -> Montgomery +-- | Subtraction in the Montgomery domain. +-- +-- Note that 'Montgomery' is an instance of 'Num', so you can use '-' +-- to apply this function. +-- +-- >>> 1 - 1 :: Montgomery +-- 0 +sub + :: Montgomery -- ^ minuend + -> Montgomery -- ^ subtrahend + -> Montgomery -- ^ difference sub (Montgomery a) (Montgomery b) = Montgomery (sub# a b) --- | Modular negation in the Montgomery domain. neg# :: (# Limb, Limb, Limb, Limb #) -- ^ argument -> (# Limb, Limb, Limb, Limb #) -- ^ modular negation neg# a = sub# (# Limb 0##, Limb 0##, Limb 0##, Limb 0## #) a {-# INLINE neg# #-} +-- | Additive inverse in the Montgomery domain. +-- +-- Note that 'Montgomery' is an instance of 'Num', so you can use 'negate' +-- to apply this function. +-- +-- >>> negate 1 :: Montgomery +-- 115792089237316195423570985008687907852837564279074904382605163141518161494336 +-- >>> (negate 1 :: Montgomery) + 1 +-- 0 neg :: Montgomery -> Montgomery neg (Montgomery a) = Montgomery (neg# a) @@ -366,16 +425,29 @@ sqr# a = in redc# l h {-# NOINLINE sqr# #-} -- cannot be inlined without exploding comp time -sqr :: Montgomery -> Montgomery +-- | Squaring in the Montgomery domain. +-- +-- >>> sqr 1 +-- 1 +-- >>> sqr 2 +-- 4 +-- >>> sqr (negate 2) +-- 4 +sqr + :: Montgomery -- ^ argument + -> Montgomery -- ^ square sqr (Montgomery a) = Montgomery (mul# a a) -one :: Montgomery -one = Montgomery (# Limb 0x402DA1732FC9BEBF##, Limb 0x4551231950B75FC4## - , Limb 0x0000000000000001##, Limb 0x0000000000000000## #) - +-- | Zero (the additive unit) in the Montgomery domain. zero :: Montgomery zero = Montgomery (# Limb 0##, Limb 0##, Limb 0##, Limb 0## #) +-- | One (the multiplicative unit) in the Montgomery domain. +one :: Montgomery +one = Montgomery + (# Limb 0x402DA1732FC9BEBF##, Limb 0x4551231950B75FC4## + , Limb 0x0000000000000001##, Limb 0x0000000000000000## #) + -- generated by etc/generate_inv.sh inv# :: (# Limb, Limb, Limb, Limb #) @@ -839,6 +911,14 @@ inv# a = in r {-# INLINE inv# #-} -inv :: Montgomery -> Montgomery +-- | Multiplicative inverse in the Montgomery domain. +-- +-- >> inv 2 +-- 57896044618658097711785492504343953926418782139537452191302581570759080747169 +-- >> inv 2 * 2 +-- 1 +inv + :: Montgomery -- ^ argument + -> Montgomery -- ^ inverse inv (Montgomery w) = Montgomery (inv# w)