diff --git a/.gitignore b/.gitignore index 7d62595..47cd148 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,7 @@ playground.xcworkspace # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. Packages/ Package.pins +Package.resolved .build/ # CocoaPods diff --git a/.swift-version b/.swift-version new file mode 100644 index 0000000..4d54dad --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +4.0.2 diff --git a/PVSS.podspec b/PVSS.podspec index 9346d21..34a6bfd 100644 --- a/PVSS.podspec +++ b/PVSS.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'PVSS' - s.version = '2.0.0' + s.version = '2.1.0' s.summary = 'An implementation of Publicly Verifiably Secret Sharing (PVSS) in Swift.' s.description = <<-DESC The library implements a PVSS scheme in Swift. The algorithm is based on "A Simple Publicly Verifiable Secret Sharing Scheme and its Application to Electronic Voting" by Berry Schoenmakers. @@ -12,7 +12,8 @@ The library implements a PVSS scheme in Swift. The algorithm is based on "A Simp s.source = { :git => 'https://github.com/FabioTacke/PubliclyVerifiableSecretSharing.git', :tag => 'v' + String(s.version) } s.social_media_url = 'https://twitter.com/FabioTacke' - s.source_files = 'Sources/*.swift' + s.source_files = 'Sources/PVSS/*.swift' + s.dependency 'BigInt' s.dependency 'CryptoSwift' diff --git a/Package.swift b/Package.swift index 3a50a52..ad8ad64 100644 --- a/Package.swift +++ b/Package.swift @@ -1,12 +1,25 @@ -// swift-tools-version:3.1 +// swift-tools-version:4.0 import PackageDescription let package = Package( name: "PVSS", + products: [ + .library( + name: "PVSS", + targets: ["PVSS"]), + ], dependencies: [ - .Package(url: "https://github.com/lorentey/BigInt.git", majorVersion: 2, minor: 1), - .Package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", majorVersion: 0), - .Package(url: "https://github.com/mdaxter/BignumGMP.git", majorVersion: 1), + .package(url: "https://github.com/attaswift/BigInt.git", .branch("master")), + .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .branch("master")), + .package(url: "https://github.com/mdaxter/BignumGMP.git", .branch("master")), + ], + targets: [ + .target( + name: "PVSS", + dependencies: ["BigInt", "Bignum", "CryptoSwift"]), + .testTarget( + name: "PVSSTests", + dependencies: ["PVSS"]), ] ) diff --git a/README.md b/README.md index a035ed3..104f7ca 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Thus PVSS can be used to share a secret among a group of participants so that ei ## Build settings Since version 2.0.0 PVSS uses GMP for speeding up the calculations. If you don't have GMP installed there's a compiled GMP library version 6.1.2 included. However you need to provide the compiler and the linker with the information where to find the GMP header file and the library. Example: -`swift [build | test] -Xcc -Lgmp/include -Xlinker -Lgmp/lib` +`swift [build | test] -Xcc -Igmp/include -Xlinker -Lgmp/lib` You can replace those paths if you already have GMP installed. diff --git a/Sources/BignumExtensions.swift b/Sources/PVSS/BignumExtensions.swift similarity index 100% rename from Sources/BignumExtensions.swift rename to Sources/PVSS/BignumExtensions.swift diff --git a/Sources/Bundles.swift b/Sources/PVSS/Bundles.swift similarity index 100% rename from Sources/Bundles.swift rename to Sources/PVSS/Bundles.swift diff --git a/Sources/DLEQ.swift b/Sources/PVSS/DLEQ.swift similarity index 100% rename from Sources/DLEQ.swift rename to Sources/PVSS/DLEQ.swift diff --git a/Sources/Extensions.swift b/Sources/PVSS/Extensions.swift similarity index 100% rename from Sources/Extensions.swift rename to Sources/PVSS/Extensions.swift diff --git a/Sources/PVSSInstance.swift b/Sources/PVSS/PVSSInstance.swift similarity index 89% rename from Sources/PVSSInstance.swift rename to Sources/PVSS/PVSSInstance.swift index 8828bcf..e1b3341 100644 --- a/Sources/PVSSInstance.swift +++ b/Sources/PVSS/PVSSInstance.swift @@ -42,7 +42,8 @@ public struct PVSSInstance { repeat { q -= 2 } while !q.isPrime() - sophieGermainCandidate = (q-1).divided(by: 2).quotient + sophieGermainCandidate = (q-1).quotientAndRemainder(dividingBy: 2).quotient +// sophieGermainCandidate = (q-1).divided(by: 2).quotient } while !sophieGermainCandidate.isPrime() let qConverted = Bignum(q.description) @@ -55,7 +56,7 @@ public struct PVSSInstance { /// Initializes a PVSSInstance with default parameters. `q` is a safe prime of length 2048 bit (RFC3526). `2` and the corresponding sophie germain prime are generators. public init() { let q = BigUInt(stringLiteral: "32317006071311007300338913926423828248817941241140239112842009751400741706634354222619689417363569347117901737909704191754605873209195028853758986185622153212175412514901774520270235796078236248884246189477587641105928646099411723245426622522193230540919037680524235519125679715870117001058055877651038861847280257976054903569732561526167081339361799541336476559160368317896729073178384589680639671900977202194168647225871031411336429319536193471636533209717077448227988588565369208645296636077250268955505928362751121174096972998068410554359584866583291642136218231078990999448652468262416972035911852507045361090559") - let g = Bignum((q-1).divided(by: 2).quotient.description) + let g = Bignum((q-1).quotientAndRemainder(dividingBy: 2).quotient.description) let G = Bignum(2) let length = 2048 @@ -66,11 +67,11 @@ public struct PVSSInstance { public func generatePrivateKey() -> Bignum { let q = BigUInt(self.q.description)! - var key = BigUInt.randomIntegerLessThan(q) + var key = BigUInt.randomInteger(lessThan: q) // We need the private key and q-1 to be coprime so that we can calculate 1/key mod (q-1) during secret reconstruction. - while BigUInt.gcd(key, q - 1) != 1 { - key = BigUInt.randomIntegerLessThan(q) + while key.greatestCommonDivisor(with: q - 1) != 1 { + key = BigUInt.randomInteger(lessThan: q) } return Bignum(key.description) } @@ -106,10 +107,10 @@ public struct PVSSInstance { let a2 = (mod_exp(key, response, q) * mod_exp(share, distributionBundle.challenge, q)) % q // Update hash - let _ = try! digest.update(withBytes: x.description.data(using: .utf8)!) - let _ = try! digest.update(withBytes: share.description.data(using: .utf8)!) - let _ = try! digest.update(withBytes: a1.description.data(using: .utf8)!) - let _ = try! digest.update(withBytes: a2.description.data(using: .utf8)!) + let _ = try! digest.update(withBytes: Array(x.description.data(using: .utf8)!)) + let _ = try! digest.update(withBytes: Array(share.description.data(using: .utf8)!)) + let _ = try! digest.update(withBytes: Array(a1.description.data(using: .utf8)!)) + let _ = try! digest.update(withBytes: Array(a2.description.data(using: .utf8)!)) } // Calculate challenge @@ -146,10 +147,10 @@ public struct PVSSInstance { let a1 = (mod_exp(G, shareBundle.response, q) * mod_exp(shareBundle.publicKey, shareBundle.challenge, q)) % q let a2 = (mod_exp(shareBundle.share, shareBundle.response, q) * mod_exp(encryptedShare, shareBundle.challenge, q)) % q - let _ = try! digest.update(withBytes: shareBundle.publicKey.description.data(using: .utf8)!) - let _ = try! digest.update(withBytes: encryptedShare.description.data(using: .utf8)!) - let _ = try! digest.update(withBytes: a1.description.data(using: .utf8)!) - let _ = try! digest.update(withBytes: a2.description.data(using: .utf8)!) + let _ = try! digest.update(withBytes: Array(shareBundle.publicKey.description.data(using: .utf8)!)) + let _ = try! digest.update(withBytes: Array(encryptedShare.description.data(using: .utf8)!)) + let _ = try! digest.update(withBytes: Array(a1.description.data(using: .utf8)!)) + let _ = try! digest.update(withBytes: Array(a2.description.data(using: .utf8)!)) let challengeHash = try! digest.finish().toHexString() let challengeInt = Bignum(hex: challengeHash) % (q-1) @@ -200,9 +201,9 @@ public struct PVSSInstance { // Cancel fraction if possible var numerator = BigUInt(lagrangeCoefficient.numerator.description)! var denominator = BigUInt(lagrangeCoefficient.denominator.abs.description)! - let gcd = BigUInt.gcd(numerator, denominator) - numerator = numerator.divided(by: gcd).quotient - denominator = denominator.divided(by: gcd).quotient + let gcd = numerator.greatestCommonDivisor(with: denominator) + numerator = numerator.quotientAndRemainder(dividingBy: gcd).quotient + denominator = denominator.quotientAndRemainder(dividingBy: gcd).quotient let q1 = BigUInt((self.q - 1).description)! if let inverseDenominator = denominator.inverse(q1) { @@ -271,9 +272,9 @@ public struct PVSSInstance { // Cancel fraction if possible var numerator = BigUInt(lagrangeCoefficient.numerator.description)! var denominator = BigUInt(lagrangeCoefficient.denominator.abs.description)! - let gcd = BigUInt.gcd(numerator, denominator) - numerator = numerator.divided(by: gcd).quotient - denominator = denominator.divided(by: gcd).quotient + let gcd = numerator.greatestCommonDivisor(with: denominator) + numerator = numerator.quotientAndRemainder(dividingBy: gcd).quotient + denominator = denominator.quotientAndRemainder(dividingBy: gcd).quotient let q1 = BigUInt((self.q - 1).description)! if let inverseDenominator = denominator.inverse(q1) { diff --git a/Sources/Participant.swift b/Sources/PVSS/Participant.swift similarity index 92% rename from Sources/Participant.swift rename to Sources/PVSS/Participant.swift index 7050fdd..7fe8fef 100644 --- a/Sources/Participant.swift +++ b/Sources/PVSS/Participant.swift @@ -93,10 +93,10 @@ public class Participant { a[key] = (dleq.a1, dleq.a2) // Update challenge hash - let _ = try! challenge.update(withBytes: x.description.data(using: .utf8)!) - let _ = try! challenge.update(withBytes: share.description.data(using: .utf8)!) - let _ = try! challenge.update(withBytes: dleq.a1.description.data(using: .utf8)!) - let _ = try! challenge.update(withBytes: dleq.a2.description.data(using: .utf8)!) + let _ = try! challenge.update(withBytes: Array(x.description.data(using: .utf8)!)) + let _ = try! challenge.update(withBytes: Array(share.description.data(using: .utf8)!)) + let _ = try! challenge.update(withBytes: Array(dleq.a1.description.data(using: .utf8)!)) + let _ = try! challenge.update(withBytes: Array(dleq.a2.description.data(using: .utf8)!)) position += 1 } @@ -134,7 +134,7 @@ public class Participant { /// - Returns: The distribution bundle that is published so everyone (especially but not only the participants) can check the shares' integrity. Furthermore the participants extract their shares from it. public func distribute(secret: Bignum, publicKeys: [Bignum], threshold: Int) -> DistributionBundle { let polynomial = Polynomial(degree: threshold - 1, bitLength: pvssInstance.length, q: pvssInstance.q) - let w = Bignum((BigUInt.randomIntegerLessThan(BigUInt((pvssInstance.q).description)!)).description) + let w = Bignum((BigUInt.randomInteger(lessThan: BigUInt((pvssInstance.q).description)!)).description) return distribute(secret: secret, publicKeys: publicKeys, threshold: threshold, polynomial: polynomial, w: w) } @@ -155,10 +155,10 @@ public class Participant { var dleq = DLEQ(g1: pvssInstance.G, h1: publicKey, g2: share, h2: encryptedShare, length: pvssInstance.length, q: pvssInstance.q, alpha: privateKey, w: w) var digest = SHA2(variant: .sha256) - let _ = try! digest.update(withBytes: publicKey.description.data(using: .utf8)!) - let _ = try! digest.update(withBytes: encryptedShare.description.data(using: .utf8)!) - let _ = try! digest.update(withBytes: dleq.a1.description.data(using: .utf8)!) - let _ = try! digest.update(withBytes: dleq.a2.description.data(using: .utf8)!) + let _ = try! digest.update(withBytes: Array(publicKey.description.data(using: .utf8)!)) + let _ = try! digest.update(withBytes: Array(encryptedShare.description.data(using: .utf8)!)) + let _ = try! digest.update(withBytes: Array(dleq.a1.description.data(using: .utf8)!)) + let _ = try! digest.update(withBytes: Array(dleq.a2.description.data(using: .utf8)!)) let challengeHash = try! digest.finish().toHexString() let challengeInt = Bignum(hex: challengeHash) % (pvssInstance.q - 1) diff --git a/Sources/Polynomial.swift b/Sources/PVSS/Polynomial.swift similarity index 89% rename from Sources/Polynomial.swift rename to Sources/PVSS/Polynomial.swift index 1280c26..62d6ab5 100644 --- a/Sources/Polynomial.swift +++ b/Sources/PVSS/Polynomial.swift @@ -22,7 +22,7 @@ public struct Polynomial { for _ in 0...degree { let threshold = BigUInt(q.description)! - coefficientList.append(Bignum(BigUInt.randomIntegerLessThan(threshold).description)) + coefficientList.append(Bignum(BigUInt.randomInteger(lessThan: threshold).description)) } self.init(coefficients: coefficientList) diff --git a/Tests/PVSSTests/MathFunctionsTest.swift b/Tests/PVSSTests/MathFunctionsTest.swift index 69f2743..56f9919 100644 --- a/Tests/PVSSTests/MathFunctionsTest.swift +++ b/Tests/PVSSTests/MathFunctionsTest.swift @@ -65,8 +65,8 @@ class MathFunctionsTest: XCTestCase { let value2: Bignum = Bignum("14735247304952934566") var digest = SHA2(variant: .sha256) - let _ = try! digest.update(withBytes: value1.description.data(using: .utf8)!) - let _ = try! digest.update(withBytes: value2.description.data(using: .utf8)!) + let _ = try! digest.update(withBytes: Array(value1.description.data(using: .utf8)!)) + let _ = try! digest.update(withBytes: Array(value2.description.data(using: .utf8)!)) let result = try! digest.finish() XCTAssertEqual(result.toHexString(), "e25e5b7edf4ea66e5238393fb4f183e0fc1593c69a522f9255a51bd0bc2b7ba7") diff --git a/Tests/PVSSTests/PVSSTest.swift b/Tests/PVSSTests/PVSSTest.swift index d54d6ab..d5146ab 100644 --- a/Tests/PVSSTests/PVSSTest.swift +++ b/Tests/PVSSTests/PVSSTest.swift @@ -59,7 +59,7 @@ public class PVSSTest: XCTestCase { XCTAssert(BigUInt((pvss.q).description)!.isPrime()) XCTAssert(BigUInt((pvss.g).description)!.isPrime()) - XCTAssertEqual(pvss.g, Bignum((BigUInt((pvss.q-1).description)!.divided(by: 2).quotient).description)) + XCTAssertEqual(pvss.g, Bignum((BigUInt((pvss.q-1).description)!.quotientAndRemainder(dividingBy: 2).quotient).description)) } public func testDistribution() { @@ -147,7 +147,8 @@ public class PVSSTest: XCTestCase { public func testParallelReconstructionPerformance() { let pvss = PVSSInstance() let dealer = Participant(pvssInstance: pvss) - let keyCount = 20 + let keyCount = 75 + let threshold = keyCount / 2 let keyPairs: [(privateKey: Bignum, publicKey: Bignum)] = pvssKeyPairs.reduce([]) { (previouskeyPairs, keyPair) in var keyPairs = previouskeyPairs if keyPairs.count < keyCount { @@ -156,11 +157,18 @@ public class PVSSTest: XCTestCase { return keyPairs } let secret = Bignum(BigUInt.randomInteger(withExactWidth: 512).description) - let distributionBundle = dealer.distribute(secret: secret, publicKeys: keyPairs.map {$0.publicKey} , threshold: keyCount) + let distributionBundle = dealer.distribute(secret: secret, publicKeys: keyPairs.map {$0.publicKey} , threshold: threshold) let participants: [Participant] = keyPairs.map { Participant(pvssInstance: pvss, privateKey: $0.privateKey, publicKey: $0.publicKey) } let shareBundles = participants.map { $0.extractShare(distributionBundle: distributionBundle, privateKey: $0.privateKey)! } + let reconstructionShareBundles: [ShareBundle] = shareBundles.reduce([]) { (previousShareBundles, shareBundle) in + var shareBundles = previousShareBundles + if shareBundles.count < threshold { + shareBundles.append(shareBundle) + } + return shareBundles + } measure { - let _ = pvss.reconstructParallelized(shareBundles: shareBundles, distributionBundle: distributionBundle) + let _ = pvss.reconstructParallelized(shareBundles: reconstructionShareBundles, distributionBundle: distributionBundle, threads: 2) } }