Commit 73d6fd54 authored by Jaromil's avatar Jaromil
Browse files

elliptic curve pairing, FP12 implementation and tests

implemented and improved basic operations for ECP2 and FP12 with test
coverage for miller loop (ate + fexp).
parent bfa60a9e
......@@ -23,19 +23,15 @@ lowmem-tests = \
${1} test/events.lua && \
${1} test/code.lua && \
${1} test/locals.lua && \
${1} test/schema.lua && \
${1} test/octet.lua && \
${1} test/hash.lua && \
${1} test/ecdh.lua && \
${1} test/ecdh_aes-gcm_vectors.lua && \
${1} test/ecp_bls383.lua
${1} test/schema.lua
crypto-tests = \
@${1} test/octet.lua && \
${1} test/hash.lua && \
${1} test/ecdh.lua && \
${1} test/ecdh_aes-gcm_vectors.lua && \
${1} test/ecp_bls383.lua
${1} test/ecp_bls383.lua && \
${1} test/pair_bls383.lua
shell-tests = \
test/octet-json.sh ${1} && \
......
......@@ -30,7 +30,7 @@ SOURCES := \
umm_malloc.o zen_memory.o \
zen_io.o zen_ast.o repl.o \
zen_octet.o zen_ecp.o zen_ecp2.o zen_big.o \
zen_fp.o zen_random.o zen_hash.o \
zen_fp12.o zen_random.o zen_hash.o \
zen_ecdh.o zen_ecdh_factory.o \
randombytes.o
......
......@@ -19,6 +19,7 @@ INSIDE = require('inspect')
I = INSIDE -- alias
ECP = require('ecp')
ECP2 = require('ecp2')
FP12 = require('fp12')
BIG = require('zenroom_big')
HASH = require('zenroom_hash')
H = HASH -- alias
......
......@@ -49,8 +49,8 @@ extern int luaopen_octet(lua_State *L);
extern int luaopen_ecdh(lua_State *L);
extern int luaopen_ecp(lua_State *L);
extern int luaopen_ecp2(lua_State *L);
extern int luaopen_fp12(lua_State *L);
extern int luaopen_big(lua_State *L);
extern int luaopen_fp(lua_State *L);
extern int luaopen_rng(lua_State *L);
extern int luaopen_hash(lua_State *L);
......@@ -161,8 +161,8 @@ int zen_require(lua_State *L) {
luaL_requiref(L, s, luaopen_ecp2, 1); }
else if(strcasecmp(s, "big") ==0) {
luaL_requiref(L, s, luaopen_big, 1); }
else if(strcasecmp(s, "fp") ==0) {
luaL_requiref(L, s, luaopen_fp, 1); }
else if(strcasecmp(s, "fp12") ==0) {
luaL_requiref(L, s, luaopen_fp12, 1); }
else if(strcasecmp(s, "rng") ==0) {
luaL_requiref(L, s, luaopen_rng, 1); }
else if(strcasecmp(s, "hash") ==0) {
......
This diff is collapsed.
......@@ -92,25 +92,32 @@
#define BIG_randomnum(m,q,r) BIG_384_29_randomnum(m,q,r)
#define FP FP_BLS383
#define FP_zero(b) FP_BLS383_zero(b)
#define FP_copy(d,s) FP_BLS383_copy(d,s)
#define FP_eq(l,r) FP_BLS383_equals(l,r)
#define FP_cmove(d,s,c) FP_BLS383_cmove(d,s,c)
#define FP_fromBig(f,b) FP_BLS383_nres(f,b)
#define FP_toBig(b,f) FP_BLS383_redc(b,f)
#define FP_mul(d, l, r) FP_BLS383_mul(d, l, r)
#define FP_imul(d, l, r) FP_BLS383_imul(d, l, r)
#define FP_sqr(d, s) FP_BLS383_sqr(d, s)
#define FP_add(d, l, r) FP_BLS383_add(d, l, r)
#define FP_sub(d, l, r) FP_BLS383_sub(d, l, r)
#define FP_div2(d, s) FP_BLS383_div2(d,s)
#define FP_pow(d, l, r) FP_BLS383_pow(d,l,r)
#define FP_sqrt(d,s) FP_BLS383_sqrt(d,s)
#define FP_neg(d,s) FP_BLS383_neg(d,s)
#define FP_reduce(f) FP_BLS383_reduce(f)
#define FP_norm(f) FP_BLS383_norm(f)
#define FP_qr(f) FP_BLS383_qr(f)
#define FP_inv(d,s) FP_BLS383_inv(d,s)
#define FP_redc(x,y) FP_BLS383_redc(x,y)
#define FP_reduce(x) FP_BLS383_reduce(x)
#define FP12 FP12_BLS383
/* #define FP12_zero(b) FP12_BLS383_zero(b) */
#define FP12_copy(d,s) FP12_BLS383_copy(d,s)
#define FP12_eq(l,r) FP12_BLS383_equals(l,r)
/* #define FP12_cmove(d,s,c) FP12_BLS383_cmove(d,s,c) */
#define FP12_fromOctet(f,o) FP12_BLS383_fromOctet(f,o)
#define FP12_toOctet(o,f) FP12_BLS383_toOctet(o,f)
#define FP12_mul(l, r) FP12_BLS383_mul(l, r)
/* #define FP12_imul(d, l, r) FP12_BLS383_imul(d, l, r) */
#define FP12_sqr(d, s) FP12_BLS383_sqr(d, s)
/* #define FP12_add(d, l, r) FP12_BLS383_add(d, l, r)
#define FP12_sub(d, l, r) FP12_BLS383_sub(d, l, r) */
#define FP12_div2(d, s) FP12_BLS383_div2(d,s)
#define FP12_pow(r, x, b) FP12_BLS383_pow(r,x,b)
// #define FP12_pinpow(r, x, b) FP12_BLS383_pinpow(r,x,b)
// #define FP12_sqrt(d,s) FP12_BLS383_sqrt(d,s)
// #define FP12_neg(d,s) FP12_BLS383_neg(d,s)
// #define FP12_reduce(f) FP12_BLS383_reduce(f)
// #define FP12_norm(f) FP12_BLS383_norm(f)
// #define FP12_qr(f) FP12_BLS383_qr(f)
#define FP12_inv(d,s) FP12_BLS383_inv(d,s)
#elif CHUNK == 16
#error "BIGnum CHUNK size: 16bit PLATFORM NOT SUPPORTED"
......
......@@ -51,21 +51,10 @@
#include <zen_error.h>
#include <zen_octet.h>
#include <zen_big.h>
#include <zen_fp12.h>
#include <zen_memory.h>
#include <lua_functions.h>
typedef struct {
char curve[16];
char type[16];
BIG order;
ECP val;
// TODO: the values above make it necessary to propagate the
// visibility on the specific curve point types to the rest of the
// code. To abstract these and have get/set functions may save a
// lot of boilerplate when implementing support for multiple
// curves ECP.
} ecp;
static char *big2strhex(char *str, BIG a) {
BIG b;
int i,len;
......@@ -131,7 +120,7 @@ static int lua_new_ecp(lua_State *L) {
if(lua_isnoneornil(L, 1)) { // no args: set to generator
ecp *e = ecp_new(L); SAFE(e);
if(!ECP_set(&e->val,
(chunk*)CURVE_Gx_BLS383, (chunk*)CURVE_Gy_BLS383)) {
(chunk*)CURVE_Gx, (chunk*)CURVE_Gy)) {
lerror(L,"ECP generator value out of curve (stack corruption)");
return 0; }
return 1; }
......@@ -159,6 +148,23 @@ static int lua_new_ecp(lua_State *L) {
return 0;
}
/***
Returns the generator of the curve: an ECP point to its X and Y coordinates.
@function generator()
@return ECP coordinates of the curve's generator.
*/
static int ecp_generator(lua_State *L) {
ecp *e = ecp_new(L); SAFE(e);
/* if(!ECP_set(&e->val,
(chunk*)CURVE_Gx, (chunk*)CURVE_Gy)) {
lerror(L,"ECP generator value out of curve (stack corruption)");
return 0; }
*/
ECP_generator(&e->val);
return 1;
}
/// Instance Methods
// @type ecp
......@@ -168,7 +174,7 @@ static int lua_new_ecp(lua_State *L) {
*/
static int ecp_affine(lua_State *L) {
ecp *in = ecp_arg(L,1); SAFE(in);
ecp *out = ecp_dup(L,in); SAFE(out);
ecp *out = ecp_dup(L,in); SAFE(out);
ECP_affine(&out->val);
return 1;
}
......@@ -215,7 +221,7 @@ static int ecp_mapit(lua_State *L) {
BIG_inc(x,1);
BIG_norm(x);
}
// #if PAIRING_FRIENDLY_BLS383 == BLS
// #if PAIRING_FRIENDLY == BLS
BIG c;
BIG_rcopy(c,CURVE_Cofactor);
ECP_mul(&e->val,c);
......@@ -295,14 +301,16 @@ static int ecp_mul(lua_State *L) {
int tn;
lua_Number n = lua_tonumberx(L, 2, &tn);
if(tn) {
func(L,"G1mul argument is a scalar number");
BIG bn;
BIG_zero(bn);
BIG_inc(bn,(int)n);
BIG_norm(bn);
ECP_mul(&out->val,bn);
PAIR_G1mul(&out->val,bn);
return 1; }
func(L,"G1mul argument is a BIG number");
big *b = big_arg(L,2); SAFE(b);
ECP_mul(&out->val,b->val);
PAIR_G1mul(&out->val,b->val);
return 1;
}
......@@ -395,7 +403,7 @@ static int ecp_get_y(lua_State *L) {
static int ecp_output(lua_State *L) {
ecp *e = ecp_arg(L, 1); SAFE(e);
ECP_BLS383 *P = &e->val;
ECP *P = &e->val;
if (ECP_isinf(P)) {
lua_pushstring(L,"Infinity");
return 1; }
......@@ -405,8 +413,8 @@ static int ecp_output(lua_State *L) {
ECP_affine(P);
BIG y;
char ys[256];
FP_BLS383_redc(x,&(P->x));
FP_BLS383_redc(y,&(P->y));
FP_redc(x,&(P->x));
FP_redc(y,&(P->y));
snprintf(out, 511,
"{ \"curve\": \"%s\",\n"
" \"encoding\": \"hex\",\n"
......@@ -419,17 +427,6 @@ static int ecp_output(lua_State *L) {
return 1;
}
/***
Returns the generator of the curve: an ECP point to its X and Y coordinates.
@function generator()
@return ECP coordinates of the curve's generator.
*/
static int ecp_generator(lua_State *L) {
ecp *e = ecp_new(L); SAFE(e);
ECP_set(&e->val, (chunk*)CURVE_Gx_BLS383, (chunk*)CURVE_Gy_BLS383);
return(1);
}
int luaopen_ecp(lua_State *L) {
const struct luaL_Reg ecp_class[] = {
......@@ -438,7 +435,6 @@ int luaopen_ecp(lua_State *L) {
{"infinity",ecp_get_infinity},
{"order",ecp_order},
{"generator",ecp_generator},
{"G",ecp_generator},
{NULL,NULL}};
const struct luaL_Reg ecp_methods[] = {
{"affine",ecp_affine},
......
......@@ -53,6 +53,7 @@
#include <zen_error.h>
#include <zen_octet.h>
#include <zen_big.h>
#include <zen_fp12.h>
#include <zen_memory.h>
#include <lua_functions.h>
......@@ -121,8 +122,8 @@ static int lua_new_ecp2(lua_State *L) {
if(lua_isnoneornil(L, 1)) { // no args: set to generator
ecp2 *e = ecp2_new(L); SAFE(e);
FP2 x, y;
FP2_from_BIGs(&x,(chunk*)CURVE_Pxa_BLS383,(chunk*)CURVE_Pxb_BLS383);
FP2_from_BIGs(&y,(chunk*)CURVE_Pya_BLS383,(chunk*)CURVE_Pyb_BLS383);
FP2_from_BIGs(&x,(chunk*)CURVE_G2xa,(chunk*)CURVE_G2xb);
FP2_from_BIGs(&y,(chunk*)CURVE_G2ya,(chunk*)CURVE_G2yb);
if(!ECP2_set(&e->val,&x,&y)) {
lerror(L,"ECP2 generator value out of curve (stack corruption)");
......@@ -133,7 +134,7 @@ static int lua_new_ecp2(lua_State *L) {
void *txi = luaL_testudata(L, 2, "zenroom.big");
void *ty = luaL_testudata(L, 3, "zenroom.big");
void *tyi = luaL_testudata(L, 4, "zenroom.big");
if(tx && txi && ty && tyi) {
ecp2 *e = ecp2_new(L); SAFE(e);
big *x, *xi, *y, *yi;
......@@ -162,6 +163,35 @@ static int lua_new_ecp2(lua_State *L) {
return 0;
}
/***
Returns the generator of the twisted curve: an ECP2 point to its X and Y coordinates.
@function generator()
@return ECP2 coordinates of the curve's generator.
*/
static int ecp2_generator(lua_State *L) {
ecp2 *e = ecp2_new(L); SAFE(e);
/* FP2 x, y;
FP2_from_BIGs(&x,(chunk*)CURVE_G2xa,(chunk*)CURVE_G2xb);
FP2_from_BIGs(&y,(chunk*)CURVE_G2ya,(chunk*)CURVE_G2yb);
if(!ECP2_set(&e->val,&x,&y)) {
lerror(L,"ECP2 generator value out of curve (stack corruption)");
return 0; }
*/
ECP2_generator(&e->val);
return 1;
}
static int ecp2_millerloop(lua_State *L) {
fp12 *f = fp12_new(L); SAFE(f);
ecp2 *x = ecp2_arg(L,1); SAFE(x);
ecp *y = ecp_arg(L,2); SAFE(y);
PAIR_ate(&f->val,&x->val,&y->val);
PAIR_fexp(&f->val);
return 1;
}
/// Class methods
// @type ecp2
......@@ -172,7 +202,7 @@ static int lua_new_ecp2(lua_State *L) {
*/
static int ecp2_affine(lua_State *L) {
ecp2 *in = ecp2_arg(L,1); SAFE(in);
ecp2 *out = ecp2_dup(L,in); SAFE(out);
ecp2 *out = ecp2_dup(L,in); SAFE(out);
ECP2_affine(&out->val);
return 1;
}
......@@ -256,9 +286,22 @@ static int ecp2_eq(lua_State *L) {
return 1;
}
static int ecp2_mul(lua_State *L) {
ecp2 *p = ecp2_arg(L,1); SAFE(p);
big *b = big_arg(L,2); SAFE(b);
ecp2 *r = ecp2_dup(L, p); SAFE(r);
PAIR_G2mul(&r->val,b->val);
return 1;
}
int luaopen_ecp2(lua_State *L) {
const struct luaL_Reg ecp2_class[] = {
{"new",lua_new_ecp2},
{"generator",ecp2_generator},
{"millerloop",ecp2_millerloop},
{"loop",ecp2_millerloop},
{"miller",ecp2_millerloop},
{"ate",ecp2_millerloop},
{NULL,NULL}};
const struct luaL_Reg ecp2_methods[] = {
{"affine",ecp2_affine},
......@@ -271,6 +314,8 @@ int luaopen_ecp2(lua_State *L) {
{"__sub",ecp2_sub},
{"eq",ecp2_eq},
{"__eq", ecp2_eq},
{"mul",ecp2_mul},
{"__mul",ecp2_mul},
{NULL,NULL}
};
zen_add_class(L, "ecp2", ecp2_class, ecp2_methods);
......
......@@ -24,11 +24,30 @@
#include <ecp_BLS383.h>
#include <ecp2_BLS383.h>
#include <pair_BLS383.h>
#define BIGSIZE 384
#include <zen_big_types.h>
#define ECP ECP_BLS383
#define ECP2 ECP2_BLS383
typedef struct {
char curve[16];
char type[16];
BIG order;
ECP val;
// TODO: the values above make it necessary to propagate the
// visibility on the specific curve point types to the rest of the
// code. To abstract these and have get/set functions may save a
// lot of boilerplate when implementing support for multiple
// curves ECP.
} ecp;
ecp* ecp_new(lua_State *L);
ecp* ecp_arg(lua_State *L,int n);
#define CURVE_A CURVE_A_BLS383
#define CURVE_B Curve_B_BLS383
#define CURVE_B_I CURVE_B_I_BLS383
......@@ -36,6 +55,10 @@
#define CURVE_Gy CURVE_Gy_BLS383
#define CURVE_Order CURVE_Order_BLS383
#define CURVE_Cofactor CURVE_Cof_BLS383
#define CURVE_G2xa CURVE_Pxa_BLS383
#define CURVE_G2xb CURVE_Pxb_BLS383
#define CURVE_G2ya CURVE_Pya_BLS383
#define CURVE_G2yb CURVE_Pyb_BLS383
#define ECP_copy(d,s) ECP_BLS383_copy(d,s)
#define ECP_set(d,x,y) ECP_BLS383_set(d, x, y)
......@@ -51,7 +74,7 @@
#define ECP_equals(l,r) ECP_BLS383_equals(l,r)
#define ECP_fromOctet(d,o) ECP_BLS383_fromOctet(d, o)
#define ECP_toOctet(o,d) ECP_BLS383_toOctet(o,d)
#define FP_redc(x,s) FP_BLS383_redc(x,s)
#define ECP_generator(e) ECP_BLS383_generator(e)
#define FP2 FP2_BLS383
#define FP2_from_BIGs(x,a,b) FP2_BLS383_from_BIGs(x,a,b)
......@@ -70,6 +93,11 @@
#define ECP2_equals(l,r) ECP2_BLS383_equals(l,r)
#define ECP2_fromOctet(d,o) ECP2_BLS383_fromOctet(d, o)
#define ECP2_toOctet(o,d) ECP2_BLS383_toOctet(o,d)
#define ECP2_generator(e) ECP2_BLS383_generator(e)
#define PAIR_ate(r,p,q) PAIR_BLS383_ate(r,p,q)
#define PAIR_fexp(x) PAIR_BLS383_fexp(x)
#define PAIR_G2mul(p,b) PAIR_BLS383_G2mul(p,b)
#define PAIR_G1mul(p,b) PAIR_BLS383_G1mul(p,b)
#endif
/* Zenroom (DECODE project)
*
* (c) Copyright 2017-2018 Dyne.org foundation
* designed, written and maintained by Denis Roio <jaromil@dyne.org>
*
* This source code is free software; you can redistribute it and/or
* modify it under the terms of the GNU Public License as published
* by the Free Software Foundation; either version 3 of the License,
* or (at your option) any later version.
*
* This source code 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.
* Please refer to the GNU Public License for more details.
*
* You should have received a copy of the GNU Public License along with
* this source code; if not, write to:
* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <jutils.h>
#include <zen_error.h>
#include <lua_functions.h>
#include <amcl.h>
#include <zenroom.h>
#include <zen_octet.h>
#include <zen_memory.h>
#include <zen_fp.h>
fp* fp_new(lua_State *L) {
fp *c = (fp *)lua_newuserdata(L, sizeof(fp));
if(!c) {
lerror(L, "Error allocating new fp in %s",__func__);
return NULL; }
luaL_getmetatable(L, "zenroom.fp");
lua_setmetatable(L, -2);
strcpy(c->name,"fp384");
c->len = sizeof(FP);
c->chunk = CHUNK;
func(L, "new fp (%u bytes)",c->len);
return(c);
}
fp* fp_arg(lua_State *L,int n) {
void *ud = luaL_checkudata(L, n, "zenroom.fp");
luaL_argcheck(L, ud != NULL, n, "fp class expected");
fp *o = (fp*)ud;
if(o->len != sizeof(FP)) {
lerror(L, "%s: fp size mismatch (%u != %u)",__func__,o->len, sizeof(FP));
return NULL; }
if(o->chunk != CHUNK) {
lerror(L, "%s: fp chunk size mismatch (%u != %u)",__func__,o->chunk, CHUNK);
return NULL; }
return(o);
}
// allocates a new fp in LUA, duplicating the one in arg
fp *fp_dup(lua_State *L, fp *s) {
SAFE(s);
fp *n = fp_new(L);
FP_copy(&n->val,&s->val);
return(n);
}
int fp_destroy(lua_State *L) {
HERE();
fp *c = fp_arg(L,1);
SAFE(c);
return 0;
}
static int newfp(lua_State *L) {
HERE();
int res = lua_isnoneornil(L, 1);
fp *c = fp_new(L); SAFE(L);
// argument if present must be an octet
if(res) {
FP_zero(&c->val);
} else {
void *ud = luaL_testudata(L, 1, "zenroom.big");
luaL_argcheck(L, ud != NULL, 1, "big argument expected");
big *b = (big*)ud;
FP_fromBig(&c->val,b->val);
}
return 1;
}
static int fp_from_big(lua_State *L) {
big *b = big_arg(L,1); SAFE(b);
fp *f = fp_new(L); SAFE(f);
BIG_norm(b->val);
FP_fromBig(&f->val,b->val);
return 1;
}
static int fp_to_big(lua_State *L) {
fp *f = fp_arg(L,1); SAFE(f);
big *b = big_new(L); SAFE(b);
FP_toBig(b->val, &f->val);
return 1;
}
// static int fp_from_octet(lua_State *L) {
// octet *o = o_arg(L,1); SAFE(o);
// fp *c = fp_new(L); SAFE(c);
// BIG_fromBytesLen(c->val, o->val, o->len);
// return 1;
// }
// static int fp_to_octet(lua_State *L) {
// fp *c = fp_arg(L,1); SAFE(c);
// BIG_norm(c->val);
// octet *o = o_new(L, c->len+2); SAFE(o);
// BIG_toBytes(o->val, c->val);
// o->len = modbytes;
// return 1;
// }
static int fp_eq(lua_State *L) {
fp *l = fp_arg(L,1); SAFE(l);
fp *r = fp_arg(L,2); SAFE(r);
int res = FP_eq(&l->val,&r->val);
lua_pushboolean(L, res);
return 1;
}
static int fp_add(lua_State *L) {
fp *l = fp_arg(L,1); SAFE(l);
fp *r = fp_arg(L,2); SAFE(r);
fp *d = fp_new(L); SAFE(d);
FP_add(&d->val, &l->val, &r->val);
return 1;
}
static int fp_sub(lua_State *L) {
fp *l = fp_arg(L,1); SAFE(l);
fp *r = fp_arg(L,2); SAFE(r);
fp *d = fp_new(L); SAFE(d);
FP_sub(&d->val, &l->val, &r->val);
return 1;
}
static int fp_mul(lua_State *L) {
fp *l = fp_arg(L,1); SAFE(l);
fp *r = fp_arg(L,2); SAFE(r);
fp *d = fp_new(L); SAFE(d);
FP_mul(&d->val,&l->val,&r->val);
return 1;
}
// static int fp_imul(lua_State *L) {
// fp *l = fp_arg(L,1); SAFE(l);
// fp *r = fp_arg(L,2); SAFE(r);
// fp *d = fp_new(L); SAFE(d);
// FP_imul(&d->val,&l->val,&r->val);
// return 1;
// }
static int fp_sqr(lua_State *L) {
fp *s = fp_arg(L,1); SAFE(s);
fp *d = fp_dup(L,s); SAFE(d);
FP_sqr(&d->val,&s->val);
return 1;
}
static int fp_sqrt(lua_State *L) {
fp *s = fp_arg(L,1); SAFE(s);
fp *d = fp_dup(L,s); SAFE(d);
FP_sqrt(&d->val,&s->val);
return 1;
}
static int fp_div2(lua_State *L) {
fp *s = fp_arg(L,1); SAFE(s);
fp *d = fp_dup(L,s); SAFE(d);
FP_div2(&d->val,&s->val);
return 1;
}
static int fp_pow(lua_State *L) {
fp *l = fp_arg(L,1); SAFE(l);
big *r = big_arg(L,2); SAFE(r);
fp *d = fp_new(L); SAFE(d);
FP_pow(&d->val,&l->val,r->val);
return 1;
}
static int fp_neg(lua_State *L) {
fp *s = fp_arg(L,1); SAFE(s);
fp *d = fp_dup(L,s); SAFE(d);
FP_neg(&d->val,&s->val);
return 1;
}
static int fp_inv(lua_State *L) {
fp *s = fp_arg(L,1); SAFE(s);
fp *d = fp_dup(L,s); SAFE(d);
FP_inv(&d->val,&s->val);
return 1;
}
static int fp_reduce(lua_State *L) {
fp *s = fp_arg(L,1); SAFE(s);
fp *d = fp_dup(L,s); SAFE(d);
FP_reduce(&d->val);
return 1;