/** * @file curve25519/elligator.c * @author Mike Hamburg * * @copyright * Copyright (c) 2015-2016 Cryptography Research, Inc. \n * Released under the MIT License. See LICENSE.txt for license information. * * @brief Elligator high-level functions. * * @warning This file was automatically generated in Python. * Please do not edit it. */ #include "word.h" #include "field.h" #include /* Template stuff */ #define API_NS(_id) decaf_255_##_id #define point_t API_NS(point_t) #define IMAGINE_TWIST 1 #define COFACTOR 8 static const int EDWARDS_D = -121665; /* End of template stuff */ extern void API_NS(deisogenize) ( gf_s *__restrict__ s, gf_s *__restrict__ minus_t_over_s, const point_t p, mask_t toggle_hibit_s, mask_t toggle_hibit_t_over_s, mask_t toggle_rotation ); void API_NS(point_from_hash_nonuniform) ( point_t p, const unsigned char ser[SER_BYTES] ) { gf r0,r,a,b,c,N,e; ignore_result(gf_deserialize(r0,ser,0)); gf_strong_reduce(r0); gf_sqr(a,r0); gf_mul_qnr(r,a); /* Compute D@c := (dr+a-d)(dr-ar-d) with a=1 */ gf_sub(a,r,ONE); gf_mulw(b,a,EDWARDS_D); /* dr-d */ gf_add(a,b,ONE); gf_sub(b,b,r); gf_mul(c,a,b); /* compute N := (r+1)(a-2d) */ gf_add(a,r,ONE); gf_mulw(N,a,1-2*EDWARDS_D); /* e = +-sqrt(1/ND) or +-r0 * sqrt(qnr/ND) */ gf_mul(a,c,N); mask_t square = gf_isr(b,a); gf_cond_sel(c,r0,ONE,square); /* r? = square ? 1 : r0 */ gf_mul(e,b,c); /* s@a = +-|N.e| */ gf_mul(a,N,e); gf_cond_neg(a,gf_hibit(a)^square); /* NB this is - what is listen in the paper */ /* t@b = -+ cN(r-1)((a-2d)e)^2 - 1 */ gf_mulw(c,e,1-2*EDWARDS_D); /* (a-2d)e */ gf_sqr(b,c); gf_sub(e,r,ONE); gf_mul(c,b,e); gf_mul(b,c,N); gf_cond_neg(b,square); gf_sub(b,b,ONE); /* isogenize */ #if IMAGINE_TWIST gf_mul(c,a,SQRT_MINUS_ONE); gf_copy(a,c); #endif gf_sqr(c,a); /* s^2 */ gf_add(a,a,a); /* 2s */ gf_add(e,c,ONE); gf_mul(p->t,a,e); /* 2s(1+s^2) */ gf_mul(p->x,a,b); /* 2st */ gf_sub(a,ONE,c); gf_mul(p->y,e,a); /* (1+s^2)(1-s^2) */ gf_mul(p->z,a,b); /* (1-s^2)t */ assert(API_NS(point_valid)(p)); } void API_NS(point_from_hash_uniform) ( point_t pt, const unsigned char hashed_data[2*SER_BYTES] ) { point_t pt2; API_NS(point_from_hash_nonuniform)(pt,hashed_data); API_NS(point_from_hash_nonuniform)(pt2,&hashed_data[SER_BYTES]); API_NS(point_add)(pt,pt,pt2); } /* Elligator_onto: * Make elligator-inverse onto at the cost of roughly halving the success probability. * Currently no effect for curves with field size 1 bit mod 8 (where the top bit * is chopped off). FUTURE MAGIC: automatic at least for brainpool-style curves; support * log p == 1 mod 8 brainpool curves maybe? */ #define MAX(A,B) (((A)>(B)) ? (A) : (B)) #define PKP_MASK ((1<<(MAX(8*SER_BYTES + 0 - 255,0)))-1) #if PKP_MASK != 0 static UNUSED mask_t plus_k_p ( uint8_t x[SER_BYTES], uint32_t factor_ ) { uint32_t carry = 0; uint64_t factor = factor_; const uint8_t p[SER_BYTES] = { 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }; for (unsigned int i=0; i>8; } return word_is_zero(carry); } #endif decaf_error_t API_NS(invert_elligator_nonuniform) ( unsigned char recovered_hash[SER_BYTES], const point_t p, uint32_t hint_ ) { mask_t hint = hint_; mask_t sgn_s = -(hint & 1), sgn_t_over_s = -(hint>>1 & 1), sgn_r0 = -(hint>>2 & 1), /* FUTURE MAGIC: eventually if there's a curve which needs sgn_ed_T but not sgn_r0, * change this mask extraction. */ sgn_ed_T = -(hint>>3 & 1); gf a, b, c, d; API_NS(deisogenize)(a,c,p,sgn_s,sgn_t_over_s,sgn_ed_T); #if 255 == 8*SER_BYTES + 1 /* p521. */ sgn_r0 = 0; #endif /* ok, a = s; c = -t/s */ gf_mul(b,c,a); gf_sub(b,ONE,b); /* t+1 */ gf_sqr(c,a); /* s^2 */ mask_t is_identity = gf_eq(p->t,ZERO); /* identity adjustments */ /* in case of identity, currently c=0, t=0, b=1, will encode to 1 */ /* if hint is 0, -> 0 */ /* if hint is to neg t/s, then go to infinity, effectively set s to 1 */ gf_cond_sel(c,c,ONE,is_identity & sgn_t_over_s); gf_cond_sel(b,b,ZERO,is_identity & ~sgn_t_over_s & ~sgn_s); gf_mulw(d,c,2*EDWARDS_D-1); /* $d = (2d-a)s^2 */ gf_add(a,b,d); /* num? */ gf_sub(d,d,b); /* den? */ gf_mul(b,a,d); /* n*d */ gf_cond_sel(a,d,a,sgn_s); gf_mul_qnr(d,b); mask_t succ = gf_isr(c,d)|gf_eq(d,ZERO); gf_mul(b,a,c); gf_cond_neg(b, sgn_r0^gf_hibit(b)); succ &= ~(gf_eq(b,ZERO) & sgn_r0); #if COFACTOR == 8 succ &= ~(is_identity & sgn_ed_T); /* NB: there are no preimages of rotated identity. */ #endif #if 255 == 8*SER_BYTES + 1 /* p521 */ gf_serialize(recovered_hash,b,0); #else gf_serialize(recovered_hash,b,1); #if PKP_MASK != 0 /* Add a multiple of p to make the result either almost-onto or completely onto. */ succ &= plus_k_p(recovered_hash, (hint >> ((COFACTOR==8)?4:3)) & PKP_MASK); #endif #endif return decaf_succeed_if(mask_to_bool(succ)); } decaf_error_t API_NS(invert_elligator_uniform) ( unsigned char partial_hash[2*SER_BYTES], const point_t p, uint32_t hint ) { point_t pt2; API_NS(point_from_hash_nonuniform)(pt2,&partial_hash[SER_BYTES]); API_NS(point_sub)(pt2,p,pt2); return API_NS(invert_elligator_nonuniform)(partial_hash,pt2,hint); }