Skip to content

Commit

Permalink
chore: improve sqrt in stdlib and fuzz
Browse files Browse the repository at this point in the history
  • Loading branch information
TomAFrench committed Jun 19, 2024
1 parent 3ef3645 commit f533e56
Showing 1 changed file with 24 additions and 4 deletions.
28 changes: 24 additions & 4 deletions noir_stdlib/src/ec.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) );
}
}
}

0 comments on commit f533e56

Please sign in to comment.