├── THANKS ├── .gitignore ├── src ├── charm.h └── charm.c ├── README.md ├── LICENSE ├── verify ├── xoodoo.saw ├── verify-xoodoo.sh └── xoodoo.cry └── .clang-format /THANKS: -------------------------------------------------------------------------------- 1 | The Xoodoo permutation was designed by 2 | 3 | Joan Daemen 4 | Seth Hoffert, 5 | Gilles Van Assche 6 | Ronny Van Keer 7 | 8 | Its implementation in Charm is based on the reference 9 | implementation by Ronny Van Keer. 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | *.bc 10 | 11 | # Linker output 12 | *.ilk 13 | *.map 14 | *.exp 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Libraries 21 | *.lib 22 | *.a 23 | *.la 24 | *.lo 25 | 26 | # Shared objects (inc. Windows DLLs) 27 | *.dll 28 | *.so 29 | *.so.* 30 | *.dylib 31 | 32 | # Executables 33 | *.exe 34 | *.out 35 | *.app 36 | *.i*86 37 | *.x86_64 38 | *.hex 39 | 40 | # Debug files 41 | *.dSYM/ 42 | *.su 43 | *.idb 44 | *.pdb 45 | 46 | # Kernel Module Compile Results 47 | *.mod* 48 | *.cmd 49 | .tmp_versions/ 50 | modules.order 51 | Module.symvers 52 | Mkfile.old 53 | dkms.conf 54 | -------------------------------------------------------------------------------- /src/charm.h: -------------------------------------------------------------------------------- 1 | #ifndef charm_H 2 | #define charm_H 1 3 | 4 | #include 5 | #include 6 | 7 | void uc_state_init(uint32_t st[12], const unsigned char key[32], const unsigned char iv[16]); 8 | 9 | void uc_encrypt(uint32_t st[12], unsigned char *msg, size_t msg_len, unsigned char tag[16]); 10 | 11 | int uc_decrypt(uint32_t st[12], unsigned char *msg, size_t msg_len, 12 | const unsigned char *expected_tag, size_t expected_tag_len); 13 | 14 | void uc_hash(uint32_t st[12], unsigned char h[32], const unsigned char *msg, size_t len); 15 | 16 | void uc_memzero(void *buf, size_t len); 17 | 18 | void uc_randombytes_buf(void *buf, size_t len); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # charm 2 | 3 | A tiny, self-contained cryptography library, implementing authenticated 4 | encryption and keyed hashing. 5 | 6 | Charm uses the Xoodoo\[12\] ([paper](https://tosc.iacr.org/index.php/ToSC/article/view/7359/6529), 7 | [presentation](https://permutationbasedcrypto.org/2018/slides/Gilles_Van_Assche.pdf)) 8 | permutation, which can be replaced by AES-based [simpira384](https://github.com/jedisct1/simpira384), Areion, or Gimli, in a duplex mode. 9 | 10 | The Xoodoo implementations in Charm are [formally verified](https://github.com/jedisct1/charm/tree/master/verify) against a Cryptol specification. 11 | 12 | Users: 13 | 14 | - [dsvpn](https://github.com/jedisct1/dsvpn): a Dead Simple VPN, designed to address the most common use case for using a VPN. 15 | 16 | Other implementations: 17 | 18 | - [zig-charm](https://github.com/jedisct1/zig-charm): an implementation of Charm in the Zig language. 19 | - [charm.js](https://github.com/jedisct1/charm.js): a JavaScript (TypeScript) implementation. 20 | - [go-charm](https://github.com/x13a/go-charm): a Go implementation. 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2025 Frank Denis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /verify/xoodoo.saw: -------------------------------------------------------------------------------- 1 | set_base 16; 2 | 3 | print "Importing Cryptol spec for Xoodoo"; 4 | import "xoodoo.cry"; 5 | 6 | let alloc_init ty v = do { 7 | p <- crucible_alloc ty; 8 | crucible_points_to p v; 9 | return p; 10 | }; 11 | 12 | let ptr_to_fresh n ty = do { 13 | x <- crucible_fresh_var n ty; 14 | p <- alloc_init ty (crucible_term x); 15 | return (x, p); 16 | }; 17 | 18 | charm_bc <- llvm_load_module "charm.bc"; 19 | charm_opt_bc <- llvm_load_module "charm-opt.bc"; 20 | 21 | let permute_spec = do { 22 | // Preconditions: amounts to having a symbolic array somewhere in memory, and a pointer to it 23 | (st, st_ptr) <- ptr_to_fresh "st" (llvm_array 12 (llvm_int 32)); 24 | 25 | // Execution is just passing the pointer into the function 26 | crucible_execute_func [st_ptr]; 27 | 28 | // Postcondition says that after running the function, `st_ptr` points to memory that contains the 29 | // same values that the spec would produce. Note that we use the `U32State` helpers to translate 30 | // the C-friendly array of `uint32_t`s into our Cryptol-friendly `State` type. 31 | crucible_points_to st_ptr (crucible_term {{ u32_state (permute (unu32_state st)) }}); 32 | }; 33 | 34 | let prove_permute mod solver = do { 35 | crucible_llvm_verify mod "permute" [] false permute_spec solver; 36 | }; 37 | 38 | print "Proving unoptimized permute equivalent to spec using ABC"; 39 | result <- with_time (prove_permute charm_bc abc); 40 | print (str_concat "Proof finished in " (str_concat (show result.0) "ms")); 41 | 42 | print "Proving -O1 optimized permute equivalent to spec using ABC"; 43 | result <- with_time (prove_permute charm_opt_bc abc); 44 | print (str_concat "Proof finished in " (str_concat (show result.0) "ms")); 45 | 46 | print "Verification succeeded!"; 47 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: true 6 | AlignConsecutiveDeclarations: true 7 | AlignEscapedNewlinesLeft: true 8 | AlignOperands: true 9 | AlignTrailingComments: true 10 | AllowAllParametersOfDeclarationOnNextLine: true 11 | AllowShortBlocksOnASingleLine: false 12 | AllowShortCaseLabelsOnASingleLine: false 13 | AllowShortFunctionsOnASingleLine: Inline 14 | AllowShortIfStatementsOnASingleLine: false 15 | AllowShortLoopsOnASingleLine: false 16 | AlwaysBreakAfterReturnType: None 17 | AlwaysBreakBeforeMultilineStrings: true 18 | AlwaysBreakTemplateDeclarations: true 19 | BinPackArguments: true 20 | BinPackParameters: true 21 | BraceWrapping: 22 | AfterClass: false 23 | AfterControlStatement: false 24 | AfterEnum: false 25 | AfterFunction: true 26 | AfterNamespace: false 27 | AfterObjCDeclaration: false 28 | AfterStruct: false 29 | AfterUnion: false 30 | BeforeCatch: false 31 | BeforeElse: false 32 | IndentBraces: false 33 | BreakBeforeBinaryOperators: None 34 | BreakBeforeBraces: WebKit 35 | BreakBeforeTernaryOperators: true 36 | BreakConstructorInitializersBeforeComma: true 37 | BreakAfterJavaFieldAnnotations: false 38 | BreakStringLiterals: true 39 | ColumnLimit: 100 40 | CommentPragmas: '^ IWYU pragma:' 41 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 42 | ConstructorInitializerIndentWidth: 4 43 | ContinuationIndentWidth: 4 44 | Cpp11BracedListStyle: false 45 | DerivePointerAlignment: false 46 | DisableFormat: false 47 | ExperimentalAutoDetectBinPacking: true 48 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 49 | IncludeCategories: 50 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 51 | Priority: 2 52 | - Regex: '^(<|"(gtest|isl|json)/)' 53 | Priority: 3 54 | - Regex: '.*' 55 | Priority: 1 56 | IncludeIsMainRegex: '$' 57 | IndentCaseLabels: false 58 | IndentWidth: 4 59 | IndentWrappedFunctionNames: false 60 | JavaScriptQuotes: Leave 61 | JavaScriptWrapImports: true 62 | KeepEmptyLinesAtTheStartOfBlocks: false 63 | MacroBlockBegin: '' 64 | MacroBlockEnd: '' 65 | MaxEmptyLinesToKeep: 1 66 | NamespaceIndentation: Inner 67 | ObjCBlockIndentWidth: 4 68 | ObjCSpaceAfterProperty: true 69 | ObjCSpaceBeforeProtocolList: true 70 | PenaltyBreakBeforeFirstCallParameter: 19 71 | PenaltyBreakComment: 300 72 | PenaltyBreakFirstLessLess: 120 73 | PenaltyBreakString: 1000 74 | PenaltyExcessCharacter: 1000000 75 | PenaltyReturnTypeOnItsOwnLine: 60 76 | PointerAlignment: Right 77 | ReflowComments: true 78 | SortIncludes: true 79 | SpaceAfterCStyleCast: true 80 | SpaceAfterTemplateKeyword: true 81 | SpaceBeforeAssignmentOperators: true 82 | SpaceBeforeParens: ControlStatements 83 | SpaceInEmptyParentheses: false 84 | SpacesBeforeTrailingComments: 1 85 | SpacesInAngles: false 86 | SpacesInContainerLiterals: true 87 | SpacesInCStyleCastParentheses: false 88 | SpacesInParentheses: false 89 | SpacesInSquareBrackets: false 90 | Standard: Cpp11 91 | TabWidth: 8 92 | UseTab: Never 93 | ... 94 | 95 | -------------------------------------------------------------------------------- /verify/verify-xoodoo.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This script formally verifies that the charm.c implementation of the Xoodoo permutation matches 4 | # the spec. The spec is implemented in Cryptol, a domain-specific language for cryptography, and 5 | # includes some properties about the spec itself that can optionally be proved. The Software 6 | # Analysis Workbench (SAW) builds formal models of the Cryptol specification, and the LLVM bitcode 7 | # generated from charm.c, and proves them equivalent using the ABC verification tool. 8 | # 9 | # I've tried to make the script check for dependencies, but you'll need clang between versions 3.6 10 | # and 7.x, and a distribution of SAW from https://saw.galois.com/downloads.html (you can build your 11 | # own if you don't mind setting up Haskell). 12 | # 13 | # If `saw` and `cryptol` aren't on your path, you can point to their installed directory with the 14 | # `SAW_BIN` environment variable. Likewise, you can specify a clang to use with the `CLANG` 15 | # environment variable. 16 | 17 | # Preliminary setup 18 | 19 | set -e 20 | 21 | [ -f verify-xoodoo.sh ] || ( 22 | echo "Must be run in the /verify directory" 23 | exit 1 24 | ) 25 | 26 | if [ -x "${SAW_BIN}/saw" ]; then 27 | echo "Using SAW executable at: ${SAW_BIN}/saw" 28 | SAW="${SAW_BIN}/saw" 29 | elif [ -x "$(command -v saw)" ]; then 30 | echo "Using SAW executable from PATH" 31 | SAW="saw" 32 | else 33 | echo "SAW not found in PATH or in the SAW_BIN=\"${SAW}\" directory" >&2 34 | echo "You can get SAW at https://saw.galois.com/downloads.html" >&2 35 | exit 1 36 | fi 37 | 38 | if [ -x "${SAW_BIN}/cryptol" ]; then 39 | echo "Using Cryptol executable at: ${SAW_BIN}/cryptol" 40 | CRYPTOL="${SAW_BIN}/cryptol" 41 | elif [ -x "$(command -v cryptol)" ]; then 42 | echo "Using Cryptol executable from PATH" 43 | CRYPTOL="cryptol" 44 | else 45 | echo "Cryptol not found in PATH or in the SAW_BIN=\"${CRYPTOL}\" directory" >&2 46 | echo "You can get Cryptol as part of the SAW distribution at https://saw.galois.com/downloads.html" >&2 47 | exit 1 48 | fi 49 | 50 | if [ -x "${CLANG}" ]; then 51 | echo "Using clang-7 executable at: ${CLANG}" 52 | elif [ -x "$(command -v clang-7)" ]; then 53 | echo "Using clang-7 executable from PATH" 54 | CLANG="clang-7" 55 | else 56 | echo "clang-7 not found in PATH or in environment variable CLANG=${CLANG}" >&2 57 | exit 1 58 | fi 59 | 60 | cleanup() { 61 | # always clean up the bitcode files generated for verification 62 | rm -f charm*.bc 63 | } 64 | trap cleanup EXIT 65 | 66 | # Cryptol spec proof or random test, depending on whether Yices is installed 67 | 68 | if [ -x "$(command -v yices)" ]; then 69 | echo "yices found in PATH; proving properties defined in the Cryptol spec" 70 | ${CRYPTOL} xoodoo.cry -c ":set prover=yices" -c ":prove" 71 | else 72 | echo "yices not found in PATH; running randomized property tests on the Cryptol spec" 73 | echo "(to prove properties instead, install yices from https://yices.csl.sri.com/" 74 | ${CRYPTOL} xoodoo.cry -c ":set tests=1000" -c ":check" 75 | fi 76 | 77 | # Build LLVM bitcodes from C implementation (-O2 seems to produce bitcode with a GEP instruction SAW 78 | # doesn't like) 79 | 80 | echo "Building unoptimized LLVM bitcode from charm.c" 81 | ${CLANG} -g -c ../src/charm.c -emit-llvm -o charm.bc 82 | 83 | echo "Building -O1 optimized LLVM bitcode from charm.c" 84 | ${CLANG} -g -c ../src/charm.c -emit-llvm -O1 -o charm-opt.bc 85 | 86 | # And finally run the equivalence proofs 87 | 88 | echo "Running SAW proof script" 89 | ${SAW} xoodoo.saw 90 | -------------------------------------------------------------------------------- /src/charm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #ifdef __SSSE3__ 5 | #include 6 | #endif 7 | #if defined(__ARM_NEON) || defined(__aarch64__) 8 | #include 9 | #endif 10 | #ifdef __linux__ 11 | #ifndef _GNU_SOURCE 12 | #define _GNU_SOURCE 13 | #endif 14 | #include 15 | #include 16 | #endif 17 | 18 | #include "charm.h" 19 | 20 | #if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ 21 | __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 22 | #define NATIVE_BIG_ENDIAN 23 | #endif 24 | #ifndef NATIVE_BIG_ENDIAN 25 | #ifndef NATIVE_LITTLE_ENDIAN 26 | #define NATIVE_LITTLE_ENDIAN 27 | #endif 28 | #endif 29 | 30 | #ifndef XOODOO_ROUNDS 31 | #define XOODOO_ROUNDS 12 32 | #endif 33 | 34 | static inline void mem_cpy(unsigned char *dst, const unsigned char *src, size_t n) 35 | { 36 | size_t i; 37 | for (i = 0; i < n; i++) { 38 | dst[i] = src[i]; 39 | } 40 | } 41 | 42 | static const uint32_t RK[12] = { 0x058, 0x038, 0x3c0, 0x0d0, 0x120, 0x014, 43 | 0x060, 0x02c, 0x380, 0x0f0, 0x1a0, 0x012 }; 44 | 45 | #ifdef __SSSE3__ 46 | #define ROL32in128(x, b) _mm_or_si128(_mm_slli_epi32((x), (b)), _mm_srli_epi32((x), 32 - (b))) 47 | 48 | static void permute(uint32_t st[12]) 49 | { 50 | const __m128i rhoEast2 = _mm_set_epi32(0x06050407, 0x02010003, 0x0e0d0c0f, 0x0a09080b); 51 | __m128i a, b, c, p, e; 52 | int r; 53 | 54 | a = _mm_loadu_si128((const __m128i *) (const void *) &st[0]); 55 | b = _mm_loadu_si128((const __m128i *) (const void *) &st[4]); 56 | c = _mm_loadu_si128((const __m128i *) (const void *) &st[8]); 57 | for (r = 0; r < XOODOO_ROUNDS; r++) { 58 | p = _mm_shuffle_epi32(_mm_xor_si128(_mm_xor_si128(a, b), c), 0x93); 59 | e = ROL32in128(p, 5); 60 | p = ROL32in128(p, 14); 61 | e = _mm_xor_si128(e, p); 62 | a = _mm_xor_si128(a, e); 63 | b = _mm_xor_si128(b, e); 64 | c = _mm_xor_si128(c, e); 65 | b = _mm_shuffle_epi32(b, 0x93); 66 | c = ROL32in128(c, 11); 67 | a = _mm_xor_si128(a, _mm_set_epi32(0, 0, 0, RK[r])); 68 | a = _mm_xor_si128(a, _mm_andnot_si128(b, c)); 69 | b = _mm_xor_si128(b, _mm_andnot_si128(c, a)); 70 | c = _mm_xor_si128(c, _mm_andnot_si128(a, b)); 71 | b = ROL32in128(b, 1); 72 | c = _mm_shuffle_epi8(c, rhoEast2); 73 | } 74 | _mm_storeu_si128((__m128i *) (void *) &st[0], a); 75 | _mm_storeu_si128((__m128i *) (void *) &st[4], b); 76 | _mm_storeu_si128((__m128i *) (void *) &st[8], c); 77 | } 78 | #elif defined(__ARM_NEON) || defined(__aarch64__) 79 | #define ROL32in128(x, b) vsriq_n_u32(vshlq_n_u32((x), (b)), (x), 32 - (b)) 80 | 81 | static void permute(uint32_t st[12]) 82 | { 83 | uint32x4_t a, b, c, d, e, f; 84 | int r; 85 | 86 | a = vld1q_u32((const uint32_t *) (const void *) &st[0]); 87 | b = vld1q_u32((const uint32_t *) (const void *) &st[4]); 88 | c = vld1q_u32((const uint32_t *) (const void *) &st[8]); 89 | for (r = 0; r < XOODOO_ROUNDS; r++) { 90 | d = veorq_u32(veorq_u32(a, b), c); 91 | d = vextq_u32(d, d, 3); 92 | e = ROL32in128(d, 5); 93 | f = ROL32in128(d, 14); 94 | e = veorq_u32(e, f); 95 | a = veorq_u32(a, e); 96 | b = veorq_u32(b, e); 97 | f = veorq_u32(c, e); 98 | c = ROL32in128(f, 11); 99 | b = vextq_u32(b, b, 3); 100 | a = veorq_u32(a, vsetq_lane_u32(RK[r], vmovq_n_u32(0), 0)); 101 | e = vbicq_u32(c, b); 102 | d = vbicq_u32(a, c); 103 | f = vbicq_u32(b, a); 104 | a = veorq_u32(a, e); 105 | d = veorq_u32(b, d); 106 | c = veorq_u32(c, f); 107 | f = vextq_u32(c, c, 2); 108 | b = ROL32in128(d, 1); 109 | c = ROL32in128(f, 8); 110 | } 111 | vst1q_u32((uint32_t *) (void *) &st[0], a); 112 | vst1q_u32((uint32_t *) (void *) &st[4], b); 113 | vst1q_u32((uint32_t *) (void *) &st[8], c); 114 | } 115 | #else 116 | #define ROTR32(x, b) (uint32_t) (((x) >> (b)) | ((x) << (32 - (b)))) 117 | #define SWAP32(s, u, v) \ 118 | do { \ 119 | t = (s)[u]; \ 120 | (s)[u] = (s)[v], (s)[v] = t; \ 121 | } while (0) 122 | 123 | static void permute(uint32_t st[12]) 124 | { 125 | uint32_t e[4], a, b, c, t, r, i; 126 | 127 | for (r = 0; r < XOODOO_ROUNDS; r++) { 128 | for (i = 0; i < 4; i++) { 129 | e[i] = ROTR32(st[i] ^ st[i + 4] ^ st[i + 8], 18); 130 | e[i] ^= ROTR32(e[i], 9); 131 | } 132 | for (i = 0; i < 12; i++) { 133 | st[i] ^= e[(i - 1) & 3]; 134 | } 135 | SWAP32(st, 7, 4); 136 | SWAP32(st, 7, 5); 137 | SWAP32(st, 7, 6); 138 | st[0] ^= RK[r]; 139 | for (i = 0; i < 4; i++) { 140 | a = st[i]; 141 | b = st[i + 4]; 142 | c = ROTR32(st[i + 8], 21); 143 | st[i + 8] = ROTR32((b & ~a) ^ c, 24); 144 | st[i + 4] = ROTR32((a & ~c) ^ b, 31); 145 | st[i] ^= c & ~b; 146 | } 147 | SWAP32(st, 8, 10); 148 | SWAP32(st, 9, 11); 149 | } 150 | } 151 | #endif 152 | 153 | static inline void endian_swap_rate(uint32_t st[12]) 154 | { 155 | (void) st; 156 | #ifdef NATIVE_BIG_ENDIAN 157 | size_t i; 158 | for (i = 0; i < 4; i++) { 159 | st[i] = __builtin_bswap32(st[i]); 160 | } 161 | #endif 162 | } 163 | 164 | static inline void endian_swap_all(uint32_t st[12]) 165 | { 166 | (void) st; 167 | #ifdef NATIVE_BIG_ENDIAN 168 | size_t i; 169 | for (i = 0; i < 12; i++) { 170 | st[i] = __builtin_bswap32(st[i]); 171 | } 172 | #endif 173 | } 174 | 175 | static inline void xor128(void *out, const void *in) 176 | { 177 | #ifdef __SSSE3__ 178 | _mm_storeu_si128((__m128i *) out, 179 | _mm_xor_si128(_mm_loadu_si128((const __m128i *) out), 180 | _mm_loadu_si128((const __m128i *) in))); 181 | #else 182 | unsigned char *out_ = (unsigned char *) out; 183 | const unsigned char *in_ = (const unsigned char *) in; 184 | size_t i; 185 | 186 | for (i = 0; i < 16; i++) { 187 | out_[i] ^= in_[i]; 188 | } 189 | #endif 190 | } 191 | 192 | static volatile unsigned char optblocker; 193 | 194 | static inline int equals(const unsigned char a[16], const unsigned char b[16], size_t len) 195 | { 196 | unsigned char d = 0; 197 | size_t i; 198 | 199 | len &= 15; 200 | for (i = 0; i < len; i++) { 201 | d |= a[i] ^ b[i]; 202 | } 203 | return (1 ^ optblocker) & ((d - 1 ^ optblocker) >> 8); 204 | } 205 | 206 | static inline void squeeze_permute(uint32_t st[12], unsigned char dst[16]) 207 | { 208 | endian_swap_rate(st); 209 | memcpy(dst, st, 16); 210 | endian_swap_rate(st); 211 | permute(st); 212 | } 213 | 214 | void uc_state_init(uint32_t st[12], const unsigned char key[32], const unsigned char iv[16]) 215 | { 216 | if (iv != NULL) { 217 | memcpy(&st[0], iv, 16); 218 | } else { 219 | memset(&st[0], 0, 16); 220 | } 221 | memcpy(&st[4], key, 32); 222 | endian_swap_all(st); 223 | permute(st); 224 | } 225 | 226 | void uc_encrypt(uint32_t st[12], unsigned char *msg, size_t msg_len, unsigned char tag[16]) 227 | { 228 | unsigned char squeezed[16]; 229 | unsigned char padded[16 + 1]; 230 | size_t off = 0; 231 | size_t leftover; 232 | 233 | if (msg_len > 16) { 234 | for (; off < msg_len - 16; off += 16) { 235 | endian_swap_rate(st); 236 | memcpy(squeezed, st, 16); 237 | xor128(st, &msg[off]); 238 | endian_swap_rate(st); 239 | xor128(&msg[off], squeezed); 240 | permute(st); 241 | } 242 | } 243 | leftover = msg_len - off; 244 | memset(padded, 0, 16); 245 | mem_cpy(padded, &msg[off], leftover); 246 | padded[leftover] = 0x80; 247 | endian_swap_rate(st); 248 | memcpy(squeezed, st, 16); 249 | xor128(st, padded); 250 | endian_swap_rate(st); 251 | st[11] ^= (1UL << 24 | (uint32_t) leftover >> 4 << 25 | 1UL << 26); 252 | xor128(padded, squeezed); 253 | mem_cpy(&msg[off], padded, leftover); 254 | permute(st); 255 | squeeze_permute(st, tag); 256 | } 257 | 258 | int uc_decrypt(uint32_t st[12], unsigned char *msg, size_t msg_len, 259 | const unsigned char *expected_tag, size_t expected_tag_len) 260 | { 261 | unsigned char tag[16]; 262 | unsigned char squeezed[16]; 263 | unsigned char padded[16 + 1]; 264 | size_t off = 0; 265 | size_t leftover; 266 | 267 | if (msg_len > 16) { 268 | for (; off < msg_len - 16; off += 16) { 269 | endian_swap_rate(st); 270 | memcpy(squeezed, st, 16); 271 | xor128(&msg[off], squeezed); 272 | xor128(st, &msg[off]); 273 | endian_swap_rate(st); 274 | permute(st); 275 | } 276 | } 277 | leftover = msg_len - off; 278 | memset(padded, 0, 16); 279 | mem_cpy(padded, &msg[off], leftover); 280 | endian_swap_rate(st); 281 | memset(squeezed, 0, 16); 282 | mem_cpy(squeezed, (const unsigned char *) (const void *) st, leftover); 283 | xor128(&padded, squeezed); 284 | padded[leftover] = 0x80; 285 | xor128(st, padded); 286 | endian_swap_rate(st); 287 | st[11] ^= (1UL << 24 | (uint32_t) leftover >> 4 << 25 | 1UL << 26); 288 | mem_cpy(&msg[off], padded, leftover); 289 | permute(st); 290 | squeeze_permute(st, tag); 291 | if (equals(expected_tag, tag, expected_tag_len) == 0) { 292 | memset(msg, 0, msg_len); 293 | return -1; 294 | } 295 | return 0; 296 | } 297 | 298 | void uc_hash(uint32_t st[12], unsigned char h[32], const unsigned char *msg, size_t len) 299 | { 300 | unsigned char padded[16 + 1]; 301 | size_t off = 0; 302 | size_t leftover; 303 | 304 | if (len > 16) { 305 | for (; off < len - 16; off += 16) { 306 | endian_swap_rate(st); 307 | xor128(st, &msg[off]); 308 | endian_swap_rate(st); 309 | permute(st); 310 | } 311 | } 312 | leftover = len - off; 313 | memset(padded, 0, 16); 314 | mem_cpy(padded, &msg[off], leftover); 315 | padded[leftover] = 0x80; 316 | endian_swap_rate(st); 317 | xor128(st, padded); 318 | endian_swap_rate(st); 319 | st[11] ^= (1UL << 24 | (uint32_t) leftover >> 4 << 25); 320 | permute(st); 321 | squeeze_permute(st, &h[0]); 322 | squeeze_permute(st, &h[16]); 323 | } 324 | 325 | void uc_memzero(void *buf, size_t len) 326 | { 327 | volatile unsigned char *volatile buf_ = (volatile unsigned char *volatile) buf; 328 | size_t i = (size_t) 0U; 329 | 330 | while (i < len) { 331 | buf_[i++] = 0U; 332 | } 333 | } 334 | 335 | void uc_randombytes_buf(void *buf, size_t len) 336 | { 337 | #ifdef __linux__ 338 | if ((size_t) syscall(SYS_getrandom, buf, (int) len, 0) != len) { 339 | abort(); 340 | } 341 | #else 342 | arc4random_buf(buf, len); 343 | #endif 344 | } 345 | -------------------------------------------------------------------------------- /verify/xoodoo.cry: -------------------------------------------------------------------------------- 1 | // Cryptol implementation of the Xoodoo permutation function based on the spec in the paper 2 | // 3 | // 4 | // Developed by Adam C. Foltzer for verification of charm 5 | 6 | module Xoodoo where 7 | 8 | type Rounds = 12 9 | 10 | type RoundIx = [width (Rounds-1)] 11 | 12 | // There are definitely more type aliases and helpers here than are strictly necessary, but it 13 | // avoids confusion about which end of the various sequences to index from 14 | 15 | type Lane = [32] 16 | 17 | type LaneIx = [width 32-1] 18 | 19 | // index from the end due to big-endian word representation 20 | bit_of_lane : Lane -> LaneIx -> Bit 21 | bit_of_lane l z = l ! z 22 | 23 | type Plane = [4]Lane 24 | 25 | type PlaneIx = [width 4-1] 26 | 27 | lane_of_plane : Plane -> PlaneIx -> Lane 28 | lane_of_plane a x = a @ x 29 | 30 | bit_of_plane : Plane -> (PlaneIx, LaneIx) -> Bit 31 | bit_of_plane a (x, z) = bit_of_lane (lane_of_plane a x) z 32 | 33 | type State = [3]Plane 34 | 35 | type StateIx = [width 3-1] 36 | 37 | plane_of_state : State -> StateIx -> Plane 38 | plane_of_state s i = s @ i 39 | 40 | bit_of_state : State -> (PlaneIx, StateIx, LaneIx) -> Bit 41 | bit_of_state s (x, y, z) = bit_of_lane (lane_of_plane (plane_of_state s y) x) z 42 | 43 | cyclic_shift : Plane -> (PlaneIx, LaneIx) -> Plane 44 | cyclic_shift a (t, v) = 45 | [ lane <<< v | lane <- a ] >>> t 46 | 47 | property cyclic_shift_id_zero a = cyclic_shift a (0, 0) == a 48 | property cyclic_shift_correct a (t, v) = 49 | and [ bit_of_plane a (x, z) == bit_of_plane a' (x + t, z + v) | x <- [0..3], z <- [0..31] ] 50 | where 51 | a' = cyclic_shift a (t, v) 52 | 53 | theta : State -> State 54 | theta [a0, a1, a2] = [a0 ^ e, a1 ^ e, a2 ^ e] 55 | where 56 | e = cyclic_shift p (1, 5) ^ cyclic_shift p (1, 14) 57 | p = a0 ^ a1 ^ a2 58 | 59 | rho_west : State -> State 60 | rho_west [a0, a1, a2] = [a0, a1', a2'] 61 | where 62 | a1' = cyclic_shift a1 (1, 0) 63 | a2' = cyclic_shift a2 (0, 11) 64 | 65 | c : RoundIx -> Plane 66 | c i = [cis @ i, 0, 0, 0] 67 | where 68 | cis = [ 0x00000058, 0x00000038, 0x000003C0 69 | , 0x000000D0, 0x00000120, 0x00000014 70 | , 0x00000060, 0x0000002C, 0x00000380 71 | , 0x000000F0, 0x000001A0, 0x00000012 72 | ] 73 | 74 | iota : RoundIx -> State -> State 75 | iota i [a0, a1, a2] = [a0', a1, a2] 76 | where 77 | a0' = a0 ^ c i 78 | 79 | chi : State -> State 80 | chi [a0, a1, a2] = [a0 ^ b0, a1 ^ b1, a2 ^ b2] 81 | where 82 | b0 = ~a1 && a2 83 | b1 = ~a2 && a0 84 | b2 = ~a0 && a1 85 | 86 | rho_east : State -> State 87 | rho_east [a0, a1, a2] = [a0, a1', a2'] 88 | where 89 | a1' = cyclic_shift a1 (0, 1) 90 | a2' = cyclic_shift a2 (2, 8) 91 | 92 | round : RoundIx -> State -> State 93 | round i s = rho_east (chi (iota i (rho_west (theta s)))) 94 | 95 | // The main entrypoint; performs the full 12-round Xoodoo permutation 96 | permute : State -> State 97 | permute s0 = ss ! 0 98 | where 99 | ss = [s0] # [ round i s 100 | | s <- ss 101 | | i <- [0 .. 11] 102 | ] 103 | 104 | // The flattened representation found in the paper; not used by any implementation I've found yet 105 | type FlatState = [384] 106 | 107 | flatten_state : State -> FlatState 108 | flatten_state s = join (reverse [ join (reverse p) | p <- s ]) 109 | 110 | unflatten_state : FlatState -> State 111 | unflatten_state s = [ reverse (split `{4} a) | a <- reverse (split `{3} s) ] 112 | 113 | bit_of_flat_state : FlatState -> (PlaneIx, StateIx, LaneIx) -> Bit 114 | bit_of_flat_state fs (x, y, z) = fs ! i 115 | where i = zext z + 32 * (zext x + 4 * (zext y : [width 384-1])) 116 | 117 | property flatten_index_correct s (x, y, z) = 118 | bit_of_state s (x, y, z) == bit_of_flat_state (flatten_state s) (x, y, z) 119 | 120 | property unflatten_index_correct fs (x, y, z) = 121 | bit_of_state (unflatten_state fs) (x, y, z) == bit_of_flat_state fs (x, y, z) 122 | 123 | property flat_inv1 s = unflatten_state (flatten_state s) == s 124 | property flat_inv2 fs = flatten_state (unflatten_state fs) == fs 125 | 126 | // This is the representation used by the reference implementation and charm.c, so this type works 127 | // as an adapter when writing the verification property 128 | type U32State = [12][32] 129 | 130 | u32_state : State -> U32State 131 | u32_state s = join s 132 | 133 | unu32_state : U32State -> State 134 | unu32_state us = split us 135 | 136 | property u32_inv1 s = unu32_state (u32_state s) == s 137 | property u32_inv2 us = u32_state (unu32_state us) == us 138 | 139 | //////////////////////////////////////////////////////////////////////////////////////////////////// 140 | // Test vector/debugging 141 | //////////////////////////////////////////////////////////////////////////////////////////////////// 142 | 143 | // Run the round function, but keep all of the intermediate states around for debugging 144 | round_expanded : RoundIx -> State -> [5]State 145 | round_expanded i s0 = drop `{1} ss 146 | where 147 | ss = [s0] # [ f s | s <- ss | f <- [theta, rho_west, iota i, chi, rho_east] ] 148 | 149 | // Run the permute function, but keep all of the intermediate states around for debugging 150 | permute_expanded : State -> [12][5]State 151 | permute_expanded s0 = ss 152 | where 153 | ss = [round_expanded 0 s0] # [ round_expanded i (s ! 0) | s <- ss | i <- [1 .. 11] ] 154 | 155 | /// These intermediate states were generated by dumping output from the reference implementation in 156 | /// 157 | property reference_states_match = permute_expanded zero == reference_states 158 | 159 | reference_states : [12][5]State 160 | reference_states = 161 | [ 162 | // round 0 163 | [ 164 | // state after theta 165 | [[0x00000000, 0x00000000, 0x00000000, 0x00000000], 166 | [0x00000000, 0x00000000, 0x00000000, 0x00000000], 167 | [0x00000000, 0x00000000, 0x00000000, 0x00000000]], 168 | // state after rho_west 169 | [[0x00000000, 0x00000000, 0x00000000, 0x00000000], 170 | [0x00000000, 0x00000000, 0x00000000, 0x00000000], 171 | [0x00000000, 0x00000000, 0x00000000, 0x00000000]], 172 | // state after iota 0 173 | [[0x00000058, 0x00000000, 0x00000000, 0x00000000], 174 | [0x00000000, 0x00000000, 0x00000000, 0x00000000], 175 | [0x00000000, 0x00000000, 0x00000000, 0x00000000]], 176 | // state after chi 177 | [[0x00000058, 0x00000000, 0x00000000, 0x00000000], 178 | [0x00000058, 0x00000000, 0x00000000, 0x00000000], 179 | [0x00000000, 0x00000000, 0x00000000, 0x00000000]], 180 | // state after rho_east 181 | [[0x00000058, 0x00000000, 0x00000000, 0x00000000], 182 | [0x000000b0, 0x00000000, 0x00000000, 0x00000000], 183 | [0x00000000, 0x00000000, 0x00000000, 0x00000000]]], 184 | 185 | // etc 186 | 187 | [[[0x00000058, 0x003a1d00, 0x00000000, 0x00000000], 188 | [0x000000b0, 0x003a1d00, 0x00000000, 0x00000000], 189 | [0x00000000, 0x003a1d00, 0x00000000, 0x00000000]], 190 | 191 | [[0x00000058, 0x003a1d00, 0x00000000, 0x00000000], 192 | [0x00000000, 0x000000b0, 0x003a1d00, 0x00000000], 193 | [0x00000000, 0xd0e80001, 0x00000000, 0x00000000]], 194 | 195 | [[0x00000060, 0x003a1d00, 0x00000000, 0x00000000], 196 | [0x00000000, 0x000000b0, 0x003a1d00, 0x00000000], 197 | [0x00000000, 0xd0e80001, 0x00000000, 0x00000000]], 198 | 199 | [[0x00000060, 0xd0d21d01, 0x00000000, 0x00000000], 200 | [0x00000060, 0x00121db0, 0x003a1d00, 0x00000000], 201 | [0x00000000, 0xd0e800b1, 0x003a1d00, 0x00000000]], 202 | 203 | [[0x00000060, 0xd0d21d01, 0x00000000, 0x00000000], 204 | [0x000000c0, 0x00243b60, 0x00743a00, 0x00000000], 205 | [0x3a1d0000, 0x00000000, 0x00000000, 0xe800b1d0]]], 206 | 207 | 208 | [[[0x2c62007d, 0xd35a0781, 0x975cb807, 0x0007401d], 209 | [0x2c6200dd, 0x03ac21e0, 0x97288207, 0x0007401d], 210 | [0x167f001d, 0x03881a80, 0x975cb807, 0xe807f1cd]], 211 | 212 | [[0x2c62007d, 0xd35a0781, 0x975cb807, 0x0007401d], 213 | [0x0007401d, 0x2c6200dd, 0x03ac21e0, 0x97288207], 214 | [0xf800e8b3, 0x40d4001c, 0xe5c03cba, 0x3f8e6f40]], 215 | 216 | [[0x2c6203bd, 0xd35a0781, 0x975cb807, 0x0007401d], 217 | [0x0007401d, 0x2c6200dd, 0x03ac21e0, 0x97288207], 218 | [0xf800e8b3, 0x40d4001c, 0xe5c03cba, 0x3f8e6f40]], 219 | 220 | [[0xd462ab1f, 0x93ce0781, 0x731ca41d, 0x28812d5d], 221 | [0x04654311, 0xbf68075c, 0x11b0a1e5, 0x9729821a], 222 | [0xf805a8b3, 0x6cf40040, 0xe5603d5a, 0xa8a6ed42]], 223 | 224 | [[0xd462ab1f, 0x93ce0781, 0x731ca41d, 0x28812d5d], 225 | [0x08ca8622, 0x7ed00eb9, 0x236143ca, 0x2e530435], 226 | [0x603d5ae5, 0xa6ed42a8, 0x05a8b3f8, 0xf400406c]]], 227 | 228 | [[[0x146eb735, 0x5c96d3b3, 0xdf91c4e8, 0xc7207dc2], 229 | [0xc8c69a08, 0xb188da8b, 0x8fec233f, 0xc1f254aa], 230 | [0xa03146cf, 0x69b5969a, 0xa925d30d, 0x1ba110f3]], 231 | 232 | [[0x146eb735, 0x5c96d3b3, 0xdf91c4e8, 0xc7207dc2], 233 | [0xc1f254aa, 0xc8c69a08, 0xb188da8b, 0x8fec233f], 234 | [0x8a367d01, 0xacb4d34d, 0x2e986d49, 0x088798dd]], 235 | 236 | [[0x146eb7e5, 0x5c96d3b3, 0xdf91c4e8, 0xc7207dc2], 237 | [0xc1f254aa, 0xc8c69a08, 0xb188da8b, 0x8fec233f], 238 | [0x8a367d01, 0xacb4d34d, 0x2e986d49, 0x088798dd]], 239 | 240 | [[0x1e6a9ee4, 0x78a692f6, 0xd181e1a8, 0xc723e502], 241 | [0xd5bad64e, 0x98c49aba, 0x60895a2b, 0x48cc463d], 242 | [0x4ba63d0b, 0x2cf4db45, 0x0e90774a, 0x004b9ae0]], 243 | 244 | [[0x1e6a9ee4, 0x78a692f6, 0xd181e1a8, 0xc723e502], 245 | [0xab75ac9d, 0x31893575, 0xc112b456, 0x91988c7a], 246 | [0x90774a0e, 0x4b9ae000, 0xa63d0b4b, 0xf4db452c]]], 247 | 248 | 249 | [[[0x597a3ce8, 0xcbb45548, 0xd6c9d165, 0x85455e1f], 250 | [0xec650e91, 0x829bf2cb, 0xc65a849b, 0xd3fe3767], 251 | [0xd767e802, 0xf88827be, 0xa1753b86, 0xb6bdfe31]], 252 | 253 | [[0x597a3ce8, 0xcbb45548, 0xd6c9d165, 0x85455e1f], 254 | [0xd3fe3767, 0xec650e91, 0x829bf2cb, 0xc65a849b], 255 | [0x3f4016bb, 0x413df7c4, 0xa9dc350b, 0xeff18db5]], 256 | 257 | [[0x597a3dc8, 0xcbb45548, 0xd6c9d165, 0x85455e1f], 258 | [0xd3fe3767, 0xec650e91, 0x829bf2cb, 0xc65a849b], 259 | [0x3f4016bb, 0x413df7c4, 0xa9dc350b, 0xeff18db5]], 260 | 261 | [[0x757a3d50, 0xcaaca40c, 0xff8dd465, 0xace4573b], 262 | [0x93c41e27, 0x66e50e99, 0xd49a32af, 0xc65ed691], 263 | [0xbdc4149c, 0x657cfd55, 0xa9ce1781, 0xadeb0d35]], 264 | 265 | [[0x757a3d50, 0xcaaca40c, 0xff8dd465, 0xace4573b], 266 | [0x27883c4f, 0xcdca1d32, 0xa934655f, 0x8cbdad23], 267 | [0xce1781a9, 0xeb0d35ad, 0xc4149cbd, 0x7cfd5565]]], 268 | 269 | 270 | [[[0xca3085d2, 0x363115e6, 0x91d8bd02, 0xb2200362], 271 | [0x98c284cd, 0x3157acd8, 0xc7610c38, 0x9279f97a], 272 | [0x715d392b, 0x17908447, 0xaa41f5da, 0x6239013c]], 273 | 274 | [[0xca3085d2, 0x363115e6, 0x91d8bd02, 0xb2200362], 275 | [0x9279f97a, 0x98c284cd, 0x3157acd8, 0xc7610c38], 276 | [0xe9c95b8a, 0x842238bc, 0x0faed552, 0xc809e311]], 277 | 278 | [[0xca3085c6, 0x363115e6, 0x91d8bd02, 0xb2200362], 279 | [0x9279f97a, 0x98c284cd, 0x3157acd8, 0xc7610c38], 280 | [0xe9c95b8a, 0x842238bc, 0x0faed552, 0xc809e311]], 281 | 282 | [[0xa3b08746, 0x32112dd6, 0x9f70ec00, 0xba28e063], 283 | [0x90497d3e, 0xaad3818f, 0xa10784d8, 0xf5410c5a], 284 | [0xf98023b2, 0x0ce0b8b5, 0x2fa9d58a, 0x8d48ef09]], 285 | 286 | [[0xa3b08746, 0x32112dd6, 0x9f70ec00, 0xba28e063], 287 | [0x2092fa7d, 0x55a7031f, 0x420f09b1, 0xea8218b5], 288 | [0xa9d58a2f, 0x48ef098d, 0x8023b2f9, 0xe0b8b50c]]], 289 | 290 | 291 | [[[0x328f9014, 0x912ac5ee, 0x3d850f53, 0x04701e3f], 292 | [0xb1aded2f, 0xf69ceb27, 0xe0faeae2, 0x54dae6e9], 293 | [0x38ea9d7d, 0xebd4e1b5, 0x22d651aa, 0x5ee04b50]], 294 | 295 | [[0x328f9014, 0x912ac5ee, 0x3d850f53, 0x04701e3f], 296 | [0x54dae6e9, 0xb1aded2f, 0xf69ceb27, 0xe0faeae2], 297 | [0x54ebe9c7, 0xa70daf5e, 0xb28d5116, 0x025a82f7]], 298 | 299 | [[0x328f9074, 0x912ac5ee, 0x3d850f53, 0x04701e3f], 300 | [0x54dae6e9, 0xb1aded2f, 0xf69ceb27, 0xe0faeae2], 301 | [0x54ebe9c7, 0xa70daf5e, 0xb28d5116, 0x025a82f7]], 302 | 303 | [[0x32ae9972, 0x972ac7be, 0x3d841f43, 0x06701e2a], 304 | [0x76def6d9, 0xa18fad8f, 0xfb9ce566, 0xe4daf6ea], 305 | [0x10bb8f4e, 0x8788875f, 0x7095b132, 0xe2d06237]], 306 | 307 | [[0x32ae9972, 0x972ac7be, 0x3d841f43, 0x06701e2a], 308 | [0xedbdedb2, 0x431f5b1f, 0xf739cacd, 0xc9b5edd5], 309 | [0x95b13270, 0xd06237e2, 0xbb8f4e10, 0x88875f87]]], 310 | 311 | 312 | [[[0x71e507aa, 0x52ce031f, 0x5da1b636, 0x86c4f1a8], 313 | [0xaef6736a, 0x86fb9fbe, 0x971c63b8, 0x49010257], 314 | [0xd6faaca8, 0x1586f343, 0xdbaae765, 0x0833b005]], 315 | 316 | [[0x71e507aa, 0x52ce031f, 0x5da1b636, 0x86c4f1a8], 317 | [0x49010257, 0xaef6736a, 0x86fb9fbe, 0x971c63b8], 318 | [0xd56546b7, 0x379a18ac, 0x573b2edd, 0x9d802841]], 319 | 320 | [[0x71e50786, 0x52ce031f, 0x5da1b636, 0x86c4f1a8], 321 | [0x49010257, 0xaef6736a, 0x86fb9fbe, 0x971c63b8], 322 | [0xd56546b7, 0x379a18ac, 0x573b2edd, 0x9d802841]], 323 | 324 | [[0xe5814326, 0x43c60b9b, 0x0ca19677, 0x8e44f9e9], 325 | [0x69810357, 0xeeb27079, 0x8e7b0f9c, 0x9558b210], 326 | [0xdd6546e6, 0x9baa68cc, 0xd5612755, 0x8c982a51]], 327 | 328 | [[0xe5814326, 0x43c60b9b, 0x0ca19677, 0x8e44f9e9], 329 | [0xd30206ae, 0xdd64e0f3, 0x1cf61f39, 0x2ab16421], 330 | [0x612755d5, 0x982a518c, 0x6546e6dd, 0xaa68cc9b]]], 331 | 332 | 333 | [[[0x627faae0, 0xb35355d8, 0xf30fcb55, 0x778dd6c3], 334 | [0x54fcef68, 0x2df1beb0, 0xe358421b, 0xd3784b0b], 335 | [0xe6d9bc13, 0x68bf0fcf, 0x9ae8bbff, 0x53a1e3b1]], 336 | 337 | [[0x627faae0, 0xb35355d8, 0xf30fcb55, 0x778dd6c3], 338 | [0xd3784b0b, 0x54fcef68, 0x2df1beb0, 0xe358421b], 339 | [0xcde09f36, 0xf87e7b45, 0x45dffcd7, 0x0f1d8a9d]], 340 | 341 | [[0x627fa960, 0xb35355d8, 0xf30fcb55, 0x778dd6c3], 342 | [0xd3784b0b, 0x54fcef68, 0x2df1beb0, 0xe358421b], 343 | [0xcde09f36, 0xf87e7b45, 0x45dffcd7, 0x0f1d8a9d]], 344 | 345 | [[0x6eff3d54, 0x1b5145dd, 0xb3018b12, 0x7b885e47], 346 | [0xf1676b4b, 0x57fdebf0, 0x9ff1bdb0, 0x93d81659], 347 | [0x5ce0dd3d, 0xbcd2d165, 0x492fc877, 0x8f4d8a85]], 348 | 349 | [[0x6eff3d54, 0x1b5145dd, 0xb3018b12, 0x7b885e47], 350 | [0xe2ced697, 0xaffbd7e0, 0x3fe37b61, 0x27b02cb3], 351 | [0x2fc87749, 0x4d8a858f, 0xe0dd3d5c, 0xd2d165bc]]], 352 | 353 | 354 | [[[0xf60ff7ff, 0x03407c77, 0x92efc305, 0x0f3a20a5], 355 | [0x7a3e1c3c, 0xb7eaee4a, 0x1e0d3376, 0x53025251], 356 | [0xb738bde2, 0x559bbc25, 0xc133754b, 0xa6631b5e]], 357 | 358 | [[0xf60ff7ff, 0x03407c77, 0x92efc305, 0x0f3a20a5], 359 | [0x53025251, 0x7a3e1c3c, 0xb7eaee4a, 0x1e0d3376], 360 | [0xc5ef15b9, 0xdde12aac, 0x9baa5e09, 0x18daf533]], 361 | 362 | [[0xf60ff70f, 0x03407c77, 0x92efc305, 0x0f3a20a5], 363 | [0x53025251, 0x7a3e1c3c, 0xb7eaee4a, 0x1e0d3376], 364 | [0xc5ef15b9, 0xdde12aac, 0x9baa5e09, 0x18daf533]], 365 | 366 | [[0x72e2f2a7, 0x86815ef7, 0x9aefd304, 0x0fe8e4a4], 367 | [0x6102b057, 0x783e486f, 0xb7af6f4e, 0x192d33f2], 368 | [0xc4ef15e9, 0xa5df2aa4, 0xbeaa7243, 0x08dfe661]], 369 | 370 | [[0x72e2f2a7, 0x86815ef7, 0x9aefd304, 0x0fe8e4a4], 371 | [0xc20560ae, 0xf07c90de, 0x6f5ede9d, 0x325a67e4], 372 | [0xaa7243be, 0xdfe66108, 0xef15e9c4, 0xdf2aa4a5]]], 373 | 374 | [[[0x281f76bd, 0xa056aeb1, 0x52525d77, 0x626329ae], 375 | [0x98f8e4b4, 0xd6ab6098, 0xa7e350ee, 0x5fd1aaee], 376 | [0xf08fc7a4, 0xf931914e, 0x27a867b7, 0xb2a169af]], 377 | 378 | [[0x281f76bd, 0xa056aeb1, 0x52525d77, 0x626329ae], 379 | [0x5fd1aaee, 0x98f8e4b4, 0xd6ab6098, 0xa7e350ee], 380 | [0x7e3d2784, 0x8c8a77c9, 0x433db93d, 0x0b4d7d95]], 381 | 382 | [[0x281f771d, 0xa056aeb1, 0x52525d77, 0x626329ae], 383 | [0x5fd1aaee, 0x98f8e4b4, 0xd6ab6098, 0xa7e350ee], 384 | [0x7e3d2784, 0x8c8a77c9, 0x433db93d, 0x0b4d7d95]], 385 | 386 | [[0x0833721d, 0xa454bdf8, 0x5346c452, 0x6a6f04bf], 387 | [0x5fd3faf7, 0xb8ac6c84, 0xc6e924da, 0xc7c150c4], 388 | [0x29fdaf66, 0x942237cd, 0xc79499b5, 0x8ecd2dd5]], 389 | 390 | [[0x0833721d, 0xa454bdf8, 0x5346c452, 0x6a6f04bf], 391 | [0xbfa7f5ee, 0x7158d909, 0x8dd249b5, 0x8f82a189], 392 | [0x9499b5c7, 0xcd2dd58e, 0xfdaf6629, 0x2237cd94]]], 393 | 394 | 395 | [[[0x6956d7b3, 0x897ff3bf, 0x3b2f2db9, 0xf7e1f5b5], 396 | [0xdec25040, 0x5c73974e, 0xe5bba05e, 0x120c5083], 397 | [0xf5fc1069, 0xe0069bc9, 0x95c68fc2, 0xbfb93c9e]], 398 | 399 | [[0x6956d7b3, 0x897ff3bf, 0x3b2f2db9, 0xf7e1f5b5], 400 | [0x120c5083, 0xdec25040, 0x5c73974e, 0xe5bba05e], 401 | [0xe0834faf, 0x34de4f00, 0x347e14ae, 0xc9e4f5fd]], 402 | 403 | [[0x6956d7a1, 0x897ff3bf, 0x3b2f2db9, 0xf7e1f5b5], 404 | [0x120c5083, 0xdec25040, 0x5c73974e, 0xe5bba05e], 405 | [0xe0834faf, 0x34de4f00, 0x347e14ae, 0xc9e4f5fd]], 406 | 407 | [[0x89d5d88d, 0xa963fcbf, 0x1b232d19, 0xffa5a014], 408 | [0x1b58c083, 0x57e3e0ff, 0x5772be5f, 0xd3baa05e], 409 | [0xf28b4fad, 0x625e4f40, 0x702e86e8, 0xc9fef5b7]], 410 | 411 | [[0x89d5d88d, 0xa963fcbf, 0x1b232d19, 0xffa5a014], 412 | [0x36b18106, 0xafc7c1fe, 0xaee57cbe, 0xa77540bd], 413 | [0x2e86e870, 0xfef5b7c9, 0x8b4fadf2, 0x5e4f4062]]]] 414 | --------------------------------------------------------------------------------