浏览代码

GiantUInt modulus (aka remainder)

Nathan Fallet 4 年之前
父节点
当前提交
fe99f6ea09
共有 2 个文件被更改,包括 72 次插入2 次删除
  1. 50 1
      Sources/CryptoSwift/GiantUInt.swift
  2. 22 1
      Tests/CryptoSwiftTests/GiantUIntTests.swift

+ 50 - 1
Sources/CryptoSwift/GiantUInt.swift

@@ -83,6 +83,25 @@ struct GiantUInt: Equatable, Comparable, ExpressibleByIntegerLiteral {
     return GiantUInt(bytes)
   }
   
+  static func - (rhs: GiantUInt, lhs: GiantUInt) -> GiantUInt {
+    var bytes = [UInt8]()
+    var r: UInt8 = 0
+    
+    for i in 0 ..< max(rhs.bytes.count, lhs.bytes.count) {
+      let rhsb = UInt16(rhs.bytes[safe: i] ?? 0)
+      let lhsb = UInt16(lhs.bytes[safe: i] ?? 0) + UInt16(r)
+      r = UInt8(rhsb < lhsb ? 1 : 0)
+      let res = (UInt16(r) << 8) + rhsb - lhsb
+      bytes.append(UInt8(res & 0xff))
+    }
+    
+    if r != 0 {
+      bytes.append(r)
+    }
+    
+    return GiantUInt(bytes)
+  }
+  
   static func * (rhs: GiantUInt, lhs: GiantUInt) -> GiantUInt {
     var offset = 0
     var sum = [GiantUInt]()
@@ -105,7 +124,18 @@ struct GiantUInt: Equatable, Comparable, ExpressibleByIntegerLiteral {
       offset += 1
     }
     
-    return sum.reduce(GiantUInt([]), +)
+    return sum.reduce(0, +)
+  }
+  
+  static func % (rhs: GiantUInt, lhs: GiantUInt) -> GiantUInt {
+    var remainder = rhs
+    
+    // This needs serious optimization (but works)
+    while remainder >= lhs {
+      remainder = remainder - lhs
+    }
+  
+    return remainder
   }
   
   static func ^^ (rhs: GiantUInt, lhs: GiantUInt) -> GiantUInt {
@@ -127,4 +157,23 @@ struct GiantUInt: Equatable, Comparable, ExpressibleByIntegerLiteral {
     return result
   }
   
+  static func exponentiateWithModulus(rhs: GiantUInt, lhs: GiantUInt, modulus: GiantUInt) -> GiantUInt {
+    let count = lhs.bytes.count
+    var result = GiantUInt([1])
+    
+    for iByte in 0 ..< count {
+      let byte = lhs.bytes[iByte]
+      for i in 0 ..< 8 {
+        if iByte != count - 1 || byte >> i > 0 {
+          result = (result * result) % modulus
+          if (byte >> i) & 1 == 1 {
+            result = (result * rhs) % modulus
+          }
+        }
+      }
+    }
+    
+    return result
+  }
+  
 }

+ 22 - 1
Tests/CryptoSwiftTests/GiantUIntTests.swift

@@ -36,6 +36,14 @@ final class GiantUIntTests: XCTestCase {
     XCTAssertEqual(c, GiantUInt([144, 145, 1]), "addition with double retenue failed")
   }
   
+  func testSubtraction() {
+    let a = GiantUInt([2]) - GiantUInt([1])
+    XCTAssertEqual(a, GiantUInt([1]), "simple subtraction failed")
+    
+    let b = GiantUInt([0, 1]) - GiantUInt([255])
+    XCTAssertEqual(b, GiantUInt([1]), "subtraction with retenue failed")
+  }
+  
   func testMultiplication() {
     let a = GiantUInt([2]) * GiantUInt([2])
     XCTAssertEqual(a, GiantUInt([4]), "simple multiplication failed")
@@ -52,6 +60,16 @@ final class GiantUIntTests: XCTestCase {
     XCTAssertEqual(a, GiantUInt([139, 8]), "simple exponentiation failed")
   }
   
+  func testModulus() {
+    let a = GiantUInt([10]) % GiantUInt([3])
+    XCTAssertEqual(a, GiantUInt([1]), "simple modulus failed")
+  }
+  
+  func testExponentiationWithModulus() {
+    let a = GiantUInt.exponentiateWithModulus(rhs: GiantUInt([3]), lhs: GiantUInt([7]), modulus: GiantUInt([0, 1]))
+    XCTAssertEqual(a, GiantUInt([139]), "simple exponentiation with modulus failed")
+  }
+  
 }
 
 extension GiantUIntTests {
@@ -59,8 +77,11 @@ extension GiantUIntTests {
     let tests = [
       ("testComparable", testComparable),
       ("testAddition", testAddition),
+      ("testSubtraction", testSubtraction),
       ("testMultiplication", testMultiplication),
-      ("testExponentiation", testExponentiation)
+      ("testExponentiation", testExponentiation),
+      ("testModulus", testModulus),
+      ("testExponentiationWithModulus", testExponentiationWithModulus)
     ]
 
     return tests