Commit the start of the work on modular X before I worry about From.

This commit is contained in:
2020-01-08 15:19:34 -10:00
parent 3e82008189
commit 8c5f18cb7c
5 changed files with 99 additions and 1 deletions

View File

@@ -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

View File

@@ -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,

View File

@@ -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
View 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)

View File

@@ -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 {