proof_of_sql/base/scalar/
scalar_ext.rs

1use super::Scalar;
2use bnum::types::U256;
3use core::cmp::Ordering;
4
5/// Extension trait for blanket implementations for `Scalar` types.
6/// This trait is primarily to avoid cluttering the core `Scalar` implementation with default implementations
7/// and provides helper methods for `Scalar`.
8pub trait ScalarExt: Scalar {
9    /// Compute 10^exponent for the Scalar. Note that we do not check for overflow.
10    fn pow10(exponent: u8) -> Self {
11        itertools::repeat_n(Self::TEN, exponent as usize).product()
12    }
13    /// Compare two `Scalar`s as signed numbers.
14    fn signed_cmp(&self, other: &Self) -> Ordering {
15        match *self - *other {
16            x if x.is_zero() => Ordering::Equal,
17            x if x > Self::MAX_SIGNED => Ordering::Less,
18            _ => Ordering::Greater,
19        }
20    }
21
22    #[must_use]
23    /// Converts a U256 to Scalar, wrapping as needed
24    fn from_wrapping(value: U256) -> Self {
25        let value_as_limbs: [u64; 4] = value.into();
26        Self::from(value_as_limbs)
27    }
28
29    /// Converts a Scalar to U256. Note that any values above `MAX_SIGNED` shall remain positive, even if they are representative of negative values.
30    fn into_u256_wrapping(self) -> U256 {
31        U256::from(Into::<[u64; 4]>::into(self))
32    }
33}
34
35impl<S: Scalar> ScalarExt for S {}
36
37#[cfg(test)]
38pub(crate) fn test_scalar_constants<S: Scalar>() {
39    assert_eq!(S::from(0), S::ZERO);
40    assert_eq!(S::from(1), S::ONE);
41    assert_eq!(S::from(2), S::TWO);
42    // -1/2 == least upper bound
43    assert_eq!(-S::TWO.inv().unwrap(), S::MAX_SIGNED);
44    assert_eq!(S::from(10), S::TEN);
45
46    // Check the challenge mask
47    assert_eq!(
48        S::CHALLENGE_MASK,
49        U256::MAX >> S::CHALLENGE_MASK.leading_zeros()
50    );
51    assert!(S::MAX_SIGNED.into_u256_wrapping() < S::CHALLENGE_MASK);
52    assert!((-S::ONE).into_u256_wrapping() > S::CHALLENGE_MASK);
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58    use crate::base::scalar::{test_scalar::TestScalar, Curve25519Scalar, MontScalar};
59    #[test]
60    fn scalar_comparison_works() {
61        let zero = Curve25519Scalar::ZERO;
62        let one = Curve25519Scalar::ONE;
63        let two = Curve25519Scalar::TWO;
64        let max = Curve25519Scalar::MAX_SIGNED;
65        let min = max + one;
66        assert_eq!(max.signed_cmp(&one), Ordering::Greater);
67        assert_eq!(one.signed_cmp(&zero), Ordering::Greater);
68        assert_eq!(min.signed_cmp(&zero), Ordering::Less);
69        assert_eq!((two * max).signed_cmp(&zero), Ordering::Less);
70        assert_eq!(two * max + one, zero);
71    }
72    #[test]
73    fn we_can_compute_powers_of_10() {
74        for i in 0..=u128::MAX.ilog10() {
75            assert_eq!(
76                TestScalar::pow10(u8::try_from(i).unwrap()),
77                TestScalar::from(u128::pow(10, i))
78            );
79        }
80        assert_eq!(
81            TestScalar::pow10(76),
82            MontScalar(ark_ff::MontFp!(
83                "10000000000000000000000000000000000000000000000000000000000000000000000000000"
84            ))
85        );
86    }
87}