@@ -5,7 +5,9 @@ use nimiq_keys::{
55 multisig:: {
66 address:: { combine_public_keys, compute_address} ,
77 commitment:: { Commitment , CommitmentPair , Nonce } ,
8+ error:: PartialSignatureError ,
89 partial_signature:: PartialSignature ,
10+ public_key:: DelinearizedPublicKey ,
911 CommitmentsBuilder ,
1012 } ,
1113 Address , Ed25519PublicKey , KeyPair , PrivateKey ,
@@ -93,6 +95,13 @@ const VECTORS: [StrTestVector; 4] = [
9395 } ,
9496] ;
9597
98+ /// Bytes that are NOT a valid compressed Edwards Y coordinate on Ed25519.
99+ /// CompressedEdwardsY(INVALID_CURVE_POINT_BYTES).decompress() returns None.
100+ const INVALID_CURVE_POINT_BYTES : [ u8 ; 32 ] = [
101+ 0xab , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
102+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x37 ,
103+ ] ;
104+
96105#[ test]
97106fn it_can_construct_public_keys ( ) {
98107 for vector in VECTORS . iter ( ) {
@@ -165,7 +174,7 @@ fn it_can_create_signatures() {
165174 builder = builder. with_signer ( pks[ j] , commitments[ j] ) ;
166175 }
167176 }
168- let data = builder. build ( & test. message ) ;
177+ let data = builder. build ( & test. message ) . unwrap ( ) ;
169178 let partial_sig = key_pair. partial_sign ( & data, & test. message ) . unwrap ( ) ;
170179
171180 assert ! (
@@ -237,7 +246,8 @@ fn it_can_create_a_valid_multisignature() {
237246 let combined_public_keys = combine_public_keys (
238247 vec ! [ keypair_a. public, keypair_b. public, keypair_c. public] ,
239248 2 ,
240- ) ;
249+ )
250+ . unwrap ( ) ;
241251 assert_eq ! ( compute_address( & combined_public_keys) , wallet_address) ;
242252
243253 let mut tx = "01f4e305f34ea1ccf00c0f7fcbc030d1347dc5eafe000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000500" . to_string ( ) ;
@@ -255,7 +265,8 @@ fn it_can_create_a_valid_multisignature() {
255265 commitment_pair_b_2. commitment ( ) ,
256266 ] ,
257267 )
258- . build ( & tx_content) ;
268+ . build ( & tx_content)
269+ . unwrap ( ) ;
259270
260271 assert_eq ! ( commitments_data_a. aggregate_public_key, signing_public_key) ;
261272 assert_eq ! (
@@ -281,7 +292,8 @@ fn it_can_create_a_valid_multisignature() {
281292 commitment_pair_a_2. commitment ( ) ,
282293 ] ,
283294 )
284- . build ( & tx_content) ;
295+ . build ( & tx_content)
296+ . unwrap ( ) ;
285297
286298 assert_eq ! ( commitments_data_b. aggregate_public_key, signing_public_key) ;
287299 assert_eq ! (
@@ -318,3 +330,96 @@ fn it_can_create_a_valid_multisignature() {
318330
319331 assert_eq ! ( & tx, signed_transaction) ;
320332}
333+
334+ fn invalid_curve_point_key ( ) -> Ed25519PublicKey {
335+ Ed25519PublicKey :: from ( INVALID_CURVE_POINT_BYTES )
336+ }
337+
338+ #[ test]
339+ fn delinearize_rejects_invalid_curve_point ( ) {
340+ let valid_kp: KeyPair = from_hex ! (
341+ "f80793b4cb1e165d1a65b5cbc9e7b2efa583de01bc13dd23f7a1d78af4349904" ,
342+ PrivateKey :: SIZE ,
343+ PrivateKey :: from
344+ )
345+ . into ( ) ;
346+ let invalid_key = invalid_curve_point_key ( ) ;
347+
348+ let result = DelinearizedPublicKey :: sum_delinearized ( & [ valid_kp. public , invalid_key] ) ;
349+ assert ! (
350+ matches!( result, Err ( PartialSignatureError :: InvalidCurvePoint ) ) ,
351+ "expected InvalidCurvePoint error, got {result:?}"
352+ ) ;
353+ }
354+
355+ #[ test]
356+ fn build_rejects_invalid_public_key ( ) {
357+ let mut rng = test_rng ( true ) ;
358+ let valid_kp: KeyPair = from_hex ! (
359+ "f80793b4cb1e165d1a65b5cbc9e7b2efa583de01bc13dd23f7a1d78af4349904" ,
360+ PrivateKey :: SIZE ,
361+ PrivateKey :: from
362+ )
363+ . into ( ) ;
364+ let invalid_key = invalid_curve_point_key ( ) ;
365+ let pairs = CommitmentPair :: generate_all ( & mut rng) ;
366+
367+ let builder = CommitmentsBuilder :: with_private_commitments ( valid_kp. public , pairs)
368+ . with_signer ( invalid_key, [ Commitment :: default ( ) ; 2 ] ) ;
369+
370+ let result = builder. build ( b"test message" ) ;
371+ assert ! (
372+ matches!( result, Err ( PartialSignatureError :: InvalidCurvePoint ) ) ,
373+ "expected InvalidCurvePoint error"
374+ ) ;
375+ }
376+
377+ #[ test]
378+ fn verify_partial_with_invalid_key_returns_false ( ) {
379+ let mut rng = test_rng ( true ) ;
380+ let valid_kp: KeyPair = from_hex ! (
381+ "f80793b4cb1e165d1a65b5cbc9e7b2efa583de01bc13dd23f7a1d78af4349904" ,
382+ PrivateKey :: SIZE ,
383+ PrivateKey :: from
384+ )
385+ . into ( ) ;
386+ let pairs = CommitmentPair :: generate_all ( & mut rng) ;
387+ let commitments = CommitmentPair :: to_commitments ( & pairs) ;
388+
389+ // Build valid commitments data first.
390+ let data = CommitmentsBuilder :: with_private_commitments ( valid_kp. public , pairs)
391+ . with_signer ( valid_kp. public , commitments)
392+ . build ( b"test" )
393+ . unwrap ( ) ;
394+ let partial_sig = valid_kp. partial_sign ( & data, b"test" ) . unwrap ( ) ;
395+
396+ // Verifying with an invalid key should return false, not panic.
397+ let invalid_key = invalid_curve_point_key ( ) ;
398+ assert ! ( !invalid_key. verify_partial( & data, & partial_sig, b"test" ) ) ;
399+ }
400+
401+ #[ test]
402+ fn commitment_try_from_rejects_invalid_bytes ( ) {
403+ let result = Commitment :: try_from ( INVALID_CURVE_POINT_BYTES ) ;
404+ assert ! (
405+ result. is_err( ) ,
406+ "expected error for invalid curve point bytes"
407+ ) ;
408+ }
409+
410+ #[ test]
411+ fn combine_public_keys_rejects_invalid_key ( ) {
412+ let valid_kp: KeyPair = from_hex ! (
413+ "f80793b4cb1e165d1a65b5cbc9e7b2efa583de01bc13dd23f7a1d78af4349904" ,
414+ PrivateKey :: SIZE ,
415+ PrivateKey :: from
416+ )
417+ . into ( ) ;
418+ let invalid_key = invalid_curve_point_key ( ) ;
419+
420+ let result = combine_public_keys ( vec ! [ valid_kp. public, invalid_key] , 2 ) ;
421+ assert ! (
422+ matches!( result, Err ( PartialSignatureError :: InvalidCurvePoint ) ) ,
423+ "expected InvalidCurvePoint error, got {result:?}"
424+ ) ;
425+ }
0 commit comments