Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Legendre Symbol #93

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/fp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,16 @@ const MODULUS: [u64; 6] = [
0x1a01_11ea_397f_e69a,
];

/// (p - 1) / 2 = 0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffffdcff7fffffffd555
const MODULUES_MINUS_ONE_OVER_TWO: [u64; 6] = [
0xdcff7fffffffd555,
0xf55ffff58a9ffff,
0xb39869507b587b12,
0xb23ba5c279c2895f,
0x258dd3db21a5d66b,
0xd0088f51cbff34d
];

/// INV = -(p^{-1} mod 2^64) mod 2^64
const INV: u64 = 0x89f3_fffc_fffc_fffd;

Expand Down Expand Up @@ -320,6 +330,21 @@ impl Fp {
res
}

#[inline]
/// Computes the legendre symbol of this element.
pub fn legendre_symbol(&self) -> isize {
let legendre = self.pow_vartime(&MODULUES_MINUS_ONE_OVER_TWO);
if legendre == Fp::zero() {
0
}
else if legendre == Fp::one() {
1
}
else {
-1
}
}

#[inline]
pub fn sqrt(&self) -> CtOption<Self> {
// We use Shank's method, as p = 3 (mod 4). This means
Expand Down Expand Up @@ -889,6 +914,16 @@ fn test_from_bytes() {
assert!(bool::from(Fp::from_bytes(&[0xff; 48]).is_none()));
}

#[test]
fn test_legendre() {
let four = Fp([4, 0, 0, 0, 0, 0]);

assert_eq!(Fp::zero().legendre_symbol(), 0);
assert_eq!(Fp::one().legendre_symbol(), 1);
assert_eq!((Fp::one() + Fp::one()).legendre_symbol(), -1);
assert_eq!(four.legendre_symbol(), 1);
}

#[test]
fn test_sqrt() {
// a = 4
Expand Down
33 changes: 33 additions & 0 deletions src/scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,15 @@ const MODULUS: Scalar = Scalar([
0x73ed_a753_299d_7d48,
]);

/// Constant representing (q - 1) / 2
/// (q - 1) / 2 = 0x39f6d3a994cebea4199cec0404d0ec02a9ded2017fff2dff7fffffff80000000
const MODULUES_MINUS_ONE_OVER_TWO: [u64; 4] = [
0x7fffffff80000000,
0xa9ded2017fff2dff,
0x199cec0404d0ec02,
0x39f6d3a994cebea4
];

/// The modulus as u32 limbs.
#[cfg(all(feature = "bits", not(target_pointer_width = "64")))]
const MODULUS_LIMBS_32: [u32; 8] = [
Expand Down Expand Up @@ -343,6 +352,20 @@ impl Scalar {
Scalar::montgomery_reduce(r0, r1, r2, r3, r4, r5, r6, r7)
}

/// Computes the legendre symbol of this element.
pub fn legendre_symbol(&self) -> isize {
let legendre = self.pow(&MODULUES_MINUS_ONE_OVER_TWO);
if legendre == Scalar::zero() {
0
}
else if legendre == Scalar::one() {
1
}
else {
-1
}
}

/// Computes the square root of this element, if it exists.
pub fn sqrt(&self) -> CtOption<Self> {
// Tonelli-Shank's algorithm for q mod 16 = 1
Expand Down Expand Up @@ -1174,6 +1197,16 @@ fn test_invert_is_pow() {
}
}

#[test]
fn test_legendre() {
let five = Scalar([5, 0, 0, 0]);

assert_eq!(Scalar::zero().legendre_symbol(), 0);
assert_eq!(Scalar::one().legendre_symbol(), 1);
assert_eq!((Scalar::one() + Scalar::one()).legendre_symbol(), 1);
assert_eq!(five.legendre_symbol(), -1);
}

#[test]
fn test_sqrt() {
{
Expand Down