diff -uNr - - akris/LICENSE.TXT akris-genesis/LICENSE.TXT --- akris/LICENSE.TXT false +++ akris-genesis/LICENSE.TXT 6aee15c0990c8c92448c42753a109379a87ffc2047876105974414ea870bf4e7a9e869074e47ea2c1de8ac0b31b53212bf5ab59208dba3660054516062464aed @@ -0,0 +1,24 @@ +(C) 2023 Adam Thorsen ( alethepedia.com ) + +This product is distributed under "The V Public License" ("VPL"; version 0xFF.) + +This means that it is a document with a cryptographically-verifiable history of attributable authorship, rather than one of the many vile agglomerations of faecal droppings from anonymous vermin typically met with in public digital cesspools. + +The V Public License mandates that all redistribution of this product is to take the canonical form of a VTree, which consists of: a Genesis VPatch; zero or more revision VPatches; and one or more VSeals which authenticate each such VPatch, including the Genesis. + +A VPatch is defined as the output of "VDiff" on a revision against its predecessor: this is presently equivalent to standard Unix "diff -uNr PREDECESSOR SUCCESSOR", where the timestamp normally found in every delta is replaced with a Keccak hash of the original or transformed file. A Genesis VPatch is a VDiff of a "revision" constituting the initial public release of the product against a null predecessor (i.e. an empty directory). + +A VSeal is a public key signature (typically generated via GPG or a compatible program) of a particular VPatch, by an author, coauthor, or reviewer who wishes to be known as a signatory. If the creator of a VSeal has a public presence, e.g. a WWW site, the public key against which the VSeal validates must be publicly accessible and publicly associated with said presence (e.g. offered for download on the creator's WWW site.) + +This product may be used for ANY PURPOSE WHATSOEVER, and is supplied with NO WARRANTY OF ANY KIND, unless otherwise specified by written and signed agreements with all of its VSeal signatories. + +However, if you choose to redistribute the product and/or any changes you have made to it, you must do so in VTree form, and the latter must include all VPatches and VSeals you had originally received. The VTree you redistribute must be fully-compatible in every respect with the format of the one you had received. + +You may offer copies of a VPL-licensed product for download to third parties in variant (i.e. non-VTree) forms, so long as the canonical VTree form at all times exactly corresponding to every such variant is made readily and conspicuously available. Concretely, this means that if you intend to distribute a binary build of a VPL-licensed computer program, you must not only distribute its VTree with it, but must also include any and all components and instructions required to reproduce a bitwise-identical binary build. + +Similarly, if you distribute a VPL-licensed product as a source archive, via a publicly-facing version control interface, as a printed book, inside a physical device, or in any form whatsoever other than a VTree, then a VTree corresponding exactly to the item you are distributing, retaining all of the history which you had originally received, must be distributed along with every such variant copy. + +The only permitted exception to the three paragraphs above is that a VPL-licensed product MAY be incorporated whole into a new (i.e. with a novel Genesis) VTree, so long as the latter contains a statement of this fact, along with any information required to locate and retrieve a copy of the original product's canonical VTree. All provisions of the VPL shall apply to the new VTree. + +The text of this notice is itself licensed under the VPL, and is to be retained where found. + diff -uNr - - akris/Makefile akris-genesis/Makefile --- akris/Makefile false +++ akris-genesis/Makefile 987407ce4219ec115197faea5cf3ce78bdc15633ecc13e28043e2e29ab8503d2347ce4e0dae19269e6bd74cdda7031212f136d393119432c1aa6972d13935d43 @@ -0,0 +1,28 @@ +.PHONY: all test + +LATEST_VERSION := $(shell cat akris/VERSION) + +all: + @echo "Building akris..." + python3 setup.py build + +dist: + pyinstaller --onefile \ + --name akris \ + --add-data ./akris/migrations/*:./akris/migrations\ + --add-data ./akris/VERSION:./akris/\ + --add-binary ./_serpent_cffi.abi3.so:./ \ + --clean bin/main.py + staticx dist/akris dist/akris-$(LATEST_VERSION).linux.x86_64.bin + +test: + @echo "Testing akris..." + rm -f tests/fixtures/*.db + python bin/main.py --daemon --api-host 127.0.0.1 --api-port 30000 --pest-host 127.0.0.1 --pest-port 40000 --akris-data-path tests/fixtures/ --akris-database-name pizarro.db & + python bin/main.py --daemon --api-host 127.0.0.1 --api-port 30001 --pest-host 127.0.0.1 --pest-port 40001 --akris-data-path tests/fixtures/ --akris-database-name cortes.db & + python bin/main.py --daemon --api-host 127.0.0.1 --api-port 30004 --pest-host 127.0.0.1 --pest-port 40004 --akris-data-path tests/fixtures/ --akris-database-name atahualpa.db & + pytest -v -W ignore::DeprecationWarning -s tests/ + +clean: + @echo "Cleaning akris..." + rm -rf build/ dist/ .eggs/ akris.egg-info/ v-build \ No newline at end of file diff -uNr - - akris/README.md akris-genesis/README.md --- akris/README.md false +++ akris-genesis/README.md 147fc92019f89d199d46734f911aed38fcb38006ffd06744583e5a531ad10ebcd69008918514573e225aafd876feec5ce7e3eaad22f870bee9adfbc570007661 @@ -0,0 +1,115 @@ +# Akris + +## Description + +Akris implements the Pest protocol. It provides a [station](http://www.loper-os.org/?p=4003#2-the-pest-station) library that can be used +to connect to a pest network. It also provides a client library that can be used to issue commands to a station. + +This document is a work in progress. + +## Getting Akris + +### Using [V](https://archive.ph/pRfAz) + +This guide assumes a working [pentacle](http://problematic.site/src/pentacle/) chroot environment + +#### Press Akris +Download Akris patches and seals from [v.alethepedia.com/akris](https://v.alethepedia.com/akris). + + mkdir -p patches + mkdir -p seals + curl -o patches/akris-genesis-VERSION.vpatch http://v.alethepedia.com/akris/akris-genesis-VERSION.vpatch + curl -o seals/akris-genesis-VERSION.vpatch.thimbronion.sig http://v.alethepedia.com/akris/akris-genesis-VERSION.vpatch.thimbronion.sig + +Pentacle v expects gpg public keys to be found in ~/wot. + +Using the bash implementation of v provided in [pentacle](http://problematic.site/src/pentacle/), +press Akris with the leaf you wish to target (usually the patch with the lowest version number): + + v press akris patches/akris-genesis-99999.vpatch + +### From signed tarball [WIP] + +```bash +wget https://v.alethepedia.com/akris/akris-genesis-99999.tar.gz +tar zxvf akris-genesis-99999.tar.gz +cd akris +python -m venv venv +source venv/bin/activate +pip install -e . +``` + +## Install using a package manager +### From PyPI [WIP] + +```bash +pip install akris +``` + +## Installation from Source + +### Setup a virtual environment + +In the akris project root directory, run: +```bash +cd akris +python -m venv venv +source venv/bin/activate +``` + +### Install Akris from source + +```bash +pip install -e . +``` + +### Running Akris + +There are several command line options you'll need to set. You can get a list of them by running akris with the --help option: +```bash +bin/main.py +``` + +## Development + +### Editable install +This will allow tests to find the akris package, while still allowing you to edit the source code +and have the changes be reflected immediately without reinstalling. + +```bash +pip install -e . +``` + +### Install development dependencies + +```bash +pip install .[dev] +``` + +### Run tests + +```bash +make test +``` + +### Code formatting + + black . + +### Database Management +#### Create a new migration + caribou create -d akris/migrations + +### Create a static binary build +#### Pre-requisites +##### Debian/Ubuntu + sudo apt-get install patchelf +#### Linux + make dist +### Creating distribution build +#### Build a PyPI package [WIP] + python3 -m build +The output will be in the dist/ directory. Upload to PyPI with twine: +```bash +python3 -m twine upload dist/* +``` \ No newline at end of file diff -uNr - - akris/akris/VERSION akris-genesis/akris/VERSION --- akris/akris/VERSION false +++ akris-genesis/akris/VERSION 14d7328d4d921e50e9c92013a2013ade9daafd0401c780f62dad415d07a934ced36a5b0d023b083260788b256f7675c6787fc5d8aa1c22fb1c409748a21b170c @@ -0,0 +1 @@ +99999 \ No newline at end of file diff -uNr - - akris/akris/__init__.py akris-genesis/akris/__init__.py --- akris/akris/__init__.py false +++ akris-genesis/akris/__init__.py 26691c382525798d231437a34db006989c1884f59c1767858cdb4bee12bfcf9734b3105d5622e4cc5d1bf1e91765248656fd832e07a67056249c7a89703ddef8 @@ -0,0 +1 @@ +# empty diff -uNr - - akris/akris/api_service.py akris-genesis/akris/api_service.py --- akris/akris/api_service.py false +++ akris-genesis/akris/api_service.py c09b81b71d33047f1eb470e7f7628cc49f21a2dc5083d0c7320434a1b6889af6a878dc098b44eccf9566fa7ef632ae23a11dd78f04bb701a4c5a61cbf7619164 @@ -0,0 +1,166 @@ +import logging +import json +import socket +from concurrent.futures import ThreadPoolExecutor +from queue import Queue +import time + +from .log_config import LogConfig +from .console_dispatch import ConsoleDispatch +from .json_stream_parser import load_iter +from .singleton_registry import SingletonRegistry +from .singleton import Singleton + +logger = LogConfig.get_instance().get_logger("akris.api_service") + +MAX_WORKERS = 10 +HOST = "127.0.0.1" +PORT = 8080 + +def fix_phf_message(message): + try: + message["body"] = message["body"][4:] + message["body"] = message["body"][:-38] + message["body"] = message["body"].rstrip(b"\x00") + message["body"] = message["body"].decode("utf-8") + return message + except UnicodeError: + message["body"] = message["body"].decode("utf-8", errors="replace") + return message + + +class ApiService(Singleton): + def __init__(self, host, port): + # set attributes from constructor arguments + self.__dict__.update({k: v for k, v in locals().items() if k != "self"}) + + self.socket = None + self.tcp_connection = None + self.tcp_executor = None + self.outbound_queue = Queue() + self.console_dispatch = ConsoleDispatch() + self.stopped = False + scheduler = SingletonRegistry.get_instance().get("Scheduler").get_instance() + scheduler.register_task( + self.process_outbound_queue, "api_service.process_outbound_queue" + ) + + def enqueue_outbound(self, message): + try: + json_message = json.dumps(message) + except TypeError as e: + fixed_message = fix_phf_message(message) + json_message = json.dumps(fixed_message) + encoded_json = json_message.encode("utf-8") + self.outbound_queue.put(encoded_json) + + def handle_tcp_connection(self, conn, addr): + with conn: + logger.info(f"API client connected from {addr}") + self.tcp_connection = conn + sock_file = conn.makefile(mode="rw") + for command in load_iter(sock_file): + logger.info("api service received: {}".format(command)) + if command.get("command") == "shutdown": + logging.info("handle_tcp_connection received shutdown command") + self.enqueue_outbound(command) + # keep the connection open until self.stopped is set + while not self.stopped: + time.sleep(0.1) + break + if command.get("command") == "disconnect": + logger.info("disconnecting API service\n") + self.enqueue_outbound({"command": "disconnect"}) + try: + response = self.console_dispatch.execute(command) + + if type(response) == list: + for r in response: + self.enqueue_outbound(r) + else: + self.enqueue_outbound(response) + except Exception as e: + logger.exception("error executing command") + error_response = { + "command": "console_response", + "type": "error", + "body": str(e), + } + self.enqueue_outbound(error_response) + logger.info(f"client at {addr} disconnected") + + def api_service_thread(self): + while not self.stopped: + try: + logger.info( + f"API service waiting for connections on {self.host}:{self.port}" + ) + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.bind((self.host, self.port)) + sock.listen() + sock.settimeout(1) + self.socket = sock + + with ThreadPoolExecutor( + max_workers=MAX_WORKERS, + thread_name_prefix="handle_tcp_connection", + ) as executor: + while not self.stopped: + try: + conn, addr = sock.accept() + future = executor.submit( + self.handle_tcp_connection, conn, addr + ) + future.add_done_callback(self.handle_tcp_thread_done) + except TimeoutError: + pass + except OSError: + logger.exception( + f"API service failed to start on {self.host}:{self.port}" + ) + time.sleep(1) + + def process_outbound_queue(self): + while not self.stopped and not self.outbound_queue.empty(): + message = self.outbound_queue.get() + try: + logger.info("api service sending: {}".format(message)) + self.tcp_connection.sendall(message) + self.tcp_connection.sendall(b"") + if type(json.loads(message)) == dict: + if json.loads(message).get("command") == "shutdown": + logger.info("shutting down API service\n") + self.stop() + break + except AttributeError: + logger.info("client not connected") + except OSError: + logger.info("client disconnected") + self.tcp_connection = None + + def ready(self): + return self.socket is not None + + def start(self): + executor = ThreadPoolExecutor( + max_workers=1, thread_name_prefix="api_service_thread" + ) + future = executor.submit(self.api_service_thread) + future.add_done_callback(self.handle_api_service_thread_done) + + def stop(self): + self.stopped = True + + def handle_api_service_thread_done(self, future): + logger.info("handle_api_service_thread_done exited") + self.stop() + ex = future.exception() + if ex is not None: + logger.exception(f"exception in api_service_thread: {ex}") + + def handle_tcp_thread_done(self, future): + logger.info("handle_tcp_thread_done exited") + ex = future.exception() + if ex is not None: + logger.exception(f"exception in handle_tcp_thread: {ex}") diff -uNr - - akris/akris/asked_for.py akris-genesis/akris/asked_for.py --- akris/akris/asked_for.py false +++ akris-genesis/akris/asked_for.py ae994d461e5a0d370726432b0a6d60ffe49dc7381142131fe81255f1a9c783629b2ddf5258823373c3e8cccc471563d247e4e17afcb047fab50cca8120366210 @@ -0,0 +1,48 @@ +import time + +from .pest_command.message import EMPTY_CHAIN +from .singleton_registry import SingletonRegistry +from .singleton import Singleton +from .pest_command.get_data import GetData + +class AskedFor(Singleton): + def __init__(self): + self.db = SingletonRegistry.get_instance().get("Database").get_instance() + self.attempts = {} + self.requested_at = {} + scheduler = SingletonRegistry.get_instance().get("Scheduler").get_instance() + scheduler.register_task(self.retry_task, "asked_for.check_interval") + + def add(self, want_hash): + self.attempts[want_hash] = 1 + if not self.db.asked_for_expects(want_hash): + self.requested_at[want_hash] = time.time() + self.db.add_asked_for(want_hash) + + def expects(self, want_hash): + if EMPTY_CHAIN == want_hash: + return True + + return self.db.asked_for_expects(want_hash) + + def unwant(self, want_hash): + # remove the want_hash from the database + self.db.unwant(want_hash) + + # Attempt to re-send any GetDatas that we have not received a response for + def retry_task(self): + for want_hash in self.db.wanted(): + if time.time() - self.db.get_requested_at(want_hash) < self.db.get_knob( + "asked_for.get_data_wait" + ): + continue + + else: + self.db.update_requested_at(want_hash) + self.db.increment_attempts(want_hash) + GetData( + { + "speaker": self.db.get_knob("handle"), + "body": want_hash, + } + ).send() diff -uNr - - akris/akris/c_serpent/__init__.py akris-genesis/akris/c_serpent/__init__.py --- akris/akris/c_serpent/__init__.py false +++ akris-genesis/akris/c_serpent/__init__.py 26691c382525798d231437a34db006989c1884f59c1767858cdb4bee12bfcf9734b3105d5622e4cc5d1bf1e91765248656fd832e07a67056249c7a89703ddef8 @@ -0,0 +1 @@ +# empty diff -uNr - - akris/akris/c_serpent/c_serpent.c akris-genesis/akris/c_serpent/c_serpent.c --- akris/akris/c_serpent/c_serpent.c false +++ akris-genesis/akris/c_serpent/c_serpent.c f4cff7a567f0af487ab66939e333563a5413f14ff97bf8e7b417f37d0064035786b8088af9bfe4b52bffa704b4e847b5f199422b13c2ff938f41994065857905 @@ -0,0 +1,72 @@ +#include "crypto.h" +#include "lib/serpent.h" +#include +#include +#include + +void serpent_init(uint8_t *skey, + uint8_t const *key, + size_t key_size){ + + int r = serpent_setkey((void *)skey,key,key_size); + assert(r); (void)r; +} + +static inline void xor_block(uint8_t *r, + uint8_t const *a, + uint8_t const *b){ + + for(size_t x = 0;x < SERPENT_BLOCK_SIZE;x++){ + r[x] = a[x]^b[x]; + } +} + +void serpent_cbc_ciph(uint8_t const *skey, + uint8_t *dst, + uint8_t const *src, + size_t size){ + + uint8_t tmp[SERPENT_BLOCK_SIZE]; + size_t block_cnt; + + assert(size%SERPENT_BLOCK_SIZE == 0); + block_cnt = size/SERPENT_BLOCK_SIZE; + memset(tmp,0x00,SERPENT_BLOCK_SIZE); + + for(size_t x = 0;x < block_cnt;x++){ + size_t off = x*SERPENT_BLOCK_SIZE; + xor_block(tmp,src+off,tmp); + serpent_block_enc((void const *)skey,dst+off,tmp); + memcpy(tmp,dst+off,SERPENT_BLOCK_SIZE); + } +} + +void serpent_cbc_deciph(uint8_t const *skey, + uint8_t *dst, + uint8_t const *src, + size_t size){ + + uint8_t _tmp1[SERPENT_BLOCK_SIZE]; + uint8_t _tmp2[SERPENT_BLOCK_SIZE]; + uint8_t *tmp1 = _tmp1; + uint8_t *tmp2 = _tmp2; + uint8_t *tmp3; + size_t block_cnt; + + assert(size%SERPENT_BLOCK_SIZE == 0); + block_cnt = size/SERPENT_BLOCK_SIZE; + memset(tmp2,0x00,SERPENT_BLOCK_SIZE); + + for(size_t x = 0;x < block_cnt;x++){ + size_t off = x*SERPENT_BLOCK_SIZE; + + memcpy(tmp1,src+off,SERPENT_BLOCK_SIZE); + serpent_block_dec((void const *)skey,dst+off,src+off); + xor_block(dst+off,dst+off,tmp2); + + tmp3 = tmp1; + tmp1 = tmp2; + tmp2 = tmp3; + } +} + diff -uNr - - akris/akris/c_serpent/config.h akris-genesis/akris/c_serpent/config.h --- akris/akris/c_serpent/config.h false +++ akris-genesis/akris/c_serpent/config.h f7dc946d073ebc7a193706600662d7f19727567e2aee6758be1a8226dceca14e6ee431d562e32082f927e3fd91c81aaacf8c577d6ddd6b35b708192724d0bf2b @@ -0,0 +1,50 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#define RNG_PATH "/dev/urandom" //entropy source file +#define STACK_WIPE_SIZE (4*MEGABYTE) //amount of stack to zeroize/randomize +//#define BIG_ENDIAN //system endianess + +#define NET_SILENT_SLEEP 10 //milliseconds to sleep when no tcp/udp +#define NET_RETRY_SLEEP 1000 //milliseconds to sleep when cant listen tcp/udp +#define IRCD_RECV_MAX 4 //max number of recvs before yield to udp +#define PEST_RECV_MAX 32 //max number of recvs before yield to tcp +#define PEST_WAIT_IRC 10 //number of seconds to wait for irc connection before fire up pest + +#define PEER_MAX 64 //max number of peers +#define KILLFILE_MAX 64 //max number of entries in killfile +#define DEDUP_POW2 18 //dedup buffer size (2^x) +#define HEARSAY_MAX 64 //hearsay buffer size +#define PENDING_MAX 512 //pending message buffer size (msg where selfchain doenst link) +#define GETDATA_MAX 64 //max parallel getdata requests +#define HEADTAIL_MAX 16 //max number of heads/tails kept track of for each chain + +#define CHAIN_CHA_POW2 17 //chain table alloc. entries (2^x, filesize = 2^x*64) +#define CHAIN_CHA_LOAD 700 //chain table load factor (x/1000) +#define CHAIN_CHA_ZEROS 5 //chain table cha* files number of zeros +#define MESS_IDX_POW2 18 //message index table alloc. entries in (2^x, filesize = 2^x*40) +#define MESS_IDX_LOAD 700 //message index table load factor (x/1000) +#define MESS_IDX_ZEROS 5 //message index idx* files number of zeros +#define MESS_MSG_POW2 15 //message files max entries in (2^x, filesize = 2^x*428) +#define MESS_MSG_ZEROS 5 //message files number of zeros in + +#define NOTICE_CHAN //send NOTICE messages to #pest channel (chain warn. always sent) +#define CONSOLE_STAMP_FMT "%F %T" //stamp format for console output +#define GETDATA_STAMP_FMT "[%T]" //stamp format for old messages +#define GETDATA_OLDSTAMP_FMT "[%F %T]" //stamp format for >24h old messages + +#define LOG_STAMP_FMT "%F %T" //stamp format for log output +#define LOG_HASH_BYTES 4 //number of least significant bytes of sha256 to display in log +#define LOG_ANSI_COLORS //use ansi colors for packet log output +#define LOG_COLLAPSE //collapse broadcast messages into one log entry +//#define LOG_MARTIAN //log martian packets +//#define LOG_STALE //log stale (invalid timestamp) packets +//#define LOG_DUPLICATE //log duplicate packets +//#define LOG_IGNORE //log incoming and outgoing ignore packets +//#define LOG_CUTOFF //log messages discarded due to bounce cutoff +//#define LOG_IOSPAM //log io operations +//#define LOG_MESS //log message storage operations +//#define LOG_CHAIN //log chain operations + +#endif + diff -uNr - - akris/akris/c_serpent/crypto.h akris-genesis/akris/c_serpent/crypto.h --- akris/akris/c_serpent/crypto.h false +++ akris-genesis/akris/c_serpent/crypto.h 84f4e59b2bf2ab51ccce05f2480fe2beb4da2715dc436094f983a0a1ced837f441be52dec5b5b7a3a68b3365cbf0e7b97e1437a7e0253e41077cb0307baebd4d @@ -0,0 +1,75 @@ +#ifndef CRYPTO_H +#define CRYPTO_H + +#include "type.h" +#include "def.h" +#include +#include +#include +#include + +void serpent_init (uint8_t *skey,uint8_t const *key,size_t key_size); +void serpent_cbc_ciph (uint8_t const *skey,uint8_t *dst,uint8_t const *src,size_t size); +void serpent_cbc_deciph(uint8_t const *skey,uint8_t *dst,uint8_t const *src,size_t size); + +void sha256 (uint8_t *sha,uint8_t const *data,size_t data_len); +void sha384 (uint8_t *sha,uint8_t const *data,size_t data_len); +void sha512 (uint8_t *sha,uint8_t const *data,size_t data_len); + +void hmac384 (uint8_t const *key,size_t key_size,uint8_t *mac,uint8_t const *msg,size_t msg_size); + +size_t base64_dec_size (char const *in,bool nullterm); +size_t base64_dec (char const *in,uint8_t *out,size_t out_size,bool nullterm); +size_t base64_enc (uint8_t const *in,size_t in_size,char *out,size_t out_size); + +bool rng_open (char const *path); +void rng_close (void); +bool rng_read (void *data,size_t size); +bool rng_read_nolog (void *data,size_t size); + +inline void hash_data (hash_t h,void const *data,size_t size); +inline void hash_zero (hash_t h); +inline void hash_copy (hash_t dst,hash_t const src); +inline bool hash_equal (hash_t const a,hash_t const b); +inline bool hash_null (hash_t const h); + +void hash_str (char *buf,size_t buf_size,hash_t const hash); +void hash_str_log (char *buf,size_t buf_size,hash_t const hash); + +void key_zero (uint8_t *key); +void key_copy (uint8_t *dst,uint8_t const *src); +void key_xor (uint8_t *dst,uint8_t const *a,uint8_t const *b); +bool key_equal (uint8_t const *a,uint8_t const *b); + +bool key_gen (uint8_t *key); +void b64_from_key (char *buf,size_t buf_size,uint8_t const *key); +bool key_from_b64 (uint8_t *key,char const *b64_key); + +void *memset_ffs (void *dst,int c,size_t size); +bool entropy_missing (uint8_t const *data,size_t size); + +inline void hash_data(hash_t h,void const *data,size_t size){ + sha256(h,data,size); +} + +inline void hash_zero(hash_t h){ + memset(h,0x00,sizeof(hash_t)); +} + +inline void hash_copy(hash_t dst,hash_t const src){ + memcpy(dst,src,sizeof(hash_t)); +} + +inline bool hash_equal(hash_t const a,hash_t const b){ + return memcmp(a,b,sizeof(hash_t)) == 0; +} + +inline bool hash_null(hash_t const h){ + for(size_t x = 0;x < HASH_SIZE;x++){ + if(h[x] != 0x00) return 0; + } + return 1; +} + +#endif + diff -uNr - - akris/akris/c_serpent/def.h akris-genesis/akris/c_serpent/def.h --- akris/akris/c_serpent/def.h false +++ akris-genesis/akris/c_serpent/def.h b2cc3c0e4af257e1fcee75219f9496ba9a32a67b8d32edc14974bf67815a28d04b37ca404b1ec82c04bec57b7e899f66ae1537eb5eaf44a7d2e2dcb2dbb2f1ff @@ -0,0 +1,194 @@ +#ifndef DEF_H +#define DEF_H + +#define PROG_NAME "smalpest" +#define PROG_VERSION "98K" +#define PROG_FULLNAME PROG_NAME "-" PROG_VERSION + +#define INT64_LEN 20 //18446744073709551616 +#define KILOBYTE (1024) +#define MEGABYTE (1024*KILOBYTE) +#define GIGABYTE (1024*MEGABYTE) + +#define PATH_LEN 255 +#define DATA_MODE 0700 +#define DATA_UMASK (~DATA_MODE) +#define DATA_PATH_DEF "./data" +#define LOG_PATH_DEF "./log" +#define DIR_PEER "peer" +#define DIR_MESS "mess" +#define DIR_CHAIN "chain" +#define DIR_BCHAIN "bchain" +#define DIR_DCHAIN "dchain" +#define FILE_IRC_USER "user" +#define FILE_IRC_PASS "pass" +#define FILE_IRC_PORT "iport" +#define FILE_PEST_PORT "pport" +#define FILE_SCRAM_PASS "scram" +#define FILE_KILLFILE "kill" +#define FILE_SETPORT "setport" +#define FILE_CUTOFF "cutoff" +#define FILE_HSTIME "hstime" +#define FILE_GDTIME "gdtime" +#define FILE_GDATT "gdatt" +#define FILE_GDINT "gdint" +#define FILE_RKRECV "rkrecv" +#define FILE_RKSEND "rksend" +#define FILE_RKTIME "rktime" +#define FILE_RKINT "rkint" +#define FILE_IGINT "igint" +#define FILE_BANNER "banner" +#define FILE_BAINT "baint" +#define FILE_ACADDR "acaddr" +#define FILE_ACINT "acint" +#define FILE_IRCTIME "irctime" +#define FILE_MASTER "master" +#define FILE_DEDUP "dedup" +#define FILE_ALIAS "alias" +#define FILE_KEY "key" +#define FILE_ADDR "addr" +#define FILE_STAMP "stamp" +#define FILE_PAUSE "pause" +#define FILE_SELF "self" +#define FILE_NET "net" +#define FILE_HEAD "head" +#define FILE_TAIL "tail" + +#define WHITE_LEN 32 //allocated for whitespace/extra newline/whatever in files + +#define PORT_MIN 0 +#define PORT_MAX 65535 +#define IPV4_LEN 15 //255.255.255.255 +#define IPV4_CHARSET "0123456789." +#define PORT_LEN 5 //55555 +#define PORT_CHARSET "0123456789" +#define AT_LEN (IPV4_LEN+1+PORT_LEN) //IPV4:PORT +#define STAMP_LEN 64 + +#define IRC_PORT_DEF 6668 +#define IRC_MSG_LEN 512 +#define IRC_USER_LEN 63 +#define IRC_HOST_LEN 63 +#define IRC_SERV_LEN 63 +#define IRC_CHAN_LEN 128 +#define IRCD_ARG_MAX 8 +#define IRCD_CMD_LEN 31 +#define IRC_SERV "pest" +#define IRC_MOTD "welcome, operator" +#define IRC_PEERHOST "pest.net" + +#define PEST_PORT_DEF 7778 +#define HANDLE_LEN SPEAKER_SIZE +#define HANDLE_MAX 8 +#define HANDLE_CHARSET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-" +#define KEY_MAX 8 +#define DEDUP_MAX (1< +#include + +static uint8_t const base64_pr2six[256] = { + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x3E,0x40,0x40,0x40,0x3F, + 0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E, + 0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x40,0x40,0x40,0x40,0x40, + 0x40,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28, + 0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, +}; + +static char const base64_basis[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +size_t base64_dec_size(char const *in,bool nullterm){ + size_t nbd; + size_t npr; + char const *in2; + + in2 = in; + while(base64_pr2six[(uint8_t)*(in2++)] < 0x40); + npr = in2-in-1; + nbd = ((npr+3)/4)*3; + + while(npr > 4) npr -= 4; + nbd -= (4-npr) & 3; + nbd += nullterm; + return nbd; +} + +size_t base64_dec(char const *in,uint8_t *out,size_t out_size,bool nullterm){ + size_t nbd; + char const *in2; + size_t npr; + + assert(out_size >= base64_dec_size(in,nullterm)); + (void)out_size; + + in2 = in; + while(base64_pr2six[(uint8_t)*(in2++)] < 0x40); + npr = in2-in-1; + nbd = ((npr+3)/4)*3; + in2 = in; + + while(npr > 4){ + *out++ = base64_pr2six[(uint8_t)*in2] << 2 | base64_pr2six[(uint8_t)in2[1]]>>4; + *out++ = base64_pr2six[(uint8_t)in2[1]] << 4 | base64_pr2six[(uint8_t)in2[2]]>>2; + *out++ = base64_pr2six[(uint8_t)in2[2]] << 6 | base64_pr2six[(uint8_t)in2[3]]; + in2 += 4; + npr -= 4; + } + + if(npr > 1) *out++ = base64_pr2six[(uint8_t)*in2] << 2 | base64_pr2six[(uint8_t)in2[1]]>>4; + if(npr > 2) *out++ = base64_pr2six[(uint8_t)in2[1]] << 4 | base64_pr2six[(uint8_t)in2[2]]>>2; + if(npr > 3) *out++ = base64_pr2six[(uint8_t)in2[2]] << 6 | base64_pr2six[(uint8_t)in2[3]]; + + if(nullterm) *out++ = 0; + nbd -= (4-npr) & 3; + nbd += nullterm; + return nbd; +} + +size_t base64_enc(uint8_t const *in,size_t in_size,char *out,size_t out_size){ + char *p = out; + size_t i; + + assert(out_size >= BASE64_ENC_SIZE(in_size,1)); + (void)out_size; + + for(i = 0;i < in_size-2;i += 3){ + *p++ = base64_basis[in[i]>>2 & 0x3F]; + *p++ = base64_basis[(in[i] & 0x03)<<4 | (int32_t)(in[i+1] & 0xF0)>>4]; + *p++ = base64_basis[(in[i+1] & 0x0F)<<2 | (int32_t)(in[i+2] & 0xC0)>>6]; + *p++ = base64_basis[in[i+2] & 0x3F]; + } + + if(i < in_size){ + *p++ = base64_basis[in[i]>>2 & 0x3F]; + if(i == in_size-1){ + *p++ = base64_basis[(in[i] & 0x03)<<4]; + *p++ = '='; + }else{ + *p++ = base64_basis[(in[i] & 0x03)<<4 | (int32_t)(in[i+1] & 0xF0)>>4]; + *p++ = base64_basis[(in[i+1] & 0x0F)<<2]; + } + *p++ = '='; + } + + *p++ = 0; + return p-out; +} + diff -uNr - - akris/akris/c_serpent/lib/hmac.c akris-genesis/akris/c_serpent/lib/hmac.c --- akris/akris/c_serpent/lib/hmac.c false +++ akris-genesis/akris/c_serpent/lib/hmac.c 753dda1c250612d1189c94b6b919dc049f3587fb607aca9a02b6d8a2c1646dd5e1c70b256cacbf540ba7ecf364c3c57c67ed4104b9c9199b9cbebc3ea88434cd @@ -0,0 +1,118 @@ +/* + * HMAC-SHA-224/256/384/512 implementation + * Last update: 06/15/2005 + * Issue date: 06/15/2005 + * + * Copyright (C) 2005 Olivier Gay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * ********************MODIFIED FOR USE IN SMALPEST******************** + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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. + */ + +#include "hmac.h" +#include + +static void sha384(uint8_t *sha,uint8_t const *msg,size_t msg_len){ + sha384_ctx ctx; + sha384_init(&ctx); + sha384_update(&ctx,msg,msg_len); + sha384_final(&ctx,sha); +} + +void hmac_sha384_init(hmac_sha384_ctx *ctx, const unsigned char *key, + unsigned int key_size) +{ + unsigned int fill; + unsigned int num; + + const unsigned char *key_used; + unsigned char key_temp[SHA384_DIGEST_SIZE]; + int i; + + if (key_size == SHA384_BLOCK_SIZE) { + key_used = key; + num = SHA384_BLOCK_SIZE; + } else { + if (key_size > SHA384_BLOCK_SIZE){ + num = SHA384_DIGEST_SIZE; + sha384(key_temp,key,key_size); + key_used = key_temp; + } else { /* key_size > SHA384_BLOCK_SIZE */ + key_used = key; + num = key_size; + } + fill = SHA384_BLOCK_SIZE - num; + + memset(ctx->block_ipad + num, 0x36, fill); + memset(ctx->block_opad + num, 0x5c, fill); + } + + for (i = 0; i < (int) num; i++) { + ctx->block_ipad[i] = key_used[i] ^ 0x36; + ctx->block_opad[i] = key_used[i] ^ 0x5c; + } + + sha384_init(&ctx->ctx_inside); + sha384_update(&ctx->ctx_inside, ctx->block_ipad, SHA384_BLOCK_SIZE); + + sha384_init(&ctx->ctx_outside); + sha384_update(&ctx->ctx_outside, ctx->block_opad, + SHA384_BLOCK_SIZE); + + /* for hmac_reinit */ + memcpy(&ctx->ctx_inside_reinit, &ctx->ctx_inside, + sizeof(sha384_ctx)); + memcpy(&ctx->ctx_outside_reinit, &ctx->ctx_outside, + sizeof(sha384_ctx)); +} + +void hmac_sha384_reinit(hmac_sha384_ctx *ctx) +{ + memcpy(&ctx->ctx_inside, &ctx->ctx_inside_reinit, + sizeof(sha384_ctx)); + memcpy(&ctx->ctx_outside, &ctx->ctx_outside_reinit, + sizeof(sha384_ctx)); +} + +void hmac_sha384_update(hmac_sha384_ctx *ctx, const unsigned char *message, + unsigned int message_len) +{ + sha384_update(&ctx->ctx_inside, message, message_len); +} + +void hmac_sha384_final(hmac_sha384_ctx *ctx, unsigned char *mac, + unsigned int mac_size) +{ + unsigned char digest_inside[SHA384_DIGEST_SIZE]; + unsigned char mac_temp[SHA384_DIGEST_SIZE]; + + sha384_final(&ctx->ctx_inside, digest_inside); + sha384_update(&ctx->ctx_outside, digest_inside, SHA384_DIGEST_SIZE); + sha384_final(&ctx->ctx_outside, mac_temp); + memcpy(mac, mac_temp, mac_size); +} + diff -uNr - - akris/akris/c_serpent/lib/hmac.h akris-genesis/akris/c_serpent/lib/hmac.h --- akris/akris/c_serpent/lib/hmac.h false +++ akris-genesis/akris/c_serpent/lib/hmac.h edc00426d5a81ff3e6fba03aa372540e04d6dbbde6309bc9a5e7974f03366dba16dee546f50f211ee53aacf208d5ba888260b1f3f1eedee389266d045c4f2851 @@ -0,0 +1,64 @@ +/* + * HMAC-SHA-224/256/384/512 implementation + * Last update: 06/15/2005 + * Issue date: 06/15/2005 + * + * Copyright (C) 2005 Olivier Gay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * ********************MODIFIED FOR USE IN SMALPEST******************** + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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. + */ + +#ifndef HMAC_SHA2_H +#define HMAC_SHA2_H + +#include "sha.h" + +typedef struct { + sha384_ctx ctx_inside; + sha384_ctx ctx_outside; + + /* for hmac_reinit */ + sha384_ctx ctx_inside_reinit; + sha384_ctx ctx_outside_reinit; + + unsigned char block_ipad[SHA384_BLOCK_SIZE]; + unsigned char block_opad[SHA384_BLOCK_SIZE]; +} hmac_sha384_ctx; + +void hmac_sha384_init(hmac_sha384_ctx *ctx, const unsigned char *key, + unsigned int key_size); +void hmac_sha384_reinit(hmac_sha384_ctx *ctx); +void hmac_sha384_update(hmac_sha384_ctx *ctx, const unsigned char *message, + unsigned int message_len); +void hmac_sha384_final(hmac_sha384_ctx *ctx, unsigned char *mac, + unsigned int mac_size); +void hmac_sha384(const unsigned char *key, unsigned int key_size, + const unsigned char *message, unsigned int message_len, + unsigned char *mac, unsigned mac_size); + +#endif /* !HMAC_SHA2_H */ diff -uNr - - akris/akris/c_serpent/lib/serpent.c akris-genesis/akris/c_serpent/lib/serpent.c --- akris/akris/c_serpent/lib/serpent.c false +++ akris-genesis/akris/c_serpent/lib/serpent.c dbff4119259f0a95cff338092e34b772d98f61b7940806c4c3dadf735a97ddf1d333d46eb40bb981f53b80d5e7571b2c9f96f4c76182987edac989a6b49a6830 @@ -0,0 +1,464 @@ +/* + * Cryptographic API. + * + * Serpent Cipher Algorithm. + * + * Copyright (C) 2002 Dag Arne Osvik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ********************MODIFIED FOR USE IN SMALPEST******************** + * + */ + +/* Key is padded to the maximum of 256 bits before round key generation. + * Any key length <= 256 bits (32 bytes) is allowed by the algorithm. + */ + +#include "serpent.h" +#include +#include + +//#define SERPENT_MIN_KEY_SIZE 0 +#define SERPENT_MAX_KEY_SIZE 32 + +#define PHI 0x9e3779b9UL +#define ROL(x,r) ((x) = ((x) << (r)) | ((x) >> (32-(r)))) +#define ROR(x,r) ((x) = ((x) >> (r)) | ((x) << (32-(r)))) + +#define keyiter(a,b,c,d,i,j) \ + b ^= d; b ^= c; b ^= a; b ^= PHI ^ i; ROL(b,11); k[j] = b; + +#define loadkeys(x0,x1,x2,x3,i) \ + x0=k[i]; x1=k[i+1]; x2=k[i+2]; x3=k[i+3]; + +#define storekeys(x0,x1,x2,x3,i) \ + k[i]=x0; k[i+1]=x1; k[i+2]=x2; k[i+3]=x3; + +#define K(x0,x1,x2,x3,i) \ + x3 ^= k[4*(i)+3]; x2 ^= k[4*(i)+2]; \ + x1 ^= k[4*(i)+1]; x0 ^= k[4*(i)+0]; + +#define LK(x0,x1,x2,x3,x4,i) \ + ROL(x0,13); \ + ROL(x2,3); x1 ^= x0; x4 = x0 << 3; \ + x3 ^= x2; x1 ^= x2; \ + ROL(x1,1); x3 ^= x4; \ + ROL(x3,7); x4 = x1; \ + x0 ^= x1; x4 <<= 7; x2 ^= x3; \ + x0 ^= x3; x2 ^= x4; x3 ^= k[4*i+3]; \ + x1 ^= k[4*i+1]; ROL(x0,5); ROL(x2,22); \ + x0 ^= k[4*i+0]; x2 ^= k[4*i+2]; + +#define KL(x0,x1,x2,x3,x4,i) \ + x0 ^= k[4*i+0]; x1 ^= k[4*i+1]; x2 ^= k[4*i+2]; \ + x3 ^= k[4*i+3]; ROR(x0,5); ROR(x2,22); \ + x4 = x1; x2 ^= x3; x0 ^= x3; \ + x4 <<= 7; x0 ^= x1; ROR(x1,1); \ + x2 ^= x4; ROR(x3,7); x4 = x0 << 3; \ + x1 ^= x0; x3 ^= x4; ROR(x0,13); \ + x1 ^= x2; x3 ^= x2; ROR(x2,3); + +#define S0(x0,x1,x2,x3,x4) \ + x4 = x3; \ + x3 |= x0; x0 ^= x4; x4 ^= x2; \ + x4 =~ x4; x3 ^= x1; x1 &= x0; \ + x1 ^= x4; x2 ^= x0; x0 ^= x3; \ + x4 |= x0; x0 ^= x2; x2 &= x1; \ + x3 ^= x2; x1 =~ x1; x2 ^= x4; \ + x1 ^= x2; + +#define S1(x0,x1,x2,x3,x4) \ + x4 = x1; \ + x1 ^= x0; x0 ^= x3; x3 =~ x3; \ + x4 &= x1; x0 |= x1; x3 ^= x2; \ + x0 ^= x3; x1 ^= x3; x3 ^= x4; \ + x1 |= x4; x4 ^= x2; x2 &= x0; \ + x2 ^= x1; x1 |= x0; x0 =~ x0; \ + x0 ^= x2; x4 ^= x1; + +#define S2(x0,x1,x2,x3,x4) \ + x3 =~ x3; \ + x1 ^= x0; x4 = x0; x0 &= x2; \ + x0 ^= x3; x3 |= x4; x2 ^= x1; \ + x3 ^= x1; x1 &= x0; x0 ^= x2; \ + x2 &= x3; x3 |= x1; x0 =~ x0; \ + x3 ^= x0; x4 ^= x0; x0 ^= x2; \ + x1 |= x2; + +#define S3(x0,x1,x2,x3,x4) \ + x4 = x1; \ + x1 ^= x3; x3 |= x0; x4 &= x0; \ + x0 ^= x2; x2 ^= x1; x1 &= x3; \ + x2 ^= x3; x0 |= x4; x4 ^= x3; \ + x1 ^= x0; x0 &= x3; x3 &= x4; \ + x3 ^= x2; x4 |= x1; x2 &= x1; \ + x4 ^= x3; x0 ^= x3; x3 ^= x2; + +#define S4(x0,x1,x2,x3,x4) \ + x4 = x3; \ + x3 &= x0; x0 ^= x4; \ + x3 ^= x2; x2 |= x4; x0 ^= x1; \ + x4 ^= x3; x2 |= x0; \ + x2 ^= x1; x1 &= x0; \ + x1 ^= x4; x4 &= x2; x2 ^= x3; \ + x4 ^= x0; x3 |= x1; x1 =~ x1; \ + x3 ^= x0; + +#define S5(x0,x1,x2,x3,x4) \ + x4 = x1; x1 |= x0; \ + x2 ^= x1; x3 =~ x3; x4 ^= x0; \ + x0 ^= x2; x1 &= x4; x4 |= x3; \ + x4 ^= x0; x0 &= x3; x1 ^= x3; \ + x3 ^= x2; x0 ^= x1; x2 &= x4; \ + x1 ^= x2; x2 &= x0; \ + x3 ^= x2; + +#define S6(x0,x1,x2,x3,x4) \ + x4 = x1; \ + x3 ^= x0; x1 ^= x2; x2 ^= x0; \ + x0 &= x3; x1 |= x3; x4 =~ x4; \ + x0 ^= x1; x1 ^= x2; \ + x3 ^= x4; x4 ^= x0; x2 &= x0; \ + x4 ^= x1; x2 ^= x3; x3 &= x1; \ + x3 ^= x0; x1 ^= x2; + +#define S7(x0,x1,x2,x3,x4) \ + x1 =~ x1; \ + x4 = x1; x0 =~ x0; x1 &= x2; \ + x1 ^= x3; x3 |= x4; x4 ^= x2; \ + x2 ^= x3; x3 ^= x0; x0 |= x1; \ + x2 &= x0; x0 ^= x4; x4 ^= x3; \ + x3 &= x0; x4 ^= x1; \ + x2 ^= x4; x3 ^= x1; x4 |= x0; \ + x4 ^= x1; + +#define SI0(x0,x1,x2,x3,x4) \ + x4 = x3; x1 ^= x0; \ + x3 |= x1; x4 ^= x1; x0 =~ x0; \ + x2 ^= x3; x3 ^= x0; x0 &= x1; \ + x0 ^= x2; x2 &= x3; x3 ^= x4; \ + x2 ^= x3; x1 ^= x3; x3 &= x0; \ + x1 ^= x0; x0 ^= x2; x4 ^= x3; + +#define SI1(x0,x1,x2,x3,x4) \ + x1 ^= x3; x4 = x0; \ + x0 ^= x2; x2 =~ x2; x4 |= x1; \ + x4 ^= x3; x3 &= x1; x1 ^= x2; \ + x2 &= x4; x4 ^= x1; x1 |= x3; \ + x3 ^= x0; x2 ^= x0; x0 |= x4; \ + x2 ^= x4; x1 ^= x0; \ + x4 ^= x1; + +#define SI2(x0,x1,x2,x3,x4) \ + x2 ^= x1; x4 = x3; x3 =~ x3; \ + x3 |= x2; x2 ^= x4; x4 ^= x0; \ + x3 ^= x1; x1 |= x2; x2 ^= x0; \ + x1 ^= x4; x4 |= x3; x2 ^= x3; \ + x4 ^= x2; x2 &= x1; \ + x2 ^= x3; x3 ^= x4; x4 ^= x0; + +#define SI3(x0,x1,x2,x3,x4) \ + x2 ^= x1; \ + x4 = x1; x1 &= x2; \ + x1 ^= x0; x0 |= x4; x4 ^= x3; \ + x0 ^= x3; x3 |= x1; x1 ^= x2; \ + x1 ^= x3; x0 ^= x2; x2 ^= x3; \ + x3 &= x1; x1 ^= x0; x0 &= x2; \ + x4 ^= x3; x3 ^= x0; x0 ^= x1; + +#define SI4(x0,x1,x2,x3,x4) \ + x2 ^= x3; x4 = x0; x0 &= x1; \ + x0 ^= x2; x2 |= x3; x4 =~ x4; \ + x1 ^= x0; x0 ^= x2; x2 &= x4; \ + x2 ^= x0; x0 |= x4; \ + x0 ^= x3; x3 &= x2; \ + x4 ^= x3; x3 ^= x1; x1 &= x0; \ + x4 ^= x1; x0 ^= x3; + +#define SI5(x0,x1,x2,x3,x4) \ + x4 = x1; x1 |= x2; \ + x2 ^= x4; x1 ^= x3; x3 &= x4; \ + x2 ^= x3; x3 |= x0; x0 =~ x0; \ + x3 ^= x2; x2 |= x0; x4 ^= x1; \ + x2 ^= x4; x4 &= x0; x0 ^= x1; \ + x1 ^= x3; x0 &= x2; x2 ^= x3; \ + x0 ^= x2; x2 ^= x4; x4 ^= x3; + +#define SI6(x0,x1,x2,x3,x4) \ + x0 ^= x2; \ + x4 = x0; x0 &= x3; x2 ^= x3; \ + x0 ^= x2; x3 ^= x1; x2 |= x4; \ + x2 ^= x3; x3 &= x0; x0 =~ x0; \ + x3 ^= x1; x1 &= x2; x4 ^= x0; \ + x3 ^= x4; x4 ^= x2; x0 ^= x1; \ + x2 ^= x0; + +#define SI7(x0,x1,x2,x3,x4) \ + x4 = x3; x3 &= x0; x0 ^= x2; \ + x2 |= x4; x4 ^= x1; x0 =~ x0; \ + x1 |= x3; x4 ^= x0; x0 &= x2; \ + x0 ^= x1; x1 &= x2; x3 ^= x2; \ + x4 ^= x3; x2 &= x3; x3 |= x0; \ + x1 ^= x4; x3 ^= x4; x4 &= x0; \ + x4 ^= x2; + +#define le32_to_cpu(I) I +#define cpu_to_le32(I) I + +int serpent_setkey(uint32_t *k,uint8_t const *key,size_t keylen){ + uint8_t *k8 = (uint8_t *)k; + uint32_t r0,r1,r2,r3,r4; + int i; + + //if ((keylen < SERPENT_MIN_KEY_SIZE) + //|| (keylen > SERPENT_MAX_KEY_SIZE)) + if (keylen > SERPENT_MAX_KEY_SIZE) + { + return 0; + } + + /* Copy key, add padding */ + + for (i = 0; (size_t)i < keylen; ++i) + k8[i] = key[i]; + if (i < SERPENT_MAX_KEY_SIZE) + k8[i++] = 1; + while (i < SERPENT_MAX_KEY_SIZE) + k8[i++] = 0; + + /* Expand key using polynomial */ + + r0 = le32_to_cpu(k[3]); + r1 = le32_to_cpu(k[4]); + r2 = le32_to_cpu(k[5]); + r3 = le32_to_cpu(k[6]); + r4 = le32_to_cpu(k[7]); + + keyiter(le32_to_cpu(k[0]),r0,r4,r2,0,0); + keyiter(le32_to_cpu(k[1]),r1,r0,r3,1,1); + keyiter(le32_to_cpu(k[2]),r2,r1,r4,2,2); + keyiter(le32_to_cpu(k[3]),r3,r2,r0,3,3); + keyiter(le32_to_cpu(k[4]),r4,r3,r1,4,4); + keyiter(le32_to_cpu(k[5]),r0,r4,r2,5,5); + keyiter(le32_to_cpu(k[6]),r1,r0,r3,6,6); + keyiter(le32_to_cpu(k[7]),r2,r1,r4,7,7); + + keyiter(k[ 0],r3,r2,r0, 8, 8); keyiter(k[ 1],r4,r3,r1, 9, 9); + keyiter(k[ 2],r0,r4,r2, 10, 10); keyiter(k[ 3],r1,r0,r3, 11, 11); + keyiter(k[ 4],r2,r1,r4, 12, 12); keyiter(k[ 5],r3,r2,r0, 13, 13); + keyiter(k[ 6],r4,r3,r1, 14, 14); keyiter(k[ 7],r0,r4,r2, 15, 15); + keyiter(k[ 8],r1,r0,r3, 16, 16); keyiter(k[ 9],r2,r1,r4, 17, 17); + keyiter(k[ 10],r3,r2,r0, 18, 18); keyiter(k[ 11],r4,r3,r1, 19, 19); + keyiter(k[ 12],r0,r4,r2, 20, 20); keyiter(k[ 13],r1,r0,r3, 21, 21); + keyiter(k[ 14],r2,r1,r4, 22, 22); keyiter(k[ 15],r3,r2,r0, 23, 23); + keyiter(k[ 16],r4,r3,r1, 24, 24); keyiter(k[ 17],r0,r4,r2, 25, 25); + keyiter(k[ 18],r1,r0,r3, 26, 26); keyiter(k[ 19],r2,r1,r4, 27, 27); + keyiter(k[ 20],r3,r2,r0, 28, 28); keyiter(k[ 21],r4,r3,r1, 29, 29); + keyiter(k[ 22],r0,r4,r2, 30, 30); keyiter(k[ 23],r1,r0,r3, 31, 31); + + k += 50; + + keyiter(k[-26],r2,r1,r4, 32,-18); keyiter(k[-25],r3,r2,r0, 33,-17); + keyiter(k[-24],r4,r3,r1, 34,-16); keyiter(k[-23],r0,r4,r2, 35,-15); + keyiter(k[-22],r1,r0,r3, 36,-14); keyiter(k[-21],r2,r1,r4, 37,-13); + keyiter(k[-20],r3,r2,r0, 38,-12); keyiter(k[-19],r4,r3,r1, 39,-11); + keyiter(k[-18],r0,r4,r2, 40,-10); keyiter(k[-17],r1,r0,r3, 41, -9); + keyiter(k[-16],r2,r1,r4, 42, -8); keyiter(k[-15],r3,r2,r0, 43, -7); + keyiter(k[-14],r4,r3,r1, 44, -6); keyiter(k[-13],r0,r4,r2, 45, -5); + keyiter(k[-12],r1,r0,r3, 46, -4); keyiter(k[-11],r2,r1,r4, 47, -3); + keyiter(k[-10],r3,r2,r0, 48, -2); keyiter(k[ -9],r4,r3,r1, 49, -1); + keyiter(k[ -8],r0,r4,r2, 50, 0); keyiter(k[ -7],r1,r0,r3, 51, 1); + keyiter(k[ -6],r2,r1,r4, 52, 2); keyiter(k[ -5],r3,r2,r0, 53, 3); + keyiter(k[ -4],r4,r3,r1, 54, 4); keyiter(k[ -3],r0,r4,r2, 55, 5); + keyiter(k[ -2],r1,r0,r3, 56, 6); keyiter(k[ -1],r2,r1,r4, 57, 7); + keyiter(k[ 0],r3,r2,r0, 58, 8); keyiter(k[ 1],r4,r3,r1, 59, 9); + keyiter(k[ 2],r0,r4,r2, 60, 10); keyiter(k[ 3],r1,r0,r3, 61, 11); + keyiter(k[ 4],r2,r1,r4, 62, 12); keyiter(k[ 5],r3,r2,r0, 63, 13); + keyiter(k[ 6],r4,r3,r1, 64, 14); keyiter(k[ 7],r0,r4,r2, 65, 15); + keyiter(k[ 8],r1,r0,r3, 66, 16); keyiter(k[ 9],r2,r1,r4, 67, 17); + keyiter(k[ 10],r3,r2,r0, 68, 18); keyiter(k[ 11],r4,r3,r1, 69, 19); + keyiter(k[ 12],r0,r4,r2, 70, 20); keyiter(k[ 13],r1,r0,r3, 71, 21); + keyiter(k[ 14],r2,r1,r4, 72, 22); keyiter(k[ 15],r3,r2,r0, 73, 23); + keyiter(k[ 16],r4,r3,r1, 74, 24); keyiter(k[ 17],r0,r4,r2, 75, 25); + keyiter(k[ 18],r1,r0,r3, 76, 26); keyiter(k[ 19],r2,r1,r4, 77, 27); + keyiter(k[ 20],r3,r2,r0, 78, 28); keyiter(k[ 21],r4,r3,r1, 79, 29); + keyiter(k[ 22],r0,r4,r2, 80, 30); keyiter(k[ 23],r1,r0,r3, 81, 31); + + k += 50; + + keyiter(k[-26],r2,r1,r4, 82,-18); keyiter(k[-25],r3,r2,r0, 83,-17); + keyiter(k[-24],r4,r3,r1, 84,-16); keyiter(k[-23],r0,r4,r2, 85,-15); + keyiter(k[-22],r1,r0,r3, 86,-14); keyiter(k[-21],r2,r1,r4, 87,-13); + keyiter(k[-20],r3,r2,r0, 88,-12); keyiter(k[-19],r4,r3,r1, 89,-11); + keyiter(k[-18],r0,r4,r2, 90,-10); keyiter(k[-17],r1,r0,r3, 91, -9); + keyiter(k[-16],r2,r1,r4, 92, -8); keyiter(k[-15],r3,r2,r0, 93, -7); + keyiter(k[-14],r4,r3,r1, 94, -6); keyiter(k[-13],r0,r4,r2, 95, -5); + keyiter(k[-12],r1,r0,r3, 96, -4); keyiter(k[-11],r2,r1,r4, 97, -3); + keyiter(k[-10],r3,r2,r0, 98, -2); keyiter(k[ -9],r4,r3,r1, 99, -1); + keyiter(k[ -8],r0,r4,r2,100, 0); keyiter(k[ -7],r1,r0,r3,101, 1); + keyiter(k[ -6],r2,r1,r4,102, 2); keyiter(k[ -5],r3,r2,r0,103, 3); + keyiter(k[ -4],r4,r3,r1,104, 4); keyiter(k[ -3],r0,r4,r2,105, 5); + keyiter(k[ -2],r1,r0,r3,106, 6); keyiter(k[ -1],r2,r1,r4,107, 7); + keyiter(k[ 0],r3,r2,r0,108, 8); keyiter(k[ 1],r4,r3,r1,109, 9); + keyiter(k[ 2],r0,r4,r2,110, 10); keyiter(k[ 3],r1,r0,r3,111, 11); + keyiter(k[ 4],r2,r1,r4,112, 12); keyiter(k[ 5],r3,r2,r0,113, 13); + keyiter(k[ 6],r4,r3,r1,114, 14); keyiter(k[ 7],r0,r4,r2,115, 15); + keyiter(k[ 8],r1,r0,r3,116, 16); keyiter(k[ 9],r2,r1,r4,117, 17); + keyiter(k[ 10],r3,r2,r0,118, 18); keyiter(k[ 11],r4,r3,r1,119, 19); + keyiter(k[ 12],r0,r4,r2,120, 20); keyiter(k[ 13],r1,r0,r3,121, 21); + keyiter(k[ 14],r2,r1,r4,122, 22); keyiter(k[ 15],r3,r2,r0,123, 23); + keyiter(k[ 16],r4,r3,r1,124, 24); keyiter(k[ 17],r0,r4,r2,125, 25); + keyiter(k[ 18],r1,r0,r3,126, 26); keyiter(k[ 19],r2,r1,r4,127, 27); + keyiter(k[ 20],r3,r2,r0,128, 28); keyiter(k[ 21],r4,r3,r1,129, 29); + keyiter(k[ 22],r0,r4,r2,130, 30); keyiter(k[ 23],r1,r0,r3,131, 31); + + /* Apply S-boxes */ + + S3(r3,r4,r0,r1,r2); storekeys(r1,r2,r4,r3, 28); loadkeys(r1,r2,r4,r3, 24); + S4(r1,r2,r4,r3,r0); storekeys(r2,r4,r3,r0, 24); loadkeys(r2,r4,r3,r0, 20); + S5(r2,r4,r3,r0,r1); storekeys(r1,r2,r4,r0, 20); loadkeys(r1,r2,r4,r0, 16); + S6(r1,r2,r4,r0,r3); storekeys(r4,r3,r2,r0, 16); loadkeys(r4,r3,r2,r0, 12); + S7(r4,r3,r2,r0,r1); storekeys(r1,r2,r0,r4, 12); loadkeys(r1,r2,r0,r4, 8); + S0(r1,r2,r0,r4,r3); storekeys(r0,r2,r4,r1, 8); loadkeys(r0,r2,r4,r1, 4); + S1(r0,r2,r4,r1,r3); storekeys(r3,r4,r1,r0, 4); loadkeys(r3,r4,r1,r0, 0); + S2(r3,r4,r1,r0,r2); storekeys(r2,r4,r3,r0, 0); loadkeys(r2,r4,r3,r0, -4); + S3(r2,r4,r3,r0,r1); storekeys(r0,r1,r4,r2, -4); loadkeys(r0,r1,r4,r2, -8); + S4(r0,r1,r4,r2,r3); storekeys(r1,r4,r2,r3, -8); loadkeys(r1,r4,r2,r3,-12); + S5(r1,r4,r2,r3,r0); storekeys(r0,r1,r4,r3,-12); loadkeys(r0,r1,r4,r3,-16); + S6(r0,r1,r4,r3,r2); storekeys(r4,r2,r1,r3,-16); loadkeys(r4,r2,r1,r3,-20); + S7(r4,r2,r1,r3,r0); storekeys(r0,r1,r3,r4,-20); loadkeys(r0,r1,r3,r4,-24); + S0(r0,r1,r3,r4,r2); storekeys(r3,r1,r4,r0,-24); loadkeys(r3,r1,r4,r0,-28); + k -= 50; + S1(r3,r1,r4,r0,r2); storekeys(r2,r4,r0,r3, 22); loadkeys(r2,r4,r0,r3, 18); + S2(r2,r4,r0,r3,r1); storekeys(r1,r4,r2,r3, 18); loadkeys(r1,r4,r2,r3, 14); + S3(r1,r4,r2,r3,r0); storekeys(r3,r0,r4,r1, 14); loadkeys(r3,r0,r4,r1, 10); + S4(r3,r0,r4,r1,r2); storekeys(r0,r4,r1,r2, 10); loadkeys(r0,r4,r1,r2, 6); + S5(r0,r4,r1,r2,r3); storekeys(r3,r0,r4,r2, 6); loadkeys(r3,r0,r4,r2, 2); + S6(r3,r0,r4,r2,r1); storekeys(r4,r1,r0,r2, 2); loadkeys(r4,r1,r0,r2, -2); + S7(r4,r1,r0,r2,r3); storekeys(r3,r0,r2,r4, -2); loadkeys(r3,r0,r2,r4, -6); + S0(r3,r0,r2,r4,r1); storekeys(r2,r0,r4,r3, -6); loadkeys(r2,r0,r4,r3,-10); + S1(r2,r0,r4,r3,r1); storekeys(r1,r4,r3,r2,-10); loadkeys(r1,r4,r3,r2,-14); + S2(r1,r4,r3,r2,r0); storekeys(r0,r4,r1,r2,-14); loadkeys(r0,r4,r1,r2,-18); + S3(r0,r4,r1,r2,r3); storekeys(r2,r3,r4,r0,-18); loadkeys(r2,r3,r4,r0,-22); + k -= 50; + S4(r2,r3,r4,r0,r1); storekeys(r3,r4,r0,r1, 28); loadkeys(r3,r4,r0,r1, 24); + S5(r3,r4,r0,r1,r2); storekeys(r2,r3,r4,r1, 24); loadkeys(r2,r3,r4,r1, 20); + S6(r2,r3,r4,r1,r0); storekeys(r4,r0,r3,r1, 20); loadkeys(r4,r0,r3,r1, 16); + S7(r4,r0,r3,r1,r2); storekeys(r2,r3,r1,r4, 16); loadkeys(r2,r3,r1,r4, 12); + S0(r2,r3,r1,r4,r0); storekeys(r1,r3,r4,r2, 12); loadkeys(r1,r3,r4,r2, 8); + S1(r1,r3,r4,r2,r0); storekeys(r0,r4,r2,r1, 8); loadkeys(r0,r4,r2,r1, 4); + S2(r0,r4,r2,r1,r3); storekeys(r3,r4,r0,r1, 4); loadkeys(r3,r4,r0,r1, 0); + S3(r3,r4,r0,r1,r2); storekeys(r1,r2,r4,r3, 0); + + return 1; +} + +void serpent_block_enc(uint32_t const *k,uint8_t *dst,uint8_t const *src){ + const uint32_t *s = (const uint32_t *)src; + uint32_t *d = (uint32_t *)dst, + r0, r1, r2, r3, r4; + +/* + * Note: The conversions between uint8_t* and uint32_t* might cause trouble + * on architectures with stricter alignment rules than x86 + */ + + r0 = le32_to_cpu(s[0]); + r1 = le32_to_cpu(s[1]); + r2 = le32_to_cpu(s[2]); + r3 = le32_to_cpu(s[3]); + + K(r0,r1,r2,r3,0); + S0(r0,r1,r2,r3,r4); LK(r2,r1,r3,r0,r4,1); + S1(r2,r1,r3,r0,r4); LK(r4,r3,r0,r2,r1,2); + S2(r4,r3,r0,r2,r1); LK(r1,r3,r4,r2,r0,3); + S3(r1,r3,r4,r2,r0); LK(r2,r0,r3,r1,r4,4); + S4(r2,r0,r3,r1,r4); LK(r0,r3,r1,r4,r2,5); + S5(r0,r3,r1,r4,r2); LK(r2,r0,r3,r4,r1,6); + S6(r2,r0,r3,r4,r1); LK(r3,r1,r0,r4,r2,7); + S7(r3,r1,r0,r4,r2); LK(r2,r0,r4,r3,r1,8); + S0(r2,r0,r4,r3,r1); LK(r4,r0,r3,r2,r1,9); + S1(r4,r0,r3,r2,r1); LK(r1,r3,r2,r4,r0,10); + S2(r1,r3,r2,r4,r0); LK(r0,r3,r1,r4,r2,11); + S3(r0,r3,r1,r4,r2); LK(r4,r2,r3,r0,r1,12); + S4(r4,r2,r3,r0,r1); LK(r2,r3,r0,r1,r4,13); + S5(r2,r3,r0,r1,r4); LK(r4,r2,r3,r1,r0,14); + S6(r4,r2,r3,r1,r0); LK(r3,r0,r2,r1,r4,15); + S7(r3,r0,r2,r1,r4); LK(r4,r2,r1,r3,r0,16); + S0(r4,r2,r1,r3,r0); LK(r1,r2,r3,r4,r0,17); + S1(r1,r2,r3,r4,r0); LK(r0,r3,r4,r1,r2,18); + S2(r0,r3,r4,r1,r2); LK(r2,r3,r0,r1,r4,19); + S3(r2,r3,r0,r1,r4); LK(r1,r4,r3,r2,r0,20); + S4(r1,r4,r3,r2,r0); LK(r4,r3,r2,r0,r1,21); + S5(r4,r3,r2,r0,r1); LK(r1,r4,r3,r0,r2,22); + S6(r1,r4,r3,r0,r2); LK(r3,r2,r4,r0,r1,23); + S7(r3,r2,r4,r0,r1); LK(r1,r4,r0,r3,r2,24); + S0(r1,r4,r0,r3,r2); LK(r0,r4,r3,r1,r2,25); + S1(r0,r4,r3,r1,r2); LK(r2,r3,r1,r0,r4,26); + S2(r2,r3,r1,r0,r4); LK(r4,r3,r2,r0,r1,27); + S3(r4,r3,r2,r0,r1); LK(r0,r1,r3,r4,r2,28); + S4(r0,r1,r3,r4,r2); LK(r1,r3,r4,r2,r0,29); + S5(r1,r3,r4,r2,r0); LK(r0,r1,r3,r2,r4,30); + S6(r0,r1,r3,r2,r4); LK(r3,r4,r1,r2,r0,31); + S7(r3,r4,r1,r2,r0); K(r0,r1,r2,r3,32); + + d[0] = cpu_to_le32(r0); + d[1] = cpu_to_le32(r1); + d[2] = cpu_to_le32(r2); + d[3] = cpu_to_le32(r3); +} + +void serpent_block_dec(uint32_t const *k,uint8_t *dst,uint8_t const *src){ + const uint32_t *s = (const uint32_t *)src; + uint32_t *d = (uint32_t *)dst, + r0, r1, r2, r3, r4; + + r0 = le32_to_cpu(s[0]); + r1 = le32_to_cpu(s[1]); + r2 = le32_to_cpu(s[2]); + r3 = le32_to_cpu(s[3]); + + K(r0,r1,r2,r3,32); + SI7(r0,r1,r2,r3,r4); KL(r1,r3,r0,r4,r2,31); + SI6(r1,r3,r0,r4,r2); KL(r0,r2,r4,r1,r3,30); + SI5(r0,r2,r4,r1,r3); KL(r2,r3,r0,r4,r1,29); + SI4(r2,r3,r0,r4,r1); KL(r2,r0,r1,r4,r3,28); + SI3(r2,r0,r1,r4,r3); KL(r1,r2,r3,r4,r0,27); + SI2(r1,r2,r3,r4,r0); KL(r2,r0,r4,r3,r1,26); + SI1(r2,r0,r4,r3,r1); KL(r1,r0,r4,r3,r2,25); + SI0(r1,r0,r4,r3,r2); KL(r4,r2,r0,r1,r3,24); + SI7(r4,r2,r0,r1,r3); KL(r2,r1,r4,r3,r0,23); + SI6(r2,r1,r4,r3,r0); KL(r4,r0,r3,r2,r1,22); + SI5(r4,r0,r3,r2,r1); KL(r0,r1,r4,r3,r2,21); + SI4(r0,r1,r4,r3,r2); KL(r0,r4,r2,r3,r1,20); + SI3(r0,r4,r2,r3,r1); KL(r2,r0,r1,r3,r4,19); + SI2(r2,r0,r1,r3,r4); KL(r0,r4,r3,r1,r2,18); + SI1(r0,r4,r3,r1,r2); KL(r2,r4,r3,r1,r0,17); + SI0(r2,r4,r3,r1,r0); KL(r3,r0,r4,r2,r1,16); + SI7(r3,r0,r4,r2,r1); KL(r0,r2,r3,r1,r4,15); + SI6(r0,r2,r3,r1,r4); KL(r3,r4,r1,r0,r2,14); + SI5(r3,r4,r1,r0,r2); KL(r4,r2,r3,r1,r0,13); + SI4(r4,r2,r3,r1,r0); KL(r4,r3,r0,r1,r2,12); + SI3(r4,r3,r0,r1,r2); KL(r0,r4,r2,r1,r3,11); + SI2(r0,r4,r2,r1,r3); KL(r4,r3,r1,r2,r0,10); + SI1(r4,r3,r1,r2,r0); KL(r0,r3,r1,r2,r4,9); + SI0(r0,r3,r1,r2,r4); KL(r1,r4,r3,r0,r2,8); + SI7(r1,r4,r3,r0,r2); KL(r4,r0,r1,r2,r3,7); + SI6(r4,r0,r1,r2,r3); KL(r1,r3,r2,r4,r0,6); + SI5(r1,r3,r2,r4,r0); KL(r3,r0,r1,r2,r4,5); + SI4(r3,r0,r1,r2,r4); KL(r3,r1,r4,r2,r0,4); + SI3(r3,r1,r4,r2,r0); KL(r4,r3,r0,r2,r1,3); + SI2(r4,r3,r0,r2,r1); KL(r3,r1,r2,r0,r4,2); + SI1(r3,r1,r2,r0,r4); KL(r4,r1,r2,r0,r3,1); + SI0(r4,r1,r2,r0,r3); K(r2,r3,r1,r4,0); + + d[0] = cpu_to_le32(r2); + d[1] = cpu_to_le32(r3); + d[2] = cpu_to_le32(r1); + d[3] = cpu_to_le32(r4); +} + diff -uNr - - akris/akris/c_serpent/lib/serpent.h akris-genesis/akris/c_serpent/lib/serpent.h --- akris/akris/c_serpent/lib/serpent.h false +++ akris-genesis/akris/c_serpent/lib/serpent.h 55338f27db9dec583b5bdb0a17a4aa27d9caad9cf0001fab8e63f8241cccc7798678d68bafe1e6d5a5148a16b02bc768d235bdfdb17a0e118480166970d9401e @@ -0,0 +1,30 @@ +/* + * Cryptographic API. + * + * Serpent Cipher Algorithm. + * + * Copyright (C) 2002 Dag Arne Osvik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * ********************MODIFIED FOR USE IN SMALPEST******************** + * + */ + +#ifndef OTHERPPL_SERPENT_H +#define OTHERPPL_SERPENT_H + +#include +#include + +#define SERPENT_BLOCK_SIZE 16 +#define SERPENT_EXPKEY_WORDS 132 + +int serpent_setkey (uint32_t *k,uint8_t const *key,size_t keylen); +void serpent_block_enc (uint32_t const *k,uint8_t *dst,uint8_t const *src); +void serpent_block_dec (uint32_t const *k,uint8_t *dst,uint8_t const *src); + +#endif diff -uNr - - akris/akris/c_serpent/lib/sha.c akris-genesis/akris/c_serpent/lib/sha.c --- akris/akris/c_serpent/lib/sha.c false +++ akris-genesis/akris/c_serpent/lib/sha.c d7d4682b42c1e6787af1f0200b4d3147827a5fcc5652c71cdf3058dbfc99e0946080f95a29deecb1ba46606812521880035cec0d18adbc490747c992ee1f114c @@ -0,0 +1,690 @@ +/* + * FIPS 180-2 SHA-224/256/384/512 implementation + * Last update: 02/02/2007 + * Issue date: 04/30/2005 + * + * Copyright (C) 2005, 2007 Olivier Gay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * ********************MODIFIED FOR USE IN SMALPEST******************** + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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. + */ + +#if 0 +#define UNROLL_LOOPS /* Enable loops unrolling */ +#endif + +#include "sha.h" +#include + +#define SHFR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) +#define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) +#define CH(x, y, z) ((x & y) ^ (~x & z)) +#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) + +#define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3)) +#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10)) + +#define SHA512_F1(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39)) +#define SHA512_F2(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41)) +#define SHA512_F3(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHFR(x, 7)) +#define SHA512_F4(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHFR(x, 6)) + +#define UNPACK32(x, str) \ +{ \ + *((str) + 3) = (uint8_t) ((x) ); \ + *((str) + 2) = (uint8_t) ((x) >> 8); \ + *((str) + 1) = (uint8_t) ((x) >> 16); \ + *((str) + 0) = (uint8_t) ((x) >> 24); \ +} + +#define PACK32(str, x) \ +{ \ + *(x) = ((uint32_t) *((str) + 3) ) \ + | ((uint32_t) *((str) + 2) << 8) \ + | ((uint32_t) *((str) + 1) << 16) \ + | ((uint32_t) *((str) + 0) << 24); \ +} + +#define UNPACK64(x, str) \ +{ \ + *((str) + 7) = (uint8_t) ((x) ); \ + *((str) + 6) = (uint8_t) ((x) >> 8); \ + *((str) + 5) = (uint8_t) ((x) >> 16); \ + *((str) + 4) = (uint8_t) ((x) >> 24); \ + *((str) + 3) = (uint8_t) ((x) >> 32); \ + *((str) + 2) = (uint8_t) ((x) >> 40); \ + *((str) + 1) = (uint8_t) ((x) >> 48); \ + *((str) + 0) = (uint8_t) ((x) >> 56); \ +} + +#define PACK64(str, x) \ +{ \ + *(x) = ((uint64_t) *((str) + 7) ) \ + | ((uint64_t) *((str) + 6) << 8) \ + | ((uint64_t) *((str) + 5) << 16) \ + | ((uint64_t) *((str) + 4) << 24) \ + | ((uint64_t) *((str) + 3) << 32) \ + | ((uint64_t) *((str) + 2) << 40) \ + | ((uint64_t) *((str) + 1) << 48) \ + | ((uint64_t) *((str) + 0) << 56); \ +} + +/* Macros used for loops unrolling */ + +#define SHA256_SCR(i) \ +{ \ + w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \ + + SHA256_F3(w[i - 15]) + w[i - 16]; \ +} + +#define SHA512_SCR(i) \ +{ \ + w[i] = SHA512_F4(w[i - 2]) + w[i - 7] \ + + SHA512_F3(w[i - 15]) + w[i - 16]; \ +} + +#define SHA256_EXP(a, b, c, d, e, f, g, h, j) \ +{ \ + t1 = wv[h] + SHA256_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \ + + sha256_k[j] + w[j]; \ + t2 = SHA256_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \ + wv[d] += t1; \ + wv[h] = t1 + t2; \ +} + +#define SHA512_EXP(a, b, c, d, e, f, g ,h, j) \ +{ \ + t1 = wv[h] + SHA512_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \ + + sha512_k[j] + w[j]; \ + t2 = SHA512_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \ + wv[d] += t1; \ + wv[h] = t1 + t2; \ +} + +uint32_t sha256_h0[8] = + {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + +uint64_t sha384_h0[8] = + {0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, + 0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL, + 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL, + 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL}; + +uint64_t sha512_h0[8] = + {0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL}; + +uint32_t sha256_k[64] = + {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; + +uint64_t sha512_k[80] = + {0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL}; + +/* SHA-256 functions */ + +static void sha256_transf(sha256_ctx *ctx, const unsigned char *message, + unsigned int block_nb) +{ + uint32_t w[64]; + uint32_t wv[8]; + uint32_t t1, t2; + const unsigned char *sub_block; + int i; + +#ifndef UNROLL_LOOPS + int j; +#endif + + for (i = 0; i < (int) block_nb; i++) { + sub_block = message + (i << 6); + +#ifndef UNROLL_LOOPS + for (j = 0; j < 16; j++) { + PACK32(&sub_block[j << 2], &w[j]); + } + + for (j = 16; j < 64; j++) { + SHA256_SCR(j); + } + + for (j = 0; j < 8; j++) { + wv[j] = ctx->h[j]; + } + + for (j = 0; j < 64; j++) { + t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + + sha256_k[j] + w[j]; + t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); + wv[7] = wv[6]; + wv[6] = wv[5]; + wv[5] = wv[4]; + wv[4] = wv[3] + t1; + wv[3] = wv[2]; + wv[2] = wv[1]; + wv[1] = wv[0]; + wv[0] = t1 + t2; + } + + for (j = 0; j < 8; j++) { + ctx->h[j] += wv[j]; + } +#else + PACK32(&sub_block[ 0], &w[ 0]); PACK32(&sub_block[ 4], &w[ 1]); + PACK32(&sub_block[ 8], &w[ 2]); PACK32(&sub_block[12], &w[ 3]); + PACK32(&sub_block[16], &w[ 4]); PACK32(&sub_block[20], &w[ 5]); + PACK32(&sub_block[24], &w[ 6]); PACK32(&sub_block[28], &w[ 7]); + PACK32(&sub_block[32], &w[ 8]); PACK32(&sub_block[36], &w[ 9]); + PACK32(&sub_block[40], &w[10]); PACK32(&sub_block[44], &w[11]); + PACK32(&sub_block[48], &w[12]); PACK32(&sub_block[52], &w[13]); + PACK32(&sub_block[56], &w[14]); PACK32(&sub_block[60], &w[15]); + + SHA256_SCR(16); SHA256_SCR(17); SHA256_SCR(18); SHA256_SCR(19); + SHA256_SCR(20); SHA256_SCR(21); SHA256_SCR(22); SHA256_SCR(23); + SHA256_SCR(24); SHA256_SCR(25); SHA256_SCR(26); SHA256_SCR(27); + SHA256_SCR(28); SHA256_SCR(29); SHA256_SCR(30); SHA256_SCR(31); + SHA256_SCR(32); SHA256_SCR(33); SHA256_SCR(34); SHA256_SCR(35); + SHA256_SCR(36); SHA256_SCR(37); SHA256_SCR(38); SHA256_SCR(39); + SHA256_SCR(40); SHA256_SCR(41); SHA256_SCR(42); SHA256_SCR(43); + SHA256_SCR(44); SHA256_SCR(45); SHA256_SCR(46); SHA256_SCR(47); + SHA256_SCR(48); SHA256_SCR(49); SHA256_SCR(50); SHA256_SCR(51); + SHA256_SCR(52); SHA256_SCR(53); SHA256_SCR(54); SHA256_SCR(55); + SHA256_SCR(56); SHA256_SCR(57); SHA256_SCR(58); SHA256_SCR(59); + SHA256_SCR(60); SHA256_SCR(61); SHA256_SCR(62); SHA256_SCR(63); + + wv[0] = ctx->h[0]; wv[1] = ctx->h[1]; + wv[2] = ctx->h[2]; wv[3] = ctx->h[3]; + wv[4] = ctx->h[4]; wv[5] = ctx->h[5]; + wv[6] = ctx->h[6]; wv[7] = ctx->h[7]; + + SHA256_EXP(0,1,2,3,4,5,6,7, 0); SHA256_EXP(7,0,1,2,3,4,5,6, 1); + SHA256_EXP(6,7,0,1,2,3,4,5, 2); SHA256_EXP(5,6,7,0,1,2,3,4, 3); + SHA256_EXP(4,5,6,7,0,1,2,3, 4); SHA256_EXP(3,4,5,6,7,0,1,2, 5); + SHA256_EXP(2,3,4,5,6,7,0,1, 6); SHA256_EXP(1,2,3,4,5,6,7,0, 7); + SHA256_EXP(0,1,2,3,4,5,6,7, 8); SHA256_EXP(7,0,1,2,3,4,5,6, 9); + SHA256_EXP(6,7,0,1,2,3,4,5,10); SHA256_EXP(5,6,7,0,1,2,3,4,11); + SHA256_EXP(4,5,6,7,0,1,2,3,12); SHA256_EXP(3,4,5,6,7,0,1,2,13); + SHA256_EXP(2,3,4,5,6,7,0,1,14); SHA256_EXP(1,2,3,4,5,6,7,0,15); + SHA256_EXP(0,1,2,3,4,5,6,7,16); SHA256_EXP(7,0,1,2,3,4,5,6,17); + SHA256_EXP(6,7,0,1,2,3,4,5,18); SHA256_EXP(5,6,7,0,1,2,3,4,19); + SHA256_EXP(4,5,6,7,0,1,2,3,20); SHA256_EXP(3,4,5,6,7,0,1,2,21); + SHA256_EXP(2,3,4,5,6,7,0,1,22); SHA256_EXP(1,2,3,4,5,6,7,0,23); + SHA256_EXP(0,1,2,3,4,5,6,7,24); SHA256_EXP(7,0,1,2,3,4,5,6,25); + SHA256_EXP(6,7,0,1,2,3,4,5,26); SHA256_EXP(5,6,7,0,1,2,3,4,27); + SHA256_EXP(4,5,6,7,0,1,2,3,28); SHA256_EXP(3,4,5,6,7,0,1,2,29); + SHA256_EXP(2,3,4,5,6,7,0,1,30); SHA256_EXP(1,2,3,4,5,6,7,0,31); + SHA256_EXP(0,1,2,3,4,5,6,7,32); SHA256_EXP(7,0,1,2,3,4,5,6,33); + SHA256_EXP(6,7,0,1,2,3,4,5,34); SHA256_EXP(5,6,7,0,1,2,3,4,35); + SHA256_EXP(4,5,6,7,0,1,2,3,36); SHA256_EXP(3,4,5,6,7,0,1,2,37); + SHA256_EXP(2,3,4,5,6,7,0,1,38); SHA256_EXP(1,2,3,4,5,6,7,0,39); + SHA256_EXP(0,1,2,3,4,5,6,7,40); SHA256_EXP(7,0,1,2,3,4,5,6,41); + SHA256_EXP(6,7,0,1,2,3,4,5,42); SHA256_EXP(5,6,7,0,1,2,3,4,43); + SHA256_EXP(4,5,6,7,0,1,2,3,44); SHA256_EXP(3,4,5,6,7,0,1,2,45); + SHA256_EXP(2,3,4,5,6,7,0,1,46); SHA256_EXP(1,2,3,4,5,6,7,0,47); + SHA256_EXP(0,1,2,3,4,5,6,7,48); SHA256_EXP(7,0,1,2,3,4,5,6,49); + SHA256_EXP(6,7,0,1,2,3,4,5,50); SHA256_EXP(5,6,7,0,1,2,3,4,51); + SHA256_EXP(4,5,6,7,0,1,2,3,52); SHA256_EXP(3,4,5,6,7,0,1,2,53); + SHA256_EXP(2,3,4,5,6,7,0,1,54); SHA256_EXP(1,2,3,4,5,6,7,0,55); + SHA256_EXP(0,1,2,3,4,5,6,7,56); SHA256_EXP(7,0,1,2,3,4,5,6,57); + SHA256_EXP(6,7,0,1,2,3,4,5,58); SHA256_EXP(5,6,7,0,1,2,3,4,59); + SHA256_EXP(4,5,6,7,0,1,2,3,60); SHA256_EXP(3,4,5,6,7,0,1,2,61); + SHA256_EXP(2,3,4,5,6,7,0,1,62); SHA256_EXP(1,2,3,4,5,6,7,0,63); + + ctx->h[0] += wv[0]; ctx->h[1] += wv[1]; + ctx->h[2] += wv[2]; ctx->h[3] += wv[3]; + ctx->h[4] += wv[4]; ctx->h[5] += wv[5]; + ctx->h[6] += wv[6]; ctx->h[7] += wv[7]; +#endif /* !UNROLL_LOOPS */ + } +} + +void sha256_init(sha256_ctx *ctx) +{ +#ifndef UNROLL_LOOPS + int i; + for (i = 0; i < 8; i++) { + ctx->h[i] = sha256_h0[i]; + } +#else + ctx->h[0] = sha256_h0[0]; ctx->h[1] = sha256_h0[1]; + ctx->h[2] = sha256_h0[2]; ctx->h[3] = sha256_h0[3]; + ctx->h[4] = sha256_h0[4]; ctx->h[5] = sha256_h0[5]; + ctx->h[6] = sha256_h0[6]; ctx->h[7] = sha256_h0[7]; +#endif /* !UNROLL_LOOPS */ + + ctx->len = 0; + ctx->tot_len = 0; +} + +void sha256_update(sha256_ctx *ctx, const unsigned char *message, + unsigned int len) +{ + unsigned int block_nb; + unsigned int new_len, rem_len, tmp_len; + const unsigned char *shifted_message; + + tmp_len = SHA256_BLOCK_SIZE - ctx->len; + rem_len = len < tmp_len ? len : tmp_len; + + memcpy(&ctx->block[ctx->len], message, rem_len); + + if (ctx->len + len < SHA256_BLOCK_SIZE) { + ctx->len += len; + return; + } + + new_len = len - rem_len; + block_nb = new_len / SHA256_BLOCK_SIZE; + + shifted_message = message + rem_len; + + sha256_transf(ctx, ctx->block, 1); + sha256_transf(ctx, shifted_message, block_nb); + + rem_len = new_len % SHA256_BLOCK_SIZE; + + memcpy(ctx->block, &shifted_message[block_nb << 6], + rem_len); + + ctx->len = rem_len; + ctx->tot_len += (block_nb + 1) << 6; +} + +void sha256_final(sha256_ctx *ctx, unsigned char *digest) +{ + unsigned int block_nb; + unsigned int pm_len; + unsigned int len_b; + +#ifndef UNROLL_LOOPS + int i; +#endif + + block_nb = (1 + ((SHA256_BLOCK_SIZE - 9) + < (ctx->len % SHA256_BLOCK_SIZE))); + + len_b = (ctx->tot_len + ctx->len) << 3; + pm_len = block_nb << 6; + + memset(ctx->block + ctx->len, 0, pm_len - ctx->len); + ctx->block[ctx->len] = 0x80; + UNPACK32(len_b, ctx->block + pm_len - 4); + + sha256_transf(ctx, ctx->block, block_nb); + +#ifndef UNROLL_LOOPS + for (i = 0 ; i < 8; i++) { + UNPACK32(ctx->h[i], &digest[i << 2]); + } +#else + UNPACK32(ctx->h[0], &digest[ 0]); + UNPACK32(ctx->h[1], &digest[ 4]); + UNPACK32(ctx->h[2], &digest[ 8]); + UNPACK32(ctx->h[3], &digest[12]); + UNPACK32(ctx->h[4], &digest[16]); + UNPACK32(ctx->h[5], &digest[20]); + UNPACK32(ctx->h[6], &digest[24]); + UNPACK32(ctx->h[7], &digest[28]); +#endif /* !UNROLL_LOOPS */ +} + +/* SHA-512 functions */ + +static void sha512_transf(sha512_ctx *ctx, const unsigned char *message, + unsigned int block_nb) +{ + uint64_t w[80]; + uint64_t wv[8]; + uint64_t t1, t2; + const unsigned char *sub_block; + int i, j; + + for (i = 0; i < (int) block_nb; i++) { + sub_block = message + (i << 7); + +#ifndef UNROLL_LOOPS + for (j = 0; j < 16; j++) { + PACK64(&sub_block[j << 3], &w[j]); + } + + for (j = 16; j < 80; j++) { + SHA512_SCR(j); + } + + for (j = 0; j < 8; j++) { + wv[j] = ctx->h[j]; + } + + for (j = 0; j < 80; j++) { + t1 = wv[7] + SHA512_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + + sha512_k[j] + w[j]; + t2 = SHA512_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); + wv[7] = wv[6]; + wv[6] = wv[5]; + wv[5] = wv[4]; + wv[4] = wv[3] + t1; + wv[3] = wv[2]; + wv[2] = wv[1]; + wv[1] = wv[0]; + wv[0] = t1 + t2; + } + + for (j = 0; j < 8; j++) { + ctx->h[j] += wv[j]; + } +#else + PACK64(&sub_block[ 0], &w[ 0]); PACK64(&sub_block[ 8], &w[ 1]); + PACK64(&sub_block[ 16], &w[ 2]); PACK64(&sub_block[ 24], &w[ 3]); + PACK64(&sub_block[ 32], &w[ 4]); PACK64(&sub_block[ 40], &w[ 5]); + PACK64(&sub_block[ 48], &w[ 6]); PACK64(&sub_block[ 56], &w[ 7]); + PACK64(&sub_block[ 64], &w[ 8]); PACK64(&sub_block[ 72], &w[ 9]); + PACK64(&sub_block[ 80], &w[10]); PACK64(&sub_block[ 88], &w[11]); + PACK64(&sub_block[ 96], &w[12]); PACK64(&sub_block[104], &w[13]); + PACK64(&sub_block[112], &w[14]); PACK64(&sub_block[120], &w[15]); + + SHA512_SCR(16); SHA512_SCR(17); SHA512_SCR(18); SHA512_SCR(19); + SHA512_SCR(20); SHA512_SCR(21); SHA512_SCR(22); SHA512_SCR(23); + SHA512_SCR(24); SHA512_SCR(25); SHA512_SCR(26); SHA512_SCR(27); + SHA512_SCR(28); SHA512_SCR(29); SHA512_SCR(30); SHA512_SCR(31); + SHA512_SCR(32); SHA512_SCR(33); SHA512_SCR(34); SHA512_SCR(35); + SHA512_SCR(36); SHA512_SCR(37); SHA512_SCR(38); SHA512_SCR(39); + SHA512_SCR(40); SHA512_SCR(41); SHA512_SCR(42); SHA512_SCR(43); + SHA512_SCR(44); SHA512_SCR(45); SHA512_SCR(46); SHA512_SCR(47); + SHA512_SCR(48); SHA512_SCR(49); SHA512_SCR(50); SHA512_SCR(51); + SHA512_SCR(52); SHA512_SCR(53); SHA512_SCR(54); SHA512_SCR(55); + SHA512_SCR(56); SHA512_SCR(57); SHA512_SCR(58); SHA512_SCR(59); + SHA512_SCR(60); SHA512_SCR(61); SHA512_SCR(62); SHA512_SCR(63); + SHA512_SCR(64); SHA512_SCR(65); SHA512_SCR(66); SHA512_SCR(67); + SHA512_SCR(68); SHA512_SCR(69); SHA512_SCR(70); SHA512_SCR(71); + SHA512_SCR(72); SHA512_SCR(73); SHA512_SCR(74); SHA512_SCR(75); + SHA512_SCR(76); SHA512_SCR(77); SHA512_SCR(78); SHA512_SCR(79); + + wv[0] = ctx->h[0]; wv[1] = ctx->h[1]; + wv[2] = ctx->h[2]; wv[3] = ctx->h[3]; + wv[4] = ctx->h[4]; wv[5] = ctx->h[5]; + wv[6] = ctx->h[6]; wv[7] = ctx->h[7]; + + j = 0; + + do { + SHA512_EXP(0,1,2,3,4,5,6,7,j); j++; + SHA512_EXP(7,0,1,2,3,4,5,6,j); j++; + SHA512_EXP(6,7,0,1,2,3,4,5,j); j++; + SHA512_EXP(5,6,7,0,1,2,3,4,j); j++; + SHA512_EXP(4,5,6,7,0,1,2,3,j); j++; + SHA512_EXP(3,4,5,6,7,0,1,2,j); j++; + SHA512_EXP(2,3,4,5,6,7,0,1,j); j++; + SHA512_EXP(1,2,3,4,5,6,7,0,j); j++; + } while (j < 80); + + ctx->h[0] += wv[0]; ctx->h[1] += wv[1]; + ctx->h[2] += wv[2]; ctx->h[3] += wv[3]; + ctx->h[4] += wv[4]; ctx->h[5] += wv[5]; + ctx->h[6] += wv[6]; ctx->h[7] += wv[7]; +#endif /* !UNROLL_LOOPS */ + } +} + +void sha512_init(sha512_ctx *ctx) +{ +#ifndef UNROLL_LOOPS + int i; + for (i = 0; i < 8; i++) { + ctx->h[i] = sha512_h0[i]; + } +#else + ctx->h[0] = sha512_h0[0]; ctx->h[1] = sha512_h0[1]; + ctx->h[2] = sha512_h0[2]; ctx->h[3] = sha512_h0[3]; + ctx->h[4] = sha512_h0[4]; ctx->h[5] = sha512_h0[5]; + ctx->h[6] = sha512_h0[6]; ctx->h[7] = sha512_h0[7]; +#endif /* !UNROLL_LOOPS */ + + ctx->len = 0; + ctx->tot_len = 0; +} + +void sha512_update(sha512_ctx *ctx, const unsigned char *message, + unsigned int len) +{ + unsigned int block_nb; + unsigned int new_len, rem_len, tmp_len; + const unsigned char *shifted_message; + + tmp_len = SHA512_BLOCK_SIZE - ctx->len; + rem_len = len < tmp_len ? len : tmp_len; + + memcpy(&ctx->block[ctx->len], message, rem_len); + + if (ctx->len + len < SHA512_BLOCK_SIZE) { + ctx->len += len; + return; + } + + new_len = len - rem_len; + block_nb = new_len / SHA512_BLOCK_SIZE; + + shifted_message = message + rem_len; + + sha512_transf(ctx, ctx->block, 1); + sha512_transf(ctx, shifted_message, block_nb); + + rem_len = new_len % SHA512_BLOCK_SIZE; + + memcpy(ctx->block, &shifted_message[block_nb << 7], + rem_len); + + ctx->len = rem_len; + ctx->tot_len += (block_nb + 1) << 7; +} + +void sha512_final(sha512_ctx *ctx, unsigned char *digest) +{ + unsigned int block_nb; + unsigned int pm_len; + unsigned int len_b; + +#ifndef UNROLL_LOOPS + int i; +#endif + + block_nb = 1 + ((SHA512_BLOCK_SIZE - 17) + < (ctx->len % SHA512_BLOCK_SIZE)); + + len_b = (ctx->tot_len + ctx->len) << 3; + pm_len = block_nb << 7; + + memset(ctx->block + ctx->len, 0, pm_len - ctx->len); + ctx->block[ctx->len] = 0x80; + UNPACK32(len_b, ctx->block + pm_len - 4); + + sha512_transf(ctx, ctx->block, block_nb); + +#ifndef UNROLL_LOOPS + for (i = 0 ; i < 8; i++) { + UNPACK64(ctx->h[i], &digest[i << 3]); + } +#else + UNPACK64(ctx->h[0], &digest[ 0]); + UNPACK64(ctx->h[1], &digest[ 8]); + UNPACK64(ctx->h[2], &digest[16]); + UNPACK64(ctx->h[3], &digest[24]); + UNPACK64(ctx->h[4], &digest[32]); + UNPACK64(ctx->h[5], &digest[40]); + UNPACK64(ctx->h[6], &digest[48]); + UNPACK64(ctx->h[7], &digest[56]); +#endif /* !UNROLL_LOOPS */ +} + +/* SHA-384 functions */ + +void sha384_init(sha384_ctx *ctx) +{ +#ifndef UNROLL_LOOPS + int i; + for (i = 0; i < 8; i++) { + ctx->h[i] = sha384_h0[i]; + } +#else + ctx->h[0] = sha384_h0[0]; ctx->h[1] = sha384_h0[1]; + ctx->h[2] = sha384_h0[2]; ctx->h[3] = sha384_h0[3]; + ctx->h[4] = sha384_h0[4]; ctx->h[5] = sha384_h0[5]; + ctx->h[6] = sha384_h0[6]; ctx->h[7] = sha384_h0[7]; +#endif /* !UNROLL_LOOPS */ + + ctx->len = 0; + ctx->tot_len = 0; +} + +void sha384_update(sha384_ctx *ctx, const unsigned char *message, + unsigned int len) +{ + unsigned int block_nb; + unsigned int new_len, rem_len, tmp_len; + const unsigned char *shifted_message; + + tmp_len = SHA384_BLOCK_SIZE - ctx->len; + rem_len = len < tmp_len ? len : tmp_len; + + memcpy(&ctx->block[ctx->len], message, rem_len); + + if (ctx->len + len < SHA384_BLOCK_SIZE) { + ctx->len += len; + return; + } + + new_len = len - rem_len; + block_nb = new_len / SHA384_BLOCK_SIZE; + + shifted_message = message + rem_len; + + sha512_transf(ctx, ctx->block, 1); + sha512_transf(ctx, shifted_message, block_nb); + + rem_len = new_len % SHA384_BLOCK_SIZE; + + memcpy(ctx->block, &shifted_message[block_nb << 7], + rem_len); + + ctx->len = rem_len; + ctx->tot_len += (block_nb + 1) << 7; +} + +void sha384_final(sha384_ctx *ctx, unsigned char *digest) +{ + unsigned int block_nb; + unsigned int pm_len; + unsigned int len_b; + +#ifndef UNROLL_LOOPS + int i; +#endif + + block_nb = (1 + ((SHA384_BLOCK_SIZE - 17) + < (ctx->len % SHA384_BLOCK_SIZE))); + + len_b = (ctx->tot_len + ctx->len) << 3; + pm_len = block_nb << 7; + + memset(ctx->block + ctx->len, 0, pm_len - ctx->len); + ctx->block[ctx->len] = 0x80; + UNPACK32(len_b, ctx->block + pm_len - 4); + + sha512_transf(ctx, ctx->block, block_nb); + +#ifndef UNROLL_LOOPS + for (i = 0 ; i < 6; i++) { + UNPACK64(ctx->h[i], &digest[i << 3]); + } +#else + UNPACK64(ctx->h[0], &digest[ 0]); + UNPACK64(ctx->h[1], &digest[ 8]); + UNPACK64(ctx->h[2], &digest[16]); + UNPACK64(ctx->h[3], &digest[24]); + UNPACK64(ctx->h[4], &digest[32]); + UNPACK64(ctx->h[5], &digest[40]); +#endif /* !UNROLL_LOOPS */ +} + diff -uNr - - akris/akris/c_serpent/lib/sha.h akris-genesis/akris/c_serpent/lib/sha.h --- akris/akris/c_serpent/lib/sha.h false +++ akris-genesis/akris/c_serpent/lib/sha.h b732edbf39e4671a814c80341bf843c33093d341bf0833b77e30270ce653ad7ececa5a9486a7b5050902afd82d61f08c705d66b50d323eb0d241285dbeffd1f6 @@ -0,0 +1,81 @@ +/* + * FIPS 180-2 SHA-224/256/384/512 implementation + * Last update: 02/02/2007 + * Issue date: 04/30/2005 + * + * Copyright (C) 2005, 2007 Olivier Gay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * ********************MODIFIED FOR USE IN SMALPEST******************** + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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. + */ + +#ifndef SHA_INTERNAL_H +#define SHA_INTERNAL_H + +#include + +#define SHA256_DIGEST_SIZE ( 256 / 8) +#define SHA384_DIGEST_SIZE ( 384 / 8) +#define SHA512_DIGEST_SIZE ( 512 / 8) + +#define SHA256_BLOCK_SIZE ( 512 / 8) +#define SHA512_BLOCK_SIZE (1024 / 8) +#define SHA384_BLOCK_SIZE SHA512_BLOCK_SIZE + +typedef struct { + unsigned int tot_len; + unsigned int len; + unsigned char block[2 * SHA256_BLOCK_SIZE]; + uint32_t h[8]; +} sha256_ctx; + +typedef struct { + unsigned int tot_len; + unsigned int len; + unsigned char block[2 * SHA512_BLOCK_SIZE]; + uint64_t h[8]; +} sha512_ctx; + +typedef sha512_ctx sha384_ctx; + +void sha256_init(sha256_ctx * ctx); +void sha256_update(sha256_ctx *ctx, const unsigned char *message, + unsigned int len); +void sha256_final(sha256_ctx *ctx, unsigned char *digest); + +void sha384_init(sha384_ctx *ctx); +void sha384_update(sha384_ctx *ctx, const unsigned char *message, + unsigned int len); +void sha384_final(sha384_ctx *ctx, unsigned char *digest); + +void sha512_init(sha512_ctx *ctx); +void sha512_update(sha512_ctx *ctx, const unsigned char *message, + unsigned int len); +void sha512_final(sha512_ctx *ctx, unsigned char *digest); + +#endif + diff -uNr - - akris/akris/c_serpent/serpent.py akris-genesis/akris/c_serpent/serpent.py --- akris/akris/c_serpent/serpent.py false +++ akris-genesis/akris/c_serpent/serpent.py 3e5228d19511e795dc6d132392abb7bb19ab4cda50086ffe9ff30c7d4b012581cd5847cc078cbbcdb1c136951ef14274034cd2522d68933d8658c509d08b9d2e @@ -0,0 +1,44 @@ +import sys +import os +import ctypes + +SERPENT_KEY_SIZE = 32 +MAX_MESSAGE_LENGTH = 428 +EXPANDED_KEY_SIZE = 528 + +try: + package_path = os.path.dirname(os.path.abspath(__file__)) + lib = ctypes.cdll.LoadLibrary(os.path.join(package_path, "../../_serpent_cffi.abi3.so")) +except OSError: + venv_site_packages_path = sys.path[4] + lib = ctypes.cdll.LoadLibrary(os.path.join(venv_site_packages_path, "_serpent_cffi.cpython-310-x86_64-linux-gnu.so")) +serpent_init = lib.serpent_init +serpent_cbc_ciph = lib.serpent_cbc_ciph +serpent_cbc_deciph = lib.serpent_cbc_deciph + +def expand_key(key): + expanded_key = ctypes.create_string_buffer(EXPANDED_KEY_SIZE) + serpent_init(ctypes.byref(expanded_key), key, SERPENT_KEY_SIZE) + return expanded_key.raw + +def encrypt(key, plaintext): + expanded_key = expand_key(key) + + red_packet_size = len(plaintext) + # Create a ctypes byte string buffer of the same length as the Python byte string + c_plaintext = ctypes.create_string_buffer(red_packet_size) + + # Set the value of the ctypes byte string using the Python byte string + c_plaintext.value = plaintext + + c_ciphertext = ctypes.create_string_buffer(red_packet_size) + serpent_cbc_ciph(expanded_key, ctypes.byref(c_ciphertext), c_plaintext, red_packet_size) + return c_ciphertext.raw + +def decrypt(key, ciphertext): + expanded_key = expand_key(key) + red_packet_size = len(ciphertext) + c_ciphertext = ctypes.create_string_buffer(ciphertext) + c_plaintext = ctypes.create_string_buffer(red_packet_size) + serpent_cbc_deciph(expanded_key,ctypes.byref(c_plaintext), c_ciphertext, red_packet_size); + return c_plaintext.raw diff -uNr - - akris/akris/c_serpent/serpent_build.py akris-genesis/akris/c_serpent/serpent_build.py --- akris/akris/c_serpent/serpent_build.py false +++ akris-genesis/akris/c_serpent/serpent_build.py fe10dfa3b1cf592e7e45e2d685b9fdb587f0e7d8f7cf69129a92e67ec38e0db87c7baab428aca58737c34e5b35f94b4fdcf5e9dae182029e9802a44a1022b8e7 @@ -0,0 +1,30 @@ +import os +from cffi import FFI +import importlib.resources +ffibuilder = FFI() +# cdef() expects a single string declaring the C types, functions and +# globals needed to use the shared object. It must be in valid C syntax. +ffibuilder.cdef(""" + void serpent_init (uint8_t *skey,uint8_t const *key,size_t key_size); + void serpent_cbc_ciph (uint8_t const *skey,uint8_t *dst,uint8_t const *src,size_t size); + void serpent_cbc_deciph(uint8_t const *skey,uint8_t *dst,uint8_t const *src,size_t size); +""") + +# set_source() gives the name of the python extension module to +# produce, and some C source code as a string. This C code needs +# to make the declarated functions, types and globals available, +# so it is often just the "#include". +with importlib.resources.path("akris", "c_serpent") as serpent_path: + ffibuilder.set_source( + "_serpent_cffi", + f""" + #include "{os.path.join(serpent_path, 'lib/serpent.h')}" + #include "{os.path.join(serpent_path, 'crypto.h')}" + """, + sources=[f"{os.path.join(serpent_path, 'lib/serpent.c')}", f"{os.path.join(serpent_path, 'c_serpent.c')}"], + include_dirs=[f"{os.path.join(serpent_path, 'lib')}"], + + ) # library name, for the linker + +if __name__ == "__main__": + ffibuilder.compile(verbose=True) diff -uNr - - akris/akris/c_serpent/spec.h akris-genesis/akris/c_serpent/spec.h --- akris/akris/c_serpent/spec.h false +++ akris-genesis/akris/c_serpent/spec.h 7105fc600df512ef6cd2cbe2a01c3b33cdff4622055aa6d4933d7dcff2d5b6a1dd4a9632ee73e36ab8098cb2dd2fbc9c6b9902afede599efb0ea12831d18498f @@ -0,0 +1,97 @@ +#ifndef SPEC_H +#define SPEC_H + +#define PEST_VERSION 0xFC + +#define CUTOFF_MIN 0 +#define CUTOFF_MAX 255 +#define BOUNCES_MAX 255 + +#define TIMESTAMP_MAXDIFF (60*15) //15min +#define DEDUP_TIMEOUT (60*60) //60min + +#define HEARSAY_PARENS_MAX 3 + +#define REKEY_PACKET_CNT 3 + +#define KEY_SIGN_SIZE 32 +#define KEY_CIPH_SIZE 32 +#define KEY_SIZE (KEY_SIGN_SIZE+KEY_CIPH_SIZE) +#define BANNER_LEN TEXT_SIZE + +#define CMD_BROADCAST 0x00 +#define CMD_DIRECT 0x01 +#define CMD_BANNER 0x02 +#define CMD_GETDATA 0x03 +#define CMD_KEYOFFER 0x04 +#define CMD_KEYSLICE 0x05 +#define CMD_ADDRESSCAST 0xFE +#define CMD_IGNORE 0xFF + +#define CMD_UNDEF_MIN 0x06 +#define CMD_UNDEF_MAX 0xFD + +//--- red address cast ---------------------------------------------------- +#define AC_CMD_SIZE sizeof(uint32_t) +#define AC_PORT_SIZE sizeof(uint16_t) +#define AC_IP_SIZE sizeof(uint32_t) +#define AC_RPAD_SIZE 262 + +#define AC_CMD_OFF ( 0 ) +#define AC_PORT_OFF ( AC_CMD_OFF + AC_CMD_SIZE ) +#define AC_IP_OFF ( AC_PORT_OFF + AC_PORT_SIZE ) +#define AC_RPAD_OFF ( AC_IP_OFF + AC_IP_SIZE ) + +#define AC_RED_SIZE ( AC_RPAD_OFF + AC_RPAD_SIZE ) + +//--- black address cast -------------------------------------------------- +#define AC_SIGN_SIZE HMAC384_SIZE +#define AC_BPAD_SIZE 4 + +#define AC_RED_OFF ( 0 ) +#define AC_SIGN_OFF ( AC_RED_OFF + AC_RED_SIZE ) +#define AC_BPAD_OFF ( AC_SIGN_OFF + AC_SIGN_SIZE ) + +#define AC_BLACK_SIZE ( AC_BPAD_OFF + AC_BPAD_SIZE ) + +//--- message ------------------------------------------------------------- +#define TIMESTAMP_SIZE sizeof(uint64_t) +#define SELFCHAIN_SIZE HASH_SIZE +#define NETCHAIN_SIZE HASH_SIZE +#define SPEAKER_SIZE 32 +#define TEXT_SIZE 324 + +#define TIMESTAMP_OFF ( 0 ) +#define SELFCHAIN_OFF ( TIMESTAMP_OFF + TIMESTAMP_SIZE ) +#define NETCHAIN_OFF ( SELFCHAIN_OFF + SELFCHAIN_SIZE ) +#define SPEAKER_OFF ( NETCHAIN_OFF + NETCHAIN_SIZE ) +#define TEXT_OFF ( SPEAKER_OFF + SPEAKER_SIZE ) + +#define MESSAGE_SIZE ( TEXT_OFF + TEXT_SIZE ) + +//--- red packet ---------------------------------------------------------- +#define NONCE_SIZE 16 +#define BOUNCES_SIZE sizeof(uint8_t) +#define VERSION_SIZE sizeof(uint8_t) +#define RESERVED_SIZE sizeof(uint8_t) +#define COMMAND_SIZE sizeof(uint8_t) + +#define NONCE_OFF ( 0 ) +#define BOUNCES_OFF ( NONCE_OFF + NONCE_SIZE ) +#define VERSION_OFF ( BOUNCES_OFF + BOUNCES_SIZE ) +#define RESERVED_OFF ( VERSION_OFF + VERSION_SIZE ) +#define COMMAND_OFF ( RESERVED_OFF + RESERVED_SIZE ) +#define MESSAGE_OFF ( COMMAND_OFF + COMMAND_SIZE ) + +#define RED_SIZE ( MESSAGE_OFF + MESSAGE_SIZE ) + +//--- black packet -------------------------------------------------------- +#define SIGN_SIZE HMAC384_SIZE + +#define RED_OFF ( 0 ) +#define SIGN_OFF ( RED_OFF + RED_SIZE ) + +#define BLACK_SIZE ( SIGN_OFF + SIGN_SIZE ) + +#endif + diff -uNr - - akris/akris/c_serpent/type.h akris-genesis/akris/c_serpent/type.h --- akris/akris/c_serpent/type.h false +++ akris-genesis/akris/c_serpent/type.h c7777239d7ecf7609cc4231fb1401c62043b1cab244069d2e40bd3b9ffb8854dbd31a8457d4084c05f28c78c6d3bb3fc430931f930f9b88e44cac9fee8961d45 @@ -0,0 +1,157 @@ +#ifndef TYPE_H +#define TYPE_H + +#include "def.h" +#include "spec.h" +#include "config.h" +#include +#include +#include + +typedef int (*qsort_f)(void const *,void const *); + +typedef struct ircmsg{ + char *pre_name; + char *pre_user; + char *pre_host; + char *cmd; + size_t argc; + char *argv[IRCD_ARG_MAX]; + char *trail; +}ircmsg_t; + +typedef void (*tcpev_f) (unsigned); +typedef void (*ircev_f) (unsigned,ircmsg_t const *); +typedef void (*pestev_f) (unsigned,char const *,char const *); +typedef void (*log_f) (char const *,...); + +typedef char handle_t [HANDLE_BUF]; +typedef uint16_t peerid_t; + +typedef uint8_t hash_t[SHA256_SIZE]; + +typedef struct addr{ + uint32_t ip; + uint16_t port; +}addr_t; + +typedef struct mess{ + char path[PATH_BUF]; + size_t idx_cnt; //# of idx files + size_t msg_cnt; //# of msg files + size_t idx_ecnt; //# of entries in last idx file + size_t msg_ecnt; //# of entries in last msg file +}mess_t; + +typedef struct chain{ + char path[PATH_BUF]; + size_t cha_cnt; //# of cha files + size_t cha_ecnt; //# of entries in last cha file +}chain_t; + +//TODO: vtf call this +typedef struct ht{ + char path[PATH_BUF]; + hash_t hash[HEADTAIL_MAX]; + size_t cnt; + size_t last; +}ht_t; + +typedef struct rekey{ + unsigned state; + bool log; + uint64_t time; + size_t pak_cnt; + uint8_t offer_self [SHA512_SIZE]; + uint8_t offer_peer [SHA512_SIZE]; + uint8_t slice_self [KEY_SIZE]; + uint8_t slice_peer [KEY_SIZE]; + uint8_t key_old [KEY_SIZE]; + uint8_t key_new [KEY_SIZE]; +}rekey_t; + +typedef struct pkey{ + union{ + uint8_t full [KEY_SIZE]; + struct{ + uint8_t sign [KEY_SIGN_SIZE]; + uint8_t ciph [KEY_CIPH_SIZE]; + }sub; + }key; + uint8_t ciph_serp [SERPENT_SKEYSIZE]; + uint64_t time; +}pkey_t; + +typedef struct peer{ + peerid_t id; + handle_t handle [HANDLE_MAX]; + size_t handle_cnt; + pkey_t key [KEY_MAX]; + size_t key_cnt; + addr_t addr; + uint64_t stamp; //last validated paket recevid from pear indep. of key + uint64_t pak_stamp; //last any paket recevid from pear indep. of key + uint64_t con_stamp; //stamp of last message displayed in console + bool active; + bool paused; + char banner [BANNER_BUF]; + mess_t mess; //peer <-> operator + chain_t dchain; //peer -> operator + chain_t bchain; //peer -> net + ht_t dhead; //peer -> operator + ht_t dtail; //peer -> operator + ht_t bhead; //peer -> net + ht_t btail; //peer -> net + hash_t self; //peer <- operator + rekey_t rekey; +}peer_t; + +typedef struct getdata{ + hash_t hash; + peerid_t peer_id; + peerid_t chan_id; + uint64_t ntime; + size_t attempt; +}getdata_t; + +typedef struct hearsay{ + hash_t hash; + uint8_t red [RED_SIZE]; + peerid_t peer [PEER_MAX]; //this is fuckd but how fix? + size_t peer_cnt; + peerid_t speaker; + uint64_t ntime; + uint8_t bounces; +}hearsay_t; + +typedef struct pending{ + uint8_t m [MESSAGE_SIZE]; + char speaker [HANDLE_EXT_BUF]; //this is so gay + hash_t hash; + peerid_t peer_id; + peerid_t chan_id; + uint64_t ntime; + bool tail; +}pending_t; + +typedef struct knob{ + void *data; + char const *name; + char const *desc; + unsigned type; + union{ + bool b; + int64_t i; + char const *s; + }def; + int64_t min; + int64_t max; +}knob_t; + +typedef void (*strval_f) (char *,size_t,void const *); +typedef unsigned (*setval_f) (knob_t const *,char const *); +typedef bool (*storeval_f) (knob_t const *,char const *); +typedef unsigned (*loadval_f) (knob_t const *,char const *); + +#endif + diff -uNr - - akris/akris/caribou.py akris-genesis/akris/caribou.py --- akris/akris/caribou.py false +++ akris-genesis/akris/caribou.py 97eebb27e6ec219b66d69a66ffe37962046b5f76a2a30a11aad259de4985789e61837290c9f327e22d2d04e7894df0aec767d67aab4e86f7c81df22eb162ad91 @@ -0,0 +1,271 @@ +""" +Caribou is a simple SQLite database migrations library, built +to manage the evoluton of client side databases over multiple releases +of an application. +""" + +from __future__ import with_statement + +__author__ = 'clutchski@gmail.com' + +import contextlib +import datetime +import glob +import imp +import os.path +import sqlite3 +import traceback + +# statics + +VERSION_TABLE = 'migration_version' +UTC_LENGTH = 14 + +# errors + +class Error(Exception): + """ Base class for all Caribou errors. """ + pass + +class InvalidMigrationError(Error): + """ Thrown when a client migration contains an error. """ + pass + +class InvalidNameError(Error): + """ Thrown when a client migration has an invalid filename. """ + + def __init__(self, filename): + msg = 'Migration filenames must start with a UTC timestamp. ' \ + 'The following file has an invalid name: %s' % filename + super(InvalidNameError, self).__init__(msg) + +# code + +@contextlib.contextmanager +def execute(conn, sql, params=None): + params = [] if params is None else params + cursor = conn.execute(sql, params) + try: + yield cursor + finally: + cursor.close() + +@contextlib.contextmanager +def transaction(conn): + try: + yield + conn.commit() + except: + conn.rollback() + msg = "Error in transaction: %s" % traceback.format_exc() + raise Error(msg) + +def has_method(an_object, method_name): + return hasattr(an_object, method_name) and \ + callable(getattr(an_object, method_name)) + +def is_directory(path): + return os.path.exists(path) and os.path.isdir(path) + +class Migration(object): + """ This class represents a migration version. """ + + def __init__(self, path): + self.path = path + self.filename = os.path.basename(path) + self.module_name, _ = os.path.splitext(self.filename) + self.get_version() # will assert the filename is valid + self.name = self.module_name[UTC_LENGTH:] + while self.name.startswith('_'): + self.name = self.name[1:] + try: + self.module = imp.load_source(self.module_name, path) + except: + msg = "Invalid migration %s: %s" % (path, traceback.format_exc()) + raise InvalidMigrationError(msg) + # assert the migration has the needed methods + missing = [m for m in ['upgrade', 'downgrade'] + if not has_method(self.module, m)] + if missing: + msg = 'Migration %s is missing required methods: %s.' % ( + self.path, ', '.join(missing)) + raise InvalidMigrationError(msg) + + def get_version(self): + if len(self.filename) < UTC_LENGTH: + raise InvalidNameError(self.filename) + timestamp = self.filename[:UTC_LENGTH] + #FIXME: is this test sufficient? + if not timestamp.isdigit(): + raise InvalidNameError(self.filename) + return timestamp + + def upgrade(self, conn): + self.module.upgrade(conn) + + def downgrade(self, conn): + self.module.downgrade(conn) + + def __repr__(self): + return 'Migration(%s)' % self.filename + +class Database(object): + + def __init__(self, db_url): + self.db_url = db_url + self.conn = sqlite3.connect(db_url) + + def close(self): + self.conn.close() + + def is_version_controlled(self): + sql = """select * + from sqlite_master + where type = 'table' + and name = :1""" + with execute(self.conn, sql, [VERSION_TABLE]) as cursor: + return bool(cursor.fetchall()) + + def upgrade(self, migrations, target_version=None): + if target_version: + _assert_migration_exists(migrations, target_version) + + migrations.sort(key=lambda x: x.get_version()) + database_version = self.get_version() + + for migration in migrations: + current_version = migration.get_version() + if current_version <= database_version: + continue + if target_version and current_version > target_version: + break + migration.upgrade(self.conn) + new_version = migration.get_version() + self.update_version(new_version) + + def downgrade(self, migrations, target_version): + if target_version not in (0, '0'): + _assert_migration_exists(migrations, target_version) + + migrations.sort(key=lambda x: x.get_version(), reverse=True) + database_version = self.get_version() + + for i, migration in enumerate(migrations): + current_version = migration.get_version() + if current_version > database_version: + continue + if current_version <= target_version: + break + migration.downgrade(self.conn) + next_version = 0 + # if an earlier migration exists, set the db version to + # its version number + if i < len(migrations) - 1: + next_migration = migrations[i + 1] + next_version = next_migration.get_version() + self.update_version(next_version) + + def get_version(self): + """ Return the database's version, or None if it is not under version + control. + """ + if not self.is_version_controlled(): + return None + sql = 'select version from %s' % VERSION_TABLE + with execute(self.conn, sql) as cursor: + result = cursor.fetchall() + return result[0][0] if result else 0 + + def update_version(self, version): + sql = 'update %s set version = :1' % VERSION_TABLE + with transaction(self.conn): + self.conn.execute(sql, [version]) + + def initialize_version_control(self): + sql = """ create table if not exists %s + ( version text ) """ % VERSION_TABLE + with transaction(self.conn): + self.conn.execute(sql) + self.conn.execute('insert into %s values (0)' % VERSION_TABLE) + + def __repr__(self): + return 'Database("%s")' % self.db_url + +def _assert_migration_exists(migrations, version): + if version not in (m.get_version() for m in migrations): + raise Error('No migration with version %s exists.' % version) + +def load_migrations(directory): + """ Return the migrations contained in the given directory. """ + if not is_directory(directory): + msg = "%s is not a directory." % directory + raise Error(msg) + wildcard = os.path.join(directory, '*.py') + migration_files = glob.glob(wildcard) + return [Migration(f) for f in migration_files] + +def upgrade(db_url, migration_dir, version=None): + """ Upgrade the given database with the migrations contained in the + migrations directory. If a version is not specified, upgrade + to the most recent version. + """ + with contextlib.closing(Database(db_url)) as db: + db = Database(db_url) + if not db.is_version_controlled(): + db.initialize_version_control() + migrations = load_migrations(migration_dir) + db.upgrade(migrations, version) + +def downgrade(db_url, migration_dir, version): + """ Downgrade the database to the given version with the migrations + contained in the given migration directory. + """ + with contextlib.closing(Database(db_url)) as db: + if not db.is_version_controlled(): + msg = "The database %s is not version controlled." % (db_url) + raise Error(msg) + migrations = load_migrations(migration_dir) + db.downgrade(migrations, version) + +def get_version(db_url): + """ Return the migration version of the given database. """ + with contextlib.closing(Database(db_url)) as db: + return db.get_version() + +def create_migration(name, directory=None): + """ Create a migration with the given name. If no directory is specified, + the current working directory will be used. + """ + directory = directory if directory else '.' + if not is_directory(directory): + msg = '%s is not a directory.' % directory + raise Error(msg) + + now = datetime.datetime.now() + version = now.strftime("%Y%m%d%H%M%S") + + contents = MIGRATION_TEMPLATE % {'name':name, 'version':version} + + name = name.replace(' ', '_') + filename = "%s_%s.py" % (version, name) + path = os.path.join(directory, filename) + with open(path, 'w') as migration_file: + migration_file.write(contents) + return path + +MIGRATION_TEMPLATE = """\ +\"\"\" +This module contains a Caribou migration. + +Migration Name: %(name)s +Migration Version: %(version)s +\"\"\" + +def upgrade(connection): + # add your upgrade step here + pass + +def downgrade(connection): + # add your downgrade step here + pass +""" diff -uNr - - akris/akris/client.py akris-genesis/akris/client.py --- akris/akris/client.py false +++ akris-genesis/akris/client.py fe9979f519eba167fd3f5a27f39e64591df69deced21bbca1479b0d1baf7451df093adc7fedf18eb2d68593e01b240617db3d326d7fb71e18442e36c0c1b5055 @@ -0,0 +1,61 @@ +import logging +import json +import queue +import socket +from concurrent.futures import ThreadPoolExecutor + +from .json_stream_parser import load_iter + +HOST = "127.0.0.1" +PORT = 8080 + +logger = logging.getLogger("akris_client") + + +class Client: + def __init__(self, host=HOST, port=PORT): + self.executor = None + self.host = host + self.port = port + self.socket = None + self.sock_file = None + self.message_queue = queue.Queue() + self.connect() + + def connect(self): + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.socket.connect((self.host, self.port)) + self.sock_file = self.socket.makefile(mode="rw") + self.executor = ThreadPoolExecutor( + max_workers=1, thread_name_prefix="api_client" + ) + self.executor.submit(self.listen) + + def listen(self): + for message in load_iter(self.sock_file): + if message["command"] == "shutdown": + break + if message["command"] == "disconnect": + break + logger.info(f"api client received: {message}") + self.message_queue.put(message) + self.close() + + def send_command(self, dict): + logger.info(f"api client sending: {dict}") + self.socket.sendall(json.dumps(dict).encode("utf-8", errors="replace")) + + def close(self): + logger.info("disconnectiong from API service") + self.executor.shutdown(wait=False) + self.socket.close() + + def shutdown_station(self): + logger.info("sending shutdown command to API service") + self.socket.sendall(json.dumps({"command": "shutdown"}).encode("utf-8")) + self.executor.shutdown(wait=False) + self.socket.close() + + def disconnect(self): + self.socket.sendall(json.dumps({"command": "disconnect"}).encode("utf-8")) + self.close() diff -uNr - - akris/akris/config.py akris-genesis/akris/config.py --- akris/akris/config.py false +++ akris-genesis/akris/config.py 93339b79601078dbb2d49670c00d1e1a7dcc2b27c019730a5220681e327700dae3761c92784ef970fe691988f12cd0507b223cc3c831d2b362138b93f87fccb5 @@ -0,0 +1,7 @@ +from .singleton import Singleton + + +class Config(Singleton): + def __init__(self, config={}): + for key, value in config.items(): + setattr(self, key, value) diff -uNr - - akris/akris/console_command_executors/__init__.py akris-genesis/akris/console_command_executors/__init__.py --- akris/akris/console_command_executors/__init__.py false +++ akris-genesis/akris/console_command_executors/__init__.py 26691c382525798d231437a34db006989c1884f59c1767858cdb4bee12bfcf9734b3105d5622e4cc5d1bf1e91765248656fd832e07a67056249c7a89703ddef8 @@ -0,0 +1 @@ +# empty diff -uNr - - akris/akris/console_command_executors/at.py akris-genesis/akris/console_command_executors/at.py --- akris/akris/console_command_executors/at.py false +++ akris-genesis/akris/console_command_executors/at.py 6c0de82fc0efa329b5f05370f1f974d44222d9e02b2fb42639c45179b61fb483c0d29d0825dae7c1b980d7c66672346687171a144e85cdcb0eb91205c1b31ce1 @@ -0,0 +1,89 @@ +import ipaddress + +from akris.database import Database +from akris.console_command_executors.help import COMMANDS + + +def sanitize(at): + for peer in at: + peer["handle"] = peer["handle"].decode() + return at + + +def valid_address(address): + try: + ip, port = address.split(":") + ipaddress.ip_address(ip) # Validate the IP + if not (0 <= int(port) <= 65535): # Validate the port + raise ValueError + except ValueError: + return False + return True + + +class At: + def __init__(self): + self.db = Database.get_instance() + + def execute(self, args): + if len(args) == 0: + response = { + "command": "console_response", + "type": "at", + "body": self.db.get_at(), + } + elif len(args) == 1: + handle = args[0] + if handle not in self.db.get_peer_handles(): + response = { + "command": "console_response", + "type": "error", + "body": "No peer with handle: {}".format(handle), + } + else: + response = { + "command": "console_response", + "type": "at", + "body": self.db.get_at(handle), + } + elif len(args) == 2: + handle = args[0] + if handle not in self.db.get_peer_handles(): + response = { + "command": "console_response", + "type": "error", + "body": "No peer with handle: {}".format(handle), + } + elif not valid_address(args[1]): + response = { + "command": "console_response", + "type": "error", + "body": "Invalid address", + } + elif self.db.address_exists(args[1]): + response = { + "command": "console_response", + "type": "error", + "body": "Duplicate address", + } + else: + address_host, port = args[1].split(":") + self.db.update_at( + { + "handle": handle, + "address": address_host, + "port": int(port), + } + ) + response = { + "command": "console_response", + "type": "at", + "body": self.db.get_at(handle), + } + else: + response = { + "command": "console_response", + "type": "error", + "body": COMMANDS["at"]["help"], + } + return response diff -uNr - - akris/akris/console_command_executors/broadcast_text.py akris-genesis/akris/console_command_executors/broadcast_text.py --- akris/akris/console_command_executors/broadcast_text.py false +++ akris-genesis/akris/console_command_executors/broadcast_text.py 51b3cc7140bce7e3701fbec9e1743d2c453668471b50e16b200ad5b0ccab83f10c5fc0f0773431ae9216aebbe657d9694a8a938fd7624cdb73a9b8d7bf1d32f1 @@ -0,0 +1,25 @@ +from .console_command_executor import split_utf8 +from ..pest_command.broadcast_text import BroadcastText as BroadcastTextCommand +from ..singleton_registry import SingletonRegistry + + +class BroadcastText: + def __init__(self): + super().__init__() + self.db = SingletonRegistry.get_instance().get("Database").get_instance() + + def execute(self, args): + # broadcast the message to the network + parts = [] + for chunk in split_utf8(args[0], maxsize=324): + broadcast_text = BroadcastTextCommand( + { + "speaker": self.db.get_knob("handle"), + "body": chunk, + }, + ) + broadcast_text.send() + + # send the message to the client to display + parts.append(broadcast_text.stringify()) + return parts diff -uNr - - akris/akris/console_command_executors/broadcast_text_m.py akris-genesis/akris/console_command_executors/broadcast_text_m.py --- akris/akris/console_command_executors/broadcast_text_m.py false +++ akris-genesis/akris/console_command_executors/broadcast_text_m.py 7fa9f12461ad47295667eb6d26b5b6974aea393ed53a40b27794669afea5db3be1d5bcb776fcd4be0c28b616a95abc5cf6600385d22800e7cbf4760076de14d6 @@ -0,0 +1,39 @@ +import time + +from .console_command_executor import split_utf8 +from ..pest_command.broadcast_text_m import BroadcastTextM as BroadcastTextMCommand +from ..singleton_registry import SingletonRegistry + + +class BroadcastTextM: + def __init__(self): + self.db = SingletonRegistry.get_instance().get("Database").get_instance() + + def execute(self, args): + concatenated_messages = [] + parts = [] + for chunk in split_utf8(args[0]): + parts.append(chunk) + of = len(parts) + # text_hash and timestamp must be identical for all parts + text_hash = BroadcastTextMCommand.gen_hash(args[0].encode("utf-8", errors="replace")) + timestamp = int(time.time()) + prev_message_hash = None + for n in range(1, of + 1): + broadcast_text_m = BroadcastTextMCommand( + { + "n": n, + "of": of, + "speaker": self.db.get_knob("handle"), + "body": parts[n - 1], + "text_hash": text_hash, + "timestamp": timestamp, + "prev_message_hash": prev_message_hash, + }, + ) + broadcast_text_m.send() + prev_message_hash = broadcast_text_m.message_hash + + # send the message to the client to display + concatenated_messages.append(broadcast_text_m.stringify()) + return concatenated_messages diff -uNr - - akris/akris/console_command_executors/console_command_executor.py akris-genesis/akris/console_command_executors/console_command_executor.py --- akris/akris/console_command_executors/console_command_executor.py false +++ akris-genesis/akris/console_command_executors/console_command_executor.py 004379c51fb37fd0cfec73a46bcbb4cd04b009c5726a61bcf66c237205c8610c25388ebacbfb91b25710eb5bb784498a839dd600b06671439ae701ede2a41807 @@ -0,0 +1,23 @@ +def bytes_for_char_utf_8(c): + return len(c.encode("utf-8", errors="replace")) + + +def split_utf8(s, maxsize=288): + b = 0 + total = 0 + result = [] + for i, c in enumerate(s): + cs = bytes_for_char_utf_8(c) + total += cs + if total > maxsize: + result.append(s[b:i]) + total = cs + b = i + elif i == len(s) - 1: + result.append(s[b:]) + return result + + +class ConsoleCommandExecutor: + def __init__(self): + pass diff -uNr - - akris/akris/console_command_executors/direct_text.py akris-genesis/akris/console_command_executors/direct_text.py --- akris/akris/console_command_executors/direct_text.py false +++ akris-genesis/akris/console_command_executors/direct_text.py 83a39bd4e16da93ab29c6695f953490a75b21d23df9435afd2f144a2ec6165ff0d5da9a7bca9b51598fa435636a1a3f1cf661bc0d40a34fa022f095206ac65bd @@ -0,0 +1,27 @@ +from .console_command_executor import split_utf8 +from ..singleton_registry import SingletonRegistry +from ..pest_command.direct_text import DirectText as DirectTextCommand +from ..filter import Filter + + +class DirectText: + def __init__(self): + self.db = SingletonRegistry.get_instance().get("Database").get_instance() + + def execute(self, args): + # send directly to peer with handle + parts = [] + for chunk in split_utf8(args[1], maxsize=324): + direct_text = DirectTextCommand( + { + "speaker": self.db.get_knob("handle"), + "handle": args[0], + "body": chunk, + "filter": Filter.get_instance(), + }, + ) + direct_text.send() + + # send the message to the client to display + parts.append(direct_text.stringify()) + return parts diff -uNr - - akris/akris/console_command_executors/direct_text_m.py akris-genesis/akris/console_command_executors/direct_text_m.py --- akris/akris/console_command_executors/direct_text_m.py false +++ akris-genesis/akris/console_command_executors/direct_text_m.py b2174dd01173c25836c00cf73cf610d097c8bfbe43655cf448f02b92d14efdff4e3f528872d8e150ffe783c3ff96dfcfc79278bbeb2f9ee0b83797eb35b0e75d @@ -0,0 +1,41 @@ +import base64 +import time + +from .console_command_executor import split_utf8 +from ..singleton_registry import SingletonRegistry +from ..pest_command.direct_text_m import DirectTextM as DirectTextMCommand + + +class DirectTextM: + def __init__(self): + self.db = SingletonRegistry.get_instance().get("Database").get_instance() + + def execute(self, args): + concatenated_messages = [] + parts = [] + for chunk in split_utf8(args[1]): + parts.append(chunk) + of = len(parts) + # text_hash and timestamp must be identical for all parts + text_hash = DirectTextMCommand.gen_hash(args[1].encode("utf-8", errors="replace")) + timestamp = int(time.time()) + prev_message_hash = None + for n in range(1, of + 1): + direct_text_m = DirectTextMCommand( + { + "handle": args[0], + "n": n, + "of": of, + "speaker": self.db.get_knob("handle"), + "body": parts[n - 1], + "text_hash": text_hash, + "timestamp": timestamp, + "prev_message_hash": prev_message_hash, + }, + ) + direct_text_m.send() + prev_message_hash = direct_text_m.message_hash + + # send the message to the client to display + concatenated_messages.append(direct_text_m.stringify()) + return concatenated_messages diff -uNr - - akris/akris/console_command_executors/genkey.py akris-genesis/akris/console_command_executors/genkey.py --- akris/akris/console_command_executors/genkey.py false +++ akris-genesis/akris/console_command_executors/genkey.py 2e218be3719051e8bb19778195dc96b0cce7f54fd85f42aea67ac4b0a99a6b0d3fc4824fa254246508fe594446a47ebdbf875f4a4614f10f94a62bfafea20258 @@ -0,0 +1,15 @@ +import base64 +import os + + +class Genkey: + def __init__(self): + pass + + def execute(self, args): + response = { + "command": "console_response", + "type": "genkey", + "body": base64.b64encode(os.urandom(64)).decode("utf-8"), + } + return response diff -uNr - - akris/akris/console_command_executors/handle.py akris-genesis/akris/console_command_executors/handle.py --- akris/akris/console_command_executors/handle.py false +++ akris-genesis/akris/console_command_executors/handle.py 13cafc89faede31af8fe25b9e3659b386b9e39f93c916960bdd65faccfb2e88b736e3c59c2d6af4eabac0d8028e7f602368033d28d31586c6900a71d0548a910 @@ -0,0 +1,31 @@ +from akris.database import Database +from akris.console_command_executors.help import COMMANDS + + +class Handle: + def __init__(self): + self.db = Database.get_instance() + + def execute(self, args): + if len(args) == 0: + # fetch the station handle if it exists + response = { + "command": "console_response", + "type": "handle", + "body": self.db.get_knob("handle"), + } + elif len(args) == 1: + # set the station handle + self.db.set_knob("handle", args[0]) + response = { + "command": "console_response", + "type": "handle", + "body": f"Handle set to {args[0]}", + } + else: + response = { + "command": "console_response", + "type": "error", + "body": COMMANDS["handle"]["help"], + } + return response diff -uNr - - akris/akris/console_command_executors/help.py akris-genesis/akris/console_command_executors/help.py --- akris/akris/console_command_executors/help.py false +++ akris-genesis/akris/console_command_executors/help.py 15cf19ccbf447923ce2edd18d97e3927317b215b889f574becec079b43738ca9aa1ff234742479915fab762d32d360bfec18f7b0c1aa8020a785edab3cbd1eb6 @@ -0,0 +1,80 @@ +COMMANDS = { + "at": { + "help": "at [handle] [address:port] - Get or set the address of a peer", + }, + "genkey": {"help": "genkey - Randomly generate a symmetric key"}, + "handle": {"help": "handle [handle] - Get or set the station handle"}, + "help": {"help": "help [command] - Get help for a command"}, + "key": {"help": "key [key] - Get or set the key for a peer"}, + "knob": { + "help": "knob [name] [value] - Get or set a knob. Omit all arguments to list knobs" + }, + "page_around": { + "help": "page_around [handle] - Get all messages from the day that includes " + "All returned messages include a ref_link_hash field to be used to group the responses." + }, + "page_down": { + "help": "page_down [handle] - Get page starting at until" + " from peer with [handle]" + " If [handle] is specified direct messages to and from the peer specified by" + " [handle] will be returned. Otherwise, broadcast messages will be returned." + " Messages are ordered by timestamp and chain, with the earliest messages first." + }, + "page_up": { + "help": "page_up [handle] - Get page starting at until" + " from peer with [handle]" + " If [handle] is specified direct messages from the peer specified by" + " [handle] will be returned. Otherwise, broadcast messages will be returned." + " Messages are ordered by timestamp and chain, with the earliest messages first." + }, + "peer": { + "help": "peer - Add a peer", + }, + "search": { + "help": "search - Search for messages containing " + }, + "searchs": { + "help": "searchs - Search for messages from containing " + }, + "unkey": {"help": "unkey [key] - Delete a key"}, + "unpeer": { + "help": "unpeer - Remove a peer", + }, + "version_info": {"help": "version_info - Get version information"}, + "wot": { + "help": "wot [handle] - Get the latest address for all peers, or the keys for a specific peer", + }, +} + + +class Help: + def __init__(self): + pass + + def execute(self, args): + if len(args) == 0: + response = { + "command": "console_response", + "type": "help", + "body": COMMANDS, + } + elif len(args) == 1: + if not COMMANDS.get(args[0]): + response = { + "command": "console_response", + "type": "error", + "body": f"No command named {args[0]}", + } + else: + response = { + "command": "console_response", + "type": "help", + "body": {args[0]: COMMANDS[args[0]]}, + } + else: + response = { + "command": "console_response", + "type": "error", + "body": COMMANDS["help"]["help"], + } + return response diff -uNr - - akris/akris/console_command_executors/key.py akris-genesis/akris/console_command_executors/key.py --- akris/akris/console_command_executors/key.py false +++ akris-genesis/akris/console_command_executors/key.py 6fa4c23573db2bba8033c8a1bbd802d11b0367bd42375151769c6d4040c968db9a2b89f68aee101dc7f2fd63f75ef1e3631061c6c6b53ccafc090287d07e0a41 @@ -0,0 +1,44 @@ +from akris.database import Database +from akris.console_command_executors.help import COMMANDS + + +class Key: + def __init__(self): + self.db = Database.get_instance() + + def execute(self, args): + if len(args) == 2: + handle = args[0] + key = args[1] + if not len(key) == 88: + response = { + "command": "console_response", + "type": "error", + "body": f"Invalid key {key}", + } + elif self.db.key_exists(key): + response = { + "command": "console_response", + "type": "error", + "body": f"Key {key} already exists", + } + elif handle not in self.db.get_peer_handles(): + response = { + "command": "console_response", + "type": "error", + "body": f"No such handle: {handle}", + } + else: + self.db.add_key(handle, key) + response = { + "command": "console_response", + "type": "key", + "body": f"Added key: {key} for peer: {handle}", + } + else: + response = { + "command": "console_response", + "type": "error", + "body": COMMANDS["key"]["help"], + } + return response diff -uNr - - akris/akris/console_command_executors/knob.py akris-genesis/akris/console_command_executors/knob.py --- akris/akris/console_command_executors/knob.py false +++ akris-genesis/akris/console_command_executors/knob.py dc09095be36fac27b6b997b4f4d9c2e3875d4c0f55d930e10a8c9919753e5c433beb1bae392b60a72bfb7d4a027ecbadfbf1b97001aded7160cef587db706e0e @@ -0,0 +1,53 @@ +from akris.database import Database +from akris.console_command_executors.help import COMMANDS + + +class Knob: + def __init__(self): + self.db = Database.get_instance() + + def execute(self, args): + if len(args) == 0: + response = { + "command": "console_response", + "type": "knob", + "body": self.db.get_knobs(), + } + elif len(args) == 1: + if not self.db.has_knob(args[0]): + response = { + "command": "console_response", + "type": "error", + "body": "No knob named {}".format(args[0]), + } + else: + response = { + "command": "console_response", + "type": "knob", + "body": {args[0]: self.db.get_knob(args[0])}, + "name": args[0], + "value": self.db.get_knob(args[0]), + } + elif len(args) == 2: + if not self.db.has_knob(args[0]): + response = { + "command": "console_response", + "type": "error", + "body": "No knob named {}".format(args[0]), + } + else: + self.db.set_knob(args[0], args[1]) + response = { + "command": "console_response", + "type": "knob", + "body": {args[0]: self.db.get_knob(args[0])}, + "name": args[0], + "value": self.db.get_knob(args[0]), + } + else: + response = { + "command": "console_response", + "type": "error", + "body": COMMANDS["knob"]["help"], + } + return response diff -uNr - - akris/akris/console_command_executors/message_stats.py akris-genesis/akris/console_command_executors/message_stats.py --- akris/akris/console_command_executors/message_stats.py false +++ akris-genesis/akris/console_command_executors/message_stats.py da458da7fa504596407d844a5697dfd3e42d04f81da0c46186735738074972ec309451f57a51786a12bd92a03f30fbff7a1fe3a6c55f7e6aeeebb9ff50e2f2b1 @@ -0,0 +1,18 @@ +from ..database import Database +class MessageStats: + def __init__(self): + self.db = Database.get_instance() + + def execute(self, args): + direct_message_timestamps = {} + handles = self.db.get_peer_handles() + for handle in handles: + direct_message_timestamps[handle] = self.db.get_latest_message_timestamp(handle) + + response = { + "command": "console_response", + "type": "message_stats", + "latest_broadcast_message_timestamp": self.db.get_latest_message_timestamp(), + "direct_message_timestamps": direct_message_timestamps, + } + return response diff -uNr - - akris/akris/console_command_executors/page.py akris-genesis/akris/console_command_executors/page.py --- akris/akris/console_command_executors/page.py false +++ akris-genesis/akris/console_command_executors/page.py 2330b6e833e34d0534ef751914e268878581702bbc6778361634732cbd60991b9b3319c6f79892664c04d29c792190ba0bca13b7e8859e20817803b1536e5ea3 @@ -0,0 +1,21 @@ +from ..message_factory import MessageFactory +from ..database import Database, MessageRecord + +class Page: + def __init__(self): + self.db = Database.get_instance() + + def annotate_page_response(self, page): + page[0]["start"] = True + page[-1]["end"] = True + # mark each message as being a page response + for message in page: + message["page_response"] = True + + def reheat_messages(self, messages): + reheated_messages = [] + for message in [MessageRecord(message) for message in messages]: + reheated_message = MessageFactory.reheat(message) + reheated_messages.append(reheated_message.stringify()) + return reheated_messages + diff -uNr - - akris/akris/console_command_executors/page_around.py akris-genesis/akris/console_command_executors/page_around.py --- akris/akris/console_command_executors/page_around.py false +++ akris-genesis/akris/console_command_executors/page_around.py 33a38461f995fba588f7dd008cb76cfe3fe8f93135deeb40284f3cdfbf9e3463ef9d245d5afcc0a684a9bab0e2a5fa95c283b0cdd02b655bf70a608f7e172fc5 @@ -0,0 +1,40 @@ +from .help import COMMANDS +from .page import Page +from ..net_chain import sort_by_chain + + +class PageAround(Page): + def __init__(self): + super().__init__() + + def execute(self, args): + response = [] + if len(args) in ( + 1, + 2, + ): + messages = self.db.get_page_around(*args) + response = self.reheat_messages(messages) + else: + response = { + "command": "console_response", + "type": "error", + "body": COMMANDS["page_around"]["help"], + } + return response + + if len(response) == 0: + return [] + + messages_sorted_by_timestamp_and_chain = sort_by_chain(response) + self.annotate_page_response(messages_sorted_by_timestamp_and_chain, args[0]) + return messages_sorted_by_timestamp_and_chain + + def annotate_page_response(self, page, message_hash): + page[0]["start"] = True + page[-1]["end"] = True + # mark each message as being a page response + for message in page: + message["ref_link_page_response"] = True + message["ref_link_hash"] = message_hash + diff -uNr - - akris/akris/console_command_executors/page_down.py akris-genesis/akris/console_command_executors/page_down.py --- akris/akris/console_command_executors/page_down.py false +++ akris-genesis/akris/console_command_executors/page_down.py b9449728a7be09e68e50d558fd5a11d24540162696b1f8138026ffb9f582823fe0689b79c7b8dd85c23677bed00ee69544f9e35e3edea0e0a1030a7d15426931 @@ -0,0 +1,31 @@ +from .page import Page +from .help import COMMANDS +from ..net_chain import sort_by_chain + + +class PageDown(Page): + def __init__(self): + super().__init__() + + def execute(self, args): + if len(args) in ( + 2, + 3, + ): + messages = self.db.get_next_page(*args) + response = self.reheat_messages(messages) + else: + response = { + "command": "console_response", + "type": "error", + "body": COMMANDS["page"]["help"], + } + return response + + + if len(response) == 0: + return [] + + messages_sorted_by_timestamp_and_chain = sort_by_chain(response) + self.annotate_page_response(messages_sorted_by_timestamp_and_chain) + return messages_sorted_by_timestamp_and_chain diff -uNr - - akris/akris/console_command_executors/page_up.py akris-genesis/akris/console_command_executors/page_up.py --- akris/akris/console_command_executors/page_up.py false +++ akris-genesis/akris/console_command_executors/page_up.py 94cfce7f5980747ba864bd98749522130d23e5853526c6b5ccceab631a9c735e5451b96f9cd976a33e2b5059df409c4acfb4c87bdafdb6c38780ec1024527a8b @@ -0,0 +1,30 @@ +from akris.console_command_executors.help import COMMANDS +from .page import Page +from ..net_chain import sort_by_chain + + +class PageUp(Page): + def __init__(self): + super().__init__() + + def execute(self, args): + if len(args) in ( + 2, + 3, + ): + messages = self.db.get_previous_page(*args) + response = self.reheat_messages(messages) + else: + response = { + "command": "console_response", + "type": "error", + "body": COMMANDS["page"]["help"], + } + return response + + if len(response) == 0: + return [] + + messages_sorted_by_timestamp_and_chain = sort_by_chain(response) + self.annotate_page_response(messages_sorted_by_timestamp_and_chain) + return messages_sorted_by_timestamp_and_chain diff -uNr - - akris/akris/console_command_executors/peer.py akris-genesis/akris/console_command_executors/peer.py --- akris/akris/console_command_executors/peer.py false +++ akris-genesis/akris/console_command_executors/peer.py 247c7063a60d6218d76bbf8de71f7b8f2edb07c32ebc1b40c1112d59d4e1957dccb01f91ca6fb64b6a0c65cb3a0922d9d43d869e1fd442c0eab6d2e1b753f3d5 @@ -0,0 +1,30 @@ +from akris.database import Database +from akris.console_command_executors.help import COMMANDS + + +class Peer: + def __init__(self): + self.db = Database.get_instance() + + def execute(self, args): + if len(args) != 1: + response = { + "command": "console_response", + "type": "error", + "body": COMMANDS["peer"]["help"], + } + else: + if not self.db.get_peer_by_handle(args[0]): + self.db.add_peer(args[0]) + response = { + "command": "console_response", + "type": "peer", + "body": "Peer added", + } + else: + response = { + "command": "console_response", + "type": "error", + "body": f"Peer already exists: {args[0]}", + } + return response diff -uNr - - akris/akris/console_command_executors/report_presence.py akris-genesis/akris/console_command_executors/report_presence.py --- akris/akris/console_command_executors/report_presence.py false +++ akris-genesis/akris/console_command_executors/report_presence.py cc91df3a1c98b3139ed24e6bbfe583e18a03ac94fa8b6aa9246bcd4c430927edb371e9778e9463237345c6463f431e224ef1749e38bac8ca611f11c00a86df58 @@ -0,0 +1,26 @@ +from ..database import Database + + +class ReportPresence: + def __init__(self): + self.db = Database.get_instance() + + def execute(self, args=[]): + response = [] + if len(args) > 0: + response = { + "command": "console_response", + "type": "error", + "body": "report_presence takes no arguments", + } + return response + + for handle in self.db.get_peer_handles(): + status = "online" if self.db.handle_is_online(handle) else "offline" + response.append({ + "command": "presence", + "handle": handle, + "type": status, + }) + + return response \ No newline at end of file diff -uNr - - akris/akris/console_command_executors/reset_database.py akris-genesis/akris/console_command_executors/reset_database.py --- akris/akris/console_command_executors/reset_database.py false +++ akris-genesis/akris/console_command_executors/reset_database.py bb51035307a0eab0d31ad5b30dd69f960543a699399d07e2cbe3e7495a55cc1b3f50f3259e64de62f8d3dc70f31bbb634583b6acfc27540bfd3833f6abe8308d @@ -0,0 +1,14 @@ +from ..singleton_registry import SingletonRegistry + + +class ResetDatabase: + def __init__(self): + self.db = SingletonRegistry.get_instance().get("Database").get_instance() + + def execute(self, command): + self.db.reset() + return { + "command": "console_response", + "type": "reset_database", + "body": "database reset", + } diff -uNr - - akris/akris/console_command_executors/search.py akris-genesis/akris/console_command_executors/search.py --- akris/akris/console_command_executors/search.py false +++ akris-genesis/akris/console_command_executors/search.py 1d372c41ed631e32855e29f2f88c6e577881d3b0b76d08d2b921ef9159f07109319f196a6dd75a3b78595cef30c7605cd7b24824464ad67170cb8731aa24b509 @@ -0,0 +1,58 @@ +import json + +from .console_command_executor import ConsoleCommandExecutor +from .help import COMMANDS +from ..database import Database + +def fix_phf_search_result(message): + try: + fixed_message = message[4:] + fixed_message = fixed_message[:-38] + fixed_message = fixed_message.rstrip(b"\x00") + fixed_message = fixed_message.decode("utf-8") + return fixed_message + + except UnicodeError: + message["body"] = message["body"].decode("utf-8", errors="replace") + return message +class Search(ConsoleCommandExecutor): + def __init__(self): + super().__init__() + self.db = Database.get_instance() + + def execute(self, args): + if len(args) == 1: + search_string = args[0] + messages = self.db.search(search_string) + response = { + "command": "console_response", + "type": "search", + "body": self.clean(messages) + } + elif len(args) == 2: + speaker = args[0] + search_string = args[1] + messages = self.db.search(search_string, speaker=speaker) + response = { + "command": "console_response", + "type": "search", + "body": self.clean(messages) + } + else: + response = { + "command": "console_response", + "type": "error", + "body": COMMANDS["search"]["help"] + } + return response + + def clean(self, messages): + results = [] + for row in messages: + try: + json.dumps(row[2]) + results.append(row) + except: + fixed_row = (row[0], row[1], fix_phf_search_result(row[2]), row[3]) + results.append(fixed_row) + return results diff -uNr - - akris/akris/console_command_executors/unkey.py akris-genesis/akris/console_command_executors/unkey.py --- akris/akris/console_command_executors/unkey.py false +++ akris-genesis/akris/console_command_executors/unkey.py ceab46dc9aaa7d9ead90793782a44822250bac89efa2c70e4e0215a2e6b8c1b04051998c0ac749428646a6f4634488a2de796ee213b3838341582f3198f20860 @@ -0,0 +1,30 @@ +from akris.database import Database +from akris.console_command_executors.help import COMMANDS + + +class Unkey: + def __init__(self): + self.db = Database.get_instance() + + def execute(self, args): + if len(args) == 1: + if not self.db.key_exists(args[0]): + response = { + "command": "console_response", + "type": "error", + "body": f"No such key: {args[0]}", + } + else: + self.db.remove_key(args[0]) + response = { + "command": "console_response", + "type": "unkey", + "body": f"Removed key: {args[0]}", + } + else: + response = { + "command": "console_response", + "type": "error", + "body": COMMANDS["unkey"]["help"], + } + return response diff -uNr - - akris/akris/console_command_executors/unpeer.py akris-genesis/akris/console_command_executors/unpeer.py --- akris/akris/console_command_executors/unpeer.py false +++ akris-genesis/akris/console_command_executors/unpeer.py 3ef832301ece526d43ebf4fb4cc8fa866d8b557a7396b7a2dfaaf820bd663b90002592a740003c02418f44fcd8a3f3724eddb936e6a9f1d2c74b5793528b5443 @@ -0,0 +1,31 @@ +from akris.database import Database +from akris.console_command_executors.help import COMMANDS + + +class Unpeer: + def __init__(self): + self.db = Database.get_instance() + + def execute(self, args): + if len(args) != 1: + response = { + "command": "console_response", + "type": "error", + "body": COMMANDS["unpeer"]["help"], + } + else: + handle = args[0] + if not self.db.get_peer_by_handle(handle): + response = { + "command": "console_response", + "type": "error", + "body": f"No such peer: {handle}", + } + else: + self.db.remove_peer(handle) + response = { + "command": "console_response", + "type": "unpeer", + "body": f"Peer {handle} removed", + } + return response diff -uNr - - akris/akris/console_command_executors/version_info.py akris-genesis/akris/console_command_executors/version_info.py --- akris/akris/console_command_executors/version_info.py false +++ akris-genesis/akris/console_command_executors/version_info.py c151b5e8f60e96cdaac17bb36805169a5207b4f5a50f2a51c0d61482c0933669bd5f43d531448c8bd54af08cc419dfecbcaf7d1105d5f9a66fe991fbb76d33d8 @@ -0,0 +1,17 @@ +from ..database import Database +from ..version import VERSION +from ..pest_command.message import EARLIEST_SUPPORTED_PEST_VERSION, PEST_VERSION + +class VersionInfo: + def __init__(self): + self.db = Database.get_instance() + + def execute(self, args): + response = { + "command": "console_response", + "type": "version_info", + "version": VERSION, + "pest_version": PEST_VERSION, + "earliest_supported_pest_version": EARLIEST_SUPPORTED_PEST_VERSION, + } + return response diff -uNr - - akris/akris/console_command_executors/wot.py akris-genesis/akris/console_command_executors/wot.py --- akris/akris/console_command_executors/wot.py false +++ akris-genesis/akris/console_command_executors/wot.py 65a82f5ee10e2b3f55c2962a9f7007c2c1ae4d22d459c2582dfc726d093ada85a3acd2cd667ab13f0c971b402178b1de8a853031028cdd7013fd396e64a4fcaa @@ -0,0 +1,39 @@ +from akris.database import Database +from akris.console_command_executors.help import COMMANDS + + +class Wot: + def __init__(self): + self.db = Database.get_instance() + + def execute(self, args): + if len(args) == 0: + # Display the current WOT + peers = self.db.get_peers() + response = { + "command": "console_response", + "type": "wot", + "body": [p.serialize() for p in peers], + } + elif len(args) == 1: + handle = args[0] + peer = self.db.get_peer_by_handle(handle) + if not peer: + response = { + "command": "console_response", + "type": "error", + "body": f"No such handle: {handle}", + } + else: + response = { + "command": "console_response", + "type": "wot", + "body": [peer.serialize()], + } + else: + response = { + "command": "console_response", + "type": "error", + "body": COMMANDS["wot"]["help"], + } + return response diff -uNr - - akris/akris/console_dispatch.py akris-genesis/akris/console_dispatch.py --- akris/akris/console_dispatch.py false +++ akris-genesis/akris/console_dispatch.py f680a75a93d1fa1871a0c59099c0d4e0f405ba4906405c8f3d67484be1db8301dae3db418bac24ca617786e5d1858a016afb75192996e456a71644c3c65c28d7 @@ -0,0 +1,63 @@ +import json + +from .console_command_executors.at import At +from .console_command_executors.broadcast_text import BroadcastText +from .console_command_executors.broadcast_text_m import BroadcastTextM +from .console_command_executors.direct_text import DirectText +from .console_command_executors.direct_text_m import DirectTextM +from .console_command_executors.genkey import Genkey +from .console_command_executors.handle import Handle +from .console_command_executors.help import Help +from .console_command_executors.key import Key +from .console_command_executors.knob import Knob +from .console_command_executors.message_stats import MessageStats +from .console_command_executors.page_around import PageAround +from .console_command_executors.page_down import PageDown +from .console_command_executors.page_up import PageUp +from .console_command_executors.peer import Peer +from .console_command_executors.report_presence import ReportPresence +from .console_command_executors.reset_database import ResetDatabase +from .console_command_executors.search import Search +from .console_command_executors.unpeer import Unpeer +from .console_command_executors.unkey import Unkey +from .console_command_executors.version_info import VersionInfo +from .console_command_executors.wot import Wot + + +class ConsoleDispatch: + def __init__(self): + self.executors = { + "at": At(), + "broadcast_text": BroadcastText(), + "broadcast_text_m": BroadcastTextM(), + "direct_text": DirectText(), + "direct_text_m": DirectTextM(), + "genkey": Genkey(), + "handle": Handle(), + "help": Help(), + "key": Key(), + "knob": Knob(), + "message_stats": MessageStats(), + "page_around": PageAround(), + "page_down": PageDown(), + "page_up": PageUp(), + "peer": Peer(), + "report_presence": ReportPresence(), + "reset_database": ResetDatabase(), + "search": Search(), + "searchs": Search(), + "unpeer": Unpeer(), + "unkey": Unkey(), + "version_info": VersionInfo(), + "wot": Wot(), + } + + def execute(self, command): + try: + return self.executors[command["command"]].execute(command["args"]) + except KeyError: + return { + "command": "console_response", + "type": "error", + "body": f"No command named {command['command']}", + } diff -uNr - - akris/akris/database.py akris-genesis/akris/database.py --- akris/akris/database.py false +++ akris-genesis/akris/database.py 3862f0ff41ab8a152afc4b845713c949e4f0572c5fa9fdde23813b3cca4beafc188cb3587108e472a8cc452b2274e31819a2b3cfa3589c923094e35150dc8208 @@ -0,0 +1,912 @@ +# coding=utf-8 +import base64 +import calendar +import json +import sqlite3 +import uuid +import logging +import datetime +import time +import os +import importlib.resources +from hashlib import sha512 +from itertools import chain + +from . import caribou + +from .sqlite3worker import Sqlite3Worker + +from .config import Config +from .peer import Peer +from .pest_command.constants import ( + ADDRESS_CAST, + BROADCAST_TEXT, + BROADCAST_TEXT_M, + DIRECT_TEXT, + DIRECT_TEXT_M, +) +from .pest_command.message import EMPTY_CHAIN +from .version import VERSION +from .singleton import Singleton +from .log_config import LogConfig + + +logger = LogConfig.get_instance().get_logger("akris.database") + + +def fetchone(results): + if len(results) > 0: + return results[0] + else: + return None + + +def convert_to_number(s): + try: + return int(s) + except ValueError: + try: + return float(s) + except ValueError: + return s + + +KNOBS = { + "api_service.process_outbound_queue": 0.1, + "asked_for.get_data_tries": 2, + "asked_for.get_data_wait": 2, + "asked_for.get_data_window": 5, + "asked_for.check_interval": 1, + "pest_service.process_inbound_queue": 0.5, + "pest_service.process_outbound_queue": 0.5, + "max_bounces": 3, + "ignore.interval_seconds": 10, + "filter.cache_expiration_seconds": 3600, + "asked_for.expiration_seconds": 120, + "presence.peer_offline_interval_seconds": 120, + "presence.report_interval": 0, + "key_offer.interval_seconds": 0, + "prod.interval_seconds": 60, + "address_cast.interval_seconds": 0, + "address_cast.port_hammering_enabled": 0, + "cold_peer_seconds": 62, + "banner": f"Akris {VERSION}", + "prod.send_address_cast": "0", + "handle": "anon", + "testing.disable_broadcast": 0, +} + + +class MessageRecord: + fields = ",".join( + [ + "speaker", + "immediate", + "recipient_handle", + "message_bytes", + "message_hash", + "command", + "timestamp", + "created_at", + "get_data", + "body", + "base64_message_hash" + ] + ) + + def __init__(self, record): + ( + self.speaker, + self.immediate, + self.recipient_handle, + self.message_bytes, + self.message_hash, + self.command, + self.timestamp, + self.created_at, + self.get_data_response, + self.body, + self.base64_message_hash, + ) = record + + +class Database(Singleton): + def __init__(self, db_path=".", db_name="akris.db"): + full_path = os.path.join(db_path, db_name) + self.config = Config.get_instance() + with importlib.resources.path("akris", "migrations") as migrations_path: + caribou.upgrade(full_path, migrations_path) + self.worker = Sqlite3Worker(full_path) + + def reset(self): + table_names = [ + "handle_self_chain", + "cache", + "broadcast_self_chain", + "at", + "wot", + "handles", + "keys", + "log", + "asked_for", + "knobs", + "key_slices", + "key_offers", + "reporting_peers", + ] + for table_name in table_names: + self.worker.execute(f"DELETE FROM {table_name};") + + def search(self, search_query, speaker=None): + if speaker: + sql_query = ( + "SELECT speaker, recipient_handle, highlight(log_index,1, '<<', '>>'), base64_message_hash FROM log_index " + "WHERE body match ? and speaker = ? order by rank", + (search_query, speaker), + ) + else: + sql_query = ( + "SELECT speaker, recipient_handle, highlight(log_index,1, '<<', '>>'), base64_message_hash FROM log_index " + "WHERE body match ? order by rank", + (search_query,), + ) + return self.worker.execute(*sql_query) + + def set_last_external_address(self, address): + self.worker.execute("DELETE FROM external_address;") + self.worker.execute( + "INSERT INTO external_address (address) VALUES (?)", (address,) + ) + + def get_last_external_address(self): + result = fetchone( + self.worker.execute("SELECT address FROM external_address LIMIT 1;") + ) + if result: + return result[0] + else: + return None + + def page_query(self, handle): + if handle: + own_handle = self.get_knob("handle") + command_ids = ",".join( + [str(command_id) for command_id in [DIRECT_TEXT, DIRECT_TEXT_M]] + ) + query = ( + f"SELECT {MessageRecord.fields} FROM log WHERE ((speaker='{own_handle}' AND recipient_handle='{handle}')" + f" OR (recipient_handle='{own_handle}' AND speaker='{handle}'))" + f" AND command in ({command_ids})" + " AND timestamp >= ? AND timestamp <= ? ORDER BY timestamp DESC" + ) + else: + command_ids = ",".join( + [str(command_id) for command_id in [BROADCAST_TEXT, BROADCAST_TEXT_M]] + ) + query = ( + f"SELECT {MessageRecord.fields} FROM log WHERE command in ({command_ids})" + " AND timestamp >= ? AND timestamp <= ? ORDER BY timestamp ASC" + ) + return query + + def get_latest_message_timestamp(self, handle=None): + if handle: + own_handle = self.get_knob("handle") + command_ids = ",".join( + [str(command_id) for command_id in [DIRECT_TEXT, DIRECT_TEXT_M]] + ) + query = ( + f"SELECT MAX(timestamp) FROM log WHERE ((speaker='{own_handle}' AND recipient_handle='{handle}')" + f" OR (recipient_handle='{own_handle}' AND speaker='{handle}'))" + f" AND command in ({command_ids})" + ) + else: + command_ids = ",".join( + [str(command_id) for command_id in [BROADCAST_TEXT, BROADCAST_TEXT_M]] + ) + query = f"SELECT MAX(timestamp) FROM log WHERE command in ({command_ids})" + results = fetchone(self.worker.execute(query)) + if results: + return results[0] + else: + return None + + # this should really be called "get_window" + def get_previous_page(self, timestamp, days_before, handle=None): + start_date = datetime.datetime.fromtimestamp(timestamp) - datetime.timedelta( + days=days_before + ) + # Add ten minutes for to cactch messages from those with significant forward clock skew + end_date = datetime.datetime.fromtimestamp(timestamp + 60 * 10) + query = self.page_query(handle) + return self.worker.execute( + query, + ( + start_date.timestamp(), + end_date.timestamp(), + ), + ) + + def get_next_page(self, timestamp, days_later, handle=None): + start_date = datetime.datetime.fromtimestamp(timestamp) + end_date = start_date + datetime.timedelta(days=1) + + query = self.page_query(handle) + return self.worker.execute( + query, + ( + start_date.timestamp(), + end_date.timestamp(), + ), + ) + + def get_page_around(self, message_hash, handle=None): + timestamp = fetchone( + self.worker.execute( + "select timestamp from log where message_hash = ?", + (base64.b64decode(message_hash),), + ) + )[0] + start_date = datetime.datetime.fromtimestamp(timestamp) - datetime.timedelta( + days=1 + ) + end_date = datetime.datetime.fromtimestamp(timestamp) + datetime.timedelta( + days=1 + ) + query = self.page_query(handle) + return self.worker.execute( + query, + ( + start_date.timestamp(), + end_date.timestamp(), + ), + ) + + def persist_cache(self, cache): + self.worker.execute("delete from cache") + filtered_cache = {} + for key, value in cache.items(): + if not value["value"]: + filtered_cache[base64.b64encode(key).decode()] = { + "timestamp": value["timestamp"], + "value": None, + } + elif value["value"].command is ADDRESS_CAST: + filtered_cache[base64.b64encode(key).decode()] = { + "timestamp": value["timestamp"], + "value": None, + } + + self.worker.execute( + "insert into cache(value) values(?);", (json.dumps(filtered_cache),) + ) + + def load_cache(self): + decoded_cache = {} + results = fetchone(self.worker.execute("select value from cache")) + if results is not None: + encoded_cache = json.loads(results[0]) + for key, value in encoded_cache.items(): + decoded_cache[base64.b64decode(key)] = value + return decoded_cache + else: + return {} + + def clear_key_offer_and_slice(self, peer_id): + self.worker.execute("delete from key_offers where peer_id=?", (peer_id,)) + self.worker.execute("delete from key_slices where peer_id=?", (peer_id,)) + + def get_key_offer(self, peer_id): + results = fetchone( + self.worker.execute( + "select slice from key_slices where peer_id=?", (peer_id,) + ) + ) + if results is not None: + return sha512(results[0]).digest() + else: + slice = os.urandom(64) + self.worker.execute( + "insert into key_slices(peer_id, slice) values(?, ?)", (peer_id, slice) + ) + return sha512(slice).digest() + + def get_peer_key_offer(self, peer_id): + results = fetchone( + self.worker.execute( + "select offer from key_offers where peer_id=?", (peer_id,) + ) + ) + if results is not None: + return results[0] + else: + return None + + def set_key_offer(self, peer_id, key_offer): + self.worker.execute( + "insert into key_offers(peer_id, offer) values(?, ?)", (peer_id, key_offer) + ) + + def get_key_slice(self, peer_id): + results = fetchone( + self.worker.execute( + "select slice from key_slices where peer_id=?", (peer_id,) + ) + ) + if results is not None: + return results[0] + else: + return None + + def set_sent_peer_key_slice(self, peer_id): + self.worker.execute("update key_slices set sent=1 where peer_id=?", (peer_id,)) + + def sent_peer_key_slice(self, peer_id): + results = fetchone( + self.worker.execute( + "select sent from key_slices where peer_id=?", (peer_id,) + ) + ) + if results is not None: + return results[0] + else: + return None + + def has_knob(self, knob): + return knob in KNOBS + + def close(self): + self.worker.close() + + def update_handle_self_chain(self, handle, message_hash): + self.worker.execute( + "insert into handle_self_chain(handle, message_hash) values(?, ?)", + (handle, memoryview(message_hash)), + ) + + def get_handle_self_chain(self, handle): + results = fetchone( + self.worker.execute( + "select message_hash from handle_self_chain where handle=?\ + order by id desc limit 1", + (handle,), + ) + ) + if results is not None: + return results[0][:] + else: + return EMPTY_CHAIN + + def get_handle_net_chain(self, handle): + command_ids = ",".join( + [str(command_id) for command_id in [DIRECT_TEXT, DIRECT_TEXT_M]] + ) + own_handle = self.get_knob("handle") + results = fetchone( + self.worker.execute( + f"SELECT message_hash FROM log WHERE ((speaker=? AND recipient_handle=?)" + f" OR (recipient_handle=? AND speaker=?))" + f" AND command in ({command_ids})" + f" ORDER BY timestamp desc LIMIT 1", + (own_handle, handle, own_handle, handle), + ) + ) + if results is not None: + return results[0][:] + else: + return EMPTY_CHAIN + + def update_broadcast_self_chain(self, message_hash): + self.worker.execute( + "insert into broadcast_self_chain(message_hash) values(?)", + (memoryview(message_hash),), + ) + + def get_broadcast_self_chain(self): + results = fetchone( + self.worker.execute( + "select message_hash from broadcast_self_chain order by id desc limit 1" + ) + ) + if results is not None: + return results[0][:] + else: + return EMPTY_CHAIN + + def get_latest_broadcast_message_records(self): + results = self.worker.execute( + "select * from log where (command=? OR command=?) " + "AND timestamp = (select max(timestamp) from log where command=? OR command=?)", + (BROADCAST_TEXT, BROADCAST_TEXT_M, BROADCAST_TEXT, BROADCAST_TEXT_M), + ) + return [MessageRecord(m) for m in results] + + def get_knobs(self): + results = self.worker.execute("select name, value from knobs order by name asc") + knobs = {} + for result in results: + knobs[result[0]] = result[1] + for key in KNOBS.keys(): + if not knobs.get(key): + knobs[key] = KNOBS[key] + return knobs + + def get_knob(self, knob_name): + result = fetchone( + self.worker.execute("select value from knobs where name=?", (knob_name,)) + ) + if result: + return convert_to_number(result[0]) + elif KNOBS.get(knob_name): + return convert_to_number(KNOBS.get(knob_name)) + else: + return None + + def set_knob(self, knob_name, knob_value): + result = fetchone( + self.worker.execute("select value from knobs where name=?", (knob_name,)) + ) + if result: + self.worker.execute( + "update knobs set value=? where name=?", + ( + knob_value, + knob_name, + ), + ) + else: + self.worker.execute( + "insert into knobs(name, value) values(?, ?)", + ( + knob_name, + knob_value, + ), + ) + + def get_at(self, handle=None): + at = [] + if handle == None: + results = self.worker.execute( + "select handle_id, address, port, updated_at, strftime('%s', updated_at) from at\ + order by updated_at desc" + ) + else: + result = fetchone( + self.worker.execute( + "select handle_id from handles where handle=?", (handle,) + ) + ) + if None != result: + handle_id = result[0] + else: + return [] + results = self.worker.execute( + "select handle_id, address, port, updated_at, strftime('%s', updated_at) from at \ + where handle_id=? order by updated_at desc", + (handle_id,), + ) + for result in results: + handle_id, address, port, updated_at_utc, updated_at_unixtime = result + h = fetchone( + self.worker.execute( + "select handle from handles where handle_id=?", (handle_id,) + ) + )[0] + if updated_at_utc: + if "." not in updated_at_utc: + updated_at_utc = updated_at_utc + ".0" + dt_format = "%Y-%m-%d %H:%M:%S.%f" + dt_utc = datetime.datetime.strptime(updated_at_utc, dt_format) + dt_local = self.utc_to_local(dt_utc) + updated_at = datetime.datetime.strftime(dt_local, dt_format) + else: + updated_at = "no packets received from this address" + + at.append( + { + "handle": h, + "address": "%s:%s" % (address, port), + "active_at": updated_at, + "active_at_unixtime": int(updated_at_unixtime) + if updated_at_unixtime + else 0, + } + ) + return at + + def update_at(self, peer, set_active_at=True): + row = self.worker.execute( + "select handle_id from handles where handle=?", (peer["handle"],) + ) + if row != None: + handle_id = row[0][0] + else: + raise Exception("handle not found") + + at_entry = fetchone( + self.worker.execute( + "select handle_id, address, port from at where handle_id=?", + (handle_id,), + ) + ) + + # if there are no AT entries for this handle, insert one + timestamp = datetime.datetime.utcnow() if set_active_at else None + if at_entry == None: + self.worker.execute( + "insert into at(handle_id, address, port, updated_at) values(?, ?, ?, ?)", + (handle_id, peer["address"], peer["port"], timestamp), + ) + logging.debug( + "inserted new at entry for %s: %s:%d" + % (peer["handle"], peer["address"], peer["port"]) + ) + + # otherwise just update the existing entry + else: + try: + self.worker.execute( + "update at set updated_at = ?,\ + address = ?,\ + port = ?\ + where handle_id=?", + (timestamp, peer["address"], peer["port"], handle_id), + ) + + except sqlite3.IntegrityError: + self.worker.execute("delete from at where handle_id=?", (handle_id,)) + + def add_peer(self, handle): + peer_id = uuid.uuid4().hex + self.worker.execute("insert into wot(peer_id) values(?)", (peer_id,)) + handle_id = uuid.uuid4().hex + self.worker.execute( + "insert into handles(handle_id, peer_id, handle) values(?, ?, ?)", + (handle_id, peer_id, handle), + ) + + def remove_peer(self, handle): + # get peer id + result = fetchone( + self.worker.execute("select peer_id from handles where handle=?", (handle,)) + ) + if result == None: + raise Exception("handle not found") + else: + peer_id = result[0] + # get all aliases + + handle_ids = self.get_handle_ids_for_peer(peer_id) + for handle_id in handle_ids: + # delete at entries for each alias + self.worker.execute("delete from at where handle_id=?", (handle_id,)) + + self.worker.execute("delete from handles where peer_id=?", (peer_id,)) + + # delete all keys for peer id + self.worker.execute("delete from keys where peer_id=?", (peer_id,)) + + # delete peer from wot + self.worker.execute("delete from wot where peer_id=?", (peer_id,)) + + def add_key(self, handle, key): + peer_id = fetchone( + self.worker.execute("select peer_id from handles where handle=?", (handle,)) + )[0] + if peer_id != None: + self.worker.execute( + "insert into keys(peer_id, key) values(?, ?)", (peer_id, key) + ) + # let's send an address cast to let our new peer know where to find us + self.set_knob("prod.send_address_cast", 1) + + def add_key_by_peer_id(self, peer_id, key): + self.worker.execute( + "insert into keys(peer_id, key) values(?, ?)", (peer_id, key) + ) + + def get_key(self, peer_id): + return fetchone( + self.worker.execute( + "select key from keys where peer_id=? order by created_at desc limit 1", + (peer_id,), + ) + )[0] + + def key_exists(self, key): + return ( + fetchone(self.worker.execute("select key from keys where key=?", (key,))) + is not None + ) + + def remove_key(self, key): + self.worker.execute("delete from keys where key=?", (key,)) + + def get_handle_ids_for_peer(self, peer_id): + return list( + chain.from_iterable( + self.worker.execute( + "select handle_id from handles where peer_id=?", (peer_id,) + ) + ) + ) + + def get_peer_handles(self): + handles = self.listify(self.worker.execute("select handle from handles")) + return handles + + def get_peers(self): + peers = [] + handles = self.worker.execute("select handle from handles") + + for handle in handles: + peer = self.get_peer_by_handle(handle[0]) + # leaving this check in here to help detect corrupt db + peers.append(peer) + return peers + + def listify(self, results): + return list(chain.from_iterable(results)) + + def wanted(self): + get_data_tries = self.get_knob("asked_for.get_data_tries") + get_data_window = self.get_knob("asked_for.get_data_window") + wanted = self.listify( + self.worker.execute( + "select want_hash from asked_for where " "attempts < ? limit ?", + (get_data_tries, get_data_window), + ) + ) + return wanted + + def increment_attempts(self, want_hash): + self.worker.execute( + "update asked_for set attempts = attempts + 1 where want_hash=?", + (want_hash,), + ) + + def get_attempts(self, want_hash): + result = fetchone( + self.worker.execute( + "select attempts from asked_for where want_hash=?", (want_hash,) + ) + ) + if result == None: + return None + else: + return result[0] + + def get_requested_at(self, want_hash): + result = fetchone( + self.worker.execute( + "select requested_at from asked_for where want_hash=?", (want_hash,) + ) + ) + if result == None: + return None + else: + return result[0] + + def update_requested_at(self, want_hash): + self.worker.execute( + "update asked_for set requested_at = ? where want_hash=?", + ( + time.time(), + want_hash, + ), + ) + + def asked_for_expects(self, message_hash): + result = fetchone( + self.worker.execute( + "select exists(select 1 from asked_for where want_hash=?)\ + limit 1", + (message_hash,), + ) + ) + return result[0] + + def add_asked_for(self, want_hash): + self.worker.execute( + "insert into asked_for(want_hash, requested_at) values(?, ?)", + (want_hash, time.time()), + ) + + def unwant(self, want_hash): + # check and make sure we have the want hash + self.worker.execute("delete from asked_for where want_hash=?", (want_hash,)) + + def log_has_message(self, message_hash): + result = fetchone( + self.worker.execute( + "select exists(select 1 from log where message_hash=?)\ + limit 1", + (message_hash,), + ) + ) + return result[0] + + def log_message(self, message): + self.worker.execute( + "insert into log(" + "message_hash, speaker, immediate, recipient_handle, message_bytes, command, timestamp, get_data, body, base64_message_hash) " + "values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + ( + message.message_hash, + message.speaker, + message.check_immediate(), + message.handle, + message.message_bytes, + message.command, + message.timestamp, + message.get_data_response, + message.body, + base64.b64encode(message.message_hash).decode("utf-8"), + ), + ) + + def log_reporting_peer(self, message_hash, peer_id): + self.worker.execute( + "insert into reporting_peers(peer_id, message_hash) values(?, ?)", + (peer_id, message_hash), + ) + + def get_reporting_peer_ids(self, message_hash): + return self.listify( + self.worker.execute( + "select peer_id from reporting_peers where message_hash=?", + (message_hash,), + ) + ) + + def get_reporting_peer_handles(self, message_hash): + peer_ids = self.listify( + self.worker.execute( + "select peer_id from reporting_peers where message_hash=?", + (message_hash,), + ) + ) + handles = [] + for peer_id in peer_ids: + result = fetchone( + self.worker.execute( + "select handle from handles where peer_id=? limit 1", + (peer_id,), + ) + ) + if result: + handles.append(result[0]) + return handles + + def get_message(self, message_hash): + result = fetchone( + self.worker.execute( + "select command, message_bytes from log where message_hash=? limit 1", + (message_hash,), + ) + ) + if result: + return result[0], result[1][:] + return None, None + + def get_keyed_peers( + self, exclude_addressless=False, exclude_ids=[], no_at_only=False + ): + if len(list(exclude_ids)) == 0: + query = "select distinct peer_id from keys order by random()" + else: + query = ( + "select distinct peer_id from keys where peer_id not in (%s) order by random()" + % ",".join("?" * len(list(exclude_ids))) + ) + + peer_ids = self.listify(self.worker.execute(query, list(exclude_ids))) + peers = [] + for peer_id in peer_ids: + try: + handle = fetchone( + self.worker.execute( + "select handle from handles where peer_id=?", (peer_id,) + ) + )[0] + peer = self.get_peer_by_handle(handle) + if exclude_addressless and (peer.address is None or peer.port is None): + continue + if no_at_only and (peer.address is not None or peer.port is not None): + continue + peers.append(peer) + except: + pass + return peers + + def get_cold_peers(self): + cold_peer_seconds = self.get_knob("cold_peer_seconds") + all_peers = self.get_peers() + cold_peers = [] + + # peers with keys and no address + for peer in all_peers: + current_time = time.time() + if peer.address is None and len(peer.keys) > 0: + cold_peers.append(peer) + elif peer.address and len(peer.keys) > 0: + at = self.get_at(peer.handles[0])[0] + if at["active_at_unixtime"] < (current_time - cold_peer_seconds): + cold_peers.append(peer) + + return cold_peers + + def handle_is_online(self, handle): + # last rubbish message from peer associated with handle is + # sufficiently recent + try: + at = self.get_at(handle)[0] + except IndexError: + return False + + if at["active_at_unixtime"] > time.time() - float( + self.get_knob("presence.peer_offline_interval_seconds") + ): + return True + else: + return False + + def utc_to_local(self, utc_dt): + # get integer timestamp to avoid precision lost + timestamp = calendar.timegm(utc_dt.timetuple()) + local_dt = datetime.datetime.fromtimestamp(timestamp) + assert utc_dt.resolution >= datetime.timedelta(microseconds=1) + return local_dt.replace(microsecond=utc_dt.microsecond) + + def get_peer_by_handle(self, handle): + handle_info = fetchone( + self.worker.execute( + "select handle_id, peer_id from handles where handle=?", (handle,) + ) + ) + + if handle_info == None: + return None + + peer_id = handle_info[1] + address = fetchone( + self.worker.execute( + "select address, port from at where handle_id=?\ + order by updated_at desc limit 1", + (handle_info[0],), + ) + ) + handles = self.listify( + self.worker.execute( + "select handle from handles where peer_id=?", (peer_id,) + ) + ) + keys = self.listify( + self.worker.execute( + "select key from keys where peer_id=?\ + order by random()", + (peer_id,), + ) + ) + return Peer( + { + "handles": handles, + "peer_id": handle_info[1], + "address": address[0] if address else None, + "port": address[1] if address else None, + "keys": keys, + } + ) + + def address_exists(self, address): + # break address into ip and port + ip, port = address.split(":") + result = fetchone( + self.worker.execute( + "select exists(select 1 from at where address=? and port=?)\ + limit 1", + (ip, int(port)), + ) + ) + # return true if address exists otherwise false + return result[0] diff -uNr - - akris/akris/exception_dispatch.py akris-genesis/akris/exception_dispatch.py --- akris/akris/exception_dispatch.py false +++ akris-genesis/akris/exception_dispatch.py b2209d8dd30bd8b8bf4963f11b329409360859d5126a2d5abb3f7ae471c595348a7ace2bea7748f2b48158d9240dfb9b1890623301132f3f6522e9cb701aacdf @@ -0,0 +1,66 @@ +import binascii + +from .exception_handlers.duplicate_packet import DuplicatePacket +from .exception_handlers.out_of_order import OutOfOrder +from .pest_command.message_exception import * +from .log_config import LogConfig + +logger = LogConfig.get_instance().get_logger("akris.exception_dispatch") + + +class ExceptionDispatch: + def __init__(self): + self.handlers = { + OUT_OF_ORDER_SELF: OutOfOrder(), + OUT_OF_ORDER_NET: OutOfOrder(), + OUT_OF_ORDER_BOTH: OutOfOrder(), + DUPLICATE_PACKET: DuplicatePacket(), + } + + def handle(self, exception): + try: + return self.handlers[exception.error_code].handle(exception) + except KeyError as e: + # just log it + error_code = e.args[0] + packet_info = exception.metadata["packet_info"] + address = packet_info[0] + port = packet_info[1] + packet_sample = packet_info[2] + + if error_code == STALE_PACKET: + logger.error( + "[%s:%d] -> stale packet: %s" + % (address, port, binascii.hexlify(exception.object.message_hash)) + ) + elif error_code == DUPLICATE_PACKET: + logger.error( + "[%s:%d] -> duplicate packet: %s" + % (address, port, binascii.hexlify(exception.object.message_hash)) + ) + elif error_code == MALFORMED_PACKET: + logger.error( + "[%s:%d] -> malformed packet: %s" % (address, port, packet_sample) + ) + elif error_code == INVALID_SIGNATURE: + logger.error( + "[%s:%d] -> invalid packet signature: %s" + % (address, port, packet_sample) + ) + elif error_code == UNSUPPORTED_VERSION: + logger.error( + "[%s:%d] -> pest version not supported: %s" + % (address, port, packet_sample) + ) + elif error_code == UNSUPPORTED_COMMAND: + logger.error( + "[%s:%d] -> pest command not supported: %s" + % (address, port, packet_sample) + ) + elif error_code == INVALID_HANDLE_ENCODING: + logger.error( + "[%s:%d] -> invalid handle encoding: %s" + % (address, port, packet_sample) + ) + else: + logger.error("No handler for exception: %s" % exception.error_code) diff -uNr - - akris/akris/exception_handlers/__init__.py akris-genesis/akris/exception_handlers/__init__.py --- akris/akris/exception_handlers/__init__.py false +++ akris-genesis/akris/exception_handlers/__init__.py 26691c382525798d231437a34db006989c1884f59c1767858cdb4bee12bfcf9734b3105d5622e4cc5d1bf1e91765248656fd832e07a67056249c7a89703ddef8 @@ -0,0 +1 @@ +# empty diff -uNr - - akris/akris/exception_handlers/duplicate_packet.py akris-genesis/akris/exception_handlers/duplicate_packet.py --- akris/akris/exception_handlers/duplicate_packet.py false +++ akris-genesis/akris/exception_handlers/duplicate_packet.py 07e356c7c99e47620a68e846525441cb70898ce2e5beff4116e41ffbac2d4e6305b030385b7308e23451a624151c3d453f97cd875376a179339810275b9be7a4 @@ -0,0 +1,40 @@ +from ..database import Database +from ..singleton_registry import SingletonRegistry +from ..pest_command.constants import BROADCAST_TEXT, BROADCAST_TEXT_M +from base64 import b64encode + +class DuplicatePacket: + def __init__(self): + self.db = Database.get_instance() + self.filter = SingletonRegistry.get_instance().get("Filter").get_instance() + self.api_service = SingletonRegistry.get_instance().get("ApiService").get_instance() + + def handle(self, exception): + message = exception.object + own_handle = self.db.get_knob("handle") + + # if we didn't originate this packet + if message.speaker == own_handle: + return + + # and the packet is still in the cache + if not self.filter.cache_has(message.message_hash): + return + + if message.command not in [BROADCAST_TEXT, BROADCAST_TEXT_M]: + return + + # log the reporting peer + self.db.log_reporting_peer(message.message_hash, message.peer.peer_id) + + # notify client + + self.api_service.enqueue_outbound( + { + "command": "message_update", + "message_hash": b64encode(message.message_hash).decode("utf-8"), + "reporting_peer": message.peer.handle(), + "message_command": message.command, + "timestamp": message.timestamp, + } + ) \ No newline at end of file diff -uNr - - akris/akris/exception_handlers/out_of_order.py akris-genesis/akris/exception_handlers/out_of_order.py --- akris/akris/exception_handlers/out_of_order.py false +++ akris-genesis/akris/exception_handlers/out_of_order.py e20f1c99857a34267f64b808826978cb410916e3b55ef36304e56361515b604ad5629d3bbf613db2c7e5204af349a31aeecd8b7c0c837c26a447af3027b1f625 @@ -0,0 +1,51 @@ +import binascii +import logging + +from ..pest_command.get_data import GetData +from ..pest_command.message_exception import ( + OUT_OF_ORDER_SELF, + OUT_OF_ORDER_NET, + OUT_OF_ORDER_BOTH, +) +from ..singleton_registry import SingletonRegistry +from ..pest_dispatch import PestDispatch +from ..log_config import LogConfig + +logger = LogConfig.get_instance().get_logger( + "akris.pest_command_executors.out_of_order" +) + + +class OutOfOrder: + def __init__(self): + self.db = SingletonRegistry.get_instance().get("Database").get_instance() + self.asked_for = SingletonRegistry.get_instance().get("AskedFor").get_instance() + self.pest_dispatch = PestDispatch() + + def handle(self, exception): + if exception.error_code == OUT_OF_ORDER_SELF: + self.add_message_to_asked_for_and_send_get_data(exception, ["self_chain"]) + elif exception.error_code == OUT_OF_ORDER_NET: + self.add_message_to_asked_for_and_send_get_data(exception, ["net_chain"]) + elif exception.error_code == OUT_OF_ORDER_BOTH: + self.add_message_to_asked_for_and_send_get_data( + exception, ["self_chain", "net_chain"] + ) + else: + raise Exception("Unexpected error code") + + def add_message_to_asked_for_and_send_get_data(self, exception, broken_chains): + message = exception.object + packet_info = exception.metadata["packet_info"] + address = packet_info[0] + port = packet_info[1] + logger.debug( + "[%s:%d] -> message received out of order: %s" + % (address, port, binascii.hexlify(message.message_hash)) + ) + for chain in broken_chains: + want_hash = getattr(message, chain) + if not self.asked_for.expects(want_hash): + self.asked_for.add(want_hash) + # handle the message as usual from here on + self.pest_dispatch.execute(message) diff -uNr - - akris/akris/filter.py akris-genesis/akris/filter.py --- akris/akris/filter.py false +++ akris-genesis/akris/filter.py a2be87e66a14077b23b87d6de2633c4614aae7754e0fa98961b8ce58389e58251586d0f33f04a9f65cf32328675f9e14f808317688afed538b90836aa9be552f @@ -0,0 +1,88 @@ +import time + +from .pest_command.broadcast_text_m import BroadcastTextM +from .pest_command.constants import * +from .pest_command.broadcast_text import BroadcastText +from .pest_command.direct_text import DirectText +from .database import Database +from .pest_command.direct_text_m import DirectTextM +from .pest_command.message import EMPTY_CHAIN +from .log_config import LogConfig + +logger = LogConfig.get_instance().get_logger("akris.filter") + + +class Filter(object): + _instance = None + + @classmethod + def get_instance(cls): + if cls._instance is None: + cls._instance = cls() + return cls._instance + + def __init__(self): + self.db = Database.get_instance() + self.cache = self.load_cache() + + def persist_cache(self): + self.db.persist_cache(self.cache) + + def load_cache(self): + return self.db.load_cache() + + def exhume(self, message_hash): + command, message_bytes = self.db.get_message(message_hash) + if message_bytes: + if command == DIRECT_TEXT: + return DirectText({"message_bytes": message_bytes}) + if command == DIRECT_TEXT_M: + return DirectTextM({"message_bytes": message_bytes}) + if command == BROADCAST_TEXT: + return BroadcastText({"message_bytes": message_bytes}) + if command == BROADCAST_TEXT_M: + return BroadcastTextM({"message_bytes": message_bytes}) + + def intern(self, message): + # somehow we are trying to intern a message we've already got + if self.has(message.message_hash): + return + + self.cache[message.message_hash] = {"timestamp": time.time(), "value": message} + self.persist_cache() + self.evict_expired() + if message.command in [ + BROADCAST_TEXT, + BROADCAST_TEXT_M, + DIRECT_TEXT, + DIRECT_TEXT_M, + ]: + self.db.log_message(message) + + # if the message is hearsay we must log the reporting peer + if not message.check_immediate(): + own_handle = self.db.get_knob("handle") + if message.speaker != own_handle: + self.db.log_reporting_peer(message.message_hash, message.peer.peer_id) + + def has(self, message_hash): + if EMPTY_CHAIN == message_hash: + return True + + if message_hash in self.cache: + return True + + if self.db.log_has_message(message_hash): + return True + return False + + def cache_has(self, message_hash): + return message_hash in self.cache + + def evict_expired(self): + working_cache = self.cache.copy() + for key in working_cache: + if time.time() - working_cache.get(key)["timestamp"] > float( + self.db.get_knob("filter.cache_expiration_seconds") + ): + self.cache.pop(key) diff -uNr - - akris/akris/json_stream_parser.py akris-genesis/akris/json_stream_parser.py --- akris/akris/json_stream_parser.py false +++ akris-genesis/akris/json_stream_parser.py 1739f5be2eb527e18d21d34baed16de55e844a92488b4a3f4a928b4443d39e82e5f4312a85bfde83eb3870cce6b679833c02101b483678fa3f62e6368527ad10 @@ -0,0 +1,233 @@ +from typing import Tuple, Union, List, Dict + + +__all__ = ('load_iter', 'JSONDecodeError') + + +class JSONDecodeError(Exception): + def __init__(self, msg, *args): + super().__init__(msg % args) + + +class JSONEOFError(JSONDecodeError): + pass + + +def load_iter(fp, *, object_pairs_hook=dict): + ch = '' + while True: + try: + ch = _skip_ch_space(ch, fp) + except JSONEOFError: + return + obj, ch = _load_obj(ch, fp, object_pairs_hook=object_pairs_hook) + yield obj + + +Value = Union[int, float, str, None, List['Value'], Dict[str, 'Value']] + + +def _load_obj(ch, fp, *, object_pairs_hook) -> Tuple[Value, str]: + if ch == '{': + ch = '' + pairs = [] + while True: + ch = _skip_ch_space(ch, fp) + if ch == '}': + return object_pairs_hook(pairs), '' + + if pairs: + if ch != ',': + raise JSONDecodeError('expect comma, got %r', ch) + ch = _skip_space(fp) + + if ch != '"': + raise JSONDecodeError('expect quote, got %r', ch) + key = _load_str(fp) + + ch = _skip_space(fp) + if ch != ':': + raise JSONDecodeError('expect colon, got %r', ch) + + val, ch = _load_obj(_skip_space(fp), fp, object_pairs_hook=object_pairs_hook) + + pairs.append((key, val)) + elif ch == '[': + ch = '' + rv = [] + while True: + ch = _skip_ch_space(ch, fp) + if ch == ']': + return rv, '' + + if len(rv) > 0: + if ch != ',': + raise JSONDecodeError('expect comma, got %r', ch) + ch = _skip_space(fp) + + val, ch = _load_obj(ch, fp, object_pairs_hook=object_pairs_hook) + rv.append(val) + elif ch == 't': + _expect(fp, 'rue') + return True, '' + elif ch == 'f': + _expect(fp, 'alse') + return False, '' + elif ch == 'n': + _expect(fp, 'ull') + return None, '' + elif ch == '"': + return _load_str(fp), '' + elif ch in '0123456789-': + return _load_num(ch, fp) + else: + raise JSONDecodeError('unknown char: %r', ch) + + +def _expect(fp, tok): + if tok != fp.read(len(tok)): + raise JSONDecodeError('expect %r', tok) + + +_ESC_MAP = { + '"': '"', + "\\": '\\', + '/': '/', + 'b': '\b', + 'f': '\f', + 'n': '\n', + 'r': '\r', + 't': '\t', +} + + +def _load_str(fp) -> str: + rv = [] + while True: + ch = _read_char(fp, 'got eof on string') + if ch == '"': + return ''.join(rv) + elif ch == '\\': + ch = _read_char(fp, 'got eof on string escape') + if ch in _ESC_MAP: + rv.append(_ESC_MAP[ch]) + elif ch == 'u': + digits = fp.read(4) + if len(digits) != 4: + raise JSONDecodeError('expect 4-hex-digits') + try: + ch = chr(int(digits, 16)) + except ValueError: + raise JSONDecodeError('expect 4-hex-digits: got %r', digits) + rv.append(ch) + else: + raise JSONDecodeError('bad excape') + else: + if ord(ch) <= 0x1f: + raise JSONDecodeError('unexpected control char: %r', ch) + rv.append(ch) + + +def _read_char(fp, errmsg) -> str: + ch = fp.read(1) + if not ch: + raise JSONDecodeError(errmsg) + return ch + + +def _load_num(ch: str, fp) -> Tuple[Union[int, float], str]: + s = ch + + # sign + if ch == '-': + ch = _read_char(fp, 'expect number') + s += ch + + # first digits of int + if ch not in '0123456789': + raise JSONDecodeError('expected 0123456789, got: %r', ch) + is_zero = (ch == '0') + + # remain of int + digits, ch = _maybe_digits(fp) # NOTE: ch may be '' + s += digits + + # check leading zero + if is_zero and digits: + raise JSONDecodeError('digits follows zero') + + # frac + is_float = False + if ch == '.': + is_float = True + digits, ch = _expect_digits(fp) + s += '.' + digits + + # exp + if ch and ch in 'eE': + is_float = True + s += ch + ch = _read_char(fp, 'expect exp') + if ch in '+-': + s += ch + ch = _read_char(fp, 'expect exp digits') + + if ch not in '0123456789': + raise JSONDecodeError('expected 0123456789, got: %r', ch) + s += ch + + digits, ch = _maybe_digits(fp) + s += digits + + if is_float: + return float(s), ch + else: + return int(s), ch + + +def _expect_digits(fp): + ch = _read_char(fp, 'expect digits') + if ch not in '0123456789': + raise JSONDecodeError('expected 0123456789, got: %r', ch) + + digits, next_ch = _maybe_digits(fp) + return ch + digits, next_ch + + +def _maybe_digits(fp) -> Tuple[str, str]: + s = '' + while True: + ch = fp.read(1) + if ch and ch in '0123456789': + s += ch + else: + break + + return s, ch + + +def _skip_space(fp) -> str: + while True: + ch = fp.read(1) + if not ch: + raise JSONEOFError('unexpected EOF') + + if ch not in ' \t\n\r': + return ch + + +def _skip_ch_space(ch, fp) -> str: + if ch and ch not in ' \t\n\r': + return ch + return _skip_space(fp) + + +def main(): + import sys + import json + for obj in load_iter(sys.stdin): + print(json.dumps(obj, ensure_ascii=False), end='\n') + + +if __name__ == '__main__': + main() diff -uNr - - akris/akris/log_config.py akris-genesis/akris/log_config.py --- akris/akris/log_config.py false +++ akris-genesis/akris/log_config.py 039a2707161264c360040ce38836cbd8af92bb1eceb79420e63092b033c1788aef272e1d910f606defa06df6991b662e1f565e7e5fa90cfa75dd7a5e72d53823 @@ -0,0 +1,28 @@ +import os +import logging +from logging.handlers import RotatingFileHandler +from .singleton import Singleton +AKRIS_DATA_PATH = os.path.join(os.path.expanduser("~"), ".akris") + +# Since LogConfig is called in many places, its easier just to parse the cmdline args here as well +class LogConfig(Singleton): + def __init__(self, data_path=AKRIS_DATA_PATH): + + if not os.path.exists(data_path): + os.makedirs(data_path) + + # Check if the directory exists + if not os.path.exists(data_path): + os.makedirs(data_path) + + log_path = os.path.join(data_path, "logs") + if not os.path.exists(log_path): + os.makedirs(log_path) + + self.handler = RotatingFileHandler(os.path.join(log_path, "station.log"), maxBytes=10**7) + + def get_logger(self, name): + logger = logging.getLogger(name) + logger.setLevel(logging.INFO) + logger.addHandler(self.handler) + return logger diff -uNr - - akris/akris/message_factory.py akris-genesis/akris/message_factory.py --- akris/akris/message_factory.py false +++ akris-genesis/akris/message_factory.py 20df8cfa4288057318f2ecfa1a86955a2649feceed768b98cfdfbabed3f07c6584904ca0e9133cb1420c56797372ce5e9c34f0a92141d952be9327808f79466e @@ -0,0 +1,105 @@ +import base64 +import hashlib +import hmac +import struct +import logging + +from .pest_command.message import EARLIEST_SUPPORTED_PEST_VERSION +from .pest_command.constants import * +from .pest_command.prod import Prod +from .pest_command.direct_text import DirectText +from .pest_command.direct_text_m import DirectTextM +from .pest_command.broadcast_text import BroadcastText +from .pest_command.broadcast_text_m import BroadcastTextM +from .pest_command.get_data import GetData +from .pest_command.ignore import Ignore +from .pest_command.address_cast import AddressCast +from .pest_command.key_offer import KeyOffer +from .pest_command.key_slice import KeySlice +from .pest_command.message_exception import ( + MessageException, + UNSUPPORTED_VERSION, + UNSUPPORTED_COMMAND, +) +from .pest_command.message_exception import MALFORMED_PACKET, INVALID_SIGNATURE +from akris.c_serpent.serpent import decrypt + +PACKET_SIZE = 496 +MAX_SPEAKER_SIZE = 32 +TS_ACCEPTABLE_SKEW = 60 * 15 +BLACK_PACKET_FORMAT = "<448s48s" +RED_PACKET_FORMAT = "<16sBBxB428s" + +MESSAGE_TYPES = { + BROADCAST_TEXT: BroadcastText, + BROADCAST_TEXT_M: BroadcastTextM, + DIRECT_TEXT: DirectText, + DIRECT_TEXT_M: DirectTextM, + PROD: Prod, + GET_DATA: GetData, + KEY_OFFER: KeyOffer, + KEY_SLICE: KeySlice, + ADDRESS_CAST: AddressCast, + IGNORE: Ignore, +} + + +class MessageFactory: + def inflate(self, peer, black_packet, metadata): + # unpack the black packet + for key in peer.keys: + key_bytes = base64.b64decode(key) + signing_key = key_bytes[:32] + cipher_key = key_bytes[32:] + + try: + black_packet_bytes, signature_bytes = struct.unpack( + BLACK_PACKET_FORMAT, black_packet + ) + except: + logging.error( + "Discarding malformed black packet from %s" % peer.get_key() + ) + raise MessageException(MALFORMED_PACKET, metadata) + + # check signature + signature_check_bytes = hmac.new( + signing_key, black_packet_bytes, hashlib.sha384 + ).digest() + + if signature_check_bytes != signature_bytes: + continue + + # try to decrypt black packet + red_packet_bytes = decrypt(cipher_key, black_packet_bytes) + + # unpack red packet + try: + nonce, bounces, version, command, message_bytes = struct.unpack( + RED_PACKET_FORMAT, red_packet_bytes + ) + + # if red_packet_bytes was never set, no matching key for the sig was found + # this is expected to happen often as only one peer's key should match for each + # message we receive + except NameError as ex: + raise MessageException(INVALID_SIGNATURE, metadata) + + if version > EARLIEST_SUPPORTED_PEST_VERSION: + raise MessageException(UNSUPPORTED_VERSION, metadata) + + try: + return MESSAGE_TYPES[command]({"metadata": metadata}).inflate( + { + "peer": peer, + "bounces": bounces, + "bytes": message_bytes, + "metadata": metadata, + } + ) + except KeyError as ke: + raise MessageException(UNSUPPORTED_COMMAND, metadata) + + @staticmethod + def reheat(message_record): + return MESSAGE_TYPES[message_record.command]({}).reheat(message_record) diff -uNr - - akris/akris/migrations/20230427195338_init.py akris-genesis/akris/migrations/20230427195338_init.py --- akris/akris/migrations/20230427195338_init.py false +++ akris-genesis/akris/migrations/20230427195338_init.py 63a88c36153484c2b93ae9849a0d21c36ed664b26ac9a5e83900a0b5c08c5ad11ee9ffb6433f234cb8c9bcd42376cddfa2b471a07a2c3934d4725ca2cf10f272 @@ -0,0 +1,138 @@ +""" +This module contains a Caribou migration. + +Migration Name: init +Migration Version: 20230427195338 +""" + + +def upgrade(connection): + connection.execute("create table if not exists external_address(address blob not null)") + + connection.execute("create table if not exists cache(value text not null)") + + connection.execute( + "create table if not exists key_offers(id integer primary key autoincrement,\ + peer_id text not null,\ + offer blob not null,\ + unique(peer_id))" + ) + + connection.execute( + "create table if not exists key_slices(id integer primary key autoincrement,\ + peer_id text not null,\ + slice blob not null,\ + sent boolean default false,\ + unique(peer_id))" + ) + + connection.execute( + "create table if not exists handle_self_chain(id integer primary key autoincrement,\ + handle string not null,\ + message_hash blob not null)" + ) + + connection.execute( + "create table if not exists broadcast_self_chain(id integer primary key autoincrement,\ + message_hash blob not null)" + ) + + connection.execute( + "create table if not exists net_chain(id integer primary key autoincrement,\ + message_hash blob not null)" + ) + + connection.execute( + "create table if not exists at(handle_id text,\ + address text not null,\ + port integer not null,\ + updated_at datetime default null,\ + unique(address, port))" + ) + + connection.execute("create table if not exists wot(peer_id text primary key)") + + connection.execute( + "create table if not exists handles(handle_id text primary key,\ + peer_id text,\ + handle text,\ + unique(handle))" + ) + + connection.execute( + "create table if not exists keys(peer_id text,\ + key text,\ + created_at datetime default current_timestamp,\ + unique(key))" + ) + + connection.execute( + "create table if not exists log(\ + speaker text not null,\ + immediate boolean default false,\ + recipient_handle text,\ + message_bytes blob not null,\ + message_hash text not null, \ + command integer not null, \ + timestamp datetime not null, \ + created_at datetime default current_timestamp, \ + get_data boolean default false, \ + body text not null, \ + base64_message_hash text not null, \ + unique(message_hash))" + ) + + connection.execute( + "create virtual table log_index using fts5(" + "speaker," + "body," + "recipient_handle," + "base64_message_hash)" + ) + + connection.execute( + "CREATE TRIGGER log_ai AFTER INSERT ON log BEGIN " + "INSERT INTO log_index(speaker, recipient_handle, body, base64_message_hash) " + "VALUES (new.speaker, new.recipient_handle, new.body, new.base64_message_hash);" + "END;" + ) + + + connection.execute( + "create table if not exists reporting_peers (\ + message_hash text not null, \ + peer_id text not null, \ + unique(message_hash, peer_id))" + ) + + connection.execute("create index speaker_index on log(speaker)") + + connection.execute("create index timestamp_index on log(timestamp)") + + connection.execute( + "create index speaker_timestamp_index on log(speaker, timestamp)" + ) + + connection.execute( + "create table if not exists asked_for(want_hash text not null, \ + attempts int default 0, \ + requested_at int not null, \ + unique(want_hash))" + ) + + connection.execute( + "create table if not exists knobs(\ + name text not null,\ + value text not null)" + ) + + +def downgrade(connection): + connection.execute("drop table handle_self_chain") + connection.execute("drop table broadcast_self_chain") + connection.execute("drop table at") + connection.execute("drop table wot") + connection.execute("drop table handles") + connection.execute("drop table keys") + connection.execute("drop table log") + connection.execute("drop table knobs") diff -uNr - - akris/akris/net_chain.py akris-genesis/akris/net_chain.py --- akris/akris/net_chain.py false +++ akris-genesis/akris/net_chain.py 0a8caed5684a3208b1b67c04cbb78ad2a3fed99a55725d17c092169352f6a5bc764ff064250522fb5f6b619d427949b8eb777ce63f1b01c59140749899ec8f48 @@ -0,0 +1,56 @@ +import base64 + +from .message_factory import MessageFactory +from .database import Database +from .pest_command.message import EMPTY_CHAIN +from .singleton import Singleton + + +# sort results with identical timestamps by message hash +# this is kind of a heuristic because messages with identical timestamps are not +# guaranteed to be descendents or antecedents of one another +def sort_by_chain(messages): + timestamp_groups = {} + for query_result in messages: + ts = query_result["timestamp"] + added = False + if timestamp_groups.get(ts, None) is None: + timestamp_groups[ts] = [query_result] + else: + for message in timestamp_groups[ts]: + # if query_result is a descendent of message + if message["message_hash"] in [query_result["net_chain"], query_result["self_chain"]]: + timestamp_groups[ts].append(query_result) + added = True + break + # query_result is an antecedent of message + elif query_result["message_hash"] in [message["net_chain"], message["self_chain"]]: + timestamp_groups[ts].insert(timestamp_groups[ts].index(message), query_result) + added = True + break + if not added: + timestamp_groups[ts].append(query_result) + + # get the values of timestamp_groups as a list sorted by key (timestamp) + messages_ordered_by_ts_and_chain = [] + ordered_ts_groups = [value for key, value in sorted(timestamp_groups.items())] + for ts_group in ordered_ts_groups: + messages_ordered_by_ts_and_chain += ts_group + return messages_ordered_by_ts_and_chain + + +class NetChain(Singleton): + def __init__(self): + super().__init__() + self.db = Database.get_instance() + + def get_broadcast_net_chain(self): + latest_message_records = self.db.get_latest_broadcast_message_records() + if len(latest_message_records) == 0: + return EMPTY_CHAIN + + reheated_messages = [MessageFactory.reheat(mr) for mr in latest_message_records] + stringified_reheated_messages = [m.stringify() for m in reheated_messages] + sorted_messages = sort_by_chain(stringified_reheated_messages) + return base64.b64decode(sorted_messages[-1]["message_hash"]) + diff -uNr - - akris/akris/peer.py akris-genesis/akris/peer.py --- akris/akris/peer.py false +++ akris-genesis/akris/peer.py 27fcc1d13e2a536c113663b145d4ddb2ff1b669f51183887918d0f285de08e93ed88fd34245524ac1f86dc1e09c3057de129a1279f817b00b01b200ca0d4a600 @@ -0,0 +1,28 @@ +class Peer(object): + def __init__(self, peer_entry): + self.handles = peer_entry.get("handles") + self.keys = peer_entry.get("keys") + self.peer_id = peer_entry.get("peer_id") + self.address = peer_entry.get("address") + self.port = peer_entry.get("port") + + def get_key(self): + if len(self.keys) > 0: + return self.keys[0] + else: + return None + + def handle(self): + if self.handles: + if len(self.handles) > 0: + return self.handles[0] + return None + + def serialize(self): + return { + "handles": self.handles, + "keys": self.keys, + "peer_id": self.peer_id, + "address": self.address, + "port": self.port, + } diff -uNr - - akris/akris/pest_command/__init__.py akris-genesis/akris/pest_command/__init__.py --- akris/akris/pest_command/__init__.py false +++ akris-genesis/akris/pest_command/__init__.py 26691c382525798d231437a34db006989c1884f59c1767858cdb4bee12bfcf9734b3105d5622e4cc5d1bf1e91765248656fd832e07a67056249c7a89703ddef8 @@ -0,0 +1 @@ +# empty diff -uNr - - akris/akris/pest_command/address_cast.py akris-genesis/akris/pest_command/address_cast.py --- akris/akris/pest_command/address_cast.py false +++ akris-genesis/akris/pest_command/address_cast.py 570933fb244e3f4e87d07e04977604eadc21a6cb16dca7c73427d8f1ba99696cf6685bd797539aabc20232039589883d1dd6c6d7ab30fb1700bff45ec213a08f @@ -0,0 +1,205 @@ +import base64 +import hashlib +import hmac +import logging +import os +import struct +import time + +from .message_exception import MessageException, DUPLICATE_PACKET +from .message import Message +from .constants import ADDRESS_CAST +from .prod import get_ascii_address +from .prod import OUTGOING +from .prod import INCOMING +from ..filter import Filter +from ..log_config import LogConfig +from ..singleton_registry import SingletonRegistry +from akris.c_serpent.serpent import encrypt, decrypt + +logger = LogConfig.get_instance().get_logger("akris.pest_command.address_cast") + +BLACK_PACKET_FORMAT = "<272s48s4s" +RED_PACKET_FORMAT = "<16sL6s246s" +LOGGING_FORMAT = "[%s:%d %s] %s %s %s %s" +NONCE_LENGTH = 16 +RED_PACKET_PADDING_LENGTH = 246 +PAYLOAD_PADDING_LENGTH = 4 +SEND_PROD = 0x00 +PORT_HAMMER = 0x01 + + +class AddressCast(Message): + def __init__(self, message): + super().__init__(message) + self.db = SingletonRegistry.get_instance().get("Database").get_instance() + self.pest_service = ( + SingletonRegistry.get_instance().get("PestService").get_instance() + ) + self.command = ADDRESS_CAST + self.address = message.get("external_address") + self.bounces = message.get("bounces", 0) + self.filter = Filter.get_instance() + self.origin_peer = None + self.flag = SEND_PROD + + def inflate(self, message): + self.peer = message.get("peer") + self.message_bytes = message.get("bytes") + (int_ts, self_chain, net_chain, speaker, body) = self._unpack_generic_message( + self.message_bytes + ) + self.timestamp = int_ts + self.speaker = speaker + self.body = body + self.message_hash = self.gen_hash(self.message_bytes) + self.filter = Filter.get_instance() + if self.filter.has(self.message_hash): + raise MessageException(DUPLICATE_PACKET, self.metadata, self) + + # if the signature checks out decrypt + for peer in self.db.get_keyed_peers(exclude_addressless=False): + if peer: + ( + black_packet_bytes, + signature, + ) = struct.unpack( + BLACK_PACKET_FORMAT, body + )[0:2] + + for key in peer.keys: + key_bytes = base64.b64decode(key) + signing_key = key_bytes[:32] + cipher_key = key_bytes[32:] + signature_check = hmac.new( + signing_key, black_packet_bytes, hashlib.sha384 + ).digest() + + if signature_check != signature: + continue + + red_packet_bytes = decrypt(cipher_key, black_packet_bytes) + + try: + (flag, address) = struct.unpack(RED_PACKET_FORMAT, red_packet_bytes)[ + 1:3 + ] + self.origin_peer = peer + self.address = address + self.flag = flag + self.log_incoming( + message.get("peer"), + peer.handles[0], + get_ascii_address(address), + ) + return self + except NameError as ne: + # This message was not intended for us. + # We must forward it on if the bounce count is below the cutoff + pass + + self.log_incoming(message.get("peer"), "N/A", "N/A") + return self + + # Increment bounce count and send to everyone except originating peer + def forward(self): + # forward to everyone except the station from which we received this + for peer in self.db.get_keyed_peers( + exclude_addressless=True, exclude_ids=[self.peer.peer_id] + ): + self.message_bytes = self.get_message_bytes() + signed_packet_bytes = self.pack( + peer, self.command, self.bounces, self.message_bytes + ) + self.pest_service.enqueue_outbound_packet_to_address( + { + "address": (peer.address, peer.port), + "black_packet": signed_packet_bytes, + } + ) + + # send to every peer with an address in the AT + def broadcast(self): + self.timestamp = int(time.time()) + + # for each *cold* peer we have a key for + cold_peers = self.db.get_cold_peers() + cold_peer_ids = map(lambda p: p.peer_id, cold_peers) + for peer in self.db.get_keyed_peers( + exclude_addressless=True, exclude_ids=cold_peer_ids + ): + for cold_peer in cold_peers: + # parse peer key + key_bytes = base64.b64decode(cold_peer.get_key()) + signing_key = key_bytes[:32] + cipher_key = key_bytes[32:] + + # build the red packet + red_packet_bytes = struct.pack( + RED_PACKET_FORMAT, + os.urandom(NONCE_LENGTH), + 1 if self.db.get_knob("port_hammering_enabled") else 0, + self.address, + os.urandom(RED_PACKET_PADDING_LENGTH), + ) + # form the black packet by encrypting and signing the red packet + black_packet_bytes = encrypt(cipher_key, red_packet_bytes) + + # sign and pack the black address cast packet + seal = hmac.new( + signing_key, black_packet_bytes, hashlib.sha384 + ).digest() + self.body = struct.pack( + BLACK_PACKET_FORMAT, + black_packet_bytes, + seal, + os.urandom(PAYLOAD_PADDING_LENGTH), + ) + + # send off the black packet + self.message_bytes = self.get_message_bytes() + self.message_hash = hashlib.sha256(self.message_bytes).digest() + self.filter.intern(self) + signed_packet_bytes = self.pack( + peer, self.command, self.bounces, self.message_bytes + ) + self.pest_service.enqueue_outbound_packet_to_address( + { + "address": (peer.address, peer.port), + "black_packet": signed_packet_bytes, + } + ) + self.log_outgoing(red_packet_bytes, cold_peer, peer) + + def log_incoming(self, peer, origin_peer_handle, address): + params = ( + peer.address, + peer.port, + peer.handles[0], + INCOMING, + "ADDRESS_CAST", + origin_peer_handle, + address, + ) + logger.info(LOGGING_FORMAT % params) + + def log_outgoing(self, red_packet_bytes, cold_peer, peer): + ( + nonce, + command, + pest_address, + padding, + ) = struct.unpack(RED_PACKET_FORMAT, red_packet_bytes) + + logger.info( + LOGGING_FORMAT + % ( + peer.address, + peer.port, + peer.handles[0], + OUTGOING, + "ADDRESS_CAST", + cold_peer.handles[0], + get_ascii_address(pest_address), + ) + ) diff -uNr - - akris/akris/pest_command/broadcast_text.py akris-genesis/akris/pest_command/broadcast_text.py --- akris/akris/pest_command/broadcast_text.py false +++ akris-genesis/akris/pest_command/broadcast_text.py bb267c5780d5ef6f0391833ff955557b0d2268f8c6be359ecd60e32475279d840649927547c48996709ee0cabc2ca540cc3bd9f48ff2fff499094ac6ebc2a58c @@ -0,0 +1,148 @@ +import base64 +import struct + +import time +import hashlib +from .constants import BROADCAST_TEXT +from .message import MAX_SPEAKER_SIZE, MESSAGE_PACKET_FORMAT +from .text_message import TextMessage +from ..singleton_registry import SingletonRegistry +from ..log_config import LogConfig + +logger = LogConfig.get_instance().get_logger("akris.pest_command.broadcast") + + +class BroadcastText(TextMessage): + def __init__(self, message): + super().__init__(message) + self.speaker = message.get("speaker") + self.command = BROADCAST_TEXT + self.bounces = message.get("bounces", 0) + self.pest_service = ( + SingletonRegistry.get_instance().get("PestService").get_instance() + ) + + def stringify(self): + return { + "command": "broadcast_text", + "body": self.body, + "message_hash": base64.b64encode(self.message_hash).decode("utf-8"), + "net_chain": base64.b64encode(self.net_chain).decode("utf-8"), + "self_chain": base64.b64encode(self.self_chain).decode("utf-8"), + "speaker": self.speaker, + "timestamp": self.get_adjusted_timestamp(), + "immediate": self.immediate, + "reporting_peers": self.reporting_peer_handles() + } + + def inflate(self, message): + self.message_bytes = message.get("bytes") + self.message_hash = self.gen_hash(self.message_bytes) + + (int_ts, self_chain, net_chain, speaker, body) = self._unpack_generic_message( + self.message_bytes, unpad_body=True + ) + + self.peer = message.get("peer") + self.body = body + self.timestamp = int_ts + self.speaker = speaker + self.bounces = message.get("bounces") + self.self_chain = self_chain + self.net_chain = net_chain + self.metadata = message.get("metadata") + + self.check_if_stale() + self.check_if_duplicate() + self.check_order() + return self + + # evidently send is only called for messages originating from the client + def send(self): + # since we are not rebroadcasting we need to set the timestamp + if not self.timestamp: + self.timestamp = int(time.time()) + + self.message_bytes = self.get_message_bytes() + self.message_hash = hashlib.sha256(self.message_bytes).digest() + + self.filter.intern(self) + + self.db.update_broadcast_self_chain(self.message_hash) + + # disable broadcast on this station for testing purposes + if self.db.get_knob("testing.disable_broadcast"): + return + + for peer in self.db.get_keyed_peers(exclude_addressless=True): + signed_packet_bytes = self.pack( + peer, self.command, self.bounces, self.message_bytes + ) + self.pest_service.enqueue_outbound_packet_to_address( + { + "black_packet": signed_packet_bytes, + "address": (peer.address, peer.port), + } + ) + self.log_outgoing(peer) + + def get_message_bytes(self): + speaker = self._pad(self.speaker, MAX_SPEAKER_SIZE) + + # let's generate the self_chain value from the last message or set it to zero if + # this is the first message + + self.self_chain = self.db.get_broadcast_self_chain() + nc = SingletonRegistry.get_instance().get("NetChain").get_instance() + self.net_chain = nc.get_broadcast_net_chain() + + body = self.body.encode("utf-8", errors="replace") + + message_bytes = struct.pack( + MESSAGE_PACKET_FORMAT, + self.timestamp, + self.self_chain, + self.net_chain, + speaker, + body, + ) + return message_bytes + + # we already have message bytes here since this message came from the long buffer + def retry(self, requesting_peer): + signed_packet_bytes = self.pack( + requesting_peer, self.command, self.bounces, self.message_bytes + ) + self.pest_service.enqueue_outbound_packet_to_address( + { + "black_packet": signed_packet_bytes, + "address": (requesting_peer.address, requesting_peer.port), + } + ) + self.log_outgoing(requesting_peer) + + def forward(self): + reporting_peer_ids = self.reporting_peer_ids() + for peer in self.db.get_keyed_peers( + exclude_addressless=True, exclude_ids=reporting_peer_ids + ): + # we don't want to send a broadcast back to the originator + if self.peer and (peer.peer_id == self.peer.peer_id): + continue + + signed_packet_bytes = self.pack( + peer, self.command, self.bounces, self.message_bytes + ) + self.pest_service.enqueue_outbound_packet_to_address( + { + "black_packet": signed_packet_bytes, + "address": (peer.address, peer.port), + } + ) + self.log_outgoing(peer) + + def reporting_peer_ids(self): + return self.db.get_reporting_peer_ids(self.message_hash) + + def reporting_peer_handles(self): + return self.db.get_reporting_peer_handles(self.message_hash) diff -uNr - - akris/akris/pest_command/broadcast_text_m.py akris-genesis/akris/pest_command/broadcast_text_m.py --- akris/akris/pest_command/broadcast_text_m.py false +++ akris-genesis/akris/pest_command/broadcast_text_m.py 76647aee107fb49a5654683571b61c94172b3401d02c7e0281b51f8deb0f17c5cc4232b8d28e3ffde6b8c494fe1c75fc790b9165040c47832a1345e59f1f6294 @@ -0,0 +1,32 @@ +import base64 + +from .multipart_message import MultipartMessage +from .broadcast_text import BroadcastText +from .constants import BROADCAST_TEXT_M + + +class BroadcastTextM(MultipartMessage, BroadcastText): + def __init__(self, command): + super().__init__(command) + self.command = BROADCAST_TEXT_M + + def inflate(self, command): + super().inflate(command) + self.check_order() + return self + + def stringify(self): + return { + "command": "broadcast_text_m", + "speaker": self.db.get_knob("handle"), + "body": self.body, + "timestamp": self.get_adjusted_timestamp(), + "net_chain": base64.b64encode(self.net_chain).decode(), + "self_chain": base64.b64encode(self.net_chain).decode(), + "n": self.n, + "of": self.of, + "message_hash": base64.b64encode(self.message_hash).decode(), + "text_hash": base64.b64encode(self.text_hash).decode(), + "immediate": self.immediate, + "reporting_peers": self.reporting_peer_handles(), + } diff -uNr - - akris/akris/pest_command/constants.py akris-genesis/akris/pest_command/constants.py --- akris/akris/pest_command/constants.py false +++ akris-genesis/akris/pest_command/constants.py 867c40cf6383dc5445929c6601970224d478ee4bbb64b96db7fac48b6f25a6da1e8f7c098c7a1be61467016b3e9d9180603feed36a75d1dee556c8928a2eeb46 @@ -0,0 +1,22 @@ +BROADCAST_TEXT = 0x00 +DIRECT_TEXT = 0x01 +PROD = 0x02 +GET_DATA = 0x03 +KEY_OFFER = 0x04 +KEY_SLICE = 0x05 +BROADCAST_TEXT_M = 0x06 +DIRECT_TEXT_M = 0x07 +IGNORE = 0xFF +ADDRESS_CAST = 0xFE + +COMMAND_LABELS = { + BROADCAST_TEXT: "BROADCAST_TEXT", + BROADCAST_TEXT_M: "BROADCAST_TEXT_M", + DIRECT_TEXT: "DIRECT_TEXT", + DIRECT_TEXT_M: "DIRECT_TEXT_M", + GET_DATA: "GETDATA", + KEY_OFFER: "KEY_OFFER", + KEY_SLICE: "KEY_SLICE", + PROD: "PROD", + IGNORE: "IGNORE", +} diff -uNr - - akris/akris/pest_command/direct_text.py akris-genesis/akris/pest_command/direct_text.py --- akris/akris/pest_command/direct_text.py false +++ akris-genesis/akris/pest_command/direct_text.py 0f87e60920344190facefc287a673a3dc2ddcf2aa3b93f8614601a376a2b7838d3ce89a7fc6baf1603ab1ea96dab19f3c807edd8b856a0c620b77963beef9946 @@ -0,0 +1,153 @@ +import base64 +import hashlib +import struct + +import time +import binascii + +from ..database import Database +from ..pest_command.constants import DIRECT_TEXT +from ..pest_command.message import ( + Message, + MAX_SPEAKER_SIZE, + EMPTY_CHAIN, + MESSAGE_PACKET_FORMAT, +) +from ..pest_command.text_message import TextMessage +from ..pest_command.message_exception import MessageException +from ..pest_command.message_exception import OUT_OF_ORDER_SELF +from ..singleton_registry import SingletonRegistry +from ..log_config import LogConfig + +logger = LogConfig.get_instance().get_logger("akris.pest_command.direct_text") + + +class DirectText(TextMessage): + def __init__(self, message): + super().__init__(message) + self.db = Database.get_instance() + self.speaker = message.get("speaker") + self.command = DIRECT_TEXT + self.bounces = 0 + + def stringify(self): + return { + "command": "direct_text", + "handle": self.peer.handle(), + "body": self.body, + "message_hash": base64.b64encode(self.message_hash).decode("utf-8"), + "net_chain": base64.b64encode(self.net_chain).decode("utf-8"), + "self_chain": base64.b64encode(self.self_chain).decode("utf-8"), + "speaker": self.speaker, + "timestamp": self.get_adjusted_timestamp(), + } + + def inflate(self, message): + self.message_bytes = message.get("bytes") + self.message_hash = Message.gen_hash(self.message_bytes) + + (int_ts, self_chain, net_chain, speaker, body) = self._unpack_generic_message( + self.message_bytes, unpad_body=True + ) + + self.handle = self.db.get_knob('handle') + self.peer = message.get("peer") + self.body = body + self.timestamp = int_ts + self.speaker = speaker + self.bounces = message.get("bounces") + self.self_chain = self_chain + self.net_chain = net_chain + self.metadata = message.get("metadata") + + self.check_if_stale() + self.check_if_duplicate() + self.check_order() + return self + + def send(self): + if not self.speaker: + logger.error("aborting message send due speaker not being set") + return + + self.timestamp = int(time.time()) + target_peer = self.db.get_peer_by_handle(self.handle) + if target_peer and not target_peer.get_key(): + logger.debug("No key for peer associated with %s" % self.handle) + return + + if target_peer == None: + logger.debug("Aborting message: unknown handle: %s" % self.handle) + return + + self.message_bytes = self.get_message_bytes(target_peer) + self.message_hash = hashlib.sha256(self.message_bytes).digest() + + logger.debug("generated message_hash: %s" % binascii.hexlify(self.message_hash)) + + self.peer = target_peer + self.filter.intern(self) + + signed_packet_bytes = self.pack( + target_peer, self.command, self.bounces, self.message_bytes + ) + self.db.update_handle_self_chain(target_peer.handles[0], self.message_hash) + self.pest_service.enqueue_outbound_packet_to_address( + { + "black_packet": signed_packet_bytes, + "address": ( + target_peer.address, + target_peer.port, + ), + } + ) + self.log_outgoing(target_peer) + + def get_message_bytes(self, peer=None): + speaker = Message._pad(self.speaker, MAX_SPEAKER_SIZE) + + # let's generate the self_chain value from the last message or set it to zero if + # this is the first message + + self.self_chain = self.db.get_handle_self_chain(peer.handles[0]) + self.net_chain = self.db.get_handle_net_chain(peer.handles[0]) + + body = self.body.encode("utf-8", errors="replace") + + message_bytes = struct.pack( + MESSAGE_PACKET_FORMAT, + self.timestamp, + self.self_chain, + self.net_chain, + speaker, + body, + ) + return message_bytes + + def retry(self, requesting_peer): + if requesting_peer == None: + logger.debug( + "Aborting message: unknown peer: %s" % requesting_peer.handles[0] + ) + return + + if not requesting_peer.get_key(): + logger.debug( + "No key for peer associated with %s" % requesting_peer.handles[0] + ) + return + + # TODO: Figure out how to verify that the requester was the original intended recipient + signed_packet_bytes = self.pack( + requesting_peer, self.command, self.bounces, self.message_bytes + ) + self.pest_service.enqueue_outbound_packet_to_address( + { + "black_packet": signed_packet_bytes, + "address": ( + requesting_peer.address, + requesting_peer.port, + ), + } + ) + self.log_outgoing(requesting_peer) diff -uNr - - akris/akris/pest_command/direct_text_m.py akris-genesis/akris/pest_command/direct_text_m.py --- akris/akris/pest_command/direct_text_m.py false +++ akris-genesis/akris/pest_command/direct_text_m.py e307db29f0ceddc9228aa44a70e1bfa004bb7609577f747d581574124b9aab31e559651779cfc28c9dfc8fd6fed87ead8a3e1e7e7bce73dd883c74ba96de639c @@ -0,0 +1,34 @@ +import base64 + +from .constants import DIRECT_TEXT_M +from .multipart_message import MultipartMessage +from .direct_text import DirectText +from ..log_config import LogConfig + +logger = LogConfig.get_instance().get_logger("akris.pest_command.direct_text_m") + + +class DirectTextM(MultipartMessage, DirectText): + def __init__(self, command): + super().__init__(command) + self.command = DIRECT_TEXT_M + + def stringify(self): + return { + "command": "direct_text_m", + "speaker": self.db.get_knob("handle"), + "handle": self.peer.handle(), + "body": self.body, + "timestamp": self.get_adjusted_timestamp(), + "net_chain": base64.b64encode(self.net_chain).decode(), + "self_chain": base64.b64encode(self.net_chain).decode(), + "n": self.n, + "of": self.of, + "message_hash": base64.b64encode(self.message_hash).decode(), + "text_hash": base64.b64encode(self.text_hash).decode(), + } + + def inflate(self, command): + super().inflate(command) + self.check_order() + return self diff -uNr - - akris/akris/pest_command/get_data.py akris-genesis/akris/pest_command/get_data.py --- akris/akris/pest_command/get_data.py false +++ akris-genesis/akris/pest_command/get_data.py f650d5856983eb10f69693c5e0d7ef4b7a8b63c7e14a2086128c1cf064c5d4c5df538c7333bfd2a282f2986c64a941b019ec66890d1f4bc4e72624c19058d8be @@ -0,0 +1,81 @@ +import struct +import time +import binascii +import hashlib +import logging +from .message import Message +from .message import OUTGOING_MESSAGE_LOGGING_FORMAT +from .constants import GET_DATA +from .constants import COMMAND_LABELS +from ..singleton_registry import SingletonRegistry + +GETDATA_MESSAGE_PACKET_FORMAT = "", + self.bounces, + binascii.hexlify(self.message_hash), + ) + ) diff -uNr - - akris/akris/pest_command/key_offer.py akris-genesis/akris/pest_command/key_offer.py --- akris/akris/pest_command/key_offer.py false +++ akris-genesis/akris/pest_command/key_offer.py 48ae826965a214e03afc311a37957fdc860f0c736da179816cc465d799dba15ace012800a7db9ea9ab87ad8ea806606a9da325dfe663ef8c9c43b60f675a3d6a @@ -0,0 +1,101 @@ +import os +import struct +import time + +from .constants import KEY_OFFER +from .message import Message, MAX_SPEAKER_SIZE, MAX_MESSAGE_LENGTH +from ..singleton_registry import SingletonRegistry +from ..log_config import LogConfig + +logger = LogConfig.get_instance().get_logger("akris.pest_command.key_offer") + +LOGGING_FORMAT = "[%s:%d %s] %s %s" +INCOMING = "->" +OUTGOING = "<-" +KEY_OFFER_PACKET_FORMAT = " ignoring packet: %s" % (address, port, packet_sample)) diff -uNr - - akris/akris/pest_command_executors/key_offer.py akris-genesis/akris/pest_command_executors/key_offer.py --- akris/akris/pest_command_executors/key_offer.py false +++ akris-genesis/akris/pest_command_executors/key_offer.py b3199a8a1901d3246540e324db19f336ef2dc2fb278c01bcff872a53cfd652f0073a390844b6e19ca381ca3b7eb3ea398b3d0609f0bbc713c6bb9478390dbc34 @@ -0,0 +1,31 @@ +from hashlib import sha512 + +from ..singleton_registry import SingletonRegistry +from ..pest_command.key_slice import KeySlice +from ..pest_command.key_offer import KeyOffer as KeyOfferCommand + + +class KeyOffer: + def __init__(self): + self.db = SingletonRegistry.get_instance().get("Database").get_instance() + + def execute(self, key_offer): + peer_id = key_offer.peer.peer_id + # check for an existing key offer to this peer + if self.db.get_key_slice(peer_id): + # generate key slice + key_slice = KeySlice({"peer": key_offer.peer}) + + # ensure the hash of the key slice is not equal to the offer + if sha512(key_slice.get_slice()) != key_offer.offer: + # send our key slice + self.db.set_sent_peer_key_slice(peer_id) + key_slice.send() + + # if there is none respond with a KeyOffer of our own + else: + # record peer's offer and send our own + KeyOfferCommand({"peer": key_offer.peer}).send() + + # we need to set the key offer from this peer whether we originated the first offer or not + self.db.set_key_offer(peer_id, key_offer.offer) diff -uNr - - akris/akris/pest_command_executors/key_slice.py akris-genesis/akris/pest_command_executors/key_slice.py --- akris/akris/pest_command_executors/key_slice.py false +++ akris-genesis/akris/pest_command_executors/key_slice.py 9286fa3851ae7963d82c65888273311f88f079034b334f2859e68d06ea98e38d0b59017b609fec3671deaa39b3dab111f7f5966f5e6be9f451c4170e3d9f0fd8 @@ -0,0 +1,56 @@ +import base64 +import sys +from hashlib import sha512 + +from ..singleton_registry import SingletonRegistry +from ..log_config import LogConfig +from ..pest_command.key_slice import KeySlice as KeySliceCommand + +logger = LogConfig.get_instance().get_logger("akris.pest_command_executors.key_slice") + + +def xor_byte_strings(byte_strings): + # Start with a 512-bit integer of all zeros + xor_result = 0 + + # Perform XOR operation on each byte string + for byte_string in byte_strings: + # Convert byte string to 512-bit integer + i = int.from_bytes(byte_string, "big") + # Perform XOR operation + xor_result ^= i + + # Convert result to 512-bit byte string + xor_result_bytes = xor_result.to_bytes(64, "big") + + return xor_result_bytes + + +class KeySlice: + def __init__(self): + self.db = SingletonRegistry.get_instance().get("Database").get_instance() + + def execute(self, key_slice): + peer_id = key_slice.peer.peer_id + # check hash of peer's key slice against peer key offer + peer_key_offer = self.db.get_peer_key_offer(peer_id) + + if peer_key_offer == sha512(key_slice.slice).digest(): + # send our key slice if we haven't already + if not self.db.sent_peer_key_slice(peer_id): + self.db.set_sent_peer_key_slice(peer_id) + KeySliceCommand({"peer": key_slice.peer}).send() + + # xor peer key, peer key slice, and our key slice and save as new peer key + peer_key = base64.b64decode(self.db.get_key(peer_id)) + our_slice = self.db.get_key_slice(peer_id) + peer_slice = key_slice.slice + + new_peer_key = xor_byte_strings([peer_key, our_slice, peer_slice]) + self.db.add_key_by_peer_id( + peer_id, base64.b64encode(new_peer_key).decode("utf-8") + ) + else: + logger.error("KeySlice hash mismatch, ignoring") + + self.db.clear_key_offer_and_slice(peer_id) diff -uNr - - akris/akris/pest_command_executors/pest_command_executor.py akris-genesis/akris/pest_command_executors/pest_command_executor.py --- akris/akris/pest_command_executors/pest_command_executor.py false +++ akris-genesis/akris/pest_command_executors/pest_command_executor.py 1dbc5f1f394e2d9c46a207d9ca65f455851e24a870be518befb7d8eeefa26ebacb840e11d783b0e3e43a359789cdbd80e589e16e19e6a0ecb1bed34632b08937 @@ -0,0 +1,11 @@ +class PestCommandExecutor: + def __init__(self): + pass + + # we only update the address table if the speaker is same as peer + def conditionally_update_at(self, command, address): + address = command.metadata["address"] + if command.speaker in command.peer.handles: + self.db.update_at( + {"handle": command.speaker, "address": address[0], "port": address[1]} + ) diff -uNr - - akris/akris/pest_command_executors/prod.py akris-genesis/akris/pest_command_executors/prod.py --- akris/akris/pest_command_executors/prod.py false +++ akris-genesis/akris/pest_command_executors/prod.py 2c094e4f0084b271dfc8e584a058db6e168d894ddd178a92d6c7492cd6de9912e44d9b82f82530b1745c3a9a635ff292587393d1ecac6a51e936d60cfce6d5c0 @@ -0,0 +1,49 @@ +from ..singleton_registry import SingletonRegistry +from .pest_command_executor import PestCommandExecutor +from ..pest_command.get_data import GetData +from ..pest_command.prod import Prod as ProdCommand, PROD_REPLY, PROD_PROMPT + + +class Prod(PestCommandExecutor): + def __init__(self): + super().__init__() + self.db = SingletonRegistry.get_instance().get("Database").get_instance() + self.filter = SingletonRegistry.get_instance().get("Filter").get_instance() + self.asked_for = SingletonRegistry.get_instance().get("AskedFor").get_instance() + + def execute(self, prod): + self.conditionally_update_at(prod, prod.metadata.get("address")) + + # we need to "refresh" the peer in case the peer for this + # prod doesn't have an address set yet + prod.peer = self.db.get_peer_by_handle(prod.peer.handles[0]) + prod.log_incoming(prod.peer) + + # reply to prod if necessary + if prod.flag == PROD_PROMPT: + ProdCommand( + { + "speaker": self.db.get_knob("handle"), + "flag": PROD_REPLY, + "prompt": prod, + } + ).reply() + + # if our external address has changed, broadcast an address cast + last_external_address = self.db.get_last_external_address() + if last_external_address is not None: + if last_external_address != prod.pest_address: + self.db.set_knob("prod.send_address_cast", 1) + + # update last_external_address for future Address Cast messages + self.db.set_last_external_address(prod.pest_address) + + # request missing chain tips + for chain in ["broadcast_self_chain", "handle_self_chain", "net_chain"]: + want_hash = getattr(prod, chain) + if not self.filter.has(want_hash): + if not self.asked_for.expects(want_hash): + self.asked_for.add(want_hash) + GetData( + {"speaker": self.db.get_knob("handle"), "body": want_hash} + ).send() diff -uNr - - akris/akris/pest_dispatch.py akris-genesis/akris/pest_dispatch.py --- akris/akris/pest_dispatch.py false +++ akris-genesis/akris/pest_dispatch.py c29cd2f454c2682f54503913a551a7ba8163e9056ea900ccf282345a8e1b3a540345b14521c29f6e966ad56987df57e25cf1964375fd10732473ad0f2c689a2e @@ -0,0 +1,49 @@ +from .pest_command_executors.address_cast import AddressCast +from .pest_command_executors.broadcast_text import BroadcastText +from .pest_command_executors.broadcast_text_m import BroadcastTextM +from .pest_command_executors.direct_text import DirectText +from .pest_command_executors.direct_text_m import DirectTextM +from .pest_command_executors.get_data import GetData +from .pest_command_executors.key_offer import KeyOffer +from .pest_command_executors.key_slice import KeySlice +from .pest_command_executors.prod import Prod +from .pest_command_executors.ignore import Ignore +from .pest_command.constants import ( + ADDRESS_CAST, + BROADCAST_TEXT, + BROADCAST_TEXT_M, + DIRECT_TEXT, + DIRECT_TEXT_M, + GET_DATA, + IGNORE, + KEY_OFFER, + KEY_SLICE, + PROD, +) +from .singleton import Singleton +from .log_config import LogConfig + +logger = LogConfig.get_instance().get_logger("akris.pest_dispatch") + + +class PestDispatch(Singleton): + def __init__(self): + self.executors = { + ADDRESS_CAST: AddressCast(), + BROADCAST_TEXT: BroadcastText(), + BROADCAST_TEXT_M: BroadcastTextM(), + DIRECT_TEXT: DirectText(), + DIRECT_TEXT_M: DirectTextM(), + GET_DATA: GetData(), + IGNORE: Ignore(), + KEY_OFFER: KeyOffer(), + KEY_SLICE: KeySlice(), + PROD: Prod(), + } + + def execute(self, message): + try: + # Nothing is done with the return value of pest command executors + return self.executors[message.command].execute(message) + except KeyError: + logger.exception("error executing command") diff -uNr - - akris/akris/pest_service.py akris-genesis/akris/pest_service.py --- akris/akris/pest_service.py false +++ akris-genesis/akris/pest_service.py 46adc33699c8d91696c6a56bc60d1ead11d9f00336cb28efac4ea39a544d9aaee44c92528dc72e2e9a6f164f08a8ca4b6479ff53d9fd3e5d9b50647eae3e16a0 @@ -0,0 +1,162 @@ +import binascii +import queue +import socket +import time +from concurrent.futures import ThreadPoolExecutor +from .database import Database +from .exception_dispatch import ExceptionDispatch +from .message_factory import * +from .pest_command.message_exception import * +from .pest_dispatch import PestDispatch +from .singleton_registry import SingletonRegistry +from .singleton import Singleton +from .log_config import LogConfig + +logger = LogConfig.get_instance().get_logger("akris.pest_service") +MAX_WORKERS = 10 +HOST = "127.0.0.1" +PORT = 8081 + + +class PestService(Singleton): + def __init__(self, host, port): + self.__dict__.update({k: v for k, v in locals().items() if k != "self"}) + self.stopped = None + self.udp_executor = None + self.udp_socket = None + self.socket_bound = None + self.db = Database.get_instance() + self.inbound_queue = queue.Queue() + self.outbound_queue = queue.Queue() + scheduler = SingletonRegistry.get_instance().get("Scheduler").get_instance() + scheduler.register_task( + self.process_inbound_queue, "pest_service.process_inbound_queue" + ) + scheduler.register_task( + self.process_outbound_queue, "pest_service.process_outbound_queue" + ) + + def handle_udp_request(self, data, address): + self.inbound_queue.put((data, address)) + + def inflate_message(self, peer, data, metadata): + try: + return MessageFactory().inflate( + peer, + data, + metadata, + ) + except MessageException as me: + return me + + def udp_server(self): + with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s: + self.udp_socket = s + s.bind((self.host, self.port)) + self.socket_bound = True + logger.info(f"UDP Server started on {self.host}:{self.port}") + + with ThreadPoolExecutor( + max_workers=MAX_WORKERS, thread_name_prefix="handle_udp_request" + ) as executor: + while True: + try: + data, addr = s.recvfrom(1024) + if self.stopped: + break + future = executor.submit(self.handle_udp_request, data, addr) + future.add_done_callback(self.handle_udp_request_done) + except OSError: + logger.exception("error shutting down udp socket") + if self.stopped: + break + time.sleep(1) + + def enqueue_outbound_packet_to_address(self, packet_and_address_dict): + self.outbound_queue.put(packet_and_address_dict) + + def process_inbound_queue(self): + while not self.inbound_queue.empty(): + data, address = self.inbound_queue.get() + try: + packet_info = (address[0], address[1], binascii.hexlify(data)[0:16]) + + metadata = { + "address": address, + "packet_info": packet_info, + } + + # if we don't have any peers let's just stop here + keyed_peers = self.db.get_keyed_peers() + if len(keyed_peers) == 0: + return + + for peer in keyed_peers: + message = self.inflate_message(peer, data, metadata) + if message.error_code is INVALID_SIGNATURE: + continue + + if message.error_code in [ + None, + UNSUPPORTED_VERSION, + UNSUPPORTED_COMMAND, + STALE_PACKET, + OUT_OF_ORDER_BOTH, + OUT_OF_ORDER_SELF, + OUT_OF_ORDER_NET, + DUPLICATE_PACKET, + MALFORMED_PACKET, + INVALID_HANDLE_ENCODING, + ]: + break + + if message.error_code is None: + PestDispatch().execute(message) + else: + # message is actually a MessageException here, which includes the original + # message + error code and metadata + ExceptionDispatch().handle(message) + except Exception as e: + logger.exception("error handling udp request") + + def process_outbound_queue(self): + while not self.outbound_queue.empty(): + packet_and_address_dict = self.outbound_queue.get() + try: + self.udp_socket.sendto( + packet_and_address_dict["black_packet"], + packet_and_address_dict["address"], + ) + except OSError: + logger.exception("Network error while attempting to send UDP packet") + time.sleep(0.5) + + def ready(self): + return self.socket_bound is not None + + def start(self): + self.udp_executor = ThreadPoolExecutor(max_workers=1, thread_name_prefix="udp") + future = self.udp_executor.submit(self.udp_server) + future.add_done_callback(self.handle_udp_server_done) + + def stop(self): + self.stopped = True + self.send_final_udp_packet() + self.udp_executor.shutdown(wait=False) + + def send_final_udp_packet(self): + # Send final UDP packet to stop UDP server + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Internet + sock.sendto(b"STOP", (self.host, self.port)) + + def handle_udp_request_done(self, future): + logger.debug("handle_udp_request exited") + ex = future.exception() + if ex is not None: + logger.exception(f"*********** error handling udp request: {ex}") + + def handle_udp_server_done(self, future): + logger.info("udp_server exited") + ex = future.exception() + if ex is not None: + logger.exception(f"*********** error in udp_server: {ex}") diff -uNr - - akris/akris/presence.py akris-genesis/akris/presence.py --- akris/akris/presence.py false +++ akris-genesis/akris/presence.py 0554e853faa0de64150175a6c6e836984cda860456ebb0614ed2e1577c61f54617439ed880fc0b96b6deb742cb41c94b128cca604bdf1e23d49ec13bb674be3c @@ -0,0 +1,45 @@ +from .api_service import ApiService +from .database import Database + + +STATUS_OFFLINE = 0 +STATUS_ONLINE = 1 +STATUS_UNPEERED = 2 + +status_map = { + STATUS_ONLINE: "online", + STATUS_OFFLINE: "offline", + STATUS_UNPEERED: "unpeered" +} + +class Presence: + def __init__(self): + self.db = Database.get_instance() + self.api_service = ApiService.get_instance() + self.presence = {} + + def send_presence(self, handle, status): + self.api_service.enqueue_outbound({ + "command": "presence", + "type": status_map[status], + "handle": handle, + }) + + def report_presence(self): + # check for removed peers + if len(self.presence) > len(self.db.get_peer_handles()): + presence_copy = self.presence.copy() + for handle in presence_copy: + if handle not in self.db.get_peer_handles(): + self.presence.pop(handle) + self.send_presence(handle, STATUS_UNPEERED) + # if handle isn't in the presence dict, check if rubbish received and send online if so + for handle in self.db.get_peer_handles(): + status = STATUS_ONLINE if self.db.handle_is_online(handle) else STATUS_OFFLINE + if self.presence.get(handle) is None: + self.presence[handle] = status + self.send_presence(handle, status) + else: + if self.presence[handle] != status: + self.presence[handle] = status + self.send_presence(handle, status) diff -uNr - - akris/akris/scheduler.py akris-genesis/akris/scheduler.py --- akris/akris/scheduler.py false +++ akris-genesis/akris/scheduler.py 4fa82e82fcec6cf3e1ec630de37478a73bc9eec64b9943afd13bc0a01a3d8541e8f958b47ffa20b36072f5cfd8f63c0373d79a19376badbdfe4a497e2c0cf385 @@ -0,0 +1,51 @@ +import time +import logging +from concurrent.futures import ThreadPoolExecutor + +from .singleton_registry import SingletonRegistry +from .singleton import Singleton + +logger = logging.getLogger("akris.scheduler") + + +class Scheduler(Singleton): + def __init__(self): + self.schedule_executor = None + self.stopped = False + self.tasks = [] + self.db = SingletonRegistry.get_instance().get("Database").get_instance() + + # accepts a task in the form of a function pointer + def register_task(self, task, interval_knob): + self.tasks.append({"task": task, "interval_knob": interval_knob, "last_run": 0}) + + def run(self): + while not self.stopped: + for task in self.tasks: + # get the interval from the database + interval = self.db.get_knob(task["interval_knob"]) + # don't run tasks with an interval of 0 + if interval is None: + continue + + if task["last_run"] + interval < time.time(): + task["task"]() + task["last_run"] = time.time() + time.sleep(0.5) + + def start(self): + self.schedule_executor = ThreadPoolExecutor( + max_workers=1, thread_name_prefix="scheduler" + ) + future = self.schedule_executor.submit(self.run) + future.add_done_callback(self.handle_scheduler_done) + + def stop(self): + self.stopped = True + self.schedule_executor.shutdown(wait=False) + + def handle_scheduler_done(self, future): + logger.info("run stopped") + ex = future.exception() + if ex is not None: + logger.exception(f"exception in scheduler: {ex}") diff -uNr - - akris/akris/serpent.py akris-genesis/akris/serpent.py --- akris/akris/serpent.py false +++ akris-genesis/akris/serpent.py fa5c61c53fec6452ce0af472a291a1db71d2da0b6794a5839bf176bbb8ea6f82d752ca3aba88dbbefa11d81554b95aa2e6bc9bd81a4f41ec7d37ae8ac69f03ba @@ -0,0 +1,3015 @@ +## serpent.py - pure Python implementation of the Serpent algorithm. +## Bjorn Edstrom 13 december 2007. +## +## Copyrights +## ========== +## +## This code is a derived from an implementation by Dr Brian Gladman +## (gladman@seven77.demon.co.uk) which is subject to the following license. +## This Python implementation is not subject to any other license. +## +##/* This is an independent implementation of the encryption algorithm: +## * +## * Serpent by Ross Anderson, Eli Biham and Lars Knudsen +## * +## * which is a candidate algorithm in the Advanced Encryption Standard +## * programme of the US National Institute of Standards and Technology +## * +## * Copyright in this implementation is held by Dr B R Gladman but I +## * hereby give permission for its free direct or derivative use subject +## * to acknowledgment of its origin and compliance with any conditions +## * that the originators of the algorithm place on its exploitation. +## * +## * Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 +## */ +## +## The above copyright notice must not be removed. +## +## Information +## =========== +## +## Anyone thinking of using this code should reconsider. It's slow. +## Try python-mcrypt instead. In case a faster library is not installed +## on the target system, this code can be used as a portable fallback. + +import binascii +import base64 + +block_size = 16 +key_size = 32 + + +class Serpent: + def __init__(self, key=None): + """Serpent.""" + + if key: + self.set_key(key) + + def set_key(self, key): + """Init.""" + + key_len = len(key) + if key_len % 4: + # XXX: add padding? + raise KeyError("key not a multiple of 4") + if key_len > 32: + # XXX: prune? + raise KeyError("key_len > 32") + + self.key_context = [0] * 140 + + key_word32 = [0] * 32 + i = 0 + while key: + key_word32[i] = struct.unpack("> n) | ((x << (32 - n)) & 0xFFFFFFFF) + + +def rotl32(x, n): + return ((x << n) & 0xFFFFFFFF) | (x >> (32 - n)) + + +def byteswap32(x): + return ( + ((x & 0xFF) << 24) + | (((x >> 8) & 0xFF) << 16) + | (((x >> 16) & 0xFF) << 8) + | ((x >> 24) & 0xFF) + ) + + +def set_key(l_key, key, key_len): + key_len *= 8 + if key_len > 256: + return False + + i = 0 + lk = (key_len + 31) / 32 + while i < lk: + l_key[i] = key[i] + if WORD_BIGENDIAN: + l_key[i] = byteswap32(key[i]) + i += 1 + + if key_len < 256: + while i < 8: + l_key[i] = 0 + i += 1 + i = key_len / 32 + lk = 1 << (key_len % 32) + l_key[i] = (l_key[i] & (lk - 1)) | lk + for i in range(132): + lk = l_key[i] ^ l_key[i + 3] ^ l_key[i + 5] ^ l_key[i + 7] ^ 0x9E3779B9 ^ i + l_key[i + 8] = ((lk << 11) & 0xFFFFFFFF) | (lk >> 21) + + key = l_key + # serpent_generate.py + a = key[4 * 0 + 8] + b = key[4 * 0 + 9] + c = key[4 * 0 + 10] + d = key[4 * 0 + 11] + e = 0 + f = 0 + g = 0 + h = 0 + t1 = 0 + t2 = 0 + t3 = 0 + t4 = 0 + t5 = 0 + t6 = 0 + t7 = 0 + t8 = 0 + t9 = 0 + t10 = 0 + t11 = 0 + t12 = 0 + t13 = 0 + t14 = 0 + t15 = 0 + t16 = 0 + t1 = a ^ c + t2 = d ^ t1 + t3 = a & t2 + t4 = d ^ t3 + t5 = b & t4 + g = t2 ^ t5 + t7 = a | g + t8 = b | d + t11 = a | d + t9 = t4 & t7 + f = t8 ^ t9 + t12 = b ^ t11 + t13 = g ^ t9 + t15 = t3 ^ t8 + h = t12 ^ t13 + t16 = c & t15 + e = t12 ^ t16 + key[4 * 0 + 8] = e + key[4 * 0 + 9] = f + key[4 * 0 + 10] = g + key[4 * 0 + 11] = h + a = key[4 * 1 + 8] + b = key[4 * 1 + 9] + c = key[4 * 1 + 10] + d = key[4 * 1 + 11] + t1 = (~a) % 0x100000000 + t2 = b ^ d + t3 = c & t1 + t13 = d | t1 + e = t2 ^ t3 + t5 = c ^ t1 + t6 = c ^ e + t7 = b & t6 + t10 = e | t5 + h = t5 ^ t7 + t9 = d | t7 + t11 = t9 & t10 + t14 = t2 ^ h + g = a ^ t11 + t15 = g ^ t13 + f = t14 ^ t15 + key[4 * 1 + 8] = e + key[4 * 1 + 9] = f + key[4 * 1 + 10] = g + key[4 * 1 + 11] = h + a = key[4 * 2 + 8] + b = key[4 * 2 + 9] + c = key[4 * 2 + 10] + d = key[4 * 2 + 11] + t1 = (~a) % 0x100000000 + t2 = b ^ t1 + t3 = a | t2 + t4 = d | t2 + t5 = c ^ t3 + g = d ^ t5 + t7 = b ^ t4 + t8 = t2 ^ g + t9 = t5 & t7 + h = t8 ^ t9 + t11 = t5 ^ t7 + f = h ^ t11 + t13 = t8 & t11 + e = t5 ^ t13 + key[4 * 2 + 8] = e + key[4 * 2 + 9] = f + key[4 * 2 + 10] = g + key[4 * 2 + 11] = h + a = key[4 * 3 + 8] + b = key[4 * 3 + 9] + c = key[4 * 3 + 10] + d = key[4 * 3 + 11] + t1 = a ^ d + t2 = a & d + t3 = c ^ t1 + t6 = b & t1 + t4 = b ^ t3 + t10 = (~t3) % 0x100000000 + h = t2 ^ t4 + t7 = a ^ t6 + t14 = (~t7) % 0x100000000 + t8 = c | t7 + t11 = t3 ^ t7 + g = t4 ^ t8 + t12 = h & t11 + f = t10 ^ t12 + e = t12 ^ t14 + key[4 * 3 + 8] = e + key[4 * 3 + 9] = f + key[4 * 3 + 10] = g + key[4 * 3 + 11] = h + a = key[4 * 4 + 8] + b = key[4 * 4 + 9] + c = key[4 * 4 + 10] + d = key[4 * 4 + 11] + t1 = (~c) % 0x100000000 + t2 = b ^ c + t3 = b | t1 + t4 = d ^ t3 + t5 = a & t4 + t7 = a ^ d + h = t2 ^ t5 + t8 = b ^ t5 + t9 = t2 | t8 + t11 = d & t3 + f = t7 ^ t9 + t12 = t5 ^ f + t15 = t1 | t4 + t13 = h & t12 + g = t11 ^ t13 + t16 = t12 ^ g + e = t15 ^ t16 + key[4 * 4 + 8] = e + key[4 * 4 + 9] = f + key[4 * 4 + 10] = g + key[4 * 4 + 11] = h + a = key[4 * 5 + 8] + b = key[4 * 5 + 9] + c = key[4 * 5 + 10] + d = key[4 * 5 + 11] + t1 = (~a) % 0x100000000 + t2 = a ^ d + t3 = b ^ t2 + t4 = t1 | t2 + t5 = c ^ t4 + f = b ^ t5 + t13 = (~t5) % 0x100000000 + t7 = t2 | f + t8 = d ^ t7 + t9 = t5 & t8 + g = t3 ^ t9 + t11 = t5 ^ t8 + e = g ^ t11 + t14 = t3 & t11 + h = t13 ^ t14 + key[4 * 5 + 8] = e + key[4 * 5 + 9] = f + key[4 * 5 + 10] = g + key[4 * 5 + 11] = h + a = key[4 * 6 + 8] + b = key[4 * 6 + 9] + c = key[4 * 6 + 10] + d = key[4 * 6 + 11] + t1 = (~a) % 0x100000000 + t2 = a ^ b + t3 = a ^ d + t4 = c ^ t1 + t5 = t2 | t3 + e = t4 ^ t5 + t7 = d & e + t8 = t2 ^ e + t10 = t1 | e + f = t7 ^ t8 + t11 = t2 | t7 + t12 = t3 ^ t10 + t14 = b ^ t7 + g = t11 ^ t12 + t15 = f & t12 + h = t14 ^ t15 + key[4 * 6 + 8] = e + key[4 * 6 + 9] = f + key[4 * 6 + 10] = g + key[4 * 6 + 11] = h + a = key[4 * 7 + 8] + b = key[4 * 7 + 9] + c = key[4 * 7 + 10] + d = key[4 * 7 + 11] + t1 = a ^ d + t2 = d & t1 + t3 = c ^ t2 + t4 = b | t3 + h = t1 ^ t4 + t6 = (~b) % 0x100000000 + t7 = t1 | t6 + e = t3 ^ t7 + t9 = a & e + t10 = t1 ^ t6 + t11 = t4 & t10 + g = t9 ^ t11 + t13 = a ^ t3 + t14 = t10 & g + f = t13 ^ t14 + key[4 * 7 + 8] = e + key[4 * 7 + 9] = f + key[4 * 7 + 10] = g + key[4 * 7 + 11] = h + a = key[4 * 8 + 8] + b = key[4 * 8 + 9] + c = key[4 * 8 + 10] + d = key[4 * 8 + 11] + t1 = a ^ c + t2 = d ^ t1 + t3 = a & t2 + t4 = d ^ t3 + t5 = b & t4 + g = t2 ^ t5 + t7 = a | g + t8 = b | d + t11 = a | d + t9 = t4 & t7 + f = t8 ^ t9 + t12 = b ^ t11 + t13 = g ^ t9 + t15 = t3 ^ t8 + h = t12 ^ t13 + t16 = c & t15 + e = t12 ^ t16 + key[4 * 8 + 8] = e + key[4 * 8 + 9] = f + key[4 * 8 + 10] = g + key[4 * 8 + 11] = h + a = key[4 * 9 + 8] + b = key[4 * 9 + 9] + c = key[4 * 9 + 10] + d = key[4 * 9 + 11] + t1 = (~a) % 0x100000000 + t2 = b ^ d + t3 = c & t1 + t13 = d | t1 + e = t2 ^ t3 + t5 = c ^ t1 + t6 = c ^ e + t7 = b & t6 + t10 = e | t5 + h = t5 ^ t7 + t9 = d | t7 + t11 = t9 & t10 + t14 = t2 ^ h + g = a ^ t11 + t15 = g ^ t13 + f = t14 ^ t15 + key[4 * 9 + 8] = e + key[4 * 9 + 9] = f + key[4 * 9 + 10] = g + key[4 * 9 + 11] = h + a = key[4 * 10 + 8] + b = key[4 * 10 + 9] + c = key[4 * 10 + 10] + d = key[4 * 10 + 11] + t1 = (~a) % 0x100000000 + t2 = b ^ t1 + t3 = a | t2 + t4 = d | t2 + t5 = c ^ t3 + g = d ^ t5 + t7 = b ^ t4 + t8 = t2 ^ g + t9 = t5 & t7 + h = t8 ^ t9 + t11 = t5 ^ t7 + f = h ^ t11 + t13 = t8 & t11 + e = t5 ^ t13 + key[4 * 10 + 8] = e + key[4 * 10 + 9] = f + key[4 * 10 + 10] = g + key[4 * 10 + 11] = h + a = key[4 * 11 + 8] + b = key[4 * 11 + 9] + c = key[4 * 11 + 10] + d = key[4 * 11 + 11] + t1 = a ^ d + t2 = a & d + t3 = c ^ t1 + t6 = b & t1 + t4 = b ^ t3 + t10 = (~t3) % 0x100000000 + h = t2 ^ t4 + t7 = a ^ t6 + t14 = (~t7) % 0x100000000 + t8 = c | t7 + t11 = t3 ^ t7 + g = t4 ^ t8 + t12 = h & t11 + f = t10 ^ t12 + e = t12 ^ t14 + key[4 * 11 + 8] = e + key[4 * 11 + 9] = f + key[4 * 11 + 10] = g + key[4 * 11 + 11] = h + a = key[4 * 12 + 8] + b = key[4 * 12 + 9] + c = key[4 * 12 + 10] + d = key[4 * 12 + 11] + t1 = (~c) % 0x100000000 + t2 = b ^ c + t3 = b | t1 + t4 = d ^ t3 + t5 = a & t4 + t7 = a ^ d + h = t2 ^ t5 + t8 = b ^ t5 + t9 = t2 | t8 + t11 = d & t3 + f = t7 ^ t9 + t12 = t5 ^ f + t15 = t1 | t4 + t13 = h & t12 + g = t11 ^ t13 + t16 = t12 ^ g + e = t15 ^ t16 + key[4 * 12 + 8] = e + key[4 * 12 + 9] = f + key[4 * 12 + 10] = g + key[4 * 12 + 11] = h + a = key[4 * 13 + 8] + b = key[4 * 13 + 9] + c = key[4 * 13 + 10] + d = key[4 * 13 + 11] + t1 = (~a) % 0x100000000 + t2 = a ^ d + t3 = b ^ t2 + t4 = t1 | t2 + t5 = c ^ t4 + f = b ^ t5 + t13 = (~t5) % 0x100000000 + t7 = t2 | f + t8 = d ^ t7 + t9 = t5 & t8 + g = t3 ^ t9 + t11 = t5 ^ t8 + e = g ^ t11 + t14 = t3 & t11 + h = t13 ^ t14 + key[4 * 13 + 8] = e + key[4 * 13 + 9] = f + key[4 * 13 + 10] = g + key[4 * 13 + 11] = h + a = key[4 * 14 + 8] + b = key[4 * 14 + 9] + c = key[4 * 14 + 10] + d = key[4 * 14 + 11] + t1 = (~a) % 0x100000000 + t2 = a ^ b + t3 = a ^ d + t4 = c ^ t1 + t5 = t2 | t3 + e = t4 ^ t5 + t7 = d & e + t8 = t2 ^ e + t10 = t1 | e + f = t7 ^ t8 + t11 = t2 | t7 + t12 = t3 ^ t10 + t14 = b ^ t7 + g = t11 ^ t12 + t15 = f & t12 + h = t14 ^ t15 + key[4 * 14 + 8] = e + key[4 * 14 + 9] = f + key[4 * 14 + 10] = g + key[4 * 14 + 11] = h + a = key[4 * 15 + 8] + b = key[4 * 15 + 9] + c = key[4 * 15 + 10] + d = key[4 * 15 + 11] + t1 = a ^ d + t2 = d & t1 + t3 = c ^ t2 + t4 = b | t3 + h = t1 ^ t4 + t6 = (~b) % 0x100000000 + t7 = t1 | t6 + e = t3 ^ t7 + t9 = a & e + t10 = t1 ^ t6 + t11 = t4 & t10 + g = t9 ^ t11 + t13 = a ^ t3 + t14 = t10 & g + f = t13 ^ t14 + key[4 * 15 + 8] = e + key[4 * 15 + 9] = f + key[4 * 15 + 10] = g + key[4 * 15 + 11] = h + a = key[4 * 16 + 8] + b = key[4 * 16 + 9] + c = key[4 * 16 + 10] + d = key[4 * 16 + 11] + t1 = a ^ c + t2 = d ^ t1 + t3 = a & t2 + t4 = d ^ t3 + t5 = b & t4 + g = t2 ^ t5 + t7 = a | g + t8 = b | d + t11 = a | d + t9 = t4 & t7 + f = t8 ^ t9 + t12 = b ^ t11 + t13 = g ^ t9 + t15 = t3 ^ t8 + h = t12 ^ t13 + t16 = c & t15 + e = t12 ^ t16 + key[4 * 16 + 8] = e + key[4 * 16 + 9] = f + key[4 * 16 + 10] = g + key[4 * 16 + 11] = h + a = key[4 * 17 + 8] + b = key[4 * 17 + 9] + c = key[4 * 17 + 10] + d = key[4 * 17 + 11] + t1 = (~a) % 0x100000000 + t2 = b ^ d + t3 = c & t1 + t13 = d | t1 + e = t2 ^ t3 + t5 = c ^ t1 + t6 = c ^ e + t7 = b & t6 + t10 = e | t5 + h = t5 ^ t7 + t9 = d | t7 + t11 = t9 & t10 + t14 = t2 ^ h + g = a ^ t11 + t15 = g ^ t13 + f = t14 ^ t15 + key[4 * 17 + 8] = e + key[4 * 17 + 9] = f + key[4 * 17 + 10] = g + key[4 * 17 + 11] = h + a = key[4 * 18 + 8] + b = key[4 * 18 + 9] + c = key[4 * 18 + 10] + d = key[4 * 18 + 11] + t1 = (~a) % 0x100000000 + t2 = b ^ t1 + t3 = a | t2 + t4 = d | t2 + t5 = c ^ t3 + g = d ^ t5 + t7 = b ^ t4 + t8 = t2 ^ g + t9 = t5 & t7 + h = t8 ^ t9 + t11 = t5 ^ t7 + f = h ^ t11 + t13 = t8 & t11 + e = t5 ^ t13 + key[4 * 18 + 8] = e + key[4 * 18 + 9] = f + key[4 * 18 + 10] = g + key[4 * 18 + 11] = h + a = key[4 * 19 + 8] + b = key[4 * 19 + 9] + c = key[4 * 19 + 10] + d = key[4 * 19 + 11] + t1 = a ^ d + t2 = a & d + t3 = c ^ t1 + t6 = b & t1 + t4 = b ^ t3 + t10 = (~t3) % 0x100000000 + h = t2 ^ t4 + t7 = a ^ t6 + t14 = (~t7) % 0x100000000 + t8 = c | t7 + t11 = t3 ^ t7 + g = t4 ^ t8 + t12 = h & t11 + f = t10 ^ t12 + e = t12 ^ t14 + key[4 * 19 + 8] = e + key[4 * 19 + 9] = f + key[4 * 19 + 10] = g + key[4 * 19 + 11] = h + a = key[4 * 20 + 8] + b = key[4 * 20 + 9] + c = key[4 * 20 + 10] + d = key[4 * 20 + 11] + t1 = (~c) % 0x100000000 + t2 = b ^ c + t3 = b | t1 + t4 = d ^ t3 + t5 = a & t4 + t7 = a ^ d + h = t2 ^ t5 + t8 = b ^ t5 + t9 = t2 | t8 + t11 = d & t3 + f = t7 ^ t9 + t12 = t5 ^ f + t15 = t1 | t4 + t13 = h & t12 + g = t11 ^ t13 + t16 = t12 ^ g + e = t15 ^ t16 + key[4 * 20 + 8] = e + key[4 * 20 + 9] = f + key[4 * 20 + 10] = g + key[4 * 20 + 11] = h + a = key[4 * 21 + 8] + b = key[4 * 21 + 9] + c = key[4 * 21 + 10] + d = key[4 * 21 + 11] + t1 = (~a) % 0x100000000 + t2 = a ^ d + t3 = b ^ t2 + t4 = t1 | t2 + t5 = c ^ t4 + f = b ^ t5 + t13 = (~t5) % 0x100000000 + t7 = t2 | f + t8 = d ^ t7 + t9 = t5 & t8 + g = t3 ^ t9 + t11 = t5 ^ t8 + e = g ^ t11 + t14 = t3 & t11 + h = t13 ^ t14 + key[4 * 21 + 8] = e + key[4 * 21 + 9] = f + key[4 * 21 + 10] = g + key[4 * 21 + 11] = h + a = key[4 * 22 + 8] + b = key[4 * 22 + 9] + c = key[4 * 22 + 10] + d = key[4 * 22 + 11] + t1 = (~a) % 0x100000000 + t2 = a ^ b + t3 = a ^ d + t4 = c ^ t1 + t5 = t2 | t3 + e = t4 ^ t5 + t7 = d & e + t8 = t2 ^ e + t10 = t1 | e + f = t7 ^ t8 + t11 = t2 | t7 + t12 = t3 ^ t10 + t14 = b ^ t7 + g = t11 ^ t12 + t15 = f & t12 + h = t14 ^ t15 + key[4 * 22 + 8] = e + key[4 * 22 + 9] = f + key[4 * 22 + 10] = g + key[4 * 22 + 11] = h + a = key[4 * 23 + 8] + b = key[4 * 23 + 9] + c = key[4 * 23 + 10] + d = key[4 * 23 + 11] + t1 = a ^ d + t2 = d & t1 + t3 = c ^ t2 + t4 = b | t3 + h = t1 ^ t4 + t6 = (~b) % 0x100000000 + t7 = t1 | t6 + e = t3 ^ t7 + t9 = a & e + t10 = t1 ^ t6 + t11 = t4 & t10 + g = t9 ^ t11 + t13 = a ^ t3 + t14 = t10 & g + f = t13 ^ t14 + key[4 * 23 + 8] = e + key[4 * 23 + 9] = f + key[4 * 23 + 10] = g + key[4 * 23 + 11] = h + a = key[4 * 24 + 8] + b = key[4 * 24 + 9] + c = key[4 * 24 + 10] + d = key[4 * 24 + 11] + t1 = a ^ c + t2 = d ^ t1 + t3 = a & t2 + t4 = d ^ t3 + t5 = b & t4 + g = t2 ^ t5 + t7 = a | g + t8 = b | d + t11 = a | d + t9 = t4 & t7 + f = t8 ^ t9 + t12 = b ^ t11 + t13 = g ^ t9 + t15 = t3 ^ t8 + h = t12 ^ t13 + t16 = c & t15 + e = t12 ^ t16 + key[4 * 24 + 8] = e + key[4 * 24 + 9] = f + key[4 * 24 + 10] = g + key[4 * 24 + 11] = h + a = key[4 * 25 + 8] + b = key[4 * 25 + 9] + c = key[4 * 25 + 10] + d = key[4 * 25 + 11] + t1 = (~a) % 0x100000000 + t2 = b ^ d + t3 = c & t1 + t13 = d | t1 + e = t2 ^ t3 + t5 = c ^ t1 + t6 = c ^ e + t7 = b & t6 + t10 = e | t5 + h = t5 ^ t7 + t9 = d | t7 + t11 = t9 & t10 + t14 = t2 ^ h + g = a ^ t11 + t15 = g ^ t13 + f = t14 ^ t15 + key[4 * 25 + 8] = e + key[4 * 25 + 9] = f + key[4 * 25 + 10] = g + key[4 * 25 + 11] = h + a = key[4 * 26 + 8] + b = key[4 * 26 + 9] + c = key[4 * 26 + 10] + d = key[4 * 26 + 11] + t1 = (~a) % 0x100000000 + t2 = b ^ t1 + t3 = a | t2 + t4 = d | t2 + t5 = c ^ t3 + g = d ^ t5 + t7 = b ^ t4 + t8 = t2 ^ g + t9 = t5 & t7 + h = t8 ^ t9 + t11 = t5 ^ t7 + f = h ^ t11 + t13 = t8 & t11 + e = t5 ^ t13 + key[4 * 26 + 8] = e + key[4 * 26 + 9] = f + key[4 * 26 + 10] = g + key[4 * 26 + 11] = h + a = key[4 * 27 + 8] + b = key[4 * 27 + 9] + c = key[4 * 27 + 10] + d = key[4 * 27 + 11] + t1 = a ^ d + t2 = a & d + t3 = c ^ t1 + t6 = b & t1 + t4 = b ^ t3 + t10 = (~t3) % 0x100000000 + h = t2 ^ t4 + t7 = a ^ t6 + t14 = (~t7) % 0x100000000 + t8 = c | t7 + t11 = t3 ^ t7 + g = t4 ^ t8 + t12 = h & t11 + f = t10 ^ t12 + e = t12 ^ t14 + key[4 * 27 + 8] = e + key[4 * 27 + 9] = f + key[4 * 27 + 10] = g + key[4 * 27 + 11] = h + a = key[4 * 28 + 8] + b = key[4 * 28 + 9] + c = key[4 * 28 + 10] + d = key[4 * 28 + 11] + t1 = (~c) % 0x100000000 + t2 = b ^ c + t3 = b | t1 + t4 = d ^ t3 + t5 = a & t4 + t7 = a ^ d + h = t2 ^ t5 + t8 = b ^ t5 + t9 = t2 | t8 + t11 = d & t3 + f = t7 ^ t9 + t12 = t5 ^ f + t15 = t1 | t4 + t13 = h & t12 + g = t11 ^ t13 + t16 = t12 ^ g + e = t15 ^ t16 + key[4 * 28 + 8] = e + key[4 * 28 + 9] = f + key[4 * 28 + 10] = g + key[4 * 28 + 11] = h + a = key[4 * 29 + 8] + b = key[4 * 29 + 9] + c = key[4 * 29 + 10] + d = key[4 * 29 + 11] + t1 = (~a) % 0x100000000 + t2 = a ^ d + t3 = b ^ t2 + t4 = t1 | t2 + t5 = c ^ t4 + f = b ^ t5 + t13 = (~t5) % 0x100000000 + t7 = t2 | f + t8 = d ^ t7 + t9 = t5 & t8 + g = t3 ^ t9 + t11 = t5 ^ t8 + e = g ^ t11 + t14 = t3 & t11 + h = t13 ^ t14 + key[4 * 29 + 8] = e + key[4 * 29 + 9] = f + key[4 * 29 + 10] = g + key[4 * 29 + 11] = h + a = key[4 * 30 + 8] + b = key[4 * 30 + 9] + c = key[4 * 30 + 10] + d = key[4 * 30 + 11] + t1 = (~a) % 0x100000000 + t2 = a ^ b + t3 = a ^ d + t4 = c ^ t1 + t5 = t2 | t3 + e = t4 ^ t5 + t7 = d & e + t8 = t2 ^ e + t10 = t1 | e + f = t7 ^ t8 + t11 = t2 | t7 + t12 = t3 ^ t10 + t14 = b ^ t7 + g = t11 ^ t12 + t15 = f & t12 + h = t14 ^ t15 + key[4 * 30 + 8] = e + key[4 * 30 + 9] = f + key[4 * 30 + 10] = g + key[4 * 30 + 11] = h + a = key[4 * 31 + 8] + b = key[4 * 31 + 9] + c = key[4 * 31 + 10] + d = key[4 * 31 + 11] + t1 = a ^ d + t2 = d & t1 + t3 = c ^ t2 + t4 = b | t3 + h = t1 ^ t4 + t6 = (~b) % 0x100000000 + t7 = t1 | t6 + e = t3 ^ t7 + t9 = a & e + t10 = t1 ^ t6 + t11 = t4 & t10 + g = t9 ^ t11 + t13 = a ^ t3 + t14 = t10 & g + f = t13 ^ t14 + key[4 * 31 + 8] = e + key[4 * 31 + 9] = f + key[4 * 31 + 10] = g + key[4 * 31 + 11] = h + a = key[4 * 32 + 8] + b = key[4 * 32 + 9] + c = key[4 * 32 + 10] + d = key[4 * 32 + 11] + t1 = a ^ c + t2 = d ^ t1 + t3 = a & t2 + t4 = d ^ t3 + t5 = b & t4 + g = t2 ^ t5 + t7 = a | g + t8 = b | d + t11 = a | d + t9 = t4 & t7 + f = t8 ^ t9 + t12 = b ^ t11 + t13 = g ^ t9 + t15 = t3 ^ t8 + h = t12 ^ t13 + t16 = c & t15 + e = t12 ^ t16 + key[4 * 32 + 8] = e + key[4 * 32 + 9] = f + key[4 * 32 + 10] = g + key[4 * 32 + 11] = h + + +def encrypt(key, in_blk): + # serpent_generate.py + a = in_blk[0] + b = in_blk[1] + c = in_blk[2] + d = in_blk[3] + if WORD_BIGENDIAN: + a = byteswap32(a) + b = byteswap32(b) + c = byteswap32(c) + d = byteswap32(d) + e = 0 + f = 0 + g = 0 + h = 0 + t1 = 0 + t2 = 0 + t3 = 0 + t4 = 0 + t5 = 0 + t6 = 0 + t7 = 0 + t8 = 0 + t9 = 0 + t10 = 0 + t11 = 0 + t12 = 0 + t13 = 0 + t14 = 0 + t15 = 0 + t16 = 0 + a ^= key[4 * 0 + 8] + b ^= key[4 * 0 + 9] + c ^= key[4 * 0 + 10] + d ^= key[4 * 0 + 11] + t1 = a ^ d + t2 = a & d + t3 = c ^ t1 + t6 = b & t1 + t4 = b ^ t3 + t10 = (~t3) % 0x100000000 + h = t2 ^ t4 + t7 = a ^ t6 + t14 = (~t7) % 0x100000000 + t8 = c | t7 + t11 = t3 ^ t7 + g = t4 ^ t8 + t12 = h & t11 + f = t10 ^ t12 + e = t12 ^ t14 + e = rotl32(e, 13) + g = rotl32(g, 3) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + h = rotl32(h, 7) + f = rotl32(f, 1) + e ^= f ^ h + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e = rotl32(e, 5) + g = rotl32(g, 22) + e ^= key[4 * 1 + 8] + f ^= key[4 * 1 + 9] + g ^= key[4 * 1 + 10] + h ^= key[4 * 1 + 11] + t1 = (~e) % 0x100000000 + t2 = f ^ t1 + t3 = e | t2 + t4 = h | t2 + t5 = g ^ t3 + c = h ^ t5 + t7 = f ^ t4 + t8 = t2 ^ c + t9 = t5 & t7 + d = t8 ^ t9 + t11 = t5 ^ t7 + b = d ^ t11 + t13 = t8 & t11 + a = t5 ^ t13 + a = rotl32(a, 13) + c = rotl32(c, 3) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + d = rotl32(d, 7) + b = rotl32(b, 1) + a ^= b ^ d + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a = rotl32(a, 5) + c = rotl32(c, 22) + a ^= key[4 * 2 + 8] + b ^= key[4 * 2 + 9] + c ^= key[4 * 2 + 10] + d ^= key[4 * 2 + 11] + t1 = (~a) % 0x100000000 + t2 = b ^ d + t3 = c & t1 + t13 = d | t1 + e = t2 ^ t3 + t5 = c ^ t1 + t6 = c ^ e + t7 = b & t6 + t10 = e | t5 + h = t5 ^ t7 + t9 = d | t7 + t11 = t9 & t10 + t14 = t2 ^ h + g = a ^ t11 + t15 = g ^ t13 + f = t14 ^ t15 + e = rotl32(e, 13) + g = rotl32(g, 3) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + h = rotl32(h, 7) + f = rotl32(f, 1) + e ^= f ^ h + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e = rotl32(e, 5) + g = rotl32(g, 22) + e ^= key[4 * 3 + 8] + f ^= key[4 * 3 + 9] + g ^= key[4 * 3 + 10] + h ^= key[4 * 3 + 11] + t1 = e ^ g + t2 = h ^ t1 + t3 = e & t2 + t4 = h ^ t3 + t5 = f & t4 + c = t2 ^ t5 + t7 = e | c + t8 = f | h + t11 = e | h + t9 = t4 & t7 + b = t8 ^ t9 + t12 = f ^ t11 + t13 = c ^ t9 + t15 = t3 ^ t8 + d = t12 ^ t13 + t16 = g & t15 + a = t12 ^ t16 + a = rotl32(a, 13) + c = rotl32(c, 3) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + d = rotl32(d, 7) + b = rotl32(b, 1) + a ^= b ^ d + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a = rotl32(a, 5) + c = rotl32(c, 22) + a ^= key[4 * 4 + 8] + b ^= key[4 * 4 + 9] + c ^= key[4 * 4 + 10] + d ^= key[4 * 4 + 11] + t1 = a ^ d + t2 = d & t1 + t3 = c ^ t2 + t4 = b | t3 + h = t1 ^ t4 + t6 = (~b) % 0x100000000 + t7 = t1 | t6 + e = t3 ^ t7 + t9 = a & e + t10 = t1 ^ t6 + t11 = t4 & t10 + g = t9 ^ t11 + t13 = a ^ t3 + t14 = t10 & g + f = t13 ^ t14 + e = rotl32(e, 13) + g = rotl32(g, 3) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + h = rotl32(h, 7) + f = rotl32(f, 1) + e ^= f ^ h + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e = rotl32(e, 5) + g = rotl32(g, 22) + e ^= key[4 * 5 + 8] + f ^= key[4 * 5 + 9] + g ^= key[4 * 5 + 10] + h ^= key[4 * 5 + 11] + t1 = (~e) % 0x100000000 + t2 = e ^ f + t3 = e ^ h + t4 = g ^ t1 + t5 = t2 | t3 + a = t4 ^ t5 + t7 = h & a + t8 = t2 ^ a + t10 = t1 | a + b = t7 ^ t8 + t11 = t2 | t7 + t12 = t3 ^ t10 + t14 = f ^ t7 + c = t11 ^ t12 + t15 = b & t12 + d = t14 ^ t15 + a = rotl32(a, 13) + c = rotl32(c, 3) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + d = rotl32(d, 7) + b = rotl32(b, 1) + a ^= b ^ d + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a = rotl32(a, 5) + c = rotl32(c, 22) + a ^= key[4 * 6 + 8] + b ^= key[4 * 6 + 9] + c ^= key[4 * 6 + 10] + d ^= key[4 * 6 + 11] + t1 = (~a) % 0x100000000 + t2 = a ^ d + t3 = b ^ t2 + t4 = t1 | t2 + t5 = c ^ t4 + f = b ^ t5 + t13 = (~t5) % 0x100000000 + t7 = t2 | f + t8 = d ^ t7 + t9 = t5 & t8 + g = t3 ^ t9 + t11 = t5 ^ t8 + e = g ^ t11 + t14 = t3 & t11 + h = t13 ^ t14 + e = rotl32(e, 13) + g = rotl32(g, 3) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + h = rotl32(h, 7) + f = rotl32(f, 1) + e ^= f ^ h + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e = rotl32(e, 5) + g = rotl32(g, 22) + e ^= key[4 * 7 + 8] + f ^= key[4 * 7 + 9] + g ^= key[4 * 7 + 10] + h ^= key[4 * 7 + 11] + t1 = (~g) % 0x100000000 + t2 = f ^ g + t3 = f | t1 + t4 = h ^ t3 + t5 = e & t4 + t7 = e ^ h + d = t2 ^ t5 + t8 = f ^ t5 + t9 = t2 | t8 + t11 = h & t3 + b = t7 ^ t9 + t12 = t5 ^ b + t15 = t1 | t4 + t13 = d & t12 + c = t11 ^ t13 + t16 = t12 ^ c + a = t15 ^ t16 + a = rotl32(a, 13) + c = rotl32(c, 3) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + d = rotl32(d, 7) + b = rotl32(b, 1) + a ^= b ^ d + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a = rotl32(a, 5) + c = rotl32(c, 22) + a ^= key[4 * 8 + 8] + b ^= key[4 * 8 + 9] + c ^= key[4 * 8 + 10] + d ^= key[4 * 8 + 11] + t1 = a ^ d + t2 = a & d + t3 = c ^ t1 + t6 = b & t1 + t4 = b ^ t3 + t10 = (~t3) % 0x100000000 + h = t2 ^ t4 + t7 = a ^ t6 + t14 = (~t7) % 0x100000000 + t8 = c | t7 + t11 = t3 ^ t7 + g = t4 ^ t8 + t12 = h & t11 + f = t10 ^ t12 + e = t12 ^ t14 + e = rotl32(e, 13) + g = rotl32(g, 3) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + h = rotl32(h, 7) + f = rotl32(f, 1) + e ^= f ^ h + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e = rotl32(e, 5) + g = rotl32(g, 22) + e ^= key[4 * 9 + 8] + f ^= key[4 * 9 + 9] + g ^= key[4 * 9 + 10] + h ^= key[4 * 9 + 11] + t1 = (~e) % 0x100000000 + t2 = f ^ t1 + t3 = e | t2 + t4 = h | t2 + t5 = g ^ t3 + c = h ^ t5 + t7 = f ^ t4 + t8 = t2 ^ c + t9 = t5 & t7 + d = t8 ^ t9 + t11 = t5 ^ t7 + b = d ^ t11 + t13 = t8 & t11 + a = t5 ^ t13 + a = rotl32(a, 13) + c = rotl32(c, 3) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + d = rotl32(d, 7) + b = rotl32(b, 1) + a ^= b ^ d + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a = rotl32(a, 5) + c = rotl32(c, 22) + a ^= key[4 * 10 + 8] + b ^= key[4 * 10 + 9] + c ^= key[4 * 10 + 10] + d ^= key[4 * 10 + 11] + t1 = (~a) % 0x100000000 + t2 = b ^ d + t3 = c & t1 + t13 = d | t1 + e = t2 ^ t3 + t5 = c ^ t1 + t6 = c ^ e + t7 = b & t6 + t10 = e | t5 + h = t5 ^ t7 + t9 = d | t7 + t11 = t9 & t10 + t14 = t2 ^ h + g = a ^ t11 + t15 = g ^ t13 + f = t14 ^ t15 + e = rotl32(e, 13) + g = rotl32(g, 3) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + h = rotl32(h, 7) + f = rotl32(f, 1) + e ^= f ^ h + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e = rotl32(e, 5) + g = rotl32(g, 22) + e ^= key[4 * 11 + 8] + f ^= key[4 * 11 + 9] + g ^= key[4 * 11 + 10] + h ^= key[4 * 11 + 11] + t1 = e ^ g + t2 = h ^ t1 + t3 = e & t2 + t4 = h ^ t3 + t5 = f & t4 + c = t2 ^ t5 + t7 = e | c + t8 = f | h + t11 = e | h + t9 = t4 & t7 + b = t8 ^ t9 + t12 = f ^ t11 + t13 = c ^ t9 + t15 = t3 ^ t8 + d = t12 ^ t13 + t16 = g & t15 + a = t12 ^ t16 + a = rotl32(a, 13) + c = rotl32(c, 3) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + d = rotl32(d, 7) + b = rotl32(b, 1) + a ^= b ^ d + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a = rotl32(a, 5) + c = rotl32(c, 22) + a ^= key[4 * 12 + 8] + b ^= key[4 * 12 + 9] + c ^= key[4 * 12 + 10] + d ^= key[4 * 12 + 11] + t1 = a ^ d + t2 = d & t1 + t3 = c ^ t2 + t4 = b | t3 + h = t1 ^ t4 + t6 = (~b) % 0x100000000 + t7 = t1 | t6 + e = t3 ^ t7 + t9 = a & e + t10 = t1 ^ t6 + t11 = t4 & t10 + g = t9 ^ t11 + t13 = a ^ t3 + t14 = t10 & g + f = t13 ^ t14 + e = rotl32(e, 13) + g = rotl32(g, 3) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + h = rotl32(h, 7) + f = rotl32(f, 1) + e ^= f ^ h + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e = rotl32(e, 5) + g = rotl32(g, 22) + e ^= key[4 * 13 + 8] + f ^= key[4 * 13 + 9] + g ^= key[4 * 13 + 10] + h ^= key[4 * 13 + 11] + t1 = (~e) % 0x100000000 + t2 = e ^ f + t3 = e ^ h + t4 = g ^ t1 + t5 = t2 | t3 + a = t4 ^ t5 + t7 = h & a + t8 = t2 ^ a + t10 = t1 | a + b = t7 ^ t8 + t11 = t2 | t7 + t12 = t3 ^ t10 + t14 = f ^ t7 + c = t11 ^ t12 + t15 = b & t12 + d = t14 ^ t15 + a = rotl32(a, 13) + c = rotl32(c, 3) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + d = rotl32(d, 7) + b = rotl32(b, 1) + a ^= b ^ d + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a = rotl32(a, 5) + c = rotl32(c, 22) + a ^= key[4 * 14 + 8] + b ^= key[4 * 14 + 9] + c ^= key[4 * 14 + 10] + d ^= key[4 * 14 + 11] + t1 = (~a) % 0x100000000 + t2 = a ^ d + t3 = b ^ t2 + t4 = t1 | t2 + t5 = c ^ t4 + f = b ^ t5 + t13 = (~t5) % 0x100000000 + t7 = t2 | f + t8 = d ^ t7 + t9 = t5 & t8 + g = t3 ^ t9 + t11 = t5 ^ t8 + e = g ^ t11 + t14 = t3 & t11 + h = t13 ^ t14 + e = rotl32(e, 13) + g = rotl32(g, 3) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + h = rotl32(h, 7) + f = rotl32(f, 1) + e ^= f ^ h + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e = rotl32(e, 5) + g = rotl32(g, 22) + e ^= key[4 * 15 + 8] + f ^= key[4 * 15 + 9] + g ^= key[4 * 15 + 10] + h ^= key[4 * 15 + 11] + t1 = (~g) % 0x100000000 + t2 = f ^ g + t3 = f | t1 + t4 = h ^ t3 + t5 = e & t4 + t7 = e ^ h + d = t2 ^ t5 + t8 = f ^ t5 + t9 = t2 | t8 + t11 = h & t3 + b = t7 ^ t9 + t12 = t5 ^ b + t15 = t1 | t4 + t13 = d & t12 + c = t11 ^ t13 + t16 = t12 ^ c + a = t15 ^ t16 + a = rotl32(a, 13) + c = rotl32(c, 3) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + d = rotl32(d, 7) + b = rotl32(b, 1) + a ^= b ^ d + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a = rotl32(a, 5) + c = rotl32(c, 22) + a ^= key[4 * 16 + 8] + b ^= key[4 * 16 + 9] + c ^= key[4 * 16 + 10] + d ^= key[4 * 16 + 11] + t1 = a ^ d + t2 = a & d + t3 = c ^ t1 + t6 = b & t1 + t4 = b ^ t3 + t10 = (~t3) % 0x100000000 + h = t2 ^ t4 + t7 = a ^ t6 + t14 = (~t7) % 0x100000000 + t8 = c | t7 + t11 = t3 ^ t7 + g = t4 ^ t8 + t12 = h & t11 + f = t10 ^ t12 + e = t12 ^ t14 + e = rotl32(e, 13) + g = rotl32(g, 3) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + h = rotl32(h, 7) + f = rotl32(f, 1) + e ^= f ^ h + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e = rotl32(e, 5) + g = rotl32(g, 22) + e ^= key[4 * 17 + 8] + f ^= key[4 * 17 + 9] + g ^= key[4 * 17 + 10] + h ^= key[4 * 17 + 11] + t1 = (~e) % 0x100000000 + t2 = f ^ t1 + t3 = e | t2 + t4 = h | t2 + t5 = g ^ t3 + c = h ^ t5 + t7 = f ^ t4 + t8 = t2 ^ c + t9 = t5 & t7 + d = t8 ^ t9 + t11 = t5 ^ t7 + b = d ^ t11 + t13 = t8 & t11 + a = t5 ^ t13 + a = rotl32(a, 13) + c = rotl32(c, 3) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + d = rotl32(d, 7) + b = rotl32(b, 1) + a ^= b ^ d + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a = rotl32(a, 5) + c = rotl32(c, 22) + a ^= key[4 * 18 + 8] + b ^= key[4 * 18 + 9] + c ^= key[4 * 18 + 10] + d ^= key[4 * 18 + 11] + t1 = (~a) % 0x100000000 + t2 = b ^ d + t3 = c & t1 + t13 = d | t1 + e = t2 ^ t3 + t5 = c ^ t1 + t6 = c ^ e + t7 = b & t6 + t10 = e | t5 + h = t5 ^ t7 + t9 = d | t7 + t11 = t9 & t10 + t14 = t2 ^ h + g = a ^ t11 + t15 = g ^ t13 + f = t14 ^ t15 + e = rotl32(e, 13) + g = rotl32(g, 3) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + h = rotl32(h, 7) + f = rotl32(f, 1) + e ^= f ^ h + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e = rotl32(e, 5) + g = rotl32(g, 22) + e ^= key[4 * 19 + 8] + f ^= key[4 * 19 + 9] + g ^= key[4 * 19 + 10] + h ^= key[4 * 19 + 11] + t1 = e ^ g + t2 = h ^ t1 + t3 = e & t2 + t4 = h ^ t3 + t5 = f & t4 + c = t2 ^ t5 + t7 = e | c + t8 = f | h + t11 = e | h + t9 = t4 & t7 + b = t8 ^ t9 + t12 = f ^ t11 + t13 = c ^ t9 + t15 = t3 ^ t8 + d = t12 ^ t13 + t16 = g & t15 + a = t12 ^ t16 + a = rotl32(a, 13) + c = rotl32(c, 3) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + d = rotl32(d, 7) + b = rotl32(b, 1) + a ^= b ^ d + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a = rotl32(a, 5) + c = rotl32(c, 22) + a ^= key[4 * 20 + 8] + b ^= key[4 * 20 + 9] + c ^= key[4 * 20 + 10] + d ^= key[4 * 20 + 11] + t1 = a ^ d + t2 = d & t1 + t3 = c ^ t2 + t4 = b | t3 + h = t1 ^ t4 + t6 = (~b) % 0x100000000 + t7 = t1 | t6 + e = t3 ^ t7 + t9 = a & e + t10 = t1 ^ t6 + t11 = t4 & t10 + g = t9 ^ t11 + t13 = a ^ t3 + t14 = t10 & g + f = t13 ^ t14 + e = rotl32(e, 13) + g = rotl32(g, 3) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + h = rotl32(h, 7) + f = rotl32(f, 1) + e ^= f ^ h + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e = rotl32(e, 5) + g = rotl32(g, 22) + e ^= key[4 * 21 + 8] + f ^= key[4 * 21 + 9] + g ^= key[4 * 21 + 10] + h ^= key[4 * 21 + 11] + t1 = (~e) % 0x100000000 + t2 = e ^ f + t3 = e ^ h + t4 = g ^ t1 + t5 = t2 | t3 + a = t4 ^ t5 + t7 = h & a + t8 = t2 ^ a + t10 = t1 | a + b = t7 ^ t8 + t11 = t2 | t7 + t12 = t3 ^ t10 + t14 = f ^ t7 + c = t11 ^ t12 + t15 = b & t12 + d = t14 ^ t15 + a = rotl32(a, 13) + c = rotl32(c, 3) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + d = rotl32(d, 7) + b = rotl32(b, 1) + a ^= b ^ d + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a = rotl32(a, 5) + c = rotl32(c, 22) + a ^= key[4 * 22 + 8] + b ^= key[4 * 22 + 9] + c ^= key[4 * 22 + 10] + d ^= key[4 * 22 + 11] + t1 = (~a) % 0x100000000 + t2 = a ^ d + t3 = b ^ t2 + t4 = t1 | t2 + t5 = c ^ t4 + f = b ^ t5 + t13 = (~t5) % 0x100000000 + t7 = t2 | f + t8 = d ^ t7 + t9 = t5 & t8 + g = t3 ^ t9 + t11 = t5 ^ t8 + e = g ^ t11 + t14 = t3 & t11 + h = t13 ^ t14 + e = rotl32(e, 13) + g = rotl32(g, 3) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + h = rotl32(h, 7) + f = rotl32(f, 1) + e ^= f ^ h + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e = rotl32(e, 5) + g = rotl32(g, 22) + e ^= key[4 * 23 + 8] + f ^= key[4 * 23 + 9] + g ^= key[4 * 23 + 10] + h ^= key[4 * 23 + 11] + t1 = (~g) % 0x100000000 + t2 = f ^ g + t3 = f | t1 + t4 = h ^ t3 + t5 = e & t4 + t7 = e ^ h + d = t2 ^ t5 + t8 = f ^ t5 + t9 = t2 | t8 + t11 = h & t3 + b = t7 ^ t9 + t12 = t5 ^ b + t15 = t1 | t4 + t13 = d & t12 + c = t11 ^ t13 + t16 = t12 ^ c + a = t15 ^ t16 + a = rotl32(a, 13) + c = rotl32(c, 3) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + d = rotl32(d, 7) + b = rotl32(b, 1) + a ^= b ^ d + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a = rotl32(a, 5) + c = rotl32(c, 22) + a ^= key[4 * 24 + 8] + b ^= key[4 * 24 + 9] + c ^= key[4 * 24 + 10] + d ^= key[4 * 24 + 11] + t1 = a ^ d + t2 = a & d + t3 = c ^ t1 + t6 = b & t1 + t4 = b ^ t3 + t10 = (~t3) % 0x100000000 + h = t2 ^ t4 + t7 = a ^ t6 + t14 = (~t7) % 0x100000000 + t8 = c | t7 + t11 = t3 ^ t7 + g = t4 ^ t8 + t12 = h & t11 + f = t10 ^ t12 + e = t12 ^ t14 + e = rotl32(e, 13) + g = rotl32(g, 3) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + h = rotl32(h, 7) + f = rotl32(f, 1) + e ^= f ^ h + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e = rotl32(e, 5) + g = rotl32(g, 22) + e ^= key[4 * 25 + 8] + f ^= key[4 * 25 + 9] + g ^= key[4 * 25 + 10] + h ^= key[4 * 25 + 11] + t1 = (~e) % 0x100000000 + t2 = f ^ t1 + t3 = e | t2 + t4 = h | t2 + t5 = g ^ t3 + c = h ^ t5 + t7 = f ^ t4 + t8 = t2 ^ c + t9 = t5 & t7 + d = t8 ^ t9 + t11 = t5 ^ t7 + b = d ^ t11 + t13 = t8 & t11 + a = t5 ^ t13 + a = rotl32(a, 13) + c = rotl32(c, 3) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + d = rotl32(d, 7) + b = rotl32(b, 1) + a ^= b ^ d + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a = rotl32(a, 5) + c = rotl32(c, 22) + a ^= key[4 * 26 + 8] + b ^= key[4 * 26 + 9] + c ^= key[4 * 26 + 10] + d ^= key[4 * 26 + 11] + t1 = (~a) % 0x100000000 + t2 = b ^ d + t3 = c & t1 + t13 = d | t1 + e = t2 ^ t3 + t5 = c ^ t1 + t6 = c ^ e + t7 = b & t6 + t10 = e | t5 + h = t5 ^ t7 + t9 = d | t7 + t11 = t9 & t10 + t14 = t2 ^ h + g = a ^ t11 + t15 = g ^ t13 + f = t14 ^ t15 + e = rotl32(e, 13) + g = rotl32(g, 3) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + h = rotl32(h, 7) + f = rotl32(f, 1) + e ^= f ^ h + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e = rotl32(e, 5) + g = rotl32(g, 22) + e ^= key[4 * 27 + 8] + f ^= key[4 * 27 + 9] + g ^= key[4 * 27 + 10] + h ^= key[4 * 27 + 11] + t1 = e ^ g + t2 = h ^ t1 + t3 = e & t2 + t4 = h ^ t3 + t5 = f & t4 + c = t2 ^ t5 + t7 = e | c + t8 = f | h + t11 = e | h + t9 = t4 & t7 + b = t8 ^ t9 + t12 = f ^ t11 + t13 = c ^ t9 + t15 = t3 ^ t8 + d = t12 ^ t13 + t16 = g & t15 + a = t12 ^ t16 + a = rotl32(a, 13) + c = rotl32(c, 3) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + d = rotl32(d, 7) + b = rotl32(b, 1) + a ^= b ^ d + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a = rotl32(a, 5) + c = rotl32(c, 22) + a ^= key[4 * 28 + 8] + b ^= key[4 * 28 + 9] + c ^= key[4 * 28 + 10] + d ^= key[4 * 28 + 11] + t1 = a ^ d + t2 = d & t1 + t3 = c ^ t2 + t4 = b | t3 + h = t1 ^ t4 + t6 = (~b) % 0x100000000 + t7 = t1 | t6 + e = t3 ^ t7 + t9 = a & e + t10 = t1 ^ t6 + t11 = t4 & t10 + g = t9 ^ t11 + t13 = a ^ t3 + t14 = t10 & g + f = t13 ^ t14 + e = rotl32(e, 13) + g = rotl32(g, 3) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + h = rotl32(h, 7) + f = rotl32(f, 1) + e ^= f ^ h + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e = rotl32(e, 5) + g = rotl32(g, 22) + e ^= key[4 * 29 + 8] + f ^= key[4 * 29 + 9] + g ^= key[4 * 29 + 10] + h ^= key[4 * 29 + 11] + t1 = (~e) % 0x100000000 + t2 = e ^ f + t3 = e ^ h + t4 = g ^ t1 + t5 = t2 | t3 + a = t4 ^ t5 + t7 = h & a + t8 = t2 ^ a + t10 = t1 | a + b = t7 ^ t8 + t11 = t2 | t7 + t12 = t3 ^ t10 + t14 = f ^ t7 + c = t11 ^ t12 + t15 = b & t12 + d = t14 ^ t15 + a = rotl32(a, 13) + c = rotl32(c, 3) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + d = rotl32(d, 7) + b = rotl32(b, 1) + a ^= b ^ d + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a = rotl32(a, 5) + c = rotl32(c, 22) + a ^= key[4 * 30 + 8] + b ^= key[4 * 30 + 9] + c ^= key[4 * 30 + 10] + d ^= key[4 * 30 + 11] + t1 = (~a) % 0x100000000 + t2 = a ^ d + t3 = b ^ t2 + t4 = t1 | t2 + t5 = c ^ t4 + f = b ^ t5 + t13 = (~t5) % 0x100000000 + t7 = t2 | f + t8 = d ^ t7 + t9 = t5 & t8 + g = t3 ^ t9 + t11 = t5 ^ t8 + e = g ^ t11 + t14 = t3 & t11 + h = t13 ^ t14 + e = rotl32(e, 13) + g = rotl32(g, 3) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + h = rotl32(h, 7) + f = rotl32(f, 1) + e ^= f ^ h + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e = rotl32(e, 5) + g = rotl32(g, 22) + e ^= key[4 * 31 + 8] + f ^= key[4 * 31 + 9] + g ^= key[4 * 31 + 10] + h ^= key[4 * 31 + 11] + t1 = (~g) % 0x100000000 + t2 = f ^ g + t3 = f | t1 + t4 = h ^ t3 + t5 = e & t4 + t7 = e ^ h + d = t2 ^ t5 + t8 = f ^ t5 + t9 = t2 | t8 + t11 = h & t3 + b = t7 ^ t9 + t12 = t5 ^ b + t15 = t1 | t4 + t13 = d & t12 + c = t11 ^ t13 + t16 = t12 ^ c + a = t15 ^ t16 + a ^= key[4 * 32 + 8] + b ^= key[4 * 32 + 9] + c ^= key[4 * 32 + 10] + d ^= key[4 * 32 + 11] + if WORD_BIGENDIAN: + a = byteswap32(a) + b = byteswap32(b) + c = byteswap32(c) + d = byteswap32(d) + in_blk[0] = a + in_blk[1] = b + in_blk[2] = c + in_blk[3] = d + + +def decrypt(key, in_blk): + # serpent_generate.py + a = in_blk[0] + b = in_blk[1] + c = in_blk[2] + d = in_blk[3] + if WORD_BIGENDIAN: + a = byteswap32(a) + b = byteswap32(b) + c = byteswap32(c) + d = byteswap32(d) + e = 0 + f = 0 + g = 0 + h = 0 + t1 = 0 + t2 = 0 + t3 = 0 + t4 = 0 + t5 = 0 + t6 = 0 + t7 = 0 + t8 = 0 + t9 = 0 + t10 = 0 + t11 = 0 + t12 = 0 + t13 = 0 + t14 = 0 + t15 = 0 + t16 = 0 + a ^= key[4 * 32 + 8] + b ^= key[4 * 32 + 9] + c ^= key[4 * 32 + 10] + d ^= key[4 * 32 + 11] + t1 = a & b + t2 = a | b + t3 = c | t1 + t4 = d & t2 + h = t3 ^ t4 + t6 = (~d) % 0x100000000 + t7 = b ^ t4 + t8 = h ^ t6 + t11 = c ^ t7 + t9 = t7 | t8 + f = a ^ t9 + t12 = d | f + e = t11 ^ t12 + t14 = a & h + t15 = t3 ^ f + t16 = e ^ t14 + g = t15 ^ t16 + e ^= key[4 * 31 + 8] + f ^= key[4 * 31 + 9] + g ^= key[4 * 31 + 10] + h ^= key[4 * 31 + 11] + g = rotr32(g, 22) + e = rotr32(e, 5) + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e ^= f ^ h + h = rotr32(h, 7) + f = rotr32(f, 1) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + g = rotr32(g, 3) + e = rotr32(e, 13) + t1 = (~e) % 0x100000000 + t2 = e ^ f + t3 = g ^ t2 + t4 = g | t1 + t5 = h ^ t4 + t13 = h & t1 + b = t3 ^ t5 + t7 = t3 & t5 + t8 = t2 ^ t7 + t9 = f | t8 + d = t5 ^ t9 + t11 = f | d + a = t8 ^ t11 + t14 = t3 ^ t11 + c = t13 ^ t14 + a ^= key[4 * 30 + 8] + b ^= key[4 * 30 + 9] + c ^= key[4 * 30 + 10] + d ^= key[4 * 30 + 11] + c = rotr32(c, 22) + a = rotr32(a, 5) + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a ^= b ^ d + d = rotr32(d, 7) + b = rotr32(b, 1) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + c = rotr32(c, 3) + a = rotr32(a, 13) + t1 = (~c) % 0x100000000 + t2 = b & t1 + t3 = d ^ t2 + t4 = a & t3 + t5 = b ^ t1 + h = t4 ^ t5 + t7 = b | h + t8 = a & t7 + f = t3 ^ t8 + t10 = a | d + t11 = t1 ^ t7 + e = t10 ^ t11 + t13 = a ^ c + t14 = b & t10 + t15 = t4 | t13 + g = t14 ^ t15 + e ^= key[4 * 29 + 8] + f ^= key[4 * 29 + 9] + g ^= key[4 * 29 + 10] + h ^= key[4 * 29 + 11] + g = rotr32(g, 22) + e = rotr32(e, 5) + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e ^= f ^ h + h = rotr32(h, 7) + f = rotr32(f, 1) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + g = rotr32(g, 3) + e = rotr32(e, 13) + t1 = g ^ h + t2 = g | h + t3 = f ^ t2 + t4 = e & t3 + b = t1 ^ t4 + t6 = e ^ h + t7 = f | h + t8 = t6 & t7 + d = t3 ^ t8 + t10 = (~e) % 0x100000000 + t11 = g ^ d + t12 = t10 | t11 + a = t3 ^ t12 + t14 = g | t4 + t15 = t7 ^ t14 + t16 = d | t10 + c = t15 ^ t16 + a ^= key[4 * 28 + 8] + b ^= key[4 * 28 + 9] + c ^= key[4 * 28 + 10] + d ^= key[4 * 28 + 11] + c = rotr32(c, 22) + a = rotr32(a, 5) + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a ^= b ^ d + d = rotr32(d, 7) + b = rotr32(b, 1) + + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + c = rotr32(c, 3) + a = rotr32(a, 13) + t1 = b ^ c + t2 = b | c + t3 = a ^ c + t7 = a ^ d + t4 = t2 ^ t3 + t5 = d | t4 + t9 = t2 ^ t7 + e = t1 ^ t5 + t8 = t1 | t5 + t11 = a & t4 + g = t8 ^ t9 + t12 = e | t9 + f = t11 ^ t12 + t14 = a & g + t15 = t2 ^ t14 + t16 = e & t15 + h = t4 ^ t16 + e ^= key[4 * 27 + 8] + f ^= key[4 * 27 + 9] + g ^= key[4 * 27 + 10] + h ^= key[4 * 27 + 11] + g = rotr32(g, 22) + e = rotr32(e, 5) + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e ^= f ^ h + h = rotr32(h, 7) + f = rotr32(f, 1) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + g = rotr32(g, 3) + e = rotr32(e, 13) + t1 = f ^ h + t2 = (~t1) % 0x100000000 + t3 = e ^ g + t4 = g ^ t1 + t7 = e | t2 + t5 = f & t4 + t8 = h ^ t7 + t11 = (~t4) % 0x100000000 + a = t3 ^ t5 + t9 = t3 | t8 + t14 = h & t11 + d = t1 ^ t9 + t12 = a | d + b = t11 ^ t12 + t15 = t3 ^ t12 + c = t14 ^ t15 + a ^= key[4 * 26 + 8] + b ^= key[4 * 26 + 9] + c ^= key[4 * 26 + 10] + d ^= key[4 * 26 + 11] + c = rotr32(c, 22) + a = rotr32(a, 5) + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a ^= b ^ d + d = rotr32(d, 7) + b = rotr32(b, 1) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + c = rotr32(c, 3) + a = rotr32(a, 13) + t1 = a ^ d + t2 = a & b + t3 = b ^ c + t4 = a ^ t3 + t5 = b | d + t7 = c | t1 + h = t4 ^ t5 + t8 = b ^ t7 + t11 = (~t2) % 0x100000000 + t9 = t4 & t8 + f = t1 ^ t9 + t13 = t9 ^ t11 + t12 = h & f + g = t12 ^ t13 + t15 = a & d + t16 = c ^ t13 + e = t15 ^ t16 + e ^= key[4 * 25 + 8] + f ^= key[4 * 25 + 9] + g ^= key[4 * 25 + 10] + h ^= key[4 * 25 + 11] + g = rotr32(g, 22) + e = rotr32(e, 5) + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e ^= f ^ h + h = rotr32(h, 7) + f = rotr32(f, 1) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + g = rotr32(g, 3) + e = rotr32(e, 13) + t1 = (~e) % 0x100000000 + t2 = e ^ f + t3 = t1 | t2 + t4 = h ^ t3 + t7 = h & t2 + t5 = g ^ t4 + t8 = t1 ^ t7 + c = t2 ^ t5 + t11 = e & t4 + t9 = c & t8 + t14 = t5 ^ t8 + b = t4 ^ t9 + t12 = t5 | b + d = t11 ^ t12 + a = d ^ t14 + a ^= key[4 * 24 + 8] + b ^= key[4 * 24 + 9] + c ^= key[4 * 24 + 10] + d ^= key[4 * 24 + 11] + c = rotr32(c, 22) + a = rotr32(a, 5) + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a ^= b ^ d + d = rotr32(d, 7) + b = rotr32(b, 1) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + c = rotr32(c, 3) + a = rotr32(a, 13) + t1 = a & b + t2 = a | b + t3 = c | t1 + t4 = d & t2 + h = t3 ^ t4 + t6 = (~d) % 0x100000000 + t7 = b ^ t4 + t8 = h ^ t6 + t11 = c ^ t7 + t9 = t7 | t8 + f = a ^ t9 + t12 = d | f + e = t11 ^ t12 + t14 = a & h + t15 = t3 ^ f + t16 = e ^ t14 + g = t15 ^ t16 + e ^= key[4 * 23 + 8] + f ^= key[4 * 23 + 9] + g ^= key[4 * 23 + 10] + h ^= key[4 * 23 + 11] + g = rotr32(g, 22) + e = rotr32(e, 5) + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e ^= f ^ h + h = rotr32(h, 7) + f = rotr32(f, 1) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + g = rotr32(g, 3) + e = rotr32(e, 13) + t1 = (~e) % 0x100000000 + t2 = e ^ f + t3 = g ^ t2 + t4 = g | t1 + t5 = h ^ t4 + t13 = h & t1 + b = t3 ^ t5 + t7 = t3 & t5 + t8 = t2 ^ t7 + t9 = f | t8 + d = t5 ^ t9 + t11 = f | d + a = t8 ^ t11 + t14 = t3 ^ t11 + c = t13 ^ t14 + a ^= key[4 * 22 + 8] + b ^= key[4 * 22 + 9] + c ^= key[4 * 22 + 10] + d ^= key[4 * 22 + 11] + c = rotr32(c, 22) + a = rotr32(a, 5) + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a ^= b ^ d + d = rotr32(d, 7) + b = rotr32(b, 1) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + c = rotr32(c, 3) + a = rotr32(a, 13) + t1 = (~c) % 0x100000000 + t2 = b & t1 + t3 = d ^ t2 + t4 = a & t3 + t5 = b ^ t1 + h = t4 ^ t5 + t7 = b | h + t8 = a & t7 + f = t3 ^ t8 + t10 = a | d + t11 = t1 ^ t7 + e = t10 ^ t11 + t13 = a ^ c + t14 = b & t10 + t15 = t4 | t13 + g = t14 ^ t15 + e ^= key[4 * 21 + 8] + f ^= key[4 * 21 + 9] + g ^= key[4 * 21 + 10] + h ^= key[4 * 21 + 11] + g = rotr32(g, 22) + e = rotr32(e, 5) + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e ^= f ^ h + h = rotr32(h, 7) + f = rotr32(f, 1) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + g = rotr32(g, 3) + e = rotr32(e, 13) + t1 = g ^ h + t2 = g | h + t3 = f ^ t2 + t4 = e & t3 + b = t1 ^ t4 + t6 = e ^ h + t7 = f | h + t8 = t6 & t7 + d = t3 ^ t8 + t10 = (~e) % 0x100000000 + t11 = g ^ d + t12 = t10 | t11 + a = t3 ^ t12 + t14 = g | t4 + t15 = t7 ^ t14 + t16 = d | t10 + c = t15 ^ t16 + a ^= key[4 * 20 + 8] + b ^= key[4 * 20 + 9] + c ^= key[4 * 20 + 10] + d ^= key[4 * 20 + 11] + c = rotr32(c, 22) + a = rotr32(a, 5) + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a ^= b ^ d + d = rotr32(d, 7) + b = rotr32(b, 1) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + c = rotr32(c, 3) + a = rotr32(a, 13) + t1 = b ^ c + t2 = b | c + t3 = a ^ c + t7 = a ^ d + t4 = t2 ^ t3 + t5 = d | t4 + t9 = t2 ^ t7 + e = t1 ^ t5 + t8 = t1 | t5 + t11 = a & t4 + g = t8 ^ t9 + t12 = e | t9 + f = t11 ^ t12 + t14 = a & g + t15 = t2 ^ t14 + t16 = e & t15 + h = t4 ^ t16 + e ^= key[4 * 19 + 8] + f ^= key[4 * 19 + 9] + g ^= key[4 * 19 + 10] + h ^= key[4 * 19 + 11] + g = rotr32(g, 22) + e = rotr32(e, 5) + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e ^= f ^ h + h = rotr32(h, 7) + f = rotr32(f, 1) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + g = rotr32(g, 3) + e = rotr32(e, 13) + t1 = f ^ h + t2 = (~t1) % 0x100000000 + t3 = e ^ g + t4 = g ^ t1 + t7 = e | t2 + t5 = f & t4 + t8 = h ^ t7 + t11 = (~t4) % 0x100000000 + a = t3 ^ t5 + t9 = t3 | t8 + t14 = h & t11 + d = t1 ^ t9 + t12 = a | d + b = t11 ^ t12 + t15 = t3 ^ t12 + c = t14 ^ t15 + a ^= key[4 * 18 + 8] + b ^= key[4 * 18 + 9] + c ^= key[4 * 18 + 10] + d ^= key[4 * 18 + 11] + c = rotr32(c, 22) + a = rotr32(a, 5) + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a ^= b ^ d + d = rotr32(d, 7) + b = rotr32(b, 1) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + c = rotr32(c, 3) + a = rotr32(a, 13) + t1 = a ^ d + t2 = a & b + t3 = b ^ c + t4 = a ^ t3 + t5 = b | d + t7 = c | t1 + h = t4 ^ t5 + t8 = b ^ t7 + t11 = (~t2) % 0x100000000 + t9 = t4 & t8 + f = t1 ^ t9 + t13 = t9 ^ t11 + t12 = h & f + g = t12 ^ t13 + t15 = a & d + t16 = c ^ t13 + e = t15 ^ t16 + e ^= key[4 * 17 + 8] + f ^= key[4 * 17 + 9] + g ^= key[4 * 17 + 10] + h ^= key[4 * 17 + 11] + g = rotr32(g, 22) + e = rotr32(e, 5) + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e ^= f ^ h + h = rotr32(h, 7) + f = rotr32(f, 1) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + g = rotr32(g, 3) + e = rotr32(e, 13) + t1 = (~e) % 0x100000000 + t2 = e ^ f + t3 = t1 | t2 + t4 = h ^ t3 + t7 = h & t2 + t5 = g ^ t4 + t8 = t1 ^ t7 + c = t2 ^ t5 + t11 = e & t4 + t9 = c & t8 + t14 = t5 ^ t8 + b = t4 ^ t9 + t12 = t5 | b + d = t11 ^ t12 + a = d ^ t14 + a ^= key[4 * 16 + 8] + b ^= key[4 * 16 + 9] + c ^= key[4 * 16 + 10] + d ^= key[4 * 16 + 11] + c = rotr32(c, 22) + a = rotr32(a, 5) + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a ^= b ^ d + d = rotr32(d, 7) + b = rotr32(b, 1) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + c = rotr32(c, 3) + a = rotr32(a, 13) + t1 = a & b + t2 = a | b + t3 = c | t1 + t4 = d & t2 + h = t3 ^ t4 + t6 = (~d) % 0x100000000 + t7 = b ^ t4 + t8 = h ^ t6 + t11 = c ^ t7 + t9 = t7 | t8 + f = a ^ t9 + t12 = d | f + e = t11 ^ t12 + t14 = a & h + t15 = t3 ^ f + t16 = e ^ t14 + g = t15 ^ t16 + e ^= key[4 * 15 + 8] + f ^= key[4 * 15 + 9] + g ^= key[4 * 15 + 10] + h ^= key[4 * 15 + 11] + g = rotr32(g, 22) + e = rotr32(e, 5) + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e ^= f ^ h + h = rotr32(h, 7) + f = rotr32(f, 1) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + g = rotr32(g, 3) + e = rotr32(e, 13) + t1 = (~e) % 0x100000000 + t2 = e ^ f + t3 = g ^ t2 + t4 = g | t1 + t5 = h ^ t4 + t13 = h & t1 + b = t3 ^ t5 + t7 = t3 & t5 + t8 = t2 ^ t7 + t9 = f | t8 + d = t5 ^ t9 + t11 = f | d + a = t8 ^ t11 + t14 = t3 ^ t11 + c = t13 ^ t14 + a ^= key[4 * 14 + 8] + b ^= key[4 * 14 + 9] + c ^= key[4 * 14 + 10] + d ^= key[4 * 14 + 11] + c = rotr32(c, 22) + a = rotr32(a, 5) + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a ^= b ^ d + d = rotr32(d, 7) + b = rotr32(b, 1) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + c = rotr32(c, 3) + a = rotr32(a, 13) + t1 = (~c) % 0x100000000 + t2 = b & t1 + t3 = d ^ t2 + t4 = a & t3 + t5 = b ^ t1 + h = t4 ^ t5 + t7 = b | h + t8 = a & t7 + f = t3 ^ t8 + t10 = a | d + t11 = t1 ^ t7 + e = t10 ^ t11 + t13 = a ^ c + t14 = b & t10 + t15 = t4 | t13 + g = t14 ^ t15 + e ^= key[4 * 13 + 8] + f ^= key[4 * 13 + 9] + g ^= key[4 * 13 + 10] + h ^= key[4 * 13 + 11] + g = rotr32(g, 22) + e = rotr32(e, 5) + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e ^= f ^ h + h = rotr32(h, 7) + f = rotr32(f, 1) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + g = rotr32(g, 3) + e = rotr32(e, 13) + t1 = g ^ h + t2 = g | h + t3 = f ^ t2 + t4 = e & t3 + b = t1 ^ t4 + t6 = e ^ h + t7 = f | h + t8 = t6 & t7 + d = t3 ^ t8 + t10 = (~e) % 0x100000000 + t11 = g ^ d + t12 = t10 | t11 + a = t3 ^ t12 + t14 = g | t4 + t15 = t7 ^ t14 + t16 = d | t10 + c = t15 ^ t16 + a ^= key[4 * 12 + 8] + b ^= key[4 * 12 + 9] + c ^= key[4 * 12 + 10] + d ^= key[4 * 12 + 11] + c = rotr32(c, 22) + a = rotr32(a, 5) + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a ^= b ^ d + d = rotr32(d, 7) + b = rotr32(b, 1) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + c = rotr32(c, 3) + a = rotr32(a, 13) + t1 = b ^ c + t2 = b | c + t3 = a ^ c + t7 = a ^ d + t4 = t2 ^ t3 + t5 = d | t4 + t9 = t2 ^ t7 + e = t1 ^ t5 + t8 = t1 | t5 + t11 = a & t4 + g = t8 ^ t9 + t12 = e | t9 + f = t11 ^ t12 + t14 = a & g + t15 = t2 ^ t14 + t16 = e & t15 + h = t4 ^ t16 + e ^= key[4 * 11 + 8] + f ^= key[4 * 11 + 9] + g ^= key[4 * 11 + 10] + h ^= key[4 * 11 + 11] + g = rotr32(g, 22) + e = rotr32(e, 5) + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e ^= f ^ h + h = rotr32(h, 7) + f = rotr32(f, 1) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + g = rotr32(g, 3) + e = rotr32(e, 13) + t1 = f ^ h + t2 = (~t1) % 0x100000000 + t3 = e ^ g + t4 = g ^ t1 + t7 = e | t2 + t5 = f & t4 + t8 = h ^ t7 + t11 = (~t4) % 0x100000000 + a = t3 ^ t5 + t9 = t3 | t8 + t14 = h & t11 + d = t1 ^ t9 + t12 = a | d + b = t11 ^ t12 + t15 = t3 ^ t12 + c = t14 ^ t15 + a ^= key[4 * 10 + 8] + b ^= key[4 * 10 + 9] + c ^= key[4 * 10 + 10] + d ^= key[4 * 10 + 11] + c = rotr32(c, 22) + a = rotr32(a, 5) + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a ^= b ^ d + d = rotr32(d, 7) + b = rotr32(b, 1) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + c = rotr32(c, 3) + a = rotr32(a, 13) + t1 = a ^ d + t2 = a & b + t3 = b ^ c + t4 = a ^ t3 + t5 = b | d + t7 = c | t1 + h = t4 ^ t5 + t8 = b ^ t7 + t11 = (~t2) % 0x100000000 + t9 = t4 & t8 + f = t1 ^ t9 + t13 = t9 ^ t11 + t12 = h & f + g = t12 ^ t13 + t15 = a & d + t16 = c ^ t13 + e = t15 ^ t16 + e ^= key[4 * 9 + 8] + f ^= key[4 * 9 + 9] + g ^= key[4 * 9 + 10] + h ^= key[4 * 9 + 11] + g = rotr32(g, 22) + e = rotr32(e, 5) + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e ^= f ^ h + h = rotr32(h, 7) + f = rotr32(f, 1) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + g = rotr32(g, 3) + e = rotr32(e, 13) + t1 = (~e) % 0x100000000 + t2 = e ^ f + t3 = t1 | t2 + t4 = h ^ t3 + t7 = h & t2 + t5 = g ^ t4 + t8 = t1 ^ t7 + c = t2 ^ t5 + t11 = e & t4 + t9 = c & t8 + t14 = t5 ^ t8 + b = t4 ^ t9 + t12 = t5 | b + d = t11 ^ t12 + a = d ^ t14 + a ^= key[4 * 8 + 8] + b ^= key[4 * 8 + 9] + c ^= key[4 * 8 + 10] + d ^= key[4 * 8 + 11] + c = rotr32(c, 22) + a = rotr32(a, 5) + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a ^= b ^ d + d = rotr32(d, 7) + b = rotr32(b, 1) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + c = rotr32(c, 3) + a = rotr32(a, 13) + t1 = a & b + t2 = a | b + t3 = c | t1 + t4 = d & t2 + h = t3 ^ t4 + t6 = (~d) % 0x100000000 + t7 = b ^ t4 + t8 = h ^ t6 + t11 = c ^ t7 + t9 = t7 | t8 + f = a ^ t9 + t12 = d | f + e = t11 ^ t12 + t14 = a & h + t15 = t3 ^ f + t16 = e ^ t14 + g = t15 ^ t16 + e ^= key[4 * 7 + 8] + f ^= key[4 * 7 + 9] + g ^= key[4 * 7 + 10] + h ^= key[4 * 7 + 11] + g = rotr32(g, 22) + e = rotr32(e, 5) + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e ^= f ^ h + h = rotr32(h, 7) + f = rotr32(f, 1) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + g = rotr32(g, 3) + e = rotr32(e, 13) + t1 = (~e) % 0x100000000 + t2 = e ^ f + t3 = g ^ t2 + t4 = g | t1 + t5 = h ^ t4 + t13 = h & t1 + b = t3 ^ t5 + t7 = t3 & t5 + t8 = t2 ^ t7 + t9 = f | t8 + d = t5 ^ t9 + t11 = f | d + a = t8 ^ t11 + t14 = t3 ^ t11 + c = t13 ^ t14 + a ^= key[4 * 6 + 8] + b ^= key[4 * 6 + 9] + c ^= key[4 * 6 + 10] + d ^= key[4 * 6 + 11] + c = rotr32(c, 22) + a = rotr32(a, 5) + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a ^= b ^ d + d = rotr32(d, 7) + b = rotr32(b, 1) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + c = rotr32(c, 3) + a = rotr32(a, 13) + t1 = (~c) % 0x100000000 + t2 = b & t1 + t3 = d ^ t2 + t4 = a & t3 + t5 = b ^ t1 + h = t4 ^ t5 + t7 = b | h + t8 = a & t7 + f = t3 ^ t8 + t10 = a | d + t11 = t1 ^ t7 + e = t10 ^ t11 + t13 = a ^ c + t14 = b & t10 + t15 = t4 | t13 + g = t14 ^ t15 + e ^= key[4 * 5 + 8] + f ^= key[4 * 5 + 9] + g ^= key[4 * 5 + 10] + h ^= key[4 * 5 + 11] + g = rotr32(g, 22) + e = rotr32(e, 5) + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e ^= f ^ h + h = rotr32(h, 7) + f = rotr32(f, 1) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + g = rotr32(g, 3) + e = rotr32(e, 13) + t1 = g ^ h + t2 = g | h + t3 = f ^ t2 + t4 = e & t3 + b = t1 ^ t4 + t6 = e ^ h + t7 = f | h + t8 = t6 & t7 + d = t3 ^ t8 + t10 = (~e) % 0x100000000 + t11 = g ^ d + t12 = t10 | t11 + a = t3 ^ t12 + t14 = g | t4 + t15 = t7 ^ t14 + t16 = d | t10 + c = t15 ^ t16 + a ^= key[4 * 4 + 8] + b ^= key[4 * 4 + 9] + c ^= key[4 * 4 + 10] + d ^= key[4 * 4 + 11] + c = rotr32(c, 22) + a = rotr32(a, 5) + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a ^= b ^ d + d = rotr32(d, 7) + b = rotr32(b, 1) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + c = rotr32(c, 3) + a = rotr32(a, 13) + t1 = b ^ c + t2 = b | c + t3 = a ^ c + t7 = a ^ d + t4 = t2 ^ t3 + t5 = d | t4 + t9 = t2 ^ t7 + e = t1 ^ t5 + t8 = t1 | t5 + t11 = a & t4 + g = t8 ^ t9 + t12 = e | t9 + f = t11 ^ t12 + t14 = a & g + t15 = t2 ^ t14 + t16 = e & t15 + h = t4 ^ t16 + e ^= key[4 * 3 + 8] + f ^= key[4 * 3 + 9] + g ^= key[4 * 3 + 10] + h ^= key[4 * 3 + 11] + g = rotr32(g, 22) + e = rotr32(e, 5) + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e ^= f ^ h + h = rotr32(h, 7) + f = rotr32(f, 1) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + g = rotr32(g, 3) + e = rotr32(e, 13) + t1 = f ^ h + t2 = (~t1) % 0x100000000 + t3 = e ^ g + t4 = g ^ t1 + t7 = e | t2 + t5 = f & t4 + t8 = h ^ t7 + t11 = (~t4) % 0x100000000 + a = t3 ^ t5 + t9 = t3 | t8 + t14 = h & t11 + d = t1 ^ t9 + t12 = a | d + b = t11 ^ t12 + t15 = t3 ^ t12 + c = t14 ^ t15 + a ^= key[4 * 2 + 8] + b ^= key[4 * 2 + 9] + c ^= key[4 * 2 + 10] + d ^= key[4 * 2 + 11] + c = rotr32(c, 22) + a = rotr32(a, 5) + c ^= d ^ ((b << 7) & 0xFFFFFFFF) + a ^= b ^ d + d = rotr32(d, 7) + b = rotr32(b, 1) + d ^= c ^ ((a << 3) & 0xFFFFFFFF) + b ^= a ^ c + c = rotr32(c, 3) + a = rotr32(a, 13) + t1 = a ^ d + t2 = a & b + t3 = b ^ c + t4 = a ^ t3 + t5 = b | d + t7 = c | t1 + h = t4 ^ t5 + t8 = b ^ t7 + t11 = (~t2) % 0x100000000 + t9 = t4 & t8 + f = t1 ^ t9 + t13 = t9 ^ t11 + t12 = h & f + g = t12 ^ t13 + t15 = a & d + t16 = c ^ t13 + e = t15 ^ t16 + e ^= key[4 * 1 + 8] + f ^= key[4 * 1 + 9] + g ^= key[4 * 1 + 10] + h ^= key[4 * 1 + 11] + g = rotr32(g, 22) + e = rotr32(e, 5) + g ^= h ^ ((f << 7) & 0xFFFFFFFF) + e ^= f ^ h + h = rotr32(h, 7) + f = rotr32(f, 1) + h ^= g ^ ((e << 3) & 0xFFFFFFFF) + f ^= e ^ g + g = rotr32(g, 3) + e = rotr32(e, 13) + t1 = (~e) % 0x100000000 + t2 = e ^ f + t3 = t1 | t2 + t4 = h ^ t3 + t7 = h & t2 + t5 = g ^ t4 + t8 = t1 ^ t7 + c = t2 ^ t5 + t11 = e & t4 + t9 = c & t8 + t14 = t5 ^ t8 + b = t4 ^ t9 + t12 = t5 | b + d = t11 ^ t12 + a = d ^ t14 + a ^= key[4 * 0 + 8] + b ^= key[4 * 0 + 9] + c ^= key[4 * 0 + 10] + d ^= key[4 * 0 + 11] + if WORD_BIGENDIAN: + a = byteswap32(a) + b = byteswap32(b) + c = byteswap32(c) + d = byteswap32(d) + in_blk[0] = a + in_blk[1] = b + in_blk[2] = c + in_blk[3] = d + + +__testkey = bytes.fromhex( + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" +) +# __testkey = bytes('\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f') +__testdat = bytes.fromhex("000102030405060708090a0b0c0d0e0f") +# __testdat = bytes('\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f') +assert bytes.fromhex("de269ff833e432b85b2e88d2701ce75c") == Serpent(__testkey).encrypt( + __testdat +) +# assert '\xde&\x9f\xf83\xe42\xb8[.\x88\xd2p\x1c\xe7\\' == Serpent(__testkey).encrypt(__testdat) +# assert __testdat == Serpent(__testkey).decrypt(bytes.fromhex('\xde&\x9f\xf83\xe42\xb8[.\x88\xd2p\x1c\xe7\\')) +assert __testdat == Serpent(__testkey).decrypt( + bytes.fromhex("de269ff833e432b85b2e88d2701ce75c") +) + + +# CBC Encrypt - Jason Reaves +def serpent_cbc_encrypt(key, data, iv=b"\x00" * 16): + out = b"" + last = iv + for i in range(int((len(data) / 16))): + temp = data[i * 16 : (i + 1) * 16] + to_encode = b"" + for j in range(4): + temp1 = struct.unpack_from(" self.start_time + self.db.get_knob("cold_peer_seconds"): + self.send_address_cast() + + # send address cast on address change + else: + if self.db.get_knob("prod.send_address_cast"): + # (rate limited for those with flakey internet) + if ( + self.sent_address_cast_time + + self.db.get_knob("address_cast.interval_seconds") + < time.time() + ): + self.sent_address_cast_time = time.time() + self.db.set_knob("prod.send_address_cast", 0) + self.send_address_cast() + + def initiate_key_offer(self): + for peer in self.db.get_keyed_peers(exclude_addressless=True): + KeyOffer({"peer": peer}).send() + + def initiate_prod(self): + Prod({"speaker": self.db.get_knob("handle"), "flag": PROD_PROMPT}).broadcast() + + def send_address_cast(self): + last_external_address = self.db.get_last_external_address() + if last_external_address is not None: + AddressCast( + { + "speaker": self.db.get_knob("handle"), + "external_address": last_external_address, + } + ).broadcast() + self.sent_first_address_cast = True + self.db.set_knob("prod.send_address_cast", 0) + + def send_ignore(self): + if self.db.get_knob("ignore.interval_seconds") == 0: + return + + Ignore().send() + diff -uNr - - akris/akris/version.py akris-genesis/akris/version.py --- akris/akris/version.py false +++ akris-genesis/akris/version.py ddeed8ce266953e24676cf836de4699d633de27a36871a415b52dd599e1485edcecea13a306555936ab3dfd5245f929e37314204f2e9fb8670f2e67a19961903 @@ -0,0 +1,5 @@ +import os + +current_path = os.path.dirname(os.path.realpath(__file__)) +with open(os.path.join(current_path, "VERSION")) as version_file: + VERSION = version_file.read().strip() diff -uNr - - akris/bin/main.py akris-genesis/bin/main.py --- akris/bin/main.py false +++ akris-genesis/bin/main.py 305dfd9a6d2829fcb4b3ee4e842b3ee2c396dff405acbbfe9d0d16d3d0e2b195c82f54e83ef9c59dc01cdc21df0551831c22edeb64931821795a1502c95f3020 @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 + +import os +import argparse +import logging + +from akris.log_config import LogConfig + +PEST_HOST = "127.0.0.1" +PEST_PORT = 8080 +API_HOST = "127.0.0.1" +API_PORT = 8081 +AKRIS_DATA_PATH = os.path.join(os.path.expanduser("~"), ".akris") +AKRIS_DATABASE_NAME = "akris.db" + +logger = logging.getLogger("akris") +logger = LogConfig().get_logger("bin.main") +logging.basicConfig(level=logging.INFO) + +def get_options(): + parser = argparse.ArgumentParser() + parser.add_argument("--daemon", action='store_true', default=False, help="continue running") + parser.add_argument("--pest-host", default=PEST_HOST, help="pest station host") + parser.add_argument("--api-host", default=API_HOST, help="api service host") + parser.add_argument("--pest-port", default=PEST_PORT, help="pest station port") + parser.add_argument("--api-port", default=API_PORT, help="api service port") + parser.add_argument( + "--akris-data-path", + default=AKRIS_DATA_PATH, + help="path at which to locate persistent Akris data", + ) + parser.add_argument( + "--akris-database-name", + default=AKRIS_DATABASE_NAME, + help="name to use for the Akris database file", + ) + return parser.parse_args() + + +if __name__ == "__main__": + options = get_options() + LogConfig(data_path=options.akris_data_path).get_logger("bin.main") + from akris.station import Station + + station = Station( + tcp_host=options.api_host, + tcp_port=int(options.api_port), + udp_port=int(options.pest_port), + host=options.pest_host, + data_path=options.akris_data_path, + database_name=options.akris_database_name, + ) + station.start(return_from_start=not options.daemon) \ No newline at end of file diff -uNr - - akris/setup.py akris-genesis/setup.py --- akris/setup.py false +++ akris-genesis/setup.py f8fb9ab26c7ee537d09071464bc7a799401bc99c3cdcec6acfb94cae629414e04ac1a4a5c02baba943f7615d4db76c8bf48707a02655020fee069c43a6e04170 @@ -0,0 +1,37 @@ +from setuptools import setup, find_packages +from akris.version import VERSION + +setup( + name="akris", + version=VERSION, + description="A pest implementation", + long_description=open("README.md").read(), + long_description_content_type="text/markdown", + author="Adam Thorsen", + author_email="awt@fastmail.fm", + url="http://alethepedia.com/akris", + license="VPL", + packages=find_packages(), + install_requires=["cffi"], + cffi_modules=["akris/c_serpent/serpent_build.py:ffibuilder"], + extras_require={ + "dev": [ + "black", + "pytest", + "pylint", + "pyinstaller", + "staticx", + "markdown2" + ] + }, + package_data={"akris": ["migrations/*.py", "VERSION"]}, + classifiers=[ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Programming Language :: Python :: 3", + ], + keywords="p2p pest chat", + python_requires=">=3.6", +) diff -uNr - - akris/tests/config.py akris-genesis/tests/config.py --- akris/tests/config.py false +++ akris-genesis/tests/config.py 71e0f35f59db1bfcd6120d1b0a173011e4d1fabc1575e469222b6c1d01ee583814725db5297e1a021978f6f986ff37e101de40f98e0f2fa0b5eec58e69143359 @@ -0,0 +1,5 @@ +import os +import sys + +# Add the project directory to the Python path +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) diff -uNr - - akris/tests/conftest.py akris-genesis/tests/conftest.py --- akris/tests/conftest.py false +++ akris-genesis/tests/conftest.py 3170a0d93c3b91422423ead9b328296fd61f58d028fc15f9dcbab993356c35d49251c2dd2c6a7b96ecc8987de5ef3c925a354cf33a3219b2ad6928cf75fa2572 @@ -0,0 +1,69 @@ +import pytest +from akris.client import Client +from helpers import ( + HOST, + PIZARRO_CLIENT_PORT, + CORTES_CLIENT_PORT, + ALVARADO_CLIENT_PORT, + MOCTEZUMA_CLIENT_PORT, + ATAHUALPA_CLIENT_PORT, + create_client, + await_messages, + assert_no_errors, +) + + +@pytest.fixture(autouse=True) +def reset_db(atahualpa_client, cortes_client, pizarro_client): + yield + atahualpa_client.send_command({"command": "reset_database", "args": []}) + assert_no_errors(await_messages(1, atahualpa_client)) + cortes_client.send_command({"command": "reset_database", "args": []}) + assert_no_errors(await_messages(1, cortes_client)) + pizarro_client.send_command({"command": "reset_database", "args": []}) + assert_no_errors(await_messages(1, pizarro_client)) + + +def pytest_sessionstart(session): + pass + + +def pytest_sessionfinish(session, exitstatus): + pass + + +@pytest.fixture(scope="session") +def cortes_client(): + client = create_client(CORTES_CLIENT_PORT) + yield client + if None is not client: + client.shutdown_station() + + +@pytest.fixture(scope="session") +def pizarro_client(): + client = create_client(PIZARRO_CLIENT_PORT) + yield client + if None is not client: + client.shutdown_station() + + +@pytest.fixture(scope="session") +def alvarado_client(): + client = create_client(ALVARADO_CLIENT_PORT) + yield client + client.shutdown_station() + + +@pytest.fixture(scope="session") +def moctezuma_client(): + client = create_client(MOCTEZUMA_CLIENT_PORT) + yield client + client.shutdown_station() + + +@pytest.fixture(scope="session") +def atahualpa_client(): + client = create_client(ATAHUALPA_CLIENT_PORT) + yield client + client.shutdown_station() diff -uNr - - akris/tests/helpers.py akris-genesis/tests/helpers.py --- akris/tests/helpers.py false +++ akris-genesis/tests/helpers.py 7554315ba21438dfb6b340075a6408a0111926e31a8beeffbeb7c239046d52d0467b2d534034b0ff13aa8bf76c58c205342b29d812602a22999be5e1ca0fb265 @@ -0,0 +1,117 @@ +import logging +import base64 +import os +import time + + +from akris.client import Client + + +HOST = "127.0.0.1" +PIZARRO_CLIENT_PORT = 30000 +PIZARRO_PEST_PORT = 40000 +CORTES_CLIENT_PORT = 30001 +CORTES_PEST_PORT = 40001 +ALVARADO_CLIENT_PORT = 30002 +ALVARADO_PEST_PORT = 40002 +MOCTEZUMA_CLIENT_PORT = 30003 +MOCTEZUMA_PEST_PORT = 40003 +ATAHUALPA_CLIENT_PORT = 30004 +ATAHUALPA_PEST_PORT = 40004 + + +def genkey(): + return base64.b64encode(os.urandom(64)).decode("utf-8") + + +P_C_KEY = genkey() +P_A_KEY = genkey() +P_M_KEY = genkey() +P_AT_KEY = genkey() +C_A_KEY = genkey() +C_M_KEY = genkey() +C_AT_KEY = genkey() +M_AT_KEY = genkey() + +CONNECT_TIMEOUT = 10 + + +logger = logging.getLogger(__name__) +AWAIT_MESSAGE_TIMEOUT = 5 + + +def await_message_with_timeout(api_client, body): + logger.info(f"await_message_with_timeout {body}") + start = time.time() + elapsed_time = 0 + + while elapsed_time < AWAIT_MESSAGE_TIMEOUT: + while api_client.message_queue.qsize() > 0: + message = api_client.message_queue.get() + if message.get("body") == body: + return message + elapsed_time = time.time() - start + time.sleep(0.1) + assert False + +def await_message_update_with_timeout(api_client, body): + logger.info(f"await_message_with_timeout {body}") + start = time.time() + elapsed_time = 0 + + while elapsed_time < AWAIT_MESSAGE_TIMEOUT: + while api_client.message_queue.qsize() > 0: + message = api_client.message_queue.get() + if message["command"] == "message_update": + return message + elapsed_time = time.time() - start + time.sleep(0.1) + assert False + +def await_messages(count, api_client): + start = time.time() + elapsed_time = 0 + + messages = [] + while elapsed_time < AWAIT_MESSAGE_TIMEOUT: + # get the last count messages from message_queue + if api_client.message_queue.qsize() > 0: + message = api_client.message_queue.get() + messages.append(message) + if len(messages) == count: + return messages + time.sleep(0.1) + elapsed_time = time.time() - start + assert False + + +def assert_no_errors(messages): + for message in messages: + assert message["type"] != "error" + + +def assert_error(messages): + for message in messages: + assert message["type"] == "error" + + +def create_client(port): + start = time.time() + elapsed_time = 0 + client = None + while elapsed_time < CONNECT_TIMEOUT: + elapsed_time = time.time() - start + try: + client = Client(host=HOST, port=port) + return client + except ConnectionRefusedError: + time.sleep(0.5) + if not client is None: + return client + return None + + +def remove_db_files(directory): + for file in os.listdir(directory): + if file.endswith(".db"): + os.remove(os.path.join(directory, file)) diff -uNr - - akris/tests/test_address_cast.py akris-genesis/tests/test_address_cast.py --- akris/tests/test_address_cast.py false +++ akris-genesis/tests/test_address_cast.py 118ccfe12155856f8bc244d68eaa4439808c55418aeeef5df18c2332a6f911b5a3ae20370d8c1ff0b39961397faee7bebd6f78918b1ac0f23bbd76937b2ab61a @@ -0,0 +1,88 @@ +import time +import pytest +from helpers import ( + await_messages, + assert_no_errors, + await_message_with_timeout, +) +from helpers import ( + HOST, + PIZARRO_PEST_PORT, + ATAHUALPA_PEST_PORT, + CORTES_PEST_PORT, + P_A_KEY, + P_C_KEY, + C_A_KEY, +) + + +def setup_cortes_station(api_client): + api_client.send_command({"command": "handle", "args": ["cortes"]}) + api_client.send_command({"command": "peer", "args": ["pizarro"]}) + api_client.send_command({"command": "key", "args": ["pizarro", P_C_KEY]}) + api_client.send_command( + {"command": "at", "args": ["pizarro", f"{HOST}:{PIZARRO_PEST_PORT}"]} + ) + api_client.send_command({"command": "peer", "args": ["atahualpa"]}) + api_client.send_command({"command": "key", "args": ["atahualpa", C_A_KEY]}) + api_client.send_command( + {"command": "at", "args": ["atahualpa", f"{HOST}:{ATAHUALPA_PEST_PORT}"]} + ) + + # wait for the setup commands to be processed + await_messages(7, api_client) + + +def setup_atahualpa_station(api_client): + api_client.send_command({"command": "handle", "args": ["atahualpa"]}) + api_client.send_command({"command": "peer", "args": ["pizarro"]}) + api_client.send_command({"command": "key", "args": ["pizarro", P_A_KEY]}) + api_client.send_command( + {"command": "at", "args": ["pizarro", f"{HOST}:{PIZARRO_PEST_PORT}"]} + ) + api_client.send_command({"command": "peer", "args": ["cortes"]}) + api_client.send_command({"command": "key", "args": ["cortes", C_A_KEY]}) + api_client.send_command( + {"command": "at", "args": ["cortes", f"{HOST}:{CORTES_PEST_PORT}"]} + ) + + # wait for the setup commands to be processed + await_messages(7, api_client) + + +def setup_pizarro_station(api_client): + api_client.send_command({"command": "handle", "args": ["pizarro"]}) + api_client.send_command({"command": "peer", "args": ["atahualpa"]}) + api_client.send_command({"command": "key", "args": ["atahualpa", P_A_KEY]}) + api_client.send_command( + {"command": "at", "args": ["atahualpa", f"{HOST}:{ATAHUALPA_PEST_PORT}"]} + ) + api_client.send_command({"command": "peer", "args": ["cortes"]}) + api_client.send_command({"command": "key", "args": ["cortes", P_C_KEY]}) + await_messages(6, api_client) + + +@pytest.mark.usefixtures() +def test_address_cast(pizarro_client, atahualpa_client, cortes_client): + setup_cortes_station(cortes_client) + setup_pizarro_station(pizarro_client) + setup_atahualpa_station(atahualpa_client) + + # disable broadcast on pizarro + pizarro_client.send_command( + {"command": "knob", "args": ["address_cast.interval_seconds", 2]} + ) + pizarro_client.send_command( + {"command": "knob", "args": ["prod.interval_seconds", 2]} + ) + pizarro_client.send_command({"command": "knob", "args": ["cold_peer_seconds", 5]}) + assert_no_errors(await_messages(3, pizarro_client)) + + # wait for the address cast to be triggered and propagated + time.sleep(7) + pizarro_client.send_command({"command": "at", "args": ["cortes"]}) + pizarro_at = await_messages(1, pizarro_client) + cortes_client.send_command({"command": "at", "args": ["pizarro"]}) + cortes_at = await_messages(1, cortes_client) + assert pizarro_at[0]["body"][0]["address"] == f"{HOST}:{CORTES_PEST_PORT}" + assert cortes_at[0]["body"][0]["address"] == f"{HOST}:{PIZARRO_PEST_PORT}" diff -uNr - - akris/tests/test_at_command.py akris-genesis/tests/test_at_command.py --- akris/tests/test_at_command.py false +++ akris-genesis/tests/test_at_command.py 09127ae152e3c92efe90e1de4eb8c48f2e2fdf389db878b8139b86e6e1103c0768a76ceceb774b505eafd2656f8c415cc550120d850a8b6f47d6f488d584515e @@ -0,0 +1,32 @@ +import pytest + +from helpers import ( + await_messages, + assert_no_errors, + assert_error, +) + + +@pytest.mark.usefixtures() +def test_at_command(cortes_client): + cortes_client.send_command({"command": "peer", "args": ["atahualpa"]}) + cortes_client.send_command( + {"command": "at", "args": ["atahualpa", "122.122.0.1:8081"]} + ) + assert_no_errors(await_messages(2, cortes_client)) + cortes_client.send_command({"command": "at", "args": []}) + assert_no_errors(await_messages(1, cortes_client)) + + +@pytest.mark.usefixtures() +def test_duplicate_address(cortes_client): + cortes_client.send_command({"command": "peer", "args": ["atahualpa"]}) + cortes_client.send_command( + {"command": "at", "args": ["atahualpa", "122.122.0.1:8081"]} + ) + cortes_client.send_command({"command": "peer", "args": ["pizarro"]}) + assert_no_errors(await_messages(3, cortes_client)) + cortes_client.send_command( + {"command": "at", "args": ["pizarro", "122.122.0.1:8081"]} + ) + assert_error(await_messages(1, cortes_client)) diff -uNr - - akris/tests/test_broadcast_text.py akris-genesis/tests/test_broadcast_text.py --- akris/tests/test_broadcast_text.py false +++ akris-genesis/tests/test_broadcast_text.py 1c299c02a2c9703e04040e0617d5524735673b9366f2487cd4d7d768b57fa4296893e713444a07c3f80c61b88a740a5bc870fbb46239f6e2a8f9956130507843 @@ -0,0 +1,55 @@ +import pytest +from helpers import ( + assert_no_errors, + await_messages, + await_message_with_timeout, + PIZARRO_PEST_PORT, + HOST, + CORTES_PEST_PORT, + P_C_KEY, +) + + +def configure_pizarro(client): + client.send_command({"command": "handle", "args": ["pizarro"]}) + client.send_command({"command": "peer", "args": ["cortes"]}) + client.send_command({"command": "key", "args": ["cortes", P_C_KEY]}) + client.send_command( + {"command": "at", "args": ["cortes", "{}:{}".format(HOST, CORTES_PEST_PORT)]} + ) + assert_no_errors(await_messages(4, client)) + + +def configure_cortes(client): + client.send_command({"command": "handle", "args": ["cortes"]}) + client.send_command({"command": "peer", "args": ["pizarro"]}) + client.send_command({"command": "key", "args": ["pizarro", P_C_KEY]}) + client.send_command( + { + "command": "at", + "args": ["pizarro", "{}:{}".format(HOST, PIZARRO_PEST_PORT)], + } + ) + assert_no_errors(await_messages(4, client)) + + +@pytest.mark.usefixtures() +def test_broadcast_text(cortes_client, pizarro_client): + configure_pizarro(pizarro_client) + configure_cortes(cortes_client) + + message_body = "conquisto" + cortes_client.send_command({"command": "broadcast_text", "args": [message_body]}) + assert await_message_with_timeout(pizarro_client, message_body) + assert await_message_with_timeout(cortes_client, message_body) + +@pytest.mark.skip(reason="broken") +@pytest.mark.usefixtures() +def test_emoji(cortes_client, pizarro_client): + configure_pizarro(pizarro_client) + configure_cortes(cortes_client) + + message_body = "🔥" + cortes_client.send_command({"command": "broadcast_text", "args": [message_body]}) + assert await_messages(1, pizarro_client) + assert await_messages(1, cortes_client) diff -uNr - - akris/tests/test_broadcast_text_m.py akris-genesis/tests/test_broadcast_text_m.py --- akris/tests/test_broadcast_text_m.py false +++ akris-genesis/tests/test_broadcast_text_m.py e6793978a7950718eb4d52236a9c8416cfc0d0f3677328b7505fa6ea7bfbc608eefefe16335bd7e9c542c3ddbe14ceea5fb1bec02069b40ede0b89cd7bd6a3e9 @@ -0,0 +1,67 @@ +import pytest +from helpers import ( + assert_no_errors, + await_messages, + await_message_with_timeout, + PIZARRO_PEST_PORT, + HOST, + CORTES_PEST_PORT, + P_C_KEY, +) + + +def configure_pizarro(client): + client.send_command({"command": "handle", "args": ["pizarro"]}) + client.send_command({"command": "peer", "args": ["cortes"]}) + client.send_command({"command": "key", "args": ["cortes", P_C_KEY]}) + client.send_command( + {"command": "at", "args": ["cortes", "{}:{}".format(HOST, CORTES_PEST_PORT)]} + ) + assert_no_errors(await_messages(4, client)) + + +def configure_cortes(client): + client.send_command({"command": "handle", "args": ["cortes"]}) + client.send_command({"command": "peer", "args": ["pizarro"]}) + client.send_command({"command": "key", "args": ["pizarro", P_C_KEY]}) + client.send_command( + { + "command": "at", + "args": ["pizarro", "{}:{}".format(HOST, PIZARRO_PEST_PORT)], + } + ) + assert_no_errors(await_messages(4, client)) + + +@pytest.mark.usefixtures() +def test_broadcast_text_m(cortes_client, pizarro_client): + configure_pizarro(pizarro_client) + configure_cortes(cortes_client) + + # when broken apart this currently comes across damaged in some way + + text = """Ἄνδρα μοι ἔννεπε, Μοῦσα, πολύτροπον, ὃς μάλα πολλὰ + πλάγχθη, ἐπεὶ Τροίης ἱερὸν πτολίεθρον ἔπερσεν: + πολλῶν δ᾽ ἀνθρώπων ἴδεν ἄστεα καὶ νόον ἔγνω, + πολλὰ δ᾽ ὅ γ᾽ ἐν πόντῳ πάθεν ἄλγεα ὃν κατὰ θυμόν, + ἀρνύμενος ἥν τε ψυχὴν καὶ νόστον ἑταίρων. + + δέκαῳ δ᾽ έτει μῆνι συνήνετο Ζεύς ἄναξ: ἐλθεῖν δ᾽ Ὀδυσσῆα τόν + γ᾽ ἠπείγοντο θεοὶ πάντες, οὐδ᾽ ἦλθε, δύω δ᾽ ἔτι πόντον ἐλώρια + τεῦχε κύνες οἰωνοῖσί τε πᾶσι, καὶ μένος ἠνείκετο λαῶν.""" + + cortes_client.send_command({"command": "broadcast_text_m", "args": [text]}) + await_messages(3, cortes_client) + await_messages(3, pizarro_client) + +@pytest.mark.skip(reason="broken") +@pytest.mark.usefixtures() +def test_emoji(cortes_client, pizarro_client): + configure_pizarro(pizarro_client) + configure_cortes(cortes_client) + + text = "🔥" + + cortes_client.send_command({"command": "broadcast_text_m", "args": [text]}) + await_messages(1, cortes_client) + await_messages(1, pizarro_client) diff -uNr - - akris/tests/test_direct_text.py akris-genesis/tests/test_direct_text.py --- akris/tests/test_direct_text.py false +++ akris-genesis/tests/test_direct_text.py b60d079ca1f44bde6612bd390d7f65c0a48710faf6043f92f80e58c12de2bdf5a90db7ccfebf6fdb3284a7697ade5f6cc858bd427fe23f4497da73b610f9f252 @@ -0,0 +1,59 @@ +import pytest +from helpers import ( + assert_no_errors, + await_messages, + await_message_with_timeout, + PIZARRO_PEST_PORT, + HOST, + CORTES_PEST_PORT, + P_C_KEY, +) + + +def configure_pizarro(client): + client.send_command({"command": "handle", "args": ["pizarro"]}) + client.send_command({"command": "peer", "args": ["cortes"]}) + client.send_command({"command": "key", "args": ["cortes", P_C_KEY]}) + client.send_command( + {"command": "at", "args": ["cortes", "{}:{}".format(HOST, CORTES_PEST_PORT)]} + ) + assert_no_errors(await_messages(4, client)) + + +def configure_cortes(client): + client.send_command({"command": "handle", "args": ["cortes"]}) + client.send_command({"command": "peer", "args": ["pizarro"]}) + client.send_command({"command": "key", "args": ["pizarro", P_C_KEY]}) + client.send_command( + { + "command": "at", + "args": ["pizarro", "{}:{}".format(HOST, PIZARRO_PEST_PORT)], + } + ) + assert_no_errors(await_messages(4, client)) + + +@pytest.mark.usefixtures() +def test_direct_text(cortes_client, pizarro_client): + configure_pizarro(pizarro_client) + configure_cortes(cortes_client) + + message_body = "conquisto" + cortes_client.send_command( + {"command": "direct_text", "args": ["pizarro", message_body]} + ) + assert await_message_with_timeout(pizarro_client, message_body) + assert await_message_with_timeout(cortes_client, message_body) + +@pytest.mark.skip(reason="broken") +@pytest.mark.usefixtures() +def test_emoji(cortes_client, pizarro_client): + configure_pizarro(pizarro_client) + configure_cortes(cortes_client) + + message_body = "conquisto 🔥" + cortes_client.send_command( + {"command": "direct_text", "args": ["pizarro", message_body]} + ) + await_messages(1, cortes_client) + await_messages(1, pizarro_client) diff -uNr - - akris/tests/test_direct_text_m.py akris-genesis/tests/test_direct_text_m.py --- akris/tests/test_direct_text_m.py false +++ akris-genesis/tests/test_direct_text_m.py 55b7aa055956928417f9bcab245f88d26db7154c874513ba2f4984cb94ff3416b250314494d5e400d574b4d89d5ae04824d6770fe9b60ea8568dd10d267d3d93 @@ -0,0 +1,65 @@ +import pytest +from helpers import ( + assert_no_errors, + await_messages, + await_message_with_timeout, + PIZARRO_PEST_PORT, + HOST, + CORTES_PEST_PORT, + P_C_KEY, +) + + +def configure_pizarro(client): + client.send_command({"command": "handle", "args": ["pizarro"]}) + client.send_command({"command": "peer", "args": ["cortes"]}) + client.send_command({"command": "key", "args": ["cortes", P_C_KEY]}) + client.send_command( + {"command": "at", "args": ["cortes", "{}:{}".format(HOST, CORTES_PEST_PORT)]} + ) + assert_no_errors(await_messages(4, client)) + + +def configure_cortes(client): + client.send_command({"command": "handle", "args": ["cortes"]}) + client.send_command({"command": "peer", "args": ["pizarro"]}) + client.send_command({"command": "key", "args": ["pizarro", P_C_KEY]}) + client.send_command( + { + "command": "at", + "args": ["pizarro", "{}:{}".format(HOST, PIZARRO_PEST_PORT)], + } + ) + assert_no_errors(await_messages(4, client)) + + +@pytest.mark.usefixtures() +def test_direct_text_m(cortes_client, pizarro_client): + configure_pizarro(pizarro_client) + configure_cortes(cortes_client) + + text = """Ἄνδρα μοι ἔννεπε, Μοῦσα, πολύτροπον, ὃς μάλα πολλὰ + πλάγχθη, ἐπεὶ Τροίης ἱερὸν πτολίεθρον ἔπερσεν: + πολλῶν δ᾽ ἀνθρώπων ἴδεν ἄστεα καὶ νόον ἔγνω, + πολλὰ δ᾽ ὅ γ᾽ ἐν πόντῳ πάθεν ἄλγεα ὃν κατὰ θυμόν, + ἀρνύμενος ἥν τε ψυχὴν καὶ νόστον ἑταίρων. + + δέκαῳ δ᾽ έτει μῆνι συνήνετο Ζεύς ἄναξ: ἐλθεῖν δ᾽ Ὀδυσσῆα τόν + γ᾽ ἠπείγοντο θεοὶ πάντες, οὐδ᾽ ἦλθε, δύω δ᾽ ἔτι πόντον ἐλώρια + τεῦχε κύνες οἰωνοῖσί τε πᾶσι, καὶ μένος ἠνείκετο λαῶν.""" + + cortes_client.send_command({"command": "direct_text_m", "args": ["pizarro", text]}) + await_messages(3, cortes_client) + await_messages(3, pizarro_client) + +@pytest.mark.skip(reason="broken") +@pytest.mark.usefixtures() +def test_emoji(cortes_client, pizarro_client): + configure_pizarro(pizarro_client) + configure_cortes(cortes_client) + + text = "🔥" + + cortes_client.send_command({"command": "direct_text_m", "args": ["pizarro", text]}) + await_messages(1, cortes_client) + await_messages(1, pizarro_client) diff -uNr - - akris/tests/test_genkey_command.py akris-genesis/tests/test_genkey_command.py --- akris/tests/test_genkey_command.py false +++ akris-genesis/tests/test_genkey_command.py 0eead259418d5d0c60b3ee276f5671c35ca30b09bcc6583c8772d7f32808e05bb95a3c6bfb618b8ccd53fb6a4aa70b6bac91102c28f5e4fb49740285cc588117 @@ -0,0 +1,8 @@ +import pytest +from helpers import assert_error, assert_no_errors, await_messages, assert_no_errors + + +@pytest.mark.usefixtures() +def test_genkey_command(cortes_client): + cortes_client.send_command({"command": "genkey", "args": []}) + assert_no_errors(await_messages(1, cortes_client)) diff -uNr - - akris/tests/test_handle_command.py akris-genesis/tests/test_handle_command.py --- akris/tests/test_handle_command.py false +++ akris-genesis/tests/test_handle_command.py 401d5b7ea21ad1fc2273a18ff511d6cb981b4d40eacb2a64e6d0edf899944c61b676e474878fac20dec2894023e3cea10c221625e44bb68836c465c87fa3ec60 @@ -0,0 +1,14 @@ +import pytest +from helpers import await_messages, assert_no_errors + + +@pytest.mark.usefixtures() +def test_fetch_handle(cortes_client): + cortes_client.send_command({"command": "handle", "args": []}) + assert_no_errors(await_messages(1, cortes_client)) + + +@pytest.mark.usefixtures() +def test_set_handle(cortes_client): + cortes_client.send_command({"command": "handle", "args": ["pizarro"]}) + assert_no_errors(await_messages(1, cortes_client)) diff -uNr - - akris/tests/test_key_command.py akris-genesis/tests/test_key_command.py --- akris/tests/test_key_command.py false +++ akris-genesis/tests/test_key_command.py 932d0a327abf1f1ce6dae94562a5653890d00ab986e57cf18974ec694f62d8794f801139d07aeef97da8e19077f4680c75afbc6dc7b608563084ce30f5beeff5 @@ -0,0 +1,72 @@ +import pytest +from helpers import await_messages, assert_no_errors, assert_error + + +@pytest.mark.usefixtures() +def test_add_key(cortes_client): + cortes_client.send_command({"command": "peer", "args": ["atahualpa"]}) + cortes_client.send_command( + { + "command": "key", + "args": [ + "atahualpa", + "wQjzT+gDEHilgmFDao7zORJ5PKMjEMWstxMAi/hVTK3coooUA+6+o705LWkAPWFZVLtIjgx2Vh+9Xr5fnPXBfQ==", + ], + } + ) + assert_no_errors(await_messages(2, cortes_client)) + + +@pytest.mark.usefixtures() +def test_duplicate_key(cortes_client): + cortes_client.send_command({"command": "peer", "args": ["atahualpa"]}) + cortes_client.send_command( + { + "command": "key", + "args": [ + "atahualpa", + "wQjzT+gDEHilgmFDao7zORJ5PKMjEMWstxMAi/hVTK3coooUA+6+o705LWkAPWFZVLtIjgx2Vh+9Xr5fnPXBfQ==", + ], + } + ) + assert_no_errors(await_messages(2, cortes_client)) + cortes_client.send_command( + { + "command": "key", + "args": [ + "atahualpa", + "wQjzT+gDEHilgmFDao7zORJ5PKMjEMWstxMAi/hVTK3coooUA+6+o705LWkAPWFZVLtIjgx2Vh+9Xr5fnPXBfQ==", + ], + } + ) + assert_error(await_messages(1, cortes_client)) + + +@pytest.mark.usefixtures() +def test_invalid_key(cortes_client): + cortes_client.send_command({"command": "peer", "args": ["atahualpa"]}) + assert_no_errors(await_messages(1, cortes_client)) + cortes_client.send_command( + { + "command": "key", + "args": [ + "atahualpa", + "4i+KHefkvTVUbeskTh4rGHiKSdDbCSnsSNKpvKHhCZT9yEzRkdVNjQP6KjDzeSM3d4M0RbwNezGcfAGcD5VtQ==", + ], + } + ) + assert_error(await_messages(1, cortes_client)) + + +@pytest.mark.usefixtures() +def test_no_such_peer(cortes_client): + cortes_client.send_command( + { + "command": "key", + "args": [ + "pizarro", + "wQjzT+gDEHilgmFDao7zORJ5PKMjEMWstxMAi/hVTK3coooUA+6+o705LWkAPWFZVLtIjgx2Vh+9Xr5fnPXBfQ==", + ], + } + ) + assert_error(await_messages(1, cortes_client)) diff -uNr - - akris/tests/test_knob_command.py akris-genesis/tests/test_knob_command.py --- akris/tests/test_knob_command.py false +++ akris-genesis/tests/test_knob_command.py 19c03c121c2774fa3bfdafb598b4d82d833b7b1cb896efb292f13b8118d258ed1f46cd76a5221a1733fb8c9b8a1b85cb30f155df9a8f1f4530b0aaee20f5b82b @@ -0,0 +1,20 @@ +import pytest +from helpers import assert_no_errors, await_messages, await_message_with_timeout + + +@pytest.mark.usefixtures() +def test_knobs(cortes_client): + cortes_client.send_command({"command": "knob", "args": []}) + assert_no_errors(await_messages(1, cortes_client)) + + +@pytest.mark.usefixtures() +def test_knob_get(cortes_client): + cortes_client.send_command({"command": "knob", "args": ["max_bounces"]}) + await_message_with_timeout(cortes_client, {"max_bounces": 3}) + + +@pytest.mark.usefixtures() +def test_knob_set(cortes_client): + cortes_client.send_command({"command": "knob", "args": ["max_bounces", "4"]}) + await_message_with_timeout(cortes_client, {"max_bounces": 4}) diff -uNr - - akris/tests/test_message_stats.py akris-genesis/tests/test_message_stats.py --- akris/tests/test_message_stats.py false +++ akris-genesis/tests/test_message_stats.py b03f41748452c024108592b3780d7342d1699d874251e1797dd10a19d621ad71080e320fa2c26912b38621dc6cd8cf059bb8190894ef90bd50b1b3f1f24a5308 @@ -0,0 +1,40 @@ +import time +import pytest +from helpers import ( + assert_no_errors, + await_messages, + await_message_with_timeout, + P_C_KEY, + HOST, + PIZARRO_PEST_PORT, +) + + +def configure_cortes(client): + client.send_command({"command": "handle", "args": ["cortes"]}) + client.send_command({"command": "peer", "args": ["pizarro"]}) + client.send_command({"command": "key", "args": ["pizarro", P_C_KEY]}) + client.send_command( + { + "command": "at", + "args": ["pizarro", "{}:{}".format(HOST, PIZARRO_PEST_PORT)], + } + ) + assert_no_errors(await_messages(3, client)) + + +@pytest.mark.usefixtures() +def test_message_stats(cortes_client): + configure_cortes(cortes_client) + + messages = [f"m{i}" for i in range(0, 2)] + for message in messages: + cortes_client.send_command({"command": "broadcast_text", "args": [message]}) + time.sleep(1) + assert await_message_with_timeout(cortes_client, message) + + cortes_client.send_command({"command": "direct_text", "args": ["pizarro", "m1"]}) + assert await_message_with_timeout(cortes_client, message) + + cortes_client.send_command({"command": "message_stats", "args": []}) + message_stats = await_messages(1, cortes_client) diff -uNr - - akris/tests/test_page.py akris-genesis/tests/test_page.py --- akris/tests/test_page.py false +++ akris-genesis/tests/test_page.py a5486c66810a69c1618c943c0fd082af6123bfcad271f64e2ca340967ccc04cdeebb4c4036e3c18054663f308caa252b8843132e905a7be445a8e9826db084eb @@ -0,0 +1,134 @@ +import time +import pytest +from helpers import ( + assert_no_errors, + await_messages, + await_message_with_timeout, + P_C_KEY, + HOST, + PIZARRO_PEST_PORT, +) + + +def configure_cortes(client): + client.send_command({"command": "handle", "args": ["cortes"]}) + client.send_command({"command": "peer", "args": ["pizarro"]}) + client.send_command({"command": "key", "args": ["pizarro", P_C_KEY]}) + client.send_command( + { + "command": "at", + "args": ["pizarro", "{}:{}".format(HOST, PIZARRO_PEST_PORT)], + } + ) + assert_no_errors(await_messages(3, client)) + + +@pytest.mark.usefixtures() +def test_broadcast_text_page_up(cortes_client): + configure_cortes(cortes_client) + + messages = [f"m{i}" for i in range(0, 10)] + for message in messages: + cortes_client.send_command({"command": "broadcast_text", "args": [message]}) + time.sleep(1) + assert await_message_with_timeout(cortes_client, message) + + cortes_client.send_command({"command": "page_up", "args": [time.time(), 1]}) + page_messages = await_messages(10, cortes_client) + assert page_messages[0]["body"] == messages[0] + assert page_messages[1]["body"] == messages[1] + assert page_messages[2]["body"] == messages[2] + + +@pytest.mark.usefixtures() +def test_broadcast_text_m_page_up(cortes_client): + configure_cortes(cortes_client) + + messages = [f"m{i}" for i in range(0, 10)] + for message in messages: + cortes_client.send_command({"command": "broadcast_text_m", "args": [message]}) + time.sleep(1) + assert await_message_with_timeout(cortes_client, message) + + cortes_client.send_command({"command": "page_up", "args": [time.time(), 1]}) + page_messages = await_messages(10, cortes_client) + assert page_messages[0]["body"] == messages[0] + assert page_messages[1]["body"] == messages[1] + assert page_messages[2]["body"] == messages[2] + + +@pytest.mark.usefixtures() +def test_direct_text_page_up(cortes_client): + configure_cortes(cortes_client) + + messages = [f"m{i}" for i in range(0, 10)] + for message in messages: + cortes_client.send_command( + {"command": "direct_text", "args": ["pizarro", message]} + ) + time.sleep(1) + assert await_message_with_timeout(cortes_client, message) + + cortes_client.send_command({"command": "page_up", "args": [time.time(), 1, "pizarro"]}) + page_messages = await_messages(10, cortes_client) + assert page_messages[0]["body"] == messages[0] + assert page_messages[1]["body"] == messages[1] + assert page_messages[2]["body"] == messages[2] + + +@pytest.mark.usefixtures() +def test_direct_text_m_page_up(cortes_client): + configure_cortes(cortes_client) + + messages = [f"m{i}" for i in range(0, 10)] + for message in messages: + cortes_client.send_command( + {"command": "direct_text_m", "args": ["pizarro", message]} + ) + time.sleep(1) + assert await_message_with_timeout(cortes_client, message) + + cortes_client.send_command({"command": "page_up", "args": [time.time(), 1, "pizarro"]}) + page_messages = await_messages(10, cortes_client) + assert page_messages[0]["body"] == messages[0] + assert page_messages[1]["body"] == messages[1] + assert page_messages[2]["body"] == messages[2] + +@pytest.mark.usefixtures() +def test_broadcast_text_page_down(cortes_client): + configure_cortes(cortes_client) + + now = time.time() + time.sleep(1) + messages = [f"m{i}" for i in range(0, 10)] + for message in messages: + cortes_client.send_command({"command": "broadcast_text", "args": [message]}) + time.sleep(1) + assert await_message_with_timeout(cortes_client, message) + + cortes_client.send_command({"command": "page_down", "args": [now, 1]}) + page_messages = await_messages(10, cortes_client) + assert page_messages[0]["body"] == messages[0] + assert page_messages[1]["body"] == messages[1] + assert page_messages[2]["body"] == messages[2] + + +@pytest.mark.usefixtures() +def test_broadcast_text_page_around(cortes_client): + configure_cortes(cortes_client) + + time.sleep(1) + messages = [f"m{i}" for i in range(0, 10)] + sent_messages = [] + for message in messages: + cortes_client.send_command({"command": "broadcast_text", "args": [message]}) + time.sleep(1) + message = await_message_with_timeout(cortes_client, message) + assert message + sent_messages.append(message) + + cortes_client.send_command({"command": "page_around", "args": [sent_messages[4].get("message_hash")]}) + page_messages = await_messages(10, cortes_client) + assert page_messages[0]["body"] == messages[0] + assert page_messages[1]["body"] == messages[1] + assert page_messages[2]["body"] == messages[2] diff -uNr - - akris/tests/test_peer_command.py akris-genesis/tests/test_peer_command.py --- akris/tests/test_peer_command.py false +++ akris-genesis/tests/test_peer_command.py 0b90dfb3a9698e2ca1d08f6c129e49b5d1cae51420a3bdda7495001daa817785fe87a56d6a136ef7bbddaa911532ac8f5c94a35fa1844b75cc2736dd3b15d2ba @@ -0,0 +1,21 @@ +import pytest +from helpers import ( + assert_error, + await_messages, + assert_no_errors, + await_message_with_timeout, +) + + +@pytest.mark.usefixtures() +def test_peer_command(cortes_client): + cortes_client.send_command({"command": "peer", "args": ["pizarro"]}) + await_message_with_timeout(cortes_client, "Peer added") + + +@pytest.mark.usefixtures() +def test_peer_exists(cortes_client): + cortes_client.send_command({"command": "peer", "args": ["atahualpa"]}) + assert_no_errors(await_messages(1, cortes_client)) + cortes_client.send_command({"command": "peer", "args": ["atahualpa"]}) + assert_error(await_messages(1, cortes_client)) diff -uNr - - akris/tests/test_prod.py akris-genesis/tests/test_prod.py --- akris/tests/test_prod.py false +++ akris-genesis/tests/test_prod.py 4f71244e331e058da269429edb275d84cb908574faf8dc23ef941089a3ca300fd99a5f6e831c962cdb5c91495699b673701d51806d219d7f2fce3063f5099e43 @@ -0,0 +1,66 @@ +import pytest +from helpers import ( + await_messages, + assert_no_errors, + await_message_with_timeout, +) +from helpers import ( + HOST, + PIZARRO_PEST_PORT, + ATAHUALPA_PEST_PORT, + P_A_KEY, +) + + +def setup_atahualpa_station(api_client): + api_client.send_command({"command": "handle", "args": ["atahualpa"]}) + api_client.send_command({"command": "peer", "args": ["pizarro"]}) + api_client.send_command({"command": "key", "args": ["pizarro", P_A_KEY]}) + api_client.send_command( + {"command": "at", "args": ["pizarro", f"{HOST}:{PIZARRO_PEST_PORT}"]} + ) + + # wait for the setup commands to be processed + await_messages(4, api_client) + + +def setup_pizarro_station(api_client): + api_client.send_command({"command": "handle", "args": ["pizarro"]}) + api_client.send_command({"command": "peer", "args": ["atahualpa"]}) + api_client.send_command({"command": "key", "args": ["atahualpa", P_A_KEY]}) + api_client.send_command( + {"command": "at", "args": ["atahualpa", f"{HOST}:{ATAHUALPA_PEST_PORT}"]} + ) + await_messages(4, api_client) + + +@pytest.mark.usefixtures() +def test_prod(pizarro_client, atahualpa_client): + setup_pizarro_station(pizarro_client) + setup_atahualpa_station(atahualpa_client) + + # disable broadcast on pizarro + pizarro_client.send_command( + {"command": "knob", "args": ["testing.disable_broadcast", 1]} + ) + assert_no_errors(await_messages(1, pizarro_client)) + + # create a broadcast message from pizarro to atahualpa + m1 = "m1" + pizarro_client.send_command({"command": "broadcast_text", "args": [m1]}) + assert await_message_with_timeout(pizarro_client, m1) + + # enable broadcast on pizarro + pizarro_client.send_command( + {"command": "knob", "args": ["testing.disable_broadcast", 0]} + ) + assert_no_errors(await_messages(1, pizarro_client)) + + # enable prod on atahualpa + atahualpa_client.send_command( + {"command": "knob", "args": ["prod.interval_seconds", 2]} + ) + assert_no_errors(await_messages(1, atahualpa_client)) + + # await the broadcast message from pizarro to atahualpa via getdata via prod + assert await_message_with_timeout(atahualpa_client, m1) diff -uNr - - akris/tests/test_rekey.py akris-genesis/tests/test_rekey.py --- akris/tests/test_rekey.py false +++ akris-genesis/tests/test_rekey.py b4753432575b79a2255ef8d0746d258e093b2abd797970052d98d42ab029ee1a745a00a72fb728307bebec3da495aaece1121208d58b71fa48d5f84f884252a3 @@ -0,0 +1,54 @@ +import time +import pytest +from helpers import ( + await_messages, + assert_no_errors, + await_message_with_timeout, +) +from helpers import ( + HOST, + PIZARRO_PEST_PORT, + ATAHUALPA_PEST_PORT, + P_A_KEY, +) + + +def setup_atahualpa_station(api_client): + api_client.send_command({"command": "handle", "args": ["atahualpa"]}) + api_client.send_command({"command": "peer", "args": ["pizarro"]}) + api_client.send_command({"command": "key", "args": ["pizarro", P_A_KEY]}) + api_client.send_command( + {"command": "at", "args": ["pizarro", f"{HOST}:{PIZARRO_PEST_PORT}"]} + ) + + # wait for the setup commands to be processed + await_messages(4, api_client) + + +def setup_pizarro_station(api_client): + api_client.send_command({"command": "handle", "args": ["pizarro"]}) + api_client.send_command({"command": "peer", "args": ["atahualpa"]}) + api_client.send_command({"command": "key", "args": ["atahualpa", P_A_KEY]}) + api_client.send_command( + {"command": "at", "args": ["atahualpa", f"{HOST}:{ATAHUALPA_PEST_PORT}"]} + ) + await_messages(4, api_client) + + +@pytest.mark.usefixtures() +def test_rekey(pizarro_client, atahualpa_client): + setup_pizarro_station(pizarro_client) + setup_atahualpa_station(atahualpa_client) + + # disable broadcast on pizarro + pizarro_client.send_command( + {"command": "knob", "args": ["key_offer.interval_seconds", 3600]} + ) + assert_no_errors(await_messages(1, pizarro_client)) + time.sleep(5) + pizarro_client.send_command({"command": "wot", "args": []}) + pizarro_wot = await_messages(1, pizarro_client) + atahualpa_client.send_command({"command": "wot", "args": []}) + atahualpa_wot = await_messages(1, atahualpa_client) + assert len(pizarro_wot[0]["body"][0]["keys"]) == 2 + assert len(atahualpa_wot[0]["body"][0]["keys"]) == 2 diff -uNr - - akris/tests/test_report_presence.py akris-genesis/tests/test_report_presence.py --- akris/tests/test_report_presence.py false +++ akris-genesis/tests/test_report_presence.py 8871959a8fb65a85286e3bec2cd4fd50d4756f5ab7fe32bbff671ab3d526e0b62168b91ca6507e64f6c948185c3e43ed093c99414a01b7c1ad8c908043660cde @@ -0,0 +1,18 @@ +import pytest + +from helpers import ( + await_messages, + assert_no_errors, + assert_error, +) + + +@pytest.mark.usefixtures() +def test_at_command(cortes_client): + cortes_client.send_command({"command": "peer", "args": ["atahualpa"]}) + cortes_client.send_command( + {"command": "at", "args": ["atahualpa", "122.122.0.1:8081"]} + ) + assert_no_errors(await_messages(2, cortes_client)) + cortes_client.send_command({"command": "report_presence", "args": []}) + assert_no_errors(await_messages(1, cortes_client)) \ No newline at end of file diff -uNr - - akris/tests/test_reporting_peers.py akris-genesis/tests/test_reporting_peers.py --- akris/tests/test_reporting_peers.py false +++ akris-genesis/tests/test_reporting_peers.py f94dc77991fca62d64878536e234b9891db62ed27133161cc8150e050d17da279327d1f6bb24afc0c72ea9fe6e674ac592610e5fccf39475775ebc5e5cf551af @@ -0,0 +1,85 @@ +import pytest +from helpers import ( + assert_no_errors, + await_messages, + await_message_with_timeout, + await_message_update_with_timeout, + PIZARRO_PEST_PORT, + HOST, + ATAHUALPA_PEST_PORT, + CORTES_PEST_PORT, + P_C_KEY, + C_A_KEY, + P_A_KEY, +) + + +def configure_pizarro(client): + client.send_command({"command": "handle", "args": ["pizarro"]}) + client.send_command({"command": "peer", "args": ["cortes"]}) + client.send_command({"command": "key", "args": ["cortes", P_C_KEY]}) + client.send_command( + {"command": "at", "args": ["cortes", "{}:{}".format(HOST, CORTES_PEST_PORT)]} + ) + client.send_command({"command": "peer", "args": ["atahualpa"]}) + client.send_command({"command": "key", "args": ["atahualpa", P_A_KEY]}) + client.send_command( + {"command": "at", "args": ["cortes", "{}:{}".format(HOST, ATAHUALPA_PEST_PORT)]} + ) + assert_no_errors(await_messages(7, client)) + + +def configure_cortes(client): + client.send_command({"command": "handle", "args": ["cortes"]}) + client.send_command({"command": "peer", "args": ["pizarro"]}) + client.send_command({"command": "key", "args": ["pizarro", P_C_KEY]}) + client.send_command( + { + "command": "at", + "args": ["pizarro", "{}:{}".format(HOST, PIZARRO_PEST_PORT)], + } + ) + client.send_command({"command": "peer", "args": ["atahualpa"]}) + client.send_command({"command": "key", "args": ["atahualpa", C_A_KEY]}) + client.send_command( + { + "command": "at", + "args": ["atahualpa", "{}:{}".format(HOST, ATAHUALPA_PEST_PORT)], + } + ) + assert_no_errors(await_messages(7, client)) + +def configure_atahualpa(client): + client.send_command({"command": "handle", "args": ["atahualpa"]}) + client.send_command({"command": "peer", "args": ["pizarro"]}) + client.send_command({"command": "key", "args": ["pizarro", P_C_KEY]}) + client.send_command( + { + "command": "at", + "args": ["pizarro", "{}:{}".format(HOST, PIZARRO_PEST_PORT)], + } + ) + client.send_command({"command": "peer", "args": ["cortes"]}) + client.send_command({"command": "key", "args": ["cortes", C_A_KEY]}) + client.send_command( + { + "command": "at", + "args": ["cortes", "{}:{}".format(HOST, CORTES_PEST_PORT)], + } + ) + assert_no_errors(await_messages(7, client)) + + +@pytest.mark.usefixtures() +def test_broadcast_text(atahualpa_client, cortes_client, pizarro_client): + configure_atahualpa(atahualpa_client) + configure_pizarro(pizarro_client) + configure_cortes(cortes_client) + + message_body = "conquisto" + cortes_client.send_command({"command": "broadcast_text", "args": [message_body]}) + assert await_message_with_timeout(pizarro_client, message_body) + update = await_message_update_with_timeout(pizarro_client, message_body) + assert update.get("reporting_peer") == "cortes" + assert await_message_with_timeout(cortes_client, message_body) + assert await_message_with_timeout(atahualpa_client, message_body) diff -uNr - - akris/tests/test_search.py akris-genesis/tests/test_search.py --- akris/tests/test_search.py false +++ akris-genesis/tests/test_search.py 02c22a5e53464e9e1548a0d35b2ae16bf5fec8f8ce091d2b59c054ab228ead54290db160dbc7899bc5f2c739046275966df7c4103b318f52b79ad7cc34382ec3 @@ -0,0 +1,39 @@ +import time +import pytest +from helpers import ( + assert_no_errors, + await_messages, + await_message_with_timeout, + P_C_KEY, + HOST, + PIZARRO_PEST_PORT, +) + + +def configure_cortes(client): + client.send_command({"command": "handle", "args": ["cortes"]}) + client.send_command({"command": "peer", "args": ["pizarro"]}) + client.send_command({"command": "key", "args": ["pizarro", P_C_KEY]}) + client.send_command( + { + "command": "at", + "args": ["pizarro", "{}:{}".format(HOST, PIZARRO_PEST_PORT)], + } + ) + assert_no_errors(await_messages(3, client)) + + +@pytest.mark.usefixtures() +def test_broadcast_text_search(cortes_client): + configure_cortes(cortes_client) + + messages = [f"m{i}" for i in range(0, 2)] + for message in messages: + cortes_client.send_command({"command": "broadcast_text", "args": [message]}) + time.sleep(1) + assert await_message_with_timeout(cortes_client, message) + + cortes_client.send_command({"command": "search", "args": ["m1"]}) + search_results = await_messages(1, cortes_client) + assert search_results[0]["type"] == "search" + diff -uNr - - akris/tests/test_trigger_get_data.py akris-genesis/tests/test_trigger_get_data.py --- akris/tests/test_trigger_get_data.py false +++ akris-genesis/tests/test_trigger_get_data.py d1d026a56f82aa970c2e9126fc05c0fe03dcad2c885f1b20ef9070a3faeae33df7616525743a601241533bd7b0018b60b32451c769f8f63d15b579544bbfe00c @@ -0,0 +1,103 @@ +import pytest +from helpers import ( + await_messages, + assert_no_errors, + await_message_with_timeout, +) +from helpers import ( + HOST, + PIZARRO_PEST_PORT, + CORTES_PEST_PORT, + ATAHUALPA_PEST_PORT, + P_A_KEY, + C_A_KEY, +) + + +def setup_atahualpa_station(api_client): + api_client.send_command({"command": "handle", "args": ["atahualpa"]}) + api_client.send_command({"command": "peer", "args": ["pizarro"]}) + api_client.send_command({"command": "key", "args": ["pizarro", P_A_KEY]}) + api_client.send_command( + {"command": "at", "args": ["pizarro", f"{HOST}:{PIZARRO_PEST_PORT}"]} + ) + api_client.send_command({"command": "peer", "args": ["cortes"]}) + api_client.send_command({"command": "key", "args": ["cortes", C_A_KEY]}) + api_client.send_command( + {"command": "at", "args": ["cortes", f"{HOST}:{CORTES_PEST_PORT}"]} + ) + + # wait for the setup commands to be processed + await_messages(7, api_client) + + +def setup_pizarro_station(api_client): + api_client.send_command({"command": "handle", "args": ["pizarro"]}) + api_client.send_command({"command": "peer", "args": ["atahualpa"]}) + api_client.send_command({"command": "key", "args": ["atahualpa", P_A_KEY]}) + api_client.send_command( + {"command": "at", "args": ["atahualpa", f"{HOST}:{ATAHUALPA_PEST_PORT}"]} + ) + await_messages(4, api_client) + + +def setup_cortes_station(api_client): + api_client.send_command({"command": "handle", "args": ["cortes"]}) + api_client.send_command({"command": "peer", "args": ["atahualpa"]}) + api_client.send_command({"command": "key", "args": ["atahualpa", C_A_KEY]}) + api_client.send_command( + {"command": "at", "args": ["atahualpa", f"{HOST}:{ATAHUALPA_PEST_PORT}"]} + ) + await_messages(3, api_client) + + +# sender: pizarro +# recipient: atahualpa +# 3rd party recipient: cortes +@pytest.mark.usefixtures() +def test_trigger_get_data(atahualpa_client, pizarro_client, cortes_client): + setup_atahualpa_station(atahualpa_client) + setup_pizarro_station(pizarro_client) + setup_cortes_station(cortes_client) + + # create a broadcast message from pizarro to atahualpa + m1 = "m1" + pizarro_client.send_command({"command": "broadcast_text", "args": [m1]}) + assert await_message_with_timeout(pizarro_client, m1) + + # wait for the message to be delivered to atahualpa's client + assert await_message_with_timeout(atahualpa_client, m1) + + # wait for the packet to be received by cortes + assert await_message_with_timeout(cortes_client, m1) + + # disable broadcast on pizarro + pizarro_client.send_command( + {"command": "knob", "args": ["testing.disable_broadcast", 1]} + ) + assert_no_errors(await_messages(1, pizarro_client)) + + # "send" a second message from pizarro to atahualpa (atahualpa shouldn't receive it) + m2 = "m2" + pizarro_client.send_command({"command": "broadcast_text", "args": [m2]}) + assert await_message_with_timeout(pizarro_client, m2) + + # enable broadcast on pizarro + pizarro_client.send_command( + {"command": "knob", "args": ["testing.disable_broadcast", 0]} + ) + assert_no_errors(await_messages(1, pizarro_client)) + + # send a third message from pizarro to atahualpa + m3 = "m3" + pizarro_client.send_command({"command": "broadcast_text", "args": [m3]}) + assert await_message_with_timeout(pizarro_client, m3) + + # wait for the message to be delivered to atahualpa's client + assert await_message_with_timeout(atahualpa_client, m3) + + # wait for the getdata response to be delivered to atahualpa's client + assert await_message_with_timeout(atahualpa_client, m2) + + # wait for the rebroadcast to reach cortes + assert await_message_with_timeout(cortes_client, m2) diff -uNr - - akris/tests/test_unkey_command.py akris-genesis/tests/test_unkey_command.py --- akris/tests/test_unkey_command.py false +++ akris-genesis/tests/test_unkey_command.py 3c28c972f8bb78000828f24754a32f40d21151021026268a7ed8631944a32e5c97a867b12327e5360e735c97adb1819796a0d1edd2b48271321dbff89ca0bd19 @@ -0,0 +1,43 @@ +import pytest +from helpers import assert_no_errors, await_messages, assert_error + + +@pytest.mark.usefixtures() +def test_unkey(cortes_client): + cortes_client.send_command( + { + "command": "peer", + "args": ["pizarro"], + } + ) + cortes_client.send_command( + { + "command": "key", + "args": [ + "pizarro", + "v4i+KHefkvTVUbeskTh4rGHiKSdDbCSnsSNKpvKHhCZT9yEzRkdVNjQP6KjDzeSM3d4M0RbwNezGcfAGcD5VtQ==", + ], + } + ) + assert_no_errors(await_messages(2, cortes_client)) + cortes_client.send_command( + { + "command": "unkey", + "args": [ + "v4i+KHefkvTVUbeskTh4rGHiKSdDbCSnsSNKpvKHhCZT9yEzRkdVNjQP6KjDzeSM3d4M0RbwNezGcfAGcD5VtQ==" + ], + } + ) + assert_no_errors(await_messages(1, cortes_client)) + + +@pytest.mark.usefixtures() +def test_key_not_found(cortes_client): + cortes_client.send_command({"command": "unkey", "args": ["foobar"]}) + assert_error(await_messages(1, cortes_client)) + + +@pytest.mark.usefixtures() +def test_no_args(cortes_client): + cortes_client.send_command({"command": "unkey", "args": []}) + assert_error(await_messages(1, cortes_client)) diff -uNr - - akris/tests/test_unpeer_command.py akris-genesis/tests/test_unpeer_command.py --- akris/tests/test_unpeer_command.py false +++ akris-genesis/tests/test_unpeer_command.py 5dbc696267f21639a59b48d2e638983c15748b5690fcf0fdd64f2dc396d30feb11cb13a8aa5f13294417424717c65b636bd4f2ee6511021b9569d4b930e4f5de @@ -0,0 +1,20 @@ +import pytest +from helpers import assert_no_errors, await_messages, assert_error + + +@pytest.mark.usefixtures() +def test_unpeer_command(cortes_client): + cortes_client.send_command({"command": "peer", "args": ["atahualpa"]}) + cortes_client.send_command( + {"command": "at", "args": ["atahualpa", "122.122.0.1:8081"]} + ) + cortes_client.send_command( + {"command": "unpeer", "args": ["atahualpa"]} + ) + assert_no_errors(await_messages(3, cortes_client)) + + +@pytest.mark.usefixtures() +def test_unpeer_unknown_command(cortes_client): + cortes_client.send_command({"command": "unpeer", "args": ["pizarro"]}) + assert_error(await_messages(1, cortes_client)) diff -uNr - - akris/tests/test_version_info.py akris-genesis/tests/test_version_info.py --- akris/tests/test_version_info.py false +++ akris-genesis/tests/test_version_info.py 0bdeb5a1e0e22006185fe0dcb45fcdb2a760fce2692377c12748070d3015948aa5672d0c0a0231f628b924b485111fc0e770c9e4c6219e754c98425fb94562bb @@ -0,0 +1,13 @@ +import pytest +from helpers import assert_no_errors, await_messages, assert_error + + +@pytest.mark.usefixtures() +def test_version_info(cortes_client): + cortes_client.send_command( + { + "command": "version_info", + "args": [], + } + ) + assert_no_errors(await_messages(1, cortes_client)) diff -uNr - - akris/tests/test_wot_command.py akris-genesis/tests/test_wot_command.py --- akris/tests/test_wot_command.py false +++ akris-genesis/tests/test_wot_command.py e0c375239df20849db7cd080621be8c7f1043c64b6dfe611941ef876c5be4ac1a0f0146a340cc412633e402f4648f99027631415159b4346e5dc7df33ed56871 @@ -0,0 +1,52 @@ +import pytest +from helpers import assert_no_errors, await_messages, assert_error + + +@pytest.mark.usefixtures() +def test_wot(cortes_client): + cortes_client.send_command( + { + "command": "peer", + "args": ["pizarro"], + } + ) + cortes_client.send_command( + { + "command": "key", + "args": [ + "pizarro", + "v4i+KHefkvTVUbeskTh4rGHiKSdDbCSnsSNKpvKHhCZT9yEzRkdVNjQP6KjDzeSM3d4M0RbwNezGcfAGcD5VtQ==", + ], + } + ) + assert_no_errors(await_messages(2, cortes_client)) + cortes_client.send_command({"command": "wot", "args": []}) + assert_no_errors(await_messages(1, cortes_client)) + + +@pytest.mark.usefixtures() +def test_wot_for_peer(cortes_client): + cortes_client.send_command( + { + "command": "peer", + "args": ["pizarro"], + } + ) + cortes_client.send_command( + { + "command": "key", + "args": [ + "pizarro", + "v4i+KHefkvTVUbeskTh4rGHiKSdDbCSnsSNKpvKHhCZT9yEzRkdVNjQP6KjDzeSM3d4M0RbwNezGcfAGcD5VtQ==", + ], + } + ) + assert_no_errors(await_messages(2, cortes_client)) + cortes_client.send_command({"command": "wot", "args": ["pizarro"]}) + assert_no_errors(await_messages(1, cortes_client)) + + +@pytest.mark.usefixtures() +def test_no_such_peer(cortes_client): + cortes_client.send_command({"command": "wot", "args": ["pizarro"]}) + assert_error(await_messages(1, cortes_client))