This module contains functions which let us generate random values.
module Random
(
randomBytes, randomBytesR
, randomResidue
, randomPrimeR
, randomWECPoint
, randomGF
) where
import Bytes ( Bytes, convBytes )
import EllipticCurve ( WECParameters(..), WECPoint, mkWECPoint )
import GCM ( GF )
import Math ( modSqrt )
import qualified Data.ByteString as B
import qualified Control.Monad.Random as R
import Math.NumberTheory.Primes.Testing ( isPrime )
randomBytes
produces a sequence of the given number of random Byte
s.
randomBytes :: R.MonadRandom m => Int -> m Bytes
randomBytes len = B.pack <$> R.replicateM len R.getRandom
randomBytesR
produces a random number of random Byte
s.
Its argument is the lower and upper bound on the number of Byte
s to produce.
randomBytesR :: R.MonadRandom m => (Int,Int) -> m Bytes
randomBytesR bounds = R.getRandomR bounds >>= randomBytes
randomResidue
produces a random element of the
finite field of the given size.
For usability as a key, we exclude 0, 1, and p-1.
randomResidue :: R.MonadRandom m => Integer -> m Integer
randomResidue p = R.getRandomR (2,p-2)
randomPrimeR
produces a prime number within the given bounds.
It generates a random integer, then tests its primality
using isPrime
from the
arithmoi package.
randomPrimeR :: R.MonadRandom m => (Integer,Integer) -> m Integer
randomPrimeR bounds = do
n <- R.getRandomR bounds
if isPrime n
then pure n
else randomPrimeR bounds
randomWECPoint
produces a random point on the elliptic curve
with the given Weierstrass-form parameters.
randomWECPoint :: R.MonadRandom m => WECParameters -> m WECPoint
randomWECPoint params@WECParameters{wecA=a, wecB=b, wecP=p} = do
x
can potentially take any value in the prime field.
x <- randomResidue p
We can then compute y^2 from the elliptic curve equation.
let x2 = (x*x) `rem` p
y2 = ((x2 + a)*x + b) `rem` p
Unfortunately, this value might not have a square root. If not, then we have to pick another x and try again.
case modSqrt p y2 of
Nothing -> randomWECPoint params
If there is a square root y, the point could be either (x,y) or (x,-y); we randomly determine which and return.
Just y -> do
neg <- R.getRandom
pure $ mkWECPoint params x $ if neg then (-y) else y
randomGF
creates a random element of GF(2^128);
this is just sixteen random bytes, converted into GF
.
randomGF :: R.MonadRandom m => m GF
randomGF = convBytes <$> randomBytes 16