Skip to content

Commit e9de693

Browse files
committed
Add an external mu variant of the ML-DSA API (65 and 87 variants)
1 parent 3ef6559 commit e9de693

File tree

3 files changed

+329
-0
lines changed

3 files changed

+329
-0
lines changed

Sources/_CryptoExtras/MLDSA/MLDSA_boring.swift

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,17 @@ extension MLDSA65 {
7575
try self.backing.signature(for: data, context: context)
7676
}
7777

78+
/// Generate a signature for the prehashed message representative (a.k.a. "external mu").
79+
///
80+
/// > Note: The message representative should be obtained via calls to ``MLDSA65/PublicKey/prehash(for:context:)``.
81+
///
82+
/// - Parameter mu: The prehashed message representative (a.k.a. "external mu").
83+
///
84+
/// - Returns: The signature of the prehashed message representative.
85+
public func signature<M: DataProtocol>(forPrehashedMessageRepresentative mu: M) throws -> Data {
86+
try self.backing.signature(forPrehashedMessageRepresentative: mu)
87+
}
88+
7889
/// The size of the private key in bytes.
7990
static let byteCount = Backing.byteCount
8091

@@ -175,6 +186,38 @@ extension MLDSA65 {
175186
return signature
176187
}
177188

189+
/// Generate a signature for the prehashed message representative (a.k.a. "external mu").
190+
///
191+
/// > Note: The message representative should be obtained via calls to ``MLDSA65/PublicKey/prehash(for:context:)``.
192+
///
193+
/// - Parameter mu: The prehashed message representative (a.k.a. "external mu").
194+
///
195+
/// - Returns: The signature of the prehashed message representative.
196+
func signature<M: DataProtocol>(forPrehashedMessageRepresentative mu: M) throws -> Data {
197+
guard mu.count == MLDSA.muByteCount else {
198+
throw CryptoKitError.incorrectParameterSize
199+
}
200+
201+
var signature = Data(repeating: 0, count: MLDSA65.signatureByteCount)
202+
203+
let rc: CInt = signature.withUnsafeMutableBytes { signaturePtr in
204+
let muBytes: ContiguousBytes = mu.regions.count == 1 ? mu.regions.first! : Array(mu)
205+
return muBytes.withUnsafeBytes { muPtr in
206+
CCryptoBoringSSL_MLDSA65_sign_message_representative(
207+
signaturePtr.baseAddress,
208+
&self.key,
209+
muPtr.baseAddress
210+
)
211+
}
212+
}
213+
214+
guard rc == 1 else {
215+
throw CryptoKitError.internalBoringSSLError()
216+
}
217+
218+
return signature
219+
}
220+
178221
/// The size of the private key in bytes.
179222
static let byteCount = Int(MLDSA65_PRIVATE_KEY_BYTES)
180223
}
@@ -233,6 +276,27 @@ extension MLDSA65 {
233276
self.backing.isValidSignature(signature, for: data, context: context)
234277
}
235278

279+
/// Generate a prehashed message representative (a.k.a. "external mu") for the given message.
280+
///
281+
/// - Parameter data: The message to prehash.
282+
///
283+
/// - Returns: The prehashed message representative (a.k.a. "external mu").
284+
public func prehash<D: DataProtocol>(for data: D) throws -> Data {
285+
let context: Data? = nil
286+
return try self.backing.prehash(for: data, context: context)
287+
}
288+
289+
/// Generate a prehashed message representative (a.k.a. "external mu") for the given message.
290+
///
291+
/// - Parameters:
292+
/// - data: The message to prehash.
293+
/// - context: The context of the message.
294+
///
295+
/// - Returns: The prehashed message representative (a.k.a. "external mu").
296+
public func prehash<D: DataProtocol, C: DataProtocol>(for data: D, context: C) throws -> Data {
297+
try self.backing.prehash(for: data, context: context)
298+
}
299+
236300
/// The size of the public key in bytes.
237301
static let byteCount = Backing.byteCount
238302

@@ -314,6 +378,41 @@ extension MLDSA65 {
314378
}
315379
}
316380

381+
/// Generate a prehashed message representative (a.k.a. "external mu") for the given message.
382+
///
383+
/// - Parameters:
384+
/// - data: The message to prehash.
385+
/// - context: The context of the message.
386+
///
387+
/// - Returns: The prehashed message representative (a.k.a. "external mu").
388+
func prehash<D: DataProtocol, C: DataProtocol>(for data: D, context: C?) throws -> Data {
389+
var mu = Data(repeating: 0, count: MLDSA.muByteCount)
390+
391+
let dataBytes: ContiguousBytes = data.regions.count == 1 ? data.regions.first! : Array(data)
392+
let rc: CInt = mu.withUnsafeMutableBytes { muPtr in
393+
dataBytes.withUnsafeBytes { dataPtr in
394+
context.withUnsafeBytes { contextPtr in
395+
var prehash = MLDSA65_prehash()
396+
let rc = CCryptoBoringSSL_MLDSA65_prehash_init(
397+
&prehash,
398+
&key,
399+
contextPtr.baseAddress,
400+
contextPtr.count
401+
)
402+
CCryptoBoringSSL_MLDSA65_prehash_update(&prehash, dataPtr.baseAddress, dataPtr.count)
403+
CCryptoBoringSSL_MLDSA65_prehash_finalize(muPtr.baseAddress, &prehash)
404+
return rc
405+
}
406+
}
407+
}
408+
409+
guard rc == 1 else {
410+
throw CryptoKitError.internalBoringSSLError()
411+
}
412+
413+
return mu
414+
}
415+
317416
/// The size of the public key in bytes.
318417
static let byteCount = Int(MLDSA65_PUBLIC_KEY_BYTES)
319418
}
@@ -381,6 +480,17 @@ extension MLDSA87 {
381480
try self.backing.signature(for: data, context: context)
382481
}
383482

483+
/// Generate a signature for the prehashed message representative (a.k.a. "external mu").
484+
///
485+
/// > Note: The message representative should be obtained via calls to ``MLDSA87/PublicKey/prehash(for:context:)``.
486+
///
487+
/// - Parameter mu: The prehashed message representative (a.k.a. "external mu").
488+
///
489+
/// - Returns: The signature of the prehashed message representative.
490+
public func signature<M: DataProtocol>(forPrehashedMessageRepresentative mu: M) throws -> Data {
491+
try self.backing.signature(forPrehashedMessageRepresentative: mu)
492+
}
493+
384494
/// The size of the private key in bytes.
385495
static let byteCount = Backing.byteCount
386496

@@ -481,6 +591,38 @@ extension MLDSA87 {
481591
return signature
482592
}
483593

594+
/// Generate a signature for the prehashed message representative (a.k.a. "external mu").
595+
///
596+
/// > Note: The message representative should be obtained via calls to ``MLDSA87/PublicKey/prehash(for:context:)``.
597+
///
598+
/// - Parameter mu: The prehashed message representative (a.k.a. "external mu").
599+
///
600+
/// - Returns: The signature of the prehashed message representative.
601+
func signature<M: DataProtocol>(forPrehashedMessageRepresentative mu: M) throws -> Data {
602+
guard mu.count == MLDSA.muByteCount else {
603+
throw CryptoKitError.incorrectParameterSize
604+
}
605+
606+
var signature = Data(repeating: 0, count: MLDSA87.signatureByteCount)
607+
608+
let rc: CInt = signature.withUnsafeMutableBytes { signaturePtr in
609+
let muBytes: ContiguousBytes = mu.regions.count == 1 ? mu.regions.first! : Array(mu)
610+
return muBytes.withUnsafeBytes { muPtr in
611+
CCryptoBoringSSL_MLDSA87_sign_message_representative(
612+
signaturePtr.baseAddress,
613+
&self.key,
614+
muPtr.baseAddress
615+
)
616+
}
617+
}
618+
619+
guard rc == 1 else {
620+
throw CryptoKitError.internalBoringSSLError()
621+
}
622+
623+
return signature
624+
}
625+
484626
/// The size of the private key in bytes.
485627
static let byteCount = Int(MLDSA87_PRIVATE_KEY_BYTES)
486628
}
@@ -539,6 +681,27 @@ extension MLDSA87 {
539681
self.backing.isValidSignature(signature, for: data, context: context)
540682
}
541683

684+
/// Generate a prehashed message representative (a.k.a. "external mu") for the given message.
685+
///
686+
/// - Parameter data: The message to prehash.
687+
///
688+
/// - Returns: The prehashed message representative (a.k.a. "external mu").
689+
public func prehash<D: DataProtocol>(for data: D) throws -> Data {
690+
let context: Data? = nil
691+
return try self.backing.prehash(for: data, context: context)
692+
}
693+
694+
/// Generate a prehashed message representative (a.k.a. "external mu") for the given message.
695+
///
696+
/// - Parameters:
697+
/// - data: The message to prehash.
698+
/// - context: The context of the message.
699+
///
700+
/// - Returns: The prehashed message representative (a.k.a. "external mu").
701+
public func prehash<D: DataProtocol, C: DataProtocol>(for data: D, context: C) throws -> Data {
702+
try self.backing.prehash(for: data, context: context)
703+
}
704+
542705
/// The size of the public key in bytes.
543706
static let byteCount = Backing.byteCount
544707

@@ -620,6 +783,41 @@ extension MLDSA87 {
620783
}
621784
}
622785

786+
/// Generate a prehashed message representative (a.k.a. "external mu") for the given message.
787+
///
788+
/// - Parameters:
789+
/// - data: The message to prehash.
790+
/// - context: The context of the message.
791+
///
792+
/// - Returns: The prehashed message representative (a.k.a. "external mu").
793+
func prehash<D: DataProtocol, C: DataProtocol>(for data: D, context: C?) throws -> Data {
794+
var mu = Data(repeating: 0, count: MLDSA.muByteCount)
795+
796+
let dataBytes: ContiguousBytes = data.regions.count == 1 ? data.regions.first! : Array(data)
797+
let rc: CInt = mu.withUnsafeMutableBytes { muPtr in
798+
dataBytes.withUnsafeBytes { dataPtr in
799+
context.withUnsafeBytes { contextPtr in
800+
var prehash = MLDSA87_prehash()
801+
let rc = CCryptoBoringSSL_MLDSA87_prehash_init(
802+
&prehash,
803+
&key,
804+
contextPtr.baseAddress,
805+
contextPtr.count
806+
)
807+
CCryptoBoringSSL_MLDSA87_prehash_update(&prehash, dataPtr.baseAddress, dataPtr.count)
808+
CCryptoBoringSSL_MLDSA87_prehash_finalize(muPtr.baseAddress, &prehash)
809+
return rc
810+
}
811+
}
812+
}
813+
814+
guard rc == 1 else {
815+
throw CryptoKitError.internalBoringSSLError()
816+
}
817+
818+
return mu
819+
}
820+
623821
/// The size of the public key in bytes.
624822
static let byteCount = Int(MLDSA87_PUBLIC_KEY_BYTES)
625823
}
@@ -635,4 +833,7 @@ extension MLDSA87 {
635833
private enum MLDSA {
636834
/// The size of the seed in bytes.
637835
fileprivate static let seedByteCount = 32
836+
837+
/// The size of the "mu" value in bytes.
838+
fileprivate static let muByteCount = 64
638839
}

Sources/_CryptoExtras/MLDSA/MLDSA_boring.swift.gyb

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,17 @@ extension MLDSA${parameter_set} {
7979
try self.backing.signature(for: data, context: context)
8080
}
8181

82+
/// Generate a signature for the prehashed message representative (a.k.a. "external mu").
83+
///
84+
/// > Note: The message representative should be obtained via calls to ``MLDSA${parameter_set}/PublicKey/prehash(for:context:)``.
85+
///
86+
/// - Parameter mu: The prehashed message representative (a.k.a. "external mu").
87+
///
88+
/// - Returns: The signature of the prehashed message representative.
89+
public func signature<M: DataProtocol>(forPrehashedMessageRepresentative mu: M) throws -> Data {
90+
try self.backing.signature(forPrehashedMessageRepresentative: mu)
91+
}
92+
8293
/// The size of the private key in bytes.
8394
static let byteCount = Backing.byteCount
8495

@@ -179,6 +190,38 @@ extension MLDSA${parameter_set} {
179190
return signature
180191
}
181192

193+
/// Generate a signature for the prehashed message representative (a.k.a. "external mu").
194+
///
195+
/// > Note: The message representative should be obtained via calls to ``MLDSA${parameter_set}/PublicKey/prehash(for:context:)``.
196+
///
197+
/// - Parameter mu: The prehashed message representative (a.k.a. "external mu").
198+
///
199+
/// - Returns: The signature of the prehashed message representative.
200+
func signature<M: DataProtocol>(forPrehashedMessageRepresentative mu: M) throws -> Data {
201+
guard mu.count == MLDSA.muByteCount else {
202+
throw CryptoKitError.incorrectParameterSize
203+
}
204+
205+
var signature = Data(repeating: 0, count: MLDSA${parameter_set}.signatureByteCount)
206+
207+
let rc: CInt = signature.withUnsafeMutableBytes { signaturePtr in
208+
let muBytes: ContiguousBytes = mu.regions.count == 1 ? mu.regions.first! : Array(mu)
209+
return muBytes.withUnsafeBytes { muPtr in
210+
CCryptoBoringSSL_MLDSA${parameter_set}_sign_message_representative(
211+
signaturePtr.baseAddress,
212+
&self.key,
213+
muPtr.baseAddress
214+
)
215+
}
216+
}
217+
218+
guard rc == 1 else {
219+
throw CryptoKitError.internalBoringSSLError()
220+
}
221+
222+
return signature
223+
}
224+
182225
/// The size of the private key in bytes.
183226
static let byteCount = Int(MLDSA${parameter_set}_PRIVATE_KEY_BYTES)
184227
}
@@ -237,6 +280,27 @@ extension MLDSA${parameter_set} {
237280
self.backing.isValidSignature(signature, for: data, context: context)
238281
}
239282

283+
/// Generate a prehashed message representative (a.k.a. "external mu") for the given message.
284+
///
285+
/// - Parameter data: The message to prehash.
286+
///
287+
/// - Returns: The prehashed message representative (a.k.a. "external mu").
288+
public func prehash<D: DataProtocol>(for data: D) throws -> Data {
289+
let context: Data? = nil
290+
return try self.backing.prehash(for: data, context: context)
291+
}
292+
293+
/// Generate a prehashed message representative (a.k.a. "external mu") for the given message.
294+
///
295+
/// - Parameters:
296+
/// - data: The message to prehash.
297+
/// - context: The context of the message.
298+
///
299+
/// - Returns: The prehashed message representative (a.k.a. "external mu").
300+
public func prehash<D: DataProtocol, C: DataProtocol>(for data: D, context: C) throws -> Data {
301+
try self.backing.prehash(for: data, context: context)
302+
}
303+
240304
/// The size of the public key in bytes.
241305
static let byteCount = Backing.byteCount
242306

@@ -318,6 +382,41 @@ extension MLDSA${parameter_set} {
318382
}
319383
}
320384

385+
/// Generate a prehashed message representative (a.k.a. "external mu") for the given message.
386+
///
387+
/// - Parameters:
388+
/// - data: The message to prehash.
389+
/// - context: The context of the message.
390+
///
391+
/// - Returns: The prehashed message representative (a.k.a. "external mu").
392+
func prehash<D: DataProtocol, C: DataProtocol>(for data: D, context: C?) throws -> Data {
393+
var mu = Data(repeating: 0, count: MLDSA.muByteCount)
394+
395+
let dataBytes: ContiguousBytes = data.regions.count == 1 ? data.regions.first! : Array(data)
396+
let rc: CInt = mu.withUnsafeMutableBytes { muPtr in
397+
dataBytes.withUnsafeBytes { dataPtr in
398+
context.withUnsafeBytes { contextPtr in
399+
var prehash = MLDSA${parameter_set}_prehash()
400+
let rc = CCryptoBoringSSL_MLDSA${parameter_set}_prehash_init(
401+
&prehash,
402+
&key,
403+
contextPtr.baseAddress,
404+
contextPtr.count
405+
)
406+
CCryptoBoringSSL_MLDSA${parameter_set}_prehash_update(&prehash, dataPtr.baseAddress, dataPtr.count)
407+
CCryptoBoringSSL_MLDSA${parameter_set}_prehash_finalize(muPtr.baseAddress, &prehash)
408+
return rc
409+
}
410+
}
411+
}
412+
413+
guard rc == 1 else {
414+
throw CryptoKitError.internalBoringSSLError()
415+
}
416+
417+
return mu
418+
}
419+
321420
/// The size of the public key in bytes.
322421
static let byteCount = Int(MLDSA${parameter_set}_PUBLIC_KEY_BYTES)
323422
}
@@ -334,4 +433,7 @@ extension MLDSA${parameter_set} {
334433
private enum MLDSA {
335434
/// The size of the seed in bytes.
336435
fileprivate static let seedByteCount = 32
436+
437+
/// The size of the "mu" value in bytes.
438+
fileprivate static let muByteCount = 64
337439
}

0 commit comments

Comments
 (0)