@@ -49,90 +49,6 @@ impl<const P: usize> PrimeField<P> {
4949 is_prime ( P ) ;
5050 Self { value : value % P }
5151 }
52-
53- /// Computes euler criterion of the field element, i.e. Returns true if the element is a quadratic
54- /// residue (a square number) in the field.
55- ///
56- /// ## NOTES
57- /// By fermat's little theorem, (assume `is_congruent_to` is =)
58- /// x^(p-1) - 1 = 0 mod P
59- ///
60- /// All primes > 2 are odd, a.k.a P is odd, hence (P-1) is even.
61- /// So, we can split as follows:
62- /// (x^(p-1)/2 - 1)(x^(p-1)/2 + 1) = 0 mod P
63- /// or L * R = 0 mod P
64- ///
65- /// All quadratic residues are of the form (g^(2k)) where `g` is the
66- /// multiplicative generator and k is some natural number. All non-residues
67- /// on the other hand are of the form (g^(2k+1)).
68- ///
69- /// In case of QR, substitute x = g^2k
70- /// g^(2k)((p-1)/2) = 1 mod P
71- /// g^(p-1) = 1 mod P
72- /// which is true by fermat's little theorem
73- ///
74- /// In the other case, the same doesn't hold.
75- /// Hence, the case `L` should hold for all quadratic residues and is the
76- /// test for quadratic residuosity.
77- ///
78- /// More info here: https://www.youtube.com/watch?v=2IBPOI43jek
79- pub fn euler_criterion ( & self ) -> bool { self . pow ( ( P - 1 ) / 2 ) . value == 1 }
80-
81- /// Computes the square root of a field element using the [Tonelli-Shanks algorithm](https://en.wikipedia.org/wiki/Tonelli–Shanks_algorithm).
82- pub fn sqrt ( & self ) -> Option < ( Self , Self ) > {
83- if * self == Self :: ZERO {
84- return Some ( ( Self :: ZERO , Self :: ZERO ) ) ;
85- }
86-
87- assert ! ( self . euler_criterion( ) , "Element is not a quadratic residue" ) ;
88-
89- // First define the Q and S values for the prime number P.
90- let q: usize ;
91- let mut s = 1 ;
92- loop {
93- let lhs = P - 1 ;
94- let rhs = 2_usize . pow ( s) ;
95- let check_value = lhs % rhs;
96- if check_value == 0 {
97- s += 1 ;
98- } else {
99- s -= 1 ;
100- q = ( P - 1 ) / 2_usize . pow ( s) ;
101- break ;
102- }
103- }
104-
105- // Find a z that is not a quadratic residue
106- let mut z = Self :: new ( 2 ) ;
107- while z. euler_criterion ( ) {
108- z += Self :: ONE ;
109- }
110- let mut m = s;
111- let mut c = z. pow ( q) ;
112- let mut t = self . pow ( q) ;
113- let mut r = self . pow ( ( q + 1 ) / 2 ) ;
114- loop {
115- if t == Self :: ONE {
116- if -r < r {
117- return Some ( ( -r, r) ) ;
118- } else {
119- return Some ( ( r, -r) ) ;
120- }
121- }
122- // Repeatedly square to find a t^2^i = 1
123- let mut i = 1 ;
124- let mut t_pow = t. pow ( 2 ) ;
125- while t_pow != Self :: ONE {
126- t_pow = t_pow. pow ( 2 ) ;
127- i += 1 ;
128- }
129- let b = c. pow ( 2_usize . pow ( m - i - 1 ) ) ;
130- m = i;
131- c = b. pow ( 2 ) ;
132- t *= c;
133- r *= b;
134- }
135- }
13652}
13753
13854impl < const P : usize > const Finite for PrimeField < P > {
@@ -223,6 +139,91 @@ impl<const P: usize> Distribution<PrimeField<P>> for Standard {
223139 }
224140}
225141
142+ impl < const P : usize > FieldExt for PrimeField < P > {
143+ /// Computes euler criterion of the field element, i.e. Returns true if the element is a quadratic
144+ /// residue (a square number) in the field.
145+ ///
146+ /// ## NOTES
147+ /// By fermat's little theorem, (assume `is_congruent_to` is =)
148+ /// x^(p-1) - 1 = 0 mod P
149+ ///
150+ /// All primes > 2 are odd, a.k.a P is odd, hence (P-1) is even.
151+ /// So, we can split as follows:
152+ /// (x^(p-1)/2 - 1)(x^(p-1)/2 + 1) = 0 mod P
153+ /// or L * R = 0 mod P
154+ ///
155+ /// All quadratic residues are of the form (g^(2k)) where `g` is the
156+ /// multiplicative generator and k is some natural number. All non-residues
157+ /// on the other hand are of the form (g^(2k+1)).
158+ ///
159+ /// In case of QR, substitute x = g^2k
160+ /// g^(2k)((p-1)/2) = 1 mod P
161+ /// g^(p-1) = 1 mod P
162+ /// which is true by fermat's little theorem
163+ ///
164+ /// In the other case, the same doesn't hold.
165+ /// Hence, the case `L` should hold for all quadratic residues and is the
166+ /// test for quadratic residuosity.
167+ ///
168+ /// More info here: https://www.youtube.com/watch?v=2IBPOI43jek
169+ fn euler_criterion ( & self ) -> bool { self . pow ( ( P - 1 ) / 2 ) . value == 1 }
170+
171+ /// Computes the square root of a field element using the [Tonelli-Shanks algorithm](https://en.wikipedia.org/wiki/Tonelli–Shanks_algorithm).
172+ fn sqrt ( & self ) -> Option < ( Self , Self ) > {
173+ if * self == Self :: ZERO {
174+ return Some ( ( Self :: ZERO , Self :: ZERO ) ) ;
175+ }
176+
177+ assert ! ( self . euler_criterion( ) , "Element is not a quadratic residue" ) ;
178+
179+ // First define the Q and S values for the prime number P.
180+ let q: usize ;
181+ let mut s = 1 ;
182+ loop {
183+ let lhs = P - 1 ;
184+ let rhs = 2_usize . pow ( s) ;
185+ let check_value = lhs % rhs;
186+ if check_value == 0 {
187+ s += 1 ;
188+ } else {
189+ s -= 1 ;
190+ q = ( P - 1 ) / 2_usize . pow ( s) ;
191+ break ;
192+ }
193+ }
194+
195+ // Find a z that is not a quadratic residue
196+ let mut z = Self :: new ( 2 ) ;
197+ while z. euler_criterion ( ) {
198+ z += Self :: ONE ;
199+ }
200+ let mut m = s;
201+ let mut c = z. pow ( q) ;
202+ let mut t = self . pow ( q) ;
203+ let mut r = self . pow ( ( q + 1 ) / 2 ) ;
204+ loop {
205+ if t == Self :: ONE {
206+ if -r < r {
207+ return Some ( ( -r, r) ) ;
208+ } else {
209+ return Some ( ( r, -r) ) ;
210+ }
211+ }
212+ // Repeatedly square to find a t^2^i = 1
213+ let mut i = 1 ;
214+ let mut t_pow = t. pow ( 2 ) ;
215+ while t_pow != Self :: ONE {
216+ t_pow = t_pow. pow ( 2 ) ;
217+ i += 1 ;
218+ }
219+ let b = c. pow ( 2_usize . pow ( m - i - 1 ) ) ;
220+ m = i;
221+ c = b. pow ( 2 ) ;
222+ t *= c;
223+ r *= b;
224+ }
225+ }
226+ }
226227impl < const P : usize > From < u32 > for PrimeField < P > {
227228 fn from ( val : u32 ) -> Self { Self :: new ( val as usize ) }
228229}
0 commit comments