diff --git a/field/src/goldilocks_field.rs b/field/src/goldilocks_field.rs index 28d17a05..c1bb60b0 100644 --- a/field/src/goldilocks_field.rs +++ b/field/src/goldilocks_field.rs @@ -280,61 +280,6 @@ impl DivAssign for GoldilocksField { } } -impl GoldilocksField { - pub fn is_quadratic_residue(&self) -> bool { - if self.is_zero() { - return true; - } - // This is based on Euler's criterion. - let power = Self::NEG_ONE.to_canonical_biguint() / 2u8; - let exp = self.exp_biguint(&power); - if exp == Self::ONE { - return true; - } - if exp == Self::NEG_ONE { - return false; - } - panic!("Unreachable") - } - - pub fn sqrt(&self) -> Option { - if self.is_zero() { - Some(*self) - } else if self.is_quadratic_residue() { - let t = (Self::order() - BigUint::from(1u32)) - / (BigUint::from(2u32).pow(Self::TWO_ADICITY as u32)); - let mut z = Self::POWER_OF_TWO_GENERATOR; - let mut w = self.exp_biguint(&((t - BigUint::from(1u32)) / BigUint::from(2u32))); - let mut x = w * *self; - let mut b = x * w; - - let mut v = Self::TWO_ADICITY as usize; - - while !b.is_one() { - let mut k = 0usize; - let mut b2k = b; - while !b2k.is_one() { - b2k = b2k * b2k; - k += 1; - } - let j = v - k - 1; - w = z; - for _ in 0..j { - w = w * w; - } - - z = w * w; - b *= z; - x *= w; - v = k; - } - Some(x) - } else { - None - } - } -} - /// Fast addition modulo ORDER for x86-64. /// This function is marked unsafe for the following reasons: /// - It is only correct if x + y < 2**64 + ORDER = 0x1ffffffff00000001. diff --git a/field/src/types.rs b/field/src/types.rs index ac94bcfa..7130b7f5 100644 --- a/field/src/types.rs +++ b/field/src/types.rs @@ -427,6 +427,59 @@ pub trait Field: pub trait PrimeField: Field { fn to_canonical_biguint(&self) -> BigUint; + + fn is_quadratic_residue(&self) -> bool { + if self.is_zero() { + return true; + } + // This is based on Euler's criterion. + let power = Self::NEG_ONE.to_canonical_biguint() / 2u8; + let exp = self.exp_biguint(&power); + if exp == Self::ONE { + return true; + } + if exp == Self::NEG_ONE { + return false; + } + panic!("Unreachable") + } + + fn sqrt(&self) -> Option { + if self.is_zero() { + Some(*self) + } else if self.is_quadratic_residue() { + let t = (Self::order() - BigUint::from(1u32)) + / (BigUint::from(2u32).pow(Self::TWO_ADICITY as u32)); + let mut z = Self::POWER_OF_TWO_GENERATOR; + let mut w = self.exp_biguint(&((t - BigUint::from(1u32)) / BigUint::from(2u32))); + let mut x = w * *self; + let mut b = x * w; + + let mut v = Self::TWO_ADICITY as usize; + + while !b.is_one() { + let mut k = 0usize; + let mut b2k = b; + while !b2k.is_one() { + b2k = b2k * b2k; + k += 1; + } + let j = v - k - 1; + w = z; + for _ in 0..j { + w = w * w; + } + + z = w * w; + b *= z; + x *= w; + v = k; + } + Some(x) + } else { + None + } + } } /// A finite field of order less than 2^64. diff --git a/plonky2/examples/square_root.rs b/plonky2/examples/square_root.rs index 230b33aa..d8b3bd69 100644 --- a/plonky2/examples/square_root.rs +++ b/plonky2/examples/square_root.rs @@ -1,7 +1,7 @@ use std::marker::PhantomData; use anyhow::Result; -use plonky2::field::types::Field; +use plonky2::field::types::{Field, PrimeField}; use plonky2::hash::hash_types::RichField; use plonky2::iop::generator::{GeneratedValues, SimpleGenerator}; use plonky2::iop::target::Target; @@ -10,7 +10,6 @@ use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::CircuitConfig; use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use plonky2_field::extension::Extendable; -use plonky2_field::goldilocks_field::GoldilocksField; #[derive(Debug)] struct SquareRootGenerator, const D: usize> { @@ -19,18 +18,14 @@ struct SquareRootGenerator, const D: usize> { _phantom: PhantomData, } -// We implement specifically for the Goldilocks field because it's currently the only field with -// the sqrt() function written. -impl SimpleGenerator for SquareRootGenerator { +impl, const D: usize> SimpleGenerator + for SquareRootGenerator +{ fn dependencies(&self) -> Vec { vec![self.x_squared] } - fn run_once( - &self, - witness: &PartitionWitness, - out_buffer: &mut GeneratedValues, - ) { + fn run_once(&self, witness: &PartitionWitness, out_buffer: &mut GeneratedValues) { let x_squared = witness.get_target(self.x_squared); let x = x_squared.sqrt().unwrap();