├── .gitignore ├── .gitmodules ├── 84cJso7keg6SHW4vbNVbXccimCZrz7WoESXTtw12b5UsWqmm5 ├── Makefile ├── README.md ├── b64.c ├── base58.py ├── sha2.c ├── sha2.h ├── verify.c └── verify.sage /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | *.sage.py 3 | verify 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "abcmint"] 2 | path = abcmint 3 | url = https://github.com/abcmint/abcmint 4 | -------------------------------------------------------------------------------- /84cJso7keg6SHW4vbNVbXccimCZrz7WoESXTtw12b5UsWqmm5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mkannwischer/breaking-abc/9bab731ed77727ff1c0b5663b0f89269df25460b/84cJso7keg6SHW4vbNVbXccimCZrz7WoESXTtw12b5UsWqmm5 -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | CXXFLAGS=-Iabcmint/src/pqcrypto/ 3 | SRC=abcmint/src/pqcrypto/*.cpp verify.c sha2.c b64.c 4 | 5 | verify: $(SRC) 6 | g++ $(CXXFLAGS) $(SRC) -o $@ 7 | 8 | clean: 9 | rm -rf *.o verify -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Breaking Abcmint using Beullens' attack on Rainbow 2 | 3 | Authors: 4 | - [Matthias J. Kannwischer](https://kannwischer.eu/) 5 | - [Lorenz Panny](https://yx7.cc/) 6 | 7 | --- 8 | 9 | This repository demonstrates that we have successfully forged a signature for the Abcmint address 10 | [84cJso7keg6SHW4vbNVbXccimCZrz7WoESXTtw12b5UsWqmm5](https://abcscan.io/#/Addressinformation?data=84cJso7keg6SHW4vbNVbXccimCZrz7WoESXTtw12b5UsWqmm5). 11 | 12 | We extracted the public key corresponding to the address from the Abcmint blockchain and used a slightly tweaked variant of [Ward Beullens' attack](https://ia.cr/2022/214) and [his corresponding software](https://github.com/WardBeullens/BreakingRainbow) 13 | to recover the corresponding private key. 14 | The three 24-core servers we used were somewhat more powerful than Ward's laptop (of breaking-Rainbow-in-a-weekend fame), hence we expected roughly 5 hours of wall-clock time to solve one `Rainbow(16,32,32,32)` public key. We got lucky and found the key after only about 3 hours. 15 | 16 | The recovered private key was then used to sign a message in the format of Abcmint's message-signing functionality, specified in https://github.com/abcmint/abcmint/blob/44dba015e2622a05a5af04e220d72a784dc48607/src/rpcwallet.cpp#L292. It could easily be used in the same way to sign transactions, but we have refrained from doing so. 17 | 18 | The forged signature is: 19 | ``` 20 | address: "84cJso7keg6SHW4vbNVbXccimCZrz7WoESXTtw12b5UsWqmm5" 21 | message: "There is no pot of gold at the end of the Rainbow." (ASCII) 22 | signature: "TqERiKoFpkDEOEUGrq2WfH/XvTxP8dzbUxUpD1UyTUyLnVUaZcqW9IV+bTLIuamWS+XVKFcslYHLnxNcjcjnCA==" (Base64) 23 | ``` 24 | 25 | The Abcmint client should in theory allow you to verify this signature by entering the data above. 26 | However, this functionality seems to be implemented incorrectly: It errors with "private key for the entered address is not available". Indeed, verification of signed messages only seems to work if you have the corresponding private key in your wallet, rendering the feature rather pointless. 27 | 28 | As a workaround, we show below how to verify the signature using either our Sage script or the verification routines from the Abcmint codebase. 29 | 30 | ## Sage 31 | ``` 32 | sage verify.sage 33 | ``` 34 | 35 | prints 36 | 37 | ``` 38 | $ sage verify.sage 39 | msg: There is no pot of gold at the end of the Rainbow. 40 | sig: TqERiKoFpkDEOEUGrq2WfH/XvTxP8dzbUxUpD1UyTUyLnVUaZcqW9IV+bTLIuamWS+XVKFcslYHLnxNcjcjnCA== 41 | h(pk): 84cJso7keg6SHW4vbNVbXccimCZrz7WoESXTtw12b5UsWqmm5 42 | Signature is valid 43 | ``` 44 | 45 | 46 | ## C++ implementation using the Abcmint codebase 47 | ``` 48 | make 49 | ./verify 50 | ``` 51 | 52 | prints 53 | 54 | ``` 55 | addr=84cJso7keg6SHW4vbNVbXccimCZrz7WoESXTtw12b5UsWqmm5 56 | sig=TqERiKoFpkDEOEUGrq2WfH/XvTxP8dzbUxUpD1UyTUyLnVUaZcqW9IV+bTLIuamWS+XVKFcslYHLnxNcjcjnCA== 57 | msg=There is no pot of gold at the end of the Rainbow. 58 | Signature is valid! 59 | ``` -------------------------------------------------------------------------------- /b64.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // adapted from util.cpp 6 | bool DecodeBase64(unsigned char *out, const char* in) 7 | { 8 | uint8_t *p = (uint8_t*) in; 9 | static const int decode64_table[256] = 10 | { 11 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13 | -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, 14 | -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 16 | 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 17 | 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 18 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 19 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 20 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 21 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 24 | }; 25 | 26 | int mode = 0; 27 | int left = 0; 28 | size_t pos = 0; 29 | 30 | while (1) 31 | { 32 | int dec = decode64_table[*p]; 33 | if (dec == -1) break; 34 | p++; 35 | switch (mode) 36 | { 37 | case 0: // we have no bits and get 6 38 | left = dec; 39 | mode = 1; 40 | break; 41 | 42 | case 1: // we have 6 bits and keep 4 43 | out[pos++] = (left<<2) | (dec>>4); 44 | left = dec & 15; 45 | mode = 2; 46 | break; 47 | 48 | case 2: // we have 4 bits and get 6, we keep 2 49 | out[pos++] = (left<<4) | (dec>>2); 50 | left = dec & 3; 51 | mode = 3; 52 | break; 53 | 54 | case 3: // we have 2 bits and get 6 55 | out[pos++] = (left<<6) | dec; 56 | mode = 0; 57 | break; 58 | } 59 | } 60 | 61 | switch (mode) 62 | { 63 | case 0: // 4n base64 characters processed: ok 64 | break; 65 | 66 | case 1: // 4n+1 base64 character processed: impossible 67 | return false; 68 | 69 | case 2: // 4n+2 base64 characters processed: require '==' 70 | if (left || p[0] != '=' || p[1] != '=' || decode64_table[p[2]] != -1) 71 | return false; 72 | break; 73 | 74 | case 3: // 4n+3 base64 characters processed: require '=' 75 | if (left || p[0] != '=' || decode64_table[p[1]] != -1) 76 | return false; 77 | break; 78 | } 79 | 80 | return true; 81 | } 82 | -------------------------------------------------------------------------------- /base58.py: -------------------------------------------------------------------------------- 1 | # modified from https://github.com/keis/base58/blob/master/base58.py 2 | 3 | '''Base58 encoding 4 | Implementations of Base58 and Base58Check endcodings that are compatible 5 | with the bitcoin network. 6 | ''' 7 | 8 | # This module is based upon base58 snippets found scattered over many bitcoin 9 | # tools written in python. From what I gather the original source is from a 10 | # forum post by Gavin Andresen, so direct your praise to him. 11 | # This module adds shiny packaging and support for python3. 12 | 13 | from hashlib import sha256 14 | 15 | __version__ = '0.2.5' 16 | 17 | # 58 character alphabet used 18 | # alphabet = b'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' 19 | alphabet = b'823456719ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' 20 | 21 | if bytes == str: # python2 22 | iseq, bseq, buffer = ( 23 | lambda s: map(ord, s), 24 | lambda s: ''.join(map(chr, s)), 25 | lambda s: s, 26 | ) 27 | else: # python3 28 | iseq, bseq, buffer = ( 29 | lambda s: s, 30 | bytes, 31 | lambda s: s.buffer, 32 | ) 33 | 34 | 35 | def scrub_input(v): 36 | if isinstance(v, str) and not isinstance(v, bytes): 37 | v = v.encode('ascii') 38 | 39 | if not isinstance(v, bytes): 40 | raise TypeError( 41 | "a bytes-like object is required (also str), not '%s'" % 42 | type(v).__name__) 43 | 44 | return v 45 | 46 | 47 | def b58encode_int(i, default_one=True): 48 | '''Encode an integer using Base58''' 49 | if not i and default_one: 50 | return alphabet[0:1] 51 | string = b"" 52 | while i: 53 | i, idx = divmod(i, 58) 54 | string = alphabet[idx:idx+1] + string 55 | return string 56 | 57 | 58 | def b58encode(v): 59 | '''Encode a string using Base58''' 60 | 61 | v = scrub_input(v) 62 | 63 | nPad = len(v) 64 | v = v.lstrip(b'\0') 65 | nPad -= len(v) 66 | 67 | p, acc = 1, 0 68 | for c in iseq(reversed(v)): 69 | acc += p * c 70 | p = p << 8 71 | 72 | result = b58encode_int(acc, default_one=False) 73 | 74 | return (alphabet[0:1] * nPad + result) 75 | 76 | 77 | def b58decode_int(v): 78 | '''Decode a Base58 encoded string as an integer''' 79 | 80 | v = scrub_input(v) 81 | 82 | decimal = 0 83 | for char in v: 84 | decimal = decimal * 58 + alphabet.index(char) 85 | return decimal 86 | 87 | 88 | def b58decode(v): 89 | '''Decode a Base58 encoded string''' 90 | 91 | v = scrub_input(v) 92 | 93 | origlen = len(v) 94 | v = v.lstrip(alphabet[0:1]) 95 | newlen = len(v) 96 | 97 | acc = b58decode_int(v) 98 | 99 | result = [] 100 | while acc > 0: 101 | acc, mod = divmod(acc, 256) 102 | result.append(mod) 103 | 104 | return (b'\0' * (origlen - newlen) + bseq(reversed(result))) 105 | 106 | 107 | def b58encode_check(v): 108 | '''Encode a string using Base58 with a 4 character checksum''' 109 | 110 | digest = sha256(sha256(v).digest()).digest() 111 | return b58encode(v + digest[:3]) 112 | 113 | 114 | def b58decode_check(v): 115 | '''Decode and verify the checksum of a Base58 encoded string''' 116 | 117 | result = b58decode(v) 118 | result, check = result[:-4], result[-4:] 119 | digest = sha256(sha256(result).digest()).digest() 120 | 121 | if check != digest[:4]: 122 | raise ValueError("Invalid checksum") 123 | 124 | return result 125 | 126 | 127 | def main(): 128 | '''Base58 encode or decode FILE, or standard input, to standard output.''' 129 | 130 | import sys 131 | import argparse 132 | 133 | stdout = buffer(sys.stdout) 134 | 135 | parser = argparse.ArgumentParser(description=main.__doc__) 136 | parser.add_argument( 137 | 'file', 138 | metavar='FILE', 139 | nargs='?', 140 | type=argparse.FileType('r'), 141 | default='-') 142 | parser.add_argument( 143 | '-d', '--decode', 144 | action='store_true', 145 | help='decode data') 146 | parser.add_argument( 147 | '-c', '--check', 148 | action='store_true', 149 | help='append a checksum before encoding') 150 | 151 | args = parser.parse_args() 152 | fun = { 153 | (False, False): b58encode, 154 | (False, True): b58encode_check, 155 | (True, False): b58decode, 156 | (True, True): b58decode_check 157 | }[(args.decode, args.check)] 158 | 159 | data = buffer(args.file).read() 160 | 161 | try: 162 | result = fun(data) 163 | except Exception as e: 164 | sys.exit(e) 165 | 166 | if not isinstance(result, bytes): 167 | result = result.encode('ascii') 168 | 169 | stdout.write(result) 170 | 171 | 172 | if __name__ == '__main__': 173 | main() -------------------------------------------------------------------------------- /sha2.c: -------------------------------------------------------------------------------- 1 | /* Based on the public domain implementation in 2 | * crypto_hash/sha512/ref/ from http://bench.cr.yp.to/supercop.html 3 | * by D. J. Bernstein */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "sha2.h" 10 | 11 | #ifdef PROFILE_HASHING 12 | #include "hal.h" 13 | extern unsigned long long hash_cycles; 14 | #endif 15 | 16 | static uint32_t load_bigendian_32(const uint8_t *x) { 17 | return (uint32_t)(x[3]) | (((uint32_t)(x[2])) << 8) | 18 | (((uint32_t)(x[1])) << 16) | (((uint32_t)(x[0])) << 24); 19 | } 20 | 21 | static uint64_t load_bigendian_64(const uint8_t *x) { 22 | return (uint64_t)(x[7]) | (((uint64_t)(x[6])) << 8) | 23 | (((uint64_t)(x[5])) << 16) | (((uint64_t)(x[4])) << 24) | 24 | (((uint64_t)(x[3])) << 32) | (((uint64_t)(x[2])) << 40) | 25 | (((uint64_t)(x[1])) << 48) | (((uint64_t)(x[0])) << 56); 26 | } 27 | 28 | static void store_bigendian_32(uint8_t *x, uint64_t u) { 29 | x[3] = (uint8_t) u; 30 | u >>= 8; 31 | x[2] = (uint8_t) u; 32 | u >>= 8; 33 | x[1] = (uint8_t) u; 34 | u >>= 8; 35 | x[0] = (uint8_t) u; 36 | } 37 | 38 | static void store_bigendian_64(uint8_t *x, uint64_t u) { 39 | x[7] = (uint8_t) u; 40 | u >>= 8; 41 | x[6] = (uint8_t) u; 42 | u >>= 8; 43 | x[5] = (uint8_t) u; 44 | u >>= 8; 45 | x[4] = (uint8_t) u; 46 | u >>= 8; 47 | x[3] = (uint8_t) u; 48 | u >>= 8; 49 | x[2] = (uint8_t) u; 50 | u >>= 8; 51 | x[1] = (uint8_t) u; 52 | u >>= 8; 53 | x[0] = (uint8_t) u; 54 | } 55 | 56 | #define SHR(x, c) ((x) >> (c)) 57 | #define ROTR_32(x, c) (((x) >> (c)) | ((x) << (32 - (c)))) 58 | #define ROTR_64(x, c) (((x) >> (c)) | ((x) << (64 - (c)))) 59 | 60 | #define Ch(x, y, z) (((x) & (y)) ^ (~(x) & (z))) 61 | #define Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) 62 | 63 | #define Sigma0_32(x) (ROTR_32(x, 2) ^ ROTR_32(x,13) ^ ROTR_32(x,22)) 64 | #define Sigma1_32(x) (ROTR_32(x, 6) ^ ROTR_32(x,11) ^ ROTR_32(x,25)) 65 | #define sigma0_32(x) (ROTR_32(x, 7) ^ ROTR_32(x,18) ^ SHR(x, 3)) 66 | #define sigma1_32(x) (ROTR_32(x,17) ^ ROTR_32(x,19) ^ SHR(x,10)) 67 | 68 | #define Sigma0_64(x) (ROTR_64(x, 28) ^ ROTR_64(x, 34) ^ ROTR_64(x, 39)) 69 | #define Sigma1_64(x) (ROTR_64(x, 14) ^ ROTR_64(x, 18) ^ ROTR_64(x, 41)) 70 | #define sigma0_64(x) (ROTR_64(x, 1) ^ ROTR_64(x, 8) ^ SHR(x, 7)) 71 | #define sigma1_64(x) (ROTR_64(x, 19) ^ ROTR_64(x, 61) ^ SHR(x, 6)) 72 | 73 | #define M_32(w0, w14, w9, w1) w0 = sigma1_32(w14) + (w9) + sigma0_32(w1) + (w0); 74 | #define M_64(w0, w14, w9, w1) w0 = sigma1_64(w14) + (w9) + sigma0_64(w1) + (w0); 75 | 76 | #define EXPAND_32 \ 77 | M_32(w0, w14, w9, w1) \ 78 | M_32(w1, w15, w10, w2) \ 79 | M_32(w2, w0, w11, w3) \ 80 | M_32(w3, w1, w12, w4) \ 81 | M_32(w4, w2, w13, w5) \ 82 | M_32(w5, w3, w14, w6) \ 83 | M_32(w6, w4, w15, w7) \ 84 | M_32(w7, w5, w0, w8) \ 85 | M_32(w8, w6, w1, w9) \ 86 | M_32(w9, w7, w2, w10) \ 87 | M_32(w10, w8, w3, w11) \ 88 | M_32(w11, w9, w4, w12) \ 89 | M_32(w12, w10, w5, w13) \ 90 | M_32(w13, w11, w6, w14) \ 91 | M_32(w14, w12, w7, w15) \ 92 | M_32(w15, w13, w8, w0) 93 | 94 | #define EXPAND_64 \ 95 | M_64(w0, w14, w9, w1) \ 96 | M_64(w1, w15, w10, w2) \ 97 | M_64(w2, w0, w11, w3) \ 98 | M_64(w3, w1, w12, w4) \ 99 | M_64(w4, w2, w13, w5) \ 100 | M_64(w5, w3, w14, w6) \ 101 | M_64(w6, w4, w15, w7) \ 102 | M_64(w7, w5, w0, w8) \ 103 | M_64(w8, w6, w1, w9) \ 104 | M_64(w9, w7, w2, w10) \ 105 | M_64(w10, w8, w3, w11) \ 106 | M_64(w11, w9, w4, w12) \ 107 | M_64(w12, w10, w5, w13) \ 108 | M_64(w13, w11, w6, w14) \ 109 | M_64(w14, w12, w7, w15) \ 110 | M_64(w15, w13, w8, w0) 111 | 112 | #define F_32(w, k) \ 113 | T1 = h + Sigma1_32(e) + Ch(e, f, g) + (k) + (w); \ 114 | T2 = Sigma0_32(a) + Maj(a, b, c); \ 115 | h = g; \ 116 | g = f; \ 117 | f = e; \ 118 | e = d + T1; \ 119 | d = c; \ 120 | c = b; \ 121 | b = a; \ 122 | a = T1 + T2; 123 | 124 | #define F_64(w, k) \ 125 | T1 = h + Sigma1_64(e) + Ch(e, f, g) + (k) + (w); \ 126 | T2 = Sigma0_64(a) + Maj(a, b, c); \ 127 | h = g; \ 128 | g = f; \ 129 | f = e; \ 130 | e = d + T1; \ 131 | d = c; \ 132 | c = b; \ 133 | b = a; \ 134 | a = T1 + T2; 135 | 136 | static size_t crypto_hashblocks_sha256(uint8_t *statebytes, 137 | const uint8_t *in, size_t inlen) { 138 | uint32_t state[8]; 139 | uint32_t a; 140 | uint32_t b; 141 | uint32_t c; 142 | uint32_t d; 143 | uint32_t e; 144 | uint32_t f; 145 | uint32_t g; 146 | uint32_t h; 147 | uint32_t T1; 148 | uint32_t T2; 149 | 150 | a = load_bigendian_32(statebytes + 0); 151 | state[0] = a; 152 | b = load_bigendian_32(statebytes + 4); 153 | state[1] = b; 154 | c = load_bigendian_32(statebytes + 8); 155 | state[2] = c; 156 | d = load_bigendian_32(statebytes + 12); 157 | state[3] = d; 158 | e = load_bigendian_32(statebytes + 16); 159 | state[4] = e; 160 | f = load_bigendian_32(statebytes + 20); 161 | state[5] = f; 162 | g = load_bigendian_32(statebytes + 24); 163 | state[6] = g; 164 | h = load_bigendian_32(statebytes + 28); 165 | state[7] = h; 166 | 167 | while (inlen >= 64) { 168 | uint32_t w0 = load_bigendian_32(in + 0); 169 | uint32_t w1 = load_bigendian_32(in + 4); 170 | uint32_t w2 = load_bigendian_32(in + 8); 171 | uint32_t w3 = load_bigendian_32(in + 12); 172 | uint32_t w4 = load_bigendian_32(in + 16); 173 | uint32_t w5 = load_bigendian_32(in + 20); 174 | uint32_t w6 = load_bigendian_32(in + 24); 175 | uint32_t w7 = load_bigendian_32(in + 28); 176 | uint32_t w8 = load_bigendian_32(in + 32); 177 | uint32_t w9 = load_bigendian_32(in + 36); 178 | uint32_t w10 = load_bigendian_32(in + 40); 179 | uint32_t w11 = load_bigendian_32(in + 44); 180 | uint32_t w12 = load_bigendian_32(in + 48); 181 | uint32_t w13 = load_bigendian_32(in + 52); 182 | uint32_t w14 = load_bigendian_32(in + 56); 183 | uint32_t w15 = load_bigendian_32(in + 60); 184 | 185 | F_32(w0, 0x428a2f98) 186 | F_32(w1, 0x71374491) 187 | F_32(w2, 0xb5c0fbcf) 188 | F_32(w3, 0xe9b5dba5) 189 | F_32(w4, 0x3956c25b) 190 | F_32(w5, 0x59f111f1) 191 | F_32(w6, 0x923f82a4) 192 | F_32(w7, 0xab1c5ed5) 193 | F_32(w8, 0xd807aa98) 194 | F_32(w9, 0x12835b01) 195 | F_32(w10, 0x243185be) 196 | F_32(w11, 0x550c7dc3) 197 | F_32(w12, 0x72be5d74) 198 | F_32(w13, 0x80deb1fe) 199 | F_32(w14, 0x9bdc06a7) 200 | F_32(w15, 0xc19bf174) 201 | 202 | EXPAND_32 203 | 204 | F_32(w0, 0xe49b69c1) 205 | F_32(w1, 0xefbe4786) 206 | F_32(w2, 0x0fc19dc6) 207 | F_32(w3, 0x240ca1cc) 208 | F_32(w4, 0x2de92c6f) 209 | F_32(w5, 0x4a7484aa) 210 | F_32(w6, 0x5cb0a9dc) 211 | F_32(w7, 0x76f988da) 212 | F_32(w8, 0x983e5152) 213 | F_32(w9, 0xa831c66d) 214 | F_32(w10, 0xb00327c8) 215 | F_32(w11, 0xbf597fc7) 216 | F_32(w12, 0xc6e00bf3) 217 | F_32(w13, 0xd5a79147) 218 | F_32(w14, 0x06ca6351) 219 | F_32(w15, 0x14292967) 220 | 221 | EXPAND_32 222 | 223 | F_32(w0, 0x27b70a85) 224 | F_32(w1, 0x2e1b2138) 225 | F_32(w2, 0x4d2c6dfc) 226 | F_32(w3, 0x53380d13) 227 | F_32(w4, 0x650a7354) 228 | F_32(w5, 0x766a0abb) 229 | F_32(w6, 0x81c2c92e) 230 | F_32(w7, 0x92722c85) 231 | F_32(w8, 0xa2bfe8a1) 232 | F_32(w9, 0xa81a664b) 233 | F_32(w10, 0xc24b8b70) 234 | F_32(w11, 0xc76c51a3) 235 | F_32(w12, 0xd192e819) 236 | F_32(w13, 0xd6990624) 237 | F_32(w14, 0xf40e3585) 238 | F_32(w15, 0x106aa070) 239 | 240 | EXPAND_32 241 | 242 | F_32(w0, 0x19a4c116) 243 | F_32(w1, 0x1e376c08) 244 | F_32(w2, 0x2748774c) 245 | F_32(w3, 0x34b0bcb5) 246 | F_32(w4, 0x391c0cb3) 247 | F_32(w5, 0x4ed8aa4a) 248 | F_32(w6, 0x5b9cca4f) 249 | F_32(w7, 0x682e6ff3) 250 | F_32(w8, 0x748f82ee) 251 | F_32(w9, 0x78a5636f) 252 | F_32(w10, 0x84c87814) 253 | F_32(w11, 0x8cc70208) 254 | F_32(w12, 0x90befffa) 255 | F_32(w13, 0xa4506ceb) 256 | F_32(w14, 0xbef9a3f7) 257 | F_32(w15, 0xc67178f2) 258 | 259 | a += state[0]; 260 | b += state[1]; 261 | c += state[2]; 262 | d += state[3]; 263 | e += state[4]; 264 | f += state[5]; 265 | g += state[6]; 266 | h += state[7]; 267 | 268 | state[0] = a; 269 | state[1] = b; 270 | state[2] = c; 271 | state[3] = d; 272 | state[4] = e; 273 | state[5] = f; 274 | state[6] = g; 275 | state[7] = h; 276 | 277 | in += 64; 278 | inlen -= 64; 279 | } 280 | 281 | store_bigendian_32(statebytes + 0, state[0]); 282 | store_bigendian_32(statebytes + 4, state[1]); 283 | store_bigendian_32(statebytes + 8, state[2]); 284 | store_bigendian_32(statebytes + 12, state[3]); 285 | store_bigendian_32(statebytes + 16, state[4]); 286 | store_bigendian_32(statebytes + 20, state[5]); 287 | store_bigendian_32(statebytes + 24, state[6]); 288 | store_bigendian_32(statebytes + 28, state[7]); 289 | 290 | return inlen; 291 | } 292 | 293 | static size_t crypto_hashblocks_sha512(uint8_t *statebytes, 294 | const uint8_t *in, size_t inlen) { 295 | uint64_t state[8]; 296 | uint64_t a; 297 | uint64_t b; 298 | uint64_t c; 299 | uint64_t d; 300 | uint64_t e; 301 | uint64_t f; 302 | uint64_t g; 303 | uint64_t h; 304 | uint64_t T1; 305 | uint64_t T2; 306 | 307 | a = load_bigendian_64(statebytes + 0); 308 | state[0] = a; 309 | b = load_bigendian_64(statebytes + 8); 310 | state[1] = b; 311 | c = load_bigendian_64(statebytes + 16); 312 | state[2] = c; 313 | d = load_bigendian_64(statebytes + 24); 314 | state[3] = d; 315 | e = load_bigendian_64(statebytes + 32); 316 | state[4] = e; 317 | f = load_bigendian_64(statebytes + 40); 318 | state[5] = f; 319 | g = load_bigendian_64(statebytes + 48); 320 | state[6] = g; 321 | h = load_bigendian_64(statebytes + 56); 322 | state[7] = h; 323 | 324 | while (inlen >= 128) { 325 | uint64_t w0 = load_bigendian_64(in + 0); 326 | uint64_t w1 = load_bigendian_64(in + 8); 327 | uint64_t w2 = load_bigendian_64(in + 16); 328 | uint64_t w3 = load_bigendian_64(in + 24); 329 | uint64_t w4 = load_bigendian_64(in + 32); 330 | uint64_t w5 = load_bigendian_64(in + 40); 331 | uint64_t w6 = load_bigendian_64(in + 48); 332 | uint64_t w7 = load_bigendian_64(in + 56); 333 | uint64_t w8 = load_bigendian_64(in + 64); 334 | uint64_t w9 = load_bigendian_64(in + 72); 335 | uint64_t w10 = load_bigendian_64(in + 80); 336 | uint64_t w11 = load_bigendian_64(in + 88); 337 | uint64_t w12 = load_bigendian_64(in + 96); 338 | uint64_t w13 = load_bigendian_64(in + 104); 339 | uint64_t w14 = load_bigendian_64(in + 112); 340 | uint64_t w15 = load_bigendian_64(in + 120); 341 | 342 | F_64(w0, 0x428a2f98d728ae22ULL) 343 | F_64(w1, 0x7137449123ef65cdULL) 344 | F_64(w2, 0xb5c0fbcfec4d3b2fULL) 345 | F_64(w3, 0xe9b5dba58189dbbcULL) 346 | F_64(w4, 0x3956c25bf348b538ULL) 347 | F_64(w5, 0x59f111f1b605d019ULL) 348 | F_64(w6, 0x923f82a4af194f9bULL) 349 | F_64(w7, 0xab1c5ed5da6d8118ULL) 350 | F_64(w8, 0xd807aa98a3030242ULL) 351 | F_64(w9, 0x12835b0145706fbeULL) 352 | F_64(w10, 0x243185be4ee4b28cULL) 353 | F_64(w11, 0x550c7dc3d5ffb4e2ULL) 354 | F_64(w12, 0x72be5d74f27b896fULL) 355 | F_64(w13, 0x80deb1fe3b1696b1ULL) 356 | F_64(w14, 0x9bdc06a725c71235ULL) 357 | F_64(w15, 0xc19bf174cf692694ULL) 358 | 359 | EXPAND_64 360 | 361 | F_64(w0, 0xe49b69c19ef14ad2ULL) 362 | F_64(w1, 0xefbe4786384f25e3ULL) 363 | F_64(w2, 0x0fc19dc68b8cd5b5ULL) 364 | F_64(w3, 0x240ca1cc77ac9c65ULL) 365 | F_64(w4, 0x2de92c6f592b0275ULL) 366 | F_64(w5, 0x4a7484aa6ea6e483ULL) 367 | F_64(w6, 0x5cb0a9dcbd41fbd4ULL) 368 | F_64(w7, 0x76f988da831153b5ULL) 369 | F_64(w8, 0x983e5152ee66dfabULL) 370 | F_64(w9, 0xa831c66d2db43210ULL) 371 | F_64(w10, 0xb00327c898fb213fULL) 372 | F_64(w11, 0xbf597fc7beef0ee4ULL) 373 | F_64(w12, 0xc6e00bf33da88fc2ULL) 374 | F_64(w13, 0xd5a79147930aa725ULL) 375 | F_64(w14, 0x06ca6351e003826fULL) 376 | F_64(w15, 0x142929670a0e6e70ULL) 377 | 378 | EXPAND_64 379 | 380 | F_64(w0, 0x27b70a8546d22ffcULL) 381 | F_64(w1, 0x2e1b21385c26c926ULL) 382 | F_64(w2, 0x4d2c6dfc5ac42aedULL) 383 | F_64(w3, 0x53380d139d95b3dfULL) 384 | F_64(w4, 0x650a73548baf63deULL) 385 | F_64(w5, 0x766a0abb3c77b2a8ULL) 386 | F_64(w6, 0x81c2c92e47edaee6ULL) 387 | F_64(w7, 0x92722c851482353bULL) 388 | F_64(w8, 0xa2bfe8a14cf10364ULL) 389 | F_64(w9, 0xa81a664bbc423001ULL) 390 | F_64(w10, 0xc24b8b70d0f89791ULL) 391 | F_64(w11, 0xc76c51a30654be30ULL) 392 | F_64(w12, 0xd192e819d6ef5218ULL) 393 | F_64(w13, 0xd69906245565a910ULL) 394 | F_64(w14, 0xf40e35855771202aULL) 395 | F_64(w15, 0x106aa07032bbd1b8ULL) 396 | 397 | EXPAND_64 398 | 399 | F_64(w0, 0x19a4c116b8d2d0c8ULL) 400 | F_64(w1, 0x1e376c085141ab53ULL) 401 | F_64(w2, 0x2748774cdf8eeb99ULL) 402 | F_64(w3, 0x34b0bcb5e19b48a8ULL) 403 | F_64(w4, 0x391c0cb3c5c95a63ULL) 404 | F_64(w5, 0x4ed8aa4ae3418acbULL) 405 | F_64(w6, 0x5b9cca4f7763e373ULL) 406 | F_64(w7, 0x682e6ff3d6b2b8a3ULL) 407 | F_64(w8, 0x748f82ee5defb2fcULL) 408 | F_64(w9, 0x78a5636f43172f60ULL) 409 | F_64(w10, 0x84c87814a1f0ab72ULL) 410 | F_64(w11, 0x8cc702081a6439ecULL) 411 | F_64(w12, 0x90befffa23631e28ULL) 412 | F_64(w13, 0xa4506cebde82bde9ULL) 413 | F_64(w14, 0xbef9a3f7b2c67915ULL) 414 | F_64(w15, 0xc67178f2e372532bULL) 415 | 416 | EXPAND_64 417 | 418 | F_64(w0, 0xca273eceea26619cULL) 419 | F_64(w1, 0xd186b8c721c0c207ULL) 420 | F_64(w2, 0xeada7dd6cde0eb1eULL) 421 | F_64(w3, 0xf57d4f7fee6ed178ULL) 422 | F_64(w4, 0x06f067aa72176fbaULL) 423 | F_64(w5, 0x0a637dc5a2c898a6ULL) 424 | F_64(w6, 0x113f9804bef90daeULL) 425 | F_64(w7, 0x1b710b35131c471bULL) 426 | F_64(w8, 0x28db77f523047d84ULL) 427 | F_64(w9, 0x32caab7b40c72493ULL) 428 | F_64(w10, 0x3c9ebe0a15c9bebcULL) 429 | F_64(w11, 0x431d67c49c100d4cULL) 430 | F_64(w12, 0x4cc5d4becb3e42b6ULL) 431 | F_64(w13, 0x597f299cfc657e2aULL) 432 | F_64(w14, 0x5fcb6fab3ad6faecULL) 433 | F_64(w15, 0x6c44198c4a475817ULL) 434 | 435 | a += state[0]; 436 | b += state[1]; 437 | c += state[2]; 438 | d += state[3]; 439 | e += state[4]; 440 | f += state[5]; 441 | g += state[6]; 442 | h += state[7]; 443 | 444 | state[0] = a; 445 | state[1] = b; 446 | state[2] = c; 447 | state[3] = d; 448 | state[4] = e; 449 | state[5] = f; 450 | state[6] = g; 451 | state[7] = h; 452 | 453 | in += 128; 454 | inlen -= 128; 455 | } 456 | 457 | store_bigendian_64(statebytes + 0, state[0]); 458 | store_bigendian_64(statebytes + 8, state[1]); 459 | store_bigendian_64(statebytes + 16, state[2]); 460 | store_bigendian_64(statebytes + 24, state[3]); 461 | store_bigendian_64(statebytes + 32, state[4]); 462 | store_bigendian_64(statebytes + 40, state[5]); 463 | store_bigendian_64(statebytes + 48, state[6]); 464 | store_bigendian_64(statebytes + 56, state[7]); 465 | 466 | return inlen; 467 | } 468 | 469 | static const uint8_t iv_224[32] = { 470 | 0xc1, 0x05, 0x9e, 0xd8, 0x36, 0x7c, 0xd5, 0x07, 471 | 0x30, 0x70, 0xdd, 0x17, 0xf7, 0x0e, 0x59, 0x39, 472 | 0xff, 0xc0, 0x0b, 0x31, 0x68, 0x58, 0x15, 0x11, 473 | 0x64, 0xf9, 0x8f, 0xa7, 0xbe, 0xfa, 0x4f, 0xa4 474 | }; 475 | 476 | static const uint8_t iv_256[32] = { 477 | 0x6a, 0x09, 0xe6, 0x67, 0xbb, 0x67, 0xae, 0x85, 478 | 0x3c, 0x6e, 0xf3, 0x72, 0xa5, 0x4f, 0xf5, 0x3a, 479 | 0x51, 0x0e, 0x52, 0x7f, 0x9b, 0x05, 0x68, 0x8c, 480 | 0x1f, 0x83, 0xd9, 0xab, 0x5b, 0xe0, 0xcd, 0x19 481 | }; 482 | 483 | static const uint8_t iv_384[64] = { 484 | 0xcb, 0xbb, 0x9d, 0x5d, 0xc1, 0x05, 0x9e, 0xd8, 0x62, 0x9a, 0x29, 485 | 0x2a, 0x36, 0x7c, 0xd5, 0x07, 0x91, 0x59, 0x01, 0x5a, 0x30, 0x70, 486 | 0xdd, 0x17, 0x15, 0x2f, 0xec, 0xd8, 0xf7, 0x0e, 0x59, 0x39, 0x67, 487 | 0x33, 0x26, 0x67, 0xff, 0xc0, 0x0b, 0x31, 0x8e, 0xb4, 0x4a, 0x87, 488 | 0x68, 0x58, 0x15, 0x11, 0xdb, 0x0c, 0x2e, 0x0d, 0x64, 0xf9, 0x8f, 489 | 0xa7, 0x47, 0xb5, 0x48, 0x1d, 0xbe, 0xfa, 0x4f, 0xa4 490 | }; 491 | 492 | static const uint8_t iv_512[64] = { 493 | 0x6a, 0x09, 0xe6, 0x67, 0xf3, 0xbc, 0xc9, 0x08, 0xbb, 0x67, 0xae, 494 | 0x85, 0x84, 0xca, 0xa7, 0x3b, 0x3c, 0x6e, 0xf3, 0x72, 0xfe, 0x94, 495 | 0xf8, 0x2b, 0xa5, 0x4f, 0xf5, 0x3a, 0x5f, 0x1d, 0x36, 0xf1, 0x51, 496 | 0x0e, 0x52, 0x7f, 0xad, 0xe6, 0x82, 0xd1, 0x9b, 0x05, 0x68, 0x8c, 497 | 0x2b, 0x3e, 0x6c, 0x1f, 0x1f, 0x83, 0xd9, 0xab, 0xfb, 0x41, 0xbd, 498 | 0x6b, 0x5b, 0xe0, 0xcd, 0x19, 0x13, 0x7e, 0x21, 0x79 499 | }; 500 | 501 | void sha224_inc_init(sha224ctx *state) { 502 | #ifdef PROFILE_HASHING 503 | uint64_t t0 = hal_get_time(); 504 | #endif 505 | 506 | for (size_t i = 0; i < 32; ++i) { 507 | state->ctx[i] = iv_224[i]; 508 | } 509 | for (size_t i = 32; i < 40; ++i) { 510 | state->ctx[i] = 0; 511 | } 512 | 513 | #ifdef PROFILE_HASHING 514 | uint64_t t1 = hal_get_time(); 515 | hash_cycles += (t1-t0); 516 | #endif 517 | } 518 | 519 | void sha256_inc_init(sha256ctx *state) { 520 | #ifdef PROFILE_HASHING 521 | uint64_t t0 = hal_get_time(); 522 | #endif 523 | 524 | for (size_t i = 0; i < 32; ++i) { 525 | state->ctx[i] = iv_256[i]; 526 | } 527 | for (size_t i = 32; i < 40; ++i) { 528 | state->ctx[i] = 0; 529 | } 530 | 531 | #ifdef PROFILE_HASHING 532 | uint64_t t1 = hal_get_time(); 533 | hash_cycles += (t1-t0); 534 | #endif 535 | } 536 | 537 | void sha384_inc_init(sha384ctx *state) { 538 | #ifdef PROFILE_HASHING 539 | uint64_t t0 = hal_get_time(); 540 | #endif 541 | 542 | for (size_t i = 0; i < 64; ++i) { 543 | state->ctx[i] = iv_384[i]; 544 | } 545 | for (size_t i = 64; i < 72; ++i) { 546 | state->ctx[i] = 0; 547 | } 548 | 549 | #ifdef PROFILE_HASHING 550 | uint64_t t1 = hal_get_time(); 551 | hash_cycles += (t1-t0); 552 | #endif 553 | } 554 | 555 | void sha512_inc_init(sha512ctx *state) { 556 | #ifdef PROFILE_HASHING 557 | uint64_t t0 = hal_get_time(); 558 | #endif 559 | 560 | for (size_t i = 0; i < 64; ++i) { 561 | state->ctx[i] = iv_512[i]; 562 | } 563 | for (size_t i = 64; i < 72; ++i) { 564 | state->ctx[i] = 0; 565 | } 566 | 567 | #ifdef PROFILE_HASHING 568 | uint64_t t1 = hal_get_time(); 569 | hash_cycles += (t1-t0); 570 | #endif 571 | } 572 | 573 | void sha224_inc_clone_state(sha224ctx *stateout, const sha224ctx *statein) { 574 | memcpy(stateout, statein, sizeof(sha224ctx)); 575 | } 576 | 577 | void sha256_inc_clone_state(sha256ctx *stateout, const sha256ctx *statein) { 578 | memcpy(stateout, statein, sizeof(sha256ctx)); 579 | } 580 | 581 | void sha384_inc_clone_state(sha384ctx *stateout, const sha384ctx *statein) { 582 | memcpy(stateout, statein, sizeof(sha384ctx)); 583 | } 584 | 585 | void sha512_inc_clone_state(sha512ctx *stateout, const sha512ctx *statein) { 586 | memcpy(stateout, statein, sizeof(sha512ctx)); 587 | } 588 | 589 | /* Destroy the hash state. 590 | * 591 | * Because this implementation is stack-based, this is a no-op 592 | */ 593 | void sha224_inc_destroy(sha224ctx *state) { 594 | (void)state; 595 | } 596 | 597 | /* Destroy the hash state. 598 | * 599 | * Because this implementation is stack-based, this is a no-op 600 | */ 601 | void sha256_inc_destroy(sha256ctx *state) { 602 | (void)state; 603 | } 604 | 605 | /* Destroy the hash state. 606 | * 607 | * Because this implementation is stack-based, this is a no-op 608 | */ 609 | void sha384_inc_destroy(sha384ctx *state) { 610 | (void)state; 611 | } 612 | 613 | /* Destroy the hash state. 614 | * 615 | * Because this implementation is stack-based, this is a no-op 616 | */ 617 | void sha512_inc_destroy(sha512ctx *state) { 618 | (void)state; 619 | } 620 | 621 | 622 | void sha256_inc_blocks(sha256ctx *state, const uint8_t *in, size_t inblocks) { 623 | #ifdef PROFILE_HASHING 624 | uint64_t t0 = hal_get_time(); 625 | #endif 626 | 627 | uint64_t bytes = load_bigendian_64(state->ctx + 32); 628 | 629 | crypto_hashblocks_sha256(state->ctx, in, 64 * inblocks); 630 | bytes += 64 * inblocks; 631 | 632 | store_bigendian_64(state->ctx + 32, bytes); 633 | 634 | #ifdef PROFILE_HASHING 635 | uint64_t t1 = hal_get_time(); 636 | hash_cycles += (t1-t0); 637 | #endif 638 | } 639 | 640 | void sha224_inc_blocks(sha224ctx *state, const uint8_t *in, size_t inblocks) { 641 | sha256_inc_blocks((sha256ctx*) state, in, inblocks); 642 | } 643 | 644 | void sha512_inc_blocks(sha512ctx *state, const uint8_t *in, size_t inblocks) { 645 | #ifdef PROFILE_HASHING 646 | uint64_t t0 = hal_get_time(); 647 | #endif 648 | 649 | uint64_t bytes = load_bigendian_64(state->ctx + 64); 650 | 651 | crypto_hashblocks_sha512(state->ctx, in, 128 * inblocks); 652 | bytes += 128 * inblocks; 653 | 654 | store_bigendian_64(state->ctx + 64, bytes); 655 | 656 | #ifdef PROFILE_HASHING 657 | uint64_t t1 = hal_get_time(); 658 | hash_cycles += (t1-t0); 659 | #endif 660 | } 661 | 662 | void sha384_inc_blocks(sha384ctx *state, const uint8_t *in, size_t inblocks) { 663 | sha512_inc_blocks((sha512ctx*) state, in, inblocks); 664 | } 665 | 666 | void sha256_inc_finalize(uint8_t *out, sha256ctx *state, const uint8_t *in, size_t inlen) { 667 | #ifdef PROFILE_HASHING 668 | uint64_t t0 = hal_get_time(); 669 | #endif 670 | 671 | uint8_t padded[128]; 672 | uint64_t bytes = load_bigendian_64(state->ctx + 32) + inlen; 673 | 674 | crypto_hashblocks_sha256(state->ctx, in, inlen); 675 | in += inlen; 676 | inlen &= 63; 677 | in -= inlen; 678 | 679 | for (size_t i = 0; i < inlen; ++i) { 680 | padded[i] = in[i]; 681 | } 682 | padded[inlen] = 0x80; 683 | 684 | if (inlen < 56) { 685 | for (size_t i = inlen + 1; i < 56; ++i) { 686 | padded[i] = 0; 687 | } 688 | padded[56] = (uint8_t) (bytes >> 53); 689 | padded[57] = (uint8_t) (bytes >> 45); 690 | padded[58] = (uint8_t) (bytes >> 37); 691 | padded[59] = (uint8_t) (bytes >> 29); 692 | padded[60] = (uint8_t) (bytes >> 21); 693 | padded[61] = (uint8_t) (bytes >> 13); 694 | padded[62] = (uint8_t) (bytes >> 5); 695 | padded[63] = (uint8_t) (bytes << 3); 696 | crypto_hashblocks_sha256(state->ctx, padded, 64); 697 | } else { 698 | for (size_t i = inlen + 1; i < 120; ++i) { 699 | padded[i] = 0; 700 | } 701 | padded[120] = (uint8_t) (bytes >> 53); 702 | padded[121] = (uint8_t) (bytes >> 45); 703 | padded[122] = (uint8_t) (bytes >> 37); 704 | padded[123] = (uint8_t) (bytes >> 29); 705 | padded[124] = (uint8_t) (bytes >> 21); 706 | padded[125] = (uint8_t) (bytes >> 13); 707 | padded[126] = (uint8_t) (bytes >> 5); 708 | padded[127] = (uint8_t) (bytes << 3); 709 | crypto_hashblocks_sha256(state->ctx, padded, 128); 710 | } 711 | 712 | for (size_t i = 0; i < 32; ++i) { 713 | out[i] = state->ctx[i]; 714 | } 715 | 716 | #ifdef PROFILE_HASHING 717 | uint64_t t1 = hal_get_time(); 718 | hash_cycles += (t1-t0); 719 | #endif 720 | } 721 | 722 | void sha224_inc_finalize(uint8_t *out, sha224ctx *state, const uint8_t *in, size_t inlen) { 723 | sha256_inc_finalize(state->ctx, (sha256ctx*)state, in, inlen); 724 | 725 | for (size_t i = 0; i < 28; ++i) { 726 | out[i] = state->ctx[i]; 727 | } 728 | } 729 | 730 | void sha512_inc_finalize(uint8_t *out, sha512ctx *state, const uint8_t *in, size_t inlen) { 731 | #ifdef PROFILE_HASHING 732 | uint64_t t0 = hal_get_time(); 733 | #endif 734 | 735 | uint8_t padded[256]; 736 | uint64_t bytes = load_bigendian_64(state->ctx + 64) + inlen; 737 | 738 | crypto_hashblocks_sha512(state->ctx, in, inlen); 739 | in += inlen; 740 | inlen &= 127; 741 | in -= inlen; 742 | 743 | for (size_t i = 0; i < inlen; ++i) { 744 | padded[i] = in[i]; 745 | } 746 | padded[inlen] = 0x80; 747 | 748 | if (inlen < 112) { 749 | for (size_t i = inlen + 1; i < 119; ++i) { 750 | padded[i] = 0; 751 | } 752 | padded[119] = (uint8_t) (bytes >> 61); 753 | padded[120] = (uint8_t) (bytes >> 53); 754 | padded[121] = (uint8_t) (bytes >> 45); 755 | padded[122] = (uint8_t) (bytes >> 37); 756 | padded[123] = (uint8_t) (bytes >> 29); 757 | padded[124] = (uint8_t) (bytes >> 21); 758 | padded[125] = (uint8_t) (bytes >> 13); 759 | padded[126] = (uint8_t) (bytes >> 5); 760 | padded[127] = (uint8_t) (bytes << 3); 761 | crypto_hashblocks_sha512(state->ctx, padded, 128); 762 | } else { 763 | for (size_t i = inlen + 1; i < 247; ++i) { 764 | padded[i] = 0; 765 | } 766 | padded[247] = (uint8_t) (bytes >> 61); 767 | padded[248] = (uint8_t) (bytes >> 53); 768 | padded[249] = (uint8_t) (bytes >> 45); 769 | padded[250] = (uint8_t) (bytes >> 37); 770 | padded[251] = (uint8_t) (bytes >> 29); 771 | padded[252] = (uint8_t) (bytes >> 21); 772 | padded[253] = (uint8_t) (bytes >> 13); 773 | padded[254] = (uint8_t) (bytes >> 5); 774 | padded[255] = (uint8_t) (bytes << 3); 775 | crypto_hashblocks_sha512(state->ctx, padded, 256); 776 | } 777 | 778 | for (size_t i = 0; i < 64; ++i) { 779 | out[i] = state->ctx[i]; 780 | } 781 | 782 | #ifdef PROFILE_HASHING 783 | uint64_t t1 = hal_get_time(); 784 | hash_cycles += (t1-t0); 785 | #endif 786 | } 787 | 788 | void sha384_inc_finalize(uint8_t *out, sha384ctx *state, const uint8_t *in, size_t inlen) { 789 | sha512_inc_finalize(state->ctx, (sha512ctx*)state, in, inlen); 790 | 791 | for (size_t i = 0; i < 48; ++i) { 792 | out[i] = state->ctx[i]; 793 | } 794 | } 795 | 796 | void sha224(uint8_t *out, const uint8_t *in, size_t inlen) { 797 | sha224ctx state; 798 | 799 | sha224_inc_init(&state); 800 | sha224_inc_finalize(out, &state, in, inlen); 801 | } 802 | 803 | void sha256(uint8_t *out, const uint8_t *in, size_t inlen) { 804 | sha256ctx state; 805 | 806 | sha256_inc_init(&state); 807 | sha256_inc_finalize(out, &state, in, inlen); 808 | } 809 | 810 | void sha384(uint8_t *out, const uint8_t *in, size_t inlen) { 811 | sha384ctx state; 812 | 813 | sha384_inc_init(&state); 814 | sha384_inc_finalize(out, &state, in, inlen); 815 | } 816 | 817 | void sha512(uint8_t *out, const uint8_t *in, size_t inlen) { 818 | sha512ctx state; 819 | 820 | sha512_inc_init(&state); 821 | sha512_inc_finalize(out, &state, in, inlen); 822 | } 823 | -------------------------------------------------------------------------------- /sha2.h: -------------------------------------------------------------------------------- 1 | #ifndef SHA2_H 2 | #define SHA2_H 3 | 4 | #include 5 | #include 6 | 7 | /* The incremental API allows hashing of individual input blocks; these blocks 8 | must be exactly 64 bytes each. 9 | Use the 'finalize' functions for any remaining bytes (possibly over 64). */ 10 | 11 | /* Structure for the incremental API */ 12 | typedef struct { 13 | uint8_t ctx[40]; 14 | } sha224ctx; 15 | 16 | /* Structure for the incremental API */ 17 | typedef struct { 18 | uint8_t ctx[40]; 19 | } sha256ctx; 20 | 21 | /* Structure for the incremental API */ 22 | typedef struct { 23 | uint8_t ctx[72]; 24 | } sha384ctx; 25 | 26 | /* Structure for the incremental API */ 27 | typedef struct { 28 | uint8_t ctx[72]; 29 | } sha512ctx; 30 | 31 | /* ====== SHA224 API ==== */ 32 | /** 33 | * Initialize the incremental hashing API 34 | */ 35 | void sha224_inc_init(sha224ctx *state); 36 | 37 | /** 38 | * Copy the hashing state 39 | */ 40 | void sha224_inc_ctx_clone(sha224ctx *stateout, const sha224ctx *statein); 41 | 42 | /** 43 | * Absorb blocks 44 | */ 45 | void sha224_inc_blocks(sha224ctx *state, const uint8_t *in, size_t inblocks); 46 | 47 | /** 48 | * Finalize and obtain the digest 49 | * 50 | * If applicable, this function will free the memory associated with the sha224ctx. 51 | */ 52 | void sha224_inc_finalize(uint8_t *out, sha224ctx *state, const uint8_t *in, size_t inlen); 53 | 54 | /** 55 | * Destroy the state. Make sure to use this, as this API may not always be stack-based. 56 | */ 57 | void sha224_inc_ctx_release(sha224ctx *state); 58 | 59 | /** 60 | * All-in-one sha224 function 61 | */ 62 | void sha224(uint8_t *out, const uint8_t *in, size_t inlen); 63 | 64 | /* ====== SHA256 API ==== */ 65 | 66 | /** 67 | * Initialize the incremental hashing API 68 | */ 69 | void sha256_inc_init(sha256ctx *state); 70 | 71 | /** 72 | * Copy the hashing state 73 | */ 74 | void sha256_inc_ctx_clone(sha256ctx *stateout, const sha256ctx *statein); 75 | 76 | /** 77 | * Absorb blocks 78 | */ 79 | void sha256_inc_blocks(sha256ctx *state, const uint8_t *in, size_t inblocks); 80 | 81 | /** 82 | * Finalize and obtain the digest 83 | * 84 | * If applicable, this function will free the memory associated with the sha256ctx. 85 | */ 86 | void sha256_inc_finalize(uint8_t *out, sha256ctx *state, const uint8_t *in, size_t inlen); 87 | 88 | /** 89 | * Destroy the state. Make sure to use this, as this API may not always be stack-based. 90 | */ 91 | void sha256_inc_ctx_release(sha256ctx *state); 92 | 93 | 94 | /** 95 | * All-in-one sha256 function 96 | */ 97 | void sha256(uint8_t *out, const uint8_t *in, size_t inlen); 98 | 99 | /* ====== SHA384 API ==== */ 100 | 101 | /** 102 | * Initialize the incremental hashing API 103 | */ 104 | void sha384_inc_init(sha384ctx *state); 105 | 106 | /** 107 | * Copy the hashing state 108 | */ 109 | void sha384_inc_ctx_clone(sha384ctx *stateout, const sha384ctx *statein); 110 | 111 | /** 112 | * Absorb blocks 113 | */ 114 | void sha384_inc_blocks(sha384ctx *state, const uint8_t *in, size_t inblocks); 115 | 116 | /** 117 | * Finalize and obtain the digest. 118 | * 119 | * If applicable, this function will free the memory associated with the sha384ctx. 120 | */ 121 | void sha384_inc_finalize(uint8_t *out, sha384ctx *state, const uint8_t *in, size_t inlen); 122 | 123 | /** 124 | * Destroy the state. Make sure to use this if not calling finalize, as this API may not always be stack-based. 125 | */ 126 | void sha384_inc_ctx_release(sha384ctx *state); 127 | 128 | /** 129 | * All-in-one sha384 function 130 | */ 131 | void sha384(uint8_t *out, const uint8_t *in, size_t inlen); 132 | 133 | 134 | /* ====== SHA512 API ==== */ 135 | 136 | /** 137 | * Initialize the incremental hashing API 138 | */ 139 | void sha512_inc_init(sha512ctx *state); 140 | 141 | /** 142 | * Copy the hashing state 143 | */ 144 | void sha512_inc_ctx_clone(sha512ctx *stateout, const sha512ctx *statein); 145 | 146 | /** 147 | * Absorb blocks 148 | */ 149 | void sha512_inc_blocks(sha512ctx *state, const uint8_t *in, size_t inblocks); 150 | 151 | /** 152 | * Finalize and obtain the digest 153 | * 154 | * If applicable, this function will free the memory associated with the sha512ctx. 155 | */ 156 | void sha512_inc_finalize(uint8_t *out, sha512ctx *state, const uint8_t *in, size_t inlen); 157 | 158 | /** 159 | * Destroy the state. Make sure to use this if not calling finalize, as this API may not always be stack-based. 160 | */ 161 | void sha512_inc_ctx_release(sha512ctx *state); 162 | 163 | 164 | /** 165 | * All-in-one sha512 function 166 | */ 167 | void sha512(uint8_t *out, const uint8_t *in, size_t inlen); 168 | 169 | #endif 170 | -------------------------------------------------------------------------------- /verify.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "api.h" 5 | #include "sha2.h" 6 | 7 | unsigned char pk[CRYPTO_PUBLICKEYBYTES]; 8 | unsigned char sig[CRYPTO_BYTES]; 9 | 10 | bool DecodeBase64(unsigned char *out, const char* in); 11 | 12 | int main(void){ 13 | char addr[] = "84cJso7keg6SHW4vbNVbXccimCZrz7WoESXTtw12b5UsWqmm5"; 14 | char sigb64[] = "TqERiKoFpkDEOEUGrq2WfH/XvTxP8dzbUxUpD1UyTUyLnVUaZcqW9IV+bTLIuamWS+XVKFcslYHLnxNcjcjnCA=="; 15 | char msg[] = "There is no pot of gold at the end of the Rainbow."; 16 | 17 | printf("addr=%s\n", addr); 18 | printf("sig=%s\n", sigb64); 19 | printf("msg=%s\n", msg); 20 | 21 | // read pk from file 22 | FILE *f = fopen(addr, "rb"); // r for read, b for binary 23 | fread(pk, sizeof(pk), 1, f); 24 | fclose(f); 25 | 26 | char strMessageMagic[] = "Abcmint Signed Message:\n"; 27 | if(strlen(msg) >= 253) { 28 | printf("msglen >= 253 bytes needs varint encoding; not implementend\n"); 29 | return -1; 30 | } 31 | unsigned char buf[300]; 32 | unsigned char h[32]; 33 | unsigned char *ptr = buf; 34 | 35 | // compute sha256(sha256(len(strMessageMagic), strMessageMagic, len(msg), msg)) 36 | // see rpcwallet.cpp line 327 37 | ptr[0] = strlen(strMessageMagic); 38 | ptr += 1; 39 | memcpy(ptr, strMessageMagic, strlen(strMessageMagic)); 40 | ptr += strlen(strMessageMagic); 41 | ptr[0] = strlen(msg); 42 | ptr += 1; 43 | memcpy(ptr, msg, strlen(msg)); 44 | ptr += strlen(msg); 45 | sha256(h, buf, 1+strlen(strMessageMagic)+1+strlen(msg)); 46 | sha256(h, h, 32); 47 | 48 | // decode signature 49 | DecodeBase64(sig, sigb64); 50 | 51 | // verify signature using abcmint code 52 | int rc = rainbow_verify(h, sig, pk); 53 | if(rc == 0){ 54 | printf("Signature is valid!\n"); 55 | } else { 56 | printf("Signature is invalid!\n"); 57 | } 58 | } -------------------------------------------------------------------------------- /verify.sage: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sage 2 | import base64 3 | import hashlib 4 | import struct 5 | 6 | # be aware that this is not the usual base58, but contains modifications to the 7 | # alphabet and checksum computation 8 | import base58 9 | 10 | 11 | addr = "84cJso7keg6SHW4vbNVbXccimCZrz7WoESXTtw12b5UsWqmm5" 12 | msg = "There is no pot of gold at the end of the Rainbow." 13 | sig = "TqERiKoFpkDEOEUGrq2WfH/XvTxP8dzbUxUpD1UyTUyLnVUaZcqW9IV+bTLIuamWS+XVKFcslYHLnxNcjcjnCA==" 14 | 15 | print(f"msg: {msg}") 16 | print(f"sig: {sig}") 17 | print(f"h(pk): {addr}") 18 | 19 | ################################################################ 20 | 21 | # convert from Rainbow tower field to F_2[x]/(x^4 + x + 1) 22 | F16. = GF(16) 23 | assert y^4+y+1 == 0 24 | x = y^2+y 25 | assert x^2+x+1 == 0 26 | 27 | def nib2el(nib): 28 | assert 0 <= nib < 16 29 | a,b,c,d = ((nib>>i)&1 for i in range(4)) 30 | return (a+b*x) + (c+d*x)*y 31 | 32 | def bytesToGF16vec(t): 33 | t = [(t[i//2]>>i%2*4)&0xf for i in range(2*len(t))] 34 | return vector(map(nib2el, t)) 35 | 36 | ################################################################ 37 | 38 | n = 96 39 | m = 64 40 | 41 | # read public key 42 | pk = open(addr,'rb').read() 43 | if pk[-1] != 0x10 or len(pk) != 152097: 44 | raise ValueError('not an ABCMint public key') 45 | 46 | # verify that it is indeed the public key corresponding to addr 47 | def hashPk(pk): 48 | h = hashlib.sha256(pk).digest() 49 | h = hashlib.sha256(h).digest() 50 | h = b'\x00' + h 51 | return base58.b58encode_check(h).decode() 52 | 53 | assert hashPk(pk) == addr 54 | 55 | # convert to GF(16) elements 56 | pk = list(bytesToGF16vec(pk[:-1])) 57 | 58 | def consume(count): 59 | global pk 60 | assert len(pk) >= count 61 | r, pk = pk[:count], pk[count:] 62 | return r 63 | 64 | # split into linear, quadratic, and constant parts 65 | linear = consume(n*m) 66 | quadratic = consume(n*(n+1)//2*m) 67 | constant = consume(m) 68 | assert not pk 69 | 70 | # convert to matrix, vector 71 | b = matrix(F16, n, m, linear) 72 | c = vector(constant) 73 | 74 | Acoeffs = quadratic[::-1] 75 | As = [matrix(F16, n, n) for _ in range(m)] 76 | for i in range(n): 77 | for j in range(i+1): 78 | for k in range(m): 79 | As[k][i,j] = Acoeffs.pop() 80 | assert not Acoeffs; del Acoeffs 81 | 82 | # Rainbow public map 83 | def pubmap(x): 84 | assert x in F16^n 85 | y = vector(x*A*x for A in As) 86 | y += x*b 87 | y += c 88 | assert y in F16^m 89 | return y 90 | 91 | ################################################################ 92 | 93 | # decode signature 94 | sig = base64.b64decode(sig) 95 | assert len(sig) == 64 96 | salt = sig[48:] 97 | sig = sig[:48] 98 | 99 | # convert signature to GF(16) 100 | sig = bytesToGF16vec(sig) 101 | 102 | # apply public map to signature to obtain hash of message 103 | h1 = pubmap(sig) 104 | 105 | def encode_varint(value): 106 | if value < pow(2, 8) - 3: 107 | size = 1 108 | varint = bytes([value]) 109 | else: 110 | if value < pow(2, 16): 111 | size = "