Skip to content

Commit

Permalink
Implement division by 3 in Fp.
Browse files Browse the repository at this point in the history
  • Loading branch information
dfaranha committed Nov 27, 2024
1 parent 000b019 commit a37d5d8
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 31 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.10)
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.1")
cmake_policy(SET CMP0054 NEW)
endif()
Expand Down
6 changes: 6 additions & 0 deletions bench/bench_fp.c
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,12 @@ static void arith(void) {
BENCH_END;
#endif

BENCH_RUN("fp_trs") {
fp_rand(a);
BENCH_ADD(fp_trs(c, a));
}
BENCH_END;

BENCH_RUN("fp_lsh") {
fp_rand(a);
a[RLC_FP_DIGS - 1] = 0;
Expand Down
2 changes: 2 additions & 0 deletions include/relic_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ typedef struct _ctx_t {
int fp_id;
/** Prime modulus. */
bn_st prime;
/** Prime modulus divided by 3. */
bn_st over3;
/** Parameter for generating prime. */
bn_st par;
/** Parameter in sparse form. */
Expand Down
4 changes: 2 additions & 2 deletions include/relic_dv.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@
#ifdef WITH_FB
#define RLC_DV_MAX (RLC_MAX(FP_PRIME, FB_POLYN))
#else /* !WITH_FB */
#define RLC_DV_MAX (FP_PRIME)
#define RLC_DV_MAX ((size_t)(2 * FP_PRIME))
#endif

#else /* !WITH_FP */

#ifdef WITH_FB
#define RLC_DV_MAX (FB_POLYN)
#define RLC_DV_MAX ((size_t)(2 * FP_PRIME))
#else /* !WITH_FB */
#define RLC_DV_MAX (0)
#endif
Expand Down
8 changes: 8 additions & 0 deletions include/relic_fp.h
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,14 @@ void fp_hlv_basic(fp_t c, const fp_t a);
*/
void fp_hlv_integ(fp_t c, const fp_t a);

/**
* Divides a prime field element by 3 (trisecting). Computes C = A/3.
*
* @param[out] C - the result.
* @param[in] A - the first prime field element.
*/
void fp_trs(fp_t c, const fp_t a);

/**
* Multiples two prime field elements using Schoolbook multiplication.
*
Expand Down
5 changes: 5 additions & 0 deletions include/relic_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@
*/
#define RLC_DMASK (RLC_HMASK | RLC_LMASK)

/**
* Bit mask used to divide by 3.
*/
#define RLC_3MASK ((RLC_DMASK - 1)/3 + 1)

/**
* Returns the lowest half of a digit.
*
Expand Down
26 changes: 0 additions & 26 deletions src/fp/relic_fp_add.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,29 +178,3 @@ void fp_dbl_integ(fp_t c, const fp_t a) {
}

#endif

#if FP_ADD == BASIC || !defined(STRIP)

void fp_hlv_basic(fp_t c, const fp_t a) {
dig_t carry = 0;

if (a[0] & 1) {
carry = fp_addn_low(c, a, fp_prime_get());
} else {
fp_copy(c, a);
}
fp_rsh1_low(c, c);
if (carry) {
c[RLC_FP_DIGS - 1] ^= ((dig_t)1 << (RLC_DIG - 1));
}
}

#endif

#if FP_ADD == INTEG || !defined(STRIP)

void fp_hlv_integ(fp_t c, const fp_t a) {
fp_hlvm_low(c, a);
}

#endif
102 changes: 102 additions & 0 deletions src/fp/relic_fp_div.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* RELIC is an Efficient LIbrary for Cryptography
* Copyright (c) 2024 RELIC Authors
*
* This file is part of RELIC. RELIC is legal property of its developers,
* whose names are not listed here. Please refer to the COPYRIGHT file
* for contact information.
*
* RELIC is free software; you can redistribute it and/or modify it under the
* terms of the version 2.1 (or later) of the GNU Lesser General Public License
* as published by the Free Software Foundation; or version 2.0 of the Apache
* License as published by the Apache Software Foundation. See the LICENSE files
* for more details.
*
* RELIC is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the LICENSE files for more details.
*
* You should have received a copy of the GNU Lesser General Public or the
* Apache License along with RELIC. If not, see <https://www.gnu.org/licenses/>
* or <https://www.apache.org/licenses/>.
*/

/**
* @file
*
* Implementation of the prime functions to divide by small constants.
*
* @ingroup fp
*/

#include "relic_core.h"
#include "relic_fp_low.h"

/*============================================================================*/
/* Public definitions */
/*============================================================================*/

#if FP_ADD == BASIC || !defined(STRIP)

void fp_hlv_basic(fp_t c, const fp_t a) {
dig_t carry = 0;

if (a[0] & 1) {
carry = fp_addn_low(c, a, fp_prime_get());
} else {
fp_copy(c, a);
}
fp_rsh1_low(c, c);
if (carry) {
c[RLC_FP_DIGS - 1] ^= ((dig_t)1 << (RLC_DIG - 1));
}
}

#endif

#if FP_ADD == INTEG || !defined(STRIP)

void fp_hlv_integ(fp_t c, const fp_t a) {
fp_hlvm_low(c, a);
}

#endif

void fp_trs(fp_t c, const fp_t a) {
const dig_t mask = (2 * RLC_3MASK + 1);
dig_t c0, c1, f0, f1;
dv_t t;

dv_null(t);

RLC_TRY {
dv_new(t);

RLC_MUL_DIG(t[RLC_FP_DIGS - 1], f0, a[RLC_FP_DIGS - 1], mask);
t[RLC_FP_DIGS - 1] >>= 1;
c1 = a[RLC_FP_DIGS - 1] - 3 * t[RLC_FP_DIGS - 1];

for (size_t i = RLC_FP_DIGS - 1; i > 0; i--) {
c0 = c1;
RLC_MUL_DIG(t[i - 1], f0, a[i - 1], mask);
t[i - 1] >>= 1;
c1 = c0 + a[i - 1] - 3 * t[i - 1];
t[i - 1] += c0 * RLC_3MASK;
f0 = ((c1 >> 1) & c1); /* c1 == 3 */
f1 = ((c1 >> 2) & !(c1 & 0x11)); /* c1 == 4 */
f0 |= f1;
t[i - 1] += f0;
c1 = c1 - 3 * f0;
}

fp_copy(c, t);
fp_sub(t, c, core_get()->over3.dp);
fp_copy_sec(c, t, (c1 & 1) | (c1 >> 1)); // c1 >= 1
fp_sub(t, c, core_get()->over3.dp);
fp_copy_sec(c, t, c1 == 2);
} RLC_CATCH_ANY {
RLC_THROW(ERR_CAUGHT);
} RLC_FINALLY {
dv_free(t);
}
}
4 changes: 4 additions & 0 deletions src/fp/relic_fp_prime.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ static void fp_prime_set(const bn_t p) {
fp_new(r);

bn_copy(&(ctx->prime), p);
bn_sub_dig(&(ctx->over3), p, 1);
bn_div_dig(&(ctx->over3), &(ctx->over3), 3);

#if FP_RDC == MONTY || !defined(STRIP)

Expand Down Expand Up @@ -237,6 +239,7 @@ void fp_prime_init(void) {
ctx_t *ctx = core_get();
ctx->fp_id = 0;
bn_make(&(ctx->prime), RLC_FP_DIGS);
bn_make(&(ctx->over3), RLC_FP_DIGS);
bn_make(&(ctx->par), RLC_FP_DIGS);
#if FP_RDC == QUICK || !defined(STRIP)
ctx->sps_len = 0;
Expand Down Expand Up @@ -271,6 +274,7 @@ void fp_prime_clean(void) {
bn_clean(&(ctx->srt));
bn_clean(&(ctx->crt));
bn_clean(&(ctx->prime));
bn_clean(&(ctx->over3));
bn_clean(&(ctx->par));
}
}
Expand Down
12 changes: 10 additions & 2 deletions test/test_fp.c
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ static int squaring(void) {
return code;
}

static int doubling_halving(void) {
static int doubling_halving_trisecting(void) {
int code = RLC_ERR;
fp_t a, b, c;

Expand Down Expand Up @@ -632,6 +632,14 @@ static int doubling_halving(void) {
TEST_ASSERT(fp_cmp(b, c) == RLC_EQ, end);
} TEST_END;
#endif

TEST_CASE("trisecting is consistent") {
fp_rand(a);
fp_dbl(b, a);
fp_add(b, b, a);
fp_trs(c, b);
TEST_ASSERT(fp_cmp(a, c) == RLC_EQ, end);
} TEST_END;
}
RLC_CATCH_ANY {
util_print("FATAL ERROR!\n");
Expand Down Expand Up @@ -1318,7 +1326,7 @@ int main(void) {
return 1;
}

if (doubling_halving() != RLC_OK) {
if (doubling_halving_trisecting() != RLC_OK) {
core_clean();
return 1;
}
Expand Down

0 comments on commit a37d5d8

Please sign in to comment.