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
15
16from nacl import exceptions as exc
17from nacl._sodium import ffi, lib
18from nacl.exceptions import ensure
19
20
21has_crypto_scalarmult_ed25519 = bool(lib.PYNACL_HAS_CRYPTO_SCALARMULT_ED25519)
22
23crypto_scalarmult_BYTES: int = lib.crypto_scalarmult_bytes()
24crypto_scalarmult_SCALARBYTES: int = lib.crypto_scalarmult_scalarbytes()
25
26crypto_scalarmult_ed25519_BYTES = 0
27crypto_scalarmult_ed25519_SCALARBYTES = 0
28
29if has_crypto_scalarmult_ed25519:
30 crypto_scalarmult_ed25519_BYTES = lib.crypto_scalarmult_ed25519_bytes()
31 crypto_scalarmult_ed25519_SCALARBYTES = (
32 lib.crypto_scalarmult_ed25519_scalarbytes()
33 )
34
35
36def crypto_scalarmult_base(n: bytes) -> bytes:
37 """
38 Computes and returns the scalar product of a standard group element and an
39 integer ``n``.
40
41 :param n: bytes
42 :rtype: bytes
43 """
44 q = ffi.new("unsigned char[]", crypto_scalarmult_BYTES)
45
46 rc = lib.crypto_scalarmult_base(q, n)
47 ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError)
48
49 return ffi.buffer(q, crypto_scalarmult_SCALARBYTES)[:]
50
51
52def crypto_scalarmult(n: bytes, p: bytes) -> bytes:
53 """
54 Computes and returns the scalar product of the given group element and an
55 integer ``n``.
56
57 :param p: bytes
58 :param n: bytes
59 :rtype: bytes
60 """
61 q = ffi.new("unsigned char[]", crypto_scalarmult_BYTES)
62
63 rc = lib.crypto_scalarmult(q, n, p)
64 ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError)
65
66 return ffi.buffer(q, crypto_scalarmult_SCALARBYTES)[:]
67
68
69def crypto_scalarmult_ed25519_base(n: bytes) -> bytes:
70 """
71 Computes and returns the scalar product of a standard group element and an
72 integer ``n`` on the edwards25519 curve.
73
74 :param n: a :py:data:`.crypto_scalarmult_ed25519_SCALARBYTES` long bytes
75 sequence representing a scalar
76 :type n: bytes
77 :return: a point on the edwards25519 curve, represented as a
78 :py:data:`.crypto_scalarmult_ed25519_BYTES` long bytes sequence
79 :rtype: bytes
80 :raises nacl.exceptions.UnavailableError: If called when using a
81 minimal build of libsodium.
82 """
83 ensure(
84 has_crypto_scalarmult_ed25519,
85 "Not available in minimal build",
86 raising=exc.UnavailableError,
87 )
88
89 ensure(
90 isinstance(n, bytes)
91 and len(n) == crypto_scalarmult_ed25519_SCALARBYTES,
92 "Input must be a {} long bytes sequence".format(
93 "crypto_scalarmult_ed25519_SCALARBYTES"
94 ),
95 raising=exc.TypeError,
96 )
97
98 q = ffi.new("unsigned char[]", crypto_scalarmult_ed25519_BYTES)
99
100 rc = lib.crypto_scalarmult_ed25519_base(q, n)
101 ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError)
102
103 return ffi.buffer(q, crypto_scalarmult_ed25519_BYTES)[:]
104
105
106def crypto_scalarmult_ed25519_base_noclamp(n: bytes) -> bytes:
107 """
108 Computes and returns the scalar product of a standard group element and an
109 integer ``n`` on the edwards25519 curve. The integer ``n`` is not clamped.
110
111 :param n: a :py:data:`.crypto_scalarmult_ed25519_SCALARBYTES` long bytes
112 sequence representing a scalar
113 :type n: bytes
114 :return: a point on the edwards25519 curve, represented as a
115 :py:data:`.crypto_scalarmult_ed25519_BYTES` long bytes sequence
116 :rtype: bytes
117 :raises nacl.exceptions.UnavailableError: If called when using a
118 minimal build of libsodium.
119 """
120 ensure(
121 has_crypto_scalarmult_ed25519,
122 "Not available in minimal build",
123 raising=exc.UnavailableError,
124 )
125
126 ensure(
127 isinstance(n, bytes)
128 and len(n) == crypto_scalarmult_ed25519_SCALARBYTES,
129 "Input must be a {} long bytes sequence".format(
130 "crypto_scalarmult_ed25519_SCALARBYTES"
131 ),
132 raising=exc.TypeError,
133 )
134
135 q = ffi.new("unsigned char[]", crypto_scalarmult_ed25519_BYTES)
136
137 rc = lib.crypto_scalarmult_ed25519_base_noclamp(q, n)
138 ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError)
139
140 return ffi.buffer(q, crypto_scalarmult_ed25519_BYTES)[:]
141
142
143def crypto_scalarmult_ed25519(n: bytes, p: bytes) -> bytes:
144 """
145 Computes and returns the scalar product of a *clamped* integer ``n``
146 and the given group element on the edwards25519 curve.
147 The scalar is clamped, as done in the public key generation case,
148 by setting to zero the bits in position [0, 1, 2, 255] and setting
149 to one the bit in position 254.
150
151 :param n: a :py:data:`.crypto_scalarmult_ed25519_SCALARBYTES` long bytes
152 sequence representing a scalar
153 :type n: bytes
154 :param p: a :py:data:`.crypto_scalarmult_ed25519_BYTES` long bytes sequence
155 representing a point on the edwards25519 curve
156 :type p: bytes
157 :return: a point on the edwards25519 curve, represented as a
158 :py:data:`.crypto_scalarmult_ed25519_BYTES` long bytes sequence
159 :rtype: bytes
160 :raises nacl.exceptions.UnavailableError: If called when using a
161 minimal build of libsodium.
162 """
163 ensure(
164 has_crypto_scalarmult_ed25519,
165 "Not available in minimal build",
166 raising=exc.UnavailableError,
167 )
168
169 ensure(
170 isinstance(n, bytes)
171 and len(n) == crypto_scalarmult_ed25519_SCALARBYTES,
172 "Input must be a {} long bytes sequence".format(
173 "crypto_scalarmult_ed25519_SCALARBYTES"
174 ),
175 raising=exc.TypeError,
176 )
177
178 ensure(
179 isinstance(p, bytes) and len(p) == crypto_scalarmult_ed25519_BYTES,
180 "Input must be a {} long bytes sequence".format(
181 "crypto_scalarmult_ed25519_BYTES"
182 ),
183 raising=exc.TypeError,
184 )
185
186 q = ffi.new("unsigned char[]", crypto_scalarmult_ed25519_BYTES)
187
188 rc = lib.crypto_scalarmult_ed25519(q, n, p)
189 ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError)
190
191 return ffi.buffer(q, crypto_scalarmult_ed25519_BYTES)[:]
192
193
194def crypto_scalarmult_ed25519_noclamp(n: bytes, p: bytes) -> bytes:
195 """
196 Computes and returns the scalar product of an integer ``n``
197 and the given group element on the edwards25519 curve. The integer
198 ``n`` is not clamped.
199
200 :param n: a :py:data:`.crypto_scalarmult_ed25519_SCALARBYTES` long bytes
201 sequence representing a scalar
202 :type n: bytes
203 :param p: a :py:data:`.crypto_scalarmult_ed25519_BYTES` long bytes sequence
204 representing a point on the edwards25519 curve
205 :type p: bytes
206 :return: a point on the edwards25519 curve, represented as a
207 :py:data:`.crypto_scalarmult_ed25519_BYTES` long bytes sequence
208 :rtype: bytes
209 :raises nacl.exceptions.UnavailableError: If called when using a
210 minimal build of libsodium.
211 """
212 ensure(
213 has_crypto_scalarmult_ed25519,
214 "Not available in minimal build",
215 raising=exc.UnavailableError,
216 )
217
218 ensure(
219 isinstance(n, bytes)
220 and len(n) == crypto_scalarmult_ed25519_SCALARBYTES,
221 "Input must be a {} long bytes sequence".format(
222 "crypto_scalarmult_ed25519_SCALARBYTES"
223 ),
224 raising=exc.TypeError,
225 )
226
227 ensure(
228 isinstance(p, bytes) and len(p) == crypto_scalarmult_ed25519_BYTES,
229 "Input must be a {} long bytes sequence".format(
230 "crypto_scalarmult_ed25519_BYTES"
231 ),
232 raising=exc.TypeError,
233 )
234
235 q = ffi.new("unsigned char[]", crypto_scalarmult_ed25519_BYTES)
236
237 rc = lib.crypto_scalarmult_ed25519_noclamp(q, n, p)
238 ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError)
239
240 return ffi.buffer(q, crypto_scalarmult_ed25519_BYTES)[:]