MySuiteA's View of Cryptogrpahy Algorithms

In MySuiteA's view, a cryptographic algorithm consist of a set of functions that transforms operands between various forms such as plaintext message, ciphertext, digest, signature, predicate, and/or other form of information;

a cryptographic algorithm is associated with a set of properties that are intrinsic of the algorithm (e.g. key and key schedule size, output size, input length limit);

an algorithm may be based on another algorithm, a.k.a. an algorithm is parameterized by another (set of) algorithm(s) - for example, a digital signature may be instantiated with a hash function, an encryption algorithm may be instantiated with a blockcipher, etc.

Based on the above premise, the term algorithm construction refers to algorithms that needs to be instantiated with another (set of) algorithm(s) or other types of parameters; the term algorithm instance refers to algorithms which have all necessary parameterizations (if any) specified and can operate on operands in a definite way.

The term algorithm can refer to either algorithm construction or algorithm instance. The term algorithm family is banned from use in MySuiteA documentations as it is ambiguous.

MySuiteA's Implementation of Algorithms

Algorithm Instances

MySuiteA implements a uniform interface for using and instantiating from cryptographic algorithms at compile, link, and run time.

At compile time, a function-like macro whose name consists of the name of the algorithm prefixed with a single lower-case letter "c" is defined. This macro takes a single argument q, which specifies the property associated with the algorithm to be queried, and evaluates to the value of that property. For other queries, this macro evaluates to 0.

At link time, a similar macro exists. In addition to the queries available in the compile time queries, the pointers to the set of functions constituting the algorithm may be queried. The prefix of this macro is "x" instead of "c".

At run time, a function with the exact behavior of the link time macro exists. A function is needed so as to enable run-time instantiation, as a function can be encapsulated in a pointer to the function. Such a function is colloquially called a "crypto object".

For the set of queries available (and their applicability to particular types of algorithm), see "mysuitea-common.h".

Algorithm Construction Instantiation at Run Time

The "crypto object" function mentioned above takes a single argument. It has the prototype:

      IntPtr (*iCryptoObj_t)(int q);
    

where IntPtr is a signed integer type with same width as a pointer type. By default this is defined to be the same as intptr_t, however on systems where object and function pointer types have different representation, this may be changed to something else by the user of the MySuiteA library.

A algorithm construction crypto object is represented as a function that takes a parameterization argument first, then the query. Such function has the prototype:

      IntPtr (*tCryptoObj_t)(const CryptoParam_t *P, int q);
    

where CryptoParam_t contains the following members:

iCryptoObj_t info; This member is used when param and aux are both NULL, which indicates this parameter is an algorithm instance.

tCryptoObj_t template; This member is used if param or aux is non-NULL, which indicates this parameter is an algorithm construction that takes further instantiation parameter(s).

The members info and template are aliased together in a union data structure.

const CryptoParam_t *param; If used, this is passed as the first argument to template. This allows an algorithm construction to be recursively instantiated by other algorithm constructions and instances.

IntPtr aux If used, this is passed as the first argument to template. This member allow certain algorithm constructions to be instantiated with miscellaneous objects and values and in ways not defined in MySuiteA. This member is aliased to param in a union data structure, so that caller of template doesn't have to be aware of its argument semantics.

Both the parameter P and the member param may point to both a single CryptoParam_t object, or the initial element of an array of which - in the case of an array, the algorithm construction is said to be parameterized by multiple elements.

Consideration for Public-Key Algorithms

Previously (before v0.2) there was a PKParamsFunc query for obtaining instantiation parameters for use in PKC algorithms. The way it's implemented caused inflexibility with re-combining PKC Algorithms with other instantiation parameters.

The approach taken in v0.2 is to have a PKC_Algo_Inst_t data structure, representing an PKC algorithm instance, defined as:

      typedef struct {
      int secbits;
      tCryptoObj_t algo;
      CryptoParam_t *param;
      } PKC_Algo_Inst_t;
    

Initial set of instantiation parameters for the algorithms are declared in the header files named ${algorithm-name}-paramset.h, and defined in the corresponding C source code file. Algorithm instances are generally named as ${Algorithm-Name}_${Parameter}

To use an algorithm instance, after checking it provides the desired security level, query algo with param as instantiation parameter, and obtain relevant algorithm characteristics and interfaces.

Facilities for Supporting Multi-Threaded Algorithms

Parallel and tree hashing had been an active area of research, with results such as KangarooTwelve and BLAKE3 turning up. These 2 algorithms are implemented in the Suite with a thin layer of hosted library support.

The model chosen for these multi-thread capable algorithms, is to implement them in such way that, they can take a parallel object to dispatch independent workloads to a crew of threads in a hosted environment; equally, in a freestanding environment, the thread crew can just be a stub that executes the workload subroutine within the control flow with no benefit of any concurrency.

The thread crew is provided as a pointer to a structure which contains at least 2 interfaces - an enqueue that dispatches the workload, and a wait that waits for all currently dispatched workloads to complete. The thread crew instances shall have structures that're layout-compatible with the TCrew_Abstract_t data type, as defined here:

      typedef void (*TCrew_Assignment_t)(void *ctx);

      typedef int (*TCrew_Dispatch_t)(
      void *crew, TCrew_Assignment_t func, void *ctx);

      typedef struct {
      TCrew_Dispatch_t enqueue;
      TCrew_Dispatch_t wait;
      } TCrew_Abstract_t;
    

MySuiteA Algorithm APIs

MySuiteA strives to implement a uniform set of interface where there's a common API for each type of cryptographic algorithm. This interface is layered, where higher-level schemes may be instantiated from lower-level primitives. As explained in the note in "notes.md" dated [2021-09-03b], blockciphers, permutations, hash, and XOF functions never take parameters to instantiate from, and will always be algorithm instances.

MySuiteA is an octet-oriented implementation, and is written with the assumption that 1 byte is exactly 8 bits (1 octet). It also assumes that 16-bit, 32-bit, 64-bit exact-width integers are available.

In the following sub-sections, property queries available to a particular type of cryptographic algorithm are listed in code shading, each followed by a description of its semantic. The following shorthands are used in function prototype descriptions:

buf void *
dat void const *
rbuf void *restrict
rdat void const *restrict
_param_ const CryptoParam_t *P
_tc_ TCrew_Abstract_t *restrict tc

Blockcipher

A blockcipher is a fixed-width keyed permutation. MySuiteA currently only support a single block size of 128 bits. Use of 64-bit blocks have negative security implications; blockciphers with larger block sizes currently lack support from higher-level algorithm constructions and therefore have poorer interoperability and is of lesser use.

Note the phrase "blockcipher instance" is used to distinguish it from a blockcipher family, which may specify many variants of blockcipher instances.

blockBytes
Block size of the blockcipher instance in bytes
keyBytes
Key size of the blockcipher instance in bytes
keyschedBytes
Key schedule size of the blockcipher instance in bytes
EncFunc
The blockcipher encryption function of prototype void (*)(dat in, buf out, rdat w); where
DecFunc
The blockcipher decryption function of prototype void (*)(dat in, buf out, rdat w); where
KschdFunc
The key schedule expansion function of prototype void (*)(rdat key, rbuf w); where

[note:in-out-ptr-alias] Note that neither in nor out has the restrict pointer qualifier. This is an intentional design decision for allowing in-place cipher computation. It is implemented as if the encryption and decryption functions first copied input to output buffer before encryption/decryption.

Permutation

blockBytes
The block size of the permutation
PermuteFunc
The (forward) permutation function of prototype void (*)(dat in, buf out); where

See note tagged [note:in-out-ptr-alias] in the Blockcipher section.

Hash Function & Message Authentication Code

outBytes
The length of the hash digest / MAC tag output in bytes
blockBytes (hash-specific)
The amount of data in bytes, which when accumulated, will cause the state transformation function, (be it a compression function, a permutation, or anything else,) to iterate for 1 invocation.
keyBytes (MAC-specific)
The supported length(s) of the key. See "mysuitea-common.h" for the interpretation of the values of this property.
contextBytes
The size of the working context, in bytes, for the hash/MAC function.
InitFunc (hash-specific)
The working context initialization function of prototype void (*)(rbuf x); where
KInitFunc (MAC-specific)
The working context initialization function of prototype void *(*)(rbuf x, rdat k, size_t klen);; or if the construction is parameterized, the function of prototype void *(*)(_param_, rbuf x, rdat k, size_t klen); where If the key length is invalid for the MAC function, or some other (yet-to-be-specified) error occurs, the function returns NULL. Otherwise, everything succeeds, and x is returned.
UpdateFunc
The update function that feeds data into the hash working context. It has the prototype void (*)(rbuf x, rdat data, size_t len); where
FinalFunc
The finalization function which marks the working context as finalized and computes the hash digest / MAC tag if the working context hasn't been finalized yet, and then reads out the result. It has the prototype void (*)(rbuf x, rdat out, size_t t); where

[note:outlen]: It is a convention of MySuiteA that, if the requested length is greater than (or less than) the digest/tag length of the hash/MAC function, then the output will be zero-extended (or truncated).

Additionally, for parallel and tree hashing algorithms, there are:

Update4Func
The multi-threaded update function. In addition to the arguments taken by the regular update function, it takes a parallel object that's layout compatible with TCrew_Abstract_t to potentially provide concurrent computation. It has the prototype void (*)(rbuf x, rdat data, size_t len, _tc_); where
Final2Func
The finalization function which marks the working context as finalized and perform some tail computation. It has the prototype void (*)(rbuf x, _tc_); where
Read4Func
The reading function that copies the digest into output buffers. It has prototype void (*)(rbuf x, rbuf data, size_t len, int flags); where

Because newer parallel and tree hashing algorithms are commonly XOFs, by default, this function behaves identically to XOF's ReadFunc when flags is 0. There is the flag HASHING_READ4_REWIND that resets the reading offset of the hashing context to the start, and it's currently the only flag defined for Read4Func.

XOF (Extendable-Output Function)

outTruncBytes
The recommended output length if this XOF is to be used as a regular hash function. This generally matches the length needed to achieve collision-resistance at the security level advertised by the algorithm.
blockBytes (hash-specific)
The amount of data in bytes, which when accumulated, will cause the state transformation function, (be it a compression function, a permutation, or anything else,) to iterate for 1 invocation.
contextBytes
The size of the working context, in bytes, for the XOF function.
InitFunc (hash-specific)
The working context initialization function of prototype void (*)(rbuf x); where
WriteFunc
The update function that feeds (writes) data into the XOF working context. It has the prototype void (*)(rbuf x, rdat data, size_t len); where
XofFinalFunc
The finalization function. If the working context hasn't been finalized yet, marks the working context as finalized and performs finalization computation to make the context ready for output being read. Otherwise, it resets output stream to the start. It has the prototype void (*)(rbuf x); where
ReadFunc
The output function that reads data out of the XOF working context. It has the prototype void (*)(rbuf x, rbuf data, size_t len); where

Because WriteFunc and UpdateFunc have identical prototype, and that they serve very similar purpose, these 2 symbolic constants are aliased together by having identical numerical value.

Some algorithms (e.g. KMAC) can operate in both XOF and regular fixed-length mode, and may support domain separation between different usage. These algorithms usually support all three of FinalFunc, XofFinalFunc, and ReadFunc. And, their FinalFunc behave similar to XofFinalFunc and ReadFunc called in adjacent sequence.

Encryption

keyBytes
The byte length of the key supported by the algorithm instance
contextBytes
The size of the cipher working context in bytes
ivBytes
The byte length of the initialization vector supported by the algorithm instance.
KInitFunc
The working context initialization function of prototype void *(*)(rbuf x, rdat k, size_t klen);; or if it's a parameterized algorithm construction, the function of prototype void *(*)(_param_, rbuf x, rdat k, size_t klen); where If the key length is invalid for the algorithm instance, or some other (yet-to-be-specified) error occurs, the function returns NULL. Otherwise, everything succeeds, and x is returned.
AEncFunc
The authenticated encryption function of prototype
void *(*)(
          rbuf x,
          size_t ivlen, dat iv,
          size_t alen, dat aad,
          size_t len, dat in, buf out,
          size_t tlen, buf T);
        
where Upon successful encryption, out will be returned. Otherwise, if there's unsupported/invalid parameter(s) or any other kind of error, NULL will be returned.
ADecFunc
The authenticated encryption function of prototype
void *(*)(
          rbuf x,
          size_t ivlen, dat iv,
          size_t alen, dat aad,
          size_t len, dat in, buf out,
          size_t tlen, dat T);
        
where Upon successful decryption, out will be returned. Otherwise, if there's decryption failure, unsupported/invalid parameter(s) or any other kind of error, NULL will be returned.

See notes tagged [note:in-out-ptr-alias] in the Blockcipher section and [note:outlen] in the Hash Function & Message Authentication Code section.

Pseudo-Random Number Generator

contextBytes
The size of the PRNG working context in bytes.
seedBytes
The supported length(s) of the seed in bytes.
InstInitFunc
The PRNG instantiation initialization function. It has the prototype: void *(*)(rbuf x, rdat seedstr, size_t len); or if the construction is parameterized, the function of prototype: void *(*)(_param_, rbuf x, rdat seedstr, size_t len); where If the seed length is unsupported, or some other (yet-to-be-speciied) error, the function returns NULL. Otherwise, everything succeeds, and x is returned.
ReseedFunc
The PRNG reseeding function of prototype: void (*)(rbuf x, rdat seedstr, size_t len); where
GenFunc
The PRNG randomness generation function of prototype: void (*)(rbuf x, rbuf out, size_t len); where

Due to functional similarity as well as them having identical prototypes, InstInitFunc, ReseedFunc, and GenFunc are aliased to KInitFunc, WriteFunc, and ReadFunc respectively, by them having identical corresponding numerical values.

Key-Pair Encoding/Decoding Function Set

The API for key-pair encoding and decoding is common to both PKE/KEM and signature schemes, therefore it's described here in the first place.

The encoder functions have the prototype:

IntPtr (*PKKeyEncoder_t)(
      rdat any,
      rbuf enc,
      size_t enclen,
      _param_);

where as the decoder functions have the prototype:

IntPtr (*PKKeyDecoder_t)(
      rbuf any,
      rdat enc,
      size_t enclen,
      _param_);

The any parameter points to the working context of the PKC algorithm, which may be the public-key or the private-key working context depending on the usage. The enc parameter points to the buffer that holds the encoded key. The enclen specifies the length of this buffer. The _param_ parameter specifies the instantiation parameters used for the algorithm, which will be taken into account when estimating the size of the working context.

These functions have 2 passes. In the 1st pass, these functions returns the estimated size of encoded key (encoder) or the working context (decoder). If some error occurs, then -1 is returned. The actual encoding/decoding is carried out in the 2nd pass. The return value in the 2nd pass is the same as that from the 1st pass.

Such setup is necessary, as some key formats (e.g. ASN.1 DER encoding of RSA private keys) have variable encoded lengths depending on the values of components of the key material, even when the parameters are otherwise constant.

In pass 1, the enc and enclen should be specified as NULL and 0 respectively for the encoder (although enclen is ignored for now, it may have other reserved meaning in future versions of MySuiteA); for the decoder, any should be specified as NULL.

In pass 2, all of any, enc, enclen, and _param_ should be specified with valid values.

PKKengenFunc
The key generation function with which this key-pair formatting function set is associated.
PKPrivkeyEncoder
PKKeyEncoder_t where any is the private-key working context
PKPrivkeyDecoder
PKKeyDecoder_t where any is the private-key working context
PKPubkeyExporter
PKKeyEncoder_t where any is the private-key working context
PKPubkeyEncoder
PKKeyEncoder_t where any is the public-key working context
PKPubkeyDecoder
PKKeyDecoder_t where any is the public-key working context

Ciphergram Encoding/Decoding Function Set

The interface for encoding and decoding is the same for both KEM/PKE and digital signatures. They're associated with the PKC algorithm through the public/private function pair.

The encoder functions have the prototype:

void *(*PKCiphergramEncoder_t)(
      rbuf x,
      rbuf c, size_t *len);

The encoder function saves the ciphergram (ciphertext or signature) into c. It returns c on success and NULL otherwise. If c is NULL then *len is set to its length.

Such set up is necessary as some formats of some signatures (e.g. ECDSA when encoding (r,s) using ASN.1 DER encoding, or the Falcon PQC digital signature scheme) have lengths that're variable.

The decoder functions have the prototype:

void *(*PKCiphergramDecoder_t)(
      rbuf x,
      rdat c, size_t len);

The decoder function loads the ciphergram into the working context of the PKC algorithm. It returns x on success and NULL on failure.

PKEncFunc (KEM-specific)
The key encapsulating function with which the ciphergram formatting function set is associated,
PKDecFunc (KEM-specific)
The key decapsulating function with which the ciphergram formatting function set is associated,
PKSignFunc (signature scheme -specific)
The private-key signing function with which the ciphergram formatting function set is associated,
PKVerifyFunc (signature scheme -specific)
The public-key verification function with which the ciphergram formatting function set is associated,
PKCtEncoder
The ciphergram encoding function of prototype PKCiphergramEncoder_t. Ct means cipher transcript.
PKCtDecoder
The ciphergram decoding function of prototype PKCiphergramDecoder_t. Ct means cipher transcript.

KEM - Key Encapsulation Mechanisms

isParamDetermByKey

If the value of this query is 1, then the values of the queries bytesCtxPriv and bytesCtxPub can only be used for private contexts for generating keys, as the parameters and the size of the working contexts are variable depending on the key to be loaded.

On the other hand, if the value of this query is 0, then bytesCtxPriv and bytesCtxPub can be used to set parameters for the working context, as they're not determined by the key. See "mysuitea-common.h" for more.

bytesCtxPriv
The size of the private-key working context
bytesCtxPub
The size of the public-key working context

PKKeygenFunc

The key generation function of prototype:

IntPtr (*PKKeygenFunc_t)(
          rbuf x, _param_,
          GenFunc_t prng_gen, rbuf prng);

where:

This function generates a key-pair and save its internal representation in the working context, which can be retrieved using key encoder/exporter functions and loaded using decoder functions.

If x is NULL, then then function returns the estimated space needed for allocating a working context based on the given parameters; otherwise, x is returned.

PKEncFunc

The KEM secret encapsulation function of prototype:

void *(*PKEncFunc_t)(
          rbuf x,
          rbuf ss, size_t *restrict sslen,
          GenFunc_t prng_gen, rbuf prng);

where:

This function generates a shared secret and a ciphertext based on the public key loaded into the public-key working context. The shared secret is stored into ss while the ciphertext is saved in a internal representation in the working context and will be exported using a ciphergram encoding function.

PKDecFunc

The KEM secret decapsulation function of prototype:

void *(*PKDecFunc_t)(
          rbuf x,
          rbuf ss, size_t *restrict sslen);

where:

This function decapsulates the shared secret from the ciphertext using the private key. The ciphertext and the private key are loaded into the private-key working context using the private key decoder function and the ciphertext decoder function. For some cryptosystems, the ciphertext may be of variable length (e.g. RSA PKE), as such, repeating the call returns the same information unless a different ciphertext is loaded using the ciphergram decoder function.

DSS - Digital Signature Schemes

isParamDetermByKey
bytesCtxPriv
bytesCtxPub
PKKeygenFunc

Same as that for KEMs'.

dssNonceNeeded
A boolean indicating whether the scheme uses nonce
dssExternRngNeededForNonce
If the implementation of the algorithm is capable of generating nonce independently of the RNG parameters, then this is false, otherwise true.

PKSignFunc

The digital signature signing function of prototype:

void *(*PKSignFunc_t)(
          rbuf x,
          rdat msg, size_t msglen,
          GenFunc_t prng_gen, rbuf prng);

where:

The function signs the message msg and saves the internal representation of the signature in x to be exported using the ciphergram encoding function. It returns x on success and NULL on failure.

PKVerifyFunc

The digital signature signing function of prototype:

const void *(*PKVerifyFunc_t)(
          rbuf x,
          rdat msg, size_t msglen);

where:

The function verifies the message msg with the public key and the signature loaded into the public-key working context using the public-key and ciphergram decoder function. It returns msg if signature is valid, and NULL otherwise.

Incremental Signing / Pre-Hashing

Many existing digital signature schemes actually signs a hash digest of the message. Those that does this including RSA (PKCS#1 v1.5 and PSS), ECDSA, and some variants of EdDSA specified in RFC-8032. To realize their full potential, incremental signing are devised.

dssPreHashingType

The type of pre-hashing supported by the algorithm instance. It can be one of the following enumerations:

PKIncSignInitFunc
PKIncVerifyInitFunc

The initialization functions for incremental signing and incremental verifying. They have the prototype:

void *(*PKIncSignInitFunc_t)(rbuf x, UpdateFunc_t *placeback);
        

This type has an alias: PKIncVerifyInitFunc_t.

When called, it initializes a hashing context and prepare it with algorithm-specific prefix data. Before returning the pointer to this working context, it places a pointer to the update function of this hashing function into placeback.

PKIncSignFinalFunc

The function that completes hashing of and produce a signature for the hashed message, of the prototype:

void *(*PKIncSignFinalFunc_t)(
          rbuf x,
          GenFunc_t prng_gen, rbuf prng);

where:

PKIncVerifyFinalFunc

The function that completes hashing and verifies the signature of the hashed message, of the prototype:

void *(*PKIncVerifyFinalFunc_t)(rbuf x);

where:

Miscellaneous Context Control Function

Context control functions are a class of catch-all functions that performs operations that're algorithm-specific. Generally, these operations involve additional parameters that can't be passed using other uniform APIs.

XctrlFunc
PubXctrlFunc
PrivXctrlFunc

The context control function of prototype:

void *(*XctrlFunc_t)(
          rbuf x,
          int cmd,
          const bufvec_t *restrict bufvec,
          int veclen,
          int flags);

where:

The query XctrlFunc generally apply to symmetric-key algorithms, whereas PubXctrlFunc and PrivXctrlFunc apply to the public and private working contexts of the asymmetric-key algorithm. And the type definition for bufvec_t is:

typedef struct {
          union {
          size_t len;
          IntPtr info;
          };
          union {
          void const *dat;
          void *buf;
          };
        } bufvec_t;