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.
 
 
 
 
 

564 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_bool_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. public:
  166. typedef decaf_255_point_t Wrapped;
  167. /** @brief Size of a serialized element */
  168. static const size_t SER_BYTES = DECAF_255_SER_BYTES;
  169. /** @brief Bytes required for hash */
  170. static const size_t HASH_BYTES = SER_BYTES;
  171. /** @brief Size of a stegged element */
  172. static const size_t STEG_BYTES = HASH_BYTES * 2;
  173. /** The c-level object. */
  174. Wrapped p;
  175. /** @brief Don't initialize. */
  176. inline Point(const NOINIT &) NOEXCEPT {}
  177. /** @brief Constructor sets to identity by default. */
  178. inline Point(const Wrapped &q = decaf_255_point_identity) NOEXCEPT { decaf_255_point_copy(p,q); }
  179. /** @brief Copy constructor. */
  180. inline Point(const Point &q) NOEXCEPT { *this = q; }
  181. /** @brief Assignment. */
  182. inline Point& operator=(const Point &q) NOEXCEPT { decaf_255_point_copy(p,q.p); return *this; }
  183. /** @brief Destructor securely zeorizes the point. */
  184. inline ~Point() NOEXCEPT { decaf_255_point_destroy(p); }
  185. /** @brief Construct from RNG */
  186. inline explicit Point(Rng &rng, bool uniform = true) NOEXCEPT {
  187. if (uniform) {
  188. FixedArrayBuffer<2*HASH_BYTES> b(rng);
  189. set_to_hash(b);
  190. } else {
  191. FixedArrayBuffer<HASH_BYTES> b(rng);
  192. set_to_hash(b);
  193. }
  194. }
  195. /**
  196. * @brief Initialize from a fixed-length byte string.
  197. * The all-zero string maps to the identity.
  198. *
  199. * @throw CryptoException the string was the wrong length, or wasn't the encoding of a point,
  200. * or was the identity and allow_identity was DECAF_FALSE.
  201. */
  202. inline explicit Point(const FixedBlock<SER_BYTES> &buffer, decaf_bool_t allow_identity=DECAF_TRUE)
  203. throw(CryptoException) {
  204. if (DECAF_SUCCESS != decode(*this,buffer,allow_identity)) {
  205. throw CryptoException();
  206. }
  207. }
  208. /**
  209. * @brief Initialize from C++ fixed-length byte string.
  210. * The all-zero string maps to the identity.
  211. *
  212. * @retval DECAF_SUCCESS the string was successfully decoded.
  213. * @return DECAF_FAILURE the string was the wrong length, or wasn't the encoding of a point,
  214. * or was the identity and allow_identity was DECAF_FALSE. Contents of the buffer are undefined.
  215. */
  216. static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
  217. Point &p, const FixedBlock<SER_BYTES> &buffer, decaf_bool_t allow_identity=DECAF_TRUE
  218. ) NOEXCEPT {
  219. return decaf_255_point_decode(p.p,buffer.data(),allow_identity);
  220. }
  221. /**
  222. * @brief Map uniformly to the curve from a hash buffer.
  223. * The empty or all-zero string maps to the identity, as does the string "\x01".
  224. * If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform,
  225. * but the buffer will be zero-padded on the right.
  226. */
  227. static inline Point from_hash ( const Block &s ) NOEXCEPT {
  228. Point p((NOINIT())); p.set_to_hash(s); return p;
  229. }
  230. /**
  231. * @brief Map to the curve from a hash buffer.
  232. * The empty or all-zero string maps to the identity, as does the string "\x01".
  233. * If the buffer is shorter than 2*HASH_BYTES, well, it won't be as uniform,
  234. * but the buffer will be zero-padded on the right.
  235. */
  236. inline void set_to_hash( const Block &s ) NOEXCEPT {
  237. if (s.size() < HASH_BYTES) {
  238. SecureBuffer b(HASH_BYTES);
  239. memcpy(b.data(), s.data(), s.size());
  240. decaf_255_point_from_hash_nonuniform(p,b.data());
  241. } else if (s.size() == HASH_BYTES) {
  242. decaf_255_point_from_hash_nonuniform(p,s.data());
  243. } else if (s.size() < 2*HASH_BYTES) {
  244. SecureBuffer b(2*HASH_BYTES);
  245. memcpy(b.data(), s.data(), s.size());
  246. decaf_255_point_from_hash_uniform(p,b.data());
  247. } else {
  248. decaf_255_point_from_hash_uniform(p,s.data());
  249. }
  250. }
  251. /** @brief Serializable instance */
  252. inline size_t serSize() const NOEXCEPT { return SER_BYTES; }
  253. /** @brief Serializable instance */
  254. inline void serializeInto(unsigned char *buffer) const NOEXCEPT {
  255. decaf_255_point_encode(buffer, p);
  256. }
  257. /** @brief Point add. */
  258. inline Point operator+ (const Point &q) const NOEXCEPT { Point r((NOINIT())); decaf_255_point_add(r.p,p,q.p); return r; }
  259. /** @brief Point add. */
  260. inline Point &operator+=(const Point &q) NOEXCEPT { decaf_255_point_add(p,p,q.p); return *this; }
  261. /** @brief Point subtract. */
  262. inline Point operator- (const Point &q) const NOEXCEPT { Point r((NOINIT())); decaf_255_point_sub(r.p,p,q.p); return r; }
  263. /** @brief Point subtract. */
  264. inline Point &operator-=(const Point &q) NOEXCEPT { decaf_255_point_sub(p,p,q.p); return *this; }
  265. /** @brief Point negate. */
  266. inline Point operator- () const NOEXCEPT { Point r((NOINIT())); decaf_255_point_negate(r.p,p); return r; }
  267. /** @brief Double the point out of place. */
  268. inline Point times_two () const NOEXCEPT { Point r((NOINIT())); decaf_255_point_double(r.p,p); return r; }
  269. /** @brief Double the point in place. */
  270. inline Point &double_in_place() NOEXCEPT { decaf_255_point_double(p,p); return *this; }
  271. /** @brief Constant-time compare. */
  272. inline bool operator!=(const Point &q) const NOEXCEPT { return ! decaf_255_point_eq(p,q.p); }
  273. /** @brief Constant-time compare. */
  274. inline bool operator==(const Point &q) const NOEXCEPT { return !!decaf_255_point_eq(p,q.p); }
  275. /** @brief Scalar multiply. */
  276. inline Point operator* (const Scalar &s) const NOEXCEPT { Point r((NOINIT())); decaf_255_point_scalarmul(r.p,p,s.s); return r; }
  277. /** @brief Scalar multiply in place. */
  278. inline Point &operator*=(const Scalar &s) NOEXCEPT { decaf_255_point_scalarmul(p,p,s.s); return *this; }
  279. /** @brief Multiply by s.inverse(). If s=0, maps to the identity. */
  280. inline Point operator/ (const Scalar &s) const throw(CryptoException) { return (*this) * s.inverse(); }
  281. /** @brief Multiply by s.inverse(). If s=0, maps to the identity. */
  282. inline Point &operator/=(const Scalar &s) throw(CryptoException) { return (*this) *= s.inverse(); }
  283. /** @brief Validate / sanity check */
  284. inline bool validate() const NOEXCEPT { return DECAF_SUCCESS == decaf_255_point_valid(p); }
  285. /** @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster. */
  286. static inline Point double_scalarmul (
  287. const Point &q, const Scalar &qs, const Point &r, const Scalar &rs
  288. ) NOEXCEPT {
  289. Point p((NOINIT())); decaf_255_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p;
  290. }
  291. /**
  292. * @brief Double-scalar multiply, equivalent to q*qs + r*rs but faster.
  293. * For those who like their scalars before the point.
  294. */
  295. static inline Point double_scalarmul (
  296. const Scalar &qs, const Point &q, const Scalar &rs, const Point &r
  297. ) NOEXCEPT {
  298. return double_scalarmul(q,qs,r,rs);
  299. }
  300. /**
  301. * @brief Double-scalar multiply: this point by the first scalar and base by the second scalar.
  302. * @warning This function takes variable time, and may leak the scalars (or points, but currently
  303. * it doesn't).
  304. */
  305. inline Point non_secret_combo_with_base(const Scalar &s, const Scalar &s_base) NOEXCEPT {
  306. Point r((NOINIT())); decaf_255_base_double_scalarmul_non_secret(r.p,s_base.s,p,s.s); return r;
  307. }
  308. /** @brief Return a point equal to *this, whose internal data is rotated by a torsion element. */
  309. inline Point debugging_torque() const NOEXCEPT {
  310. Point q; decaf_255_point_debugging_torque(q.p,p); return q;
  311. }
  312. /** @brief Return a point equal to *this, whose internal data has a modified representation. */
  313. inline Point debugging_pscale(const FixedBlock<SER_BYTES> factor) const NOEXCEPT {
  314. Point q; decaf_255_point_debugging_pscale(q.p,p,factor.data()); return q;
  315. }
  316. /** @brief Return a point equal to *this, whose internal data has a randomized representation. */
  317. inline Point debugging_pscale(Rng &r) const NOEXCEPT {
  318. FixedArrayBuffer<SER_BYTES> sb(r); return debugging_pscale(sb);
  319. }
  320. /**
  321. * Modify buffer so that Point::from_hash(Buffer) == *this, and return true;
  322. * or leave buf unmodified and return false.
  323. */
  324. inline bool invert_elligator (
  325. Buffer buf, uint16_t hint
  326. ) const NOEXCEPT {
  327. unsigned char buf2[2*HASH_BYTES];
  328. memset(buf2,0,sizeof(buf2));
  329. memcpy(buf2,buf.data(),(buf.size() > 2*HASH_BYTES) ? 2*HASH_BYTES : buf.size());
  330. decaf_bool_t ret;
  331. if (buf.size() > HASH_BYTES) {
  332. ret = decaf_255_invert_elligator_uniform(buf2, p, hint);
  333. } else {
  334. ret = decaf_255_invert_elligator_nonuniform(buf2, p, hint);
  335. }
  336. if (buf.size() < HASH_BYTES) {
  337. ret &= decaf_memeq(&buf2[buf.size()], &buf2[HASH_BYTES], HASH_BYTES - buf.size());
  338. }
  339. if (DECAF_SUCCESS == ret) {
  340. /* TODO: make this constant time?? */
  341. memcpy(buf.data(),buf2,(buf.size() < HASH_BYTES) ? buf.size() : HASH_BYTES);
  342. }
  343. decaf_bzero(buf2,sizeof(buf2));
  344. return DECAF_SUCCESS == ret;
  345. }
  346. /** @brief Steganographically encode this */
  347. inline SecureBuffer steg_encode(Rng &rng, size_t size=STEG_BYTES) const throw(std::bad_alloc, LengthException) {
  348. if (size <= HASH_BYTES + 4 || size > 2*HASH_BYTES) throw LengthException();
  349. SecureBuffer out(STEG_BYTES);
  350. bool done;
  351. do {
  352. rng.read(Buffer(out).slice(HASH_BYTES-1,STEG_BYTES-HASH_BYTES+1));
  353. done = invert_elligator(out, out[HASH_BYTES-1]);
  354. } while (!done);
  355. return out;
  356. }
  357. /** @brief Return the base point */
  358. static inline const Point base() NOEXCEPT { return Point(decaf_255_point_base); }
  359. /** @brief Return the identity point */
  360. static inline const Point identity() NOEXCEPT { return Point(decaf_255_point_identity); }
  361. };
  362. /**
  363. * @brief Precomputed table of points.
  364. * Minor difficulties arise here because the decaf API doesn't expose, as a constant, how big such an object is.
  365. * Therefore we have to call malloc() or friends, but that's probably for the best, because you don't want to
  366. * stack-allocate a 15kiB object anyway.
  367. */
  368. /** @cond internal */
  369. typedef decaf_255_precomputed_s Precomputed_U;
  370. /** @endcond */
  371. class Precomputed
  372. /** @cond internal */
  373. : protected OwnedOrUnowned<Precomputed,Precomputed_U>
  374. /** @endcond */
  375. {
  376. public:
  377. /** Destructor securely zeorizes the memory. */
  378. inline ~Precomputed() NOEXCEPT { clear(); }
  379. /**
  380. * @brief Initialize from underlying type, declared as a reference to prevent
  381. * it from being called with 0, thereby breaking override.
  382. *
  383. * The underlying object must remain valid throughout the lifetime of this one.
  384. *
  385. * By default, initializes to the table for the base point.
  386. *
  387. * @warning The empty initializer makes this equal to base, unlike the empty
  388. * initializer for points which makes this equal to the identity.
  389. */
  390. inline Precomputed (
  391. const Precomputed_U &yours = *defaultValue()
  392. ) NOEXCEPT : OwnedOrUnowned<Precomputed,Precomputed_U>(yours) {}
  393. #if __cplusplus >= 201103L
  394. /** @brief Move-assign operator */
  395. inline Precomputed &operator=(Precomputed &&it) NOEXCEPT {
  396. OwnedOrUnowned<Precomputed,Precomputed_U>::operator= (it);
  397. return *this;
  398. }
  399. /** @brief Move constructor */
  400. inline Precomputed(Precomputed &&it) NOEXCEPT : OwnedOrUnowned<Precomputed,Precomputed_U>() {
  401. *this = it;
  402. }
  403. /** @brief Undelete copy operator */
  404. inline Precomputed &operator=(const Precomputed &it) NOEXCEPT {
  405. OwnedOrUnowned<Precomputed,Precomputed_U>::operator= (it);
  406. return *this;
  407. }
  408. #endif
  409. /**
  410. * @brief Initilaize from point. Must allocate memory, and may throw.
  411. */
  412. inline Precomputed &operator=(const Point &it) throw(std::bad_alloc) {
  413. alloc();
  414. decaf_255_precompute(ours.mine,it.p);
  415. return *this;
  416. }
  417. /**
  418. * @brief Copy constructor.
  419. */
  420. inline Precomputed(const Precomputed &it) throw(std::bad_alloc)
  421. : OwnedOrUnowned<Precomputed,Precomputed_U>() { *this = it; }
  422. /**
  423. * @brief Constructor which initializes from point.
  424. */
  425. inline explicit Precomputed(const Point &it) throw(std::bad_alloc)
  426. : OwnedOrUnowned<Precomputed,Precomputed_U>() { *this = it; }
  427. /** @brief Fixed base scalarmul. */
  428. inline Point operator* (const Scalar &s) const NOEXCEPT { Point r; decaf_255_precomputed_scalarmul(r.p,get(),s.s); return r; }
  429. /** @brief Multiply by s.inverse(). If s=0, maps to the identity. */
  430. inline Point operator/ (const Scalar &s) const throw(CryptoException) { return (*this) * s.inverse(); }
  431. /** @brief Return the table for the base point. */
  432. static inline const Precomputed base() NOEXCEPT { return Precomputed(); }
  433. public:
  434. /** @cond internal */
  435. friend class OwnedOrUnowned<Precomputed,Precomputed_U>;
  436. static inline size_t size() NOEXCEPT { return sizeof_decaf_255_precomputed_s; }
  437. static inline size_t alignment() NOEXCEPT { return alignof_decaf_255_precomputed_s; }
  438. static inline const Precomputed_U * defaultValue() NOEXCEPT { return decaf_255_precomputed_base; }
  439. /** @endcond */
  440. };
  441. }; /* struct IsoEd25519 */
  442. /** @cond internal */
  443. inline SecureBuffer IsoEd25519::Scalar::direct_scalarmul (
  444. const Block &in,
  445. decaf_bool_t allow_identity,
  446. decaf_bool_t short_circuit
  447. ) const throw(CryptoException) {
  448. SecureBuffer out(IsoEd25519::Point::SER_BYTES);
  449. if (DECAF_SUCCESS !=
  450. decaf_255_direct_scalarmul(out.data(), in.data(), s, allow_identity, short_circuit)
  451. ) {
  452. throw CryptoException();
  453. }
  454. return out;
  455. }
  456. /** endcond */
  457. #undef NOEXCEPT
  458. } /* namespace decaf */
  459. #endif /* __DECAF_255_HXX__ */