Browse Source

utils: implement Legendre Symbol for Fp

Lennart Braun 2 years ago
parent
commit
4a777c4c69
1 changed files with 90 additions and 0 deletions
  1. 90 0
      utils/src/field.rs

+ 90 - 0
utils/src/field.rs

@@ -28,6 +28,40 @@ pub trait FromHash {
 }
 }
 
 
 impl Fp {
 impl Fp {
+    // (p-1)/ 2 = 0b11111111111111111111111111111111111111111111111111111111111 00 1
+    // 00000000000000000000000000000000000000000000000000000000000000000
+    // (59x '1', 2x '9', 1x '1', 65x '0')
+
+    /// Compute the Legendre Symbol (p/a)
+    pub fn legendre_symbol(a: Self) -> Self {
+        // handle 65x even
+        let mut x = a;
+        for _ in 0..65 {
+            x = x.square();
+        }
+
+        // handle 1x odd
+        let mut y = x;
+        x = x.square();
+
+        // handle 2x even
+        x = x.square();
+        x = x.square();
+
+        // handle 59x odd
+        for _ in 0..58 {
+            y = x * y;
+            x = x.square();
+        }
+        let z = x * y;
+
+        assert!(
+            (z == -Fp::ONE || z == Fp::ONE || z == Fp::ZERO) && (z != Fp::ZERO || a == Fp::ZERO)
+        );
+
+        z
+    }
+
     fn from_xof(xof: &mut blake3::OutputReader) -> Self {
     fn from_xof(xof: &mut blake3::OutputReader) -> Self {
         assert_eq!(Self::NUM_BITS, 128);
         assert_eq!(Self::NUM_BITS, 128);
         loop {
         loop {
@@ -82,3 +116,59 @@ impl FromHash for Fp {
         Self::from_xof(&mut xof)
         Self::from_xof(&mut xof)
     }
     }
 }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_lagrange_symbol() {
+        const INPUTS: [u128; 20] = [
+            0,
+            1,
+            2,
+            35122421919063474048031845924062067909,
+            61212839083344548205786527436063227216,
+            108886203898319005744174078164860101674,
+            112160854746794802432264095652132979488,
+            142714630766673706362679167860844911107,
+            144328356835331043954321695814395383527,
+            149714699338443771695584577213555322897,
+            162837698983268132975860461485836731565,
+            185920817468766357617527011469055960606,
+            207479253861772423381237297118907360324,
+            220976947578297059190439898234224764278,
+            225624737240143795963751467909724695007,
+            230022448309092634504744292546382561960,
+            284649339713848098295138218361935151979,
+            293856596737329296797721884860187281734,
+            315840344961299616831836711745928570660,
+            340282366920938462946865773367900766208,
+        ];
+        const OUTPUTS: [u128; 20] = [
+            0,
+            1,
+            1,
+            1,
+            1,
+            1,
+            340282366920938462946865773367900766208,
+            1,
+            1,
+            340282366920938462946865773367900766208,
+            1,
+            340282366920938462946865773367900766208,
+            1,
+            1,
+            1,
+            340282366920938462946865773367900766208,
+            340282366920938462946865773367900766208,
+            1,
+            1,
+            1,
+        ];
+        for (&x, &y) in INPUTS.iter().zip(OUTPUTS.iter()) {
+            assert_eq!(Fp::legendre_symbol(Fp::from_u128(x)), Fp::from_u128(y));
+        }
+    }
+}