diff --git a/Sources/K1/K1/ECDSA/ECDSA.swift b/Sources/K1/K1/ECDSA/ECDSA.swift index 83a356e..4a81445 100644 --- a/Sources/K1/K1/ECDSA/ECDSA.swift +++ b/Sources/K1/K1/ECDSA/ECDSA.swift @@ -72,7 +72,7 @@ extension K1.ECDSA.SigningOptions.NonceFunction { public static let byteCount = Curve.Field.byteCount public init(arbitraryData: [UInt8]) throws { guard arbitraryData.count == Self.byteCount else { - throw K1.Error.incorrectByteCountOfArbitraryDataForNonceFunction + throw K1.Error.incorrectParameterSize } self.arbitraryData = arbitraryData } diff --git a/Sources/K1/K1/ECDSA/ECDSASignatureRecoverable.swift b/Sources/K1/K1/ECDSA/ECDSASignatureRecoverable.swift index 4ca195d..18cd37a 100644 --- a/Sources/K1/K1/ECDSA/ECDSASignatureRecoverable.swift +++ b/Sources/K1/K1/ECDSA/ECDSASignatureRecoverable.swift @@ -87,10 +87,7 @@ extension K1.ECDSA.Recoverable.Signature { recoveryID: RecoveryID ) throws { guard compact.count == Self.byteCountRS else { - throw K1.Error.failedToDeserializeCompactRSRecoverableSignatureInvalidByteCount( - got: compact.count, - expected: Self.byteCountRS - ) + throw K1.Error.incorrectKeySize } self.compact = compact self.recoveryID = recoveryID @@ -108,7 +105,7 @@ extension K1.ECDSA.Recoverable.Signature.Compact { format: SerializationFormat ) throws { guard rawRepresentation.count == Self.byteCount else { - throw K1.Error.failedToDeserializeCompactRecoverableSignatureInvalidByteCount(got: rawRepresentation.count, expected: Self.byteCount) + throw K1.Error.incorrectKeySize } switch format { case .vrs: diff --git a/Sources/K1/K1/ECDSA/RecoveryID.swift b/Sources/K1/K1/ECDSA/RecoveryID.swift index bc9fac0..d8d1acd 100644 --- a/Sources/K1/K1/ECDSA/RecoveryID.swift +++ b/Sources/K1/K1/ECDSA/RecoveryID.swift @@ -17,14 +17,14 @@ extension K1.ECDSA.Recoverable.Signature { extension K1.ECDSA.Recoverable.Signature.RecoveryID { public init(byte: UInt8) throws { guard let self_ = Self(rawValue: byte) else { - throw K1.Error.invalidRecoveryID(got: Int(byte)) + throw K1.Error.invalidParameter } self = self_ } public init(recid: Int32) throws { guard recid <= 3, recid >= 0 else { - throw K1.Error.invalidRecoveryID(got: Int(recid)) + throw K1.Error.invalidParameter } try self.init(byte: UInt8(recid)) } diff --git a/Sources/K1/K1/Keys/PrivateKeyImplementation.swift b/Sources/K1/K1/Keys/PrivateKeyImplementation.swift index 2c2d6b9..946a674 100644 --- a/Sources/K1/K1/Keys/PrivateKeyImplementation.swift +++ b/Sources/K1/K1/Keys/PrivateKeyImplementation.swift @@ -56,7 +56,7 @@ extension K1._PrivateKeyImplementation { let parsed = try ASN1.PKCS8PrivateKey(asn1Encoded: Array(pem.derBytes)) self = try .init(rawRepresentation: parsed.privateKey.privateKey) default: - throw K1.Error.invalidPEMDocument + throw K1.ASN1Error.invalidPEMDocument } } @@ -73,7 +73,7 @@ extension K1._PrivateKeyImplementation { ) throws { let length = x963Representation.withUnsafeBytes { $0.count } guard length == Self.x963ByteCount else { - throw K1.Error.incorrectByteCountOfX963PrivateKey(got: length, expected: Self.x963ByteCount) + throw K1.Error.incorrectKeySize } let publicKeyX963 = x963Representation.bytes.prefix(K1._PublicKeyImplementation.x963ByteCount) @@ -81,7 +81,7 @@ extension K1._PrivateKeyImplementation { let privateKeyRaw = x963Representation.bytes.suffix(Self.rawByteCount) try self.init(rawRepresentation: privateKeyRaw) guard self.publicKey == publicKeyFromX963 else { - throw K1.Error.invalidPrivateX963RepresentationPublicKeyDiscrepancy + throw K1.Error.invalidKey } // All good } diff --git a/Sources/K1/K1/Keys/PublicKeyImplementation.swift b/Sources/K1/K1/Keys/PublicKeyImplementation.swift index cb71ac0..d2165e3 100644 --- a/Sources/K1/K1/Keys/PublicKeyImplementation.swift +++ b/Sources/K1/K1/Keys/PublicKeyImplementation.swift @@ -61,7 +61,7 @@ extension K1._PublicKeyImplementation { init(pemRepresentation: String) throws { let pem = try ASN1.PEMDocument(pemString: pemRepresentation) guard pem.type == Self.pemType else { - throw K1.Error.invalidPEMDocument + throw K1.ASN1Error.invalidPEMDocument } self = try .init(derRepresentation: pem.derBytes) } diff --git a/Sources/K1/K1/Schnorr/Schnorr.swift b/Sources/K1/K1/Schnorr/Schnorr.swift index 5ef52e5..d86827e 100644 --- a/Sources/K1/K1/Schnorr/Schnorr.swift +++ b/Sources/K1/K1/Schnorr/Schnorr.swift @@ -58,7 +58,7 @@ extension K1.Schnorr.SigningOptions.AuxiliaryRandomData { public static let byteCount = Curve.Field.byteCount public init(aux: some DataProtocol) throws { guard aux.count == Self.byteCount else { - throw K1.Error.failedToSchnorrSignDigestProvidedRandomnessInvalidLength + throw K1.Error.incorrectParameterSize } self.aux = [UInt8](aux) } diff --git a/Sources/K1/Support/FFI/API/ECDH/FFI+ECDH.swift b/Sources/K1/Support/FFI/API/ECDH/FFI+ECDH.swift index b960bef..44021e3 100644 --- a/Sources/K1/Support/FFI/API/ECDH/FFI+ECDH.swift +++ b/Sources/K1/Support/FFI/API/ECDH/FFI+ECDH.swift @@ -68,7 +68,7 @@ extension FFI.ECDH { }() var publicKeyRaw = publicKey.raw try FFI.call( - ifFailThrow: .failedToPerformDiffieHellmanKeyExchange + ifFailThrow: .ecdh ) { context in secp256k1_ecdh( context, diff --git a/Sources/K1/Support/FFI/API/ECDSA/FFI+ECDSA.swift b/Sources/K1/Support/FFI/API/ECDSA/FFI+ECDSA.swift index 4f21f77..e631259 100644 --- a/Sources/K1/Support/FFI/API/ECDSA/FFI+ECDSA.swift +++ b/Sources/K1/Support/FFI/API/ECDSA/FFI+ECDSA.swift @@ -38,16 +38,13 @@ extension FFI.ECDSA { options: K1.ECDSA.SigningOptions = .default ) throws -> WrappedSignature where WrappedSignature: WrappedECDSASignature { guard message.count == Curve.Field.byteCount else { - throw K1.Error.unableToSignMessageHasInvalidLength( - got: message.count, - expected: Curve.Field.byteCount - ) + throw K1.Error.incorrectParameterSize } var raw = WrappedSignature.Raw() try FFI.call( - ifFailThrow: .failedToECDSASignDigest + ifFailThrow: .ecdsaSign ) { context in WrappedSignature.sign()( context, diff --git a/Sources/K1/Support/FFI/API/ECDSA/NonRecovery/FFI+ECDSA+NonRecovery.swift b/Sources/K1/Support/FFI/API/ECDSA/NonRecovery/FFI+ECDSA+NonRecovery.swift index 04586bf..fda0043 100644 --- a/Sources/K1/Support/FFI/API/ECDSA/NonRecovery/FFI+ECDSA+NonRecovery.swift +++ b/Sources/K1/Support/FFI/API/ECDSA/NonRecovery/FFI+ECDSA+NonRecovery.swift @@ -28,8 +28,12 @@ extension FFI.ECDSA.NonRecoverable { static func compact(_ wrapped: Wrapped) throws -> Data { var out = [UInt8](repeating: 0, count: Self.byteCount) var rawSignature = wrapped.raw - try FFI.call(ifFailThrow: .failedToSerializeSignature) { context in - secp256k1_ecdsa_signature_serialize_compact(context, &out, &rawSignature) + try FFI.call(ifFailThrow: .ecdsaSignatureSerializeCompact) { context in + secp256k1_ecdsa_signature_serialize_compact( + context, + &out, + &rawSignature + ) } return Data(out) } @@ -40,7 +44,7 @@ extension FFI.ECDSA.NonRecoverable { var derMaxLength = 75 // in fact max is 73, but we can have some margin. var derSignature = [UInt8](repeating: 0, count: derMaxLength) var rawSignature = wrapped.raw - try FFI.call(ifFailThrow: .failedToSerializeDERSignature) { context in + try FFI.call(ifFailThrow: .ecdsaSignatureSerializeDER) { context in secp256k1_ecdsa_signature_serialize_der( context, &derSignature, @@ -60,7 +64,7 @@ extension FFI.ECDSA.NonRecoverable { message: [UInt8] ) throws -> FFI.PublicKey.Wrapped { guard message.count == Curve.Field.byteCount else { - throw K1.Error.unableToRecoverMessageHasInvalidLength(got: message.count, expected: Curve.Field.byteCount) + throw K1.Error.incorrectParameterSize } let nonRecoverableCompact = try FFI.ECDSA.NonRecoverable.compact(wrapped) return try Self.recoverPublicKey( @@ -76,14 +80,11 @@ extension FFI.ECDSA.NonRecoverable { message: [UInt8] ) throws -> FFI.PublicKey.Wrapped { guard message.count == Curve.Field.byteCount else { - throw K1.Error.unableToRecoverMessageHasInvalidLength( - got: message.count, - expected: Curve.Field.byteCount - ) + throw K1.Error.incorrectParameterSize } var compact = [UInt8](nonRecoverableCompact) var recoverable = secp256k1_ecdsa_recoverable_signature() - try FFI.call(ifFailThrow: .failedToParseRecoverableSignatureFromCompact) { context in + try FFI.call(ifFailThrow: .recoverableSignatureParseCompact) { context in secp256k1_ecdsa_recoverable_signature_parse_compact( context, &recoverable, @@ -92,7 +93,7 @@ extension FFI.ECDSA.NonRecoverable { ) } var publicKeyRaw = secp256k1_pubkey() - try FFI.call(ifFailThrow: .failedToRecoverPublicKey) { context in + try FFI.call(ifFailThrow: .recover) { context in secp256k1_ecdsa_recover( context, &publicKeyRaw, diff --git a/Sources/K1/Support/FFI/API/ECDSA/Recovery/FFI+ECDSA+Recovery.swift b/Sources/K1/Support/FFI/API/ECDSA/Recovery/FFI+ECDSA+Recovery.swift index b4f7f9e..9678a56 100644 --- a/Sources/K1/Support/FFI/API/ECDSA/Recovery/FFI+ECDSA+Recovery.swift +++ b/Sources/K1/Support/FFI/API/ECDSA/Recovery/FFI+ECDSA+Recovery.swift @@ -18,7 +18,7 @@ extension FFI.ECDSA.Recoverable { ) throws -> Wrapped { var raw = Wrapped.Raw() try FFI.call( - ifFailThrow: .failedSignatureToConvertRecoverableSignatureToCompact + ifFailThrow: .recoverableSignatureParseCompact ) { context in secp256k1_ecdsa_recoverable_signature_parse_compact( context, @@ -40,7 +40,7 @@ extension FFI.ECDSA.Recoverable { var recoveryID: Int32 = 0 var rawSignature = wrapped.raw try FFI.call( - ifFailThrow: .failedSignatureToConvertRecoverableSignatureToCompact + ifFailThrow: .recoverableSignatureSerializeCompact ) { context in secp256k1_ecdsa_recoverable_signature_serialize_compact( context, @@ -62,7 +62,7 @@ extension FFI.ECDSA.Recoverable { var recoverable = wrapped.raw try FFI.call( - ifFailThrow: .failedToConvertRecoverableSignatureToNonRecoverable + ifFailThrow: .recoverableSignatureConvert ) { context in secp256k1_ecdsa_recoverable_signature_convert( context, @@ -82,12 +82,12 @@ extension FFI.ECDSA.Recoverable { message: [UInt8] ) throws -> FFI.PublicKey.Wrapped { guard message.count == Curve.Field.byteCount else { - throw K1.Error.unableToRecoverMessageHasInvalidLength(got: message.count, expected: Curve.Field.byteCount) + throw K1.Error.incorrectParameterSize } var rawSignature = wrapped.raw var rawPublicKey = secp256k1_pubkey() try FFI.call( - ifFailThrow: .failedToRecoverPublicKey + ifFailThrow: .recover ) { context in secp256k1_ecdsa_recover( context, diff --git a/Sources/K1/Support/FFI/API/Keys/PrivateKey/PrivateKey+Wrapped.swift b/Sources/K1/Support/FFI/API/Keys/PrivateKey/PrivateKey+Wrapped.swift index d2ca3e8..5fd6f18 100644 --- a/Sources/K1/Support/FFI/API/Keys/PrivateKey/PrivateKey+Wrapped.swift +++ b/Sources/K1/Support/FFI/API/Keys/PrivateKey/PrivateKey+Wrapped.swift @@ -10,14 +10,11 @@ extension FFI { fileprivate init(secureBytes: SecureBytes) throws { guard secureBytes.count == Curve.Field.byteCount else { - throw K1.Error.failedToInitializePrivateKeyIncorrectByteCount( - got: secureBytes.count, - expected: Curve.Field.byteCount - ) + throw K1.Error.incorrectKeySize } if secureBytes.allSatisfy({ $0 == .zero }) { - throw K1.Error.invalidPrivateKeyMustNotBeZero + throw K1.Error.invalidKey } self.secureBytes = secureBytes @@ -25,8 +22,12 @@ extension FFI { self.publicKey = try secureBytes.withUnsafeMutableBytes { seckey in var raw = secp256k1_pubkey() - try FFI.call(ifFailThrow: .invalidPrivateKeyMustBeSmallerThanOrder) { context in - secp256k1_ec_pubkey_create(context, &raw, seckey.baseAddress!) + try FFI.call(ifFailThrow: .publicKeyCreate) { context in + secp256k1_ec_pubkey_create( + context, + &raw, + seckey.baseAddress! + ) } return FFI.PublicKey.Wrapped(raw: raw) diff --git a/Sources/K1/Support/FFI/API/Keys/PublicKey/FFI+PublicKey.swift b/Sources/K1/Support/FFI/API/Keys/PublicKey/FFI+PublicKey.swift index c688978..8e7ae40 100644 --- a/Sources/K1/Support/FFI/API/Keys/PublicKey/FFI+PublicKey.swift +++ b/Sources/K1/Support/FFI/API/Keys/PublicKey/FFI+PublicKey.swift @@ -19,7 +19,7 @@ extension FFI.PublicKey { try contiguousBytes.withUnsafeBytes { bufferPointer throws -> Wrapped in let expected = Self.x963ByteCount guard bufferPointer.count == expected else { - throw K1.Error.incorrectByteCountOfX963PublicKey(got: bufferPointer.count, expected: expected) + throw K1.Error.incorrectKeySize } return try Self._deserialize(bytes: [UInt8](bufferPointer)) } @@ -32,14 +32,9 @@ extension FFI.PublicKey { try contiguousBytes.withUnsafeBytes { bufferPointer throws -> Wrapped in let expected = Self.rawByteCount guard bufferPointer.count == expected else { - throw K1.Error.incorrectByteCountOfRawPublicKey(got: bufferPointer.count, expected: expected) - } - // We can simply prepend `04` and parse as x963Representation - do { - return try Self.deserialize(x963Representation: [0x04] + [UInt8](bufferPointer)) - } catch { - throw K1.Error.unableToDeserializePublicKeyFromRawRepresentation + throw K1.Error.incorrectKeySize } + return try Self.deserialize(x963Representation: [0x04] + [UInt8](bufferPointer)) } } @@ -50,7 +45,7 @@ extension FFI.PublicKey { try contiguousBytes.withUnsafeBytes { bufferPointer throws -> Wrapped in let expected = Self.compressedByteCount guard bufferPointer.count == expected else { - throw K1.Error.incorrectByteCountOfCompressedPublicKey(got: bufferPointer.count, expected: expected) + throw K1.Error.incorrectKeySize } return try Self._deserialize(bytes: [UInt8](bufferPointer)) } @@ -59,7 +54,7 @@ extension FFI.PublicKey { private static func _deserialize(bytes: [UInt8]) throws -> Wrapped { var raw = secp256k1_pubkey() try FFI.call( - ifFailThrow: .failedToDeserializePublicKey + ifFailThrow: .publicKeyParse ) { context in secp256k1_ec_pubkey_parse( context, @@ -81,7 +76,7 @@ extension FFI.PublicKey { var byteCount = format.length var out = [UInt8](repeating: 0x00, count: byteCount) var publicKeyRaw = wrapped.raw - try FFI.call(ifFailThrow: .failedToSerializePublicKey) { context in + try FFI.call(ifFailThrow: .publicKeySerialize) { context in secp256k1_ec_pubkey_serialize( context, &out, diff --git a/Sources/K1/Support/FFI/API/Schnorr/FFI+Schnorr.swift b/Sources/K1/Support/FFI/API/Schnorr/FFI+Schnorr.swift index 5afcad0..027efdf 100644 --- a/Sources/K1/Support/FFI/API/Schnorr/FFI+Schnorr.swift +++ b/Sources/K1/Support/FFI/API/Schnorr/FFI+Schnorr.swift @@ -16,7 +16,7 @@ extension FFI.Schnorr { try FFI.toC { ffi -> Bool in var publicKeyX = secp256k1_xonly_pubkey() var publicKeyRaw = publicKey.raw - try FFI.call(ifFailThrow: .failedToSchnorrVerifyGettingXFromPubKey) { context in + try FFI.call(ifFailThrow: .xonlyPublicKeyFromPublicKey) { context in secp256k1_xonly_pubkey_from_pubkey( context, &publicKeyX, @@ -48,10 +48,7 @@ extension FFI.Schnorr { guard message.count == Curve.Field.byteCount else { - throw K1.Error.unableToSignMessageHasInvalidLength( - got: message.count, - expected: Curve.Field.byteCount - ) + throw K1.Error.incorrectParameterSize } var signatureOut = [UInt8](repeating: 0, count: FFI.Schnorr.Wrapped.byteCount) @@ -59,7 +56,7 @@ extension FFI.Schnorr { var keyPair = secp256k1_keypair() try FFI.call( - ifFailThrow: .failedToInitializeKeyPairForSchnorrSigning + ifFailThrow: .keypairCreate ) { context in secp256k1_keypair_create( context, @@ -69,7 +66,7 @@ extension FFI.Schnorr { } try FFI.call( - ifFailThrow: .failedToSchnorrSignDigest + ifFailThrow: .schnorrSign ) { context in secp256k1_schnorrsig_sign32( context, diff --git a/Sources/K1/Support/FFI/API/Schnorr/Schnorr+Wrapped.swift b/Sources/K1/Support/FFI/API/Schnorr/Schnorr+Wrapped.swift index c1b4214..68c97ea 100644 --- a/Sources/K1/Support/FFI/API/Schnorr/Schnorr+Wrapped.swift +++ b/Sources/K1/Support/FFI/API/Schnorr/Schnorr+Wrapped.swift @@ -9,10 +9,7 @@ extension FFI.Schnorr { init(bytes: [UInt8]) throws { guard bytes.count == Self.byteCount else { - throw K1.Error.failedToInitSchnorrSignatureInvalidByteCount( - got: bytes.count, - expected: Self.byteCount - ) + throw K1.Error.incorrectParameterSize } self.bytes = bytes } diff --git a/Sources/K1/Support/FFI/Internals/FFI+Call.swift b/Sources/K1/Support/FFI/Internals/FFI+Call.swift index 435350f..a9a688a 100644 --- a/Sources/K1/Support/FFI/Internals/FFI+Call.swift +++ b/Sources/K1/Support/FFI/Internals/FFI+Call.swift @@ -9,7 +9,7 @@ final class FFI { /* "Create a secp256k1 context object." */ let context = secp256k1_context_create(Context.sign.rawValue | Context.verify.rawValue) else { - throw K1.Error.failedToCreateContextForSecp256k1 + throw K1.Error.underlyingLibsecp256k1Error(.failedToCreateContextForSecp256k1) } self.context = context @@ -43,18 +43,18 @@ extension FFI { } func call( - ifFailThrow error: K1.Error, + ifFailThrow error: FFI.Error, _ method: (OpaquePointer) -> Int32 ) throws { let result = callWithResultCode(method) let successCode = 1 guard result == successCode else { - throw error + throw K1.Error.underlyingLibsecp256k1Error(error) } } static func call( - ifFailThrow error: K1.Error, + ifFailThrow error: FFI.Error, _ method: (OpaquePointer) -> Int32 ) throws { try toC { ffi in diff --git a/Sources/K1/Support/FFI/Internals/FFI+Raw.swift b/Sources/K1/Support/FFI/Internals/FFI+Raw.swift index 8790a56..6495750 100644 --- a/Sources/K1/Support/FFI/Internals/FFI+Raw.swift +++ b/Sources/K1/Support/FFI/Internals/FFI+Raw.swift @@ -12,10 +12,7 @@ extension Raw { guard rawRepresentation.count == expected else { - throw K1.Error.incorrectByteCountOfRawRecoverableSignature( - got: rawRepresentation.count, - expected: expected - ) + throw K1.Error.incorrectParameterSize } var raw = secp256k1_ecdsa_recoverable_signature() withUnsafeMutableBytes(of: &raw.data) { pointer in @@ -31,7 +28,7 @@ extension Raw { ) throws -> secp256k1_ecdsa_signature { var raw = secp256k1_ecdsa_signature() - try FFI.call(ifFailThrow: .failedToParseNonRecoverableSignatureFromCompactRepresentation) { context in + try FFI.call(ifFailThrow: .ecdsaSignatureParseCompact) { context in secp256k1_ecdsa_signature_parse_compact( context, &raw, @@ -47,7 +44,7 @@ extension Raw { ) throws -> secp256k1_ecdsa_signature { var raw = secp256k1_ecdsa_signature() - try FFI.call(ifFailThrow: .failedToParseNonRecoverableSignatureFromCompactRepresentation) { context in + try FFI.call(ifFailThrow: .ecdsaSignatureParseDER) { context in secp256k1_ecdsa_signature_parse_der( context, &raw, diff --git a/Sources/K1/Support/Misc/K1+Error.swift b/Sources/K1/Support/Misc/K1+Error.swift index 7f261f7..11e7207 100644 --- a/Sources/K1/Support/Misc/K1+Error.swift +++ b/Sources/K1/Support/Misc/K1+Error.swift @@ -1,49 +1,164 @@ import Foundation +// MARK: - K1.Error extension K1 { - enum Error: Sendable, Swift.Error, Hashable { - case invalidPEMDocument - case invalidPrivateKeyMustNotBeZero - case invalidPrivateKeyMustBeSmallerThanOrder - case failedToProduceSharedSecret - case failedToComputePublicKeyFromPrivateKey - case failedToPerformDiffieHellmanKeyExchange - case failedToInitializePrivateKeyIncorrectByteCount(got: Int, expected: Int) + /// General cryptography errors used by K1. + public enum Error: Sendable, Swift.Error, Hashable { + /// The key is invalid. + case invalidKey + + /// The key size is incorrect. + case incorrectKeySize + + /// The parameter is invalid. + case invalidParameter + + /// The parameter size is incorrect. + case incorrectParameterSize + + /// The underlying `libsecp256k1` library is unable to complete the requested action. + case underlyingLibsecp256k1(error: Int) + + /// This library is unable to complete the requested action. + case internalFailure(error: UInt) + } +} + +extension K1.Error { + static func underlyingLibsecp256k1Error(_ error: FFI.Error) -> Self { + .underlyingLibsecp256k1(error: error.rawValue) + } + + static func internalFailure(_ error: InternalFailure) -> Self { + .internalFailure(error: error.rawValue) + } +} + +// MARK: - InternalFailure +enum InternalFailure: UInt, Sendable, Swift.Error, Hashable { + /// Failed to cast to `CryptoKit.SharedSecret` from internal representation. + case sharedSecretIncorrectSize +} + +// MARK: - FFI.Error +extension FFI { + enum Error: Int, Sendable, Swift.Error, Hashable { case failedToCreateContextForSecp256k1 - case failedToDeserializePublicKey - case failedToSerializePublicKey - case failedToSchnorrVerifyGettingXFromPubKey - case incorrectByteCountOfX963PrivateKey(got: Int, expected: Int) - - /// The public key encoded in the x963 privateKey representation does not match the derived public key from the private key. - case invalidPrivateX963RepresentationPublicKeyDiscrepancy - - case incorrectByteCountOfX963PublicKey(got: Int, expected: Int) - case incorrectByteCountOfRawPublicKey(got: Int, expected: Int) - case unableToDeserializePublicKeyFromRawRepresentation - case incorrectByteCountOfCompressedPublicKey(got: Int, expected: Int) - case failedSignatureToConvertRecoverableSignatureToCompact - case failedToConvertRecoverableSignatureToNonRecoverable - case failedToRecoverPublicKey - case unableToSignMessageHasInvalidLength(got: Int, expected: Int) - case failedToInitializeKeyPairForSchnorrSigning - case failedToSchnorrSignDigestProvidedRandomnessInvalidLength - case failedToSchnorrSignDigest - case failedToInitSchnorrSignatureInvalidByteCount(got: Int, expected: Int) - case failedToSchnorrSignMessageInvalidLength - case incorrectByteCountOfArbitraryDataForNonceFunction - case invalidByteCount - case failedToECDSASignDigest - case unableToRecoverMessageHasInvalidLength(got: Int, expected: Int) - case failedToComparePublicKeys - case failedToSerializeDERSignature - case failedToSerializeSignature - case failedToParseRecoverableSignatureFromCompact - case incorrectByteCountOfRawSignature - case incorrectByteCountOfRawRecoverableSignature(got: Int, expected: Int) - case failedToParseNonRecoverableSignatureFromCompactRepresentation - case failedToDeserializeCompactRecoverableSignatureInvalidByteCount(got: Int, expected: Int) - case failedToDeserializeCompactRSRecoverableSignatureInvalidByteCount(got: Int, expected: Int) - case invalidRecoveryID(got: Int) + + //// `secp256k1_ecdsa_signature_parse_compact` failed + case ecdsaSignatureParseCompact + + /// `secp256k1_ecdsa_signature_parse_der` failed + case ecdsaSignatureParseDER + + /// `secp256k1_ecdsa_signature_serialize_compact` failed + case ecdsaSignatureSerializeCompact + + /// `secp256k1_ecdsa_signature_serialize_der` failed + case ecdsaSignatureSerializeDER + + /// `secp256k1_ecdsa_recoverable_signature_parse_compact` failed + case recoverableSignatureParseCompact + + /// `secp256k1_ecdsa_recoverable_signature_serialize_compact` failed + case recoverableSignatureSerializeCompact + + /// `secp256k1_ecdsa_recoverable_signature_convert` failed + case recoverableSignatureConvert + + /// `secp256k1_ecdsa_recover` failed + case recover + + /// `secp256k1_ec_pubkey_parse` failed + case publicKeyParse + + /// `secp256k1_ec_pubkey_serialize` failed + case publicKeySerialize + + /// `secp256k1_ecdh` failed + case ecdh + + /// `secp256k1_ecdsa_sign_recoverable` or `secp256k1_ecdsa_sign` failed + case ecdsaSign + + /// `secp256k1_xonly_pubkey_from_pubkey` failed + case xonlyPublicKeyFromPublicKey + + /// `secp256k1_keypair_create` failed + case keypairCreate + + /// `secp256k1_schnorrsig_sign32` failed + case schnorrSign + + /// `secp256k1_ec_pubkey_create` + case publicKeyCreate + } +} + +// MARK: - K1.Error + CustomDebugStringConvertible +extension K1.Error: CustomDebugStringConvertible { + public var debugDescription: String { + switch self { + case .incorrectKeySize: + return "incorrect key size" + case .incorrectParameterSize: + return "incorrect parameter size" + case .invalidParameter: + return "invalid parameter" + case .invalidKey: return "invalidKey" + + case let .internalFailure(rawValue): + guard let internalFailure = InternalFailure(rawValue: rawValue) else { + return "Internal failure" + } + let reason: String = { + switch internalFailure { + case .sharedSecretIncorrectSize: + return "Failed to form SharedSecret" + } + }() + return "Internal failure reason: \(reason)" + + case let .underlyingLibsecp256k1(rawValue): + guard let ffi = FFI.Error(rawValue: rawValue) else { + return "Underlying libsecp256k1 failure." + } + let call: String = { + switch ffi { + case .ecdh: return "ecdh" + case .ecdsaSign: return "ECDSA sign" + case .ecdsaSignatureParseCompact: return "ECDSA signature parse compact" + case .failedToCreateContextForSecp256k1: + return "create context" + case .ecdsaSignatureParseDER: + return "ECDSA signature parse DER" + case .ecdsaSignatureSerializeCompact: + return "ECDSA signature serialzie compact" + case .ecdsaSignatureSerializeDER: + return "ECDSA signature serialize DER" + case .recoverableSignatureParseCompact: + return "Recoverable ECDSA signature parse compact" + case .recoverableSignatureSerializeCompact: + return "Recoverable ECDSA signature serialize compact" + case .recoverableSignatureConvert: + return "Recoverable ECDSA convert to non-recoverable" + case .recover: + return "Recover PublicKey" + case .publicKeyParse: + return "PublicKey parse" + case .publicKeySerialize: + return "PublicKey serialize" + case .xonlyPublicKeyFromPublicKey: + return "Parse PublicKey from Xonly PublicKey" + case .keypairCreate: + return "Keypair create" + case .schnorrSign: + return "Schnorr sign" + case .publicKeyCreate: + return "PublicKey create" + } + }() + return "libsecp256k \(call) failed." + } } } diff --git a/Sources/K1/Support/Misc/SharedSecret.swift b/Sources/K1/Support/Misc/SharedSecret.swift index f129f48..254af6e 100644 --- a/Sources/K1/Support/Misc/SharedSecret.swift +++ b/Sources/K1/Support/Misc/SharedSecret.swift @@ -19,7 +19,7 @@ extension CryptoKit.SharedSecret { let __sharedSecret = __SharedSecret(ss: .init(bytes: data)) let sharedSecret = unsafeBitCast(__sharedSecret, to: SharedSecret.self) guard sharedSecret.withUnsafeBytes({ Data($0).count == data.count }) else { - throw K1.Error.failedToProduceSharedSecret + throw K1.Error.internalFailure(.sharedSecretIncorrectSize) } self = sharedSecret diff --git a/Tests/K1Tests/TestCases/Keys/PrivateKey/PrivateKeyImportTests.swift b/Tests/K1Tests/TestCases/Keys/PrivateKey/PrivateKeyImportTests.swift index 1063083..188a020 100644 --- a/Tests/K1Tests/TestCases/Keys/PrivateKey/PrivateKeyImportTests.swift +++ b/Tests/K1Tests/TestCases/Keys/PrivateKey/PrivateKeyImportTests.swift @@ -7,7 +7,7 @@ final class PrivateKeyImportTests: XCTestCase { let raw = try Data(hex: "deadbeef") try assert( K1.ECDSA.NonRecoverable.PrivateKey(rawRepresentation: raw), - throws: K1.Error.failedToInitializePrivateKeyIncorrectByteCount(got: 4, expected: 32) + throws: K1.Error.incorrectKeySize ) } @@ -15,7 +15,7 @@ final class PrivateKeyImportTests: XCTestCase { let raw = Data(repeating: 0xBA, count: 33) try assert( K1.ECDSA.NonRecoverable.PrivateKey(rawRepresentation: raw), - throws: K1.Error.failedToInitializePrivateKeyIncorrectByteCount(got: 33, expected: 32) + throws: K1.Error.incorrectKeySize ) } @@ -23,7 +23,7 @@ final class PrivateKeyImportTests: XCTestCase { let raw = Data(repeating: 0x00, count: 32) try assert( K1.ECDSA.NonRecoverable.PrivateKey(rawRepresentation: raw), - throws: K1.Error.invalidPrivateKeyMustNotBeZero + throws: K1.Error.invalidKey ) } @@ -31,7 +31,7 @@ final class PrivateKeyImportTests: XCTestCase { let raw = try Data(hex: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") try assert( K1.ECDSA.NonRecoverable.PrivateKey(rawRepresentation: raw), - throws: K1.Error.invalidPrivateKeyMustBeSmallerThanOrder + throws: K1.Error.underlyingLibsecp256k1Error(.publicKeyCreate) ) } @@ -39,7 +39,7 @@ final class PrivateKeyImportTests: XCTestCase { let raw = Data(repeating: 0xFF, count: 32) try assert( K1.ECDSA.NonRecoverable.PrivateKey(rawRepresentation: raw), - throws: K1.Error.invalidPrivateKeyMustBeSmallerThanOrder + throws: K1.Error.underlyingLibsecp256k1Error(.publicKeyCreate) ) } diff --git a/Tests/K1Tests/TestCases/Keys/PublicKey/PublicKeyImportTests.swift b/Tests/K1Tests/TestCases/Keys/PublicKey/PublicKeyImportTests.swift index 7363284..4279d8a 100644 --- a/Tests/K1Tests/TestCases/Keys/PublicKey/PublicKeyImportTests.swift +++ b/Tests/K1Tests/TestCases/Keys/PublicKey/PublicKeyImportTests.swift @@ -7,7 +7,7 @@ final class PublicKeyImportTests: XCTestCase { let raw = try Data(hex: "deadbeef") try assert( K1.ECDSA.NonRecoverable.PublicKey(x963Representation: raw), - throws: K1.Error.incorrectByteCountOfX963PublicKey(got: 4, expected: 65) + throws: K1.Error.incorrectKeySize ) } @@ -15,7 +15,7 @@ final class PublicKeyImportTests: XCTestCase { let raw = Data(repeating: 0xDE, count: 66) try assert( K1.ECDSA.NonRecoverable.PublicKey(x963Representation: raw), - throws: K1.Error.incorrectByteCountOfX963PublicKey(got: 66, expected: 65) + throws: K1.Error.incorrectKeySize ) } @@ -23,7 +23,7 @@ final class PublicKeyImportTests: XCTestCase { let raw = Data(repeating: 0x04, count: 65) try assert( K1.ECDSA.NonRecoverable.PublicKey(x963Representation: raw), - throws: K1.Error.failedToDeserializePublicKey + throws: K1.Error.underlyingLibsecp256k1Error(.publicKeyParse) ) } @@ -31,7 +31,7 @@ final class PublicKeyImportTests: XCTestCase { let raw = Data(repeating: 0x03, count: 33) try assert( K1.ECDSA.NonRecoverable.PublicKey(compressedRepresentation: raw), - throws: K1.Error.failedToDeserializePublicKey + throws: K1.Error.underlyingLibsecp256k1Error(.publicKeyParse) ) } @@ -58,7 +58,7 @@ final class PublicKeyImportTests: XCTestCase { try assert( K1.ECDSA.NonRecoverable.PublicKey(x963Representation: raw), - throws: K1.Error.failedToDeserializePublicKey + throws: K1.Error.underlyingLibsecp256k1Error(.publicKeyParse) ) } } diff --git a/Tests/K1Tests/TestCases/Schnorr/SchnorrSignatureBitcoinCoreTests.swift b/Tests/K1Tests/TestCases/Schnorr/SchnorrSignatureBitcoinCoreTests.swift index 982fc80..37a5fac 100644 --- a/Tests/K1Tests/TestCases/Schnorr/SchnorrSignatureBitcoinCoreTests.swift +++ b/Tests/K1Tests/TestCases/Schnorr/SchnorrSignatureBitcoinCoreTests.swift @@ -121,7 +121,7 @@ private extension SchnorrSignatureBitcoinCoreTests { guard !vector.invalidPublicKey else { XCTAssertThrowsError(try parsePublicKey(), "") { anyError in if let error = anyError as? K1.Error { - XCTAssertEqual(error, K1.Error.failedToDeserializePublicKey) + XCTAssertEqual(error, K1.Error.underlyingLibsecp256k1Error(.publicKeyParse)) } else { XCTFail("Failed to cast error") } diff --git a/Tests/K1Tests/Util/XCTestUtils.swift b/Tests/K1Tests/Util/XCTestUtils.swift index fa13186..48b2b6c 100644 --- a/Tests/K1Tests/Util/XCTestUtils.swift +++ b/Tests/K1Tests/Util/XCTestUtils.swift @@ -8,10 +8,10 @@ extension XCTestCase { ) { XCTAssertThrowsError(try fn()) { anyError in guard let error = anyError as? E else { - XCTFail("Incorrect type of error, got '\(type(of: anyError))' but expected: \(E.self)") + XCTFail("Incorrect type of error, got errorType: '\(type(of: anyError))' but expected errorType: \(E.self), got: \(String(describing: anyError))", file: file, line: line) return } - XCTAssertEqual(error, expectedError) + XCTAssertEqual(error, expectedError, file: file, line: line) } } }