You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

331 lines
11 KiB

  1. /**
  2. * @cond internal
  3. * @brief EdDSA routines.
  4. */
  5. #include "word.h"
  6. #include <decaf/ed$(gf_bits).h>
  7. #include <decaf/shake.h>
  8. #include <decaf/sha512.h>
  9. #include <string.h>
  10. #define API_NAME "$(c_ns)"
  11. #define API_NS(_id) $(c_ns)_##_id
  12. #define hash_ctx_t decaf_$(eddsa_hash)_ctx_t
  13. #define hash_init decaf_$(eddsa_hash)_init
  14. #define hash_update decaf_$(eddsa_hash)_update
  15. #define hash_final decaf_$(eddsa_hash)_final
  16. #define hash_destroy decaf_$(eddsa_hash)_destroy
  17. #define hash_hash decaf_$(eddsa_hash)_hash
  18. #define SUPPORTS_CONTEXTS DECAF_EDDSA_$(gf_shortname)_SUPPORTS_CONTEXTS
  19. #define EDDSA_USE_SIGMA_ISOGENY $(eddsa_sigma_iso)
  20. #define COFACTOR $(cofactor)
  21. /* EDDSA_BASE_POINT_RATIO = 1 or 2
  22. * Because EdDSA25519 is not on E_d but on the isogenous E_sigma_d,
  23. * its base point is twice ours.
  24. */
  25. #define EDDSA_BASE_POINT_RATIO (1+EDDSA_USE_SIGMA_ISOGENY)
  26. static void clamp (
  27. uint8_t secret_scalar_ser[DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES]
  28. ) {
  29. /* Blarg */
  30. secret_scalar_ser[0] &= -COFACTOR;
  31. uint8_t hibit = (1<<$(gf_bits % 8))>>1;
  32. if (hibit == 0) {
  33. secret_scalar_ser[DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES - 1] = 0;
  34. secret_scalar_ser[DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES - 2] |= 0x80;
  35. } else {
  36. secret_scalar_ser[DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES - 1] &= hibit-1;
  37. secret_scalar_ser[DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES - 1] |= hibit;
  38. }
  39. }
  40. static void hash_init_with_dom(
  41. hash_ctx_t hash,
  42. uint8_t prehashed,
  43. uint8_t for_prehash,
  44. const uint8_t *context,
  45. uint8_t context_len
  46. ) {
  47. hash_init(hash);
  48. #if SUPPORTS_CONTEXTS
  49. const char *dom_s = "$(eddsa_dom)";
  50. const uint8_t dom[2] = {2+word_is_zero(prehashed)+word_is_zero(for_prehash), context_len};
  51. hash_update(hash,(const unsigned char *)dom_s, strlen(dom_s));
  52. hash_update(hash,dom,2);
  53. hash_update(hash,context,context_len);
  54. #else
  55. (void)prehashed;
  56. (void)for_prehash;
  57. (void)context;
  58. assert(context==NULL);
  59. (void)context_len;
  60. assert(context_len == 0);
  61. #endif
  62. }
  63. void decaf_ed$(gf_shortname)_prehash_init (
  64. hash_ctx_t hash
  65. #if DECAF_EDDSA_$(gf_shortname)_SUPPORTS_CONTEXTS
  66. , const uint8_t *context,
  67. uint8_t context_len
  68. #endif
  69. ) {
  70. #if DECAF_EDDSA_$(gf_shortname)_SUPPORTS_CONTEXTS
  71. hash_init_with_dom(hash,1,1,context,context_len);
  72. #else
  73. hash_init_with_dom(hash,1,1,NULL,0);
  74. #endif
  75. }
  76. void decaf_ed$(gf_shortname)_derive_public_key (
  77. uint8_t pubkey[DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES],
  78. const uint8_t privkey[DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES]
  79. ) {
  80. /* only this much used for keygen */
  81. uint8_t secret_scalar_ser[DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES];
  82. hash_hash(
  83. secret_scalar_ser,
  84. sizeof(secret_scalar_ser),
  85. privkey,
  86. DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES
  87. );
  88. clamp(secret_scalar_ser);
  89. API_NS(scalar_t) secret_scalar;
  90. API_NS(scalar_decode_long)(secret_scalar, secret_scalar_ser, sizeof(secret_scalar_ser));
  91. /* Since we are going to mul_by_cofactor during encoding, divide by it here.
  92. * However, the EdDSA base point is not the same as the decaf base point if
  93. * the sigma isogeny is in use: the EdDSA base point is on Etwist_d/(1-d) and
  94. * the decaf base point is on Etwist_d, and when converted it effectively
  95. * picks up a factor of 2 from the isogenies. So we might start at 2 instead of 1.
  96. */
  97. for (unsigned int c = EDDSA_BASE_POINT_RATIO; c < COFACTOR; c <<= 1) {
  98. API_NS(scalar_halve)(secret_scalar,secret_scalar);
  99. }
  100. API_NS(point_t) p;
  101. API_NS(precomputed_scalarmul)(p,API_NS(precomputed_base),secret_scalar);
  102. API_NS(point_mul_by_cofactor_and_encode_like_eddsa)(pubkey, p);
  103. /* Cleanup */
  104. API_NS(scalar_destroy)(secret_scalar);
  105. API_NS(point_destroy)(p);
  106. decaf_bzero(secret_scalar_ser, sizeof(secret_scalar_ser));
  107. }
  108. void decaf_ed$(gf_shortname)_sign (
  109. uint8_t signature[DECAF_EDDSA_$(gf_shortname)_SIGNATURE_BYTES],
  110. const uint8_t privkey[DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES],
  111. const uint8_t pubkey[DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES],
  112. const uint8_t *message,
  113. size_t message_len,
  114. uint8_t prehashed
  115. #if SUPPORTS_CONTEXTS
  116. , const uint8_t *context,
  117. uint8_t context_len
  118. #endif
  119. ) {
  120. #if !SUPPORTS_CONTEXTS
  121. const uint8_t *const context = NULL;
  122. const uint8_t context_len = 0;
  123. #endif
  124. API_NS(scalar_t) secret_scalar;
  125. hash_ctx_t hash;
  126. {
  127. /* Schedule the secret key */
  128. struct {
  129. uint8_t secret_scalar_ser[DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES];
  130. uint8_t seed[DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES];
  131. } __attribute__((packed)) expanded;
  132. hash_hash(
  133. (uint8_t *)&expanded,
  134. sizeof(expanded),
  135. privkey,
  136. DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES
  137. );
  138. clamp(expanded.secret_scalar_ser);
  139. API_NS(scalar_decode_long)(secret_scalar, expanded.secret_scalar_ser, sizeof(expanded.secret_scalar_ser));
  140. /* Hash to create the nonce */
  141. hash_init_with_dom(hash,prehashed,0,context,context_len);
  142. hash_update(hash,expanded.seed,sizeof(expanded.seed));
  143. hash_update(hash,message,message_len);
  144. decaf_bzero(&expanded, sizeof(expanded));
  145. }
  146. /* Decode the nonce */
  147. API_NS(scalar_t) nonce_scalar;
  148. {
  149. uint8_t nonce[2*DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES];
  150. hash_final(hash,nonce,sizeof(nonce));
  151. API_NS(scalar_decode_long)(nonce_scalar, nonce, sizeof(nonce));
  152. decaf_bzero(nonce, sizeof(nonce));
  153. }
  154. uint8_t nonce_point[DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES] = {0};
  155. {
  156. /* Scalarmul to create the nonce-point */
  157. API_NS(scalar_t) nonce_scalar_2;
  158. API_NS(scalar_halve)(nonce_scalar_2,nonce_scalar);
  159. for (unsigned int c = 2*EDDSA_BASE_POINT_RATIO; c < COFACTOR; c <<= 1) {
  160. API_NS(scalar_halve)(nonce_scalar_2,nonce_scalar_2);
  161. }
  162. API_NS(point_t) p;
  163. API_NS(precomputed_scalarmul)(p,API_NS(precomputed_base),nonce_scalar_2);
  164. API_NS(point_mul_by_cofactor_and_encode_like_eddsa)(nonce_point, p);
  165. API_NS(point_destroy)(p);
  166. API_NS(scalar_destroy)(nonce_scalar_2);
  167. }
  168. API_NS(scalar_t) challenge_scalar;
  169. {
  170. /* Compute the challenge */
  171. hash_init_with_dom(hash,prehashed,0,context,context_len);
  172. hash_update(hash,nonce_point,sizeof(nonce_point));
  173. hash_update(hash,pubkey,DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES);
  174. hash_update(hash,message,message_len);
  175. uint8_t challenge[2*DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES];
  176. hash_final(hash,challenge,sizeof(challenge));
  177. hash_destroy(hash);
  178. API_NS(scalar_decode_long)(challenge_scalar,challenge,sizeof(challenge));
  179. decaf_bzero(challenge,sizeof(challenge));
  180. }
  181. API_NS(scalar_mul)(challenge_scalar,challenge_scalar,secret_scalar);
  182. API_NS(scalar_add)(challenge_scalar,challenge_scalar,nonce_scalar);
  183. decaf_bzero(signature,DECAF_EDDSA_$(gf_shortname)_SIGNATURE_BYTES);
  184. memcpy(signature,nonce_point,sizeof(nonce_point));
  185. API_NS(scalar_encode)(&signature[DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES],challenge_scalar);
  186. API_NS(scalar_destroy)(secret_scalar);
  187. API_NS(scalar_destroy)(nonce_scalar);
  188. API_NS(scalar_destroy)(challenge_scalar);
  189. }
  190. void decaf_ed$(gf_shortname)_sign_prehash (
  191. uint8_t signature[DECAF_EDDSA_$(gf_shortname)_SIGNATURE_BYTES],
  192. const uint8_t privkey[DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES],
  193. const uint8_t pubkey[DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES],
  194. const decaf_ed$(gf_shortname)_prehash_ctx_t hash
  195. #if DECAF_EDDSA_$(gf_shortname)_SUPPORTS_CONTEXTS
  196. , const uint8_t *context,
  197. uint8_t context_len
  198. #endif
  199. ) {
  200. uint8_t hash_output[64]; /* MAGIC but true for all existing schemes */
  201. {
  202. decaf_ed$(gf_shortname)_prehash_ctx_t hash_too;
  203. memcpy(hash_too,hash,sizeof(hash_too));
  204. hash_final(hash_too,hash_output,sizeof(hash_output));
  205. hash_destroy(hash_too);
  206. }
  207. #if DECAF_EDDSA_$(gf_shortname)_SUPPORTS_CONTEXTS
  208. decaf_ed$(gf_shortname)_sign(signature,privkey,pubkey,hash_output,sizeof(hash_output),1,context,context_len);
  209. #else
  210. decaf_ed$(gf_shortname)_sign(signature,privkey,pubkey,hash_output,sizeof(hash_output),1);
  211. #endif
  212. decaf_bzero(hash_output,sizeof(hash_output));
  213. }
  214. decaf_error_t decaf_ed$(gf_shortname)_verify (
  215. const uint8_t signature[DECAF_EDDSA_$(gf_shortname)_SIGNATURE_BYTES],
  216. const uint8_t pubkey[DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES],
  217. const uint8_t *message,
  218. size_t message_len,
  219. uint8_t prehashed
  220. #if SUPPORTS_CONTEXTS
  221. , const uint8_t *context,
  222. uint8_t context_len
  223. #endif
  224. ) {
  225. #if !SUPPORTS_CONTEXTS
  226. const uint8_t *const context = NULL;
  227. const uint8_t context_len = 0;
  228. #endif
  229. API_NS(point_t) pk_point, r_point;
  230. decaf_error_t error = API_NS(point_decode_like_eddsa_and_ignore_cofactor)(pk_point,pubkey);
  231. if (DECAF_SUCCESS != error) { return error; }
  232. error = API_NS(point_decode_like_eddsa_and_ignore_cofactor)(r_point,signature);
  233. if (DECAF_SUCCESS != error) { return error; }
  234. API_NS(scalar_t) challenge_scalar;
  235. {
  236. /* Compute the challenge */
  237. hash_ctx_t hash;
  238. hash_init_with_dom(hash,prehashed,0,context,context_len);
  239. hash_update(hash,signature,DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES);
  240. hash_update(hash,pubkey,DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES);
  241. hash_update(hash,message,message_len);
  242. uint8_t challenge[2*DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES];
  243. hash_final(hash,challenge,sizeof(challenge));
  244. hash_destroy(hash);
  245. API_NS(scalar_decode_long)(challenge_scalar,challenge,sizeof(challenge));
  246. decaf_bzero(challenge,sizeof(challenge));
  247. }
  248. API_NS(scalar_sub)(challenge_scalar, API_NS(scalar_zero), challenge_scalar);
  249. API_NS(scalar_t) response_scalar;
  250. API_NS(scalar_decode_long)(
  251. response_scalar,
  252. &signature[DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES],
  253. DECAF_EDDSA_$(gf_shortname)_PRIVATE_BYTES
  254. );
  255. #if EDDSA_BASE_POINT_RATIO == 2
  256. API_NS(scalar_add)(response_scalar,response_scalar,response_scalar);
  257. #endif
  258. /* pk_point = -c(x(P)) + (cx + k)G = kG */
  259. API_NS(base_double_scalarmul_non_secret)(
  260. pk_point,
  261. response_scalar,
  262. pk_point,
  263. challenge_scalar
  264. );
  265. return decaf_succeed_if(API_NS(point_eq(pk_point,r_point)));
  266. }
  267. decaf_error_t decaf_ed$(gf_shortname)_verify_prehash (
  268. const uint8_t signature[DECAF_EDDSA_$(gf_shortname)_SIGNATURE_BYTES],
  269. const uint8_t pubkey[DECAF_EDDSA_$(gf_shortname)_PUBLIC_BYTES],
  270. const decaf_ed$(gf_shortname)_prehash_ctx_t hash
  271. #if DECAF_EDDSA_$(gf_shortname)_SUPPORTS_CONTEXTS
  272. , const uint8_t *context,
  273. uint8_t context_len
  274. #endif
  275. ) {
  276. decaf_error_t ret;
  277. uint8_t hash_output[64]; /* MAGIC but true for all existing schemes */
  278. {
  279. decaf_ed$(gf_shortname)_prehash_ctx_t hash_too;
  280. memcpy(hash_too,hash,sizeof(hash_too));
  281. hash_final(hash_too,hash_output,sizeof(hash_output));
  282. hash_destroy(hash_too);
  283. }
  284. #if DECAF_EDDSA_$(gf_shortname)_SUPPORTS_CONTEXTS
  285. ret = decaf_ed$(gf_shortname)_verify(signature,pubkey,hash_output,sizeof(hash_output),1,context,context_len);
  286. #else
  287. ret = decaf_ed$(gf_shortname)_verify(signature,pubkey,hash_output,sizeof(hash_output),1);
  288. #endif
  289. return ret;
  290. }