kaspa_math/
lib.rs

1use borsh::{BorshDeserialize, BorshSerialize};
2use wasm_bindgen::JsValue;
3use workflow_core::sendable::Sendable;
4
5pub mod int;
6pub mod uint;
7pub mod wasm;
8
9construct_uint!(Uint192, 3, BorshSerialize, BorshDeserialize);
10construct_uint!(Uint256, 4);
11construct_uint!(Uint320, 5);
12construct_uint!(Uint3072, 48);
13
14#[derive(thiserror::Error, Debug)]
15pub enum Error {
16    #[error("{0:?}")]
17    JsValue(Sendable<JsValue>),
18
19    #[error("Invalid hex string: {0}")]
20    Hex(#[from] faster_hex::Error),
21
22    #[error(transparent)]
23    TryFromSliceError(#[from] uint::TryFromSliceError),
24    // TryFromSliceError(#[from] std::array::TryFromSliceError),
25    #[error("Utf8 error: {0}")]
26    Utf8(#[from] std::str::Utf8Error),
27
28    #[error(transparent)]
29    WorkflowWasm(#[from] workflow_wasm::error::Error),
30
31    #[error(transparent)]
32    SerdeWasmBindgen(#[from] serde_wasm_bindgen::Error),
33
34    #[error("{0:?}")]
35    JsSys(Sendable<js_sys::Error>),
36
37    #[error("Supplied value is not compatible with this type")]
38    NotCompatible,
39
40    #[error("range error: {0:?}")]
41    Range(Sendable<js_sys::RangeError>),
42}
43
44impl From<js_sys::Error> for Error {
45    fn from(err: js_sys::Error) -> Self {
46        Error::JsSys(Sendable(err))
47    }
48}
49
50impl From<js_sys::RangeError> for Error {
51    fn from(err: js_sys::RangeError) -> Self {
52        Error::Range(Sendable(err))
53    }
54}
55
56impl From<JsValue> for Error {
57    fn from(err: JsValue) -> Self {
58        Error::JsValue(Sendable(err))
59    }
60}
61
62impl Uint256 {
63    #[inline]
64    pub fn from_compact_target_bits(bits: u32) -> Self {
65        // This is a floating-point "compact" encoding originally used by
66        // OpenSSL, which satoshi put into consensus code, so we're stuck
67        // with it. The exponent needs to have 3 subtracted from it, hence
68        // this goofy decoding code:
69        let (mant, expt) = {
70            let unshifted_expt = bits >> 24;
71            if unshifted_expt <= 3 {
72                ((bits & 0xFFFFFF) >> (8 * (3 - unshifted_expt)), 0)
73            } else {
74                (bits & 0xFFFFFF, 8 * ((bits >> 24) - 3))
75            }
76        };
77        // The mantissa is signed but may not be negative
78        if mant > 0x7FFFFF {
79            Uint256::ZERO
80        } else {
81            Uint256::from_u64(u64::from(mant)) << expt
82        }
83    }
84
85    #[inline]
86    /// Computes the target value in float format from BigInt format.
87    pub fn compact_target_bits(self) -> u32 {
88        let mut size = (self.bits() + 7) / 8;
89        let mut compact = if size <= 3 {
90            (self.as_u64() << (8 * (3 - size))) as u32
91        } else {
92            let bn = self >> (8 * (size - 3));
93            bn.as_u64() as u32
94        };
95
96        if (compact & 0x00800000) != 0 {
97            compact >>= 8;
98            size += 1;
99        }
100        compact | (size << 24)
101    }
102}
103
104impl From<Uint256> for Uint320 {
105    #[inline]
106    fn from(u: Uint256) -> Self {
107        let mut result = Uint320::ZERO;
108        result.0[..4].copy_from_slice(&u.0);
109        result
110    }
111}
112
113impl TryFrom<Uint320> for Uint256 {
114    type Error = crate::uint::TryFromIntError;
115
116    #[inline]
117    fn try_from(value: Uint320) -> Result<Self, Self::Error> {
118        if value.0[4] != 0 {
119            Err(crate::uint::TryFromIntError)
120        } else {
121            let mut result = Uint256::ZERO;
122            result.0.copy_from_slice(&value.0[..4]);
123            Ok(result)
124        }
125    }
126}
127
128impl TryFrom<Uint256> for Uint192 {
129    type Error = crate::uint::TryFromIntError;
130
131    #[inline]
132    fn try_from(value: Uint256) -> Result<Self, Self::Error> {
133        if value.0[3] != 0 {
134            Err(crate::uint::TryFromIntError)
135        } else {
136            let mut result = Uint192::ZERO;
137            result.0.copy_from_slice(&value.0[..3]);
138            Ok(result)
139        }
140    }
141}
142
143#[cfg(test)]
144mod tests {
145    use crate::{Uint256, Uint3072};
146
147    #[test]
148    fn test_overflow_bug() {
149        let a = Uint256::from_le_bytes([
150            255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
151            255, 255,
152        ]);
153        let b = Uint256::from_le_bytes([
154            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 71, 33, 0, 0, 0, 0, 0, 0,
155            0, 32, 0, 0, 0,
156        ]);
157        let c = a.overflowing_add(b).0;
158        let expected = [254, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 71, 33, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0];
159        assert_eq!(c.to_le_bytes(), expected);
160    }
161    #[rustfmt::skip]
162    #[test]
163    fn div_rem_u3072_bug() {
164        let r = Uint3072([
165            18446744073708447899, 18446744069733351423, 18446744073709551615, 18446744073709551615,
166            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
167            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
168            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
169            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
170            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
171            18446744073709551615, 18446744073642442751, 18446744073709551615, 18446744073709551615,
172            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
173            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
174            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
175            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
176            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
177        ]);
178        let newr = Uint3072([
179            0, 3976200192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
180            0, 67108864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
181        ]);
182        let expected = Uint3072([
183            18446744073709551614, 18446744073709551615, 18446744073709551615, 18446744073709551615,
184            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
185            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
186            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
187            18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615,
188            18446744073709551615, 18446744073709551615, 274877906943, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
189            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
190        ]);
191        assert_eq!(r / newr, expected);
192    }
193}