{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE NumericUnderscores #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE UnboxedSums #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE UnliftedNewtypes #-}

-- |
-- Module: Numeric.Montgomery.Secp256k1.Scalar
-- Copyright: (c) 2025 Jared Tobin
-- License: MIT
-- Maintainer: Jared Tobin <jared@ppad.tech>
--
-- Montgomery form 'Wider' words, as well as arithmetic operations, with
-- domain derived from the secp256k1 elliptic curve scalar group order.

module Numeric.Montgomery.Secp256k1.Scalar (
  -- * Montgomery form, secp256k1 scalar group order modulus
    Montgomery(..)
  , render
  , to
  , from
  , zero
  , one

  -- * Comparison
  , eq
  , eq_vartime

  -- * Reduction and retrieval
  , redc
  , redc#
  , retr
  , retr#

  -- * Constant-time selection
  , select
  , select#

  -- * Montgomery arithmetic
  , add
  , add#
  , sub
  , sub#
  , mul
  , mul#
  , sqr
  , sqr#
  , neg
  , neg#
  , inv
  , inv#
  , exp
  , exp#
  , odd_vartime
  , odd#
  ) where

import Control.DeepSeq
import qualified Data.Choice as C
import Data.Word.Limb (Limb(..))
import qualified Data.Word.Limb as L
import qualified Data.Word.Wide as W
import Data.Word.Wider (Wider(..))
import qualified Data.Word.Wider as WW
import GHC.Exts (Word(..), Word#)
import Prelude hiding (or, and, not, exp)

-- 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 !Limb4

instance Show Montgomery where
  show :: Montgomery -> String
show = Wider -> String
forall a. Show a => a -> String
show (Wider -> String) -> (Montgomery -> Wider) -> Montgomery -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Montgomery -> Wider
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 -> String
render (Montgomery (L4 Word#
a Word#
b Word#
c Word#
d)) =
     String
"(" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Word -> String
forall a. Show a => a -> String
show (Word# -> Word
W# Word#
a) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
", " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Word -> String
forall a. Show a => a -> String
show (Word# -> Word
W# Word#
b) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
", "
  String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Word -> String
forall a. Show a => a -> String
show (Word# -> Word
W# Word#
c) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
", " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Word -> String
forall a. Show a => a -> String
show (Word# -> Word
W# Word#
d) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
")"

-- | Note that 'fromInteger' necessarily runs in variable time due
--   to conversion from the variable-size, potentially heap-allocated
--   'Integer' type.
instance Num Montgomery where
  Montgomery
a + :: Montgomery -> Montgomery -> Montgomery
+ Montgomery
b = Montgomery -> Montgomery -> Montgomery
add Montgomery
a Montgomery
b
  Montgomery
a - :: Montgomery -> Montgomery -> Montgomery
- Montgomery
b = Montgomery -> Montgomery -> Montgomery
sub Montgomery
a Montgomery
b
  Montgomery
a * :: Montgomery -> Montgomery -> Montgomery
* Montgomery
b = Montgomery -> Montgomery -> Montgomery
mul Montgomery
a Montgomery
b
  negate :: Montgomery -> Montgomery
negate Montgomery
a = Montgomery -> Montgomery
neg Montgomery
a
  abs :: Montgomery -> Montgomery
abs = Montgomery -> Montgomery
forall a. a -> a
id
  fromInteger :: Integer -> Montgomery
fromInteger = Wider -> Montgomery
to (Wider -> Montgomery)
-> (Integer -> Wider) -> Integer -> Montgomery
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Wider
WW.to_vartime
  signum :: Montgomery -> Montgomery
signum (Montgomery (# Limb
l0, Limb
l1, Limb
l2, Limb
l3 #)) =
    let !(Limb Word#
l) = Limb
l0 Limb -> Limb -> Limb
`L.or#` Limb
l1 Limb -> Limb -> Limb
`L.or#` Limb
l2 Limb -> Limb -> Limb
`L.or#` Limb
l3
        !n :: Choice
n = Word# -> Choice
C.from_word_nonzero# Word#
l
        !b :: Word#
b = Choice -> Word#
C.to_word# Choice
n
    in  Limb4 -> Montgomery
Montgomery (Word# -> Word# -> Word# -> Word# -> Limb4
L4 Word#
b Word#
0## Word#
0## Word#
0##)

instance NFData Montgomery where
  rnf :: Montgomery -> ()
rnf (Montgomery Limb4
a) = case Limb4
a of (# Limb
_, Limb
_, Limb
_, Limb
_ #) -> ()

-- utilities ------------------------------------------------------------------

type Limb2 = (# Limb, Limb #)

type Limb4 = (# Limb, Limb, Limb, Limb #)

pattern L4 :: Word# -> Word# -> Word# -> Word# -> Limb4
pattern $mL4 :: forall {r}.
Limb4
-> (Word# -> Word# -> Word# -> Word# -> r) -> ((# #) -> r) -> r
$bL4 :: Word# -> Word# -> Word# -> Word# -> Limb4
L4 w0 w1 w2 w3 = (# Limb w0, Limb w1, Limb w2, Limb w3 #)
{-# COMPLETE L4 #-}

-- Wide wrapping addition, when addend is only a limb.
wadd_w# :: Limb2 -> Limb -> Limb2
wadd_w# :: Limb2 -> Limb -> Limb2
wadd_w# (# Limb
x_lo, Limb
x_hi #) Limb
y_lo =
  let !(# Limb
s0, Limb
c0 #) = Limb -> Limb -> Limb2
L.add_o# Limb
x_lo Limb
y_lo
      !(# Limb
s1, Limb
_ #) = Limb -> Limb -> Limb2
L.add_o# Limb
x_hi Limb
c0
  in  (# Limb
s0, Limb
s1 #)
{-# INLINE wadd_w# #-}

-- Truncate a wide word to a 'Limb'.
lo :: Limb2 -> Limb
lo :: Limb2 -> Limb
lo (# Limb
l, Limb
_ #) = Limb
l
{-# INLINE lo #-}

-- comparison -----------------------------------------------------------------

-- | Constant-time equality comparison.
eq :: Montgomery -> Montgomery -> C.Choice
eq :: Montgomery -> Montgomery -> Choice
eq (Montgomery (L4 Word#
a0 Word#
a1 Word#
a2 Word#
a3)) (Montgomery (L4 Word#
b0 Word#
b1 Word#
b2 Word#
b3)) =
  Limb4 -> Limb4 -> Choice
C.eq_wider# (# Word#
a0, Word#
a1, Word#
a2, Word#
a3 #) (# Word#
b0, Word#
b1, Word#
b2, Word#
b3 #)
{-# INLINE eq #-}

-- | Variable-time equality comparison.
eq_vartime :: Montgomery -> Montgomery -> Bool
eq_vartime :: Montgomery -> Montgomery -> Bool
eq_vartime (Montgomery (Limb4 -> Wider
Wider -> Wider
a)) (Montgomery (Limb4 -> Wider
Wider -> Wider
b)) =
  Wider -> Wider -> Bool
WW.eq_vartime Wider
a Wider
b

-- innards --------------------------------------------------------------------

redc_inner#
  :: Limb4             -- ^ upper limbs
  -> Limb4             -- ^ lower limbs
  -> (# Limb4, Limb #) -- ^ upper limbs, meta-carry
redc_inner# :: Limb4 -> Limb4 -> (# Limb4, Limb #)
redc_inner# (# Limb
u0, Limb
u1, Limb
u2, Limb
u3 #) (# Limb
l0, Limb
l1, Limb
l2, Limb
l3 #) =
  let !(# Limb
m0, Limb
m1, Limb
m2, Limb
m3 #) =
        Word# -> Word# -> Word# -> Word# -> Limb4
L4 Word#
0xBFD25E8CD0364141## Word#
0xBAAEDCE6AF48A03B##
           Word#
0xFFFFFFFFFFFFFFFE## Word#
0xFFFFFFFFFFFFFFFF##
      !n :: Limb
n                = Word# -> Limb
Limb Word#
0x4B0DFF665588B13F##
      !w_0 :: Limb
w_0              = Limb -> Limb -> Limb
L.mul_w# Limb
l0 Limb
n
      !(# Limb
_, Limb
c_00 #)    = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
w_0 Limb
m0 Limb
l0 (Word# -> Limb
Limb Word#
0##)
      !(# Limb
l0_1, Limb
c_01 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
w_0 Limb
m1 Limb
l1 Limb
c_00
      !(# Limb
l0_2, Limb
c_02 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
w_0 Limb
m2 Limb
l2 Limb
c_01
      !(# Limb
l0_3, Limb
c_03 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
w_0 Limb
m3 Limb
l3 Limb
c_02
      !(# Limb
u_0, Limb
mc_0 #)  = Limb -> Limb -> Limb -> Limb2
L.add_c# Limb
u0 Limb
c_03 (Word# -> Limb
Limb Word#
0##)
      !w_1 :: Limb
w_1              = Limb -> Limb -> Limb
L.mul_w# Limb
l0_1 Limb
n
      !(# Limb
_, Limb
c_10 #)    = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
w_1 Limb
m0 Limb
l0_1 (Word# -> Limb
Limb Word#
0##)
      !(# Limb
l1_1, Limb
c_11 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
w_1 Limb
m1 Limb
l0_2 Limb
c_10
      !(# Limb
l1_2, Limb
c_12 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
w_1 Limb
m2 Limb
l0_3 Limb
c_11
      !(# Limb
u1_3, Limb
c_13 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
w_1 Limb
m3 Limb
u_0 Limb
c_12
      !(# Limb
u_1, Limb
mc_1 #)  = Limb -> Limb -> Limb -> Limb2
L.add_c# Limb
u1 Limb
c_13 Limb
mc_0
      !w_2 :: Limb
w_2              = Limb -> Limb -> Limb
L.mul_w# Limb
l1_1 Limb
n
      !(# Limb
_, Limb
c_20 #)    = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
w_2 Limb
m0 Limb
l1_1 (Word# -> Limb
Limb Word#
0##)
      !(# Limb
l2_1, Limb
c_21 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
w_2 Limb
m1 Limb
l1_2 Limb
c_20
      !(# Limb
u2_2, Limb
c_22 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
w_2 Limb
m2 Limb
u1_3 Limb
c_21
      !(# Limb
u2_3, Limb
c_23 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
w_2 Limb
m3 Limb
u_1 Limb
c_22
      !(# Limb
u_2, Limb
mc_2 #)  = Limb -> Limb -> Limb -> Limb2
L.add_c# Limb
u2 Limb
c_23 Limb
mc_1
      !w_3 :: Limb
w_3              = Limb -> Limb -> Limb
L.mul_w# Limb
l2_1 Limb
n
      !(# Limb
_, Limb
c_30 #)    = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
w_3 Limb
m0 Limb
l2_1 (Word# -> Limb
Limb Word#
0##)
      !(# Limb
u3_1, Limb
c_31 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
w_3 Limb
m1 Limb
u2_2 Limb
c_30
      !(# Limb
u3_2, Limb
c_32 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
w_3 Limb
m2 Limb
u2_3 Limb
c_31
      !(# Limb
u3_3, Limb
c_33 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
w_3 Limb
m3 Limb
u_2 Limb
c_32
      !(# Limb
u_3, Limb
mc_3 #)  = Limb -> Limb -> Limb -> Limb2
L.add_c# Limb
u3 Limb
c_33 Limb
mc_2
  in  (# (# Limb
u3_1, Limb
u3_2, Limb
u3_3, Limb
u_3 #), Limb
mc_3 #)
{-# INLINE redc_inner# #-}

redc#
  :: Limb4 -- ^ lower limbs
  -> Limb4 -- ^ upper limbs
  -> Limb4 -- ^ result
redc# :: Limb4 -> Limb4 -> Limb4
redc# Limb4
l Limb4
u =
  let -- group order
      !m :: Limb4
m = Word# -> Word# -> Word# -> Word# -> Limb4
L4 Word#
0xBFD25E8CD0364141## Word#
0xBAAEDCE6AF48A03B##
              Word#
0xFFFFFFFFFFFFFFFE## Word#
0xFFFFFFFFFFFFFFFF##
      !(# Limb4
nu, Limb
mc #) = Limb4 -> Limb4 -> (# Limb4, Limb #)
redc_inner# Limb4
u Limb4
l
  in  Limb4 -> Limb -> Limb4 -> Limb4 -> Limb4
WW.sub_mod_c# Limb4
nu Limb
mc Limb4
m Limb4
m
{-# INLINE redc# #-}

-- | 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 -> Montgomery -> Montgomery
redc (Montgomery Limb4
l) (Montgomery Limb4
u) =
  let !res :: Limb4
res = Limb4 -> Limb4 -> Limb4
redc# Limb4
l Limb4
u
  in  (Limb4 -> Montgomery
Montgomery Limb4
res)

retr_inner#
  :: Limb4 -- ^ value in montgomery form
  -> Limb4 -- ^ retrieved value
retr_inner# :: Limb4 -> Limb4
retr_inner# (# Limb
x0, Limb
x1, Limb
x2, Limb
x3 #) =
  let !(# Limb
m0, Limb
m1, Limb
m2, Limb
m3 #) =
        Word# -> Word# -> Word# -> Word# -> Limb4
L4 Word#
0xBFD25E8CD0364141## Word#
0xBAAEDCE6AF48A03B##
           Word#
0xFFFFFFFFFFFFFFFE## Word#
0xFFFFFFFFFFFFFFFF##
      !n :: Limb
n                = Word# -> Limb
Limb Word#
0x4B0DFF665588B13F##
      !u_0 :: Limb
u_0              = Limb -> Limb -> Limb
L.mul_w# Limb
x0 Limb
n
      !(# Limb
_, Limb
o0 #)      = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
u_0 Limb
m0 Limb
x0 (Word# -> Limb
Limb Word#
0##)
      !(# Limb
o0_1, Limb
p0_1 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
u_0 Limb
m1 (Word# -> Limb
Limb Word#
0##) Limb
o0
      !(# Limb
p0_2, Limb
q0_2 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
u_0 Limb
m2 (Word# -> Limb
Limb Word#
0##) Limb
p0_1
      !(# Limb
q0_3, Limb
r0_3 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
u_0 Limb
m3 (Word# -> Limb
Limb Word#
0##) Limb
q0_2
      !u_1 :: Limb
u_1              = Limb -> Limb -> Limb
L.mul_w# (Limb -> Limb -> Limb
L.add_w# Limb
o0_1 Limb
x1) Limb
n
      !(# Limb
_, Limb
o1 #)      = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
u_1 Limb
m0 Limb
x1 Limb
o0_1
      !(# Limb
o1_1, Limb
p1_1 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
u_1 Limb
m1 Limb
p0_2 Limb
o1
      !(# Limb
p1_2, Limb
q1_2 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
u_1 Limb
m2 Limb
q0_3 Limb
p1_1
      !(# Limb
q1_3, Limb
r1_3 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
u_1 Limb
m3 Limb
r0_3 Limb
q1_2
      !u_2 :: Limb
u_2              = Limb -> Limb -> Limb
L.mul_w# (Limb -> Limb -> Limb
L.add_w# Limb
o1_1 Limb
x2) Limb
n
      !(# Limb
_, Limb
o2 #)      = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
u_2 Limb
m0 Limb
x2 Limb
o1_1
      !(# Limb
o2_1, Limb
p2_1 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
u_2 Limb
m1 Limb
p1_2 Limb
o2
      !(# Limb
p2_2, Limb
q2_2 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
u_2 Limb
m2 Limb
q1_3 Limb
p2_1
      !(# Limb
q2_3, Limb
r2_3 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
u_2 Limb
m3 Limb
r1_3 Limb
q2_2
      !u_3 :: Limb
u_3              = Limb -> Limb -> Limb
L.mul_w# (Limb -> Limb -> Limb
L.add_w# Limb
o2_1 Limb
x3) Limb
n
      !(# Limb
_, Limb
o3 #)      = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
u_3 Limb
m0 Limb
x3 Limb
o2_1
      !(# Limb
o3_1, Limb
p3_1 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
u_3 Limb
m1 Limb
p2_2 Limb
o3
      !(# Limb
p3_2, Limb
q3_2 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
u_3 Limb
m2 Limb
q2_3 Limb
p3_1
      !(# Limb
q3_3, Limb
r3_3 #) = Limb -> Limb -> Limb -> Limb -> Limb2
L.mac# Limb
u_3 Limb
m3 Limb
r2_3 Limb
q3_2
  in  (# Limb
o3_1, Limb
p3_2, Limb
q3_3, Limb
r3_3 #)
{-# INLINE retr_inner# #-}

retr#
  :: Limb4
  -> Limb4
retr# :: Limb4 -> Limb4
retr# Limb4
f = Limb4 -> Limb4
retr_inner# Limb4
f
{-# INLINE retr# #-}

-- | Retrieve a 'Montgomery' value from the Montgomery domain, producing
--   a 'Wider' word.
retr
  :: Montgomery -- ^ value in Montgomery form
  -> Wider      -- ^ retrieved value
retr :: Montgomery -> Wider
retr (Montgomery Limb4
f) =
  let !res :: Limb4
res = Limb4 -> Limb4
retr# Limb4
f
  in  (Limb4 -> Wider
Wider Limb4
res)

-- | Montgomery multiplication (FIOS), without conditional subtract.
mul_inner#
  :: Limb4              -- ^ x
  -> Limb4              -- ^ y
  -> (# Limb4, Limb #)  -- ^ product, meta-carry
mul_inner# :: Limb4 -> Limb4 -> (# Limb4, Limb #)
mul_inner# (# Limb
x0, Limb
x1, Limb
x2, Limb
x3 #) (# Limb
y0, Limb
y1, Limb
y2, Limb
y3 #) =
  let !(# Limb
m0, Limb
m1, Limb
m2, Limb
m3 #) =
        Word# -> Word# -> Word# -> Word# -> Limb4
L4 Word#
0xBFD25E8CD0364141## Word#
0xBAAEDCE6AF48A03B##
           Word#
0xFFFFFFFFFFFFFFFE## Word#
0xFFFFFFFFFFFFFFFF##
      !n :: Limb
n                           = Word# -> Limb
Limb Word#
0x4B0DFF665588B13F##
      !axy0 :: Limb2
axy0                        = Limb -> Limb -> Limb2
L.mul_c# Limb
x0 Limb
y0
      !u0 :: Limb
u0                          = Limb -> Limb -> Limb
L.mul_w# (Limb2 -> Limb
lo Limb2
axy0) Limb
n
      !(# (# Limb
_, Limb
a0 #), Limb
c0 #)       = Limb2 -> Limb2 -> (# Limb2, Limb #)
W.add_o# (Limb -> Limb -> Limb2
L.mul_c# Limb
u0 Limb
m0) Limb2
axy0
      !carry0 :: Limb2
carry0                      = (# Limb
a0, Limb
c0 #)
      !axy0_1 :: Limb2
axy0_1                      = Limb -> Limb -> Limb2
L.mul_c# Limb
x0 Limb
y1
      !umc0_1 :: Limb2
umc0_1                      = Limb2 -> Limb2 -> Limb2
W.add_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
u0 Limb
m1) Limb2
carry0
      !(# (# Limb
o0, Limb
ab0_1 #), Limb
c0_1 #) = Limb2 -> Limb2 -> (# Limb2, Limb #)
W.add_o# Limb2
axy0_1 Limb2
umc0_1
      !carry0_1 :: Limb2
carry0_1                    = (# Limb
ab0_1, Limb
c0_1 #)
      !axy0_2 :: Limb2
axy0_2                      = Limb -> Limb -> Limb2
L.mul_c# Limb
x0 Limb
y2
      !umc0_2 :: Limb2
umc0_2                      = Limb2 -> Limb2 -> Limb2
W.add_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
u0 Limb
m2) Limb2
carry0_1
      !(# (# Limb
p0, Limb
ab0_2 #), Limb
c0_2 #) = Limb2 -> Limb2 -> (# Limb2, Limb #)
W.add_o# Limb2
axy0_2 Limb2
umc0_2
      !carry0_2 :: Limb2
carry0_2                    = (# Limb
ab0_2, Limb
c0_2 #)
      !axy0_3 :: Limb2
axy0_3                      = Limb -> Limb -> Limb2
L.mul_c# Limb
x0 Limb
y3
      !umc0_3 :: Limb2
umc0_3                      = Limb2 -> Limb2 -> Limb2
W.add_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
u0 Limb
m3) Limb2
carry0_2
      !(# (# Limb
q0, Limb
ab0_3 #), Limb
c0_3 #) = Limb2 -> Limb2 -> (# Limb2, Limb #)
W.add_o# Limb2
axy0_3 Limb2
umc0_3
      !carry0_3 :: Limb2
carry0_3                    = (# Limb
ab0_3, Limb
c0_3 #)
      !(# Limb
r0, Limb
mc0 #)               = Limb2
carry0_3
      !axy1 :: Limb2
axy1                        = Limb2 -> Limb -> Limb2
wadd_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
x1 Limb
y0) Limb
o0
      !u1 :: Limb
u1                          = Limb -> Limb -> Limb
L.mul_w# (Limb2 -> Limb
lo Limb2
axy1) Limb
n
      !(# (# Limb
_, Limb
a1 #), Limb
c1 #)       = Limb2 -> Limb2 -> (# Limb2, Limb #)
W.add_o# (Limb -> Limb -> Limb2
L.mul_c# Limb
u1 Limb
m0) Limb2
axy1
      !carry1 :: Limb2
carry1                      = (# Limb
a1, Limb
c1 #)
      !axy1_1 :: Limb2
axy1_1                      = Limb2 -> Limb -> Limb2
wadd_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
x1 Limb
y1) Limb
p0
      !umc1_1 :: Limb2
umc1_1                      = Limb2 -> Limb2 -> Limb2
W.add_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
u1 Limb
m1) Limb2
carry1
      !(# (# Limb
o1, Limb
ab1_1 #), Limb
c1_1 #) = Limb2 -> Limb2 -> (# Limb2, Limb #)
W.add_o# Limb2
axy1_1 Limb2
umc1_1
      !carry1_1 :: Limb2
carry1_1                    = (# Limb
ab1_1, Limb
c1_1 #)
      !axy1_2 :: Limb2
axy1_2                      = Limb2 -> Limb -> Limb2
wadd_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
x1 Limb
y2) Limb
q0
      !umc1_2 :: Limb2
umc1_2                      = Limb2 -> Limb2 -> Limb2
W.add_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
u1 Limb
m2) Limb2
carry1_1
      !(# (# Limb
p1, Limb
ab1_2 #), Limb
c1_2 #) = Limb2 -> Limb2 -> (# Limb2, Limb #)
W.add_o# Limb2
axy1_2 Limb2
umc1_2
      !carry1_2 :: Limb2
carry1_2                    = (# Limb
ab1_2, Limb
c1_2 #)
      !axy1_3 :: Limb2
axy1_3                      = Limb2 -> Limb -> Limb2
wadd_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
x1 Limb
y3) Limb
r0
      !umc1_3 :: Limb2
umc1_3                      = Limb2 -> Limb2 -> Limb2
W.add_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
u1 Limb
m3) Limb2
carry1_2
      !(# (# Limb
q1, Limb
ab1_3 #), Limb
c1_3 #) = Limb2 -> Limb2 -> (# Limb2, Limb #)
W.add_o# Limb2
axy1_3 Limb2
umc1_3
      !carry1_3 :: Limb2
carry1_3                    = (# Limb
ab1_3, Limb
c1_3 #)
      !(# Limb
r1, Limb
mc1 #)               = Limb2 -> Limb -> Limb2
wadd_w# Limb2
carry1_3 Limb
mc0
      !axy2 :: Limb2
axy2                        = Limb2 -> Limb -> Limb2
wadd_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
x2 Limb
y0) Limb
o1
      !u2 :: Limb
u2                          = Limb -> Limb -> Limb
L.mul_w# (Limb2 -> Limb
lo Limb2
axy2) Limb
n
      !(# (# Limb
_, Limb
a2 #), Limb
c2 #)       = Limb2 -> Limb2 -> (# Limb2, Limb #)
W.add_o# (Limb -> Limb -> Limb2
L.mul_c# Limb
u2 Limb
m0) Limb2
axy2
      !carry2 :: Limb2
carry2                      = (# Limb
a2, Limb
c2 #)
      !axy2_1 :: Limb2
axy2_1                      = Limb2 -> Limb -> Limb2
wadd_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
x2 Limb
y1) Limb
p1
      !umc2_1 :: Limb2
umc2_1                      = Limb2 -> Limb2 -> Limb2
W.add_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
u2 Limb
m1) Limb2
carry2
      !(# (# Limb
o2, Limb
ab2_1 #), Limb
c2_1 #) = Limb2 -> Limb2 -> (# Limb2, Limb #)
W.add_o# Limb2
axy2_1 Limb2
umc2_1
      !carry2_1 :: Limb2
carry2_1                    = (# Limb
ab2_1, Limb
c2_1 #)
      !axy2_2 :: Limb2
axy2_2                      = Limb2 -> Limb -> Limb2
wadd_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
x2 Limb
y2) Limb
q1
      !umc2_2 :: Limb2
umc2_2                      = Limb2 -> Limb2 -> Limb2
W.add_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
u2 Limb
m2) Limb2
carry2_1
      !(# (# Limb
p2, Limb
ab2_2 #), Limb
c2_2 #) = Limb2 -> Limb2 -> (# Limb2, Limb #)
W.add_o# Limb2
axy2_2 Limb2
umc2_2
      !carry2_2 :: Limb2
carry2_2                    = (# Limb
ab2_2, Limb
c2_2 #)
      !axy2_3 :: Limb2
axy2_3                      = Limb2 -> Limb -> Limb2
wadd_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
x2 Limb
y3) Limb
r1
      !umc2_3 :: Limb2
umc2_3                      = Limb2 -> Limb2 -> Limb2
W.add_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
u2 Limb
m3) Limb2
carry2_2
      !(# (# Limb
q2, Limb
ab2_3 #), Limb
c2_3 #) = Limb2 -> Limb2 -> (# Limb2, Limb #)
W.add_o# Limb2
axy2_3 Limb2
umc2_3
      !carry2_3 :: Limb2
carry2_3                    = (# Limb
ab2_3, Limb
c2_3 #)
      !(# Limb
r2, Limb
mc2 #)               = Limb2 -> Limb -> Limb2
wadd_w# Limb2
carry2_3 Limb
mc1
      !axy3 :: Limb2
axy3                        = Limb2 -> Limb -> Limb2
wadd_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
x3 Limb
y0) Limb
o2
      !u3 :: Limb
u3                          = Limb -> Limb -> Limb
L.mul_w# (Limb2 -> Limb
lo Limb2
axy3) Limb
n
      !(# (# Limb
_, Limb
a3 #), Limb
c3 #)       = Limb2 -> Limb2 -> (# Limb2, Limb #)
W.add_o# (Limb -> Limb -> Limb2
L.mul_c# Limb
u3 Limb
m0) Limb2
axy3
      !carry3 :: Limb2
carry3                      = (# Limb
a3, Limb
c3 #)
      !axy3_1 :: Limb2
axy3_1                      = Limb2 -> Limb -> Limb2
wadd_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
x3 Limb
y1) Limb
p2
      !umc3_1 :: Limb2
umc3_1                      = Limb2 -> Limb2 -> Limb2
W.add_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
u3 Limb
m1) Limb2
carry3
      !(# (# Limb
o3, Limb
ab3_1 #), Limb
c3_1 #) = Limb2 -> Limb2 -> (# Limb2, Limb #)
W.add_o# Limb2
axy3_1 Limb2
umc3_1
      !carry3_1 :: Limb2
carry3_1                    = (# Limb
ab3_1, Limb
c3_1 #)
      !axy3_2 :: Limb2
axy3_2                      = Limb2 -> Limb -> Limb2
wadd_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
x3 Limb
y2) Limb
q2
      !umc3_2 :: Limb2
umc3_2                      = Limb2 -> Limb2 -> Limb2
W.add_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
u3 Limb
m2) Limb2
carry3_1
      !(# (# Limb
p3, Limb
ab3_2 #), Limb
c3_2 #) = Limb2 -> Limb2 -> (# Limb2, Limb #)
W.add_o# Limb2
axy3_2 Limb2
umc3_2
      !carry3_2 :: Limb2
carry3_2                    = (# Limb
ab3_2, Limb
c3_2 #)
      !axy3_3 :: Limb2
axy3_3                      = Limb2 -> Limb -> Limb2
wadd_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
x3 Limb
y3) Limb
r2
      !umc3_3 :: Limb2
umc3_3                      = Limb2 -> Limb2 -> Limb2
W.add_w# (Limb -> Limb -> Limb2
L.mul_c# Limb
u3 Limb
m3) Limb2
carry3_2
      !(# (# Limb
q3, Limb
ab3_3 #), Limb
c3_3 #) = Limb2 -> Limb2 -> (# Limb2, Limb #)
W.add_o# Limb2
axy3_3 Limb2
umc3_3
      !carry3_3 :: Limb2
carry3_3                    = (# Limb
ab3_3, Limb
c3_3 #)
      !(# Limb
r3, Limb
mc3 #)               = Limb2 -> Limb -> Limb2
wadd_w# Limb2
carry3_3 Limb
mc2
  in  (# (# Limb
o3, Limb
p3, Limb
q3, Limb
r3 #), Limb
mc3 #)
{-# INLINE mul_inner# #-}

mul#
  :: Limb4
  -> Limb4
  -> Limb4
mul# :: Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
b =
  let -- group order
      !m :: Limb4
m = Word# -> Word# -> Word# -> Word# -> Limb4
L4 Word#
0xBFD25E8CD0364141## Word#
0xBAAEDCE6AF48A03B##
              Word#
0xFFFFFFFFFFFFFFFE## Word#
0xFFFFFFFFFFFFFFFF##
      !(# Limb4
nu, Limb
mc #) = Limb4 -> Limb4 -> (# Limb4, Limb #)
mul_inner# Limb4
a Limb4
b
  in  Limb4 -> Limb -> Limb4 -> Limb4 -> Limb4
WW.sub_mod_c# Limb4
nu Limb
mc Limb4
m Limb4
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 -- ^ multiplicand in montgomery form
  -> Montgomery -- ^ multiplier in montgomery form
  -> Montgomery -- ^ montgomery product
mul :: Montgomery -> Montgomery -> Montgomery
mul (Montgomery Limb4
a) (Montgomery Limb4
b) = Limb4 -> Montgomery
Montgomery (Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
b)

to#
  :: Limb4 -- ^ integer
  -> Limb4
to# :: Limb4 -> Limb4
to# Limb4
x =
  let !r2 :: Limb4
r2 = Word# -> Word# -> Word# -> Word# -> Limb4
L4 Word#
0x896CF21467D7D140## Word#
0x741496C20E7CF878## -- r^2 mod m
               Word#
0xE697F5E45BCD07C6## Word#
0x9D671CD581C69BC5##
  in  Limb4 -> Limb4 -> Limb4
mul# Limb4
x Limb4
r2
{-# INLINE to# #-}

-- | Convert a 'Wider' word to the Montgomery domain.
to :: Wider -> Montgomery
to :: Wider -> Montgomery
to (Wider Limb4
x) = Limb4 -> Montgomery
Montgomery (Limb4 -> Limb4
to# Limb4
x)

-- | Retrieve a 'Montgomery' word from the Montgomery domain.
--
--   This function is a synonym for 'retr'.
from :: Montgomery -> Wider
from :: Montgomery -> Wider
from = Montgomery -> Wider
retr

add#
  :: Limb4 -- ^ augend
  -> Limb4 -- ^ addend
  -> Limb4 -- ^ sum
add# :: Limb4 -> Limb4 -> Limb4
add# Limb4
a Limb4
b =
  let -- group order
      !m :: Limb4
m = Word# -> Word# -> Word# -> Word# -> Limb4
L4 Word#
0xBFD25E8CD0364141## Word#
0xBAAEDCE6AF48A03B##
              Word#
0xFFFFFFFFFFFFFFFE## Word#
0xFFFFFFFFFFFFFFFF##
  in  Limb4 -> Limb4 -> Limb4 -> Limb4
WW.add_mod# Limb4
a Limb4
b Limb4
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 -- ^ augend
  -> Montgomery -- ^ addend
  -> Montgomery -- ^ sum
add :: Montgomery -> Montgomery -> Montgomery
add (Montgomery Limb4
a) (Montgomery Limb4
b) = Limb4 -> Montgomery
Montgomery (Limb4 -> Limb4 -> Limb4
add# Limb4
a Limb4
b)

sub#
  :: Limb4 -- ^ minuend
  -> Limb4 -- ^ subtrahend
  -> Limb4 -- ^ difference
sub# :: Limb4 -> Limb4 -> Limb4
sub# Limb4
a Limb4
b =
  let !m :: Limb4
m = Word# -> Word# -> Word# -> Word# -> Limb4
L4 Word#
0xBFD25E8CD0364141## Word#
0xBAAEDCE6AF48A03B##
              Word#
0xFFFFFFFFFFFFFFFE## Word#
0xFFFFFFFFFFFFFFFF##
  in  Limb4 -> Limb4 -> Limb4 -> Limb4
WW.sub_mod# Limb4
a Limb4
b Limb4
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 -- ^ minuend
  -> Montgomery -- ^ subtrahend
  -> Montgomery -- ^ difference
sub :: Montgomery -> Montgomery -> Montgomery
sub (Montgomery Limb4
a) (Montgomery Limb4
b) = Limb4 -> Montgomery
Montgomery (Limb4 -> Limb4 -> Limb4
sub# Limb4
a Limb4
b)

neg#
  :: Limb4 -- ^ argument
  -> Limb4 -- ^ modular negation
neg# :: Limb4 -> Limb4
neg# Limb4
a = Limb4 -> Limb4 -> Limb4
sub# (Word# -> Word# -> Word# -> Word# -> Limb4
L4 Word#
0## Word#
0## Word#
0## Word#
0##) Limb4
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 -> Montgomery
neg (Montgomery Limb4
a) = Limb4 -> Montgomery
Montgomery (Limb4 -> Limb4
neg# Limb4
a)

sqr# :: Limb4 -> Limb4
sqr# :: Limb4 -> Limb4
sqr# Limb4
a =
  let !(# Limb4
l, Limb4
h #) = Limb4 -> (# Limb4, Limb4 #)
WW.sqr# Limb4
a
  in  Limb4 -> Limb4 -> Limb4
redc# Limb4
l Limb4
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 -- ^ argument
  -> Montgomery -- ^ square
sqr :: Montgomery -> Montgomery
sqr (Montgomery Limb4
a) = Limb4 -> Montgomery
Montgomery (Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
a)

-- | Zero (the additive unit) in the Montgomery domain.
zero :: Montgomery
zero :: Montgomery
zero = Limb4 -> Montgomery
Montgomery (Word# -> Word# -> Word# -> Word# -> Limb4
L4 Word#
0## Word#
0## Word#
0## Word#
0##)

-- | One (the multiplicative unit) in the Montgomery domain.
one :: Montgomery
one :: Montgomery
one = Limb4 -> Montgomery
Montgomery (Word# -> Word# -> Word# -> Word# -> Limb4
L4 Word#
0x402DA1732FC9BEBF## Word#
0x4551231950B75FC4##
                     Word#
0x0000000000000001## Word#
0x0000000000000000##)

-- generated by etc/generate_inv.sh
inv#
  :: Limb4
  -> Limb4
inv# :: Limb4 -> Limb4
inv# Limb4
a =
  let !t0 :: Limb4
t0 = Word# -> Word# -> Word# -> Word# -> Limb4
L4 Word#
0x402DA1732FC9BEBF## Word#
0x4551231950B75FC4##
               Word#
0x0000000000000001## Word#
0x0000000000000000##
      !t1 :: Limb4
t1 = Limb4 -> Limb4
sqr# Limb4
t0
      !t2 :: Limb4
t2 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t1
      !t3 :: Limb4
t3 = Limb4 -> Limb4
sqr# Limb4
t2
      !t4 :: Limb4
t4 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t3
      !t5 :: Limb4
t5 = Limb4 -> Limb4
sqr# Limb4
t4
      !t6 :: Limb4
t6 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t5
      !t7 :: Limb4
t7 = Limb4 -> Limb4
sqr# Limb4
t6
      !t8 :: Limb4
t8 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t7
      !t9 :: Limb4
t9 = Limb4 -> Limb4
sqr# Limb4
t8
      !t10 :: Limb4
t10 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t9
      !t11 :: Limb4
t11 = Limb4 -> Limb4
sqr# Limb4
t10
      !t12 :: Limb4
t12 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t11
      !t13 :: Limb4
t13 = Limb4 -> Limb4
sqr# Limb4
t12
      !t14 :: Limb4
t14 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t13
      !t15 :: Limb4
t15 = Limb4 -> Limb4
sqr# Limb4
t14
      !t16 :: Limb4
t16 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t15
      !t17 :: Limb4
t17 = Limb4 -> Limb4
sqr# Limb4
t16
      !t18 :: Limb4
t18 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t17
      !t19 :: Limb4
t19 = Limb4 -> Limb4
sqr# Limb4
t18
      !t20 :: Limb4
t20 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t19
      !t21 :: Limb4
t21 = Limb4 -> Limb4
sqr# Limb4
t20
      !t22 :: Limb4
t22 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t21
      !t23 :: Limb4
t23 = Limb4 -> Limb4
sqr# Limb4
t22
      !t24 :: Limb4
t24 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t23
      !t25 :: Limb4
t25 = Limb4 -> Limb4
sqr# Limb4
t24
      !t26 :: Limb4
t26 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t25
      !t27 :: Limb4
t27 = Limb4 -> Limb4
sqr# Limb4
t26
      !t28 :: Limb4
t28 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t27
      !t29 :: Limb4
t29 = Limb4 -> Limb4
sqr# Limb4
t28
      !t30 :: Limb4
t30 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t29
      !t31 :: Limb4
t31 = Limb4 -> Limb4
sqr# Limb4
t30
      !t32 :: Limb4
t32 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t31
      !t33 :: Limb4
t33 = Limb4 -> Limb4
sqr# Limb4
t32
      !t34 :: Limb4
t34 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t33
      !t35 :: Limb4
t35 = Limb4 -> Limb4
sqr# Limb4
t34
      !t36 :: Limb4
t36 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t35
      !t37 :: Limb4
t37 = Limb4 -> Limb4
sqr# Limb4
t36
      !t38 :: Limb4
t38 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t37
      !t39 :: Limb4
t39 = Limb4 -> Limb4
sqr# Limb4
t38
      !t40 :: Limb4
t40 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t39
      !t41 :: Limb4
t41 = Limb4 -> Limb4
sqr# Limb4
t40
      !t42 :: Limb4
t42 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t41
      !t43 :: Limb4
t43 = Limb4 -> Limb4
sqr# Limb4
t42
      !t44 :: Limb4
t44 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t43
      !t45 :: Limb4
t45 = Limb4 -> Limb4
sqr# Limb4
t44
      !t46 :: Limb4
t46 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t45
      !t47 :: Limb4
t47 = Limb4 -> Limb4
sqr# Limb4
t46
      !t48 :: Limb4
t48 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t47
      !t49 :: Limb4
t49 = Limb4 -> Limb4
sqr# Limb4
t48
      !t50 :: Limb4
t50 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t49
      !t51 :: Limb4
t51 = Limb4 -> Limb4
sqr# Limb4
t50
      !t52 :: Limb4
t52 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t51
      !t53 :: Limb4
t53 = Limb4 -> Limb4
sqr# Limb4
t52
      !t54 :: Limb4
t54 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t53
      !t55 :: Limb4
t55 = Limb4 -> Limb4
sqr# Limb4
t54
      !t56 :: Limb4
t56 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t55
      !t57 :: Limb4
t57 = Limb4 -> Limb4
sqr# Limb4
t56
      !t58 :: Limb4
t58 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t57
      !t59 :: Limb4
t59 = Limb4 -> Limb4
sqr# Limb4
t58
      !t60 :: Limb4
t60 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t59
      !t61 :: Limb4
t61 = Limb4 -> Limb4
sqr# Limb4
t60
      !t62 :: Limb4
t62 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t61
      !t63 :: Limb4
t63 = Limb4 -> Limb4
sqr# Limb4
t62
      !t64 :: Limb4
t64 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t63
      !t65 :: Limb4
t65 = Limb4 -> Limb4
sqr# Limb4
t64
      !t66 :: Limb4
t66 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t65
      !t67 :: Limb4
t67 = Limb4 -> Limb4
sqr# Limb4
t66
      !t68 :: Limb4
t68 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t67
      !t69 :: Limb4
t69 = Limb4 -> Limb4
sqr# Limb4
t68
      !t70 :: Limb4
t70 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t69
      !t71 :: Limb4
t71 = Limb4 -> Limb4
sqr# Limb4
t70
      !t72 :: Limb4
t72 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t71
      !t73 :: Limb4
t73 = Limb4 -> Limb4
sqr# Limb4
t72
      !t74 :: Limb4
t74 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t73
      !t75 :: Limb4
t75 = Limb4 -> Limb4
sqr# Limb4
t74
      !t76 :: Limb4
t76 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t75
      !t77 :: Limb4
t77 = Limb4 -> Limb4
sqr# Limb4
t76
      !t78 :: Limb4
t78 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t77
      !t79 :: Limb4
t79 = Limb4 -> Limb4
sqr# Limb4
t78
      !t80 :: Limb4
t80 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t79
      !t81 :: Limb4
t81 = Limb4 -> Limb4
sqr# Limb4
t80
      !t82 :: Limb4
t82 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t81
      !t83 :: Limb4
t83 = Limb4 -> Limb4
sqr# Limb4
t82
      !t84 :: Limb4
t84 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t83
      !t85 :: Limb4
t85 = Limb4 -> Limb4
sqr# Limb4
t84
      !t86 :: Limb4
t86 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t85
      !t87 :: Limb4
t87 = Limb4 -> Limb4
sqr# Limb4
t86
      !t88 :: Limb4
t88 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t87
      !t89 :: Limb4
t89 = Limb4 -> Limb4
sqr# Limb4
t88
      !t90 :: Limb4
t90 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t89
      !t91 :: Limb4
t91 = Limb4 -> Limb4
sqr# Limb4
t90
      !t92 :: Limb4
t92 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t91
      !t93 :: Limb4
t93 = Limb4 -> Limb4
sqr# Limb4
t92
      !t94 :: Limb4
t94 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t93
      !t95 :: Limb4
t95 = Limb4 -> Limb4
sqr# Limb4
t94
      !t96 :: Limb4
t96 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t95
      !t97 :: Limb4
t97 = Limb4 -> Limb4
sqr# Limb4
t96
      !t98 :: Limb4
t98 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t97
      !t99 :: Limb4
t99 = Limb4 -> Limb4
sqr# Limb4
t98
      !t100 :: Limb4
t100 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t99
      !t101 :: Limb4
t101 = Limb4 -> Limb4
sqr# Limb4
t100
      !t102 :: Limb4
t102 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t101
      !t103 :: Limb4
t103 = Limb4 -> Limb4
sqr# Limb4
t102
      !t104 :: Limb4
t104 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t103
      !t105 :: Limb4
t105 = Limb4 -> Limb4
sqr# Limb4
t104
      !t106 :: Limb4
t106 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t105
      !t107 :: Limb4
t107 = Limb4 -> Limb4
sqr# Limb4
t106
      !t108 :: Limb4
t108 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t107
      !t109 :: Limb4
t109 = Limb4 -> Limb4
sqr# Limb4
t108
      !t110 :: Limb4
t110 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t109
      !t111 :: Limb4
t111 = Limb4 -> Limb4
sqr# Limb4
t110
      !t112 :: Limb4
t112 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t111
      !t113 :: Limb4
t113 = Limb4 -> Limb4
sqr# Limb4
t112
      !t114 :: Limb4
t114 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t113
      !t115 :: Limb4
t115 = Limb4 -> Limb4
sqr# Limb4
t114
      !t116 :: Limb4
t116 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t115
      !t117 :: Limb4
t117 = Limb4 -> Limb4
sqr# Limb4
t116
      !t118 :: Limb4
t118 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t117
      !t119 :: Limb4
t119 = Limb4 -> Limb4
sqr# Limb4
t118
      !t120 :: Limb4
t120 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t119
      !t121 :: Limb4
t121 = Limb4 -> Limb4
sqr# Limb4
t120
      !t122 :: Limb4
t122 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t121
      !t123 :: Limb4
t123 = Limb4 -> Limb4
sqr# Limb4
t122
      !t124 :: Limb4
t124 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t123
      !t125 :: Limb4
t125 = Limb4 -> Limb4
sqr# Limb4
t124
      !t126 :: Limb4
t126 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t125
      !t127 :: Limb4
t127 = Limb4 -> Limb4
sqr# Limb4
t126
      !t128 :: Limb4
t128 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t127
      !t129 :: Limb4
t129 = Limb4 -> Limb4
sqr# Limb4
t128
      !t130 :: Limb4
t130 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t129
      !t131 :: Limb4
t131 = Limb4 -> Limb4
sqr# Limb4
t130
      !t132 :: Limb4
t132 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t131
      !t133 :: Limb4
t133 = Limb4 -> Limb4
sqr# Limb4
t132
      !t134 :: Limb4
t134 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t133
      !t135 :: Limb4
t135 = Limb4 -> Limb4
sqr# Limb4
t134
      !t136 :: Limb4
t136 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t135
      !t137 :: Limb4
t137 = Limb4 -> Limb4
sqr# Limb4
t136
      !t138 :: Limb4
t138 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t137
      !t139 :: Limb4
t139 = Limb4 -> Limb4
sqr# Limb4
t138
      !t140 :: Limb4
t140 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t139
      !t141 :: Limb4
t141 = Limb4 -> Limb4
sqr# Limb4
t140
      !t142 :: Limb4
t142 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t141
      !t143 :: Limb4
t143 = Limb4 -> Limb4
sqr# Limb4
t142
      !t144 :: Limb4
t144 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t143
      !t145 :: Limb4
t145 = Limb4 -> Limb4
sqr# Limb4
t144
      !t146 :: Limb4
t146 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t145
      !t147 :: Limb4
t147 = Limb4 -> Limb4
sqr# Limb4
t146
      !t148 :: Limb4
t148 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t147
      !t149 :: Limb4
t149 = Limb4 -> Limb4
sqr# Limb4
t148
      !t150 :: Limb4
t150 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t149
      !t151 :: Limb4
t151 = Limb4 -> Limb4
sqr# Limb4
t150
      !t152 :: Limb4
t152 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t151
      !t153 :: Limb4
t153 = Limb4 -> Limb4
sqr# Limb4
t152
      !t154 :: Limb4
t154 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t153
      !t155 :: Limb4
t155 = Limb4 -> Limb4
sqr# Limb4
t154
      !t156 :: Limb4
t156 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t155
      !t157 :: Limb4
t157 = Limb4 -> Limb4
sqr# Limb4
t156
      !t158 :: Limb4
t158 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t157
      !t159 :: Limb4
t159 = Limb4 -> Limb4
sqr# Limb4
t158
      !t160 :: Limb4
t160 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t159
      !t161 :: Limb4
t161 = Limb4 -> Limb4
sqr# Limb4
t160
      !t162 :: Limb4
t162 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t161
      !t163 :: Limb4
t163 = Limb4 -> Limb4
sqr# Limb4
t162
      !t164 :: Limb4
t164 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t163
      !t165 :: Limb4
t165 = Limb4 -> Limb4
sqr# Limb4
t164
      !t166 :: Limb4
t166 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t165
      !t167 :: Limb4
t167 = Limb4 -> Limb4
sqr# Limb4
t166
      !t168 :: Limb4
t168 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t167
      !t169 :: Limb4
t169 = Limb4 -> Limb4
sqr# Limb4
t168
      !t170 :: Limb4
t170 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t169
      !t171 :: Limb4
t171 = Limb4 -> Limb4
sqr# Limb4
t170
      !t172 :: Limb4
t172 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t171
      !t173 :: Limb4
t173 = Limb4 -> Limb4
sqr# Limb4
t172
      !t174 :: Limb4
t174 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t173
      !t175 :: Limb4
t175 = Limb4 -> Limb4
sqr# Limb4
t174
      !t176 :: Limb4
t176 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t175
      !t177 :: Limb4
t177 = Limb4 -> Limb4
sqr# Limb4
t176
      !t178 :: Limb4
t178 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t177
      !t179 :: Limb4
t179 = Limb4 -> Limb4
sqr# Limb4
t178
      !t180 :: Limb4
t180 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t179
      !t181 :: Limb4
t181 = Limb4 -> Limb4
sqr# Limb4
t180
      !t182 :: Limb4
t182 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t181
      !t183 :: Limb4
t183 = Limb4 -> Limb4
sqr# Limb4
t182
      !t184 :: Limb4
t184 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t183
      !t185 :: Limb4
t185 = Limb4 -> Limb4
sqr# Limb4
t184
      !t186 :: Limb4
t186 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t185
      !t187 :: Limb4
t187 = Limb4 -> Limb4
sqr# Limb4
t186
      !t188 :: Limb4
t188 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t187
      !t189 :: Limb4
t189 = Limb4 -> Limb4
sqr# Limb4
t188
      !t190 :: Limb4
t190 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t189
      !t191 :: Limb4
t191 = Limb4 -> Limb4
sqr# Limb4
t190
      !t192 :: Limb4
t192 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t191
      !t193 :: Limb4
t193 = Limb4 -> Limb4
sqr# Limb4
t192
      !t194 :: Limb4
t194 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t193
      !t195 :: Limb4
t195 = Limb4 -> Limb4
sqr# Limb4
t194
      !t196 :: Limb4
t196 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t195
      !t197 :: Limb4
t197 = Limb4 -> Limb4
sqr# Limb4
t196
      !t198 :: Limb4
t198 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t197
      !t199 :: Limb4
t199 = Limb4 -> Limb4
sqr# Limb4
t198
      !t200 :: Limb4
t200 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t199
      !t201 :: Limb4
t201 = Limb4 -> Limb4
sqr# Limb4
t200
      !t202 :: Limb4
t202 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t201
      !t203 :: Limb4
t203 = Limb4 -> Limb4
sqr# Limb4
t202
      !t204 :: Limb4
t204 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t203
      !t205 :: Limb4
t205 = Limb4 -> Limb4
sqr# Limb4
t204
      !t206 :: Limb4
t206 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t205
      !t207 :: Limb4
t207 = Limb4 -> Limb4
sqr# Limb4
t206
      !t208 :: Limb4
t208 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t207
      !t209 :: Limb4
t209 = Limb4 -> Limb4
sqr# Limb4
t208
      !t210 :: Limb4
t210 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t209
      !t211 :: Limb4
t211 = Limb4 -> Limb4
sqr# Limb4
t210
      !t212 :: Limb4
t212 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t211
      !t213 :: Limb4
t213 = Limb4 -> Limb4
sqr# Limb4
t212
      !t214 :: Limb4
t214 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t213
      !t215 :: Limb4
t215 = Limb4 -> Limb4
sqr# Limb4
t214
      !t216 :: Limb4
t216 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t215
      !t217 :: Limb4
t217 = Limb4 -> Limb4
sqr# Limb4
t216
      !t218 :: Limb4
t218 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t217
      !t219 :: Limb4
t219 = Limb4 -> Limb4
sqr# Limb4
t218
      !t220 :: Limb4
t220 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t219
      !t221 :: Limb4
t221 = Limb4 -> Limb4
sqr# Limb4
t220
      !t222 :: Limb4
t222 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t221
      !t223 :: Limb4
t223 = Limb4 -> Limb4
sqr# Limb4
t222
      !t224 :: Limb4
t224 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t223
      !t225 :: Limb4
t225 = Limb4 -> Limb4
sqr# Limb4
t224
      !t226 :: Limb4
t226 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t225
      !t227 :: Limb4
t227 = Limb4 -> Limb4
sqr# Limb4
t226
      !t228 :: Limb4
t228 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t227
      !t229 :: Limb4
t229 = Limb4 -> Limb4
sqr# Limb4
t228
      !t230 :: Limb4
t230 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t229
      !t231 :: Limb4
t231 = Limb4 -> Limb4
sqr# Limb4
t230
      !t232 :: Limb4
t232 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t231
      !t233 :: Limb4
t233 = Limb4 -> Limb4
sqr# Limb4
t232
      !t234 :: Limb4
t234 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t233
      !t235 :: Limb4
t235 = Limb4 -> Limb4
sqr# Limb4
t234
      !t236 :: Limb4
t236 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t235
      !t237 :: Limb4
t237 = Limb4 -> Limb4
sqr# Limb4
t236
      !t238 :: Limb4
t238 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t237
      !t239 :: Limb4
t239 = Limb4 -> Limb4
sqr# Limb4
t238
      !t240 :: Limb4
t240 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t239
      !t241 :: Limb4
t241 = Limb4 -> Limb4
sqr# Limb4
t240
      !t242 :: Limb4
t242 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t241
      !t243 :: Limb4
t243 = Limb4 -> Limb4
sqr# Limb4
t242
      !t244 :: Limb4
t244 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t243
      !t245 :: Limb4
t245 = Limb4 -> Limb4
sqr# Limb4
t244
      !t246 :: Limb4
t246 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t245
      !t247 :: Limb4
t247 = Limb4 -> Limb4
sqr# Limb4
t246
      !t248 :: Limb4
t248 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t247
      !t249 :: Limb4
t249 = Limb4 -> Limb4
sqr# Limb4
t248
      !t250 :: Limb4
t250 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t249
      !t251 :: Limb4
t251 = Limb4 -> Limb4
sqr# Limb4
t250
      !t252 :: Limb4
t252 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t251
      !t253 :: Limb4
t253 = Limb4 -> Limb4
sqr# Limb4
t252
      !t254 :: Limb4
t254 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t253
      !t255 :: Limb4
t255 = Limb4 -> Limb4
sqr# Limb4
t254
      !t256 :: Limb4
t256 = Limb4 -> Limb4
sqr# Limb4
t255
      !t257 :: Limb4
t257 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t256
      !t258 :: Limb4
t258 = Limb4 -> Limb4
sqr# Limb4
t257
      !t259 :: Limb4
t259 = Limb4 -> Limb4
sqr# Limb4
t258
      !t260 :: Limb4
t260 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t259
      !t261 :: Limb4
t261 = Limb4 -> Limb4
sqr# Limb4
t260
      !t262 :: Limb4
t262 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t261
      !t263 :: Limb4
t263 = Limb4 -> Limb4
sqr# Limb4
t262
      !t264 :: Limb4
t264 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t263
      !t265 :: Limb4
t265 = Limb4 -> Limb4
sqr# Limb4
t264
      !t266 :: Limb4
t266 = Limb4 -> Limb4
sqr# Limb4
t265
      !t267 :: Limb4
t267 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t266
      !t268 :: Limb4
t268 = Limb4 -> Limb4
sqr# Limb4
t267
      !t269 :: Limb4
t269 = Limb4 -> Limb4
sqr# Limb4
t268
      !t270 :: Limb4
t270 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t269
      !t271 :: Limb4
t271 = Limb4 -> Limb4
sqr# Limb4
t270
      !t272 :: Limb4
t272 = Limb4 -> Limb4
sqr# Limb4
t271
      !t273 :: Limb4
t273 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t272
      !t274 :: Limb4
t274 = Limb4 -> Limb4
sqr# Limb4
t273
      !t275 :: Limb4
t275 = Limb4 -> Limb4
sqr# Limb4
t274
      !t276 :: Limb4
t276 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t275
      !t277 :: Limb4
t277 = Limb4 -> Limb4
sqr# Limb4
t276
      !t278 :: Limb4
t278 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t277
      !t279 :: Limb4
t279 = Limb4 -> Limb4
sqr# Limb4
t278
      !t280 :: Limb4
t280 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t279
      !t281 :: Limb4
t281 = Limb4 -> Limb4
sqr# Limb4
t280
      !t282 :: Limb4
t282 = Limb4 -> Limb4
sqr# Limb4
t281
      !t283 :: Limb4
t283 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t282
      !t284 :: Limb4
t284 = Limb4 -> Limb4
sqr# Limb4
t283
      !t285 :: Limb4
t285 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t284
      !t286 :: Limb4
t286 = Limb4 -> Limb4
sqr# Limb4
t285
      !t287 :: Limb4
t287 = Limb4 -> Limb4
sqr# Limb4
t286
      !t288 :: Limb4
t288 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t287
      !t289 :: Limb4
t289 = Limb4 -> Limb4
sqr# Limb4
t288
      !t290 :: Limb4
t290 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t289
      !t291 :: Limb4
t291 = Limb4 -> Limb4
sqr# Limb4
t290
      !t292 :: Limb4
t292 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t291
      !t293 :: Limb4
t293 = Limb4 -> Limb4
sqr# Limb4
t292
      !t294 :: Limb4
t294 = Limb4 -> Limb4
sqr# Limb4
t293
      !t295 :: Limb4
t295 = Limb4 -> Limb4
sqr# Limb4
t294
      !t296 :: Limb4
t296 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t295
      !t297 :: Limb4
t297 = Limb4 -> Limb4
sqr# Limb4
t296
      !t298 :: Limb4
t298 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t297
      !t299 :: Limb4
t299 = Limb4 -> Limb4
sqr# Limb4
t298
      !t300 :: Limb4
t300 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t299
      !t301 :: Limb4
t301 = Limb4 -> Limb4
sqr# Limb4
t300
      !t302 :: Limb4
t302 = Limb4 -> Limb4
sqr# Limb4
t301
      !t303 :: Limb4
t303 = Limb4 -> Limb4
sqr# Limb4
t302
      !t304 :: Limb4
t304 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t303
      !t305 :: Limb4
t305 = Limb4 -> Limb4
sqr# Limb4
t304
      !t306 :: Limb4
t306 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t305
      !t307 :: Limb4
t307 = Limb4 -> Limb4
sqr# Limb4
t306
      !t308 :: Limb4
t308 = Limb4 -> Limb4
sqr# Limb4
t307
      !t309 :: Limb4
t309 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t308
      !t310 :: Limb4
t310 = Limb4 -> Limb4
sqr# Limb4
t309
      !t311 :: Limb4
t311 = Limb4 -> Limb4
sqr# Limb4
t310
      !t312 :: Limb4
t312 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t311
      !t313 :: Limb4
t313 = Limb4 -> Limb4
sqr# Limb4
t312
      !t314 :: Limb4
t314 = Limb4 -> Limb4
sqr# Limb4
t313
      !t315 :: Limb4
t315 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t314
      !t316 :: Limb4
t316 = Limb4 -> Limb4
sqr# Limb4
t315
      !t317 :: Limb4
t317 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t316
      !t318 :: Limb4
t318 = Limb4 -> Limb4
sqr# Limb4
t317
      !t319 :: Limb4
t319 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t318
      !t320 :: Limb4
t320 = Limb4 -> Limb4
sqr# Limb4
t319
      !t321 :: Limb4
t321 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t320
      !t322 :: Limb4
t322 = Limb4 -> Limb4
sqr# Limb4
t321
      !t323 :: Limb4
t323 = Limb4 -> Limb4
sqr# Limb4
t322
      !t324 :: Limb4
t324 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t323
      !t325 :: Limb4
t325 = Limb4 -> Limb4
sqr# Limb4
t324
      !t326 :: Limb4
t326 = Limb4 -> Limb4
sqr# Limb4
t325
      !t327 :: Limb4
t327 = Limb4 -> Limb4
sqr# Limb4
t326
      !t328 :: Limb4
t328 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t327
      !t329 :: Limb4
t329 = Limb4 -> Limb4
sqr# Limb4
t328
      !t330 :: Limb4
t330 = Limb4 -> Limb4
sqr# Limb4
t329
      !t331 :: Limb4
t331 = Limb4 -> Limb4
sqr# Limb4
t330
      !t332 :: Limb4
t332 = Limb4 -> Limb4
sqr# Limb4
t331
      !t333 :: Limb4
t333 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t332
      !t334 :: Limb4
t334 = Limb4 -> Limb4
sqr# Limb4
t333
      !t335 :: Limb4
t335 = Limb4 -> Limb4
sqr# Limb4
t334
      !t336 :: Limb4
t336 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t335
      !t337 :: Limb4
t337 = Limb4 -> Limb4
sqr# Limb4
t336
      !t338 :: Limb4
t338 = Limb4 -> Limb4
sqr# Limb4
t337
      !t339 :: Limb4
t339 = Limb4 -> Limb4
sqr# Limb4
t338
      !t340 :: Limb4
t340 = Limb4 -> Limb4
sqr# Limb4
t339
      !t341 :: Limb4
t341 = Limb4 -> Limb4
sqr# Limb4
t340
      !t342 :: Limb4
t342 = Limb4 -> Limb4
sqr# Limb4
t341
      !t343 :: Limb4
t343 = Limb4 -> Limb4
sqr# Limb4
t342
      !t344 :: Limb4
t344 = Limb4 -> Limb4
sqr# Limb4
t343
      !t345 :: Limb4
t345 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t344
      !t346 :: Limb4
t346 = Limb4 -> Limb4
sqr# Limb4
t345
      !t347 :: Limb4
t347 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t346
      !t348 :: Limb4
t348 = Limb4 -> Limb4
sqr# Limb4
t347
      !t349 :: Limb4
t349 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t348
      !t350 :: Limb4
t350 = Limb4 -> Limb4
sqr# Limb4
t349
      !t351 :: Limb4
t351 = Limb4 -> Limb4
sqr# Limb4
t350
      !t352 :: Limb4
t352 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t351
      !t353 :: Limb4
t353 = Limb4 -> Limb4
sqr# Limb4
t352
      !t354 :: Limb4
t354 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t353
      !t355 :: Limb4
t355 = Limb4 -> Limb4
sqr# Limb4
t354
      !t356 :: Limb4
t356 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t355
      !t357 :: Limb4
t357 = Limb4 -> Limb4
sqr# Limb4
t356
      !t358 :: Limb4
t358 = Limb4 -> Limb4
sqr# Limb4
t357
      !t359 :: Limb4
t359 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t358
      !t360 :: Limb4
t360 = Limb4 -> Limb4
sqr# Limb4
t359
      !t361 :: Limb4
t361 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t360
      !t362 :: Limb4
t362 = Limb4 -> Limb4
sqr# Limb4
t361
      !t363 :: Limb4
t363 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t362
      !t364 :: Limb4
t364 = Limb4 -> Limb4
sqr# Limb4
t363
      !t365 :: Limb4
t365 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t364
      !t366 :: Limb4
t366 = Limb4 -> Limb4
sqr# Limb4
t365
      !t367 :: Limb4
t367 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t366
      !t368 :: Limb4
t368 = Limb4 -> Limb4
sqr# Limb4
t367
      !t369 :: Limb4
t369 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t368
      !t370 :: Limb4
t370 = Limb4 -> Limb4
sqr# Limb4
t369
      !t371 :: Limb4
t371 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t370
      !t372 :: Limb4
t372 = Limb4 -> Limb4
sqr# Limb4
t371
      !t373 :: Limb4
t373 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t372
      !t374 :: Limb4
t374 = Limb4 -> Limb4
sqr# Limb4
t373
      !t375 :: Limb4
t375 = Limb4 -> Limb4
sqr# Limb4
t374
      !t376 :: Limb4
t376 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t375
      !t377 :: Limb4
t377 = Limb4 -> Limb4
sqr# Limb4
t376
      !t378 :: Limb4
t378 = Limb4 -> Limb4
sqr# Limb4
t377
      !t379 :: Limb4
t379 = Limb4 -> Limb4
sqr# Limb4
t378
      !t380 :: Limb4
t380 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t379
      !t381 :: Limb4
t381 = Limb4 -> Limb4
sqr# Limb4
t380
      !t382 :: Limb4
t382 = Limb4 -> Limb4
sqr# Limb4
t381
      !t383 :: Limb4
t383 = Limb4 -> Limb4
sqr# Limb4
t382
      !t384 :: Limb4
t384 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t383
      !t385 :: Limb4
t385 = Limb4 -> Limb4
sqr# Limb4
t384
      !t386 :: Limb4
t386 = Limb4 -> Limb4
sqr# Limb4
t385
      !t387 :: Limb4
t387 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t386
      !t388 :: Limb4
t388 = Limb4 -> Limb4
sqr# Limb4
t387
      !t389 :: Limb4
t389 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t388
      !t390 :: Limb4
t390 = Limb4 -> Limb4
sqr# Limb4
t389
      !t391 :: Limb4
t391 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t390
      !t392 :: Limb4
t392 = Limb4 -> Limb4
sqr# Limb4
t391
      !t393 :: Limb4
t393 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t392
      !t394 :: Limb4
t394 = Limb4 -> Limb4
sqr# Limb4
t393
      !t395 :: Limb4
t395 = Limb4 -> Limb4
sqr# Limb4
t394
      !t396 :: Limb4
t396 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t395
      !t397 :: Limb4
t397 = Limb4 -> Limb4
sqr# Limb4
t396
      !t398 :: Limb4
t398 = Limb4 -> Limb4
sqr# Limb4
t397
      !t399 :: Limb4
t399 = Limb4 -> Limb4
sqr# Limb4
t398
      !t400 :: Limb4
t400 = Limb4 -> Limb4
sqr# Limb4
t399
      !t401 :: Limb4
t401 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t400
      !t402 :: Limb4
t402 = Limb4 -> Limb4
sqr# Limb4
t401
      !t403 :: Limb4
t403 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t402
      !t404 :: Limb4
t404 = Limb4 -> Limb4
sqr# Limb4
t403
      !t405 :: Limb4
t405 = Limb4 -> Limb4
sqr# Limb4
t404
      !t406 :: Limb4
t406 = Limb4 -> Limb4
sqr# Limb4
t405
      !t407 :: Limb4
t407 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t406
      !t408 :: Limb4
t408 = Limb4 -> Limb4
sqr# Limb4
t407
      !t409 :: Limb4
t409 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t408
      !t410 :: Limb4
t410 = Limb4 -> Limb4
sqr# Limb4
t409
      !t411 :: Limb4
t411 = Limb4 -> Limb4
sqr# Limb4
t410
      !t412 :: Limb4
t412 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t411
      !t413 :: Limb4
t413 = Limb4 -> Limb4
sqr# Limb4
t412
      !t414 :: Limb4
t414 = Limb4 -> Limb4
sqr# Limb4
t413
      !t415 :: Limb4
t415 = Limb4 -> Limb4
sqr# Limb4
t414
      !t416 :: Limb4
t416 = Limb4 -> Limb4
sqr# Limb4
t415
      !t417 :: Limb4
t417 = Limb4 -> Limb4
sqr# Limb4
t416
      !t418 :: Limb4
t418 = Limb4 -> Limb4
sqr# Limb4
t417
      !t419 :: Limb4
t419 = Limb4 -> Limb4
sqr# Limb4
t418
      !t420 :: Limb4
t420 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t419
      !t421 :: Limb4
t421 = Limb4 -> Limb4
sqr# Limb4
t420
      !t422 :: Limb4
t422 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t421
      !t423 :: Limb4
t423 = Limb4 -> Limb4
sqr# Limb4
t422
      !t424 :: Limb4
t424 = Limb4 -> Limb4
sqr# Limb4
t423
      !t425 :: Limb4
t425 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t424
      !t426 :: Limb4
t426 = Limb4 -> Limb4
sqr# Limb4
t425
      !t427 :: Limb4
t427 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t426
      !t428 :: Limb4
t428 = Limb4 -> Limb4
sqr# Limb4
t427
      !t429 :: Limb4
t429 = Limb4 -> Limb4
sqr# Limb4
t428
      !t430 :: Limb4
t430 = Limb4 -> Limb4
sqr# Limb4
t429
      !t431 :: Limb4
t431 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t430
      !t432 :: Limb4
t432 = Limb4 -> Limb4
sqr# Limb4
t431
      !t433 :: Limb4
t433 = Limb4 -> Limb4
sqr# Limb4
t432
      !t434 :: Limb4
t434 = Limb4 -> Limb4
sqr# Limb4
t433
      !t435 :: Limb4
t435 = Limb4 -> Limb4
sqr# Limb4
t434
      !t436 :: Limb4
t436 = Limb4 -> Limb4
sqr# Limb4
t435
      !t437 :: Limb4
t437 = Limb4 -> Limb4
sqr# Limb4
t436
      !t438 :: Limb4
t438 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t437
      !t439 :: Limb4
t439 = Limb4 -> Limb4
sqr# Limb4
t438
      !t440 :: Limb4
t440 = Limb4 -> Limb4
sqr# Limb4
t439
      !t441 :: Limb4
t441 = Limb4 -> Limb4
sqr# Limb4
t440
      !t442 :: Limb4
t442 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t441
      !t443 :: Limb4
t443 = Limb4 -> Limb4
sqr# Limb4
t442
      !t444 :: Limb4
t444 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t443
      !t445 :: Limb4
t445 = Limb4 -> Limb4
sqr# Limb4
t444
      !t446 :: Limb4
t446 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t445
      !t447 :: Limb4
t447 = Limb4 -> Limb4
sqr# Limb4
t446
      !t448 :: Limb4
t448 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t447
      !t449 :: Limb4
t449 = Limb4 -> Limb4
sqr# Limb4
t448
      !t450 :: Limb4
t450 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t449
      !t451 :: Limb4
t451 = Limb4 -> Limb4
sqr# Limb4
t450
      !t452 :: Limb4
t452 = Limb4 -> Limb4 -> Limb4
mul# Limb4
a Limb4
t451
      !r :: Limb4
r = Limb4
t452
  in  Limb4
r
{-# INLINE inv# #-}

-- | Multiplicative inverse in the Montgomery domain.
--
--   >> inv 2
--   57896044618658097711785492504343953926418782139537452191302581570759080747169
--   >> inv 2 * 2
--   1
inv
  :: Montgomery -- ^ argument
  -> Montgomery -- ^ inverse
inv :: Montgomery -> Montgomery
inv (Montgomery Limb4
w) = Limb4 -> Montgomery
Montgomery (Limb4 -> Limb4
inv# Limb4
w)

-- | Exponentiation in the Montgomery domain.
--
--   >>> exp 2 3
--   8
--   >>> exp 2 10
--   1024
exp :: Montgomery -> Wider -> Montgomery
exp :: Montgomery -> Wider -> Montgomery
exp (Montgomery Limb4
b) (Wider Limb4
e) = Limb4 -> Montgomery
Montgomery (Limb4 -> Limb4 -> Limb4
exp# Limb4
b Limb4
e)

exp#
  :: Limb4
  -> Limb4
  -> Limb4
exp# :: Limb4 -> Limb4 -> Limb4
exp# Limb4
b Limb4
e =
  let !o :: Limb4
o = Word# -> Word# -> Word# -> Word# -> Limb4
L4 Word#
0x402DA1732FC9BEBF## Word#
0x4551231950B75FC4##
              Word#
0x0000000000000001## Word#
0x0000000000000000##
      loop :: Limb4 -> Limb4 -> Limb4 -> t -> Limb4
loop !Limb4
r !Limb4
m !Limb4
ex t
n = case t
n of
        t
0 -> Limb4
r
        t
_ ->
          let !(# Limb4
ne, Choice
bit #) = Limb4 -> (# Limb4, Choice #)
WW.shr1_c# Limb4
ex
              !candidate :: Limb4
candidate = Limb4 -> Limb4 -> Limb4
mul# Limb4
r Limb4
m
              !nr :: Limb4
nr = Limb4 -> Limb4 -> Choice -> Limb4
select# Limb4
r Limb4
candidate Choice
bit
              !nm :: Limb4
nm = Limb4 -> Limb4
sqr# Limb4
m
          in  Limb4 -> Limb4 -> Limb4 -> t -> Limb4
loop Limb4
nr Limb4
nm Limb4
ne (t
n t -> t -> t
forall a. Num a => a -> a -> a
- t
1)
  in  Limb4 -> Limb4 -> Limb4 -> Word -> Limb4
forall {t}. (Eq t, Num t) => Limb4 -> Limb4 -> Limb4 -> t -> Limb4
loop Limb4
o Limb4
b Limb4
e (Word
256 :: Word)
{-# INLINE exp# #-}

odd# :: Limb4 -> C.Choice
odd# :: Limb4 -> Choice
odd# = Limb4 -> Choice
WW.odd#
{-# INLINE odd# #-}

-- | Check if a 'Montgomery' value is odd.
--
--   Note that the comparison is performed in constant time, but we
--   branch when converting to 'Bool'.
--
--   >>> odd 1
--   True
--   >>> odd 2
--   False
--   >>> Data.Word.Wider.odd (retr 3) -- parity is preserved
--   True
odd_vartime :: Montgomery -> Bool
odd_vartime :: Montgomery -> Bool
odd_vartime (Montgomery Limb4
m) = Choice -> Bool
C.decide (Limb4 -> Choice
odd# Limb4
m)

-- constant-time selection ----------------------------------------------------

select#
  :: Limb4    -- ^ a
  -> Limb4    -- ^ b
  -> C.Choice -- ^ c
  -> Limb4    -- ^ result
select# :: Limb4 -> Limb4 -> Choice -> Limb4
select# = Limb4 -> Limb4 -> Choice -> Limb4
WW.select#
{-# INLINE select# #-}

-- | Return a if c is truthy, otherwise return b.
--
--   >>> import qualified Data.Choice as C
--   >>> select 0 1 (C.true# ())
--   1
select
  :: Montgomery    -- ^ a
  -> Montgomery    -- ^ b
  -> C.Choice      -- ^ c
  -> Montgomery    -- ^ result
select :: Montgomery -> Montgomery -> Choice -> Montgomery
select (Montgomery Limb4
a) (Montgomery Limb4
b) Choice
c = Limb4 -> Montgomery
Montgomery (Limb4 -> Limb4 -> Choice -> Limb4
select# Limb4
a Limb4
b Choice
c)