Skip to content

Commit

Permalink
Fixed a bug with the mnemonic splitting functions
Browse files Browse the repository at this point in the history
  • Loading branch information
plaprade committed Oct 8, 2023
1 parent 24b16bc commit 52161d0
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 9 deletions.
8 changes: 4 additions & 4 deletions haskoin-wallet.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ cabal-version: 1.12
--
-- see: https://github.com/sol/hpack
--
-- hash: bcfb029745842f0bf0972b664cc70165ab6d6c346ca41d665f38e9da9b45d1c5
-- hash: 3a09ee5a54cbb8291ce9925e53adb95e29db8f16435843ca8d381bc144e4a675

name: haskoin-wallet
version: 0.7.0
version: 0.7.1
synopsis: Lightweight command-line wallet for Bitcoin and Bitcoin Cash
description: haskoin-wallet (hw) is a lightweight Bitcoin wallet using BIP39 mnemonics and
BIP44 account structure. It requires a full blockchain index such as
Expand Down Expand Up @@ -100,7 +100,7 @@ executable hw
, haskeline >=0.7.5.0
, haskoin-core >=1.0.0
, haskoin-store-data >=1.0.0
, haskoin-wallet ==0.7.0
, haskoin-wallet ==0.7.1
, http-types >=0.12.3
, lens >=4.18.1
, lens-aeson >=1.1
Expand Down Expand Up @@ -151,7 +151,7 @@ test-suite spec
, haskeline >=0.7.5.0
, haskoin-core >=1.0.0
, haskoin-store-data >=1.0.0
, haskoin-wallet ==0.7.0
, haskoin-wallet ==0.7.1
, hspec >=2.7.1
, http-types >=0.12.3
, lens >=4.18.1
Expand Down
2 changes: 1 addition & 1 deletion package.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: haskoin-wallet
version: &version 0.7.0
version: &version 0.7.1
synopsis: Lightweight command-line wallet for Bitcoin and Bitcoin Cash
description: !
haskoin-wallet (hw) is a lightweight Bitcoin wallet using BIP39 mnemonics and
Expand Down
7 changes: 5 additions & 2 deletions src/Network/Haskoin/Wallet/Entropy.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import Data.List (foldl')
import Data.Text (Text)
import qualified Data.Text as T
import Data.Word (Word8)
import Haskoin.Crypto (Mnemonic, mnemonicToSeed, toMnemonic)
import Haskoin.Crypto (Mnemonic, toMnemonic, fromMnemonic)
import Haskoin.Util (bsToInteger)
import Network.Haskoin.Wallet.Util (chunksOf)
import Numeric (showIntAtBase)
Expand Down Expand Up @@ -139,7 +139,7 @@ mergeMnemonicParts :: [T.Text] -> Either String Mnemonic
mergeMnemonicParts mnems
| length mnems < 2 = Left "Invalid call to mergeMnemonicParts"
| otherwise = do
bs <- mapM (mnemonicToSeed "") mnems
bs <- mapM fromMnemonic mnems
let ent = foldl' xorBytes (head bs) (tail bs)
toMnemonic ent

Expand Down Expand Up @@ -204,6 +204,9 @@ genMnemonic reqEnt reqDice splitIn
unless (ent == foldl' xorBytes (head ks) (tail ks)) $
throwError "Something went wrong while splitting the keys"
splitMnems <- liftEither $ mapM toMnemonic ks
unsplitMnem <- liftEither $ mergeMnemonicParts splitMnems
unless (mnem == unsplitMnem) $
throwError "Something went wrong while reconstructing the mnemonic"
return (origEnt, mnem, splitMnems)
else return (origEnt, mnem, [])
| otherwise = throwError "The entropy value can only be in [16,20..32]"
Expand Down
15 changes: 13 additions & 2 deletions test/Network/Haskoin/Wallet/EntropySpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import Network.Haskoin.Wallet.Entropy
( base6ToWord8,
splitEntropyWith,
word8ToBase6,
xorBytes,
xorBytes, mergeMnemonicParts,
)
import Network.Haskoin.Wallet.Signing (signingKey)
import Network.Haskoin.Wallet.TestUtils (forceRight)
Expand All @@ -44,6 +44,7 @@ import Test.Hspec
)
import Test.Hspec.QuickCheck (prop)
import Test.QuickCheck (forAll)
import Haskoin.Crypto (toMnemonic)

spec :: Spec
spec = prepareContext $ \ctx -> do
Expand Down Expand Up @@ -123,13 +124,23 @@ entropySpec = do
forAll (arbitraryBSn 32) $ \k2 ->
splitEntropyWith s [k1, k2]
`shouldBe` [s `xorBytes` k1 `xorBytes` k2, k1, k2]
prop "prop: can reconstruct secret key" $
prop "prop: can reconstruct entropy" $
forAll (arbitraryBSn 32) $ \s ->
forAll (arbitraryBSn 32) $ \k1 ->
forAll (arbitraryBSn 32) $ \k2 -> do
case splitEntropyWith s [k1, k2] of
[a, b, c] -> (a `xorBytes` b `xorBytes` c) `shouldBe` s
_ -> expectationFailure "Invalid splitEntropyWith"
prop "prop: can reconstruct original mnemonic" $
forAll (arbitraryBSn 32) $ \s ->
forAll (arbitraryBSn 32) $ \k1 ->
case splitEntropyWith s [k1] of
[a, b] ->
let mnem = toMnemonic s
splitMnems = mapM toMnemonic [a, b]
unsplitMnem = mergeMnemonicParts $ forceRight splitMnems
in unsplitMnem `shouldBe` mnem
_ -> expectationFailure "Invalid splitEntropyWith"

-- https://github.com/iancoleman/bip39/issues/58
mnemonicSpec :: Ctx -> Spec
Expand Down

0 comments on commit 52161d0

Please sign in to comment.