zkaluvm/
fe.rs

1// AluVM extensions for zero knowledge, STARKs and SNARKs"
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Designed in 2024-2025 by Dr Maxim Orlovsky <orlovsky@ubideco.org>
6// Written in 2024-2025 by Dr Maxim Orlovsky <orlovsky@ubideco.org>
7//
8// Copyright (C) 2024-2025 Laboratories for Ubiquitous Deterministic Computing (UBIDECO),
9//                         Institute for Distributed and Cognitive Systems (InDCS), Switzerland.
10// Copyright (C) 2024-2025 Dr Maxim Orlovsky.
11// All rights under the above copyrights are reserved.
12//
13// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
14// in compliance with the License. You may obtain a copy of the License at
15//
16//        http://www.apache.org/licenses/LICENSE-2.0
17//
18// Unless required by applicable law or agreed to in writing, software distributed under the License
19// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
20// or implied. See the License for the specific language governing permissions and limitations under
21// the License.
22
23use core::str::FromStr;
24
25use amplify::confinement::TinyBlob;
26use amplify::hex::FromHex;
27use amplify::num::u256;
28use amplify::{hex, Bytes32, Wrapper};
29use strict_encoding::{
30    DecodeError, ReadTuple, StrictDecode, StrictProduct, StrictTuple, StrictType, TypeName, TypedRead,
31};
32
33use crate::LIB_NAME_FINITE_FIELD;
34
35#[allow(non_camel_case_types)]
36#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Display, From)]
37#[display("{0:X}.fe")]
38#[derive(StrictDumb, StrictEncode)]
39#[strict_type(lib = LIB_NAME_FINITE_FIELD)]
40pub struct fe256(
41    #[from(u8)]
42    #[from(u16)]
43    #[from(u32)]
44    #[from(u64)]
45    #[from(u128)]
46    u256,
47);
48
49impl fe256 {
50    pub const ZERO: Self = Self(u256::ZERO);
51
52    #[must_use]
53    fn test_value(val: u256) -> bool { val.into_inner()[3] & 0xF800_0000_0000_0000 == 0 }
54
55    pub const fn to_u256(&self) -> u256 { self.0 }
56}
57
58impl From<Bytes32> for fe256 {
59    fn from(bytes: Bytes32) -> Self { Self::from(bytes.into_inner()) }
60}
61
62impl From<[u8; 32]> for fe256 {
63    fn from(bytes: [u8; 32]) -> Self {
64        let val = u256::from_le_bytes(bytes);
65        Self::from(val)
66    }
67}
68
69impl From<u256> for fe256 {
70    fn from(val: u256) -> Self {
71        // We make sure we are well below any commonly used field order
72        assert!(
73            Self::test_value(val),
74            "the provided value for 256-bit field element is in a risk zone above order of some commonly used 256-bit \
75             finite fields. The probability of this event for randomly-generated values (including the ones coming \
76             from hashes) is astronomically low, thus, an untrusted input is used in an unfiltered way. Adjust your \
77             code and do not use externally-provided values without checking them first."
78        );
79        Self(val)
80    }
81}
82
83impl StrictType for fe256 {
84    const STRICT_LIB_NAME: &'static str = LIB_NAME_FINITE_FIELD;
85    fn strict_name() -> Option<TypeName> { Some(tn!("Fe256")) }
86}
87impl StrictProduct for fe256 {}
88impl StrictTuple for fe256 {
89    const FIELD_COUNT: u8 = 1;
90}
91impl StrictDecode for fe256 {
92    fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
93        reader.read_tuple(|r| {
94            let val = r.read_field::<u256>()?;
95            if !Self::test_value(val) {
96                return Err(DecodeError::DataIntegrityError(format!(
97                    "the provided value {val:#X} for a field element is above the order of some of the finite fields \
98                     and is disallowed"
99                )));
100            }
101            Ok(Self(val))
102        })
103    }
104}
105
106#[cfg(feature = "serde")]
107mod _serde {
108    use serde::de::{Error, Unexpected};
109    use serde::{Deserialize, Deserializer, Serialize, Serializer};
110
111    use super::*;
112
113    impl Serialize for fe256 {
114        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
115        where S: Serializer {
116            if serializer.is_human_readable() {
117                self.to_string().serialize(serializer)
118            } else {
119                self.0.serialize(serializer)
120            }
121        }
122    }
123
124    impl<'de> Deserialize<'de> for fe256 {
125        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
126        where D: Deserializer<'de> {
127            if deserializer.is_human_readable() {
128                let s = String::deserialize(deserializer)?;
129                Self::from_str(&s).map_err(|e| D::Error::invalid_value(Unexpected::Str(&s), &e.to_string().as_str()))
130            } else {
131                let val = u256::deserialize(deserializer)?;
132                if !Self::test_value(val) {
133                    return Err(D::Error::invalid_value(
134                        Unexpected::Bytes(&val.to_le_bytes()),
135                        &"the value for a field element is above the order of some of the finite fields and is \
136                          disallowed",
137                    ));
138                }
139                Ok(Self(val))
140            }
141        }
142    }
143}
144
145#[derive(Clone, PartialEq, Eq, Debug, Display, Error, From)]
146#[display(doc_comments)]
147pub enum ParseFeError {
148    /// field element `{0}` must have a `.fe` suffix.
149    NoSuffix(String),
150
151    #[from]
152    #[display(inner)]
153    Value(hex::Error),
154
155    /// value {0:#x} overflows safe range for field element values.
156    Overflow(u256),
157}
158
159impl FromStr for fe256 {
160    type Err = ParseFeError;
161
162    fn from_str(s: &str) -> Result<Self, Self::Err> {
163        let s = s
164            .strip_suffix(".fe")
165            .ok_or_else(|| ParseFeError::NoSuffix(s.to_owned()))?;
166        let bytes = if s.len() % 2 == 1 { TinyBlob::from_hex(&format!("0{s}"))? } else { TinyBlob::from_hex(s)? };
167        let mut buf = [0u8; 32];
168        if bytes.len() > 32 {
169            return Err(hex::Error::InvalidLength(32, bytes.len()).into());
170        }
171        buf[..bytes.len()].copy_from_slice(bytes.as_slice());
172        let val = u256::from_le_bytes(buf);
173        if !Self::test_value(val) {
174            return Err(ParseFeError::Overflow(val));
175        }
176        Ok(Self(val))
177    }
178}