1 module Voting.Protocol.Cryptography where
4 import Control.Applicative (pure)
5 import Control.Monad (bind)
6 import Data.Argonaut.Core as JSON
7 import Data.Argonaut.Decode (class DecodeJson, decodeJson)
8 import Data.Argonaut.Encode (class EncodeJson, encodeJson)
9 import Data.Argonaut.Parser as JSON
10 import Data.BigInt (BigInt)
11 import Data.BigInt as BigInt
12 import Data.Boolean (otherwise)
13 import Data.Bounded (class Bounded, top)
14 import Data.Either (Either(..))
15 import Data.Eq (class Eq, (==), (/=))
16 import Data.EuclideanRing (class EuclideanRing, (/), mod)
17 import Data.Foldable (intercalate)
18 import Data.Function (($), identity, (<<<), flip)
19 import Data.Functor ((<$>))
20 import Data.HeytingAlgebra ((&&))
21 import Data.List (List, (:))
22 import Data.Maybe (Maybe(..), maybe, fromJust)
23 import Data.Monoid (class Monoid, mempty, (<>))
24 import Data.Newtype (class Newtype, wrap, unwrap)
25 import Data.Ord (class Ord, (>=))
26 import Data.Reflection (class Reifies, reflect)
27 import Data.Ring (class Ring, (-), negate)
28 import Data.Semiring (class Semiring, zero, (+), one, (*))
29 import Data.Show (class Show, show)
30 import Data.String.CodeUnits as String
31 import Node.Crypto as Crypto
32 import Node.Crypto.Hash as Crypto
33 import Effect.Random (randomInt)
34 import Partial.Unsafe (unsafePartial)
35 import Type.Proxy (Proxy(..))
37 import Voting.Protocol.Arithmetic
40 newtype Hash crypto c = Hash (E crypto c)
41 derive newtype instance eqHash :: Eq (Hash crypto c)
42 derive newtype instance ordHash :: Ord (Hash crypto c)
43 derive newtype instance showHash :: Show (Hash crypto c)
46 -- | @('hash' bs gs)@ returns as a number in 'G'
47 -- the 'Crypto.SHA256' hash of the given 'BS.ByteString' 'bs'
48 -- prefixing the decimal representation of given subgroup elements 'gs',
49 -- with a comma (",") intercalated between them.
51 -- NOTE: to avoid any collision when the 'hash' function is used in different contexts,
52 -- a message 'gs' is actually prefixed by a 'bs' indicating the context.
54 -- Used by 'proveEncryption' and 'verifyEncryption',
55 -- where the 'bs' usually contains the 'statement' to be proven,
56 -- and the 'gs' contains the 'commitments'.
60 CryptoParams crypto c =>
61 String -> List (G crypto c) ->
64 let s = bs <> intercalate "," (bytesNat <$> gs)
65 h <- Crypto.hex Crypto.SHA256 s
66 pure $ fromNatural $ Natural $
67 unsafePartial $ fromJust $
70 -- | `('bytesNat' x)` returns the serialization of `x`.
71 bytesNat :: forall n. ToNatural n => n -> String
72 bytesNat = show <<< nat
74 -- | `'randomBigInt' low high` returns a random 'BigInt' within `low` and `high`.
76 -- NOTE: adapted from GHC's 'randomIvalInteger'
77 randomBigInt :: BigInt -> BigInt -> Effect BigInt
85 b = BigInt.fromInt srcHigh - BigInt.fromInt srcLow + one
88 -- Probabilities of the most likely and least likely result
89 -- will differ at most by a factor of (1 +- 1/q).
90 -- Assuming the 'random' is uniform, of course.
91 -- On average, log q / log b more random values will be generated
93 q = BigInt.fromInt 1000
94 targetMagnitude = k * q
95 -- generate random values until we exceed the target magnitude
97 | mag >= targetMagnitude = pure acc
99 r <- randomInt srcLow srcHigh
101 (acc * b + (BigInt.fromInt r - BigInt.fromInt srcLow))
105 CryptoParams crypto c =>
107 randomE = E <<< Natural <$> randomBigInt zero (unwrap (nat (top::E crypto c)))