Alright, I solved the issue regarding signature verification. For context, the end point I used utilizes P256 methods that conform with the RFC6979 protocol:
https://www.rfc-editor.org/rfc/rfc6979.txt
And, it turns out, that the signatures returned from CryptoKit's P256 class do in fact conform to this protocol, with one catch: the signature needs to be normalized before you send it off to the end point. I written up some code here that will help out with normalizing these signatures so that s, in context with r || s for P256 elliptic curves, is in the lower half of the curve; and normalized.
Note: The developer is required to install the BigInt package published by attaswift, as the signature values are too high to store in a normal UInt64 variable:
extension Data {
func hexEncodedString() -> String {
return map { String(format: "%02hhx", $0) }.joined()
}
}
func normalizeSignature(_ signatureHex: String) -> String? {
let curveOrder = BigInt("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", radix: 16)!
// Assuming the signature is evenly split between r and s
let rHex = String(signatureHex.prefix(signatureHex.count / 2))
let sHex = String(signatureHex.suffix(signatureHex.count / 2))
// Convert hex to BigInt
var s = BigInt(sHex, radix: 16)!
// Normalize s if necessary
let halfCurveOrder = curveOrder / 2
if s > halfCurveOrder {
s = curveOrder - s
}
// Convert back to hex, ensuring it's zero-padded to the correct length
let normalizedSHex = String(s, radix: 16).leftPad(toLength: sHex.count, withPad: "0")
return rHex + normalizedSHex
}
extension String {
func leftPad(toLength: Int, withPad: String) -> String {
guard toLength > self.count else { return self }
let padding = String(repeating: withPad, count: toLength - self.count)
return padding + self
}
}
While the signature is still not matching that of Rust's FastCrypto, the signature will pass verification if passed into FastCrypto's verification function:
% target/debug/sigs-cli verify --msg 48656c6c6f2c20776f726c6421 --public-key 0227322b3a891a0a280d6bc1fb2cbb23d28f54906fd6407f5f741f6def5762609a --signature 4672703055add7ea9f75a80798f4fb65f9dfab2db5a661a002ead74cde53f4bc50e54e4ed2d88c95211b70903562daa3e4088452b32fce659d911665aac0ed2e --scheme secp256r1
Verify result: Ok(())
In short, in order for the developer to be able to use a CryptoKit P256 signature with Rust's FastCrypto library, they must normalize s first before passing the signature into the Rust application.
I will mark this post as the solution.
Topic:
Programming Languages
SubTopic:
Swift
Tags: