packages feed

Dust-crypto (empty) → 0.1

raw patch · 12 files changed

+1704/−0 lines, 12 filesdep +Dustdep +HUnitdep +QuickChecksetup-changed

Dependencies added: Dust, HUnit, QuickCheck, base, binary, bytestring, cereal, containers, crypto-api, cryptohash, directory, entropy, ghc-prim, network, random, random-extras, random-fu, random-source, skein, split, test-framework, test-framework-hunit, test-framework-quickcheck2, threefish

Files

+ Dust-crypto.cabal view
@@ -0,0 +1,74 @@+Name:                Dust-crypto+Version:             0.1+Description:         Cryptographic operations used by the Dust polymorphic protocl engine+Synopsis:            Cryptographic operations+Category:            Cryptography+License:             GPL+License-file:        LICENSE+Author:              Brandon Wiley+Maintainer:          brandon@ischool.utexas.edu+Build-Type:          Simple+Cabal-Version:       >=1.8++Library+  Build-Depends:+    base >= 4.6.0.1 && < 5,+    bytestring,+    entropy,+    network,+    cereal,+    ghc-prim,+    binary,+    random,+    random-extras,+    random-source,+    random-fu,+    containers,+    directory,+    split,+    skein,+    crypto-api,+    cryptohash,+    threefish+  Extensions:+    ForeignFunctionInterface++  Exposed-modules:+      Dust.Crypto.Keys,+      Dust.Crypto.ECDSA,+      Dust.Crypto.ECDH,+      Dust.Crypto.DustCipher++--  if os(windows)+--    build-depends: Win32+--    C-sources: lib/curve25519-donna.c, lib/ed25519-donna/ed25519.c+--    extra-lib-dirs=C:\OpenSSL-Win64 /OpenSSL-Win64 C:\OpenSSL-Win64\lib C:\OpenSSL-Win64\bin+--    extra-libraries: ssleay32 eay32++  if os(linux) || os(darwin)+    C-sources: lib/curve25519-donna.c, lib/ed25519-donna/ed25519.c+    Include-Dirs: lib+    extra-libraries: crypto+    Exposed-modules:+      Dust.Crypto.Curve25519+      Dust.Crypto.Ed25519++test-suite crypto+  type: exitcode-stdio-1.0+  main-is: TestCrypto.hs+  ghc-options: -w -threaded -rtsopts -with-rtsopts=-N+  hs-source-dirs: tests++  build-depends:+    base,+    Dust,+    HUnit >= 1.2,+    test-framework       >= 0.6,+    test-framework-hunit >= 0.2,+    test-framework-quickcheck2,+--    test-framework-th,+    bytestring,+    threefish,+    cereal,+    ghc-prim,+    QuickCheck
+ Dust/Crypto/Curve25519.hs view
@@ -0,0 +1,39 @@+{-# CFILES lib/curve25519-donna.c #-}+{-# LANGUAGE ForeignFunctionInterface #-}++module Dust.Crypto.Curve25519 (curve25519) where++import Data.ByteString (ByteString)+import qualified Data.ByteString as B+import Data.ByteString.Unsafe (unsafeUseAsCString)+import Foreign.C.String (CString)++import Foreign.Marshal.Unsafe (unsafeLocalState)++curve25519 :: ByteString -> ByteString -> ByteString+curve25519 bs1 bs2 = curve+	where+	Just curve = unsafeLocalState $ unsafe_curve25519 bs1 bs2++unsafe_curve25519 :: ByteString -> ByteString -> IO (Maybe ByteString)+unsafe_curve25519 secret basepoint+    | B.length secret >= 32 && B.length basepoint >= 32 =+        -- This ByteString will be overwritten by the C call, but so long as+        -- the C side does not keep a reference to it afterward, it does what we+        -- expect and saves us a copy+        unsafeUseAsCString outBS $ \output ->+            B.useAsCString secret $ \csecret ->+                B.useAsCString basepoint $ \cbasepoint -> do+                    result <- c_curve25519_donna output csecret cbasepoint+                    case result of+                        0 -> return $ Just outBS+                        _ -> return Nothing+    | otherwise = return Nothing+    where+    outBS = B.replicate 32 0xAB++-- Should be Ptr Word8 (not CString), but this should be safe if we just+-- use them as bytes++foreign import ccall unsafe "curve25519_donna" c_curve25519_donna ::+    CString -> CString -> CString -> IO Int
+ Dust/Crypto/DustCipher.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE DeriveGeneric, DefaultSignatures #-} -- For automatic generation of cereal put and get++module Dust.Crypto.DustCipher+(+  EncryptionKey(..),+  IV(..),+  Plaintext(..),+  Ciphertext(..),++  encrypt,+  decrypt,+  createIV+) where++import GHC.Generics+import Data.ByteString+import Data.Serialize+import Data.ByteString.Lazy (toChunks, fromChunks, toStrict)+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as BL+import Crypto.Threefish+import Crypto.Threefish.Random+import qualified Crypto.Threefish.Skein.StreamCipher as SSC++import Dust.Crypto.Keys++data EncryptionKey = EncryptionKey ByteString deriving (Show, Eq)+newtype IV = IV ByteString deriving (Show, Eq, Generic)+newtype Plaintext = Plaintext ByteString deriving (Show, Eq, Generic)+newtype Ciphertext = Ciphertext ByteString deriving (Show, Eq, Generic)++instance Serialize IV+instance Serialize Plaintext+instance Serialize Ciphertext++encrypt :: EncryptionKey -> IV -> Plaintext -> Ciphertext+encrypt (EncryptionKey keyBytes) (IV ivBytes) (Plaintext plaintext) =+  let lazy = fromChunks [plaintext]+      maybeKey = toBlock keyBytes+      maybeIv = toBlock ivBytes+  in case (maybeKey, maybeIv) of+    (Just key, Just iv) -> Ciphertext $ toStrict $ SSC.encrypt key iv lazy+    otherwise           -> Ciphertext B.empty++decrypt :: EncryptionKey -> IV -> Ciphertext -> Plaintext+decrypt (EncryptionKey keyBytes) (IV ivBytes) (Ciphertext ciphertext) =+  let lazy = fromChunks [ciphertext]+      maybeKey = toBlock keyBytes+      maybeIv = toBlock ivBytes+  in case (maybeKey, maybeIv) of+    (Just key, Just iv) -> Plaintext $ toStrict $ SSC.decrypt key iv lazy+    otherwise           -> Plaintext B.empty++createIV :: SkeinGen -> (IV, SkeinGen)+createIV rand =+    let (ivBytes, rand') = randomBytes 32 rand+    in (IV ivBytes, rand')
+ Dust/Crypto/ECDH.hs view
@@ -0,0 +1,47 @@+module Dust.Crypto.ECDH+(+  splitSecret,+  createPrivate,+  createPublic,+  createKeypair,+  createShared,+  createEphemeral+) where++import Data.ByteString as B+import Data.Word+import Data.Bits+import Crypto.Threefish.Random++import Dust.Crypto.Keys+import Dust.Crypto.DustCipher+import Dust.Crypto.Curve25519++createEphemeral :: SkeinGen -> (Keypair, SkeinGen)+createEphemeral rand =+    let (bytes, rand') = randomBytes 32 rand+    in (createKeypair bytes, rand')++splitSecret :: ByteString -> (Word8,ByteString,Word8)+splitSecret bs = let firstByte = B.head bs+                     lastByte  = B.last bs+                     middle = B.tail (B.init bs)+                 in (firstByte,middle,lastByte)++createPrivate :: ByteString -> PrivateKey+createPrivate bs = let (firstByte,middle,lastByte) = splitSecret bs+                       firstByte' = firstByte .&. 248+                       lastByte'  = (lastByte .&. 127) .|. 64+                   in PrivateKey ((firstByte' `cons` middle) `snoc` lastByte')++createPublic :: PrivateKey -> PublicKey+createPublic private = let bps = pack [9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]+                       in PublicKey (curve25519 (privateBytes private) bps)++createKeypair :: ByteString -> Keypair+createKeypair entropy = let private = createPrivate entropy+                            public = createPublic private+                        in Keypair public private++createShared :: PrivateKey -> PublicKey -> EncryptionKey+createShared private public = EncryptionKey (curve25519 (privateBytes private) (publicBytes public))
+ Dust/Crypto/ECDSA.hs view
@@ -0,0 +1,42 @@+{-# LANGUAGE DeriveGeneric, DefaultSignatures #-} -- For automatic generation of cereal put and get++module Dust.Crypto.ECDSA+(+  Signature,+  Signedtext(..),+  createPrivate,+  createPublic,+  createSigningKeypair,+  sign,+  verify+) where++import GHC.Generics (Generic)+import Data.Serialize (Serialize)+import Data.ByteString (ByteString)++import Dust.Crypto.Keys+import Dust.Crypto.Ed25519++newtype Signature = Signature { signatureBytes :: ByteString } deriving (Show, Eq, Generic)+instance Serialize Signature++data Signedtext = Signedtext PublicKey Signature ByteString deriving (Eq, Show, Generic)+instance Serialize Signedtext++createPrivate :: ByteString -> PrivateKey+createPrivate = PrivateKey++createPublic :: PrivateKey -> PublicKey+createPublic = PublicKey . ed25519_publickey . privateBytes++createSigningKeypair :: ByteString -> Keypair+createSigningKeypair entropy = Keypair (createPublic private) private+    where+    private = createPrivate entropy++sign :: ByteString -> Keypair -> Signedtext+sign msg (Keypair pubkey private) = Signedtext pubkey (Signature $ ed25519_sign msg (privateBytes private) (publicBytes pubkey)) msg++verify :: Signedtext -> Bool+verify (Signedtext pubkey signature msg) = ed25519_sign_open msg (publicBytes pubkey) (signatureBytes signature)
+ Dust/Crypto/Ed25519.hs view
@@ -0,0 +1,85 @@+{-# CFILES lib/ed25519-donna/ed25519.c #-}+{-# LANGUAGE ForeignFunctionInterface #-}++module Dust.Crypto.Ed25519+(+    ed25519_publickey,+    ed25519_sign_open,+    ed25519_sign+) where++import qualified Data.ByteString as B+import Data.ByteString (ByteString)+import Data.ByteString.Unsafe (unsafeUseAsCString)++import Foreign.C+import Foreign.Marshal.Unsafe (unsafeLocalState)++ed25519_publickey :: ByteString -> ByteString+ed25519_publickey privkey = pubkey+    where+    Just pubkey = fmap unsafeLocalState (unsafe_ed25519_publickey privkey)++ed25519_sign_open :: ByteString -> ByteString -> ByteString -> Bool+ed25519_sign_open msg pubkey signature = result+	where+	Just result = fmap unsafeLocalState $ unsafe_ed25519_sign_open msg pubkey signature++ed25519_sign :: ByteString -> ByteString -> ByteString -> ByteString+ed25519_sign msg secret pubkey = signature+	where+	Just signature = fmap unsafeLocalState $ unsafe_ed25519_sign msg secret pubkey++unsafe_ed25519_publickey :: ByteString -> Maybe (IO ByteString)+unsafe_ed25519_publickey input+    | B.length input <= 32 = Just $+        -- This ByteString will be overwritten by the C call, but so long as+        -- the C side does not keep a reference to it afterward, it does what we+        -- expect and saves us a copy+        unsafeUseAsCString outBS $ \output ->+            B.useAsCString input $ \cinput -> do+                c_ed25519_publickey cinput output+                return outBS+    | otherwise = Nothing+    where+    outBS = B.replicate 32 0xAB+    {-# NOINLINE outBS #-}++unsafe_ed25519_sign_open :: ByteString -> ByteString -> ByteString -> Maybe (IO Bool)+unsafe_ed25519_sign_open msg pubkey signature+    | B.length pubkey <= 32 && B.length signature <= 64 = Just $+        B.useAsCStringLen msg $ \(cmsg, cmsglen) ->+            B.useAsCString pubkey $ \cpubkey ->+                B.useAsCString signature $ \csignature ->+                    let result = c_ed25519_sign_open cmsg (fromIntegral cmsglen) cpubkey csignature in+                        return (result == 0)+    | otherwise = Nothing++unsafe_ed25519_sign :: ByteString -> ByteString -> ByteString -> Maybe (IO ByteString)+unsafe_ed25519_sign msg secret pubkey+    | B.length secret <= 32 && B.length pubkey <= 32 = Just $+        -- This ByteString will be overwritten by the C call, but so long as+        -- the C side does not keep a reference to it afterward, it does what we+        -- expect and saves us a copy+        unsafeUseAsCString outBS $ \signature ->+            B.useAsCStringLen msg $ \(cmsg, cmsglen) ->+                B.useAsCString secret $ \csecret ->+                    B.useAsCString pubkey $ \cpubkey -> do+                        c_ed25519_sign cmsg (fromIntegral cmsglen) csecret cpubkey signature+                        return outBS+    | otherwise = Nothing+    where+    outBS = B.replicate 64 0xAB+    {-# NOINLINE outBS #-}++-- Should be Ptr CUChar (not CString), but this should be safe if we just+-- use them as bytes++foreign import ccall unsafe "ed25519_publickey" c_ed25519_publickey ::+   CString -> CString -> IO ()++foreign import ccall unsafe "ed25519_sign_open" c_ed25519_sign_open ::+    CString -> CSize -> CString -> CString -> CInt++foreign import ccall unsafe "ed25519_sign" c_ed25519_sign ::+    CString -> CSize -> CString -> CString -> CString -> IO ()
+ Dust/Crypto/Keys.hs view
@@ -0,0 +1,75 @@+{-# LANGUAGE DeriveGeneric, DefaultSignatures #-} -- For automatic generation of cereal put and get++module Dust.Crypto.Keys+(+   PublicKey(..),+   PrivateKey(..),+   Keypair(..),++   loadKeypair,+   saveKeypair,+   loadPublic,++   loadSigningKeypair,+   saveSigningKeypair+) where++import GHC.Generics+import Data.Serialize+import Data.ByteString++newtype PublicKey = PublicKey { publicBytes :: ByteString } deriving (Show, Eq, Generic)+newtype PrivateKey = PrivateKey { privateBytes :: ByteString } deriving (Show, Eq, Generic)++instance Serialize PublicKey++data Keypair = Keypair {+    public :: PublicKey,+    private :: PrivateKey+} deriving (Show, Eq)++loadKeypair :: IO (Keypair)+loadKeypair = do+    public <- loadPublic "id.pub"+    private <- loadPrivate "id.priv"+    return (Keypair public private)++loadPrivate :: FilePath -> IO (PrivateKey)+loadPrivate path = do+    key <- loadKey path+    return (PrivateKey key)++loadPublic :: FilePath -> IO (PublicKey)+loadPublic path = do+    key <- loadKey path+    return (PublicKey key)++loadKey :: FilePath -> IO (ByteString)+loadKey path = Data.ByteString.readFile path++saveKeypair :: Keypair -> IO ()+saveKeypair (Keypair public private) = do+    savePublic "id.pub" public+    savePrivate "id.priv" private++savePrivate :: FilePath -> PrivateKey -> IO ()+savePrivate path (PrivateKey bs) = do+    saveKey path bs++savePublic :: FilePath -> PublicKey -> IO ()+savePublic path (PublicKey bs) = do+    saveKey path bs++saveKey :: FilePath -> ByteString -> IO ()+saveKey path bs = Data.ByteString.writeFile path bs++loadSigningKeypair :: IO (Keypair)+loadSigningKeypair = do+    public <- loadPublic "sign.pub"+    private <- loadPrivate "sign.priv"+    return (Keypair public private)++saveSigningKeypair :: Keypair -> IO ()+saveSigningKeypair (Keypair public private) = do+    savePublic "sign.pub" public+    savePrivate "sign.priv" private
+ LICENSE view
@@ -0,0 +1,339 @@+                    GNU GENERAL PUBLIC LICENSE+                       Version 2, June 1991++ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA+ Everyone is permitted to copy and distribute verbatim copies+ of this license document, but changing it is not allowed.++                            Preamble++  The licenses for most software are designed to take away your+freedom to share and change it.  By contrast, the GNU General Public+License is intended to guarantee your freedom to share and change free+software--to make sure the software is free for all its users.  This+General Public License applies to most of the Free Software+Foundation's software and to any other program whose authors commit to+using it.  (Some other Free Software Foundation software is covered by+the GNU Lesser General Public License instead.)  You can apply it to+your programs, too.++  When we speak of free software, we are referring to freedom, not+price.  Our General Public Licenses are designed to make sure that you+have the freedom to distribute copies of free software (and charge for+this service if you wish), that you receive source code or can get it+if you want it, that you can change the software or use pieces of it+in new free programs; and that you know you can do these things.++  To protect your rights, we need to make restrictions that forbid+anyone to deny you these rights or to ask you to surrender the rights.+These restrictions translate to certain responsibilities for you if you+distribute copies of the software, or if you modify it.++  For example, if you distribute copies of such a program, whether+gratis or for a fee, you must give the recipients all the rights that+you have.  You must make sure that they, too, receive or can get the+source code.  And you must show them these terms so they know their+rights.++  We protect your rights with two steps: (1) copyright the software, and+(2) offer you this license which gives you legal permission to copy,+distribute and/or modify the software.++  Also, for each author's protection and ours, we want to make certain+that everyone understands that there is no warranty for this free+software.  If the software is modified by someone else and passed on, we+want its recipients to know that what they have is not the original, so+that any problems introduced by others will not reflect on the original+authors' reputations.++  Finally, any free program is threatened constantly by software+patents.  We wish to avoid the danger that redistributors of a free+program will individually obtain patent licenses, in effect making the+program proprietary.  To prevent this, we have made it clear that any+patent must be licensed for everyone's free use or not licensed at all.++  The precise terms and conditions for copying, distribution and+modification follow.++                    GNU GENERAL PUBLIC LICENSE+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION++  0. This License applies to any program or other work which contains+a notice placed by the copyright holder saying it may be distributed+under the terms of this General Public License.  The "Program", below,+refers to any such program or work, and a "work based on the Program"+means either the Program or any derivative work under copyright law:+that is to say, a work containing the Program or a portion of it,+either verbatim or with modifications and/or translated into another+language.  (Hereinafter, translation is included without limitation in+the term "modification".)  Each licensee is addressed as "you".++Activities other than copying, distribution and modification are not+covered by this License; they are outside its scope.  The act of+running the Program is not restricted, and the output from the Program+is covered only if its contents constitute a work based on the+Program (independent of having been made by running the Program).+Whether that is true depends on what the Program does.++  1. You may copy and distribute verbatim copies of the Program's+source code as you receive it, in any medium, provided that you+conspicuously and appropriately publish on each copy an appropriate+copyright notice and disclaimer of warranty; keep intact all the+notices that refer to this License and to the absence of any warranty;+and give any other recipients of the Program a copy of this License+along with the Program.++You may charge a fee for the physical act of transferring a copy, and+you may at your option offer warranty protection in exchange for a fee.++  2. You may modify your copy or copies of the Program or any portion+of it, thus forming a work based on the Program, and copy and+distribute such modifications or work under the terms of Section 1+above, provided that you also meet all of these conditions:++    a) You must cause the modified files to carry prominent notices+    stating that you changed the files and the date of any change.++    b) You must cause any work that you distribute or publish, that in+    whole or in part contains or is derived from the Program or any+    part thereof, to be licensed as a whole at no charge to all third+    parties under the terms of this License.++    c) If the modified program normally reads commands interactively+    when run, you must cause it, when started running for such+    interactive use in the most ordinary way, to print or display an+    announcement including an appropriate copyright notice and a+    notice that there is no warranty (or else, saying that you provide+    a warranty) and that users may redistribute the program under+    these conditions, and telling the user how to view a copy of this+    License.  (Exception: if the Program itself is interactive but+    does not normally print such an announcement, your work based on+    the Program is not required to print an announcement.)++These requirements apply to the modified work as a whole.  If+identifiable sections of that work are not derived from the Program,+and can be reasonably considered independent and separate works in+themselves, then this License, and its terms, do not apply to those+sections when you distribute them as separate works.  But when you+distribute the same sections as part of a whole which is a work based+on the Program, the distribution of the whole must be on the terms of+this License, whose permissions for other licensees extend to the+entire whole, and thus to each and every part regardless of who wrote it.++Thus, it is not the intent of this section to claim rights or contest+your rights to work written entirely by you; rather, the intent is to+exercise the right to control the distribution of derivative or+collective works based on the Program.++In addition, mere aggregation of another work not based on the Program+with the Program (or with a work based on the Program) on a volume of+a storage or distribution medium does not bring the other work under+the scope of this License.++  3. You may copy and distribute the Program (or a work based on it,+under Section 2) in object code or executable form under the terms of+Sections 1 and 2 above provided that you also do one of the following:++    a) Accompany it with the complete corresponding machine-readable+    source code, which must be distributed under the terms of Sections+    1 and 2 above on a medium customarily used for software interchange; or,++    b) Accompany it with a written offer, valid for at least three+    years, to give any third party, for a charge no more than your+    cost of physically performing source distribution, a complete+    machine-readable copy of the corresponding source code, to be+    distributed under the terms of Sections 1 and 2 above on a medium+    customarily used for software interchange; or,++    c) Accompany it with the information you received as to the offer+    to distribute corresponding source code.  (This alternative is+    allowed only for noncommercial distribution and only if you+    received the program in object code or executable form with such+    an offer, in accord with Subsection b above.)++The source code for a work means the preferred form of the work for+making modifications to it.  For an executable work, complete source+code means all the source code for all modules it contains, plus any+associated interface definition files, plus the scripts used to+control compilation and installation of the executable.  However, as a+special exception, the source code distributed need not include+anything that is normally distributed (in either source or binary+form) with the major components (compiler, kernel, and so on) of the+operating system on which the executable runs, unless that component+itself accompanies the executable.++If distribution of executable or object code is made by offering+access to copy from a designated place, then offering equivalent+access to copy the source code from the same place counts as+distribution of the source code, even though third parties are not+compelled to copy the source along with the object code.++  4. You may not copy, modify, sublicense, or distribute the Program+except as expressly provided under this License.  Any attempt+otherwise to copy, modify, sublicense or distribute the Program is+void, and will automatically terminate your rights under this License.+However, parties who have received copies, or rights, from you under+this License will not have their licenses terminated so long as such+parties remain in full compliance.++  5. You are not required to accept this License, since you have not+signed it.  However, nothing else grants you permission to modify or+distribute the Program or its derivative works.  These actions are+prohibited by law if you do not accept this License.  Therefore, by+modifying or distributing the Program (or any work based on the+Program), you indicate your acceptance of this License to do so, and+all its terms and conditions for copying, distributing or modifying+the Program or works based on it.++  6. Each time you redistribute the Program (or any work based on the+Program), the recipient automatically receives a license from the+original licensor to copy, distribute or modify the Program subject to+these terms and conditions.  You may not impose any further+restrictions on the recipients' exercise of the rights granted herein.+You are not responsible for enforcing compliance by third parties to+this License.++  7. If, as a consequence of a court judgment or allegation of patent+infringement or for any other reason (not limited to patent issues),+conditions are imposed on you (whether by court order, agreement or+otherwise) that contradict the conditions of this License, they do not+excuse you from the conditions of this License.  If you cannot+distribute so as to satisfy simultaneously your obligations under this+License and any other pertinent obligations, then as a consequence you+may not distribute the Program at all.  For example, if a patent+license would not permit royalty-free redistribution of the Program by+all those who receive copies directly or indirectly through you, then+the only way you could satisfy both it and this License would be to+refrain entirely from distribution of the Program.++If any portion of this section is held invalid or unenforceable under+any particular circumstance, the balance of the section is intended to+apply and the section as a whole is intended to apply in other+circumstances.++It is not the purpose of this section to induce you to infringe any+patents or other property right claims or to contest validity of any+such claims; this section has the sole purpose of protecting the+integrity of the free software distribution system, which is+implemented by public license practices.  Many people have made+generous contributions to the wide range of software distributed+through that system in reliance on consistent application of that+system; it is up to the author/donor to decide if he or she is willing+to distribute software through any other system and a licensee cannot+impose that choice.++This section is intended to make thoroughly clear what is believed to+be a consequence of the rest of this License.++  8. If the distribution and/or use of the Program is restricted in+certain countries either by patents or by copyrighted interfaces, the+original copyright holder who places the Program under this License+may add an explicit geographical distribution limitation excluding+those countries, so that distribution is permitted only in or among+countries not thus excluded.  In such case, this License incorporates+the limitation as if written in the body of this License.++  9. The Free Software Foundation may publish revised and/or new versions+of the General Public License from time to time.  Such new versions will+be similar in spirit to the present version, but may differ in detail to+address new problems or concerns.++Each version is given a distinguishing version number.  If the Program+specifies a version number of this License which applies to it and "any+later version", you have the option of following the terms and conditions+either of that version or of any later version published by the Free+Software Foundation.  If the Program does not specify a version number of+this License, you may choose any version ever published by the Free Software+Foundation.++  10. If you wish to incorporate parts of the Program into other free+programs whose distribution conditions are different, write to the author+to ask for permission.  For software which is copyrighted by the Free+Software Foundation, write to the Free Software Foundation; we sometimes+make exceptions for this.  Our decision will be guided by the two goals+of preserving the free status of all derivatives of our free software and+of promoting the sharing and reuse of software generally.++                            NO WARRANTY++  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,+REPAIR OR CORRECTION.++  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE+POSSIBILITY OF SUCH DAMAGES.++                     END OF TERMS AND CONDITIONS++            How to Apply These Terms to Your New Programs++  If you develop a new program, and you want it to be of the greatest+possible use to the public, the best way to achieve this is to make it+free software which everyone can redistribute and change under these terms.++  To do so, attach the following notices to the program.  It is safest+to attach them to the start of each source file to most effectively+convey the exclusion of warranty; and each file should have at least+the "copyright" line and a pointer to where the full notice is found.++    <one line to give the program's name and a brief idea of what it does.>+    Copyright (C) <year>  <name of author>++    This program is free software; you can redistribute it and/or modify+    it under the terms of the GNU General Public License as published by+    the Free Software Foundation; either version 2 of the License, or+    (at your option) any later version.++    This program is distributed in the hope that it will be useful,+    but WITHOUT ANY WARRANTY; without even the implied warranty of+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+    GNU General Public License for more details.++    You should have received a copy of the GNU General Public License along+    with this program; if not, write to the Free Software Foundation, Inc.,+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.++Also add information on how to contact you by electronic and paper mail.++If the program is interactive, make it output a short notice like this+when it starts in an interactive mode:++    Gnomovision version 69, Copyright (C) year name of author+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.+    This is free software, and you are welcome to redistribute it+    under certain conditions; type `show c' for details.++The hypothetical commands `show w' and `show c' should show the appropriate+parts of the General Public License.  Of course, the commands you use may+be called something other than `show w' and `show c'; they could even be+mouse-clicks or menu items--whatever suits your program.++You should also get your employer (if you work as a programmer) or your+school, if any, to sign a "copyright disclaimer" for the program, if+necessary.  Here is a sample; alter the names:++  Yoyodyne, Inc., hereby disclaims all copyright interest in the program+  `Gnomovision' (which makes passes at compilers) written by James Hacker.++  <signature of Ty Coon>, 1 April 1989+  Ty Coon, President of Vice++This General Public License does not permit incorporating your program into+proprietary programs.  If your program is a subroutine library, you may+consider it more useful to permit linking proprietary applications with the+library.  If this is what you want to do, use the GNU Lesser General+Public License instead of this License.
+ Setup.hs view
@@ -0,0 +1,3 @@+import Distribution.Simple+main = defaultMain+
+ lib/curve25519-donna.c view
@@ -0,0 +1,730 @@+/* Copyright 2008, Google Inc.+ * All rights reserved.+ *+ * Redistribution and use in source and binary forms, with or without+ * modification, are permitted provided that the following conditions are+ * met:+ *+ *     * Redistributions of source code must retain the above copyright+ * notice, this list of conditions and the following disclaimer.+ *     * Redistributions in binary form must reproduce the above+ * copyright notice, this list of conditions and the following disclaimer+ * in the documentation and/or other materials provided with the+ * distribution.+ *     * Neither the name of Google Inc. nor the names of its+ * contributors may be used to endorse or promote products derived from+ * this software without specific prior written permission.+ *+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+ *+ * curve25519-donna: Curve25519 elliptic curve, public key function+ *+ * http://code.google.com/p/curve25519-donna/+ *+ * Adam Langley <agl@imperialviolet.org>+ *+ * Derived from public domain C code by Daniel J. Bernstein <djb@cr.yp.to>+ *+ * More information about curve25519 can be found here+ *   http://cr.yp.to/ecdh.html+ *+ * djb's sample implementation of curve25519 is written in a special assembly+ * language called qhasm and uses the floating point registers.+ *+ * This is, almost, a clean room reimplementation from the curve25519 paper. It+ * uses many of the tricks described therein. Only the crecip function is taken+ * from the sample implementation.+ */++#include <string.h>+#include <stdint.h>++typedef uint8_t u8;+typedef int32_t s32;+typedef int64_t limb;++/* Field element representation:+ *+ * Field elements are written as an array of signed, 64-bit limbs, least+ * significant first. The value of the field element is:+ *   x[0] + 2^26·x[1] + x^51·x[2] + 2^102·x[3] + ...+ *+ * i.e. the limbs are 26, 25, 26, 25, ... bits wide.+ */++/* Sum two numbers: output += in */+static void fsum(limb *output, const limb *in) {+  unsigned i;+  for (i = 0; i < 10; i += 2) {+    output[0+i] = (output[0+i] + in[0+i]);+    output[1+i] = (output[1+i] + in[1+i]);+  }+}++/* Find the difference of two numbers: output = in - output+ * (note the order of the arguments!)+ */+static void fdifference(limb *output, const limb *in) {+  unsigned i;+  for (i = 0; i < 10; ++i) {+    output[i] = (in[i] - output[i]);+  }+}++/* Multiply a number by a scalar: output = in * scalar */+static void fscalar_product(limb *output, const limb *in, const limb scalar) {+  unsigned i;+  for (i = 0; i < 10; ++i) {+    output[i] = in[i] * scalar;+  }+}++/* Multiply two numbers: output = in2 * in+ *+ * output must be distinct to both inputs. The inputs are reduced coefficient+ * form, the output is not.+ */+static void fproduct(limb *output, const limb *in2, const limb *in) {+  output[0] =       ((limb) ((s32) in2[0])) * ((s32) in[0]);+  output[1] =       ((limb) ((s32) in2[0])) * ((s32) in[1]) ++                    ((limb) ((s32) in2[1])) * ((s32) in[0]);+  output[2] =  2 *  ((limb) ((s32) in2[1])) * ((s32) in[1]) ++                    ((limb) ((s32) in2[0])) * ((s32) in[2]) ++                    ((limb) ((s32) in2[2])) * ((s32) in[0]);+  output[3] =       ((limb) ((s32) in2[1])) * ((s32) in[2]) ++                    ((limb) ((s32) in2[2])) * ((s32) in[1]) ++                    ((limb) ((s32) in2[0])) * ((s32) in[3]) ++                    ((limb) ((s32) in2[3])) * ((s32) in[0]);+  output[4] =       ((limb) ((s32) in2[2])) * ((s32) in[2]) ++               2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) ++                    ((limb) ((s32) in2[3])) * ((s32) in[1])) ++                    ((limb) ((s32) in2[0])) * ((s32) in[4]) ++                    ((limb) ((s32) in2[4])) * ((s32) in[0]);+  output[5] =       ((limb) ((s32) in2[2])) * ((s32) in[3]) ++                    ((limb) ((s32) in2[3])) * ((s32) in[2]) ++                    ((limb) ((s32) in2[1])) * ((s32) in[4]) ++                    ((limb) ((s32) in2[4])) * ((s32) in[1]) ++                    ((limb) ((s32) in2[0])) * ((s32) in[5]) ++                    ((limb) ((s32) in2[5])) * ((s32) in[0]);+  output[6] =  2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) ++                    ((limb) ((s32) in2[1])) * ((s32) in[5]) ++                    ((limb) ((s32) in2[5])) * ((s32) in[1])) ++                    ((limb) ((s32) in2[2])) * ((s32) in[4]) ++                    ((limb) ((s32) in2[4])) * ((s32) in[2]) ++                    ((limb) ((s32) in2[0])) * ((s32) in[6]) ++                    ((limb) ((s32) in2[6])) * ((s32) in[0]);+  output[7] =       ((limb) ((s32) in2[3])) * ((s32) in[4]) ++                    ((limb) ((s32) in2[4])) * ((s32) in[3]) ++                    ((limb) ((s32) in2[2])) * ((s32) in[5]) ++                    ((limb) ((s32) in2[5])) * ((s32) in[2]) ++                    ((limb) ((s32) in2[1])) * ((s32) in[6]) ++                    ((limb) ((s32) in2[6])) * ((s32) in[1]) ++                    ((limb) ((s32) in2[0])) * ((s32) in[7]) ++                    ((limb) ((s32) in2[7])) * ((s32) in[0]);+  output[8] =       ((limb) ((s32) in2[4])) * ((s32) in[4]) ++               2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) ++                    ((limb) ((s32) in2[5])) * ((s32) in[3]) ++                    ((limb) ((s32) in2[1])) * ((s32) in[7]) ++                    ((limb) ((s32) in2[7])) * ((s32) in[1])) ++                    ((limb) ((s32) in2[2])) * ((s32) in[6]) ++                    ((limb) ((s32) in2[6])) * ((s32) in[2]) ++                    ((limb) ((s32) in2[0])) * ((s32) in[8]) ++                    ((limb) ((s32) in2[8])) * ((s32) in[0]);+  output[9] =       ((limb) ((s32) in2[4])) * ((s32) in[5]) ++                    ((limb) ((s32) in2[5])) * ((s32) in[4]) ++                    ((limb) ((s32) in2[3])) * ((s32) in[6]) ++                    ((limb) ((s32) in2[6])) * ((s32) in[3]) ++                    ((limb) ((s32) in2[2])) * ((s32) in[7]) ++                    ((limb) ((s32) in2[7])) * ((s32) in[2]) ++                    ((limb) ((s32) in2[1])) * ((s32) in[8]) ++                    ((limb) ((s32) in2[8])) * ((s32) in[1]) ++                    ((limb) ((s32) in2[0])) * ((s32) in[9]) ++                    ((limb) ((s32) in2[9])) * ((s32) in[0]);+  output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) ++                    ((limb) ((s32) in2[3])) * ((s32) in[7]) ++                    ((limb) ((s32) in2[7])) * ((s32) in[3]) ++                    ((limb) ((s32) in2[1])) * ((s32) in[9]) ++                    ((limb) ((s32) in2[9])) * ((s32) in[1])) ++                    ((limb) ((s32) in2[4])) * ((s32) in[6]) ++                    ((limb) ((s32) in2[6])) * ((s32) in[4]) ++                    ((limb) ((s32) in2[2])) * ((s32) in[8]) ++                    ((limb) ((s32) in2[8])) * ((s32) in[2]);+  output[11] =      ((limb) ((s32) in2[5])) * ((s32) in[6]) ++                    ((limb) ((s32) in2[6])) * ((s32) in[5]) ++                    ((limb) ((s32) in2[4])) * ((s32) in[7]) ++                    ((limb) ((s32) in2[7])) * ((s32) in[4]) ++                    ((limb) ((s32) in2[3])) * ((s32) in[8]) ++                    ((limb) ((s32) in2[8])) * ((s32) in[3]) ++                    ((limb) ((s32) in2[2])) * ((s32) in[9]) ++                    ((limb) ((s32) in2[9])) * ((s32) in[2]);+  output[12] =      ((limb) ((s32) in2[6])) * ((s32) in[6]) ++               2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) ++                    ((limb) ((s32) in2[7])) * ((s32) in[5]) ++                    ((limb) ((s32) in2[3])) * ((s32) in[9]) ++                    ((limb) ((s32) in2[9])) * ((s32) in[3])) ++                    ((limb) ((s32) in2[4])) * ((s32) in[8]) ++                    ((limb) ((s32) in2[8])) * ((s32) in[4]);+  output[13] =      ((limb) ((s32) in2[6])) * ((s32) in[7]) ++                    ((limb) ((s32) in2[7])) * ((s32) in[6]) ++                    ((limb) ((s32) in2[5])) * ((s32) in[8]) ++                    ((limb) ((s32) in2[8])) * ((s32) in[5]) ++                    ((limb) ((s32) in2[4])) * ((s32) in[9]) ++                    ((limb) ((s32) in2[9])) * ((s32) in[4]);+  output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) ++                    ((limb) ((s32) in2[5])) * ((s32) in[9]) ++                    ((limb) ((s32) in2[9])) * ((s32) in[5])) ++                    ((limb) ((s32) in2[6])) * ((s32) in[8]) ++                    ((limb) ((s32) in2[8])) * ((s32) in[6]);+  output[15] =      ((limb) ((s32) in2[7])) * ((s32) in[8]) ++                    ((limb) ((s32) in2[8])) * ((s32) in[7]) ++                    ((limb) ((s32) in2[6])) * ((s32) in[9]) ++                    ((limb) ((s32) in2[9])) * ((s32) in[6]);+  output[16] =      ((limb) ((s32) in2[8])) * ((s32) in[8]) ++               2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) ++                    ((limb) ((s32) in2[9])) * ((s32) in[7]));+  output[17] =      ((limb) ((s32) in2[8])) * ((s32) in[9]) ++                    ((limb) ((s32) in2[9])) * ((s32) in[8]);+  output[18] = 2 *  ((limb) ((s32) in2[9])) * ((s32) in[9]);+}++/* Reduce a long form to a short form by taking the input mod 2^255 - 19. */+static void freduce_degree(limb *output) {+  /* Each of these shifts and adds ends up multiplying the value by 19. */+  output[8] += output[18] << 4;+  output[8] += output[18] << 1;+  output[8] += output[18];+  output[7] += output[17] << 4;+  output[7] += output[17] << 1;+  output[7] += output[17];+  output[6] += output[16] << 4;+  output[6] += output[16] << 1;+  output[6] += output[16];+  output[5] += output[15] << 4;+  output[5] += output[15] << 1;+  output[5] += output[15];+  output[4] += output[14] << 4;+  output[4] += output[14] << 1;+  output[4] += output[14];+  output[3] += output[13] << 4;+  output[3] += output[13] << 1;+  output[3] += output[13];+  output[2] += output[12] << 4;+  output[2] += output[12] << 1;+  output[2] += output[12];+  output[1] += output[11] << 4;+  output[1] += output[11] << 1;+  output[1] += output[11];+  output[0] += output[10] << 4;+  output[0] += output[10] << 1;+  output[0] += output[10];+}++#if (-1 & 3) != 3+#error "This code only works on a two's complement system"+#endif++/* return v / 2^26, using only shifts and adds. */+static inline limb+div_by_2_26(const limb v)+{+  /* High word of v; no shift needed*/+  const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);+  /* Set to all 1s if v was negative; else set to 0s. */+  const int32_t sign = ((int32_t) highword) >> 31;+  /* Set to 0x3ffffff if v was negative; else set to 0. */+  const int32_t roundoff = ((uint32_t) sign) >> 6;+  /* Should return v / (1<<26) */+  return (v + roundoff) >> 26;+}++/* return v / (2^25), using only shifts and adds. */+static inline limb+div_by_2_25(const limb v)+{+  /* High word of v; no shift needed*/+  const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);+  /* Set to all 1s if v was negative; else set to 0s. */+  const int32_t sign = ((int32_t) highword) >> 31;+  /* Set to 0x1ffffff if v was negative; else set to 0. */+  const int32_t roundoff = ((uint32_t) sign) >> 7;+  /* Should return v / (1<<25) */+  return (v + roundoff) >> 25;+}++static inline s32+div_s32_by_2_25(const s32 v)+{+   const s32 roundoff = ((uint32_t)(v >> 31)) >> 7;+   return (v + roundoff) >> 25;+}++/* Reduce all coefficients of the short form input so that |x| < 2^26.+ *+ * On entry: |output[i]| < 2^62+ */+static void freduce_coefficients(limb *output) {+  unsigned i;++  output[10] = 0;++  for (i = 0; i < 10; i += 2) {+    limb over = div_by_2_26(output[i]);+    output[i] -= over << 26;+    output[i+1] += over;++    over = div_by_2_25(output[i+1]);+    output[i+1] -= over << 25;+    output[i+2] += over;+  }+  /* Now |output[10]| < 2 ^ 38 and all other coefficients are reduced. */+  output[0] += output[10] << 4;+  output[0] += output[10] << 1;+  output[0] += output[10];++  output[10] = 0;++  /* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19 * 2^38+   * So |over| will be no more than 77825  */+  {+    limb over = div_by_2_26(output[0]);+    output[0] -= over << 26;+    output[1] += over;+  }++  /* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 77825+   * So |over| will be no more than 1. */+  {+    /* output[1] fits in 32 bits, so we can use div_s32_by_2_25 here. */+    s32 over32 = div_s32_by_2_25((s32) output[1]);+    output[1] -= over32 << 25;+    output[2] += over32;+  }++  /* Finally, output[0,1,3..9] are reduced, and output[2] is "nearly reduced":+   * we have |output[2]| <= 2^26.  This is good enough for all of our math,+   * but it will require an extra freduce_coefficients before fcontract. */+}++/* A helpful wrapper around fproduct: output = in * in2.+ *+ * output must be distinct to both inputs. The output is reduced degree and+ * reduced coefficient.+ */+static void+fmul(limb *output, const limb *in, const limb *in2) {+  limb t[19];+  fproduct(t, in, in2);+  freduce_degree(t);+  freduce_coefficients(t);+  memcpy(output, t, sizeof(limb) * 10);+}++static void fsquare_inner(limb *output, const limb *in) {+  output[0] =       ((limb) ((s32) in[0])) * ((s32) in[0]);+  output[1] =  2 *  ((limb) ((s32) in[0])) * ((s32) in[1]);+  output[2] =  2 * (((limb) ((s32) in[1])) * ((s32) in[1]) ++                    ((limb) ((s32) in[0])) * ((s32) in[2]));+  output[3] =  2 * (((limb) ((s32) in[1])) * ((s32) in[2]) ++                    ((limb) ((s32) in[0])) * ((s32) in[3]));+  output[4] =       ((limb) ((s32) in[2])) * ((s32) in[2]) ++               4 *  ((limb) ((s32) in[1])) * ((s32) in[3]) ++               2 *  ((limb) ((s32) in[0])) * ((s32) in[4]);+  output[5] =  2 * (((limb) ((s32) in[2])) * ((s32) in[3]) ++                    ((limb) ((s32) in[1])) * ((s32) in[4]) ++                    ((limb) ((s32) in[0])) * ((s32) in[5]));+  output[6] =  2 * (((limb) ((s32) in[3])) * ((s32) in[3]) ++                    ((limb) ((s32) in[2])) * ((s32) in[4]) ++                    ((limb) ((s32) in[0])) * ((s32) in[6]) ++               2 *  ((limb) ((s32) in[1])) * ((s32) in[5]));+  output[7] =  2 * (((limb) ((s32) in[3])) * ((s32) in[4]) ++                    ((limb) ((s32) in[2])) * ((s32) in[5]) ++                    ((limb) ((s32) in[1])) * ((s32) in[6]) ++                    ((limb) ((s32) in[0])) * ((s32) in[7]));+  output[8] =       ((limb) ((s32) in[4])) * ((s32) in[4]) ++               2 * (((limb) ((s32) in[2])) * ((s32) in[6]) ++                    ((limb) ((s32) in[0])) * ((s32) in[8]) ++               2 * (((limb) ((s32) in[1])) * ((s32) in[7]) ++                    ((limb) ((s32) in[3])) * ((s32) in[5])));+  output[9] =  2 * (((limb) ((s32) in[4])) * ((s32) in[5]) ++                    ((limb) ((s32) in[3])) * ((s32) in[6]) ++                    ((limb) ((s32) in[2])) * ((s32) in[7]) ++                    ((limb) ((s32) in[1])) * ((s32) in[8]) ++                    ((limb) ((s32) in[0])) * ((s32) in[9]));+  output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) ++                    ((limb) ((s32) in[4])) * ((s32) in[6]) ++                    ((limb) ((s32) in[2])) * ((s32) in[8]) ++               2 * (((limb) ((s32) in[3])) * ((s32) in[7]) ++                    ((limb) ((s32) in[1])) * ((s32) in[9])));+  output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) ++                    ((limb) ((s32) in[4])) * ((s32) in[7]) ++                    ((limb) ((s32) in[3])) * ((s32) in[8]) ++                    ((limb) ((s32) in[2])) * ((s32) in[9]));+  output[12] =      ((limb) ((s32) in[6])) * ((s32) in[6]) ++               2 * (((limb) ((s32) in[4])) * ((s32) in[8]) ++               2 * (((limb) ((s32) in[5])) * ((s32) in[7]) ++                    ((limb) ((s32) in[3])) * ((s32) in[9])));+  output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) ++                    ((limb) ((s32) in[5])) * ((s32) in[8]) ++                    ((limb) ((s32) in[4])) * ((s32) in[9]));+  output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) ++                    ((limb) ((s32) in[6])) * ((s32) in[8]) ++               2 *  ((limb) ((s32) in[5])) * ((s32) in[9]));+  output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) ++                    ((limb) ((s32) in[6])) * ((s32) in[9]));+  output[16] =      ((limb) ((s32) in[8])) * ((s32) in[8]) ++               4 *  ((limb) ((s32) in[7])) * ((s32) in[9]);+  output[17] = 2 *  ((limb) ((s32) in[8])) * ((s32) in[9]);+  output[18] = 2 *  ((limb) ((s32) in[9])) * ((s32) in[9]);+}++static void+fsquare(limb *output, const limb *in) {+  limb t[19];+  fsquare_inner(t, in);+  freduce_degree(t);+  freduce_coefficients(t);+  memcpy(output, t, sizeof(limb) * 10);+}++/* Take a little-endian, 32-byte number and expand it into polynomial form */+static void+fexpand(limb *output, const u8 *input) {+#define F(n,start,shift,mask) \+  output[n] = ((((limb) input[start + 0]) | \+                ((limb) input[start + 1]) << 8 | \+                ((limb) input[start + 2]) << 16 | \+                ((limb) input[start + 3]) << 24) >> shift) & mask;+  F(0, 0, 0, 0x3ffffff);+  F(1, 3, 2, 0x1ffffff);+  F(2, 6, 3, 0x3ffffff);+  F(3, 9, 5, 0x1ffffff);+  F(4, 12, 6, 0x3ffffff);+  F(5, 16, 0, 0x1ffffff);+  F(6, 19, 1, 0x3ffffff);+  F(7, 22, 3, 0x1ffffff);+  F(8, 25, 4, 0x3ffffff);+  F(9, 28, 6, 0x1ffffff);+#undef F+}++#if (-32 >> 1) != -16+#error "This code only works when >> does sign-extension on negative numbers"+#endif++/* Take a fully reduced polynomial form number and contract it into a+ * little-endian, 32-byte array+ */+static void+fcontract(u8 *output, limb *input) {+  int i;+  int j;++  for (j = 0; j < 2; ++j) {+    for (i = 0; i < 9; ++i) {+      if ((i & 1) == 1) {+        /* This calculation is a time-invariant way to make input[i] positive+           by borrowing from the next-larger limb.+        */+        const s32 mask = (s32)(input[i]) >> 31;+        const s32 carry = -(((s32)(input[i]) & mask) >> 25);+        input[i] = (s32)(input[i]) + (carry << 25);+        input[i+1] = (s32)(input[i+1]) - carry;+      } else {+        const s32 mask = (s32)(input[i]) >> 31;+        const s32 carry = -(((s32)(input[i]) & mask) >> 26);+        input[i] = (s32)(input[i]) + (carry << 26);+        input[i+1] = (s32)(input[i+1]) - carry;+      }+    }+    {+      const s32 mask = (s32)(input[9]) >> 31;+      const s32 carry = -(((s32)(input[9]) & mask) >> 25);+      input[9] = (s32)(input[9]) + (carry << 25);+      input[0] = (s32)(input[0]) - (carry * 19);+    }+  }++  /* The first borrow-propagation pass above ended with every limb+     except (possibly) input[0] non-negative.++     Since each input limb except input[0] is decreased by at most 1+     by a borrow-propagation pass, the second borrow-propagation pass+     could only have wrapped around to decrease input[0] again if the+     first pass left input[0] negative *and* input[1] through input[9]+     were all zero.  In that case, input[1] is now 2^25 - 1, and this+     last borrow-propagation step will leave input[1] non-negative.+  */+  {+    const s32 mask = (s32)(input[0]) >> 31;+    const s32 carry = -(((s32)(input[0]) & mask) >> 26);+    input[0] = (s32)(input[0]) + (carry << 26);+    input[1] = (s32)(input[1]) - carry;+  }++  /* Both passes through the above loop, plus the last 0-to-1 step, are+     necessary: if input[9] is -1 and input[0] through input[8] are 0,+     negative values will remain in the array until the end.+   */++  input[1] <<= 2;+  input[2] <<= 3;+  input[3] <<= 5;+  input[4] <<= 6;+  input[6] <<= 1;+  input[7] <<= 3;+  input[8] <<= 4;+  input[9] <<= 6;+#define F(i, s) \+  output[s+0] |=  input[i] & 0xff; \+  output[s+1]  = (input[i] >> 8) & 0xff; \+  output[s+2]  = (input[i] >> 16) & 0xff; \+  output[s+3]  = (input[i] >> 24) & 0xff;+  output[0] = 0;+  output[16] = 0;+  F(0,0);+  F(1,3);+  F(2,6);+  F(3,9);+  F(4,12);+  F(5,16);+  F(6,19);+  F(7,22);+  F(8,25);+  F(9,28);+#undef F+}++/* Input: Q, Q', Q-Q'+ * Output: 2Q, Q+Q'+ *+ *   x2 z3: long form+ *   x3 z3: long form+ *   x z: short form, destroyed+ *   xprime zprime: short form, destroyed+ *   qmqp: short form, preserved+ */+static void fmonty(limb *x2, limb *z2,  /* output 2Q */+                   limb *x3, limb *z3,  /* output Q + Q' */+                   limb *x, limb *z,    /* input Q */+                   limb *xprime, limb *zprime,  /* input Q' */+                   const limb *qmqp /* input Q - Q' */) {+  limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19],+        zzprime[19], zzzprime[19], xxxprime[19];++  memcpy(origx, x, 10 * sizeof(limb));+  fsum(x, z);+  fdifference(z, origx);  // does x - z++  memcpy(origxprime, xprime, sizeof(limb) * 10);+  fsum(xprime, zprime);+  fdifference(zprime, origxprime);+  fproduct(xxprime, xprime, z);+  fproduct(zzprime, x, zprime);+  freduce_degree(xxprime);+  freduce_coefficients(xxprime);+  freduce_degree(zzprime);+  freduce_coefficients(zzprime);+  memcpy(origxprime, xxprime, sizeof(limb) * 10);+  fsum(xxprime, zzprime);+  fdifference(zzprime, origxprime);+  fsquare(xxxprime, xxprime);+  fsquare(zzzprime, zzprime);+  fproduct(zzprime, zzzprime, qmqp);+  freduce_degree(zzprime);+  freduce_coefficients(zzprime);+  memcpy(x3, xxxprime, sizeof(limb) * 10);+  memcpy(z3, zzprime, sizeof(limb) * 10);++  fsquare(xx, x);+  fsquare(zz, z);+  fproduct(x2, xx, zz);+  freduce_degree(x2);+  freduce_coefficients(x2);+  fdifference(zz, xx);  // does zz = xx - zz+  memset(zzz + 10, 0, sizeof(limb) * 9);+  fscalar_product(zzz, zz, 121665);+  /* No need to call freduce_degree here:+     fscalar_product doesn't increase the degree of its input. */+  freduce_coefficients(zzz);+  fsum(zzz, xx);+  fproduct(z2, zz, zzz);+  freduce_degree(z2);+  freduce_coefficients(z2);+}++/* Conditionally swap two reduced-form limb arrays if 'iswap' is 1, but leave+ * them unchanged if 'iswap' is 0.  Runs in data-invariant time to avoid+ * side-channel attacks.+ *+ * NOTE that this function requires that 'iswap' be 1 or 0; other values give+ * wrong results.  Also, the two limb arrays must be in reduced-coefficient,+ * reduced-degree form: the values in a[10..19] or b[10..19] aren't swapped,+ * and all all values in a[0..9],b[0..9] must have magnitude less than+ * INT32_MAX.+ */+static void+swap_conditional(limb a[19], limb b[19], limb iswap) {+  unsigned i;+  const s32 swap = (s32) -iswap;++  for (i = 0; i < 10; ++i) {+    const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) );+    a[i] = ((s32)a[i]) ^ x;+    b[i] = ((s32)b[i]) ^ x;+  }+}++/* Calculates nQ where Q is the x-coordinate of a point on the curve+ *+ *   resultx/resultz: the x coordinate of the resulting curve point (short form)+ *   n: a little endian, 32-byte number+ *   q: a point of the curve (short form)+ */+static void+cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {+  limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0};+  limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t;+  limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1};+  limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h;++  unsigned i, j;++  memcpy(nqpqx, q, sizeof(limb) * 10);++  for (i = 0; i < 32; ++i) {+    u8 byte = n[31 - i];+    for (j = 0; j < 8; ++j) {+      const limb bit = byte >> 7;++      swap_conditional(nqx, nqpqx, bit);+      swap_conditional(nqz, nqpqz, bit);+      fmonty(nqx2, nqz2,+             nqpqx2, nqpqz2,+             nqx, nqz,+             nqpqx, nqpqz,+             q);+      swap_conditional(nqx2, nqpqx2, bit);+      swap_conditional(nqz2, nqpqz2, bit);++      t = nqx;+      nqx = nqx2;+      nqx2 = t;+      t = nqz;+      nqz = nqz2;+      nqz2 = t;+      t = nqpqx;+      nqpqx = nqpqx2;+      nqpqx2 = t;+      t = nqpqz;+      nqpqz = nqpqz2;+      nqpqz2 = t;++      byte <<= 1;+    }+  }++  memcpy(resultx, nqx, sizeof(limb) * 10);+  memcpy(resultz, nqz, sizeof(limb) * 10);+}++// -----------------------------------------------------------------------------+// Shamelessly copied from djb's code+// -----------------------------------------------------------------------------+static void+crecip(limb *out, const limb *z) {+  limb z2[10];+  limb z9[10];+  limb z11[10];+  limb z2_5_0[10];+  limb z2_10_0[10];+  limb z2_20_0[10];+  limb z2_50_0[10];+  limb z2_100_0[10];+  limb t0[10];+  limb t1[10];+  int i;++  /* 2 */ fsquare(z2,z);+  /* 4 */ fsquare(t1,z2);+  /* 8 */ fsquare(t0,t1);+  /* 9 */ fmul(z9,t0,z);+  /* 11 */ fmul(z11,z9,z2);+  /* 22 */ fsquare(t0,z11);+  /* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9);++  /* 2^6 - 2^1 */ fsquare(t0,z2_5_0);+  /* 2^7 - 2^2 */ fsquare(t1,t0);+  /* 2^8 - 2^3 */ fsquare(t0,t1);+  /* 2^9 - 2^4 */ fsquare(t1,t0);+  /* 2^10 - 2^5 */ fsquare(t0,t1);+  /* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0);++  /* 2^11 - 2^1 */ fsquare(t0,z2_10_0);+  /* 2^12 - 2^2 */ fsquare(t1,t0);+  /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }+  /* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0);++  /* 2^21 - 2^1 */ fsquare(t0,z2_20_0);+  /* 2^22 - 2^2 */ fsquare(t1,t0);+  /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }+  /* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0);++  /* 2^41 - 2^1 */ fsquare(t1,t0);+  /* 2^42 - 2^2 */ fsquare(t0,t1);+  /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }+  /* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0);++  /* 2^51 - 2^1 */ fsquare(t0,z2_50_0);+  /* 2^52 - 2^2 */ fsquare(t1,t0);+  /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }+  /* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0);++  /* 2^101 - 2^1 */ fsquare(t1,z2_100_0);+  /* 2^102 - 2^2 */ fsquare(t0,t1);+  /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }+  /* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0);++  /* 2^201 - 2^1 */ fsquare(t0,t1);+  /* 2^202 - 2^2 */ fsquare(t1,t0);+  /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }+  /* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0);++  /* 2^251 - 2^1 */ fsquare(t1,t0);+  /* 2^252 - 2^2 */ fsquare(t0,t1);+  /* 2^253 - 2^3 */ fsquare(t1,t0);+  /* 2^254 - 2^4 */ fsquare(t0,t1);+  /* 2^255 - 2^5 */ fsquare(t1,t0);+  /* 2^255 - 21 */ fmul(out,t1,z11);+}++int curve25519_donna(u8 *, const u8 *, const u8 *);++int+curve25519_donna(u8 *mypublic, const u8 *secret, const u8 *basepoint) {+  limb bp[10], x[10], z[11], zmone[10];+  uint8_t e[32];+  int i;++  for (i = 0; i < 32; ++i) e[i] = secret[i];+  e[0] &= 248;+  e[31] &= 127;+  e[31] |= 64;++  fexpand(bp, basepoint);+  cmult(x, z, e, bp);+  crecip(zmone, z);+  fmul(z, x, zmone);+  freduce_coefficients(z);+  fcontract(mypublic, z);+  return 0;+}
+ lib/ed25519-donna/ed25519.c view
@@ -0,0 +1,109 @@+/*+	Public domain by Andrew M. <liquidsun@gmail.com>++	Ed25519 reference implementation using Ed25519-donna+*/+++#include "ed25519-donna.h"+#include "ed25519.h"+#include "ed25519-randombytes.h"+#include <openssl/sha.h>++/*+	Generates a (extsk[0..31]) and aExt (extsk[32..63])+*/++static void DONNA_INLINE+ed25519_extsk(hash_512bits extsk, const ed25519_secret_key sk) {+	SHA512(sk, 32, extsk);+	extsk[0] &= 248;+	extsk[31] &= 127;+	extsk[31] |= 64;+}++static void+ed25519_hram(hash_512bits hram, const ed25519_signature RS, const ed25519_public_key pk, const unsigned char *m, size_t mlen) {+	SHA512_CTX shactx;+	SHA512_Init(&shactx);+	SHA512_Update(&shactx, RS, 32);+	SHA512_Update(&shactx, pk, 32);+	SHA512_Update(&shactx, m, mlen);+	SHA512_Final(hram, &shactx);+}++void+ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk) {+	bignum256modm a;+	ge25519 MM16 A;+	hash_512bits extsk;++	/* A = aB */+	ed25519_extsk(extsk, sk);+	expand256_modm(a, extsk, 32);+	ge25519_scalarmult_base_niels(&A, a);+	ge25519_pack(pk, &A);+}+++void+ed25519_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS) {+	SHA512_CTX shactx;+	bignum256modm r, S, a;+	ge25519 MM16 R;+	hash_512bits extsk, hashr, hram;++	ed25519_extsk(extsk, sk);++	/* r = H(aExt[32..64], m) */+	SHA512_Init(&shactx);+	SHA512_Update(&shactx, extsk + 32, 32);+	SHA512_Update(&shactx, m, mlen);+	SHA512_Final(hashr, &shactx);+	expand256_modm(r, hashr, 64);++	/* R = rB */+	ge25519_scalarmult_base_niels(&R, r);+	ge25519_pack(RS, &R);++	/* S = H(R,A,m).. */+	ed25519_hram(hram, RS, pk, m, mlen);+	expand256_modm(S, hram, 64);++	/* S = H(R,A,m)a */+	expand256_modm(a, extsk, 32);+	mul256_modm(S, S, a);++	/* S = (r + H(R,A,m)a) */+	add256_modm(S, S, r);++	/* S = (r + H(R,A,m)a) mod L */	+	contract256_modm(RS + 32, S);+}++int+ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS) {+	ge25519 MM16 R, A;+	hash_512bits hash;+	bignum256modm hram, S;+	unsigned char checkR[32];++	if ((RS[63] & 224) || !ge25519_unpack_negative_vartime(&A, pk))+		return -1;++	/* hram = H(R,A,m) */+	ed25519_hram(hash, RS, pk, m, mlen);+	expand256_modm(hram, hash, 64);++	/* S */+	expand256_modm(S, RS + 32, 32);++	/* SB - H(R,A,m)A */+	ge25519_double_scalarmult_vartime(&R, &A, hram, S);+	ge25519_pack(checkR, &R);++	/* check that R = SB - H(R,A,m)A */+	return ed25519_verify(RS, checkR, 32) ? 0 : -1;+}++#include "ed25519-donna-batchverify.h"
+ tests/TestCrypto.hs view
@@ -0,0 +1,104 @@+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}+{-# LANGUAGE TemplateHaskell #-}++module Main where++import Test.Framework.Providers.HUnit+import Test.Framework.Providers.QuickCheck2+import Test.Framework+import Test.HUnit hiding (test)+import Test.QuickCheck+import Test.QuickCheck.Gen++import Data.ByteString as B (ByteString, length)+import Data.ByteString.Char8 (pack, useAsCString, packCString)++import Dust.Crypto.DustCipher+import qualified Dust.Crypto.ECDH as ECDH+import qualified Dust.Crypto.ECDSA as ECDSA+import Dust.Crypto.Keys++gen_privkeys :: Gen String+gen_privkeys =+  let e = elements ['\00'..'\FF']+  in vectorOf 32 e++prop_ECDH_pubkey_size :: Property+prop_ECDH_pubkey_size =+  forAll gen_privkeys $ \privBytes ->+    let priv = PrivateKey $ pack privBytes+        (PublicKey pub)  = ECDH.createPublic priv+    in B.length pub == 32++prop_ECDSA_pubkey_size :: Property+prop_ECDSA_pubkey_size =+  forAll gen_privkeys $ \privBytes ->+    let priv = PrivateKey $ pack privBytes+        (PublicKey pub)  = ECDSA.createPublic priv+    in B.length pub == 32++case_ECDH_keypair_save_load = do+    let input = (pack "1234567890123457890123456789012")+    let keypair1 = ECDH.createKeypair input+    saveKeypair keypair1++    keypair2 <- loadKeypair++    keypair1 @?= keypair2++case_ECDH_createShared = do+    let entropy1 = (pack "1234567890123457890123456789012")+    let private1 = ECDH.createPrivate entropy1+    let public1 = ECDH.createPublic private1++    let entropy2 = (pack "2109876543210987543210987654321")+    let private2 = ECDH.createPrivate entropy2+    let public2 = ECDH.createPublic private2++    let shared1 = ECDH.createShared private1 public2+    let shared2 = ECDH.createShared private2 public1++    shared1 @?= shared2++case_ECDH_createKeypair = do+    let input = (pack "1234567890123457890123456789012")+    let keys = ECDH.createKeypair input+    let Keypair public private = keys+    publicBytes public @?= pack "\164x}\156n\177\164\240\187F\163\202\232}\221\207/x\ETX\178\SOH\208\238\213q\138%\137\159\253+{"+    privateBytes private @?= pack "023456789012345789012345678901r"++case_ECDH_createPublic = do+    let input = (pack "1234567890123457890123456789012")+    let private = ECDH.createPrivate input+    let public = ECDH.createPublic private+    publicBytes public @?= pack "\164x}\156n\177\164\240\187F\163\202\232}\221\207/x\ETX\178\SOH\208\238\213q\138%\137\159\253+{"++case_ECDH_createPrivate = do+    let input = (pack "1234567890123457890123456789012")+    let output = ECDH.createPrivate input+    privateBytes output @?= pack "023456789012345789012345678901r"++case_encrypt_decrypt = let key = EncryptionKey (pack "1234567890123456")+                           iv = IV (pack "1234567890123456")++                           plain1 = Plaintext (pack "majestic")+                           cipher = encrypt key iv plain1+                           plain2 = decrypt key iv cipher++                       in plain1 @?= plain2++main :: IO ()+main =+ defaultMain [+     testGroup "ECDH25519" [ +         testCase "ECDH_createPrivate" case_ECDH_createPrivate,+         testCase "ECDH_createPublic" case_ECDH_createPublic,+         testCase "ECDH_createKeypair" case_ECDH_createKeypair,+         testCase "ECDH_createShared" case_ECDH_createShared,+         testCase "ECDH_keypair_save_load" case_ECDH_keypair_save_load,+         testCase "encrypt_decrypt" case_encrypt_decrypt,+        +         testProperty "ECDH_pubkey_size" prop_ECDH_pubkey_size,+         testProperty "ECDSA_pubkey_size" prop_ECDSA_pubkey_size+       ]+   ]