587 lines
21 KiB

  1. /**
  2. * @file decaf/decaf_255.hxx
  3. * @author Mike Hamburg
  4. *
  5. * @copyright
  6. * Copyright (c) 2015 Cryptography Research, Inc. \n
  7. * Released under the MIT License. See LICENSE.txt for license information.
  8. *
  9. * @brief A group of prime order p, C++ wrapper.
  10. *
  11. * The Decaf library implements cryptographic operations on a an elliptic curve
  12. * group of prime order p. It accomplishes this by using a twisted Edwards
  13. * curve (isogenous to Curve25519) and wiping out the cofactor.
  14. *
  15. * The formulas are all complete and have no special cases, except that
  16. * decaf_255_decode can fail because not every sequence of bytes is a valid group
  17. * element.
  18. *
  19. * The formulas contain no data-dependent branches, timing or memory accesses,
  20. * except for decaf_255_base_double_scalarmul_non_secret.
  21. */
  22. #ifndef __DECAF_255_HXX__
  23. #define __DECAF_255_HXX__ 1
  24. /** This code uses posix_memalign. */
  25. #ifndef _XOPEN_SOURCE
  26. #define _XOPEN_SOURCE 600
  27. #endif
  28. #include <stdlib.h>
  29. #include <string.h> /* for memcpy */
  30. #include <decaf.h>
  31. #include <decaf/secure_buffer.hxx>
  32. #include <string>
  33. #include <sys/types.h>
  34. #include <limits.h>
  35. /** @cond internal */
  36. #if __cplusplus >= 201103L
  37. #define NOEXCEPT noexcept
  38. #else
  39. #define NOEXCEPT throw()
  40. #endif
  41. /** @endcond */
  42. namespace decaf {
  43. /**
  44. * @brief Curve25519/Decaf instantiation of group.
  45. */
  46. struct IsoEd25519 {
  47. /** The name of the curve */
  48. static inline const char *name() { return "IsoEd25519"; }
  49. /** The curve's cofactor (removed, but useful for testing) */
  50. static const int REMOVED_COFACTOR = 8;
  51. /** Residue class of field modulus: p == this mod 2*(this-1) */
  52. static const int FIELD_MODULUS_TYPE = 5;
  53. /** @cond internal */
  54. class Point;
  55. class Precomputed;
  56. /** @endcond */
  57. /**
  58. * @brief A scalar modulo the curve order.
  59. * Supports the usual arithmetic operations, all in constant time.
  60. * FIXME: make it clearer which init-from-buffer operations reject scalars that are too big.
  61. */
  62. class Scalar : public Serializable<Scalar> {
  63. private:
  64. /** @brief wrapped C type */
  65. typedef decaf_255_scalar_t Wrapped;
  66. public:
  67. /** @brief Size of a serialized element */
  68. static const size_t SER_BYTES = DECAF_255_SCALAR_BYTES;
  69. /** @brief access to the underlying scalar object */
  70. Wrapped s;
  71. /** @brief Don't initialize. */
  72. inline Scalar(const NOINIT &) NOEXCEPT {}
  73. /** @brief Set to an unsigned word */
  74. inline Scalar(const decaf_word_t w) NOEXCEPT { *this = w; }
  75. /** @brief Set to a signed word */
  76. inline Scalar(const int w) NOEXCEPT { *this = w; }
  77. /** @brief Construct from RNG */
  78. inline explicit Scalar(Rng &rng) NOEXCEPT {
  79. FixedArrayBuffer<SER_BYTES> sb(rng);
  80. *this = sb;
  81. }
  82. /** @brief Construct from decaf_scalar_t object. */
  83. inline Scalar(const Wrapped &t = decaf_255_scalar_zero) NOEXCEPT { decaf_255_scalar_copy(s,t); }
  84. /** @brief Copy constructor. */
  85. inline Scalar(const Scalar &x) NOEXCEPT { *this = x; }
  86. /** @brief Construct from arbitrary-length little-endian byte sequence. */
  87. inline Scalar(const Block &buffer) NOEXCEPT { *this = buffer; }
  88. /** @brief Serializable instance */
  89. inline size_t serSize() const NOEXCEPT { return SER_BYTES; }
  90. /** @brief Serializable instance */
  91. inline void serializeInto(unsigned char *buffer) const NOEXCEPT {
  92. decaf_255_scalar_encode(buffer, s);
  93. }
  94. /** @brief Assignment. */
  95. inline Scalar& operator=(const Scalar &x) NOEXCEPT { decaf_255_scalar_copy(s,x.s); return *this; }
  96. /** @brief Assign from unsigned word. */
  97. inline Scalar& operator=(decaf_word_t w) NOEXCEPT { decaf_255_scalar_set_unsigned(s,w); return *this; }
  98. /** @brief Assign from signed int. */
  99. inline Scalar& operator=(int w) NOEXCEPT {
  100. Scalar t(-(decaf_word_t)INT_MIN);
  101. decaf_255_scalar_set_unsigned(s,(decaf_word_t)w - (decaf_word_t)INT_MIN);
  102. *this -= t;
  103. return *this;
  104. }
  105. /** Destructor securely zeorizes the scalar. */
  106. inline ~Scalar() NOEXCEPT { decaf_255_scalar_destroy(s); }
  107. /** @brief Assign from arbitrary-length little-endian byte sequence in a Block. */
  108. inline Scalar &operator=(const Block &bl) NOEXCEPT {
  109. decaf_255_scalar_decode_long(s,bl.data(),bl.size()); return *this;
  110. }
  111. /**
  112. * @brief Decode from correct-length little-endian byte sequence.
  113. * @return DECAF_FAILURE if the scalar is greater than or equal to the group order q.
  114. */
  115. static inline decaf_error_t __attribute__((warn_unused_result)) decode (
  116. Scalar &sc, const FixedBlock<SER_BYTES> buffer
  117. ) NOEXCEPT {
  118. return decaf_255_scalar_decode(sc.s,buffer.data());
  119. }
  120. /** Add. */
  121. inline Scalar operator+ (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_255_scalar_add(r.s,s,q.s); return r; }
  122. /** Add to this. */
  123. inline Scalar &operator+=(const Scalar &q) NOEXCEPT { decaf_255_scalar_add(s,s,q.s); return *this; }
  124. /** Subtract. */
  125. inline Scalar operator- (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_255_scalar_sub(r.s,s,q.s); return r; }
  126. /** Subtract from this. */
  127. inline Scalar &operator-=(const Scalar &q) NOEXCEPT { decaf_255_scalar_sub(s,s,q.s); return *this; }
  128. /** Multiply */
  129. inline Scalar operator* (const Scalar &q) const NOEXCEPT { Scalar r((NOINIT())); decaf_255_scalar_mul(r.s,s,q.s); return r; }
  130. /** Multiply into this. */
  131. inline Scalar &operator*=(const Scalar &q) NOEXCEPT { decaf_255_scalar_mul(s,s,q.s); return *this; }
  132. /** Negate */
  133. inline Scalar operator- () const NOEXCEPT { Scalar r((NOINIT())); decaf_255_scalar_sub(r.s,decaf_255_scalar_zero,s); return r; }
  134. /** @brief Invert with Fermat's Little Theorem (slow!). If *this == 0, return 0. */
  135. inline Scalar inverse() const throw(CryptoException) {
  136. Scalar r;
  137. if (DECAF_SUCCESS != decaf_255_scalar_invert(r.s,s)) {
  138. throw CryptoException();
  139. }
  140. return r;
  141. }
  142. /** @brief Divide by inverting q. If q == 0, return 0. */
  143. inline Scalar operator/ (const Scalar &q) const throw(CryptoException) { return *this * q.inverse(); }
  144. /** @brief Divide by inverting q. If q == 0, return 0. */
  145. inline Scalar &operator/=(const Scalar &q) throw(CryptoException) { return *this *= q.inverse(); }
  146. /** @brief Compare in constant time */
  147. inline bool operator!=(const Scalar &q) const NOEXCEPT { return !(*this == q); }
  148. /** @brief Compare in constant time */
  149. inline bool operator==(const Scalar &q) const NOEXCEPT { return !!decaf_255_scalar_eq(s,q.s); }
  150. /** @brief Scalarmul with scalar on left. */
  151. inline Point operator* (const Point &q) const NOEXCEPT { return q * (*this); }
  152. /** @brief Scalarmul-precomputed with scalar on left. */
  153. inline Point operator* (const Precomputed &q) const NOEXCEPT { return q * (*this); }
  154. /** @brief Direct scalar multiplication. */
  155. inline SecureBuffer direct_scalarmul(
  156. const Block &in,
  157. decaf_bool_t allow_identity=DECAF_FALSE,
  158. decaf_bool_t short_circuit=DECAF_TRUE
  159. ) const throw(CryptoException);
  160. };
  161. /**
  162. * @brief Element of prime-order group.
  163. */
  164. class Point : public Serializable<Point> {
  165. private:
  166. /** @brief wrapped C type */
  167. typedef decaf_255_point_t Wrapped;
  168. public:
  169. /** @brief Size of a serialized element */
  170. static const size_t SER_BYTES = DECAF_255_SER_BYTES;
  171. /** @brief Bytes required for hash */
  172. static const size_t HASH_BYTES = SER_BYTES;
  173. /** @brief Size of a stegged element */
  174. static const size_t STEG_BYTES = HASH_BYTES * 2;
  175. /** The c-level object. */
  176. Wrapped p;
  177. /** @brief Don't initialize. */
  178. inline Point(const NOINIT &) NOEXCEPT {}
  179. /** @brief Constructor sets to identity by default. */
  180. inline Point(const Wrapped &q = decaf_255_point_identity) NOEXCEPT { decaf_255_point_copy(p,q); }
  181. /** @brief Copy constructor. */
  182. inline Point(const Point &q) NOEXCEPT { *this = q; }
  183. /** @brief Assignment. */
  184. inline Point& operator=(const Point &q) NOEXCEPT { decaf_255_point_copy(p,q.p); return *this; }
  185. /** @brief Destructor securely zeorizes the point. */
  186. inline ~Point() NOEXCEPT { decaf_255_point_destroy(p); }
  187. /** @brief Construct from RNG */
  188. inline explicit Point(Rng &rng, bool uniform = true) NOEXCEPT {
  189. if (uniform) {
  190. FixedArrayBuffer<2*HASH_BYTES> b(rng);
  191. set_to_hash(b);
  192. } else {
  193. FixedArrayBuffer<HASH_BYTES> b(rng);
  194. set_to_hash(b);
  195. }
  196. }
  197. /**
  198. * @brief Initialize from a fixed-length byte string.
  199. * The all-zero string maps to the identity.
  200. *
  201. * @throw CryptoException the string was the wrong length, or wasn't the encoding of a point,
  202. * or was the identity and allow_identity was DECAF_FALSE.
  203. */
  204. inline explicit Point(const FixedBlock<SER_BYTES> &buffer, decaf_bool_t allow_identity=DECAF_TRUE)
  205. throw(CryptoException) {
  206. if (DECAF_SUCCESS != decode(*this,buffer,allow_identity)) {
  207. throw CryptoException();
  208. }
  209. }
  210. /**
  211. * @brief Initialize from C++ fixed-length byte string.
  212. * The all-zero string maps to the identity.
  213. *
  214. * @retval DECAF_SUCCESS the string was successfully decoded.
  215. * @return DECAF_FAILURE the string was the wrong length, or wasn't the encoding of a point,
  216. * or was the identity and allow_identity was DECAF_FALSE. Contents of the buffer are undefined.
  217. */
  218. static inline decaf_error_t __attribute__((warn_unused_result)) decode (
  219. Point &p, const FixedBlock<SER_BYTES> &buffer, decaf_bool_t allow_identity=DECAF_TRUE
  220. ) NOEXCEPT {
  221. return decaf_255_point_decode(p.p,buffer.data(),allow_identity);
  222. }
  223. /**
  224. * @brief Map uniformly to the curve from a hash buffer.
  225. * The empty or all-zero string maps to the identity, as does the string "\x01".
  226. * If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform,
  227. * but the buffer will be zero-padded on the right.
  228. */
  229. static inline Point from_hash ( const Block &s ) NOEXCEPT {
  230. Point p((NOINIT())); p.set_to_hash(s); return p;
  231. }
  232. /**
  233. * @brief Map to the curve from a hash buffer.
  234. * The empty or all-zero string maps to the identity, as does the string "\x01".
  235. * If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform,
  236. * but the buffer will be zero-padded on the right.
  237. */
  238. inline void set_to_hash( const Block &s ) NOEXCEPT {
  239. if (s.size() < HASH_BYTES) {
  240. SecureBuffer b(HASH_BYTES);
  241. memcpy(b.data(), s.data(), s.size());
  242. decaf_255_point_from_hash_nonuniform(p,b.data());
  243. } else if (s.size() == HASH_BYTES) {
  244. decaf_255_point_from_hash_nonuniform(p,s.data());
  245. } else if (s.size() < 2*HASH_BYTES) {
  246. SecureBuffer b(2*HASH_BYTES);
  247. memcpy(b.data(), s.data(), s.size());
  248. decaf_255_point_from_hash_uniform(p,b.data());
  249. } else {
  250. decaf_255_point_from_hash_uniform(p,s.data());
  251. }
  252. }
  253. /**
  254. * @brief Encode to string. The identity encodes to the all-zero string.
  255. */
  256. inline operator SecureBuffer() const {
  257. SecureBuffer buffer(SER_BYTES);
  258. decaf_255_point_encode(buffer.data(), p);
  259. return buffer;
  260. }
  261. /** @brief Serializable instance */
  262. inline size_t serSize() const NOEXCEPT { return SER_BYTES; }
  263. /** @brief Serializable instance */
  264. inline void serializeInto(unsigned char *buffer) const NOEXCEPT {
  265. decaf_255_point_encode(buffer, p);
  266. }
  267. /** @brief Point add. */
  268. inline Point operator+ (const Point &q) const NOEXCEPT { Point r((NOINIT())); decaf_255_point_add(r.p,p,q.p); return r; }
  269. /** @brief Point add. */
  270. inline Point &operator+=(const Point &q) NOEXCEPT { decaf_255_point_add(p,p,q.p); return *this; }
  271. /** @brief Point subtract. */
  272. inline Point operator- (const Point &q) const NOEXCEPT { Point r((NOINIT())); decaf_255_point_sub(r.p,p,q.p); return r; }
  273. /** @brief Point subtract. */
  274. inline Point &operator-=(const Point &q) NOEXCEPT { decaf_255_point_sub(p,p,q.p); return *this; }
  275. /** @brief Point negate. */
  276. inline Point operator- () const NOEXCEPT { Point r((NOINIT())); decaf_255_point_negate(r.p,p); return r; }
  277. /** @brief Double the point out of place. */
  278. inline Point times_two () const NOEXCEPT { Point r((NOINIT())); decaf_255_point_double(r.p,p); return r; }
  279. /** @brief Double the point in place. */
  280. inline Point &double_in_place() NOEXCEPT { decaf_255_point_double(p,p); return *this; }
  281. /** @brief Constant-time compare. */
  282. inline bool operator!=(const Point &q) const NOEXCEPT { return ! decaf_255_point_eq(p,q.p); }
  283. /** @brief Constant-time compare. */
  284. inline bool operator==(const Point &q) const NOEXCEPT { return !!decaf_255_point_eq(p,q.p); }
  285. /** @brief Scalar multiply. */
  286. inline Point operator* (const Scalar &s) const NOEXCEPT { Point r((NOINIT())); decaf_255_point_scalarmul(r.p,p,s.s); return r; }
  287. /** @brief Scalar multiply in place. */
  288. inline Point &operator*=(const Scalar &s) NOEXCEPT { decaf_255_point_scalarmul(p,p,s.s); return *this; }
  289. /** @brief Multiply by s.inverse(). If s=0, maps to the identity. */
  290. inline Point operator/ (const Scalar &s) const throw(CryptoException) { return (*this) * s.inverse(); }
  291. /** @brief Multiply by s.inverse(). If s=0, maps to the identity. */
  292. inline Point &operator/=(const Scalar &s) throw(CryptoException) { return (*this) *= s.inverse(); }
  293. /** @brief Validate / sanity check */
  294. inline bool validate() const NOEXCEPT { return decaf_255_point_valid(p); }
  295. /** @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster. */
  296. static inline Point double_scalarmul (
  297. const Point &q, const Scalar &qs, const Point &r, const Scalar &rs
  298. ) NOEXCEPT {
  299. Point p((NOINIT())); decaf_255_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p;
  300. }
  301. /** @brief Dual-scalar multiply, equivalent to this*r1, this*r2 but faster. */
  302. inline void dual_scalarmul (
  303. Point &q1, Point &q2, const Scalar &r1, const Scalar &r2
  304. ) const NOEXCEPT {
  305. decaf_255_point_dual_scalarmul(q1.p,q2.p,p,r1.s,r2.s);
  306. }
  307. /**
  308. * @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster.
  309. * For those who like their scalars before the point.
  310. */
  311. static inline Point double_scalarmul (
  312. const Scalar &qs, const Point &q, const Scalar &rs, const Point &r
  313. ) NOEXCEPT {
  314. return double_scalarmul(q,qs,r,rs);
  315. }
  316. /**
  317. * @brief Double-scalar multiply: this point by the first scalar and base by the second scalar.
  318. * @warning This function takes variable time, and may leak the scalars (or points, but currently
  319. * it doesn't).
  320. */
  321. inline Point non_secret_combo_with_base(const Scalar &s, const Scalar &s_base) NOEXCEPT {
  322. Point r((NOINIT())); decaf_255_base_double_scalarmul_non_secret(r.p,s_base.s,p,s.s); return r;
  323. }
  324. /** @brief Return a point equal to *this, whose internal data is rotated by a torsion element. */
  325. inline Point debugging_torque() const NOEXCEPT {
  326. Point q;
  327. decaf_255_point_debugging_torque(q.p,p);
  328. return q;
  329. }
  330. /** @brief Return a point equal to *this, whose internal data has a modified representation. */
  331. inline Point debugging_pscale(const FixedBlock<SER_BYTES> factor) const NOEXCEPT {
  332. Point q;
  333. decaf_255_point_debugging_pscale(q.p,p,factor.data());
  334. return q;
  335. }
  336. /** @brief Return a point equal to *this, whose internal data has a randomized representation. */
  337. inline Point debugging_pscale(Rng &r) const NOEXCEPT {
  338. FixedArrayBuffer<SER_BYTES> sb(r);
  339. return debugging_pscale(sb);
  340. }
  341. /**
  342. * Modify buffer so that Point::from_hash(Buffer) == *this, and return DECAF_SUCCESS;
  343. * or leave buf unmodified and return DECAF_FAILURE.
  344. */
  345. inline decaf_error_t invert_elligator (
  346. Buffer buf, uint16_t hint
  347. ) const NOEXCEPT {
  348. unsigned char buf2[2*HASH_BYTES];
  349. memset(buf2,0,sizeof(buf2));
  350. memcpy(buf2,buf.data(),(buf.size() > 2*HASH_BYTES) ? 2*HASH_BYTES : buf.size());
  351. decaf_bool_t ret;
  352. if (buf.size() > HASH_BYTES) {
  353. ret = decaf_successful(decaf_255_invert_elligator_uniform(buf2, p, hint));
  354. } else {
  355. ret = decaf_successful(decaf_255_invert_elligator_nonuniform(buf2, p, hint));
  356. }
  357. if (buf.size() < HASH_BYTES) {
  358. ret &= decaf_memeq(&buf2[buf.size()], &buf2[HASH_BYTES], HASH_BYTES - buf.size());
  359. }
  360. if (ret) {
  361. /* TODO: make this constant time?? */
  362. memcpy(buf.data(),buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES);
  363. }
  364. decaf_bzero(buf2,sizeof(buf2));
  365. return decaf_succeed_if(ret);
  366. }
  367. /** @brief Steganographically encode this */
  368. inline SecureBuffer steg_encode(Rng &rng, size_t size=STEG_BYTES) const throw(std::bad_alloc, LengthException) {
  369. if (size <= HASH_BYTES + 4 || size > 2*HASH_BYTES) throw LengthException();
  370. SecureBuffer out(STEG_BYTES);
  371. decaf_error_t done;
  372. do {
  373. rng.read(Buffer(out).slice(HASH_BYTES-1,STEG_BYTES-HASH_BYTES+1));
  374. done = invert_elligator(out, out[HASH_BYTES-1]);
  375. } while (!decaf_successful(done));
  376. return out;
  377. }
  378. /** @brief Return the base point */
  379. static inline const Point base() NOEXCEPT { return Point(decaf_255_point_base); }
  380. /** @brief Return the identity point */
  381. static inline const Point identity() NOEXCEPT { return Point(decaf_255_point_identity); }
  382. };
  383. /**
  384. * @brief Precomputed table of points.
  385. * Minor difficulties arise here because the decaf API doesn't expose, as a constant, how big such an object is.
  386. * Therefore we have to call malloc() or friends, but that's probably for the best, because you don't want to
  387. * stack-allocate a 15kiB object anyway.
  388. */
  389. /** @cond internal */
  390. typedef decaf_255_precomputed_s Precomputed_U;
  391. /** @endcond */
  392. class Precomputed
  393. /** @cond internal */
  394. : protected OwnedOrUnowned<Precomputed,Precomputed_U>
  395. /** @endcond */
  396. {
  397. public:
  398. /** Destructor securely zeorizes the memory. */
  399. inline ~Precomputed() NOEXCEPT { clear(); }
  400. /**
  401. * @brief Initialize from underlying type, declared as a reference to prevent
  402. * it from being called with 0, thereby breaking override.
  403. *
  404. * The underlying object must remain valid throughout the lifetime of this one.
  405. *
  406. * By default, initializes to the table for the base point.
  407. *
  408. * @warning The empty initializer makes this equal to base, unlike the empty
  409. * initializer for points which makes this equal to the identity.
  410. */
  411. inline Precomputed (
  412. const Precomputed_U &yours = *defaultValue()
  413. ) NOEXCEPT : OwnedOrUnowned<Precomputed,Precomputed_U>(yours) {}
  414. #if __cplusplus >= 201103L
  415. /** @brief Move-assign operator */
  416. inline Precomputed &operator=(Precomputed &&it) NOEXCEPT {
  417. OwnedOrUnowned<Precomputed,Precomputed_U>::operator= (it);
  418. return *this;
  419. }
  420. /** @brief Move constructor */
  421. inline Precomputed(Precomputed &&it) NOEXCEPT : OwnedOrUnowned<Precomputed,Precomputed_U>() {
  422. *this = it;
  423. }
  424. /** @brief Undelete copy operator */
  425. inline Precomputed &operator=(const Precomputed &it) NOEXCEPT {
  426. OwnedOrUnowned<Precomputed,Precomputed_U>::operator= (it);
  427. return *this;
  428. }
  429. #endif
  430. /**
  431. * @brief Initilaize from point. Must allocate memory, and may throw.
  432. */
  433. inline Precomputed &operator=(const Point &it) throw(std::bad_alloc) {
  434. alloc();
  435. decaf_255_precompute(ours.mine,it.p);
  436. return *this;
  437. }
  438. /**
  439. * @brief Copy constructor.
  440. */
  441. inline Precomputed(const Precomputed &it) throw(std::bad_alloc)
  442. : OwnedOrUnowned<Precomputed,Precomputed_U>() { *this = it; }
  443. /**
  444. * @brief Constructor which initializes from point.
  445. */
  446. inline explicit Precomputed(const Point &it) throw(std::bad_alloc)
  447. : OwnedOrUnowned<Precomputed,Precomputed_U>() { *this = it; }
  448. /** @brief Fixed base scalarmul. */
  449. inline Point operator* (const Scalar &s) const NOEXCEPT { Point r; decaf_255_precomputed_scalarmul(r.p,get(),s.s); return r; }
  450. /** @brief Multiply by s.inverse(). If s=0, maps to the identity. */
  451. inline Point operator/ (const Scalar &s) const throw(CryptoException) { return (*this) * s.inverse(); }
  452. /** @brief Return the table for the base point. */
  453. static inline const Precomputed base() NOEXCEPT { return Precomputed(); }
  454. public:
  455. /** @cond internal */
  456. friend class OwnedOrUnowned<Precomputed,Precomputed_U>;
  457. static inline size_t size() NOEXCEPT { return sizeof_decaf_255_precomputed_s; }
  458. static inline size_t alignment() NOEXCEPT { return alignof_decaf_255_precomputed_s; }
  459. static inline const Precomputed_U * defaultValue() NOEXCEPT { return decaf_255_precomputed_base; }
  460. /** @endcond */
  461. };
  462. }; /* struct IsoEd25519 */
  463. /** @cond internal */
  464. inline SecureBuffer IsoEd25519::Scalar::direct_scalarmul (
  465. const Block &in,
  466. decaf_bool_t allow_identity,
  467. decaf_bool_t short_circuit
  468. ) const throw(CryptoException) {
  469. SecureBuffer out(IsoEd25519::Point::SER_BYTES);
  470. if (DECAF_SUCCESS !=
  471. decaf_255_direct_scalarmul(out.data(), in.data(), s, allow_identity, short_circuit)
  472. ) {
  473. throw CryptoException();
  474. }
  475. return out;
  476. }
  477. /** endcond */
  478. #undef NOEXCEPT
  479. } /* namespace decaf */
  480. #endif /* __DECAF_255_HXX__ */