Support for fast squaring.
This commit is contained in:
@@ -11,6 +11,7 @@ mod comparison;
|
|||||||
mod conversions;
|
mod conversions;
|
||||||
mod encoding;
|
mod encoding;
|
||||||
mod multiplication;
|
mod multiplication;
|
||||||
|
mod squaring;
|
||||||
mod subtraction;
|
mod subtraction;
|
||||||
|
|
||||||
pub use self::basetypes::*;
|
pub use self::basetypes::*;
|
||||||
|
|||||||
91
src/cryptonum/squaring.rs
Normal file
91
src/cryptonum/squaring.rs
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
// This is algorithm 14.16 from "Handbook of Applied Cryptography".
|
||||||
|
pub fn raw_square(x: &[u64], result: &mut [u64])
|
||||||
|
{
|
||||||
|
assert_eq!(x.len() * 2, result.len());
|
||||||
|
let t = x.len();
|
||||||
|
let mut w: Vec<u128> = Vec::with_capacity(t * 2);
|
||||||
|
w.resize(t * 2, 0);
|
||||||
|
|
||||||
|
for i in 0..t {
|
||||||
|
let x128 = x[i] as u128;
|
||||||
|
let mut uvb = (w[2*i] as u128) + (x128 * x128);
|
||||||
|
w[2*i] = uvb & 0xFFFFFFFFFFFFFFFF;
|
||||||
|
let mut c = uvb >> 64;
|
||||||
|
for j in (i+1)..t {
|
||||||
|
let xj128 = x[j] as u128;
|
||||||
|
let xi128 = x[i] as u128;
|
||||||
|
// this first product is safely 128 bits or less, because the
|
||||||
|
// input arguments are both 64 bits.
|
||||||
|
let xij128 = xj128 * xi128;
|
||||||
|
// this next bit may overflow, but will do so by exactly one bit.
|
||||||
|
let twoxij128 = xij128 << 1;
|
||||||
|
let carried_shl = (xij128 & (1 << 127)) != 0;
|
||||||
|
// this next bit may *also* overflow, but should also do so by no
|
||||||
|
// more than one bit.
|
||||||
|
let (newstuff, carried_add1) = twoxij128.overflowing_add(c);
|
||||||
|
// ditto ...
|
||||||
|
let (uvb2, carried_add2) = newstuff.overflowing_add(w[i+j] as u128);
|
||||||
|
// for the value we're going to save for this digit, we only care
|
||||||
|
// about the low bits, so we can forget about the carry stuff.
|
||||||
|
w[i+j] = uvb2 & 0xFFFFFFFFFFFFFFFF;
|
||||||
|
// for c, though, we do care about the carries, above. Fortunately,
|
||||||
|
// they were both by only one bit, so we should be able to just
|
||||||
|
// back-fix them.
|
||||||
|
c = uvb2 >> 64;
|
||||||
|
if carried_shl { c += 1 << 64; }
|
||||||
|
if carried_add1 { c += 1 << 64; }
|
||||||
|
if carried_add2 { c += 1 << 64; }
|
||||||
|
}
|
||||||
|
w[i+t] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (idx, val) in w.iter().enumerate() {
|
||||||
|
result[idx] = *val as u64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use testing::run_test;
|
||||||
|
#[cfg(test)]
|
||||||
|
use cryptonum::Decoder;
|
||||||
|
#[cfg(test)]
|
||||||
|
use cryptonum::encoding::raw_decoder;
|
||||||
|
#[cfg(test)]
|
||||||
|
use cryptonum::{U192,U256,U384,U512,U576,U1024,U2048,U3072,U4096,U8192,U15360};
|
||||||
|
|
||||||
|
macro_rules! generate_tests {
|
||||||
|
($name: ident, $testname: ident) => (
|
||||||
|
#[cfg(test)]
|
||||||
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn $testname() {
|
||||||
|
let fname = format!("tests/math/squaring{}.test",
|
||||||
|
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 mut result = Vec::with_capacity(a.values.len() * 2);
|
||||||
|
result.resize(a.values.len() * 2, 0);
|
||||||
|
let mut myresult = result.clone();
|
||||||
|
raw_decoder(rbytes, &mut result);
|
||||||
|
raw_square(&a.values, &mut myresult);
|
||||||
|
assert_eq!(result, myresult);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_tests!(U192,u192);
|
||||||
|
generate_tests!(U256,u256);
|
||||||
|
generate_tests!(U384,u384);
|
||||||
|
generate_tests!(U512,u512);
|
||||||
|
generate_tests!(U576,u576);
|
||||||
|
generate_tests!(U1024,u1024);
|
||||||
|
generate_tests!(U2048,u2048);
|
||||||
|
generate_tests!(U3072,u3072);
|
||||||
|
generate_tests!(U4096,u4096);
|
||||||
|
generate_tests!(U8192,u8192);
|
||||||
|
generate_tests!(U15360,u15360);
|
||||||
@@ -12,7 +12,8 @@ testTypes = [("addition", addTest),
|
|||||||
("modadd", modaddTest),
|
("modadd", modaddTest),
|
||||||
("subtraction", subTest),
|
("subtraction", subTest),
|
||||||
("multiplication", mulTest),
|
("multiplication", mulTest),
|
||||||
("expandingmul", expmulTest)
|
("expandingmul", expmulTest),
|
||||||
|
("squaring", squareTest)
|
||||||
]
|
]
|
||||||
|
|
||||||
bitSizes :: [Int]
|
bitSizes :: [Int]
|
||||||
@@ -94,6 +95,15 @@ expmulTest bitsize gen0 = (res, gen2)
|
|||||||
("b", showHex b' ""),
|
("b", showHex b' ""),
|
||||||
("c", showHex c "")]
|
("c", showHex c "")]
|
||||||
|
|
||||||
|
squareTest :: Int -> StdGen -> (Map String String, StdGen)
|
||||||
|
squareTest bitsize gen0 = (res, gen1)
|
||||||
|
where
|
||||||
|
(a, gen1) = random gen0
|
||||||
|
a' = a .&. mask bitsize
|
||||||
|
r = a' * a'
|
||||||
|
res = Map.fromList [("a", showHex a' ""),
|
||||||
|
("r", showHex r "")]
|
||||||
|
|
||||||
log :: String -> IO ()
|
log :: String -> IO ()
|
||||||
log str =
|
log str =
|
||||||
do putStr str
|
do putStr str
|
||||||
|
|||||||
2000
tests/math/squaringU1024.test
Normal file
2000
tests/math/squaringU1024.test
Normal file
File diff suppressed because it is too large
Load Diff
2000
tests/math/squaringU15360.test
Normal file
2000
tests/math/squaringU15360.test
Normal file
File diff suppressed because one or more lines are too long
2000
tests/math/squaringU192.test
Normal file
2000
tests/math/squaringU192.test
Normal file
File diff suppressed because it is too large
Load Diff
2000
tests/math/squaringU2048.test
Normal file
2000
tests/math/squaringU2048.test
Normal file
File diff suppressed because it is too large
Load Diff
2000
tests/math/squaringU256.test
Normal file
2000
tests/math/squaringU256.test
Normal file
File diff suppressed because it is too large
Load Diff
2000
tests/math/squaringU3072.test
Normal file
2000
tests/math/squaringU3072.test
Normal file
File diff suppressed because it is too large
Load Diff
2000
tests/math/squaringU384.test
Normal file
2000
tests/math/squaringU384.test
Normal file
File diff suppressed because it is too large
Load Diff
2000
tests/math/squaringU4096.test
Normal file
2000
tests/math/squaringU4096.test
Normal file
File diff suppressed because it is too large
Load Diff
2000
tests/math/squaringU512.test
Normal file
2000
tests/math/squaringU512.test
Normal file
File diff suppressed because it is too large
Load Diff
2000
tests/math/squaringU576.test
Normal file
2000
tests/math/squaringU576.test
Normal file
File diff suppressed because it is too large
Load Diff
2000
tests/math/squaringU8192.test
Normal file
2000
tests/math/squaringU8192.test
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user