Support unsigned integral square root computations.

This commit is contained in:
2018-11-30 11:28:20 -08:00
parent 0ec5f90d8e
commit 2b9f5ea7a2
13 changed files with 13156 additions and 20 deletions

View File

@@ -3,9 +3,11 @@ base_impls!(U192, 3);
random_impls!(U192, UniformU192); random_impls!(U192, UniformU192);
multiply_impls!(U192, U384); multiply_impls!(U192, U384);
shift_impls!(U192, 3); shift_impls!(U192, 3);
subtraction_impls!(U192, 3);
conversion_impls!(U192, U256); conversion_impls!(U192, U256);
conversion_impls!(U192, U384); conversion_impls!(U192, U384);
conversion_impls!(U192, U1024); conversion_impls!(U192, U1024);
sqrt_impls!(U192);
addition_impls!(U256, U320); addition_impls!(U256, U320);
base_impls!(U256, 4); base_impls!(U256, 4);
random_impls!(U256, UniformU256); random_impls!(U256, UniformU256);
@@ -24,6 +26,7 @@ conversion_impls!(U256, U512);
conversion_impls!(U256, U576); conversion_impls!(U256, U576);
conversion_impls!(U256, U2048); conversion_impls!(U256, U2048);
conversion_impls!(U256, U3072); conversion_impls!(U256, U3072);
sqrt_impls!(U256);
prime_gen_impls!(U256); prime_gen_impls!(U256);
addition_impls!(U320, U384); addition_impls!(U320, U384);
base_impls!(U320, 5); base_impls!(U320, 5);
@@ -92,6 +95,7 @@ subtraction_impls!(U1024, 16);
conversion_impls!(U1024, U1088); conversion_impls!(U1024, U1088);
conversion_impls!(U1024, U2048); conversion_impls!(U1024, U2048);
conversion_impls!(U1024, U2112); conversion_impls!(U1024, U2112);
sqrt_impls!(U1024);
prime_gen_impls!(U1024); prime_gen_impls!(U1024);
addition_impls!(U1088, U1152); addition_impls!(U1088, U1152);
base_impls!(U1088, 17); base_impls!(U1088, 17);
@@ -152,6 +156,7 @@ subtraction_impls!(U2048, 32);
conversion_impls!(U2048, U2112); conversion_impls!(U2048, U2112);
conversion_impls!(U2048, U4096); conversion_impls!(U2048, U4096);
conversion_impls!(U2048, U4160); conversion_impls!(U2048, U4160);
sqrt_impls!(U2048);
prime_gen_impls!(U2048); prime_gen_impls!(U2048);
addition_impls!(U2112, U2176); addition_impls!(U2112, U2176);
base_impls!(U2112, 33); base_impls!(U2112, 33);
@@ -184,6 +189,7 @@ subtraction_impls!(U3072, 48);
conversion_impls!(U3072, U3136); conversion_impls!(U3072, U3136);
conversion_impls!(U3072, U6144); conversion_impls!(U3072, U6144);
conversion_impls!(U3072, U6208); conversion_impls!(U3072, U6208);
sqrt_impls!(U3072);
addition_impls!(U3136, U3200); addition_impls!(U3136, U3200);
base_impls!(U3136, 49); base_impls!(U3136, 49);
random_impls!(U3136, UniformU3136); random_impls!(U3136, UniformU3136);
@@ -608,6 +614,7 @@ mod tests {
use super::super::*; use super::super::*;
use testing::{build_test_path,run_test}; use testing::{build_test_path,run_test};
generate_sub_tests!(U192, u192);
generate_sub_tests!(U256, u256); generate_sub_tests!(U256, u256);
generate_sub_tests!(U320, u320); generate_sub_tests!(U320, u320);
generate_sub_tests!(U512, u512); generate_sub_tests!(U512, u512);
@@ -901,6 +908,16 @@ mod tests {
generate_square_tests!(ignore U8192, u8192, U16384); generate_square_tests!(ignore U8192, u8192, U16384);
generate_square_tests!(ignore U15360, u15360, U30720); generate_square_tests!(ignore U15360, u15360, U30720);
} }
mod sqrt {
use super::super::*;
use testing::{build_test_path,run_test};
generate_sqrt_tests!(U192, u192);
generate_sqrt_tests!(U256, u256);
generate_sqrt_tests!(U1024, u1024);
generate_sqrt_tests!(U2048, u2048);
generate_sqrt_tests!(U3072, u3072);
}
mod barrett_modsq { mod barrett_modsq {
use super::super::*; use super::super::*;
use testing::{build_test_path,run_test}; use testing::{build_test_path,run_test};

View File

@@ -44,6 +44,8 @@ mod rand;
#[macro_use] #[macro_use]
mod shifts; mod shifts;
#[macro_use] #[macro_use]
mod sqrt;
#[macro_use]
mod square; mod square;
#[macro_use] #[macro_use]
mod sub; mod sub;
@@ -56,6 +58,7 @@ pub use self::modmul::ModMul;
pub use self::modsq::ModSquare; pub use self::modsq::ModSquare;
pub use self::primes::PrimeGen; pub use self::primes::PrimeGen;
pub use self::square::Square; pub use self::square::Square;
pub use self::sqrt::SquareRoot;
pub(crate) use self::add::unsafe_addition; pub(crate) use self::add::unsafe_addition;

66
src/unsigned/sqrt.rs Normal file
View File

@@ -0,0 +1,66 @@
pub trait SquareRoot {
/// Compute the integer square root of the given value. The integer square
/// root is the value Z such that the real root R satisfies Z <= R < Z+1.
fn sqrt(&self) -> Self;
}
macro_rules! sqrt_impls
{
($name: ident) => {
impl SquareRoot for $name {
fn sqrt(&self) -> Self {
let mut num = self.clone();
let mut res = $name::zero();
let mut bit = $name::from(1u64) << ($name::bit_length() - 2);
while bit > num {
bit >>= 2;
}
while !bit.is_zero() {
let mut resbit = res.clone();
resbit += &bit;
if num >= resbit {
num -= resbit;
res += &bit << 1;
}
res >>= 1;
bit >>= 2;
}
res
}
}
}
}
#[cfg(test)]
macro_rules! generate_sqrt_tests {
($name: ident, $lname: ident) => {
#[test]
fn $lname() {
generate_sqrt_tests!(body $name, $lname);
}
};
(ignore $name: ident, $lname: ident) => {
#[test]
#[ignore]
fn $lname() {
generate_sqrt_tests!(body $name, $lname);
}
};
(body $name: ident, $lname: ident) => {
let fname = build_test_path("sqrt", stringify!($name));
run_test(fname.to_string(), 2, |case| {
let (neg0, abytes) = case.get("a").unwrap();
let (neg1, rbytes) = case.get("r").unwrap();
assert!(!neg0 && !neg1);
let a = $name::from_bytes(abytes);
let r = $name::from_bytes(rbytes);
assert_eq!(r, a.sqrt());
});
};
}

View File

@@ -62,6 +62,7 @@ main = do
Mul -> hPutStrLn hndl ("multiply_impls!(U" ++ show size ++ ", U" ++ show (size * 2) ++ ");") Mul -> hPutStrLn hndl ("multiply_impls!(U" ++ show size ++ ", U" ++ show (size * 2) ++ ");")
Shifts -> hPutStrLn hndl ("shift_impls!(U" ++ show size ++ ", " ++ show (size `div` 64) ++ ");") Shifts -> hPutStrLn hndl ("shift_impls!(U" ++ show size ++ ", " ++ show (size `div` 64) ++ ");")
Square -> hPutStrLn hndl ("square_impls!(U" ++ show size ++ ", U" ++ show (size * 2) ++ ", " ++ show size ++ ");") Square -> hPutStrLn hndl ("square_impls!(U" ++ show size ++ ", U" ++ show (size * 2) ++ ", " ++ show size ++ ");")
SquareRoot -> hPutStrLn hndl ("sqrt_impls!(U" ++ show size ++ ");")
Sub -> hPutStrLn hndl ("subtraction_impls!(U" ++ show size ++ ", " ++ show (size `div` 64) ++ ");") Sub -> hPutStrLn hndl ("subtraction_impls!(U" ++ show size ++ ", " ++ show (size `div` 64) ++ ");")
Convert to -> hPutStrLn hndl ("conversion_impls!(U" ++ show size ++ ", U" ++ show to ++ ");") Convert to -> hPutStrLn hndl ("conversion_impls!(U" ++ show size ++ ", U" ++ show to ++ ");")
PrimeGen -> hPutStrLn hndl ("prime_gen_impls!(U" ++ show size ++ ");") PrimeGen -> hPutStrLn hndl ("prime_gen_impls!(U" ++ show size ++ ");")
@@ -69,25 +70,26 @@ main = do
hPutStrLn hndl "" hPutStrLn hndl ""
hPutStrLn hndl "\n#[cfg(test)]" hPutStrLn hndl "\n#[cfg(test)]"
hPutStrLn hndl "mod tests {" hPutStrLn hndl "mod tests {"
generateTestBlock hndl "base" BaseOps True 16384 [] generateTestBlock hndl "base" BaseOps True 16384 []
generateTestBlock hndl "conversion" BaseOps False 90000 [] generateTestBlock hndl "conversion" BaseOps False 90000 []
generateTestBlock hndl "codec" BaseOps False 90000 [] generateTestBlock hndl "codec" BaseOps False 90000 []
generateTestBlock hndl "cmp" BaseOps True 16384 [] generateTestBlock hndl "cmp" BaseOps True 16384 []
generateTestBlock hndl "sub" Sub True 9000 [] generateTestBlock hndl "sub" Sub True 9000 []
generateTestBlock hndl "shiftl" Shifts True 9000 [] generateTestBlock hndl "shiftl" Shifts True 9000 []
generateTestBlock hndl "shiftr" Shifts True 9000 [] generateTestBlock hndl "shiftr" Shifts True 9000 []
generateTestBlock hndl "add" Add True 9000 [(+ 64)] generateTestBlock hndl "add" Add True 9000 [(+ 64)]
generateTestBlock hndl "mul" Mul True 9000 [(* 2)] generateTestBlock hndl "mul" Mul True 9000 [(* 2)]
generateTestBlock hndl "div" Div True 2049 [] generateTestBlock hndl "div" Div True 2049 []
generateTestBlock hndl "barrett_gen" Barretts True 2000 [(+ 64)] generateTestBlock hndl "barrett_gen" Barretts True 2000 [(+ 64)]
generateTestBlock hndl "barrett_red" Barretts True 4000 [(+ 64), (* 2)] generateTestBlock hndl "barrett_red" Barretts True 4000 [(+ 64), (* 2)]
generateTestBlock hndl "modsq" ModSq True 4000 [] generateTestBlock hndl "modsq" ModSq True 4000 []
generateTestBlock hndl "modmul" ModMul True 4000 [] generateTestBlock hndl "modmul" ModMul True 4000 []
generateTestBlock hndl "modexp" ModExp True 512 [] generateTestBlock hndl "modexp" ModExp True 512 []
generateTestBlock hndl "square" Square True 4000 [(* 2)] generateTestBlock hndl "square" Square True 4000 [(* 2)]
generateTestBlock hndl "barrett_modsq" ModSq True 4000 [(+ 64)] generateTestBlock hndl "sqrt" SquareRoot True 4096 []
generateTestBlock hndl "barrett_modmul" ModMul True 4000 [(+ 64)] generateTestBlock hndl "barrett_modsq" ModSq True 4000 [(+ 64)]
generateTestBlock hndl "barrett_modexp" ModExp True 1024 [(+ 64)] generateTestBlock hndl "barrett_modmul" ModMul True 4000 [(+ 64)]
generateTestBlock hndl "barrett_modexp" ModExp True 1024 [(+ 64)]
hPutStrLn hndl "}" hPutStrLn hndl "}"
withFile "../src/signed/invoc.rs" WriteMode $ \ hndl -> withFile "../src/signed/invoc.rs" WriteMode $ \ hndl ->
do forM_ requirements $ \ (Req size oper) -> do forM_ requirements $ \ (Req size oper) ->

View File

@@ -3,10 +3,12 @@ module Math(
extendedGCD extendedGCD
, barrett, computeK, base , barrett, computeK, base
, modulate, modulate' , modulate, modulate'
, isqrt
, showX, showB , showX, showB
) )
where where
import Data.Bits(shiftL,shiftR)
import Numeric(showHex) import Numeric(showHex)
data AlgState = AlgState { data AlgState = AlgState {
@@ -102,6 +104,24 @@ showB :: Bool -> String
showB False = "0" showB False = "0"
showB True = "1" showB True = "1"
isqrt :: Int -> Integer -> Integer
isqrt bits val = final
where
bit' = part1 (1 `shiftL` (bits - 2))
--
part1 x | x > val = part1 (x `shiftR` 2)
| otherwise = x
--
final = loop val 0 bit'
--
loop num res bit
| bit == 0 = res
| otherwise = let (num', res') = adjust num res bit
in loop num' (res' `shiftR` 1) (bit `shiftR` 2)
adjust num res bit
| num >= (res + bit) = (num - (res + bit), res + (bit `shiftL` 1))
| otherwise = (num, res)
_run :: Integer -> Integer -> IO () _run :: Integer -> Integer -> IO ()
_run inputx inputy = _run inputx inputy =
do let (x, y, g, initState) = initialState inputx inputy 1 do let (x, y, g, initState) = initialState inputx inputy 1

View File

@@ -25,6 +25,7 @@ data Operation = Add
| SignedShift | SignedShift
| SignedSub | SignedSub
| SigConvert Int | SigConvert Int
| SquareRoot
| EGCD | EGCD
| ModInv | ModInv
| PrimeGen | PrimeGen
@@ -47,7 +48,8 @@ needs = [ Need RSA (\ size -> [Req (size `div` 2) Sub,
]) ])
, Need DSA (\ size -> [Req size BaseOps, , Need DSA (\ size -> [Req size BaseOps,
Req size Shifts, Req size Shifts,
Req size Add]) Req size Add,
Req size SquareRoot])
, Need PrimeGen (\ size -> [Req size Div, , Need PrimeGen (\ size -> [Req size Div,
Req size Shifts, Req size Shifts,
Req size ModExp, Req size ModExp,
@@ -149,6 +151,11 @@ needs = [ Need RSA (\ size -> [Req (size `div` 2) Sub,
Req (size + 64) SignedAdd, Req (size + 64) SignedAdd,
Req size Barretts Req size Barretts
]) ])
, Need SquareRoot (\ size -> [Req size BaseOps,
Req size Shifts,
Req size Add,
Req size Sub
])
] ]
newRequirements :: Requirement -> [Requirement] newRequirements :: Requirement -> [Requirement]

View File

@@ -39,6 +39,7 @@ testDatabase = [
(SignedShift, "sigshiftr", "signed shift right", sigshiftrTest), (SignedShift, "sigshiftr", "signed shift right", sigshiftrTest),
(SignedShift, "sigshiftl", "signed shift left", sigshiftlTest), (SignedShift, "sigshiftl", "signed shift left", sigshiftlTest),
(SignedSub, "sigsub", "signed subtraction", sigsubTest), (SignedSub, "sigsub", "signed subtraction", sigsubTest),
(SquareRoot, "sqrt", "square root", sqrtTest),
(EGCD, "egcd", "EGCD", egcdTest), (EGCD, "egcd", "EGCD", egcdTest),
(ModInv, "modinv", "modular inversion", modinvTest) (ModInv, "modinv", "modular inversion", modinvTest)
] ]
@@ -202,6 +203,13 @@ sigsubTest size memory0 =
("c", showX c)] ("c", showX c)]
in (res, c, memory2) in (res, c, memory2)
sqrtTest :: Test
sqrtTest size memory0 =
let (a, memory1) = generateNum memory0 "a" size
r = isqrt size a
res = Map.fromList [("a", showX a), ("r", showX r)]
in (res, r, memory1)
signedTest :: Test signedTest :: Test
signedTest size memory0 = signedTest size memory0 =
let (x, memory1) = genSign (generateNum memory0 "x" size) let (x, memory1) = genSign (generateNum memory0 "x" size)

2002
testdata/sqrt/00192.test vendored Normal file

File diff suppressed because it is too large Load Diff

2002
testdata/sqrt/00256.test vendored Normal file

File diff suppressed because it is too large Load Diff

2002
testdata/sqrt/01024.test vendored Normal file

File diff suppressed because it is too large Load Diff

2002
testdata/sqrt/02048.test vendored Normal file

File diff suppressed because it is too large Load Diff

2002
testdata/sqrt/03072.test vendored Normal file

File diff suppressed because it is too large Load Diff

3003
testdata/sub/00192.test vendored Normal file

File diff suppressed because it is too large Load Diff