| /* |
| * PRNG and interface to the system RNG. |
| * |
| * ==========================(LICENSE BEGIN)============================ |
| * |
| * Copyright (c) 2017-2019 Falcon Project |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining |
| * a copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sublicense, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be |
| * included in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
| * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * |
| * ===========================(LICENSE END)============================= |
| * |
| * @author Thomas Pornin <[email protected]> |
| */ |
| |
| #include <assert.h> |
| #include <stdio.h> |
| #include "inner.h" |
| |
| int PQCLEAN_FALCONPADDED512_AARCH64_get_seed(void *seed, size_t len) { |
| unsigned char tmp[48]; |
| for (size_t i = 0; i < len; i++) { |
| tmp[i] = (unsigned char) i; |
| } |
| memcpy(seed, tmp, len); |
| return 1; |
| } |
| |
| /* see inner.h */ |
| void |
| PQCLEAN_FALCONPADDED512_AARCH64_prng_init(prng *p, inner_shake256_context *src) { |
| /* |
| * To ensure reproducibility for a given seed, we |
| * must enforce little-endian interpretation of |
| * the state words. |
| */ |
| uint8_t tmp[56]; |
| uint64_t th, tl; |
| int i; |
| |
| inner_shake256_extract(src, tmp, 56); |
| for (i = 0; i < 14; i ++) { |
| uint32_t w; |
| |
| w = (uint32_t)tmp[(i << 2) + 0] |
| | ((uint32_t)tmp[(i << 2) + 1] << 8) |
| | ((uint32_t)tmp[(i << 2) + 2] << 16) |
| | ((uint32_t)tmp[(i << 2) + 3] << 24); |
| *(uint32_t *)(p->state.d + (i << 2)) = w; |
| } |
| tl = *(uint32_t *)(p->state.d + 48); |
| th = *(uint32_t *)(p->state.d + 52); |
| *(uint64_t *)(p->state.d + 48) = tl + (th << 32); |
| PQCLEAN_FALCONPADDED512_AARCH64_prng_refill(p); |
| } |
| |
| /* |
| * PRNG based on ChaCha20. |
| * |
| * State consists in key (32 bytes) then IV (16 bytes) and block counter |
| * (8 bytes). Normally, we should not care about local endianness (this |
| * is for a PRNG), but for the NIST competition we need reproducible KAT |
| * vectors that work across architectures, so we enforce little-endian |
| * interpretation where applicable. Moreover, output words are "spread |
| * out" over the output buffer with the interleaving pattern that is |
| * naturally obtained from the AVX2 implementation that runs eight |
| * ChaCha20 instances in parallel. |
| * |
| * The block counter is XORed into the first 8 bytes of the IV. |
| */ |
| void |
| PQCLEAN_FALCONPADDED512_AARCH64_prng_refill(prng *p) { |
| |
| static const uint32_t CW[] = { |
| 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 |
| }; |
| |
| uint64_t cc; |
| size_t u; |
| |
| /* |
| * State uses local endianness. Only the output bytes must be |
| * converted to little endian (if used on a big-endian machine). |
| */ |
| cc = *(uint64_t *)(p->state.d + 48); |
| for (u = 0; u < 8; u ++) { |
| uint32_t state[16]; |
| size_t v; |
| int i; |
| |
| memcpy(&state[0], CW, sizeof CW); |
| memcpy(&state[4], p->state.d, 48); |
| state[14] ^= (uint32_t)cc; |
| state[15] ^= (uint32_t)(cc >> 32); |
| for (i = 0; i < 10; i ++) { |
| |
| #define QROUND(a, b, c, d) do { \ |
| state[a] += state[b]; \ |
| state[d] ^= state[a]; \ |
| state[d] = (state[d] << 16) | (state[d] >> 16); \ |
| state[c] += state[d]; \ |
| state[b] ^= state[c]; \ |
| state[b] = (state[b] << 12) | (state[b] >> 20); \ |
| state[a] += state[b]; \ |
| state[d] ^= state[a]; \ |
| state[d] = (state[d] << 8) | (state[d] >> 24); \ |
| state[c] += state[d]; \ |
| state[b] ^= state[c]; \ |
| state[b] = (state[b] << 7) | (state[b] >> 25); \ |
| } while (0) |
| |
| QROUND( 0, 4, 8, 12); |
| QROUND( 1, 5, 9, 13); |
| QROUND( 2, 6, 10, 14); |
| QROUND( 3, 7, 11, 15); |
| QROUND( 0, 5, 10, 15); |
| QROUND( 1, 6, 11, 12); |
| QROUND( 2, 7, 8, 13); |
| QROUND( 3, 4, 9, 14); |
| |
| #undef QROUND |
| |
| } |
| |
| for (v = 0; v < 4; v ++) { |
| state[v] += CW[v]; |
| } |
| for (v = 4; v < 14; v ++) { |
| state[v] += ((uint32_t *)p->state.d)[v - 4]; |
| } |
| state[14] += ((uint32_t *)p->state.d)[10] |
| ^ (uint32_t)cc; |
| state[15] += ((uint32_t *)p->state.d)[11] |
| ^ (uint32_t)(cc >> 32); |
| cc ++; |
| |
| /* |
| * We mimic the interleaving that is used in the AVX2 |
| * implementation. |
| */ |
| for (v = 0; v < 16; v ++) { |
| p->buf.d[(u << 2) + (v << 5) + 0] = |
| (uint8_t)state[v]; |
| p->buf.d[(u << 2) + (v << 5) + 1] = |
| (uint8_t)(state[v] >> 8); |
| p->buf.d[(u << 2) + (v << 5) + 2] = |
| (uint8_t)(state[v] >> 16); |
| p->buf.d[(u << 2) + (v << 5) + 3] = |
| (uint8_t)(state[v] >> 24); |
| } |
| } |
| *(uint64_t *)(p->state.d + 48) = cc; |
| |
| p->ptr = 0; |
| } |
| |
| /* see inner.h */ |
| void |
| PQCLEAN_FALCONPADDED512_AARCH64_prng_get_bytes(prng *p, void *dst, size_t len) { |
| uint8_t *buf; |
| |
| buf = dst; |
| while (len > 0) { |
| size_t clen; |
| |
| clen = (sizeof p->buf.d) - p->ptr; |
| if (clen > len) { |
| clen = len; |
| } |
| memcpy(buf, p->buf.d, clen); |
| buf += clen; |
| len -= clen; |
| p->ptr += clen; |
| if (p->ptr == sizeof p->buf.d) { |
| PQCLEAN_FALCONPADDED512_AARCH64_prng_refill(p); |
| } |
| } |
| } |