1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2019-2022 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 4e1051a39Sopenharmony_ci * 5e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 6e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 7e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 8e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 9e1051a39Sopenharmony_ci */ 10e1051a39Sopenharmony_ci 11e1051a39Sopenharmony_ci#include <openssl/crypto.h> 12e1051a39Sopenharmony_ci#include <openssl/bn.h> 13e1051a39Sopenharmony_ci#include "crypto/sparse_array.h" 14e1051a39Sopenharmony_ci 15e1051a39Sopenharmony_ci/* 16e1051a39Sopenharmony_ci * How many bits are used to index each level in the tree structure? 17e1051a39Sopenharmony_ci * This setting determines the number of pointers stored in each node of the 18e1051a39Sopenharmony_ci * tree used to represent the sparse array. Having more pointers reduces the 19e1051a39Sopenharmony_ci * depth of the tree but potentially wastes more memory. That is, this is a 20e1051a39Sopenharmony_ci * direct space versus time tradeoff. 21e1051a39Sopenharmony_ci * 22e1051a39Sopenharmony_ci * The default is to use four bits which means that the are 16 23e1051a39Sopenharmony_ci * pointers in each tree node. 24e1051a39Sopenharmony_ci * 25e1051a39Sopenharmony_ci * The library builder is also permitted to define other sizes in the closed 26e1051a39Sopenharmony_ci * interval [2, sizeof(ossl_uintmax_t) * 8]. Space use generally scales 27e1051a39Sopenharmony_ci * exponentially with the block size, although the implementation only 28e1051a39Sopenharmony_ci * creates enough blocks to support the largest used index. The depth is: 29e1051a39Sopenharmony_ci * ceil(log_2(largest index) / 2^{block size}) 30e1051a39Sopenharmony_ci * E.g. with a block size of 4, and a largest index of 1000, the depth 31e1051a39Sopenharmony_ci * will be three. 32e1051a39Sopenharmony_ci */ 33e1051a39Sopenharmony_ci#ifndef OPENSSL_SA_BLOCK_BITS 34e1051a39Sopenharmony_ci# define OPENSSL_SA_BLOCK_BITS 4 35e1051a39Sopenharmony_ci#elif OPENSSL_SA_BLOCK_BITS < 2 || OPENSSL_SA_BLOCK_BITS > (BN_BITS2 - 1) 36e1051a39Sopenharmony_ci# error OPENSSL_SA_BLOCK_BITS is out of range 37e1051a39Sopenharmony_ci#endif 38e1051a39Sopenharmony_ci 39e1051a39Sopenharmony_ci/* 40e1051a39Sopenharmony_ci * From the number of bits, work out: 41e1051a39Sopenharmony_ci * the number of pointers in a tree node; 42e1051a39Sopenharmony_ci * a bit mask to quickly extract an index and 43e1051a39Sopenharmony_ci * the maximum depth of the tree structure. 44e1051a39Sopenharmony_ci */ 45e1051a39Sopenharmony_ci#define SA_BLOCK_MAX (1 << OPENSSL_SA_BLOCK_BITS) 46e1051a39Sopenharmony_ci#define SA_BLOCK_MASK (SA_BLOCK_MAX - 1) 47e1051a39Sopenharmony_ci#define SA_BLOCK_MAX_LEVELS (((int)sizeof(ossl_uintmax_t) * 8 \ 48e1051a39Sopenharmony_ci + OPENSSL_SA_BLOCK_BITS - 1) \ 49e1051a39Sopenharmony_ci / OPENSSL_SA_BLOCK_BITS) 50e1051a39Sopenharmony_ci 51e1051a39Sopenharmony_cistruct sparse_array_st { 52e1051a39Sopenharmony_ci int levels; 53e1051a39Sopenharmony_ci ossl_uintmax_t top; 54e1051a39Sopenharmony_ci size_t nelem; 55e1051a39Sopenharmony_ci void **nodes; 56e1051a39Sopenharmony_ci}; 57e1051a39Sopenharmony_ci 58e1051a39Sopenharmony_ciOPENSSL_SA *ossl_sa_new(void) 59e1051a39Sopenharmony_ci{ 60e1051a39Sopenharmony_ci OPENSSL_SA *res = OPENSSL_zalloc(sizeof(*res)); 61e1051a39Sopenharmony_ci 62e1051a39Sopenharmony_ci return res; 63e1051a39Sopenharmony_ci} 64e1051a39Sopenharmony_ci 65e1051a39Sopenharmony_cistatic void sa_doall(const OPENSSL_SA *sa, void (*node)(void **), 66e1051a39Sopenharmony_ci void (*leaf)(ossl_uintmax_t, void *, void *), void *arg) 67e1051a39Sopenharmony_ci{ 68e1051a39Sopenharmony_ci int i[SA_BLOCK_MAX_LEVELS]; 69e1051a39Sopenharmony_ci void *nodes[SA_BLOCK_MAX_LEVELS]; 70e1051a39Sopenharmony_ci ossl_uintmax_t idx = 0; 71e1051a39Sopenharmony_ci int l = 0; 72e1051a39Sopenharmony_ci 73e1051a39Sopenharmony_ci i[0] = 0; 74e1051a39Sopenharmony_ci nodes[0] = sa->nodes; 75e1051a39Sopenharmony_ci while (l >= 0) { 76e1051a39Sopenharmony_ci const int n = i[l]; 77e1051a39Sopenharmony_ci void ** const p = nodes[l]; 78e1051a39Sopenharmony_ci 79e1051a39Sopenharmony_ci if (n >= SA_BLOCK_MAX) { 80e1051a39Sopenharmony_ci if (p != NULL && node != NULL) 81e1051a39Sopenharmony_ci (*node)(p); 82e1051a39Sopenharmony_ci l--; 83e1051a39Sopenharmony_ci idx >>= OPENSSL_SA_BLOCK_BITS; 84e1051a39Sopenharmony_ci } else { 85e1051a39Sopenharmony_ci i[l] = n + 1; 86e1051a39Sopenharmony_ci if (p != NULL && p[n] != NULL) { 87e1051a39Sopenharmony_ci idx = (idx & ~SA_BLOCK_MASK) | n; 88e1051a39Sopenharmony_ci if (l < sa->levels - 1) { 89e1051a39Sopenharmony_ci i[++l] = 0; 90e1051a39Sopenharmony_ci nodes[l] = p[n]; 91e1051a39Sopenharmony_ci idx <<= OPENSSL_SA_BLOCK_BITS; 92e1051a39Sopenharmony_ci } else if (leaf != NULL) { 93e1051a39Sopenharmony_ci (*leaf)(idx, p[n], arg); 94e1051a39Sopenharmony_ci } 95e1051a39Sopenharmony_ci } 96e1051a39Sopenharmony_ci } 97e1051a39Sopenharmony_ci } 98e1051a39Sopenharmony_ci} 99e1051a39Sopenharmony_ci 100e1051a39Sopenharmony_cistatic void sa_free_node(void **p) 101e1051a39Sopenharmony_ci{ 102e1051a39Sopenharmony_ci OPENSSL_free(p); 103e1051a39Sopenharmony_ci} 104e1051a39Sopenharmony_ci 105e1051a39Sopenharmony_cistatic void sa_free_leaf(ossl_uintmax_t n, void *p, void *arg) 106e1051a39Sopenharmony_ci{ 107e1051a39Sopenharmony_ci OPENSSL_free(p); 108e1051a39Sopenharmony_ci} 109e1051a39Sopenharmony_ci 110e1051a39Sopenharmony_civoid ossl_sa_free(OPENSSL_SA *sa) 111e1051a39Sopenharmony_ci{ 112e1051a39Sopenharmony_ci if (sa != NULL) { 113e1051a39Sopenharmony_ci sa_doall(sa, &sa_free_node, NULL, NULL); 114e1051a39Sopenharmony_ci OPENSSL_free(sa); 115e1051a39Sopenharmony_ci } 116e1051a39Sopenharmony_ci} 117e1051a39Sopenharmony_ci 118e1051a39Sopenharmony_civoid ossl_sa_free_leaves(OPENSSL_SA *sa) 119e1051a39Sopenharmony_ci{ 120e1051a39Sopenharmony_ci sa_doall(sa, &sa_free_node, &sa_free_leaf, NULL); 121e1051a39Sopenharmony_ci OPENSSL_free(sa); 122e1051a39Sopenharmony_ci} 123e1051a39Sopenharmony_ci 124e1051a39Sopenharmony_ci/* Wrap this in a structure to avoid compiler warnings */ 125e1051a39Sopenharmony_cistruct trampoline_st { 126e1051a39Sopenharmony_ci void (*func)(ossl_uintmax_t, void *); 127e1051a39Sopenharmony_ci}; 128e1051a39Sopenharmony_ci 129e1051a39Sopenharmony_cistatic void trampoline(ossl_uintmax_t n, void *l, void *arg) 130e1051a39Sopenharmony_ci{ 131e1051a39Sopenharmony_ci ((const struct trampoline_st *)arg)->func(n, l); 132e1051a39Sopenharmony_ci} 133e1051a39Sopenharmony_ci 134e1051a39Sopenharmony_civoid ossl_sa_doall(const OPENSSL_SA *sa, void (*leaf)(ossl_uintmax_t, void *)) 135e1051a39Sopenharmony_ci{ 136e1051a39Sopenharmony_ci struct trampoline_st tramp; 137e1051a39Sopenharmony_ci 138e1051a39Sopenharmony_ci tramp.func = leaf; 139e1051a39Sopenharmony_ci if (sa != NULL) 140e1051a39Sopenharmony_ci sa_doall(sa, NULL, &trampoline, &tramp); 141e1051a39Sopenharmony_ci} 142e1051a39Sopenharmony_ci 143e1051a39Sopenharmony_civoid ossl_sa_doall_arg(const OPENSSL_SA *sa, 144e1051a39Sopenharmony_ci void (*leaf)(ossl_uintmax_t, void *, void *), 145e1051a39Sopenharmony_ci void *arg) 146e1051a39Sopenharmony_ci{ 147e1051a39Sopenharmony_ci if (sa != NULL) 148e1051a39Sopenharmony_ci sa_doall(sa, NULL, leaf, arg); 149e1051a39Sopenharmony_ci} 150e1051a39Sopenharmony_ci 151e1051a39Sopenharmony_cisize_t ossl_sa_num(const OPENSSL_SA *sa) 152e1051a39Sopenharmony_ci{ 153e1051a39Sopenharmony_ci return sa == NULL ? 0 : sa->nelem; 154e1051a39Sopenharmony_ci} 155e1051a39Sopenharmony_ci 156e1051a39Sopenharmony_civoid *ossl_sa_get(const OPENSSL_SA *sa, ossl_uintmax_t n) 157e1051a39Sopenharmony_ci{ 158e1051a39Sopenharmony_ci int level; 159e1051a39Sopenharmony_ci void **p, *r = NULL; 160e1051a39Sopenharmony_ci 161e1051a39Sopenharmony_ci if (sa == NULL || sa->nelem == 0) 162e1051a39Sopenharmony_ci return NULL; 163e1051a39Sopenharmony_ci 164e1051a39Sopenharmony_ci if (n <= sa->top) { 165e1051a39Sopenharmony_ci p = sa->nodes; 166e1051a39Sopenharmony_ci for (level = sa->levels - 1; p != NULL && level > 0; level--) 167e1051a39Sopenharmony_ci p = (void **)p[(n >> (OPENSSL_SA_BLOCK_BITS * level)) 168e1051a39Sopenharmony_ci & SA_BLOCK_MASK]; 169e1051a39Sopenharmony_ci r = p == NULL ? NULL : p[n & SA_BLOCK_MASK]; 170e1051a39Sopenharmony_ci } 171e1051a39Sopenharmony_ci return r; 172e1051a39Sopenharmony_ci} 173e1051a39Sopenharmony_ci 174e1051a39Sopenharmony_cistatic ossl_inline void **alloc_node(void) 175e1051a39Sopenharmony_ci{ 176e1051a39Sopenharmony_ci return OPENSSL_zalloc(SA_BLOCK_MAX * sizeof(void *)); 177e1051a39Sopenharmony_ci} 178e1051a39Sopenharmony_ci 179e1051a39Sopenharmony_ciint ossl_sa_set(OPENSSL_SA *sa, ossl_uintmax_t posn, void *val) 180e1051a39Sopenharmony_ci{ 181e1051a39Sopenharmony_ci int i, level = 1; 182e1051a39Sopenharmony_ci ossl_uintmax_t n = posn; 183e1051a39Sopenharmony_ci void **p; 184e1051a39Sopenharmony_ci 185e1051a39Sopenharmony_ci if (sa == NULL) 186e1051a39Sopenharmony_ci return 0; 187e1051a39Sopenharmony_ci 188e1051a39Sopenharmony_ci for (level = 1; level < SA_BLOCK_MAX_LEVELS; level++) 189e1051a39Sopenharmony_ci if ((n >>= OPENSSL_SA_BLOCK_BITS) == 0) 190e1051a39Sopenharmony_ci break; 191e1051a39Sopenharmony_ci 192e1051a39Sopenharmony_ci for (;sa->levels < level; sa->levels++) { 193e1051a39Sopenharmony_ci p = alloc_node(); 194e1051a39Sopenharmony_ci if (p == NULL) 195e1051a39Sopenharmony_ci return 0; 196e1051a39Sopenharmony_ci p[0] = sa->nodes; 197e1051a39Sopenharmony_ci sa->nodes = p; 198e1051a39Sopenharmony_ci } 199e1051a39Sopenharmony_ci if (sa->top < posn) 200e1051a39Sopenharmony_ci sa->top = posn; 201e1051a39Sopenharmony_ci 202e1051a39Sopenharmony_ci p = sa->nodes; 203e1051a39Sopenharmony_ci for (level = sa->levels - 1; level > 0; level--) { 204e1051a39Sopenharmony_ci i = (posn >> (OPENSSL_SA_BLOCK_BITS * level)) & SA_BLOCK_MASK; 205e1051a39Sopenharmony_ci if (p[i] == NULL && (p[i] = alloc_node()) == NULL) 206e1051a39Sopenharmony_ci return 0; 207e1051a39Sopenharmony_ci p = p[i]; 208e1051a39Sopenharmony_ci } 209e1051a39Sopenharmony_ci p += posn & SA_BLOCK_MASK; 210e1051a39Sopenharmony_ci if (val == NULL && *p != NULL) 211e1051a39Sopenharmony_ci sa->nelem--; 212e1051a39Sopenharmony_ci else if (val != NULL && *p == NULL) 213e1051a39Sopenharmony_ci sa->nelem++; 214e1051a39Sopenharmony_ci *p = val; 215e1051a39Sopenharmony_ci return 1; 216e1051a39Sopenharmony_ci} 217