diff --git a/include/ox_bn.h b/include/ox_bn.h index d300b769..131d690f 100644 --- a/include/ox_bn.h +++ b/include/ox_bn.h @@ -1075,4 +1075,30 @@ SYSCALL cx_err_t cx_bn_next_prime(cx_bn_t n); */ SYSCALL cx_err_t cx_bn_rng(cx_bn_t r, const cx_bn_t n); +/** + * @brief Performs a multiplication over GF(2^n). + * + * @param[out] bn_r BN index for the result. + * + * @param[in] bn_a BN index of the first operand. + * + * @param[in] bn_b BN index of the second 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 + */ +WARN_UNUSED_RESULT cx_err_t cx_bn_gf2_n_mul(cx_bn_t bn_r, + const cx_bn_t bn_a, + const cx_bn_t bn_b, + const cx_bn_t bn_n, + const cx_bn_t bn_h); #endif /* CX_BN_H */ diff --git a/src/cx_wrappers.c b/src/cx_wrappers.c index db26f262..de56ebe3 100644 --- a/src/cx_wrappers.c +++ b/src/cx_wrappers.c @@ -113,3 +113,72 @@ uint32_t cx_crc32(const void *buf, size_t len) { return cx_crc32_update(CX_CRC32_INIT, buf, len); } + +// At some point this could/should be migrated to the OS +// Meanwhile, it's implemented here +cx_err_t cx_bn_gf2_n_mul(cx_bn_t bn_r, + const cx_bn_t bn_a, + const cx_bn_t bn_b, + const cx_bn_t bn_n, + const cx_bn_t bn_h __attribute__((unused))) { + + cx_err_t error = CX_OK; + uint32_t degree, nbits_a, nbits_b; + + // Calculate the degree of the modulus polynomial + CX_CHECK(cx_bn_cnt_bits(bn_n, °ree)); + degree--; + + CX_CHECK(cx_bn_cnt_bits(bn_a, &nbits_a)); + CX_CHECK(cx_bn_cnt_bits(bn_b, &nbits_b)); + + // Ensure both operands are in field + if (degree < 1 || nbits_a > degree || nbits_b > degree) { + error = CX_INVALID_PARAMETER; + goto end; + } + + // Preliminaries + cx_bn_t bn_tempa, bn_tempb, bn_tempx; + uint32_t bit_indexb = 0; + size_t nbytes; + bool bit_set = 0; + + CX_CHECK(cx_bn_nbytes(bn_n, &nbytes)); + CX_CHECK(cx_bn_alloc(&bn_tempa, nbytes)); + CX_CHECK(cx_bn_alloc(&bn_tempb, nbytes)); + CX_CHECK(cx_bn_alloc(&bn_tempx, nbytes)); + + CX_CHECK(cx_bn_copy(bn_tempa, bn_a)); + CX_CHECK(cx_bn_copy(bn_tempb, bn_b)); + CX_CHECK(cx_bn_set_u32(bn_r, (uint32_t) 0)); + + // Main loop for multiplication + if (nbits_a) { + while (nbits_b > bit_indexb) { + CX_CHECK(cx_bn_tst_bit(bn_tempb, bit_indexb, &bit_set)); + if (bit_set) { + CX_CHECK(cx_bn_copy(bn_tempx, bn_r)); + CX_CHECK(cx_bn_xor(bn_r, bn_tempa, bn_tempx)); + } + + CX_CHECK(cx_bn_shl(bn_tempa, 1)); + CX_CHECK(cx_bn_tst_bit(bn_tempa, degree, &bit_set)); + + if (bit_set) { + CX_CHECK(cx_bn_copy(bn_tempx, bn_tempa)); + CX_CHECK(cx_bn_xor(bn_tempa, bn_n, bn_tempx)); + } + + bit_indexb++; + } + } + + // Clean up + CX_CHECK(cx_bn_destroy(&bn_tempa)); + CX_CHECK(cx_bn_destroy(&bn_tempb)); + CX_CHECK(cx_bn_destroy(&bn_tempx)); + +end: + return error; +}