From a7ffdbdee049304753950f94d59f25ce1ea26c63 Mon Sep 17 00:00:00 2001 From: Mirek Kratochvil Date: Sat, 7 Nov 2015 23:17:09 +0100 Subject: [PATCH] bvector: use faster to/from string/byte conversion --- src/actions.cpp | 10 +++++---- src/algos_enc.cpp | 48 +++++++++++++++++----------------------- src/algos_sig.cpp | 20 ++++++----------- src/bvector.cpp | 51 +++++++++++++++++++++++++++++++------------ src/bvector.h | 13 +++++++++-- src/serialization.cpp | 14 ++++-------- 6 files changed, 85 insertions(+), 71 deletions(-) diff --git a/src/actions.cpp b/src/actions.cpp index 841c14d..1f0a0e4 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -519,7 +519,7 @@ int action_decrypt (bool armor, const std::string&symmetric, return 1; } - if (!plaintext.to_string (data)) { + if (!plaintext.to_string_check (data)) { err ("error: malformed data"); return 1; } @@ -862,7 +862,8 @@ int action_verify (bool armor, const std::string&detach, sencode_destroy (M); std::string tmp; - if (!msg.message.to_string (tmp) || tmp != MSG_CLEARTEXT) { + if (!msg.message.to_string_check (tmp) + || tmp != MSG_CLEARTEXT) { err ("error: malformed cleartext signature"); return 1; } @@ -913,7 +914,8 @@ int action_verify (bool armor, const std::string&detach, sencode_destroy (M); std::string tmp; - if (!msg.message.to_string (tmp) || tmp != MSG_DETACHED) { + if (!msg.message.to_string_check (tmp) + || tmp != MSG_DETACHED) { err ("error: malformed detached signature"); return 1; } @@ -1210,7 +1212,7 @@ int action_decrypt_verify (bool armor, bool yes, return 1; } - if (!bv.to_string (data)) { + if (!bv.to_string_check (data)) { err ("error: malformed data"); return 1; } diff --git a/src/algos_enc.cpp b/src/algos_enc.cpp index 4745978..8463ad7 100644 --- a/src/algos_enc.cpp +++ b/src/algos_enc.cpp @@ -133,20 +133,15 @@ static void msg_pad_length (const std::vector& msg, static void message_pad (const bvector&in, std::vector&out, prng&rng, hash_func&pad_hash) { - out.clear(); + in.to_bytes (out); //make space for the bit stage - if (in.size() == 0) out.resize (1, 0); - else out.resize ( ( (in.size() - 1) >> 3) + 2, 0); - - //copy message bits - uint i; - for (i = 0; i < in.size(); ++i) - if (in[i]) out[i >> 3] |= 1 << (i & 0x7); + out.resize (out.size() + 1, 0); //pad with random bits to whole byte unsigned char rtmp = rng.random (256); - for (; i & 0x7; ++i) + uint i; + for (i = in.size(); i & 0x7; ++i) if (rtmp >> (i & 0x7)) out[i >> 3] |= 1 << (i & 0x7); @@ -214,10 +209,7 @@ static bool message_unpad (std::vector in, bvector&out, //convert to bvector uint msg_size = ( (in_end - (bit_overflow ? 2 : 1)) << 3) + bit_overflow; - out.clear(); - out.resize (msg_size); - for (uint i = 0; i < msg_size; ++i) - out[i] = 1 & (in[i >> 3] >> (i & 0x7)); + out.from_bytes (in, msg_size); return true; } @@ -275,7 +267,7 @@ static int fo_encrypt (const bvector&plain, bvector&cipher, hash_type hf; H = hf (M2); - //prepare the error vector + //prepare the error vector (rotate the hash so we don't need ultralong hash functions) bvector ev_rank; ev_rank.resize (ranksize); for (i = 0; i < ranksize; ++i) @@ -286,8 +278,8 @@ static int fo_encrypt (const bvector&plain, bvector&cipher, //prepare plaintext bvector mce_plain; - mce_plain.resize (plainsize); - for (i = 0; i < plainsize; ++i) mce_plain[i] = 1 & (K[i >> 3] >> (i & 0x7)); + mce_plain.from_bytes (K); + mce_plain.resize (plainsize, 0); //pad with 0's to exact size //run McEliece if (Pub.encrypt (mce_plain, cipher, ev)) return 5; @@ -301,11 +293,10 @@ static int fo_encrypt (const bvector&plain, bvector&cipher, //encrypt for (i = 0; i < M.size(); ++i) M[i] = M[i] ^ sc.gen(); - //append the message part to the ciphertext - cipher.resize (ciphersize + (M.size() << 3)); - for (i = 0; i < (M.size() << 3); ++i) - cipher[ciphersize + i] = 1 & (M[i >> 3] >> (i & 0x7)); - + //append the message part to the key block. + bvector Mb; + Mb.from_bytes (M); + cipher.append (Mb); return 0; } @@ -375,13 +366,14 @@ static int fo_decrypt (const bvector&cipher, bvector&plain, //convert stuff to byte vectors std::vector K, M; - K.resize (plainsize >> 3, 0); - for (i = 0; i < plainsize; ++i) - if (mce_plain[i]) K[i >> 3] |= 1 << (i & 0x7); - M.resize (msize >> 3, 0); - for (i = 0; i < msize; ++i) - if (cipher[ciphersize + i]) M[i >> 3] |= 1 << (i & 0x7); + bvector Kb; + mce_plain.get_block (0, plainsize, Kb); + Kb.to_bytes (K); + + bvector Mb; + cipher.get_block (ciphersize, msize, Mb); + Mb.to_bytes (M); //prepare symmetric cipher scipher sc; @@ -403,7 +395,7 @@ static int fo_decrypt (const bvector&cipher, bvector&plain, bvector ev_rank; ev.colex_rank (ev_rank); ev_rank.resize (ranksize, 0); - for (i = 0; i < ranksize; ++i) + for (i = 0; i < ranksize; ++i) //cyclic hash repetition again if (ev_rank[i] != (1 & (H[ (i >> 3) % H.size()] >> (i & 0x7)))) return 7; diff --git a/src/algos_sig.cpp b/src/algos_sig.cpp index a3cfec1..1f2f2f3 100644 --- a/src/algos_sig.cpp +++ b/src/algos_sig.cpp @@ -57,16 +57,12 @@ typedef chacha20 padding_generator; -static void msg_pad (const bvector&in, std::vector&out, size_t minsize) +static void msg_pad (const bvector&in, std::vector&out, size_t tgt_size) { uint i; - out.clear(); - out.resize ( ( (in.size() - 1) >> 3) + 1, 0); - for (i = 0; i < in.size(); ++i) - if (in[i]) out[i >> 3] |= 1 << (i & 0x7); - - if (out.size() >= minsize) return; + in.to_bytes (out); + if (out.size() >= tgt_size) return; padding_generator g; g.init (); @@ -74,8 +70,8 @@ static void msg_pad (const bvector&in, std::vector&out, size_t minsize) g.load_key_vector (out); i = out.size(); - out.resize (minsize); - for (; i < minsize; ++i) out[i] = g.gen(); + out.resize (tgt_size); + for (; i < tgt_size; ++i) out[i] = g.gen(); } /* @@ -106,8 +102,7 @@ static int fmtseq_generic_sign (const bvector&msg, //convert to bvector bvector hash; - hash.resize (hs, 0); - for (uint i = 0; i < hs; ++i) hash[i] = 1 & (H[i >> 3] >> (i & 0x7)); + hash.from_bytes (H); //make a signature tree_hash hf; @@ -145,8 +140,7 @@ static int fmtseq_generic_verify (const bvector&sig, //convert to bvector bvector hash; - hash.resize (hs, 0); - for (uint i = 0; i < hs; ++i) hash[i] = 1 & (H[i >> 3] >> (i & 0x7)); + hash.from_bytes (H); //check the signature tree_hash hf; diff --git a/src/bvector.cpp b/src/bvector.cpp index d8d3f51..a2a55a0 100644 --- a/src/bvector.cpp +++ b/src/bvector.cpp @@ -199,6 +199,7 @@ void bvector::get_block (size_t offset, size_t bs, bvector&out) const uint bvector::and_hamming_weight (const bvector&a) const { + /* sizes must match */ uint r = 0; size_t s = _data.size(); if (s > a._data.size()) s = a._data.size(); @@ -222,26 +223,48 @@ void bvector::from_poly_cotrace (const polynomial&r, gf2m&fld) item (i) = (r[i % s] >> (i / s)) & 1; } -bool bvector::to_string (std::string& out) const +void bvector::to_bytes (std::vector& out) const { - if (size() & 0x7) return false; + out.resize ( (size() + 7) >> 3, 0); - out.clear(); - out.resize (size() >> 3, 0); - - for (size_t i = 0; i < size(); ++i) - if (item (i)) out[i >> 3] |= (1 << (i & 0x7)); - - return true; + for (size_t i = 0; i < size(); i += 8) + out[i >> 3] = (_data[i >> 6] + >> ( ( (i >> 3) & 7) << 3)) & 0xff; } -void bvector::from_string (const std::string&in) +void bvector::to_string (std::string& out) const { - clear(); - resize (in.length() << 3); + out.resize ( (size() + 7) >> 3, '\0'); - for (size_t i = 0; i < size(); ++i) - item (i) = (in[i >> 3] >> (i & 0x7)) & 1; + for (size_t i = 0; i < size(); i += 8) + out[i >> 3] = (_data[i >> 6] + >> ( ( (i >> 3) & 7) << 3)) & 0xff; +} + +void bvector::from_string (const std::string&in, size_t bits) +{ + if (bits) resize (bits); + else resize (in.length() << 3); + fill_zeros(); + + for (size_t i = 0; i < size(); i += 8) + _data[i >> 6] |= + ( (uint64_t) (unsigned char) in[i >> 3]) + << ( ( (i >> 3) & 7) << 3); + fix_padding(); +} + +void bvector::from_bytes (const std::vector&in, size_t bits) +{ + if (bits) resize (bits); + else resize (in.size() << 3); + fill_zeros(); + + for (size_t i = 0; i < size(); i += 8) + _data[i >> 6] |= + ( (uint64_t) (unsigned char) in[i >> 3]) + << ( ( (i >> 3) & 7) << 3); + fix_padding(); } /* diff --git a/src/bvector.h b/src/bvector.h index 029d11e..1e57a8d 100644 --- a/src/bvector.h +++ b/src/bvector.h @@ -197,8 +197,17 @@ public: void colex_rank (bvector&) const; bool colex_unrank (bvector&, uint n, uint k) const; - bool to_string (std::string&) const; - void from_string (const std::string&); + void to_string (std::string&) const; + void to_bytes (std::vector&) const; + + bool to_string_check (std::string&s) const { + if (size() & 7) return false; + to_string (s); + return true; + } + + void from_string (const std::string&, size_t bits = 0); + void from_bytes (const std::vector&, size_t bits = 0); sencode* serialize(); bool unserialize (sencode*); diff --git a/src/serialization.cpp b/src/serialization.cpp index 1a54361..1df792e 100644 --- a/src/serialization.cpp +++ b/src/serialization.cpp @@ -62,14 +62,10 @@ static bool unserialize_uint_vector (std::vector*v, sencode*s) sencode* bvector::serialize() { - uint ss = (size() + 7) / 8; std::string bytes; - bytes.resize (ss, '\0'); //the padding of each vector is zero, we can stuff the bytes right in. Just make it sure here: fix_padding(); - - for (size_t i = 0; i < size(); i += 8) - bytes[i >> 3] = (_data[i >> 6] >> ( ( (i >> 3) & 7) << 3)) & 0xff; + to_string (bytes); sencode_list*l = new sencode_list; l->items.push_back (new sencode_int (size())); @@ -85,19 +81,17 @@ bool bvector::unserialize (sencode* s) sencode_int*CAST_INT (l->items[0], size); sencode_bytes*CAST_BYTES (l->items[1], bytes); if (bytes->b.size() != ( (size->i + 7) / 8)) return false; - clear(); - resize (size->i, 0); - for (i = 0; i < _size; i += 8) - _data[i >> 6] |= ( (uint64_t) (unsigned char) bytes->b[i >> 3]) << ( ( (i >> 3) & 7) << 3); /* * the important part. verify that padding is always zero, because * sencode serialization must be bijective */ - for (i = _size; i < 8 * bytes->b.size(); ++i) + for (i = size->i; i < 8 * bytes->b.size(); ++i) if ( (bytes->b[i / 8] >> (i % 8)) & 1) return false; + from_string (bytes->b, size->i); + return true; }