diff --git a/generation/src/UnsignedBase.hs b/generation/src/UnsignedBase.hs index ae276a8..35d46d9 100644 --- a/generation/src/UnsignedBase.hs +++ b/generation/src/UnsignedBase.hs @@ -4,6 +4,7 @@ module UnsignedBase( where import Control.Monad(forM_) +import Data.List(intercalate) import File import Gen @@ -56,6 +57,36 @@ declareBaseStructure bitsize = wrapIndent ("if idx >= " ++ show entries) $ out "return false;" out "(self.value[idx] & (1u64 << offset)) != 0" + blank + wrapIndent ("fn from_bytes(&self, bytes: &[u8]) -> Self") $ + do let bytes = bitsize `div` 8; + forM_ [0..bytes-1] $ \ idx -> + out ("let byte" ++ show idx ++ " = " ++ + "if " ++ show idx ++ " < bytes.len() { " ++ + "bytes[" ++ show idx ++ "] as u64 } else { 0 };") + blank + let byteNames = map (\ x -> "byte" ++ show x) [0..bytes-1] + byteGroups = groupCount 8 (reverse byteNames) + forM_ (zip byteGroups [0..bytes-1]) $ \ (byteGroup, idx) -> + do let shiftAmts = [0,8..56] + shifts = zipWith (\ n s -> n ++ " << " ++ show s) + byteGroup shiftAmts + shift0 = head shifts + shiftL = last shifts + middles = reverse (drop 1 (reverse (drop 1 shifts))) + prefix = "let word" ++ show idx ++ " " + blankPrefix = map (const ' ') prefix + out (prefix ++ " = " ++ shift0) + forM_ middles $ \ s -> out (blankPrefix ++ " | " ++ s) + out (blankPrefix ++ " | " ++ shiftL ++ ";") + blank + wrapIndent name $ + do out ("value: [") + let vwords = map (\ x -> "word" ++ show x) [0..top] + linewords = groupCount 4 vwords + vlines = map (intercalate ", ") linewords + forM_ vlines $ \ l -> out (" " ++ l ++ ",") + out ("]") blank implFor "PartialEq" name $ wrapIndent "fn eq(&self, other: &Self) -> bool" $ @@ -121,4 +152,9 @@ declareBaseStructure bitsize = out ("assert_eq!(x.testbit(b), t);") out ("x.mask(usize::from(&m));") out ("assert_eq!(x, r);") - out ("});") \ No newline at end of file + out ("});") + +groupCount :: Int -> [a] -> [[a]] +groupCount x ls + | x >= length ls = [ls] + | otherwise = take x ls : groupCount x (drop x ls) \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 825ccdd..87ed59a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,5 +20,17 @@ pub trait CryptoNum { /// Test if the given bit is zero, where bits are numbered in /// least-significant order (0 is the LSB, etc.). fn testbit(&self, bit: usize) -> bool; + /// Convert a slice into a CryptoNum, assuming big-endian memory layout. + /// If you pass in a slice bigger than the bit size of the numeric type, + /// this will assume that the number is in the first `n` bits of the + /// memory layout. If you pass in a smaller buffer, it will use the bits + /// available as the low `n` bits of the number. + fn from_bytes(&self, bytes: &[u8]) -> Self; + /// Write the cryptonum into the provide slice. If the provided slice + /// is greater than or equal to `n` bits in length, `to_bytes` will + /// write to the first `n` bits. If the slice is less than `n` bits + /// in length, `to_bytes` will write the lower-order bits that fit + /// into the provided slice. + fn to_bytes(&self, bytes: &mut [u8]); }