@@ -10,17 +10,17 @@ describe('Detached Signatures', () => {
1010 const keypair = crypto . generateKeypair ( )
1111 const message = 'Hello, World!'
1212 const messageHash = crypto . hash ( message )
13-
13+
1414 // Create detached signature
1515 const signature = crypto . signDetached ( messageHash , keypair . secretKey )
16-
16+
1717 // Verify signature is 64 bytes (128 hex chars)
1818 expect ( signature . length ) . toBe ( 128 )
19-
19+
2020 // Verify the signature
2121 const isValid = crypto . verifyDetached ( messageHash , signature , keypair . publicKey )
2222 expect ( isValid ) . toBe ( true )
23-
23+
2424 // Verify with wrong message fails
2525 const wrongMessage = crypto . hash ( 'Wrong message' )
2626 const isInvalid = crypto . verifyDetached ( wrongMessage , signature , keypair . publicKey )
@@ -34,19 +34,19 @@ describe('Detached Signatures', () => {
3434 const testObj = {
3535 message : 'Test object' ,
3636 value : 42 ,
37- timestamp : Date . now ( )
37+ timestamp : Date . now ( ) ,
3838 }
39-
39+
4040 // Sign with detached signature
4141 const signedObj = crypto . signObjDetached ( testObj , keypair . secretKey , keypair . publicKey )
42-
42+
4343 // Verify signature is 64 bytes
4444 expect ( signedObj . sign . sig . length ) . toBe ( 128 )
45-
45+
4646 // Verify the signed object
4747 const isValid = crypto . verifyObjDetached ( signedObj )
4848 expect ( isValid ) . toBe ( true )
49-
49+
5050 // Tamper with object and verify it fails
5151 signedObj . value = 43
5252 const isInvalid = crypto . verifyObjDetached ( signedObj )
@@ -59,51 +59,51 @@ describe('Detached Signatures', () => {
5959 const keypair = crypto . generateKeypair ( )
6060 const message = 'Test message'
6161 const messageHash = crypto . hash ( message )
62-
62+
6363 // Create old-style (non-detached) signature
6464 const oldSignature = crypto . sign ( messageHash , keypair . secretKey , false )
6565 // Old signature should be 96 bytes for 32-byte hash (64 + 32)
6666 expect ( oldSignature . length ) . toBe ( 192 )
67-
68- // Create new-style (detached) signature
67+
68+ // Create new-style (detached) signature
6969 const newSignature = crypto . sign ( messageHash , keypair . secretKey , true )
7070 // New signature should be 64 bytes
7171 expect ( newSignature . length ) . toBe ( 128 )
72-
72+
7373 // Both should verify successfully with verifyObj
7474 const testObj1 = { data : 'test' }
7575 const testObj2 = { data : 'test' }
76-
76+
7777 // Sign with old style
78- crypto . signObj ( testObj1 , keypair . secretKey , keypair . publicKey , false )
79- expect ( crypto . verifyObj ( testObj1 ) ) . toBe ( true )
80-
78+ const signedObj1 = crypto . signObj ( testObj1 , keypair . secretKey , keypair . publicKey , false )
79+ expect ( crypto . verifyObj ( signedObj1 ) ) . toBe ( true )
80+
8181 // Sign with new style
82- crypto . signObj ( testObj2 , keypair . secretKey , keypair . publicKey , true )
83- expect ( crypto . verifyObj ( testObj2 ) ) . toBe ( true )
82+ const signedObj2 = crypto . signObj ( testObj2 , keypair . secretKey , keypair . publicKey , true )
83+ expect ( crypto . verifyObj ( signedObj2 ) ) . toBe ( true )
8484 } )
8585
8686 it ( 'should handle mixed signature types correctly' , ( ) => {
8787 const keypair = crypto . generateKeypair ( )
8888 const testObj = { data : 'test data' , id : 123 }
89-
89+
9090 // Create both types of signatures
9191 const objOld = JSON . parse ( JSON . stringify ( testObj ) )
9292 const objNew = JSON . parse ( JSON . stringify ( testObj ) )
93-
93+
9494 // Sign with old method
9595 crypto . signObj ( objOld , keypair . secretKey , keypair . publicKey , false )
96-
97- // Sign with new method
96+
97+ // Sign with new method
9898 crypto . signObj ( objNew , keypair . secretKey , keypair . publicKey , true )
99-
99+
100100 // Old signature should be longer
101101 expect ( objOld . sign . sig . length ) . toBeGreaterThan ( objNew . sign . sig . length )
102-
102+
103103 // Both should verify with verifyObj (auto-detection)
104104 expect ( crypto . verifyObj ( objOld ) ) . toBe ( true )
105105 expect ( crypto . verifyObj ( objNew ) ) . toBe ( true )
106-
106+
107107 // New detached verify should work only with detached signature
108108 expect ( crypto . verifyObjDetached ( objNew ) ) . toBe ( true )
109109 expect ( ( ) => crypto . verifyObjDetached ( objOld ) ) . toThrow ( )
@@ -114,49 +114,101 @@ describe('Detached Signatures', () => {
114114 it ( 'should produce different signature lengths based on detached parameter' , ( ) => {
115115 const keypair = crypto . generateKeypair ( )
116116 const message = crypto . hash ( 'test' )
117-
117+
118118 // Default (undefined) should now use detached
119119 const defaultSig = crypto . sign ( message , keypair . secretKey )
120120 expect ( defaultSig . length ) . toBe ( 128 ) // 64 bytes sig only
121-
121+
122122 // Explicit false should use non-detached
123123 const nonDetachedSig = crypto . sign ( message , keypair . secretKey , false )
124124 expect ( nonDetachedSig . length ) . toBe ( 192 ) // 96 bytes = 64 sig + 32 msg
125-
125+
126126 // Explicit true should use detached
127127 const detachedSig = crypto . sign ( message , keypair . secretKey , true )
128128 expect ( detachedSig . length ) . toBe ( 128 ) // 64 bytes sig only
129129 } )
130130 } )
131-
131+
132132 describe ( 'Default behavior change' , ( ) => {
133133 it ( 'sign() should default to detached signatures' , ( ) => {
134134 const keypair = crypto . generateKeypair ( )
135135 const message = crypto . hash ( 'test message' )
136-
136+
137137 // Call without detached parameter
138138 const signature = crypto . sign ( message , keypair . secretKey )
139-
139+
140140 // Should produce 64-byte signature
141141 expect ( signature . length ) . toBe ( 128 ) // 128 hex chars = 64 bytes
142-
142+
143143 // Should verify with verifyDetached
144144 expect ( crypto . verifyDetached ( message , signature , keypair . publicKey ) ) . toBe ( true )
145145 } )
146-
146+
147147 it ( 'signObj() should default to detached signatures' , ( ) => {
148148 const keypair = crypto . generateKeypair ( )
149149 const obj = { data : 'test' , value : 123 }
150-
150+
151151 // Call without detached parameter
152152 const signedObj = crypto . signObj ( obj , keypair . secretKey , keypair . publicKey )
153-
153+
154154 // Should produce 64-byte signature
155155 expect ( signedObj . sign . sig . length ) . toBe ( 128 )
156-
156+
157157 // Should verify with both methods due to auto-detection
158158 expect ( crypto . verifyObj ( signedObj ) ) . toBe ( true )
159159 expect ( crypto . verifyObjDetached ( signedObj ) ) . toBe ( true )
160160 } )
161161 } )
162- } )
162+
163+ describe ( 'Manual signature conversion' , ( ) => {
164+ it ( 'should convert non-detached signature to detached by removing excess and verify with verifyObj' , ( ) => {
165+ const keypair = crypto . generateKeypair ( )
166+ const testObj = {
167+ message : 'Test conversion' ,
168+ timestamp : Date . now ( ) ,
169+ id : 'test-123' ,
170+ }
171+
172+ // Create a copy for manual signature manipulation
173+ const objForManualConversion = JSON . parse ( JSON . stringify ( testObj ) )
174+
175+ // Sign with old method (non-detached) - this includes message + signature
176+ const signedObjOld = crypto . signObj ( objForManualConversion , keypair . secretKey , keypair . publicKey , false )
177+
178+ // Verify the old signature works
179+ expect ( crypto . verifyObj ( signedObjOld ) ) . toBe ( true )
180+
181+ // Get the non-detached signature
182+ const nonDetachedSig = signedObjOld . sign . sig
183+
184+ // Non-detached signature should be longer than 128 hex chars (64 bytes)
185+ expect ( nonDetachedSig . length ) . toBeGreaterThan ( 128 )
186+
187+ // Manual conversion: Extract just the signature part (first 128 hex chars = 64 bytes)
188+ // In libsodium, non-detached signatures have format: [64-byte signature][original message]
189+ const detachedSigFromOld = nonDetachedSig . substring ( 0 , 128 )
190+
191+ // Verify the detached signature is exactly 64 bytes
192+ expect ( detachedSigFromOld . length ) . toBe ( 128 )
193+
194+ // Create a new object with the manually converted detached signature
195+ const objWithDetachedSig = {
196+ ...testObj ,
197+ sign : {
198+ owner : signedObjOld . sign . owner ,
199+ sig : detachedSigFromOld ,
200+ } ,
201+ }
202+
203+ // This should verify successfully using verifyObj with auto-detection
204+ expect ( crypto . verifyObj ( objWithDetachedSig ) ) . toBe ( true )
205+
206+ // It should also verify with the specific detached verification method
207+ expect ( crypto . verifyObjDetached ( objWithDetachedSig ) ) . toBe ( true )
208+
209+ // For additional verification, let's also test direct signature verification
210+ const objHash = crypto . hashObj ( objWithDetachedSig , true ) // true to remove sign field for hashing
211+ expect ( crypto . verifyDetached ( objHash , detachedSigFromOld , keypair . publicKey ) ) . toBe ( true )
212+ } )
213+ } )
214+ } )
0 commit comments