Skip to content

Commit 710bed0

Browse files
committed
Add ECDH support, tested with Wycheproof test vectors
1 parent 92a6f8c commit 710bed0

File tree

16 files changed

+4866
-98
lines changed

16 files changed

+4866
-98
lines changed

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
/*.xcodeproj
5+
xcuserdata/
6+
DerivedData/
7+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

Lines changed: 0 additions & 7 deletions
This file was deleted.

.swiftpm/xcode/xcuserdata/sajjon.xcuserdatad/xcschemes/xcschememanagement.plist

Lines changed: 0 additions & 79 deletions
This file was deleted.

Package.resolved

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ let package = Package(
2323

2424
dependencies: [
2525
.package(url: "https://github.com/apple/swift-crypto.git", "2.0.0" ..< "3.0.0"),
26-
.package(url: "https://github.com/attaswift/BigInt.git", from: "5.3.0")
26+
.package(url: "https://github.com/attaswift/BigInt.git", from: "5.3.0"),
27+
.package(url: "https://github.com/filom/ASN1Decoder", .branch("master"))
2728
],
2829

2930
targets: [
@@ -51,6 +52,7 @@ let package = Package(
5152
"libsecp256k1/autogen.sh",
5253
"libsecp256k1/libsecp256k1.pc.in",
5354
"libsecp256k1/doc",
55+
"libsecp256k1/contrib",
5456
"libsecp256k1/ci",
5557
"libsecp256k1/sage",
5658
"libsecp256k1/build-aux",
@@ -59,19 +61,21 @@ let package = Package(
5961
"libsecp256k1/COPYING",
6062
"libsecp256k1/SECURITY.md"
6163
],
64+
sources: ["src", "libsecp256k1/src"],
6265
cSettings: [
63-
.headerSearchPath("secp256k1"),
66+
.headerSearchPath("secp256k1/include/"),
6467
// Basic config values that are universal and require no dependencies.
6568
// https://github.com/bitcoin-core/secp256k1/blob/master/src/basic-config.h#L12-L13
6669
.define("ECMULT_WINDOW_SIZE", to: "15"),
6770
.define("ECMULT_GEN_PREC_BITS", to: "4"),
68-
// Enabling additional secp256k1 modules.
69-
.define("SECP256K1_ECDH_H"),
70-
.define("SECP256K1_MODULE_ECDH_MAIN_H"),
71-
.define("SECP256K1_EXTRAKEYS_H"),
72-
.define("SECP256K1_MODULE_EXTRAKEYS_MAIN_H"),
73-
.define("SECP256K1_SCHNORRSIG_H"),
74-
.define("SECP256K1_MODULE_SCHNORRSIG_MAIN_H"),
71+
72+
// Enable modules in secp256k1.
73+
// See bottom of: Sources/secp256k1/libsecp256k1/src/secp256k1.c
74+
// For list
75+
.define("ENABLE_MODULE_ECDH"),
76+
.define("ENABLE_MODULE_RECOVERY"),
77+
.define("ENABLE_MODULE_SCHNORRSIG"),
78+
.define("ENABLE_MODULE_EXTRAKEYS"),
7579
]
7680
),
7781

@@ -87,7 +91,9 @@ let package = Package(
8791
.testTarget(
8892
name: "K1Tests",
8993
dependencies: [
90-
"K1"
94+
"K1",
95+
// "ASN1Swift"
96+
"ASN1Decoder"
9197
],
9298
resources: [
9399
.process("Resources/"),

Sources/K1/K1/K1/Error.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public extension K1 {
2929
case failedToSerializeCompactSignature
3030
case failedToSerializeDERSignature
3131
case failedToSignDigest
32+
case failedToPerformDiffieHellmanKeyExchange
3233
}
3334

3435
}

Sources/K1/K1/Keys/PrivateKey/PrivateKey/PrivateKey+Bridge+To+C.swift

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,45 @@ extension Bridge {
3434
count: MemoryLayout.size(ofValue: signatureBridgedToC.data)
3535
)
3636
}
37+
38+
static func ecdh(
39+
publicKey publicKeyBytes: [UInt8],
40+
privateKey: SecureBytes
41+
) throws -> Data {
42+
43+
var publicKeyBridgedToC = secp256k1_pubkey()
44+
45+
try Self.call(ifFailThrow: .failedToSerializePublicKeyIntoBytes) { context in
46+
/* "Serialize a pubkey object into a serialized byte sequence." */
47+
secp256k1_ec_pubkey_parse(
48+
context,
49+
&publicKeyBridgedToC,
50+
publicKeyBytes,
51+
publicKeyBytes.count
52+
)
53+
}
54+
55+
var sharedPublicPointBytes = [UInt8](
56+
repeating: 0,
57+
count: K1.Format.uncompressed.length
58+
)
59+
60+
try Self.call(
61+
ifFailThrow: .failedToPerformDiffieHellmanKeyExchange
62+
) { context in
63+
/** Compute an EC Diffie-Hellman secret in constant time
64+
*/
65+
secp256k1_ecdh(
66+
context,
67+
&sharedPublicPointBytes, // output
68+
&publicKeyBridgedToC, // pubkey
69+
privateKey.backing.bytes, // seckey
70+
ecdh_skip_hash_extract_x_and_y, // hashfp
71+
nil // arbitrary data pointer that is passed through to hashfp
72+
)
73+
}
74+
return Data(sharedPublicPointBytes)
75+
}
3776
}
3877

3978
public extension K1.PrivateKey {
@@ -47,4 +86,17 @@ public extension K1.PrivateKey {
4786
signatureData
4887
)
4988
}
89+
90+
/// Performs a key agreement with provided public key share.
91+
///
92+
/// - Parameter publicKeyShare: The public key to perform the ECDH with.
93+
/// - Returns: Returns the public point obtain by performing EC mult between
94+
/// this `privateKey` and `publicKeyShare`
95+
/// - Throws: An error occurred while computing the shared secret
96+
func sharedSecret(with publicKeyShare: K1.PublicKey) throws -> Data {
97+
let sharedSecretData = try withSecureBytes { secureBytes in
98+
try Bridge.ecdh(publicKey: publicKeyShare.rawRepresentation, privateKey: secureBytes)
99+
}
100+
return sharedSecretData
101+
}
50102
}

Sources/K1/K1/Keys/PrivateKey/Wrapped/PrivateKey+Wrapped.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ internal extension K1.PrivateKey.Wrapped {
6767

6868
var attempt = 0
6969

70-
while attempt < 10_000 {
70+
while attempt < 100 {
7171
defer { attempt += 1 }
7272
do {
7373
let secureBytes = SecureBytes(count: Self.byteCount)
@@ -81,7 +81,7 @@ internal extension K1.PrivateKey.Wrapped {
8181

8282
// Probability of this happening is:
8383
// n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
84-
// (n / 2^256) ^ 10_000 = lim 0
84+
// (n / 2^256) ^ 100 = lim 0
8585
// I.e. will not happen.
8686
fatalError("""
8787
Failed to generate private key after #\(attempt) attempts.

0 commit comments

Comments
 (0)