Commit 83c59a64 authored by Michael Hamburg's avatar Michael Hamburg

decaf scalars work

parent 8e10a919
......@@ -22,6 +22,13 @@
#include <stdint.h>
/* Goldilocks' build flags default to hidden and stripping executables. */
#define API_VIS __attribute__((visibility("default")))
#define WARN_UNUSED __attribute__((warn_unused_result))
#define NONNULL1 __attribute__((nonnull(1)))
#define NONNULL2 __attribute__((nonnull(1,2)))
#define NONNULL3 __attribute__((nonnull(1,2,3)))
typedef uint64_t decaf_word_t, decaf_bool_t;
/* TODO: prefix all these operations and factor to support multiple curves. */
......@@ -34,6 +41,9 @@ typedef uint64_t decaf_word_t, decaf_bool_t;
/** Number of bytes in a serialized point. One less bit than you'd think. */
#define DECAF_SER_BYTES ((DECAF_FIELD_BITS+6)/8)
/** Number of bytes in a serialized scalar. Two less bits than you'd think. */
#define DECAF_SCALAR_BYTES ((DECAF_FIELD_BITS+5)/8)
/** Twisted Edwards (-1,d-1) extended homogeneous coordinates */
typedef struct decaf_point_s {
decaf_word_t x[DECAF_LIMBS],y[DECAF_LIMBS],z[DECAF_LIMBS],t[DECAF_LIMBS];
......@@ -50,25 +60,58 @@ static const decaf_bool_t DECAF_SUCCESS = -(decaf_bool_t)1 /*DECAF_TRUE*/,
DECAF_FAILURE = 0 /*DECAF_FALSE*/;
/** The identity point on the curve. */
const decaf_point_t decaf_identity;
const decaf_point_t decaf_identity API_VIS;
/** The prime p, for debugging purposes.
* FIXME: prevent this scalar from actually being used for non-debugging purposes?
*/
const decaf_scalar_t decaf_scalar_p API_VIS;
/** A scalar equal to 1. */
const decaf_scalar_t decaf_scalar_one API_VIS;
/** A scalar equal to 0. */
const decaf_scalar_t decaf_scalar_zero API_VIS;
/** An arbitrarily chosen base point on the curve. TODO: define */
const decaf_point_t decaf_basepoint;
const decaf_point_t decaf_basepoint API_VIS;
#ifdef __cplusplus
extern "C" {
#endif
/* Goldilocks' build flags default to hidden and stripping executables. */
#define API_VIS __attribute__((visibility("default")))
#define WARN_UNUSED __attribute__((warn_unused_result))
#define NONNULL1 __attribute__((nonnull(1)))
#define NONNULL2 __attribute__((nonnull(1,2)))
#define NONNULL3 __attribute__((nonnull(1,2,3)))
// TODO: ser, deser, inv?.
// FIXME: scalar math is untested, and therefore probably wrong.
/**
* @brief Read a scalar from wire format or from bytes.
*
* Return DECAF_SUCCESS if the scalar was in reduced form. This
* function is not WARN_UNUSED because eg challenges in signatures
* may need to be longer.
*
* TODO: create a decode long function.
*
* @param [in] ser Serialized form of a scalar.
* @param [out] out Deserialized form.
*/
decaf_bool_t decaf_decode_scalar(
decaf_scalar_t s,
const unsigned char ser[DECAF_SER_BYTES]
) API_VIS NONNULL2;
/**
* @brief Serialize a scalar to wire format.
*
* @param [out] ser Serialized form of a scalar.
* @param [in] s Deserialized scalar.
*/
void decaf_encode_scalar(
unsigned char ser[DECAF_SER_BYTES],
const decaf_scalar_t s
) API_VIS NONNULL2;
/**
* @brief Add two scalars. The scalars may use the same memory.
* @param [in] a One scalar.
......@@ -81,6 +124,18 @@ void decaf_add_scalars (
const decaf_scalar_t b
) API_VIS NONNULL3;
/**
* @brief Compare two scalars.
* @param [in] a One scalar.
* @param [in] b Another scalar.
* @retval DECAF_TRUE The scalars are equal.
* @retval DECAF_FALSE The scalars are not equal.
*/
decaf_bool_t decaf_eq_scalars (
const decaf_scalar_t a,
const decaf_scalar_t b
) API_VIS WARN_UNUSED NONNULL2;
/**
* @brief Subtract two scalars. The scalars may use the same memory.
* @param [in] a One scalar.
......
......@@ -215,7 +215,7 @@ sv decaf_subx(
}
}
static const decaf_scalar_t DECAF_SCALAR_P = {{{
const decaf_scalar_t decaf_scalar_p = {{{
0x2378c292ab5844f3ull,
0x216cc2728dc58f55ull,
0xc44edb49aed63690ull,
......@@ -224,7 +224,9 @@ static const decaf_scalar_t DECAF_SCALAR_P = {{{
0xffffffffffffffffull,
0x3fffffffffffffffull
// TODO 32-bit clean
}}}, DECAF_SCALAR_R2 = {{{
}}}, decaf_scalar_one = {{{1}}}, decaf_scalar_zero = {{{0}}};
static const decaf_scalar_t decaf_scalar_r2 = {{{
0xe3539257049b9b60ull,
0x7af32c4bc1b195d9ull,
0x0d66de2388ea1859ull,
......@@ -235,7 +237,7 @@ static const decaf_scalar_t DECAF_SCALAR_P = {{{
// TODO 32-bit clean
}}};
static const decaf_word_t DECAF_MONTGOMERY_FACTOR = 0xfc42bbf0516e743b;
static const decaf_word_t DECAF_MONTGOMERY_FACTOR = 0x3bd440fae918bc5ull;
sv decaf_montmul (
decaf_scalar_t out,
......@@ -254,7 +256,7 @@ sv decaf_montmul (
decaf_dword_t chain = 0;
for (j=0; j<DECAF_SCALAR_LIMBS; j++) {
chain += (decaf_dword_t)mand*mier[j] + accum[j];
chain += ((decaf_dword_t)mand)*mier[j] + accum[j];
accum[j] = chain;
chain >>= WBITS;
}
......@@ -282,8 +284,8 @@ void decaf_mul_scalars (
const decaf_scalar_t a,
const decaf_scalar_t b
) {
decaf_montmul(out,a,b,DECAF_SCALAR_P,DECAF_MONTGOMERY_FACTOR);
decaf_montmul(out,out,DECAF_SCALAR_R2,DECAF_SCALAR_P,DECAF_MONTGOMERY_FACTOR);
decaf_montmul(out,a,b,decaf_scalar_p,DECAF_MONTGOMERY_FACTOR);
decaf_montmul(out,out,decaf_scalar_r2,decaf_scalar_p,DECAF_MONTGOMERY_FACTOR);
}
void decaf_sub_scalars (
......@@ -291,7 +293,7 @@ void decaf_sub_scalars (
const decaf_scalar_t a,
const decaf_scalar_t b
) {
decaf_subx(out, a->limb, b, DECAF_SCALAR_P, 0);
decaf_subx(out, a->limb, b, decaf_scalar_p, 0);
}
void decaf_add_scalars (
......@@ -306,7 +308,19 @@ void decaf_add_scalars (
out->limb[i] = chain;
chain >>= WBITS;
}
decaf_subx(out, out->limb, b, DECAF_SCALAR_P, chain);
decaf_subx(out, out->limb, decaf_scalar_p, decaf_scalar_p, chain);
}
decaf_bool_t decaf_eq_scalars (
const decaf_scalar_t a,
const decaf_scalar_t b
) {
decaf_word_t diff = 0;
unsigned int i;
for (i=0; i<DECAF_SCALAR_LIMBS; i++) {
diff |= a->limb[i] ^ b->limb[i];
}
return (((decaf_dword_t)diff)-1)>>WBITS;
}
/* *** API begins here *** */
......@@ -451,6 +465,41 @@ void decaf_copy (
gf_cpy(a->t, b->t);
}
decaf_bool_t decaf_decode_scalar(
decaf_scalar_t s,
const unsigned char ser[DECAF_SER_BYTES]
) {
unsigned int i,j,k=0;
for (i=0; i<DECAF_SCALAR_LIMBS; i++) {
decaf_word_t out = 0;
for (j=0; j<sizeof(decaf_word_t); j++,k++) {
out |= ((decaf_word_t)ser[k])<<(8*j);
}
s->limb[i] = out;
}
decaf_sdword_t accum = 0;
for (i=0; i<DECAF_SCALAR_LIMBS; i++) {
accum = (accum + s->limb[i] - decaf_scalar_p->limb[i]) >> WBITS;
}
//decaf_mul_scalars(s,s,decaf_scalar_one); /* ham-handed reduce */
return accum;
}
void decaf_encode_scalar(
unsigned char ser[DECAF_SER_BYTES],
const decaf_scalar_t s
) {
unsigned int i,j,k=0;
for (i=0; i<DECAF_SCALAR_LIMBS; i++) {
for (j=0; j<sizeof(decaf_word_t); j++,k++) {
ser[k] = s->limb[i] >> (8*j);
}
}
}
void decaf_scalarmul (
decaf_point_t a,
const decaf_point_t b,
......
......@@ -266,6 +266,16 @@ int main(int argc, char **argv) {
when = now() - when;
printf("barrett mac: %5.1fns\n", when * 1e9 / i);
decaf_scalar_t asc,bsc,csc;
memset(asc,0,sizeof(asc));
memset(bsc,0,sizeof(bsc));
when = now();
for (i=0; i<nbase*10; i++) {
decaf_mul_scalars(csc,asc,bsc);
}
when = now() - when;
printf("decaf mulsc: %5.1fns\n", when * 1e9 / i);
memset(&ext,0,sizeof(ext));
memset(&niels,0,sizeof(niels)); /* avoid assertions in p521 even though this isn't a valid ext or niels */
......
#include "field.h"
#include "test.h"
#include "decaf.h"
#include <gmp.h>
#include <string.h>
#include <stdio.h>
mpz_t mp_field;
mpz_t mp_scalar_field;
void decaf_scalar_print (
const char *descr,
const decaf_scalar_t scalar
) {
int j;
printf("%s = 0x", descr);
for (j=DECAF_SCALAR_LIMBS-1; j>=0; j--) {
printf(PRIxWORDfull, scalar->limb[j]);
}
printf("\n");
}
static mask_t mpz_to_field (
field_a_t out,
......@@ -20,6 +34,78 @@ static mask_t mpz_to_field (
return succ;
}
static mask_t mpz_to_scalar (
decaf_scalar_t out,
const mpz_t in
) {
uint8_t ser[DECAF_SCALAR_BYTES];
mpz_t modded;
memset(ser,0,sizeof(ser));
mpz_init(modded);
mpz_mod(modded, in, mp_scalar_field);
mpz_export(ser, NULL, -1, 1, -1, 0, modded);
mask_t succ = decaf_decode_scalar(out, ser);
return succ;
}
static mask_t scalar_assert_eq_gmp(
const char *descr,
const decaf_scalar_t a,
const decaf_scalar_t b,
const decaf_scalar_t x,
const mpz_t ma,
const mpz_t mb,
const mpz_t y
) {
uint8_t xser[FIELD_BYTES], yser[FIELD_BYTES];
mpz_t modded;
memset(yser,0,sizeof(yser));
decaf_encode_scalar(xser, x);
mpz_init(modded);
mpz_mod(modded, y, mp_scalar_field);
mpz_export(yser, NULL, -1, 1, -1, 0, modded);
if (memcmp(xser,yser,FIELD_BYTES)) {
youfail();
printf(" Failed arithmetic test %s\n", descr);
decaf_scalar_print(" a", a);
decaf_scalar_print(" b", b);
decaf_scalar_print(" decaf", x);
// printf(" gmpa = 0x");
int j;
// mpz_export(yser, NULL, -1, 1, -1, 0, ma);
// for (j=FIELD_BYTES-1; j>=0; j--) {
// printf("%02x", yser[j]);
// }
// printf("\n");
// printf(" gmpb = 0x");
//
//
// mpz_export(yser, NULL, -1, 1, -1, 0, mb);
// for (j=FIELD_BYTES-1; j>=0; j--) {
// printf("%02x", yser[j]);
// }
// printf("\n");
(void)ma; (void)mb;
printf(" gmpy = 0x");
mpz_export(yser, NULL, -1, 1, -1, 0, modded);
for (j=FIELD_BYTES-1; j>=0; j--) {
printf("%02x", yser[j]);
}
printf("\n");
return MASK_FAILURE;
}
mpz_clear(modded);
return MASK_SUCCESS;
}
static inline int BRANCH_ON_CONSTANT(int x) {
__asm__ ("" : "+r"(x));
return x;
......@@ -127,6 +213,34 @@ static mask_t test_add_sub_RAW (
return succ;
}
static mask_t test_scalar (
const mpz_t x,
const mpz_t y
) {
decaf_scalar_t xx,yy,tt;
mpz_t t;
mask_t succ = MASK_SUCCESS;
succ = mpz_to_scalar(xx,x);
succ &= mpz_to_scalar(yy,y);
mpz_init(t);
decaf_add_scalars(tt,xx,yy);
mpz_add(t,x,y);
succ &= scalar_assert_eq_gmp("scalar add",xx,yy,tt,x,y,t);
decaf_sub_scalars(tt,xx,yy);
mpz_sub(t,x,y);
succ &= scalar_assert_eq_gmp("scalar sub",xx,yy,tt,x,y,t);
decaf_mul_scalars(tt,xx,yy);
mpz_mul(t,x,y);
succ &= scalar_assert_eq_gmp("scalar mul",xx,yy,tt,x,y,t);
mpz_clear(t);
return succ;
}
static mask_t test_mul_sqr (
const mpz_t x,
const mpz_t y,
......@@ -208,6 +322,8 @@ int test_arithmetic (void) {
mpz_init(mp_field);
mpz_import(mp_field, FIELD_BYTES, -1, 1, -1, 0, FIELD_MODULUS);
mpz_import(mp_scalar_field, DECAF_SCALAR_LIMBS, -1, sizeof(decaf_word_t), -1, 0, decaf_scalar_p);
mpz_t x,y;
mpz_init(x);
mpz_init(y);
......@@ -234,6 +350,7 @@ int test_arithmetic (void) {
succ &= test_add_sub_RAW(x,y,word);
succ &= test_mul_sqr(x,y,word);
succ &= test_scalar(x,y);
if (j < 1000)
succ &= test_isr(x);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment