Double-scalar multiplication using Shamir's trick

This commit is contained in:
Olivier Chéron 2016-08-27 08:42:03 +02:00
parent 8908af3216
commit 43233cb911
3 changed files with 47 additions and 5 deletions

View File

@ -102,10 +102,7 @@ verify hashAlg pk@(PublicKey curve q) (Signature r s) msg
let z = tHash hashAlg msg n
u1 = z * w `mod` n
u2 = r * w `mod` n
-- TODO: Use Shamir's trick
g' = pointMul curve u1 g
q' = pointMul curve u2 q
x = pointAdd curve g' q'
x = pointAddTwoMuls curve u1 g u2 q
case x of
PointO -> Nothing
Point x1 _ -> return $ x1 `mod` n

View File

@ -7,6 +7,7 @@ module Crypto.PubKey.ECC.Prim
, pointDouble
, pointBaseMul
, pointMul
, pointAddTwoMuls
, isPointAtInfinity
, isPointValid
) where
@ -108,6 +109,33 @@ pointMul c n p
| odd n = pointAdd c p (pointMul c (n - 1) p)
| otherwise = pointMul c (n `div` 2) (pointDouble c p)
-- | Elliptic curve double-scalar multiplication (uses Shamir's trick).
--
-- > pointAddTwoMuls c n1 p1 n2 p2 == pointAdd c (pointMul c n1 p1)
-- > (pointMul c n2 p2)
--
-- /WARNING:/ Vulnerable to timing attacks.
pointAddTwoMuls :: Curve -> Integer -> Point -> Integer -> Point -> Point
pointAddTwoMuls _ _ PointO _ PointO = PointO
pointAddTwoMuls c _ PointO n2 p2 = pointMul c n2 p2
pointAddTwoMuls c n1 p1 _ PointO = pointMul c n1 p1
pointAddTwoMuls c n1 p1 n2 p2
| n1 < 0 = pointAddTwoMuls c (-n1) (pointNegate c p1) n2 p2
| n2 < 0 = pointAddTwoMuls c n1 p1 (-n2) (pointNegate c p2)
| otherwise = go (n1, n2)
where
p0 = pointAdd c p1 p2
go (0, 0 ) = PointO
go (k1, k2) =
let q = pointDouble c $ go (k1 `div` 2, k2 `div` 2)
in case (odd k1, odd k2) of
(True , True ) -> pointAdd c p0 q
(True , False ) -> pointAdd c p1 q
(False , True ) -> pointAdd c p2 q
(False , False ) -> q
-- | Check if a point is the point at infinity.
isPointAtInfinity :: Point -> Bool
isPointAtInfinity PointO = True

View File

@ -138,10 +138,16 @@ vectorsPoint =
doPointValidTest (i, vector) = testCase (show i) (valid vector @=? ECC.isPointValid (curve vector) (ECC.Point (x vector) (y vector)))
arbitraryPoint :: ECC.Curve -> Gen ECC.Point
arbitraryPoint aCurve =
frequency [(5, return ECC.PointO), (95, pointGen)]
where
n = ECC.ecc_n (ECC.common_curve aCurve)
pointGen = ECC.pointBaseMul aCurve <$> choose (1, n - 1)
eccTests = testGroup "ECC"
[ testGroup "valid-point" $ map doPointValidTest (zip [katZero..] vectorsPoint)
, testGroup "property" $
, testGroup "property"
[ testProperty "point-add" $ \aCurve (QAInteger r1) (QAInteger r2) ->
let curveN = ECC.ecc_n . ECC.common_curve $ aCurve
curveGen = ECC.ecc_g . ECC.common_curve $ aCurve
@ -149,6 +155,17 @@ eccTests = testGroup "ECC"
p2 = ECC.pointMul aCurve r2 curveGen
pR = ECC.pointMul aCurve ((r1 + r2) `mod` curveN) curveGen
in pR `propertyEq` ECC.pointAdd aCurve p1 p2
, testProperty "point-mul-mul" $ \aCurve (QAInteger n1) (QAInteger n2) -> do
p <- arbitraryPoint aCurve
let pRes = ECC.pointMul aCurve (n1 * n2) p
let pDef = ECC.pointMul aCurve n1 (ECC.pointMul aCurve n2 p)
return $ pRes `propertyEq` pDef
, testProperty "double-scalar-mult" $ \aCurve (QAInteger n1) (QAInteger n2) -> do
p1 <- arbitraryPoint aCurve
p2 <- arbitraryPoint aCurve
let pRes = ECC.pointAddTwoMuls aCurve n1 p1 n2 p2
let pDef = ECC.pointAdd aCurve (ECC.pointMul aCurve n1 p1) (ECC.pointMul aCurve n2 p2)
return $ pRes `propertyEq` pDef
]
]