Skip to content

Commit

Permalink
Release 2.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
leif-ibsen committed Aug 23, 2021
1 parent af585f7 commit bc3392f
Show file tree
Hide file tree
Showing 52 changed files with 438 additions and 111 deletions.
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ let package = Package(
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(url: "https://github.com/leif-ibsen/ASN1", from: "2.0.0"),
.package(url: "https://github.com/leif-ibsen/BigInt", from: "1.2.5"),
.package(url: "https://github.com/leif-ibsen/BigInt", from: "1.2.6"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ SwiftECC requires Swift 5.0. It also requires that the Int and UInt types be 64
In your project Package.swift file add a dependency like<br/>

dependencies: [
.package(url: "https://github.com/leif-ibsen/SwiftECC", from: "2.0.0"),
.package(url: "https://github.com/leif-ibsen/SwiftECC", from: "2.1.0"),
]

<h2><b>Basics</b></h2>
Expand Down Expand Up @@ -337,7 +337,7 @@ The SwiftECC package depends on the ASN1 and BigInt packages

dependencies: [
.package(url: "https://github.com/leif-ibsen/ASN1", from: "2.0.0"),
.package(url: "https://github.com/leif-ibsen/BigInt", from: "1.2.5"),
.package(url: "https://github.com/leif-ibsen/BigInt", from: "1.2.6"),
],

<h2><b>References</b></h2>
Expand Down
3 changes: 1 addition & 2 deletions Sources/SwiftECC/Base64.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,9 @@ public struct Base64 {
var bytes: Bytes = []
var eq = 0
var i = 0
var x = 0
var bbbb = Bytes(repeating: 0, count: 4)
for s in input {
x = Int(s.unicodeScalars.first!.value)
var x = Int(s.unicodeScalars.first!.value)
switch x {
case 65...90: // A .. Z
if eq > 0 {
Expand Down
15 changes: 14 additions & 1 deletion Sources/SwiftECC/Domain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public typealias Bytes = [Byte]
/// A Domain instance contains an elliptic curve domain - either with characteristic 2 or characteristic an odd prime.
/// Please refer [SEC 1] section 3.1.
///
public class Domain: CustomStringConvertible {
public class Domain: CustomStringConvertible, Equatable {

init(_ domainP: DomainP) {
self.name = domainP.name
Expand Down Expand Up @@ -303,6 +303,19 @@ public class Domain: CustomStringConvertible {

// MARK: Instance Methods

/// Equality of two Domain instances
///
/// - Parameters:
/// - d1: a Domain instance
/// - d2: a Domain instance
/// - Returns: *true* if d1 and d2 are equal, *false* otherwise
public static func == (d1: Domain, d2: Domain) -> Bool {
if d1.characteristic2 != d2.characteristic2 {
return false
}
return d1.p == d2.p && d1.a == d2.a && d1.b == d2.b && d1.g == d2.g && d1.order == d2.order && d1.cofactor == d2.cofactor
}

/// Doubles a curve Point
///
/// - Parameters:
Expand Down
22 changes: 21 additions & 1 deletion Sources/SwiftECC/Domain2/Domain2.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,10 @@ class Domain2 {
return pt.infinity ? Point2.INFINITY : Point2(pt.x, pt.x.plus(pt.y))
}

/*
// [CRANDALL] - algorithm 7.2.4
func multiply(_ pt: Point2, _ n: BInt) -> Point2 {
assert(0 <= n && n < self.order)
if n.isZero {
return Point2.INFINITY
}
Expand All @@ -122,7 +124,25 @@ class Domain2 {
}
return q
}

*/

// Montgomery ladder algorithm, about 40% slower than the above algorithm but runs in constant time
func multiply(_ pt: Point2, _ n: BInt) -> Point2 {
assert(0 <= n && n < self.order)
var r0 = Point2.INFINITY
var r1 = pt
for i in (0 ..< n.bitWidth).reversed() {
if n.testBit(i) {
r0 = add(r0, r1)
r1 = double(r1)
} else {
r1 = add(r0, r1)
r0 = double(r0)
}
}
return r0
}

// Multiply the generator point by n
func multiplyG(_ n: BInt) -> Point {
return multiplyGW(n, &self.gpts)
Expand Down
20 changes: 20 additions & 0 deletions Sources/SwiftECC/DomainP/DomainP.swift
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,10 @@ class DomainP {
return pt.infinity ? Point.INFINITY : Point(pt.x, self.p - pt.y)
}

/*
// [CRANDALL] - algorithm 7.2.4
func multiply(_ pt: Point, _ n: BInt) -> Point {
assert(0 <= n && n < self.order)
if n.isZero {
return Point.INFINITY
}
Expand All @@ -152,6 +154,24 @@ class DomainP {
}
return q
}
*/

// Montgomery ladder algorithm, about 40% slower than the above algorithm but runs in constant time
func multiply(_ pt: Point, _ n: BInt) -> Point {
assert(0 <= n && n < self.order)
var p0 = Point.INFINITY
var p1 = pt
for i in (0 ..< n.bitWidth).reversed() {
if n.testBit(i) {
p0 = add(p0, p1)
p1 = double(p1)
} else {
p1 = add(p0, p1)
p0 = double(p0)
}
}
return p0
}

// Multiply the generator point by n
func multiplyG(_ n: BInt) -> Point {
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftECC/PrivateKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public class ECPrivateKey: CustomStringConvertible {
}
let r = R.x.mod(order)
let s = (k.modInverse(order) * (h + r * self.s)).mod(order)
return ECSignature(r: self.domain.align(r.asMagnitudeBytes()), s: self.domain.align(s.asMagnitudeBytes()))
return ECSignature(domain: domain, r: self.domain.align(r.asMagnitudeBytes()), s: self.domain.align(s.asMagnitudeBytes()))
}

/// Signs a Data message with ECDSA
Expand Down
3 changes: 3 additions & 0 deletions Sources/SwiftECC/PublicKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ public class ECPublicKey: CustomStringConvertible {
/// - bw: Optional bitwidth used to select the proper message digest. By default the domain field size is used
/// - Returns: *true* iff the signature is verified
public func verify(signature: ECSignature, msg: Bytes, bw: Int? = nil) -> Bool {
if self.domain != signature.domain {
return false
}
let order = self.domain.order
guard signature.r.count > 0 && signature.s.count > 0 else {
return false
Expand Down
10 changes: 7 additions & 3 deletions Sources/SwiftECC/Signature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ public class ECSignature {
/// Creates a signature from its *r* and *s* components
///
/// - Parameters:
/// - domain: The domain of the signature
/// - r: The r component
/// - s: The s component
public init(r: Bytes, s: Bytes) {
public init(domain: Domain, r: Bytes, s: Bytes) {
self.domain = domain
self.r = r
self.s = s
}
Expand All @@ -44,17 +46,19 @@ public class ECSignature {
guard let s1 = seq.get(1) as? ASN1Integer else {
throw ECException.asn1Structure
}
self.init(r: domain.align(r0.value.asMagnitudeBytes()), s: domain.align(s1.value.asMagnitudeBytes()))
self.init(domain: domain, r: domain.align(r0.value.asMagnitudeBytes()), s: domain.align(s1.value.asMagnitudeBytes()))
}


// MARK: Stored Properties

/// The domain of the signature
public let domain: Domain
/// The *r* component of the signature
public let r: Bytes
/// The *s* component of the signature
public let s: Bytes


// MARK: Computed Properties

Expand Down
21 changes: 12 additions & 9 deletions Tests/SwiftECCTests/BlueTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -303,24 +303,27 @@ let encryptedA100_521: Bytes =
}

func testVerify256() throws {
let domain = Domain.instance(curve: .EC256r1)
let pub256 = try ECPublicKey(pem: pub256r1)
XCTAssert(pub256.verify(signature: ECSignature(r: emptyR256, s: emptyS256), msg: empty.data(using: .utf8)!))
XCTAssert(pub256.verify(signature: ECSignature(r: foxR256, s: foxS256), msg: fox.data(using: .utf8)!))
XCTAssert(pub256.verify(signature: ECSignature(r: a100_R256, s: a100_S256), msg: a100.data(using: .utf8)!))
XCTAssert(pub256.verify(signature: ECSignature(domain: domain, r: emptyR256, s: emptyS256), msg: empty.data(using: .utf8)!))
XCTAssert(pub256.verify(signature: ECSignature(domain: domain, r: foxR256, s: foxS256), msg: fox.data(using: .utf8)!))
XCTAssert(pub256.verify(signature: ECSignature(domain: domain, r: a100_R256, s: a100_S256), msg: a100.data(using: .utf8)!))
}

func testVerify384() throws {
let domain = Domain.instance(curve: .EC384r1)
let pub384 = try ECPublicKey(pem: pub384r1)
XCTAssert(pub384.verify(signature: ECSignature(r: emptyR384, s: emptyS384), msg: empty.data(using: .utf8)!))
XCTAssert(pub384.verify(signature: ECSignature(r: foxR384, s: foxS384), msg: fox.data(using: .utf8)!))
XCTAssert(pub384.verify(signature: ECSignature(r: a100_R384, s: a100_S384), msg: a100.data(using: .utf8)!))
XCTAssert(pub384.verify(signature: ECSignature(domain: domain, r: emptyR384, s: emptyS384), msg: empty.data(using: .utf8)!))
XCTAssert(pub384.verify(signature: ECSignature(domain: domain, r: foxR384, s: foxS384), msg: fox.data(using: .utf8)!))
XCTAssert(pub384.verify(signature: ECSignature(domain: domain, r: a100_R384, s: a100_S384), msg: a100.data(using: .utf8)!))
}

func testVerify521() throws {
let domain = Domain.instance(curve: .EC521r1)
let pub521 = try ECPublicKey(pem: pub521r1)
XCTAssert(pub521.verify(signature: ECSignature(r: emptyR521, s: emptyS521), msg: empty.data(using: .utf8)!))
XCTAssert(pub521.verify(signature: ECSignature(r: foxR521, s: foxS521), msg: fox.data(using: .utf8)!))
XCTAssert(pub521.verify(signature: ECSignature(r: a100_R521, s: a100_S521), msg: a100.data(using: .utf8)!))
XCTAssert(pub521.verify(signature: ECSignature(domain: domain, r: emptyR521, s: emptyS521), msg: empty.data(using: .utf8)!))
XCTAssert(pub521.verify(signature: ECSignature(domain: domain, r: foxR521, s: foxS521), msg: fox.data(using: .utf8)!))
XCTAssert(pub521.verify(signature: ECSignature(domain: domain, r: a100_R521, s: a100_S521), msg: a100.data(using: .utf8)!))
}

}
13 changes: 13 additions & 0 deletions Tests/SwiftECCTests/DomainTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,18 @@ class DomainTest: XCTestCase {
XCTAssertEqual(d.reduceModP(domain.p + 1), BInt.ONE)
}

func equalTest(_ c: ECCurve) {
let domain = Domain.instance(curve: c)
for c1 in ECCurve.allCases {
let domain1 = Domain.instance(curve: c1)
if domain.name == domain1.name {
XCTAssertTrue(domain == domain1)
} else {
XCTAssertFalse(domain == domain1)
}
}
}

func doTest(_ c: ECCurve) throws {
let domain = Domain.instance(curve: c)
try domainTest(domain, try domain.multiplyPoint(domain.g, BInt(0)))
Expand All @@ -65,6 +77,7 @@ class DomainTest: XCTestCase {
try multiplyGTest(domain, BInt(2))
try multiplyGTest(domain, BInt(bitWidth: domain.g.x.bitWidth / 2))
reduceModPTest(domain)
equalTest(c)
}

func test() throws {
Expand Down
8 changes: 4 additions & 4 deletions Tests/SwiftECCTests/FuzzTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ class FuzzTest: XCTestCase {
for c in ECCurve.allCases {
let domain = Domain.instance(curve: c)
let (pub, _) = domain.makeKeyPair()
XCTAssertFalse(pub.verify(signature: ECSignature(r: [], s: []), msg: [1]))
XCTAssertFalse(pub.verify(signature: ECSignature(r: Bytes(repeating: 1, count: 100000), s: Bytes(repeating: 1, count: 100000)), msg: [1]))
XCTAssertFalse(pub.verify(signature: ECSignature(r: [1], s: [1]), msg: []))
XCTAssertFalse(pub.verify(signature: ECSignature(r: Bytes(repeating: 1, count: 100000), s: Bytes(repeating: 1, count: 100000)), msg: []))
XCTAssertFalse(pub.verify(signature: ECSignature(domain: domain, r: [], s: []), msg: [1]))
XCTAssertFalse(pub.verify(signature: ECSignature(domain: domain, r: Bytes(repeating: 1, count: 100000), s: Bytes(repeating: 1, count: 100000)), msg: [1]))
XCTAssertFalse(pub.verify(signature: ECSignature(domain: domain, r: [1], s: [1]), msg: []))
XCTAssertFalse(pub.verify(signature: ECSignature(domain: domain, r: Bytes(repeating: 1, count: 100000), s: Bytes(repeating: 1, count: 100000)), msg: []))
}
}

Expand Down
8 changes: 4 additions & 4 deletions Tests/SwiftECCTests/SignatureTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ class SignatureTest: XCTestCase {

// Signature r and s out of range

let sig3 = ECSignature(r: [0], s: sig2.s)
let sig3 = ECSignature(domain: domain, r: [0], s: sig2.s)
XCTAssertFalse(pub.verify(signature: sig3, msg: data1))
let sig4 = ECSignature(r: Bytes(repeating: 0xff, count: (domain.order.bitWidth + 7) / 8), s: sig2.s)
let sig4 = ECSignature(domain: domain, r: Bytes(repeating: 0xff, count: (domain.order.bitWidth + 7) / 8), s: sig2.s)
XCTAssertFalse(pub.verify(signature: sig4, msg: data1))
let sig5 = ECSignature(r: sig2.r, s: [0])
let sig5 = ECSignature(domain: domain, r: sig2.r, s: [0])
XCTAssertFalse(pub.verify(signature: sig5, msg: data1))
let sig6 = ECSignature(r: sig2.r, s: Bytes(repeating: 0xff, count: (domain.order.bitWidth + 7) / 8))
let sig6 = ECSignature(domain: domain, r: sig2.r, s: Bytes(repeating: 0xff, count: (domain.order.bitWidth + 7) / 8))
XCTAssertFalse(pub.verify(signature: sig6, msg: data1))
}

Expand Down
Loading

0 comments on commit bc3392f

Please sign in to comment.