Skip to main content

snarkvm_console_types_scalar/
from_field.rs

1// Copyright (c) 2019-2026 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::*;
17
18impl<E: Environment> FromField for Scalar<E> {
19    type Field = Field<E>;
20
21    /// Casts a scalar from a base field element.
22    ///
23    /// This method guarantees the following:
24    ///   1. If the field element is larger than the scalar field modulus, then the operation will fail.
25    ///   2. If the field element is smaller than the scalar field modulus, then the operation will succeed.
26    ///         - This is particularly useful for the case where a user called, `Scalar::from_field(scalar.to_field())`,
27    ///           and the scalar bit representation is between `size_in_data_bits < bits.len() < size_in_bits`.
28    fn from_field(field: &Self::Field) -> Result<Self> {
29        // Note: We are reconstituting the base field into a scalar field.
30        // This is safe as the scalar field modulus is less than the base field modulus,
31        // and thus will always fit within a single base field element.
32        debug_assert!(Scalar::<E>::size_in_bits() < Field::<E>::size_in_bits());
33
34        // Do not truncate the field bits, which provides the following features:
35        //   1. If the field element is larger than the scalar field modulus, then the operation will fail.
36        //   2. If the field element is smaller than the scalar field modulus, then the operation will succeed.
37        //     - This is particularly useful for the case where a user called, `Scalar::from_field(scalar.to_field())`,
38        //       and the scalar bit representation is between `size_in_data_bits < bits.len() < size_in_bits`.
39        Self::from_bits_le(&field.to_bits_le())
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46    use snarkvm_console_network_environment::Console;
47
48    type CurrentEnvironment = Console;
49
50    const ITERATIONS: u64 = 10_000;
51
52    #[test]
53    fn test_from_field() -> Result<()> {
54        let mut rng = TestRng::default();
55
56        for _ in 0..ITERATIONS {
57            // Sample a random scalar.
58            let expected = Scalar::<CurrentEnvironment>::rand(&mut rng);
59            // Perform the operation.
60            let candidate = Scalar::from_field(&expected.to_field()?)?;
61            assert_eq!(expected, candidate);
62
63            // Sample a random field.
64            let expected = Field::<CurrentEnvironment>::rand(&mut rng);
65            // Filter for field elements that exceed the scalar field modulus.
66            if expected > (-Scalar::<CurrentEnvironment>::one()).to_field()? {
67                // Perform the operation.
68                assert!(Scalar::from_field(&expected).is_err());
69            } else {
70                // Perform the operation.
71                assert!(Scalar::from_field(&expected).is_ok());
72            }
73        }
74        Ok(())
75    }
76}