LCOV - code coverage report
Current view: top level - src/wallet - bip39.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 75 81 92.6 %
Date: 2026-06-25 07:23:43 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /**
       2             :  * Copyright (c) 2013-2014 Tomas Dzetkulic
       3             :  * Copyright (c) 2013-2014 Pavol Rusnak
       4             :  *
       5             :  * Permission is hereby granted, free of charge, to any person obtaining
       6             :  * a copy of this software and associated documentation files (the "Software"),
       7             :  * to deal in the Software without restriction, including without limitation
       8             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
       9             :  * and/or sell copies of the Software, and to permit persons to whom the
      10             :  * Software is furnished to do so, subject to the following conditions:
      11             :  *
      12             :  * The above copyright notice and this permission notice shall be included
      13             :  * in all copies or substantial portions of the Software.
      14             :  *
      15             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      16             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      18             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
      19             :  * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      20             :  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
      21             :  * OTHER DEALINGS IN THE SOFTWARE.
      22             :  */
      23             : 
      24             : // Source:
      25             : // https://github.com/trezor/trezor-crypto
      26             : 
      27             : #include <wallet/bip39.h>
      28             : #include <wallet/bip39_english.h>
      29             : #include <crypto/pkcs5_pbkdf2_hmac_sha512.h>
      30             : #include <crypto/sha256.h>
      31             : #include <random.h>
      32             : 
      33        3062 : SecureString CMnemonic::Generate(int strength)
      34             : {
      35        3062 :     if (strength % 32 || strength < 128 || strength > 256) {
      36           4 :         return SecureString();
      37             :     }
      38        3058 :     SecureVector data(32);
      39        3058 :     GetStrongRandBytes({data.data(), 32});
      40        3058 :     SecureString mnemonic = FromData(data, strength / 8);
      41        3058 :     return mnemonic;
      42        3062 : }
      43             : 
      44             : // SecureString CMnemonic::FromData(const uint8_t *data, int len)
      45        3082 : SecureString CMnemonic::FromData(const SecureVector& data, int len)
      46             : {
      47        3082 :     if (len % 4 || len < 16 || len > 32) {
      48           0 :         return SecureString();
      49             :     }
      50             : 
      51        3082 :     SecureVector checksum(32);
      52        3082 :     CSHA256().Write(data.data(), len).Finalize(checksum.data());
      53             : 
      54             :     // data
      55        3082 :     SecureVector bits(len);
      56        3082 :     memcpy(bits.data(), data.data(), len);
      57             :     // checksum
      58        3082 :     bits.push_back(checksum[0]);
      59             : 
      60        3082 :     int mlen = len * 3 / 4;
      61        3082 :     SecureString mnemonic;
      62             : 
      63       40450 :     for (int i = 0; i < mlen; i++) {
      64       37368 :         int idx = 0;
      65      448416 :         for (int j = 0; j < 11; j++) {
      66      411048 :             idx <<= 1;
      67      411048 :             idx += (bits[(i * 11 + j) / 8] & (1 << (7 - ((i * 11 + j) % 8)))) > 0;
      68      411048 :         }
      69       37368 :         mnemonic.append(wordlist[idx]);
      70       37368 :         if (i < mlen - 1) {
      71       34286 :             mnemonic += ' ';
      72       34286 :         }
      73       37368 :     }
      74             : 
      75        3082 :     return mnemonic;
      76        3082 : }
      77             : 
      78        1015 : bool CMnemonic::Check(const SecureString& mnemonic)
      79             : {
      80        1015 :     if (mnemonic.empty()) {
      81           0 :         return false;
      82             :     }
      83             : 
      84        1015 :     uint32_t nWordCount{};
      85             : 
      86       79615 :     for (size_t i = 0; i < mnemonic.size(); ++i) {
      87       78600 :         if (mnemonic[i] == ' ') {
      88       11429 :             nWordCount++;
      89       11429 :         }
      90       78600 :     }
      91        1015 :     nWordCount++;
      92             :     // check number of words
      93        1015 :     if (nWordCount % 3 != 0 || nWordCount < 12 || nWordCount > 24) {
      94           0 :         return false;
      95             :     }
      96             : 
      97        1015 :     SecureString ssCurrentWord;
      98        1015 :     SecureVector bits(32 + 1);
      99        1015 :     uint32_t nBitsCount{};
     100             : 
     101       13459 :     for (size_t i = 0; i < mnemonic.size(); ++i)
     102             :     {
     103       12444 :         ssCurrentWord.resize(0); // we resize ssCurrentWord instead recreating to avoid new allocations
     104       79615 :         while (i + ssCurrentWord.size() < mnemonic.size() && mnemonic[i + ssCurrentWord.size()] != ' ') {
     105       67171 :             if (ssCurrentWord.size() >= 9) {
     106           0 :                 return false;
     107             :             }
     108       67171 :             ssCurrentWord += mnemonic[i + ssCurrentWord.size()];
     109             :         }
     110       12444 :         i += ssCurrentWord.size();
     111       12444 :         uint32_t nWordIndex = 0;
     112    12667524 :         for (;;) {
     113    12667524 :             if (!wordlist[nWordIndex]) { // word not found
     114           0 :                 return false;
     115             :             }
     116    12667524 :             if (ssCurrentWord == wordlist[nWordIndex]) { // word found on index nWordIndex
     117      149328 :                 for (uint32_t ki = 0; ki < 11; ki++) {
     118      136884 :                     if (nWordIndex & (1 << (10 - ki))) {
     119       68254 :                         bits[nBitsCount / 8] |= 1 << (7 - (nBitsCount % 8));
     120       68254 :                     }
     121      136884 :                     nBitsCount++;
     122      136884 :                 }
     123       12444 :                 break;
     124             :             }
     125    12655080 :             nWordIndex++;
     126             :         }
     127       12444 :     }
     128        1015 :     if (nBitsCount != nWordCount * 11) {
     129           0 :         return false;
     130             :     }
     131        1015 :     bits[32] = bits[nWordCount * 4 / 3];
     132        1015 :     CSHA256().Write(bits.data(), nWordCount * 4 / 3).Finalize(bits.data());
     133             : 
     134        1015 :     const char checksum_length = nWordCount / 3;
     135        1015 :     const char mask = (2 ^ checksum_length) << (8 - checksum_length);
     136             : 
     137        1015 :     return (bits[0] & mask) == (bits[32] & mask);
     138        1015 : }
     139             : 
     140             : // passphrase must be at most 256 characters otherwise it would be truncated
     141        3119 : void CMnemonic::ToSeed(const SecureString& mnemonic, const SecureString& passphrase, SecureVector& seedRet)
     142             : {
     143             : 
     144        3119 :     SecureString ssSalt = SecureString("mnemonic") + passphrase;
     145        3119 :     SecureVector vchSalt(ssSalt.begin(), ssSalt.begin() + std::min<size_t>(256, ssSalt.size()));
     146        3119 :     seedRet.resize(64);
     147             :     // NOTE: c_str() here is fine because mnemonic has only [a-z ] characters
     148        3119 :     PKCS5_PBKDF2_HMAC_SHA512(mnemonic.c_str(), mnemonic.size(), vchSalt.data(), vchSalt.size(), 2048, 64, seedRet.data());
     149        3119 : }

Generated by: LCOV version 1.16