README.md
1Selecting algorithm implementations by properties
2=================================================
3
4Properties are associated with algorithms and are used to select between
5different implementations dynamically.
6
7This implementation is based on a number of assumptions:
8
9* Property definition is uncommon. I.e. providers will be loaded and
10 unloaded relatively infrequently, if at all.
11
12* The number of distinct property names will be small.
13
14* Providers will often give the same implementation properties to most or
15 all of their implemented algorithms. E.g. the FIPS property would be set
16 across an entire provider. Likewise for, hardware, accelerated, software,
17 HSM and, perhaps, constant_time.
18
19* There are a lot of algorithm implementations, therefore property
20 definitions should be space efficient. However...
21
22* ... property queries are very common. These must be fast.
23
24* Property queries come from a small set and are reused many times typically.
25 I.e. an application tends to use the same set of queries over and over,
26 rather than spanning a wide variety of queries.
27
28* Property queries can never add new property definitions.
29
30Some consequences of these assumptions are:
31
32* That definition is uncommon and queries are very common, we can treat
33 the property definitions as almost immutable. Specifically, a query can
34 never change the state of the definitions.
35
36* That definition is uncommon and needs to be space efficient, it will
37 be feasible to use a hash table to contain the names (and possibly also
38 values) of all properties and to reference these instead of duplicating
39 strings. Moreover, such a data structure need not be garbage collected.
40 By converting strings to integers using a structure such as this, string
41 comparison degenerates to integer comparison. Additionally, lists of
42 properties can be sorted by the string index which makes comparisons linear
43 time rather than quadratic time - the O(n log n) sort cost being amortised.
44
45* A cache for property definitions is also viable, if only implementation
46 properties are used and not algorithm properties, or at least these are
47 maintained separately. This cache would be a hash table, indexed by
48 the property definition string, and algorithms with the same properties
49 would share their definition structure. Again, reducing space use.
50
51* A query cache is desirable. This would be a hash table keyed by the
52 algorithm identifier and the entire query string and it would map to
53 the chosen algorithm. When a provider is loaded or unloaded, this cache
54 must be invalidated. The cache will also be invalidated when the global
55 properties are changed as doing so removes the need to index on both the
56 global and requested property strings.
57
58The implementation:
59
60* [property_lock.c](property_lock.c)
61 contains some wrapper functions to handle the global
62 lock more easily. The global lock is held for short periods of time with
63 per algorithm locking being used for longer intervals.
64
65* [property_string.c](property_string.c)
66 contains the string cache which converts property
67 names and values to small integer indices. Names and values are stored in
68 separate hash tables. The two Boolean values, the strings "yes" and "no",
69 are populated as the first two members of the value table. All property
70 names reserved by OpenSSL are also populated here. No functions are
71 provided to convert from an index back to the original string (this can be
72 done by maintaining parallel stacks of strings if required).
73
74* [property_parse.c](property_parse.c)
75 contains the property definition and query parsers.
76 These convert ASCII strings into lists of properties. The resulting
77 lists are sorted by the name index. Some additional utility functions
78 for dealing with property lists are also included: comparison of a query
79 against a definition and merging two queries into a single larger query.
80
81* [property.c](property.c)
82 contains the main APIs for defining and using properties.
83 Algorithms are discovered from their NID and a query string.
84 The results are cached.
85
86 The caching of query results has to be efficient but it must also be robust
87 against a denial of service attack. The cache cannot be permitted to grow
88 without bounds and must garbage collect under-used entries. The garbage
89 collection does not have to be exact.
90
91* [defn_cache.c](defn_cache.c)
92 contains a cache that maps property definition strings to
93 parsed properties. It is used by property.c to improve performance when
94 the same definition appears multiple times.
95