From a2e7e05c401ef86fb40ffaa5b48ecdcd2ad4b4d7 Mon Sep 17 00:00:00 2001 From: tevador Date: Wed, 13 Mar 2019 22:58:22 +0100 Subject: [PATCH] Improved definition of magic constants --- doc/design.md | 4 ++-- doc/specs.md | 49 +++++++++++++++++++++++++++++++++++++------------ 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/doc/design.md b/doc/design.md index b76459d..d4fd423 100644 --- a/doc/design.md +++ b/doc/design.md @@ -106,9 +106,9 @@ SquareHash was chosen for its relative simplicity (uses only two operations - mu From a cryptographic standpoint, SquareHash achieves full [Avalanche effect](https://en.wikipedia.org/wiki/Avalanche_effect). SquareHash was originally based on [exponentiation by squaring](https://en.wikipedia.org/wiki/Exponentiation_by_squaring). In the [x86 assembly implementation](https://github.com/tevador/RandomX/blob/master/src/asm/squareHash.inc), if `adc rax, 0` is added after each subtraction, SquareHash becomes the following operation: -(x+1613783669344650115)4398046511104 mod 264+1 +(x+9507361525245169745)4398046511104 mod 264+1 , -where 4398046511104 = 242. The addition of the carry was removed to improve CPU performance. The constant `1613783669344650115` is added to make SquareHash sensitive to zero. +where 4398046511104 = 242. The addition of the carry was removed to improve CPU performance. The constant `9507361525245169745` is added to make SquareHash sensitive to zero. #### Generator diff --git a/doc/specs.md b/doc/specs.md index 6a07eeb..510ee7c 100644 --- a/doc/specs.md +++ b/doc/specs.md @@ -97,11 +97,20 @@ The Generator produces a sequence of pseudo-random bytes. The Generator state consists of 64 bytes arranged into four columns of 16 bytes each. During each output iteration, every column is decrypted (columns 0, 2) or encrypted (columns 1, 3) with one AES round using the following round keys (one key per column): ``` -key0 = 26 4d a0 67 ab e6 2d 7d 2f 8d 49 79 06 f2 74 92 -key1 = 12 98 71 4f 15 8a 65 86 1d 6f 3a 2a 05 af f7 e1 -key2 = 0e 75 90 ba ce 7b c7 14 14 c9 2e 9e 91 f7 b1 d1 -key3 = 1f 62 07 aa 4f be 3b a5 3c 88 57 6e d9 0f 9d 17 +key0 = 2d ec ee 84 d5 f6 4f 45 32 91 32 ca e3 a2 20 df +key1 = d0 63 7b 01 78 c5 0f f1 7f 38 d0 fe 71 59 eb 1d +key2 = 52 7a 7d 32 a1 70 2c 2f b4 ce 17 a5 b3 26 c9 df +key3 = d3 77 8d 5c 5e da 17 3d a9 e0 ec a0 1c f3 1c 34 ``` +These keys were generated by calculating Blake2b hash with 256-bit output of these ASCII strings (first 128 bits of the hash are used): +``` +"RandomX Generator key0" +"RandomX Generator key1" +"RandomX Generator key2" +"RandomX Generator key3" +``` + + Single iteration produces 64 bytes of output which also become the new generator state. ``` state0 (16 B) state1 (16 B) state2 (16 B) state3 (16 B) @@ -120,10 +129,18 @@ The Finalizer calculates a 512-bit fingerprint of its input. The Finalizer has a 64-byte internal state, which is arranged into four columns of 16 bytes each. The initial state is: ``` -state0 = 5d 9f e4 3f 93 8d ac 30 85 33 94 59 ae b0 04 9d -state1 = 64 60 0c 7b d3 ec 24 a7 35 09 c1 dd f1 eb 39 8a -state2 = e3 82 53 fb f7 ec 12 7c da ed 01 df 20 04 c7 7e -state3 = 05 b7 28 77 09 41 e7 b2 c8 d1 82 50 01 d2 a9 94 +state0 = 00 8e 77 c4 ab f5 7a 88 67 d1 46 11 fd 26 31 8d +state1 = 4b ef 34 b8 89 af 95 1b 2b 63 da 58 a1 9f fe 19 +state2 = 3a dd 42 77 00 3a 28 ab 44 d7 5a c3 74 cd b2 1b +state3 = 9a 44 8b e1 cc 97 5d dc 57 3c 59 49 8a a5 30 bb +``` + +The initial state vectors were generated by calculating Blake2b hash with 256-bit output of these ASCII strings (first 128 bits of the hash are used): +``` +"RandomX Finalizer state0" +"RandomX Finalizer state1" +"RandomX Finalizer state2" +"RandomX Finalizer state3" ``` The input is processed in 64-byte blocks. Each input block is considered to be a set of four AES round keys `key0`, `key1`, `key2`, `key3`. Each state column is encrypted (columns 0, 2) or decrypted (columns 1, 3) with one AES round using the corresponding round key: @@ -141,8 +158,14 @@ state0 (16 B) state1 (16 B) state2 (16 B) state3 (16 B) When all input bytes have been processed, the state is processed with two additional AES rounds with the following extra keys (one key per round, same pair of keys for all columns): ``` -xkey0 = 17 7b 76 c3 44 a7 31 82 05 d7 3b 05 c5 37 f6 4f -xkey1 = 2e ae 8f 8a 00 a2 1d b0 58 9d 87 a8 a6 a1 94 65 +xkey0 = 47 f2 cb 11 9c 92 5a 2a 3d 59 c5 e4 83 12 95 83 +xkey1 = 95 6c 81 ce 0b ef 7b 47 23 25 bc ab b2 5b 21 ff +``` + +The extra keys were generated by calculating Blake2b hash with 256-bit output of these ASCII strings (first 128 bits of the hash are used): +``` +"RandomX Finalizer xkey0" +"RandomX Finalizer xkey1" ``` ``` @@ -163,14 +186,16 @@ The final state is the output of the function. ### 3.4 SquareHash -`SquareHash` is a custom diffusion function with a 64-bit input and a 64-bit output. It is calculated by adding `1613783669344650115` to the input value and then repeatedly squaring the state, splitting the 128-bit result in to two 64-bit halves and subtracting the high half from the low half. This is repeated 42 times. +`SquareHash` is a custom diffusion function with a 64-bit input and a 64-bit output. It is calculated by adding `9507361525245169745` to the input value and then repeatedly squaring the state, splitting the 128-bit result in to two 64-bit halves and subtracting the high half from the low half. This is repeated 42 times. -1. `state = input + 1613783669344650115` +1. `state = input + 9507361525245169745` 2. `(hi, lo) = state * state` 3. `state = lo - hi` 4. Perform steps 2-3 total of 42 times. 5. Return `state`. +The magic constant `9507361525245169745` was generated by calculating `SquareHash0(42)`, where `SquareHash0` is a version of `SquareHash` without the magic constant addition in step 1. + ## 4. Virtual Machine The RandomX virtual machine can be summarized by the following schematic: