I had the same issue as in this (very) old unanswered thread below. It took me quite a while to figure out why. In case it might help someone else puzzled by the same, the root cause is insufficient buffer size. Specifically, the "Shares[i]" should be made larger.
Based on the original poster's code, the "last byte or two" problem can be shown by: const Bytes secret = {0x01, 0x02, 0x03, 0x04, 0x05}; const auto shares = SecretShareBytes(secret, 3, 7); std::vector<Bytes> partial; partial.push_back(shares[6]); partial.push_back(shares[3]); partial.push_back(shares[5]); const auto recovered = SecretRecoverBytes(partial, partial.size()); std::cout << "Secret -> " << std::dec << secret.size() << " bytes: "; for (const auto & uch : secret) std::cout << std::hex << std::setfill('0') << std::setw(2) << static_cast<unsigned>(uch) << " "; std::cout << std::endl; std::cout << "Recovered -> " << std::dec << recovered.size() << " bytes: "; for (const auto & uch : recovered) std::cout << std::hex << std::setfill('0') << std::setw(2) << static_cast<unsigned>(uch) << " "; std::cout << std::endl; The output will be something like: Secret -> 5 bytes: 01 02 03 04 05 Recovered -> 5 bytes: 01 02 03 04 7a What I found is that if the output is to FileSink (as in https://github.com/weidai11/cryptopp/blob/master/test.cpp#L657), the share/recovery works perfectly. Yet strangely ArraySink always gives trouble. The culprit seems to be in: shares[i] = Bytes( secret.size() + sizeof(int) ); This should be given a larger size. Otherwise the outputs of SecretSharing are chopped off. With the incomplete shares, re-construction can't be successful. There might be a way to precisely decide the correct buffer size for the shares. However, I find it easier to use ostringstream to manage the buffers. Counter-intuitively, ArraySink will have to be replaced by FileSink, due to the fact that ArraySink only accepts fixed length buffers. With this change, the original poster's code would look like: std::vector<Bytes> SecretShareBytes(const Bytes& secret, int threshold, int nShares) { CryptoPP::AutoSeededRandomPool rng; CryptoPP::ChannelSwitch *channelSwitch; CryptoPP::ArraySource source( secret.data(), secret.size(), false,new CryptoPP::SecretSharing( rng, threshold, nShares, channelSwitch = new CryptoPP::ChannelSwitch) ); std::vector<std::ostringstream> shares( nShares ); CryptoPP::vector_member_ptrs<CryptoPP::FileSink> sinks( nShares ); std::string channel; for (int i = 0; i < nShares; i++) { sinks[i].reset( new CryptoPP::FileSink(shares[i])); channel = CryptoPP::WordToString<word32>(i); sinks[i]->Put( (byte *)channel.data(), 4 ); channelSwitch->AddRoute( channel,*sinks[i], DEFAULT_CHANNEL); } source.PumpAll(); std::vector<Bytes> ret; for (const auto &share : shares) { const auto & piece = share.str(); ret.push_back(Bytes(piece.begin(), piece.begin() + piece.size())); } return move(ret); } Bytes SecretRecoverBytes(std::vector<Bytes>& shares, int threshold) { std::ostringstream out; CryptoPP::SecretRecovery recovery( threshold, new CryptoPP::FileSink(out) ); CryptoPP::SecByteBlock channel(4); for (int i = 0; i < threshold; i++) { CryptoPP::ArraySource arraySource(shares[i].data(), shares[i].size(), false); arraySource.Pump(4); arraySource.Get( channel, 4 ); arraySource.Attach( new CryptoPP::ChannelSwitch( recovery, std::string( (char *)channel.begin(), 4) ) ); arraySource.PumpAll(); } const auto & secret = out.str(); return Bytes(secret.begin(), secret.begin() + secret.size()); } And the print out will be correct. Secret -> 5 bytes: 01 02 03 04 05 Recovered -> 5 bytes: 01 02 03 04 05 On Friday, 11 December 2015 10:34:42 UTC, Whou Lee wrote: > > Hi, all! > I am trying to make CryptoPP::SecretSharing to work with in memory byte > objects. > My current solution partly works. I can reconstruct the original secret > except for the last byte or two, depends on the length of original secret. > Could you please suggest me how to fix this. > > The code: > std::vector<Bytes> SecretShareBytes(const Bytes& secret, int threshold, > int nShares) > { > CryptoPP::AutoSeededRandomPool rng; > > CryptoPP::ChannelSwitch *channelSwitch; > CryptoPP::ArraySource source( secret.data(), secret.size(), false,new > CryptoPP::SecretSharing( rng, threshold, nShares, channelSwitch = new > CryptoPP::ChannelSwitch) ); > > std::vector<Bytes> shares( nShares ); > CryptoPP::vector_member_ptrs<CryptoPP::ArraySink> arraySinks( nShares ); > std::string channel; > for (int i = 0; i < nShares; i++) > { > shares[i] = Bytes( secret.size() + sizeof(int) ); > arraySinks[i].reset( new CryptoPP::ArraySink((byte*)shares[i].data(), > shares[i].size()) ); > > channel = CryptoPP::WordToString<word32>(i); > arraySinks[i]->Put( (byte *)channel.data(), 4 ); > channelSwitch->AddRoute( > channel,*arraySinks[i],CryptoPP::BufferedTransformation::NULL_CHANNEL ); > } > > source.PumpAll(); > return shares; > } > > > Bytes SecretRecoverBytes(std::vector<Bytes>& shares, int threshold) > { > Bytes bytes( shares[0].size() - sizeof( int ) ); > CryptoPP::SecretRecovery recovery( threshold, new > CryptoPP::ArraySink(bytes.data(), bytes.size()) ); > > CryptoPP::SecByteBlock channel(4); > for (int i = 0; i < threshold; i++) > { > CryptoPP::ArraySource arraySource(shares[i].data(), shares[i].size(), > false); > > arraySource.Pump(4); > arraySource.Get( channel, 4 ); > arraySource.Attach( new CryptoPP::ChannelSwitch( recovery, std::string( > (char *)channel.begin(), 4) ) ); > > arraySource.PumpAll(); > } > > return bytes; > } > -- -- You received this message because you are subscribed to the "Crypto++ Users" Google Group. To unsubscribe, send an email to cryptopp-users-unsubscr...@googlegroups.com. More information about Crypto++ and this group is available at http://www.cryptopp.com. --- You received this message because you are subscribed to the Google Groups "Crypto++ Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to cryptopp-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.