From f127fd65104b33aca2b321f9e8de2dd8b0e90275 Mon Sep 17 00:00:00 2001 From: Bouke Haarsma Date: Wed, 24 Aug 2016 22:19:37 +0200 Subject: [PATCH] Initial commit --- .gitignore | 4 + LICENSE | 19 +++++ Package.swift | 8 ++ README.md | 7 ++ Sources/Bignum.swift | 116 ++++++++++++++++++++++++++++ Tests/BignumTests/BignumTests.swift | 45 +++++++++++ Tests/LinuxMain.swift | 6 ++ 7 files changed, 205 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Package.swift create mode 100644 README.md create mode 100644 Sources/Bignum.swift create mode 100644 Tests/BignumTests/BignumTests.swift create mode 100644 Tests/LinuxMain.swift diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..02c0875 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2ff4725 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2016 Bouke Haarsma + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..7802bfd --- /dev/null +++ b/Package.swift @@ -0,0 +1,8 @@ +import PackageDescription + +let package = Package( + name: "Bignum", + dependencies: [ + .Package(url: "https://github.com/Bouke/COpenSSL.git", majorVersion: 1), + ] +) diff --git a/README.md b/README.md new file mode 100644 index 0000000..c44200d --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +Swift big number library +======================== + +A big number library for Swift, backed by OpenSSL. Not all methods are currently provided, but can be added if needed. + + let result = Bignum("2") + Bignum("3") * Bignum("4") / Bignum("2") + assert(result == Bignum("8")) diff --git a/Sources/Bignum.swift b/Sources/Bignum.swift new file mode 100644 index 0000000..e360da4 --- /dev/null +++ b/Sources/Bignum.swift @@ -0,0 +1,116 @@ +import COpenSSL +import Foundation + +public class Bignum { + internal let ctx: UnsafeMutablePointer + + init() { + ctx = BN_new() + } + + init(ctx: UnsafeMutablePointer) { + self.ctx = ctx + } + + public init(_ dec: String) { + var ctx: UnsafeMutablePointer? = nil + BN_dec2bn(&ctx, dec) + self.ctx = ctx! + } + + public init(hex: String) { + var ctx: UnsafeMutablePointer? = nil + BN_hex2bn(&ctx, hex) + self.ctx = ctx! + } + + public convenience init(data: Data) { + self.init() + _ = data.withUnsafeBytes { pData in + BN_bin2bn(pData, Int32(data.count), ctx) + } + } + + deinit { + BN_free(ctx) + } + + public var data: Data { + var data = Data(count: Int((BN_num_bits(ctx) + 7) / 8)) + _ = data.withUnsafeMutableBytes { pData in + BN_bn2bin(ctx, pData) + } + return data + } + + public var dec: String { + return String(validatingUTF8: BN_bn2dec(ctx))! + } + + public var hex: String { + return String(validatingUTF8: BN_bn2hex(ctx))! + } +} + +extension Bignum: CustomStringConvertible { + public var description: String { + return dec + } +} + +extension Bignum: Comparable { + public static func == (lhs: Bignum, rhs: Bignum) -> Bool { + return BN_cmp(lhs.ctx, rhs.ctx) == 0 + } + + public static func < (lhs: Bignum, rhs: Bignum) -> Bool { + return BN_cmp(lhs.ctx, rhs.ctx) == -1 + } +} + +internal let ctx = BN_CTX_new() + +func operation(_ block: (_ result: Bignum) -> Int32) -> Bignum { + let result = Bignum() + precondition(block(result) == 1) + return result +} + +/// Returns: (a ** b) % N +public func mod_exp(_ a: Bignum, _ p: Bignum, _ m: Bignum) -> Bignum { + return operation { + BN_mod_exp($0.ctx, a.ctx, p.ctx, m.ctx, ctx) + } +} + +public func * (lhs: Bignum, rhs: Bignum) -> Bignum { + return operation { + BN_mul($0.ctx, lhs.ctx, rhs.ctx, ctx) + } +} + +public func + (lhs: Bignum, rhs: Bignum) -> Bignum { + return operation { + BN_add($0.ctx, lhs.ctx, rhs.ctx) + } +} + +public func - (lhs: Bignum, rhs: Bignum) -> Bignum { + return operation { + BN_sub($0.ctx, lhs.ctx, rhs.ctx) + } +} + +/// Returns lhs / rhs, rounded to zero. +public func / (lhs: Bignum, rhs: Bignum) -> Bignum { + return operation { + BN_div($0.ctx, nil, lhs.ctx, rhs.ctx, ctx) + } +} + +/// Returns: (a + b) % N +public func mod_add(_ a: Bignum, _ b: Bignum, _ m: Bignum) -> Bignum { + return operation { + BN_mod_add($0.ctx, a.ctx, b.ctx, m.ctx, ctx) + } +} diff --git a/Tests/BignumTests/BignumTests.swift b/Tests/BignumTests/BignumTests.swift new file mode 100644 index 0000000..30a30fc --- /dev/null +++ b/Tests/BignumTests/BignumTests.swift @@ -0,0 +1,45 @@ +import XCTest +@testable import Bignum + +class BignumTests: XCTestCase { + func testAddition() { + XCTAssertEqual(Bignum("1") + Bignum("2"), Bignum("3")) + } + + func testSubtraction() { + XCTAssertEqual(Bignum("5") - Bignum("3"), Bignum("2")) + } + + func testMultiplication() { + XCTAssertEqual(Bignum("2") * Bignum("3"), Bignum("6")) + } + + func testDivision() { + XCTAssertEqual(Bignum("10") / Bignum("5"), Bignum("2")) + } + + func testModExp() { + XCTAssertEqual(mod_exp(Bignum("5"), Bignum("8"), Bignum("13")), Bignum("1")) + } + + func testModAdd() { + XCTAssertEqual(mod_exp(Bignum("5"), Bignum("7"), Bignum("13")), Bignum("8")) + } + + func testReadme() { + let result = Bignum("2") + Bignum("3") * Bignum("4") / Bignum("2") + assert(result == Bignum("8")) + } + + static var allTests : [(String, (BignumTests) -> () throws -> Void)] { + return [ + ("testAddition", testAddition), + ("testSubtraction", testSubtraction), + ("testMultiplication", testMultiplication), + ("testDivision", testDivision), + ("testModExp", testModExp), + ("testModAdd", testModAdd), + ("testReadme", testReadme) + ] + } +} diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift new file mode 100644 index 0000000..6f6a55b --- /dev/null +++ b/Tests/LinuxMain.swift @@ -0,0 +1,6 @@ +import XCTest +@testable import BignumTests + +XCTMain([ + testCase(BignumTests.allTests), +])