From 45c2ec0b17256d6bcbb28f49ac5dd65f04fd6da4 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sun, 21 Apr 2019 23:47:00 +0800 Subject: [PATCH] works on K210! --- kernel/Cargo.toml | 1 + kernel/Makefile | 27 +- kernel/src/arch/riscv32/board/k210/linker.ld | 49 ++ .../linker64.ld => board/u540/linker.ld} | 0 kernel/src/arch/riscv32/boot/entry_k210.asm | 30 + kernel/src/arch/riscv32/consts.rs | 6 + kernel/src/arch/riscv32/memory.rs | 2 + kernel/src/arch/riscv32/mod.rs | 5 +- kernel/src/fs/stdio.rs | 9 + kernel/src/memory.rs | 18 +- kernel/src/process/structs.rs | 2 +- tools/k210/kflash.py | 829 ++++++++++++++++++ tools/opensbi/README.md | 6 + tools/opensbi/k210.elf | Bin 0 -> 239264 bytes 14 files changed, 968 insertions(+), 16 deletions(-) create mode 100644 kernel/src/arch/riscv32/board/k210/linker.ld rename kernel/src/arch/riscv32/{boot/linker64.ld => board/u540/linker.ld} (100%) create mode 100644 kernel/src/arch/riscv32/boot/entry_k210.asm create mode 100755 tools/k210/kflash.py create mode 100755 tools/opensbi/k210.elf diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index c4ce68cb..74a7eb41 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -23,6 +23,7 @@ default = ["sv39"] # Page table sv39 or sv48 (for riscv64) sv39 = [] board_u540 = ["sv39", "link_user"] +board_k210 = ["sv39", "link_user"] # (for aarch64 RaspberryPi3) nographic = [] board_raspi3 = ["bcm2837", "link_user"] diff --git a/kernel/Makefile b/kernel/Makefile index af393e3e..f1937d4b 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -23,8 +23,9 @@ # smp = 1 | 2 | ... SMP core number # graphic = on | off Enable/disable qemu graphical output # board = none Running on QEMU -# | pc Only available on x86_64, run on real pc +# | pc Only available on x86_64, run on real pc # | u540 Only available on riscv64, run on HiFive U540, use Sv39 +# | k210 Only available on riscv64, run on K210, use Sv39 # | raspi3 Only available on aarch64, run on Raspberry Pi 3 Model B/B+ # pci_passthru = 0000:00:00.1 Only available on x86_64, passthrough the specified PCI device # init = /bin/ls Only available on riscv64, run specified program instead of user shell @@ -59,7 +60,7 @@ ifeq ($(arch), $(filter $(arch), aarch64 mipsel)) export SFSIMG = $(user_dir)/build/$(arch).img else # board is pc or qemu? -ifeq ($(board), pc) +ifeq ($(board), $(filter $(board), pc u540 k210)) #link user img, so use original image export SFSIMG = $(user_dir)/build/$(arch).img else @@ -201,11 +202,6 @@ features += raspi3_use_generic_timer endif endif -ifeq ($(board), u540) -features += sv39 -riscv_pk_args += --enable-sv39 -endif - ifneq ($(board), none) features += board_$(board) endif @@ -325,6 +321,11 @@ ifeq ($(arch), x86_64) @bootimage build $(build_args) @mv target/x86_64/bootimage.bin $(bootimage) else ifeq ($(arch), $(filter $(arch), riscv32 riscv64)) +ifeq ($(board), k210) + @cp src/arch/riscv32/board/k210/linker.ld src/arch/riscv32/boot/linker64.ld +else + @cp src/arch/riscv32/board/u540/linker.ld src/arch/riscv32/boot/linker64.ld +endif @-patch -p0 -N -b \ $(shell rustc --print sysroot)/lib/rustlib/src/rust/src/libcore/sync/atomic.rs \ src/arch/riscv32/atomic.patch @@ -367,8 +368,16 @@ ifeq ($(board), u540) .PHONY: install: $(kernel_img) @$(objcopy) -S -O binary ../tools/opensbi/fu540.elf $(build_path)/bin - @dd if=$< of=$(build_path)/bin bs=131072 seek=16 - @../tools/u540/mkimg.sh $(build_path)/bin $(build_path)/sd.img + @dd if=$< of=$(build_path)/bin bs=0x20000 seek=16 + @../tools/u540/mkimg.sh $(build_path)/bin $(build_path)/u540.img +endif + +ifeq ($(board), k210) +.PHONY: +install: $(kernel_img) + @$(objcopy) -S -O binary ../tools/opensbi/k210.elf $(build_path)/k210.img + @dd if=$< of=$(build_path)/k210.img bs=0x10000 seek=1 + @python3 ../tools/k210/kflash.py -b 600000 $(build_path)/k210.img endif .PHONY: diff --git a/kernel/src/arch/riscv32/board/k210/linker.ld b/kernel/src/arch/riscv32/board/k210/linker.ld new file mode 100644 index 00000000..7abc05b7 --- /dev/null +++ b/kernel/src/arch/riscv32/board/k210/linker.ld @@ -0,0 +1,49 @@ +/* Copy from bbl-ucore : https://ring00.github.io/bbl-ucore */ + +/* Simple linker script for the ucore kernel. + See the GNU ld 'info' manual ("info ld") to learn the syntax. */ + +OUTPUT_ARCH(riscv) +ENTRY(_start) + +BASE_ADDRESS = 0xffffffffc0010000; + +SECTIONS +{ + /* Load the kernel at this address: "." means the current address */ + . = BASE_ADDRESS; + start = .; + + .text : { + stext = .; + *(.text.entry) + *(.text .text.*) + . = ALIGN(4K); + etext = .; + } + + .rodata : { + srodata = .; + *(.rodata .rodata.*) + . = ALIGN(4K); + erodata = .; + } + + .data : { + sdata = .; + *(.data .data.*) + edata = .; + } + + .stack : { + *(.bss.stack) + } + + .bss : { + sbss = .; + *(.bss .bss.*) + ebss = .; + } + + PROVIDE(end = .); +} diff --git a/kernel/src/arch/riscv32/boot/linker64.ld b/kernel/src/arch/riscv32/board/u540/linker.ld similarity index 100% rename from kernel/src/arch/riscv32/boot/linker64.ld rename to kernel/src/arch/riscv32/board/u540/linker.ld diff --git a/kernel/src/arch/riscv32/boot/entry_k210.asm b/kernel/src/arch/riscv32/boot/entry_k210.asm new file mode 100644 index 00000000..29a65e07 --- /dev/null +++ b/kernel/src/arch/riscv32/boot/entry_k210.asm @@ -0,0 +1,30 @@ + .section .text.entry + .globl _start +_start: + # a0 == hartid + # pc == 0x80010000 + # sp == 0x8000xxxx + + # 1. set sp + # sp = bootstack + (hartid + 1) * 0x10000 + add t0, a0, 1 + slli t0, t0, 14 + lui sp, %hi(bootstack) + add sp, sp, t0 + + # 1.1 set device tree paddr + # OpenSBI give me 0 ??? + li a1, 0x800003b0 + + # 2. jump to rust_main (absolute address) + lui t0, %hi(rust_main) + addi t0, t0, %lo(rust_main) + jr t0 + + .section .bss.stack + .align 12 # page align + .global bootstack +bootstack: + .space 4096 * 4 * 2 + .global bootstacktop +bootstacktop: diff --git a/kernel/src/arch/riscv32/consts.rs b/kernel/src/arch/riscv32/consts.rs index 30420545..01b9f46f 100644 --- a/kernel/src/arch/riscv32/consts.rs +++ b/kernel/src/arch/riscv32/consts.rs @@ -22,10 +22,16 @@ pub const KERNEL_P2_INDEX: usize = (KERNEL_OFFSET >> 12 >> 10) & 0x3ff; #[cfg(target_arch = "riscv64")] pub const KERNEL_P4_INDEX: usize = (KERNEL_OFFSET >> 12 >> 9 >> 9 >> 9) & 0o777; +#[cfg(feature = "board_k210")] +pub const KERNEL_HEAP_SIZE: usize = 0x0020_0000; +#[cfg(not(feature = "board_k210"))] pub const KERNEL_HEAP_SIZE: usize = 0x0080_0000; pub const MEMORY_OFFSET: usize = 0x8000_0000; // TODO: get memory end from device tree +#[cfg(feature = "board_k210")] +pub const MEMORY_END: usize = 0x8060_0000; +#[cfg(not(feature = "board_k210"))] pub const MEMORY_END: usize = 0x8800_0000; // FIXME: rv64 `sh` and `ls` will crash if stack top > 0x80000000 ??? diff --git a/kernel/src/arch/riscv32/memory.rs b/kernel/src/arch/riscv32/memory.rs index af7333b2..ef0509b9 100644 --- a/kernel/src/arch/riscv32/memory.rs +++ b/kernel/src/arch/riscv32/memory.rs @@ -9,6 +9,8 @@ use riscv::{addr::*, register::sstatus}; /// Initialize the memory management module pub fn init(dtb: usize) { // allow user memory access + // NOTE: In K210 priv v1.9.1, sstatus.SUM is PUM which has opposite meaning! + #[cfg(not(feature = "board_k210"))] unsafe { sstatus::set_sum(); } diff --git a/kernel/src/arch/riscv32/mod.rs b/kernel/src/arch/riscv32/mod.rs index 1b30ad30..f05a082d 100644 --- a/kernel/src/arch/riscv32/mod.rs +++ b/kernel/src/arch/riscv32/mod.rs @@ -55,6 +55,7 @@ pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! { // FIXME: init driver on u540 #[cfg(not(feature = "board_u540"))] crate::drivers::init(device_tree_vaddr); + #[cfg(not(feature = "board_k210"))] unsafe { board::enable_serial_interrupt(); board::init_external_interrupt(); @@ -108,6 +109,8 @@ global_asm!( ); #[cfg(target_arch = "riscv32")] global_asm!(include_str!("boot/entry32.asm")); -#[cfg(target_arch = "riscv64")] +#[cfg(all(target_arch = "riscv64", not(feature = "board_k210")))] global_asm!(include_str!("boot/entry64.asm")); +#[cfg(feature = "board_k210")] +global_asm!(include_str!("boot/entry_k210.asm")); global_asm!(include_str!("boot/trap.asm")); diff --git a/kernel/src/fs/stdio.rs b/kernel/src/fs/stdio.rs index 28bb9346..3967e412 100644 --- a/kernel/src/fs/stdio.rs +++ b/kernel/src/fs/stdio.rs @@ -20,6 +20,15 @@ impl Stdin { self.pushed.notify_one(); } pub fn pop(&self) -> char { + #[cfg(feature = "board_k210")] + loop { + // polling + let c = crate::arch::io::getchar(); + if c != '\0' { + return c; + } + } + #[cfg(not(feature = "board_k210"))] loop { let ret = self.buf.lock().pop_front(); match ret { diff --git a/kernel/src/memory.rs b/kernel/src/memory.rs index ee152c9a..3156ff0b 100644 --- a/kernel/src/memory.rs +++ b/kernel/src/memory.rs @@ -16,13 +16,21 @@ pub type MemorySet = rcore_memory::memory_set::MemorySet; #[cfg(target_arch = "x86_64")] pub type FrameAlloc = bitmap_allocator::BitAlloc16M; -// RISCV has 1G memory -#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] +// RISCV, ARM, MIPS has 1G memory +#[cfg(all( + any( + target_arch = "riscv32", + target_arch = "riscv64", + target_arch = "aarch64", + target_arch = "mips" + ), + not(feature = "board_k210") +))] pub type FrameAlloc = bitmap_allocator::BitAlloc1M; -// Raspberry Pi 3 has 1G memory -#[cfg(any(target_arch = "aarch64", target_arch = "mips"))] -pub type FrameAlloc = bitmap_allocator::BitAlloc1M; +// K210 has 8M memory +#[cfg(feature = "board_k210")] +pub type FrameAlloc = bitmap_allocator::BitAlloc4K; lazy_static! { pub static ref FRAME_ALLOCATOR: SpinNoIrqLock = diff --git a/kernel/src/process/structs.rs b/kernel/src/process/structs.rs index c19cbe70..c86751a1 100644 --- a/kernel/src/process/structs.rs +++ b/kernel/src/process/structs.rs @@ -127,7 +127,7 @@ impl Thread { Box::new(Thread { context: Context::null(), // safety: other fields will never be used - .. core::mem::uninitialized() + ..core::mem::uninitialized() }) } diff --git a/tools/k210/kflash.py b/tools/k210/kflash.py new file mode 100755 index 00000000..518c5742 --- /dev/null +++ b/tools/k210/kflash.py @@ -0,0 +1,829 @@ +#!/usr/bin/env python3 +import sys +import time +import zlib +import copy +import struct +from enum import Enum +import binascii +import hashlib +import argparse +import math +import zipfile, tempfile +import json +import re +import os + +BASH_TIPS = dict(NORMAL='\033[0m',BOLD='\033[1m',DIM='\033[2m',UNDERLINE='\033[4m', + DEFAULT='\033[39', RED='\033[31m', YELLOW='\033[33m', GREEN='\033[32m', + BG_DEFAULT='\033[49m', BG_WHITE='\033[107m') + +ERROR_MSG = BASH_TIPS['RED']+BASH_TIPS['BOLD']+'[ERROR]'+BASH_TIPS['NORMAL'] +WARN_MSG = BASH_TIPS['YELLOW']+BASH_TIPS['BOLD']+'[WARN]'+BASH_TIPS['NORMAL'] +INFO_MSG = BASH_TIPS['GREEN']+BASH_TIPS['BOLD']+'[INFO]'+BASH_TIPS['NORMAL'] + +VID_LIST_FOR_AUTO_LOOKUP = "(1A86)|(0403)|(067B)|(10C4)" +# WCH FTDI PL CL +timeout = 0.5 + +MAX_RETRY_TIMES = 10 + +class TimeoutError(Exception): pass + +try: + import serial + import serial.tools.list_ports +except ImportError: + print(ERROR_MSG,'PySerial must be installed, run '+BASH_TIPS['GREEN']+'`pip3 install pyserial`',BASH_TIPS['DEFAULT']) + sys.exit(1) + +# AES is from: https://github.com/ricmoo/pyaes, Copyright by Richard Moore +class AES: + '''Encapsulates the AES block cipher. + You generally should not need this. Use the AESModeOfOperation classes + below instead.''' + @staticmethod + def _compact_word(word): + return (word[0] << 24) | (word[1] << 16) | (word[2] << 8) | word[3] + + # Number of rounds by keysize + number_of_rounds = {16: 10, 24: 12, 32: 14} + + # Round constant words + rcon = [ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ] + + # S-box and Inverse S-box (S is for Substitution) + S = [ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ] + Si =[ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d ] + + # Transformations for encryption + T1 = [ 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a ] + T2 = [ 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616 ] + T3 = [ 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16 ] + T4 = [ 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c ] + + # Transformations for decryption + T5 = [ 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 ] + T6 = [ 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857 ] + T7 = [ 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8 ] + T8 = [ 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0 ] + + # Transformations for decryption key expansion + U1 = [ 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3 ] + U2 = [ 0x00000000, 0x0b0e090d, 0x161c121a, 0x1d121b17, 0x2c382434, 0x27362d39, 0x3a24362e, 0x312a3f23, 0x58704868, 0x537e4165, 0x4e6c5a72, 0x4562537f, 0x74486c5c, 0x7f466551, 0x62547e46, 0x695a774b, 0xb0e090d0, 0xbbee99dd, 0xa6fc82ca, 0xadf28bc7, 0x9cd8b4e4, 0x97d6bde9, 0x8ac4a6fe, 0x81caaff3, 0xe890d8b8, 0xe39ed1b5, 0xfe8ccaa2, 0xf582c3af, 0xc4a8fc8c, 0xcfa6f581, 0xd2b4ee96, 0xd9bae79b, 0x7bdb3bbb, 0x70d532b6, 0x6dc729a1, 0x66c920ac, 0x57e31f8f, 0x5ced1682, 0x41ff0d95, 0x4af10498, 0x23ab73d3, 0x28a57ade, 0x35b761c9, 0x3eb968c4, 0x0f9357e7, 0x049d5eea, 0x198f45fd, 0x12814cf0, 0xcb3bab6b, 0xc035a266, 0xdd27b971, 0xd629b07c, 0xe7038f5f, 0xec0d8652, 0xf11f9d45, 0xfa119448, 0x934be303, 0x9845ea0e, 0x8557f119, 0x8e59f814, 0xbf73c737, 0xb47dce3a, 0xa96fd52d, 0xa261dc20, 0xf6ad766d, 0xfda37f60, 0xe0b16477, 0xebbf6d7a, 0xda955259, 0xd19b5b54, 0xcc894043, 0xc787494e, 0xaedd3e05, 0xa5d33708, 0xb8c12c1f, 0xb3cf2512, 0x82e51a31, 0x89eb133c, 0x94f9082b, 0x9ff70126, 0x464de6bd, 0x4d43efb0, 0x5051f4a7, 0x5b5ffdaa, 0x6a75c289, 0x617bcb84, 0x7c69d093, 0x7767d99e, 0x1e3daed5, 0x1533a7d8, 0x0821bccf, 0x032fb5c2, 0x32058ae1, 0x390b83ec, 0x241998fb, 0x2f1791f6, 0x8d764dd6, 0x867844db, 0x9b6a5fcc, 0x906456c1, 0xa14e69e2, 0xaa4060ef, 0xb7527bf8, 0xbc5c72f5, 0xd50605be, 0xde080cb3, 0xc31a17a4, 0xc8141ea9, 0xf93e218a, 0xf2302887, 0xef223390, 0xe42c3a9d, 0x3d96dd06, 0x3698d40b, 0x2b8acf1c, 0x2084c611, 0x11aef932, 0x1aa0f03f, 0x07b2eb28, 0x0cbce225, 0x65e6956e, 0x6ee89c63, 0x73fa8774, 0x78f48e79, 0x49deb15a, 0x42d0b857, 0x5fc2a340, 0x54ccaa4d, 0xf741ecda, 0xfc4fe5d7, 0xe15dfec0, 0xea53f7cd, 0xdb79c8ee, 0xd077c1e3, 0xcd65daf4, 0xc66bd3f9, 0xaf31a4b2, 0xa43fadbf, 0xb92db6a8, 0xb223bfa5, 0x83098086, 0x8807898b, 0x9515929c, 0x9e1b9b91, 0x47a17c0a, 0x4caf7507, 0x51bd6e10, 0x5ab3671d, 0x6b99583e, 0x60975133, 0x7d854a24, 0x768b4329, 0x1fd13462, 0x14df3d6f, 0x09cd2678, 0x02c32f75, 0x33e91056, 0x38e7195b, 0x25f5024c, 0x2efb0b41, 0x8c9ad761, 0x8794de6c, 0x9a86c57b, 0x9188cc76, 0xa0a2f355, 0xabacfa58, 0xb6bee14f, 0xbdb0e842, 0xd4ea9f09, 0xdfe49604, 0xc2f68d13, 0xc9f8841e, 0xf8d2bb3d, 0xf3dcb230, 0xeecea927, 0xe5c0a02a, 0x3c7a47b1, 0x37744ebc, 0x2a6655ab, 0x21685ca6, 0x10426385, 0x1b4c6a88, 0x065e719f, 0x0d507892, 0x640a0fd9, 0x6f0406d4, 0x72161dc3, 0x791814ce, 0x48322bed, 0x433c22e0, 0x5e2e39f7, 0x552030fa, 0x01ec9ab7, 0x0ae293ba, 0x17f088ad, 0x1cfe81a0, 0x2dd4be83, 0x26dab78e, 0x3bc8ac99, 0x30c6a594, 0x599cd2df, 0x5292dbd2, 0x4f80c0c5, 0x448ec9c8, 0x75a4f6eb, 0x7eaaffe6, 0x63b8e4f1, 0x68b6edfc, 0xb10c0a67, 0xba02036a, 0xa710187d, 0xac1e1170, 0x9d342e53, 0x963a275e, 0x8b283c49, 0x80263544, 0xe97c420f, 0xe2724b02, 0xff605015, 0xf46e5918, 0xc544663b, 0xce4a6f36, 0xd3587421, 0xd8567d2c, 0x7a37a10c, 0x7139a801, 0x6c2bb316, 0x6725ba1b, 0x560f8538, 0x5d018c35, 0x40139722, 0x4b1d9e2f, 0x2247e964, 0x2949e069, 0x345bfb7e, 0x3f55f273, 0x0e7fcd50, 0x0571c45d, 0x1863df4a, 0x136dd647, 0xcad731dc, 0xc1d938d1, 0xdccb23c6, 0xd7c52acb, 0xe6ef15e8, 0xede11ce5, 0xf0f307f2, 0xfbfd0eff, 0x92a779b4, 0x99a970b9, 0x84bb6bae, 0x8fb562a3, 0xbe9f5d80, 0xb591548d, 0xa8834f9a, 0xa38d4697 ] + U3 = [ 0x00000000, 0x0d0b0e09, 0x1a161c12, 0x171d121b, 0x342c3824, 0x3927362d, 0x2e3a2436, 0x23312a3f, 0x68587048, 0x65537e41, 0x724e6c5a, 0x7f456253, 0x5c74486c, 0x517f4665, 0x4662547e, 0x4b695a77, 0xd0b0e090, 0xddbbee99, 0xcaa6fc82, 0xc7adf28b, 0xe49cd8b4, 0xe997d6bd, 0xfe8ac4a6, 0xf381caaf, 0xb8e890d8, 0xb5e39ed1, 0xa2fe8cca, 0xaff582c3, 0x8cc4a8fc, 0x81cfa6f5, 0x96d2b4ee, 0x9bd9bae7, 0xbb7bdb3b, 0xb670d532, 0xa16dc729, 0xac66c920, 0x8f57e31f, 0x825ced16, 0x9541ff0d, 0x984af104, 0xd323ab73, 0xde28a57a, 0xc935b761, 0xc43eb968, 0xe70f9357, 0xea049d5e, 0xfd198f45, 0xf012814c, 0x6bcb3bab, 0x66c035a2, 0x71dd27b9, 0x7cd629b0, 0x5fe7038f, 0x52ec0d86, 0x45f11f9d, 0x48fa1194, 0x03934be3, 0x0e9845ea, 0x198557f1, 0x148e59f8, 0x37bf73c7, 0x3ab47dce, 0x2da96fd5, 0x20a261dc, 0x6df6ad76, 0x60fda37f, 0x77e0b164, 0x7aebbf6d, 0x59da9552, 0x54d19b5b, 0x43cc8940, 0x4ec78749, 0x05aedd3e, 0x08a5d337, 0x1fb8c12c, 0x12b3cf25, 0x3182e51a, 0x3c89eb13, 0x2b94f908, 0x269ff701, 0xbd464de6, 0xb04d43ef, 0xa75051f4, 0xaa5b5ffd, 0x896a75c2, 0x84617bcb, 0x937c69d0, 0x9e7767d9, 0xd51e3dae, 0xd81533a7, 0xcf0821bc, 0xc2032fb5, 0xe132058a, 0xec390b83, 0xfb241998, 0xf62f1791, 0xd68d764d, 0xdb867844, 0xcc9b6a5f, 0xc1906456, 0xe2a14e69, 0xefaa4060, 0xf8b7527b, 0xf5bc5c72, 0xbed50605, 0xb3de080c, 0xa4c31a17, 0xa9c8141e, 0x8af93e21, 0x87f23028, 0x90ef2233, 0x9de42c3a, 0x063d96dd, 0x0b3698d4, 0x1c2b8acf, 0x112084c6, 0x3211aef9, 0x3f1aa0f0, 0x2807b2eb, 0x250cbce2, 0x6e65e695, 0x636ee89c, 0x7473fa87, 0x7978f48e, 0x5a49deb1, 0x5742d0b8, 0x405fc2a3, 0x4d54ccaa, 0xdaf741ec, 0xd7fc4fe5, 0xc0e15dfe, 0xcdea53f7, 0xeedb79c8, 0xe3d077c1, 0xf4cd65da, 0xf9c66bd3, 0xb2af31a4, 0xbfa43fad, 0xa8b92db6, 0xa5b223bf, 0x86830980, 0x8b880789, 0x9c951592, 0x919e1b9b, 0x0a47a17c, 0x074caf75, 0x1051bd6e, 0x1d5ab367, 0x3e6b9958, 0x33609751, 0x247d854a, 0x29768b43, 0x621fd134, 0x6f14df3d, 0x7809cd26, 0x7502c32f, 0x5633e910, 0x5b38e719, 0x4c25f502, 0x412efb0b, 0x618c9ad7, 0x6c8794de, 0x7b9a86c5, 0x769188cc, 0x55a0a2f3, 0x58abacfa, 0x4fb6bee1, 0x42bdb0e8, 0x09d4ea9f, 0x04dfe496, 0x13c2f68d, 0x1ec9f884, 0x3df8d2bb, 0x30f3dcb2, 0x27eecea9, 0x2ae5c0a0, 0xb13c7a47, 0xbc37744e, 0xab2a6655, 0xa621685c, 0x85104263, 0x881b4c6a, 0x9f065e71, 0x920d5078, 0xd9640a0f, 0xd46f0406, 0xc372161d, 0xce791814, 0xed48322b, 0xe0433c22, 0xf75e2e39, 0xfa552030, 0xb701ec9a, 0xba0ae293, 0xad17f088, 0xa01cfe81, 0x832dd4be, 0x8e26dab7, 0x993bc8ac, 0x9430c6a5, 0xdf599cd2, 0xd25292db, 0xc54f80c0, 0xc8448ec9, 0xeb75a4f6, 0xe67eaaff, 0xf163b8e4, 0xfc68b6ed, 0x67b10c0a, 0x6aba0203, 0x7da71018, 0x70ac1e11, 0x539d342e, 0x5e963a27, 0x498b283c, 0x44802635, 0x0fe97c42, 0x02e2724b, 0x15ff6050, 0x18f46e59, 0x3bc54466, 0x36ce4a6f, 0x21d35874, 0x2cd8567d, 0x0c7a37a1, 0x017139a8, 0x166c2bb3, 0x1b6725ba, 0x38560f85, 0x355d018c, 0x22401397, 0x2f4b1d9e, 0x642247e9, 0x692949e0, 0x7e345bfb, 0x733f55f2, 0x500e7fcd, 0x5d0571c4, 0x4a1863df, 0x47136dd6, 0xdccad731, 0xd1c1d938, 0xc6dccb23, 0xcbd7c52a, 0xe8e6ef15, 0xe5ede11c, 0xf2f0f307, 0xfffbfd0e, 0xb492a779, 0xb999a970, 0xae84bb6b, 0xa38fb562, 0x80be9f5d, 0x8db59154, 0x9aa8834f, 0x97a38d46 ] + U4 = [ 0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12, 0x24342c38, 0x2d392736, 0x362e3a24, 0x3f23312a, 0x48685870, 0x4165537e, 0x5a724e6c, 0x537f4562, 0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a, 0x90d0b0e0, 0x99ddbbee, 0x82caa6fc, 0x8bc7adf2, 0xb4e49cd8, 0xbde997d6, 0xa6fe8ac4, 0xaff381ca, 0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582, 0xfc8cc4a8, 0xf581cfa6, 0xee96d2b4, 0xe79bd9ba, 0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9, 0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1, 0x73d323ab, 0x7ade28a5, 0x61c935b7, 0x68c43eb9, 0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281, 0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629, 0x8f5fe703, 0x8652ec0d, 0x9d45f11f, 0x9448fa11, 0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59, 0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261, 0x766df6ad, 0x7f60fda3, 0x6477e0b1, 0x6d7aebbf, 0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787, 0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf, 0x1a3182e5, 0x133c89eb, 0x082b94f9, 0x01269ff7, 0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f, 0xc2896a75, 0xcb84617b, 0xd0937c69, 0xd99e7767, 0xaed51e3d, 0xa7d81533, 0xbccf0821, 0xb5c2032f, 0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17, 0x4dd68d76, 0x44db8678, 0x5fcc9b6a, 0x56c19064, 0x69e2a14e, 0x60efaa40, 0x7bf8b752, 0x72f5bc5c, 0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814, 0x218af93e, 0x2887f230, 0x3390ef22, 0x3a9de42c, 0xdd063d96, 0xd40b3698, 0xcf1c2b8a, 0xc6112084, 0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc, 0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4, 0xb15a49de, 0xb85742d0, 0xa3405fc2, 0xaa4d54cc, 0xecdaf741, 0xe5d7fc4f, 0xfec0e15d, 0xf7cdea53, 0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b, 0xa4b2af31, 0xadbfa43f, 0xb6a8b92d, 0xbfa5b223, 0x80868309, 0x898b8807, 0x929c9515, 0x9b919e1b, 0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3, 0x583e6b99, 0x51336097, 0x4a247d85, 0x4329768b, 0x34621fd1, 0x3d6f14df, 0x267809cd, 0x2f7502c3, 0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb, 0xd7618c9a, 0xde6c8794, 0xc57b9a86, 0xcc769188, 0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0, 0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8, 0xbb3df8d2, 0xb230f3dc, 0xa927eece, 0xa02ae5c0, 0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168, 0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50, 0x0fd9640a, 0x06d46f04, 0x1dc37216, 0x14ce7918, 0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520, 0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe, 0xbe832dd4, 0xb78e26da, 0xac993bc8, 0xa59430c6, 0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e, 0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6, 0x0a67b10c, 0x036aba02, 0x187da710, 0x1170ac1e, 0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026, 0x420fe97c, 0x4b02e272, 0x5015ff60, 0x5918f46e, 0x663bc544, 0x6f36ce4a, 0x7421d358, 0x7d2cd856, 0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725, 0x8538560f, 0x8c355d01, 0x97224013, 0x9e2f4b1d, 0xe9642247, 0xe0692949, 0xfb7e345b, 0xf2733f55, 0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d, 0x31dccad7, 0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5, 0x15e8e6ef, 0x1ce5ede1, 0x07f2f0f3, 0x0efffbfd, 0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5, 0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d ] + + def __init__(self, key): + + if len(key) not in (16, 24, 32): + raise ValueError('Invalid key size') + + rounds = self.number_of_rounds[len(key)] + + # Encryption round keys + self._Ke = [[0] * 4 for i in range(rounds + 1)] + + # Decryption round keys + self._Kd = [[0] * 4 for i in range(rounds + 1)] + + round_key_count = (rounds + 1) * 4 + KC = len(key) // 4 + + # Convert the key into ints + tk = [ struct.unpack('>i', key[i:i + 4])[0] for i in range(0, len(key), 4) ] + + # Copy values into round key arrays + for i in range(0, KC): + self._Ke[i // 4][i % 4] = tk[i] + self._Kd[rounds - (i // 4)][i % 4] = tk[i] + + # Key expansion (fips-197 section 5.2) + rconpointer = 0 + t = KC + while t < round_key_count: + + tt = tk[KC - 1] + tk[0] ^= ((self.S[(tt >> 16) & 0xFF] << 24) ^ + (self.S[(tt >> 8) & 0xFF] << 16) ^ + (self.S[ tt & 0xFF] << 8) ^ + self.S[(tt >> 24) & 0xFF] ^ + (self.rcon[rconpointer] << 24)) + rconpointer += 1 + + if KC != 8: + for i in range(1, KC): + tk[i] ^= tk[i - 1] + + # Key expansion for 256-bit keys is "slightly different" (fips-197) + else: + for i in range(1, KC // 2): + tk[i] ^= tk[i - 1] + tt = tk[KC // 2 - 1] + + tk[KC // 2] ^= (self.S[ tt & 0xFF] ^ + (self.S[(tt >> 8) & 0xFF] << 8) ^ + (self.S[(tt >> 16) & 0xFF] << 16) ^ + (self.S[(tt >> 24) & 0xFF] << 24)) + + for i in range(KC // 2 + 1, KC): + tk[i] ^= tk[i - 1] + + # Copy values into round key arrays + j = 0 + while j < KC and t < round_key_count: + self._Ke[t // 4][t % 4] = tk[j] + self._Kd[rounds - (t // 4)][t % 4] = tk[j] + j += 1 + t += 1 + + # Inverse-Cipher-ify the decryption round key (fips-197 section 5.3) + for r in range(1, rounds): + for j in range(0, 4): + tt = self._Kd[r][j] + self._Kd[r][j] = (self.U1[(tt >> 24) & 0xFF] ^ + self.U2[(tt >> 16) & 0xFF] ^ + self.U3[(tt >> 8) & 0xFF] ^ + self.U4[ tt & 0xFF]) + + def encrypt(self, plaintext): + 'Encrypt a block of plain text using the AES block cipher.' + + if len(plaintext) != 16: + raise ValueError('wrong block length') + + rounds = len(self._Ke) - 1 + (s1, s2, s3) = [1, 2, 3] + a = [0, 0, 0, 0] + + # Convert plaintext to (ints ^ key) + t = [(AES._compact_word(plaintext[4 * i:4 * i + 4]) ^ self._Ke[0][i]) for i in range(0, 4)] + + # Apply round transforms + for r in range(1, rounds): + for i in range(0, 4): + a[i] = (self.T1[(t[ i ] >> 24) & 0xFF] ^ + self.T2[(t[(i + s1) % 4] >> 16) & 0xFF] ^ + self.T3[(t[(i + s2) % 4] >> 8) & 0xFF] ^ + self.T4[ t[(i + s3) % 4] & 0xFF] ^ + self._Ke[r][i]) + t = copy.copy(a) + + # The last round is special + result = [ ] + for i in range(0, 4): + tt = self._Ke[rounds][i] + result.append((self.S[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF) + result.append((self.S[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF) + result.append((self.S[(t[(i + s2) % 4] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF) + result.append((self.S[ t[(i + s3) % 4] & 0xFF] ^ tt ) & 0xFF) + + return result + + def decrypt(self, ciphertext): + 'Decrypt a block of cipher text using the AES block cipher.' + + if len(ciphertext) != 16: + raise ValueError('wrong block length') + + rounds = len(self._Kd) - 1 + (s1, s2, s3) = [3, 2, 1] + a = [0, 0, 0, 0] + + # Convert ciphertext to (ints ^ key) + t = [(AES._compact_word(ciphertext[4 * i:4 * i + 4]) ^ self._Kd[0][i]) for i in range(0, 4)] + + # Apply round transforms + for r in range(1, rounds): + for i in range(0, 4): + a[i] = (self.T5[(t[ i ] >> 24) & 0xFF] ^ + self.T6[(t[(i + s1) % 4] >> 16) & 0xFF] ^ + self.T7[(t[(i + s2) % 4] >> 8) & 0xFF] ^ + self.T8[ t[(i + s3) % 4] & 0xFF] ^ + self._Kd[r][i]) + t = copy.copy(a) + + # The last round is special + result = [ ] + for i in range(0, 4): + tt = self._Kd[rounds][i] + result.append((self.Si[(t[ i ] >> 24) & 0xFF] ^ (tt >> 24)) & 0xFF) + result.append((self.Si[(t[(i + s1) % 4] >> 16) & 0xFF] ^ (tt >> 16)) & 0xFF) + result.append((self.Si[(t[(i + s2) % 4] >> 8) & 0xFF] ^ (tt >> 8)) & 0xFF) + result.append((self.Si[ t[(i + s3) % 4] & 0xFF] ^ tt ) & 0xFF) + + return result + +class AES_128_CBC: + + def __init__(self, key, iv = None): + self._aes = AES(key) + if iv is None: + self._last_cipherblock = [ 0 ] * 16 + elif len(iv) != 16: + raise ValueError('initialization vector must be 16 bytes') + else: + self._last_cipherblock = iv + + + def encrypt(self, plaintext): + if len(plaintext) != 16: + raise ValueError('plaintext block must be 16 bytes') + + precipherblock = [ (p ^ l) for (p, l) in zip(plaintext, self._last_cipherblock) ] + self._last_cipherblock = self._aes.encrypt(precipherblock) + + return b''.join(map(lambda x: x.to_bytes(1, 'little'), self._last_cipherblock)) + + def decrypt(self, ciphertext): + if len(ciphertext) != 16: + raise ValueError('ciphertext block must be 16 bytes') + + cipherblock = ciphertext + plaintext = [ (p ^ l) for (p, l) in zip(self._aes.decrypt(cipherblock), self._last_cipherblock) ] + self._last_cipherblock = cipherblock + + return b''.join(map(lambda x: x.to_bytes(1, 'little'), plaintext)) + + +ISP_PROG = '789cedbc0d5854d7d53fbacff7805fe85106039189a390d8d4a283420231632aa226cd4b93a8499b54c801d104150543d2c6b7e0308ca84930471d0cf4959808896d53d351c7d6a4682b62faf1d67c28499a467480d168024460d40073d7dae70c1f2726b7efff7f9fe7defb7f8acfcf357b9dfdb1f6da7bafbdf63efbec35a498b4ffe1d79f16642424146458007644a29b2544ddc88e2aa87820412584c80c840132f20132071420f34001b20014208b4001b20414209b8002e430a000391c28401e0114208f040a90470105c8a38102e431400157264724282758c8dff28335194773dddb805fc25c30bf88b2ace3e5756c6fc1547ba72a5888927f90c89113181bfb4790770291c78e656ccc5cb2c61ec1c90cd36c4d1c4bacc9b7106bea0c624d98cb5a137fc85a93b3586bea5ad69a50c25b13b7f1d6e497796bea9bbc35e198684d7c57b4269f13ada99da235810983f461903e0cd28741fa11907e04a41f01e94740fa51907e14a41f05e94741fa31907e0ca41f03e9c7c4273011f1896323e2936f89884f9d11119f30775c7ce20fc7c527678d8b4f5d3b2e3ea1647c7ce2b6f1f1c92f8f8f4f7d737c7cc2b1c8f8c47723e393cf45c6a7764642fa89907e22a49f08e92742fa68481f0de9a3217d34a4bf19d2df0ce96f86f43743fa58481f0be963217d6cc1544be295a91189b2c840fb3011ca1281b4db33c6aec1f6cfa8985a103121d1915042b8190ce39851c2703319d631b384e56c0ce7b095705c22c33b124b786e162338669508dc6c4674cc2e11b92446722495485c326372249798b83b9830c71d2561dc9d4cb8e3ce92702e8519e1482919c1a532231da92523b9bb98518ebb4a46717398d18e3925a3b9bb99318ebb4bc648a01f57424984348319eb9a5132569ac98c73cd2c1927d918d9652b91a54466bc2bb164bc348b99e09a5532419acd44ba6697444a498cd99554629692992857724994740733d17547c944e94ee626d79d253749294cb42ba5245a4a65625ca92531d25dcccdaebb4a6e96e630935c734a26497733b1aebb4b62a17f580a8825016810fbc995387ba7db057dcd953ecfe1954892180c72752ec656d4489222b19f47feb72db791587fe527c02772ae99585fc5df8ddaef5af85deb2249d2b5a02c0582b6a7dae07923f01a89ada84d7b5e97ced0b8fb42bfe3f5df122317f983d6d7f4dfc887dfb21441948a3656162248bba5e2a12bb9f3120a4846c495787ba21a7011df66a9bf9d9cda80ed88e311eac2e4161362de4408b7e0e41db2944f52cc12a3d5abf14e37f01d274fde299b1208d631252a8ab1e54a4cb424116b8d9f44bb7a82d63d5ab9583759ea1853e5ec0eaadddd6394ca569ef2412ec7de74b6ca29407c81285d87808a600b4492e26cb02b79adac3a4162d5d3027ba4accd6e130f115fa5d86b7d0dca7855a272a28cdc02017e4f807225694dc7d96bdc5e49549d13c82b2feced5fd3b1fb2bad0e9bbe1baa836a8a207afb4cd79e2d984eeb50691a5607ebab666698dcdb5b45c75e8905fbc41e11bc76f946323fd1ca0f9519eb8972d3361008abbc28f2aa68c77667e5a2a5c417d3d4ffedf5597615ebc2357407ad357522d60f65c032534c07ed4ae187245a3269e56f429d5d20a1f2b15c9401d268799cc43c30cfdd7dd0befdaa9409e5946836176d2ff40d6b2ad839be93b4779cbd0c7d81d1fb028b72693a93a25157d1d2f0f675c409206f93e8884ba394b66d2db46d9948f5a3149e8134a0a73201f474c8ae6443db46829c674436456cb37b9ca7892fea066d8b6d5916096d598b6dd90bb2f45953b7c1fcd0115479d4d32906ec27d8e3b1ac757c273167e3bc72bcb33d2183515ee42364219fb427146f90850ea011da3c2354e0ef3055380abf8b713c3c0e756728df722a4b15ecc0af81df11f03b037eef87df1999aa80fa3a8af197a9902f948df17fe248e289197463bd336082798ba1bff980a84ac51a9f457ec6005fd3a34b443dca9285b6018e5d6badc486eaef96a8aea3689a990116db48e335fe4c6b2b8b96777200da2af63d682b16ec2c0b7636d4661cea8fd623a17815cc814c7b02c9d7ea0f754820cf38924a3599e6047a5126eb66e9ba2ad568f99a02bdd03f18e83b5d5a5f19ec1b56e14df20aff32f6917f0cef3f09c05bf68eb1df607a6b32c4934097d86622da189c4b2206fb1cc13eb7ec778e74cdfe584917c17ca04ecc0df2e1be3d9fb307feeff291854e1a1fcaece1d23a691c79fd84a132f7a9d036d6919da46aa9c0bc42a993d07e46fbdb9be0071c23d6519de49551a88bd8bfc0dc461cb3196c4f46867e8efd08f23f2cf31128d3d5684120be91cefe505b0d6b27bd6e982fd68de64de5dbdd80365bb753e7b06db8f4749f2ae693233b4526c5dc4a6cb94d217b764e8fd7ac8a166a97310e3e0fd934592abe05fada68ebab75d8f738e089d61a970873050bf332b6259be26cb3635d70bc2a850d4085c1719bd92a0e1db738fe71ec0ed8b7a86fb16f540fcb2e0cd183d62e43fa0a8e75aea147b775b1d750ae23622bd85a830dd97448b375ba2c2803ca0369aed23c4ef6186c1d61b1efd2b6e4f5b6c4fe02fde01581b6df6f86f7656cbbddd537eacb909738682777ffd2684321af5d374a37d8e776bfef48ef2472209e281120bf3f1e74778ebc22d131f03707f4472eed1cc63ba98d79d7a7981f1d97a981a3ba1d48d1c7ff5143395f69fee80c0efc4cce9afa4306fc4cc69ab8163016fcd36de0b7dec2a961307e360378117dea08f0a959f716c877cb9623ca4d3c0be5f1badfc6815fc6815fc6825fc6825fc6805fc6805f16f21304da6e816b638eb8aec37cd405e3932755a5309ff25d76b99c8776ab421f9e757847807ec289ec0c23d16218f1174b443587b16a13b471e994b947c2ee606ce1d7896f27df0b762700795fb726cfe5e49744f4b7a13e591c8c1146fed1678cf951f4ffffba30e93b847817a11ea0ce09b708e05f439da1aea963a94f4eed4439f4df30a8e71691d8c23733d123a227576dde7c8b521d86f514a09e02f54fef80fade01f5bd13ea7b27d43705ea9b02f54d1de8a322ad2bf4a5aad23098fb931858bfb068d794e622c1111f4e3c2e17f84d502f298168fd8dd7fb5ba9ded7a0af94f1d057c28836cf94403bfffda2eae6a91e52f8edc416768d1c29df857db94795f6df301f9cff302fabd83924bf0c0269be82349c754a6768beae711c928866371a77a34d3be2f613731984e7cfafd67ca246e2f1877865d538a6433c6b5c09a972a1ede881396ac91819ca5285305dee3141185f5d50de082cafca0cb2c585ca75550e969b5e39bcdc13dbbf5eaeb86368b9a13261de996cddd7331acab90ae58883f572bdc81dd2e64f0c3b1aa517dd4ea00dc20bd4369a0360fb0e415e601b217fc709f1851473d3f03a59a04ed3968c81bef625e43dfaeb7548df3abc8cc62d5a190d9b6e5cc6894da13206f35f8ef95fc6390adae67d55c436dafd1eea4596d2373a664b74aef1d2b1bd0dd798304e67301ea97b60aee17ee7228e3a91417f470d83be156802ffbe878e3f47dd7ca6aac90c3c33515e944c49a568838e331ee701d24eec2baac0762b7f95448fab146d3253259a896c061f7629f81abf6a2236e922cc9175e0abb9982433ca2431ca534de8d78d86b981e5bc615a39f1e037839db2de1a20437d0d18330c8c9981798cdb3b9fc8ebbba1cebb7b64a939e8abf0f7d2b20fc17a269dd619faeb3c6273b51065d219623d0ceba0037e82f5f7b8ba604d2411f457ad87a19d0e34a1aefa75ff6314b5b93847829f87e3ba9d1cbd1ffd20da1789fd0159e091575825a05f88bfc90fdb49f17dc6f9dfbbb43612da273fe5741deb2ea2b674250773a517d6698e7817e309c07c297407e50902272f16385b6b1db1de5e47fd514723f8d18dd00ed021b476f67fa9ee943898833819edc0134db79a97623d5d8cea8e833a811f5ca7b531f51b06da18da16db199eab6083e55290196c32da0eae610794e3a4beb53cc1496c39dd10de0b654a0ccae2683c88e5331e7f1ded67ca5301b437fdb01e1f297707c6803df91b9d83e2c126609b59aea1cdc2e7e18e78901de61ddf26a917e61ab5bde33fdae97c1c23807f7db66fc8f3eb8ec6c5d0a7d3a0be0d7a7d9b209c43e4322751c1aff0f87b20bc1e7e97319e36f8dd789aa0bf1fd20dd7d88a7d8df1e406e07737f13a0f7fae3a8599b219d6c2c08b965cd48e295130073606824a710ff8cc96fe578abbbebd8fa589c4d358477df7e80fb5be7f44eab07b02ddc087f51bb41deac5374ee887b536941308d27553fa76c22d2cd5e58b67b885af12796218c8770df807e07739635b798d448781decc0b39a554d264005986ca615e8c3eb4d08af2c0faec4c527730685bff3ad8c317aea96138ff8ff958f37166051de91f806d3b0e639267b472611d3fbf05d2c3b88a041de6f640b80b7e9731b6e53d302f8ae82b3ac056b472a04f07e81ef445505f0ed027ed03a05b07e853eb039aad91253b51cafc682fa11d632f737b0506fc877761fc34a3ce921cc120c87b0dfa9d08fd10fc17dcaf82f9327186a0d7e7231b9385e3e76e6f39f65f86492a0d06555718a7f5d1d23e4fa99b24e133b19ca5eb08278eb1e269aa0863cb15c6d8a426184bf374fd384f5b130298df9dda1873d9d01f45ff08fc5956dba768fada3e45bbe5681c3e6fb7905b70ae71e3dea0d3f96b8d7734de0b360aea5b7ca52e3de14a2e9fa09595f62e8cff44943924afc7153fd79a08732384659eef439e1c66e9b395baa8ad0179188c4fc7e74118431582a8f3d9d098f56d957a43bc81b8c82f967ab9a412a2d91e9ebc026b256abf4df17d43e382ff89766914fab10eb019980675268b3c5d5fbd62c231187bc4ebd2f48d32515debf95af7d3f461d41712c8c83509c5df0ded31c91219a94c6ac5b5e92858cbdd0e6bba5174ef8661983509e43bb2b47f942faab5bf3dc13e0dd6a920c3b27e7587c0525b7a5a60b5b5c636ea8fa22df5f0078912b37d60ad04fd7dc0a7e4d240667e3cfaa657d146d0b50adae2c497619df2265d43396631849b853e018c33f47d212d5d3b829c8e3a9883c6b5b24a25fa45b04eabe9266b889db5d680ad813942764ad4b6d23daacd507f58bb281b9b58b40d2877955960b03e554dd25cdf4dadbde84b40dee0e71c1da544c13c59d38af66d24eef5a8e2a95198ce1779fabac6df8ffabf7ed7f7a7b994b57f62d5a20039e67bfb9cfa9418bc6bf3ef778ef48df4cf957cab9afac79edf58ec11ff64df2ce2fef5ce9db9c5b5c42a79c92ba217bc2ca00250c02b3c50c02b1c50c02b2c50c02b0c50c02b0428606331ee19a93b9de4f473ea4e81a1ffb3a79f7bc4abee8c275a19651bfdc571d777161f33dffcc29c9dbeb57fbafa0befcd6bf75c98563add39bda5ec723b6996dcb9d803eb3affd0ec4cff434b4cd49e9c3997cbd3e79c4a5d30ad5710a65f9dd63572c536ff6488df4e2cf29e1c871bb4e58ee7941f48a47c3957d7107efa056b6537b956d467bef682b5b63b3cc134d909394fee5b3af6dcebe96d99f3b3e738a7666d2cd6c769cf3ee726654d477d609fcb2971609757056dce3afb86091b8b99348835014764dae435a4e6c1b96327378b2dd34aad510789756203f40658b92602e284706b2a500bf4b429027bcbfc923418a5e1ed1df57eb7997a567d31bdda2f89a4366bbf5c7c6a8bf62b572257532fecc964b3e7325aa9ccd8b816585f8da82aed0e7a4a8fb38b9aa7974fbe205e569da523a12e3f9c56cafc8d963e652a9325982e80ed18519206e5354f769ecfbc277b4f36bb5218a863a31f6bb8fb4aeac2972fcd1d2bb64c6ed6d654755fa67efe5cba754af703aae47c10ea95dcfd00e4fa80298799bf0d72bbbbd3b44298bf177eedee30e585cd7f077e05db9de9a92743b2a2a4ba1ecfc5b5942a8b9ac5cb6f2d987c615a79893fce09a3fd9a5aca3f50bca27a5e5f92724622d599e57f29cd6ca8e7cc3c33aa112cd58856efb6b44518b37353f386ce37d371f666e60dafc5b12267bc358e0fb726809548e449cc496b2afcb2f0a06d5ed7f63cd0f6d953c0e7810ff61e60e14d39f52823fed3a4ac6bdaa4683676ef791893091a37fdcc00f7c21ad23c3de689127f49fa1ce7c6624793c04c5cbbe7ea9f3bdebb50d65bdbf5df97cfb47cdcfc93dec7af2eef7aa263f5e597b7ccdc3cbd745af9bb7faf5e75ecef0e58b538ee08d756ba51d268e796924530ab46326925f732f72aa61153265efc51d9eb693f81fe5811ae48c214413812be7eee92ad4ac18f991f6d3565c6e48dcf50faeb26cf9b77b05af9b8d4faa933aeac9d644c88c9dce35ce4ac75c734b747d8272ae38488239b5fb20b698a3b9ce093f68866f38656475238535b651b516587b9cb6e4d7e89bcdbb5ab863e27a7b2fb964e7df7bbaf397e1f461c07cac9b1b0be0f6bcb94822af271596ae6c8a74be296942d726e742b0fd584633efb5e2adf8ae3c09abc8f3c73ad24bd2d7f7e616da1f84cdbcaf94fd43e213e79fe67f73cbbe75976c3f955739c61d04649234871c9a29279f2bd238e3ee6c552b8b7b19479f36a5dbeb051fd1ce8c694a93e2559944de26865e52f4cf07bc13b27f88c917947f86a76d47355a3c03eba6e269fb98f1cdfce29dd5d44987a84df0bf3a6645ff8f75a5a0bfbe409ad5a1f415dab7e89b7467591bea5cf79b17cf5de4b41e607f2bd5f0547dd577edf23de9179abcba6819dc85c8fa5efc9958b025e39573259a35a48cc65fed417ee23a507e6c634cf3bfe99ebb352a5a08f7ce63265ce293be39c03a99a373c3c6f4feecdbb1f3e1e95f97bd03cd5ee4bb651bf18d0ee8e8ed683716554ae9fef733dd63d328fb6c4582a5b201040d9caeb63f214f062a15d8bfec92a05bf209f95c64109907fd1a3f3525c6e7b4ce6c3c7b165d3ae682d95f1b3473e1ae5fdd8a5f87ec97ce63ad2d8c42643fb60eb1c296b6259f7be52dfbd353d8cd77104747ca49c3069c7c2167baac2a349ce11e5de4f08b6e64f685b42cc1fd47cf2d1db8f977d8ae5e53f3aef7ce911976beea3c76332cf4389eb8f3cb6764f735cef031d4b2e97b52cba7a7f17acb91e60e6098bfa7eb4ebc264676da6987dbef09e67f63cc3fef4fc1359d0cadcefa087bf5e4afaee503e0823a59917eb1d4bc318e5d9ebc461be8d51362d65168165deb8634fcec2adcc14392c6cc447f58365fce8c24f5ab472a66d7e63b35ed6bd7d3f2ebf6c2ceb9e27f73c79a3f23ed2cafbd9575a79ae22e6cfce079c1b5f0a95760e4a8beb5d74b5ac654ff3fd5da1321f6f564bd73330f7b2d3ca957e77063866c5c72aa90fdee226ca970758ddeea47d5d0a360fe500ed65aa527eac72d1cdab4d89a4243eda6526d16633712fc75dbcda31a3a5d96e92ab8a525089fc809035e5f18ae41263b2a3f2c6afe8acdae3aefc62fca5ca5c7c8755e9c756268f82cfc3ccad979bb6e3aa8063feb22d5df1fb4d6a5336787c2e2e94ff68492ba12c8ce62f48c10d694ad8011295bdb6ca26baed4a4643785f9233debd126295df267107c2582dc572e9905309ff607454f686343deee206934782f25ac613bec59d033edc816e91d2b7baf9ededdb2fa9cb23c976ff647784efcdfa77d39556f0b625afb0a35e95ec024847d4a6e3b806149ff3026782c6e9024e915452af8af6c5a063c9e76beb529ba63055ae46e9bbf5e3f39405228959b1bdbdfa338fd442badf9e5d5ae2356399b34ff7533ae7742fc699ec8ec955fd6612e36f38a88a1db1cab9b6c8510e263e7a49bcdd39dfb3f30411e2b943e5ba56de7dfe7eb719ea69b59db93a5e9141ef1197c75f0067f58be8a678bbf07d9bec231cb8f6cae3b9a2e7a95cb2abadb34ae4f0d7b6f8d64f37dc3fa8dfb9e6fbdd776e9ae3e41237314a143f5198aa3e358bcc35b55e577b9288522dc6603e6afa95e0b517ccb9f4bd478703e41039a5653951267231dc9130f022b710f9a7c7834aee4bc423bd64df90aedc1bb855f3661a9f2e56b45ff1f9db950d4be3b6cfd9aaec6e8b82f98fd5c67c7351dfd27d9b15a1dbe291ee6594c26ea2c4a6c4ba9fc41dca279fe2ea46905b7663ab5a7fd556a8542e35ab3bd33965bb18e9f086310f6c97b3c793623fca06ebf0b50e881da5e02a994a6b0be46b4f72d700b7307013e5260656afdd272f71936df395f3277875492eac65cbb8e832583f464692d1e2fd3b65410c463cae4c6c1085f4aa3371764f6413d5e847cfd31c929a9a4d97232e908be48b670ebe3b5f693d41aac443c206ec07d0574e10754923e4d926aef7026782c60900e7296965bd2c405f11a1afac68b8aa2e8967aaca4e483ff4463ca1880d64fcf2ce977c4f36f59b56a779c76747e475bee4d9b4d3aefc781217b562b0f746b4477da6d7ef634a53021fcafe28b2b57deba54aff9e9dd6fd914cd6ef94bf98c89e9dd5cbb15f55b7c5aca8688ff96ce19b334b6f791b476a94d297e41bddd43ceaed6df122670b2c2739675b3dfb5cffac77e6f64973b6f7156dd8ea3cc8cd1e49fa962891674cd886d6faa50faaddd74979c3b1748fd36b7fe32567ee1f762cd9de67deb0d556eab4ebedf9a3bea5caf86eb2c4c9ccc3f6b0098be7bebc7bda762ae9b4c0c3d86234b7c34bff663db099f8d89456e83179e99c33dd7a00ac29b46b65eeda2a8f04a336c74de0d9bc008f391747bdfe078febbafd77bb695e53020f3d57ef4882bec76fee9f5be9dc72ec056be25764ef7c8fb40546f2f64bbef5ae4f5561044367965b3b8f807d6064ff78821a896ad9a34934cb7dbcbae5d78770a7d777c9fb0658a771b8d33bf10fe8d34fdba98c6f20e8953ad26195ff9cb75f10fabc9ec6bde4175b6c520329f1ff225d696f24fb5ccaca565807384e08c4293985575e68eaf77de6ef879541d17af2f6a57d2ef52957502e137b95de46d1e11188e3b74ee2a81718aedec938fe20b0dc1f9c2ce71138c7612707ab601e7d64eeb033687dabe8ba75ffd25eeb81409ff5b0bfcffa56539f757f63d07a20b7df7ad80ccfa5e07aefd072d59e22d27a7d6e3db66545d6cbd2cb82f5adc67edf2590c8efefd9588c722b6d7b5166d5cfc24ac8d5406e7edef74c77bfa7ac916c83b5519fd97142221bcc56d244babd4ec171a23be89430ef6b5ef42771dd5276797a696dcb9f9befef7de0ea92ae1f75fce4f26f9d6197e767b765d6668b2bcf3f73cf4ff7fc94fdd9f927a766c1fa62e7becd335bda3b7ede0b6b96d9a5419c8dd472989546f041f9da89a0723d0937e58ae5afc2827466eacae56056aab94e9845b86679c069cc736331bec5f0ad3ed2ab3cb4d2a68df1f8ba88273daeef40df514c3d445eef0fced961ca11ca175e84be14769128937a585918c12a7f7addf47195a77ce55cda0b0f16ed552f4e84d92005fcd7d2e012e7e4cdeab589c4737125634d4d0ce24ae060bdf2ce4aa1724df59395ed319738ef16e2295b3977c37c618bc795c228ebcf4cf3acbc4473f0389f64d43698475a2b738f094b9cda9cd74ef26134c04ae2b2bc7904739797492f49776e56dc628c239187354e959dfb7d2958d03f0717bda43c2f8df384a58335ee09572590f6c4b571952baaf364b13c286fe69998f6ca4bb254cc2b4aa34915f3d9f75c4adf091293597d2126bbfa32ccd39c72ae919f0bfd8767a3322b7d51d995fea81595973cae6c06ebacdb8bed5a9d9398ea6ce716cfc55cc67a20914119979d7fe660cc8aea8e98bcea2e456a2368a7212f6e717d4c3efce6aaaf7249d0822e9eafec4df3ee010f04d62ffff88157f9e3ca30d41095d3c933a829941be55551de2f1a7959ca67950d8d04e4ba00725d9651da558d642e0f29d898cc987331d931ad312b622ed66e59f93648dd1195570952f45029200ed7895238795e93c4019254f79e032960fdf35ea757b9ff09a93aaf72454886ffb5b2df2b5fe8fd9f951dfb974e2feaee7b17a66df68d163ec367b22404af557dea562afdc4718733a85e7b27f8e75def7a50362a534ba3a8cbc44765469d8bca8e6aa5326535b2b2043eb42430e395edbef1b9dbfd514f565edae35c82b6f5c76f825ea22e46e5457d4e6593a0752481fd086593782ea6737c2184b9f1ddef7af7b926bb36d453f98ebde3fd73f9cb1ecfc58bb497867cb1831e5cd5e30e04ae05adaf495bc596f6840416ecf7c46ea2af9fb7547f7fdb9f628e8656bd98627aa963c75406e2920e5e5928904757ec733f3ab086c715c086a20db803016b80cfbdd47ac25af299b5933be22e2fba707f8bd8a506a4887da5d34b67961f2adfd588b995cf67e683edcd1b9eda31610ac316eec9ffefb245657b56deb332ce793e3b2d0b56affc70398a57f42dc5758e12dd4dfab4dd0f481d92c899fb110d2fb8d0e7c5146b48cdd850cd7feb9c5d46edc0ebd2b3587bcbcff4da539fc5ffb3e1b58715bfc63f1fd7b2af749382fb12d34bc31a5217eef2b53707afe1da5e354bdc3155ed7191d7bf507b24a6fc8bbde9d54761edc5e3da6bc3626d758f6bfb6d5b7634de9eb7ed1d559a2729ce6e12072d7cf42e5cc7a316607d4fd480b70f258fc98335185df5b988162e6fc7b02c110be8f256dc0fdee3c4f43559941f3013a13126c31ac7d3fdf2980f62f298b48fae38ccf84c32cd3a1b5a3f3aebcbb730e9db7c51190f1fefac1fe80fa8911a290f35d27cff508d343e61d4887879f285b89645cde517998558b745ced0de05b6704837775fc0b2af9dd5a51453574c83961ff9741caebb1f14c88647b495a3642a6f1c9987712cdf35ea86dc8ebab9fdd96d0df4f97770a7a3bdf96ca7358a27edcd3fef5ce8d56494ded1f6b57ede833b64d8ef64b7c4cd55e32e8b5dd8ff602e26289b52214608b9b224157ff442651aee9c293f6826871f511635c39cbf279f2d3c9f7dcfca3d2bd3a02ec9d91b9ab8d7a145762671d61a9e8c7c5af9503465ac40a9b76dd9d51833efe6e753f376fd29f561a0d9239f2e998f35eb5bea5802bdf2e66e526d5f9fae3c1e302549768b20d9960688b065d65ffa8a5457e0e75179dd2f54b92506773da39ab155b0ed657712a73c2c11cd9baab66ff32db8707b9eb5660a73f0dda15aa9b909b55252cfcc7742992c9439adcc37a1bba7da7ef07d28d3e9278fa42bdbfd3ca6fcae57f58bb4dd372c16bc8edf3919dfd6b00eee770219b5c5ba7f16931276c7dc92f4b1beea1f3e7adcb7ccd28eebe93f97dd5f465b29bd6660e76143fdbe5d2961afdb3beb99b13806a6954e84762ef74f6f696fdefd8eb633b9ab71b2f39eecf399027a007eec194c1aed154ee673bd9dde08ed3d09bd6b3ad63ca7af137e4df724afdfb176f2d5b8ae451df75f9ede22f64e2b773f82abbc776e6def680fa08fb827a734d7992b9706fa3a2b476d8ddb3ea378c3f899bcf25817c13db5bf773369e7f3ef29dc53c83e737ee52d506e89b6d7f626a6ad75fb2675f77a84623bf2cefe06741cddcd6a31826f7010a30fbcc856bbef1f3dd7b515e5fc57b73faeadd0263c4757237b6b7f95558f79956c45afbcd4af499ffecbeaef2f72a694baec740ced71ed6bef18f3b990b6a35e291626a1b6e25aa695be512a5e6eef5873c97110e6d2323ea8bf97895603ad415b590f895ace250b8cb37c6d9532f124ff7b77f945cecb07773d5ff1c4efdd95aba3be88b824832c956df8fed19ad814a5af7f5e8255ce677e7da4c6bfbc55990cf5a9bfa4b503da9c351dffd112d5c62cd871ce71900fba1f86789b5e1bffdcf36fb8b73ea16c9e10e6385cc658df9ac0580f1f261ea18d6ccd7196ef68fdbd3bea09e56693e85e4cf709c72a66af685e42d79fe3284d391351f945e567c2024d2a9bab87c4f87c134c576509d6b2d9015e6e4a22fa6a36dde36e241139efbe4053ceec195925994995db4c9e97f6b92b15b94c0a56405e30f3b5bfec1516fcba3e6235ae771ef3ca67dc646c3acc8f905b2ebe51e4a245b3be629bb653d5566c950da2333d7a69bcdde6f693989cc75e70a386eafdfcd62f2a3edb7e71fc17a7dffe61ba92d308e90f09c7bc32aeed731b89dc841cbfb8013913340ebeb52c92d6d6abb05e93716d7fb1e1aadc14cf444b8dd223b85e2b6b80765a5be5bbe4ef1f09eb356d6e1c36a7fc468a440b4aa4a116b42e72b8059db536aef50d3a934dbe287e3eb354f90456074d60ff6b4482f67007f830c43eeab504d36cdcf71fbb67b96faed0ff65fa5db942ceb517c27277bda07a6185f7478c15d30cbda8f8b61af8cdc73433699f652ecade973d2a6b700616bb700e2edf32bdb4fcefaa5428c534c75c76a6c79c0a593bb4750f9104b08fe0aff6ecc999560e36a679f7c7cce7fadc6179e6abce2afaae19ad48bddb8f6f0e1b37bc75196d8309d6c5601f4c74f6cd8d39f562fab6bfe31c4e673613f30ec6c1d4669a1a43f816d61a358599ebfd9af66a241eb46749786ad8fcc37edd1fd152d134b512c134a7560e4de30ade380d4df16ba91753743c3134456eeff014f82e4bf9ac8e95274c25b052613dae3a7c97a99d8b2a321365b4a48723083d935de3d7de73091dc1d019c381f384fab9808229f6ce82dbec09e00d9aae78b5779ce0d9b336a985c55e0bf6f149b55422367c1739dbc5289b45c2cd92e879447fb148f0dcde95223ec11b4fdf936eba52272514442cc4fc588fd4c5e2190b5856314a84c43bbc2ea26c95d8a474c2cae313898d6f215c124fcf2c5813befe0e5e760a03efe0a12f51f906de07eaef12e9f9cc5281603dae14cdd3e4c7b3181dcb3ed7e57f4c1e3f8fe07b583c37ab94818e6695d2b36046b9f18cfac0d90d274f86be93c4736ef4ec6fe258be9d54dc238b84d7ceb63230ebffc7313c8b67b6e1b7265ca76c2211f2d2257635328ea813e2417686f788ef138fd38be76a88e335a1575edfc3549d71316a4f2439b2b39678da22c18f02bfaae674af6c8ec7ef1e789bab8d38e2a4deaa263743cf1cb8ebe89908ab25d01b2d4612df24f11ae44dbf5f4912be93218bc504cf6aab91f1c4239e86bc0e8d8630581033ce09181ee98b68c47390fcb0b3745207abb4d545e1d9737a3e22cf1b89ef6ed5d3ad8c1beaa43afee4f3383c903747b0ef459f7112f9a91e5235ae8c7027385275a681603d6ccb9710ef973012377e19acda7982d89e5a02bc33a4eaec69e26d037e3016e6b09e60f4d956e2790af8bbcf125b5b0fa33e154ba277b711ef098883cf9bbae9f3a4b26050167b829eb63606fb77b439403c3d2740576da4ea53814992e079cf2482df2c447f3a81898e14195ba08d789683e52c9a0456d90c71fae9370d554db3e833af78959681df43a04eabdc498cada8899e77887e3f8df1e239efa764d017a4f9703153b5733ee3290a101be85d0d4491aa9d4b214e73109f233ffac31c06dbc42b1e0dca45515afdccb9f44c0f3d2b717a3dc8504c6550bb27104f00783b90f79d0c8fdf4b6c421db467b7f6fd91fe5e5a7f0f1da4edd252173e709607c7ee90335bd684b9f47b013ccba3b71b0fe34ec2ef97948ddd3c9edf4a0aff4e861a46b86801cf984c251ee93a3d53a0060263944a188fe20ea20ac512f81f67a3c326125fcc1d7d2a8c1f7ad6a263f7a728d78dcec670773254dec1f1d931f05efd4abcbd537649bc572423657311c17e6cb5405c58cc79cada48128c393cbb619d2c818f29d1b3ac491219a90a11bcbc338ed8c446882f92aa32e8e39587fad59d8d34be57b440bf8674382789e41e8fab89752f41bfe8c454f88deff1793cc3603d2041da1e682389f1558afd984e953244ccc311974ecf0c29802a68435fa5d43ff48c47e83b00b0b5b03aaee3b12ed14b170f9c6153c1a878a40051ddf1588f9168bbd0e6e279bb941db5c4965347f02c8eb5a66ee09b8290fda57936a3fd1658b0df23e5c5ad8ccd89ed7ff06b71a90ecd022b0b161ee2d0b2757b66b609ad300ed3084d9b70107caf8681f4f87d8dec4ee79487a4d1d036bd6023f1ec05f49d6d60f76fe1aca93318ccfb0ad87cda3edb41b7a565a07f0be8b88538a6a413ee36d05f29f4819d3c2b2f1141de3868b75ae2a815e95925d49fd58267f68a4d0549e9090574ceb0f0a00b563b8bd6087a81f1e54ea7bac26d35251cecee41173d6fee27129d37bc58260feb8cc9dbbf3e87542c4cb05aa630d0f7f07b2e0efa1e0b7d8f85be179a1778aa2fa7a0b7573303ba1d8fba3527513ff463aa5fd0153d638663cfe5a7e7dd92a479198e78895303fea0a7d54bacb77aa98dd7f8e983fc69c3f9553b26d0b390784664903715d7c7c08bed1be4cd025e119e01fb6a909786630ebf29b93ec85b8cbc3ec8efda202f07795fe1b9f241de7ae40520bf9e419e1379ed905ff7206f07f2ce427e5d83bcbdc8ab87fcae7845e0d5cde79202c160d58e8368377f8ef688d675df21edaca21ea76a4703c178b27696ad6f907f9a2481b785e7240779ad24a91179cb86c4eb26492ee4c5f60ef2349b0df95d1fe44da0361af2bb36c89b0abc5eccefea206f16f0ae627e81415e1af0d0569eed1ee42d065e333d273cc8cb01de51ccefca204fb3cb90df97833c27f008e6d731c8db813c6cb7f641de5ee4c16a71d91743f482bc66c8eff3217a41de51c8ef12f2e077b1ae1b464e47bd2ebba0e2ee1bd899c17edb78e89bfaad962f8e55d24fe734906da0fd5e3d346003b478276e1caff6109e71d5db49646e18e7358cb34cefbb2e76603c4cf1e219ab6b21fed7c703f28ce30179c6f1803ce378409e713c340e961d8765c77e19e27fbdecc61b94dd7883b21b6f5036f206c68ede0f4fb0a1f6a363801433213eb663a80d87e815e5bb3098df405dba0679a1311b7b6590171a9f673b691f8131a795ad8d4f3c4b36288f362607c700f242e3313406a8dcfa780c8d01e485c663680c202f341e43630079a1f1181a03c80b8dc7d018405e68ec85c600f242632f340690171a7bda18d078a1b1b7fbb341dec098ba38c81b18f31706790363b46d903730465b077907917715f26b19a2abd018f50dea3f646fcf7e34c80bd9dbdd1f7a81c7ed4d27fa1a2048bffb4ac0b38cda3946f0912a71bd017314fa49daf77e7826b223d6ad4a15ac72a1ce143a43192d4d059f2e9f512ef8595ccb79dc7e68a778686777bf0dfa119e4b4e4aff90d0df31e06b0472895221f1da373ebbdf367e2b3b303e713f764a80c5713dc893f05bbafe216196ae9d74ff02cf2cd3efaca41a9837fd9afd89a7f6e7e9a1f667b8ed1159b57b3d8976c398ea2eeaf5b4b6e29a821d6e77427140afdd015f68ee401e3e8b76ef20de6ef0f39dddb19e6e2f19621338b507fce06e09c63bac5d6ec7f1be5beffb659cdadd0d79a6619e1db4dc5fe178db7d55cbbb9b609c68b73394f7182def909d0ba56f20de09f439f6a97ee4e1f368b7c0601cafd039d49ea03c63409e0e2acf742a4fa75ede18e84f5a79c2607954ae37a81d68c738a1bcbd0283639ad3ca0db5512357b5d309cf08837c5d5eddee419b0f2ddbe2e5414f1707cb16f91b965d7308e22df37fbd6c910f95adeb83c738a1e7a1f2691eaf621ea1f1e1e28d325279a650799af57a0c97350e9fc59e1da2a71bcb5a8be5ecfee4067ae20d7afa9a0c43f4240c2bfb562c7b59d3103d09372cfb352cfbec0737d09330bcec745edd297034fd19911ba8ff645aff53a138553b0546dd01fee46981c37e15d21daca139fcc603f9743dd88ab22fbb4cedc2f9bad983632e7dc1d03117b217686742e32f645fa86d21e43edce331f09261ad40e898e7b17c9ea5dfe86c94e89a06bf2d6827c50b908fe5ca8b0556fb8e2709d61466625bdc4dd72df45e05c837646364a1986def88ed463be8a883311a08e0596a51e3efbe12e25735a563ddfaf5f85f0ef2a91dead5e3770cf21ba98fa1c76fd7f812c89484f335ac03cc246571378ea58016e7ece5c138b944b365c85f766990efc63c7be99d0384c40f96e5c23ed385fa011d4cd5f8d0b66e68b32689c3b95d7b76d41a7a8672a30cb8270c6903faf35bf43cb19ff56a738324e0f747d1c20452659e40921ab632a0c7d770de0f3d8f5eeca4f242d9095afa46d4e3189cdbdb89fd7b219e2e673fc83e7d9087fa5b06698fdeaef370dc60f83b8361ccfbe8b45018f26142e56b7ad1f63a944df8dd8144edf51a7294ca2a83aca1b2f07b7790270efb01f6a3c1f44dff427a09e5f8124f887e3dbdff5f4c1fdb01e9277d3d7de05f4cbfec73487f53287d685e0ac583e7efa9f8ddca796d0dae8d3d29fa46f35d282df4f509d89f607cb1daf8da1dc47e07f9ff29946fc837088d59ba4f6bea36294460f1db0145ec0ea7fb3b927edf8c263f47e5ae75d13b39a04f11b5a787442f4d27725180c36f8a657c27d15487be08ad038e532cef4169c27befbbc4f71e2c0adcf4be24211df7be4b7aef7d083fb8c3fcc71b8d63adac467ae707b4f50dcba27eb7663b18594aa07242f90cda08df26ff7533fd9eced547d7f40d12eeb15e72c4f10c07f1314d284f9499e60b72a32ca1fc517eec97b4fee02316c4db3be9f782e324116da6d582f716d410657c37fad8c960df21af009ee41de37b49eac7b01a903a546d0f947c5b1cfa0d9d65700f06e2da713f0ee70ef41b42edd5de31e6bcb791c17d070bda1b2fe489df2da2ddc67dc161dfe5e5409ebfaad3ee50413fec06f7a83886dca3e2e9c17b549a08ea1df71eff57ee5109d977ac03dde710b4fe237322c925dcb0effc549e059f9425b6d2527b688f10bff1c3ef7fd472fc469125e042e1d71445b897d87e2a58258b105fdc69c77c6d8293b41fddfd8132294c7427d1f71cadda9a34bdd53d9fbe7f6c86f1c0e037955c5c6390ee29bfd1d8efbbd0d4ef4ea7ef1d3fd5fa48fa5af071f9f6e6b35bc1e65f741f5c86df54659bf1bb1e41c8c779a33da2785a7bf3eeb7c16402afc1d61e614f688f389a643e817bbe275e549d61f49b35fc2e019e7d4f2b4ba26b36facd79f22d1c7e738ef5c3ba99a7d2efb2ceb9a7d2fa9da5df9ee377e9f8fdb9fe5dbaf6dda308763cc32c9785d1ef8ab5740d9fb6938848f76df86e37ac5d0e8b20ee69f07bf3a2b3727804cb1d2ea5e7011d87c0cf3f04724961a44a8036768693e8b0db30bf71908e554b79c677d3c23ef36d78875479b8ca4710f334bc476ad1a76a5804eb48867c66435bb878f27e20f9d48381d9a7aa9c5d4118bbf7c84238a92a9d42e2133a098ce97bb8e430869b1d461e7449e7e5b03056e679a69d9c1ae1fbaf4498332b1e84df7365f32ce28ea77aff84ee437a24da271c754eb4952ce707bf04d7194bba59a5ab8de5bc4e463555e077bbac037edba480ddbabf95eefbf86e127a91e21e1eae9f310dd72630d19b44625bdfcd7a9a1a5959249cf28989e14e629fca17e4a717108537e16f0ec7f791b213e495314df83de0f5ff4fc950a7c970e47f20c31129406548791864a8159814285f154de4c8ff5006adaf66315c8a48fba1237e3ee1a695c15a7004ce157c4af867f69452bf9d4b3f41427725d0bb14f01e05ecc3896b99501fc7feebb8b38c51788944f35d4147234fbf9d55364bd0e6f41c0ea3ecf49ba2f996a0f2909d49e1e7cd757879523502e3b951172647c371a29409746cf98bc3c8401e5b4117a13c5ef49bc01e70c3e208c5821a4827ca7689be2f083d53e6d9257c1e1dce6b73f47f49a26dcb13e08f1687c95231f155fb7b5056f4e3204f3694ae6acb5741df827c58837605f1fe06e5219ebe0349e103787f50374dfba2ff3aca81f3d25079a2c3af07e9f7f9069e6f81fd1bf2431f529777d3138cbaf926e26880f83b857ed40f9615cdeb3a2af6f3ffd25d14a1776743ea84f5f42d28c676efc57d69907197660f1bcb54b12348e72afc4eb85aea575d22f94d7c602486c7908e31be17a57efabdf72181fa09325741645306514d35441e5d43609eec53fb0363e8f7d7ebdee7aaa4ee6bf41dcef2ab6c95b4e3baf2e15562dd8f6bc5363a4fa4485fb0a1bb4d5260be469920cd57749eccbb0abf77f452bf9c617aacc925266be236933581de17275993e74ad6c41f4ad6d4b1c0cb92709f03dfb15a138f814d041b1ac6b06ad829560e279c03bf318579dd9a780e740ab2ed14f0fbe530d05f18e80fef583381fe24d09f04fa13417f229419aeedd967b0caa66efaeda9bf98a7eb01477a09679dceb05696e1611e0f5a4776d2ef32ad964eedfbe154e08b09ecd072d11751c609220769f15415bedba173e9c873ac2cd5b0caa4565176c5eb71cd3056c289bc6533ace93b59e513585b413a3c9f866139d745301d9e0e56c2bb45357c04de251684796f84327216a3b0699c2fe6f4559413cf1fa01faafdc6749db847d0a385d1d7890dd276039dcb12b4e79670e2cb0e5c97c5638c4aefb35876ce117f8cc172697993babf562f2affb856d330f9e34710357c0b513e904848375c3cc32b0b244d96805fd75b8d248be05fc5748b98af5a86f9be4bf3457ba88a15a2c29e0e572ed48e56c56241e14f8f53ced79a7c4468c1b651850cd6c776b7413f3937b41e4a66801dac43ec695a07900175856b25ab85e1e9fb4bf1a8886390ea6b3694ef8a24f88d34d720d2f27d110d5755579cce8b24fa77b63dd0bea2127e3a5215eda22fe2f4c7aa5843ac53dee595259276ff97e51c4fefb18236047b37923b184e9487712feb146b136aec561664114a38f0335e9045d0077e03ad9d09a883f61a07f94b8a08756da9c5be053ae81e0d724abe9bbadf0bb5aba63ff4fbed8c2a6648cac8d360ff8b255fd4e953e0c333280ff5b3e797800d725e97674d009ffa5010df8fdb5a6b21fdcb2cf68d6f95bdda4fe544f9415fddf47be417fdec37d7e7ec66dc3be6f60e3e4f19f63c761b3cefc47c30ac6cd7f2c2751dde0d669dd249e5a0df44437ba10cb4fcbdb4fc5e474338d513f2713c6aed19fb4787379cdee744c74c3294056b1825bc89702724fa8e16fd7a254a1ce88bd08617b8d92502de85604d3d867d01cf6c5cd5de3f0e791f99aaf9a7d6c437616c1f035fed5df0d9ce89d01f446b3283f647ba32c5de694ec43bd64a6742fbfdd2113f0fda5c0ac73aa06f6a9d1648405fd5fa9a3b01ed28fdfd86345df75fefe00ee2bbd9121eefabd14ef935d4e21880beb11ff3069dd572f1a5a0f796d19877b42b1074cfc63cdaa629f735d33ad1726e0d4ca379ef91a66139a1f79294572bdd3aecfda4b6476ba2dfb263de2fb5d0fd0c9acfe4401cbeb31b90f535690adee1806587e6064daeddd5b4aedb25fa5ec81a9764a5748a7b32a6d5ea2e597cdb25b0e3bb3b6839d543ca991e9884630f75af9d2738db3b443f31aae99430f41ed4028271777f39f81e5abf0f2fb9cca4f998d2587aa754d1d531f45e8246899ebdc1fb9c64c8548bd338899ee549dc46b82451c239c371186cd2ec32b03f65926356a9c0cd16456e162fe0d91d7fb109cf98413eaff2b8dec47526aeb1a1df02b50fdc0d60137618cfe25cc7bb97e83d4b3006b53584f3167a0753b27e372adecb940c7e3fdee3940af316f8fd328f6bd6dd4dd03719eafbd374422cf4ab339aefffce21eafbdf84beffe6d87fc9f7efd8fdded77dff85ef51dfff26f4fd374ffa7fc4f7ef88fd2bfafedf767f54e8bea8c13b1b047a37e895a964bf390edb79fe257d9d7409f26bc43d017c9765adf19bb0bddb3b5e787e0dd1d2e3fd67aa083a2bd375acad936ab43573ec05ba0681b5f437c775eed2e22e6bd5e29eedf9967cf5b8bbcf6b7163bbbe39aea06a71cf9ed5e22eeb749c15e8fd576af06eb00d411eef7fa8fab491447f5844aadef393e84f0324fa2cacb50373702f455247837d7cfa2a53b511d6cbffd9cf447363c891fffa8228cf0738bc274a1d43ef8560bf45de6dbabc4dbabc17f1fedfe865f576451c43e4822b77cbdfbf1254cd738847eaa1f7e2a17e6ddc15ea93daa457c0e7001f3e6a16bd77d38677d6f8fdf4de3bdf3d4d41b97b1c912b93d1a7e19517c7d0f942d9f8054bef5c29450af2edfc8254b95d4c55936baecd24e2fe2f1b3abd4dfd0e9744f7127d1bc7f4db36898c35e12a919d6903efb1be562f3a16d27eaeb7ef9ff5f6fd87a309fd516d6c2aff05bef16b02499a84771f8fee8f6e5a00e53d4d6cfff905ea15ead0c8447f7a92c84f0718b9e83f214e04897eff2a499904cfaf5e95201f1674c3501ff6f90bac3a3a5fabcbe60fb96f964978566fefa37a7bbf47fde3d35ed035de1d14b81bbfd652a36cc4638a64b8832682e722e509a03f93c4da9cb5849badf9d4559149b00e3d43acc54dfa993833f1457ed11fd28b4da825fa5cf54dfa59adebe7b0ae9f77868e35d5058035e2955b61bc69fde4b06c827c9c26a28f3f0ff54970ac359f6dc2b10675e0dd75cbf07ce803caf53a76e04edf81312bea7909bf061d6cd1de01da83a13d216acf7f5f779cde9d3b8beeaffc28f47e8fee435ea8e307ee7a049b6b2b6d80320f80bf857ea1307857a5200ede89e89c407d7d7ad74af3b2bf81bd2478df0abd0f5528be8e719470c1a4cdb1d25b78be07cbf0361232f45ca60df709a7b860ddd3a8dd9d3a9e6755b7c4ca0ff1b0664a20b616179e9d6cf706aeb3d0274c479676b3496963b00e53502e8c8b77d4799676b1741e68aa633d813ad6babf45bb6bf340d7f079419fb3607dab8d5d3c2724168b38c7d176db7fb656d35ff1f521ef37687de85e8a763f48fad0bd149a8f50a3a56f1ef30ad8cb0c47924ba0a78753033c5df356483ca82083f3ba38393710617d0bef31c3fdbcc620de2b86bf7d93a47e78ced0f28b605df3967f605f0ff3c3bb64f6394be633f399b4352473d4dcb12569da5d2778cb8aa6e9dc573629a9abb6fd69a31bef53b1dcf2cc5a6dd6cdfde5e40ef3147a0fed3e5ba9cb1efabe695469c9bc39e5e71e516eda4ef0fba5d07724e0974ef4b8123927ff67b7c3eb0a6e745fabd7be09d072c9ae7503554b5bf6966cc5fb449e2b65162ae65dacf6b4f455ed29ff6ac9d676d23c9e3ebd7917197a5f484ca610760bbfd17dd11bfa75ad5eab43bcbb5299e6801ac796fb5549b2800e2755a66f58b061b132ef02af8473ac1c9544e6545a934f46385e936608f35322db88e7c249f094cc33acc91f5acae72be6f7f1aedf198b9fb7ee6b4cc01be6c2a4d1d2f6c6dfbbb7faf03bafc7d6eafaaab8bfcbf13b8968b710e08d047833c14f5af66d9ebe59b8973b501ecb9ce4e7f525cabb12c9e45dca3f7972e33b1094b07068a3b05b14673ad3979835f1a3fa98798ed9614c5f92b2d3cdf2c7bbcf70f1fc8c94c82ae2f84e2959fb02131fd6be7167d43c87b73cd67773d1359fd8d5bbb0de9a1c463eaa079f6e866356d8d8ce174ae24bfc4b9c1b779eab9f0effbf53aff55d8476434c491a331ffa437a49ba6aaae0d03f9b568a5e7f0a5f6c87d6b790631b1e8a066f3d743a7c68fc5302c6571e158876ca5c6cd1521d8d21c7981aa6064ffb8b9fbf513af9e266e7602a22184b393a114b89736ec6affec663698367f927aebd9d94f5b677fcfcabbea58ad84d66a6452f3e6d17cadbf2f13612bd0e7acecd5f977f3ce63cd939781a7e68fc8eafc71f3b3c3edecfa3f7c367ab33b197e29d37cfb53369213da8a6cc517a2e3fc1bbfbc828cc0972593cec7e1e1841d63fd43db52913d32dda11926020ed8004240c25a8cedcb078ce2e5fec94aff0ed917586ab708e33ad7eb8f48437a6b50bc3a5afceb2467493ea1ceb58f87fe1a3c73e5968c5afab7e609dd04d3ef98135127eafb59ae1ff67622ebe95957ab1fab1d4d6b772623e7f6b554cf75beb63fa34b9c1df7e7c93b2b198ff5530781fa018d00178f8d7c1e001c0b3fb83c152c0ab80470109bf0d066f053a376f65eeea9c6c4bceba756bd6dd124e7e3c2fed9ec5e98f5956aeb6cccfcb2a5861f9c19aec1ca841884f99c8bb13a2ac2cb4accf5a5708bf0a73d6adcf2fbc71bcbc356bf2e1490561002c808b2584bf7b3f11002240029800618070c008c04888330a301a300610412ab8b140c7417a19e878a0130091f0db0c888aad2013013701a20131809b019300b1000be016c06480153005301510078807dc0ab80d300df01dc0ed80ef02a603be074800cc00cc04d80089805980d980244032e00ec09d8014402ae02ec01cc0dd003bc83a17e4bc07e8f781ce039a06743ed4351db000b010b008702fe03ec00f00f7439cff0064007e087800f4f020d087e0d962c863096029841f063c02f811847f0c7814f018e027c05b06c80464011e0728806c400e3c5f0ec805ac00ac04de1380270179805580d58035807c78be16b00e50002804de7ac0538022c0d3d0c2cf007e0af819e059c006c07f46ec223f0714034a001b010e4029a47102ca002ec86f13a01cb019b005b015f01ce079c00b00fcb70df062c22ea202b6c3ef1d809d0037a012b00bf27a095005a806fc02f05f80dd801ac0cb803d10ef15c0ab80bd805a401df05f03bc0ed807f825e057805f03de00fc06b01fe2bd09f82dc00338003808fc43002fe030e07780df038e00de02bc0df803a01e7014700cf047c09f00c7010d80138046c049c03b803f03fe02f82be06f80ff06fc1d700af02ee03dc0fb800f00a74186338026c087808f40431fc7ee22ff80df9f00fe09f814dae02cd066887f0e701ee003b4005a016d003fe002e022e033c025c065c0e7802f00ed800e4027e04bc0154017a01bd0030800ae02ae01ae03be02f402fa00fd80208060d7d5fe1ed4c8940c3dfc10fef7f47bc16005e035c05b80538016c055c0c8f783410b2011b000f028201fb01df02bc051c007800b805e40c407c1e0144032e03e4026a010b009500dd80f380ef81070197000f009809c867480544006201bf034602ba0067018f0574033a00bf0f01948f36130381e9007bf4d8062c076c0af0047011f002e007a01114d903fa01a900cb80f90092804ec071c076c027c08b80c88813489800ac8ff00e0af80cb00d34760bb010b00d98067019580a3804f005701e33f867a008aff01361ff016e0610c035e051c055c00f0c0b7005201d97adc038093805380984f4006c0b3801ac061c07d9f68cf4e01cdd67fe3f315ff040aa8007c08b8003c1ee814c0ab800380e3ffd4e23e3b244fa4519f827c804a4032c479f89f83cf6bf43242145101f10a014f038a019b00d88fd6af5e91b53a3b0f66343a29e9b312d8bc35eb722cd9eb57e5df69995a104ec8f7b3d617e458129e9e9a306376ded3b75bd232be3f1082c7645d4eee8fa726cccc7eecd6a905b759ee1a12f39b9e84d372967fd3e35ba72ebfed76cbb73ec61c4c8b4831b9119df90d7c9dda677cfbf32949dffebc79b5462fe8f4aa4ec91a8d46e8344aa7b7ea3441a7769d2ed0e9c33acdd4e9d38670b121bc49a7153addafd3c33a3da9d3533abd6a08c304a5d547a7b71ac2098670b2216c37841718c2193a7d58a72b0ce17c43f86943b8d810de64085718c29586708d21fc9a21bc3f7fb83e0f1bc2470de1938670c62a3d3f9dae3084f30de1a70de162437893215c6108571ac2353a7d4da7470de1933a3da5d30e43f8aa4e89de6fa3560f0f5b0ce15b0de1044338d910b6eb74814e330de1158670be21fcb4215c6c086f32842b0ce14a43b8c6107e4da7fb757ad2103e65087f68082f2f4cb0209d9f6129cc5995bf665dd6ba953905c89f61d19ecfd4a94da7893a9da5d3d93a4dd268c1407e05594f813906c3b7b2002c7201d52a3cd7f3cd1a8897b52e77fdaa9cd58505df5b9753b87edd6acb535979eb7342f1b342f1677e2dfed088cbb374f9b274f9b274f9b274f9b242f20de4f3e08de5d3f329d0f329d0f329d0f32908e593acd33b743a2341a733347d2487ca796850af96ef67e5e5e5aca3cff574857aba422ddd4f73d6adc1070bb2d6657fb768e53a901059645d96c582fc073415656567afcb2900990bf235fe838559ca9396fc3574f68370aece4fcf5bf37856dee083429dffd08a753959d943f8093aff46c2c21f7407fa1cba03a50509df5b8eabbbe14afcdef27559ab728688410af474c3e3c19a442f6ffefad54ae1ca35abbfbd17407c3d9fac99df946e7802e80e5afc449dced2e96c9d26e9f5987923f90a48819ebe404f5fa0a72fd0d31784d227ebf40e9dce48d0e90c4d5f7a3e857a3e857a3e857a3e2b966ae370bb4e8feaf4b24ea31ed6c7fb231a2dd4e98a1fe9e1c5df4e1f87667e92b687a697e559ebf30a2dcb730a951543c2796bb2b2873e2f2804b78986574217c8850eb4727541e1baf554e594bf6a654196be853098d9703ecd7448783053f26fbfe3df7ec7703fe0df7ec7f0f0ffe97e47f48f13526c3356a5596e9d9ab7fe36589bdd69f98ff5859635cb2dab7256ad59f74c384458050ba3071f79f0fb73efbb4f8b6f5bb57448fc82670a96e53cbdb2d0a2e03c956d79fc190b5ded4dcdcbb614ad2c5c816b2c589e6919dda0bcc5ab0bd6e7c3645788b6e99902cc05d3de69c94ab86b2aaef8b266e87426d25b4222fdeffd891ae10d6c61688065ff774b19fc93fe2791b97f39e6767dfec9d6e7995bf5f9ea039d7ffb8f75fea31acdd3e36dd5f9037f1bf47ea1d3ccff343cfffff91fa3d3d1b6bffd3271dcaab6cb9f0a64c4ffab12fdfbefdf7ffffefbf7dfbffffe4ffc8bf8b9367f86a8c540130cd46ea019069a69a0f9065a6ca015065a63a0fb0df4a8819e32d06603ed3050f87f188d30508b812618a8dd40330c34d340f30db4d8402b0cb4c640f71be851033d65a0cd06da61a0a464388d30508b812618a8dd40330c34d340f30db4d8402b0cb4c640f71be851033d65a0cd06da61a064e3701a61a016034d3050bb81661868a681e61b68b1815618688d81ee37d0a3067aca409b0db4c3408963388d30508b812618a8dd40330c34d340f30db4d8402b0cb4c640f71be851033d65a0cd06da61a0a474388d30508b812618a8dd40330c34d340f30db4d8402b0cb4c640f71be851033d65a0cd06da61a0c4399c4618a8c540130cd46ea019069a69a0f9065a6ca015065a63a0fb0df4a8819e32d06603ed305052369c4618a8c540130cd46ea019069a69a0f9065a6ca015065a63a0fb0df4a8819e32d06603ed3050e23250fd2f18d4de8b9f2cd2f8211ad4ff0819d863d07e3003e1642a4f053f2cbfd0dfff05896fca73' + +ISP_PROG = binascii.unhexlify(ISP_PROG) + +#print('ISP_FLASH progam size (compressed)', len(ISP_PROG)) +ISP_PROG = zlib.decompress(ISP_PROG) +#print('ISP_FLASH progam size (decompressed)', len(ISP_PROG)) + +def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 100, fill = '█'): + """ + Call in a loop to create terminal progress bar + @params: + iteration - Required : current iteration (Int) + total - Required : total iterations (Int) + prefix - Optional : prefix string (Str) + suffix - Optional : suffix string (Str) + decimals - Optional : positive number of decimals in percent complete (Int) + length - Optional : character length of bar (Int) + fill - Optional : bar fill character (Str) + """ + percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total))) + filledLength = int(length * iteration // total) + bar = fill * filledLength + '-' * (length - filledLength) + print('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix), end = '\r') + # Print New Line on Complete + if iteration == total: + print() + +def slip_reader(port): + partial_packet = None + in_escape = False + + while True: + waiting = port.inWaiting() + read_bytes = port.read(1 if waiting == 0 else waiting) + if read_bytes == b'': + raise Exception("Timed out waiting for packet %s" % ("header" if partial_packet is None else "content")) + for b in read_bytes: + + if type(b) is int: + b = bytes([b]) # python 2/3 compat + + if partial_packet is None: # waiting for packet header + if b == b'\xc0': + partial_packet = b"" + else: + raise Exception('Invalid head of packet (%r)' % b) + elif in_escape: # part-way through escape sequence + in_escape = False + if b == b'\xdc': + partial_packet += b'\xc0' + elif b == b'\xdd': + partial_packet += b'\xdb' + else: + raise Exception('Invalid SLIP escape (%r%r)' % (b'\xdb', b)) + elif b == b'\xdb': # start of escape sequence + in_escape = True + elif b == b'\xc0': # end of packet + yield partial_packet + partial_packet = None + else: # normal byte in packet + partial_packet += b + + +class ISPResponse: + class ISPOperation(Enum): + ISP_ECHO = 0xC1 + ISP_NOP = 0xC2 + ISP_MEMORY_WRITE = 0xC3 + ISP_MEMORY_READ = 0xC4 + ISP_MEMORY_BOOT = 0xC5 + ISP_DEBUG_INFO = 0xD1 + + class ErrorCode(Enum): + ISP_RET_DEFAULT = 0 + ISP_RET_OK = 0xE0 + ISP_RET_BAD_DATA_LEN = 0xE1 + ISP_RET_BAD_DATA_CHECKSUM = 0xE2 + ISP_RET_INVALID_COMMAND = 0xE3 + + @staticmethod + def parse(data): + op = data[0] + reason = data[1] + text = '' + try: + if ISPResponse.ISPOperation(op) == ISPResponse.ISPOperation.ISP_DEBUG_INFO: + text = data[2:].decode() + except ValueError: + print('Warning: recv unknown op', op) + + return (op, reason, text) + + +class FlashModeResponse: + class Operation(Enum): + ISP_DEBUG_INFO = 0xD1 + ISP_NOP = 0xD2 + ISP_FLASH_ERASE = 0xD3 + ISP_FLASH_WRITE = 0xD4 + ISP_REBOOT = 0xD5 + ISP_UARTHS_BAUDRATE_SET = 0xD6 + FLASHMODE_FLASH_INIT = 0xD7 + + class ErrorCode(Enum): + ISP_RET_DEFAULT = 0 + ISP_RET_OK = 0xE0 + ISP_RET_BAD_DATA_LEN = 0xE1 + ISP_RET_BAD_DATA_CHECKSUM = 0xE2 + ISP_RET_INVALID_COMMAND = 0xE3 + + @staticmethod + def parse(data): + op = data[0] + reason = data[1] + text = '' + if FlashModeResponse.Operation(op) == FlashModeResponse.Operation.ISP_DEBUG_INFO: + text = data[2:].decode() + + return (op, reason, text) + + +def chunks(l, n): + """Yield successive n-sized chunks from l.""" + for i in range(0, len(l), n): + yield l[i:i + n] + + +class MAIXLoader: + def change_baudrate(self, baudrate): + print(INFO_MSG,"Selected Baudrate: ", baudrate, BASH_TIPS['DEFAULT']) + out = struct.pack('III', 0, 4, baudrate) + crc32_checksum = struct.pack('I', binascii.crc32(out) & 0xFFFFFFFF) + out = struct.pack('HH', 0xd6, 0x00) + crc32_checksum + out + self.write(out) + time.sleep(0.05) + self._port.baudrate = baudrate + + def __init__(self, port='/dev/ttyUSB1', baudrate=115200): + # configure the serial connections (the parameters differs on the device you are connecting to) + self._port = serial.Serial( + port=port, + baudrate=baudrate, + parity=serial.PARITY_NONE, + stopbits=serial.STOPBITS_ONE, + bytesize=serial.EIGHTBITS, + timeout=0.1 + ) + print(INFO_MSG, "Default baudrate is", baudrate, ", later it may be changed to the value you set.", BASH_TIPS['DEFAULT']) + + self._port.isOpen() + self._slip_reader = slip_reader(self._port) + + """ Read a SLIP packet from the serial port """ + + def read(self): + return next(self._slip_reader) + + """ Write bytes to the serial port while performing SLIP escaping """ + + def write(self, packet): + buf = b'\xc0' \ + + (packet.replace(b'\xdb', b'\xdb\xdd').replace(b'\xc0', b'\xdb\xdc')) \ + + b'\xc0' + #print('[WRITE]', binascii.hexlify(buf)) + return self._port.write(buf) + + def read_loop(self): + out = b'' + # while self._port.inWaiting() > 0: + # out += self._port.read(1) + + # print(out) + while 1: + sys.stdout.write('[RECV] raw data: ') + sys.stdout.write(binascii.hexlify(self._port.read(1)).decode()) + sys.stdout.flush() + + def recv_one_return(self): + timeout_init = time.time() + data = b'' + # find start boarder + #sys.stdout.write('[RECV one return] raw data: ') + while 1: + if time.time() - timeout_init > timeout: + raise TimeoutError + c = self._port.read(1) + #sys.stdout.write(binascii.hexlify(c).decode()) + sys.stdout.flush() + if c == b'\xc0': + break + + in_escape = False + while 1: + if time.time() - timeout_init > timeout: + raise TimeoutError + c = self._port.read(1) + #sys.stdout.write(binascii.hexlify(c).decode()) + sys.stdout.flush() + if c == b'\xc0': + break + + elif in_escape: # part-way through escape sequence + in_escape = False + if c == b'\xdc': + data += b'\xc0' + elif c == b'\xdd': + data += b'\xdb' + else: + raise Exception('Invalid SLIP escape (%r%r)' % (b'\xdb', b)) + elif c == b'\xdb': # start of escape sequence + in_escape = True + + data += c + + #sys.stdout.write('\n') + return data + + def reset_to_isp_kd233(self): + self._port.setDTR (False) + self._port.setRTS (False) + time.sleep(0.01) + #print('-- RESET to LOW, IO16 to HIGH --') + # Pull reset down and keep 10ms + self._port.setDTR (True) + self._port.setRTS (False) + time.sleep(0.01) + #print('-- IO16 to LOW, RESET to HIGH --') + # Pull IO16 to low and release reset + self._port.setRTS (True) + self._port.setDTR (False) + time.sleep(0.01) + + def reset_to_isp_dan(self): + self._port.dtr = False + self._port.rts = False + time.sleep(0.01) + #print('-- RESET to LOW, IO16 to HIGH --') + # Pull reset down and keep 10ms + self._port.dtr = False + self._port.rts = True + time.sleep(0.01) + #print('-- IO16 to LOW, RESET to HIGH --') + # Pull IO16 to low and release reset + self._port.rts = False + self._port.dtr = True + time.sleep(0.01) + + def reset_to_boot(self): + self._port.setDTR (False) + self._port.setRTS (False) + time.sleep(0.01) + #print('-- RESET to LOW --') + # Pull reset down and keep 10ms + self._port.setRTS (False) + self._port.setDTR (True) + time.sleep(0.01) + #print('-- RESET to HIGH, BOOT --') + # Pull IO16 to low and release reset + self._port.setRTS (False) + self._port.setDTR (False) + time.sleep(0.01) + + def greeting(self): + self._port.write(b'\xc0\xc2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0') + op, reason, text = ISPResponse.parse(self.recv_one_return()) + + #print('MAIX return op:', ISPResponse.ISPOperation(op).name, 'reason:', ISPResponse.ErrorCode(reason).name) + + + def flash_greeting(self): + retry_count = 0 + while 1: + self._port.write(b'\xc0\xd2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0') + retry_count = retry_count + 1 + try: + op, reason, text = FlashModeResponse.parse(self.recv_one_return()) + except IndexError: + if retry_count > MAX_RETRY_TIMES: + print(ERROR_MSG,"Failed to Connect to K210's Stub",BASH_TIPS['DEFAULT']) + sys.exit(1) + time.sleep(0.1) + continue + print(WARN_MSG,"Unexcepted Return recevied, retrying...",BASH_TIPS['DEFAULT']) + #print('MAIX return op:', FlashModeResponse.Operation(op).name, 'reason:', + # FlashModeResponse.ErrorCode(reason).name) + if FlashModeResponse.Operation(op) == FlashModeResponse.Operation.ISP_NOP: + print(INFO_MSG,"Boot to Flashmode Successfully",BASH_TIPS['DEFAULT']) + break + else: + if retry_count > MAX_RETRY_TIMES: + print(ERROR_MSG,"Failed to Connect to K210's Stub",BASH_TIPS['DEFAULT']) + sys.exit(1) + print(WARN_MSG,"Unexcepted Return recevied, retrying...",BASH_TIPS['DEFAULT']) + time.sleep(0.1) + continue + + def boot(self, address=0x80000000): + print(INFO_MSG,"Booting From " + hex(address),BASH_TIPS['DEFAULT']) + + out = struct.pack('II', address, 0) + + crc32_checksum = struct.pack('I', binascii.crc32(out) & 0xFFFFFFFF) + + out = struct.pack('HH', 0xc5, 0x00) + crc32_checksum + out # op: ISP_MEMORY_WRITE: 0xc3 + self.write(out) + + def recv_debug(self): + op, reason, text = ISPResponse.parse(self.recv_one_return()) + #print('[RECV] op:', ISPResponse.ISPOperation(op).name, 'reason:', ISPResponse.ErrorCode(reason).name) + if text: + print('-' * 30) + print(text) + print('-' * 30) + if ISPResponse.ErrorCode(reason) not in (ISPResponse.ErrorCode.ISP_RET_DEFAULT, ISPResponse.ErrorCode.ISP_RET_OK): + print('Failed, retry, errcode=', hex(reason)) + return False + return True + + def flash_recv_debug(self): + op, reason, text = FlashModeResponse.parse(self.recv_one_return()) + #print('[Flash-RECV] op:', FlashModeResponse.Operation(op).name, 'reason:', + # FlashModeResponse.ErrorCode(reason).name) + if text: + print('-' * 30) + print(text) + print('-' * 30) + + if FlashModeResponse.ErrorCode(reason) not in (FlashModeResponse.ErrorCode.ISP_RET_OK, FlashModeResponse.ErrorCode.ISP_RET_OK): + print('Failed, retry') + return False + return True + + def init_flash(self, chip_type): + chip_type = int(chip_type) + print(INFO_MSG,"Selected Flash: ",("In-Chip", "On-Board")[chip_type],BASH_TIPS['DEFAULT']) + out = struct.pack('II', chip_type, 0) + crc32_checksum = struct.pack('I', binascii.crc32(out) & 0xFFFFFFFF) + + out = struct.pack('HH', 0xd7, 0x00) + crc32_checksum + out + + sent = self.write(out) + op, reason, text = FlashModeResponse.parse(self.recv_one_return()) + #print('MAIX return op:', FlashModeResponse.Operation(op).name, 'reason:', + # FlashModeResponse.ErrorCode(reason).name) + + def flash_dataframe(self, data, address=0x80000000): + DATAFRAME_SIZE = 1024 + data_chunks = chunks(data, DATAFRAME_SIZE) + #print('[DEBUG] flash dataframe | data length:', len(data)) + total_chunk = math.ceil(len(data)/DATAFRAME_SIZE) + + for n, chunk in enumerate(data_chunks): + while 1: + #print('[INFO] sending chunk', i, '@address', hex(address), 'chunklen', len(chunk)) + out = struct.pack('II', address, len(chunk)) + + crc32_checksum = struct.pack('I', binascii.crc32(out + chunk) & 0xFFFFFFFF) + + out = struct.pack('HH', 0xc3, 0x00) + crc32_checksum + out + chunk # op: ISP_MEMORY_WRITE: 0xc3 + sent = self.write(out) + #print('[INFO]', 'sent', sent, 'bytes', 'checksum', binascii.hexlify(crc32_checksum).decode()) + + address += len(chunk) + + if self.recv_debug(): + break + printProgressBar(n+1, total_chunk, prefix = 'Downloading ISP:', suffix = 'Complete', length = 50) + + def dump_to_flash(self, data, address=0): + ''' + typedef struct __attribute__((packed)) { + uint8_t op; + int32_t checksum; // 下面的所有字段都要参与checksum的计算 + uint32_t address; + uint32_t data_len; + uint8_t data_buf[1024]; + } isp_request_t; + ''' + + DATAFRAME_SIZE = 4096 + data_chunks = chunks(data, DATAFRAME_SIZE) + #print('[DEBUG] flash dataframe | data length:', len(data)) + + + + for n, chunk in enumerate(data_chunks): + #print('[INFO] sending chunk', i, '@address', hex(address)) + out = struct.pack('II', address, len(chunk)) + + crc32_checksum = struct.pack('I', binascii.crc32(out + chunk) & 0xFFFFFFFF) + + out = struct.pack('HH', 0xd4, 0x00) + crc32_checksum + out + chunk + #print("[$$$$]", binascii.hexlify(out[:32]).decode()) + retry_count = 0 + while True: + try: + sent = self.write(out) + #print('[INFO]', 'sent', sent, 'bytes', 'checksum', crc32_checksum) + self.flash_recv_debug() + except: + retry_count = retry_count + 1 + if retry_count > MAX_RETRY_TIMES: + print(ERROR_MSG,"Error Count Exceeded, Stop Trying",BASH_TIPS['DEFAULT']) + sys.exit(1) + continue + break + address += len(chunk) + + + + def flash_erase(self): + #print('[DEBUG] erasing spi flash.') + self._port.write(b'\xc0\xd3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0') + op, reason, text = FlashModeResponse.parse(self.recv_one_return()) + #print('MAIX return op:', FlashModeResponse.Operation(op).name, 'reason:', + # FlashModeResponse.ErrorCode(reason).name) + + def install_flash_bootloader(self, data): + # 1. 刷入 flash bootloader + self.flash_dataframe(data, address=0x80000000) + + def flash_firmware(self, firmware_bin: bytes, aes_key: bytes = None, address_offset = 0, sha256Prefix = True): + #print('[DEBUG] flash_firmware DEBUG: aeskey=', aes_key) + + if sha256Prefix == True: + # 固件加上头 + # 格式: SHA256(after)(32bytes) + AES_CIPHER_FLAG (1byte) + firmware_size(4bytes) + firmware_data + aes_cipher_flag = b'\x01' if aes_key else b'\x00' + + # 加密 + if aes_key: + enc = AES_128_CBC(aes_key, iv=b'\x00'*16).encrypt + padded = firmware_bin + b'\x00'*15 # zero pad + firmware_bin = b''.join([enc(padded[i*16:i*16+16]) for i in range(len(padded)//16)]) + + firmware_len = len(firmware_bin) + + data = aes_cipher_flag + struct.pack('I', firmware_len) + firmware_bin + + sha256_hash = hashlib.sha256(data).digest() + + firmware_with_header = data + sha256_hash + + total_chunk = math.ceil(len(firmware_with_header)/4096) + # 3. 分片刷入固件 + data_chunks = chunks(firmware_with_header, 4096) # 4kb for a sector + else: + total_chunk = math.ceil(len(firmware_bin)/4096) + data_chunks = chunks(firmware_bin, 4096) + + for n, chunk in enumerate(data_chunks): + chunk = chunk.ljust(4096, b'\x00') # align by 4kb + + # 3.1 刷入一个dataframe + #print('[INFO]', 'Write firmware data piece') + self.dump_to_flash(chunk, address= n * 4096 + address_offset) + printProgressBar(n+1, total_chunk, prefix = 'Downloading:', suffix = 'Complete', length = 50) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("-p", "--port", help="COM Port", default="DEFAULT") + parser.add_argument("-c", "--chip", help="SPI Flash type, 1 for in-chip, 0 for on-board", default=1) + parser.add_argument("-b", "--baudrate", type=int, help="UART baudrate for uploading firmware", default=115200) + parser.add_argument("-l", "--bootloader", help="bootloader bin path", required=False, default=None) + parser.add_argument("-k", "--key", help="AES key in hex, if you need encrypt your firmware.", required=False, default=None) + parser.add_argument("-v", "--verbose", help="increase output verbosity", default=False, + action="store_true") + parser.add_argument("-t", "--terminal", help="Start a terminal after finish", default=False, action="store_true") + parser.add_argument("firmware", help="firmware bin path") + + args = parser.parse_args() + if args.port == "DEFAULT": + try: + list_port_info = next(serial.tools.list_ports.grep(VID_LIST_FOR_AUTO_LOOKUP)) #Take the first one within the list + print(INFO_MSG,"COM Port Auto Detected, Selected ",list_port_info.device,BASH_TIPS['DEFAULT']) + _port = list_port_info.device + except StopIteration: + print(ERROR_MSG,"No vaild COM Port found in Auto Detect, Check Your Connection or Specify One by"+BASH_TIPS['GREEN']+'`--port/-p`',BASH_TIPS['DEFAULT']) + sys.exit(1) + else: + _port = args.port + print(INFO_MSG,"COM Port Selected Manually: ",_port,BASH_TIPS['DEFAULT']) + + loader = MAIXLoader(port=_port, baudrate=115200) + + + # 1. Greeting. + print(INFO_MSG,"Trying to Enter the ISP Mode...",BASH_TIPS['DEFAULT']) + + retry_count = 0 + + while 1: + retry_count = retry_count + 1 + if retry_count > 15: + print("\n" + ERROR_MSG,"No vaild Kendryte K210 found in Auto Detect, Check Your Connection or Specify One by"+BASH_TIPS['GREEN']+'`-p '+('/dev/ttyUSB0', 'COM3')[sys.platform == 'win32']+'`',BASH_TIPS['DEFAULT']) + sys.exit(1) + try: + print('.', end='') + loader.reset_to_isp_dan() + loader.greeting() + break + except TimeoutError: + pass + + try: + print('_', end='') + loader.reset_to_isp_kd233() + loader.greeting() + break + except TimeoutError: + pass + timeout = 3 + print() + print(INFO_MSG,"Greeting Message Detected, Start Downloading ISP",BASH_TIPS['DEFAULT']) + # 2. flash bootloader and firmware + try: + firmware_bin = open(args.firmware, 'rb') + except FileNotFoundError: + print(ERROR_MSG,'Unable to find the firmware at ', args.firmware, BASH_TIPS['DEFAULT']) + sys.exit(1) + + # install bootloader at 0x80000000 + if args.bootloader: + loader.install_flash_bootloader(open(args.bootloader, 'rb').read()) + else: + loader.install_flash_bootloader(ISP_PROG) + + loader.boot() + + print(INFO_MSG,"Wait For 0.3 second for ISP to Boot", BASH_TIPS['DEFAULT']) + + time.sleep(0.3) + + loader.flash_greeting() + + if args.baudrate != 115200: + loader.change_baudrate(args.baudrate) + + loader.init_flash(args.chip) + + if ".kfpkg" == os.path.splitext(args.firmware)[1]: + print(INFO_MSG,"Extracting KFPKG ... ", BASH_TIPS['DEFAULT']) + firmware_bin.close() + with tempfile.TemporaryDirectory() as tmpdir: + try: + with zipfile.ZipFile(args.firmware) as zf: + zf.extractall(tmpdir) + except zipfile.BadZipFile: + print(ERROR_MSG,'Unable to Decompress the kfpkg, your file might be corrupted.',BASH_TIPS['DEFAULT']) + sys.exit(1) + + fFlashList = open(os.path.join(tmpdir, 'flash-list.json'), "r") + sFlashList = re.sub(r'"address": (.*),', r'"address": "\1",', fFlashList.read()) #Pack the Hex Number in json into str + fFlashList.close() + jsonFlashList = json.loads(sFlashList) + for lBinFiles in jsonFlashList['files']: + print(INFO_MSG,"Writing",lBinFiles['bin'],"into","0x%08x"%int(lBinFiles['address'], 0),BASH_TIPS['DEFAULT']) + firmware_bin = open(os.path.join(tmpdir, lBinFiles["bin"]), "rb") + loader.flash_firmware(firmware_bin.read(), None, int(lBinFiles['address'], 0), lBinFiles['sha256Prefix']) + firmware_bin.close() + else: + if args.key: + aes_key = binascii.a2b_hex(args.key) + if len(aes_key) != 16: + raise ValueError('AES key must by 16 bytes') + + loader.flash_firmware(firmware_bin.read(), aes_key=aes_key) + else: + loader.flash_firmware(firmware_bin.read()) + + # 3. boot + loader.reset_to_boot() + print(INFO_MSG,"Rebooting...", BASH_TIPS['DEFAULT']) + loader._port.close() + + if(args.terminal == True): + import serial.tools.miniterm + sys.argv = [''] + serial.tools.miniterm.main(default_port=_port, default_baudrate=115200, default_dtr=False, default_rts=False) diff --git a/tools/opensbi/README.md b/tools/opensbi/README.md index 79ad945a..2546f40f 100644 --- a/tools/opensbi/README.md +++ b/tools/opensbi/README.md @@ -7,3 +7,9 @@ These are binary release of OpenSBI on this [commit](https://github.com/riscv/op - virt_rv64.elf: opensbi-0.3-rv64-bin/platform/qemu/virt/firmware/fw_jump.elf NOTE: The [official v0.3 release](https://github.com/riscv/opensbi/releases/tag/v0.3) has bug on serial interrupt. + + + +For K210: It needs some modification. The binary is from this [commit](https://github.com/rcore-os/opensbi/commit/4400a1a7d40b5399b3e07b4bad9fd303885c8c16). + +* k210.elf: build/platform/kendryte/k210/firmware/fw_payload.elf \ No newline at end of file diff --git a/tools/opensbi/k210.elf b/tools/opensbi/k210.elf new file mode 100755 index 0000000000000000000000000000000000000000..221c37ee8d5589a181ed7c08f6d2b08429565d78 GIT binary patch literal 239264 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 Y4ix?{ZpyTNar)=>8|lvo1a literal 0 HcmV?d00001