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

chore: improve sqrt in stdlib and fuzz #5293

Closed
wants to merge 3 commits into from
Closed
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
28 changes: 24 additions & 4 deletions noir_stdlib/src/ec/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,13 @@ global C5 = 19103219067921713944291392827692070036145651957329286315305642004821
pub fn safe_inverse(x: Field) -> Field {
if x == 0 { 0 } else { 1 / x }
}

// Boolean indicating whether Field element is a square, i.e. whether there exists a y in Field s.t. x = y*y.
pub fn is_square(x: Field) -> bool {
let v = pow(x, 0 - 1 / 2);

v * (v - 1) == 0
let sqrt_x = sqrt_unconstrained(x);
sqrt_x * sqrt_x == x
}

// Power function of two Field arguments of arbitrary size.
// Adapted from std::field::pow_32.
pub fn pow(x: Field, y: Field) -> Field {
Expand All @@ -168,12 +169,19 @@ pub fn pow(x: Field, y: Field) -> Field {

r
}

pub fn sqrt(x: Field) -> Field {
let sqrt_x = sqrt_unconstrained(x);
assert_eq(sqrt_x * sqrt_x, x);
x
}

// Tonelli-Shanks algorithm for computing the square root of a Field element.
// Requires C1 = max{c: 2^c divides (p-1)}, where p is the order of Field
// as well as C3 = (C2 - 1)/2, where C2 = (p-1)/(2^c1),
// and C5 = ZETA^C2, where ZETA is a non-square element of Field.
// These are pre-computed above as globals.
pub fn sqrt(x: Field) -> Field {
unconstrained fn sqrt_unconstrained(x: Field) -> Field {
let mut z = pow(x, C3);
let mut t = z * z * x;
z *= x;
Expand All @@ -196,3 +204,15 @@ pub fn sqrt(x: Field) -> Field {

z
}

mod tests {
mod sqrt {
#[test]
fn returns_sqrt_of_squared_input(x: Field) {
let xx = x * x;
let sqrt_xx = crate::ec::sqrt_unconstrained(xx);
// The sqrt has two solutions `n` and `p - n` so we must check both.
assert((x == sqrt_xx) | (x == -sqrt_xx) );
}
}
}
Loading