From a8e9bba1ed1765bc504f5b5b452b3652ca66d280 Mon Sep 17 00:00:00 2001 From: Aido Date: Sat, 2 Mar 2024 23:48:25 +0000 Subject: [PATCH] Added detailed documentation for all SSKR and SSS functions --- CHANGELOG.md | 4 +- src/sskr/sskr.c | 198 ++++++++++++++++++++------- src/sskr/sskr.h | 88 ++++++------ src/sskr/sss/interpolate.c | 70 ++++++---- src/sskr/sss/interpolate.h | 50 ++++--- src/sskr/sss/sss.c | 48 +++++-- src/sskr/sss/sss.h | 61 ++++++--- src/ux_common/onboarding_seed_sskr.c | 28 ++-- tests/unit/tests/sskr.c | 16 +-- 9 files changed, 368 insertions(+), 195 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dedf134..5a1c2be3 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Change log -## [1.7.0] - 2024-03-02 +## [1.7.0] - 2024-03-03 ### Added -- +- Added detailed documentation for all SSKR and SSS functions ### Changed - Changed Shamir interpolate function to use `cx_bn_gf2_n_mul()` syscalls diff --git a/src/sskr/sskr.c b/src/sskr/sskr.c index 9c1f6d63..e3b3f98d 100644 --- a/src/sskr/sskr.c +++ b/src/sskr/sskr.c @@ -15,6 +15,20 @@ #define memzero(...) explicit_bzero(__VA_ARGS__) +/** + * @brief Validates the length of a secret for SSKR functions. + * + * @details This function checks if the length of a secret is within the acceptable + * range for use in SSKR. It enforces constraints on the secret length to + * ensure security and compatibility. + * + * @param[in] len Length of the secret in bytes. + * + * @return 0 on success, indicating a valid secret length, or a negative error code on failure: + * - SSKR_ERROR_SECRET_TOO_SHORT: if len is less than SSKR_MIN_STRENGTH_BYTES + * - SSKR_ERROR_SECRET_TOO_LONG: if len is greater than SSKR_MAX_STRENGTH_BYTES + * - SSKR_ERROR_SECRET_LENGTH_NOT_EVEN: if len is not even + */ static int16_t sskr_check_secret_length(uint8_t len) { if (len < SSKR_MIN_STRENGTH_BYTES) { return SSKR_ERROR_SECRET_TOO_SHORT; @@ -28,6 +42,21 @@ static int16_t sskr_check_secret_length(uint8_t len) { return 0; } +/** + * @brief Serializes an SSKR shard into a byte array. + * + * @details This function converts an `sskr_shard_t` structure into a byte array suitable for + * storage or transmission. It packs the shard's metadata (identifier, group/member + * information) and value into a single buffer. + * + * @param[in] shard Pointer to the `sskr_shard_t` structure to be serialized. + * @param[out] destination Pointer to the buffer where the serialized data will be written. + * @param[in] destination_len Length of the `destination` buffer in bytes. + * + * @return Length of the serialized shard data on success, or a negative error code: + * - SSKR_ERROR_INSUFFICIENT_SPACE: if `destination_len` is not enough to hold the + * serialized data. + */ static int16_t sskr_serialize_shard(const sskr_shard_t *shard, uint8_t *destination, uint16_t destination_len) { @@ -68,6 +97,25 @@ static int16_t sskr_serialize_shard(const sskr_shard_t *shard, return shard->value_len + SSKR_METADATA_LENGTH_BYTES; } +/** + * @brief Deserializes an SSKR shard from a byte array. + * + * @details This function reconstructs an `sskr_shard_t` structure from a serialized + * byte array created using `sskr_serialize_shard`. It validates the metadata + * and extracts the shard's identifier, group/member information, and value. + * + * @param[in] source Pointer to the serialized shard data. + * @param[in] source_len Length of the `source` array in bytes. + * @param[out] shard Pointer to an `sskr_shard_t` structure to be populated. + * + * @return Length of the shard value on success, or a negative error code: + * - SSKR_ERROR_NOT_ENOUGH_SERIALIZED_BYTES: if `source_len` is too short. + * - SSKR_ERROR_INVALID_GROUP_THRESHOLD: if group threshold exceeds group count. + * - SSKR_ERROR_INVALID_RESERVED_BITS: if reserved bits are not zero. + * - SSKR_ERROR_SECRET_TOO_SHORT, SSKR_ERROR_SECRET_TOO_LONG, + * SSKR_ERROR_SECRET_LENGTH_NOT_EVEN (via `sskr_check_secret_length`) + * if the extracted value length is invalid. + */ static int16_t sskr_deserialize_shard(const uint8_t *source, uint16_t source_len, sskr_shard_t *shard) { @@ -102,6 +150,25 @@ static int16_t sskr_deserialize_shard(const uint8_t *source, return shard->value_len; } +/** + * @brief Calculates the total number of shards generated for a given SSKR configuration. + * + * @details This function determines the total shard count based on the group threshold, + * group descriptors, and their respective member counts. It validates the + * group configuration and enforces constraints to ensure logical consistency. + * + * @param[in] group_threshold Minimum number of groups required for secret reconstruction. + * @param[in] groups Pointer to an array of `sskr_group_descriptor_t` structures. + * @param[in] groups_len Number of groups in the `groups` array. + * + * @return Total number of shards on success, or a negative error code: + * - SSKR_ERROR_INVALID_GROUP_LENGTH: if `groups_len` is less than 1. + * - SSKR_ERROR_INVALID_GROUP_THRESHOLD: if `group_threshold` exceeds `groups_len`. + * - SSKR_ERROR_INVALID_GROUP_COUNT: if any group has a count less than 1. + * - SSKR_ERROR_INVALID_MEMBER_THRESHOLD: if any group's threshold exceeds its count. + * - SSKR_ERROR_INVALID_SINGLETON_MEMBER: if any group with threshold 1 has a count greater + * than 1. + */ int16_t sskr_count_shards(uint8_t group_threshold, const sskr_group_descriptor_t *groups, uint8_t groups_len) { @@ -131,17 +198,39 @@ int16_t sskr_count_shards(uint8_t group_threshold, return shard_count; } -////////////////////////////////////////////////// -// generate shards -// -static int16_t sskr_generate_shards(uint8_t group_threshold, - const sskr_group_descriptor_t *groups, - uint8_t groups_len, - const uint8_t *master_secret, - uint16_t master_secret_len, - sskr_shard_t *shards, - uint16_t shards_size, - unsigned char *(*random_generator)(uint8_t *, size_t)) { +/** + * @brief Internal function to generate SSKR shards from a master secret. + * + * @details This function performs the core logic of generating a set of shards + * from a given master secret, using a specific group configuration and a + * random number generator. It's an internal function, not intended for direct + * use by external applications. + * + * @param[in] group_threshold Minimum number of groups required for secret reconstruction. + * @param[in] groups Pointer to an array of `sskr_group_descriptor_t` structures. + * @param[in] groups_len Number of groups in the `groups` array. + * @param[in] master_secret Pointer to the master secret to be split. + * @param[in] master_secret_len Length of the master secret in bytes. + * @param[out] shards Pointer to an array of `sskr_shard_t` structures to store + * the generated shards. + * @param[in] shards_size Size of the `shards` array in bytes. + * @param[in] random_generator Pointer to a function that generates random bytes. + * + * @return Number of shards generated on success, or a negative error code: + * - SSKR_ERROR_INVALID_SECRET_LENGTH: if master secret length is invalid. + * - SSKR_ERROR_INSUFFICIENT_SPACE: if `shards_size` is insufficient. + * - SSKR_ERROR_INVALID_GROUP_THRESHOLD: if `group_threshold` exceeds `groups_len`. + * - Other error codes from `sss_split_secret`. + */ +static int16_t sskr_generate_shards_internal(uint8_t group_threshold, + const sskr_group_descriptor_t *groups, + uint8_t groups_len, + const uint8_t *master_secret, + uint16_t master_secret_len, + sskr_shard_t *shards, + uint16_t shards_size, + unsigned char *(*random_generator)(uint8_t *, + size_t)) { int16_t err = sskr_check_secret_length(master_secret_len); if (err) { return err; @@ -216,18 +305,15 @@ static int16_t sskr_generate_shards(uint8_t group_threshold, return shards_count; } -////////////////////////////////////////////////// -// generate mnemonics -// -int16_t sskr_generate(uint8_t group_threshold, - const sskr_group_descriptor_t *groups, - uint8_t groups_len, - const uint8_t *master_secret, - uint16_t master_secret_len, - uint8_t *shard_len, - uint8_t *output, - uint16_t buffer_size, - unsigned char *(*random_generator)(uint8_t *, size_t)) { +int16_t sskr_generate_shards(uint8_t group_threshold, + const sskr_group_descriptor_t *groups, + uint8_t groups_len, + const uint8_t *master_secret, + uint16_t master_secret_len, + uint8_t *shard_len, + uint8_t *output, + uint16_t buffer_size, + unsigned char *(*random_generator)(uint8_t *, size_t)) { int16_t err = sskr_check_secret_length(master_secret_len); if (err) { return err; @@ -252,14 +338,14 @@ int16_t sskr_generate(uint8_t group_threshold, sskr_shard_t shards[SSS_MAX_SHARE_COUNT * SSKR_MAX_GROUP_COUNT]; // generate shards - total_shards = sskr_generate_shards(group_threshold, - groups, - groups_len, - master_secret, - master_secret_len, - shards, - (uint16_t) total_shards, - random_generator); + total_shards = sskr_generate_shards_internal(group_threshold, + groups, + groups_len, + master_secret, + master_secret_len, + shards, + (uint16_t) total_shards, + random_generator); if (total_shards < 0) { error = total_shards; @@ -296,19 +382,29 @@ typedef struct sskr_group_struct { uint8_t count; uint8_t member_index[SSS_MAX_SHARE_COUNT]; const uint8_t *value[SSS_MAX_SHARE_COUNT]; -} sskr_group; +} sskr_group_t; /** - * This version of combine shards potentially modifies the shard structures - * in place, so it is for internal use only, however it provides the implementation - * for both combine_shards and sskr_combine. + * @brief Internal function to combine shards for secret reconstruction. + * + * @details This function implements the core logic for combining SSKR shards to + * recover the original secret. It potentially modifies shard structures in + * place, making it unsuitable for direct public use. It's the underlying + * implementation for and `sskr_combine_shards`. + * + * @param[in,out] shards Pointer to an array of `sskr_shard_t` structures to be combined. + * @param[in] shards_count Number of shards in the `shards` array. + * @param[out] buffer Pointer to a buffer for working space and storing the reconstructed + * secret. + * @param[in] buffer_len Length of the `buffer` array in bytes. + * + * @return Length of the reconstructed secret on success, or a negative error code. + * Specific error codes are implementation-dependent, consult implementation details. */ -static int16_t sskr_combine_shards_internal( - sskr_shard_t *shards, // array of shard structures - uint8_t shards_count, // number of shards in array - uint8_t *buffer, // working space, and place to return secret - uint16_t buffer_len // total amount of working space -) { +static int16_t sskr_combine_shards_internal(sskr_shard_t *shards, + uint8_t shards_count, + uint8_t *buffer, + uint16_t buffer_len) { int16_t error = 0; uint16_t identifier = 0; uint8_t group_threshold = 0; @@ -319,7 +415,7 @@ static int16_t sskr_combine_shards_internal( } uint8_t next_group = 0; - sskr_group groups[SSKR_MAX_GROUP_COUNT]; + sskr_group_t groups[SSKR_MAX_GROUP_COUNT]; uint8_t secret_len = 0; for (uint8_t i = 0; i < shards_count; ++i) { @@ -359,7 +455,7 @@ static int16_t sskr_combine_shards_internal( } if (!group_found) { - sskr_group *g = &groups[next_group]; + sskr_group_t *g = &groups[next_group]; g->group_index = shard->group_index; g->member_threshold = shard->member_threshold; g->count = 1; @@ -387,7 +483,7 @@ static int16_t sskr_combine_shards_internal( uint8_t *group_share = group_shares; for (uint8_t i = 0; !error && i < (uint8_t) next_group; ++i) { - sskr_group *g = &groups[i]; + sskr_group_t *g = &groups[i]; gx[i] = g->group_index; if (g->count < g->member_threshold) { @@ -437,15 +533,11 @@ static int16_t sskr_combine_shards_internal( return secret_len; } -///////////////////////////////////////////////// -// sskr_combine - -int16_t sskr_combine(const uint8_t **input_shards, // array of pointers to 10-bit words - uint8_t shard_len, // number of bytes in each serialized shard - uint8_t shards_count, // total number of shards - uint8_t *buffer, // working space, and place to return secret - uint16_t buffer_len // total amount of working space -) { +int16_t sskr_combine_shards(const uint8_t **input_shards, + uint8_t shard_len, + uint8_t shards_count, + uint8_t *buffer, + uint16_t buffer_len) { int16_t result = 0; if (shards_count == 0) { diff --git a/src/sskr/sskr.h b/src/sskr/sskr.h index 0ca1ea66..a2be68d5 100644 --- a/src/sskr/sskr.h +++ b/src/sskr/sskr.h @@ -19,53 +19,61 @@ int16_t sskr_count_shards(uint8_t group_threshold, uint8_t groups_len); /** - * generate a set of shards that can be used to reconstruct a secret - * using the given group policy. + * @brief Generate a set of shards that can be used to reconstruct a secret + * using the given group policy. * - * returns: the number of shards generated if successful, - * or a negative number indicating an error code when unsuccessful + * @details This function splits a secret into multiple shards according to a defined group policy. + * To reconstruct the secret, a specific number of shards from different groups + * (`group_threshold`) must be combined. * - * inputs: group_threshold: the number of groups that need to be satisfied in order - * to reconstruct the secret - * groups: an array of group descriptors - * groups_length: the length of the groups array - * master_secret: pointer to the secret to split up - * master_secret_length: length of the master secret in bytes. - * must be >= 16, <= 32, and even. - * shard_len: pointer to an integer that will be filled with the number of - * bytes in each shard - * output: array of bytes to store the resulting shards. - * the ith shard will be represented by - * output[i*shard_len]..output[(i+1)*shard_len -1] - * buffer_size: maximum number of bytes to write to the output array + * @param[in] group_threshold Minimum number of groups required for secret reconstruction. + * @param[in] groups Pointer to an array of `sskr_group_descriptor_t` structures, + * defining the groups and their members. + * @param[in] groups_length Number of groups in the `groups` array. + * @param[in] master_secret Pointer to the secret to be split up (must be 16-32 bytes long + * and even). + * @param[in] master_secret_length Length of the `master_secret` array in bytes. + * @param[out] shard_len Pointer to a variable that will be filled with the length of + * each shard. + * @param[out] output Pointer to a buffer where the generated shards will be stored. + * @param[in] buffer_size Maximum size of the `output` buffer in bytes. + * @param[in] random_generator Pointer to a function that generates random data (same as in SSS + * functions). + * + * @return Number of shards generated on success, or a negative error code on failure. + * Specific error codes are implementation-specific, consult implementation details. */ -int16_t sskr_generate(uint8_t group_threshold, - const sskr_group_descriptor_t *groups, - uint8_t groups_length, - const uint8_t *master_secret, - uint16_t master_secret_length, - uint8_t *shard_len, - uint8_t *output, - uint16_t buffer_size, - unsigned char *(*random_generator)(uint8_t *, size_t)); +int16_t sskr_generate_shards(uint8_t group_threshold, + const sskr_group_descriptor_t *groups, + uint8_t groups_length, + const uint8_t *master_secret, + uint16_t master_secret_length, + uint8_t *shard_len, + uint8_t *output, + uint16_t buffer_size, + unsigned char *(*random_generator)(uint8_t *, size_t)); /** - * combine a set of serialized shards to reconstruct a secret + * @brief Combines shards to reconstruct a secret. + * + * @details This function takes a collection of shards generated using `sskr_generate_shards` + * and reconstructs the original secret, assuming the provided shards meet + * the group threshold requirements. It employs Shamir's Secret Sharing (SSS) + * for secret reconstruction. * - * returns: the length of the reconstructed secret if successful - * or a negative number indicating an error code when unsuccessful + * @param[in] input_shards Pointer to an array of pointers to serialized shards. + * @param[in] shard_len Length of each shard in bytes. + * @param[in] shards_count Number of shards in the `input_shards` array. + * @param[out] buffer Pointer to a buffer where the reconstructed secret will be stored. + * @param[in] buffer_length Maximum size of the `buffer` in bytes. * - * inputs: input_shards: an array of pointers to serialized shards - * shard_len: number of bytes in each serialized shard - * shards_count: total number of shards - * buffer: location to store the result - * buffer_length: maximum space available in buffer + * @return Length of the reconstructed secret on success, or a negative error code on failure. + * Specific error codes are implementation-specific, consult implementation details. */ -int16_t sskr_combine(const uint8_t **input_shards, // an array of pointers to serialized shards - uint8_t shard_len, // number of bytes in each serialized shard - uint8_t shards_count, // total number of shards - uint8_t *buffer, // working space, and place to return secret - uint16_t buffer_length // total amount of working space -); +int16_t sskr_combine_shards(const uint8_t **input_shards, + uint8_t shard_len, + uint8_t shards_count, + uint8_t *buffer, + uint16_t buffer_length); #endif /* SSKR_H */ diff --git a/src/sskr/sss/interpolate.c b/src/sskr/sss/interpolate.c index 99629e43..cd4eb7d7 100644 --- a/src/sskr/sss/interpolate.c +++ b/src/sskr/sss/interpolate.c @@ -135,8 +135,24 @@ cx_err_t cx_bn_gf2_n_mul(cx_bn_t bn_r, } #endif -/* - * Invert `bn_a` in GF(2^8) and write the result to `bn_r` +/** + * @brief Performs an invert operation over GF(2^8). + * + * @param[out] bn_r BN index for the result. + * + * @param[in] bn_a BN index of the first operand. + * + * @param[in] bn_n BN index of the modulus. + * The modulus must be an irreducible polynomial over GF(2) + * of degree n. + * + * @param[in] bn_h BN index of the second montgomery constant. + * + * @return Error code: + * - CX_OK on success + * - CX_NOT_LOCKED + * - CX_INVALID_PARAMETER + * - CX_MEMORY_FULL */ cx_err_t bn_gf2_8_inv(cx_bn_t bn_r, const cx_bn_t bn_a, const cx_bn_t bn_n, const cx_bn_t bn_h) { cx_err_t error = CX_OK; // By default, until some error occurs @@ -168,32 +184,38 @@ cx_err_t bn_gf2_8_inv(cx_bn_t bn_r, const cx_bn_t bn_a, const cx_bn_t bn_n, cons } /** - * safely interpolate the polynomial going through - * the points (x0 [y0_0 y0_1 y0_2 ... y0_31]) , (x1 [y1_0 ...]), ... + * @brief Performs polynomial interpolation on SSS shares. + * + * @details This function interpolates a polynomial that passes through the provided points + * represented by `xi` (x-coordinates) and `yij` (y-coordinate arrays) i.e. + * where: + * xi points to [x0 x1 ... xn-1 ] + * y contains an array of pointers to 32-bit arrays of y values + * y contains [y0 y1 y2 ... yn-1] + * and each of the yi arrays contain [yi_0 yi_i ... yi_31]. * - * where - * xi points to [x0 x1 ... xn-1 ] - * y contains an array of pointers to 32-bit arrays of y values - * y contains [y0 y1 y2 ... yn-1] - * and each of the yi arrays contain [yi_0 yi_i ... yi_31]. + * This interpolation is used in Shamir's Secret Sharing (SSS) to recover + * the secret from a set of shares. * - * returns: on success, CX_OK - * on failure, a negative error code + * @param[in] n Number of points to interpolate (length of `xi` and `yij`). + * @param[in] xi Pointer to an array containing the x-coordinates of the points (length `n`). + * @param[in] yl Length of each y-coordinate array in bytes. + * @param[in] yij Pointer to an array of `n` pointers, each pointing to a y-coordinate array of + * length `yl`. + * @param[in] x X-coordinate at which to perform the interpolation. + * @param[out] result Pointer to a buffer where the interpolated value will be stored (must be `yl` + * bytes long). * - * inputs: n: number of points to interpolate - * xi: x coordinates for points (array of length n) - * yl: length of y coordinate arrays - * yij: array of n pointers to arrays of length yl - * x: coordinate to interpolate at - * result: space for yl bytes of interpolate data + * @return - CX_OK on success + * - A negative error code on failure (specific error codes not defined here, + * consult implementation details for specific error handling) */ -cx_err_t interpolate(uint8_t n, // number of points to interpolate - const uint8_t *xi, // x coordinates for points (array of length n) - uint8_t yl, // length of y coordinate array - const uint8_t **yij, // n arrays of yl bytes representing y values - uint8_t x, // x coordinate to interpolate - uint8_t *result // space for yl bytes of results -) { +cx_err_t interpolate(uint8_t n, + const uint8_t* xi, + uint8_t yl, + const uint8_t** yij, + uint8_t x, + uint8_t* result) { const uint8_t N[2] = SSS_POLYNOMIAL; const uint8_t R2[1] = MONTGOMERY_CONSTANT_R2; diff --git a/src/sskr/sss/interpolate.h b/src/sskr/sss/interpolate.h index 09b2dbd9..2342298a 100644 --- a/src/sskr/sss/interpolate.h +++ b/src/sskr/sss/interpolate.h @@ -9,31 +9,37 @@ #define INTERPOLATE_H /** - * safely interpolate the polynomial going through - * the points (x0 [y0_0 y0_1 y0_2 ... y0_31]) , (x1 [y1_0 ...]), ... + * @brief Performs polynomial interpolation on SSS shares. * - * where - * xi points to [x0 x1 ... xn-1 ] - * y contains an array of pointers to 32-bit arrays of y values - * y contains [y0 y1 y2 ... yn-1] - * and each of the yi arrays contain [yi_0 yi_i ... yi_31]. + * @details This function interpolates a polynomial that passes through the provided points + * represented by `xi` (x-coordinates) and `yij` (y-coordinate arrays) i.e. + * where: + * xi points to [x0 x1 ... xn-1 ] + * y contains an array of pointers to 32-bit arrays of y values + * y contains [y0 y1 y2 ... yn-1] + * and each of the yi arrays contain [yi_0 yi_i ... yi_31]. * - * returns: on success, CX_OK - * on failure, a negative error code + * This interpolation is used in Shamir's Secret Sharing (SSS) to recover + * the secret from a set of shares. * - * inputs: n: number of points to interpolate - * xi: x coordinates for points (array of length n) - * yl: length of y coordinate arrays - * yij: array of n pointers to arrays of length yl - * x: coordinate to interpolate at - * result: space for yl bytes of interpolate data + * @param[in] n Number of points to interpolate (length of `xi` and `yij`). + * @param[in] xi Pointer to an array containing the x-coordinates of the points (length `n`). + * @param[in] yl Length of each y-coordinate array in bytes. + * @param[in] yij Pointer to an array of `n` pointers, each pointing to a y-coordinate array of + * length `yl`. + * @param[in] x X-coordinate at which to perform the interpolation. + * @param[out] result Pointer to a buffer where the interpolated value will be stored (must be `yl + * bytes long). + * + * @return - CX_OK on success + * - A negative error code on failure (specific error codes not defined here, + * consult implementation details for specific error handling) */ -cx_err_t interpolate(uint8_t n, // number of points to interpolate - const uint8_t* xi, // x coordinates for points (array of length n) - uint8_t yl, // length of y coordinate array - const uint8_t** yij, // n arrays of yl bytes representing y values - uint8_t x, // x coordinate to interpolate - uint8_t* result // space for yl bytes of results -); +cx_err_t interpolate(uint8_t n, + const uint8_t* xi, + uint8_t yl, + const uint8_t** yij, + uint8_t x, + uint8_t* result); #endif /* INTERPOLATE_H */ diff --git a/src/sskr/sss/sss.c b/src/sskr/sss/sss.c index 262ef2e9..b973896b 100644 --- a/src/sskr/sss/sss.c +++ b/src/sskr/sss/sss.c @@ -13,6 +13,28 @@ #define memzero(...) explicit_bzero(__VA_ARGS__) +/** + * @brief Validates the parameters for Shamir's Secret Sharing (SSS) functions. + * + * @details This function checks if the provided threshold, share count, and + * secret length are within the acceptable ranges for SSS operations. + * It enforces constraints to ensure the integrity and security of the + * secret sharing process. + * + * @param[in] threshold The minimum number of shares required to recover the secret. + * @param[in] share_count The total number of shares to be generated. + * @param[in] secret_length The length of the secret in bytes. + * + * @return 0 on success, or a negative error code on failure: + * - SSS_ERROR_TOO_MANY_SHARES: if share_count exceeds SSS_MAX_SHARE_COUNT + * - SSS_ERROR_INVALID_THRESHOLD: if threshold is invalid (< 1 or > + * share_count) + * - SSS_ERROR_SECRET_TOO_LONG: if secret_length exceeds + * SSS_MAX_SECRET_SIZE + * - SSS_ERROR_SECRET_TOO_SHORT: if secret_length is less than + * SSS_MIN_SECRET_SIZE + * - SSS_ERROR_SECRET_NOT_EVEN_LEN: if secret_length is not even + */ static int16_t sss_validate_parameters(uint8_t threshold, uint8_t share_count, uint8_t secret_length) { @@ -30,17 +52,21 @@ static int16_t sss_validate_parameters(uint8_t threshold, return 0; } -////////////////////////////////////////////////// -// hmac sha256 /** - * creates a digest used to help valididate secret reconstruction (see SLIP-39 docs) + * @brief Creates a digest used to help validate secret reconstruction (see SLIP-39 docs). + * + * @details This function takes random data, a shared secret, and calculates a 4-byte + * digest using HMAC. This digest can be used to verify the integrity of the + * reconstructed secret during Shamir's Secret Sharing (SSS) recovery process. + * + * @param[in] random_data Pointer to the array containing the random data. + * @param[in] rdlen Length of the `random_data` array in bytes. + * @param[in] shared_secret Pointer to the array containing the shared secret. + * @param[in] sslen Length of the `shared_secret` array in bytes. + * @param[out] result Pointer to a 4-byte array where the digest will be stored. * - * returns: a pointer to the resulting 4-byte digest - * inputs: random_data: array of data to create a digest for - * rdlen: length of random_data array - * shared_secret: bytes to use as the key for the hmac when generating digest - * sslen: length of the shared secret array - * result: a pointer to a block of 4 bytes to store the resulting digest + * @return Pointer to the `result` array containing the digest, + * or `NULL` on failure. */ uint8_t *sss_create_digest(const uint8_t *random_data, uint32_t rdlen, @@ -58,8 +84,6 @@ uint8_t *sss_create_digest(const uint8_t *random_data, return result; } -////////////////////////////////////////////////// -// shamir secret sharing int16_t sss_split_secret(uint8_t threshold, uint8_t share_count, const uint8_t *secret, @@ -119,8 +143,6 @@ int16_t sss_split_secret(uint8_t threshold, return share_count; } -// returns the number of bytes written to the secret array, or a negative value if there was an -// error int16_t sss_recover_secret(uint8_t threshold, const uint8_t *x, const uint8_t **shares, diff --git a/src/sskr/sss/sss.h b/src/sskr/sss/sss.h index 75b2e18a..34381368 100644 --- a/src/sskr/sss/sss.h +++ b/src/sskr/sss/sss.h @@ -14,20 +14,35 @@ #define SSS_SECRET_INDEX 255 #define SSS_DIGEST_INDEX 254 -////////////////////////////////////////////////// -// Shamir Secret Sharing (based on SLIP-39) - /** - * uses SLIP-39's strategy for shamir sharing to split a secret up into - * share_count shares such that threshold of them must be presented - * to recover the secret. + * @brief Splits a secret into shares using Shamir's Secret Sharing (SSS) with SLIP-39 strategy. + * + * @details This function splits a secret into a specified number of shares (`share_count`) + * using SSS with a given threshold (`threshold`). To recover the secret, at least + * `threshold` shares must be combined. This implementation follows the strategy + * outlined in SLIP-39 for generating SSS shares. * - * returns: the number of shares created, or a negative value if there was an error + * @param[in] threshold Minimum number of shares required to recover the secret + * (1 <= threshold <= share_count). + * @param[in] share_count Total number of shares to generate. + * @param[in] secret Pointer to the array containing the secret data. + * @param[in] secret_length Length of the `secret` array in bytes (must be between 16 and 32, + * inclusive, and even). + * @param[out] result Pointer to a buffer where the generated shares will be stored. + * The size of this buffer must be `share_count * secret_length` bytes. + * @param[in] random_generator A pointer to a function that generates random data. This function + * must take two arguments: a pointer to a buffer and the size of the + * buffer to fill with random bytes. The function should return 0 on + * with random bytes. The function should return 0 on success or a + * success or a negative value on failure. * - * inputs: threshold: number of shares required to recover secret. Must be 1 <= threshold <= - * share_count. share_count: number of shares to generate secret: array of bytes representing the - * secret secret_length: length of the secret array. must be >= 16, <= 32 and even. result: place to - * store the resulting shares. Must be able to hold share_count * secret_length bytes + * @return The number of shares created on success, or a negative value on + * error: + * - SSS_INVALID_ARGS: if threshold or share_count is invalid + * - SSS_MEM_ALLOC_FAIL: if memory allocation fails + * - SSS_RANDOM_FAILURE: if random data generation fails + * - Other negative values may be returned by the `random_generator` + * function. */ int16_t sss_split_secret(uint8_t threshold, uint8_t share_count, @@ -37,16 +52,24 @@ int16_t sss_split_secret(uint8_t threshold, unsigned char *(*random_generator)(uint8_t *, size_t)); /** - * recover a secret from shares + * @brief Recovers a secret from Shamir's Secret Sharing (SSS) shares. + * + * @details This function recovers a secret from a set of SSS shares provided as `x` values + * and pointers to `y` value arrays (`shares`). To successfully recover the secret, + * at least `threshold` shares must be provided. This implementation follows the + * Lagrange polynomial interpolation method for SSS recovery. * - * returns: the number of bytes written to the secret array, or a negative value if there was an - * error + * @param[in] threshold Minimum number of shares required to recover the secret + * (1 <= threshold <= share_count). + * @param[in] x Pointer to an array containing the x values (length: threshold). + * @param[in] shares Pointer to an array of length `threshold`, where each element is a + * pointer to a y value array. + * @param[in] share_length Length of each y value array in bytes. + * @param[out] secret Pointer to a buffer where the recovered secret will be stored. + * The size of this buffer must be at least `share_length` bytes. * - * inputs: threshold: number of shares required and provided to this function - * x: array of x values (length: threshold) - * shares: array (length: threshold) of pointers to y value arrays - * share_length: number of bytes in each y value array - * secret: array for writing results (must be at least share_length long) + * @return The number of bytes written to the `secret` array on success, + * or a negative value on error: */ int16_t sss_recover_secret(uint8_t threshold, const uint8_t *x, diff --git a/src/ux_common/onboarding_seed_sskr.c b/src/ux_common/onboarding_seed_sskr.c index 7a78ee54..a71a3ff4 100644 --- a/src/ux_common/onboarding_seed_sskr.c +++ b/src/ux_common/onboarding_seed_sskr.c @@ -49,11 +49,11 @@ unsigned int bolos_ux_sskr_hex_decode(unsigned char *mnemonic_hex, mnemonic_hex + (i * mnemonic_length / sskr_shares_count) + 4 + (sskr_share_len > 23); } - uint16_t output_len = sskr_combine(ptr_sskr_shares, - sskr_share_len, - (uint8_t) sskr_shares_count, - output, - SSKR_MAX_STRENGTH_BYTES); + uint16_t output_len = sskr_combine_shards(ptr_sskr_shares, + sskr_share_len, + (uint8_t) sskr_shares_count, + output, + SSKR_MAX_STRENGTH_BYTES); if (output_len < 1) { memzero(mnemonic_hex, sizeof(mnemonic_hex)); @@ -108,15 +108,15 @@ unsigned int bolos_ux_sskr_generate(uint8_t groups_threshold, PRINTF("SSKR generate input:\n %.*H\n", seed_len, seed); // convert seed to SSKR shares - int share_count = sskr_generate(groups_threshold, - groups, - groups_len, - seed, - seed_len, - share_len, - share_buffer, - share_buffer_len, - cx_rng); + int share_count = sskr_generate_shards(groups_threshold, + groups, + groups_len, + seed, + seed_len, + share_len, + share_buffer, + share_buffer_len, + cx_rng); if ((share_count < 0) || ((unsigned int) share_count != share_count_expected) || (*share_len != share_len_expected)) { diff --git a/tests/unit/tests/sskr.c b/tests/unit/tests/sskr.c index 04fc680b..ffa7dd38 100644 --- a/tests/unit/tests/sskr.c +++ b/tests/unit/tests/sskr.c @@ -92,7 +92,7 @@ static void test_sskr_generate(void **state) { uint8_t share_buffer[share_buffer_len]; uint8_t share_len; - int16_t share_count = sskr_generate(groups_threshold, + int16_t share_count = sskr_generate_shards(groups_threshold, groups, groups_len, seed, @@ -131,21 +131,21 @@ static void test_sskr_combine(void **state) { uint8_t share_count = 2; uint8_t output[sizeof(seed)]; - int16_t output_len = sskr_combine(shares, share_len, share_count, output, sizeof(output)); + int16_t output_len = sskr_combine_shards(shares, share_len, share_count, output, sizeof(output)); assert_int_equal(output_len, sizeof(seed)); assert_memory_equal(output, seed, output_len); shares[1] = share1_3; - output_len = sskr_combine(shares, share_len, share_count, output, sizeof(output)); + output_len = sskr_combine_shards(shares, share_len, share_count, output, sizeof(output)); assert_int_equal(output_len, sizeof(seed)); assert_memory_equal(output, seed, output_len); shares[0] = share1_2; - output_len = sskr_combine(shares, share_len, share_count, output, sizeof(output)); + output_len = sskr_combine_shards(shares, share_len, share_count, output, sizeof(output)); assert_int_equal(output_len, sizeof(seed)); assert_memory_equal(output, seed, output_len); @@ -171,27 +171,27 @@ static void test_sskr_combine(void **state) { shares[0] = share2_1; shares[1] = share2_2; - output_len = sskr_combine(shares, share_len, share_count, output, sizeof(output)); + output_len = sskr_combine_shards(shares, share_len, share_count, output, sizeof(output)); assert_int_equal(output_len, sizeof(seed)); assert_memory_equal(output, seed, output_len); shares[1] = share2_3; - output_len = sskr_combine(shares, share_len, share_count, output, sizeof(output)); + output_len = sskr_combine_shards(shares, share_len, share_count, output, sizeof(output)); assert_int_equal(output_len, sizeof(seed)); assert_memory_equal(output, seed, output_len); shares[0] = share2_2; - output_len = sskr_combine(shares, share_len, share_count, output, sizeof(output)); + output_len = sskr_combine_shards(shares, share_len, share_count, output, sizeof(output)); assert_int_equal(output_len, sizeof(seed)); assert_memory_equal(output, seed, output_len); share_count = 0; - output_len = sskr_combine(shares, share_len, share_count, output, sizeof(output)); + output_len = sskr_combine_shards(shares, share_len, share_count, output, sizeof(output)); assert_int_equal(output_len, SSKR_ERROR_EMPTY_SHARD_SET); }