|
- /** @brief Elligator high-level functions. */
-
- #include "word.h"
- #include "field.h"
- #include <decaf.h>
-
- /* Template stuff */
- #define API_NS(_id) $(c_ns)_##_id
- #define point_t API_NS(point_t)
- #define IMAGINE_TWIST $(imagine_twist)
- #define COFACTOR $(cofactor)
- static const int EDWARDS_D = $(d);
-
- #define RISTRETTO_FACTOR $(C_NS)_RISTRETTO_FACTOR
- extern const gf RISTRETTO_FACTOR;
-
- /* End of template stuff */
- extern mask_t API_NS(deisogenize) (
- gf_s *__restrict__ s,
- gf_s *__restrict__ inv_el_sum,
- gf_s *__restrict__ inv_el_m1,
- const point_t p,
- mask_t toggle_hibit_s,
- mask_t toggle_altx,
- 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;
- const uint8_t mask = (uint8_t)(0xFE<<($((gf_bits-1)%8)));
- ignore_result(gf_deserialize(r0,ser,mask));
- 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_lobit(a) ^ ~square);
-
- /* 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))
-
- 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 = ~((1 - (hint & 1))*DECAF_MASK_ALL_SET), /* expand hint bit 0 to the whole mask without branching */
- sgn_altx = ~((1 - (hint>>1 & 1))*DECAF_MASK_ALL_SET),
- sgn_r0 = ~((1 - (hint>>2 & 1))*DECAF_MASK_ALL_SET),
- /* FUTURE MAGIC: eventually if there's a curve which needs sgn_ed_T but not sgn_r0,
- * change this mask extraction.
- */
- sgn_ed_T = ~((1 - (hint>>3 & 1))*DECAF_MASK_ALL_SET);
- gf a,b,c;
- API_NS(deisogenize)(a,b,c,p,sgn_s,sgn_altx,sgn_ed_T);
-
- mask_t is_identity = gf_eq(p->t,ZERO);
- #if COFACTOR==4
- gf_cond_sel(b,b,ONE,is_identity & sgn_altx);
- gf_cond_sel(c,c,ONE,is_identity & sgn_s &~ sgn_altx);
- #elif IMAGINE_TWIST
- /* Terrible, terrible special casing due to lots of 0/0 is deisogenize
- * Basically we need to generate -D and +- i*RISTRETTO_FACTOR
- */
- gf_mul_i(a,RISTRETTO_FACTOR);
- gf_cond_sel(b,b,ONE,is_identity);
- gf_cond_neg(a,sgn_altx);
- gf_cond_sel(c,c,a,is_identity & sgn_ed_T);
- gf_cond_sel(c,c,ZERO,is_identity & ~sgn_ed_T);
- gf_mulw(a,ONE,-EDWARDS_D);
- gf_cond_sel(c,c,a,is_identity & ~sgn_ed_T &~ sgn_altx);
- #else
- #error "Different special-casing goes here!"
- #endif
-
- #if IMAGINE_TWIST
- gf_mulw(a,b,-EDWARDS_D);
- #else
- gf_mulw(a,b,EDWARDS_D-1);
- #endif
- gf_add(b,a,b);
- gf_sub(a,a,c);
- gf_add(b,b,c);
- gf_cond_swap(a,b,sgn_s);
- gf_mul_qnr(c,b);
- gf_mul(b,c,a);
- mask_t succ = gf_isr(c,b);
- succ |= gf_eq(b,ZERO);
- gf_mul(b,c,a);
-
- #if $(gf_bits) == 8*SER_BYTES + 1 /* p521. */
- #error "this won't work because it needs to adjust high bit, not low bit"
- sgn_r0 = 0;
- #endif
-
- gf_cond_neg(b, sgn_r0^gf_lobit(b));
- /* Eliminate duplicate values for identity ... */
- succ &= ~(gf_eq(b,ZERO) & (sgn_r0 | sgn_s));
- // #if COFACTOR == 8
- // succ &= ~(is_identity & sgn_ed_T); /* NB: there are no preimages of rotated identity. */
- // #endif
-
- gf_serialize(recovered_hash,b);
- #if $(gf_bits%8)
- #if COFACTOR==8
- recovered_hash[SER_BYTES-1] ^= (hint>>4)<<$(gf_bits%8);
- #else
- recovered_hash[SER_BYTES-1] ^= (hint>>3)<<$(gf_bits%8);
- #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);
- }
|