4
4
//! for the list of supported algorithms.
5
5
use alloc:: vec:: Vec ;
6
6
7
- use core:: ptr:: NonNull ;
7
+ use core:: ptr:: { null , NonNull } ;
8
8
9
9
#[ cfg( not( feature = "std" ) ) ]
10
10
use cstr_core:: CStr ;
@@ -24,6 +24,8 @@ newtype_buffer!(Signature, SignatureRef);
24
24
25
25
/// Message type
26
26
pub type Message = [ u8 ] ;
27
+ /// Context string type
28
+ pub type CtxStr = [ u8 ] ;
27
29
28
30
macro_rules! implement_sigs {
29
31
{ $( ( $feat: literal) $sig: ident: $oqs_id: ident) ,* $( , ) ? } => (
@@ -67,6 +69,53 @@ macro_rules! implement_sigs {
67
69
sig. verify( & message, & signature, & pk)
68
70
}
69
71
72
+ #[ test]
73
+ #[ cfg( feature = $feat) ]
74
+ fn test_signing_with_empty_context_string( ) -> Result <( ) > {
75
+ crate :: init( ) ;
76
+ let message = [ 0u8 ; 100 ] ;
77
+ let ctx_str: [ u8 ; 0 ] = [ ] ;
78
+ let sig = Sig :: new( Algorithm :: $sig) ?;
79
+ let ( pk, sk) = sig. keypair( ) ?;
80
+ let signature = sig. sign_with_ctx_str( & message, & ctx_str, & sk) ?;
81
+ sig. verify_with_ctx_str( & message, & signature, & ctx_str, & pk)
82
+ }
83
+
84
+ #[ test]
85
+ #[ cfg( feature = $feat) ]
86
+ fn test_signing_with_nonempty_context_string( ) -> Result <( ) > {
87
+ crate :: init( ) ;
88
+ let message = [ 0u8 ; 100 ] ;
89
+ let ctx_str = [ 0u8 ; 100 ] ;
90
+ let sig = Sig :: new( Algorithm :: $sig) ?;
91
+ let ( pk, sk) = sig. keypair( ) ?;
92
+ if sig. has_ctx_str_support( ) {
93
+ let signature = sig. sign_with_ctx_str( & message, & ctx_str, & sk) ?;
94
+ sig. verify_with_ctx_str( & message, & signature, & ctx_str, & pk)
95
+ } else {
96
+ let sig_result = sig. sign_with_ctx_str( & message, & ctx_str, & sk) ;
97
+ // Expect a generic error
98
+ let sig_result: Result <( ) > = match sig_result {
99
+ Err ( Error :: Error ) => Ok ( ( ) ) ,
100
+ Ok ( _) => Err ( Error :: Error ) ,
101
+ Err ( e) => Err ( e)
102
+ } ;
103
+ if sig_result. is_ok( ) {
104
+ // get a valid signature with which to test verify
105
+ let signature = sig. sign( & message, & sk) ?;
106
+ // Expect a generic error
107
+ match sig. verify_with_ctx_str( & message, & signature, & ctx_str, & pk) {
108
+ Err ( Error :: Error ) => Ok ( ( ) ) ,
109
+ Ok ( _) => Err ( Error :: Error ) ,
110
+ Err ( e) => Err ( e)
111
+
112
+ }
113
+ } else {
114
+ sig_result
115
+ }
116
+ }
117
+ }
118
+
70
119
#[ test]
71
120
fn test_enabled( ) {
72
121
crate :: init( ) ;
@@ -261,6 +310,12 @@ impl Sig {
261
310
sig. euf_cma
262
311
}
263
312
313
+ /// Does this algorithm support signing with a context string?
314
+ pub fn has_ctx_str_support ( & self ) -> bool {
315
+ let sig = unsafe { self . sig . as_ref ( ) } ;
316
+ sig. sig_with_ctx_support
317
+ }
318
+
264
319
/// Length of the public key
265
320
pub fn length_public_key ( & self ) -> usize {
266
321
let sig = unsafe { self . sig . as_ref ( ) } ;
@@ -356,6 +411,47 @@ impl Sig {
356
411
Ok ( sig)
357
412
}
358
413
414
+ /// Sign a message with a context string
415
+ pub fn sign_with_ctx_str < ' a , S : Into < SecretKeyRef < ' a > > > (
416
+ & self ,
417
+ message : & Message ,
418
+ ctx_str : & CtxStr ,
419
+ sk : S ,
420
+ ) -> Result < Signature > {
421
+ let sk = sk. into ( ) ;
422
+ let sig = unsafe { self . sig . as_ref ( ) } ;
423
+ let func = sig. sign_with_ctx_str . unwrap ( ) ;
424
+ let mut sig = Signature {
425
+ bytes : Vec :: with_capacity ( sig. length_signature ) ,
426
+ } ;
427
+ let mut sig_len = 0 ;
428
+ // For algorithms without context string support, liboqs
429
+ // expects the context to be NULL. Converting an empty
430
+ // slice to a pointer doesn't actually do this.
431
+ let ctx_str_ptr = if !ctx_str. is_empty ( ) {
432
+ ctx_str. as_ptr ( )
433
+ } else {
434
+ null ( )
435
+ } ;
436
+ let status = unsafe {
437
+ func (
438
+ sig. bytes . as_mut_ptr ( ) ,
439
+ & mut sig_len,
440
+ message. as_ptr ( ) ,
441
+ message. len ( ) ,
442
+ ctx_str_ptr,
443
+ ctx_str. len ( ) ,
444
+ sk. bytes . as_ptr ( ) ,
445
+ )
446
+ } ;
447
+ status_to_result ( status) ?;
448
+ // This is safe to do as it's initialised now.
449
+ unsafe {
450
+ sig. bytes . set_len ( sig_len) ;
451
+ }
452
+ Ok ( sig)
453
+ }
454
+
359
455
/// Verify a message
360
456
pub fn verify < ' a , ' b > (
361
457
& self ,
@@ -383,4 +479,43 @@ impl Sig {
383
479
} ;
384
480
status_to_result ( status)
385
481
}
482
+
483
+ /// Verify a message with a context string
484
+ pub fn verify_with_ctx_str < ' a , ' b > (
485
+ & self ,
486
+ message : & Message ,
487
+ signature : impl Into < SignatureRef < ' a > > ,
488
+ ctx_str : & CtxStr ,
489
+ pk : impl Into < PublicKeyRef < ' b > > ,
490
+ ) -> Result < ( ) > {
491
+ let signature = signature. into ( ) ;
492
+ let pk = pk. into ( ) ;
493
+ if signature. bytes . len ( ) > self . length_signature ( )
494
+ || pk. bytes . len ( ) != self . length_public_key ( )
495
+ {
496
+ return Err ( Error :: InvalidLength ) ;
497
+ }
498
+ let sig = unsafe { self . sig . as_ref ( ) } ;
499
+ let func = sig. verify_with_ctx_str . unwrap ( ) ;
500
+ // For algorithms without context string support, liboqs
501
+ // expects the context to be NULL. Converting an empty
502
+ // slice to a pointer doesn't actually do this.
503
+ let ctx_str_ptr = if !ctx_str. is_empty ( ) {
504
+ ctx_str. as_ptr ( )
505
+ } else {
506
+ null ( )
507
+ } ;
508
+ let status = unsafe {
509
+ func (
510
+ message. as_ptr ( ) ,
511
+ message. len ( ) ,
512
+ signature. bytes . as_ptr ( ) ,
513
+ signature. len ( ) ,
514
+ ctx_str_ptr,
515
+ ctx_str. len ( ) ,
516
+ pk. bytes . as_ptr ( ) ,
517
+ )
518
+ } ;
519
+ status_to_result ( status)
520
+ }
386
521
}
0 commit comments