Skip to content
Snippets Groups Projects
Unverified Commit 8cf5fadd authored by Recolic Keghart's avatar Recolic Keghart
Browse files

init

parents
No related branches found
No related tags found
No related merge requests found
.idea
.vscode
cmake-build-debug
build
cmake_minimum_required(VERSION 3.14)
project(udp_forwarder_ng)
find_package(rlib)
set(CMAKE_CXX_STANDARD 14)
include_directories(./lib)
include_directories(.)
add_executable(udp_forwarder_ng main.cc Forwarder.hpp Crypto.hpp Dictionary.hpp)
target_link_libraries(udp_forwarder_ng r)
add_executable(crypto_test test/TestCrypto.cc Crypto.hpp Dictionary.hpp)
target_link_libraries(crypto_test r)
//
// Created by recolic on 19-6-9.
//
#ifndef UDP_FORWARDER_NG_CRYPTO_HPP
#define UDP_FORWARDER_NG_CRYPTO_HPP
#include <string>
#include <numeric>
#include <limits>
#include "Dictionary.hpp"
#if defined(__linux__)
# include <endian.h>
#include <rlib/stdio.hpp>
#elif defined(__FreeBSD__) || defined(__NetBSD__)
# include <sys/endian.h>
#elif defined(__OpenBSD__)
# include <sys/types.h>
# define be16toh(x) betoh16(x)
# define be32toh(x) betoh32(x)
# define be64toh(x) betoh64(x)
#endif
using std::string;
class Crypto {
public:
Crypto() = default;
void convertL2R(string &data, const string &lKey, const string &rKey) {
// If lKey is not null, decrypt the data.
// If rKey is not null, encrypt the data.
if(!lKey.empty()) {
decrypt(data, lKey);
}
if(!rKey.empty()) {
encrypt(data, rKey);
}
}
private:
static constexpr inline float sq(float a) {return a*a;}
string uint64ToBinStr(uint64_t n) {
n = htobe64(n); // to network byte order
string s (sizeof(uint64_t) / sizeof(char), '\0');
*(uint64_t *)s.data() = n;
return s;
}
uint64_t uint64FromBinStr(const string &s) {
auto n = *(uint64_t *)s.data();
return be64toh(n);
}
void encrypt(string &data, const string &key) {
auto message_len = data.size();
auto postfix_len = (size_t)(message_len * (sq((float)xorshf_rand.get() / std::numeric_limits<uint64_t>::max())));
if(postfix_len > crypto_dictionary.size()) {
postfix_len = 0;
}
if(postfix_len + dict_current_index >= crypto_dictionary.size()) {
dict_current_index = 0;
}
string toEncrypt = "r" + uint64ToBinStr(message_len) + data + crypto_dictionary.substr(dict_current_index, postfix_len);
string nonce = uint64ToBinStr(xorshf_rand.get());
block_encrypt(toEncrypt, key, nonce);
data = nonce + toEncrypt;
// PACKET:
// nonce 'r' msgLen payload junk
// 0 8 9 17 17+len end
}
void block_encrypt(string &data, const string &key, const string &nonce) {
// nonce is unique for every packet.
// key is shared by all packets.
for(auto cter = 0; cter < data.size(); ++cter) {
const auto key_index = cter % key.size();
const auto nonce_index = cter % nonce.size();
data[cter] ^= key[key_index] ^ nonce[nonce_index];
}
}
void decrypt(string &data, const string &key) {
if(data.size() < 8)
throw std::runtime_error("Decrypt: Data length less than 8. ");
string nonce = data.substr(0, 8);
string toDecrypt = data.substr(8);
block_decrypt(toDecrypt, key, nonce);
if(toDecrypt.size() < 9)
throw std::runtime_error("Decrypt: decrypted data length less than 9. ");
if(toDecrypt[0] != 'r')
throw std::runtime_error("Decrypt: decrypted magic number incorrect. ");
uint64_t msgLen = uint64FromBinStr(toDecrypt.substr(1, 9));
if(toDecrypt.size() < 9+msgLen)
throw std::runtime_error("Decrypt: decrypted data length < 9+payloadLength");
data = toDecrypt.substr(9, msgLen);
}
void block_decrypt(string &data, const string &key, const string &nonce) {
return block_encrypt(data, key, nonce);
}
size_t dict_current_index = 0;
struct {
uint64_t x=123456789, y=362436069, z=521288629;
uint64_t get() {
uint64_t t;
x ^= x << 16;
x ^= x >> 5;
x ^= x << 1;
t = x;
x = y;
y = z;
z = t ^ x ^ y;
return z;
}
} xorshf_rand;
};
#endif //UDP_FORWARDER_NG_CRYPTO_HPP
#ifndef _UDP_FORWARDER_NG_DICTIONARY_HPP
#define _UDP_FORWARDER_NG_DICTIONARY_HPP 1
#include <string>
const std::string crypto_dictionary = R"RSTR(
Optimizing C++/Code optimization/Faster operations
< Optimizing C++ | Code optimization
Jump to navigationJump to search
Optimizing C++
Cover
Introduction
Optimization life cycle
Writing efficient code
Performance improving features
Performance worsening features
Constructions and destructions
Allocations and deallocations
Memory access
Thread usage
General optimization techniques
Input/Output
Memoization
Sorting
Other techniques
Code optimization
Allocations and deallocations
Run-time support
Instruction count
Constructions and destructions
Pipeline
Memory access
Faster operations
Some elementary operations, even being conceptually as simple as others, are much faster for the processor. A clever programmer can choose the faster instructions for the job.
Though, every optimizing compiler is already able to choose the fastest instructions for the target processor, and so some techniques are useless with some compilers.
In addition, some techniques may even worsen performance on some processors.
In this section some techniques are presented that may improve performance on some compiler/processor combinations.
Contents
1 Structure fields order
2 Floating point to integer conversion
3 Integer numbers bit twiddling
4 Array cells size
5 Prefix vs. Postfix Operators
6 Explicit inlining
7 Operations with powers of two
8 Integer division by a constant
9 Processors with reduced data bus
10 Rearrange an array of structures as several arrays
Structure fields order
Arrange the member variables of classes and structures in such a way that the most used variables are in the first 128 bytes, and then sorted from the longest object to the shortest.
If in the following structure the msg member is used only for error messages, while the other members are used for computations:
struct {
char msg[400];
double d;
int i;
};
you can speed up the computation by replacing the structure with the following one:
struct {
double d;
int i;
char msg[400];
};
On some processors, the addressing of a member is more efficient if its distance from the beginning of the structure is less than 128 bytes.
In the first example, to address the d and i fields using a pointer to the beginning of the structure, an offset of at least 400 bytes is required.
Instead, in the second example, containing the same fields in a different order, the offsets to address d and i are of few bytes, and this allows to use more compact instructions.
Now, let's assume you wrote the following structure:
struct {
bool b;
double d;
short s;
int i;
};
Because of fields alignment, it typically occupies 1 (bool) + 7 (padding) + 8 (double) + 2 (short) + 2 (padding) + 4 (int) = 24 bytes.
The following structure is obtained from the previous one by sorting the fields from the longest to the shortest:
struct {
double d;
int i;
short s;
bool b;
};
It typically occupies 8 (double) + 4 (int) + 2 (short) + 1 (bool) + 1 (padding) = 16 bytes. The sorting minimized the paddings (or holes) caused by the alignment requirements, and so generates a more compact structure.
Floating point to integer conversion
Exploit non-standard routines to round floating point numbers to integer numbers.
The C++ language do not provide a primitive operation to round floating point numbers. The simplest technique to convert a floating point number x to the nearest integer number n is the following statement:
n = int(floor(x + 0.5f));
Using such a technique, if x is exactly equidistant between two integers, n will be the upper integer (for example, 0.5 generates 1, 1.5 generates 2, -0.5 generates 0, and -1.5 generates -1).
Unfortunately, on some processors (in particular, the Pentium family), such expression is compiled in a very slow machine code. Some processors have specific instructions to round numbers.
In particular, the Pentium family has the instruction fistp, that, used as in the following code, gives much faster, albeit not exactly equivalent, code:
#if defined(__unix__) || defined(__GNUC__)
// For 32-bit Linux, with Gnu/AT&T syntax
__asm ("fldl %1 \n fistpl %0 " : "=m"(n) : "m"(x) : "memory" );
#else
// For 32-bit Windows, with Intel/MASM syntax
__asm fld qword ptr x;
__asm fistp dword ptr n;
#endif
The above code rounds x to the nearest integer, but if x is exactly equidistant between to integers, n will be the nearest even integer (for example, 0.5 generates 0, 1.5 generates 2, -0.5 generates 0, and -1.5 generates -2).
If this result is tolerable or even desired, and you are allowed to use embedded assembly, then use this code. Obviously, it is not portable to other processor families.
Integer numbers bit twiddling
Twiddle the bits of integer numbers exploiting your knowledge of their representation.
A collection of hacks of this kind is here. Some of these tricks are actually already used by some compilers, others are useful to solve rare problems, others are useful only on some platforms.
Array cells size
Ensure that the size (resulting from the sizeof operator) of non-large cells of arrays or of vectors be a power of two, and that the size of large cells of arrays or of vectors be not a power of two.
The direct access to an array cell is performed by multiplying the index by the cell size, that is a constant. If the second factor of this multiplication is a power of two, such an operation is much faster, as it is performed as a bit shift. Analogously, in multidimensional arrays, all the sizes, except at most the first one, should be powers of two.
This sizing is obtained by adding unused fields to structures and unused cells to arrays. For example, if every cell is a 3-tuple of float objects, it is enough to add a fourth dummy float object to every cell.
Though, when accessing the cells of a multidimensional array in which the last dimension is an enough large power of two, you can drop into the data cache contention phenomenon (aka data cache conflict), that may slow down the computation by a factor of 10 or more. This phenomenon happens only when the array cells exceed a certain size, that depends on the data cache, but is about 1 to 8 KB. Therefore, in case an algorithm has to process an array whose cells have or could have as size a power of two greater or equal to 1024 bytes, first, you should detect if the data cache contention happens, in such a case you should avoid such phenomenon.
For example, a matrix of 100 x 512 float objects is an array of 100 arrays of 512 floats. Every cell of the first-level array has a size of 512 x 4 = 2048 bytes, and therefore it is at risk of data cache contention.
To detect the contention, it is enough to add an elementary cell (a float) to every to every last-level array, but keeping to process the same cells than before, and measure whether the processing time decrease substantially (by at least 20%). In such a case, you have to ensure that such improvement be stabilized. For that goal, you can employ one of the following techniques:
Add one or more unused cells at the end of every last-level array. For example, the array double a[100][1024] could become double a[100][1026], even if the computation will process such an array up to the previous sizes.
Keep the array sizes, but partition it in rectangular blocks, and process all the cells in one block at a time.
Prefix vs. Postfix Operators
Prefer prefix operators over postfix operators.
When dealing with primitive types, the prefix and postfix arithmetic operations are likely to have identical performance. With objects, however, postfix operators can cause the object to create a copy of itself to preserve its initial state (to be returned as a result of the operation), as well as causing the side-effect of the operation. Consider the following example:
class IntegerIncreaser
{
int m_Value;
public:
/* Postfix operator. */
IntegerIncreaser operator++ (int) {
IntegerIncreaser tmp (*this);
++m_Value;
return tmp;
};
/* Prefix operator. */
IntegerIncreaser operator++ () {
++m_Value;
return *this;
};
};
Because the postfix operators are required to return an unaltered version of the value being incremented (or decremented) — regardless of whether the result is actually being used — they will most likely make a copy. STL iterators (for example) are more efficient when altered with the prefix operators.
Explicit inlining
If you don't use the compiler options of whole program optimization and to allow the compiler to inline any function, try to move to the header files the functions called in bottlenecks, and declare them inline.
As explained in the guideline "Inlined functions" in section 3.1, every inlined function is faster, but many inlined functions slow down the whole program.
Try to declare inline a couple of functions at a time, as long as you get significant speed improvements (at least 10%) in a single command.
Operations with powers of two
If you have to choose an integer constant by which you have to multiply or divide often, choose a power of two.
The multiplication, division, and modulo operations between integer numbers are much faster if the second operand is a constant power of two, as in such case they are implemented as bit shifts or bit maskings.
Integer division by a constant
When you divide an integer (that is known to be positive or zero) by a constant, convert the integer to unsigned.
If s is a signed integer, u is an unsigned integer, and C is a constant integer expression (positive or negative), the operation s / C is slower than u / C, and s % C is slower than u % C. This is most significant when C is a power of two, but in all cases, the sign must be taken into account during division.
The conversion from signed to unsigned, however, is free of charge, as it is only a reinterpretation of the same bits. Therefore, if s is a signed integer that you know to be positive or zero, you can speed up its division using the following (equivalent) expressions: (unsigned)s / C and (unsigned)s % C.
Processors with reduced data bus
If the data bus of the target processor is smaller than the processor registers, if possible, use integer types not larger than the data bus for all the variables except for function parameters and for the most used local variables.
The types int and unsigned int are the most efficient, after they have been loaded in processor registers. Though, with some processor families, they could not be the most efficient type to access in memory.
For example, there are processors having 16-bit registers, but an 8-bit data bus, and other processors having 32-bit registers, but 16-bit data bus. For processors having the data bus smaller than the internal registers, usually the types int and unsigned int match the size of the registers.
For such systems, loading and storing in memory an int object takes a longer time than that taken by an integer not larger than the data bus.
The function arguments and the most used local variables are usually allocated in registers, and therefore do not cause memory access.
Rearrange an array of structures as several arrays
Instead of processing a single array of aggregate objects, process in parallel two or more arrays having the same length.
For example, instead of the following code:
const int n = 10000;
struct { double a, b, c; } s[n];
for (int i = 0; i < n; ++i) {
s[i].a = s[i].b + s[i].c;
}
the following code may be faster:
const int n = 10000;
double a[n], b[n], c[n];
for (int i = 0; i < n; ++i) {
a[i] = b[i] + c[i];
}
Using this rearrangement, "a", "b", and "c" may be processed by array processing instructions that are significantly faster than scalar instructions. This optimization may have null or adverse results on some (simpler) architectures.
Even better is to interleave the arrays:
const int n = 10000;
double interleaved[n * 3];
for (int i = 0; i < n; ++i) {
const size_t idx = i * 3;
interleaved[idx] = interleaved[idx + 1] + interleaved[idx + 2];
}
Remember test everything! And don't optimise prematurely.
Category: Book:Optimizing C++
Navigation menu
Not logged inDiscussion for this IP addressContributionsCreate accountLog inBookDiscussionReadEditView historySearch
Search Wikibooks
Main Page
Help
Browse
Cookbook
Wikijunior
Featured books
Recent changes
Donations
Random book
Using Wikibooks
Community
Reading room
Community portal
Bulletin Board
Help out!
Policies and guidelines
Contact us
Tools
What links here
Related changes
Upload file
Special pages
Permanent link
Page information
Cite this page
In other languages
Italiano
Add links
Sister projects
Wikipedia
Wikiversity
Wiktionary
Wikiquote
Wikisource
Wikinews
Wikivoyage
Commons
Wikidata
Print/export
Create a collection
Download as PDF
Printable version
This page was last edited on 26 August 2016, at 02:04.
Text is available under the Creative Commons Attribution-ShareAlike License.; additional terms may apply. By using this site, you agree to the Terms of Use and Privacy Policy.
Privacy policyAbout WikibooksDisclaimersDevelopersCookie statementMobile viewWikimedia Foundation Powered by MediaWiki
)RSTR";
#endif //_UDP_FORWARDER_NG_DICTIONARY_HPP
//
// Created by recolic on 19-6-9.
//
#ifndef UDP_FORWARDER_NG_FORWARDER_HPP
#define UDP_FORWARDER_NG_FORWARDER_HPP
#include <string>
#include <picosha2.h>
#include <rlib/sys/sio.hpp>
#include <sys/epoll.h>
#include <rlib/stdio.hpp>
#include "Crypto.hpp"
using std::string;
using namespace std::literals;
class Forwarder {
public:
Forwarder(string listenAddr, uint16_t listenPort, string serverAddr, uint16_t serverPort, string lPassword,
string rPassword)
: listenAddr(listenAddr), listenPort(listenPort), serverAddr(serverAddr), serverPort(serverPort),
lKey(picosha2::k_digest_size, '\0'), rKey(picosha2::k_digest_size, '\0') {
picosha2::hash256(lPassword.begin(), lPassword.end(), lKey.begin(), lKey.end());
picosha2::hash256(rPassword.begin(), rPassword.end(), rKey.begin(), rKey.end());
if(lPassword.empty())
lKey = "";
if(rPassword.empty())
rKey = "";
}
private:
auto setup_epoll(fd_t listenFd, fd_t serverFd) {
auto epollFd = epoll_create1(NULL);
if(epollFd == -1)
throw std::runtime_error("Failed to create epoll fd.");
// setup epoll.
epoll_event eventL {
.events = EPOLLIN,
.data.fd = listenFd,
}, eventS {
.events = EPOLLIN,
.data.fd = serverFd,
};
auto ret1 = epoll_ctl(epollFd, EPOLL_CTL_ADD, listenFd, &eventL);
auto ret2 = epoll_ctl(epollFd, EPOLL_CTL_ADD, serverFd, &eventS);
if(ret1 == -1 or ret2 == -1)
throw std::runtime_error("epoll_ctl failed.");
return epollFd;
}
public:
[[noreturn]] void run() {
// setup connections.
auto listenFd = rlib::quick_listen(listenAddr, listenPort, true);
auto serverFd = rlib::quick_connect(serverAddr, serverPort, true);
auto epollFd = setup_epoll(listenFd, serverFd);
constexpr size_t MAX_EVENTS = 16;
epoll_event events[MAX_EVENTS];
// DGRAM packet usually smaller than 1400B.
constexpr size_t DGRAM_BUFFER_SIZE = 20480; // 20KiB
char buffer[DGRAM_BUFFER_SIZE];
// Main loop!
while(true) {
auto nfds = epoll_wait(epollFd, events, MAX_EVENTS, -1);
if(nfds == -1)
throw std::runtime_error("epoll_wait failed.");
for(auto cter = 0; cter < nfds; ++cter) {
auto recvFd = events[cter].data.fd;
auto recvSideIsListenSide = recvFd == listenFd;
auto anotherFd = recvSideIsListenSide ? serverFd : listenFd;
const auto &recvSideKey = recvSideIsListenSide ? lKey : rKey;
const auto &sendSideKey = recvSideIsListenSide ? rKey : lKey;
try {
auto size = recvfrom(recvFd, buffer, DGRAM_BUFFER_SIZE, NULL, NULL, NULL);
if(size == -1) {
throw std::runtime_error("ERR: recvfrom returns -1. "s + strerror(errno));
}
string bufferStr (std::begin(buffer), std::begin(buffer) + size);
crypto.convertL2R(bufferStr, recvSideKey, sendSideKey);
size = sendto(anotherFd, bufferStr.data(), bufferStr.size(), NULL, NULL, NULL);
if(size == -1) {
throw std::runtime_error("ERR: sendto returns -1. "s + strerror(errno));
}
if(size != bufferStr.size()) {
rlib::println("ERR: sendto not sent all data.");
}
}
catch(std::exception &e) {
rlib::println(e.what());
}
}
}
}
private:
string listenAddr;
uint16_t listenPort;
string serverAddr;
uint16_t serverPort;
string lKey;
string rKey;
Crypto crypto;
};
#endif //UDP_FORWARDER_NG_FORWARDER_HPP
/*
The MIT License (MIT)
Copyright (C) 2017 okdshin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef PICOSHA2_H
#define PICOSHA2_H
// picosha2:20140213
#ifndef PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR
#define PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR \
1048576 //=1024*1024: default is 1MB memory
#endif
#include <algorithm>
#include <cassert>
#include <iterator>
#include <sstream>
#include <vector>
#include <fstream>
namespace picosha2 {
typedef unsigned long word_t;
typedef unsigned char byte_t;
static const size_t k_digest_size = 32;
namespace detail {
inline byte_t mask_8bit(byte_t x) { return x & 0xff; }
inline word_t mask_32bit(word_t x) { return x & 0xffffffff; }
const word_t add_constant[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
const word_t initial_message_digest[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372,
0xa54ff53a, 0x510e527f, 0x9b05688c,
0x1f83d9ab, 0x5be0cd19};
inline word_t ch(word_t x, word_t y, word_t z) { return (x & y) ^ ((~x) & z); }
inline word_t maj(word_t x, word_t y, word_t z) {
return (x & y) ^ (x & z) ^ (y & z);
}
inline word_t rotr(word_t x, std::size_t n) {
assert(n < 32);
return mask_32bit((x >> n) | (x << (32 - n)));
}
inline word_t bsig0(word_t x) { return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22); }
inline word_t bsig1(word_t x) { return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25); }
inline word_t shr(word_t x, std::size_t n) {
assert(n < 32);
return x >> n;
}
inline word_t ssig0(word_t x) { return rotr(x, 7) ^ rotr(x, 18) ^ shr(x, 3); }
inline word_t ssig1(word_t x) { return rotr(x, 17) ^ rotr(x, 19) ^ shr(x, 10); }
template <typename RaIter1, typename RaIter2>
void hash256_block(RaIter1 message_digest, RaIter2 first, RaIter2 last) {
assert(first + 64 == last);
static_cast<void>(last); // for avoiding unused-variable warning
word_t w[64];
std::fill(w, w + 64, 0);
for (std::size_t i = 0; i < 16; ++i) {
w[i] = (static_cast<word_t>(mask_8bit(*(first + i * 4))) << 24) |
(static_cast<word_t>(mask_8bit(*(first + i * 4 + 1))) << 16) |
(static_cast<word_t>(mask_8bit(*(first + i * 4 + 2))) << 8) |
(static_cast<word_t>(mask_8bit(*(first + i * 4 + 3))));
}
for (std::size_t i = 16; i < 64; ++i) {
w[i] = mask_32bit(ssig1(w[i - 2]) + w[i - 7] + ssig0(w[i - 15]) +
w[i - 16]);
}
word_t a = *message_digest;
word_t b = *(message_digest + 1);
word_t c = *(message_digest + 2);
word_t d = *(message_digest + 3);
word_t e = *(message_digest + 4);
word_t f = *(message_digest + 5);
word_t g = *(message_digest + 6);
word_t h = *(message_digest + 7);
for (std::size_t i = 0; i < 64; ++i) {
word_t temp1 = h + bsig1(e) + ch(e, f, g) + add_constant[i] + w[i];
word_t temp2 = bsig0(a) + maj(a, b, c);
h = g;
g = f;
f = e;
e = mask_32bit(d + temp1);
d = c;
c = b;
b = a;
a = mask_32bit(temp1 + temp2);
}
*message_digest += a;
*(message_digest + 1) += b;
*(message_digest + 2) += c;
*(message_digest + 3) += d;
*(message_digest + 4) += e;
*(message_digest + 5) += f;
*(message_digest + 6) += g;
*(message_digest + 7) += h;
for (std::size_t i = 0; i < 8; ++i) {
*(message_digest + i) = mask_32bit(*(message_digest + i));
}
}
} // namespace detail
template <typename InIter>
void output_hex(InIter first, InIter last, std::ostream& os) {
os.setf(std::ios::hex, std::ios::basefield);
while (first != last) {
os.width(2);
os.fill('0');
os << static_cast<unsigned int>(*first);
++first;
}
os.setf(std::ios::dec, std::ios::basefield);
}
template <typename InIter>
void bytes_to_hex_string(InIter first, InIter last, std::string& hex_str) {
std::ostringstream oss;
output_hex(first, last, oss);
hex_str.assign(oss.str());
}
template <typename InContainer>
void bytes_to_hex_string(const InContainer& bytes, std::string& hex_str) {
bytes_to_hex_string(bytes.begin(), bytes.end(), hex_str);
}
template <typename InIter>
std::string bytes_to_hex_string(InIter first, InIter last) {
std::string hex_str;
bytes_to_hex_string(first, last, hex_str);
return hex_str;
}
template <typename InContainer>
std::string bytes_to_hex_string(const InContainer& bytes) {
std::string hex_str;
bytes_to_hex_string(bytes, hex_str);
return hex_str;
}
class hash256_one_by_one {
public:
hash256_one_by_one() { init(); }
void init() {
buffer_.clear();
std::fill(data_length_digits_, data_length_digits_ + 4, 0);
std::copy(detail::initial_message_digest,
detail::initial_message_digest + 8, h_);
}
template <typename RaIter>
void process(RaIter first, RaIter last) {
add_to_data_length(static_cast<word_t>(std::distance(first, last)));
std::copy(first, last, std::back_inserter(buffer_));
std::size_t i = 0;
for (; i + 64 <= buffer_.size(); i += 64) {
detail::hash256_block(h_, buffer_.begin() + i,
buffer_.begin() + i + 64);
}
buffer_.erase(buffer_.begin(), buffer_.begin() + i);
}
void finish() {
byte_t temp[64];
std::fill(temp, temp + 64, 0);
std::size_t remains = buffer_.size();
std::copy(buffer_.begin(), buffer_.end(), temp);
temp[remains] = 0x80;
if (remains > 55) {
std::fill(temp + remains + 1, temp + 64, 0);
detail::hash256_block(h_, temp, temp + 64);
std::fill(temp, temp + 64 - 4, 0);
} else {
std::fill(temp + remains + 1, temp + 64 - 4, 0);
}
write_data_bit_length(&(temp[56]));
detail::hash256_block(h_, temp, temp + 64);
}
template <typename OutIter>
void get_hash_bytes(OutIter first, OutIter last) const {
for (const word_t* iter = h_; iter != h_ + 8; ++iter) {
for (std::size_t i = 0; i < 4 && first != last; ++i) {
*(first++) = detail::mask_8bit(
static_cast<byte_t>((*iter >> (24 - 8 * i))));
}
}
}
private:
void add_to_data_length(word_t n) {
word_t carry = 0;
data_length_digits_[0] += n;
for (std::size_t i = 0; i < 4; ++i) {
data_length_digits_[i] += carry;
if (data_length_digits_[i] >= 65536u) {
carry = data_length_digits_[i] >> 16;
data_length_digits_[i] &= 65535u;
} else {
break;
}
}
}
void write_data_bit_length(byte_t* begin) {
word_t data_bit_length_digits[4];
std::copy(data_length_digits_, data_length_digits_ + 4,
data_bit_length_digits);
// convert byte length to bit length (multiply 8 or shift 3 times left)
word_t carry = 0;
for (std::size_t i = 0; i < 4; ++i) {
word_t before_val = data_bit_length_digits[i];
data_bit_length_digits[i] <<= 3;
data_bit_length_digits[i] |= carry;
data_bit_length_digits[i] &= 65535u;
carry = (before_val >> (16 - 3)) & 65535u;
}
// write data_bit_length
for (int i = 3; i >= 0; --i) {
(*begin++) = static_cast<byte_t>(data_bit_length_digits[i] >> 8);
(*begin++) = static_cast<byte_t>(data_bit_length_digits[i]);
}
}
std::vector<byte_t> buffer_;
word_t data_length_digits_[4]; // as 64bit integer (16bit x 4 integer)
word_t h_[8];
};
inline void get_hash_hex_string(const hash256_one_by_one& hasher,
std::string& hex_str) {
byte_t hash[k_digest_size];
hasher.get_hash_bytes(hash, hash + k_digest_size);
return bytes_to_hex_string(hash, hash + k_digest_size, hex_str);
}
inline std::string get_hash_hex_string(const hash256_one_by_one& hasher) {
std::string hex_str;
get_hash_hex_string(hasher, hex_str);
return hex_str;
}
namespace impl {
template <typename RaIter, typename OutIter>
void hash256_impl(RaIter first, RaIter last, OutIter first2, OutIter last2, int,
std::random_access_iterator_tag) {
hash256_one_by_one hasher;
// hasher.init();
hasher.process(first, last);
hasher.finish();
hasher.get_hash_bytes(first2, last2);
}
template <typename InputIter, typename OutIter>
void hash256_impl(InputIter first, InputIter last, OutIter first2,
OutIter last2, int buffer_size, std::input_iterator_tag) {
std::vector<byte_t> buffer(buffer_size);
hash256_one_by_one hasher;
// hasher.init();
while (first != last) {
int size = buffer_size;
for (int i = 0; i != buffer_size; ++i, ++first) {
if (first == last) {
size = i;
break;
}
buffer[i] = *first;
}
hasher.process(buffer.begin(), buffer.begin() + size);
}
hasher.finish();
hasher.get_hash_bytes(first2, last2);
}
}
template <typename InIter, typename OutIter>
void hash256(InIter first, InIter last, OutIter first2, OutIter last2,
int buffer_size = PICOSHA2_BUFFER_SIZE_FOR_INPUT_ITERATOR) {
picosha2::impl::hash256_impl(
first, last, first2, last2, buffer_size,
typename std::iterator_traits<InIter>::iterator_category());
}
template <typename InIter, typename OutContainer>
void hash256(InIter first, InIter last, OutContainer& dst) {
hash256(first, last, dst.begin(), dst.end());
}
template <typename InContainer, typename OutIter>
void hash256(const InContainer& src, OutIter first, OutIter last) {
hash256(src.begin(), src.end(), first, last);
}
template <typename InContainer, typename OutContainer>
void hash256(const InContainer& src, OutContainer& dst) {
hash256(src.begin(), src.end(), dst.begin(), dst.end());
}
template <typename InIter>
void hash256_hex_string(InIter first, InIter last, std::string& hex_str) {
byte_t hashed[k_digest_size];
hash256(first, last, hashed, hashed + k_digest_size);
std::ostringstream oss;
output_hex(hashed, hashed + k_digest_size, oss);
hex_str.assign(oss.str());
}
template <typename InIter>
std::string hash256_hex_string(InIter first, InIter last) {
std::string hex_str;
hash256_hex_string(first, last, hex_str);
return hex_str;
}
inline void hash256_hex_string(const std::string& src, std::string& hex_str) {
hash256_hex_string(src.begin(), src.end(), hex_str);
}
template <typename InContainer>
void hash256_hex_string(const InContainer& src, std::string& hex_str) {
hash256_hex_string(src.begin(), src.end(), hex_str);
}
template <typename InContainer>
std::string hash256_hex_string(const InContainer& src) {
return hash256_hex_string(src.begin(), src.end());
}
template<typename OutIter>void hash256(std::ifstream& f, OutIter first, OutIter last){
hash256(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>(), first,last);
}
}// namespace picosha2
#endif // PICOSHA2_H
main.cc 0 → 100644
#include <iostream>
#include <rlib/stdio.hpp>
#include <rlib/opt.hpp>
using namespace rlib::literals;
int main(int argc, char **argv) {
rlib::opt_parser args(argc, argv);
if(args.getBoolArg("--help", "-h")) {
rlib::println("Usage: {} -l listenAddr -p listenPort -s serverAddr -P serverPort -lp LPassword -rp R(emote)Password"_rs.format(args.getSelf()));
}
auto listenAddr = args.getValueArg("-l");
auto listenPort = args.getValueArg("-p").as<uint16_t>();
auto serverAddr = args.getValueArg("-s");
auto serverPort = args.getValueArg("-P").as<uint16_t>();
auto lPassword = args.getValueArg("-lp");
auto rPassword = args.getValueArg("-rp");
return 0;
}
\ No newline at end of file
//
// Created by recolic on 19-6-10.
//
#include <Crypto.hpp>
#include <rlib/stdio.hpp>
#include <vector>
Crypto crypto;
void test(std::string c, std::string l, std::string r) {
auto backup = c;
crypto.convertL2R(c, "", l);
rlib::println("ORIGIN len", backup.size(), ", 1ORDER-ENC len", c.size());
crypto.convertL2R(c, l, r);
crypto.convertL2R(c, r, l);
crypto.convertL2R(c, l, "");
if(backup != c) {
throw std::runtime_error("Failed testcase:" + backup + ":" + l + ":" + r + ":GOT:" + c);
}
}
int main() {
test("v99x0cv0zxcv", "1", "");
test("v99x0cv0zxcv", "1", "");
test("v99x0cv0zxcv", "1", "");
test("v99x0cv0zxcv", "1", "");
test("v99x0cv0zxcv", "1", "");
test("v99x0cv0zxcv", "1", "");
std::string k1 = "1", k2 = "", k3 = "12989d8vh9xuncv'sd;", k4 = std::string("sdvpn0923\0t;,ew',;ds") + '\0' + '2';
std::vector<std::string> keys {k1, k2, k3, k4};
std::vector<std::string> tests {"v99x0cv0zxcv", "", "1", std::string("1290urj3j90nxv09snd\0goi\0oweinfge") + '\0' + '2', crypto_dictionary};
for(auto t : tests) {
for(auto l : keys) {
for(auto r : keys) {
test(t, l, r);
}
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment