Commit the start of the work on modular X before I worry about From.
This commit is contained in:
@@ -10,6 +10,7 @@ import CryptoNum(cryptoNum)
|
|||||||
import Control.Monad(forM_,unless)
|
import Control.Monad(forM_,unless)
|
||||||
import Division(divisionOps)
|
import Division(divisionOps)
|
||||||
import File(File,Task(..),generateTasks)
|
import File(File,Task(..),generateTasks)
|
||||||
|
import ModOps(modulusOps)
|
||||||
import Multiply(safeMultiplyOps, unsafeMultiplyOps)
|
import Multiply(safeMultiplyOps, unsafeMultiplyOps)
|
||||||
import Scale(safeScaleOps, unsafeScaleOps)
|
import Scale(safeScaleOps, unsafeScaleOps)
|
||||||
import Shift(shiftOps)
|
import Shift(shiftOps)
|
||||||
@@ -38,6 +39,7 @@ unsignedFiles = [
|
|||||||
, conversions
|
, conversions
|
||||||
, cryptoNum
|
, cryptoNum
|
||||||
, divisionOps
|
, divisionOps
|
||||||
|
, modulusOps
|
||||||
, safeAddOps
|
, safeAddOps
|
||||||
, safeMultiplyOps
|
, safeMultiplyOps
|
||||||
, safeScaleOps
|
, safeScaleOps
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ library
|
|||||||
containers,
|
containers,
|
||||||
directory,
|
directory,
|
||||||
filepath,
|
filepath,
|
||||||
|
integer-gmp,
|
||||||
language-rust,
|
language-rust,
|
||||||
largeword,
|
largeword,
|
||||||
mtl,
|
mtl,
|
||||||
@@ -40,6 +41,7 @@ library
|
|||||||
Gen,
|
Gen,
|
||||||
Generators,
|
Generators,
|
||||||
Karatsuba,
|
Karatsuba,
|
||||||
|
ModOps,
|
||||||
Multiply,
|
Multiply,
|
||||||
Scale,
|
Scale,
|
||||||
Shift,
|
Shift,
|
||||||
|
|||||||
@@ -207,6 +207,6 @@ generateDivisionTests size g = go g numTestCases
|
|||||||
("z", showX (x `div` y)),
|
("z", showX (x `div` y)),
|
||||||
("r", showX (x `mod` y))]
|
("r", showX (x `mod` y))]
|
||||||
in if y == 0
|
in if y == 0
|
||||||
then go g0 i
|
then go g2 i
|
||||||
else tcase : go g2 (i - 1)
|
else tcase : go g2 (i - 1)
|
||||||
|
|
||||||
|
|||||||
76
generation/src/ModOps.hs
Normal file
76
generation/src/ModOps.hs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
{-# LANGUAGE QuasiQuotes #-}
|
||||||
|
module ModOps(modulusOps)
|
||||||
|
where
|
||||||
|
|
||||||
|
import Data.Map.Strict(Map)
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
|
import File
|
||||||
|
import Gen(toLit)
|
||||||
|
import Generators
|
||||||
|
import GHC.Integer.GMP.Internals(powModInteger)
|
||||||
|
import Language.Rust.Data.Ident
|
||||||
|
import Language.Rust.Data.Position
|
||||||
|
import Language.Rust.Quote
|
||||||
|
import Language.Rust.Syntax
|
||||||
|
import System.Random(RandomGen)
|
||||||
|
|
||||||
|
numTestCases :: Int
|
||||||
|
numTestCases = 3000
|
||||||
|
|
||||||
|
modulusOps :: File
|
||||||
|
modulusOps = File {
|
||||||
|
predicate = \ me others -> (me * 2) `elem` others,
|
||||||
|
outputName = "modops",
|
||||||
|
isUnsigned = True,
|
||||||
|
generator = declareModOps,
|
||||||
|
testCase = Just generateModulusTests
|
||||||
|
}
|
||||||
|
|
||||||
|
declareModOps :: Word -> SourceFile Span
|
||||||
|
declareModOps bitsize =
|
||||||
|
let sname = mkIdent ("U" ++ show bitsize)
|
||||||
|
bname = mkIdent ("U" ++ show (bitsize * 2))
|
||||||
|
in [sourceFile|
|
||||||
|
use crate::unsigned::$$sname;
|
||||||
|
use crate::{DivMod, ModularOperations};
|
||||||
|
|
||||||
|
impl ModularOperations for $$sname {
|
||||||
|
fn reduce(&self, m: &$$sname) -> $$sname {
|
||||||
|
let (_, res) = self.divmod(m);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn modmul(&self, y: &$$sname, m: &$$sname) -> $$sname {
|
||||||
|
panic!("modmul")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn modsq(&self, m: &$$sname) -> $$sname {
|
||||||
|
panic!("reduce")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn modexp(&self, e: &$$sname, m: &$$sname) -> $$sname {
|
||||||
|
panic!("reduce")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|]
|
||||||
|
|
||||||
|
generateModulusTests :: RandomGen g => Word -> g -> [Map String String]
|
||||||
|
generateModulusTests size g = go g numTestCases
|
||||||
|
where
|
||||||
|
go _ 0 = []
|
||||||
|
go g0 i =
|
||||||
|
let (x, g1) = generateNum g0 size
|
||||||
|
(y, g2) = generateNum g1 size
|
||||||
|
(m, g3) = generateNum g2 size
|
||||||
|
tcase = Map.fromList [("x", showX x), ("y", showX y),
|
||||||
|
("m", showX m),
|
||||||
|
("r", showX (x `mod` m)),
|
||||||
|
("t", showX ((x * y) `mod` m)),
|
||||||
|
("s", showX ((x * x) `mod` m)),
|
||||||
|
("e", showX (powModInteger x y m))
|
||||||
|
]
|
||||||
|
in if y < 2
|
||||||
|
then go g3 i
|
||||||
|
else tcase : go g3 (i - 1)
|
||||||
|
|
||||||
|
|
||||||
18
src/lib.rs
18
src/lib.rs
@@ -42,12 +42,30 @@ pub trait CryptoNum {
|
|||||||
/// this is used as the implementation of division and multiplication, and
|
/// this is used as the implementation of division and multiplication, and
|
||||||
/// so you can save time doing both at once if you need them.
|
/// so you can save time doing both at once if you need them.
|
||||||
///
|
///
|
||||||
|
/// WARNING: There has been some effort made to make this have a constant-time
|
||||||
|
/// implementation, but it does use a single conditional inside an otherwise-
|
||||||
|
/// constant time loop. There may be unforeseen timing effects of this, or
|
||||||
|
/// the compiler may do something funny to "optimize" some math.
|
||||||
pub trait DivMod: Sized {
|
pub trait DivMod: Sized {
|
||||||
/// Divide and modulus as a single operation. The first element of the tuple
|
/// Divide and modulus as a single operation. The first element of the tuple
|
||||||
/// is the quotient, the second is the modulus.
|
/// is the quotient, the second is the modulus.
|
||||||
fn divmod(&self, rhs: &Self) -> (Self, Self);
|
fn divmod(&self, rhs: &Self) -> (Self, Self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Provides support for a variety of modular mathematical operations, as beloved
|
||||||
|
// by cryptographers.
|
||||||
|
pub trait ModularOperations<Modulus=Self> {
|
||||||
|
// reduce the current value by the provided modulus
|
||||||
|
fn reduce(&self, m: &Modulus) -> Self;
|
||||||
|
// multiply this value by the provided one, modulo the modulus
|
||||||
|
fn modmul(&self, rhs: &Self, m: &Modulus) -> Self;
|
||||||
|
// square the provided number, modulo the modulus
|
||||||
|
fn modsq(&self, m: &Modulus) -> Self;
|
||||||
|
// modular exponentiation!
|
||||||
|
fn modexp(&self, e: &Self, m: &Modulus) -> Self;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// An error in conversion of large numbers (either to primitives or to other numbers
|
/// An error in conversion of large numbers (either to primitives or to other numbers
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ConversionError {
|
pub enum ConversionError {
|
||||||
|
|||||||
Reference in New Issue
Block a user