1use core::ops::DerefMut as _;
2
3#[allow(unused_imports)]
4use std_shims::prelude::*;
5use std_shims::io::{self, *};
6
7use subtle::{Choice, ConstantTimeEq, ConditionallySelectable};
8use zeroize::{Zeroize, Zeroizing};
9
10use rand_core::{RngCore, CryptoRng};
11
12use sha3::{Digest as _, Keccak256};
13
14use monero_io::*;
15
16#[derive(Clone, Copy, Eq, Debug, Zeroize)]
18pub struct Scalar([u8; 32]);
19
20impl ConstantTimeEq for Scalar {
21 fn ct_eq(&self, other: &Self) -> Choice {
22 self.0.ct_eq(&other.0)
23 }
24}
25impl PartialEq for Scalar {
26 fn eq(&self, other: &Self) -> bool {
28 bool::from(self.ct_eq(other))
29 }
30}
31
32impl ConditionallySelectable for Scalar {
33 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
34 let mut result = [0; 32];
35 #[allow(clippy::needless_range_loop)]
36 for i in 0 .. 32 {
37 result[i] = u8::conditional_select(&a.0[i], &b.0[i], choice);
38 }
39 Self(result)
40 }
41}
42
43impl Scalar {
44 pub const ZERO: Self = Self([0; 32]);
46 #[rustfmt::skip]
48 pub const ONE: Self = Self([
49 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51 ]);
52 #[rustfmt::skip]
60 pub const INV_EIGHT: Self = Self([
61 121, 47, 220, 226, 41, 229, 6, 97, 208, 218, 28, 125, 179, 157, 211, 7,
62 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
63 ]);
64
65 pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
69 w.write_all(&self.0)
70 }
71
72 pub fn read<R: Read>(r: &mut R) -> io::Result<Scalar> {
79 let bytes = read_bytes(r)?;
80 Option::<curve25519_dalek::Scalar>::from(curve25519_dalek::Scalar::from_canonical_bytes(bytes))
81 .ok_or_else(|| io::Error::other("unreduced scalar"))?;
82 Ok(Self(bytes))
83 }
84
85 #[doc(hidden)]
89 pub fn from(scalar: curve25519_dalek::Scalar) -> Self {
90 Self(scalar.to_bytes())
91 }
92
93 #[doc(hidden)]
97 pub fn into(self) -> curve25519_dalek::Scalar {
98 curve25519_dalek::Scalar::from_canonical_bytes(self.0)
99 .expect("`Scalar` instantiated with invalid contents")
100 }
101
102 #[doc(hidden)]
106 pub fn random(rng: &mut (impl RngCore + CryptoRng)) -> Self {
107 let mut raw = Zeroizing::new([0; 64]);
108 rng.fill_bytes(raw.deref_mut());
109 Self(Zeroizing::new(curve25519_dalek::Scalar::from_bytes_mod_order_wide(&raw)).to_bytes())
110 }
111
112 pub fn hash(data: impl AsRef<[u8]>) -> Self {
119 let scalar =
120 curve25519_dalek::Scalar::from_bytes_mod_order(Keccak256::digest(data.as_ref()).into());
121
122 assert!(
131 scalar != curve25519_dalek::Scalar::ZERO,
132 "keccak256(preimage) \\cong 0 \\mod l! Preimage: {:?}",
133 data.as_ref()
134 );
135
136 Self::from(scalar)
137 }
138}
139
140impl From<Scalar> for [u8; 32] {
141 fn from(scalar: Scalar) -> [u8; 32] {
142 scalar.0
143 }
144}