module VectorPedersen (
dot,
mkGs,
scalarGenerateN,
ecCommit,
ecOpen,
ecVerifyAddCommitments,
vecSum,
ecAddVector,
ecVerifyAddVector,
ECReveal(..),
ECPedersen(..),
ECCommitParams(..),
ECCommitment(..)
) where
import Protolude hiding (hash)
import Crypto.Hash
import Crypto.Number.Serialize (os2ip)
import qualified Crypto.PubKey.ECC.Prim as ECC
import qualified Crypto.PubKey.ECC.Types as ECC
import Crypto.Random.Types (MonadRandom(..))
import qualified Data.ByteArray as BA
import Data.Monoid ((<>))
import Pedersen (
ecSetup,
ECCommitParams(..),
ECCommitment(..)
)
data ECReveal = ECReveal
{ ecRevealVal :: [Integer]
, ecRevealScalar :: Integer
}
data ECPedersen = ECPedersen
{ ecCommitment :: ECCommitment
, ecReveal :: ECReveal
}
oracle :: ECC.Curve -> ByteString -> Integer
oracle curve x = os2ip (sha256 x) `mod` n
where
n :: Integer
n = ECC.ecc_n $ ECC.common_curve curve
sha256 :: ByteString -> ByteString
sha256 bs = BA.convert (hash bs :: Digest SHA3_256)
scalarGenerateN :: MonadRandom m => ECC.Curve -> Word8 -> m [Integer]
scalarGenerateN curve n = scalarGenerateN' curve n []
scalarGenerateN' :: MonadRandom m => ECC.Curve -> Word8 -> [Integer] -> m [Integer]
scalarGenerateN' curve n v
| n == 0 = return v
| otherwise = do
vi <- ECC.scalarGenerate curve
if vi `elem` v
then scalarGenerateN' curve n v
else scalarGenerateN' curve (n-1) (vi:v)
dot :: ECC.Curve -> [Integer] -> [ECC.Point] -> ECC.Point
dot curve scalars points = foldl' (ECC.pointAdd curve) ECC.PointO $
zipWith (ECC.pointMul curve) scalars points
appendCoordinates :: ECC.Point -> ByteString
appendCoordinates ECC.PointO = ""
appendCoordinates (ECC.Point x y) = show x <> show y
mkGs :: ECC.Curve -> [ECC.Point]
mkGs curve =
fmap (ECC.pointBaseMul curve . oracle curve . (<> appendCoordinates g) . show) [1..]
where
g = ECC.ecc_g $ ECC.common_curve curve
ecCommit :: MonadRandom m => [Integer] -> ECCommitParams -> m ECPedersen
ecCommit v (ECCommitParams curve h) = do
r <- ECC.scalarGenerate curve
let vG = dot curve v (mkGs curve)
let rH = ECC.pointMul curve r h
let commitment = ECCommitment $ ECC.pointAdd curve vG rH
let reveal = ECReveal v r
return $ ECPedersen commitment reveal
ecOpen :: ECCommitParams -> ECCommitment -> ECReveal -> Bool
ecOpen (ECCommitParams curve h) (ECCommitment c) (ECReveal v r) =
c == ECC.pointAdd curve vG rH
where
vG = dot curve v (mkGs curve)
rH = ECC.pointMul curve r h
vecSum :: ECC.Curve -> [Integer] -> [Integer] -> [Integer]
vecSum curve = zipWith (\a b -> a + b `mod` n)
where
n :: Integer
n = ECC.ecc_n $ ECC.common_curve curve
ecVerifyAddCommitments
:: ECCommitParams
-> ECPedersen
-> ECPedersen
-> ECPedersen
ecVerifyAddCommitments (ECCommitParams curve h) p1 p2 =
ECPedersen newCommitment newReveal
where
ECReveal v r1 = ecReveal p1
ECReveal w r2 = ecReveal p2
vw = vecSum curve v w
r = r1 + r2
vwG = dot curve vw (mkGs curve)
rH = ECC.pointMul curve r h
newCommitment = ECCommitment $ ECC.pointAdd curve vwG rH
newReveal = ECReveal vw r
ecAddVector :: ECCommitParams -> ECCommitment -> [Integer] -> ECCommitment
ecAddVector (ECCommitParams curve h) (ECCommitment c) w =
ECCommitment $ ECC.pointAdd curve wG c
where
wG = dot curve w (mkGs curve)
ecVerifyAddVector :: ECCommitParams -> ECPedersen -> [Integer] -> ECPedersen
ecVerifyAddVector (ECCommitParams curve h) p w =
ECPedersen newCommitment newReveal
where
ECReveal v r = ecReveal p
vw = vecSum curve v w
vwG = dot curve vw (mkGs curve)
rH = ECC.pointMul curve r h
newCommitment = ECCommitment $ ECC.pointAdd curve vwG rH
newReveal = ECReveal vw r