crypto_scalarmult.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. # Copyright 2013-2018 Donald Stufft and individual contributors
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. from nacl import exceptions as exc
  15. from nacl._sodium import ffi, lib
  16. from nacl.exceptions import ensure
  17. has_crypto_scalarmult_ed25519 = bool(lib.PYNACL_HAS_CRYPTO_SCALARMULT_ED25519)
  18. crypto_scalarmult_BYTES: int = lib.crypto_scalarmult_bytes()
  19. crypto_scalarmult_SCALARBYTES: int = lib.crypto_scalarmult_scalarbytes()
  20. crypto_scalarmult_ed25519_BYTES = 0
  21. crypto_scalarmult_ed25519_SCALARBYTES = 0
  22. if has_crypto_scalarmult_ed25519:
  23. crypto_scalarmult_ed25519_BYTES = lib.crypto_scalarmult_ed25519_bytes()
  24. crypto_scalarmult_ed25519_SCALARBYTES = (
  25. lib.crypto_scalarmult_ed25519_scalarbytes()
  26. )
  27. def crypto_scalarmult_base(n: bytes) -> bytes:
  28. """
  29. Computes and returns the scalar product of a standard group element and an
  30. integer ``n``.
  31. :param n: bytes
  32. :rtype: bytes
  33. """
  34. q = ffi.new("unsigned char[]", crypto_scalarmult_BYTES)
  35. rc = lib.crypto_scalarmult_base(q, n)
  36. ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError)
  37. return ffi.buffer(q, crypto_scalarmult_SCALARBYTES)[:]
  38. def crypto_scalarmult(n: bytes, p: bytes) -> bytes:
  39. """
  40. Computes and returns the scalar product of the given group element and an
  41. integer ``n``.
  42. :param p: bytes
  43. :param n: bytes
  44. :rtype: bytes
  45. """
  46. q = ffi.new("unsigned char[]", crypto_scalarmult_BYTES)
  47. rc = lib.crypto_scalarmult(q, n, p)
  48. ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError)
  49. return ffi.buffer(q, crypto_scalarmult_SCALARBYTES)[:]
  50. def crypto_scalarmult_ed25519_base(n: bytes) -> bytes:
  51. """
  52. Computes and returns the scalar product of a standard group element and an
  53. integer ``n`` on the edwards25519 curve.
  54. :param n: a :py:data:`.crypto_scalarmult_ed25519_SCALARBYTES` long bytes
  55. sequence representing a scalar
  56. :type n: bytes
  57. :return: a point on the edwards25519 curve, represented as a
  58. :py:data:`.crypto_scalarmult_ed25519_BYTES` long bytes sequence
  59. :rtype: bytes
  60. :raises nacl.exceptions.UnavailableError: If called when using a
  61. minimal build of libsodium.
  62. """
  63. ensure(
  64. has_crypto_scalarmult_ed25519,
  65. "Not available in minimal build",
  66. raising=exc.UnavailableError,
  67. )
  68. ensure(
  69. isinstance(n, bytes)
  70. and len(n) == crypto_scalarmult_ed25519_SCALARBYTES,
  71. "Input must be a {} long bytes sequence".format(
  72. "crypto_scalarmult_ed25519_SCALARBYTES"
  73. ),
  74. raising=exc.TypeError,
  75. )
  76. q = ffi.new("unsigned char[]", crypto_scalarmult_ed25519_BYTES)
  77. rc = lib.crypto_scalarmult_ed25519_base(q, n)
  78. ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError)
  79. return ffi.buffer(q, crypto_scalarmult_ed25519_BYTES)[:]
  80. def crypto_scalarmult_ed25519_base_noclamp(n: bytes) -> bytes:
  81. """
  82. Computes and returns the scalar product of a standard group element and an
  83. integer ``n`` on the edwards25519 curve. The integer ``n`` is not clamped.
  84. :param n: a :py:data:`.crypto_scalarmult_ed25519_SCALARBYTES` long bytes
  85. sequence representing a scalar
  86. :type n: bytes
  87. :return: a point on the edwards25519 curve, represented as a
  88. :py:data:`.crypto_scalarmult_ed25519_BYTES` long bytes sequence
  89. :rtype: bytes
  90. :raises nacl.exceptions.UnavailableError: If called when using a
  91. minimal build of libsodium.
  92. """
  93. ensure(
  94. has_crypto_scalarmult_ed25519,
  95. "Not available in minimal build",
  96. raising=exc.UnavailableError,
  97. )
  98. ensure(
  99. isinstance(n, bytes)
  100. and len(n) == crypto_scalarmult_ed25519_SCALARBYTES,
  101. "Input must be a {} long bytes sequence".format(
  102. "crypto_scalarmult_ed25519_SCALARBYTES"
  103. ),
  104. raising=exc.TypeError,
  105. )
  106. q = ffi.new("unsigned char[]", crypto_scalarmult_ed25519_BYTES)
  107. rc = lib.crypto_scalarmult_ed25519_base_noclamp(q, n)
  108. ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError)
  109. return ffi.buffer(q, crypto_scalarmult_ed25519_BYTES)[:]
  110. def crypto_scalarmult_ed25519(n: bytes, p: bytes) -> bytes:
  111. """
  112. Computes and returns the scalar product of a *clamped* integer ``n``
  113. and the given group element on the edwards25519 curve.
  114. The scalar is clamped, as done in the public key generation case,
  115. by setting to zero the bits in position [0, 1, 2, 255] and setting
  116. to one the bit in position 254.
  117. :param n: a :py:data:`.crypto_scalarmult_ed25519_SCALARBYTES` long bytes
  118. sequence representing a scalar
  119. :type n: bytes
  120. :param p: a :py:data:`.crypto_scalarmult_ed25519_BYTES` long bytes sequence
  121. representing a point on the edwards25519 curve
  122. :type p: bytes
  123. :return: a point on the edwards25519 curve, represented as a
  124. :py:data:`.crypto_scalarmult_ed25519_BYTES` long bytes sequence
  125. :rtype: bytes
  126. :raises nacl.exceptions.UnavailableError: If called when using a
  127. minimal build of libsodium.
  128. """
  129. ensure(
  130. has_crypto_scalarmult_ed25519,
  131. "Not available in minimal build",
  132. raising=exc.UnavailableError,
  133. )
  134. ensure(
  135. isinstance(n, bytes)
  136. and len(n) == crypto_scalarmult_ed25519_SCALARBYTES,
  137. "Input must be a {} long bytes sequence".format(
  138. "crypto_scalarmult_ed25519_SCALARBYTES"
  139. ),
  140. raising=exc.TypeError,
  141. )
  142. ensure(
  143. isinstance(p, bytes) and len(p) == crypto_scalarmult_ed25519_BYTES,
  144. "Input must be a {} long bytes sequence".format(
  145. "crypto_scalarmult_ed25519_BYTES"
  146. ),
  147. raising=exc.TypeError,
  148. )
  149. q = ffi.new("unsigned char[]", crypto_scalarmult_ed25519_BYTES)
  150. rc = lib.crypto_scalarmult_ed25519(q, n, p)
  151. ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError)
  152. return ffi.buffer(q, crypto_scalarmult_ed25519_BYTES)[:]
  153. def crypto_scalarmult_ed25519_noclamp(n: bytes, p: bytes) -> bytes:
  154. """
  155. Computes and returns the scalar product of an integer ``n``
  156. and the given group element on the edwards25519 curve. The integer
  157. ``n`` is not clamped.
  158. :param n: a :py:data:`.crypto_scalarmult_ed25519_SCALARBYTES` long bytes
  159. sequence representing a scalar
  160. :type n: bytes
  161. :param p: a :py:data:`.crypto_scalarmult_ed25519_BYTES` long bytes sequence
  162. representing a point on the edwards25519 curve
  163. :type p: bytes
  164. :return: a point on the edwards25519 curve, represented as a
  165. :py:data:`.crypto_scalarmult_ed25519_BYTES` long bytes sequence
  166. :rtype: bytes
  167. :raises nacl.exceptions.UnavailableError: If called when using a
  168. minimal build of libsodium.
  169. """
  170. ensure(
  171. has_crypto_scalarmult_ed25519,
  172. "Not available in minimal build",
  173. raising=exc.UnavailableError,
  174. )
  175. ensure(
  176. isinstance(n, bytes)
  177. and len(n) == crypto_scalarmult_ed25519_SCALARBYTES,
  178. "Input must be a {} long bytes sequence".format(
  179. "crypto_scalarmult_ed25519_SCALARBYTES"
  180. ),
  181. raising=exc.TypeError,
  182. )
  183. ensure(
  184. isinstance(p, bytes) and len(p) == crypto_scalarmult_ed25519_BYTES,
  185. "Input must be a {} long bytes sequence".format(
  186. "crypto_scalarmult_ed25519_BYTES"
  187. ),
  188. raising=exc.TypeError,
  189. )
  190. q = ffi.new("unsigned char[]", crypto_scalarmult_ed25519_BYTES)
  191. rc = lib.crypto_scalarmult_ed25519_noclamp(q, n, p)
  192. ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError)
  193. return ffi.buffer(q, crypto_scalarmult_ed25519_BYTES)[:]