1use std::cmp::Ordering::{Equal, Greater, Less};
2
3use ark_ff::{fields::arithmetic::InvalidBigInt, BigInteger256, Field};
4use mina_p2p_messages::v2::BlockTimeTimeStableV1;
5use rand::Rng;
6
7use crate::proofs::{
8 field::FieldWitness, to_field_elements::ToFieldElements, transaction::Check, witness::Witness,
9};
10
11#[derive(Copy, Clone, Debug, PartialEq, Eq)]
12pub enum Sgn {
13 Pos,
14 Neg,
15}
16
17impl Sgn {
18 pub fn is_pos(&self) -> bool {
19 match self {
20 Sgn::Pos => true,
21 Sgn::Neg => false,
22 }
23 }
24
25 pub fn negate(&self) -> Self {
26 match self {
27 Sgn::Pos => Sgn::Neg,
28 Sgn::Neg => Sgn::Pos,
29 }
30 }
31
32 pub fn to_field<F: FieldWitness>(&self) -> F {
33 match self {
34 Sgn::Pos => F::one(),
35 Sgn::Neg => F::one().neg(),
36 }
37 }
38}
39
40pub trait Magnitude
41where
42 Self: Sized + PartialOrd + Copy,
43{
44 const NBITS: usize;
45
46 fn abs_diff(&self, rhs: &Self) -> Self;
47 fn wrapping_add(&self, rhs: &Self) -> Self;
48 fn wrapping_mul(&self, rhs: &Self) -> Self;
49 fn wrapping_sub(&self, rhs: &Self) -> Self;
50 fn checked_add(&self, rhs: &Self) -> Option<Self>;
51 fn checked_mul(&self, rhs: &Self) -> Option<Self>;
52 fn checked_sub(&self, rhs: &Self) -> Option<Self>;
53 fn checked_div(&self, rhs: &Self) -> Option<Self>;
54 fn checked_rem(&self, rhs: &Self) -> Option<Self>;
55
56 fn is_zero(&self) -> bool;
57 fn zero() -> Self;
58
59 fn add_flagged(&self, rhs: &Self) -> (Self, bool) {
60 let z = self.wrapping_add(rhs);
61 (z, z < *self)
62 }
63
64 fn sub_flagged(&self, rhs: &Self) -> (Self, bool) {
65 (self.wrapping_sub(rhs), self < rhs)
66 }
67
68 fn to_field<F: FieldWitness>(&self) -> F;
69 fn of_field<F: FieldWitness>(field: F) -> Self;
70}
71
72pub trait MinMax {
74 fn min() -> Self;
75 fn max() -> Self;
76}
77
78#[derive(Copy, Clone, Debug, PartialEq, Eq)]
79pub struct Signed<T: Magnitude> {
80 pub magnitude: T,
81 pub sgn: Sgn,
82}
83
84impl<T> Signed<T>
85where
86 T: Magnitude + PartialOrd + Ord + Clone,
87{
88 const NBITS: usize = T::NBITS;
89
90 pub fn create(magnitude: T, sgn: Sgn) -> Self {
91 Self {
92 magnitude,
93 sgn: if magnitude.is_zero() { Sgn::Pos } else { sgn },
94 }
95 }
96
97 pub fn of_unsigned(magnitude: T) -> Self {
98 Self::create(magnitude, Sgn::Pos)
99 }
100
101 pub fn negate(&self) -> Self {
102 if self.magnitude.is_zero() {
103 Self::zero()
104 } else {
105 Self {
106 magnitude: self.magnitude,
107 sgn: self.sgn.negate(),
108 }
109 }
110 }
111
112 pub fn is_pos(&self) -> bool {
113 matches!(self.sgn, Sgn::Pos)
114 }
115
116 pub fn is_non_neg(&self) -> bool {
118 matches!(self.sgn, Sgn::Pos)
119 }
120
121 pub fn is_neg(&self) -> bool {
122 matches!(self.sgn, Sgn::Neg)
123 }
124
125 pub fn zero() -> Self {
127 Self {
128 magnitude: T::zero(),
129 sgn: Sgn::Pos,
130 }
131 }
132
133 pub fn is_zero(&self) -> bool {
134 self.magnitude.is_zero() }
136
137 pub fn add(&self, rhs: &Self) -> Option<Self> {
139 let (magnitude, sgn) = if self.sgn == rhs.sgn {
140 let magnitude = self.magnitude.checked_add(&rhs.magnitude)?;
141 let sgn = self.sgn;
142
143 (magnitude, sgn)
144 } else {
145 let sgn = match self.magnitude.cmp(&rhs.magnitude) {
146 Less => rhs.sgn,
147 Greater => self.sgn,
148 Equal => return Some(Self::zero()),
149 };
150 let magnitude = self.magnitude.abs_diff(&rhs.magnitude);
151
152 (magnitude, sgn)
153 };
154
155 Some(Self::create(magnitude, sgn))
156 }
157
158 pub fn add_flagged(&self, rhs: Self) -> (Self, bool) {
159 match (self.sgn, rhs.sgn) {
160 (Sgn::Neg, sgn @ Sgn::Neg) | (Sgn::Pos, sgn @ Sgn::Pos) => {
161 let (magnitude, overflow) = self.magnitude.add_flagged(&rhs.magnitude);
162 (Self { magnitude, sgn }, overflow)
163 }
164 (Sgn::Pos, Sgn::Neg) | (Sgn::Neg, Sgn::Pos) => {
165 let sgn = match self.magnitude.cmp(&rhs.magnitude) {
166 Less => rhs.sgn,
167 Greater => self.sgn,
168 Equal => Sgn::Pos,
169 };
170 let magnitude = self.magnitude.abs_diff(&rhs.magnitude);
171 (Self { magnitude, sgn }, false)
172 }
173 }
174 }
175}
176
177impl Signed<Amount> {
178 pub fn to_fee(self) -> Signed<Fee> {
179 let Self { magnitude, sgn } = self;
180
181 Signed {
182 magnitude: Fee(magnitude.0),
183 sgn,
184 }
185 }
186}
187
188impl<T> Signed<T>
189where
190 T: Magnitude + PartialOrd + Ord + Clone,
191 rand::distributions::Standard: rand::distributions::Distribution<T>,
192{
193 pub fn gen() -> Self {
194 let mut rng = rand::thread_rng();
195
196 let magnitude: T = rng.gen();
197 let sgn = if rng.gen::<bool>() {
198 Sgn::Pos
199 } else {
200 Sgn::Neg
201 };
202
203 Self::create(magnitude, sgn)
204 }
205}
206
207impl Amount {
208 const UNIT_TO_NANO: u64 = 1_000_000_000;
210
211 pub fn of_fee(fee: &Fee) -> Self {
212 Self(fee.0)
213 }
214
215 pub fn add_signed_flagged(&self, rhs: Signed<Self>) -> (Self, bool) {
216 if let Sgn::Pos = rhs.sgn {
217 self.add_flagged(&rhs.magnitude)
218 } else {
219 self.sub_flagged(&rhs.magnitude)
220 }
221 }
222
223 pub fn to_nanomina_int(&self) -> Self {
224 *self
225 }
226
227 pub fn to_mina_int(&self) -> Self {
228 Self(self.0.checked_div(Self::UNIT_TO_NANO).unwrap())
229 }
230
231 pub fn of_mina_int_exn(int: u64) -> Self {
232 Self::from_u64(int).scale(Self::UNIT_TO_NANO).unwrap()
233 }
234
235 pub fn of_nanomina_int_exn(int: u64) -> Self {
236 Self::from_u64(int)
237 }
238}
239
240impl Balance {
241 pub fn sub_amount(&self, amount: Amount) -> Option<Self> {
242 self.0.checked_sub(amount.0).map(Self)
243 }
244
245 pub fn add_amount(&self, amount: Amount) -> Option<Self> {
246 self.0.checked_add(amount.0).map(Self)
247 }
248
249 pub fn add_signed_flagged(&self, rhs: Signed<Self>) -> (Self, bool) {
250 if let Sgn::Pos = rhs.sgn {
251 self.add_flagged(&rhs.magnitude)
252 } else {
253 self.sub_flagged(&rhs.magnitude)
254 }
255 }
256
257 pub fn add_signed_amount_flagged(&self, rhs: Signed<Amount>) -> (Self, bool) {
258 let rhs = Signed {
259 magnitude: Balance::from_u64(rhs.magnitude.0),
260 sgn: rhs.sgn,
261 };
262
263 if let Sgn::Pos = rhs.sgn {
264 self.add_flagged(&rhs.magnitude)
265 } else {
266 self.sub_flagged(&rhs.magnitude)
267 }
268 }
269
270 pub fn to_amount(self) -> Amount {
271 Amount(self.0)
272 }
273
274 pub fn from_mina(amount: u64) -> Option<Self> {
276 amount.checked_mul(1_000_000_000).map(Self::from_u64)
277 }
278
279 pub fn of_nanomina_int_exn(int: u64) -> Self {
280 Self::from_u64(int)
281 }
282}
283
284impl Fee {
285 pub const fn of_nanomina_int_exn(int: u64) -> Self {
286 Self::from_u64(int)
287 }
288}
289
290impl Index {
291 pub fn incr(&self) -> Self {
293 Self(self.0.wrapping_add(1))
294 }
295}
296
297impl Nonce {
298 pub fn incr(&self) -> Self {
300 Self(self.0.wrapping_add(1))
301 }
302
303 pub fn succ(&self) -> Self {
304 self.incr()
305 }
306
307 pub fn add_signed_flagged(&self, rhs: Signed<Self>) -> (Self, bool) {
308 if let Sgn::Pos = rhs.sgn {
309 self.add_flagged(&rhs.magnitude)
310 } else {
311 self.sub_flagged(&rhs.magnitude)
312 }
313 }
314
315 pub fn between(&self, low: &Self, high: &Self) -> bool {
317 low <= self && self <= high
318 }
319}
320
321impl BlockTime {
322 pub fn add(&self, span: BlockTimeSpan) -> Self {
323 Self(self.0.checked_add(span.0).unwrap())
324 }
325
326 pub fn sub(&self, span: BlockTimeSpan) -> Self {
327 Self(self.0.checked_sub(span.0).unwrap())
328 }
329
330 pub fn diff(&self, other: Self) -> BlockTimeSpan {
331 BlockTimeSpan(self.0 - other.0)
332 }
333
334 pub fn to_span_since_epoch(&self) -> BlockTimeSpan {
335 let Self(ms) = self;
336 BlockTimeSpan(*ms)
337 }
338
339 pub fn of_span_since_epoch(span: BlockTimeSpan) -> Self {
340 let BlockTimeSpan(ms) = span;
341 Self(ms)
342 }
343}
344
345impl From<BlockTimeTimeStableV1> for BlockTime {
346 fn from(bt: BlockTimeTimeStableV1) -> Self {
347 Self(bt.0 .0 .0)
348 }
349}
350
351impl BlockTimeSpan {
352 pub fn of_ms(ms: u64) -> Self {
353 Self(ms)
354 }
355 pub fn to_ms(&self) -> u64 {
356 let Self(ms) = self;
357 *ms
358 }
359}
360
361impl Slot {
362 pub fn incr(&self) -> Self {
364 Self(self.0.wrapping_add(1))
365 }
366
367 pub fn add(&self, other: SlotSpan) -> Self {
368 let SlotSpan(other) = other;
369 Self(self.0.checked_add(other).unwrap())
370 }
371
372 pub fn succ(&self) -> Self {
373 self.incr()
374 }
375
376 pub fn gen_small() -> Self {
377 let mut rng = rand::thread_rng();
378 Self(rng.gen::<u32>() % 10_000)
379 }
380}
381
382macro_rules! impl_number {
383 (32: { $($name32:ident,)* }, 64: { $($name64:ident,)* },) => {
384 $(impl_number!({$name32, u32, as_u32, from_u32, next_u32, append_u32},);)+
385 $(impl_number!({$name64, u64, as_u64, from_u64, next_u64, append_u64},);)+
386 };
387 ($({ $name:ident, $inner:ty, $as_name:ident, $from_name:ident, $next_name:ident, $append_name:ident },)*) => ($(
388 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize)]
389 pub struct $name(pub(super) $inner);
390
391 impl std::fmt::Debug for $name {
392 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
393 f.write_fmt(format_args!("{}({:?})", stringify!($name), self.0))
394 }
395 }
396
397 impl Magnitude for $name {
398 const NBITS: usize = Self::NBITS;
399
400 fn zero() -> Self {
401 Self(0)
402 }
403
404 fn is_zero(&self) -> bool {
405 self.0 == 0
406 }
407
408 fn wrapping_add(&self, rhs: &Self) -> Self {
409 Self(self.0.wrapping_add(rhs.0))
410 }
411
412 fn wrapping_mul(&self, rhs: &Self) -> Self {
413 Self(self.0.wrapping_mul(rhs.0))
414 }
415
416 fn wrapping_sub(&self, rhs: &Self) -> Self {
417 Self(self.0.wrapping_sub(rhs.0))
418 }
419
420 fn checked_add(&self, rhs: &Self) -> Option<Self> {
421 self.0.checked_add(rhs.0).map(Self)
422 }
423
424 fn checked_mul(&self, rhs: &Self) -> Option<Self> {
425 self.0.checked_mul(rhs.0).map(Self)
426 }
427
428 fn checked_sub(&self, rhs: &Self) -> Option<Self> {
429 self.0.checked_sub(rhs.0).map(Self)
430 }
431
432 fn checked_div(&self, rhs: &Self) -> Option<Self> {
433 self.0.checked_div(rhs.0).map(Self)
434 }
435
436 fn checked_rem(&self, rhs: &Self) -> Option<Self> {
437 self.0.checked_rem(rhs.0).map(Self)
438 }
439
440 fn abs_diff(&self, rhs: &Self) -> Self {
441 Self(self.0.abs_diff(rhs.0))
442 }
443
444 fn to_field<F: FieldWitness>(&self) -> F {
445 self.to_field()
446 }
447
448 fn of_field<F: FieldWitness>(field: F) -> Self {
449 let amount: BigInteger256 = field.into();
450 let amount: $inner = amount.to_64x4()[0].try_into().unwrap();
451
452 Self::$from_name(amount)
453 }
454 }
455
456 impl MinMax for $name {
457 fn min() -> Self { Self(0) }
458 fn max() -> Self { Self(<$inner>::MAX) }
459 }
460
461 impl $name {
462 pub const NBITS: usize = <$inner>::BITS as usize;
463
464 pub fn $as_name(&self) -> $inner {
465 self.0
466 }
467
468 pub const fn $from_name(value: $inner) -> Self {
469 Self(value)
470 }
471
472 pub const fn scale(&self, n: $inner) -> Option<Self> {
474 match self.0.checked_mul(n) {
475 Some(n) => Some(Self(n)),
476 None => None
477 }
478 }
479
480 pub fn min() -> Self {
481 <Self as MinMax>::min()
482 }
483
484 pub fn max() -> Self {
485 <Self as MinMax>::max()
486 }
487
488 pub fn of_mina_string_exn(input: &str) -> Self {
490 const PRECISION: usize = 9;
491
492 let mut s = String::with_capacity(input.len() + 9);
493
494 if !input.contains('.') {
495 let append = "000000000";
496 assert_eq!(append.len(), PRECISION);
497
498 s.push_str(input);
499 s.push_str(append);
500 } else {
501 let (whole, decimal) = {
502 let mut splitted = input.split('.');
503 let whole = splitted.next().unwrap();
504 let decimal = splitted.next().unwrap();
505 assert!(splitted.next().is_none(), "Currency.of_mina_string_exn: Invalid currency input");
506 (whole, decimal)
507 };
508
509 let decimal_length = decimal.len();
510
511 if decimal_length > PRECISION {
512 s.push_str(whole);
513 s.push_str(&decimal[0..PRECISION]);
514 } else {
515 s.push_str(whole);
516 s.push_str(decimal);
517 for _ in 0..PRECISION - decimal_length {
518 s.push('0');
519 }
520 }
521 }
522
523 let n = s.parse::<$inner>().unwrap();
524 Self(n)
525 }
526
527 pub fn to_bits(&self) -> [bool; <$inner>::BITS as usize] {
528 use crate::proofs::transaction::legacy_input::bits_iter;
529
530 let mut iter = bits_iter::<$inner, { <$inner>::BITS as usize }>(self.0);
531 std::array::from_fn(|_| iter.next().unwrap())
532 }
533
534 pub fn to_field<F: Field + TryFrom<BigInteger256, Error = InvalidBigInt>>(&self) -> F {
535 let int = self.0 as u64;
536 F::from(int)
537 }
538 }
539
540 impl rand::distributions::Distribution<$name> for rand::distributions::Standard {
541 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> $name {
542 $name(rng.$next_name())
543 }
544 }
545
546 impl crate::ToInputs for $name {
547 fn to_inputs(&self, inputs: &mut poseidon::hash::Inputs) {
548 inputs.$append_name(self.0);
549 }
550 }
551
552 impl<F: FieldWitness> ToFieldElements<F> for $name {
553 fn to_field_elements(&self, fields: &mut Vec<F>) {
554 fields.push(self.to_field());
555 }
556 }
557
558 impl<F: FieldWitness> Check<F> for $name {
559 fn check(&self, witnesses: &mut Witness<F>) {
560 use crate::proofs::transaction::scalar_challenge::to_field_checked_prime;
561
562 const NBITS: usize = <$inner>::BITS as usize;
563
564 let number: $inner = self.$as_name();
565 assert_eq!(NBITS, std::mem::size_of_val(&number) * 8);
566
567 let number: F = number.into();
568 to_field_checked_prime::<F, NBITS>(number, witnesses);
569 }
570 }
571
572 )+)
573}
574
575impl_number!(
576 32: { Length, Slot, Nonce, Index, SlotSpan, TxnVersion, Epoch, },
577 64: { Amount, Balance, Fee, BlockTime, BlockTimeSpan, N, },
578);