generic_ec/non_zero/
mod.rs

1use core::{
2    cmp,
3    iter::{self, Product, Sum},
4};
5
6use rand_core::{CryptoRng, RngCore};
7use subtle::{ConstantTimeEq, CtOption};
8
9use crate::{
10    as_raw::FromRaw,
11    core::Samplable,
12    errors::{ZeroPoint, ZeroScalar},
13    Curve, Point, Scalar, SecretScalar,
14};
15
16use self::definition::NonZero;
17
18pub mod coords;
19pub mod definition;
20
21impl<E: Curve> NonZero<Point<E>> {
22    /// Constructs non-zero point
23    ///
24    /// Returns `None` if point is zero
25    pub fn from_point(point: Point<E>) -> Option<Self> {
26        Self::ct_from_point(point).into()
27    }
28
29    /// Constructs non-zero point (constant time)
30    ///
31    /// Returns `None` if point is zero
32    pub fn ct_from_point(point: Point<E>) -> CtOption<Self> {
33        let zero = Point::zero();
34        let is_non_zero = !point.ct_eq(&zero);
35
36        // Correctness: although we technically construct `NonZero` regardless if
37        // it's actually non-zero, `CtOption` never exposes it, so `NonZero` with
38        // zero value is not accessible by anyone
39        CtOption::new(Self::new_unchecked(point), is_non_zero)
40    }
41}
42
43impl<E: Curve> NonZero<Scalar<E>> {
44    /// Generates random non-zero scalar
45    ///
46    /// Algorithm is based on rejection sampling: we sample a scalar, if it's zero try again.
47    /// It may be considered constant-time as zero scalar appears with $2^{-256}$ probability
48    /// which is considered to be negligible.
49    ///
50    /// ## Panics
51    /// Panics if randomness source returned 100 zero scalars in a row. It happens with
52    /// $2^{-25600}$ probability, which practically means that randomness source is broken.
53    pub fn random<R: RngCore>(rng: &mut R) -> Self {
54        match iter::repeat_with(|| E::Scalar::random(rng))
55            .take(100)
56            .flat_map(|s| NonZero::from_scalar(Scalar::from_raw(s)))
57            .next()
58        {
59            Some(s) => s,
60            None => panic!("defected source of randomness"),
61        }
62    }
63
64    #[doc = include_str!("../../docs/hash_to_scalar.md")]
65    ///
66    /// ## Example
67    /// ```rust
68    /// use generic_ec::{Scalar, NonZero, curves::Secp256k1};
69    /// use sha2::Sha256;
70    ///
71    /// #[derive(udigest::Digestable)]
72    /// struct Data<'a> {
73    ///     nonce: &'a [u8],
74    ///     param_a: &'a str,
75    ///     param_b: u128,
76    ///     // ...
77    /// }
78    ///
79    /// let scalar = NonZero::<Scalar<Secp256k1>>::from_hash::<Sha256>(&Data {
80    ///     nonce: b"some data",
81    ///     param_a: "some other data",
82    ///     param_b: 12345,
83    ///     // ...
84    /// });
85    /// ```
86    #[cfg(feature = "hash-to-scalar")]
87    pub fn from_hash<D: digest::Digest>(data: &impl udigest::Digestable) -> Self {
88        let mut rng = rand_hash::HashRng::<D, _>::from_seed(data);
89        Self::random(&mut rng)
90    }
91
92    /// Constructs $S = 1$
93    pub fn one() -> Self {
94        // Correctness: constructed scalar = 1, so it's non-zero
95        Self::new_unchecked(Scalar::one())
96    }
97
98    /// Constructs non-zero scalar
99    ///
100    /// Returns `None` if scalar is zero
101    pub fn from_scalar(scalar: Scalar<E>) -> Option<Self> {
102        Self::ct_from_scalar(scalar).into()
103    }
104
105    /// Constructs non-zero scalar (constant time)
106    ///
107    /// Returns `None` if scalar is zero
108    pub fn ct_from_scalar(scalar: Scalar<E>) -> CtOption<Self> {
109        let zero = Scalar::zero();
110        let is_non_zero = !scalar.ct_eq(&zero);
111
112        // Correctness: although we technically construct `NonZero` regardless if
113        // it's actually non-zero, `CtOption` never exposes it, so `NonZero` with
114        // zero value is not accessible by anyone
115        CtOption::new(Self::new_unchecked(scalar), is_non_zero)
116    }
117
118    /// Returns scalar inverse $S^{-1}$
119    ///
120    /// Similar to [Scalar::invert], but this function is always defined as inverse is defined for all
121    /// non-zero scalars
122    pub fn invert(&self) -> NonZero<Scalar<E>> {
123        #[allow(clippy::expect_used)]
124        let inv = (**self)
125            .invert()
126            .expect("nonzero scalar always has an invert");
127        // Correctness: `inv` is nonzero by definition
128        Self::new_unchecked(inv)
129    }
130
131    /// Upgrades the non-zero scalar into non-zero [`SecretScalar`]
132    pub fn into_secret(self) -> NonZero<SecretScalar<E>> {
133        let mut scalar = self.into_inner();
134        let secret_scalar = SecretScalar::new(&mut scalar);
135        // Correctness: `scalar` was checked to be nonzero
136        NonZero::new_unchecked(secret_scalar)
137    }
138}
139
140impl<E: Curve> NonZero<SecretScalar<E>> {
141    /// Generates random non-zero scalar
142    ///
143    /// Algorithm is based on rejection sampling: we sample a scalar, if it's zero try again.
144    /// It may be considered constant-time as zero scalar appears with $2^{-256}$ probability
145    /// which is considered to be negligible.
146    ///
147    /// ## Panics
148    /// Panics if randomness source returned 100 zero scalars in a row. It happens with
149    /// $2^{-25600}$ probability, which practically means that randomness source is broken.
150    pub fn random<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
151        <Self as crate::traits::Samplable>::random(rng)
152    }
153
154    /// Constructs $S = 1$
155    pub fn one() -> Self {
156        // Correctness: constructed scalar = 1, so it's non-zero
157        Self::new_unchecked(SecretScalar::one())
158    }
159
160    /// Constructs non-zero scalar
161    ///
162    /// Returns `None` if scalar is zero
163    pub fn from_secret_scalar(scalar: SecretScalar<E>) -> Option<Self> {
164        Self::ct_from_secret_scalar(scalar).into()
165    }
166
167    /// Constructs non-zero scalar (constant time)
168    ///
169    /// Returns `None` if scalar is zero
170    pub fn ct_from_secret_scalar(secret_scalar: SecretScalar<E>) -> CtOption<Self> {
171        let zero = Scalar::zero();
172        let is_non_zero = !secret_scalar.as_ref().ct_eq(&zero);
173
174        // Correctness: although we technically construct `NonZero` regardless if
175        // it's actually non-zero, `CtOption` never exposes it, so `NonZero` with
176        // zero value is not accessible by anyone
177        CtOption::new(Self::new_unchecked(secret_scalar), is_non_zero)
178    }
179
180    /// Returns scalar inverse $S^{-1}$
181    ///
182    /// Similar to [SecretScalar::invert], but this function is always defined as inverse is defined for all
183    /// non-zero scalars
184    pub fn invert(&self) -> NonZero<SecretScalar<E>> {
185        #[allow(clippy::expect_used)]
186        let inv = (**self)
187            .invert()
188            .expect("nonzero scalar always has an invert");
189        // Correctness: `inv` is nonzero by definition
190        Self::new_unchecked(inv)
191    }
192}
193
194impl<E: Curve> From<NonZero<Point<E>>> for Point<E> {
195    fn from(point: NonZero<Point<E>>) -> Self {
196        point.into_inner()
197    }
198}
199
200impl<E: Curve> From<NonZero<Scalar<E>>> for Scalar<E> {
201    fn from(scalar: NonZero<Scalar<E>>) -> Self {
202        scalar.into_inner()
203    }
204}
205
206impl<E: Curve> From<NonZero<SecretScalar<E>>> for SecretScalar<E> {
207    fn from(secret_scalar: NonZero<SecretScalar<E>>) -> Self {
208        secret_scalar.into_inner()
209    }
210}
211
212impl<E: Curve> TryFrom<Point<E>> for NonZero<Point<E>> {
213    type Error = ZeroPoint;
214
215    fn try_from(point: Point<E>) -> Result<Self, Self::Error> {
216        Self::from_point(point).ok_or(ZeroPoint)
217    }
218}
219
220impl<E: Curve> TryFrom<Scalar<E>> for NonZero<Scalar<E>> {
221    type Error = ZeroScalar;
222
223    fn try_from(scalar: Scalar<E>) -> Result<Self, Self::Error> {
224        Self::from_scalar(scalar).ok_or(ZeroScalar)
225    }
226}
227
228impl<E: Curve> TryFrom<SecretScalar<E>> for NonZero<SecretScalar<E>> {
229    type Error = ZeroScalar;
230
231    fn try_from(secret_scalar: SecretScalar<E>) -> Result<Self, Self::Error> {
232        Self::from_secret_scalar(secret_scalar).ok_or(ZeroScalar)
233    }
234}
235
236impl<E: Curve> Sum<NonZero<Scalar<E>>> for Scalar<E> {
237    fn sum<I: Iterator<Item = NonZero<Scalar<E>>>>(iter: I) -> Self {
238        iter.fold(Scalar::zero(), |acc, x| acc + x)
239    }
240}
241
242impl<'s, E: Curve> Sum<&'s NonZero<Scalar<E>>> for Scalar<E> {
243    fn sum<I: Iterator<Item = &'s NonZero<Scalar<E>>>>(iter: I) -> Self {
244        iter.fold(Scalar::zero(), |acc, x| acc + x)
245    }
246}
247
248impl<'s, E: Curve> Sum<&'s NonZero<SecretScalar<E>>> for SecretScalar<E> {
249    fn sum<I: Iterator<Item = &'s NonZero<SecretScalar<E>>>>(iter: I) -> Self {
250        let mut out = Scalar::zero();
251        iter.for_each(|x| out += x);
252        SecretScalar::new(&mut out)
253    }
254}
255
256impl<E: Curve> Sum<NonZero<SecretScalar<E>>> for SecretScalar<E> {
257    fn sum<I: Iterator<Item = NonZero<SecretScalar<E>>>>(iter: I) -> Self {
258        let mut out = Scalar::zero();
259        iter.for_each(|x| out += x);
260        SecretScalar::new(&mut out)
261    }
262}
263
264impl<E: Curve> Product<NonZero<Scalar<E>>> for NonZero<Scalar<E>> {
265    fn product<I: Iterator<Item = NonZero<Scalar<E>>>>(iter: I) -> Self {
266        iter.fold(Self::one(), |acc, x| acc * x)
267    }
268}
269
270impl<'s, E: Curve> Product<&'s NonZero<Scalar<E>>> for NonZero<Scalar<E>> {
271    fn product<I: Iterator<Item = &'s NonZero<Scalar<E>>>>(iter: I) -> Self {
272        iter.fold(Self::one(), |acc, x| acc * x)
273    }
274}
275
276impl<'s, E: Curve> Product<&'s NonZero<SecretScalar<E>>> for NonZero<SecretScalar<E>> {
277    fn product<I: Iterator<Item = &'s NonZero<SecretScalar<E>>>>(iter: I) -> Self {
278        let mut out = NonZero::<Scalar<E>>::one();
279        iter.for_each(|x| out *= x);
280        out.into_secret()
281    }
282}
283
284impl<E: Curve> Product<NonZero<SecretScalar<E>>> for NonZero<SecretScalar<E>> {
285    fn product<I: Iterator<Item = NonZero<SecretScalar<E>>>>(iter: I) -> Self {
286        let mut out = NonZero::<Scalar<E>>::one();
287        iter.for_each(|x| out *= x);
288        out.into_secret()
289    }
290}
291
292impl<E: Curve> Sum<NonZero<Point<E>>> for Point<E> {
293    fn sum<I: Iterator<Item = NonZero<Point<E>>>>(iter: I) -> Self {
294        iter.fold(Point::zero(), |acc, x| acc + x)
295    }
296}
297impl<'s, E: Curve> Sum<&'s NonZero<Point<E>>> for Point<E> {
298    fn sum<I: Iterator<Item = &'s NonZero<Point<E>>>>(iter: I) -> Self {
299        iter.fold(Point::zero(), |acc, x| acc + x)
300    }
301}
302
303impl<E: Curve> crate::traits::Samplable for NonZero<Scalar<E>> {
304    fn random<R: RngCore>(rng: &mut R) -> Self {
305        Self::random(rng)
306    }
307}
308
309impl<E: Curve> crate::traits::Samplable for NonZero<SecretScalar<E>> {
310    fn random<R: RngCore>(rng: &mut R) -> Self {
311        NonZero::<Scalar<E>>::random(rng).into_secret()
312    }
313}
314
315impl<T> crate::traits::IsZero for NonZero<T> {
316    /// Returns `false` as `NonZero<T>` cannot be zero
317    #[inline(always)]
318    fn is_zero(&self) -> bool {
319        false
320    }
321}
322
323impl<E: Curve> crate::traits::One for NonZero<Scalar<E>> {
324    fn one() -> Self {
325        Self::one()
326    }
327
328    fn is_one(x: &Self) -> subtle::Choice {
329        x.ct_eq(&Self::one())
330    }
331}
332
333impl<E: Curve> AsRef<Scalar<E>> for NonZero<SecretScalar<E>> {
334    fn as_ref(&self) -> &Scalar<E> {
335        let secret_scalar: &SecretScalar<E> = self.as_ref();
336        secret_scalar.as_ref()
337    }
338}
339
340impl<T> cmp::PartialEq<T> for NonZero<T>
341where
342    T: cmp::PartialEq,
343{
344    fn eq(&self, other: &T) -> bool {
345        self.as_ref() == other
346    }
347}
348
349impl<T> cmp::PartialOrd<T> for NonZero<T>
350where
351    T: cmp::PartialOrd,
352{
353    fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
354        self.as_ref().partial_cmp(other)
355    }
356}
357
358/// We can't write blanket implementation `impl<T> cmp::PartialEq<NonZero<T>> for T` due to
359/// the restrictions of the compiler, which implies unfortunate limitations that we can
360/// do `a == b` but we can't write `b == a` and that's not user-friendly.
361///
362/// However, we can write implementation of PartialEq/PartialOrd for specific `T` such as
363/// `Scalar<E>`, `Point<E>` and others. Moreover, we know for sure all possible `T` for which
364/// `NonZero<T>` is defined, so we use this macro to implement these traits for all possible `T`.
365macro_rules! impl_reverse_partial_eq_cmp {
366    ($($t:ty),+) => {$(
367        impl<E: Curve> cmp::PartialEq<NonZero<$t>> for $t {
368            fn eq(&self, other: &NonZero<$t>) -> bool {
369                let other: &$t = other.as_ref();
370                self == other
371            }
372        }
373        impl<E: Curve> cmp::PartialOrd<NonZero<$t>> for $t {
374            fn partial_cmp(&self, other: &NonZero<$t>) -> Option<cmp::Ordering> {
375                let other: &$t = other.as_ref();
376                self.partial_cmp(other)
377            }
378        }
379    )*};
380}
381
382// Note: not implemented for SecretScalar as it doesn't implement `PartialEq` for security reasons.
383impl_reverse_partial_eq_cmp!(Point<E>, Scalar<E>);
384
385impl<T: ConstantTimeEq> ConstantTimeEq for NonZero<T> {
386    fn ct_eq(&self, other: &Self) -> subtle::Choice {
387        self.as_ref().ct_eq(other.as_ref())
388    }
389}
390
391#[cfg(all(test, feature = "serde"))]
392mod non_zero_is_serializable {
393    use crate::{Curve, NonZero, Point, Scalar, SecretScalar};
394
395    fn impls_serde<T>()
396    where
397        T: serde::Serialize + serde::de::DeserializeOwned,
398    {
399    }
400
401    #[allow(dead_code)]
402    fn ensure_non_zero_is_serde<E: Curve>() {
403        impls_serde::<NonZero<Point<E>>>();
404        impls_serde::<NonZero<Scalar<E>>>();
405        impls_serde::<NonZero<SecretScalar<E>>>();
406    }
407}