1use ark_ff::{BigInteger256, PrimeField};
2use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
3use malloc_size_of::MallocSizeOf;
4use rsexp::{OfSexp, SexpOf};
5use serde::{Deserialize, Serialize};
6
7#[derive(Clone, Debug)]
11pub struct InvalidBigInt;
12
13impl core::fmt::Display for InvalidBigInt {
14 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
15 write!(f, "InvalidBigInt")
16 }
17}
18
19impl From<InvalidBigInt> for String {
20 fn from(_: InvalidBigInt) -> Self {
21 "InvalidBigInt".to_string()
22 }
23}
24
25impl std::error::Error for InvalidBigInt {}
26#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, derive_more::From, derive_more::Into)]
29pub struct BigInt(BigInteger256);
30
31impl std::fmt::Debug for BigInt {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 let Self(bigint) = self;
34 f.write_fmt(format_args!("BigInt({:?})", bigint.0))
36 }
37}
38
39impl MallocSizeOf for BigInt {
40 fn size_of(&self, _ops: &mut malloc_size_of::MallocSizeOfOps) -> usize {
41 0
42 }
43}
44
45#[derive(Debug, thiserror::Error)]
46#[error("Invalid decimal number")]
47pub struct InvalidDecimalNumber;
48
49impl BigInt {
50 pub fn zero() -> Self {
51 mina_curves::pasta::Fp::from(0u64).into()
52 }
53
54 pub fn one() -> Self {
55 mina_curves::pasta::Fp::from(1u64).into()
56 }
57
58 pub fn to_field<F>(&self) -> Result<F, InvalidBigInt>
59 where
60 F: ark_ff::Field + From<BigInteger256>,
61 {
62 let Self(biginteger) = self;
63 Ok(F::from(*biginteger))
64 }
65
66 pub fn to_bytes(&self) -> [u8; 32] {
67 let mut bytes = Vec::with_capacity(32);
68 self.0.serialize_uncompressed(&mut bytes).unwrap(); bytes.try_into().unwrap()
70 }
71
72 pub fn from_bytes(bytes: [u8; 32]) -> Self {
73 let value = BigInteger256::deserialize_uncompressed(&bytes[..]).expect("Don't fail");
74 Self(value) }
76
77 pub fn from_decimal(s: &str) -> Result<Self, InvalidDecimalNumber> {
78 num_bigint::BigInt::<4>::parse_bytes(s.as_bytes(), 10)
79 .map(|num| {
80 let mut bytes = num.to_bytes_be().1;
81 bytes.reverse();
82 bytes.resize(32, 0); BigInt::from_bytes(bytes.try_into().unwrap())
84 })
85 .ok_or(InvalidDecimalNumber)
86 }
87
88 pub fn to_decimal(&self) -> String {
89 let bigint: num_bigint::BigUint = self.0.into();
90 bigint.to_string()
91 }
92}
93
94impl AsRef<BigInteger256> for BigInt {
95 fn as_ref(&self) -> &BigInteger256 {
96 let Self(biginteger) = self;
97 biginteger
98 }
99}
100
101impl From<mina_curves::pasta::Fp> for BigInt {
102 fn from(field: mina_curves::pasta::Fp) -> Self {
103 Self(field.into_bigint())
104 }
105}
106
107impl From<mina_curves::pasta::Fq> for BigInt {
108 fn from(field: mina_curves::pasta::Fq) -> Self {
109 Self(field.into_bigint())
110 }
111}
112
113impl From<&mina_curves::pasta::Fp> for BigInt {
114 fn from(field: &mina_curves::pasta::Fp) -> Self {
115 Self(field.into_bigint())
116 }
117}
118
119impl From<&mina_curves::pasta::Fq> for BigInt {
120 fn from(field: &mina_curves::pasta::Fq) -> Self {
121 Self(field.into_bigint())
122 }
123}
124
125impl TryFrom<BigInt> for mina_curves::pasta::Fp {
126 type Error = InvalidBigInt;
127
128 fn try_from(bigint: BigInt) -> Result<Self, Self::Error> {
129 bigint.to_field()
130 }
131}
132
133impl TryFrom<BigInt> for mina_curves::pasta::Fq {
134 type Error = InvalidBigInt;
135
136 fn try_from(bigint: BigInt) -> Result<Self, Self::Error> {
137 bigint.to_field()
138 }
139}
140
141impl TryFrom<&BigInt> for mina_curves::pasta::Fp {
142 type Error = InvalidBigInt;
143
144 fn try_from(bigint: &BigInt) -> Result<Self, Self::Error> {
145 bigint.to_field()
146 }
147}
148
149impl TryFrom<&BigInt> for mina_curves::pasta::Fq {
150 type Error = InvalidBigInt;
151
152 fn try_from(bigint: &BigInt) -> Result<Self, Self::Error> {
153 bigint.to_field()
154 }
155}
156
157impl OfSexp for BigInt {
158 fn of_sexp(s: &rsexp::Sexp) -> Result<Self, rsexp::IntoSexpError>
159 where
160 Self: Sized,
161 {
162 let bytes = s.extract_atom("BigInt")?;
163 let hex_str = std::str::from_utf8(bytes).map_err(|_| {
164 rsexp::IntoSexpError::StringConversionError {
165 err: format!("Expected hex string with 0x prefix, got {bytes:?}"),
166 }
167 })?;
168
169 let hex_str = hex_str.strip_prefix("0x").unwrap_or(hex_str);
170
171 let padded_hex = format!("{:0>64}", hex_str);
172
173 if padded_hex.len() != 64 {
174 return Err(rsexp::IntoSexpError::StringConversionError {
175 err: format!("Expected 64-character hex string, got {padded_hex:?}"),
176 });
177 }
178
179 let byte_vec: Vec<u8> = (0..padded_hex.len())
180 .step_by(2)
181 .map(|i| u8::from_str_radix(&padded_hex[i..i + 2], 16))
182 .rev()
183 .collect::<Result<Vec<u8>, _>>()
184 .map_err(|_| rsexp::IntoSexpError::StringConversionError {
185 err: format!("Failed to parse hex string: {padded_hex:?}"),
186 })?;
187
188 Ok(BigInt::from_bytes(byte_vec.try_into().unwrap()))
189 }
190}
191
192impl SexpOf for BigInt {
193 fn sexp_of(&self) -> rsexp::Sexp {
194 use std::fmt::Write;
195 let byte_vec = self.to_bytes();
196 let hex_str = byte_vec
197 .iter()
198 .rev()
199 .fold("0x".to_string(), |mut output, byte| {
200 let _ = write!(output, "{byte:02X}");
201 output
202 });
203
204 rsexp::Sexp::Atom(hex_str.into_bytes())
205 }
206}
207
208impl binprot::BinProtRead for BigInt {
209 fn binprot_read<R: std::io::Read + ?Sized>(r: &mut R) -> Result<Self, binprot::Error>
210 where
211 Self: Sized,
212 {
213 let mut bytes = [0u8; 32];
214 r.read_exact(&mut bytes)?;
215 Ok(Self::from_bytes(bytes))
216 }
217}
218
219impl binprot::BinProtWrite for BigInt {
220 fn binprot_write<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
221 w.write_all(&self.to_bytes())
222 }
223}
224
225impl Serialize for BigInt {
226 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
227 where
228 S: serde::Serializer,
229 {
230 if serializer.is_human_readable() {
231 let mut rev = self.to_bytes();
233 rev[..].reverse();
234 let mut hex = [0_u8; 32 * 2 + 2];
235 hex[..2].copy_from_slice(b"0x");
236 hex::encode_to_slice(rev, &mut hex[2..]).unwrap();
237 serializer.serialize_str(String::from_utf8_lossy(&hex).as_ref())
238 } else {
239 serializer.serialize_bytes(&self.to_bytes())
240 }
241 }
242}
243
244impl<'de> Deserialize<'de> for BigInt {
245 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
246 where
247 D: serde::Deserializer<'de>,
248 {
249 if deserializer.is_human_readable() {
250 struct V;
251 impl<'de> serde::de::Visitor<'de> for V {
252 type Value = Vec<u8>;
253
254 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
255 formatter.write_str("hex string or numeric string")
256 }
257
258 fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
259 where
260 E: serde::de::Error,
261 {
262 match v.strip_prefix("0x") {
263 Some(v) => hex::decode(v).map_err(|_| {
264 serde::de::Error::custom(format!("failed to decode hex str: {v}"))
265 }),
266 None => {
267 num_bigint::BigInt::<4>::parse_bytes(v.as_bytes(), 10)
269 .map(|num| {
270 let mut bytes = num.to_bytes_be().1;
271 bytes.reverse();
272 bytes.resize(32, 0); bytes.reverse();
274 bytes
275 })
276 .ok_or_else(|| {
277 serde::de::Error::custom(
278 "failed to parse decimal number".to_string(),
279 )
280 })
281 }
282 }
283 }
284
285 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
286 where
287 E: serde::de::Error,
288 {
289 self.visit_borrowed_str(v)
290 }
291 }
292 let mut v = deserializer.deserialize_str(V)?;
293 v.reverse();
294 v.try_into()
295 .map_err(|_| serde::de::Error::custom("failed to convert vec to array".to_string()))
296 } else {
297 struct V;
298 impl serde::de::Visitor<'_> for V {
299 type Value = [u8; 32];
300
301 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
302 formatter.write_str("sequence of 32 bytes")
303 }
304
305 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
306 where
307 E: serde::de::Error,
308 {
309 let v: [u8; 32] = v
310 .try_into()
311 .map_err(|_| serde::de::Error::custom("expecting 32 bytes".to_string()))?;
312 Ok(v)
313 }
314 }
315 deserializer.deserialize_bytes(V)
316 }
317 .map(Self::from_bytes)
318 }
319}
320
321impl mina_hasher::Hashable for BigInt {
322 type D = ();
323
324 fn to_roinput(&self) -> mina_hasher::ROInput {
325 mina_hasher::ROInput::new()
326 .append_field(self.to_field().expect("Failed to convert Hash into Fp"))
327 }
328
329 fn domain_string(_: Self::D) -> Option<String> {
330 None
331 }
332}
333
334#[cfg(feature = "openapi")]
336const _: () = {
337 use utoipa::{
338 openapi::schema::{Object, SchemaType, Type},
339 PartialSchema, ToSchema,
340 };
341 impl PartialSchema for BigInt {
342 fn schema() -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
343 Object::builder()
344 .schema_type(SchemaType::Type(Type::String))
345 .description(Some("Unsigned 256-bit integer as 0x-prefixed hex string"))
346 .pattern(Some(r"^0x[0-9a-fA-F]{64}$"))
347 .build()
348 .into()
349 }
350 }
351 impl ToSchema for BigInt {
352 fn name() -> std::borrow::Cow<'static, str> {
353 std::borrow::Cow::Borrowed("BigInt")
354 }
355 }
356};
357
358#[cfg(test)]
359mod tests {
360 use super::BigInt;
361 use binprot::{BinProtRead, BinProtWrite};
362
363 fn to_binprot(v: &BigInt) -> Vec<u8> {
364 let mut w = Vec::new();
365 v.binprot_write(&mut w).unwrap();
366 w
367 }
368
369 fn from_binprot(mut b: &[u8]) -> BigInt {
370 BigInt::binprot_read(&mut b).unwrap()
371 }
372
373 fn from_bytes<'a, I>(it: I) -> BigInt
377 where
378 I: IntoIterator<Item = &'a u8>,
379 I::IntoIter: Clone,
380 {
381 let mut bytes = [0; 32];
382 let it = it.into_iter().cycle();
383 bytes.iter_mut().zip(it).for_each(|(b, i)| *b = *i);
384 BigInt::from_bytes(bytes)
385 }
386
387 #[test]
388 fn serialize_bigint() {
389 let bigints = [
390 BigInt::from_bytes([0; 32]),
391 BigInt::from_bytes([1; 32]),
392 BigInt::from_bytes([0xff; 32]),
393 from_bytes(&[0, 1, 2, 3, 4]),
394 ];
395
396 for bigint in bigints {
397 let binprot = to_binprot(&bigint);
398 assert_eq!(binprot.as_slice(), bigint.to_bytes());
399 }
400 }
401
402 #[test]
403 fn deserialize_bigint() {
404 let bigints = [
405 BigInt::from_bytes([0; 32]),
406 BigInt::from_bytes([1; 32]),
407 BigInt::from_bytes([0xff; 32]),
408 from_bytes(&[0, 1, 2, 3, 4]),
409 ];
410
411 for bigint in bigints {
412 let deser: BigInt = from_binprot(&bigint.to_bytes());
413 assert_eq!(&bigint.0, &deser.0);
414 }
415 }
416
417 #[test]
418 fn to_json() {
419 let bigints = [
420 BigInt::from_bytes([0; 32]),
421 BigInt::from_bytes([1; 32]),
422 BigInt::from_bytes([0xff; 32]),
423 from_bytes(&[0, 1, 2, 3, 4]),
424 ];
425
426 for bigint in bigints {
427 let json = serde_json::to_string(&bigint).unwrap();
428 let mut v = bigint.to_bytes();
429 v.reverse();
430 let json_exp = format!(r#""0x{}""#, hex::encode(v));
431 assert_eq!(json, json_exp);
432 }
433 }
434
435 #[test]
436 fn from_json() {
437 let bigints = [
438 BigInt::from_bytes([0; 32]),
439 BigInt::from_bytes([1; 32]),
440 BigInt::from_bytes([0xff; 32]),
441 from_bytes(&[0, 1, 2, 3, 4]),
442 ];
443
444 for bigint in bigints {
445 let mut be = bigint.to_bytes();
446 be.reverse();
447 let json = format!(r#""0x{}""#, hex::encode(be.as_ref()));
448 let bigint_exp = serde_json::from_str(&json).unwrap();
449 assert_eq!(bigint, bigint_exp);
450 }
451 }
452
453 #[test]
454 fn from_numeric_string() {
455 let hex = "00000000000000000000000000000000000000000000000000000000075bcd15";
457 let deser: BigInt = serde_json::from_str(r#""123456789""#).unwrap();
458
459 let mut deser = deser.to_bytes();
460 deser.reverse();
461 let result_hex = hex::encode(deser);
462
463 assert_eq!(result_hex, hex.to_string());
464 }
465
466 #[test]
467 fn from_numeric_string_2() {
468 let rx =
469 r#""23298604903871047876308234794524469025218548053411207476198573374353464993732""#;
470 let s = r#""160863098041039391219472069845715442980741444645399750596310972807022542440""#;
471
472 let deser_rx: BigInt = serde_json::from_str(rx).unwrap();
473 let deser_s: BigInt = serde_json::from_str(s).unwrap();
474
475 println!("rx: {:?}", deser_rx);
476 println!("s: {:?}", deser_s);
477
478 let _ = deser_rx.to_field::<mina_curves::pasta::Fp>().unwrap();
479 println!("rx OK");
480 let _ = deser_s.to_field::<mina_curves::pasta::Fp>().unwrap();
481 println!("s OK");
482 }
483
484 use super::*;
485 use rsexp::Sexp;
486
487 #[test]
488 fn test_sexp_bigint() {
489 let hex_str = "0x248D179F4E92EA85C644CD99EF72187463B541D5F797943898C3D7A6CEEEC523";
490 let expected_array = [
491 0x98C3D7A6CEEEC523,
492 0x63B541D5F7979438,
493 0xC644CD99EF721874,
494 0x248D179F4E92EA85,
495 ];
496
497 let original_sexp = Sexp::Atom(hex_str.as_bytes().to_vec());
498
499 let result = BigInt::of_sexp(&original_sexp).expect("Failed to convert Sexp to BigInt");
500 let expected_result = BigInt(BigInteger256::new(expected_array));
501
502 assert_eq!(result, expected_result);
503
504 let produced_sexp = result.sexp_of();
505
506 assert_eq!(original_sexp, produced_sexp);
507 }
508}