Coverage Report

Created: 2026-11-12 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/crypto-bigint-0.7.10/src/limb/encoding.rs
Line
Count
Source
1
//! Limb encoding
2
3
use super::{Limb, Word};
4
use crate::{Encoding, bitlen};
5
6
impl Limb {
7
    /// Decode from big endian bytes.
8
    #[inline]
9
    #[must_use]
10
52.0k
    pub const fn from_be_bytes(bytes: [u8; Self::BYTES]) -> Self {
11
52.0k
        Limb(Word::from_be_bytes(bytes))
12
52.0k
    }
13
14
    /// Decode from little endian bytes.
15
    #[inline]
16
    #[must_use]
17
0
    pub const fn from_le_bytes(bytes: [u8; Self::BYTES]) -> Self {
18
0
        Limb(Word::from_le_bytes(bytes))
19
0
    }
20
21
    /// Decode limb from a big endian byte slice, which may be shorter than [`Limb::BYTES`].
22
    ///
23
    /// # Panics
24
    /// If the slice larger than [`Limb::BYTES`].
25
    #[must_use]
26
    #[track_caller]
27
52.0k
    pub const fn from_be_slice(bytes: &[u8]) -> Self {
28
52.0k
        let offset = Self::BYTES
29
52.0k
            .checked_sub(bytes.len())
30
52.0k
            .expect("The given slice is larger than Limb::BYTES");
31
32
52.0k
        let mut repr = [0u8; Self::BYTES];
33
52.0k
        let mut i = 0;
34
468k
        while i < bytes.len() {
35
416k
            repr[offset + i] = bytes[i];
36
416k
            i += 1;
37
416k
        }
38
52.0k
        Self::from_be_bytes(repr)
39
52.0k
    }
40
41
    /// Decode limb from a little endian byte slice, which may be shorter than [`Limb::BYTES`].
42
    ///
43
    /// # Panics
44
    /// If the slice larger than [`Limb::BYTES`].
45
    #[must_use]
46
    #[track_caller]
47
0
    pub const fn from_le_slice(bytes: &[u8]) -> Self {
48
0
        assert!(
49
0
            bytes.len() <= Self::BYTES,
50
0
            "The given slice is larger than Limb::BYTES"
51
        );
52
53
0
        let mut repr = [0u8; Self::BYTES];
54
0
        let mut i = 0;
55
0
        while i < bytes.len() {
56
0
            repr[i] = bytes[i];
57
0
            i += 1;
58
0
        }
59
0
        Self::from_le_bytes(repr)
60
0
    }
61
62
    /// Decode limb from the provided big endian bytes, zero padding if necessary, and
63
    /// truncating to the least significant bytes in the event the given amount of data exceeds
64
    /// `bits_precision`.
65
    ///
66
    /// # Panics
67
    /// If `bits_precision > Self::BITS`.
68
    #[inline]
69
    #[must_use]
70
    #[track_caller]
71
0
    pub const fn from_be_slice_truncated(mut bytes: &[u8], bits_precision: u32) -> Self {
72
0
        assert!(bits_precision <= Self::BITS);
73
0
        let bytes_precision = bitlen::to_bytes(bits_precision);
74
0
        if bytes.len() > bytes_precision {
75
0
            bytes = bytes
76
0
                .split_at(bytes.len().saturating_sub(bytes_precision))
77
0
                .1;
78
0
        }
79
80
0
        let mut ret = Self::from_be_slice(bytes);
81
0
        ret.mask_to_precision(bits_precision);
82
0
        ret
83
0
    }
84
85
    /// Decode limb from the provided little endian bytes, zero padding if necessary, and
86
    /// truncating to the least significant bytes in the event the given amount of data exceeds
87
    /// `bits_precision`.
88
    ///
89
    /// # Panics
90
    /// If `bits_precision > Self::BITS`.
91
    #[inline]
92
    #[must_use]
93
    #[track_caller]
94
0
    pub const fn from_le_slice_truncated(mut bytes: &[u8], bits_precision: u32) -> Self {
95
0
        assert!(bits_precision <= Self::BITS);
96
0
        let bytes_precision = bitlen::to_bytes(bits_precision);
97
0
        if bytes.len() > bytes_precision {
98
0
            bytes = bytes.split_at(bytes_precision).0;
99
0
        }
100
101
0
        let mut ret = Self::from_le_slice(bytes);
102
0
        ret.mask_to_precision(bits_precision);
103
0
        ret
104
0
    }
105
106
    /// Encode as big endian bytes.
107
    #[inline]
108
    #[must_use]
109
146k
    pub const fn to_be_bytes(&self) -> [u8; Self::BYTES] {
110
146k
        self.0.to_be_bytes()
111
146k
    }
<crypto_bigint::limb::Limb>::to_be_bytes
Line
Count
Source
109
17.2k
    pub const fn to_be_bytes(&self) -> [u8; Self::BYTES] {
110
17.2k
        self.0.to_be_bytes()
111
17.2k
    }
<crypto_bigint::limb::Limb>::to_be_bytes
Line
Count
Source
109
129k
    pub const fn to_be_bytes(&self) -> [u8; Self::BYTES] {
110
129k
        self.0.to_be_bytes()
111
129k
    }
Unexecuted instantiation: <crypto_bigint::limb::Limb>::to_be_bytes
112
113
    /// Encode as little endian bytes.
114
    #[inline]
115
    #[must_use]
116
0
    pub const fn to_le_bytes(&self) -> [u8; Self::BYTES] {
117
0
        self.0.to_le_bytes()
118
0
    }
Unexecuted instantiation: <crypto_bigint::limb::Limb>::to_le_bytes
Unexecuted instantiation: <crypto_bigint::limb::Limb>::to_le_bytes
119
120
    /// Mask to the given number of bits precision.
121
    #[inline(always)]
122
0
    pub(crate) const fn mask_to_precision(&mut self, bits_precision: u32) {
123
0
        debug_assert!(bits_precision <= Self::BITS);
124
0
        self.0 &= Word::MAX >> (Limb::BITS.saturating_sub(bits_precision));
125
0
    }
126
}
127
128
impl Encoding for Limb {
129
    type Repr = [u8; Self::BYTES];
130
131
    #[inline]
132
0
    fn from_be_bytes(bytes: Self::Repr) -> Self {
133
0
        Self::from_be_bytes(bytes)
134
0
    }
135
136
    #[inline]
137
0
    fn from_le_bytes(bytes: Self::Repr) -> Self {
138
0
        Self::from_le_bytes(bytes)
139
0
    }
140
141
    #[inline]
142
0
    fn from_be_slice_truncated(bytes: &[u8], bits_precision: u32) -> Self {
143
0
        Self::from_be_slice_truncated(bytes, bits_precision)
144
0
    }
145
146
    #[inline]
147
0
    fn from_le_slice_truncated(bytes: &[u8], bits_precision: u32) -> Self {
148
0
        Self::from_le_slice_truncated(bytes, bits_precision)
149
0
    }
150
151
    #[inline]
152
0
    fn to_be_bytes(&self) -> Self::Repr {
153
0
        self.to_be_bytes()
154
0
    }
155
156
    #[inline]
157
0
    fn to_le_bytes(&self) -> Self::Repr {
158
0
        self.to_le_bytes()
159
0
    }
160
}
161
162
#[cfg(test)]
163
mod test {
164
    use super::*;
165
166
    cpubits::cpubits! {
167
        32 => { const LIMB: Limb = Limb(0x7654_3210); }
168
        64 => { const LIMB: Limb = Limb(0xFEDCBA9876543210); }
169
    }
170
171
    #[test]
172
    fn from_be_slice_truncated() {
173
        // Enough capacity
174
        let limb = Limb::from_be_slice_truncated(&[1], 32);
175
        assert_eq!(limb, Limb::ONE);
176
177
        // Result needs masking
178
        let limb = Limb::from_be_slice_truncated(&[3], 1);
179
        assert_eq!(limb, Limb::ONE);
180
    }
181
182
    #[test]
183
    #[should_panic]
184
    fn from_be_slice_truncated_oversized() {
185
        let _ = Limb::from_be_slice_truncated(b"", 65);
186
    }
187
188
    #[test]
189
    fn from_le_slice_truncated() {
190
        // Enough capacity
191
        let limb = Limb::from_le_slice_truncated(&[1], 32);
192
        assert_eq!(limb, Limb::ONE);
193
194
        // Result needs masking
195
        let limb = Limb::from_le_slice_truncated(&[1], 1);
196
        assert_eq!(limb, Limb::ONE);
197
    }
198
199
    #[test]
200
    #[should_panic]
201
    fn from_le_slice_truncated_oversized() {
202
        let _ = Limb::from_le_slice_truncated(b"", 65);
203
    }
204
205
    #[test]
206
    fn roundtrip() {
207
        assert_eq!(LIMB, Limb::from_be_bytes(LIMB.to_be_bytes()));
208
        assert_eq!(LIMB, Limb::from_le_bytes(LIMB.to_le_bytes()));
209
    }
210
211
    #[test]
212
    fn reverse() {
213
        let mut bytes = LIMB.to_be_bytes();
214
        bytes.reverse();
215
        assert_eq!(LIMB, Limb::from_le_bytes(bytes));
216
217
        let mut bytes = LIMB.to_le_bytes();
218
        bytes.reverse();
219
        assert_eq!(LIMB, Limb::from_be_bytes(bytes));
220
    }
221
}