mldsa 0.1.0.0 → 0.1.1.0
raw patch · 14 files changed
+227/−57 lines, 14 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- CHANGELOG.md +15/−0
- mldsa.cabal +6/−2
- src/Auxiliary.hs +36/−9
- src/Barrier.hs +60/−0
- src/BlockN.hs +1/−1
- src/Builder.hs +5/−2
- src/Crypto.hs +14/−4
- src/Crypto/PubKey/ML_DSA.hs +10/−6
- src/Endian.hs +58/−0
- src/Fusion.hs +2/−2
- src/Internal.hs +15/−11
- src/Machine.hs +3/−18
- src/ScrubbedBlock.hs +1/−1
- tests/get-vectors.sh +1/−1
CHANGELOG.md view
@@ -1,5 +1,20 @@ # Changelog for `mldsa` +## 0.1.1.0 - 2026-08-16++* Remove redundant hashing for mu and rho'' during signature generation++* Use cached public-key hash during signature verification++* Improve performance of modular reduction with the NCG++* Use `finally` instead of masking asynchronous exceptions while hashing the+ entire message++* Add value barriers to prevent LLVM from introducing unwanted branches++* Refresh the test vectors+ ## 0.1.0.0 - 2026-07-05 * First version. Released on an unsuspecting world.
mldsa.cabal view
@@ -1,11 +1,11 @@ cabal-version: 2.2 --- This file has been generated from package.yaml by hpack version 0.39.1.+-- This file has been generated from package.yaml by hpack version 0.39.6. -- -- see: https://github.com/sol/hpack name: mldsa-version: 0.1.0.0+version: 0.1.1.0 synopsis: Module-Lattice-based Digital Signature Algorithm description: Module-Lattice-based Digital Signature Algorithm (ML-DSA) implemented in Haskell.@@ -38,12 +38,14 @@ Crypto.PubKey.ML_DSA other-modules: Auxiliary+ Barrier Base Block BlockN Builder ByteArrayST Crypto+ Endian Equality Fusion Internal@@ -122,6 +124,7 @@ main-is: Tests.hs other-modules: Auxiliary+ Barrier Base Block BlockN@@ -129,6 +132,7 @@ ByteArrayST Crypto Crypto.PubKey.ML_DSA+ Endian Equality Fusion Internal
src/Auxiliary.hs view
@@ -37,7 +37,6 @@ import Data.ByteArray (ByteArrayAccess) import qualified Data.ByteArray as B-import qualified Data.Memory.Endian as B import Data.Primitive.Types (Prim(..)) @@ -62,6 +61,7 @@ import Foreign.Storable (pokeByteOff) import Base+import Barrier import Block (blockIndex) import BlockN (BlockN, MutableBlockN) import Builder (Builder)@@ -76,6 +76,7 @@ import qualified Builder import qualified ByteArrayST as ST import qualified Crypto+import qualified Endian as B import qualified Vector import Math @@ -124,12 +125,36 @@ -- Reduction 𝑥 mod 𝑞 for 0 ≤ 𝑥 < 2𝑞 reduceSimple :: Word32 -> Word32-reduceSimple x = select32 mask x subtracted+#ifdef __GLASGOW_HASKELL_LLVM__+reduceSimple = reduceSimpleLLVM+#else+reduceSimple = fromIntegral . reduceSimpleNCG . fromIntegral+#endif+{-# INLINE reduceSimple #-}++#ifdef __GLASGOW_HASKELL_LLVM__+-- LLVM operates more efficiently on Word16 directly+reduceSimpleLLVM :: Word32 -> Word32+reduceSimpleLLVM x = (mask .&. x) .|. (complement mask .&. subtracted) where subtracted = x - q32 mask = subtracted `unsafeShiftIR` 31-{-# INLINE reduceSimple #-}+#else+-- NCG code performance is better with full machine words, as this removes+-- conversion instructions at several intermediate steps+reduceSimpleNCG :: Word -> Word+reduceSimpleNCG x = (mask .&. x) .|. (complement mask .&. subtracted)+ where+ subtracted = x - qW+ mask = subtracted `unsafeShiftIRW` (finiteBitSize qW - 1) + unsafeShiftIRW :: Word -> Int -> Word+ unsafeShiftIRW w s = fromIntegral ((fromIntegral w :: Int) `unsafeShiftR` s)++ qW :: Word+ qW = fromInteger q+#endif+ #ifdef ML_DSA_TESTING -- Reduction 𝑥 mod 𝑞 for 0 ≤ 𝑥 < 1025𝑞 reduce :: Word64 -> Word32@@ -703,7 +728,7 @@ set mb val >> go (idx + 1) new :: ST s (MutableBlockN Sec N H s)- new = newF >>= \mb -> BlockN.erase mb >> return mb+ new = newF >>= \mb -> mb <$ BlockN.erase mb set :: MutableBlockN Sec N H s -> Word8 -> ST s () set mb val = BlockN.write mb (fromIntegral val) (H 1)@@ -724,7 +749,7 @@ -- Samples a polynomial 𝑐 ∈ 𝑅 with coefficients from {-1, 0, 1} and -- Hamming weight 𝜏 ≤ 64 sampleInBall :: Int -> SecureBytes Sec -> Rq Sec-sampleInBall tau rho = Rq $+sampleInBall tau rho = Rq $ BlockN.seq tau $ BlockN.runNew (Proxy :: Proxy Sec) $ \c -> runXof c 136 where runXof :: MutableBlockN Sec N Zq s -> Int -> ST s ()@@ -826,8 +851,9 @@ -- rejection sampling from {-2, … , 2} poke2 b j z- | z < 15 = BlockN.write b j (Zq 2 .- Zq (mod5 z)) >> return (j + 1)+ | z < 15 = BlockN.write b j (Zq 2 .- Zq z') >> return (j + 1) | otherwise = return j+ where z' = barrier32 (mod5 z) -- rejection sampling from {-4, … , 4} poke4 b j z@@ -886,16 +912,17 @@ _ -> high523776 r high190464 :: Word32 -> Word32-high190464 r = r1 `xor` (((43 - r1) `unsafeShiftIR` 31) .&. r1)+high190464 r = wrapAround (barrier32 r1) where+ wrapAround x = x .&. ((x - 44) `unsafeShiftIR` 31) r' = (r + 127) `unsafeShiftR` 7- r1 = (r' * 11275 + (1 `unsafeShiftL` 23)) `unsafeShiftR` 24;+ r1 = (r' * 11275 + (1 `unsafeShiftL` 23)) `unsafeShiftR` 24 high523776 :: Word32 -> Word32 high523776 r = r1 .&. 15 where r' = (r + 127) `unsafeShiftR` 7- r1 = (r' * 1025 + (1 `unsafeShiftL` 21)) `unsafeShiftR` 22;+ r1 = (r' * 1025 + (1 `unsafeShiftL` 21)) `unsafeShiftR` 22 -- Returns 𝑟1 from the output of decomposeZq 𝑟 highBits :: Word32 -> Rq Sec -> BlockN Sec N Word32
+ src/Barrier.hs view
@@ -0,0 +1,60 @@+-- |+-- Module : Barrier+-- License : BSD-3-Clause+-- Copyright : (c) 2026 Olivier Chéron+--+-- Utilities to block LLVM optimizations that are unwanted. Currently this+-- targets the X86 CMOV conversion pass, to make sure constant-time masking+-- operations are preserved and not transformed into branches.+--+{-# LANGUAGE CPP #-}+#if (defined(i386_HOST_ARCH) || defined(x86_64_HOST_ARCH)) \+ && defined(__GLASGOW_HASKELL_LLVM__)+#define MLDSA_USE_VALUE_BARRIER 1+#endif+#ifdef MLDSA_USE_VALUE_BARRIER+{-# LANGUAGE MagicHash #-}+#endif+module Barrier+ ( barrier32+ ) where++import Data.Word++#ifdef MLDSA_USE_VALUE_BARRIER++#if MIN_VERSION_base(4,16,0)+import GHC.Exts (Word32#)+#else+import GHC.Exts (Word#)+#endif+import GHC.Word (Word32(W32#))++-- Implements a value barrier: at call site the content of the function is+-- opaque to the optimizer, thus the call prevents optimizations that need+-- knowledge of the value.+--+-- We want to avoid memory allocations and use CPU registers so the mechanism+-- relies on unlifted values in and out.++barrier32 :: Word32 -> Word32+barrier32 (W32# x#) = W32# (barrier32# x#)+{-# INLINE barrier32 #-}++#if MIN_VERSION_base(4,16,0)+barrier32# :: Word32# -> Word32#+#else+barrier32# :: Word# -> Word#+#endif+barrier32# x# = x#+{-# NOINLINE barrier32# #-}++#else++-- When using the NCG, or not on X86, the call can be completely eliminated.++barrier32 :: Word32 -> Word32+barrier32 = id+{-# INLINE barrier32 #-}++#endif
src/BlockN.hs view
@@ -241,7 +241,7 @@ iterMapIxContext :: (EqPrimSize a b, Classified marking, KnownNat n) => (Int -> a -> b) -> Context (BlockN marking n a) -> Context (BlockN marking n b) iterMapIxContext f = mapContext m where m = MapF { mapUpdate = unsafeMapIx f- , mapInit = \x -> newF >>= \mb -> Prelude.seq x (iterSet (g x) mb) >> return mb+ , mapInit = \x -> newF >>= \mb -> mb <$ Prelude.seq x (iterSet (g x) mb) } g x (Offset i) = f i (index x (Offset i)) {-# INLINE [1] iterMapIxContext #-}
src/Builder.hs view
@@ -10,8 +10,8 @@ {-# LANGUAGE KindSignatures #-} {-# LANGUAGE RankNTypes #-} module Builder- ( Builder, builderLength, bytes, copyBuilderToPtr, create, promote, public- , run, runRelaxed, runToBlock, secret, storable, unsafeCreate+ ( Builder, builderLength, bytes, copyBuilderToPtr, create, memo, promote+ , public, run, runRelaxed, runToBlock, secret, storable, unsafeCreate ) where import Data.ByteArray (ByteArray, ByteArrayAccess)@@ -69,6 +69,9 @@ empty :: Builder marking empty = Builder 0 $ \_ -> return ()++memo :: Classified marking => Builder marking -> Builder marking+memo = bytes . run public :: ByteArrayAccess ba => ba -> Builder marking public b = unsafeCreate (B.length b) (B.copyByteArrayToPtr b)
src/Crypto.hs view
@@ -23,7 +23,7 @@ import Crypto.Hash.Algorithms import Crypto.Hash.IO -import Control.Exception (assert, mask_)+import Control.Exception (assert, finally) import Control.Monad.ST import Data.ByteArray (ByteArrayAccess, Bytes, MemView(..), ScrubbedBytes)@@ -108,17 +108,21 @@ constEqW a b | Block.length a /= Block.length b = falseW | otherwise = Block.foldZipWith (\mask x y -> mask `andW` eqW x y) trueW a b+ {-# NOINLINE constEqW #-} instance ConstEqW (ScrubbedBlock Word) where constEqW a b | ScrubbedBlock.length a /= ScrubbedBlock.length b = falseW | otherwise = ScrubbedBlock.foldZipWith (\mask x y -> mask `andW` eqW x y) trueW a b+ {-# NOINLINE constEqW #-} instance ConstEqW Bytes where constEqW = bytesConstEqW+ {-# NOINLINE constEqW #-} instance ConstEqW ScrubbedBytes where constEqW = bytesConstEqW+ {-# NOINLINE constEqW #-} bytesConstEqW :: (ByteArrayAccess bs1, ByteArrayAccess bs2) => bs1 -> bs2 -> BoolW bytesConstEqW a b@@ -196,11 +200,10 @@ hashWith :: forall marking a ba. (HashAlgorithm a, ByteArrayAccess ba) => a -> ba -> Builder marking hashWith a ba = Builder.unsafeCreate (hashDigestSize a) $ \dig ->- hashMutableInit >>= \ctx -> mask_ $ do+ withScrubbedContext a $ \ctx -> do hashUpdateChunked (ctx :: MutableContext a) ba- B.withByteArray ctx $ \pctx -> do+ B.withByteArray ctx $ \pctx -> hashInternalFinalize (castPtr pctx :: Ptr (Context a)) dig- fillBytes pctx 0 (B.length ctx) hashUpdateChunked :: (HashAlgorithm a, ByteArrayAccess ba) => MutableContext a -> ba -> IO () hashUpdateChunked ctx ba = B.withByteArray ba $ goChunked (B.length ba)@@ -212,3 +215,10 @@ hashMutableUpdate ctx (MemView p chunkSize) goChunked (remaining - chunkSize) (p `plusPtr` chunkSize) | otherwise = hashMutableUpdate ctx (MemView p remaining)++withScrubbedContext :: HashAlgorithm a => a -> (MutableContext a -> IO b) -> IO b+withScrubbedContext _ f =+ hashMutableInit >>= \ctx -> f ctx `finally` eraseBytes ctx++eraseBytes :: ByteArrayAccess ba => ba -> IO ()+eraseBytes ctx = B.withByteArray ctx $ \p -> fillBytes p 0 (B.length ctx)
src/Crypto/PubKey/ML_DSA.hs view
@@ -27,20 +27,24 @@ -- ** Pre-hash version -- -- | This version of ML-DSA can be used to sign or verify a message that is- -- hashed externally. Typical use case is when the message is too large to- -- fit into memory, as pre-hashing can be performed through an incremental- -- API.+ -- hashed externally. -- -- Note that signatures produced by HashML-DSA are incompatible with the -- "pure" version above. So both signing and verification must use the same -- version of ML-DSA. Keys can use either version indistinctly but it is -- advised to restrict them to one version only to avoid ambiguity.+ --+ -- Compared to the "pure" version, HashML-DSA offers resistance against+ -- collision attacks that is slightly reduced due to message hashing being+ -- separete and not mixed directly with the public key as a single step. , PreHashAlgorithm, signDigest, signDigestWith, verifyDigest -- ** External µ version --- -- | An internal signing and verfication API that operates on a message- -- representative µ. For testing purpose only.+ -- | Signing and verfication API that operates on a message representative+ -- µ. This is a low-level API that enables external and incremental hashing+ -- for the "pure" version, or even alternate constructions. But it may also+ -- lessen security properties of ML-DSA if not used correctly. , Mu, externalMu, signExternalMu, signExternalMuWith, verifyExternalMu -- ** Internal version@@ -63,12 +67,12 @@ import Data.ByteArray (ByteArrayAccess, Bytes, ScrubbedBytes) import qualified Data.ByteArray as B-import qualified Data.Memory.Endian as B import Data.Word import Builder import Internal+import qualified Endian as B -- | ML-DSA-44 (security category 2) data ML_DSA_44 = ML_DSA_44 deriving Show
+ src/Endian.hs view
@@ -0,0 +1,58 @@+-- |+-- Module : Endian+-- License : BSD-3-Clause+-- Copyright : (c) 2026 Olivier Chéron+--+-- Endianness utilities+--+{-# LANGUAGE CPP #-}+module Endian+ ( B.BE, ByteSwap, B.LE, fromLE, toBE, toLE+ ) where++#include "MachDeps.h"++-- Little-endian conversion in `memory` / `ram` is avoided at compile+-- time only for AMD/Intel, here we will short circuit on ARM too+#if (defined(arm_HOST_ARCH) || defined(aarch64_HOST_ARCH)) \+ && !defined(WORDS_BIGENDIAN)+#define MLDSA_FORCE_LITTLE_ENDIAN_ARCH 1+#endif++#ifdef MLDSA_FORCE_LITTLE_ENDIAN_ARCH+import Data.Word+#else+import Data.Memory.Endian (ByteSwap)+#endif++import qualified Data.Memory.Endian as B++#ifdef MLDSA_FORCE_LITTLE_ENDIAN_ARCH+class ByteSwap a where+ byteSwap :: a -> a+instance ByteSwap Word16 where+ byteSwap = byteSwap16+#endif++#ifdef MLDSA_FORCE_LITTLE_ENDIAN_ARCH+fromLE :: B.LE a -> a+fromLE = B.unLE -- unwrap constructor with no byte swapping+#else+fromLE :: ByteSwap a => B.LE a -> a+fromLE = B.fromLE -- byte swap if necessary+#endif++#ifdef MLDSA_FORCE_LITTLE_ENDIAN_ARCH+toLE :: a -> B.LE a+toLE = B.LE -- wrap constructor with no byte swapping+#else+toLE :: ByteSwap a => a -> B.LE a+toLE = B.toLE -- byte swap if necessary+#endif++toBE :: ByteSwap a => a -> B.BE a+#ifdef MLDSA_FORCE_LITTLE_ENDIAN_ARCH+toBE = B.BE . byteSwap -- always byte swap+#else+toBE = B.toBE -- byte swap if necessary+#endif
src/Fusion.hs view
@@ -51,10 +51,10 @@ thawContext :: Fusion a => a -> Context a thawContext a = Context $ thawF a-{-# INLINE [0] thawContext #-}+{-# INLINE CONLIKE [0] thawContext #-} modifyContext :: (forall s. Mut a s -> ST s ()) -> Context a -> Context a-modifyContext f = bindContext $ \ma -> f ma >> return ma+modifyContext f = bindContext $ \ma -> ma <$ f ma mapContext :: MapF a b -> Context a -> Context b mapContext m = bindContext (mapUpdate m)
src/Internal.hs view
@@ -23,7 +23,6 @@ import Data.ByteArray (ByteArray, ByteArrayAccess, Bytes, ScrubbedBytes) import qualified Data.ByteArray as B-import qualified Data.Memory.Endian as B import Data.Bits import Data.Proxy@@ -39,6 +38,7 @@ import Math import Vector (Vector) import qualified Auxiliary as Aux+import qualified Endian as B import qualified Matrix import qualified Vector @@ -83,7 +83,6 @@ data PrivateKey a = PrivateKey { skPub :: {-# UNPACK #-} !(PublicKey a) , skK :: {-# UNPACK #-} !ScrubbedBytes- , skTr :: {-# UNPACK #-} !Bytes , skE1 :: {-# UNPACK #-} !ScrubbedBytes -- serialized s1 & s2 , skE2 :: {-# UNPACK #-} !Bytes -- serialized t0 , skS1 :: Vector (L a) (Tq Sec)@@ -94,6 +93,9 @@ skRho :: PrivateKey a -> Bytes skRho = pkRho . skPub +skTr :: PrivateKey a -> Bytes+skTr = pkTr . skPub+ skT1 :: PrivateKey a -> Vector (K a) (Tq Pub) skT1 = pkT1 . skPub @@ -104,6 +106,7 @@ data PublicKey a = PublicKey { pkRho :: {-# UNPACK #-} !Bytes , pkE :: {-# UNPACK #-} !Bytes -- serialized t1+ , pkTr :: Bytes -- public-key hash , pkT1 :: Vector (K a) (Tq Pub) , pkA :: Vector (K a) (Vector (L a) (Tq Pub)) }@@ -160,7 +163,7 @@ instance NFData (PublicKey a) where rnf pk = rnf (pkRho pk) `seq` rnf (pkE pk)- -- pkT1, pkA omitted because just for caching+ -- pkTr, pkT1, pkA omitted because just for caching instance NFData (Signature a) where rnf sig = rnf (sigCt sig) `seq`@@ -181,9 +184,10 @@ guard (B.length input == 32 + 320 * k) let rho = B.convert $ B.takeView input 32 pe = B.convert $ B.dropView input 32+ tr = Builder.run $ Crypto.h64 (Builder.run $ Builder.public input) t1 = Vector.create $ \i -> Aux.simpleBitUnpack10 (view320 i) aa = expandA rho- Just PublicKey { pkRho = rho, pkE = pe, pkT1 = Aux.ntt <$> t1, pkA = aa }+ Just PublicKey { pkRho = rho, pkE = pe, pkTr = tr, pkT1 = Aux.ntt <$> t1, pkA = aa } where params = getParams p k = kdim params@@ -218,9 +222,9 @@ ss2 = Aux.ntt <$> s2 t = Aux.nttInv <$> Matrix.mmulAdd aa ss1 ss2 (t1, t0) = Vector.unzipWith Aux.powerTwoRound t- pk = PublicKey { pkRho = rho, pkE = pe, pkT1 = Aux.ntt <$> t1, pkA = aa }+ pk = PublicKey { pkRho = rho, pkE = pe, pkTr = tr, pkT1 = Aux.ntt <$> t1, pkA = aa } tr = Builder.run $ Crypto.h64 (encode pk :: Bytes)- sk = PrivateKey { skPub = pk, skK = kk, skTr = tr, skE1 = e1, skE2 = e2, skS1 = ss1, skS2 = ss2, skT0 = Aux.ntt <$> t0 }+ sk = PrivateKey { skPub = pk, skK = kk, skE1 = e1, skE2 = e2, skS1 = ss1, skS2 = ss2, skT0 = Aux.ntt <$> t0 } pe = Builder.run $ Vector.concatMap Aux.simpleBitPack10 t1 guard $ Crypto.toBool $ Crypto.constEqW t0 t0' `Crypto.andW` Crypto.constEqW tr tr'@@ -275,9 +279,9 @@ ss2 = Aux.ntt <$> s2 t = Aux.nttInv <$> Matrix.mmulAdd aa ss1 ss2 (t1, t0) = Vector.unzipWith Aux.powerTwoRound t- pk = PublicKey { pkRho = rho, pkE = pe, pkT1 = Aux.ntt <$> t1, pkA = aa }+ pk = PublicKey { pkRho = rho, pkE = pe, pkTr = tr, pkT1 = Aux.ntt <$> t1, pkA = aa } tr = Builder.run $ Crypto.h64 (encode pk :: Bytes)- sk = PrivateKey { skPub = pk, skK = kk, skTr = tr, skE1 = e1, skE2 = e2, skS1 = ss1, skS2 = ss2, skT0 = Aux.ntt <$> t0 }+ sk = PrivateKey { skPub = pk, skK = kk, skE1 = e1, skE2 = e2, skS1 = ss1, skS2 = ss2, skT0 = Aux.ntt <$> t0 } pe = Builder.run $ Vector.concatMap Aux.simpleBitPack10 t1 e1 = Builder.run $ Vector.concatMap (Aux.bitPack (fromIntegral eta) twoEtaBits) s1 <>@@ -293,12 +297,12 @@ sigGen sk m' = sigGenMu sk mu where tr = Builder.bytes (skTr sk)- mu = Crypto.h64 (Builder.run $ Builder.promote tr <> Builder.secret m')+ mu = Builder.memo $ Crypto.h64 (Builder.run $ Builder.promote tr <> Builder.secret m') sigGenMu :: (ParamSet a, ByteArrayAccess rnd) => PrivateKey a -> Builder Sec -> rnd -> Signature a sigGenMu sk mu rnd = loop 0 where- rhos = Crypto.h64 (Builder.run $ Builder.bytes (skK sk) <> Builder.secret rnd <> mu)+ rhos = Builder.memo $ Crypto.h64 (Builder.run $ Builder.bytes (skK sk) <> Builder.secret rnd <> mu) loop kappa | Crypto.toBool cn1 && Crypto.toBool cn2 =@@ -338,7 +342,7 @@ sigVer :: (ParamSet a, ByteArrayAccess m) => PublicKey a -> m -> Signature a -> Bool sigVer pk m' = sigVerMu pk mu where- tr = Crypto.h64 (encode pk :: Bytes)+ tr = Builder.bytes (pkTr pk) mu = Crypto.h64 (Builder.run $ Builder.promote tr <> Builder.secret m') sigVerMu :: ParamSet a => PublicKey a -> Builder Sec -> Signature a -> Bool
src/Machine.hs view
@@ -22,19 +22,12 @@ || defined(powerpc64le_HOST_ARCH) #define MLDSA_ALLOW_UNALIGNED_OP 1 --- Little-endian conversion in `memory` / `ram` is avoided at compile--- time only for AMD/Intel, here we will short circuit on ARM too-#if (defined(arm_HOST_ARCH) || defined(aarch64_HOST_ARCH)) \- && !defined(WORDS_BIGENDIAN)-#define MLDSA_FORCE_LITTLE_ENDIAN_ARCH 1 #endif -#endif- import Control.Exception (assert) #ifdef MLDSA_ALLOW_UNALIGNED_OP-import qualified Data.Memory.Endian as B+import qualified Endian as B #endif import Data.Bits@@ -52,18 +45,10 @@ type WordLE = B.LE WordM fromLE :: WordLE -> WordM-#ifdef MLDSA_FORCE_LITTLE_ENDIAN_ARCH-fromLE = B.unLE -- unwrap constructor with no byte swapping-#else-fromLE = B.fromLE -- byte swap if necessary-#endif+fromLE = B.fromLE toLE :: WordM -> WordLE-#ifdef MLDSA_FORCE_LITTLE_ENDIAN_ARCH-toLE = B.LE -- wrap constructor with no byte swapping-#else-toLE = B.toLE -- byte swap if necessary-#endif+toLE = B.toLE #else
src/ScrubbedBlock.hs view
@@ -72,7 +72,7 @@ checkPinned b = assertPinned b (ScrubbedBlock b) scrubbed :: PrimMonad prim => MutableBlock ty (PrimState prim) -> prim (MutableBlock ty (PrimState prim))-scrubbed b = unsafePrimFromIO (scheduleBlockScrubbing b >> return b)+scrubbed b = unsafePrimFromIO (b <$ scheduleBlockScrubbing b) wakeUpAfterInception :: MutableBlock ty s -> MutableBlock ty RealWorld wakeUpAfterInception = unsafeCoerce -- sometimes disappointing
tests/get-vectors.sh view
@@ -2,7 +2,7 @@ DESTDIR="`dirname "$0"`" -REF=commit/79e78ba49d1605baaf9acdbf475304af6ae36a59+REF=commit/5eb1feba427e657ea260113558604e628185e2ba CURL=curl for KEY in keyGen sigGen sigVer; do