1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//! Support for the [`ark-ff`](https://crates.io/crates/ark-ff) crate.
#![cfg(feature = "ark-ff")]
#![cfg_attr(has_doc_cfg, doc(cfg(feature = "ark-ff")))]

use crate::{ToFieldError, Uint};
use ark_ff::{biginteger::*, fields::models::*, PrimeField};

macro_rules! impl_from_ark {
    ($ark:ty, $bits:expr, $limbs:expr) => {
        impl From<$ark> for Uint<$bits, $limbs> {
            fn from(value: $ark) -> Self {
                Self::from_limbs(value.0)
            }
        }

        impl From<&$ark> for Uint<$bits, $limbs> {
            fn from(value: &$ark) -> Self {
                Self::from_limbs(value.0)
            }
        }

        impl From<Uint<$bits, $limbs>> for $ark {
            fn from(value: Uint<$bits, $limbs>) -> Self {
                Self(value.into_limbs())
            }
        }

        impl From<&Uint<$bits, $limbs>> for $ark {
            fn from(value: &Uint<$bits, $limbs>) -> Self {
                Self(value.into_limbs())
            }
        }
    };
}

impl_from_ark!(BigInteger64, 64, 1);
impl_from_ark!(BigInteger128, 128, 2);
impl_from_ark!(BigInteger256, 256, 4);
impl_from_ark!(BigInteger320, 320, 5);
impl_from_ark!(BigInteger384, 384, 6);
impl_from_ark!(BigInteger448, 448, 7);
impl_from_ark!(BigInteger768, 768, 12);
impl_from_ark!(BigInteger832, 832, 13);

macro_rules! impl_from_ark_field {
    ($field:ident, $params:ident, $bits:expr, $limbs:expr) => {
        impl<P: $params> From<$field<P>> for Uint<$bits, $limbs> {
            fn from(value: $field<P>) -> Self {
                value.into_repr().into()
            }
        }

        impl<P: $params> From<&$field<P>> for Uint<$bits, $limbs> {
            fn from(value: &$field<P>) -> Self {
                value.into_repr().into()
            }
        }

        impl<P: $params> TryFrom<Uint<$bits, $limbs>> for $field<P> {
            type Error = ToFieldError;

            fn try_from(value: Uint<$bits, $limbs>) -> Result<Self, ToFieldError> {
                Self::from_repr(value.into()).ok_or(ToFieldError::NotInField)
            }
        }

        impl<P: $params> TryFrom<&Uint<$bits, $limbs>> for $field<P> {
            type Error = ToFieldError;

            fn try_from(value: &Uint<$bits, $limbs>) -> Result<Self, ToFieldError> {
                Self::from_repr(value.into()).ok_or(ToFieldError::NotInField)
            }
        }
    };
}

impl_from_ark_field!(Fp64, Fp64Parameters, 64, 1);
impl_from_ark_field!(Fp256, Fp256Parameters, 256, 4);
impl_from_ark_field!(Fp320, Fp320Parameters, 320, 5);
impl_from_ark_field!(Fp384, Fp384Parameters, 384, 6);
impl_from_ark_field!(Fp448, Fp448Parameters, 448, 7);
impl_from_ark_field!(Fp768, Fp768Parameters, 768, 12);
impl_from_ark_field!(Fp832, Fp832Parameters, 832, 13);

#[cfg(test)]
mod tests {
    use super::*;
    use crate::aliases::U256;
    use ark_bn254::{Fq, FqParameters, Fr, FrParameters};
    use ark_ff::FpParameters;
    use proptest::proptest;

    macro_rules! test_roundtrip {
        ($ark:ty, $bits:expr, $limbs:expr) => {
            proptest!(|(value: Uint<$bits, $limbs>)| {
                let ark: $ark = value.into();
                let back: Uint<$bits, $limbs> = ark.into();
                assert_eq!(back, value);
            });
        }
    }

    #[test]
    fn test_roundtrip() {
        test_roundtrip!(BigInteger64, 64, 1);
        test_roundtrip!(BigInteger128, 128, 2);
        test_roundtrip!(BigInteger256, 256, 4);
        test_roundtrip!(BigInteger320, 320, 5);
        test_roundtrip!(BigInteger384, 384, 6);
        test_roundtrip!(BigInteger448, 448, 7);
        test_roundtrip!(BigInteger768, 768, 12);
        test_roundtrip!(BigInteger832, 832, 13);
    }

    #[test]
    fn test_fq_roundtrip() {
        let modulus: U256 = FqParameters::MODULUS.into();
        proptest!(|(value: U256)| {
            let value: U256 = value % modulus;
            let f: Fq = value.try_into().unwrap();
            let back: U256 = f.into();
            assert_eq!(back, value);
        });
    }

    #[test]
    fn test_fr_roundtrip() {
        let modulus: U256 = FrParameters::MODULUS.into();
        proptest!(|(value: U256)| {
            let value: U256 = value % modulus;
            let f: Fr = value.try_into().unwrap();
            let back: U256 = f.into();
            assert_eq!(back, value);
        });
    }
}