mirror of
https://github.com/tomoko-dev9/nntpchan.git
synced 2026-03-28 17:32:35 +01:00
Compare commits
118 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb890e716b | ||
|
|
1a2c5b9e4a | ||
|
|
358fe300ed | ||
|
|
f4a6988f11 | ||
|
|
f2d854d88f | ||
|
|
4ede62a667 | ||
|
|
59ea3da355 | ||
|
|
2983eb6fbd | ||
|
|
0870b270cc | ||
|
|
f3e76a1e0f | ||
|
|
7d56d68d14 | ||
|
|
7524db96fe | ||
|
|
bd67be0280 | ||
|
|
5be6c9f7e8 | ||
|
|
e78286cc06 | ||
|
|
fea75f7200 | ||
|
|
d61228215e | ||
|
|
cc5d94ee5f | ||
|
|
2152cd3246 | ||
|
|
c6a79b8893 | ||
|
|
838f2b8ca7 | ||
|
|
88d723219a | ||
|
|
dbb5897305 | ||
|
|
892a7ea58b | ||
|
|
64c52e327a | ||
|
|
86b3d3ce62 | ||
|
|
aa3cf130b3 | ||
|
|
ed2f88c0fc | ||
|
|
2d090269c5 | ||
|
|
aa637b7cb6 | ||
|
|
38b24825fd | ||
|
|
bb1b9f427d | ||
|
|
c18152a7ba | ||
|
|
17e89387b5 | ||
|
|
89c5773625 | ||
|
|
1dc800b89c | ||
|
|
c1f9191045 | ||
|
|
bbefe94e8a | ||
|
|
d28f272b94 | ||
|
|
4770129ad6 | ||
|
|
e87005a178 | ||
|
|
1e69493eef | ||
|
|
1a70ff9d92 | ||
|
|
41a8541660 | ||
|
|
f61470468b | ||
|
|
23ae28bc71 | ||
|
|
fa5e250595 | ||
|
|
f079a1fee4 | ||
|
|
5e66346662 | ||
|
|
d48b585fcf | ||
|
|
32e9e4b3eb | ||
|
|
a60ecff7e3 | ||
|
|
54b8b60edd | ||
|
|
2e4c42ff8a | ||
|
|
e9cb9e4f46 | ||
|
|
1753e2e54b | ||
|
|
c2c2146ad3 | ||
|
|
1f1dc6a63b | ||
|
|
f07a6faec6 | ||
|
|
51e0763faf | ||
|
|
5ea8b1b245 | ||
|
|
aecbe2a5a9 | ||
|
|
cff13becaf | ||
|
|
a06a671415 | ||
|
|
70feeed809 | ||
|
|
6af4470473 | ||
|
|
bdabd25867 | ||
|
|
d301021122 | ||
|
|
741ded6694 | ||
|
|
2074e49d75 | ||
|
|
809863c472 | ||
|
|
be54d399f3 | ||
|
|
76a3288d8c | ||
|
|
3d4d106554 | ||
|
|
c7da354244 | ||
|
|
acebb66227 | ||
|
|
3a273ccf08 | ||
|
|
dbc47f8c65 | ||
|
|
c03c8c370e | ||
|
|
a6e5fd13e0 | ||
|
|
37ebcc2693 | ||
|
|
31a1109372 | ||
|
|
d241137ded | ||
|
|
b78f044b0b | ||
|
|
4262f4dc59 | ||
|
|
3629eb41d9 | ||
|
|
d21efc7fd2 | ||
|
|
90652f8e7b | ||
|
|
4469462cb7 | ||
|
|
37598e187d | ||
|
|
e4a9db3f11 | ||
|
|
0965d34fbb | ||
|
|
89c2398a96 | ||
|
|
279faa56b7 | ||
|
|
19d75eb917 | ||
|
|
dba185c6aa | ||
|
|
07e62d2057 | ||
|
|
2f122529b0 | ||
|
|
942294317a | ||
|
|
cfaa96b82c | ||
|
|
cc467ac312 | ||
|
|
0966a247e5 | ||
|
|
4f3ac9f256 | ||
|
|
e9620558ac | ||
|
|
cac9979280 | ||
|
|
fdb6831064 | ||
|
|
fbafc56b4c | ||
|
|
9e291b1c5a | ||
|
|
8d4778c2d7 | ||
|
|
0abb5882ec | ||
|
|
96f51c9862 | ||
|
|
872c5d3757 | ||
|
|
66c1adfece | ||
|
|
66655b18d5 | ||
|
|
f370a4ccbd | ||
|
|
cff94dc8d8 | ||
|
|
db03367945 | ||
|
|
aca6a0dfa4 |
3
Makefile
3
Makefile
@@ -30,11 +30,12 @@ $(JS): js-deps
|
||||
|
||||
|
||||
$(SRND):
|
||||
make -C $(SRND_DIR)
|
||||
$(MAKE) -C $(SRND_DIR)
|
||||
cp $(SRND_DIR)/srndv2 $(SRND)
|
||||
|
||||
clean:
|
||||
rm -f $(SRND) $(JS)
|
||||
$(MAKE) -C $(SRND_DIR) clean
|
||||
|
||||
distclean: clean
|
||||
rm -rf $(REPO_GOPATH)
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
## Bugs and issues
|
||||
|
||||
*PLEASE* report any bugs you find while building, setting-up or using NNTPChan on the [GitHub issue tracker](https://github.com/majestrate/nntpchan/issues) or on the [GitGud issue tracker](https://gitgud.io/uguu/nntpchan/issues) so that the probelms can be resolved or discussed.
|
||||
*PLEASE* report any bugs you find while building, setting-up or using NNTPChan on the [GitHub issue tracker](https://github.com/majestrate/nntpchan/issues), the [issue tracker on tor](http://git.psii2pdloxelodts.onion/psi/nntpchan/), the [issue tracker on i2p](http://git.psi.i2p/psi/nntpchan/) or on the [GitGud issue tracker](https://gitgud.io/jeff/nntpchan/issues) so that the probelms can be resolved or discussed.
|
||||
|
||||
## Clients
|
||||
|
||||
@@ -47,6 +47,7 @@ Like this project? Why not help by funding it? This address pays for the server
|
||||
|
||||
Bitcoin: [15yuMzuueV8y5vPQQ39ZqQVz5Ey98DNrjE](bitcoin://15yuMzuueV8y5vPQQ39ZqQVz5Ey98DNrjE)
|
||||
|
||||
Monero: 46thSVXSPNhJkCgUsFD9WuCjW4K41DAHGL9khni2VEqmZZhfEZVvcukCp357rfhngZdviZMaeNdj5CLqhLyeK2qZRBCyL7Q
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
|
||||
4
TODO.md
4
TODO.md
@@ -1,7 +1,7 @@
|
||||
## TODO ##
|
||||
|
||||
* extra stylesheets
|
||||
* more alternative templates
|
||||
* javascript free mod panel
|
||||
* liveui
|
||||
* better mod panel
|
||||
* easier peering
|
||||
* improve command line mod tools
|
||||
|
||||
5
contrib/backends/nntpchan-daemon/.gitignore
vendored
5
contrib/backends/nntpchan-daemon/.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
*.o
|
||||
*.a
|
||||
nntpd
|
||||
nntpchan-tool
|
||||
test
|
||||
tools/authtool
|
||||
tools/testtool
|
||||
.gdb_history
|
||||
@@ -1,9 +1,4 @@
|
||||
|
||||
EXE = nntpd
|
||||
|
||||
TOOL = nntpchan-tool
|
||||
|
||||
CXX = g++
|
||||
REPO=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||
SRC_PATH = $(REPO)/src
|
||||
|
||||
@@ -11,24 +6,43 @@ SOURCES := $(wildcard $(SRC_PATH)/*.cpp)
|
||||
HEADERS := $(wildcard $(SRC_PATH)/*.hpp)
|
||||
OBJECTS := $(SOURCES:.cpp=.o)
|
||||
|
||||
TOOL_SRC_PATH := $(REPO)/tools
|
||||
|
||||
TOOL_SRC := $(wildcard $(TOOL_SRC_PATH)/*.cpp)
|
||||
TOOLS := $(TOOL_SRC:.cpp=)
|
||||
|
||||
DAEMON_SRC = $(REPO)/daemon
|
||||
|
||||
PKGS := libuv libsodium
|
||||
|
||||
LD_FLAGS := $(shell pkg-config --libs $(PKGS))
|
||||
INC_FLAGS := $(shell pkg-config --cflags $(PKGS)) -I $(REPO)/src
|
||||
CXXFLAGS := -std=c++11 -Wall -Wextra $(INC_FLAGS) -g
|
||||
CXXFLAGS := -std=c++11 -Wall -Wextra $(INC_FLAGS)
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
CXXFLAGS += -g
|
||||
endif
|
||||
|
||||
LIB = $(REPO)/libnntpchan.a
|
||||
|
||||
EXE = $(REPO)/nntpd
|
||||
|
||||
|
||||
all: $(EXE) $(TOOLS)
|
||||
|
||||
all: $(EXE) $(TOOL)
|
||||
$(LIB): $(OBJECTS)
|
||||
$(AR) -r $(LIB) $(OBJECTS)
|
||||
|
||||
$(EXE): $(OBJECTS)
|
||||
$(CXX) -o $(EXE) $(OBJECTS) $(CXXFLAGS) nntpd.cpp $(LD_FLAGS)
|
||||
$(EXE): $(LIB)
|
||||
$(CXX) $(CXXFLAGS) $(DAEMON_SRC)/main.cpp $(LIB) $(LD_FLAGS) -o $(EXE)
|
||||
|
||||
$(TOOL): $(OBJECTS)
|
||||
$(CXX) -o $(TOOL) $(OBJECTS) $(CXXFLAGS) tool.cpp $(LD_FLAGS)
|
||||
$(TOOL_SRC): $(LIB)
|
||||
|
||||
build-test: $(OBJECTS)
|
||||
$(CXX) -o test $(OBJECTS) $(CXXFLAGS) test.cpp $(LD_FLAGS)
|
||||
$(TOOLS): $(TOOL_SRC)
|
||||
$(CXX) $(CXXFLAGS) $< $(LIB) $(LD_FLAGS) -o $@
|
||||
|
||||
build-test: $(LIB)
|
||||
$(CXX) -o test $(CXXFLAGS) test.cpp $(LIB) $(LD_FLAGS)
|
||||
|
||||
test: build-test
|
||||
./test
|
||||
@@ -37,4 +51,4 @@ test: build-test
|
||||
$(CXX) $(CXXFLAGS) -c -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(OBJECTS) $(EXE) $(TOOL) test
|
||||
rm -f $(OBJECTS) $(LIB) $(EXE) $(TOOLS)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "ini.hpp"
|
||||
|
||||
#include "crypto.hpp"
|
||||
#include "storage.hpp"
|
||||
#include "nntp_server.hpp"
|
||||
#include "event.hpp"
|
||||
@@ -15,21 +16,24 @@ int main(int argc, char * argv[]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
nntpchan::Crypto crypto();
|
||||
|
||||
nntpchan::Mainloop loop;
|
||||
|
||||
|
||||
nntpchan::NNTPServer nntp(loop);
|
||||
|
||||
|
||||
|
||||
std::string fname(argv[1]);
|
||||
|
||||
std::ifstream i(fname);
|
||||
|
||||
if(i.is_open()) {
|
||||
INI::Parser conf(i);
|
||||
|
||||
std::vector<std::string> requiredSections = {"nntp", "storage"};
|
||||
|
||||
|
||||
std::vector<std::string> requiredSections = {"nntp", "articles"};
|
||||
|
||||
auto & level = conf.top();
|
||||
|
||||
|
||||
for ( const auto & section : requiredSections ) {
|
||||
if(level.sections.find(section) == level.sections.end()) {
|
||||
std::cerr << "config file " << fname << " does not have required section: ";
|
||||
@@ -38,15 +42,15 @@ int main(int argc, char * argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
auto & storeconf = level.sections["storage"].values;
|
||||
auto & storeconf = level.sections["articles"].values;
|
||||
|
||||
if (storeconf.find("path") == storeconf.end()) {
|
||||
std::cerr << "storage section does not have 'path' value" << std::endl;
|
||||
if (storeconf.find("store_path") == storeconf.end()) {
|
||||
std::cerr << "storage section does not have 'store_path' value" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
nntp.SetStoragePath(storeconf["path"]);
|
||||
|
||||
nntp.SetStoragePath(storeconf["store_path"]);
|
||||
|
||||
auto & nntpconf = level.sections["nntp"].values;
|
||||
|
||||
if (nntpconf.find("bind") == nntpconf.end()) {
|
||||
@@ -54,6 +58,13 @@ int main(int argc, char * argv[]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(nntpconf.find("instance_name") == nntpconf.end()) {
|
||||
std::cerr << "nntp section lacks 'instance_name' value" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
nntp.SetInstanceName(nntpconf["instance_name"]);
|
||||
|
||||
if (nntpconf.find("authdb") != nntpconf.end()) {
|
||||
nntp.SetLoginDB(nntpconf["authdb"]);
|
||||
}
|
||||
@@ -74,30 +85,28 @@ int main(int argc, char * argv[]) {
|
||||
nntp.SetFrontend(new nntpchan::ExecFrontend(frontconf["exec"]));
|
||||
} else {
|
||||
std::cerr << "unknown frontend type '" << ftype << "'" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
auto & a = nntpconf["bind"];
|
||||
|
||||
try {
|
||||
nntp.Bind(a);
|
||||
nntp.Bind(a);
|
||||
} catch ( std::exception & ex ) {
|
||||
std::cerr << "failed to bind: " << ex.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
try {
|
||||
std::cerr << "run mainloop" << std::endl;
|
||||
loop.Run();
|
||||
} catch ( std::exception & ex ) {
|
||||
std::cerr << "exception in mainloop: " << ex.what() << std::endl;
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
std::cerr << "nntpd for " << nntp.InstanceName() << " bound to " << a << std::endl;
|
||||
|
||||
loop.Run();
|
||||
|
||||
} else {
|
||||
std::cerr << "failed to open " << fname << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
[nntp]
|
||||
bind = [::]:1199
|
||||
instance_name=nntp.server.tld
|
||||
bind=[::]:1199
|
||||
authdb=auth.txt
|
||||
|
||||
[storage]
|
||||
path = ./storage/
|
||||
[articles]
|
||||
store_path=./storage/
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include "crypto.hpp"
|
||||
#include <sodium.h>
|
||||
#include <cassert>
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
@@ -6,4 +8,13 @@ namespace nntpchan
|
||||
{
|
||||
crypto_hash(h.data(), d, l);
|
||||
}
|
||||
|
||||
Crypto::Crypto()
|
||||
{
|
||||
assert(sodium_init() == 0);
|
||||
}
|
||||
|
||||
Crypto::~Crypto()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,15 @@
|
||||
namespace nntpchan
|
||||
{
|
||||
typedef std::array<uint8_t, crypto_hash_BYTES> SHA512Digest;
|
||||
|
||||
|
||||
void SHA512(const uint8_t * d, std::size_t l, SHA512Digest & h);
|
||||
|
||||
/** global crypto initializer */
|
||||
struct Crypto
|
||||
{
|
||||
Crypto();
|
||||
~Crypto();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace nntpchan
|
||||
|
||||
void Mainloop::Run(uv_run_mode mode)
|
||||
{
|
||||
uv_run(m_loop, mode);
|
||||
assert(uv_run(m_loop, mode) == 0);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
6
contrib/backends/nntpchan-daemon/src/http.hpp
Normal file
6
contrib/backends/nntpchan-daemon/src/http.hpp
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef NNTPCHAN_HTTP_HPP
|
||||
#define NNTPCHAN_HTTP_HPP
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
5
contrib/backends/nntpchan-daemon/src/http_client.hpp
Normal file
5
contrib/backends/nntpchan-daemon/src/http_client.hpp
Normal file
@@ -0,0 +1,5 @@
|
||||
#ifndef NNTPCHAN_HTTP_CLIENT_HPP
|
||||
#define NNTPCHAN_HTTP_CLIENT_HPP
|
||||
|
||||
|
||||
#endif
|
||||
6
contrib/backends/nntpchan-daemon/src/http_server.hpp
Normal file
6
contrib/backends/nntpchan-daemon/src/http_server.hpp
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef NNTPCHAN_HTTP_SERVER_HPP
|
||||
#define NNTPCHAN_HTTP_SERVER_HPP
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,20 +1,27 @@
|
||||
#include "line.hpp"
|
||||
#include <iostream>
|
||||
|
||||
namespace nntpchan {
|
||||
|
||||
void LineReader::OnData(const char * d, ssize_t l)
|
||||
LineReader::LineReader(size_t limit) : m_close(false), lineLimit(limit) {}
|
||||
|
||||
void LineReader::Data(const char * data, ssize_t l)
|
||||
{
|
||||
if(l <= 0) return;
|
||||
// process leftovers
|
||||
std::size_t idx = 0;
|
||||
std::size_t pos = 0;
|
||||
while(l-- > 0) {
|
||||
char c = d[idx++];
|
||||
char c = data[idx++];
|
||||
if(c == '\n') {
|
||||
OnLine(d, idx-1);
|
||||
d += idx;
|
||||
} else if (c == '\r' && d[idx] == '\n') {
|
||||
OnLine(d, idx-1);
|
||||
d += idx + 1;
|
||||
OnLine(data, pos);
|
||||
pos = 0;
|
||||
data += idx;
|
||||
} else if (c == '\r' && data[idx] == '\n') {
|
||||
OnLine(data, pos);
|
||||
data += idx + 1;
|
||||
pos = 0;
|
||||
} else {
|
||||
pos ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,21 +31,9 @@ namespace nntpchan {
|
||||
std::string line(d, l);
|
||||
HandleLine(line);
|
||||
}
|
||||
|
||||
bool LineReader::HasNextLine()
|
||||
{
|
||||
return m_sendlines.size() > 0;
|
||||
}
|
||||
|
||||
std::string LineReader::GetNextLine()
|
||||
bool LineReader::ShouldClose()
|
||||
{
|
||||
std::string line = m_sendlines[0];
|
||||
m_sendlines.pop_front();
|
||||
return line;
|
||||
}
|
||||
|
||||
void LineReader::QueueLine(const std::string & line)
|
||||
{
|
||||
m_sendlines.push_back(line);
|
||||
return m_close;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef NNTPCHAN_LINE_HPP
|
||||
#define NNTPCHAN_LINE_HPP
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include "server.hpp"
|
||||
#include <stdint.h>
|
||||
namespace nntpchan
|
||||
{
|
||||
|
||||
@@ -9,26 +9,25 @@ namespace nntpchan
|
||||
class LineReader
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
LineReader(size_t lineLimit);
|
||||
|
||||
/** @brief queue inbound data from connection */
|
||||
void OnData(const char * data, ssize_t s);
|
||||
void Data(const char * data, ssize_t s);
|
||||
|
||||
/** @brief do we have line to send to the client? */
|
||||
bool HasNextLine();
|
||||
/** @brief get the next line to send to the client, does not check if it exists */
|
||||
std::string GetNextLine();
|
||||
/** implements IConnHandler */
|
||||
virtual bool ShouldClose();
|
||||
|
||||
protected:
|
||||
/** @brief handle a line from the client */
|
||||
virtual void HandleLine(const std::string & line) = 0;
|
||||
/** @brief queue the next line to send to the client */
|
||||
void QueueLine(const std::string & line);
|
||||
|
||||
|
||||
|
||||
private:
|
||||
void OnLine(const char * d, const size_t l);
|
||||
// lines to send
|
||||
std::deque<std::string> m_sendlines;
|
||||
std::string m_leftovers;
|
||||
bool m_close;
|
||||
const size_t lineLimit;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
bool IsValidMessageID(const MessageID & msgid)
|
||||
bool IsValidMessageID(const std::string & msgid)
|
||||
{
|
||||
auto itr = msgid.begin();
|
||||
auto end = msgid.end();
|
||||
--end;
|
||||
if (*itr != '<') return false;
|
||||
if (*end != '>') return false;
|
||||
if(msgid[0] != '<') return false;
|
||||
if(msgid[msgid.size()-1] != '>') return false;
|
||||
auto itr = msgid.begin() + 1;
|
||||
auto end = msgid.end() - 1;
|
||||
bool atfound = false;
|
||||
while(itr != end) {
|
||||
auto c = *itr;
|
||||
@@ -18,10 +17,10 @@ namespace nntpchan
|
||||
atfound = true;
|
||||
continue;
|
||||
}
|
||||
if (c == '$' || c == '_' || c == '-') continue;
|
||||
if (c > '0' && c < '9') continue;
|
||||
if (c > 'A' && c < 'Z') continue;
|
||||
if (c > 'a' && c < 'z') continue;
|
||||
if (c == '$' || c == '_' || c == '-' || c == '.') continue;
|
||||
if (c >= '0' && c <= '9') continue;
|
||||
if (c >= 'A' && c <= 'Z') continue;
|
||||
if (c >= 'a' && c <= 'z') continue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -8,12 +8,10 @@
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
typedef std::string MessageID;
|
||||
|
||||
bool IsValidMessageID(const MessageID & msgid);
|
||||
bool IsValidMessageID(const std::string & msgid);
|
||||
|
||||
typedef std::pair<std::string, std::string> MessageHeader;
|
||||
|
||||
|
||||
typedef std::map<std::string, std::string> MIMEPartHeader;
|
||||
|
||||
typedef std::function<bool(const MessageHeader &)> MessageHeaderFilter;
|
||||
@@ -21,15 +19,15 @@ namespace nntpchan
|
||||
typedef std::function<bool(const MIMEPartHeader &)> MIMEPartFilter;
|
||||
|
||||
/**
|
||||
read MIME message from i,
|
||||
filter each header with h,
|
||||
filter each part with p,
|
||||
read MIME message from i,
|
||||
filter each header with h,
|
||||
filter each part with p,
|
||||
store result in o
|
||||
|
||||
return true if we read the whole message, return false if there is remaining
|
||||
return true if we read the whole message, return false if there is remaining
|
||||
*/
|
||||
bool StoreMIMEMessage(std::istream & i, MessageHeaderFilter h, MIMEPartHeader p, std::ostream & o);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
262
contrib/backends/nntpchan-daemon/src/mustache.cpp
Normal file
262
contrib/backends/nntpchan-daemon/src/mustache.cpp
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
Author: José Bollo <jobol@nonadev.net>
|
||||
Author: José Bollo <jose.bollo@iot.bzh>
|
||||
|
||||
https://gitlab.com/jobol/mustach
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "mustache.hpp"
|
||||
|
||||
#define NAME_LENGTH_MAX 1024
|
||||
#define DEPTH_MAX 256
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
namespace mustache
|
||||
{
|
||||
|
||||
|
||||
static int getpartial(struct mustach_itf *itf, void *closure, const char *name, char **result)
|
||||
{
|
||||
int rc;
|
||||
FILE *file;
|
||||
size_t size;
|
||||
|
||||
*result = NULL;
|
||||
file = open_memstream(result, &size);
|
||||
if (file == NULL)
|
||||
rc = MUSTACH_ERROR_SYSTEM;
|
||||
else {
|
||||
rc = itf->put(closure, name, 0, file);
|
||||
if (rc == 0)
|
||||
/* adds terminating null */
|
||||
rc = fputc(0, file) ? MUSTACH_ERROR_SYSTEM : 0;
|
||||
fclose(file);
|
||||
if (rc < 0) {
|
||||
free(*result);
|
||||
*result = NULL;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int process(const char *templ, struct mustach_itf *itf, void *closure, FILE *file, const char *opstr, const char *clstr)
|
||||
{
|
||||
char name[NAME_LENGTH_MAX + 1], *partial, c;
|
||||
const char *beg, *term;
|
||||
struct { const char *name, *again; size_t length; int emit, entered; } stack[DEPTH_MAX];
|
||||
size_t oplen, cllen, len, l;
|
||||
int depth, rc, emit;
|
||||
|
||||
emit = 1;
|
||||
oplen = strlen(opstr);
|
||||
cllen = strlen(clstr);
|
||||
depth = 0;
|
||||
for(;;) {
|
||||
beg = strstr(templ, opstr);
|
||||
if (beg == NULL) {
|
||||
/* no more mustach */
|
||||
if (emit)
|
||||
fwrite(templ, strlen(templ), 1, file);
|
||||
return depth ? MUSTACH_ERROR_UNEXPECTED_END : 0;
|
||||
}
|
||||
if (emit)
|
||||
fwrite(templ, (size_t)(beg - templ), 1, file);
|
||||
beg += oplen;
|
||||
term = strstr(beg, clstr);
|
||||
if (term == NULL)
|
||||
return MUSTACH_ERROR_UNEXPECTED_END;
|
||||
templ = term + cllen;
|
||||
len = (size_t)(term - beg);
|
||||
c = *beg;
|
||||
switch(c) {
|
||||
case '!':
|
||||
case '=':
|
||||
break;
|
||||
case '{':
|
||||
for (l = 0 ; clstr[l] == '}' ; l++);
|
||||
if (clstr[l]) {
|
||||
if (!len || beg[len-1] != '}')
|
||||
return MUSTACH_ERROR_BAD_UNESCAPE_TAG;
|
||||
len--;
|
||||
} else {
|
||||
if (term[l] != '}')
|
||||
return MUSTACH_ERROR_BAD_UNESCAPE_TAG;
|
||||
templ++;
|
||||
}
|
||||
c = '&';
|
||||
case '^':
|
||||
case '#':
|
||||
case '/':
|
||||
case '&':
|
||||
case '>':
|
||||
#if !defined(NO_EXTENSION_FOR_MUSTACH) && !defined(NO_COLON_EXTENSION_FOR_MUSTACH)
|
||||
case ':':
|
||||
#endif
|
||||
beg++; len--;
|
||||
default:
|
||||
while (len && isspace(beg[0])) { beg++; len--; }
|
||||
while (len && isspace(beg[len-1])) len--;
|
||||
if (len == 0)
|
||||
return MUSTACH_ERROR_EMPTY_TAG;
|
||||
if (len > NAME_LENGTH_MAX)
|
||||
return MUSTACH_ERROR_TAG_TOO_LONG;
|
||||
memcpy(name, beg, len);
|
||||
name[len] = 0;
|
||||
break;
|
||||
}
|
||||
switch(c) {
|
||||
case '!':
|
||||
/* comment */
|
||||
/* nothing to do */
|
||||
break;
|
||||
case '=':
|
||||
/* defines separators */
|
||||
if (len < 5 || beg[len - 1] != '=')
|
||||
return MUSTACH_ERROR_BAD_SEPARATORS;
|
||||
beg++;
|
||||
len -= 2;
|
||||
for (l = 0; l < len && !isspace(beg[l]) ; l++);
|
||||
if (l == len)
|
||||
return MUSTACH_ERROR_BAD_SEPARATORS;
|
||||
opstr = strndupa(beg, l);
|
||||
while (l < len && isspace(beg[l])) l++;
|
||||
if (l == len)
|
||||
return MUSTACH_ERROR_BAD_SEPARATORS;
|
||||
clstr = strndupa(beg + l, len - l);
|
||||
oplen = strlen(opstr);
|
||||
cllen = strlen(clstr);
|
||||
break;
|
||||
case '^':
|
||||
case '#':
|
||||
/* begin section */
|
||||
if (depth == DEPTH_MAX)
|
||||
return MUSTACH_ERROR_TOO_DEPTH;
|
||||
rc = emit;
|
||||
if (rc) {
|
||||
rc = itf->enter(closure, name);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
stack[depth].name = beg;
|
||||
stack[depth].again = templ;
|
||||
stack[depth].length = len;
|
||||
stack[depth].emit = emit;
|
||||
stack[depth].entered = rc;
|
||||
if ((c == '#') == (rc == 0))
|
||||
emit = 0;
|
||||
depth++;
|
||||
break;
|
||||
case '/':
|
||||
/* end section */
|
||||
if (depth-- == 0 || len != stack[depth].length || memcmp(stack[depth].name, name, len))
|
||||
return MUSTACH_ERROR_CLOSING;
|
||||
rc = emit && stack[depth].entered ? itf->next(closure) : 0;
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (rc) {
|
||||
templ = stack[depth++].again;
|
||||
} else {
|
||||
emit = stack[depth].emit;
|
||||
if (emit && stack[depth].entered)
|
||||
itf->leave(closure);
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
/* partials */
|
||||
if (emit) {
|
||||
rc = getpartial(itf, closure, name, &partial);
|
||||
if (rc == 0) {
|
||||
rc = process(partial, itf, closure, file, opstr, clstr);
|
||||
free(partial);
|
||||
}
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* replacement */
|
||||
if (emit) {
|
||||
rc = itf->put(closure, name, c != '&', file);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int fmustach(const char *templ, struct mustach_itf *itf, void *closure, FILE *file)
|
||||
{
|
||||
int rc = itf->start ? itf->start(closure) : 0;
|
||||
if (rc == 0)
|
||||
rc = process(templ, itf, closure, file, "{{", "}}");
|
||||
return rc;
|
||||
}
|
||||
|
||||
int fdmustach(const char *templ, struct mustach_itf *itf, void *closure, int fd)
|
||||
{
|
||||
int rc;
|
||||
FILE *file;
|
||||
|
||||
file = fdopen(fd, "w");
|
||||
if (file == NULL) {
|
||||
rc = MUSTACH_ERROR_SYSTEM;
|
||||
errno = ENOMEM;
|
||||
} else {
|
||||
rc = fmustach(templ, itf, closure, file);
|
||||
fclose(file);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int mustach(const char *templ, struct mustach_itf *itf, void *closure, char **result, size_t *size)
|
||||
{
|
||||
int rc;
|
||||
FILE *file;
|
||||
size_t s;
|
||||
|
||||
*result = NULL;
|
||||
if (size == NULL)
|
||||
size = &s;
|
||||
file = open_memstream(result, size);
|
||||
if (file == NULL) {
|
||||
rc = MUSTACH_ERROR_SYSTEM;
|
||||
errno = ENOMEM;
|
||||
} else {
|
||||
rc = fmustach(templ, itf, closure, file);
|
||||
if (rc == 0)
|
||||
/* adds terminating null */
|
||||
rc = fputc(0, file) ? MUSTACH_ERROR_SYSTEM : 0;
|
||||
fclose(file);
|
||||
if (rc >= 0)
|
||||
/* removes terminating null of the length */
|
||||
(*size)--;
|
||||
else {
|
||||
free(*result);
|
||||
*result = NULL;
|
||||
*size = 0;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
96
contrib/backends/nntpchan-daemon/src/mustache.hpp
Normal file
96
contrib/backends/nntpchan-daemon/src/mustache.hpp
Normal file
@@ -0,0 +1,96 @@
|
||||
#ifndef NNTPCHAN_MUSTACHE
|
||||
#define NNTPCHAN_MUSTACHE
|
||||
|
||||
/*
|
||||
Author: José Bollo <jobol@nonadev.net>
|
||||
Author: José Bollo <jose.bollo@iot.bzh>
|
||||
|
||||
https://gitlab.com/jobol/mustach
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define MUSTACH_OK 0
|
||||
#define MUSTACH_ERROR_SYSTEM -1
|
||||
#define MUSTACH_ERROR_UNEXPECTED_END -2
|
||||
#define MUSTACH_ERROR_EMPTY_TAG -3
|
||||
#define MUSTACH_ERROR_TAG_TOO_LONG -4
|
||||
#define MUSTACH_ERROR_BAD_SEPARATORS -5
|
||||
#define MUSTACH_ERROR_TOO_DEPTH -6
|
||||
#define MUSTACH_ERROR_CLOSING -7
|
||||
#define MUSTACH_ERROR_BAD_UNESCAPE_TAG -8
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
namespace mustache
|
||||
{
|
||||
|
||||
/**
|
||||
* mustach_itf - interface for callbacks
|
||||
*
|
||||
* All of this function should return a negative value to stop
|
||||
* the mustache processing. The returned negative value will be
|
||||
* then returned to the caller of mustach as is.
|
||||
*
|
||||
* The functions enter and next should return 0 or 1.
|
||||
*
|
||||
* All other functions should normally return 0.
|
||||
*
|
||||
* @start: Starts the mustach processing of the closure
|
||||
* 'start' is optional (can be NULL)
|
||||
*
|
||||
* @put: Writes the value of 'name' to 'file' with 'escape' or not
|
||||
*
|
||||
* @enter: Enters the section of 'name' if possible.
|
||||
* Musts return 1 if entered or 0 if not entered.
|
||||
* When 1 is returned, the function 'leave' will always be called.
|
||||
* Conversely 'leave' is never called when enter returns 0 or
|
||||
* a negative value.
|
||||
* When 1 is returned, the function must activate the first
|
||||
* item of the section.
|
||||
*
|
||||
* @next: Activates the next item of the section if it exists.
|
||||
* Musts return 1 when the next item is activated.
|
||||
* Musts return 0 when there is no item to activate.
|
||||
*
|
||||
* @leave: Leaves the last entered section
|
||||
*/
|
||||
struct mustach_itf {
|
||||
int (*start)(void *closure);
|
||||
int (*put)(void *closure, const char *name, int escape, FILE *file);
|
||||
int (*enter)(void *closure, const char *name);
|
||||
int (*next)(void *closure);
|
||||
int (*leave)(void *closure);
|
||||
};
|
||||
/**
|
||||
* fmustach - Renders the mustache 'template' in 'file' for 'itf' and 'closure'.
|
||||
*
|
||||
* @template: the template string to instanciate
|
||||
* @itf: the interface to the functions that mustach calls
|
||||
* @closure: the closure to pass to functions called
|
||||
* @file: the file where to write the result
|
||||
*
|
||||
* Returns 0 in case of success, -1 with errno set in case of system error
|
||||
* a other negative value in case of error.
|
||||
*/
|
||||
int fmustach(const char *templ, struct mustach_itf *itf, void *closure, FILE *file);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
HashedCredDB::HashedCredDB() : LineReader(1024) {}
|
||||
|
||||
bool HashedCredDB::CheckLogin(const std::string & user, const std::string & passwd)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_access);
|
||||
@@ -19,7 +21,7 @@ namespace nntpchan
|
||||
char * buff = new char[l];
|
||||
// read file
|
||||
m_instream->read(buff, l);
|
||||
OnData(buff, l);
|
||||
Data(buff, l);
|
||||
delete [] buff;
|
||||
return m_found;
|
||||
}
|
||||
@@ -58,7 +60,7 @@ namespace nntpchan
|
||||
{
|
||||
m_instream = s;
|
||||
}
|
||||
|
||||
|
||||
std::string HashedCredDB::Hash(const std::string & data, const std::string & salt)
|
||||
{
|
||||
SHA512Digest h;
|
||||
@@ -71,7 +73,7 @@ namespace nntpchan
|
||||
m_fname(fname),
|
||||
f(nullptr)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
HashedFileDB::~HashedFileDB()
|
||||
@@ -95,4 +97,3 @@ namespace nntpchan
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,20 +20,21 @@ namespace nntpchan
|
||||
virtual bool CheckLogin(const std::string & user, const std::string & passwd) = 0;
|
||||
virtual ~NNTPCredentialDB() {}
|
||||
};
|
||||
|
||||
|
||||
/** @brief nntp credential db using hashed+salted passwords */
|
||||
class HashedCredDB : public NNTPCredentialDB, public LineReader
|
||||
{
|
||||
public:
|
||||
HashedCredDB();
|
||||
bool CheckLogin(const std::string & user, const std::string & passwd);
|
||||
protected:
|
||||
void SetStream(std::istream * i);
|
||||
|
||||
|
||||
std::string Hash(const std::string & data, const std::string & salt);
|
||||
void HandleLine(const std::string & line);
|
||||
private:
|
||||
bool ProcessLine(const std::string & line);
|
||||
|
||||
|
||||
std::mutex m_access;
|
||||
std::string m_user, m_passwd;
|
||||
bool m_found;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "nntp_handler.hpp"
|
||||
#include "message.hpp"
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
@@ -8,6 +10,8 @@
|
||||
namespace nntpchan
|
||||
{
|
||||
NNTPServerHandler::NNTPServerHandler(const std::string & storage) :
|
||||
LineReader(1024),
|
||||
m_article(nullptr),
|
||||
m_auth(nullptr),
|
||||
m_store(storage),
|
||||
m_authed(false),
|
||||
@@ -22,7 +26,8 @@ namespace nntpchan
|
||||
|
||||
void NNTPServerHandler::HandleLine(const std::string &line)
|
||||
{
|
||||
if(m_state == eStateReadCommand) {
|
||||
if(m_state == eStateReadCommand)
|
||||
{
|
||||
std::deque<std::string> command;
|
||||
std::istringstream s;
|
||||
s.str(line);
|
||||
@@ -34,45 +39,135 @@ namespace nntpchan
|
||||
else
|
||||
QueueLine("501 Syntax error");
|
||||
}
|
||||
else if(m_state == eStateStoreArticle)
|
||||
{
|
||||
std::string l = line + "\r\n";
|
||||
OnData(l.c_str(), l.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "invalid state" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void NNTPServerHandler::OnData(const char * data, ssize_t l)
|
||||
{
|
||||
if(l <= 0 ) return;
|
||||
if(m_state == eStateStoreArticle)
|
||||
{
|
||||
const char * end = strstr(data, "\r\n.\r\n");
|
||||
if(end)
|
||||
{
|
||||
std::size_t diff = end - data ;
|
||||
if(m_article)
|
||||
m_article->write(data, diff+2);
|
||||
ArticleObtained();
|
||||
diff += 5;
|
||||
Data(end+5, l-diff);
|
||||
return;
|
||||
}
|
||||
if(m_article)
|
||||
m_article->write(data, l);
|
||||
}
|
||||
else
|
||||
Data(data, l);
|
||||
}
|
||||
|
||||
void NNTPServerHandler::HandleCommand(const std::deque<std::string> & command)
|
||||
{
|
||||
auto cmd = command[0];
|
||||
std::transform(cmd.begin(), cmd.end(), cmd.begin(),
|
||||
[](unsigned char ch) { return std::toupper(ch); });
|
||||
std::transform(cmd.begin(), cmd.end(), cmd.begin(), ::toupper);
|
||||
std::size_t cmdlen = command.size();
|
||||
std::cerr << "handle command [" << cmd << "] " << (int) cmdlen << std::endl;
|
||||
for(const auto & part : command)
|
||||
std::cerr << " " << part;
|
||||
std::cerr << std::endl;
|
||||
if (cmd == "QUIT") {
|
||||
Quit();
|
||||
return;
|
||||
} else if (cmd == "MODE" ) {
|
||||
if(cmdlen == 1) {
|
||||
}
|
||||
else if (cmd[0] == '5')
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (cmd == "MODE" ) {
|
||||
if(cmdlen == 2) {
|
||||
// set mode
|
||||
SwitchMode(command[1]);
|
||||
} else if(cmdlen) {
|
||||
// too many arguments
|
||||
QueueLine("500 too many arguments");
|
||||
} else {
|
||||
// get mode
|
||||
QueueLine("500 wrong arguments");
|
||||
}
|
||||
|
||||
} else if(cmd == "CAPABILITIES") {
|
||||
QueueLine("101 I support the following:");
|
||||
QueueLine("READER");
|
||||
QueueLine("IMPLEMENTATION nntpchan-daemon");
|
||||
QueueLine("VERSION 2");
|
||||
QueueLine("STREAMING");
|
||||
QueueLine(".");
|
||||
} else if (cmd == "CHECK") {
|
||||
if(cmdlen == 2) {
|
||||
const std::string & msgid = command[1];
|
||||
if(IsValidMessageID(msgid) && m_store.Accept(msgid))
|
||||
{
|
||||
QueueLine("238 "+msgid);
|
||||
return;
|
||||
}
|
||||
QueueLine("438 "+msgid);
|
||||
}
|
||||
else
|
||||
QueueLine("501 syntax error");
|
||||
} else if (cmd == "TAKETHIS") {
|
||||
if (cmdlen == 2)
|
||||
{
|
||||
const std::string & msgid = command[1];
|
||||
if(m_store.Accept(msgid))
|
||||
{
|
||||
m_article = m_store.OpenWrite(msgid);
|
||||
}
|
||||
m_articleName = msgid;
|
||||
EnterState(eStateStoreArticle);
|
||||
return;
|
||||
}
|
||||
QueueLine("501 invalid syntax");
|
||||
} else {
|
||||
// unknown command
|
||||
QueueLine("500 Unknown Command");
|
||||
}
|
||||
}
|
||||
|
||||
void NNTPServerHandler::ArticleObtained()
|
||||
{
|
||||
if(m_article)
|
||||
{
|
||||
m_article->flush();
|
||||
m_article->close();
|
||||
delete m_article;
|
||||
m_article = nullptr;
|
||||
QueueLine("239 "+m_articleName);
|
||||
std::cerr << "stored " << m_articleName << std::endl;
|
||||
}
|
||||
else
|
||||
QueueLine("439 "+m_articleName);
|
||||
m_articleName = "";
|
||||
EnterState(eStateReadCommand);
|
||||
}
|
||||
|
||||
void NNTPServerHandler::SwitchMode(const std::string & mode)
|
||||
{
|
||||
if (mode == "READER") {
|
||||
m_mode = mode;
|
||||
std::string m = mode;
|
||||
std::transform(m.begin(), m.end(), m.begin(), ::toupper);
|
||||
if (m == "READER") {
|
||||
m_mode = m;
|
||||
if(PostingAllowed()) {
|
||||
QueueLine("200 Posting is permitted yo");
|
||||
} else {
|
||||
QueueLine("201 Posting is not permitted yo");
|
||||
}
|
||||
} else if (mode == "STREAM") {
|
||||
m_mode = mode;
|
||||
} else if (m == "STREAM") {
|
||||
m_mode = m;
|
||||
if (PostingAllowed()) {
|
||||
QueueLine("203 Streaming enabled");
|
||||
} else {
|
||||
@@ -84,14 +179,19 @@ namespace nntpchan
|
||||
}
|
||||
}
|
||||
|
||||
void NNTPServerHandler::EnterState(State st)
|
||||
{
|
||||
std::cerr << "enter state " << st << std::endl;
|
||||
m_state = st;
|
||||
}
|
||||
|
||||
void NNTPServerHandler::Quit()
|
||||
{
|
||||
std::cerr << "quitting" << std::endl;
|
||||
m_state = eStateQuit;
|
||||
EnterState(eStateQuit);
|
||||
QueueLine("205 quitting");
|
||||
}
|
||||
|
||||
bool NNTPServerHandler::Done()
|
||||
bool NNTPServerHandler::ShouldClose()
|
||||
{
|
||||
return m_state == eStateQuit;
|
||||
}
|
||||
|
||||
@@ -8,23 +8,25 @@
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
class NNTPServerHandler : public LineReader
|
||||
class NNTPServerHandler : public LineReader, public IConnHandler
|
||||
{
|
||||
public:
|
||||
NNTPServerHandler(const std::string & storage);
|
||||
~NNTPServerHandler();
|
||||
|
||||
bool Done();
|
||||
|
||||
virtual bool ShouldClose();
|
||||
|
||||
void SetAuth(NNTPCredentialDB * creds);
|
||||
|
||||
virtual void OnData(const char *, ssize_t);
|
||||
|
||||
void Greet();
|
||||
|
||||
|
||||
protected:
|
||||
void HandleLine(const std::string & line);
|
||||
void HandleCommand(const std::deque<std::string> & command);
|
||||
private:
|
||||
|
||||
|
||||
enum State {
|
||||
eStateReadCommand,
|
||||
eStateStoreArticle,
|
||||
@@ -32,6 +34,11 @@ namespace nntpchan
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
void EnterState(State st);
|
||||
|
||||
void ArticleObtained();
|
||||
|
||||
// handle quit command, this queues a reply
|
||||
void Quit();
|
||||
|
||||
@@ -39,8 +46,10 @@ namespace nntpchan
|
||||
void SwitchMode(const std::string & mode);
|
||||
|
||||
bool PostingAllowed();
|
||||
|
||||
|
||||
private:
|
||||
std::string m_articleName;
|
||||
std::fstream * m_article;
|
||||
NNTPCredentialDB * m_auth;
|
||||
ArticleStorage m_store;
|
||||
std::string m_mode;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "buffer.hpp"
|
||||
|
||||
#include "nntp_server.hpp"
|
||||
#include "nntp_auth.hpp"
|
||||
#include "nntp_handler.hpp"
|
||||
#include "net.hpp"
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
@@ -8,142 +9,79 @@
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
NNTPServer::NNTPServer(uv_loop_t * loop)
|
||||
{
|
||||
uv_tcp_init(loop, &m_server);
|
||||
m_loop = loop;
|
||||
m_server.data = this;
|
||||
}
|
||||
|
||||
NNTPServer::NNTPServer(uv_loop_t * loop) : Server(loop), m_frontend(nullptr) {}
|
||||
|
||||
NNTPServer::~NNTPServer()
|
||||
{
|
||||
if (m_frontend) delete m_frontend;
|
||||
}
|
||||
|
||||
void NNTPServer::Close()
|
||||
IServerConn * NNTPServer::CreateConn(uv_stream_t * s)
|
||||
{
|
||||
uv_close((uv_handle_t*)&m_server, [](uv_handle_t * s) {
|
||||
NNTPServer * self = (NNTPServer*)s->data;
|
||||
if (self) delete self;
|
||||
s->data = nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
void NNTPServer::Bind(const std::string & addr)
|
||||
{
|
||||
auto saddr = ParseAddr(addr);
|
||||
assert(uv_tcp_bind(*this, saddr, 0) == 0);
|
||||
std::cerr << "nntp server bound to " << saddr.to_string() << std::endl;
|
||||
auto cb = [] (uv_stream_t * s, int status) {
|
||||
NNTPServer * self = (NNTPServer *) s->data;
|
||||
self->OnAccept(s, status);
|
||||
};
|
||||
|
||||
assert(uv_listen(*this, 5, cb) == 0);
|
||||
}
|
||||
|
||||
void NNTPServer::OnAccept(uv_stream_t * s, int status)
|
||||
{
|
||||
if(status < 0) {
|
||||
std::cerr << "nntp server OnAccept fail: " << uv_strerror(status) << std::endl;
|
||||
return;
|
||||
}
|
||||
NNTPCredentialDB * creds = nullptr;
|
||||
|
||||
std::ifstream i;
|
||||
i.open(m_logindbpath);
|
||||
if(i.is_open()) creds = new HashedFileDB(m_logindbpath);
|
||||
|
||||
NNTPServerConn * conn = new NNTPServerConn(m_loop, s, m_storagePath, creds);
|
||||
conn->Greet();
|
||||
}
|
||||
|
||||
NNTPServerHandler * handler = new NNTPServerHandler(m_storagePath);
|
||||
if(creds)
|
||||
handler->SetAuth(creds);
|
||||
|
||||
NNTPServerConn * conn = new NNTPServerConn(GetLoop(), s, this, handler);
|
||||
return conn;
|
||||
}
|
||||
|
||||
void NNTPServer::SetLoginDB(const std::string path)
|
||||
{
|
||||
m_logindbpath = path;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void NNTPServer::SetStoragePath(const std::string & path)
|
||||
{
|
||||
m_storagePath = path;
|
||||
}
|
||||
|
||||
void NNTPServer::SetInstanceName(const std::string & name)
|
||||
{
|
||||
m_servername = name;
|
||||
}
|
||||
|
||||
std::string NNTPServer::InstanceName() const
|
||||
{
|
||||
return m_servername;
|
||||
}
|
||||
|
||||
void NNTPServer::SetFrontend(Frontend * f)
|
||||
{
|
||||
if(m_frontend) delete m_frontend;
|
||||
m_frontend = f;
|
||||
}
|
||||
|
||||
NNTPServerConn::NNTPServerConn(uv_loop_t * l, uv_stream_t * s, const std::string & storage, NNTPCredentialDB * creds) :
|
||||
m_handler(storage)
|
||||
|
||||
void NNTPServer::OnAcceptError(int status)
|
||||
{
|
||||
m_handler.SetAuth(creds);
|
||||
uv_tcp_init(l, &m_conn);
|
||||
m_conn.data = this;
|
||||
uv_accept(s, (uv_stream_t*) &m_conn);
|
||||
uv_read_start((uv_stream_t*) &m_conn, [] (uv_handle_t * h, size_t s, uv_buf_t * b) {
|
||||
NNTPServerConn * self = (NNTPServerConn*) h->data;
|
||||
if(self == nullptr) return;
|
||||
b->base = self->m_readbuff;
|
||||
if (s > sizeof(self->m_readbuff))
|
||||
b->len = sizeof(self->m_readbuff);
|
||||
else
|
||||
b->len = s;
|
||||
}, [] (uv_stream_t * s, ssize_t nread, const uv_buf_t * b) {
|
||||
NNTPServerConn * self = (NNTPServerConn*) s->data;
|
||||
if(self == nullptr) return;
|
||||
if(nread > 0) {
|
||||
self->m_handler.OnData(b->base, nread);
|
||||
self->SendNextReply();
|
||||
if(self->m_handler.Done())
|
||||
self->Close();
|
||||
} else {
|
||||
if (nread != UV_EOF) {
|
||||
std::cerr << "error in nntp server conn alloc: ";
|
||||
std::cerr << uv_strerror(nread);
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
// got eof or error
|
||||
self->Close();
|
||||
}
|
||||
});
|
||||
std::cerr << "nntpserver::accept() " << uv_strerror(status) << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void NNTPServerConn::SendNextReply()
|
||||
{
|
||||
if(m_handler.HasNextLine()) {
|
||||
auto line = m_handler.GetNextLine();
|
||||
SendString(line+"\n");
|
||||
IConnHandler * handler = GetHandler();
|
||||
while(handler->HasNextLine()) {
|
||||
auto line = handler->GetNextLine();
|
||||
SendString(line + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void NNTPServerConn::Greet()
|
||||
{
|
||||
m_handler.Greet();
|
||||
IConnHandler * handler = GetHandler();
|
||||
handler->Greet();
|
||||
SendNextReply();
|
||||
}
|
||||
|
||||
void NNTPServerConn::SendString(const std::string & str)
|
||||
{
|
||||
WriteBuffer * b = new WriteBuffer(str);
|
||||
uv_write(&b->w, *this, &b->b, 1, [](uv_write_t * w, int status) {
|
||||
(void) status;
|
||||
WriteBuffer * wb = (WriteBuffer *) w->data;
|
||||
if(wb)
|
||||
delete wb;
|
||||
});
|
||||
}
|
||||
|
||||
void NNTPServerConn::Close()
|
||||
{
|
||||
uv_close((uv_handle_t*)&m_conn, [] (uv_handle_t * s) {
|
||||
NNTPServerConn * self = (NNTPServerConn*) s->data;
|
||||
if(self)
|
||||
delete self;
|
||||
s->data = nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,77 +3,59 @@
|
||||
#include <uv.h>
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include "storage.hpp"
|
||||
#include "frontend.hpp"
|
||||
#include "nntp_auth.hpp"
|
||||
#include "nntp_handler.hpp"
|
||||
#include "server.hpp"
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
|
||||
class NNTPServerConn;
|
||||
|
||||
class NNTPServer
|
||||
|
||||
class NNTPServer : public Server
|
||||
{
|
||||
public:
|
||||
|
||||
NNTPServer(uv_loop_t * loop);
|
||||
~NNTPServer();
|
||||
|
||||
void Bind(const std::string & addr);
|
||||
|
||||
void OnAccept(uv_stream_t * s, int status);
|
||||
virtual ~NNTPServer();
|
||||
|
||||
void SetStoragePath(const std::string & path);
|
||||
|
||||
void SetLoginDB(const std::string path);
|
||||
|
||||
void SetInstanceName(const std::string & name);
|
||||
|
||||
std::string InstanceName() const;
|
||||
|
||||
void SetFrontend(Frontend * f);
|
||||
|
||||
void Close();
|
||||
|
||||
|
||||
virtual IServerConn * CreateConn(uv_stream_t * s);
|
||||
|
||||
virtual void OnAcceptError(int status);
|
||||
|
||||
private:
|
||||
|
||||
operator uv_handle_t * () { return (uv_handle_t*) &m_server; }
|
||||
operator uv_tcp_t * () { return &m_server; }
|
||||
operator uv_stream_t * () { return (uv_stream_t *) &m_server; }
|
||||
|
||||
uv_tcp_t m_server;
|
||||
uv_loop_t * m_loop;
|
||||
|
||||
std::deque<NNTPServerConn *> m_conns;
|
||||
|
||||
std::string m_logindbpath;
|
||||
std::string m_storagePath;
|
||||
std::string m_servername;
|
||||
|
||||
Frontend * m_frontend;
|
||||
|
||||
|
||||
};
|
||||
|
||||
class NNTPServerConn
|
||||
|
||||
class NNTPServerConn : public IServerConn
|
||||
{
|
||||
public:
|
||||
NNTPServerConn(uv_loop_t * l, uv_stream_t * s, const std::string & storage, NNTPCredentialDB * creds);
|
||||
/** @brief close connection, this connection cannot be used after calling this */
|
||||
void Close();
|
||||
|
||||
|
||||
NNTPServerConn(uv_loop_t * l, uv_stream_t * s, Server * parent, IConnHandler * h) : IServerConn(l, s, parent, h) {}
|
||||
|
||||
virtual bool IsTimedOut() { return false; };
|
||||
|
||||
/** @brief send next queued reply */
|
||||
void SendNextReply();
|
||||
virtual void SendNextReply();
|
||||
|
||||
void Greet();
|
||||
|
||||
private:
|
||||
virtual void Greet();
|
||||
|
||||
void SendString(const std::string & line);
|
||||
|
||||
|
||||
operator uv_stream_t * () { return (uv_stream_t *) &m_conn; }
|
||||
|
||||
uv_tcp_t m_conn;
|
||||
|
||||
NNTPServerHandler m_handler;
|
||||
|
||||
char m_readbuff[1028];
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
140
contrib/backends/nntpchan-daemon/src/server.cpp
Normal file
140
contrib/backends/nntpchan-daemon/src/server.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
#include "buffer.hpp"
|
||||
#include "server.hpp"
|
||||
#include "net.hpp"
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
Server::Server(uv_loop_t * loop)
|
||||
{
|
||||
m_loop = loop;
|
||||
uv_tcp_init(m_loop, &m_server);
|
||||
m_server.data = this;
|
||||
}
|
||||
|
||||
void Server::Close()
|
||||
{
|
||||
std::cout << "Close server" << std::endl;
|
||||
uv_close((uv_handle_t*)&m_server, [](uv_handle_t * s) {
|
||||
Server * self = (Server*)s->data;
|
||||
if (self) delete self;
|
||||
s->data = nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
void Server::Bind(const std::string & addr)
|
||||
{
|
||||
auto saddr = ParseAddr(addr);
|
||||
assert(uv_tcp_bind(*this, saddr, 0) == 0);
|
||||
auto cb = [] (uv_stream_t * s, int status) {
|
||||
Server * self = (Server *) s->data;
|
||||
self->OnAccept(s, status);
|
||||
};
|
||||
assert(uv_listen(*this, 5, cb) == 0);
|
||||
}
|
||||
|
||||
void Server::OnAccept(uv_stream_t * s, int status)
|
||||
{
|
||||
if(status < 0) {
|
||||
OnAcceptError(status);
|
||||
return;
|
||||
}
|
||||
IServerConn * conn = CreateConn(s);
|
||||
assert(conn);
|
||||
m_conns.push_back(conn);
|
||||
conn->Greet();
|
||||
}
|
||||
|
||||
void Server::RemoveConn(IServerConn * conn)
|
||||
{
|
||||
auto itr = m_conns.begin();
|
||||
while(itr != m_conns.end())
|
||||
{
|
||||
if(*itr == conn)
|
||||
itr = m_conns.erase(itr);
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
void IConnHandler::QueueLine(const std::string & line)
|
||||
{
|
||||
m_sendlines.push_back(line);
|
||||
}
|
||||
|
||||
bool IConnHandler::HasNextLine()
|
||||
{
|
||||
return m_sendlines.size() > 0;
|
||||
}
|
||||
|
||||
std::string IConnHandler::GetNextLine()
|
||||
{
|
||||
std::string line = m_sendlines[0];
|
||||
m_sendlines.pop_front();
|
||||
return line;
|
||||
}
|
||||
|
||||
IServerConn::IServerConn(uv_loop_t * l, uv_stream_t * st, Server * parent, IConnHandler * h)
|
||||
{
|
||||
m_loop = l;
|
||||
m_parent = parent;
|
||||
m_handler = h;
|
||||
uv_tcp_init(l, &m_conn);
|
||||
m_conn.data = this;
|
||||
uv_accept(st, (uv_stream_t*) &m_conn);
|
||||
uv_read_start((uv_stream_t*) &m_conn, [] (uv_handle_t * h, size_t s, uv_buf_t * b) {
|
||||
IServerConn * self = (IServerConn*) h->data;
|
||||
if(self == nullptr) return;
|
||||
b->base = self->m_readbuff;
|
||||
if (s > sizeof(self->m_readbuff))
|
||||
b->len = sizeof(self->m_readbuff);
|
||||
else
|
||||
b->len = s;
|
||||
}, [] (uv_stream_t * s, ssize_t nread, const uv_buf_t * b) {
|
||||
IServerConn * self = (IServerConn*) s->data;
|
||||
if(self == nullptr) return;
|
||||
if(nread > 0) {
|
||||
self->m_handler->OnData(b->base, nread);
|
||||
self->SendNextReply();
|
||||
if(self->m_handler->ShouldClose())
|
||||
self->Close();
|
||||
} else {
|
||||
if (nread != UV_EOF) {
|
||||
std::cerr << "error in nntp server conn alloc: ";
|
||||
std::cerr << uv_strerror(nread);
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
// got eof or error
|
||||
self->Close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
IServerConn::~IServerConn()
|
||||
{
|
||||
delete m_handler;
|
||||
}
|
||||
|
||||
void IServerConn::SendString(const std::string & str)
|
||||
{
|
||||
WriteBuffer * b = new WriteBuffer(str);
|
||||
uv_write(&b->w, (uv_stream_t*)&m_conn, &b->b, 1, [](uv_write_t * w, int status) {
|
||||
(void) status;
|
||||
WriteBuffer * wb = (WriteBuffer *) w->data;
|
||||
if(wb)
|
||||
delete wb;
|
||||
});
|
||||
}
|
||||
|
||||
void IServerConn::Close()
|
||||
{
|
||||
m_parent->RemoveConn(this);
|
||||
uv_close((uv_handle_t*)&m_conn, [] (uv_handle_t * s) {
|
||||
IServerConn * self = (IServerConn*) s->data;
|
||||
if(self)
|
||||
delete self;
|
||||
s->data = nullptr;
|
||||
});
|
||||
}
|
||||
}
|
||||
99
contrib/backends/nntpchan-daemon/src/server.hpp
Normal file
99
contrib/backends/nntpchan-daemon/src/server.hpp
Normal file
@@ -0,0 +1,99 @@
|
||||
#ifndef NNTPCHAN_SERVER_HPP
|
||||
#define NNTPCHAN_SERVER_HPP
|
||||
#include <uv.h>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace nntpchan
|
||||
{
|
||||
|
||||
class Server;
|
||||
|
||||
|
||||
struct IConnHandler
|
||||
{
|
||||
|
||||
virtual ~IConnHandler() {};
|
||||
|
||||
/** got inbound data */
|
||||
virtual void OnData(const char * data, ssize_t s) = 0;
|
||||
|
||||
/** get next line of data to send */
|
||||
std::string GetNextLine();
|
||||
|
||||
/** return true if we have a line to send */
|
||||
bool HasNextLine();
|
||||
|
||||
/** return true if we should close this connection otherwise return false */
|
||||
virtual bool ShouldClose() = 0;
|
||||
|
||||
/** queue a data send */
|
||||
void QueueLine(const std::string & line);
|
||||
|
||||
virtual void Greet() = 0;
|
||||
|
||||
|
||||
private:
|
||||
std::deque<std::string> m_sendlines;
|
||||
};
|
||||
|
||||
/** server connection handler interface */
|
||||
struct IServerConn
|
||||
{
|
||||
IServerConn(uv_loop_t * l, uv_stream_t * s, Server * parent, IConnHandler * h);
|
||||
virtual ~IServerConn();
|
||||
virtual void Close();
|
||||
virtual void Greet() = 0;
|
||||
virtual void SendNextReply() = 0;
|
||||
virtual bool IsTimedOut() = 0;
|
||||
void SendString(const std::string & str);
|
||||
Server * Parent() { return m_parent; };
|
||||
IConnHandler * GetHandler() { return m_handler; };
|
||||
uv_loop_t * GetLoop() { return m_loop; };
|
||||
private:
|
||||
uv_tcp_t m_conn;
|
||||
uv_loop_t * m_loop;
|
||||
Server * m_parent;
|
||||
IConnHandler * m_handler;
|
||||
char m_readbuff[65536];
|
||||
};
|
||||
|
||||
class Server
|
||||
{
|
||||
public:
|
||||
Server(uv_loop_t * loop);
|
||||
/** called after socket close, NEVER call directly */
|
||||
virtual ~Server() {}
|
||||
/** create connection handler from open stream */
|
||||
virtual IServerConn * CreateConn(uv_stream_t * s) = 0;
|
||||
/** close all sockets and stop */
|
||||
void Close();
|
||||
/** bind to address */
|
||||
void Bind(const std::string & addr);
|
||||
|
||||
typedef std::function<void(IServerConn *)> ConnVisitor;
|
||||
|
||||
/** visit all open connections */
|
||||
void VisitConns(ConnVisitor v);
|
||||
|
||||
/** remove connection from server, called after proper close */
|
||||
void RemoveConn(IServerConn * conn);
|
||||
|
||||
protected:
|
||||
uv_loop_t * GetLoop() { return m_loop; }
|
||||
virtual void OnAcceptError(int status) = 0;
|
||||
private:
|
||||
operator uv_handle_t * () { return (uv_handle_t*) &m_server; }
|
||||
operator uv_tcp_t * () { return &m_server; }
|
||||
operator uv_stream_t * () { return (uv_stream_t *) &m_server; }
|
||||
|
||||
void OnAccept(uv_stream_t * s, int status);
|
||||
std::deque<IServerConn *> m_conns;
|
||||
uv_tcp_t m_server;
|
||||
uv_loop_t * m_loop;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -12,7 +12,7 @@ namespace nntpchan
|
||||
ArticleStorage::ArticleStorage(const std::string & fpath) {
|
||||
SetPath(fpath);
|
||||
}
|
||||
|
||||
|
||||
ArticleStorage::~ArticleStorage()
|
||||
{
|
||||
}
|
||||
@@ -25,22 +25,35 @@ namespace nntpchan
|
||||
mkdir(basedir.c_str(), 0700);
|
||||
}
|
||||
|
||||
bool ArticleStorage::Accept(const MessageID & msgid)
|
||||
bool ArticleStorage::Accept(const std::string& msgid)
|
||||
{
|
||||
if (!IsValidMessageID(msgid)) return false;
|
||||
std::stringstream ss;
|
||||
ss << basedir << GetPathSep() << msgid;
|
||||
auto s = ss.str();
|
||||
auto s = MessagePath(msgid);
|
||||
FILE * f = fopen(s.c_str(), "r");
|
||||
if ( f == nullptr) return errno == ENOENT;
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string ArticleStorage::MessagePath(const std::string & msgid)
|
||||
{
|
||||
return basedir + GetPathSep() + msgid;
|
||||
}
|
||||
|
||||
std::fstream * ArticleStorage::OpenRead(const std::string & msgid)
|
||||
{
|
||||
return OpenMode(msgid, std::ios::in);
|
||||
}
|
||||
|
||||
std::fstream * ArticleStorage::OpenWrite(const std::string & msgid)
|
||||
{
|
||||
return OpenMode(msgid, std::ios::out);
|
||||
}
|
||||
|
||||
char ArticleStorage::GetPathSep()
|
||||
{
|
||||
return '/';
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef NNTPCHAN_STORAGE_HPP
|
||||
#define NNTPCHAN_STORAGE_HPP
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include "message.hpp"
|
||||
|
||||
@@ -15,20 +16,38 @@ namespace nntpchan
|
||||
|
||||
void SetPath(const std::string & fpath);
|
||||
|
||||
std::ostream & OpenWrite(const MessageID & msgid);
|
||||
std::istream & OpenRead(const MessageID & msgid);
|
||||
std::fstream * OpenWrite(const std::string & msgid);
|
||||
std::fstream * OpenRead(const std::string & msgid);
|
||||
|
||||
/**
|
||||
return true if we should accept a new message give its message id
|
||||
*/
|
||||
bool Accept(const MessageID & msgid);
|
||||
|
||||
bool Accept(const std::string & msgid);
|
||||
|
||||
private:
|
||||
|
||||
template<typename Mode>
|
||||
std::fstream * OpenMode(const std::string & msgid, const Mode & m)
|
||||
{
|
||||
if(IsValidMessageID(msgid))
|
||||
{
|
||||
std::fstream * f = new std::fstream;
|
||||
f->open(MessagePath(msgid), m);
|
||||
if(f->is_open())
|
||||
return f;
|
||||
delete f;
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
std::string MessagePath(const std::string & msgid);
|
||||
|
||||
static char GetPathSep();
|
||||
|
||||
|
||||
std::string basedir;
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -9,11 +9,12 @@
|
||||
|
||||
static void print_help(const std::string & exename)
|
||||
{
|
||||
std::cout << "usage: " << exename << " [help|gencred|checkcred]" << std::endl;
|
||||
std::cout << "usage: " << exename << " [help|gen|check]" << std::endl;
|
||||
}
|
||||
|
||||
static void print_long_help() {
|
||||
|
||||
static void print_long_help()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void gen_passwd(const std::string & username, const std::string & passwd)
|
||||
@@ -58,16 +59,16 @@ int main(int argc, char * argv[])
|
||||
print_long_help();
|
||||
return 0;
|
||||
}
|
||||
if (cmd == "gencred") {
|
||||
if (cmd == "gen") {
|
||||
if(argc == 4) {
|
||||
gen_passwd(argv[2], argv[3]);
|
||||
return 0;
|
||||
} else {
|
||||
std::cout << "usage: " << argv[0] << " passwd username password" << std::endl;
|
||||
std::cout << "usage: " << argv[0] << " gen username password" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if(cmd == "checkcred" ) {
|
||||
if(cmd == "check" ) {
|
||||
std::string cred;
|
||||
std::cout << "credential: " ;
|
||||
if(!std::getline(std::cin, cred)) {
|
||||
14
contrib/backends/nntpchan-daemon/tools/testtool.cpp
Normal file
14
contrib/backends/nntpchan-daemon/tools/testtool.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#include "exec_frontend.hpp"
|
||||
#include "message.hpp"
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
|
||||
int main(int , char * [])
|
||||
{
|
||||
nntpchan::Frontend * f = new nntpchan::ExecFrontend("./contrib/nntpchan.sh");
|
||||
assert(nntpchan::IsValidMessageID("<a28a71493831188@web.oniichan.onion>"));
|
||||
assert(f->AcceptsNewsgroup("overchan.test"));
|
||||
std::cout << "all good" << std::endl;
|
||||
}
|
||||
@@ -1,11 +1,15 @@
|
||||
REPO=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||
|
||||
all: clean build
|
||||
|
||||
build: srndv2
|
||||
all: srndv2
|
||||
|
||||
srndv2:
|
||||
GOPATH=$(REPO) go build -v
|
||||
|
||||
clean:
|
||||
GOPATH=$(REPO) go clean -v
|
||||
|
||||
test:
|
||||
GOPATH=$(REPO) go test -v -tags libsodium srnd
|
||||
|
||||
test-pure:
|
||||
GOPATH=$(REPO) go test -v srnd
|
||||
|
||||
@@ -5,18 +5,44 @@
|
||||
package srnd
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/base32"
|
||||
"fmt"
|
||||
"github.com/majestrate/configparser"
|
||||
"github.com/majestrate/nacl"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type FilterConfig struct {
|
||||
globalFilters []*regexp.Regexp
|
||||
}
|
||||
|
||||
func (fc *FilterConfig) LoadFile(fname string) (err error) {
|
||||
var data []byte
|
||||
data, err = ioutil.ReadFile(fname)
|
||||
if err == nil {
|
||||
r := bytes.NewReader(data)
|
||||
sc := bufio.NewScanner(r)
|
||||
for sc.Scan() {
|
||||
txt := sc.Text()
|
||||
idx := strings.Index(txt, "#")
|
||||
if idx >= 0 {
|
||||
txt = txt[:idx]
|
||||
}
|
||||
fc.globalFilters = append(fc.globalFilters, regexp.MustCompile(txt))
|
||||
}
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type FeedConfig struct {
|
||||
policy FeedPolicy
|
||||
quarks map[string]string
|
||||
@@ -58,17 +84,19 @@ type HookConfig struct {
|
||||
}
|
||||
|
||||
type SRNdConfig struct {
|
||||
daemon map[string]string
|
||||
crypto *CryptoConfig
|
||||
store map[string]string
|
||||
database map[string]string
|
||||
cache map[string]string
|
||||
feeds []FeedConfig
|
||||
frontend map[string]string
|
||||
system map[string]string
|
||||
worker map[string]string
|
||||
pprof *ProfilingConfig
|
||||
hooks []*HookConfig
|
||||
daemon map[string]string
|
||||
crypto *CryptoConfig
|
||||
store map[string]string
|
||||
database map[string]string
|
||||
cache map[string]string
|
||||
feeds []FeedConfig
|
||||
frontend map[string]string
|
||||
system map[string]string
|
||||
worker map[string]string
|
||||
pprof *ProfilingConfig
|
||||
hooks []*HookConfig
|
||||
inboundPolicy *FeedPolicy
|
||||
filter FilterConfig
|
||||
}
|
||||
|
||||
// check for config files
|
||||
@@ -211,7 +239,7 @@ func GenSRNdConfig() *configparser.Configuration {
|
||||
sect.Add("json-api", "0")
|
||||
sect.Add("json-api-username", "fucking-change-this-value")
|
||||
sect.Add("json-api-password", "seriously-fucking-change-this-value")
|
||||
secret_bytes := nacl.RandBytes(8)
|
||||
secret_bytes := randbytes(8)
|
||||
secret := base32.StdEncoding.EncodeToString(secret_bytes)
|
||||
sect.Add("api-secret", secret)
|
||||
|
||||
@@ -219,8 +247,16 @@ func GenSRNdConfig() *configparser.Configuration {
|
||||
}
|
||||
|
||||
// save a list of feeds to overwrite feeds.ini
|
||||
func SaveFeeds(feeds []FeedConfig) (err error) {
|
||||
func SaveFeeds(feeds []FeedConfig, inboundPolicy *FeedPolicy) (err error) {
|
||||
conf := configparser.NewConfiguration()
|
||||
|
||||
if inboundPolicy != nil {
|
||||
s := conf.NewSection("")
|
||||
for k, v := range inboundPolicy.rules {
|
||||
s.Add(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
for _, feed := range feeds {
|
||||
if len(feed.Name) == 0 {
|
||||
// don't do feed with no name
|
||||
@@ -381,8 +417,8 @@ func ReadConfig() *SRNdConfig {
|
||||
fname = os.Getenv("SRND_FEEDS_INI_PATH")
|
||||
}
|
||||
}
|
||||
|
||||
confs, err := feedParse(fname)
|
||||
var confs []FeedConfig
|
||||
confs, sconf.inboundPolicy, err = feedParse(fname)
|
||||
if err != nil {
|
||||
log.Fatal("failed to parse", fname, err)
|
||||
}
|
||||
@@ -399,7 +435,7 @@ func ReadConfig() *SRNdConfig {
|
||||
if err == nil {
|
||||
for _, f := range feeds {
|
||||
log.Println("load feed", f)
|
||||
confs, err := feedParse(f)
|
||||
confs, _, err := feedParse(f)
|
||||
if err != nil {
|
||||
log.Fatal("failed to parse feed", f, err)
|
||||
}
|
||||
@@ -408,15 +444,32 @@ func ReadConfig() *SRNdConfig {
|
||||
}
|
||||
}
|
||||
|
||||
filterFile := "filters.txt"
|
||||
|
||||
if CheckFile(filterFile) {
|
||||
err = sconf.filter.LoadFile(filterFile)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to load %s: %s", filterFile, err)
|
||||
}
|
||||
log.Printf("loaded %d filters", len(sconf.filter.globalFilters))
|
||||
}
|
||||
return &sconf
|
||||
}
|
||||
|
||||
func feedParse(fname string) (confs []FeedConfig, err error) {
|
||||
func feedParse(fname string) (confs []FeedConfig, inboundPolicy *FeedPolicy, err error) {
|
||||
|
||||
conf, err := configparser.Read(fname)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
|
||||
default_sect, err := conf.Section("")
|
||||
if err == nil {
|
||||
opts := default_sect.Options()
|
||||
inboundPolicy = &FeedPolicy{
|
||||
rules: opts,
|
||||
}
|
||||
}
|
||||
|
||||
sections, err := conf.Find("feed-*")
|
||||
|
||||
68
contrib/backends/srndv2/src/srnd/crypto_test.go
Normal file
68
contrib/backends/srndv2/src/srnd/crypto_test.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package srnd
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const asdKey = "3c7850617b4fe116c98f4ed4a2eaf00ab219d16dd6351d9ee786f9fc710bad55"
|
||||
|
||||
func TestSeedToKeypair(t *testing.T) {
|
||||
seed := parseTripcodeSecret("asd")
|
||||
pk, _ := naclSeedToKeyPair(seed)
|
||||
hexpk := hexify(pk)
|
||||
if hexpk != asdKey {
|
||||
t.Logf("%s != %s", asdKey, hexpk)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSign(t *testing.T) {
|
||||
|
||||
msgid := "<wut@wut.wut>"
|
||||
var seed [32]byte
|
||||
pk, sec := naclSeedToKeyPair(seed[:])
|
||||
sig := msgidFrontendSign(sec, msgid)
|
||||
t.Logf("seed=%s pk=%s sk=%s sig=%s", hexify(seed[:]), hexify(pk), hexify(sec), sig)
|
||||
if !verifyFrontendSig(hexify(pk), sig, msgid) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerify(t *testing.T) {
|
||||
d := filepath.Join("testdata", "article.test.txt")
|
||||
|
||||
f, e := os.Open(d)
|
||||
if e != nil {
|
||||
t.Logf("os.Open returned error: %s", e)
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
|
||||
r := bufio.NewReader(f)
|
||||
|
||||
msg, er := readMIMEHeader(r)
|
||||
if er != nil {
|
||||
t.Logf("readMIMEHeader returned error: %s", er)
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
|
||||
b := &io.LimitedReader{
|
||||
R: msg.Body,
|
||||
N: 1000000000,
|
||||
}
|
||||
|
||||
err := read_message_body(b, msg.Header, nil, ioutil.Discard, true, func(msg NNTPMessage) {
|
||||
return
|
||||
})
|
||||
if err != nil {
|
||||
t.Logf("read_message_body returned error: %s", err)
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
}
|
||||
46
contrib/backends/srndv2/src/srnd/cryptography.go
Normal file
46
contrib/backends/srndv2/src/srnd/cryptography.go
Normal file
@@ -0,0 +1,46 @@
|
||||
// +build !libsodium
|
||||
|
||||
package srnd
|
||||
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"edwards25519"
|
||||
"golang.org/x/crypto/ed25519"
|
||||
)
|
||||
|
||||
func naclCryptoVerifyFucky(h, sig, pk []byte) bool {
|
||||
pub := make(ed25519.PublicKey, ed25519.PublicKeySize)
|
||||
copy(pub, pk)
|
||||
return ed25519.Verify(pub, h, sig)
|
||||
}
|
||||
|
||||
func naclCryptoSignFucky(hash, sk []byte) []byte {
|
||||
sec := make(ed25519.PrivateKey, ed25519.PrivateKeySize)
|
||||
copy(sec, sk)
|
||||
return ed25519.Sign(sec, hash)
|
||||
}
|
||||
|
||||
func naclSeedToKeyPair(seed []byte) (pk, sk []byte) {
|
||||
|
||||
h := sha512.Sum512(seed[0:32])
|
||||
sk = h[:]
|
||||
sk[0] &= 248
|
||||
sk[31] &= 63
|
||||
sk[31] |= 64
|
||||
// scalarmult magick shit
|
||||
pk = scalarBaseMult(sk[0:32])
|
||||
copy(sk[0:32], seed[0:32])
|
||||
copy(sk[32:64], pk[0:32])
|
||||
return
|
||||
}
|
||||
|
||||
func scalarBaseMult(sk []byte) (pk []byte) {
|
||||
var skey [32]byte
|
||||
var pkey [32]byte
|
||||
copy(skey[:], sk[0:32])
|
||||
var h edwards25519.ExtendedGroupElement
|
||||
edwards25519.GeScalarMultBase(&h, &skey)
|
||||
h.ToBytes(&pkey)
|
||||
pk = pkey[:]
|
||||
return
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/majestrate/nacl"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -131,6 +130,16 @@ type NNTPDaemon struct {
|
||||
article_lifetime time.Duration
|
||||
}
|
||||
|
||||
// return true if text passes all checks and is okay for posting
|
||||
func (self *NNTPDaemon) CheckText(text string) bool {
|
||||
for _, re := range self.conf.filter.globalFilters {
|
||||
if re.MatchString(text) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (self NNTPDaemon) End() {
|
||||
if self.listener != nil {
|
||||
self.listener.Close()
|
||||
@@ -156,14 +165,10 @@ func (self *NNTPDaemon) WrapSign(nntp NNTPMessage) {
|
||||
if seed == nil {
|
||||
log.Println("invalid secretkey will not sign")
|
||||
} else {
|
||||
kp := nacl.LoadSignKey(seed)
|
||||
defer kp.Free()
|
||||
sec := kp.Secret()
|
||||
pk, sec := naclSeedToKeyPair(seed)
|
||||
sig := msgidFrontendSign(sec, nntp.MessageID())
|
||||
pk := hexify(kp.Public())
|
||||
nntp.Headers().Add("X-Frontend-Signature", sig)
|
||||
nntp.Headers().Add("X-Frontend-Pubkey", pk)
|
||||
log.Println("signed", nntp.MessageID(), "as from", pk)
|
||||
nntp.Headers().Add("X-Frontend-Pubkey", hexify(pk))
|
||||
}
|
||||
} else {
|
||||
log.Println("sending", nntp.MessageID(), "unsigned")
|
||||
@@ -295,7 +300,7 @@ func (self *NNTPDaemon) storeFeedsConfig() (err error) {
|
||||
for _, status := range feeds {
|
||||
feedconfigs = append(feedconfigs, *status.State.Config)
|
||||
}
|
||||
err = SaveFeeds(feedconfigs)
|
||||
err = SaveFeeds(feedconfigs, self.conf.inboundPolicy)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -410,7 +415,7 @@ func (self *NNTPDaemon) persistFeed(conf *FeedConfig, mode string, n int) {
|
||||
continue
|
||||
}
|
||||
nntp := createNNTPConnection(conf.Addr)
|
||||
nntp.policy = conf.policy
|
||||
nntp.policy = &conf.policy
|
||||
nntp.feedname = conf.Name
|
||||
nntp.name = fmt.Sprintf("%s-%d-%s", conf.Name, n, mode)
|
||||
stream, reader, use_tls, err := nntp.outboundHandshake(textproto.NewConn(conn), conf)
|
||||
@@ -457,8 +462,7 @@ func (self *NNTPDaemon) syncPull(proxy_type, proxy_addr, remote_addr string) {
|
||||
if reader {
|
||||
// we can do it
|
||||
err = nntp.scrapeServer(self, conn)
|
||||
if err == nil {
|
||||
// we succeeded
|
||||
if err == nil { // we succeeded
|
||||
log.Println(nntp.name, "Scrape successful")
|
||||
nntp.Quit(conn)
|
||||
conn.Close()
|
||||
@@ -478,6 +482,12 @@ func (self *NNTPDaemon) syncPull(proxy_type, proxy_addr, remote_addr string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (self *NNTPDaemon) ExpireAll() {
|
||||
log.Println("expiring all orphans")
|
||||
self.expire = createExpirationCore(self.database, self.store, self.informHooks)
|
||||
self.expire.ExpireOrphans()
|
||||
}
|
||||
|
||||
// run daemon
|
||||
func (self *NNTPDaemon) Run() {
|
||||
|
||||
@@ -948,6 +958,7 @@ func (self *NNTPDaemon) acceptloop() {
|
||||
}
|
||||
addr := conn.RemoteAddr()
|
||||
nntp.name = fmt.Sprintf("%s-inbound-feed", addr.String())
|
||||
nntp.policy = self.conf.inboundPolicy
|
||||
c := textproto.NewConn(conn)
|
||||
// send banners and shit
|
||||
err = nntp.inboundHandshake(c)
|
||||
|
||||
@@ -77,6 +77,7 @@ func (self expire) ExpireThread(group, rootMsgid string) {
|
||||
}
|
||||
}
|
||||
self.database.DeleteThread(rootMsgid)
|
||||
self.database.DeleteArticle(rootMsgid)
|
||||
self.expireCache(group, rootMsgid, rootMsgid)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/majestrate/nacl"
|
||||
"io"
|
||||
"log"
|
||||
"mime"
|
||||
@@ -393,7 +392,7 @@ func (self *httpFrontend) poll() {
|
||||
R: msg.Body,
|
||||
N: self.daemon.messageSizeLimitFor(nntp.Newsgroup()),
|
||||
}
|
||||
err = self.daemon.store.ProcessMessageBody(f, textproto.MIMEHeader(msg.Header), body)
|
||||
err = self.daemon.store.ProcessMessageBody(f, textproto.MIMEHeader(msg.Header), body, self.daemon.CheckText)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -803,6 +802,11 @@ func (self *httpFrontend) handle_postRequest(pr *postRequest, b bannedFunc, e er
|
||||
return
|
||||
}
|
||||
|
||||
if !self.daemon.CheckText(pr.Message) {
|
||||
e(errors.New("spam"))
|
||||
return
|
||||
}
|
||||
|
||||
if len(pr.Frontend) == 0 {
|
||||
// :-DDD
|
||||
pr.Frontend = "mongo.db.is.web.scale"
|
||||
@@ -916,14 +920,9 @@ func (self *httpFrontend) handle_postRequest(pr *postRequest, b bannedFunc, e er
|
||||
}
|
||||
// pack it before sending so that the article is well formed
|
||||
// sign if needed
|
||||
if len(tripcode_privkey) == nacl.CryptoSignSeedLen() {
|
||||
kp := nacl.LoadSignKey(tripcode_privkey)
|
||||
if kp == nil {
|
||||
e(errors.New("seed keypair was nil?"))
|
||||
return
|
||||
}
|
||||
defer kp.Free()
|
||||
nntp.headers.Set("X-PubKey-Ed25519", hexify(kp.Public()))
|
||||
if len(tripcode_privkey) == 32 {
|
||||
pk, _ := naclSeedToKeyPair(tripcode_privkey)
|
||||
nntp.headers.Set("X-PubKey-Ed25519", hexify(pk))
|
||||
nntp.Pack()
|
||||
err = self.daemon.store.RegisterPost(nntp)
|
||||
if err != nil {
|
||||
|
||||
@@ -297,7 +297,7 @@ func handleKeyPost(self *dialogNode, form url.Values, conf *configparser.Configu
|
||||
|
||||
func prepareKeyModel(self *dialogNode, err error, conf *configparser.Configuration) templateModel {
|
||||
param := make(map[string]interface{})
|
||||
public, secret := newSignKeypair()
|
||||
public, secret := newNaclSignKeypair()
|
||||
param["dialog"] = &KeyModel{ErrorModel{err}, StepModel{self}, public, secret}
|
||||
return param
|
||||
}
|
||||
|
||||
@@ -80,6 +80,10 @@ func formatline(line, prefix string) (markup string) {
|
||||
markup += "<span class='memearrows'>"
|
||||
markup += escapeline(line)
|
||||
markup += "</span>"
|
||||
} else if strings.HasPrefix(line_nospace, "<") {
|
||||
markup += "<span class='fagarrows'>"
|
||||
markup += escapeline(line)
|
||||
markup += "</span>"
|
||||
} else {
|
||||
// regular line
|
||||
// for each word
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/majestrate/nacl"
|
||||
"github.com/dchest/blake2b"
|
||||
"io"
|
||||
"log"
|
||||
"mime"
|
||||
@@ -162,7 +162,7 @@ func signArticle(nntp NNTPMessage, seed []byte) (signed *nntpArticle, err error)
|
||||
// copy headers
|
||||
// copy into signed part
|
||||
for k := range h {
|
||||
if k == "X-PubKey-Ed25519" || k == "X-Signature-Ed25519-SHA512" {
|
||||
if k == "X-PubKey-Ed25519" || k == "X-Signature-Ed25519-SHA512" || k == "X-Signature-Ed25519-BLAKE2B" {
|
||||
// don't set signature or pubkey header
|
||||
} else if k == "Content-Type" {
|
||||
signed.headers.Set(k, "message/rfc822; charset=UTF-8")
|
||||
@@ -172,28 +172,24 @@ func signArticle(nntp NNTPMessage, seed []byte) (signed *nntpArticle, err error)
|
||||
}
|
||||
}
|
||||
sha := sha512.New()
|
||||
blake := blake2b.New256()
|
||||
signed.signedPart = &nntpAttachment{}
|
||||
// write body to sign buffer
|
||||
mw := io.MultiWriter(sha, signed.signedPart)
|
||||
mw := io.MultiWriter(sha, blake, signed.signedPart)
|
||||
err = nntp.WriteTo(mw, MaxMessageSize)
|
||||
mw.Write([]byte{10})
|
||||
if err == nil {
|
||||
// build keypair
|
||||
kp := nacl.LoadSignKey(seed)
|
||||
if kp == nil {
|
||||
log.Println("failed to load seed for signing article")
|
||||
return
|
||||
}
|
||||
defer kp.Free()
|
||||
sk := kp.Secret()
|
||||
pk := getSignPubkey(sk)
|
||||
pk, sk := naclSeedToKeyPair(seed)
|
||||
// sign it nigguh
|
||||
digest := sha.Sum(nil)
|
||||
sig := cryptoSign(digest, sk)
|
||||
sig := cryptoSignFucky(digest, sk)
|
||||
// log that we signed it
|
||||
log.Printf("signed %s pubkey=%s sig=%s hash=%s", nntp.MessageID(), pk, sig, hexify(digest))
|
||||
// log.Printf("signed %s pubkey=%s sig=%s hash=%s", nntp.MessageID(), pk, sig, hexify(digest))
|
||||
signed.headers.Set("X-Signature-Ed25519-SHA512", sig)
|
||||
signed.headers.Set("X-PubKey-Ed25519", pk)
|
||||
signed.headers.Set("X-PubKey-Ed25519", hexify(pk[:]))
|
||||
//sig = cryptoSignProper(blake.Sum(nil), sk)
|
||||
//signed.headers.Set("X-Signature-Ed25519-BLAKE2B", sig)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -441,7 +437,7 @@ func (self *nntpArticle) WriteBody(wr io.Writer, limit int64) (err error) {
|
||||
// verify a signed message's body
|
||||
// innerHandler must close reader when done
|
||||
// returns error if one happens while verifying article
|
||||
func verifyMessage(pk, sig string, body *io.LimitedReader, innerHandler func(map[string][]string, io.Reader)) (err error) {
|
||||
func verifyMessageSHA512(pk, sig string, body *io.LimitedReader, innerHandler func(map[string][]string, io.Reader)) (err error) {
|
||||
log.Println("unwrapping signed message from", pk)
|
||||
pk_bytes := unhex(pk)
|
||||
sig_bytes := unhex(sig)
|
||||
@@ -468,7 +464,45 @@ func verifyMessage(pk, sig string, body *io.LimitedReader, innerHandler func(map
|
||||
hash := h.Sum(nil)
|
||||
log.Printf("hash=%s", hexify(hash))
|
||||
log.Printf("sig=%s", hexify(sig_bytes))
|
||||
if nacl.CryptoVerifyFucky(hash, sig_bytes, pk_bytes) {
|
||||
if naclCryptoVerifyFucky(hash, sig_bytes, pk_bytes) {
|
||||
log.Println("signature is valid :^)")
|
||||
} else {
|
||||
err = errors.New("invalid signature")
|
||||
}
|
||||
}
|
||||
// flush pipe
|
||||
pw.Close()
|
||||
return
|
||||
}
|
||||
|
||||
func verifyMessageBLAKE2B(pk, sig string, body *io.LimitedReader, innerHandler func(map[string][]string, io.Reader)) (err error) {
|
||||
log.Println("unwrapping signed message from", pk)
|
||||
pk_bytes := unhex(pk)
|
||||
sig_bytes := unhex(sig)
|
||||
h := blake2b.New256()
|
||||
pr, pw := io.Pipe()
|
||||
// read header
|
||||
// handle inner body
|
||||
go func(hdr_reader *io.PipeReader) {
|
||||
r := bufio.NewReader(hdr_reader)
|
||||
msg, err := readMIMEHeader(r)
|
||||
if err == nil {
|
||||
innerHandler(msg.Header, msg.Body)
|
||||
}
|
||||
hdr_reader.Close()
|
||||
}(pr)
|
||||
body = &io.LimitedReader{
|
||||
R: io.TeeReader(body, pw),
|
||||
N: body.N,
|
||||
}
|
||||
// copy body 128 bytes at a time
|
||||
var buff [128]byte
|
||||
_, err = io.CopyBuffer(h, body, buff[:])
|
||||
if err == nil {
|
||||
hash := h.Sum(nil)
|
||||
log.Printf("hash=%s", hexify(hash))
|
||||
log.Printf("sig=%s", hexify(sig_bytes))
|
||||
if naclCryptoVerifyFucky(hash, sig_bytes, pk_bytes) {
|
||||
log.Println("signature is valid :^)")
|
||||
} else {
|
||||
err = errors.New("invalid signature")
|
||||
|
||||
@@ -51,7 +51,7 @@ type ModUI interface {
|
||||
type ModAction string
|
||||
|
||||
const ModInetBan = ModAction("overchan-inet-ban")
|
||||
const ModDelete = ModAction("overchan-delete")
|
||||
const ModDelete = ModAction("delete")
|
||||
const ModRemoveAttachment = ModAction("overchan-del-attachment")
|
||||
const ModStick = ModAction("overchan-stick")
|
||||
const ModLock = ModAction("overchan-lock")
|
||||
@@ -81,7 +81,13 @@ func (self simpleModEvent) String() string {
|
||||
}
|
||||
|
||||
func (self simpleModEvent) Action() ModAction {
|
||||
return ModAction(strings.Split(string(self), " ")[0])
|
||||
switch strings.Split(string(self), " ")[0] {
|
||||
case "delete":
|
||||
return ModDelete
|
||||
case "overchan-inet-ban":
|
||||
return ModInetBan
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self simpleModEvent) Reason() string {
|
||||
@@ -89,7 +95,11 @@ func (self simpleModEvent) Reason() string {
|
||||
}
|
||||
|
||||
func (self simpleModEvent) Target() string {
|
||||
return strings.Split(string(self), " ")[1]
|
||||
parts := strings.Split(string(self), " ")
|
||||
if len(parts) > 1 {
|
||||
return parts[1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (self simpleModEvent) Scope() string {
|
||||
@@ -311,8 +321,10 @@ func (mod *modEngine) HandleMessage(msgid string) {
|
||||
pubkey := nntp.Pubkey()
|
||||
for _, line := range strings.Split(nntp.Message(), "\n") {
|
||||
line = strings.Trim(line, "\r\t\n ")
|
||||
ev := ParseModEvent(line)
|
||||
mod.Execute(ev, pubkey)
|
||||
if len(line) > 0 {
|
||||
ev := ParseModEvent(line)
|
||||
mod.Execute(ev, pubkey)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,7 +333,7 @@ func (mod *modEngine) Do(ev ModEvent) {
|
||||
action := ev.Action()
|
||||
target := ev.Target()
|
||||
if action == ModDelete || action == ModDeleteAlt {
|
||||
msgid := ev.Target()
|
||||
msgid := target
|
||||
if !ValidMessageID(msgid) {
|
||||
// invalid message-id
|
||||
log.Println("invalid message-id", msgid)
|
||||
@@ -412,7 +424,6 @@ func (mod *modEngine) Execute(ev ModEvent, pubkey string) {
|
||||
action := ev.Action()
|
||||
target := ev.Target()
|
||||
switch action {
|
||||
case ModDeleteAlt:
|
||||
case ModDelete:
|
||||
if mod.AllowDelete(pubkey, target) {
|
||||
mod.Do(ev)
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"fmt"
|
||||
"github.com/gorilla/csrf"
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/majestrate/nacl"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
@@ -416,12 +415,9 @@ func (self httpModUI) CheckPubkey(pubkey, scope string) (bool, error) {
|
||||
func (self httpModUI) CheckKey(privkey, scope string) (bool, error) {
|
||||
privkey_bytes, err := hex.DecodeString(privkey)
|
||||
if err == nil {
|
||||
kp := nacl.LoadSignKey(privkey_bytes)
|
||||
if kp != nil {
|
||||
defer kp.Free()
|
||||
pubkey := hex.EncodeToString(kp.Public())
|
||||
return self.CheckPubkey(pubkey, scope)
|
||||
}
|
||||
pk, _ := naclSeedToKeyPair(privkey_bytes)
|
||||
pubkey := hex.EncodeToString(pk)
|
||||
return self.CheckPubkey(pubkey, scope)
|
||||
}
|
||||
log.Println("invalid key format for key", privkey)
|
||||
return false, err
|
||||
@@ -705,7 +701,7 @@ func (self httpModUI) HandleLogin(wr http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (self httpModUI) HandleKeyGen(wr http.ResponseWriter, r *http.Request) {
|
||||
pk, sk := newSignKeypair()
|
||||
pk, sk := newNaclSignKeypair()
|
||||
tripcode := makeTripcode(pk)
|
||||
self.writeTemplateParam(wr, r, "keygen.mustache", map[string]interface{}{"public": pk, "secret": sk, "tripcode": tripcode})
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ type PostModel interface {
|
||||
Board() string
|
||||
Sage() bool
|
||||
Pubkey() string
|
||||
PubkeyHex() string
|
||||
Reference() string
|
||||
ReferenceHash() string
|
||||
|
||||
|
||||
@@ -376,6 +376,10 @@ func (self *post) ShortHash() string {
|
||||
return ShortHashMessageID(self.MessageID())
|
||||
}
|
||||
|
||||
func (self *post) PubkeyHex() string {
|
||||
return self.Key
|
||||
}
|
||||
|
||||
func (self *post) Pubkey() string {
|
||||
if len(self.Key) > 0 {
|
||||
return fmt.Sprintf("<label title=\"%s\">%s</label>", self.Key, makeTripcode(self.Key))
|
||||
@@ -416,11 +420,11 @@ func (self *post) MessageID() string {
|
||||
}
|
||||
|
||||
func (self *post) Frontend() string {
|
||||
idx := strings.LastIndex(self.MessagePath, "!")
|
||||
idx := strings.LastIndex(self.Message_id, "@")
|
||||
if idx == -1 {
|
||||
return self.MessagePath
|
||||
return "malformed"
|
||||
}
|
||||
return self.MessagePath[idx+1:]
|
||||
return self.Message_id[1+idx : len(self.Message_id)-1]
|
||||
}
|
||||
|
||||
func (self *post) Board() string {
|
||||
|
||||
33
contrib/backends/srndv2/src/srnd/nacl_crypto.go
Normal file
33
contrib/backends/srndv2/src/srnd/nacl_crypto.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// +build libsodium
|
||||
|
||||
package srnd
|
||||
|
||||
import (
|
||||
"github.com/majestrate/nacl"
|
||||
"golang.org/x/crypto/curve25519"
|
||||
)
|
||||
|
||||
func naclCryptoVerifyFucky(h, sig, pk []byte) bool {
|
||||
return nacl.CryptoVerifyFucky(h, sig, pk)
|
||||
}
|
||||
|
||||
func naclCryptoSignFucky(hash, sk []byte) []byte {
|
||||
return nacl.CryptoSignFucky(hash, sk)
|
||||
}
|
||||
|
||||
func naclCryptoVerifyDetached(hash, sig, pk []byte) bool {
|
||||
return nacl.CryptoVerifyDetached(hash, sig, pk)
|
||||
}
|
||||
|
||||
func naclCryptoSignDetached(hash, sk []byte) []byte {
|
||||
return nacl.CryptoSignDetached(hash, sk)
|
||||
}
|
||||
|
||||
func naclSeedToKeyPair(seed []byte) (pk, sk []byte) {
|
||||
kp := nacl.LoadSignKey(seed)
|
||||
defer kp.Free()
|
||||
pk, sk = kp.Public(), kp.Secret()
|
||||
return
|
||||
}
|
||||
|
||||
var naclScalarBaseMult = curve25519.ScalarBaseMult
|
||||
@@ -61,7 +61,7 @@ type nntpConnection struct {
|
||||
// what article is currently selected
|
||||
selected_article string
|
||||
// the policy for federation
|
||||
policy FeedPolicy
|
||||
policy *FeedPolicy
|
||||
// lock help when expecting non pipelined activity
|
||||
access sync.Mutex
|
||||
|
||||
@@ -439,6 +439,10 @@ func (self *nntpConnection) checkMIMEHeaderNoAuth(daemon *NNTPDaemon, hdr textpr
|
||||
reason = "poster's pubkey is banned"
|
||||
ban = true
|
||||
return
|
||||
} else if self.policy != nil && !self.policy.AllowsNewsgroup(newsgroup) {
|
||||
reason = "newsgroup not allowed by feed policy"
|
||||
ban = true
|
||||
return
|
||||
} else if !(ValidMessageID(msgid) || (reference != "" && !ValidMessageID(reference))) {
|
||||
// invalid message id or reference
|
||||
reason = "invalid reference or message id is '" + msgid + "' reference is '" + reference + "'"
|
||||
@@ -561,7 +565,7 @@ func (self *nntpConnection) storeMessage(daemon *NNTPDaemon, hdr textproto.MIMEH
|
||||
// now store attachments and article
|
||||
err = writeMIMEHeader(f, hdr)
|
||||
if err == nil {
|
||||
err = daemon.store.ProcessMessageBody(f, hdr, body)
|
||||
err = daemon.store.ProcessMessageBody(f, hdr, body, daemon.CheckText)
|
||||
if err == nil {
|
||||
// tell daemon
|
||||
daemon.loadFromInfeed(msgid)
|
||||
@@ -1221,14 +1225,11 @@ func (self *nntpConnection) handleLine(daemon *NNTPDaemon, code int, line string
|
||||
func (self *nntpConnection) startStreaming(daemon *NNTPDaemon, reader bool, conn *textproto.Conn) {
|
||||
self.keepalive = time.NewTicker(time.Minute)
|
||||
defer self.keepalive.Stop()
|
||||
for {
|
||||
err := self.handleStreaming(daemon, conn)
|
||||
if err == nil {
|
||||
log.Println(self.name, "done with streaming")
|
||||
return
|
||||
} else {
|
||||
log.Println(self.name, "error while streaming:", err)
|
||||
}
|
||||
err := self.handleStreaming(daemon, conn)
|
||||
if err == nil {
|
||||
log.Println(self.name, "done with streaming")
|
||||
} else {
|
||||
log.Println(self.name, "error while streaming:", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,11 @@ func (self *nullHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
hash := parts[0]
|
||||
msg, err := self.database.GetMessageIDByHash(hash)
|
||||
if err == nil {
|
||||
|
||||
if !self.database.HasArticleLocal(msg.MessageID()) {
|
||||
goto notfound
|
||||
}
|
||||
|
||||
template.genThread(self.attachments, self.requireCaptcha, msg, self.prefix, self.name, w, self.database, isjson)
|
||||
return
|
||||
} else {
|
||||
@@ -63,6 +68,12 @@ func (self *nullHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if !hasgroup {
|
||||
goto notfound
|
||||
}
|
||||
|
||||
banned, _ := self.database.NewsgroupBanned(group)
|
||||
if banned {
|
||||
goto notfound
|
||||
}
|
||||
|
||||
pages := self.database.GetGroupPageCount(group)
|
||||
if page >= int(pages) {
|
||||
goto notfound
|
||||
@@ -128,10 +139,16 @@ func (self *nullHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if len(hash) == 0 {
|
||||
goto notfound
|
||||
}
|
||||
|
||||
msg, err := self.database.GetMessageIDByHash(hash)
|
||||
if err != nil {
|
||||
goto notfound
|
||||
}
|
||||
|
||||
if !self.database.HasArticleLocal(msg.MessageID()) {
|
||||
goto notfound
|
||||
}
|
||||
|
||||
template.genThread(self.attachments, self.requireCaptcha, msg, self.prefix, self.name, w, self.database, isjson)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
package srnd
|
||||
|
||||
import (
|
||||
"log"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type FeedPolicy struct {
|
||||
@@ -15,18 +15,22 @@ type FeedPolicy struct {
|
||||
// do we allow this newsgroup?
|
||||
func (self *FeedPolicy) AllowsNewsgroup(newsgroup string) (result bool) {
|
||||
var k, v string
|
||||
var allows int
|
||||
for k, v = range self.rules {
|
||||
v = strings.Trim(v, " ")
|
||||
match, err := regexp.MatchString(k, newsgroup)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if match {
|
||||
if v == "0" {
|
||||
return false
|
||||
} else if v == "1" {
|
||||
result = true
|
||||
if err == nil {
|
||||
if match {
|
||||
if v == "1" {
|
||||
allows++
|
||||
} else if v == "0" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
||||
result = allows > 0
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -145,12 +145,13 @@ const SearchByHash_1 = "SearchByHash_1"
|
||||
const SearchByHash_2 = "SearchByHash_2"
|
||||
const GetNNTPPostsInGroup = "GetNNTPPostsInGroup"
|
||||
const GetCitesByPostHashLike = "GetCitesByPostHashLike"
|
||||
const GetYearlyPostHistory = "GetYearlyPostHistory"
|
||||
|
||||
func (self *PostgresDatabase) prepareStatements() {
|
||||
self.stmt = map[string]string{
|
||||
NewsgroupBanned: "SELECT COUNT(newsgroup) FROM BannedGroups WHERE newsgroup = $1",
|
||||
ArticleBanned: "SELECT COUNT(message_id) FROM BannedArticles WHERE message_id = $1",
|
||||
GetAllNewsgroups: "SELECT name FROM Newsgroups",
|
||||
GetAllNewsgroups: "SELECT name FROM Newsgroups WHERE name NOT IN ( SELECT newsgroup FROM BannedGroups )",
|
||||
GetPostsInGroup: "SELECT newsgroup, message_id, ref_id, name, subject, path, time_posted, message, addr FROM ArticlePosts WHERE newsgroup = $1 ORDER BY time_posted",
|
||||
GetPostModel: "SELECT newsgroup, message_id, ref_id, name, subject, path, time_posted, message, addr FROM ArticlePosts WHERE message_id = $1 LIMIT 1",
|
||||
GetArticlePubkey: "SELECT pubkey FROM ArticleKeys WHERE message_id = $1",
|
||||
@@ -210,6 +211,7 @@ func (self *PostgresDatabase) prepareStatements() {
|
||||
SearchByHash_2: "SELECT message_newsgroup, message_id, message_ref_id FROM Articles WHERE message_newsgroup = $2 AND message_id_hash LIKE $1 ORDER BY time_obtained DESC",
|
||||
GetNNTPPostsInGroup: "SELECT message_no, ArticlePosts.message_id, subject, time_posted, ref_id, name, path FROM ArticleNumbers INNER JOIN ArticlePosts ON ArticleNumbers.message_id = ArticlePosts.message_id WHERE ArticlePosts.newsgroup = $1 ORDER BY message_no",
|
||||
GetCitesByPostHashLike: "SELECT message_id, message_ref_id FROM Articles WHERE message_id_hash LIKE $1",
|
||||
GetYearlyPostHistory: "WITH times(endtime, begintime) AS ( SELECT CAST(EXTRACT(epoch from i) AS BIGINT) AS endtime, CAST(EXTRACT(epoch from i - interval '1 month') AS BIGINT) AS begintime FROM generate_series(now() - interval '10 year', now(), '1 month'::interval) i ) SELECT begintime, endtime, ( SELECT count(*) FROM ArticlePosts WHERE time_posted > begintime AND time_posted < endtime) FROM times",
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1720,34 +1722,14 @@ func (self *PostgresDatabase) GetLastPostedPostModels(prefix string, n int64) (p
|
||||
}
|
||||
|
||||
func (self *PostgresDatabase) GetMonthlyPostHistory() (posts []PostEntry) {
|
||||
var oldest int64
|
||||
now := time.Now()
|
||||
now = time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, time.UTC)
|
||||
err := self.conn.QueryRow(self.stmt[GetMonthlyPostHistory]).Scan(&oldest)
|
||||
if err == nil {
|
||||
// we got the oldest
|
||||
// convert it to the oldest year/date
|
||||
old := time.Unix(oldest, 0)
|
||||
old = time.Date(old.Year(), old.Month(), 1, 0, 0, 0, 0, time.UTC)
|
||||
// count up from oldest to newest
|
||||
for now.Unix() >= old.Unix() {
|
||||
var count int64
|
||||
var next_month time.Time
|
||||
if now.Month() < 12 {
|
||||
next_month = time.Date(old.Year(), old.Month()+1, 1, 0, 0, 0, 0, time.UTC)
|
||||
} else {
|
||||
next_month = time.Date(old.Year()+1, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
}
|
||||
// get the post count in that montth
|
||||
err = self.conn.QueryRow(self.stmt[GetLastDaysPosts], old.Unix(), next_month.Unix()).Scan(&count)
|
||||
if err == nil {
|
||||
posts = append(posts, PostEntry{old.Unix(), count})
|
||||
old = next_month
|
||||
} else {
|
||||
posts = nil
|
||||
break
|
||||
}
|
||||
rows, err := self.conn.Query(self.stmt[GetYearlyPostHistory])
|
||||
if rows != nil {
|
||||
for rows.Next() {
|
||||
var begin, end, mag int64
|
||||
rows.Scan(&begin, &end, &mag)
|
||||
posts = append(posts, PostEntry{begin, mag})
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
if err != nil {
|
||||
log.Println("failed getting monthly post history", err)
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
package srnd
|
||||
|
||||
import "testing"
|
||||
import "fmt"
|
||||
import "github.com/majestrate/nacl"
|
||||
|
||||
func TestSignVerify(t *testing.T) {
|
||||
|
||||
msgid := "<asd@asd.asd>"
|
||||
secret := "asdasdasd"
|
||||
seed := parseTripcodeSecret(secret)
|
||||
kp := nacl.LoadSignKey(seed)
|
||||
defer kp.Free()
|
||||
pubkey := hexify(kp.Public())
|
||||
seckey := kp.Secret()
|
||||
sig := msgidFrontendSign(seckey, msgid)
|
||||
fmt.Println(sig, pubkey, msgid)
|
||||
if !verifyFrontendSig(pubkey, sig, msgid) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,7 @@ type ArticleStore interface {
|
||||
// process body of nntp message, register attachments and the article
|
||||
// write the body into writer as we go through the body
|
||||
// does NOT write mime header
|
||||
ProcessMessageBody(wr io.Writer, hdr textproto.MIMEHeader, body *io.LimitedReader) error
|
||||
ProcessMessageBody(wr io.Writer, hdr textproto.MIMEHeader, body *io.LimitedReader, spamfilter func(string) bool) error
|
||||
// register this post with the daemon
|
||||
RegisterPost(nntp NNTPMessage) error
|
||||
// register signed message
|
||||
@@ -428,7 +428,9 @@ func (self *articleStore) getMIMEHeader(messageID string) (hdr textproto.MIMEHea
|
||||
var msg *mail.Message
|
||||
msg, err = readMIMEHeader(r)
|
||||
f.Close()
|
||||
hdr = textproto.MIMEHeader(msg.Header)
|
||||
if msg != nil {
|
||||
hdr = textproto.MIMEHeader(msg.Header)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
log.Println("failed to load article headers for", messageID, err)
|
||||
@@ -437,8 +439,12 @@ func (self *articleStore) getMIMEHeader(messageID string) (hdr textproto.MIMEHea
|
||||
return hdr
|
||||
}
|
||||
|
||||
func (self *articleStore) ProcessMessageBody(wr io.Writer, hdr textproto.MIMEHeader, body *io.LimitedReader) (err error) {
|
||||
func (self *articleStore) ProcessMessageBody(wr io.Writer, hdr textproto.MIMEHeader, body *io.LimitedReader, spamfilter func(string) bool) (err error) {
|
||||
err = read_message_body(body, hdr, self, wr, false, func(nntp NNTPMessage) {
|
||||
if !spamfilter(nntp.Message()) {
|
||||
err = errors.New("spam message")
|
||||
return
|
||||
}
|
||||
err = self.RegisterPost(nntp)
|
||||
if err == nil {
|
||||
pk := hdr.Get("X-PubKey-Ed25519")
|
||||
@@ -469,11 +475,11 @@ func (self *articleStore) GetMessage(msgid string) (nntp NNTPMessage) {
|
||||
R: msg.Body,
|
||||
N: MaxMessageSize,
|
||||
}
|
||||
err = read_message_body(body, hdr, nil, nil, true, func(nntp NNTPMessage) {
|
||||
err = read_message_body(body, hdr, nil, nil, true, func(n NNTPMessage) {
|
||||
c := chnl
|
||||
// inject pubkey for mod
|
||||
nntp.Headers().Set("X-PubKey-Ed25519", hdr.Get("X-PubKey-Ed25519"))
|
||||
c <- nntp
|
||||
n.Headers().Set("X-PubKey-Ed25519", hdr.Get("X-PubKey-Ed25519"))
|
||||
c <- n
|
||||
close(c)
|
||||
})
|
||||
if err == nil {
|
||||
@@ -569,25 +575,35 @@ func read_message_body(body *io.LimitedReader, hdr map[string][]string, store Ar
|
||||
} else if media_type == "message/rfc822" {
|
||||
// tripcoded message
|
||||
sig := nntp.headers.Get("X-Signature-Ed25519-Sha512", "")
|
||||
var blake bool
|
||||
if sig == "" {
|
||||
sig = nntp.headers.Get("X-Signature-Ed25519-Blake2b", "")
|
||||
blake = sig != ""
|
||||
}
|
||||
pk := nntp.Pubkey()
|
||||
if pk == "" || sig == "" {
|
||||
if (pk == "" || sig == "") && !blake {
|
||||
log.Println("invalid sig or pubkey", sig, pk)
|
||||
nntp.Reset()
|
||||
return errors.New("invalid headers")
|
||||
}
|
||||
// process inner body
|
||||
// verify message
|
||||
err = verifyMessage(pk, sig, body, func(h map[string][]string, innerBody io.Reader) {
|
||||
f := func(h map[string][]string, innerBody io.Reader) {
|
||||
// handle inner message
|
||||
ir := &io.LimitedReader{
|
||||
R: innerBody,
|
||||
N: body.N,
|
||||
}
|
||||
err := read_message_body(ir, h, store, nil, true, callback)
|
||||
if err != nil {
|
||||
log.Println("error reading inner signed message", err)
|
||||
e := read_message_body(ir, h, store, nil, true, callback)
|
||||
if e != nil {
|
||||
log.Println("error reading inner signed message", e)
|
||||
}
|
||||
})
|
||||
}
|
||||
if blake {
|
||||
err = verifyMessageBLAKE2B(pk, sig, body, f)
|
||||
} else {
|
||||
err = verifyMessageSHA512(pk, sig, body, f)
|
||||
}
|
||||
if err != nil {
|
||||
log.Println("error reading inner message", err)
|
||||
}
|
||||
|
||||
@@ -292,11 +292,12 @@ func (self *templateEngine) genThread(allowFiles, requireCaptcha bool, root Arti
|
||||
newsgroup := root.Newsgroup()
|
||||
msgid := root.MessageID()
|
||||
|
||||
if !db.HasArticleLocal(msgid) {
|
||||
log.Println("don't have", msgid, "locally, not regenerating")
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
if !db.HasArticleLocal(msgid) {
|
||||
log.Println("don't have", msgid, "locally, not regenerating")
|
||||
return
|
||||
}
|
||||
*/
|
||||
t, err := db.GetThreadModel(prefix, msgid)
|
||||
if err == nil {
|
||||
if json {
|
||||
@@ -416,10 +417,12 @@ func (self *templateEngine) genGraphs(prefix string, wr io.Writer, db Database)
|
||||
|
||||
var all_posts postsGraph
|
||||
// this may take a bit
|
||||
log.Println("getting monthly post history...")
|
||||
posts := db.GetMonthlyPostHistory()
|
||||
|
||||
if posts == nil {
|
||||
// wtf?
|
||||
log.Println("no monthly posts gotten wtfug yo?")
|
||||
} else {
|
||||
for _, entry := range posts {
|
||||
all_posts = append(all_posts, postsGraphRow{
|
||||
|
||||
23
contrib/backends/srndv2/src/srnd/testdata/article.test.txt
vendored
Normal file
23
contrib/backends/srndv2/src/srnd/testdata/article.test.txt
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
Subject: My moderation decision/perspective
|
||||
From: mgs <poster@web.oniichan.onion>
|
||||
X-Signature-Ed25519-SHA512: 6e0478722d0de3c0896e8aa7bd9bb1fa94ba6831faf0c54c4aa1d91a191382f85ae57833a6e00f1d4da53048df0e0cb8402df5f952948aa53fb5788ca9242f02
|
||||
X-Frontend-Pubkey: b1dcaa6ba60c1381a5823c3c61c995afeaead79896f95f9748da5fe1cf6ea43f
|
||||
Path: web.oniichan.onion
|
||||
Content-Type: message/rfc822; charset=UTF-8
|
||||
Newsgroups: overchan.moderation
|
||||
Message-ID: <b880c1483096181@web.oniichan.onion>
|
||||
Date: Fri, 30 Dec 2016 11:09:41 +0000
|
||||
X-PubKey-Ed25519: 9a659a2c761009374b510f2eb133cf7e67220f93c8912fd4668c601144823121
|
||||
X-Frontend-Signature: 11eb01c8a137e29f4e7a8b25a2cf38b5d913db9d4faaca5c5f8946b0e7f83d826bd3af6c9fc6a40c1091c09ad437b2b9d9aa41617c63a464e5b1833ed77fe202
|
||||
|
||||
Path: web.oniichan.onion
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
Newsgroups: overchan.moderation
|
||||
Subject: My moderation decision/perspective
|
||||
From: mgs <poster@web.oniichan.onion>
|
||||
Message-ID: <b880c1483096181@web.oniichan.onion>
|
||||
Date: Fri, 30 Dec 2016 11:09:41 +0000
|
||||
|
||||
Like the subject says, I will update in this thread on decisions I made on ctl with briefs/explanations. Anyone is actually welcomed to comment, discuss, and opinionate here, but not spam. If anyone uses this very thread to spam, I will delete, the node owners will see it, and I will reply it here exactly saying so.
|
||||
|
||||
Iow: please critique.
|
||||
@@ -84,7 +84,7 @@ func reThumbnail(threads int, store ArticleStore, missing bool) {
|
||||
|
||||
// generate a keypair from the command line
|
||||
func KeygenTool() {
|
||||
pub, sec := newSignKeypair()
|
||||
pub, sec := newNaclSignKeypair()
|
||||
log.Println("public key:", pub)
|
||||
log.Println("secret key:", sec)
|
||||
}
|
||||
|
||||
@@ -6,12 +6,13 @@ package srnd
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"crypto/sha512"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/majestrate/nacl"
|
||||
"golang.org/x/crypto/ed25519"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
@@ -102,9 +103,15 @@ func OpenFileWriter(fname string) (io.WriteCloser, error) {
|
||||
return os.Create(fname)
|
||||
}
|
||||
|
||||
func randbytes(l int) []byte {
|
||||
b := make([]byte, l)
|
||||
io.ReadFull(rand.Reader, b)
|
||||
return b
|
||||
}
|
||||
|
||||
// make a random string
|
||||
func randStr(length int) string {
|
||||
return hex.EncodeToString(nacl.RandBytes(length))[length:]
|
||||
return hex.EncodeToString(randbytes(length))[length:]
|
||||
}
|
||||
|
||||
// time for right now as int64
|
||||
@@ -210,7 +217,7 @@ func i2pDestHashLen() int {
|
||||
// generate a new encryption key for it
|
||||
// return the encryption key and the encrypted address
|
||||
func newAddrEnc(addr string) (string, string) {
|
||||
key_bytes := nacl.RandBytes(encAddrBytes())
|
||||
key_bytes := randbytes(encAddrBytes())
|
||||
key := base64.StdEncoding.EncodeToString(key_bytes)
|
||||
return key, encAddr(addr, key)
|
||||
}
|
||||
@@ -271,7 +278,12 @@ func decAddr(encaddr, key string) string {
|
||||
res_bytes[idx] = encaddr_bytes[idx] ^ b
|
||||
}
|
||||
res := string(res_bytes)
|
||||
return strings.Trim(res, " ")
|
||||
res = strings.Trim(res, " ")
|
||||
if strings.Index(res, "/") == -1 {
|
||||
// TODO: ipv6
|
||||
res += "/32"
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
var exp_valid_newsgroup = regexp.MustCompilePOSIX(`^[a-zA-Z0-9.]{1,128}$`)
|
||||
@@ -284,13 +296,16 @@ func ValidNewsgroup(newsgroup string) bool {
|
||||
return newsgroupValidFormat(newsgroup)
|
||||
}
|
||||
|
||||
func genNaclKeypair() (pk, sk []byte) {
|
||||
sk = randbytes(32)
|
||||
pk, _ = naclSeedToKeyPair(sk)
|
||||
return
|
||||
}
|
||||
|
||||
// generate a new signing keypair
|
||||
// public, secret
|
||||
func newSignKeypair() (string, string) {
|
||||
kp := nacl.GenSignKeypair()
|
||||
defer kp.Free()
|
||||
pk := kp.Public()
|
||||
sk := kp.Seed()
|
||||
func newNaclSignKeypair() (string, string) {
|
||||
pk, sk := genNaclKeypair()
|
||||
return hex.EncodeToString(pk), hex.EncodeToString(sk)
|
||||
}
|
||||
|
||||
@@ -380,15 +395,27 @@ func hexify(data []byte) string {
|
||||
// extract pubkey from secret key
|
||||
// return as hex
|
||||
func getSignPubkey(sk []byte) string {
|
||||
k, _ := nacl.GetSignPubkey(sk)
|
||||
return hexify(k)
|
||||
pk, _ := naclSeedToKeyPair(sk)
|
||||
return hexify(pk)
|
||||
}
|
||||
|
||||
// sign data with secret key the fucky srnd way
|
||||
// return signature as hex
|
||||
func cryptoSign(h, sk []byte) string {
|
||||
// XXX: DEPRECATED
|
||||
func cryptoSignFucky(h, sk []byte) string {
|
||||
// sign
|
||||
sig := nacl.CryptoSignFucky(h, sk)
|
||||
sig := naclCryptoSignFucky(h, sk)
|
||||
if sig == nil {
|
||||
return "[failed to sign]"
|
||||
}
|
||||
return hexify(sig)
|
||||
}
|
||||
|
||||
func cryptoSignProper(h, sk []byte) string {
|
||||
key := make(ed25519.PrivateKey, ed25519.PrivateKeySize)
|
||||
copy(key, sk)
|
||||
// sign
|
||||
sig := ed25519.Sign(key, h)
|
||||
if sig == nil {
|
||||
return "[failed to sign]"
|
||||
}
|
||||
@@ -400,7 +427,7 @@ func cryptoSign(h, sk []byte) string {
|
||||
func parseTripcodeSecret(str string) []byte {
|
||||
// try decoding hex
|
||||
raw := unhex(str)
|
||||
keylen := nacl.CryptoSignSeedLen()
|
||||
keylen := 32
|
||||
if raw == nil || len(raw) != keylen {
|
||||
// treat this as a "regular" chan tripcode
|
||||
// decode as bytes then pad the rest with 0s if it doesn't fit
|
||||
@@ -641,17 +668,17 @@ func extractRealIP(r *http.Request) (ip string, err error) {
|
||||
|
||||
func serverPubkeyIsValid(pubkey string) bool {
|
||||
b := unhex(pubkey)
|
||||
return b != nil && len(b) == nacl.CryptoSignPubKeySize()
|
||||
return b != nil && len(b) == 32
|
||||
}
|
||||
|
||||
func verifyFrontendSig(pubkey, sig, msgid string) bool {
|
||||
s := unhex(sig)
|
||||
k := unhex(pubkey)
|
||||
h := sha512.Sum512([]byte(msgid))
|
||||
return nacl.CryptoVerifyFucky(h[:], s, k)
|
||||
return naclCryptoVerifyFucky(h[:], s, k)
|
||||
}
|
||||
|
||||
func msgidFrontendSign(sk []byte, msgid string) string {
|
||||
h := sha512.Sum512([]byte(msgid))
|
||||
return cryptoSign(h[:], sk)
|
||||
return cryptoSignFucky(h[:], sk)
|
||||
}
|
||||
|
||||
@@ -57,6 +57,8 @@ func (self *VarnishCache) RegenAll() {
|
||||
|
||||
func (self *VarnishCache) RegenFrontPage() {
|
||||
self.invalidate(fmt.Sprintf("%s%s", self.varnish_url, self.prefix))
|
||||
// TODO: this is also lazy af
|
||||
self.invalidate(fmt.Sprintf("%s%shistory.html", self.varnish_url, self.prefix))
|
||||
}
|
||||
|
||||
func (self *VarnishCache) invalidateUkko() {
|
||||
|
||||
10
contrib/backends/srndv2/src/srnd/vendor/edwards25519/BUILD.bazel
vendored
Normal file
10
contrib/backends/srndv2/src/srnd/vendor/edwards25519/BUILD.bazel
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"const.go",
|
||||
"edwards25519.go",
|
||||
],
|
||||
visibility = ["//sign:__subpackages__"],
|
||||
)
|
||||
27
contrib/backends/srndv2/src/srnd/vendor/edwards25519/LICENSE
vendored
Normal file
27
contrib/backends/srndv2/src/srnd/vendor/edwards25519/LICENSE
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2017 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
1422
contrib/backends/srndv2/src/srnd/vendor/edwards25519/const.go
vendored
Normal file
1422
contrib/backends/srndv2/src/srnd/vendor/edwards25519/const.go
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1769
contrib/backends/srndv2/src/srnd/vendor/edwards25519/edwards25519.go
vendored
Normal file
1769
contrib/backends/srndv2/src/srnd/vendor/edwards25519/edwards25519.go
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
contrib/backends/srndv2/src/srnd/vendor/edwards25519/readme.txt
vendored
Normal file
1
contrib/backends/srndv2/src/srnd/vendor/edwards25519/readme.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
cloned from https://github.com/kevinburke/nacl/commit/38707d146a0b97e13e5de807a3ad62a933f7668c
|
||||
23
contrib/backends/srndv2/src/srnd/vendor/github.com/dchest/blake2b/README
generated
vendored
Normal file
23
contrib/backends/srndv2/src/srnd/vendor/github.com/dchest/blake2b/README
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
Go implementation of BLAKE2b collision-resistant cryptographic hash function
|
||||
created by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, and
|
||||
Christian Winnerlein (https://blake2.net).
|
||||
|
||||
INSTALLATION
|
||||
|
||||
$ go get github.com/dchest/blake2b
|
||||
|
||||
|
||||
DOCUMENTATION
|
||||
|
||||
See http://godoc.org/github.com/dchest/blake2b
|
||||
|
||||
|
||||
PUBLIC DOMAIN DEDICATION
|
||||
|
||||
Written in 2012 by Dmitry Chestnykh.
|
||||
|
||||
To the extent possible under law, the author have dedicated all copyright
|
||||
and related and neighboring rights to this software to the public domain
|
||||
worldwide. This software is distributed without any warranty.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
293
contrib/backends/srndv2/src/srnd/vendor/github.com/dchest/blake2b/blake2b.go
generated
vendored
Normal file
293
contrib/backends/srndv2/src/srnd/vendor/github.com/dchest/blake2b/blake2b.go
generated
vendored
Normal file
@@ -0,0 +1,293 @@
|
||||
// Written in 2012 by Dmitry Chestnykh.
|
||||
//
|
||||
// To the extent possible under law, the author have dedicated all copyright
|
||||
// and related and neighboring rights to this software to the public domain
|
||||
// worldwide. This software is distributed without any warranty.
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
// Package blake2b implements BLAKE2b cryptographic hash function.
|
||||
package blake2b
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"hash"
|
||||
)
|
||||
|
||||
const (
|
||||
BlockSize = 128 // block size of algorithm
|
||||
Size = 64 // maximum digest size
|
||||
SaltSize = 16 // maximum salt size
|
||||
PersonSize = 16 // maximum personalization string size
|
||||
KeySize = 64 // maximum size of key
|
||||
)
|
||||
|
||||
type digest struct {
|
||||
h [8]uint64 // current chain value
|
||||
t [2]uint64 // message bytes counter
|
||||
f [2]uint64 // finalization flags
|
||||
x [BlockSize]byte // buffer for data not yet compressed
|
||||
nx int // number of bytes in buffer
|
||||
|
||||
ih [8]uint64 // initial chain value (after config)
|
||||
paddedKey [BlockSize]byte // copy of key, padded with zeros
|
||||
isKeyed bool // indicates whether hash was keyed
|
||||
size uint8 // digest size in bytes
|
||||
isLastNode bool // indicates processing of the last node in tree hashing
|
||||
}
|
||||
|
||||
// Initialization values.
|
||||
var iv = [8]uint64{
|
||||
0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
|
||||
0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
|
||||
0x510e527fade682d1, 0x9b05688c2b3e6c1f,
|
||||
0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
|
||||
}
|
||||
|
||||
// Config is used to configure hash function parameters and keying.
|
||||
// All parameters are optional.
|
||||
type Config struct {
|
||||
Size uint8 // digest size (if zero, default size of 64 bytes is used)
|
||||
Key []byte // key for prefix-MAC
|
||||
Salt []byte // salt (if < 16 bytes, padded with zeros)
|
||||
Person []byte // personalization (if < 16 bytes, padded with zeros)
|
||||
Tree *Tree // parameters for tree hashing
|
||||
}
|
||||
|
||||
// Tree represents parameters for tree hashing.
|
||||
type Tree struct {
|
||||
Fanout uint8 // fanout
|
||||
MaxDepth uint8 // maximal depth
|
||||
LeafSize uint32 // leaf maximal byte length (0 for unlimited)
|
||||
NodeOffset uint64 // node offset (0 for first, leftmost or leaf)
|
||||
NodeDepth uint8 // node depth (0 for leaves)
|
||||
InnerHashSize uint8 // inner hash byte length
|
||||
IsLastNode bool // indicates processing of the last node of layer
|
||||
}
|
||||
|
||||
var (
|
||||
defaultConfig = &Config{Size: Size}
|
||||
config256 = &Config{Size: 32}
|
||||
)
|
||||
|
||||
func verifyConfig(c *Config) error {
|
||||
if c.Size > Size {
|
||||
return errors.New("digest size is too large")
|
||||
}
|
||||
if len(c.Key) > KeySize {
|
||||
return errors.New("key is too large")
|
||||
}
|
||||
if len(c.Salt) > SaltSize {
|
||||
// Smaller salt is okay: it will be padded with zeros.
|
||||
return errors.New("salt is too large")
|
||||
}
|
||||
if len(c.Person) > PersonSize {
|
||||
// Smaller personalization is okay: it will be padded with zeros.
|
||||
return errors.New("personalization is too large")
|
||||
}
|
||||
if c.Tree != nil {
|
||||
if c.Tree.InnerHashSize > Size {
|
||||
return errors.New("incorrect tree inner hash size")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// New returns a new hash.Hash configured with the given Config.
|
||||
// Config can be nil, in which case the default one is used, calculating 64-byte digest.
|
||||
// Returns non-nil error if Config contains invalid parameters.
|
||||
func New(c *Config) (hash.Hash, error) {
|
||||
if c == nil {
|
||||
c = defaultConfig
|
||||
} else {
|
||||
if c.Size == 0 {
|
||||
// Set default size if it's zero.
|
||||
c.Size = Size
|
||||
}
|
||||
if err := verifyConfig(c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
d := new(digest)
|
||||
d.initialize(c)
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// initialize initializes digest with the given
|
||||
// config, which must be non-nil and verified.
|
||||
func (d *digest) initialize(c *Config) {
|
||||
// Create parameter block.
|
||||
var p [BlockSize]byte
|
||||
p[0] = c.Size
|
||||
p[1] = uint8(len(c.Key))
|
||||
if c.Salt != nil {
|
||||
copy(p[32:], c.Salt)
|
||||
}
|
||||
if c.Person != nil {
|
||||
copy(p[48:], c.Person)
|
||||
}
|
||||
if c.Tree != nil {
|
||||
p[2] = c.Tree.Fanout
|
||||
p[3] = c.Tree.MaxDepth
|
||||
binary.LittleEndian.PutUint32(p[4:], c.Tree.LeafSize)
|
||||
binary.LittleEndian.PutUint64(p[8:], c.Tree.NodeOffset)
|
||||
p[16] = c.Tree.NodeDepth
|
||||
p[17] = c.Tree.InnerHashSize
|
||||
} else {
|
||||
p[2] = 1
|
||||
p[3] = 1
|
||||
}
|
||||
// Initialize.
|
||||
d.size = c.Size
|
||||
for i := 0; i < 8; i++ {
|
||||
d.h[i] = iv[i] ^ binary.LittleEndian.Uint64(p[i*8:])
|
||||
}
|
||||
if c.Tree != nil && c.Tree.IsLastNode {
|
||||
d.isLastNode = true
|
||||
}
|
||||
// Process key.
|
||||
if len(c.Key) > 0 {
|
||||
copy(d.paddedKey[:], c.Key)
|
||||
d.Write(d.paddedKey[:])
|
||||
d.isKeyed = true
|
||||
}
|
||||
// Save a copy of initialized state.
|
||||
copy(d.ih[:], d.h[:])
|
||||
}
|
||||
|
||||
// New512 returns a new hash.Hash computing the BLAKE2b 64-byte checksum.
|
||||
func New512() hash.Hash {
|
||||
d := new(digest)
|
||||
d.initialize(defaultConfig)
|
||||
return d
|
||||
}
|
||||
|
||||
// New256 returns a new hash.Hash computing the BLAKE2b 32-byte checksum.
|
||||
func New256() hash.Hash {
|
||||
d := new(digest)
|
||||
d.initialize(config256)
|
||||
return d
|
||||
}
|
||||
|
||||
// NewMAC returns a new hash.Hash computing BLAKE2b prefix-
|
||||
// Message Authentication Code of the given size in bytes
|
||||
// (up to 64) with the given key (up to 64 bytes in length).
|
||||
func NewMAC(outBytes uint8, key []byte) hash.Hash {
|
||||
d, err := New(&Config{Size: outBytes, Key: key})
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// Reset resets the state of digest to the initial state
|
||||
// after configuration and keying.
|
||||
func (d *digest) Reset() {
|
||||
copy(d.h[:], d.ih[:])
|
||||
d.t[0] = 0
|
||||
d.t[1] = 0
|
||||
d.f[0] = 0
|
||||
d.f[1] = 0
|
||||
d.nx = 0
|
||||
if d.isKeyed {
|
||||
d.Write(d.paddedKey[:])
|
||||
}
|
||||
}
|
||||
|
||||
// Size returns the digest size in bytes.
|
||||
func (d *digest) Size() int { return int(d.size) }
|
||||
|
||||
// BlockSize returns the algorithm block size in bytes.
|
||||
func (d *digest) BlockSize() int { return BlockSize }
|
||||
|
||||
func (d *digest) Write(p []byte) (nn int, err error) {
|
||||
nn = len(p)
|
||||
left := BlockSize - d.nx
|
||||
if len(p) > left {
|
||||
// Process buffer.
|
||||
copy(d.x[d.nx:], p[:left])
|
||||
p = p[left:]
|
||||
blocks(d, d.x[:])
|
||||
d.nx = 0
|
||||
}
|
||||
// Process full blocks except for the last one.
|
||||
if len(p) > BlockSize {
|
||||
n := len(p) &^ (BlockSize - 1)
|
||||
if n == len(p) {
|
||||
n -= BlockSize
|
||||
}
|
||||
blocks(d, p[:n])
|
||||
p = p[n:]
|
||||
}
|
||||
// Fill buffer.
|
||||
d.nx += copy(d.x[d.nx:], p)
|
||||
return
|
||||
}
|
||||
|
||||
// Sum returns the calculated checksum.
|
||||
func (d0 *digest) Sum(in []byte) []byte {
|
||||
// Make a copy of d0 so that caller can keep writing and summing.
|
||||
d := *d0
|
||||
hash := d.checkSum()
|
||||
return append(in, hash[:d.size]...)
|
||||
}
|
||||
|
||||
func (d *digest) checkSum() [Size]byte {
|
||||
// Do not create unnecessary copies of the key.
|
||||
if d.isKeyed {
|
||||
for i := 0; i < len(d.paddedKey); i++ {
|
||||
d.paddedKey[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
dec := BlockSize - uint64(d.nx)
|
||||
if d.t[0] < dec {
|
||||
d.t[1]--
|
||||
}
|
||||
d.t[0] -= dec
|
||||
|
||||
// Pad buffer with zeros.
|
||||
for i := d.nx; i < len(d.x); i++ {
|
||||
d.x[i] = 0
|
||||
}
|
||||
// Set last block flag.
|
||||
d.f[0] = 0xffffffffffffffff
|
||||
if d.isLastNode {
|
||||
d.f[1] = 0xffffffffffffffff
|
||||
}
|
||||
// Compress last block.
|
||||
blocks(d, d.x[:])
|
||||
|
||||
var out [Size]byte
|
||||
j := 0
|
||||
for _, s := range d.h[:(d.size-1)/8+1] {
|
||||
out[j+0] = byte(s >> 0)
|
||||
out[j+1] = byte(s >> 8)
|
||||
out[j+2] = byte(s >> 16)
|
||||
out[j+3] = byte(s >> 24)
|
||||
out[j+4] = byte(s >> 32)
|
||||
out[j+5] = byte(s >> 40)
|
||||
out[j+6] = byte(s >> 48)
|
||||
out[j+7] = byte(s >> 56)
|
||||
j += 8
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Sum512 returns a 64-byte BLAKE2b hash of data.
|
||||
func Sum512(data []byte) [64]byte {
|
||||
var d digest
|
||||
d.initialize(defaultConfig)
|
||||
d.Write(data)
|
||||
return d.checkSum()
|
||||
}
|
||||
|
||||
// Sum256 returns a 32-byte BLAKE2b hash of data.
|
||||
func Sum256(data []byte) (out [32]byte) {
|
||||
var d digest
|
||||
d.initialize(config256)
|
||||
d.Write(data)
|
||||
sum := d.checkSum()
|
||||
copy(out[:], sum[:32])
|
||||
return
|
||||
}
|
||||
625
contrib/backends/srndv2/src/srnd/vendor/github.com/dchest/blake2b/blake2b_test.go
generated
vendored
Normal file
625
contrib/backends/srndv2/src/srnd/vendor/github.com/dchest/blake2b/blake2b_test.go
generated
vendored
Normal file
@@ -0,0 +1,625 @@
|
||||
// Written in 2012 by Dmitry Chestnykh.
|
||||
//
|
||||
// To the extent possible under law, the author have dedicated all copyright
|
||||
// and related and neighboring rights to this software to the public domain
|
||||
// worldwide. This software is distributed without any warranty.
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
package blake2b
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSum(t *testing.T) {
|
||||
buf := make([]byte, len(golden))
|
||||
for i := range buf {
|
||||
buf[i] = byte(i)
|
||||
}
|
||||
h := New512()
|
||||
for i, v := range golden {
|
||||
if v != fmt.Sprintf("%x", Sum512(buf[:i])) {
|
||||
t.Errorf("%d: Sum512(): \nexpected %s\ngot %x", i, v, Sum512(buf[:i]))
|
||||
}
|
||||
h.Reset()
|
||||
h.Write(buf[:i])
|
||||
sum := h.Sum(nil)
|
||||
if fmt.Sprintf("%x", sum) != v {
|
||||
t.Errorf("%d:\nexpected %s\ngot %x", i, v, sum)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestSum256(t *testing.T) {
|
||||
// Simple one-hash test.
|
||||
in := "The cryptographic hash function BLAKE2 is an improved version of the SHA-3 finalist BLAKE"
|
||||
good := "e5866d0c42b4e27e89a316fa5c3ba8cacae754e53d8267da37ba1893c2fcd92c"
|
||||
if good != fmt.Sprintf("%x", Sum256([]byte(in))) {
|
||||
t.Errorf("Sum256(): \nexpected %s\ngot %x", good, Sum256([]byte(in)))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestSumLength(t *testing.T) {
|
||||
h, _ := New(&Config{Size: 19})
|
||||
sum := h.Sum(nil)
|
||||
if len(sum) != 19 {
|
||||
t.Fatalf("Sum() returned a slice larger than the given hash size")
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyedSum(t *testing.T) {
|
||||
buf := make([]byte, len(goldenKeyed))
|
||||
for i := range buf {
|
||||
buf[i] = byte(i)
|
||||
}
|
||||
h := NewMAC(64, buf[:64])
|
||||
for i, v := range goldenKeyed {
|
||||
h.Reset()
|
||||
h.Write(buf[:i])
|
||||
sum := h.Sum(nil)
|
||||
if fmt.Sprintf("%x", sum) != v {
|
||||
t.Errorf("%d:\nexpected %s\ngot %x", i, v, sum)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var bench = New512()
|
||||
var buf = make([]byte, 8<<10)
|
||||
|
||||
func BenchmarkWrite1K(b *testing.B) {
|
||||
b.SetBytes(1024)
|
||||
for i := 0; i < b.N; i++ {
|
||||
bench.Write(buf[:1024])
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkWrite8K(b *testing.B) {
|
||||
b.SetBytes(int64(len(buf)))
|
||||
for i := 0; i < b.N; i++ {
|
||||
bench.Write(buf)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHash64(b *testing.B) {
|
||||
b.SetBytes(64)
|
||||
for i := 0; i < b.N; i++ {
|
||||
Sum512(buf[:64])
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHash128(b *testing.B) {
|
||||
b.SetBytes(128)
|
||||
for i := 0; i < b.N; i++ {
|
||||
Sum512(buf[:128])
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHash1K(b *testing.B) {
|
||||
b.SetBytes(1024)
|
||||
for i := 0; i < b.N; i++ {
|
||||
Sum512(buf[:1024])
|
||||
}
|
||||
}
|
||||
|
||||
// Test vectors taken from reference implementation in C#.
|
||||
var golden = []string{
|
||||
"786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce",
|
||||
"2fa3f686df876995167e7c2e5d74c4c7b6e48f8068fe0e44208344d480f7904c36963e44115fe3eb2a3ac8694c28bcb4f5a0f3276f2e79487d8219057a506e4b",
|
||||
"1c08798dc641aba9dee435e22519a4729a09b2bfe0ff00ef2dcd8ed6f8a07d15eaf4aee52bbf18ab5608a6190f70b90486c8a7d4873710b1115d3debbb4327b5",
|
||||
"40a374727302d9a4769c17b5f409ff32f58aa24ff122d7603e4fda1509e919d4107a52c57570a6d94e50967aea573b11f86f473f537565c66f7039830a85d186",
|
||||
"77ddf4b14425eb3d053c1e84e3469d92c4cd910ed20f92035e0c99d8a7a86cecaf69f9663c20a7aa230bc82f60d22fb4a00b09d3eb8fc65ef547fe63c8d3ddce",
|
||||
"cbaa0ba7d482b1f301109ae41051991a3289bc1198005af226c5e4f103b66579f461361044c8ba3439ff12c515fb29c52161b7eb9c2837b76a5dc33f7cb2e2e8",
|
||||
"f95d45cf69af5c2023bdb505821e62e85d7caedf7beda12c0248775b0c88205eeb35af3a90816f6608ce7dd44ec28db1140614e1ddebf3aa9cd1843e0fad2c36",
|
||||
"8f945ba700f2530e5c2a7df7d5dce0f83f9efc78c073fe71ae1f88204a4fd1cf70a073f5d1f942ed623aa16e90a871246c90c45b621b3401a5ddbd9df6264165",
|
||||
"e998e0dc03ec30eb99bb6bfaaf6618acc620320d7220b3af2b23d112d8e9cb1262f3c0d60d183b1ee7f096d12dae42c958418600214d04f5ed6f5e718be35566",
|
||||
"6a9a090c61b3410aede7ec9138146ceb2c69662f460c3da53c6515c1eb31f41ca3d280e567882f95cf664a94147d78f42cfc714a40d22ef19470e053493508a2",
|
||||
"29102511d749db3cc9b4e335fa1f5e8faca8421d558f6a3f3321d50d044a248ba595cfc3efd3d2adc97334da732413f5cbf4751c362ba1d53862ac1e8dabeee8",
|
||||
"c97a4779d47e6f77729b5917d0138abb35980ab641bd73a8859eb1ac98c05362ed7d608f2e9587d6ba9e271d343125d40d933a8ed04ec1fe75ec407c7a53c34e",
|
||||
"10f0dc91b9f845fb95fad6860e6ce1adfa002c7fc327116d44d047cd7d5870d772bb12b5fac00e02b08ac2a0174d0446c36ab35f14ca31894cd61c78c849b48a",
|
||||
"dea9101cac62b8f6a3c650f90eea5bfae2653a4eafd63a6d1f0f132db9e4f2b1b662432ec85b17bcac41e775637881f6aab38dd66dcbd080f0990a7a6e9854fe",
|
||||
"441ffaa08cd79dff4afc9b9e5b5620eec086730c25f661b1d6fbfbd1cec3148dd72258c65641f2fca5eb155fadbcabb13c6e21dc11faf72c2a281b7d56145f19",
|
||||
"444b240fe3ed86d0e2ef4ce7d851edde22155582aa0914797b726cd058b6f45932e0e129516876527b1dd88fc66d7119f4ab3bed93a61a0e2d2d2aeac336d958",
|
||||
"bfbabbef45554ccfa0dc83752a19cc35d5920956b301d558d772282bc867009168e9e98606bb5ba73a385de5749228c925a85019b71f72fe29b3cd37ca52efe6",
|
||||
"9c4d0c3e1cdbbf485bec86f41cec7c98373f0e09f392849aaa229ebfbf397b22085529cb7ef39f9c7c2222a514182b1effaa178cc3687b1b2b6cbcb6fdeb96f8",
|
||||
"477176b3bfcbadd7657c23c24625e4d0d674d1868f006006398af97aa41877c8e70d3d14c3bbc9bbcdcea801bd0e1599af1f3eec67405170f4e26c964a57a8b7",
|
||||
"a78c490eda3173bb3f10dee52f110fb1c08e0302230b85ddd7c11257d92de148785ef00c039c0bb8eb9808a35b2d8c080f572859714c9d4069c5bcaf090e898e",
|
||||
"58d023397beb5b4145cb2255b07d74290b36d9fd1e594afbd8eea47c205b2efbfe6f46190faf95af504ab072e36f6c85d767a321bfd7f22687a4abbf494a689c",
|
||||
"4001ec74d5a46fd29c2c3cdbe5d1b9f20e51a941be98d2a4e1e2fbf866a672121db6f81a514cfd10e7358d571bdba48e4ce708b9d124894bc0b5ed554935f73a",
|
||||
"ccd1b22dab6511225d2401ea2d8625d206a12473cc732b615e5640cefff0a4adf971b0e827a619e0a80f5db9ccd0962329010d07e34a2064e731c520817b2183",
|
||||
"b4a0a9e3574edb9e1e72aa31e39cc5f30dbf943f8cabc408449654a39131e66d718a18819143e3ea96b4a1895988a1c0056cf2b6e04f9ac19d657383c2910c44",
|
||||
"447becab16630608d39f4f058b16f7af95b85a76aa0fa7cea2b80755fb76e9c804f2ca78f02643c915fbf2fce5e19de86000de03b18861815a83126071f8a37b",
|
||||
"54e6dab9977380a5665822db93374eda528d9beb626f9b94027071cb26675e112b4a7fec941ee60a81e4d2ea3ff7bc52cfc45dfbfe735a1c646b2cf6d6a49b62",
|
||||
"3ea62625949e3646704d7e3c906f82f6c028f540f5f72a794b0c57bf97b7649bfeb90b01d3ca3e829de21b3826e6f87014d3c77350cb5a15ff5d468a81bec160",
|
||||
"213cfe145c54a33691569980e5938c8883a46d84d149c8ff1a67cd287b4d49c6da69d3a035443db085983d0efe63706bd5b6f15a7da459e8d50a19093db55e80",
|
||||
"5716c4a38f38db104e494a0a27cbe89a26a6bb6f499ec01c8c01aa7cb88497e75148cd6eee12a7168b6f78ab74e4be749251a1a74c38c86d6129177e2889e0b6",
|
||||
"030460a98bdf9ff17cd96404f28fc304f2b7c04eaade53677fd28f788ca22186b8bc80dd21d17f8549c711aff0e514e19d4e15f5990252a03e082f28dc2052f6",
|
||||
"19e7f1ccee88a10672333e390cf22013a8c734c6cb9eab41f17c3c8032a2e4aca0569ea36f0860c7a1af28fa476840d66011168859334a9e4ef9cc2e61a0e29e",
|
||||
"29f8b8c78c80f2fcb4bdf7825ed90a70d625ff785d262677e250c04f3720c888d03f8045e4edf3f5285bd39d928a10a7d0a5df00b8484ac2868142a1e8bea351",
|
||||
"5c52920a7263e39d57920ca0cb752ac6d79a04fef8a7a216a1ecb7115ce06d89fd7d735bd6f4272555dba22c2d1c96e6352322c62c5630fde0f4777a76c3de2c",
|
||||
"83b098f262251bf660064a9d3511ce7687a09e6dfbb878299c30e93dfb43a9314db9a600337db26ebeedaf2256a96dabe9b29e7573ad11c3523d874dde5be7ed",
|
||||
"9447d98aa5c9331352f43d3e56d0a9a9f9581865998e2885cc56dd0a0bd5a7b50595bd10f7529bcd31f37dc16a1465d594079667da2a3fcb70401498837cedeb",
|
||||
"867732f2feeb23893097561ac710a4bff453be9cfbedba8ba324f9d312a82d732e1b83b829fdcd177b882ca0c1bf544b223be529924a246a63cf059bfdc50a1b",
|
||||
"f15ab26d4cdfcf56e196bb6ba170a8fccc414de9285afd98a3d3cf2fb88fcbc0f19832ac433a5b2cc2392a4ce34332987d8d2c2bef6c3466138db0c6e42fa47b",
|
||||
"2813516d68ed4a08b39d648aa6aacd81e9d655ecd5f0c13556c60fdf0d333ea38464b36c02baccd746e9575e96c63014f074ae34a0a25b320f0fbedd6acf7665",
|
||||
"d3259afca8a48962fa892e145acf547f26923ae8d4924c8a531581526b04b44c7af83c643ef5a0bc282d36f3fb04c84e28b351f40c74b69dc7840bc717b6f15f",
|
||||
"f14b061ae359fa31b989e30332bfe8de8cc8cdb568e14be214a2223b84caab7419549ecfcc96ce2acec119485d87d157d3a8734fc426597d64f36570ceaf224d",
|
||||
"55e70b01d1fbf8b23b57fb62e26c2ce54f13f8fa2464e6eb98d16a6117026d8b90819012496d4071ebe2e59557ece3519a7aa45802f9615374877332b73490b3",
|
||||
"25261eb296971d6e4a71b2928e64839c67d422872bf9f3c31993615222de9f8f0b2c4be8548559b4b354e736416e3218d4e8a1e219a4a6d43e1a9a521d0e75fc",
|
||||
"08307f347c41294e34bb54cb42b1522d22f824f7b6e5db50fda096798e181a8f026fa27b4ae45d52a62caf9d5198e24a4913c6671775b2d723c1239bfbf016d7",
|
||||
"1e5c62e7e9bfa1b118747a2de08b3ca10112af96a46e4b22c3fc06f9bfee4eb5c49e057a4a4886234324572576bb9b5ecfde0d99b0de4f98ec16e4d1b85fa947",
|
||||
"c74a77395fb8bc126447454838e561e962853dc7eb49a1e3cb67c3d0851f3e39517be8c350ac910903d49cd2bfdf545c99316d0346170b739f0add5d533c2cfc",
|
||||
"0dd57b423cc01eb2861391eb886a0d17079b933fc76eb3fc08a19f8a74952cb68f6bcdc644f77370966e4d13e80560bcf082ef0479d48fbbab4df03b53a4e178",
|
||||
"4d8dc3923edccdfce70072398b8a3da5c31fcb3ee3b645c85f717cbaeb4b673a19394425a585bfb464d92f1597d0b754d163f97ced343b25db5a70ef48ebb34f",
|
||||
"f0a50553e4dfb0c4e3e3d3ba82034857e3b1e50918f5b8a7d698e10d242b0fb544af6c92d0c3aaf9932220416117b4e78ecb8a8f430e13b82a5915290a5819c5",
|
||||
"b15543f3f736086627cc5365e7e8988c2ef155c0fd4f428961b00d1526f04d6d6a658b4b8ed32c5d8621e7f4f8e8a933d9ecc9dd1b8333cbe28cfc37d9719e1c",
|
||||
"7b4fa158e415fef023247264cbbe15d16d91a44424a8db707eb1e2033c30e9e1e7c8c0864595d2cb8c580eb47e9d16abbd7e44e824f7cedb7def57130e52cfe9",
|
||||
"60424ff23234c34dc9687ad502869372cc31a59380186bc2361c835d972f49666eb1ac69629de646f03f9b4db9e2ace093fbfdf8f20ab5f98541978be8ef549f",
|
||||
"7406018ce704d84f5eb9c79fea97da345699468a350ee0b2d0f3a4bf2070304ea862d72a51c57d3064947286f531e0eaf7563702262e6c724abf5ed8c8398d17",
|
||||
"14ef5c6d647b3bd1e6e32006c231199810de5c4dc88e70240273b0ea18e651a3eb4f5ca3114b8a56716969c7cda27e0c8db832ad5e89a2dc6cb0adbe7d93abd1",
|
||||
"38cf6c24e3e08bcf1f6cf3d1b1f65b905239a3118033249e448113ec632ea6dc346feeb2571c38bd9a7398b2221280328002b23e1a45adaffe66d93f6564eaa2",
|
||||
"6cd7208a4bc7e7e56201bbba02a0f489cd384abe40afd4222f158b3d986ee72a54c50fb64fd4ed2530eda2c8af2928a0da6d4f830ae1c9db469dfd970f12a56f",
|
||||
"659858f0b5c9edab5b94fd732f6e6b17c51cc096104f09beb3afc3aa467c2ecf885c4c6541effa9023d3b5738ae5a14d867e15db06fe1f9d1127b77e1aabb516",
|
||||
"26cca0126f5d1a813c62e5c71001c046f9c92095704550be5873a495a999ad010a4f79491f24f286500adce1a137bc2084e4949f5b7294cefe51ecaff8e95cba",
|
||||
"4147c1f55172788c5567c561feef876f621fff1ce87786b8467637e70dfbcd0dbdb6415cb600954ab9c04c0e457e625b407222c0fe1ae21b2143688ada94dc58",
|
||||
"5b1bf154c62a8af6e93d35f18f7f90abb16a6ef0e8d1aecd118bf70167bab2af08935c6fdc0663ce74482d17a8e54b546d1c296631c65f3b522a515839d43d71",
|
||||
"9f600419a4e8f4fb834c24b0f7fc13bf4e279d98e8a3c765ee934917403e3a66097182ea21453cb63ebbe8b73a9c2167596446438c57627f330badd4f569f7d6",
|
||||
"457ef6466a8924fd8011a34471a5a1ac8ccd9bd0d07a97414ac943021ce4b9e4b9c8db0a28f016ed43b1542481990022147b313e194671131e708dd43a3ed7dc",
|
||||
"9997b2194d9af6dfcb9143f41c0ed83d3a3f4388361103d38c2a49b280a581212715fd908d41c651f5c715ca38c0ce2830a37e00e508ced1bcdc320e5e4d1e2e",
|
||||
"5c6bbf16baa180f986bd40a1287ed4c549770e7284858fc47bc21ab95ebbf3374b4ee3fd9f2af60f3395221b2acc76f2d34c132954049f8a3a996f1e32ec84e5",
|
||||
"d10bf9a15b1c9fc8d41f89bb140bf0be08d2f3666176d13baac4d381358ad074c9d4748c300520eb026daeaea7c5b158892fde4e8ec17dc998dcd507df26eb63",
|
||||
"2fc6e69fa26a89a5ed269092cb9b2a449a4409a7a44011eecad13d7c4b0456602d402fa5844f1a7a758136ce3d5d8d0e8b86921ffff4f692dd95bdc8e5ff0052",
|
||||
"fcbe8be7dcb49a32dbdf239459e26308b84dff1ea480df8d104eeff34b46fae98627b450c2267d48c0946a697c5b59531452ac0484f1c84e3a33d0c339bb2e28",
|
||||
"a19093a6e3bcf5952f850f2030f69b9606f147f90b8baee3362da71d9f35b44ef9d8f0a7712ba1877fddcd2d8ea8f1e5a773d0b745d4725605983a2de901f803",
|
||||
"3c2006423f73e268fa59d2920377eb29a4f9a8b462be15983ee3b85ae8a78e992633581a9099893b63db30241c34f643027dc878279af5850d7e2d4a2653073a",
|
||||
"d0f2f2e3787653f77cce2fa24835785bbd0c433fc779465a115149905a9dd1cb827a628506d457fcf124a0c2aef9ce2d2a0a0f63545570d8667ff9e2eba07334",
|
||||
"78a9fc048e25c6dcb5de45667de8ffdd3a93711141d594e9fa62a959475da6075ea8f0916e84e45ad911b75467077ee52d2c9aebf4d58f20ce4a3a00458b05d4",
|
||||
"45813f441769ab6ed37d349ff6e72267d76ae6bb3e3c612ec05c6e02a12af5a37c918b52bf74267c3f6a3f183a8064ff84c07b193d08066789a01accdb6f9340",
|
||||
"956da1c68d83a7b881e01b9a966c3c0bf27f68606a8b71d457bd016d4c41dd8a380c709a296cb4c6544792920fd788835771a07d4a16fb52ed48050331dc4c8b",
|
||||
"df186c2dc09caa48e14e942f75de5ac1b7a21e4f9f072a5b371e09e07345b0740c76177b01278808fec025eded9822c122afd1c63e6f0ce2e32631041063145c",
|
||||
"87475640966a9fdcd6d3a3b5a2cca5c08f0d882b10243c0ec1bf3c6b1c37f2cd3212f19a057864477d5eaf8faed73f2937c768a0af415e84bbce6bd7de23b660",
|
||||
"c3b573bbe10949a0fbd4ff884c446f2229b76902f9dfdbb8a0353da5c83ca14e8151bbaac82fd1576a009adc6f1935cf26edd4f1fb8da483e6c5cd9d8923adc3",
|
||||
"b09d8d0bba8a7286e43568f7907550e42036d674e3c8fc34d8ca46f771d6466b70fb605875f6a863c877d12f07063fdc2e90ccd459b1910dcd52d8f10b2b0a15",
|
||||
"af3a22bf75b21abfb0acd54422ba1b7300a952eff02ebeb65b5c234471a98df32f4f9643ce1904108a168767924280bd76c83f8c82d9a79d9259b195362a2a04",
|
||||
"bf4ff2221b7e6957a724cd964aa3d5d0d9941f540413752f4699d8101b3e537508bf09f8508b317736ffd265f2847aa7d84bd2d97569c49d632aed9945e5fa5e",
|
||||
"9c6b6b78199b1bdacb4300e31479fa622a6b5bc80d4678a6078f88a8268cd7206a2799e8d4621a464ef6b43dd8adffe97caf221b22b6b8778b149a822aefbb09",
|
||||
"890656f09c99d280b5ecb381f56427b813751bc652c7828078b23a4af83b4e3a61fdbac61f89bee84ea6bee760c047f25c6b0a201c69a38fd6fd971af18588bb",
|
||||
"31a046f7882ffe6f83ce472e9a0701832ec7b3f76fbcfd1df60fe3ea48fde1651254247c3fd95e100f9172731e17fd5297c11f4bb328363ca361624a81af797c",
|
||||
"27a60b2d00e7a671d47d0aec2a686a0ac04b52f40ab6629028eb7d13f4baa99ac0fe46ee6c814944f2f4b4d20e9378e4847ea44c13178091e277b87ea7a55711",
|
||||
"8b5ccef194162c1f19d68f91e0b0928f289ec5283720840c2f73d253111238dcfe94af2b59c2c1ca2591901a7bc060e7459b6c47df0f71701a35cc0aa831b5b6",
|
||||
"57ab6c4b2229aeb3b70476d803cd63812f107ce6da17fed9b17875e8f86c724f49e024cbf3a1b8b119c50357652b81879d2ade2d588b9e4f7cedba0e4644c9ee",
|
||||
"0190a8dac320a739f322e15731aa140ddaf5bed294d5c82e54fef29f214e18aafaa84f8be99af62950266b8f901f15dd4c5d35516fc35b4cab2e96e4695bbe1c",
|
||||
"d14d7c4c415eeb0e10b159224bea127ebd84f9591c702a330f5bb7bb7aa44ea39de6ed01f18da7adf40cfb97c5d152c27528824b21e239526af8f36b214e0cfb",
|
||||
"be28c4be706970488fac7d29c3bd5c4e986085c4c3332f1f3fd30973db614164ba2f31a78875ffdc150325c88327a9443ed04fdfe5be93876d1628560c764a80",
|
||||
"031da1069e3a2e9c3382e436ffd79df74b1ca6a8adb2deabe676ab45994cbc054f037d2f0eace858d32c14e2d1c8b46077308e3bdc2c1b53172ecf7a8c14e349",
|
||||
"4665cef8ba4db4d0acb118f2987f0bb09f8f86aa445aa3d5fc9a8b346864787489e8fcecc125d17e9b56e12988eac5ecc7286883db0661b8ff05da2afff30fe4",
|
||||
"63b7032e5f930cc9939517f9e986816cfbec2be59b9568b13f2ead05bae7777cab620c6659404f7409e4199a3be5f7865aa7cbdf8c4253f7e8219b1bd5f46fea",
|
||||
"9f09bf093a2b0ff8c2634b49e37f1b2135b447aa9144c9787dbfd92129316c99e88aab8a21fdef2372d1189aec500f95775f1f92bfb45545e4259fb9b7b02d14",
|
||||
"f9f8493c68088807df7f6a2693d64ea59f03e9e05a223e68524ca32195a4734b654fcea4d2734c866cf95c889fb10c49159be2f5043dc98bb55e02ef7bdcb082",
|
||||
"3c9a7359ab4febce07b20ac447b06a240b7fe1dae5439c49b60b5819f7812e4c172406c1aac316713cf0dded1038077258e2eff5b33913d9d95caeb4e6c6b970",
|
||||
"ad6aab8084510e822cfce8625d62cf4de655f4763884c71e80bab9ac9d5318dba4a6033ed29084e65216c031606ca17615dcfe3ba11d26851ae0999ca6e232cf",
|
||||
"156e9e6261374c9dc884f36e70f0fe1ab9297997b836fa7d170a9c9ebf575b881e7bcea44d6c0248d35597907154828955be19135852f9228815eca024a8adfb",
|
||||
"4215407633f4cca9b6788be93e6aa3d963c7d6ce4b147247099f46a3acb500a30038cb3e788c3d29f132ad844e80e9e99251f6db96acd8a091cfc770af53847b",
|
||||
"1c077e279de6548523502b6df800ffdab5e2c3e9442eb838f58c295f3b147cef9d701c41c321283f00c71affa0619310399126295b78dd4d1a74572ef9ed5135",
|
||||
"f07a555f49fe481cf4cd0a87b71b82e4a95064d06677fdd90a0eb598877ba1c83d4677b393c3a3b6661c421f5b12cb99d20376ba7275c2f3a8f5a9b7821720da",
|
||||
"b5911b380d20c7b04323e4026b38e200f534259233b581e02c1e3e2d8438d6c66d5a4eb201d5a8b75072c4ec29106334da70bc79521b0ced2cfd533f5ff84f95",
|
||||
"01f070a09bae911296361f91aa0e8e0d09a7725478536d9d48c5fe1e5e7c3c5b9b9d6eb07796f6da57ae562a7d70e882e37adfde83f0c433c2cd363536bb22c8",
|
||||
"6f793eb4374a48b0775acaf9adcf8e45e54270c9475f004ad8d5973e2aca52747ff4ed04ae967275b9f9eb0e1ff75fb4f794fa8be9add7a41304868d103fab10",
|
||||
"965f20f139765fcc4ce4ba3794675863cac24db472cd2b799d035bce3dbea502da7b524865f6b811d8c5828d3a889646fe64a380da1aa7c7044e9f245dced128",
|
||||
"ec295b5783601244c30e4641e3b45be222c4dce77a58700f53bc8ec52a941690b4d0b087fb6fcb3f39832b9de8f75ec20bd43079811749cdc907edb94157d180",
|
||||
"61c72f8ccc91dbb54ca6750bc489672de09faedb8fdd4f94ff2320909a303f5d5a98481c0bc1a625419fb4debfbf7f8a53bb07ec3d985e8ea11e72d559940780",
|
||||
"afd8145b259eefc8d12620c3c5b03e1ed8fd2ccefe0365078c80fd42c1770e28b44948f27e65a1886690110db814397b68e43d80d1ba16dfa358e739c898cfa3",
|
||||
"552fc7893cf1ce933ada35c0da98844e41545e244c3157a1428d7b4c21f9cd7e4071aed77b7ca9f1c38fba32237412ef21a342742ec8324378f21e507fafdd88",
|
||||
"467a33fbadf5ebc52596ef86aaaefc6faba8ee651b1ce04de368a03a5a9040ef2835e00adb09abb3fbd2bce818a2413d0b0253b5bda4fc5b2f6f85f3fd5b55f2",
|
||||
"22eff8e6dd5236f5f57d94ede874d6c9428e8f5d566f17cd6d1848cd752fe13c655cb10fbaaff76872f2bf2da99e15dc624075e1ec2f58a3f64072121838569e",
|
||||
"9cec6bbf62c4bce4138abae1cbec8dad31950444e90321b1347196834c114b864af3f3cc3508f83751ffb4eda7c84d140734bb4263c3625c00f04f4c8068981b",
|
||||
"a8b60fa4fc2442f6f1514ad7402626920cc7c2c9f72124b8cba8ee2cb7c4586f658a4410cffcc0ab88343955e094c6af0d20d0c714fb0a988f543f300f58d389",
|
||||
"8271cc45dfa5e4170e847e8630b952cf9c2aa777d06f26a7585b8381f188dacc7337391cfcc94b053dc4ec29cc17f077870428f1ac23fddda165ef5a3f155f39",
|
||||
"bf23c0c25c8060e4f6995f1623a3bebecaa96e308680000a8aa3cd56bb1a6da099e10d9231b37f4519b2efd2c24de72f31a5f19535241b4a59fa3c03ceb790e7",
|
||||
"877fd652c05281009c0a5250e7a3a671f8b18c108817fe4a874de22da8e45db11958a600c5f62e67d36cbf84474cf244a9c2b03a9fb9dc711cd1a2cab6f3fae0",
|
||||
"29df4d87ea444baf5bcdf5f4e41579e28a67de84149f06c03f110ea84f572a9f676addd04c4878f49c5c00accda441b1a387caceb2e993bb7a10cd8c2d6717e1",
|
||||
"710dacb166844639cd7b637c274209424e2449dc35d790bbfa4f76177054a36b3b76fac0ca6e61df1e687000678ac0746df75d0a3954897681fd393a155a1bb4",
|
||||
"c1d5f93b8dea1f2571babccbc01764541a0cda87e444d673c50966ca559c33354b3acb26e5d5781ffb28847a4b4754d77008c62a835835f500dea7c3b58bdae2",
|
||||
"a41e41271cdab8af4d72b104bfb2ad041ac4df14677da671d85640c4b187f50c2b66513c4619fbd5d5dc4fe65dd37b9042e9848dda556a504caa2b1c6afe4730",
|
||||
"e7bcbacdc379c43d81ebadcb37781552fc1d753e8cf310d968392d06c91f1d64cc9e90ce1d22c32d277fc6cda433a4d442c762e9eacf2c259f32d64cf9da3a22",
|
||||
"51755b4ac5456b13218a19c5b9242f57c4a981e4d4ecdce09a3193362b808a579345d4881c2607a56534dd7f21956aff72c2f4173a6e7b6cc2212ba0e3daee1f",
|
||||
"dcc2c4beb9c1f2607b786c20c631972347034c1cc02fcc7d02ff01099cfe1c6989840ac213923629113aa8bad713ccf0fe4ce13264fb32b8b0fe372da382544a",
|
||||
"3d55176acea4a7e3a65ffa9fb10a7a1767199cf077cee9f71532d67cd7c73c9f93cfc37ccdcc1fdef50aad46a504a650d298d597a3a9fa95c6c40cb71fa5e725",
|
||||
"d07713c005de96dd21d2eb8bbeca66746ea51a31ae922a3e74864889540a48db27d7e4c90311638b224bf0201b501891754848113c266108d0adb13db71909c7",
|
||||
"58983c21433d950caa23e4bc18543b8e601c204318532152daf5e159a0cd1480183d29285c05f129cb0cc3164687928086ffe380158df1d394c6ac0d4288bca8",
|
||||
"8100a8dc528d2b682ab4250801ba33f02a3e94c54dac0ae1482aa21f51ef3a82f3807e6facb0aeb05947bf7aa2adcb034356f90fa4560ede02201a37e411ec1a",
|
||||
"07025f1bb6c784f3fe49de5c14b936a5acacacaab33f6ac4d0e00ab6a12483d6bec00b4fe67c7ca5cc508c2a53efb5bfa5398769d843ff0d9e8b14d36a01a77f",
|
||||
"ba6aefd972b6186e027a76273a4a723321a3f580cfa894da5a9ce8e721c828552c64dacee3a7fd2d743b5c35ad0c8efa71f8ce99bf96334710e2c2346e8f3c52",
|
||||
"e0721e02517aedfa4e7e9ba503e025fd46e714566dc889a84cbfe56a55dfbe2fc4938ac4120588335deac8ef3fa229adc9647f54ad2e3472234f9b34efc46543",
|
||||
"b6292669ccd38d5f01caae96ba272c76a879a45743afa0725d83b9ebb26665b731f1848c52f11972b6644f554c064fa90780dbbbf3a89d4fc31f67df3e5857ef",
|
||||
"2319e3789c47e2daa5fe807f61bec2a1a6537fa03f19ff32e87eecbfd64b7e0e8ccff439ac333b040f19b0c4ddd11a61e24ac1fe0f10a039806c5dcc0da3d115",
|
||||
"f59711d44a031d5f97a9413c065d1e614c417ede998590325f49bad2fd444d3e4418be19aec4e11449ac1a57207898bc57d76a1bcf3566292c20c683a5c4648f",
|
||||
"df0a9d0c212843a6a934e3902b2dd30d17fba5f969d2030b12a546d8a6a45e80cf5635f071f0452e9c919275da99bed51eb1173c1af0518726b75b0ec3bae2b5",
|
||||
"a3eb6e6c7bf2fb8b28bfe8b15e15bb500f781ecc86f778c3a4e655fc5869bf2846a245d4e33b7b14436a17e63be79b36655c226a50ffbc7124207b0202342db5",
|
||||
"56d4cbcd070563426a017069425c2cd2ae540668287a5fb9dac432eb8ab1a353a30f2fe1f40d83333afe696a267795408a92fe7da07a0c1814cf77f36e105ee8",
|
||||
"e59b9987d428b3eda37d80abdb16cd2b0aef674c2b1dda4432ea91ee6c935c684b48b4428a8cc740e579a30deff35a803013820dd23f14ae1d8413b5c8672aec",
|
||||
"cd9fcc99f99d4cc16d031900b2a736e1508db4b586814e6345857f354a70ccecb1df3b50a19adaf43c278efa423ff4bb6c523ec7fd7859b97b168a7ebff8467c",
|
||||
"0602185d8c3a78738b99164b8bc6ffb21c7debebbf806372e0da44d121545597b9c662a255dc31542cf995ecbe6a50fb5e6e0ee4ef240fe557eded1188087e86",
|
||||
"c08afa5b927bf08097afc5fff9ca4e7800125c1f52f2af3553fa2b89e1e3015c4f87d5e0a48956ad31450b083dad147ffb5ec03434a26830cf37d103ab50c5da",
|
||||
"36f1e1c11d6ef6bc3b536d505d544a871522c5c2a253067ec9933b6ec25464daf985525f5b9560a16d890259ac1bb5cc67c0c469cde133def000ea1d686f4f5d",
|
||||
"bf2ab2e2470f5438c3b689e66e7686fffa0cb1e1798ad3a86ff99075bf6138e33d9c0ce59afb24ac67a02af34428191a9a0a6041c07471b7c3b1a752d6fc0b8b",
|
||||
"d400601f9728ccc4c92342d9787d8d28ab323af375ca5624b4bb91d17271fbae862e413be73f1f68e615b8c5c391be0dbd9144746eb339ad541547ba9c468a17",
|
||||
"79fe2fe157eb85a038abb8ebbc647731d2c83f51b0ac6ee14aa284cb6a3549a4dcceb300740a825f52f5fb30b03b8c4d8b0f4aa67a63f4a94e3303c4eda4c02b",
|
||||
"75351313b52a8529298d8c186b1768666dcca8595317d7a4816eb88c062020c0c8efc554bb341b64688db5ccafc35f3c3cd09d6564b36d7b04a248e146980d4b",
|
||||
"e3128b1d311d02179d7f25f97a5a8bee2cc8c86303644fcd664e157d1fef00f23e46f9a5e8e5c890ce565bb6abd4302ce06469d52a5bd53e1c5a54d04649dc03",
|
||||
"c2382a72d2d3ace9d5933d00b60827ed380cda08d0ba5f6dd41e29ee6dbe8ecb9235f06be95d83b6816a2fb7a5ad47035e8a4b69a4884b99e4bece58cab25d44",
|
||||
"6b1c69460bbd50ac2ed6f32e6e887cfed407d47dcf0aaa60387fe320d780bd03eab6d7baeb2a07d10cd552a300341354ea9a5f03183a623f92a2d4d9f00926af",
|
||||
"6cda206c80cdc9c44ba990e0328c314f819b142d00630404c48c05dc76d1b00ce4d72fc6a48e1469ddef609412c364820854214b4869af090f00d3c1ba443e1b",
|
||||
"7ffc8c26fbd6a0f7a609e6e1939f6a9edf1b0b066641fb76c4f9602ed748d11602496b35355b1aa255850a509d2f8ee18c8f3e1d7dcbc37a136598f56a59ed17",
|
||||
"70de1f08dd4e09d5fc151f17fc991a23abfc05104290d50468882efaf582b6ec2f14f577c0d68c3ad06626916e3c86e6daab6c53e5163e82b6bd0ce49fc0d8df",
|
||||
"4f81935756ed35ee2058ee0c6a6110d6fac5cb6a4f46aa9411603f99965823b6da4838276c5c06bc7880e376d92758369ee7305bcec8d3cfd28ccabb7b4f0579",
|
||||
"abcb61cb3683d18f27ad527908ed2d32a0426cb7bb4bf18061903a7dc42e7e76f982382304d18af8c80d91dd58dd47af76f8e2c36e28af2476b4bccf82e89fdf",
|
||||
"02d261ad56a526331b643dd2186de9a82e72a58223cd1e723686c53d869b83b94632b7b647ab2afc0d522e29da3a5615b741d82852e0df41b66007dbcba90543",
|
||||
"c5832741fa30c5436823015383d297ff4c4a5d7276c3f902122066e04be5431b1a85faf73b918434f9300963d1dea9e8ac3924ef490226edeea5f743e410669f",
|
||||
"cfaeab268cd075a5a6aed515023a032d54f2f2ff733ce0cbc78db51db4504d675923f82746d6594606ad5d67734b11a67cc6a468c2032e43ca1a94c6273a985e",
|
||||
"860850f92eb268272b67d133609bd64e34f61bf03f4c1738645c17fec818465d7ecd2be2907641130025fda79470ab731646e7f69440e8367ea76ac4cee8a1df",
|
||||
"84b154ed29bbedefa648286839046f4b5aa34430e2d67f7496e4c39f2c7ea78995f69e1292200016f16ac3b37700e6c7e7861afc396b64a59a1dbf47a55c4bbc",
|
||||
"aeeec260a5d8eff5ccab8b95da435a63ed7a21ea7fc7559413fd617e33609f8c290e64bbacc528f6c080262288b0f0a3219be223c991bee92e72349593e67638",
|
||||
"8ad78a9f26601d127e8d2f2f976e63d19a054a17dcf59e0f013ab54a6887bbdffde7aaae117e0fbf3271016595b9d9c712c01b2c53e9655a382bc4522e616645",
|
||||
"8934159dade1ac74147dfa282c75954fcef443ef25f80dfe9fb6ea633b8545111d08b34ef43fff17026c7964f5deac6d2b3c29dacf2747f022df5967dfdc1a0a",
|
||||
"cd36dd0b240614cf2fa2b9e959679dcdd72ec0cd58a43da3790a92f6cdeb9e1e795e478a0a47d371100d340c5cedcdbbc9e68b3f460818e5bdff7b4cda4c2744",
|
||||
"00df4e099b807137a85990f49d3a94315e5a5f7f7a6076b303e96b056fb93800111f479628e2f8db59aeb6ac70c3b61f51f9b46e80ffdeae25ebddb4af6cb4ee",
|
||||
"2b9c955e6caed4b7c9e246b86f9a1726e810c59d126cee66ed71bf015b83558a4b6d84d18dc3ff4620c2ffb722359fdef85ba0d4e2d22ecbe0ed784f99afe587",
|
||||
"181df0a261a2f7d29ea5a15772715105d450a4b6c236f699f462d60ca76487feedfc9f5eb92df838e8fb5dc3694e84c5e0f4a10b761f506762be052c745a6ee8",
|
||||
"21fb203458bf3a7e9a80439f9a902899cd5de0139dfd56f7110c9dec8437b26bda63de2f565926d85edb1d6c6825669743dd9992653d13979544d5dc8228bfaa",
|
||||
"ef021f29c5ffb830e64b9aa9058dd660fd2fcb81c497a7e698bcfbf59de5ad4a86ff93c10a4b9d1ae5774725f9072dcde9e1f199bab91f8bff921864aa502eee",
|
||||
"b3cfda40526b7f1d37569bdfcdf911e5a6efe6b2ec90a0454c47b2c046bf130fc3b352b34df4813d48d33ab8e269b69b075676cb6d00a8dcf9e1f967ec191b2c",
|
||||
"b4c6c3b267071eefb9c8c72e0e2b941293641f8673cb70c1cc26ad1e73cf141755860ad19b34c2f34ed35bb52ec4507cc1fe59047743a5f0c6febde625e26091",
|
||||
"57a34f2bcca60d4b85103b830c9d7952a416be5263ae429c9e5e53fe8590a8f78ec65a51109ea85dcdf7b6223f9f2b340539fad81923dbf8edabf95129e4dff6",
|
||||
"9cf46662fcd61a232277b685663b8b5da832dfd9a3b8ccfeec993ec6ac415ad07e048adfe414df272770dba867da5c1224c6fd0aa0c2187d426ac647e9887361",
|
||||
"5ce1042ab4d542c2f9ee9d17262af8164098935bef173d0e18489b04841746cd2f2df866bd7da6e5ef9024c648023ec723ab9c62fd80285739d84f15d2ab515a",
|
||||
"8488396bd4a8729b7a473178f232dadf3f0f8e22678ba5a43e041e72da1e2cf82194c307207a54cb8156293339eaec693ff66bfcd5efc65e95e4ecaf54530abd",
|
||||
"f598da901c3835bca560779037dfde9f0c51dc61c0b760fc1522d7b470ee63f5bdc6498476e86049ad86e4e21af2854a984cc905427d2f17f66b1f41c3da6f61",
|
||||
"5f93269798cf02132107337660a8d7a177354c0212eb93e555e7c37a08aef3d8dce01217011cd965c04dd2c105f2e2b6cae5e4e6bcaf09dfbee3e0a6a6357c37",
|
||||
"0ecf581d47bac9230986faabd70c2f5b80e91066f0ec55a842937882286d2ca007bb4e973b0b091d52167ff7c4009c7ab4ad38fff1dceacdb7be81ef4a452952",
|
||||
"5aeca8abe1528582b2a307b4009585498a3d467ca6101cb0c5126f9976056e9ffc123cc20c302b2a737f492c75d21f01512c90ca0541dfa56e950a321dcb28d8",
|
||||
"732fbf8f1cb2b8329263ede27858fe46f8d3354d376bcda0548e7ce1fa9dd11f85eb661fe950b543aa635ca4d3f04ede5b32d6b656e5ce1c44d35c4a6c56cff8",
|
||||
"d5e938735d63788c80100aefd18648d18cf272f69f20ff24cfe2895c088ad08b0104da1672a4eb26fc52545cc7d7a01b266cf546c403c45bd129eb41bdd9200b",
|
||||
"65a245b49352ee297d91af8c8be00528ac6e046dd83ac7bd465a98816dd68f3e00e1ae8f895327a7e9a8c9326598379a29c9fc91ec0c6eef08f3e2b216c11008",
|
||||
"c95654b63019130ab45dd0fb4941b98aeb3af2a123913eca2ce99b3e97410a7bf8661cc7fbaa2bc1cf2b13113b1ed40a0118b88e5fffc3542759ea007ed4c58d",
|
||||
"1eb262f38fa494431f017dad44c0dfb69324ac032f04b657fc91a88647bb74760f24e7c956514f0cf002990b182c1642b9b2426e96a61187e4e012f00e217d84",
|
||||
"3b955aeebfa5151ac1ab8e3f5cc1e3767084c842a575d36269836e97353d41622b731dddcd5f269550a3a5b87be1e90326340b6e0e62555815d9600597ac6ef9",
|
||||
"68289f6605473ba0e4f241baf7477a9885426a858f19ef2a18b0d40ef8e41282ed5526b519799e270f13881327918278755711071d8511fe963e3b5606aa3716",
|
||||
"80a33787542612c38f6bcd7cd86cab460227509b1cbad5ec408a91413d51155a0476dadbf3a2518e4a6e77cc346622e347a469bf8baa5f04eb2d98705355d063",
|
||||
"34629bc6d831391c4cdf8af1b4b7b6b8e8ee17cf98c70e5dd586cd99f14b11df945166236a9571e6d591bb83ee4d164d46f6b9d8ef86ff865a81bfb91b00424b",
|
||||
"8b7cc339163863bb4383e542b0ef0e7cf36b84ad932cdf5a80419ec9ad692e7a7e784d2c7cb3796a18b8f800035f3aa06c824100611120a7bdeb35618ccb81b7",
|
||||
"4f084e4939dd5a7f5a658fad58a18a15c25c32ec1c7fd5c5c6c3e892b3971aeaac308304ef17b1c47239ea4bb398b3fd6d4528d8de8e768ae0f1a5a5c6b5c297",
|
||||
"48f407a1af5b8009b2051742e8cf5cd5656669e7d722ee8e7bd202060849442168d8facc117c012bfb7bf449d99befff6a34aea203f1d8d352722be5014ec818",
|
||||
"a6aa82cd1e426f9a73bfa39a29037876114655b8c22d6d3ff8b638ae7dea6b17843e09e52eb66fa1e475e4a8a3de429b7d0f4a776fcb8bdc9b9fede7d52e815f",
|
||||
"5817027d6bdd00c5dd10ac593cd560372270775a18526d7e6f13872a2e20eab664625be7168ac4bd7c9e0ce7fc4099e0f48442e2c767191c6e1284e9b2ccea8c",
|
||||
"08e41028340a45c74e4052b3a8d6389e22e043a1adab5e28d97619450d723469b620caa519b81c14523854f619fd3027e3847bd03276e60604a80ddb4de876d6",
|
||||
"130b8420537eb07d72abda07c85acbd8b9a44f16321dd0422145f809673d30f2b5321326e2bff317ef3fef983c51c4f8ab24a325d298e34afce569a82555774c",
|
||||
"ac49b844afaa012e31c474ca263648844fd2f6307992c2f752aca02c3828965175794deee2d2ee95c61cd284f6b5a2d75e2ef2b29ee8149e77fb81447b2fd04b",
|
||||
"b9d7ca81cc60bb9578e44024e5a0a0be80f27336a6a9f4e53df3999cb191280b090e2ac2d29c5baad9d71415bdc129e69aa2667af6a7fd5e189fccdcee817340",
|
||||
"a755e113386572c75ced61d719706070b9146048e42a9f8cd35667a088b42f08808abdf77e618abd959afc757379ca2c00bcc1a48390fa2bff618b1e0078a613",
|
||||
"a73c7debed326f1c0db0795ee7d6e3946894b826b1f8101c56c823ba17168312e7f53fc7dbe52c3e11e69852c40485e2ef182477862ea6a34ec136e2dfeea6f4",
|
||||
"6cb8f9d52c56d82cac28f39ea1593e8bb2506293ac0d68376a1709b62a46df14a4ae64b2d8fab76733a1ced2d548e3f3c6fcb49d40c3d5808e449cd83d1c2aa2",
|
||||
"683fa2b2369a10162c1c1c7b24bc970ee67da220564f32203f625696c0352a0b9ad96624362d952d84463c1106a2dba7a092599884b35a0b89c8f1b6a9b5a61e",
|
||||
"aad9ad44610118b77d508aeb1bbcd1c1b7d0171397fb510a401bbc0ec34623670d86a2dc3c8f3ab5a2044df730256727545f0860ce21a1eac717dfc48f5d228e",
|
||||
"c42578de23b4c987d5e1ac4d689ed5de4b0417f9704bc6bce969fa13471585d62c2cb1212a944f397fc9ca2c3747c3beb694ec4c5be68828dda53ef43faec6c0",
|
||||
"470f00841ee8244e63ed2c7ea30e2e419897c197462ecccecf713b42a5065fff5914bc9b79affe8f6b657875e789ae213bd914cd35bd174d46e9d18bd843773d",
|
||||
"34fc4213730f47a5e9a3580f643e12945cfcb31bf206f6ad450ce528da3fa432e005d6b0ecce10dca7c5995f6aacc5150e1b009e19751e8309f8859531844374",
|
||||
"fb3c1f0f56a56f8e316fdf5d853c8c872c39635d083634c3904fc3ac07d1b578e85ff0e480e92d44ade33b62e893ee32343e79ddf6ef292e89b582d312502314",
|
||||
"c7c97fc65dd2b9e3d3d607d31598d3f84261e9919251e9c8e57bb5f829377d5f73eabbed55c6c381180f29ad02e5be797ffec7e57bdecbc50ad3d062f0993ab0",
|
||||
"a57a49cdbe67ae7d9f797bb5cc7efc2df07f4e1b15955f85dae74b76e2ecb85afb6cd9eeed8888d5ca3ec5ab65d27a7b19e578475760a045ac3c92e13a938e77",
|
||||
"c7143fce9614a17fd653aeb140726dc9c3dbb1de6cc581b2726897ec24b7a50359ad492243be66d9edd8c933b5b80e0b91bb61ea98056006516976fae8d99a35",
|
||||
"65bb58d07f937e2d3c7e65385f9c54730b704105ccdb691f6e146d4ee8f6c086f49511035110a9ad6031fdceb943e0f9613bcb276dd40f0624ef0f924f809783",
|
||||
"e540277f683b1186dd3b5b3f61433396581a35feb12002be8c6a6231fc40ffa70f08081bc58b2d94f7649543614a435faa2d62110e13dabc7b86629b63af9c24",
|
||||
"418500878c5fbcb584c432f4285e05e49f2e3e075399a0dbfcf874ebf8c03d02bf16bc6989d161c77ca0786b05053c6c709433712319192128835cf0b660595b",
|
||||
"889090dbb1944bdc9433ee5ef1010c7a4a24a8e71ecea8e12a31318ce49dcab0aca5c3802334aab2cc84b14c6b9321fe586bf3f876f19cd406eb1127fb944801",
|
||||
"53b6a28910aa92e27e536fb549cf9b9918791060898e0b9fe183577ff43b5e9c7689c745b32e412269837c31b89e6cc12bf76e13cad366b74ece48bb85fd09e9",
|
||||
"7c092080c6a80d672409d081d3d177106bcd63567785140719490950ae07ae8fcaabbaaab330cfbcf7374482c220af2eadeeb73dcbb35ed823344e144e7d4899",
|
||||
"9ccde566d2400509181111f32dde4cd63209fe59a30c114546ad2776d889a41bad8fa1bb468cb2f9d42ca9928a7770fef8e8ba4d0c812d9a1e75c3d8d2ccd75a",
|
||||
"6e293bf5d03fe43977cfe3f57ccdb3ae282a85455dca33f37f4b74f8398cc612433d755cbec412f8f82a3bd3bc4a278f7ecd0dfa9bbdc40be7a787c8f159b2df",
|
||||
"c56546fb2178456f336164c18b90deffc83ae2b5a3aca77b6884d36d2c1db39501b3e65e36c758c66e3188451fdb3515ee162c001f06c3e8cb573adf30f7a101",
|
||||
"6f82f89f299ebca2fe014b59bffe1aa84e88b1915fe256afb646fd8448af2b8891a7fab37a4ea6f9a50e6c317039d8cf878f4c8e1a0dd464f0b4d6ff1c7ea853",
|
||||
"2b8599ff9c3d6198637ad51e57d1998b0d75313fe2dd61a533c964a6dd9607c6f723e9452ce46e014b1c1d6de77ba5b88c914d1c597bf1eae13474b4290e89b2",
|
||||
"08bf346d38e1df06c8260edb1da75579275948d5c0a0aa9ed2886f8856de5417a156998758f5b17e52f101ca957a71137473dfd18d7d209c4c10d9233c93691d",
|
||||
"6df2156d773114d310b63db9ee5350d77e6bcf25b05fcd910f9b31bc42bb13fe8225ebcb2a23a62280777b6bf74e2cd0917c7640b43defe468cd1e18c943c66a",
|
||||
"7c7038bc13a91151828a5ba82b4a96040f258a4dfb1b1373f0d359168afb0517a20b28a12d3644046be66b8d08d8ae7f6a923ea1c00187c6d11dc502bac71305",
|
||||
"bcd1b30d808fb739b987cbf154bea00da9d40380b861d4c1d6377122dadd61c0e59018b71941cfb62e00dcd70aeb9abf0473e80f0a7eca6b6dea246ab229dd2b",
|
||||
"7ed4468d968530fe7ab2c33540b26d8c3bd3ed44b34fbe8c2a9d7f805b5ada0ea252eeade4fce97f89728ad85bc8bb2430b1bef2cddd32c8446e59b8e8ba3c67",
|
||||
"6d30b7c6ce8a3236c0ca2f8d728b1088ca06983a8043e621d5dcf0c537d13b08791edeb01a3cf0943ec1c890ab6e29b146a236cd46bcb9d93bf516fb67c63fe5",
|
||||
"97fe03cef31438508911bded975980a66029305dc5e3fa8ad1b4fb22fcdf5a19a733320327d8f71ccf496cb3a44a77af56e3dde73d3a5f176896cc57c9a5ad99",
|
||||
"785a9d0fbd21136dbce8fa7eafd63c9dad220052978416b31d9753eaa149097847ed9b30a65c70507eff01879149ed5cf0471d37798edc05abd56ad4a2cccb1d",
|
||||
"ad408d2abddfd37b3bf34794c1a3371d928ed7fc8d966225333584c5665817832a37c07f0dc7cb5aa874cd7d20fe8fab8eabcb9b33d2e0841f6e200960899d95",
|
||||
"97668f745b6032fc815d9579322769dccd9501a5080029b8ae826befb6742331bd9f76efeb3e2b8e81a9786b282f5068a3a2424697a77c41876b7e753f4c7767",
|
||||
"26bb985f47e7fee0cfd252d4ef96bed42b9c370c1c6a3e8c9eb04ef7f7818b833a0d1f043ebafb911dc779e02740a02a44d3a1ea45ed4ad55e686c927cafe97e",
|
||||
"5bfe2b1dcf7fe9b95088acedb575c19016c743b2e763bf5851ac407c9eda43715edfa48b4825492c5179593fff21351b76e8b7e034e4c53c79f61f29c479bd08",
|
||||
"c76509ef72f4a6f9c9c40618ed52b2084f83502232e0ac8bdaf3264368e4d0180f6854c4abf4f6509c79caafc44cf3194afc57bd077bd7b3c9bda3d4b8775816",
|
||||
"d66f2beab990e354ccb910e4e9c7ac618c7b63ef292a96b552341de78dc46d3ec8cfabc699b50af41fda39cf1b0173660923510ad67faedef5207cffe8641d20",
|
||||
"7d8f0672992b79be3a364d8e5904f4ab713bbc8ab01b4f309ad8ccf223ce1034a860dcb0b00550612cc2fa17f2969e18f22e1427d254b4a82b3a03a3eb394adf",
|
||||
"a56d6725bfb3de47c1414adf25fc8f0fc9846f6987722bc06366d5ca4e89722925ebbc881418844075397a0ca89842c7b9e9e07e1d9d183ebeb39e120b483bf7",
|
||||
"af5e03d7fe60c67e10313344434e79485a03a758d6dce985574745763c1c5c77d4fb3e6fb12230368370993bf90feed0c5d1607524562d7c09c0c210ed393d7c",
|
||||
"7a20540cc07bf72b582421fc342e82f52134b69841ec28ed189e2ea6a29dd2f82a640352d222b52f2911dc72a7dab31caadd80c6118f13c56b2a1e4373be0ea3",
|
||||
"486f02c63e5467ea1fdde7e82bfacc2c1ba5d636d9f3d08b210da3f372f706ec218cc17ff60aef703bbe0c15c38ae55d286a684f864c78211ccab4178c92adba",
|
||||
"1c7a5c1dedcd04a921788f7eb23361ca1953b04b9c7aec35d65ea3e4996db26f281278ea4ae666ad81027d98af57262cdbfa4c085f4210568c7e15eec7805114",
|
||||
"9ce3fa9a860bdbd5378fd6d7b8b671c6cb7692910ce8f9b6cb4122cbcbe6ac06ca0422cef1225935053b7d193a81b9e972eb85a1d3074f14cbb5ec9f0573892d",
|
||||
"a91187be5c371c4265c174fd4653b8ab708551f83d1fee1cc1479581bc006d6fb78fcc9a5dee1db3666f508f9780a37593ebcccf5fbed39667dc6361e921f779",
|
||||
"4625767d7b1d3d3ed2fbc674af14e0244152f2a4021fcf3311505d89bd81e2f9f9a500c3b199914db49500b3c98d03ea93286751a686a3b875daab0ccd63b44f",
|
||||
"43dfdfe1b014fed3a2acabb7f3e9a182f2aa18019d27e3e6cdcf31a15b428e91e7b08cf5e5c376fce2d8a28ff85ab0a0a1656edb4a0a91532620096d9a5a652d",
|
||||
"279e3202be3989ba3112772585177487e4fe3ee3eab49c2f7fa7fe87cfe7b80d3e0355edff6d031e6c96c795db1c6f041880ec3824defacf9263820a8e7327de",
|
||||
"ea2d066ac229d4d4b616a8bedec734325224e4b4e58f1ae6dad7e40c2da29196c3b1ea9571dacc81e87328caa0211e09027b0524aa3f4a849917b3586747ebbb",
|
||||
"49f014f5c61822c899ab5cae51be4044a4495e777deb7da9b6d8490efbb87530adf293daf079f94c33b7044ef62e2e5bb3eb11e17304f8453ee6ce24f033ddb0",
|
||||
"9233490344e5b0dc5912671b7ae54cee7730dbe1f4c7d92a4d3e3aab50571708db51dcf9c2944591db651db32d22935b86944969be77d5b5feae6c3840a8db26",
|
||||
"b6e75e6f4c7f453b7465d25b5ac8c7196902eaa953875228c8634e16e2ae1f38bc3275304335f5989eccc1e34167d4e68d7719968fba8e2fe67947c35c48e806",
|
||||
"cc14ca665af1483efbc3af80080e650d5046a3932f4f51f3fe90a0705ec25104adf07839265dc51d43401411246e474f0d5e5637af94767283d53e0617e981f4",
|
||||
"230a1c857cb2e7852e41b647e90e4585d2d881e1734dc38955356e8dd7bff39053092c6b38e236e1899525647073dddf6895d64206325e7647f275567b255909",
|
||||
"cbb65321ac436e2ffdab2936359ce49023f7dee7614ef28d173c3d27c5d1bffa51553d433f8ee3c9e49c05a2b883cce954c9a8093b80612a0cdd4732e041f995",
|
||||
"3e7e570074337275efb51315588034c3cf0dddca20b4612e0bd5b881e7e5476d319ce4fe9f19186e4c0826f44f131eb048e65be242b1172c63badb123ab0cbe8",
|
||||
"d32e9ec02d38d4e1b8249df8dcb00c5b9c68eb8922672e3505393b6a210ba56f9496e5ee0490ef387c3cdec061f06bc0382d9304cafbb8e0cd33d57029e62df2",
|
||||
"8c1512466089f05b3775c262b62d22b83854a83218130b4ec91b3ccbd293d2a54302cecaab9b100c68d1e6ddc8f07cddbdfe6fdaaaf099cc09d6b725879c6369",
|
||||
"91a7f61c97c2911e4c812ef71d780ad8fa788794561d08303fd1c1cb608a46a12563086ec5b39d471aed94fb0f6c678a43b8792932f9028d772a22768ea23a9b",
|
||||
"4f6bb222a395e8b18f6ba155477aed3f0729ac9e83e16d31a2a8bc655422b837c891c6199e6f0d75799e3b691525c581953517f252c4b9e3a27a28fbaf49644c",
|
||||
"5d06c07e7a646c413a501c3f4bb2fc38127de7509b7077c4d9b5613201c1aa02fd5f79d2745915dd57fbcb4ce08695f6efc0cb3d2d330e19b4b0e6004ea6471e",
|
||||
"b96756e57909968f14b796a5d30f4c9d671472cf82c8cfb2caca7ac7a44ca0a14c9842d00c82e337502c94d5960aca4c492ea7b0df919ddf1aada2a275bb10d4",
|
||||
"ff0a015e98db9c99f03977710aac3e658c0d896f6d71d618ba79dc6cf72ac75b7c038eb6862dede4543e145413a6368d69f5722c827ba3ef25b6ae6440d39276",
|
||||
"5b21c5fd8868367612474fa2e70e9cfa2201ffeee8fafab5797ad58fefa17c9b5b107da4a3db6320baaf2c8617d5a51df914ae88da3867c2d41f0cc14fa67928",
|
||||
}
|
||||
|
||||
var goldenKeyed = []string{
|
||||
"10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568",
|
||||
"961f6dd1e4dd30f63901690c512e78e4b45e4742ed197c3c5e45c549fd25f2e4187b0bc9fe30492b16b0d0bc4ef9b0f34c7003fac09a5ef1532e69430234cebd",
|
||||
"da2cfbe2d8409a0f38026113884f84b50156371ae304c4430173d08a99d9fb1b983164a3770706d537f49e0c916d9f32b95cc37a95b99d857436f0232c88a965",
|
||||
"33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1",
|
||||
"beaa5a3d08f3807143cf621d95cd690514d0b49efff9c91d24b59241ec0eefa5f60196d407048bba8d2146828ebcb0488d8842fd56bb4f6df8e19c4b4daab8ac",
|
||||
"098084b51fd13deae5f4320de94a688ee07baea2800486689a8636117b46c1f4c1f6af7f74ae7c857600456a58a3af251dc4723a64cc7c0a5ab6d9cac91c20bb",
|
||||
"6044540d560853eb1c57df0077dd381094781cdb9073e5b1b3d3f6c7829e12066bbaca96d989a690de72ca3133a83652ba284a6d62942b271ffa2620c9e75b1f",
|
||||
"7a8cfe9b90f75f7ecb3acc053aaed6193112b6f6a4aeeb3f65d3de541942deb9e2228152a3c4bbbe72fc3b12629528cfbb09fe630f0474339f54abf453e2ed52",
|
||||
"380beaf6ea7cc9365e270ef0e6f3a64fb902acae51dd5512f84259ad2c91f4bc4108db73192a5bbfb0cbcf71e46c3e21aee1c5e860dc96e8eb0b7b8426e6abe9",
|
||||
"60fe3c4535e1b59d9a61ea8500bfac41a69dffb1ceadd9aca323e9a625b64da5763bad7226da02b9c8c4f1a5de140ac5a6c1124e4f718ce0b28ea47393aa6637",
|
||||
"4fe181f54ad63a2983feaaf77d1e7235c2beb17fa328b6d9505bda327df19fc37f02c4b6f0368ce23147313a8e5738b5fa2a95b29de1c7f8264eb77b69f585cd",
|
||||
"f228773ce3f3a42b5f144d63237a72d99693adb8837d0e112a8a0f8ffff2c362857ac49c11ec740d1500749dac9b1f4548108bf3155794dcc9e4082849e2b85b",
|
||||
"962452a8455cc56c8511317e3b1f3b2c37df75f588e94325fdd77070359cf63a9ae6e930936fdf8e1e08ffca440cfb72c28f06d89a2151d1c46cd5b268ef8563",
|
||||
"43d44bfa18768c59896bf7ed1765cb2d14af8c260266039099b25a603e4ddc5039d6ef3a91847d1088d401c0c7e847781a8a590d33a3c6cb4df0fab1c2f22355",
|
||||
"dcffa9d58c2a4ca2cdbb0c7aa4c4c1d45165190089f4e983bb1c2cab4aaeff1fa2b5ee516fecd780540240bf37e56c8bcca7fab980e1e61c9400d8a9a5b14ac6",
|
||||
"6fbf31b45ab0c0b8dad1c0f5f4061379912dde5aa922099a030b725c73346c524291adef89d2f6fd8dfcda6d07dad811a9314536c2915ed45da34947e83de34e",
|
||||
"a0c65bddde8adef57282b04b11e7bc8aab105b99231b750c021f4a735cb1bcfab87553bba3abb0c3e64a0b6955285185a0bd35fb8cfde557329bebb1f629ee93",
|
||||
"f99d815550558e81eca2f96718aed10d86f3f1cfb675cce06b0eff02f617c5a42c5aa760270f2679da2677c5aeb94f1142277f21c7f79f3c4f0cce4ed8ee62b1",
|
||||
"95391da8fc7b917a2044b3d6f5374e1ca072b41454d572c7356c05fd4bc1e0f40b8bb8b4a9f6bce9be2c4623c399b0dca0dab05cb7281b71a21b0ebcd9e55670",
|
||||
"04b9cd3d20d221c09ac86913d3dc63041989a9a1e694f1e639a3ba7e451840f750c2fc191d56ad61f2e7936bc0ac8e094b60caeed878c18799045402d61ceaf9",
|
||||
"ec0e0ef707e4ed6c0c66f9e089e4954b058030d2dd86398fe84059631f9ee591d9d77375355149178c0cf8f8e7c49ed2a5e4f95488a2247067c208510fadc44c",
|
||||
"9a37cce273b79c09913677510eaf7688e89b3314d3532fd2764c39de022a2945b5710d13517af8ddc0316624e73bec1ce67df15228302036f330ab0cb4d218dd",
|
||||
"4cf9bb8fb3d4de8b38b2f262d3c40f46dfe747e8fc0a414c193d9fcf753106ce47a18f172f12e8a2f1c26726545358e5ee28c9e2213a8787aafbc516d2343152",
|
||||
"64e0c63af9c808fd893137129867fd91939d53f2af04be4fa268006100069b2d69daa5c5d8ed7fddcb2a70eeecdf2b105dd46a1e3b7311728f639ab489326bc9",
|
||||
"5e9c93158d659b2def06b0c3c7565045542662d6eee8a96a89b78ade09fe8b3dcc096d4fe48815d88d8f82620156602af541955e1f6ca30dce14e254c326b88f",
|
||||
"7775dff889458dd11aef417276853e21335eb88e4dec9cfb4e9edb49820088551a2ca60339f12066101169f0dfe84b098fddb148d9da6b3d613df263889ad64b",
|
||||
"f0d2805afbb91f743951351a6d024f9353a23c7ce1fc2b051b3a8b968c233f46f50f806ecb1568ffaa0b60661e334b21dde04f8fa155ac740eeb42e20b60d764",
|
||||
"86a2af316e7d7754201b942e275364ac12ea8962ab5bd8d7fb276dc5fbffc8f9a28cae4e4867df6780d9b72524160927c855da5b6078e0b554aa91e31cb9ca1d",
|
||||
"10bdf0caa0802705e706369baf8a3f79d72c0a03a80675a7bbb00be3a45e516424d1ee88efb56f6d5777545ae6e27765c3a8f5e493fc308915638933a1dfee55",
|
||||
"b01781092b1748459e2e4ec178696627bf4ebafebba774ecf018b79a68aeb84917bf0b84bb79d17b743151144cd66b7b33a4b9e52c76c4e112050ff5385b7f0b",
|
||||
"c6dbc61dec6eaeac81e3d5f755203c8e220551534a0b2fd105a91889945a638550204f44093dd998c076205dffad703a0e5cd3c7f438a7e634cd59fededb539e",
|
||||
"eba51acffb4cea31db4b8d87e9bf7dd48fe97b0253ae67aa580f9ac4a9d941f2bea518ee286818cc9f633f2a3b9fb68e594b48cdd6d515bf1d52ba6c85a203a7",
|
||||
"86221f3ada52037b72224f105d7999231c5e5534d03da9d9c0a12acb68460cd375daf8e24386286f9668f72326dbf99ba094392437d398e95bb8161d717f8991",
|
||||
"5595e05c13a7ec4dc8f41fb70cb50a71bce17c024ff6de7af618d0cc4e9c32d9570d6d3ea45b86525491030c0d8f2b1836d5778c1ce735c17707df364d054347",
|
||||
"ce0f4f6aca89590a37fe034dd74dd5fa65eb1cbd0a41508aaddc09351a3cea6d18cb2189c54b700c009f4cbf0521c7ea01be61c5ae09cb54f27bc1b44d658c82",
|
||||
"7ee80b06a215a3bca970c77cda8761822bc103d44fa4b33f4d07dcb997e36d55298bceae12241b3fa07fa63be5576068da387b8d5859aeab701369848b176d42",
|
||||
"940a84b6a84d109aab208c024c6ce9647676ba0aaa11f86dbb7018f9fd2220a6d901a9027f9abcf935372727cbf09ebd61a2a2eeb87653e8ecad1bab85dc8327",
|
||||
"2020b78264a82d9f4151141adba8d44bf20c5ec062eee9b595a11f9e84901bf148f298e0c9f8777dcdbc7cc4670aac356cc2ad8ccb1629f16f6a76bcefbee760",
|
||||
"d1b897b0e075ba68ab572adf9d9c436663e43eb3d8e62d92fc49c9be214e6f27873fe215a65170e6bea902408a25b49506f47babd07cecf7113ec10c5dd31252",
|
||||
"b14d0c62abfa469a357177e594c10c194243ed2025ab8aa5ad2fa41ad318e0ff48cd5e60bec07b13634a711d2326e488a985f31e31153399e73088efc86a5c55",
|
||||
"4169c5cc808d2697dc2a82430dc23e3cd356dc70a94566810502b8d655b39abf9e7f902fe717e0389219859e1945df1af6ada42e4ccda55a197b7100a30c30a1",
|
||||
"258a4edb113d66c839c8b1c91f15f35ade609f11cd7f8681a4045b9fef7b0b24c82cda06a5f2067b368825e3914e53d6948ede92efd6e8387fa2e537239b5bee",
|
||||
"79d2d8696d30f30fb34657761171a11e6c3f1e64cbe7bebee159cb95bfaf812b4f411e2f26d9c421dc2c284a3342d823ec293849e42d1e46b0a4ac1e3c86abaa",
|
||||
"8b9436010dc5dee992ae38aea97f2cd63b946d94fedd2ec9671dcde3bd4ce9564d555c66c15bb2b900df72edb6b891ebcadfeff63c9ea4036a998be7973981e7",
|
||||
"c8f68e696ed28242bf997f5b3b34959508e42d613810f1e2a435c96ed2ff560c7022f361a9234b9837feee90bf47922ee0fd5f8ddf823718d86d1e16c6090071",
|
||||
"b02d3eee4860d5868b2c39ce39bfe81011290564dd678c85e8783f29302dfc1399ba95b6b53cd9ebbf400cca1db0ab67e19a325f2d115812d25d00978ad1bca4",
|
||||
"7693ea73af3ac4dad21ca0d8da85b3118a7d1c6024cfaf557699868217bc0c2f44a199bc6c0edd519798ba05bd5b1b4484346a47c2cadf6bf30b785cc88b2baf",
|
||||
"a0e5c1c0031c02e48b7f09a5e896ee9aef2f17fc9e18e997d7f6cac7ae316422c2b1e77984e5f3a73cb45deed5d3f84600105e6ee38f2d090c7d0442ea34c46d",
|
||||
"41daa6adcfdb69f1440c37b596440165c15ada596813e2e22f060fcd551f24dee8e04ba6890387886ceec4a7a0d7fc6b44506392ec3822c0d8c1acfc7d5aebe8",
|
||||
"14d4d40d5984d84c5cf7523b7798b254e275a3a8cc0a1bd06ebc0bee726856acc3cbf516ff667cda2058ad5c3412254460a82c92187041363cc77a4dc215e487",
|
||||
"d0e7a1e2b9a447fee83e2277e9ff8010c2f375ae12fa7aaa8ca5a6317868a26a367a0b69fbc1cf32a55d34eb370663016f3d2110230eba754028a56f54acf57c",
|
||||
"e771aa8db5a3e043e8178f39a0857ba04a3f18e4aa05743cf8d222b0b095825350ba422f63382a23d92e4149074e816a36c1cd28284d146267940b31f8818ea2",
|
||||
"feb4fd6f9e87a56bef398b3284d2bda5b5b0e166583a66b61e538457ff0584872c21a32962b9928ffab58de4af2edd4e15d8b35570523207ff4e2a5aa7754caa",
|
||||
"462f17bf005fb1c1b9e671779f665209ec2873e3e411f98dabf240a1d5ec3f95ce6796b6fc23fe171903b502023467dec7273ff74879b92967a2a43a5a183d33",
|
||||
"d3338193b64553dbd38d144bea71c5915bb110e2d88180dbc5db364fd6171df317fc7268831b5aef75e4342b2fad8797ba39eddcef80e6ec08159350b1ad696d",
|
||||
"e1590d585a3d39f7cb599abd479070966409a6846d4377acf4471d065d5db94129cc9be92573b05ed226be1e9b7cb0cabe87918589f80dadd4ef5ef25a93d28e",
|
||||
"f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e76842d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2",
|
||||
"30186055c07949948183c850e9a756cc09937e247d9d928e869e20bafc3cd9721719d34e04a0899b92c736084550186886efba2e790d8be6ebf040b209c439a4",
|
||||
"f3c4276cb863637712c241c444c5cc1e3554e0fddb174d035819dd83eb700b4ce88df3ab3841ba02085e1a99b4e17310c5341075c0458ba376c95a6818fbb3e2",
|
||||
"0aa007c4dd9d5832393040a1583c930bca7dc5e77ea53add7e2b3f7c8e231368043520d4a3ef53c969b6bbfd025946f632bd7f765d53c21003b8f983f75e2a6a",
|
||||
"08e9464720533b23a04ec24f7ae8c103145f765387d738777d3d343477fd1c58db052142cab754ea674378e18766c53542f71970171cc4f81694246b717d7564",
|
||||
"d37ff7ad297993e7ec21e0f1b4b5ae719cdc83c5db687527f27516cbffa822888a6810ee5c1ca7bfe3321119be1ab7bfa0a502671c8329494df7ad6f522d440f",
|
||||
"dd9042f6e464dcf86b1262f6accfafbd8cfd902ed3ed89abf78ffa482dbdeeb6969842394c9a1168ae3d481a017842f660002d42447c6b22f7b72f21aae021c9",
|
||||
"bd965bf31e87d70327536f2a341cebc4768eca275fa05ef98f7f1b71a0351298de006fba73fe6733ed01d75801b4a928e54231b38e38c562b2e33ea1284992fa",
|
||||
"65676d800617972fbd87e4b9514e1c67402b7a331096d3bfac22f1abb95374abc942f16e9ab0ead33b87c91968a6e509e119ff07787b3ef483e1dcdccf6e3022",
|
||||
"939fa189699c5d2c81ddd1ffc1fa207c970b6a3685bb29ce1d3e99d42f2f7442da53e95a72907314f4588399a3ff5b0a92beb3f6be2694f9f86ecf2952d5b41c",
|
||||
"c516541701863f91005f314108ceece3c643e04fc8c42fd2ff556220e616aaa6a48aeb97a84bad74782e8dff96a1a2fa949339d722edcaa32b57067041df88cc",
|
||||
"987fd6e0d6857c553eaebb3d34970a2c2f6e89a3548f492521722b80a1c21a153892346d2cba6444212d56da9a26e324dccbc0dcde85d4d2ee4399eec5a64e8f",
|
||||
"ae56deb1c2328d9c4017706bce6e99d41349053ba9d336d677c4c27d9fd50ae6aee17e853154e1f4fe7672346da2eaa31eea53fcf24a22804f11d03da6abfc2b",
|
||||
"49d6a608c9bde4491870498572ac31aac3fa40938b38a7818f72383eb040ad39532bc06571e13d767e6945ab77c0bdc3b0284253343f9f6c1244ebf2ff0df866",
|
||||
"da582ad8c5370b4469af862aa6467a2293b2b28bd80ae0e91f425ad3d47249fdf98825cc86f14028c3308c9804c78bfeeeee461444ce243687e1a50522456a1d",
|
||||
"d5266aa3331194aef852eed86d7b5b2633a0af1c735906f2e13279f14931a9fc3b0eac5ce9245273bd1aa92905abe16278ef7efd47694789a7283b77da3c70f8",
|
||||
"2962734c28252186a9a1111c732ad4de4506d4b4480916303eb7991d659ccda07a9911914bc75c418ab7a4541757ad054796e26797feaf36e9f6ad43f14b35a4",
|
||||
"e8b79ec5d06e111bdfafd71e9f5760f00ac8ac5d8bf768f9ff6f08b8f026096b1cc3a4c973333019f1e3553e77da3f98cb9f542e0a90e5f8a940cc58e59844b3",
|
||||
"dfb320c44f9d41d1efdcc015f08dd5539e526e39c87d509ae6812a969e5431bf4fa7d91ffd03b981e0d544cf72d7b1c0374f8801482e6dea2ef903877eba675e",
|
||||
"d88675118fdb55a5fb365ac2af1d217bf526ce1ee9c94b2f0090b2c58a06ca58187d7fe57c7bed9d26fca067b4110eefcd9a0a345de872abe20de368001b0745",
|
||||
"b893f2fc41f7b0dd6e2f6aa2e0370c0cff7df09e3acfcc0e920b6e6fad0ef747c40668417d342b80d2351e8c175f20897a062e9765e6c67b539b6ba8b9170545",
|
||||
"6c67ec5697accd235c59b486d7b70baeedcbd4aa64ebd4eef3c7eac189561a726250aec4d48cadcafbbe2ce3c16ce2d691a8cce06e8879556d4483ed7165c063",
|
||||
"f1aa2b044f8f0c638a3f362e677b5d891d6fd2ab0765f6ee1e4987de057ead357883d9b405b9d609eea1b869d97fb16d9b51017c553f3b93c0a1e0f1296fedcd",
|
||||
"cbaa259572d4aebfc1917acddc582b9f8dfaa928a198ca7acd0f2aa76a134a90252e6298a65b08186a350d5b7626699f8cb721a3ea5921b753ae3a2dce24ba3a",
|
||||
"fa1549c9796cd4d303dcf452c1fbd5744fd9b9b47003d920b92de34839d07ef2a29ded68f6fc9e6c45e071a2e48bd50c5084e96b657dd0404045a1ddefe282ed",
|
||||
"5cf2ac897ab444dcb5c8d87c495dbdb34e1838b6b629427caa51702ad0f9688525f13bec503a3c3a2c80a65e0b5715e8afab00ffa56ec455a49a1ad30aa24fcd",
|
||||
"9aaf80207bace17bb7ab145757d5696bde32406ef22b44292ef65d4519c3bb2ad41a59b62cc3e94b6fa96d32a7faadae28af7d35097219aa3fd8cda31e40c275",
|
||||
"af88b163402c86745cb650c2988fb95211b94b03ef290eed9662034241fd51cf398f8073e369354c43eae1052f9b63b08191caa138aa54fea889cc7024236897",
|
||||
"48fa7d64e1ceee27b9864db5ada4b53d00c9bc7626555813d3cd6730ab3cc06ff342d727905e33171bde6e8476e77fb1720861e94b73a2c538d254746285f430",
|
||||
"0e6fd97a85e904f87bfe85bbeb34f69e1f18105cf4ed4f87aec36c6e8b5f68bd2a6f3dc8a9ecb2b61db4eedb6b2ea10bf9cb0251fb0f8b344abf7f366b6de5ab",
|
||||
"06622da5787176287fdc8fed440bad187d830099c94e6d04c8e9c954cda70c8bb9e1fc4a6d0baa831b9b78ef6648681a4867a11da93ee36e5e6a37d87fc63f6f",
|
||||
"1da6772b58fabf9c61f68d412c82f182c0236d7d575ef0b58dd22458d643cd1dfc93b03871c316d8430d312995d4197f0874c99172ba004a01ee295abac24e46",
|
||||
"3cd2d9320b7b1d5fb9aab951a76023fa667be14a9124e394513918a3f44096ae4904ba0ffc150b63bc7ab1eeb9a6e257e5c8f000a70394a5afd842715de15f29",
|
||||
"04cdc14f7434e0b4be70cb41db4c779a88eaef6accebcb41f2d42fffe7f32a8e281b5c103a27021d0d08362250753cdf70292195a53a48728ceb5844c2d98bab",
|
||||
"9071b7a8a075d0095b8fb3ae5113785735ab98e2b52faf91d5b89e44aac5b5d4ebbf91223b0ff4c71905da55342e64655d6ef8c89a4768c3f93a6dc0366b5bc8",
|
||||
"ebb30240dd96c7bc8d0abe49aa4edcbb4afdc51ff9aaf720d3f9e7fbb0f9c6d6571350501769fc4ebd0b2141247ff400d4fd4be414edf37757bb90a32ac5c65a",
|
||||
"8532c58bf3c8015d9d1cbe00eef1f5082f8f3632fbe9f1ed4f9dfb1fa79e8283066d77c44c4af943d76b300364aecbd0648c8a8939bd204123f4b56260422dec",
|
||||
"fe9846d64f7c7708696f840e2d76cb4408b6595c2f81ec6a28a7f2f20cb88cfe6ac0b9e9b8244f08bd7095c350c1d0842f64fb01bb7f532dfcd47371b0aeeb79",
|
||||
"28f17ea6fb6c42092dc264257e29746321fb5bdaea9873c2a7fa9d8f53818e899e161bc77dfe8090afd82bf2266c5c1bc930a8d1547624439e662ef695f26f24",
|
||||
"ec6b7d7f030d4850acae3cb615c21dd25206d63e84d1db8d957370737ba0e98467ea0ce274c66199901eaec18a08525715f53bfdb0aacb613d342ebdceeddc3b",
|
||||
"b403d3691c03b0d3418df327d5860d34bbfcc4519bfbce36bf33b208385fadb9186bc78a76c489d89fd57e7dc75412d23bcd1dae8470ce9274754bb8585b13c5",
|
||||
"31fc79738b8772b3f55cd8178813b3b52d0db5a419d30ba9495c4b9da0219fac6df8e7c23a811551a62b827f256ecdb8124ac8a6792ccfecc3b3012722e94463",
|
||||
"bb2039ec287091bcc9642fc90049e73732e02e577e2862b32216ae9bedcd730c4c284ef3968c368b7d37584f97bd4b4dc6ef6127acfe2e6ae2509124e66c8af4",
|
||||
"f53d68d13f45edfcb9bd415e2831e938350d5380d3432278fc1c0c381fcb7c65c82dafe051d8c8b0d44e0974a0e59ec7bf7ed0459f86e96f329fc79752510fd3",
|
||||
"8d568c7984f0ecdf7640fbc483b5d8c9f86634f6f43291841b309a350ab9c1137d24066b09da9944bac54d5bb6580d836047aac74ab724b887ebf93d4b32eca9",
|
||||
"c0b65ce5a96ff774c456cac3b5f2c4cd359b4ff53ef93a3da0778be4900d1e8da1601e769e8f1b02d2a2f8c5b9fa10b44f1c186985468feeb008730283a6657d",
|
||||
"4900bba6f5fb103ece8ec96ada13a5c3c85488e05551da6b6b33d988e611ec0fe2e3c2aa48ea6ae8986a3a231b223c5d27cec2eadde91ce07981ee652862d1e4",
|
||||
"c7f5c37c7285f927f76443414d4357ff789647d7a005a5a787e03c346b57f49f21b64fa9cf4b7e45573e23049017567121a9c3d4b2b73ec5e9413577525db45a",
|
||||
"ec7096330736fdb2d64b5653e7475da746c23a4613a82687a28062d3236364284ac01720ffb406cfe265c0df626a188c9e5963ace5d3d5bb363e32c38c2190a6",
|
||||
"82e744c75f4649ec52b80771a77d475a3bc091989556960e276a5f9ead92a03f718742cdcfeaee5cb85c44af198adc43a4a428f5f0c2ddb0be36059f06d7df73",
|
||||
"2834b7a7170f1f5b68559ab78c1050ec21c919740b784a9072f6e5d69f828d70c919c5039fb148e39e2c8a52118378b064ca8d5001cd10a5478387b966715ed6",
|
||||
"16b4ada883f72f853bb7ef253efcab0c3e2161687ad61543a0d2824f91c1f81347d86be709b16996e17f2dd486927b0288ad38d13063c4a9672c39397d3789b6",
|
||||
"78d048f3a69d8b54ae0ed63a573ae350d89f7c6cf1f3688930de899afa037697629b314e5cd303aa62feea72a25bf42b304b6c6bcb27fae21c16d925e1fbdac3",
|
||||
"0f746a48749287ada77a82961f05a4da4abdb7d77b1220f836d09ec814359c0ec0239b8c7b9ff9e02f569d1b301ef67c4612d1de4f730f81c12c40cc063c5caa",
|
||||
"f0fc859d3bd195fbdc2d591e4cdac15179ec0f1dc821c11df1f0c1d26e6260aaa65b79fafacafd7d3ad61e600f250905f5878c87452897647a35b995bcadc3a3",
|
||||
"2620f687e8625f6a412460b42e2cef67634208ce10a0cbd4dff7044a41b7880077e9f8dc3b8d1216d3376a21e015b58fb279b521d83f9388c7382c8505590b9b",
|
||||
"227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c528fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f",
|
||||
"1a929901b09c25f27d6b35be7b2f1c4745131fdebca7f3e2451926720434e0db6e74fd693ad29b777dc3355c592a361c4873b01133a57c2e3b7075cbdb86f4fc",
|
||||
"5fd7968bc2fe34f220b5e3dc5af9571742d73b7d60819f2888b629072b96a9d8ab2d91b82d0a9aaba61bbd39958132fcc4257023d1eca591b3054e2dc81c8200",
|
||||
"dfcce8cf32870cc6a503eadafc87fd6f78918b9b4d0737db6810be996b5497e7e5cc80e312f61e71ff3e9624436073156403f735f56b0b01845c18f6caf772e6",
|
||||
"02f7ef3a9ce0fff960f67032b296efca3061f4934d690749f2d01c35c81c14f39a67fa350bc8a0359bf1724bffc3bca6d7c7bba4791fd522a3ad353c02ec5aa8",
|
||||
"64be5c6aba65d594844ae78bb022e5bebe127fd6b6ffa5a13703855ab63b624dcd1a363f99203f632ec386f3ea767fc992e8ed9686586aa27555a8599d5b808f",
|
||||
"f78585505c4eaa54a8b5be70a61e735e0ff97af944ddb3001e35d86c4e2199d976104b6ae31750a36a726ed285064f5981b503889fef822fcdc2898dddb7889a",
|
||||
"e4b5566033869572edfd87479a5bb73c80e8759b91232879d96b1dda36c012076ee5a2ed7ae2de63ef8406a06aea82c188031b560beafb583fb3de9e57952a7e",
|
||||
"e1b3e7ed867f6c9484a2a97f7715f25e25294e992e41f6a7c161ffc2adc6daaeb7113102d5e6090287fe6ad94ce5d6b739c6ca240b05c76fb73f25dd024bf935",
|
||||
"85fd085fdc12a080983df07bd7012b0d402a0f4043fcb2775adf0bad174f9b08d1676e476985785c0a5dcc41dbff6d95ef4d66a3fbdc4a74b82ba52da0512b74",
|
||||
"aed8fa764b0fbff821e05233d2f7b0900ec44d826f95e93c343c1bc3ba5a24374b1d616e7e7aba453a0ada5e4fab5382409e0d42ce9c2bc7fb39a99c340c20f0",
|
||||
"7ba3b2e297233522eeb343bd3ebcfd835a04007735e87f0ca300cbee6d416565162171581e4020ff4cf176450f1291ea2285cb9ebffe4c56660627685145051c",
|
||||
"de748bcf89ec88084721e16b85f30adb1a6134d664b5843569babc5bbd1a15ca9b61803c901a4fef32965a1749c9f3a4e243e173939dc5a8dc495c671ab52145",
|
||||
"aaf4d2bdf200a919706d9842dce16c98140d34bc433df320aba9bd429e549aa7a3397652a4d768277786cf993cde2338673ed2e6b66c961fefb82cd20c93338f",
|
||||
"c408218968b788bf864f0997e6bc4c3dba68b276e2125a4843296052ff93bf5767b8cdce7131f0876430c1165fec6c4f47adaa4fd8bcfacef463b5d3d0fa61a0",
|
||||
"76d2d819c92bce55fa8e092ab1bf9b9eab237a25267986cacf2b8ee14d214d730dc9a5aa2d7b596e86a1fd8fa0804c77402d2fcd45083688b218b1cdfa0dcbcb",
|
||||
"72065ee4dd91c2d8509fa1fc28a37c7fc9fa7d5b3f8ad3d0d7a25626b57b1b44788d4caf806290425f9890a3a2a35a905ab4b37acfd0da6e4517b2525c9651e4",
|
||||
"64475dfe7600d7171bea0b394e27c9b00d8e74dd1e416a79473682ad3dfdbb706631558055cfc8a40e07bd015a4540dcdea15883cbbf31412df1de1cd4152b91",
|
||||
"12cd1674a4488a5d7c2b3160d2e2c4b58371bedad793418d6f19c6ee385d70b3e06739369d4df910edb0b0a54cbff43d54544cd37ab3a06cfa0a3ddac8b66c89",
|
||||
"60756966479dedc6dd4bcff8ea7d1d4ce4d4af2e7b097e32e3763518441147cc12b3c0ee6d2ecabf1198cec92e86a3616fba4f4e872f5825330adbb4c1dee444",
|
||||
"a7803bcb71bc1d0f4383dde1e0612e04f872b715ad30815c2249cf34abb8b024915cb2fc9f4e7cc4c8cfd45be2d5a91eab0941c7d270e2da4ca4a9f7ac68663a",
|
||||
"b84ef6a7229a34a750d9a98ee2529871816b87fbe3bc45b45fa5ae82d5141540211165c3c5d7a7476ba5a4aa06d66476f0d9dc49a3f1ee72c3acabd498967414",
|
||||
"fae4b6d8efc3f8c8e64d001dabec3a21f544e82714745251b2b4b393f2f43e0da3d403c64db95a2cb6e23ebb7b9e94cdd5ddac54f07c4a61bd3cb10aa6f93b49",
|
||||
"34f7286605a122369540141ded79b8957255da2d4155abbf5a8dbb89c8eb7ede8eeef1daa46dc29d751d045dc3b1d658bb64b80ff8589eddb3824b13da235a6b",
|
||||
"3b3b48434be27b9eababba43bf6b35f14b30f6a88dc2e750c358470d6b3aa3c18e47db4017fa55106d8252f016371a00f5f8b070b74ba5f23cffc5511c9f09f0",
|
||||
"ba289ebd6562c48c3e10a8ad6ce02e73433d1e93d7c9279d4d60a7e879ee11f441a000f48ed9f7c4ed87a45136d7dccdca482109c78a51062b3ba4044ada2469",
|
||||
"022939e2386c5a37049856c850a2bb10a13dfea4212b4c732a8840a9ffa5faf54875c5448816b2785a007da8a8d2bc7d71a54e4e6571f10b600cbdb25d13ede3",
|
||||
"e6fec19d89ce8717b1a087024670fe026f6c7cbda11caef959bb2d351bf856f8055d1c0ebdaaa9d1b17886fc2c562b5e99642fc064710c0d3488a02b5ed7f6fd",
|
||||
"94c96f02a8f576aca32ba61c2b206f907285d9299b83ac175c209a8d43d53bfe683dd1d83e7549cb906c28f59ab7c46f8751366a28c39dd5fe2693c9019666c8",
|
||||
"31a0cd215ebd2cb61de5b9edc91e6195e31c59a5648d5c9f737e125b2605708f2e325ab3381c8dce1a3e958886f1ecdc60318f882cfe20a24191352e617b0f21",
|
||||
"91ab504a522dce78779f4c6c6ba2e6b6db5565c76d3e7e7c920caf7f757ef9db7c8fcf10e57f03379ea9bf75eb59895d96e149800b6aae01db778bb90afbc989",
|
||||
"d85cabc6bd5b1a01a5afd8c6734740da9fd1c1acc6db29bfc8a2e5b668b028b6b3154bfb8703fa3180251d589ad38040ceb707c4bad1b5343cb426b61eaa49c1",
|
||||
"d62efbec2ca9c1f8bd66ce8b3f6a898cb3f7566ba6568c618ad1feb2b65b76c3ce1dd20f7395372faf28427f61c9278049cf0140df434f5633048c86b81e0399",
|
||||
"7c8fdc6175439e2c3db15bafa7fb06143a6a23bc90f449e79deef73c3d492a671715c193b6fea9f036050b946069856b897e08c00768f5ee5ddcf70b7cd6d0e0",
|
||||
"58602ee7468e6bc9df21bd51b23c005f72d6cb013f0a1b48cbec5eca299299f97f09f54a9a01483eaeb315a6478bad37ba47ca1347c7c8fc9e6695592c91d723",
|
||||
"27f5b79ed256b050993d793496edf4807c1d85a7b0a67c9c4fa99860750b0ae66989670a8ffd7856d7ce411599e58c4d77b232a62bef64d15275be46a68235ff",
|
||||
"3957a976b9f1887bf004a8dca942c92d2b37ea52600f25e0c9bc5707d0279c00c6e85a839b0d2d8eb59c51d94788ebe62474a791cadf52cccf20f5070b6573fc",
|
||||
"eaa2376d55380bf772ecca9cb0aa4668c95c707162fa86d518c8ce0ca9bf7362b9f2a0adc3ff59922df921b94567e81e452f6c1a07fc817cebe99604b3505d38",
|
||||
"c1e2c78b6b2734e2480ec550434cb5d613111adcc21d475545c3b1b7e6ff12444476e5c055132e2229dc0f807044bb919b1a5662dd38a9ee65e243a3911aed1a",
|
||||
"8ab48713389dd0fcf9f965d3ce66b1e559a1f8c58741d67683cd971354f452e62d0207a65e436c5d5d8f8ee71c6abfe50e669004c302b31a7ea8311d4a916051",
|
||||
"24ce0addaa4c65038bd1b1c0f1452a0b128777aabc94a29df2fd6c7e2f85f8ab9ac7eff516b0e0a825c84a24cfe492eaad0a6308e46dd42fe8333ab971bb30ca",
|
||||
"5154f929ee03045b6b0c0004fa778edee1d139893267cc84825ad7b36c63de32798e4a166d24686561354f63b00709a1364b3c241de3febf0754045897467cd4",
|
||||
"e74e907920fd87bd5ad636dd11085e50ee70459c443e1ce5809af2bc2eba39f9e6d7128e0e3712c316da06f4705d78a4838e28121d4344a2c79c5e0db307a677",
|
||||
"bf91a22334bac20f3fd80663b3cd06c4e8802f30e6b59f90d3035cc9798a217ed5a31abbda7fa6842827bdf2a7a1c21f6fcfccbb54c6c52926f32da816269be1",
|
||||
"d9d5c74be5121b0bd742f26bffb8c89f89171f3f934913492b0903c271bbe2b3395ef259669bef43b57f7fcc3027db01823f6baee66e4f9fead4d6726c741fce",
|
||||
"50c8b8cf34cd879f80e2faab3230b0c0e1cc3e9dcadeb1b9d97ab923415dd9a1fe38addd5c11756c67990b256e95ad6d8f9fedce10bf1c90679cde0ecf1be347",
|
||||
"0a386e7cd5dd9b77a035e09fe6fee2c8ce61b5383c87ea43205059c5e4cd4f4408319bb0a82360f6a58e6c9ce3f487c446063bf813bc6ba535e17fc1826cfc91",
|
||||
"1f1459cb6b61cbac5f0efe8fc487538f42548987fcd56221cfa7beb22504769e792c45adfb1d6b3d60d7b749c8a75b0bdf14e8ea721b95dca538ca6e25711209",
|
||||
"e58b3836b7d8fedbb50ca5725c6571e74c0785e97821dab8b6298c10e4c079d4a6cdf22f0fedb55032925c16748115f01a105e77e00cee3d07924dc0d8f90659",
|
||||
"b929cc6505f020158672deda56d0db081a2ee34c00c1100029bdf8ea98034fa4bf3e8655ec697fe36f40553c5bb46801644a627d3342f4fc92b61f03290fb381",
|
||||
"72d353994b49d3e03153929a1e4d4f188ee58ab9e72ee8e512f29bc773913819ce057ddd7002c0433ee0a16114e3d156dd2c4a7e80ee53378b8670f23e33ef56",
|
||||
"c70ef9bfd775d408176737a0736d68517ce1aaad7e81a93c8c1ed967ea214f56c8a377b1763e676615b60f3988241eae6eab9685a5124929d28188f29eab06f7",
|
||||
"c230f0802679cb33822ef8b3b21bf7a9a28942092901d7dac3760300831026cf354c9232df3e084d9903130c601f63c1f4a4a4b8106e468cd443bbe5a734f45f",
|
||||
"6f43094cafb5ebf1f7a4937ec50f56a4c9da303cbb55ac1f27f1f1976cd96beda9464f0e7b9c54620b8a9fba983164b8be3578425a024f5fe199c36356b88972",
|
||||
"3745273f4c38225db2337381871a0c6aafd3af9b018c88aa02025850a5dc3a42a1a3e03e56cbf1b0876d63a441f1d2856a39b8801eb5af325201c415d65e97fe",
|
||||
"c50c44cca3ec3edaae779a7e179450ebdda2f97067c690aa6c5a4ac7c30139bb27c0df4db3220e63cb110d64f37ffe078db72653e2daacf93ae3f0a2d1a7eb2e",
|
||||
"8aef263e385cbc61e19b28914243262af5afe8726af3ce39a79c27028cf3ecd3f8d2dfd9cfc9ad91b58f6f20778fd5f02894a3d91c7d57d1e4b866a7f364b6be",
|
||||
"28696141de6e2d9bcb3235578a66166c1448d3e905a1b482d423be4bc5369bc8c74dae0acc9cc123e1d8ddce9f97917e8c019c552da32d39d2219b9abf0fa8c8",
|
||||
"2fb9eb2085830181903a9dafe3db428ee15be7662224efd643371fb25646aee716e531eca69b2bdc8233f1a8081fa43da1500302975a77f42fa592136710e9dc",
|
||||
"66f9a7143f7a3314a669bf2e24bbb35014261d639f495b6c9c1f104fe8e320aca60d4550d69d52edbd5a3cdeb4014ae65b1d87aa770b69ae5c15f4330b0b0ad8",
|
||||
"f4c4dd1d594c3565e3e25ca43dad82f62abea4835ed4cd811bcd975e46279828d44d4c62c3679f1b7f7b9dd4571d7b49557347b8c5460cbdc1bef690fb2a08c0",
|
||||
"8f1dc9649c3a84551f8f6e91cac68242a43b1f8f328ee92280257387fa7559aa6db12e4aeadc2d26099178749c6864b357f3f83b2fb3efa8d2a8db056bed6bcc",
|
||||
"3139c1a7f97afd1675d460ebbc07f2728aa150df849624511ee04b743ba0a833092f18c12dc91b4dd243f333402f59fe28abdbbbae301e7b659c7a26d5c0f979",
|
||||
"06f94a2996158a819fe34c40de3cf0379fd9fb85b3e363ba3926a0e7d960e3f4c2e0c70c7ce0ccb2a64fc29869f6e7ab12bd4d3f14fce943279027e785fb5c29",
|
||||
"c29c399ef3eee8961e87565c1ce263925fc3d0ce267d13e48dd9e732ee67b0f69fad56401b0f10fcaac119201046cca28c5b14abdea3212ae65562f7f138db3d",
|
||||
"4cec4c9df52eef05c3f6faaa9791bc7445937183224ecc37a1e58d0132d35617531d7e795f52af7b1eb9d147de1292d345fe341823f8e6bc1e5badca5c656108",
|
||||
"898bfbae93b3e18d00697eab7d9704fa36ec339d076131cefdf30edbe8d9cc81c3a80b129659b163a323bab9793d4feed92d54dae966c77529764a09be88db45",
|
||||
"ee9bd0469d3aaf4f14035be48a2c3b84d9b4b1fff1d945e1f1c1d38980a951be197b25fe22c731f20aeacc930ba9c4a1f4762227617ad350fdabb4e80273a0f4",
|
||||
"3d4d3113300581cd96acbf091c3d0f3c310138cd6979e6026cde623e2dd1b24d4a8638bed1073344783ad0649cc6305ccec04beb49f31c633088a99b65130267",
|
||||
"95c0591ad91f921ac7be6d9ce37e0663ed8011c1cfd6d0162a5572e94368bac02024485e6a39854aa46fe38e97d6c6b1947cd272d86b06bb5b2f78b9b68d559d",
|
||||
"227b79ded368153bf46c0a3ca978bfdbef31f3024a5665842468490b0ff748ae04e7832ed4c9f49de9b1706709d623e5c8c15e3caecae8d5e433430ff72f20eb",
|
||||
"5d34f3952f0105eef88ae8b64c6ce95ebfade0e02c69b08762a8712d2e4911ad3f941fc4034dc9b2e479fdbcd279b902faf5d838bb2e0c6495d372b5b7029813",
|
||||
"7f939bf8353abce49e77f14f3750af20b7b03902e1a1e7fb6aaf76d0259cd401a83190f15640e74f3e6c5a90e839c7821f6474757f75c7bf9002084ddc7a62dc",
|
||||
"062b61a2f9a33a71d7d0a06119644c70b0716a504de7e5e1be49bd7b86e7ed6817714f9f0fc313d06129597e9a2235ec8521de36f7290a90ccfc1ffa6d0aee29",
|
||||
"f29e01eeae64311eb7f1c6422f946bf7bea36379523e7b2bbaba7d1d34a22d5ea5f1c5a09d5ce1fe682cced9a4798d1a05b46cd72dff5c1b355440b2a2d476bc",
|
||||
"ec38cd3bbab3ef35d7cb6d5c914298351d8a9dc97fcee051a8a02f58e3ed6184d0b7810a5615411ab1b95209c3c810114fdeb22452084e77f3f847c6dbaafe16",
|
||||
"c2aef5e0ca43e82641565b8cb943aa8ba53550caef793b6532fafad94b816082f0113a3ea2f63608ab40437ecc0f0229cb8fa224dcf1c478a67d9b64162b92d1",
|
||||
"15f534efff7105cd1c254d074e27d5898b89313b7d366dc2d7d87113fa7d53aae13f6dba487ad8103d5e854c91fdb6e1e74b2ef6d1431769c30767dde067a35c",
|
||||
"89acbca0b169897a0a2714c2df8c95b5b79cb69390142b7d6018bb3e3076b099b79a964152a9d912b1b86412b7e372e9cecad7f25d4cbab8a317be36492a67d7",
|
||||
"e3c0739190ed849c9c962fd9dbb55e207e624fcac1eb417691515499eea8d8267b7e8f1287a63633af5011fde8c4ddf55bfdf722edf88831414f2cfaed59cb9a",
|
||||
"8d6cf87c08380d2d1506eee46fd4222d21d8c04e585fbfd08269c98f702833a156326a0724656400ee09351d57b440175e2a5de93cc5f80db6daf83576cf75fa",
|
||||
"da24bede383666d563eeed37f6319baf20d5c75d1635a6ba5ef4cfa1ac95487e96f8c08af600aab87c986ebad49fc70a58b4890b9c876e091016daf49e1d322e",
|
||||
"f9d1d1b1e87ea7ae753a029750cc1cf3d0157d41805e245c5617bb934e732f0ae3180b78e05bfe76c7c3051e3e3ac78b9b50c05142657e1e03215d6ec7bfd0fc",
|
||||
"11b7bc1668032048aa43343de476395e814bbbc223678db951a1b03a021efac948cfbe215f97fe9a72a2f6bc039e3956bfa417c1a9f10d6d7ba5d3d32ff323e5",
|
||||
"b8d9000e4fc2b066edb91afee8e7eb0f24e3a201db8b6793c0608581e628ed0bcc4e5aa6787992a4bcc44e288093e63ee83abd0bc3ec6d0934a674a4da13838a",
|
||||
"ce325e294f9b6719d6b61278276ae06a2564c03bb0b783fafe785bdf89c7d5acd83e78756d301b445699024eaeb77b54d477336ec2a4f332f2b3f88765ddb0c3",
|
||||
"29acc30e9603ae2fccf90bf97e6cc463ebe28c1b2f9b4b765e70537c25c702a29dcbfbf14c99c54345ba2b51f17b77b5f15db92bbad8fa95c471f5d070a137cc",
|
||||
"3379cbaae562a87b4c0425550ffdd6bfe1203f0d666cc7ea095be407a5dfe61ee91441cd5154b3e53b4f5fb31ad4c7a9ad5c7af4ae679aa51a54003a54ca6b2d",
|
||||
"3095a349d245708c7cf550118703d7302c27b60af5d4e67fc978f8a4e60953c7a04f92fcf41aee64321ccb707a895851552b1e37b00bc5e6b72fa5bcef9e3fff",
|
||||
"07262d738b09321f4dbccec4bb26f48cb0f0ed246ce0b31b9a6e7bc683049f1f3e5545f28ce932dd985c5ab0f43bd6de0770560af329065ed2e49d34624c2cbb",
|
||||
"b6405eca8ee3316c87061cc6ec18dba53e6c250c63ba1f3bae9e55dd3498036af08cd272aa24d713c6020d77ab2f3919af1a32f307420618ab97e73953994fb4",
|
||||
"7ee682f63148ee45f6e5315da81e5c6e557c2c34641fc509c7a5701088c38a74756168e2cd8d351e88fd1a451f360a01f5b2580f9b5a2e8cfc138f3dd59a3ffc",
|
||||
"1d263c179d6b268f6fa016f3a4f29e943891125ed8593c81256059f5a7b44af2dcb2030d175c00e62ecaf7ee96682aa07ab20a611024a28532b1c25b86657902",
|
||||
"106d132cbdb4cd2597812846e2bc1bf732fec5f0a5f65dbb39ec4e6dc64ab2ce6d24630d0f15a805c3540025d84afa98e36703c3dbee713e72dde8465bc1be7e",
|
||||
"0e79968226650667a8d862ea8da4891af56a4e3a8b6d1750e394f0dea76d640d85077bcec2cc86886e506751b4f6a5838f7f0b5fef765d9dc90dcdcbaf079f08",
|
||||
"521156a82ab0c4e566e5844d5e31ad9aaf144bbd5a464fdca34dbd5717e8ff711d3ffebbfa085d67fe996a34f6d3e4e60b1396bf4b1610c263bdbb834d560816",
|
||||
"1aba88befc55bc25efbce02db8b9933e46f57661baeabeb21cc2574d2a518a3cba5dc5a38e49713440b25f9c744e75f6b85c9d8f4681f676160f6105357b8406",
|
||||
"5a9949fcb2c473cda968ac1b5d08566dc2d816d960f57e63b898fa701cf8ebd3f59b124d95bfbbedc5f1cf0e17d5eaed0c02c50b69d8a402cabcca4433b51fd4",
|
||||
"b0cead09807c672af2eb2b0f06dde46cf5370e15a4096b1a7d7cbb36ec31c205fbefca00b7a4162fa89fb4fb3eb78d79770c23f44e7206664ce3cd931c291e5d",
|
||||
"bb6664931ec97044e45b2ae420ae1c551a8874bc937d08e969399c3964ebdba8346cdd5d09caafe4c28ba7ec788191ceca65ddd6f95f18583e040d0f30d0364d",
|
||||
"65bc770a5faa3792369803683e844b0be7ee96f29f6d6a35568006bd5590f9a4ef639b7a8061c7b0424b66b60ac34af3119905f33a9d8c3ae18382ca9b689900",
|
||||
"ea9b4dca333336aaf839a45c6eaa48b8cb4c7ddabffea4f643d6357ea6628a480a5b45f2b052c1b07d1fedca918b6f1139d80f74c24510dcbaa4be70eacc1b06",
|
||||
"e6342fb4a780ad975d0e24bce149989b91d360557e87994f6b457b895575cc02d0c15bad3ce7577f4c63927ff13f3e381ff7e72bdbe745324844a9d27e3f1c01",
|
||||
"3e209c9b33e8e461178ab46b1c64b49a07fb745f1c8bc95fbfb94c6b87c69516651b264ef980937fad41238b91ddc011a5dd777c7efd4494b4b6ecd3a9c22ac0",
|
||||
"fd6a3d5b1875d80486d6e69694a56dbb04a99a4d051f15db2689776ba1c4882e6d462a603b7015dc9f4b7450f05394303b8652cfb404a266962c41bae6e18a94",
|
||||
"951e27517e6bad9e4195fc8671dee3e7e9be69cee1422cb9fecfce0dba875f7b310b93ee3a3d558f941f635f668ff832d2c1d033c5e2f0997e4c66f147344e02",
|
||||
"8eba2f874f1ae84041903c7c4253c82292530fc8509550bfdc34c95c7e2889d5650b0ad8cb988e5c4894cb87fbfbb19612ea93ccc4c5cad17158b9763464b492",
|
||||
"16f712eaa1b7c6354719a8e7dbdfaf55e4063a4d277d947550019b38dfb564830911057d50506136e2394c3b28945cc964967d54e3000c2181626cfb9b73efd2",
|
||||
"c39639e7d5c7fb8cdd0fd3e6a52096039437122f21c78f1679cea9d78a734c56ecbeb28654b4f18e342c331f6f7229ec4b4bc281b2d80a6eb50043f31796c88c",
|
||||
"72d081af99f8a173dcc9a0ac4eb3557405639a29084b54a40172912a2f8a395129d5536f0918e902f9e8fa6000995f4168ddc5f893011be6a0dbc9b8a1a3f5bb",
|
||||
"c11aa81e5efd24d5fc27ee586cfd8847fbb0e27601ccece5ecca0198e3c7765393bb74457c7e7a27eb9170350e1fb53857177506be3e762cc0f14d8c3afe9077",
|
||||
"c28f2150b452e6c0c424bcde6f8d72007f9310fed7f2f87de0dbb64f4479d6c1441ba66f44b2accee61609177ed340128b407ecec7c64bbe50d63d22d8627727",
|
||||
"f63d88122877ec30b8c8b00d22e89000a966426112bd44166e2f525b769ccbe9b286d437a0129130dde1a86c43e04bedb594e671d98283afe64ce331de9828fd",
|
||||
"348b0532880b88a6614a8d7408c3f913357fbb60e995c60205be9139e74998aede7f4581e42f6b52698f7fa1219708c14498067fd1e09502de83a77dd281150c",
|
||||
"5133dc8bef725359dff59792d85eaf75b7e1dcd1978b01c35b1b85fcebc63388ad99a17b6346a217dc1a9622ebd122ecf6913c4d31a6b52a695b86af00d741a0",
|
||||
"2753c4c0e98ecad806e88780ec27fccd0f5c1ab547f9e4bf1659d192c23aa2cc971b58b6802580baef8adc3b776ef7086b2545c2987f348ee3719cdef258c403",
|
||||
"b1663573ce4b9d8caefc865012f3e39714b9898a5da6ce17c25a6a47931a9ddb9bbe98adaa553beed436e89578455416c2a52a525cf2862b8d1d49a2531b7391",
|
||||
"64f58bd6bfc856f5e873b2a2956ea0eda0d6db0da39c8c7fc67c9f9feefcff3072cdf9e6ea37f69a44f0c61aa0da3693c2db5b54960c0281a088151db42b11e8",
|
||||
"0764c7be28125d9065c4b98a69d60aede703547c66a12e17e1c618994132f5ef82482c1e3fe3146cc65376cc109f0138ed9a80e49f1f3c7d610d2f2432f20605",
|
||||
"f748784398a2ff03ebeb07e155e66116a839741a336e32da71ec696001f0ad1b25cd48c69cfca7265eca1dd71904a0ce748ac4124f3571076dfa7116a9cf00e9",
|
||||
"3f0dbc0186bceb6b785ba78d2a2a013c910be157bdaffae81bb6663b1a73722f7f1228795f3ecada87cf6ef0078474af73f31eca0cc200ed975b6893f761cb6d",
|
||||
"d4762cd4599876ca75b2b8fe249944dbd27ace741fdab93616cbc6e425460feb51d4e7adcc38180e7fc47c89024a7f56191adb878dfde4ead62223f5a2610efe",
|
||||
"cd36b3d5b4c91b90fcbba79513cfee1907d8645a162afd0cd4cf4192d4a5f4c892183a8eacdb2b6b6a9d9aa8c11ac1b261b380dbee24ca468f1bfd043c58eefe",
|
||||
"98593452281661a53c48a9d8cd790826c1a1ce567738053d0bee4a91a3d5bd92eefdbabebe3204f2031ca5f781bda99ef5d8ae56e5b04a9e1ecd21b0eb05d3e1",
|
||||
"771f57dd2775ccdab55921d3e8e30ccf484d61fe1c1b9c2ae819d0fb2a12fab9be70c4a7a138da84e8280435daade5bbe66af0836a154f817fb17f3397e725a3",
|
||||
"c60897c6f828e21f16fbb5f15b323f87b6c8955eabf1d38061f707f608abdd993fac3070633e286cf8339ce295dd352df4b4b40b2f29da1dd50b3a05d079e6bb",
|
||||
"8210cd2c2d3b135c2cf07fa0d1433cd771f325d075c6469d9c7f1ba0943cd4ab09808cabf4acb9ce5bb88b498929b4b847f681ad2c490d042db2aec94214b06b",
|
||||
"1d4edfffd8fd80f7e4107840fa3aa31e32598491e4af7013c197a65b7f36dd3ac4b478456111cd4309d9243510782fa31b7c4c95fa951520d020eb7e5c36e4ef",
|
||||
"af8e6e91fab46ce4873e1a50a8ef448cc29121f7f74deef34a71ef89cc00d9274bc6c2454bbb3230d8b2ec94c62b1dec85f3593bfa30ea6f7a44d7c09465a253",
|
||||
"29fd384ed4906f2d13aa9fe7af905990938bed807f1832454a372ab412eea1f5625a1fcc9ac8343b7c67c5aba6e0b1cc4644654913692c6b39eb9187ceacd3ec",
|
||||
"a268c7885d9874a51c44dffed8ea53e94f78456e0b2ed99ff5a3924760813826d960a15edbedbb5de5226ba4b074e71b05c55b9756bb79e55c02754c2c7b6c8a",
|
||||
"0cf8545488d56a86817cd7ecb10f7116b7ea530a45b6ea497b6c72c997e09e3d0da8698f46bb006fc977c2cd3d1177463ac9057fdd1662c85d0c126443c10473",
|
||||
"b39614268fdd8781515e2cfebf89b4d5402bab10c226e6344e6b9ae000fb0d6c79cb2f3ec80e80eaeb1980d2f8698916bd2e9f747236655116649cd3ca23a837",
|
||||
"74bef092fc6f1e5dba3663a3fb003b2a5ba257496536d99f62b9d73f8f9eb3ce9ff3eec709eb883655ec9eb896b9128f2afc89cf7d1ab58a72f4a3bf034d2b4a",
|
||||
"3a988d38d75611f3ef38b8774980b33e573b6c57bee0469ba5eed9b44f29945e7347967fba2c162e1c3be7f310f2f75ee2381e7bfd6b3f0baea8d95dfb1dafb1",
|
||||
"58aedfce6f67ddc85a28c992f1c0bd0969f041e66f1ee88020a125cbfcfebcd61709c9c4eba192c15e69f020d462486019fa8dea0cd7a42921a19d2fe546d43d",
|
||||
"9347bd291473e6b4e368437b8e561e065f649a6d8ada479ad09b1999a8f26b91cf6120fd3bfe014e83f23acfa4c0ad7b3712b2c3c0733270663112ccd9285cd9",
|
||||
"b32163e7c5dbb5f51fdc11d2eac875efbbcb7e7699090a7e7ff8a8d50795af5d74d9ff98543ef8cdf89ac13d0485278756e0ef00c817745661e1d59fe38e7537",
|
||||
"1085d78307b1c4b008c57a2e7e5b234658a0a82e4ff1e4aaac72b312fda0fe27d233bc5b10e9cc17fdc7697b540c7d95eb215a19a1a0e20e1abfa126efd568c7",
|
||||
"4e5c734c7dde011d83eac2b7347b373594f92d7091b9ca34cb9c6f39bdf5a8d2f134379e16d822f6522170ccf2ddd55c84b9e6c64fc927ac4cf8dfb2a17701f2",
|
||||
"695d83bd990a1117b3d0ce06cc888027d12a054c2677fd82f0d4fbfc93575523e7991a5e35a3752e9b70ce62992e268a877744cdd435f5f130869c9a2074b338",
|
||||
"a6213743568e3b3158b9184301f3690847554c68457cb40fc9a4b8cfd8d4a118c301a07737aeda0f929c68913c5f51c80394f53bff1c3e83b2e40ca97eba9e15",
|
||||
"d444bfa2362a96df213d070e33fa841f51334e4e76866b8139e8af3bb3398be2dfaddcbc56b9146de9f68118dc5829e74b0c28d7711907b121f9161cb92b69a9",
|
||||
"142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e92484be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461",
|
||||
}
|
||||
1420
contrib/backends/srndv2/src/srnd/vendor/github.com/dchest/blake2b/block.go
generated
vendored
Normal file
1420
contrib/backends/srndv2/src/srnd/vendor/github.com/dchest/blake2b/block.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
132
contrib/backends/srndv2/src/srnd/vendor/github.com/majestrate/nacl/box.go
generated
vendored
132
contrib/backends/srndv2/src/srnd/vendor/github.com/majestrate/nacl/box.go
generated
vendored
@@ -7,89 +7,89 @@ package nacl
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// encrypts a message to a user given their public key is known
|
||||
// returns an encrypted box
|
||||
func CryptoBox(msg, nounce, pk, sk []byte) ([]byte, error) {
|
||||
msgbuff := NewBuffer(msg)
|
||||
defer msgbuff.Free()
|
||||
msgbuff := NewBuffer(msg)
|
||||
defer msgbuff.Free()
|
||||
|
||||
// check sizes
|
||||
if len(pk) != int(C.crypto_box_publickeybytes()) {
|
||||
err := errors.New("len(pk) != crypto_box_publickey_bytes")
|
||||
return nil, err
|
||||
}
|
||||
if len(sk) != int(C.crypto_box_secretkeybytes()) {
|
||||
err := errors.New("len(sk) != crypto_box_secretkey_bytes")
|
||||
return nil, err
|
||||
}
|
||||
if len(nounce) != int(C.crypto_box_macbytes()) {
|
||||
err := errors.New ("len(nounce) != crypto_box_macbytes()")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pkbuff := NewBuffer(pk)
|
||||
defer pkbuff.Free()
|
||||
skbuff := NewBuffer(sk)
|
||||
defer skbuff.Free()
|
||||
nouncebuff := NewBuffer(nounce)
|
||||
defer nouncebuff.Free()
|
||||
|
||||
resultbuff := malloc(msgbuff.size + nouncebuff.size)
|
||||
defer resultbuff.Free()
|
||||
res := C.crypto_box_easy(resultbuff.uchar(), msgbuff.uchar(), C.ulonglong(msgbuff.size), nouncebuff.uchar(), pkbuff.uchar(), skbuff.uchar())
|
||||
if res != 0 {
|
||||
err := errors.New("crypto_box_easy failed")
|
||||
return nil, err
|
||||
}
|
||||
return resultbuff.Bytes(), nil
|
||||
// check sizes
|
||||
if len(pk) != int(C.crypto_box_publickeybytes()) {
|
||||
err := errors.New("len(pk) != crypto_box_publickey_bytes")
|
||||
return nil, err
|
||||
}
|
||||
if len(sk) != int(C.crypto_box_secretkeybytes()) {
|
||||
err := errors.New("len(sk) != crypto_box_secretkey_bytes")
|
||||
return nil, err
|
||||
}
|
||||
if len(nounce) != int(C.crypto_box_macbytes()) {
|
||||
err := errors.New("len(nounce) != crypto_box_macbytes()")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pkbuff := NewBuffer(pk)
|
||||
defer pkbuff.Free()
|
||||
skbuff := NewBuffer(sk)
|
||||
defer skbuff.Free()
|
||||
nouncebuff := NewBuffer(nounce)
|
||||
defer nouncebuff.Free()
|
||||
|
||||
resultbuff := malloc(msgbuff.size + nouncebuff.size)
|
||||
defer resultbuff.Free()
|
||||
res := C.crypto_box_easy(resultbuff.uchar(), msgbuff.uchar(), C.ulonglong(msgbuff.size), nouncebuff.uchar(), pkbuff.uchar(), skbuff.uchar())
|
||||
if res != 0 {
|
||||
err := errors.New("crypto_box_easy failed")
|
||||
return nil, err
|
||||
}
|
||||
return resultbuff.Bytes(), nil
|
||||
}
|
||||
|
||||
// open an encrypted box
|
||||
func CryptoBoxOpen(box, nounce, sk, pk []byte) ([]byte, error) {
|
||||
boxbuff := NewBuffer(box)
|
||||
defer boxbuff.Free()
|
||||
boxbuff := NewBuffer(box)
|
||||
defer boxbuff.Free()
|
||||
|
||||
// check sizes
|
||||
if len(pk) != int(C.crypto_box_publickeybytes()) {
|
||||
err := errors.New("len(pk) != crypto_box_publickey_bytes")
|
||||
return nil, err
|
||||
}
|
||||
if len(sk) != int(C.crypto_box_secretkeybytes()) {
|
||||
err := errors.New("len(sk) != crypto_box_secretkey_bytes")
|
||||
return nil, err
|
||||
}
|
||||
if len(nounce) != int(C.crypto_box_macbytes()) {
|
||||
err := errors.New("len(nounce) != crypto_box_macbytes()")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pkbuff := NewBuffer(pk)
|
||||
defer pkbuff.Free()
|
||||
skbuff := NewBuffer(sk)
|
||||
defer skbuff.Free()
|
||||
nouncebuff := NewBuffer(nounce)
|
||||
defer nouncebuff.Free()
|
||||
resultbuff := malloc(boxbuff.size - nouncebuff.size)
|
||||
defer resultbuff.Free()
|
||||
|
||||
// decrypt
|
||||
res := C.crypto_box_open_easy(resultbuff.uchar(), boxbuff.uchar(), C.ulonglong(boxbuff.size), nouncebuff.uchar(), pkbuff.uchar(), skbuff.uchar())
|
||||
if res != 0 {
|
||||
return nil, errors.New("crypto_box_open_easy failed")
|
||||
}
|
||||
// return result
|
||||
return resultbuff.Bytes(), nil
|
||||
// check sizes
|
||||
if len(pk) != int(C.crypto_box_publickeybytes()) {
|
||||
err := errors.New("len(pk) != crypto_box_publickey_bytes")
|
||||
return nil, err
|
||||
}
|
||||
if len(sk) != int(C.crypto_box_secretkeybytes()) {
|
||||
err := errors.New("len(sk) != crypto_box_secretkey_bytes")
|
||||
return nil, err
|
||||
}
|
||||
if len(nounce) != int(C.crypto_box_macbytes()) {
|
||||
err := errors.New("len(nounce) != crypto_box_macbytes()")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pkbuff := NewBuffer(pk)
|
||||
defer pkbuff.Free()
|
||||
skbuff := NewBuffer(sk)
|
||||
defer skbuff.Free()
|
||||
nouncebuff := NewBuffer(nounce)
|
||||
defer nouncebuff.Free()
|
||||
resultbuff := malloc(boxbuff.size - nouncebuff.size)
|
||||
defer resultbuff.Free()
|
||||
|
||||
// decrypt
|
||||
res := C.crypto_box_open_easy(resultbuff.uchar(), boxbuff.uchar(), C.ulonglong(boxbuff.size), nouncebuff.uchar(), pkbuff.uchar(), skbuff.uchar())
|
||||
if res != 0 {
|
||||
return nil, errors.New("crypto_box_open_easy failed")
|
||||
}
|
||||
// return result
|
||||
return resultbuff.Bytes(), nil
|
||||
}
|
||||
|
||||
// generate a new nounce
|
||||
func NewBoxNounce() []byte {
|
||||
return RandBytes(NounceLen())
|
||||
return RandBytes(NounceLen())
|
||||
}
|
||||
|
||||
// length of a nounce
|
||||
func NounceLen() int {
|
||||
return int(C.crypto_box_macbytes())
|
||||
return int(C.crypto_box_macbytes())
|
||||
}
|
||||
|
||||
73
contrib/backends/srndv2/src/srnd/vendor/github.com/majestrate/nacl/buffer.go
generated
vendored
73
contrib/backends/srndv2/src/srnd/vendor/github.com/majestrate/nacl/buffer.go
generated
vendored
@@ -10,78 +10,77 @@ package nacl
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
"encoding/hex"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// wrapper arround malloc/free
|
||||
type Buffer struct {
|
||||
ptr unsafe.Pointer;
|
||||
length C.int;
|
||||
size C.size_t;
|
||||
|
||||
ptr unsafe.Pointer
|
||||
length C.int
|
||||
size C.size_t
|
||||
}
|
||||
|
||||
// wrapper arround nacl.malloc
|
||||
func Malloc(size int) *Buffer {
|
||||
if size > 0 {
|
||||
return malloc(C.size_t(size))
|
||||
}
|
||||
return nil
|
||||
if size > 0 {
|
||||
return malloc(C.size_t(size))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// does not check for negatives
|
||||
func malloc(size C.size_t) *Buffer {
|
||||
ptr := C.malloc(size)
|
||||
C.sodium_memzero(ptr, size)
|
||||
buffer := &Buffer{ptr: ptr, size: size , length: C.int(size)}
|
||||
return buffer
|
||||
ptr := C.malloc(size)
|
||||
C.sodium_memzero(ptr, size)
|
||||
buffer := &Buffer{ptr: ptr, size: size, length: C.int(size)}
|
||||
return buffer
|
||||
}
|
||||
|
||||
// create a new buffer copying from a byteslice
|
||||
func NewBuffer(buff []byte) *Buffer {
|
||||
buffer := Malloc(len(buff))
|
||||
if buffer == nil {
|
||||
return nil
|
||||
}
|
||||
if copy(buffer.Data(), buff) != len(buff) {
|
||||
return nil
|
||||
}
|
||||
return buffer
|
||||
buffer := Malloc(len(buff))
|
||||
if buffer == nil {
|
||||
return nil
|
||||
}
|
||||
if copy(buffer.Data(), buff) != len(buff) {
|
||||
return nil
|
||||
}
|
||||
return buffer
|
||||
}
|
||||
|
||||
func (self *Buffer) uchar() *C.uchar {
|
||||
return C.deref_uchar(self.ptr)
|
||||
return C.deref_uchar(self.ptr)
|
||||
}
|
||||
|
||||
func (self *Buffer) Length() int {
|
||||
return int(self.length)
|
||||
return int(self.length)
|
||||
}
|
||||
|
||||
// get immutable byte slice
|
||||
func (self *Buffer) Bytes() []byte {
|
||||
buff := make([]byte, self.Length())
|
||||
copy(buff, self.Data())
|
||||
return buff
|
||||
buff := make([]byte, self.Length())
|
||||
copy(buff, self.Data())
|
||||
return buff
|
||||
}
|
||||
|
||||
// get underlying byte slice
|
||||
func (self *Buffer) Data() []byte {
|
||||
hdr := reflect.SliceHeader{
|
||||
Data: uintptr(self.ptr),
|
||||
Len: self.Length(),
|
||||
Cap: self.Length(),
|
||||
}
|
||||
return *(*[]byte)(unsafe.Pointer(&hdr))
|
||||
hdr := reflect.SliceHeader{
|
||||
Data: uintptr(self.ptr),
|
||||
Len: self.Length(),
|
||||
Cap: self.Length(),
|
||||
}
|
||||
return *(*[]byte)(unsafe.Pointer(&hdr))
|
||||
}
|
||||
|
||||
func (self *Buffer) String() string {
|
||||
return hex.EncodeToString(self.Data())
|
||||
return hex.EncodeToString(self.Data())
|
||||
}
|
||||
|
||||
// zero out memory and then free
|
||||
func (self *Buffer) Free() {
|
||||
C.sodium_memzero(self.ptr, self.size)
|
||||
C.free(self.ptr)
|
||||
C.sodium_memzero(self.ptr, self.size)
|
||||
C.free(self.ptr)
|
||||
}
|
||||
|
||||
222
contrib/backends/srndv2/src/srnd/vendor/github.com/majestrate/nacl/key.go
generated
vendored
222
contrib/backends/srndv2/src/srnd/vendor/github.com/majestrate/nacl/key.go
generated
vendored
@@ -7,174 +7,172 @@ package nacl
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type KeyPair struct {
|
||||
pk *Buffer
|
||||
sk *Buffer
|
||||
pk *Buffer
|
||||
sk *Buffer
|
||||
}
|
||||
|
||||
// free this keypair from memory
|
||||
func (self *KeyPair) Free() {
|
||||
self.pk.Free()
|
||||
self.sk.Free()
|
||||
self.pk.Free()
|
||||
self.sk.Free()
|
||||
}
|
||||
|
||||
func (self *KeyPair) Secret() []byte {
|
||||
return self.sk.Bytes()
|
||||
return self.sk.Bytes()
|
||||
}
|
||||
|
||||
func (self *KeyPair) Public() []byte {
|
||||
return self.pk.Bytes()
|
||||
return self.pk.Bytes()
|
||||
}
|
||||
|
||||
func (self *KeyPair) Seed() []byte {
|
||||
seed_len := C.crypto_sign_seedbytes()
|
||||
return self.sk.Bytes()[:seed_len]
|
||||
seed_len := C.crypto_sign_seedbytes()
|
||||
return self.sk.Bytes()[:seed_len]
|
||||
}
|
||||
|
||||
// generate a keypair
|
||||
func GenSignKeypair() *KeyPair {
|
||||
sk_len := C.crypto_sign_secretkeybytes()
|
||||
sk := malloc(sk_len)
|
||||
pk_len := C.crypto_sign_publickeybytes()
|
||||
pk := malloc(pk_len)
|
||||
res := C.crypto_sign_keypair(pk.uchar(), sk.uchar())
|
||||
if res == 0 {
|
||||
return &KeyPair{pk,sk}
|
||||
}
|
||||
pk.Free()
|
||||
sk.Free()
|
||||
return nil
|
||||
sk_len := C.crypto_sign_secretkeybytes()
|
||||
sk := malloc(sk_len)
|
||||
pk_len := C.crypto_sign_publickeybytes()
|
||||
pk := malloc(pk_len)
|
||||
res := C.crypto_sign_keypair(pk.uchar(), sk.uchar())
|
||||
if res == 0 {
|
||||
return &KeyPair{pk, sk}
|
||||
}
|
||||
pk.Free()
|
||||
sk.Free()
|
||||
return nil
|
||||
}
|
||||
|
||||
// get public key from secret key
|
||||
func GetSignPubkey(sk []byte) ([]byte, error) {
|
||||
sk_len := C.crypto_sign_secretkeybytes()
|
||||
if C.size_t(len(sk)) != sk_len {
|
||||
return nil, errors.New(fmt.Sprintf("nacl.GetSignPubkey() invalid secret key size %d != %d", len(sk), sk_len))
|
||||
}
|
||||
|
||||
pk_len := C.crypto_sign_publickeybytes()
|
||||
pkbuff := malloc(pk_len)
|
||||
defer pkbuff.Free()
|
||||
sk_len := C.crypto_sign_secretkeybytes()
|
||||
if C.size_t(len(sk)) != sk_len {
|
||||
return nil, errors.New(fmt.Sprintf("nacl.GetSignPubkey() invalid secret key size %d != %d", len(sk), sk_len))
|
||||
}
|
||||
|
||||
skbuff := NewBuffer(sk)
|
||||
defer skbuff.Free()
|
||||
//XXX: hack
|
||||
res := C.crypto_sign_seed_keypair(pkbuff.uchar(), skbuff.uchar(), skbuff.uchar())
|
||||
|
||||
if res != 0 {
|
||||
return nil, errors.New(fmt.Sprintf("nacl.GetSignPubkey() failed to get public key from secret key: %d", res))
|
||||
}
|
||||
|
||||
return pkbuff.Bytes(), nil
|
||||
pk_len := C.crypto_sign_publickeybytes()
|
||||
pkbuff := malloc(pk_len)
|
||||
defer pkbuff.Free()
|
||||
|
||||
skbuff := NewBuffer(sk)
|
||||
defer skbuff.Free()
|
||||
//XXX: hack
|
||||
res := C.crypto_sign_seed_keypair(pkbuff.uchar(), skbuff.uchar(), skbuff.uchar())
|
||||
|
||||
if res != 0 {
|
||||
return nil, errors.New(fmt.Sprintf("nacl.GetSignPubkey() failed to get public key from secret key: %d", res))
|
||||
}
|
||||
|
||||
return pkbuff.Bytes(), nil
|
||||
}
|
||||
|
||||
// make keypair from seed
|
||||
func LoadSignKey(seed []byte) *KeyPair {
|
||||
seed_len := C.crypto_sign_seedbytes()
|
||||
if C.size_t(len(seed)) != seed_len {
|
||||
return nil
|
||||
}
|
||||
seedbuff := NewBuffer(seed)
|
||||
defer seedbuff.Free()
|
||||
pk_len := C.crypto_sign_publickeybytes()
|
||||
sk_len := C.crypto_sign_secretkeybytes()
|
||||
pkbuff := malloc(pk_len)
|
||||
skbuff := malloc(sk_len)
|
||||
res := C.crypto_sign_seed_keypair(pkbuff.uchar(), skbuff.uchar(), seedbuff.uchar())
|
||||
if res != 0 {
|
||||
pkbuff.Free()
|
||||
skbuff.Free()
|
||||
return nil
|
||||
}
|
||||
return &KeyPair{pkbuff, skbuff}
|
||||
seed_len := C.crypto_sign_seedbytes()
|
||||
if C.size_t(len(seed)) != seed_len {
|
||||
panic(fmt.Sprintf("Bad seed length %d bytes", len(seed)))
|
||||
}
|
||||
seedbuff := NewBuffer(seed)
|
||||
defer seedbuff.Free()
|
||||
pk_len := C.crypto_sign_publickeybytes()
|
||||
sk_len := C.crypto_sign_secretkeybytes()
|
||||
pkbuff := malloc(pk_len)
|
||||
skbuff := malloc(sk_len)
|
||||
res := C.crypto_sign_seed_keypair(pkbuff.uchar(), skbuff.uchar(), seedbuff.uchar())
|
||||
if res != 0 {
|
||||
pkbuff.Free()
|
||||
skbuff.Free()
|
||||
return nil
|
||||
}
|
||||
return &KeyPair{pkbuff, skbuff}
|
||||
}
|
||||
|
||||
func GenBoxKeypair() *KeyPair {
|
||||
sk_len := C.crypto_box_secretkeybytes()
|
||||
sk := malloc(sk_len)
|
||||
pk_len := C.crypto_box_publickeybytes()
|
||||
pk := malloc(pk_len)
|
||||
res := C.crypto_box_keypair(pk.uchar(), sk.uchar())
|
||||
if res == 0 {
|
||||
return &KeyPair{pk,sk}
|
||||
}
|
||||
pk.Free()
|
||||
sk.Free()
|
||||
return nil
|
||||
sk_len := C.crypto_box_secretkeybytes()
|
||||
sk := malloc(sk_len)
|
||||
pk_len := C.crypto_box_publickeybytes()
|
||||
pk := malloc(pk_len)
|
||||
res := C.crypto_box_keypair(pk.uchar(), sk.uchar())
|
||||
if res == 0 {
|
||||
return &KeyPair{pk, sk}
|
||||
}
|
||||
pk.Free()
|
||||
sk.Free()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
// get public key from secret key
|
||||
func GetBoxPubkey(sk []byte) []byte {
|
||||
sk_len := C.crypto_box_seedbytes()
|
||||
if C.size_t(len(sk)) != sk_len {
|
||||
return nil
|
||||
}
|
||||
|
||||
pk_len := C.crypto_box_publickeybytes()
|
||||
pkbuff := malloc(pk_len)
|
||||
defer pkbuff.Free()
|
||||
sk_len := C.crypto_box_seedbytes()
|
||||
if C.size_t(len(sk)) != sk_len {
|
||||
return nil
|
||||
}
|
||||
|
||||
skbuff := NewBuffer(sk)
|
||||
defer skbuff.Free()
|
||||
pk_len := C.crypto_box_publickeybytes()
|
||||
pkbuff := malloc(pk_len)
|
||||
defer pkbuff.Free()
|
||||
|
||||
// compute the public key
|
||||
C.crypto_scalarmult_base(pkbuff.uchar(), skbuff.uchar())
|
||||
|
||||
return pkbuff.Bytes()
|
||||
skbuff := NewBuffer(sk)
|
||||
defer skbuff.Free()
|
||||
|
||||
// compute the public key
|
||||
C.crypto_scalarmult_base(pkbuff.uchar(), skbuff.uchar())
|
||||
|
||||
return pkbuff.Bytes()
|
||||
}
|
||||
|
||||
// load keypair from secret key
|
||||
func LoadBoxKey(sk []byte) *KeyPair {
|
||||
pk := GetBoxPubkey(sk)
|
||||
if pk == nil {
|
||||
return nil
|
||||
}
|
||||
pkbuff := NewBuffer(pk)
|
||||
skbuff := NewBuffer(sk)
|
||||
return &KeyPair{pkbuff, skbuff}
|
||||
pk := GetBoxPubkey(sk)
|
||||
if pk == nil {
|
||||
return nil
|
||||
}
|
||||
pkbuff := NewBuffer(pk)
|
||||
skbuff := NewBuffer(sk)
|
||||
return &KeyPair{pkbuff, skbuff}
|
||||
}
|
||||
|
||||
// make keypair from seed
|
||||
func SeedBoxKey(seed []byte) *KeyPair {
|
||||
seed_len := C.crypto_box_seedbytes()
|
||||
if C.size_t(len(seed)) != seed_len {
|
||||
return nil
|
||||
}
|
||||
seedbuff := NewBuffer(seed)
|
||||
defer seedbuff.Free()
|
||||
pk_len := C.crypto_box_publickeybytes()
|
||||
sk_len := C.crypto_box_secretkeybytes()
|
||||
pkbuff := malloc(pk_len)
|
||||
skbuff := malloc(sk_len)
|
||||
res := C.crypto_box_seed_keypair(pkbuff.uchar(), skbuff.uchar(), seedbuff.uchar())
|
||||
if res != 0 {
|
||||
pkbuff.Free()
|
||||
skbuff.Free()
|
||||
return nil
|
||||
}
|
||||
return &KeyPair{pkbuff, skbuff}
|
||||
seed_len := C.crypto_box_seedbytes()
|
||||
if C.size_t(len(seed)) != seed_len {
|
||||
return nil
|
||||
}
|
||||
seedbuff := NewBuffer(seed)
|
||||
defer seedbuff.Free()
|
||||
pk_len := C.crypto_box_publickeybytes()
|
||||
sk_len := C.crypto_box_secretkeybytes()
|
||||
pkbuff := malloc(pk_len)
|
||||
skbuff := malloc(sk_len)
|
||||
res := C.crypto_box_seed_keypair(pkbuff.uchar(), skbuff.uchar(), seedbuff.uchar())
|
||||
if res != 0 {
|
||||
pkbuff.Free()
|
||||
skbuff.Free()
|
||||
return nil
|
||||
}
|
||||
return &KeyPair{pkbuff, skbuff}
|
||||
}
|
||||
|
||||
func (self *KeyPair) String() string {
|
||||
return fmt.Sprintf("pk=%s sk=%s", hex.EncodeToString(self.pk.Data()), hex.EncodeToString(self.sk.Data()))
|
||||
return fmt.Sprintf("pk=%s sk=%s", hex.EncodeToString(self.pk.Data()), hex.EncodeToString(self.sk.Data()))
|
||||
}
|
||||
|
||||
func CryptoSignPublicLen() int {
|
||||
return int(C.crypto_sign_publickeybytes())
|
||||
return int(C.crypto_sign_publickeybytes())
|
||||
}
|
||||
|
||||
|
||||
func CryptoSignSecretLen() int {
|
||||
return int(C.crypto_sign_secretkeybytes())
|
||||
return int(C.crypto_sign_secretkeybytes())
|
||||
}
|
||||
|
||||
func CryptoSignSeedLen() int {
|
||||
return int(C.crypto_sign_seedbytes())
|
||||
return int(C.crypto_sign_seedbytes())
|
||||
}
|
||||
|
||||
21
contrib/backends/srndv2/src/srnd/vendor/github.com/majestrate/nacl/nacl.go
generated
vendored
21
contrib/backends/srndv2/src/srnd/vendor/github.com/majestrate/nacl/nacl.go
generated
vendored
@@ -7,39 +7,38 @@ package nacl
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"log"
|
||||
"log"
|
||||
)
|
||||
|
||||
// return how many bytes overhead does CryptoBox have
|
||||
func CryptoBoxOverhead() int {
|
||||
return int(C.crypto_box_macbytes())
|
||||
return int(C.crypto_box_macbytes())
|
||||
}
|
||||
|
||||
// size of crypto_box public keys
|
||||
func CryptoBoxPubKeySize() int {
|
||||
return int(C.crypto_box_publickeybytes())
|
||||
return int(C.crypto_box_publickeybytes())
|
||||
}
|
||||
|
||||
// size of crypto_box private keys
|
||||
func CryptoBoxPrivKeySize() int {
|
||||
return int(C.crypto_box_secretkeybytes())
|
||||
return int(C.crypto_box_secretkeybytes())
|
||||
}
|
||||
|
||||
// size of crypto_sign public keys
|
||||
func CryptoSignPubKeySize() int {
|
||||
return int(C.crypto_sign_publickeybytes())
|
||||
return int(C.crypto_sign_publickeybytes())
|
||||
}
|
||||
|
||||
// size of crypto_sign private keys
|
||||
func CryptoSignPrivKeySize() int {
|
||||
return int(C.crypto_sign_secretkeybytes())
|
||||
return int(C.crypto_sign_secretkeybytes())
|
||||
}
|
||||
|
||||
|
||||
// initialize sodium
|
||||
func init() {
|
||||
status := C.sodium_init()
|
||||
if status == -1 {
|
||||
log.Fatalf("failed to initialize libsodium status=%d", status)
|
||||
}
|
||||
status := C.sodium_init()
|
||||
if status == -1 {
|
||||
log.Fatalf("failed to initialize libsodium status=%d", status)
|
||||
}
|
||||
}
|
||||
|
||||
18
contrib/backends/srndv2/src/srnd/vendor/github.com/majestrate/nacl/rand.go
generated
vendored
18
contrib/backends/srndv2/src/srnd/vendor/github.com/majestrate/nacl/rand.go
generated
vendored
@@ -8,17 +8,17 @@ import "C"
|
||||
|
||||
func randbytes(size C.size_t) *Buffer {
|
||||
|
||||
buff := malloc(size)
|
||||
C.randombytes_buf(buff.ptr, size)
|
||||
return buff
|
||||
buff := malloc(size)
|
||||
C.randombytes_buf(buff.ptr, size)
|
||||
return buff
|
||||
|
||||
}
|
||||
|
||||
func RandBytes(size int) []byte {
|
||||
if size > 0 {
|
||||
buff := randbytes(C.size_t(size))
|
||||
defer buff.Free()
|
||||
return buff.Bytes()
|
||||
}
|
||||
return nil
|
||||
if size > 0 {
|
||||
buff := randbytes(C.size_t(size))
|
||||
defer buff.Free()
|
||||
return buff.Bytes()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
86
contrib/backends/srndv2/src/srnd/vendor/github.com/majestrate/nacl/sign.go
generated
vendored
86
contrib/backends/srndv2/src/srnd/vendor/github.com/majestrate/nacl/sign.go
generated
vendored
@@ -6,55 +6,53 @@ package nacl
|
||||
// #include <sodium.h>
|
||||
import "C"
|
||||
|
||||
|
||||
// sign data detached with secret key sk
|
||||
// sign data detached with secret key sk
|
||||
func CryptoSignDetached(msg, sk []byte) []byte {
|
||||
msgbuff := NewBuffer(msg)
|
||||
defer msgbuff.Free()
|
||||
skbuff := NewBuffer(sk)
|
||||
defer skbuff.Free()
|
||||
if skbuff.size != C.crypto_sign_bytes() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// allocate the signature buffer
|
||||
sig := malloc(C.crypto_sign_bytes())
|
||||
defer sig.Free()
|
||||
// compute signature
|
||||
siglen := C.ulonglong(0)
|
||||
res := C.crypto_sign_detached(sig.uchar(), &siglen, msgbuff.uchar(), C.ulonglong(msgbuff.size), skbuff.uchar())
|
||||
if res == 0 && siglen == C.ulonglong(C.crypto_sign_bytes()) {
|
||||
// return copy of signature buffer
|
||||
return sig.Bytes()
|
||||
}
|
||||
// failure to sign
|
||||
return nil
|
||||
}
|
||||
msgbuff := NewBuffer(msg)
|
||||
defer msgbuff.Free()
|
||||
skbuff := NewBuffer(sk)
|
||||
defer skbuff.Free()
|
||||
if skbuff.size != C.crypto_sign_bytes() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// allocate the signature buffer
|
||||
sig := malloc(C.crypto_sign_bytes())
|
||||
defer sig.Free()
|
||||
// compute signature
|
||||
siglen := C.ulonglong(0)
|
||||
res := C.crypto_sign_detached(sig.uchar(), &siglen, msgbuff.uchar(), C.ulonglong(msgbuff.size), skbuff.uchar())
|
||||
if res == 0 && siglen == C.ulonglong(C.crypto_sign_bytes()) {
|
||||
// return copy of signature buffer
|
||||
return sig.Bytes()
|
||||
}
|
||||
// failure to sign
|
||||
return nil
|
||||
}
|
||||
|
||||
// sign data with secret key sk
|
||||
// return detached sig
|
||||
// this uses crypto_sign instead pf crypto_sign_detached
|
||||
func CryptoSignFucky(msg, sk []byte) []byte {
|
||||
msgbuff := NewBuffer(msg)
|
||||
defer msgbuff.Free()
|
||||
skbuff := NewBuffer(sk)
|
||||
defer skbuff.Free()
|
||||
if skbuff.size != C.crypto_sign_bytes() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// allocate the signed message buffer
|
||||
sig := malloc(C.crypto_sign_bytes()+msgbuff.size)
|
||||
defer sig.Free()
|
||||
// compute signature
|
||||
siglen := C.ulonglong(0)
|
||||
res := C.crypto_sign(sig.uchar(), &siglen, msgbuff.uchar(), C.ulonglong(msgbuff.size), skbuff.uchar())
|
||||
if res == 0 {
|
||||
// return copy of signature inside the signed message
|
||||
offset := int(C.crypto_sign_bytes())
|
||||
return sig.Bytes()[:offset]
|
||||
}
|
||||
// failure to sign
|
||||
return nil
|
||||
msgbuff := NewBuffer(msg)
|
||||
defer msgbuff.Free()
|
||||
skbuff := NewBuffer(sk)
|
||||
defer skbuff.Free()
|
||||
if skbuff.size != C.crypto_sign_bytes() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// allocate the signed message buffer
|
||||
sig := malloc(C.crypto_sign_bytes() + msgbuff.size)
|
||||
defer sig.Free()
|
||||
// compute signature
|
||||
siglen := C.ulonglong(0)
|
||||
res := C.crypto_sign(sig.uchar(), &siglen, msgbuff.uchar(), C.ulonglong(msgbuff.size), skbuff.uchar())
|
||||
if res == 0 {
|
||||
// return copy of signature inside the signed message
|
||||
offset := int(C.crypto_sign_bytes())
|
||||
return sig.Bytes()[:offset]
|
||||
}
|
||||
// failure to sign
|
||||
return nil
|
||||
}
|
||||
|
||||
451
contrib/backends/srndv2/src/srnd/vendor/github.com/majestrate/nacl/stream.go
generated
vendored
451
contrib/backends/srndv2/src/srnd/vendor/github.com/majestrate/nacl/stream.go
generated
vendored
@@ -1,15 +1,14 @@
|
||||
package nacl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TOY encrypted authenticated stream protocol like tls
|
||||
|
||||
// TOY encrypted authenticated stream protocol like tls
|
||||
|
||||
var BadHandshake = errors.New("Bad handshake")
|
||||
var ShortWrite = errors.New("short write")
|
||||
@@ -23,106 +22,106 @@ const DefaultMTU = 512
|
||||
// provides an authenticated encrypted stream
|
||||
// this is a TOY
|
||||
type CryptoStream struct {
|
||||
// underlying stream to write on
|
||||
stream io.ReadWriteCloser
|
||||
// secret key seed
|
||||
key *KeyPair
|
||||
// public key of who we expect on the other end
|
||||
remote_pk []byte
|
||||
tx_nonce []byte
|
||||
rx_nonce []byte
|
||||
// box size
|
||||
mtu int
|
||||
// underlying stream to write on
|
||||
stream io.ReadWriteCloser
|
||||
// secret key seed
|
||||
key *KeyPair
|
||||
// public key of who we expect on the other end
|
||||
remote_pk []byte
|
||||
tx_nonce []byte
|
||||
rx_nonce []byte
|
||||
// box size
|
||||
mtu int
|
||||
}
|
||||
|
||||
func (cs *CryptoStream) Close() (err error) {
|
||||
if cs.key != nil {
|
||||
cs.key.Free()
|
||||
cs.key = nil
|
||||
}
|
||||
return cs.stream.Close()
|
||||
if cs.key != nil {
|
||||
cs.key.Free()
|
||||
cs.key = nil
|
||||
}
|
||||
return cs.stream.Close()
|
||||
}
|
||||
|
||||
// implements io.Writer
|
||||
func (cs *CryptoStream) Write(data []byte) (n int, err error) {
|
||||
// let's split it up
|
||||
for n < len(data) && err == nil {
|
||||
if n + cs.mtu < len(data) {
|
||||
err = cs.writeSegment(data[n:n+cs.mtu])
|
||||
n += cs.mtu
|
||||
} else {
|
||||
err = cs.writeSegment(data[n:])
|
||||
if err == nil {
|
||||
n = len(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
// let's split it up
|
||||
for n < len(data) && err == nil {
|
||||
if n+cs.mtu < len(data) {
|
||||
err = cs.writeSegment(data[n : n+cs.mtu])
|
||||
n += cs.mtu
|
||||
} else {
|
||||
err = cs.writeSegment(data[n:])
|
||||
if err == nil {
|
||||
n = len(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cs *CryptoStream) public() (p []byte) {
|
||||
p = cs.key.Public()
|
||||
return
|
||||
p = cs.key.Public()
|
||||
return
|
||||
}
|
||||
|
||||
func (cs *CryptoStream) secret() (s []byte) {
|
||||
s = cs.key.Secret()
|
||||
return
|
||||
s = cs.key.Secret()
|
||||
return
|
||||
}
|
||||
|
||||
// read 1 segment
|
||||
func (cs *CryptoStream) readSegment() (s []byte, err error) {
|
||||
var stream_read int
|
||||
var seg []byte
|
||||
nl := NounceLen()
|
||||
msg := make([]byte, cs.mtu + nl)
|
||||
stream_read, err = cs.stream.Read(msg)
|
||||
seg, err = CryptoBoxOpen(msg[:stream_read], cs.rx_nonce, cs.secret(), cs.remote_pk)
|
||||
if err == nil {
|
||||
copy(cs.rx_nonce, seg[:nl])
|
||||
s = seg[nl:]
|
||||
}
|
||||
return
|
||||
var stream_read int
|
||||
var seg []byte
|
||||
nl := NounceLen()
|
||||
msg := make([]byte, cs.mtu+nl)
|
||||
stream_read, err = cs.stream.Read(msg)
|
||||
seg, err = CryptoBoxOpen(msg[:stream_read], cs.rx_nonce, cs.secret(), cs.remote_pk)
|
||||
if err == nil {
|
||||
copy(cs.rx_nonce, seg[:nl])
|
||||
s = seg[nl:]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// write 1 segment encrypted
|
||||
// update nounce
|
||||
func (cs *CryptoStream) writeSegment(data []byte) (err error) {
|
||||
var segment []byte
|
||||
nl := NounceLen()
|
||||
msg := make([]byte, len(data) + nl)
|
||||
// generate next nounce
|
||||
nextNounce := NewBoxNounce()
|
||||
copy(msg, nextNounce)
|
||||
copy(msg[nl:], data)
|
||||
// encrypt segment with current nounce
|
||||
segment, err = CryptoBox(data, cs.tx_nonce, cs.remote_pk, cs.secret())
|
||||
var n int
|
||||
n, err = cs.stream.Write(segment)
|
||||
if n != len(segment) {
|
||||
// short write?
|
||||
err = ShortWrite
|
||||
return
|
||||
}
|
||||
// update nounce
|
||||
copy(cs.tx_nonce, nextNounce)
|
||||
return
|
||||
var segment []byte
|
||||
nl := NounceLen()
|
||||
msg := make([]byte, len(data)+nl)
|
||||
// generate next nounce
|
||||
nextNounce := NewBoxNounce()
|
||||
copy(msg, nextNounce)
|
||||
copy(msg[nl:], data)
|
||||
// encrypt segment with current nounce
|
||||
segment, err = CryptoBox(data, cs.tx_nonce, cs.remote_pk, cs.secret())
|
||||
var n int
|
||||
n, err = cs.stream.Write(segment)
|
||||
if n != len(segment) {
|
||||
// short write?
|
||||
err = ShortWrite
|
||||
return
|
||||
}
|
||||
// update nounce
|
||||
copy(cs.tx_nonce, nextNounce)
|
||||
return
|
||||
}
|
||||
|
||||
// implements io.Reader
|
||||
func (cs *CryptoStream) Read(data []byte) (n int, err error) {
|
||||
var seg []byte
|
||||
seg, err = cs.readSegment()
|
||||
if err == nil {
|
||||
if len(seg) <= len(data) {
|
||||
copy(data, seg)
|
||||
n = len(seg)
|
||||
} else {
|
||||
// too big?
|
||||
err = ShortRead
|
||||
}
|
||||
}
|
||||
return
|
||||
var seg []byte
|
||||
seg, err = cs.readSegment()
|
||||
if err == nil {
|
||||
if len(seg) <= len(data) {
|
||||
copy(data, seg)
|
||||
n = len(seg)
|
||||
} else {
|
||||
// too big?
|
||||
err = ShortRead
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// version 0 protocol magic
|
||||
@@ -130,216 +129,214 @@ var protocol_magic = []byte("BENIS|00")
|
||||
|
||||
// verify that a handshake is signed right and is in the correct format etc
|
||||
func verifyHandshake(hs, pk []byte) (valid bool) {
|
||||
ml := len(protocol_magic)
|
||||
// valid handshake?
|
||||
if bytes.Equal(hs[0:ml], protocol_magic) {
|
||||
// check pk
|
||||
pl := CryptoSignPublicLen()
|
||||
nl := NounceLen()
|
||||
if bytes.Equal(pk, hs[ml:ml+pl]) {
|
||||
// check signature
|
||||
msg := hs[0:ml+pl+nl]
|
||||
sig := hs[ml+pl+nl:]
|
||||
valid = CryptoVerifyFucky(msg, sig, pk)
|
||||
}
|
||||
}
|
||||
return
|
||||
ml := len(protocol_magic)
|
||||
// valid handshake?
|
||||
if bytes.Equal(hs[0:ml], protocol_magic) {
|
||||
// check pk
|
||||
pl := CryptoSignPublicLen()
|
||||
nl := NounceLen()
|
||||
if bytes.Equal(pk, hs[ml:ml+pl]) {
|
||||
// check signature
|
||||
msg := hs[0 : ml+pl+nl]
|
||||
sig := hs[ml+pl+nl:]
|
||||
valid = CryptoVerifyFucky(msg, sig, pk)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// get claimed public key from handshake
|
||||
func getPubkey(hs []byte) (pk []byte) {
|
||||
ml := len(protocol_magic)
|
||||
pl := CryptoSignPublicLen()
|
||||
pk = hs[ml:ml+pl]
|
||||
return
|
||||
ml := len(protocol_magic)
|
||||
pl := CryptoSignPublicLen()
|
||||
pk = hs[ml : ml+pl]
|
||||
return
|
||||
}
|
||||
|
||||
func (cs *CryptoStream) genHandshake() (d []byte) {
|
||||
// protocol magic string version 00
|
||||
// Benis Encrypted Network Information Stream
|
||||
// :-DDDDD meme crypto
|
||||
d = append(d, protocol_magic...)
|
||||
// our public key
|
||||
d = append(d, cs.public()...)
|
||||
// nounce
|
||||
cs.tx_nonce = NewBoxNounce()
|
||||
d = append(d, cs.tx_nonce...)
|
||||
// sign protocol magic string, nounce and pubkey
|
||||
sig := CryptoSignFucky(d, cs.secret())
|
||||
// if sig is nil we'll just die
|
||||
d = append(d, sig...)
|
||||
return
|
||||
// protocol magic string version 00
|
||||
// Benis Encrypted Network Information Stream
|
||||
// :-DDDDD meme crypto
|
||||
d = append(d, protocol_magic...)
|
||||
// our public key
|
||||
d = append(d, cs.public()...)
|
||||
// nounce
|
||||
cs.tx_nonce = NewBoxNounce()
|
||||
d = append(d, cs.tx_nonce...)
|
||||
// sign protocol magic string, nounce and pubkey
|
||||
sig := CryptoSignFucky(d, cs.secret())
|
||||
// if sig is nil we'll just die
|
||||
d = append(d, sig...)
|
||||
return
|
||||
}
|
||||
|
||||
// extract nounce from handshake
|
||||
func getNounce(hs []byte) (n []byte) {
|
||||
ml := len(protocol_magic)
|
||||
pl := CryptoSignPublicLen()
|
||||
nl := NounceLen()
|
||||
n = hs[ml+pl:ml+pl+nl]
|
||||
return
|
||||
ml := len(protocol_magic)
|
||||
pl := CryptoSignPublicLen()
|
||||
nl := NounceLen()
|
||||
n = hs[ml+pl : ml+pl+nl]
|
||||
return
|
||||
}
|
||||
|
||||
// initiate protocol handshake
|
||||
func (cs *CryptoStream) Handshake() (err error) {
|
||||
// send them our info
|
||||
hs := cs.genHandshake()
|
||||
var n int
|
||||
n, err = cs.stream.Write(hs)
|
||||
if n != len(hs) {
|
||||
err = ShortWrite
|
||||
return
|
||||
}
|
||||
// read thier info
|
||||
buff := make([]byte, len(hs))
|
||||
_, err = io.ReadFull(cs.stream, buff)
|
||||
// send them our info
|
||||
hs := cs.genHandshake()
|
||||
var n int
|
||||
n, err = cs.stream.Write(hs)
|
||||
if n != len(hs) {
|
||||
err = ShortWrite
|
||||
return
|
||||
}
|
||||
// read thier info
|
||||
buff := make([]byte, len(hs))
|
||||
_, err = io.ReadFull(cs.stream, buff)
|
||||
|
||||
if cs.remote_pk == nil {
|
||||
// inbound
|
||||
pk := getPubkey(buff)
|
||||
cs.remote_pk = make([]byte, len(pk))
|
||||
copy(cs.remote_pk, pk)
|
||||
}
|
||||
|
||||
if ! verifyHandshake(buff, cs.remote_pk) {
|
||||
// verification failed
|
||||
err = BadHandshake
|
||||
return
|
||||
}
|
||||
cs.rx_nonce = make([]byte, NounceLen())
|
||||
copy(cs.rx_nonce, getNounce(buff))
|
||||
return
|
||||
if cs.remote_pk == nil {
|
||||
// inbound
|
||||
pk := getPubkey(buff)
|
||||
cs.remote_pk = make([]byte, len(pk))
|
||||
copy(cs.remote_pk, pk)
|
||||
}
|
||||
|
||||
if !verifyHandshake(buff, cs.remote_pk) {
|
||||
// verification failed
|
||||
err = BadHandshake
|
||||
return
|
||||
}
|
||||
cs.rx_nonce = make([]byte, NounceLen())
|
||||
copy(cs.rx_nonce, getNounce(buff))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// create a client
|
||||
// create a client
|
||||
func Client(stream io.ReadWriteCloser, local_sk, remote_pk []byte) (c *CryptoStream) {
|
||||
c = &CryptoStream{
|
||||
stream: stream,
|
||||
mtu: DefaultMTU,
|
||||
}
|
||||
c.remote_pk = make([]byte, len(remote_pk))
|
||||
copy(c.remote_pk, remote_pk)
|
||||
c.key = LoadSignKey(local_sk)
|
||||
if c.key == nil {
|
||||
return nil
|
||||
}
|
||||
return c
|
||||
c = &CryptoStream{
|
||||
stream: stream,
|
||||
mtu: DefaultMTU,
|
||||
}
|
||||
c.remote_pk = make([]byte, len(remote_pk))
|
||||
copy(c.remote_pk, remote_pk)
|
||||
c.key = LoadSignKey(local_sk)
|
||||
if c.key == nil {
|
||||
return nil
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
|
||||
type CryptoConn struct {
|
||||
stream *CryptoStream
|
||||
conn net.Conn
|
||||
stream *CryptoStream
|
||||
conn net.Conn
|
||||
}
|
||||
|
||||
func (cc *CryptoConn) Close() (err error) {
|
||||
err = cc.stream.Close()
|
||||
return
|
||||
err = cc.stream.Close()
|
||||
return
|
||||
}
|
||||
|
||||
func (cc *CryptoConn) Write(d []byte) (n int, err error) {
|
||||
return cc.stream.Write(d)
|
||||
return cc.stream.Write(d)
|
||||
}
|
||||
|
||||
func (cc *CryptoConn) Read(d []byte) (n int, err error) {
|
||||
return cc.stream.Read(d)
|
||||
return cc.stream.Read(d)
|
||||
}
|
||||
|
||||
func (cc *CryptoConn) LocalAddr() net.Addr {
|
||||
return cc.conn.LocalAddr()
|
||||
return cc.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (cc *CryptoConn) RemoteAddr() net.Addr {
|
||||
return cc.conn.RemoteAddr()
|
||||
return cc.conn.RemoteAddr()
|
||||
}
|
||||
|
||||
func (cc *CryptoConn) SetDeadline(t time.Time) (err error) {
|
||||
return cc.conn.SetDeadline(t)
|
||||
return cc.conn.SetDeadline(t)
|
||||
}
|
||||
|
||||
func (cc *CryptoConn) SetReadDeadline(t time.Time) (err error) {
|
||||
return cc.conn.SetReadDeadline(t)
|
||||
return cc.conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (cc *CryptoConn) SetWriteDeadline(t time.Time) (err error) {
|
||||
return cc.conn.SetWriteDeadline(t)
|
||||
return cc.conn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
type CryptoListener struct {
|
||||
l net.Listener
|
||||
handshake chan net.Conn
|
||||
accepted chan *CryptoConn
|
||||
trust func(pk []byte) bool
|
||||
key *KeyPair
|
||||
l net.Listener
|
||||
handshake chan net.Conn
|
||||
accepted chan *CryptoConn
|
||||
trust func(pk []byte) bool
|
||||
key *KeyPair
|
||||
}
|
||||
|
||||
func (cl *CryptoListener) Close() (err error) {
|
||||
err = cl.l.Close()
|
||||
close(cl.accepted)
|
||||
close(cl.handshake)
|
||||
cl.key.Free()
|
||||
cl.key = nil
|
||||
return
|
||||
err = cl.l.Close()
|
||||
close(cl.accepted)
|
||||
close(cl.handshake)
|
||||
cl.key.Free()
|
||||
cl.key = nil
|
||||
return
|
||||
}
|
||||
|
||||
func (cl *CryptoListener) acceptInbound() {
|
||||
for {
|
||||
c, err := cl.l.Accept()
|
||||
if err == nil {
|
||||
cl.handshake <- c
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
for {
|
||||
c, err := cl.l.Accept()
|
||||
if err == nil {
|
||||
cl.handshake <- c
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (cl *CryptoListener) runChans() {
|
||||
for {
|
||||
select {
|
||||
case c := <- cl.handshake:
|
||||
go func(){
|
||||
s := &CryptoStream{
|
||||
stream: c,
|
||||
mtu: DefaultMTU,
|
||||
key: cl.key,
|
||||
}
|
||||
err := s.Handshake()
|
||||
if err == nil {
|
||||
// we gud handshake was okay
|
||||
if cl.trust(s.remote_pk) {
|
||||
// the key is trusted okay
|
||||
cl.accepted <- &CryptoConn{stream: s, conn: c}
|
||||
} else {
|
||||
// not trusted, close connection
|
||||
s.Close()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case c := <-cl.handshake:
|
||||
go func() {
|
||||
s := &CryptoStream{
|
||||
stream: c,
|
||||
mtu: DefaultMTU,
|
||||
key: cl.key,
|
||||
}
|
||||
err := s.Handshake()
|
||||
if err == nil {
|
||||
// we gud handshake was okay
|
||||
if cl.trust(s.remote_pk) {
|
||||
// the key is trusted okay
|
||||
cl.accepted <- &CryptoConn{stream: s, conn: c}
|
||||
} else {
|
||||
// not trusted, close connection
|
||||
s.Close()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// accept inbound authenticated and trusted connections
|
||||
func (cl *CryptoListener) Accept() (c net.Conn, err error) {
|
||||
var ok bool
|
||||
c, ok = <- cl.accepted
|
||||
if ! ok {
|
||||
err = Closed
|
||||
}
|
||||
return
|
||||
var ok bool
|
||||
c, ok = <-cl.accepted
|
||||
if !ok {
|
||||
err = Closed
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// create a listener
|
||||
func Server(l net.Listener, local_sk []byte, trust func(pk []byte) bool) (s *CryptoListener) {
|
||||
s = &CryptoListener{
|
||||
l: l,
|
||||
trust: trust,
|
||||
handshake: make(chan net.Conn),
|
||||
accepted: make(chan *CryptoConn),
|
||||
}
|
||||
s.key = LoadSignKey(local_sk)
|
||||
go s.runChans()
|
||||
go s.acceptInbound()
|
||||
return
|
||||
s = &CryptoListener{
|
||||
l: l,
|
||||
trust: trust,
|
||||
handshake: make(chan net.Conn),
|
||||
accepted: make(chan *CryptoConn),
|
||||
}
|
||||
s.key = LoadSignKey(local_sk)
|
||||
go s.runChans()
|
||||
go s.acceptInbound()
|
||||
return
|
||||
}
|
||||
|
||||
63
contrib/backends/srndv2/src/srnd/vendor/github.com/majestrate/nacl/verfiy.go
generated
vendored
63
contrib/backends/srndv2/src/srnd/vendor/github.com/majestrate/nacl/verfiy.go
generated
vendored
@@ -6,49 +6,48 @@ package nacl
|
||||
// #include <sodium.h>
|
||||
import "C"
|
||||
|
||||
|
||||
// verify a fucky detached sig
|
||||
func CryptoVerifyFucky(msg, sig, pk []byte) bool {
|
||||
var smsg []byte
|
||||
smsg = append(smsg, sig...)
|
||||
smsg = append(smsg, msg...)
|
||||
return CryptoVerify(smsg, pk)
|
||||
var smsg []byte
|
||||
smsg = append(smsg, sig...)
|
||||
smsg = append(smsg, msg...)
|
||||
return CryptoVerify(smsg, pk)
|
||||
}
|
||||
|
||||
// verify a signed message
|
||||
func CryptoVerify(smsg, pk []byte) bool {
|
||||
smsg_buff := NewBuffer(smsg)
|
||||
defer smsg_buff.Free()
|
||||
pk_buff := NewBuffer(pk)
|
||||
defer pk_buff.Free()
|
||||
smsg_buff := NewBuffer(smsg)
|
||||
defer smsg_buff.Free()
|
||||
pk_buff := NewBuffer(pk)
|
||||
defer pk_buff.Free()
|
||||
|
||||
if pk_buff.size != C.crypto_sign_publickeybytes() {
|
||||
return false
|
||||
}
|
||||
mlen := C.ulonglong(0)
|
||||
msg := malloc(C.size_t(len(smsg)))
|
||||
defer msg.Free()
|
||||
smlen := C.ulonglong(smsg_buff.size)
|
||||
return C.crypto_sign_open(msg.uchar(), &mlen, smsg_buff.uchar(), smlen, pk_buff.uchar()) != -1
|
||||
if pk_buff.size != C.crypto_sign_publickeybytes() {
|
||||
return false
|
||||
}
|
||||
mlen := C.ulonglong(0)
|
||||
msg := malloc(C.size_t(len(smsg)))
|
||||
defer msg.Free()
|
||||
smlen := C.ulonglong(smsg_buff.size)
|
||||
return C.crypto_sign_open(msg.uchar(), &mlen, smsg_buff.uchar(), smlen, pk_buff.uchar()) != -1
|
||||
}
|
||||
|
||||
// verfiy a detached signature
|
||||
// return true on valid otherwise false
|
||||
func CryptoVerifyDetached(msg, sig, pk []byte) bool {
|
||||
msg_buff := NewBuffer(msg)
|
||||
defer msg_buff.Free()
|
||||
sig_buff := NewBuffer(sig)
|
||||
defer sig_buff.Free()
|
||||
pk_buff := NewBuffer(pk)
|
||||
defer pk_buff.Free()
|
||||
msg_buff := NewBuffer(msg)
|
||||
defer msg_buff.Free()
|
||||
sig_buff := NewBuffer(sig)
|
||||
defer sig_buff.Free()
|
||||
pk_buff := NewBuffer(pk)
|
||||
defer pk_buff.Free()
|
||||
|
||||
if pk_buff.size != C.crypto_sign_publickeybytes() {
|
||||
return false
|
||||
}
|
||||
|
||||
// invalid sig size
|
||||
if sig_buff.size != C.crypto_sign_bytes() {
|
||||
return false
|
||||
}
|
||||
return C.crypto_sign_verify_detached(sig_buff.uchar(), msg_buff.uchar(), C.ulonglong(len(msg)), pk_buff.uchar()) == 0
|
||||
if pk_buff.size != C.crypto_sign_publickeybytes() {
|
||||
return false
|
||||
}
|
||||
|
||||
// invalid sig size
|
||||
if sig_buff.size != C.crypto_sign_bytes() {
|
||||
return false
|
||||
}
|
||||
return C.crypto_sign_verify_detached(sig_buff.uchar(), msg_buff.uchar(), C.ulonglong(len(msg)), pk_buff.uchar()) == 0
|
||||
}
|
||||
|
||||
8
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/const_amd64.h
generated
vendored
Normal file
8
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/const_amd64.h
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This code was translated into a form compatible with 6a from the public
|
||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
|
||||
|
||||
#define REDMASK51 0x0007FFFFFFFFFFFF
|
||||
20
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/const_amd64.s
generated
vendored
Normal file
20
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/const_amd64.s
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This code was translated into a form compatible with 6a from the public
|
||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
// These constants cannot be encoded in non-MOVQ immediates.
|
||||
// We access them directly from memory instead.
|
||||
|
||||
DATA ·_121666_213(SB)/8, $996687872
|
||||
GLOBL ·_121666_213(SB), 8, $8
|
||||
|
||||
DATA ·_2P0(SB)/8, $0xFFFFFFFFFFFDA
|
||||
GLOBL ·_2P0(SB), 8, $8
|
||||
|
||||
DATA ·_2P1234(SB)/8, $0xFFFFFFFFFFFFE
|
||||
GLOBL ·_2P1234(SB), 8, $8
|
||||
65
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
generated
vendored
Normal file
65
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
// func cswap(inout *[4][5]uint64, v uint64)
|
||||
TEXT ·cswap(SB),7,$0
|
||||
MOVQ inout+0(FP),DI
|
||||
MOVQ v+8(FP),SI
|
||||
|
||||
SUBQ $1, SI
|
||||
NOTQ SI
|
||||
MOVQ SI, X15
|
||||
PSHUFD $0x44, X15, X15
|
||||
|
||||
MOVOU 0(DI), X0
|
||||
MOVOU 16(DI), X2
|
||||
MOVOU 32(DI), X4
|
||||
MOVOU 48(DI), X6
|
||||
MOVOU 64(DI), X8
|
||||
MOVOU 80(DI), X1
|
||||
MOVOU 96(DI), X3
|
||||
MOVOU 112(DI), X5
|
||||
MOVOU 128(DI), X7
|
||||
MOVOU 144(DI), X9
|
||||
|
||||
MOVO X1, X10
|
||||
MOVO X3, X11
|
||||
MOVO X5, X12
|
||||
MOVO X7, X13
|
||||
MOVO X9, X14
|
||||
|
||||
PXOR X0, X10
|
||||
PXOR X2, X11
|
||||
PXOR X4, X12
|
||||
PXOR X6, X13
|
||||
PXOR X8, X14
|
||||
PAND X15, X10
|
||||
PAND X15, X11
|
||||
PAND X15, X12
|
||||
PAND X15, X13
|
||||
PAND X15, X14
|
||||
PXOR X10, X0
|
||||
PXOR X10, X1
|
||||
PXOR X11, X2
|
||||
PXOR X11, X3
|
||||
PXOR X12, X4
|
||||
PXOR X12, X5
|
||||
PXOR X13, X6
|
||||
PXOR X13, X7
|
||||
PXOR X14, X8
|
||||
PXOR X14, X9
|
||||
|
||||
MOVOU X0, 0(DI)
|
||||
MOVOU X2, 16(DI)
|
||||
MOVOU X4, 32(DI)
|
||||
MOVOU X6, 48(DI)
|
||||
MOVOU X8, 64(DI)
|
||||
MOVOU X1, 80(DI)
|
||||
MOVOU X3, 96(DI)
|
||||
MOVOU X5, 112(DI)
|
||||
MOVOU X7, 128(DI)
|
||||
MOVOU X9, 144(DI)
|
||||
RET
|
||||
834
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/curve25519.go
generated
vendored
Normal file
834
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/curve25519.go
generated
vendored
Normal file
@@ -0,0 +1,834 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// We have a implementation in amd64 assembly so this code is only run on
|
||||
// non-amd64 platforms. The amd64 assembly does not support gccgo.
|
||||
// +build !amd64 gccgo appengine
|
||||
|
||||
package curve25519
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// This code is a port of the public domain, "ref10" implementation of
|
||||
// curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
|
||||
|
||||
// fieldElement represents an element of the field GF(2^255 - 19). An element
|
||||
// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
|
||||
// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
|
||||
// context.
|
||||
type fieldElement [10]int32
|
||||
|
||||
func feZero(fe *fieldElement) {
|
||||
for i := range fe {
|
||||
fe[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
func feOne(fe *fieldElement) {
|
||||
feZero(fe)
|
||||
fe[0] = 1
|
||||
}
|
||||
|
||||
func feAdd(dst, a, b *fieldElement) {
|
||||
for i := range dst {
|
||||
dst[i] = a[i] + b[i]
|
||||
}
|
||||
}
|
||||
|
||||
func feSub(dst, a, b *fieldElement) {
|
||||
for i := range dst {
|
||||
dst[i] = a[i] - b[i]
|
||||
}
|
||||
}
|
||||
|
||||
func feCopy(dst, src *fieldElement) {
|
||||
for i := range dst {
|
||||
dst[i] = src[i]
|
||||
}
|
||||
}
|
||||
|
||||
// feCSwap replaces (f,g) with (g,f) if b == 1; replaces (f,g) with (f,g) if b == 0.
|
||||
//
|
||||
// Preconditions: b in {0,1}.
|
||||
func feCSwap(f, g *fieldElement, b int32) {
|
||||
b = -b
|
||||
for i := range f {
|
||||
t := b & (f[i] ^ g[i])
|
||||
f[i] ^= t
|
||||
g[i] ^= t
|
||||
}
|
||||
}
|
||||
|
||||
// load3 reads a 24-bit, little-endian value from in.
|
||||
func load3(in []byte) int64 {
|
||||
var r int64
|
||||
r = int64(in[0])
|
||||
r |= int64(in[1]) << 8
|
||||
r |= int64(in[2]) << 16
|
||||
return r
|
||||
}
|
||||
|
||||
// load4 reads a 32-bit, little-endian value from in.
|
||||
func load4(in []byte) int64 {
|
||||
return int64(binary.LittleEndian.Uint32(in))
|
||||
}
|
||||
|
||||
func feFromBytes(dst *fieldElement, src *[32]byte) {
|
||||
h0 := load4(src[:])
|
||||
h1 := load3(src[4:]) << 6
|
||||
h2 := load3(src[7:]) << 5
|
||||
h3 := load3(src[10:]) << 3
|
||||
h4 := load3(src[13:]) << 2
|
||||
h5 := load4(src[16:])
|
||||
h6 := load3(src[20:]) << 7
|
||||
h7 := load3(src[23:]) << 5
|
||||
h8 := load3(src[26:]) << 4
|
||||
h9 := load3(src[29:]) << 2
|
||||
|
||||
var carry [10]int64
|
||||
carry[9] = (h9 + 1<<24) >> 25
|
||||
h0 += carry[9] * 19
|
||||
h9 -= carry[9] << 25
|
||||
carry[1] = (h1 + 1<<24) >> 25
|
||||
h2 += carry[1]
|
||||
h1 -= carry[1] << 25
|
||||
carry[3] = (h3 + 1<<24) >> 25
|
||||
h4 += carry[3]
|
||||
h3 -= carry[3] << 25
|
||||
carry[5] = (h5 + 1<<24) >> 25
|
||||
h6 += carry[5]
|
||||
h5 -= carry[5] << 25
|
||||
carry[7] = (h7 + 1<<24) >> 25
|
||||
h8 += carry[7]
|
||||
h7 -= carry[7] << 25
|
||||
|
||||
carry[0] = (h0 + 1<<25) >> 26
|
||||
h1 += carry[0]
|
||||
h0 -= carry[0] << 26
|
||||
carry[2] = (h2 + 1<<25) >> 26
|
||||
h3 += carry[2]
|
||||
h2 -= carry[2] << 26
|
||||
carry[4] = (h4 + 1<<25) >> 26
|
||||
h5 += carry[4]
|
||||
h4 -= carry[4] << 26
|
||||
carry[6] = (h6 + 1<<25) >> 26
|
||||
h7 += carry[6]
|
||||
h6 -= carry[6] << 26
|
||||
carry[8] = (h8 + 1<<25) >> 26
|
||||
h9 += carry[8]
|
||||
h8 -= carry[8] << 26
|
||||
|
||||
dst[0] = int32(h0)
|
||||
dst[1] = int32(h1)
|
||||
dst[2] = int32(h2)
|
||||
dst[3] = int32(h3)
|
||||
dst[4] = int32(h4)
|
||||
dst[5] = int32(h5)
|
||||
dst[6] = int32(h6)
|
||||
dst[7] = int32(h7)
|
||||
dst[8] = int32(h8)
|
||||
dst[9] = int32(h9)
|
||||
}
|
||||
|
||||
// feToBytes marshals h to s.
|
||||
// Preconditions:
|
||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
||||
//
|
||||
// Write p=2^255-19; q=floor(h/p).
|
||||
// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
|
||||
//
|
||||
// Proof:
|
||||
// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
|
||||
// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4.
|
||||
//
|
||||
// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
|
||||
// Then 0<y<1.
|
||||
//
|
||||
// Write r=h-pq.
|
||||
// Have 0<=r<=p-1=2^255-20.
|
||||
// Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
|
||||
//
|
||||
// Write x=r+19(2^-255)r+y.
|
||||
// Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
|
||||
//
|
||||
// Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
|
||||
// so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
|
||||
func feToBytes(s *[32]byte, h *fieldElement) {
|
||||
var carry [10]int32
|
||||
|
||||
q := (19*h[9] + (1 << 24)) >> 25
|
||||
q = (h[0] + q) >> 26
|
||||
q = (h[1] + q) >> 25
|
||||
q = (h[2] + q) >> 26
|
||||
q = (h[3] + q) >> 25
|
||||
q = (h[4] + q) >> 26
|
||||
q = (h[5] + q) >> 25
|
||||
q = (h[6] + q) >> 26
|
||||
q = (h[7] + q) >> 25
|
||||
q = (h[8] + q) >> 26
|
||||
q = (h[9] + q) >> 25
|
||||
|
||||
// Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20.
|
||||
h[0] += 19 * q
|
||||
// Goal: Output h-2^255 q, which is between 0 and 2^255-20.
|
||||
|
||||
carry[0] = h[0] >> 26
|
||||
h[1] += carry[0]
|
||||
h[0] -= carry[0] << 26
|
||||
carry[1] = h[1] >> 25
|
||||
h[2] += carry[1]
|
||||
h[1] -= carry[1] << 25
|
||||
carry[2] = h[2] >> 26
|
||||
h[3] += carry[2]
|
||||
h[2] -= carry[2] << 26
|
||||
carry[3] = h[3] >> 25
|
||||
h[4] += carry[3]
|
||||
h[3] -= carry[3] << 25
|
||||
carry[4] = h[4] >> 26
|
||||
h[5] += carry[4]
|
||||
h[4] -= carry[4] << 26
|
||||
carry[5] = h[5] >> 25
|
||||
h[6] += carry[5]
|
||||
h[5] -= carry[5] << 25
|
||||
carry[6] = h[6] >> 26
|
||||
h[7] += carry[6]
|
||||
h[6] -= carry[6] << 26
|
||||
carry[7] = h[7] >> 25
|
||||
h[8] += carry[7]
|
||||
h[7] -= carry[7] << 25
|
||||
carry[8] = h[8] >> 26
|
||||
h[9] += carry[8]
|
||||
h[8] -= carry[8] << 26
|
||||
carry[9] = h[9] >> 25
|
||||
h[9] -= carry[9] << 25
|
||||
// h10 = carry9
|
||||
|
||||
// Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
|
||||
// Have h[0]+...+2^230 h[9] between 0 and 2^255-1;
|
||||
// evidently 2^255 h10-2^255 q = 0.
|
||||
// Goal: Output h[0]+...+2^230 h[9].
|
||||
|
||||
s[0] = byte(h[0] >> 0)
|
||||
s[1] = byte(h[0] >> 8)
|
||||
s[2] = byte(h[0] >> 16)
|
||||
s[3] = byte((h[0] >> 24) | (h[1] << 2))
|
||||
s[4] = byte(h[1] >> 6)
|
||||
s[5] = byte(h[1] >> 14)
|
||||
s[6] = byte((h[1] >> 22) | (h[2] << 3))
|
||||
s[7] = byte(h[2] >> 5)
|
||||
s[8] = byte(h[2] >> 13)
|
||||
s[9] = byte((h[2] >> 21) | (h[3] << 5))
|
||||
s[10] = byte(h[3] >> 3)
|
||||
s[11] = byte(h[3] >> 11)
|
||||
s[12] = byte((h[3] >> 19) | (h[4] << 6))
|
||||
s[13] = byte(h[4] >> 2)
|
||||
s[14] = byte(h[4] >> 10)
|
||||
s[15] = byte(h[4] >> 18)
|
||||
s[16] = byte(h[5] >> 0)
|
||||
s[17] = byte(h[5] >> 8)
|
||||
s[18] = byte(h[5] >> 16)
|
||||
s[19] = byte((h[5] >> 24) | (h[6] << 1))
|
||||
s[20] = byte(h[6] >> 7)
|
||||
s[21] = byte(h[6] >> 15)
|
||||
s[22] = byte((h[6] >> 23) | (h[7] << 3))
|
||||
s[23] = byte(h[7] >> 5)
|
||||
s[24] = byte(h[7] >> 13)
|
||||
s[25] = byte((h[7] >> 21) | (h[8] << 4))
|
||||
s[26] = byte(h[8] >> 4)
|
||||
s[27] = byte(h[8] >> 12)
|
||||
s[28] = byte((h[8] >> 20) | (h[9] << 6))
|
||||
s[29] = byte(h[9] >> 2)
|
||||
s[30] = byte(h[9] >> 10)
|
||||
s[31] = byte(h[9] >> 18)
|
||||
}
|
||||
|
||||
// feMul calculates h = f * g
|
||||
// Can overlap h with f or g.
|
||||
//
|
||||
// Preconditions:
|
||||
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
// |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
//
|
||||
// Postconditions:
|
||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
||||
//
|
||||
// Notes on implementation strategy:
|
||||
//
|
||||
// Using schoolbook multiplication.
|
||||
// Karatsuba would save a little in some cost models.
|
||||
//
|
||||
// Most multiplications by 2 and 19 are 32-bit precomputations;
|
||||
// cheaper than 64-bit postcomputations.
|
||||
//
|
||||
// There is one remaining multiplication by 19 in the carry chain;
|
||||
// one *19 precomputation can be merged into this,
|
||||
// but the resulting data flow is considerably less clean.
|
||||
//
|
||||
// There are 12 carries below.
|
||||
// 10 of them are 2-way parallelizable and vectorizable.
|
||||
// Can get away with 11 carries, but then data flow is much deeper.
|
||||
//
|
||||
// With tighter constraints on inputs can squeeze carries into int32.
|
||||
func feMul(h, f, g *fieldElement) {
|
||||
f0 := f[0]
|
||||
f1 := f[1]
|
||||
f2 := f[2]
|
||||
f3 := f[3]
|
||||
f4 := f[4]
|
||||
f5 := f[5]
|
||||
f6 := f[6]
|
||||
f7 := f[7]
|
||||
f8 := f[8]
|
||||
f9 := f[9]
|
||||
g0 := g[0]
|
||||
g1 := g[1]
|
||||
g2 := g[2]
|
||||
g3 := g[3]
|
||||
g4 := g[4]
|
||||
g5 := g[5]
|
||||
g6 := g[6]
|
||||
g7 := g[7]
|
||||
g8 := g[8]
|
||||
g9 := g[9]
|
||||
g1_19 := 19 * g1 // 1.4*2^29
|
||||
g2_19 := 19 * g2 // 1.4*2^30; still ok
|
||||
g3_19 := 19 * g3
|
||||
g4_19 := 19 * g4
|
||||
g5_19 := 19 * g5
|
||||
g6_19 := 19 * g6
|
||||
g7_19 := 19 * g7
|
||||
g8_19 := 19 * g8
|
||||
g9_19 := 19 * g9
|
||||
f1_2 := 2 * f1
|
||||
f3_2 := 2 * f3
|
||||
f5_2 := 2 * f5
|
||||
f7_2 := 2 * f7
|
||||
f9_2 := 2 * f9
|
||||
f0g0 := int64(f0) * int64(g0)
|
||||
f0g1 := int64(f0) * int64(g1)
|
||||
f0g2 := int64(f0) * int64(g2)
|
||||
f0g3 := int64(f0) * int64(g3)
|
||||
f0g4 := int64(f0) * int64(g4)
|
||||
f0g5 := int64(f0) * int64(g5)
|
||||
f0g6 := int64(f0) * int64(g6)
|
||||
f0g7 := int64(f0) * int64(g7)
|
||||
f0g8 := int64(f0) * int64(g8)
|
||||
f0g9 := int64(f0) * int64(g9)
|
||||
f1g0 := int64(f1) * int64(g0)
|
||||
f1g1_2 := int64(f1_2) * int64(g1)
|
||||
f1g2 := int64(f1) * int64(g2)
|
||||
f1g3_2 := int64(f1_2) * int64(g3)
|
||||
f1g4 := int64(f1) * int64(g4)
|
||||
f1g5_2 := int64(f1_2) * int64(g5)
|
||||
f1g6 := int64(f1) * int64(g6)
|
||||
f1g7_2 := int64(f1_2) * int64(g7)
|
||||
f1g8 := int64(f1) * int64(g8)
|
||||
f1g9_38 := int64(f1_2) * int64(g9_19)
|
||||
f2g0 := int64(f2) * int64(g0)
|
||||
f2g1 := int64(f2) * int64(g1)
|
||||
f2g2 := int64(f2) * int64(g2)
|
||||
f2g3 := int64(f2) * int64(g3)
|
||||
f2g4 := int64(f2) * int64(g4)
|
||||
f2g5 := int64(f2) * int64(g5)
|
||||
f2g6 := int64(f2) * int64(g6)
|
||||
f2g7 := int64(f2) * int64(g7)
|
||||
f2g8_19 := int64(f2) * int64(g8_19)
|
||||
f2g9_19 := int64(f2) * int64(g9_19)
|
||||
f3g0 := int64(f3) * int64(g0)
|
||||
f3g1_2 := int64(f3_2) * int64(g1)
|
||||
f3g2 := int64(f3) * int64(g2)
|
||||
f3g3_2 := int64(f3_2) * int64(g3)
|
||||
f3g4 := int64(f3) * int64(g4)
|
||||
f3g5_2 := int64(f3_2) * int64(g5)
|
||||
f3g6 := int64(f3) * int64(g6)
|
||||
f3g7_38 := int64(f3_2) * int64(g7_19)
|
||||
f3g8_19 := int64(f3) * int64(g8_19)
|
||||
f3g9_38 := int64(f3_2) * int64(g9_19)
|
||||
f4g0 := int64(f4) * int64(g0)
|
||||
f4g1 := int64(f4) * int64(g1)
|
||||
f4g2 := int64(f4) * int64(g2)
|
||||
f4g3 := int64(f4) * int64(g3)
|
||||
f4g4 := int64(f4) * int64(g4)
|
||||
f4g5 := int64(f4) * int64(g5)
|
||||
f4g6_19 := int64(f4) * int64(g6_19)
|
||||
f4g7_19 := int64(f4) * int64(g7_19)
|
||||
f4g8_19 := int64(f4) * int64(g8_19)
|
||||
f4g9_19 := int64(f4) * int64(g9_19)
|
||||
f5g0 := int64(f5) * int64(g0)
|
||||
f5g1_2 := int64(f5_2) * int64(g1)
|
||||
f5g2 := int64(f5) * int64(g2)
|
||||
f5g3_2 := int64(f5_2) * int64(g3)
|
||||
f5g4 := int64(f5) * int64(g4)
|
||||
f5g5_38 := int64(f5_2) * int64(g5_19)
|
||||
f5g6_19 := int64(f5) * int64(g6_19)
|
||||
f5g7_38 := int64(f5_2) * int64(g7_19)
|
||||
f5g8_19 := int64(f5) * int64(g8_19)
|
||||
f5g9_38 := int64(f5_2) * int64(g9_19)
|
||||
f6g0 := int64(f6) * int64(g0)
|
||||
f6g1 := int64(f6) * int64(g1)
|
||||
f6g2 := int64(f6) * int64(g2)
|
||||
f6g3 := int64(f6) * int64(g3)
|
||||
f6g4_19 := int64(f6) * int64(g4_19)
|
||||
f6g5_19 := int64(f6) * int64(g5_19)
|
||||
f6g6_19 := int64(f6) * int64(g6_19)
|
||||
f6g7_19 := int64(f6) * int64(g7_19)
|
||||
f6g8_19 := int64(f6) * int64(g8_19)
|
||||
f6g9_19 := int64(f6) * int64(g9_19)
|
||||
f7g0 := int64(f7) * int64(g0)
|
||||
f7g1_2 := int64(f7_2) * int64(g1)
|
||||
f7g2 := int64(f7) * int64(g2)
|
||||
f7g3_38 := int64(f7_2) * int64(g3_19)
|
||||
f7g4_19 := int64(f7) * int64(g4_19)
|
||||
f7g5_38 := int64(f7_2) * int64(g5_19)
|
||||
f7g6_19 := int64(f7) * int64(g6_19)
|
||||
f7g7_38 := int64(f7_2) * int64(g7_19)
|
||||
f7g8_19 := int64(f7) * int64(g8_19)
|
||||
f7g9_38 := int64(f7_2) * int64(g9_19)
|
||||
f8g0 := int64(f8) * int64(g0)
|
||||
f8g1 := int64(f8) * int64(g1)
|
||||
f8g2_19 := int64(f8) * int64(g2_19)
|
||||
f8g3_19 := int64(f8) * int64(g3_19)
|
||||
f8g4_19 := int64(f8) * int64(g4_19)
|
||||
f8g5_19 := int64(f8) * int64(g5_19)
|
||||
f8g6_19 := int64(f8) * int64(g6_19)
|
||||
f8g7_19 := int64(f8) * int64(g7_19)
|
||||
f8g8_19 := int64(f8) * int64(g8_19)
|
||||
f8g9_19 := int64(f8) * int64(g9_19)
|
||||
f9g0 := int64(f9) * int64(g0)
|
||||
f9g1_38 := int64(f9_2) * int64(g1_19)
|
||||
f9g2_19 := int64(f9) * int64(g2_19)
|
||||
f9g3_38 := int64(f9_2) * int64(g3_19)
|
||||
f9g4_19 := int64(f9) * int64(g4_19)
|
||||
f9g5_38 := int64(f9_2) * int64(g5_19)
|
||||
f9g6_19 := int64(f9) * int64(g6_19)
|
||||
f9g7_38 := int64(f9_2) * int64(g7_19)
|
||||
f9g8_19 := int64(f9) * int64(g8_19)
|
||||
f9g9_38 := int64(f9_2) * int64(g9_19)
|
||||
h0 := f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38
|
||||
h1 := f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19
|
||||
h2 := f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38
|
||||
h3 := f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19
|
||||
h4 := f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38
|
||||
h5 := f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19
|
||||
h6 := f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38
|
||||
h7 := f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19
|
||||
h8 := f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38
|
||||
h9 := f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0
|
||||
var carry [10]int64
|
||||
|
||||
// |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38))
|
||||
// i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8
|
||||
// |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19))
|
||||
// i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9
|
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26
|
||||
h1 += carry[0]
|
||||
h0 -= carry[0] << 26
|
||||
carry[4] = (h4 + (1 << 25)) >> 26
|
||||
h5 += carry[4]
|
||||
h4 -= carry[4] << 26
|
||||
// |h0| <= 2^25
|
||||
// |h4| <= 2^25
|
||||
// |h1| <= 1.51*2^58
|
||||
// |h5| <= 1.51*2^58
|
||||
|
||||
carry[1] = (h1 + (1 << 24)) >> 25
|
||||
h2 += carry[1]
|
||||
h1 -= carry[1] << 25
|
||||
carry[5] = (h5 + (1 << 24)) >> 25
|
||||
h6 += carry[5]
|
||||
h5 -= carry[5] << 25
|
||||
// |h1| <= 2^24; from now on fits into int32
|
||||
// |h5| <= 2^24; from now on fits into int32
|
||||
// |h2| <= 1.21*2^59
|
||||
// |h6| <= 1.21*2^59
|
||||
|
||||
carry[2] = (h2 + (1 << 25)) >> 26
|
||||
h3 += carry[2]
|
||||
h2 -= carry[2] << 26
|
||||
carry[6] = (h6 + (1 << 25)) >> 26
|
||||
h7 += carry[6]
|
||||
h6 -= carry[6] << 26
|
||||
// |h2| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h6| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h3| <= 1.51*2^58
|
||||
// |h7| <= 1.51*2^58
|
||||
|
||||
carry[3] = (h3 + (1 << 24)) >> 25
|
||||
h4 += carry[3]
|
||||
h3 -= carry[3] << 25
|
||||
carry[7] = (h7 + (1 << 24)) >> 25
|
||||
h8 += carry[7]
|
||||
h7 -= carry[7] << 25
|
||||
// |h3| <= 2^24; from now on fits into int32 unchanged
|
||||
// |h7| <= 2^24; from now on fits into int32 unchanged
|
||||
// |h4| <= 1.52*2^33
|
||||
// |h8| <= 1.52*2^33
|
||||
|
||||
carry[4] = (h4 + (1 << 25)) >> 26
|
||||
h5 += carry[4]
|
||||
h4 -= carry[4] << 26
|
||||
carry[8] = (h8 + (1 << 25)) >> 26
|
||||
h9 += carry[8]
|
||||
h8 -= carry[8] << 26
|
||||
// |h4| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h8| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h5| <= 1.01*2^24
|
||||
// |h9| <= 1.51*2^58
|
||||
|
||||
carry[9] = (h9 + (1 << 24)) >> 25
|
||||
h0 += carry[9] * 19
|
||||
h9 -= carry[9] << 25
|
||||
// |h9| <= 2^24; from now on fits into int32 unchanged
|
||||
// |h0| <= 1.8*2^37
|
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26
|
||||
h1 += carry[0]
|
||||
h0 -= carry[0] << 26
|
||||
// |h0| <= 2^25; from now on fits into int32 unchanged
|
||||
// |h1| <= 1.01*2^24
|
||||
|
||||
h[0] = int32(h0)
|
||||
h[1] = int32(h1)
|
||||
h[2] = int32(h2)
|
||||
h[3] = int32(h3)
|
||||
h[4] = int32(h4)
|
||||
h[5] = int32(h5)
|
||||
h[6] = int32(h6)
|
||||
h[7] = int32(h7)
|
||||
h[8] = int32(h8)
|
||||
h[9] = int32(h9)
|
||||
}
|
||||
|
||||
// feSquare calculates h = f*f. Can overlap h with f.
|
||||
//
|
||||
// Preconditions:
|
||||
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
//
|
||||
// Postconditions:
|
||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
||||
func feSquare(h, f *fieldElement) {
|
||||
f0 := f[0]
|
||||
f1 := f[1]
|
||||
f2 := f[2]
|
||||
f3 := f[3]
|
||||
f4 := f[4]
|
||||
f5 := f[5]
|
||||
f6 := f[6]
|
||||
f7 := f[7]
|
||||
f8 := f[8]
|
||||
f9 := f[9]
|
||||
f0_2 := 2 * f0
|
||||
f1_2 := 2 * f1
|
||||
f2_2 := 2 * f2
|
||||
f3_2 := 2 * f3
|
||||
f4_2 := 2 * f4
|
||||
f5_2 := 2 * f5
|
||||
f6_2 := 2 * f6
|
||||
f7_2 := 2 * f7
|
||||
f5_38 := 38 * f5 // 1.31*2^30
|
||||
f6_19 := 19 * f6 // 1.31*2^30
|
||||
f7_38 := 38 * f7 // 1.31*2^30
|
||||
f8_19 := 19 * f8 // 1.31*2^30
|
||||
f9_38 := 38 * f9 // 1.31*2^30
|
||||
f0f0 := int64(f0) * int64(f0)
|
||||
f0f1_2 := int64(f0_2) * int64(f1)
|
||||
f0f2_2 := int64(f0_2) * int64(f2)
|
||||
f0f3_2 := int64(f0_2) * int64(f3)
|
||||
f0f4_2 := int64(f0_2) * int64(f4)
|
||||
f0f5_2 := int64(f0_2) * int64(f5)
|
||||
f0f6_2 := int64(f0_2) * int64(f6)
|
||||
f0f7_2 := int64(f0_2) * int64(f7)
|
||||
f0f8_2 := int64(f0_2) * int64(f8)
|
||||
f0f9_2 := int64(f0_2) * int64(f9)
|
||||
f1f1_2 := int64(f1_2) * int64(f1)
|
||||
f1f2_2 := int64(f1_2) * int64(f2)
|
||||
f1f3_4 := int64(f1_2) * int64(f3_2)
|
||||
f1f4_2 := int64(f1_2) * int64(f4)
|
||||
f1f5_4 := int64(f1_2) * int64(f5_2)
|
||||
f1f6_2 := int64(f1_2) * int64(f6)
|
||||
f1f7_4 := int64(f1_2) * int64(f7_2)
|
||||
f1f8_2 := int64(f1_2) * int64(f8)
|
||||
f1f9_76 := int64(f1_2) * int64(f9_38)
|
||||
f2f2 := int64(f2) * int64(f2)
|
||||
f2f3_2 := int64(f2_2) * int64(f3)
|
||||
f2f4_2 := int64(f2_2) * int64(f4)
|
||||
f2f5_2 := int64(f2_2) * int64(f5)
|
||||
f2f6_2 := int64(f2_2) * int64(f6)
|
||||
f2f7_2 := int64(f2_2) * int64(f7)
|
||||
f2f8_38 := int64(f2_2) * int64(f8_19)
|
||||
f2f9_38 := int64(f2) * int64(f9_38)
|
||||
f3f3_2 := int64(f3_2) * int64(f3)
|
||||
f3f4_2 := int64(f3_2) * int64(f4)
|
||||
f3f5_4 := int64(f3_2) * int64(f5_2)
|
||||
f3f6_2 := int64(f3_2) * int64(f6)
|
||||
f3f7_76 := int64(f3_2) * int64(f7_38)
|
||||
f3f8_38 := int64(f3_2) * int64(f8_19)
|
||||
f3f9_76 := int64(f3_2) * int64(f9_38)
|
||||
f4f4 := int64(f4) * int64(f4)
|
||||
f4f5_2 := int64(f4_2) * int64(f5)
|
||||
f4f6_38 := int64(f4_2) * int64(f6_19)
|
||||
f4f7_38 := int64(f4) * int64(f7_38)
|
||||
f4f8_38 := int64(f4_2) * int64(f8_19)
|
||||
f4f9_38 := int64(f4) * int64(f9_38)
|
||||
f5f5_38 := int64(f5) * int64(f5_38)
|
||||
f5f6_38 := int64(f5_2) * int64(f6_19)
|
||||
f5f7_76 := int64(f5_2) * int64(f7_38)
|
||||
f5f8_38 := int64(f5_2) * int64(f8_19)
|
||||
f5f9_76 := int64(f5_2) * int64(f9_38)
|
||||
f6f6_19 := int64(f6) * int64(f6_19)
|
||||
f6f7_38 := int64(f6) * int64(f7_38)
|
||||
f6f8_38 := int64(f6_2) * int64(f8_19)
|
||||
f6f9_38 := int64(f6) * int64(f9_38)
|
||||
f7f7_38 := int64(f7) * int64(f7_38)
|
||||
f7f8_38 := int64(f7_2) * int64(f8_19)
|
||||
f7f9_76 := int64(f7_2) * int64(f9_38)
|
||||
f8f8_19 := int64(f8) * int64(f8_19)
|
||||
f8f9_38 := int64(f8) * int64(f9_38)
|
||||
f9f9_38 := int64(f9) * int64(f9_38)
|
||||
h0 := f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38
|
||||
h1 := f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38
|
||||
h2 := f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19
|
||||
h3 := f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38
|
||||
h4 := f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38
|
||||
h5 := f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38
|
||||
h6 := f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19
|
||||
h7 := f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38
|
||||
h8 := f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38
|
||||
h9 := f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2
|
||||
var carry [10]int64
|
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26
|
||||
h1 += carry[0]
|
||||
h0 -= carry[0] << 26
|
||||
carry[4] = (h4 + (1 << 25)) >> 26
|
||||
h5 += carry[4]
|
||||
h4 -= carry[4] << 26
|
||||
|
||||
carry[1] = (h1 + (1 << 24)) >> 25
|
||||
h2 += carry[1]
|
||||
h1 -= carry[1] << 25
|
||||
carry[5] = (h5 + (1 << 24)) >> 25
|
||||
h6 += carry[5]
|
||||
h5 -= carry[5] << 25
|
||||
|
||||
carry[2] = (h2 + (1 << 25)) >> 26
|
||||
h3 += carry[2]
|
||||
h2 -= carry[2] << 26
|
||||
carry[6] = (h6 + (1 << 25)) >> 26
|
||||
h7 += carry[6]
|
||||
h6 -= carry[6] << 26
|
||||
|
||||
carry[3] = (h3 + (1 << 24)) >> 25
|
||||
h4 += carry[3]
|
||||
h3 -= carry[3] << 25
|
||||
carry[7] = (h7 + (1 << 24)) >> 25
|
||||
h8 += carry[7]
|
||||
h7 -= carry[7] << 25
|
||||
|
||||
carry[4] = (h4 + (1 << 25)) >> 26
|
||||
h5 += carry[4]
|
||||
h4 -= carry[4] << 26
|
||||
carry[8] = (h8 + (1 << 25)) >> 26
|
||||
h9 += carry[8]
|
||||
h8 -= carry[8] << 26
|
||||
|
||||
carry[9] = (h9 + (1 << 24)) >> 25
|
||||
h0 += carry[9] * 19
|
||||
h9 -= carry[9] << 25
|
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26
|
||||
h1 += carry[0]
|
||||
h0 -= carry[0] << 26
|
||||
|
||||
h[0] = int32(h0)
|
||||
h[1] = int32(h1)
|
||||
h[2] = int32(h2)
|
||||
h[3] = int32(h3)
|
||||
h[4] = int32(h4)
|
||||
h[5] = int32(h5)
|
||||
h[6] = int32(h6)
|
||||
h[7] = int32(h7)
|
||||
h[8] = int32(h8)
|
||||
h[9] = int32(h9)
|
||||
}
|
||||
|
||||
// feMul121666 calculates h = f * 121666. Can overlap h with f.
|
||||
//
|
||||
// Preconditions:
|
||||
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
//
|
||||
// Postconditions:
|
||||
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
|
||||
func feMul121666(h, f *fieldElement) {
|
||||
h0 := int64(f[0]) * 121666
|
||||
h1 := int64(f[1]) * 121666
|
||||
h2 := int64(f[2]) * 121666
|
||||
h3 := int64(f[3]) * 121666
|
||||
h4 := int64(f[4]) * 121666
|
||||
h5 := int64(f[5]) * 121666
|
||||
h6 := int64(f[6]) * 121666
|
||||
h7 := int64(f[7]) * 121666
|
||||
h8 := int64(f[8]) * 121666
|
||||
h9 := int64(f[9]) * 121666
|
||||
var carry [10]int64
|
||||
|
||||
carry[9] = (h9 + (1 << 24)) >> 25
|
||||
h0 += carry[9] * 19
|
||||
h9 -= carry[9] << 25
|
||||
carry[1] = (h1 + (1 << 24)) >> 25
|
||||
h2 += carry[1]
|
||||
h1 -= carry[1] << 25
|
||||
carry[3] = (h3 + (1 << 24)) >> 25
|
||||
h4 += carry[3]
|
||||
h3 -= carry[3] << 25
|
||||
carry[5] = (h5 + (1 << 24)) >> 25
|
||||
h6 += carry[5]
|
||||
h5 -= carry[5] << 25
|
||||
carry[7] = (h7 + (1 << 24)) >> 25
|
||||
h8 += carry[7]
|
||||
h7 -= carry[7] << 25
|
||||
|
||||
carry[0] = (h0 + (1 << 25)) >> 26
|
||||
h1 += carry[0]
|
||||
h0 -= carry[0] << 26
|
||||
carry[2] = (h2 + (1 << 25)) >> 26
|
||||
h3 += carry[2]
|
||||
h2 -= carry[2] << 26
|
||||
carry[4] = (h4 + (1 << 25)) >> 26
|
||||
h5 += carry[4]
|
||||
h4 -= carry[4] << 26
|
||||
carry[6] = (h6 + (1 << 25)) >> 26
|
||||
h7 += carry[6]
|
||||
h6 -= carry[6] << 26
|
||||
carry[8] = (h8 + (1 << 25)) >> 26
|
||||
h9 += carry[8]
|
||||
h8 -= carry[8] << 26
|
||||
|
||||
h[0] = int32(h0)
|
||||
h[1] = int32(h1)
|
||||
h[2] = int32(h2)
|
||||
h[3] = int32(h3)
|
||||
h[4] = int32(h4)
|
||||
h[5] = int32(h5)
|
||||
h[6] = int32(h6)
|
||||
h[7] = int32(h7)
|
||||
h[8] = int32(h8)
|
||||
h[9] = int32(h9)
|
||||
}
|
||||
|
||||
// feInvert sets out = z^-1.
|
||||
func feInvert(out, z *fieldElement) {
|
||||
var t0, t1, t2, t3 fieldElement
|
||||
var i int
|
||||
|
||||
feSquare(&t0, z)
|
||||
for i = 1; i < 1; i++ {
|
||||
feSquare(&t0, &t0)
|
||||
}
|
||||
feSquare(&t1, &t0)
|
||||
for i = 1; i < 2; i++ {
|
||||
feSquare(&t1, &t1)
|
||||
}
|
||||
feMul(&t1, z, &t1)
|
||||
feMul(&t0, &t0, &t1)
|
||||
feSquare(&t2, &t0)
|
||||
for i = 1; i < 1; i++ {
|
||||
feSquare(&t2, &t2)
|
||||
}
|
||||
feMul(&t1, &t1, &t2)
|
||||
feSquare(&t2, &t1)
|
||||
for i = 1; i < 5; i++ {
|
||||
feSquare(&t2, &t2)
|
||||
}
|
||||
feMul(&t1, &t2, &t1)
|
||||
feSquare(&t2, &t1)
|
||||
for i = 1; i < 10; i++ {
|
||||
feSquare(&t2, &t2)
|
||||
}
|
||||
feMul(&t2, &t2, &t1)
|
||||
feSquare(&t3, &t2)
|
||||
for i = 1; i < 20; i++ {
|
||||
feSquare(&t3, &t3)
|
||||
}
|
||||
feMul(&t2, &t3, &t2)
|
||||
feSquare(&t2, &t2)
|
||||
for i = 1; i < 10; i++ {
|
||||
feSquare(&t2, &t2)
|
||||
}
|
||||
feMul(&t1, &t2, &t1)
|
||||
feSquare(&t2, &t1)
|
||||
for i = 1; i < 50; i++ {
|
||||
feSquare(&t2, &t2)
|
||||
}
|
||||
feMul(&t2, &t2, &t1)
|
||||
feSquare(&t3, &t2)
|
||||
for i = 1; i < 100; i++ {
|
||||
feSquare(&t3, &t3)
|
||||
}
|
||||
feMul(&t2, &t3, &t2)
|
||||
feSquare(&t2, &t2)
|
||||
for i = 1; i < 50; i++ {
|
||||
feSquare(&t2, &t2)
|
||||
}
|
||||
feMul(&t1, &t2, &t1)
|
||||
feSquare(&t1, &t1)
|
||||
for i = 1; i < 5; i++ {
|
||||
feSquare(&t1, &t1)
|
||||
}
|
||||
feMul(out, &t1, &t0)
|
||||
}
|
||||
|
||||
func scalarMult(out, in, base *[32]byte) {
|
||||
var e [32]byte
|
||||
|
||||
copy(e[:], in[:])
|
||||
e[0] &= 248
|
||||
e[31] &= 127
|
||||
e[31] |= 64
|
||||
|
||||
var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement
|
||||
feFromBytes(&x1, base)
|
||||
feOne(&x2)
|
||||
feCopy(&x3, &x1)
|
||||
feOne(&z3)
|
||||
|
||||
swap := int32(0)
|
||||
for pos := 254; pos >= 0; pos-- {
|
||||
b := e[pos/8] >> uint(pos&7)
|
||||
b &= 1
|
||||
swap ^= int32(b)
|
||||
feCSwap(&x2, &x3, swap)
|
||||
feCSwap(&z2, &z3, swap)
|
||||
swap = int32(b)
|
||||
|
||||
feSub(&tmp0, &x3, &z3)
|
||||
feSub(&tmp1, &x2, &z2)
|
||||
feAdd(&x2, &x2, &z2)
|
||||
feAdd(&z2, &x3, &z3)
|
||||
feMul(&z3, &tmp0, &x2)
|
||||
feMul(&z2, &z2, &tmp1)
|
||||
feSquare(&tmp0, &tmp1)
|
||||
feSquare(&tmp1, &x2)
|
||||
feAdd(&x3, &z3, &z2)
|
||||
feSub(&z2, &z3, &z2)
|
||||
feMul(&x2, &tmp1, &tmp0)
|
||||
feSub(&tmp1, &tmp1, &tmp0)
|
||||
feSquare(&z2, &z2)
|
||||
feMul121666(&z3, &tmp1)
|
||||
feSquare(&x3, &x3)
|
||||
feAdd(&tmp0, &tmp0, &z3)
|
||||
feMul(&z3, &x1, &z2)
|
||||
feMul(&z2, &tmp1, &tmp0)
|
||||
}
|
||||
|
||||
feCSwap(&x2, &x3, swap)
|
||||
feCSwap(&z2, &z3, swap)
|
||||
|
||||
feInvert(&z2, &z2)
|
||||
feMul(&x2, &x2, &z2)
|
||||
feToBytes(out, &x2)
|
||||
}
|
||||
39
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/curve25519_test.go
generated
vendored
Normal file
39
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/curve25519_test.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package curve25519
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const expectedHex = "89161fde887b2b53de549af483940106ecc114d6982daa98256de23bdf77661a"
|
||||
|
||||
func TestBaseScalarMult(t *testing.T) {
|
||||
var a, b [32]byte
|
||||
in := &a
|
||||
out := &b
|
||||
a[0] = 1
|
||||
|
||||
for i := 0; i < 200; i++ {
|
||||
ScalarBaseMult(out, in)
|
||||
in, out = out, in
|
||||
}
|
||||
|
||||
result := fmt.Sprintf("%x", in[:])
|
||||
if result != expectedHex {
|
||||
t.Errorf("incorrect result: got %s, want %s", result, expectedHex)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkScalarBaseMult(b *testing.B) {
|
||||
var in, out [32]byte
|
||||
in[0] = 1
|
||||
|
||||
b.SetBytes(32)
|
||||
for i := 0; i < b.N; i++ {
|
||||
ScalarBaseMult(&out, &in)
|
||||
}
|
||||
}
|
||||
23
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/doc.go
generated
vendored
Normal file
23
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/doc.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package curve25519 provides an implementation of scalar multiplication on
|
||||
// the elliptic curve known as curve25519. See https://cr.yp.to/ecdh.html
|
||||
package curve25519 // import "golang.org/x/crypto/curve25519"
|
||||
|
||||
// basePoint is the x coordinate of the generator of the curve.
|
||||
var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
|
||||
// ScalarMult sets dst to the product in*base where dst and base are the x
|
||||
// coordinates of group points and all values are in little-endian form.
|
||||
func ScalarMult(dst, in, base *[32]byte) {
|
||||
scalarMult(dst, in, base)
|
||||
}
|
||||
|
||||
// ScalarBaseMult sets dst to the product in*base where dst and base are the x
|
||||
// coordinates of group points, base is the standard generator and all values
|
||||
// are in little-endian form.
|
||||
func ScalarBaseMult(dst, in *[32]byte) {
|
||||
ScalarMult(dst, in, &basePoint)
|
||||
}
|
||||
73
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/freeze_amd64.s
generated
vendored
Normal file
73
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/freeze_amd64.s
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This code was translated into a form compatible with 6a from the public
|
||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
#include "const_amd64.h"
|
||||
|
||||
// func freeze(inout *[5]uint64)
|
||||
TEXT ·freeze(SB),7,$0-8
|
||||
MOVQ inout+0(FP), DI
|
||||
|
||||
MOVQ 0(DI),SI
|
||||
MOVQ 8(DI),DX
|
||||
MOVQ 16(DI),CX
|
||||
MOVQ 24(DI),R8
|
||||
MOVQ 32(DI),R9
|
||||
MOVQ $REDMASK51,AX
|
||||
MOVQ AX,R10
|
||||
SUBQ $18,R10
|
||||
MOVQ $3,R11
|
||||
REDUCELOOP:
|
||||
MOVQ SI,R12
|
||||
SHRQ $51,R12
|
||||
ANDQ AX,SI
|
||||
ADDQ R12,DX
|
||||
MOVQ DX,R12
|
||||
SHRQ $51,R12
|
||||
ANDQ AX,DX
|
||||
ADDQ R12,CX
|
||||
MOVQ CX,R12
|
||||
SHRQ $51,R12
|
||||
ANDQ AX,CX
|
||||
ADDQ R12,R8
|
||||
MOVQ R8,R12
|
||||
SHRQ $51,R12
|
||||
ANDQ AX,R8
|
||||
ADDQ R12,R9
|
||||
MOVQ R9,R12
|
||||
SHRQ $51,R12
|
||||
ANDQ AX,R9
|
||||
IMUL3Q $19,R12,R12
|
||||
ADDQ R12,SI
|
||||
SUBQ $1,R11
|
||||
JA REDUCELOOP
|
||||
MOVQ $1,R12
|
||||
CMPQ R10,SI
|
||||
CMOVQLT R11,R12
|
||||
CMPQ AX,DX
|
||||
CMOVQNE R11,R12
|
||||
CMPQ AX,CX
|
||||
CMOVQNE R11,R12
|
||||
CMPQ AX,R8
|
||||
CMOVQNE R11,R12
|
||||
CMPQ AX,R9
|
||||
CMOVQNE R11,R12
|
||||
NEGQ R12
|
||||
ANDQ R12,AX
|
||||
ANDQ R12,R10
|
||||
SUBQ R10,SI
|
||||
SUBQ AX,DX
|
||||
SUBQ AX,CX
|
||||
SUBQ AX,R8
|
||||
SUBQ AX,R9
|
||||
MOVQ SI,0(DI)
|
||||
MOVQ DX,8(DI)
|
||||
MOVQ CX,16(DI)
|
||||
MOVQ R8,24(DI)
|
||||
MOVQ R9,32(DI)
|
||||
RET
|
||||
1377
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s
generated
vendored
Normal file
1377
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
240
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go
generated
vendored
Normal file
240
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go
generated
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
package curve25519
|
||||
|
||||
// These functions are implemented in the .s files. The names of the functions
|
||||
// in the rest of the file are also taken from the SUPERCOP sources to help
|
||||
// people following along.
|
||||
|
||||
//go:noescape
|
||||
|
||||
func cswap(inout *[5]uint64, v uint64)
|
||||
|
||||
//go:noescape
|
||||
|
||||
func ladderstep(inout *[5][5]uint64)
|
||||
|
||||
//go:noescape
|
||||
|
||||
func freeze(inout *[5]uint64)
|
||||
|
||||
//go:noescape
|
||||
|
||||
func mul(dest, a, b *[5]uint64)
|
||||
|
||||
//go:noescape
|
||||
|
||||
func square(out, in *[5]uint64)
|
||||
|
||||
// mladder uses a Montgomery ladder to calculate (xr/zr) *= s.
|
||||
func mladder(xr, zr *[5]uint64, s *[32]byte) {
|
||||
var work [5][5]uint64
|
||||
|
||||
work[0] = *xr
|
||||
setint(&work[1], 1)
|
||||
setint(&work[2], 0)
|
||||
work[3] = *xr
|
||||
setint(&work[4], 1)
|
||||
|
||||
j := uint(6)
|
||||
var prevbit byte
|
||||
|
||||
for i := 31; i >= 0; i-- {
|
||||
for j < 8 {
|
||||
bit := ((*s)[i] >> j) & 1
|
||||
swap := bit ^ prevbit
|
||||
prevbit = bit
|
||||
cswap(&work[1], uint64(swap))
|
||||
ladderstep(&work)
|
||||
j--
|
||||
}
|
||||
j = 7
|
||||
}
|
||||
|
||||
*xr = work[1]
|
||||
*zr = work[2]
|
||||
}
|
||||
|
||||
func scalarMult(out, in, base *[32]byte) {
|
||||
var e [32]byte
|
||||
copy(e[:], (*in)[:])
|
||||
e[0] &= 248
|
||||
e[31] &= 127
|
||||
e[31] |= 64
|
||||
|
||||
var t, z [5]uint64
|
||||
unpack(&t, base)
|
||||
mladder(&t, &z, &e)
|
||||
invert(&z, &z)
|
||||
mul(&t, &t, &z)
|
||||
pack(out, &t)
|
||||
}
|
||||
|
||||
func setint(r *[5]uint64, v uint64) {
|
||||
r[0] = v
|
||||
r[1] = 0
|
||||
r[2] = 0
|
||||
r[3] = 0
|
||||
r[4] = 0
|
||||
}
|
||||
|
||||
// unpack sets r = x where r consists of 5, 51-bit limbs in little-endian
|
||||
// order.
|
||||
func unpack(r *[5]uint64, x *[32]byte) {
|
||||
r[0] = uint64(x[0]) |
|
||||
uint64(x[1])<<8 |
|
||||
uint64(x[2])<<16 |
|
||||
uint64(x[3])<<24 |
|
||||
uint64(x[4])<<32 |
|
||||
uint64(x[5])<<40 |
|
||||
uint64(x[6]&7)<<48
|
||||
|
||||
r[1] = uint64(x[6])>>3 |
|
||||
uint64(x[7])<<5 |
|
||||
uint64(x[8])<<13 |
|
||||
uint64(x[9])<<21 |
|
||||
uint64(x[10])<<29 |
|
||||
uint64(x[11])<<37 |
|
||||
uint64(x[12]&63)<<45
|
||||
|
||||
r[2] = uint64(x[12])>>6 |
|
||||
uint64(x[13])<<2 |
|
||||
uint64(x[14])<<10 |
|
||||
uint64(x[15])<<18 |
|
||||
uint64(x[16])<<26 |
|
||||
uint64(x[17])<<34 |
|
||||
uint64(x[18])<<42 |
|
||||
uint64(x[19]&1)<<50
|
||||
|
||||
r[3] = uint64(x[19])>>1 |
|
||||
uint64(x[20])<<7 |
|
||||
uint64(x[21])<<15 |
|
||||
uint64(x[22])<<23 |
|
||||
uint64(x[23])<<31 |
|
||||
uint64(x[24])<<39 |
|
||||
uint64(x[25]&15)<<47
|
||||
|
||||
r[4] = uint64(x[25])>>4 |
|
||||
uint64(x[26])<<4 |
|
||||
uint64(x[27])<<12 |
|
||||
uint64(x[28])<<20 |
|
||||
uint64(x[29])<<28 |
|
||||
uint64(x[30])<<36 |
|
||||
uint64(x[31]&127)<<44
|
||||
}
|
||||
|
||||
// pack sets out = x where out is the usual, little-endian form of the 5,
|
||||
// 51-bit limbs in x.
|
||||
func pack(out *[32]byte, x *[5]uint64) {
|
||||
t := *x
|
||||
freeze(&t)
|
||||
|
||||
out[0] = byte(t[0])
|
||||
out[1] = byte(t[0] >> 8)
|
||||
out[2] = byte(t[0] >> 16)
|
||||
out[3] = byte(t[0] >> 24)
|
||||
out[4] = byte(t[0] >> 32)
|
||||
out[5] = byte(t[0] >> 40)
|
||||
out[6] = byte(t[0] >> 48)
|
||||
|
||||
out[6] ^= byte(t[1]<<3) & 0xf8
|
||||
out[7] = byte(t[1] >> 5)
|
||||
out[8] = byte(t[1] >> 13)
|
||||
out[9] = byte(t[1] >> 21)
|
||||
out[10] = byte(t[1] >> 29)
|
||||
out[11] = byte(t[1] >> 37)
|
||||
out[12] = byte(t[1] >> 45)
|
||||
|
||||
out[12] ^= byte(t[2]<<6) & 0xc0
|
||||
out[13] = byte(t[2] >> 2)
|
||||
out[14] = byte(t[2] >> 10)
|
||||
out[15] = byte(t[2] >> 18)
|
||||
out[16] = byte(t[2] >> 26)
|
||||
out[17] = byte(t[2] >> 34)
|
||||
out[18] = byte(t[2] >> 42)
|
||||
out[19] = byte(t[2] >> 50)
|
||||
|
||||
out[19] ^= byte(t[3]<<1) & 0xfe
|
||||
out[20] = byte(t[3] >> 7)
|
||||
out[21] = byte(t[3] >> 15)
|
||||
out[22] = byte(t[3] >> 23)
|
||||
out[23] = byte(t[3] >> 31)
|
||||
out[24] = byte(t[3] >> 39)
|
||||
out[25] = byte(t[3] >> 47)
|
||||
|
||||
out[25] ^= byte(t[4]<<4) & 0xf0
|
||||
out[26] = byte(t[4] >> 4)
|
||||
out[27] = byte(t[4] >> 12)
|
||||
out[28] = byte(t[4] >> 20)
|
||||
out[29] = byte(t[4] >> 28)
|
||||
out[30] = byte(t[4] >> 36)
|
||||
out[31] = byte(t[4] >> 44)
|
||||
}
|
||||
|
||||
// invert calculates r = x^-1 mod p using Fermat's little theorem.
|
||||
func invert(r *[5]uint64, x *[5]uint64) {
|
||||
var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t [5]uint64
|
||||
|
||||
square(&z2, x) /* 2 */
|
||||
square(&t, &z2) /* 4 */
|
||||
square(&t, &t) /* 8 */
|
||||
mul(&z9, &t, x) /* 9 */
|
||||
mul(&z11, &z9, &z2) /* 11 */
|
||||
square(&t, &z11) /* 22 */
|
||||
mul(&z2_5_0, &t, &z9) /* 2^5 - 2^0 = 31 */
|
||||
|
||||
square(&t, &z2_5_0) /* 2^6 - 2^1 */
|
||||
for i := 1; i < 5; i++ { /* 2^20 - 2^10 */
|
||||
square(&t, &t)
|
||||
}
|
||||
mul(&z2_10_0, &t, &z2_5_0) /* 2^10 - 2^0 */
|
||||
|
||||
square(&t, &z2_10_0) /* 2^11 - 2^1 */
|
||||
for i := 1; i < 10; i++ { /* 2^20 - 2^10 */
|
||||
square(&t, &t)
|
||||
}
|
||||
mul(&z2_20_0, &t, &z2_10_0) /* 2^20 - 2^0 */
|
||||
|
||||
square(&t, &z2_20_0) /* 2^21 - 2^1 */
|
||||
for i := 1; i < 20; i++ { /* 2^40 - 2^20 */
|
||||
square(&t, &t)
|
||||
}
|
||||
mul(&t, &t, &z2_20_0) /* 2^40 - 2^0 */
|
||||
|
||||
square(&t, &t) /* 2^41 - 2^1 */
|
||||
for i := 1; i < 10; i++ { /* 2^50 - 2^10 */
|
||||
square(&t, &t)
|
||||
}
|
||||
mul(&z2_50_0, &t, &z2_10_0) /* 2^50 - 2^0 */
|
||||
|
||||
square(&t, &z2_50_0) /* 2^51 - 2^1 */
|
||||
for i := 1; i < 50; i++ { /* 2^100 - 2^50 */
|
||||
square(&t, &t)
|
||||
}
|
||||
mul(&z2_100_0, &t, &z2_50_0) /* 2^100 - 2^0 */
|
||||
|
||||
square(&t, &z2_100_0) /* 2^101 - 2^1 */
|
||||
for i := 1; i < 100; i++ { /* 2^200 - 2^100 */
|
||||
square(&t, &t)
|
||||
}
|
||||
mul(&t, &t, &z2_100_0) /* 2^200 - 2^0 */
|
||||
|
||||
square(&t, &t) /* 2^201 - 2^1 */
|
||||
for i := 1; i < 50; i++ { /* 2^250 - 2^50 */
|
||||
square(&t, &t)
|
||||
}
|
||||
mul(&t, &t, &z2_50_0) /* 2^250 - 2^0 */
|
||||
|
||||
square(&t, &t) /* 2^251 - 2^1 */
|
||||
square(&t, &t) /* 2^252 - 2^2 */
|
||||
square(&t, &t) /* 2^253 - 2^3 */
|
||||
|
||||
square(&t, &t) /* 2^254 - 2^4 */
|
||||
|
||||
square(&t, &t) /* 2^255 - 2^5 */
|
||||
mul(r, &t, &z11) /* 2^255 - 21 */
|
||||
}
|
||||
169
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/mul_amd64.s
generated
vendored
Normal file
169
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/mul_amd64.s
generated
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This code was translated into a form compatible with 6a from the public
|
||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
#include "const_amd64.h"
|
||||
|
||||
// func mul(dest, a, b *[5]uint64)
|
||||
TEXT ·mul(SB),0,$16-24
|
||||
MOVQ dest+0(FP), DI
|
||||
MOVQ a+8(FP), SI
|
||||
MOVQ b+16(FP), DX
|
||||
|
||||
MOVQ DX,CX
|
||||
MOVQ 24(SI),DX
|
||||
IMUL3Q $19,DX,AX
|
||||
MOVQ AX,0(SP)
|
||||
MULQ 16(CX)
|
||||
MOVQ AX,R8
|
||||
MOVQ DX,R9
|
||||
MOVQ 32(SI),DX
|
||||
IMUL3Q $19,DX,AX
|
||||
MOVQ AX,8(SP)
|
||||
MULQ 8(CX)
|
||||
ADDQ AX,R8
|
||||
ADCQ DX,R9
|
||||
MOVQ 0(SI),AX
|
||||
MULQ 0(CX)
|
||||
ADDQ AX,R8
|
||||
ADCQ DX,R9
|
||||
MOVQ 0(SI),AX
|
||||
MULQ 8(CX)
|
||||
MOVQ AX,R10
|
||||
MOVQ DX,R11
|
||||
MOVQ 0(SI),AX
|
||||
MULQ 16(CX)
|
||||
MOVQ AX,R12
|
||||
MOVQ DX,R13
|
||||
MOVQ 0(SI),AX
|
||||
MULQ 24(CX)
|
||||
MOVQ AX,R14
|
||||
MOVQ DX,R15
|
||||
MOVQ 0(SI),AX
|
||||
MULQ 32(CX)
|
||||
MOVQ AX,BX
|
||||
MOVQ DX,BP
|
||||
MOVQ 8(SI),AX
|
||||
MULQ 0(CX)
|
||||
ADDQ AX,R10
|
||||
ADCQ DX,R11
|
||||
MOVQ 8(SI),AX
|
||||
MULQ 8(CX)
|
||||
ADDQ AX,R12
|
||||
ADCQ DX,R13
|
||||
MOVQ 8(SI),AX
|
||||
MULQ 16(CX)
|
||||
ADDQ AX,R14
|
||||
ADCQ DX,R15
|
||||
MOVQ 8(SI),AX
|
||||
MULQ 24(CX)
|
||||
ADDQ AX,BX
|
||||
ADCQ DX,BP
|
||||
MOVQ 8(SI),DX
|
||||
IMUL3Q $19,DX,AX
|
||||
MULQ 32(CX)
|
||||
ADDQ AX,R8
|
||||
ADCQ DX,R9
|
||||
MOVQ 16(SI),AX
|
||||
MULQ 0(CX)
|
||||
ADDQ AX,R12
|
||||
ADCQ DX,R13
|
||||
MOVQ 16(SI),AX
|
||||
MULQ 8(CX)
|
||||
ADDQ AX,R14
|
||||
ADCQ DX,R15
|
||||
MOVQ 16(SI),AX
|
||||
MULQ 16(CX)
|
||||
ADDQ AX,BX
|
||||
ADCQ DX,BP
|
||||
MOVQ 16(SI),DX
|
||||
IMUL3Q $19,DX,AX
|
||||
MULQ 24(CX)
|
||||
ADDQ AX,R8
|
||||
ADCQ DX,R9
|
||||
MOVQ 16(SI),DX
|
||||
IMUL3Q $19,DX,AX
|
||||
MULQ 32(CX)
|
||||
ADDQ AX,R10
|
||||
ADCQ DX,R11
|
||||
MOVQ 24(SI),AX
|
||||
MULQ 0(CX)
|
||||
ADDQ AX,R14
|
||||
ADCQ DX,R15
|
||||
MOVQ 24(SI),AX
|
||||
MULQ 8(CX)
|
||||
ADDQ AX,BX
|
||||
ADCQ DX,BP
|
||||
MOVQ 0(SP),AX
|
||||
MULQ 24(CX)
|
||||
ADDQ AX,R10
|
||||
ADCQ DX,R11
|
||||
MOVQ 0(SP),AX
|
||||
MULQ 32(CX)
|
||||
ADDQ AX,R12
|
||||
ADCQ DX,R13
|
||||
MOVQ 32(SI),AX
|
||||
MULQ 0(CX)
|
||||
ADDQ AX,BX
|
||||
ADCQ DX,BP
|
||||
MOVQ 8(SP),AX
|
||||
MULQ 16(CX)
|
||||
ADDQ AX,R10
|
||||
ADCQ DX,R11
|
||||
MOVQ 8(SP),AX
|
||||
MULQ 24(CX)
|
||||
ADDQ AX,R12
|
||||
ADCQ DX,R13
|
||||
MOVQ 8(SP),AX
|
||||
MULQ 32(CX)
|
||||
ADDQ AX,R14
|
||||
ADCQ DX,R15
|
||||
MOVQ $REDMASK51,SI
|
||||
SHLQ $13,R9:R8
|
||||
ANDQ SI,R8
|
||||
SHLQ $13,R11:R10
|
||||
ANDQ SI,R10
|
||||
ADDQ R9,R10
|
||||
SHLQ $13,R13:R12
|
||||
ANDQ SI,R12
|
||||
ADDQ R11,R12
|
||||
SHLQ $13,R15:R14
|
||||
ANDQ SI,R14
|
||||
ADDQ R13,R14
|
||||
SHLQ $13,BP:BX
|
||||
ANDQ SI,BX
|
||||
ADDQ R15,BX
|
||||
IMUL3Q $19,BP,DX
|
||||
ADDQ DX,R8
|
||||
MOVQ R8,DX
|
||||
SHRQ $51,DX
|
||||
ADDQ R10,DX
|
||||
MOVQ DX,CX
|
||||
SHRQ $51,DX
|
||||
ANDQ SI,R8
|
||||
ADDQ R12,DX
|
||||
MOVQ DX,R9
|
||||
SHRQ $51,DX
|
||||
ANDQ SI,CX
|
||||
ADDQ R14,DX
|
||||
MOVQ DX,AX
|
||||
SHRQ $51,DX
|
||||
ANDQ SI,R9
|
||||
ADDQ BX,DX
|
||||
MOVQ DX,R10
|
||||
SHRQ $51,DX
|
||||
ANDQ SI,AX
|
||||
IMUL3Q $19,DX,DX
|
||||
ADDQ DX,R8
|
||||
ANDQ SI,R10
|
||||
MOVQ R8,0(DI)
|
||||
MOVQ CX,8(DI)
|
||||
MOVQ R9,16(DI)
|
||||
MOVQ AX,24(DI)
|
||||
MOVQ R10,32(DI)
|
||||
RET
|
||||
132
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/square_amd64.s
generated
vendored
Normal file
132
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/curve25519/square_amd64.s
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This code was translated into a form compatible with 6a from the public
|
||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
#include "const_amd64.h"
|
||||
|
||||
// func square(out, in *[5]uint64)
|
||||
TEXT ·square(SB),7,$0-16
|
||||
MOVQ out+0(FP), DI
|
||||
MOVQ in+8(FP), SI
|
||||
|
||||
MOVQ 0(SI),AX
|
||||
MULQ 0(SI)
|
||||
MOVQ AX,CX
|
||||
MOVQ DX,R8
|
||||
MOVQ 0(SI),AX
|
||||
SHLQ $1,AX
|
||||
MULQ 8(SI)
|
||||
MOVQ AX,R9
|
||||
MOVQ DX,R10
|
||||
MOVQ 0(SI),AX
|
||||
SHLQ $1,AX
|
||||
MULQ 16(SI)
|
||||
MOVQ AX,R11
|
||||
MOVQ DX,R12
|
||||
MOVQ 0(SI),AX
|
||||
SHLQ $1,AX
|
||||
MULQ 24(SI)
|
||||
MOVQ AX,R13
|
||||
MOVQ DX,R14
|
||||
MOVQ 0(SI),AX
|
||||
SHLQ $1,AX
|
||||
MULQ 32(SI)
|
||||
MOVQ AX,R15
|
||||
MOVQ DX,BX
|
||||
MOVQ 8(SI),AX
|
||||
MULQ 8(SI)
|
||||
ADDQ AX,R11
|
||||
ADCQ DX,R12
|
||||
MOVQ 8(SI),AX
|
||||
SHLQ $1,AX
|
||||
MULQ 16(SI)
|
||||
ADDQ AX,R13
|
||||
ADCQ DX,R14
|
||||
MOVQ 8(SI),AX
|
||||
SHLQ $1,AX
|
||||
MULQ 24(SI)
|
||||
ADDQ AX,R15
|
||||
ADCQ DX,BX
|
||||
MOVQ 8(SI),DX
|
||||
IMUL3Q $38,DX,AX
|
||||
MULQ 32(SI)
|
||||
ADDQ AX,CX
|
||||
ADCQ DX,R8
|
||||
MOVQ 16(SI),AX
|
||||
MULQ 16(SI)
|
||||
ADDQ AX,R15
|
||||
ADCQ DX,BX
|
||||
MOVQ 16(SI),DX
|
||||
IMUL3Q $38,DX,AX
|
||||
MULQ 24(SI)
|
||||
ADDQ AX,CX
|
||||
ADCQ DX,R8
|
||||
MOVQ 16(SI),DX
|
||||
IMUL3Q $38,DX,AX
|
||||
MULQ 32(SI)
|
||||
ADDQ AX,R9
|
||||
ADCQ DX,R10
|
||||
MOVQ 24(SI),DX
|
||||
IMUL3Q $19,DX,AX
|
||||
MULQ 24(SI)
|
||||
ADDQ AX,R9
|
||||
ADCQ DX,R10
|
||||
MOVQ 24(SI),DX
|
||||
IMUL3Q $38,DX,AX
|
||||
MULQ 32(SI)
|
||||
ADDQ AX,R11
|
||||
ADCQ DX,R12
|
||||
MOVQ 32(SI),DX
|
||||
IMUL3Q $19,DX,AX
|
||||
MULQ 32(SI)
|
||||
ADDQ AX,R13
|
||||
ADCQ DX,R14
|
||||
MOVQ $REDMASK51,SI
|
||||
SHLQ $13,R8:CX
|
||||
ANDQ SI,CX
|
||||
SHLQ $13,R10:R9
|
||||
ANDQ SI,R9
|
||||
ADDQ R8,R9
|
||||
SHLQ $13,R12:R11
|
||||
ANDQ SI,R11
|
||||
ADDQ R10,R11
|
||||
SHLQ $13,R14:R13
|
||||
ANDQ SI,R13
|
||||
ADDQ R12,R13
|
||||
SHLQ $13,BX:R15
|
||||
ANDQ SI,R15
|
||||
ADDQ R14,R15
|
||||
IMUL3Q $19,BX,DX
|
||||
ADDQ DX,CX
|
||||
MOVQ CX,DX
|
||||
SHRQ $51,DX
|
||||
ADDQ R9,DX
|
||||
ANDQ SI,CX
|
||||
MOVQ DX,R8
|
||||
SHRQ $51,DX
|
||||
ADDQ R11,DX
|
||||
ANDQ SI,R8
|
||||
MOVQ DX,R9
|
||||
SHRQ $51,DX
|
||||
ADDQ R13,DX
|
||||
ANDQ SI,R9
|
||||
MOVQ DX,AX
|
||||
SHRQ $51,DX
|
||||
ADDQ R15,DX
|
||||
ANDQ SI,AX
|
||||
MOVQ DX,R10
|
||||
SHRQ $51,DX
|
||||
IMUL3Q $19,DX,DX
|
||||
ADDQ DX,CX
|
||||
ANDQ SI,R10
|
||||
MOVQ CX,0(DI)
|
||||
MOVQ R8,8(DI)
|
||||
MOVQ R9,16(DI)
|
||||
MOVQ AX,24(DI)
|
||||
MOVQ R10,32(DI)
|
||||
RET
|
||||
181
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/ed25519/ed25519.go
generated
vendored
Normal file
181
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/ed25519/ed25519.go
generated
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package ed25519 implements the Ed25519 signature algorithm. See
|
||||
// https://ed25519.cr.yp.to/.
|
||||
//
|
||||
// These functions are also compatible with the “Ed25519” function defined in
|
||||
// https://tools.ietf.org/html/draft-irtf-cfrg-eddsa-05.
|
||||
package ed25519
|
||||
|
||||
// This code is a port of the public domain, “ref10” implementation of ed25519
|
||||
// from SUPERCOP.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
cryptorand "crypto/rand"
|
||||
"crypto/sha512"
|
||||
"errors"
|
||||
"io"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/crypto/ed25519/internal/edwards25519"
|
||||
)
|
||||
|
||||
const (
|
||||
// PublicKeySize is the size, in bytes, of public keys as used in this package.
|
||||
PublicKeySize = 32
|
||||
// PrivateKeySize is the size, in bytes, of private keys as used in this package.
|
||||
PrivateKeySize = 64
|
||||
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
|
||||
SignatureSize = 64
|
||||
)
|
||||
|
||||
// PublicKey is the type of Ed25519 public keys.
|
||||
type PublicKey []byte
|
||||
|
||||
// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
|
||||
type PrivateKey []byte
|
||||
|
||||
// Public returns the PublicKey corresponding to priv.
|
||||
func (priv PrivateKey) Public() crypto.PublicKey {
|
||||
publicKey := make([]byte, PublicKeySize)
|
||||
copy(publicKey, priv[32:])
|
||||
return PublicKey(publicKey)
|
||||
}
|
||||
|
||||
// Sign signs the given message with priv.
|
||||
// Ed25519 performs two passes over messages to be signed and therefore cannot
|
||||
// handle pre-hashed messages. Thus opts.HashFunc() must return zero to
|
||||
// indicate the message hasn't been hashed. This can be achieved by passing
|
||||
// crypto.Hash(0) as the value for opts.
|
||||
func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
|
||||
if opts.HashFunc() != crypto.Hash(0) {
|
||||
return nil, errors.New("ed25519: cannot sign hashed message")
|
||||
}
|
||||
|
||||
return Sign(priv, message), nil
|
||||
}
|
||||
|
||||
// GenerateKey generates a public/private key pair using entropy from rand.
|
||||
// If rand is nil, crypto/rand.Reader will be used.
|
||||
func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, err error) {
|
||||
if rand == nil {
|
||||
rand = cryptorand.Reader
|
||||
}
|
||||
|
||||
privateKey = make([]byte, PrivateKeySize)
|
||||
publicKey = make([]byte, PublicKeySize)
|
||||
_, err = io.ReadFull(rand, privateKey[:32])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
digest := sha512.Sum512(privateKey[:32])
|
||||
digest[0] &= 248
|
||||
digest[31] &= 127
|
||||
digest[31] |= 64
|
||||
|
||||
var A edwards25519.ExtendedGroupElement
|
||||
var hBytes [32]byte
|
||||
copy(hBytes[:], digest[:])
|
||||
edwards25519.GeScalarMultBase(&A, &hBytes)
|
||||
var publicKeyBytes [32]byte
|
||||
A.ToBytes(&publicKeyBytes)
|
||||
|
||||
copy(privateKey[32:], publicKeyBytes[:])
|
||||
copy(publicKey, publicKeyBytes[:])
|
||||
|
||||
return publicKey, privateKey, nil
|
||||
}
|
||||
|
||||
// Sign signs the message with privateKey and returns a signature. It will
|
||||
// panic if len(privateKey) is not PrivateKeySize.
|
||||
func Sign(privateKey PrivateKey, message []byte) []byte {
|
||||
if l := len(privateKey); l != PrivateKeySize {
|
||||
panic("ed25519: bad private key length: " + strconv.Itoa(l))
|
||||
}
|
||||
|
||||
h := sha512.New()
|
||||
h.Write(privateKey[:32])
|
||||
|
||||
var digest1, messageDigest, hramDigest [64]byte
|
||||
var expandedSecretKey [32]byte
|
||||
h.Sum(digest1[:0])
|
||||
copy(expandedSecretKey[:], digest1[:])
|
||||
expandedSecretKey[0] &= 248
|
||||
expandedSecretKey[31] &= 63
|
||||
expandedSecretKey[31] |= 64
|
||||
|
||||
h.Reset()
|
||||
h.Write(digest1[32:])
|
||||
h.Write(message)
|
||||
h.Sum(messageDigest[:0])
|
||||
|
||||
var messageDigestReduced [32]byte
|
||||
edwards25519.ScReduce(&messageDigestReduced, &messageDigest)
|
||||
var R edwards25519.ExtendedGroupElement
|
||||
edwards25519.GeScalarMultBase(&R, &messageDigestReduced)
|
||||
|
||||
var encodedR [32]byte
|
||||
R.ToBytes(&encodedR)
|
||||
|
||||
h.Reset()
|
||||
h.Write(encodedR[:])
|
||||
h.Write(privateKey[32:])
|
||||
h.Write(message)
|
||||
h.Sum(hramDigest[:0])
|
||||
var hramDigestReduced [32]byte
|
||||
edwards25519.ScReduce(&hramDigestReduced, &hramDigest)
|
||||
|
||||
var s [32]byte
|
||||
edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced)
|
||||
|
||||
signature := make([]byte, SignatureSize)
|
||||
copy(signature[:], encodedR[:])
|
||||
copy(signature[32:], s[:])
|
||||
|
||||
return signature
|
||||
}
|
||||
|
||||
// Verify reports whether sig is a valid signature of message by publicKey. It
|
||||
// will panic if len(publicKey) is not PublicKeySize.
|
||||
func Verify(publicKey PublicKey, message, sig []byte) bool {
|
||||
if l := len(publicKey); l != PublicKeySize {
|
||||
panic("ed25519: bad public key length: " + strconv.Itoa(l))
|
||||
}
|
||||
|
||||
if len(sig) != SignatureSize || sig[63]&224 != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
var A edwards25519.ExtendedGroupElement
|
||||
var publicKeyBytes [32]byte
|
||||
copy(publicKeyBytes[:], publicKey)
|
||||
if !A.FromBytes(&publicKeyBytes) {
|
||||
return false
|
||||
}
|
||||
edwards25519.FeNeg(&A.X, &A.X)
|
||||
edwards25519.FeNeg(&A.T, &A.T)
|
||||
|
||||
h := sha512.New()
|
||||
h.Write(sig[:32])
|
||||
h.Write(publicKey[:])
|
||||
h.Write(message)
|
||||
var digest [64]byte
|
||||
h.Sum(digest[:0])
|
||||
|
||||
var hReduced [32]byte
|
||||
edwards25519.ScReduce(&hReduced, &digest)
|
||||
|
||||
var R edwards25519.ProjectiveGroupElement
|
||||
var b [32]byte
|
||||
copy(b[:], sig[32:])
|
||||
edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &b)
|
||||
|
||||
var checkR [32]byte
|
||||
R.ToBytes(&checkR)
|
||||
return bytes.Equal(sig[:32], checkR[:])
|
||||
}
|
||||
183
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/ed25519/ed25519_test.go
generated
vendored
Normal file
183
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/ed25519/ed25519_test.go
generated
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ed25519
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/crypto/ed25519/internal/edwards25519"
|
||||
)
|
||||
|
||||
type zeroReader struct{}
|
||||
|
||||
func (zeroReader) Read(buf []byte) (int, error) {
|
||||
for i := range buf {
|
||||
buf[i] = 0
|
||||
}
|
||||
return len(buf), nil
|
||||
}
|
||||
|
||||
func TestUnmarshalMarshal(t *testing.T) {
|
||||
pub, _, _ := GenerateKey(rand.Reader)
|
||||
|
||||
var A edwards25519.ExtendedGroupElement
|
||||
var pubBytes [32]byte
|
||||
copy(pubBytes[:], pub)
|
||||
if !A.FromBytes(&pubBytes) {
|
||||
t.Fatalf("ExtendedGroupElement.FromBytes failed")
|
||||
}
|
||||
|
||||
var pub2 [32]byte
|
||||
A.ToBytes(&pub2)
|
||||
|
||||
if pubBytes != pub2 {
|
||||
t.Errorf("FromBytes(%v)->ToBytes does not round-trip, got %x\n", pubBytes, pub2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignVerify(t *testing.T) {
|
||||
var zero zeroReader
|
||||
public, private, _ := GenerateKey(zero)
|
||||
|
||||
message := []byte("test message")
|
||||
sig := Sign(private, message)
|
||||
if !Verify(public, message, sig) {
|
||||
t.Errorf("valid signature rejected")
|
||||
}
|
||||
|
||||
wrongMessage := []byte("wrong message")
|
||||
if Verify(public, wrongMessage, sig) {
|
||||
t.Errorf("signature of different message accepted")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCryptoSigner(t *testing.T) {
|
||||
var zero zeroReader
|
||||
public, private, _ := GenerateKey(zero)
|
||||
|
||||
signer := crypto.Signer(private)
|
||||
|
||||
publicInterface := signer.Public()
|
||||
public2, ok := publicInterface.(PublicKey)
|
||||
if !ok {
|
||||
t.Fatalf("expected PublicKey from Public() but got %T", publicInterface)
|
||||
}
|
||||
|
||||
if !bytes.Equal(public, public2) {
|
||||
t.Errorf("public keys do not match: original:%x vs Public():%x", public, public2)
|
||||
}
|
||||
|
||||
message := []byte("message")
|
||||
var noHash crypto.Hash
|
||||
signature, err := signer.Sign(zero, message, noHash)
|
||||
if err != nil {
|
||||
t.Fatalf("error from Sign(): %s", err)
|
||||
}
|
||||
|
||||
if !Verify(public, message, signature) {
|
||||
t.Errorf("Verify failed on signature from Sign()")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGolden(t *testing.T) {
|
||||
// sign.input.gz is a selection of test cases from
|
||||
// https://ed25519.cr.yp.to/python/sign.input
|
||||
testDataZ, err := os.Open("testdata/sign.input.gz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer testDataZ.Close()
|
||||
testData, err := gzip.NewReader(testDataZ)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer testData.Close()
|
||||
|
||||
scanner := bufio.NewScanner(testData)
|
||||
lineNo := 0
|
||||
|
||||
for scanner.Scan() {
|
||||
lineNo++
|
||||
|
||||
line := scanner.Text()
|
||||
parts := strings.Split(line, ":")
|
||||
if len(parts) != 5 {
|
||||
t.Fatalf("bad number of parts on line %d", lineNo)
|
||||
}
|
||||
|
||||
privBytes, _ := hex.DecodeString(parts[0])
|
||||
pubKey, _ := hex.DecodeString(parts[1])
|
||||
msg, _ := hex.DecodeString(parts[2])
|
||||
sig, _ := hex.DecodeString(parts[3])
|
||||
// The signatures in the test vectors also include the message
|
||||
// at the end, but we just want R and S.
|
||||
sig = sig[:SignatureSize]
|
||||
|
||||
if l := len(pubKey); l != PublicKeySize {
|
||||
t.Fatalf("bad public key length on line %d: got %d bytes", lineNo, l)
|
||||
}
|
||||
|
||||
var priv [PrivateKeySize]byte
|
||||
copy(priv[:], privBytes)
|
||||
copy(priv[32:], pubKey)
|
||||
|
||||
sig2 := Sign(priv[:], msg)
|
||||
if !bytes.Equal(sig, sig2[:]) {
|
||||
t.Errorf("different signature result on line %d: %x vs %x", lineNo, sig, sig2)
|
||||
}
|
||||
|
||||
if !Verify(pubKey, msg, sig2) {
|
||||
t.Errorf("signature failed to verify on line %d", lineNo)
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
t.Fatalf("error reading test data: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkKeyGeneration(b *testing.B) {
|
||||
var zero zeroReader
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, _, err := GenerateKey(zero); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSigning(b *testing.B) {
|
||||
var zero zeroReader
|
||||
_, priv, err := GenerateKey(zero)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
message := []byte("Hello, world!")
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Sign(priv, message)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkVerification(b *testing.B) {
|
||||
var zero zeroReader
|
||||
pub, priv, err := GenerateKey(zero)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
message := []byte("Hello, world!")
|
||||
signature := Sign(priv, message)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Verify(pub, message, signature)
|
||||
}
|
||||
}
|
||||
1422
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go
generated
vendored
Normal file
1422
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1771
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
generated
vendored
Normal file
1771
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/ed25519/testdata/sign.input.gz
generated
vendored
Normal file
BIN
contrib/backends/srndv2/src/srnd/vendor/golang.org/x/crypto/ed25519/testdata/sign.input.gz
generated
vendored
Normal file
Binary file not shown.
@@ -6,7 +6,7 @@ package srnd
|
||||
|
||||
import "fmt"
|
||||
|
||||
var major_version = 4
|
||||
var major_version = 5
|
||||
var minor_version = 0
|
||||
var program_name = "srnd"
|
||||
|
||||
|
||||
@@ -94,6 +94,9 @@ func main() {
|
||||
} else {
|
||||
fmt.Fprintf(os.Stdout, "usage: %s tool mod [[add|del] pubkey]|[do modactiongoeshere]\n", os.Args[0])
|
||||
}
|
||||
} else if tool == "expire" {
|
||||
daemon.Setup()
|
||||
daemon.ExpireAll()
|
||||
} else if tool == "rethumb" {
|
||||
if len(os.Args) >= 4 {
|
||||
threads := runtime.NumCPU()
|
||||
@@ -132,10 +135,10 @@ func main() {
|
||||
fmt.Fprintf(os.Stdout, "Usage: %s tool nntp [add-login|del-login]\n", os.Args[0])
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(os.Stdout, "Usage: %s tool [rethumb|keygen|nntp|mod]\n", os.Args[0])
|
||||
fmt.Fprintf(os.Stdout, "Usage: %s tool [rethumb|keygen|nntp|mod|expire]\n", os.Args[0])
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(os.Stdout, "Usage: %s tool [rethumb|keygen|nntp|mod]\n", os.Args[0])
|
||||
fmt.Fprintf(os.Stdout, "Usage: %s tool [rethumb|keygen|nntp|mod|expire]\n", os.Args[0])
|
||||
}
|
||||
} else {
|
||||
log.Println("Invalid action:", action)
|
||||
|
||||
2
contrib/static/.gitignore
vendored
2
contrib/static/.gitignore
vendored
@@ -1,3 +1,3 @@
|
||||
nntpchan.js
|
||||
neochan.js
|
||||
neochan.css
|
||||
neochan.css
|
||||
|
||||
BIN
contrib/static/admin.png
Normal file
BIN
contrib/static/admin.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 214 KiB |
BIN
contrib/static/blackface.png
Normal file
BIN
contrib/static/blackface.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
@@ -49,8 +49,10 @@ function inject_nntp_feed_element(feed, elem) {
|
||||
elem.appendChild(name);
|
||||
var conns = document.createElement("div");
|
||||
conns.setAttribute("class", "connections");
|
||||
for ( var idx = 0 ; idx < feed.Conns.length; idx ++ ) {
|
||||
conns.appendChild(createConnectionElement(feed.Conns[idx]));
|
||||
if (feed.Conns) {
|
||||
for ( var idx = 0 ; idx < feed.Conns.length; idx ++ ) {
|
||||
conns.appendChild(createConnectionElement(feed.Conns[idx]));
|
||||
}
|
||||
}
|
||||
elem.appendChild(conns);
|
||||
}
|
||||
|
||||
@@ -198,6 +198,7 @@
|
||||
background: #141414;
|
||||
border: 1px solid #3B3B3B;
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
.datatable th {
|
||||
background: #1C1C1C;
|
||||
@@ -364,7 +365,7 @@
|
||||
}
|
||||
|
||||
[data-subject="None"] { display: none; }
|
||||
[data-sage="1"] { background: darkred; }
|
||||
[data-sage="1"] { filter: saturate(0); }
|
||||
|
||||
.overboard, .threadpage, .boardpage {
|
||||
background-image: url('/static/changolia-logo.png');
|
||||
@@ -418,3 +419,37 @@
|
||||
background-repeat: no-repeat;
|
||||
background-position: top right;
|
||||
}
|
||||
|
||||
[data-name~="nigger"] {
|
||||
background-image: url('/static/blackface.png');
|
||||
background-size: 25%;
|
||||
background-repeat: repeat;
|
||||
}
|
||||
|
||||
/** change me as needed, admin's pubkey */
|
||||
[data-pubkey~="039a876792db66966241e63140e7df79df488033360064b67d890635814e925e"] {
|
||||
background-image: url('/static/admin.png');
|
||||
background-size: 25%;
|
||||
background-repeat: repeat;
|
||||
}
|
||||
|
||||
/** another mod */
|
||||
[data-pubkey~="f59602a8497d21c0bda92c01cf33d1d0b2e41d5065eebcafdcbf99f973d1c105"]{
|
||||
background-image: url('/static/mgs_mod.png');
|
||||
background-size: 20%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: right bottom;
|
||||
}
|
||||
|
||||
.fagarrows {
|
||||
color: #E0727F;
|
||||
}
|
||||
|
||||
.message_span {
|
||||
white-space: pre-line;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
#captcha_img {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
BIN
contrib/static/mgs_mod.png
Normal file
BIN
contrib/static/mgs_mod.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 245 KiB |
1
contrib/static/neochan-app.js
Normal file
1
contrib/static/neochan-app.js
Normal file
@@ -0,0 +1 @@
|
||||
/** neochan js code */
|
||||
24
contrib/static/neochan.html
Normal file
24
contrib/static/neochan.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons' rel="stylesheet">
|
||||
<link href="https://unpkg.com/vuetify/dist/vuetify.min.css" rel="stylesheet">
|
||||
<title> Neochan UI </title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<v-app>
|
||||
<main>
|
||||
<v-container>Hello world</v-container>
|
||||
</main>
|
||||
</v-app>
|
||||
</div>
|
||||
|
||||
<script src="https://unpkg.com/vue/dist/vue.js"></script>
|
||||
<script src="https://unpkg.com/vuetify/dist/vuetify.js"></script>
|
||||
<script src="/static/neochan-app.js"></script>
|
||||
<script>
|
||||
new Vue({ el: '#app' })
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user