@@ -11,7 +11,7 @@ mod tests {
1111 #[ contractclient( name = "IpRegistryClient" ) ]
1212 #[ allow( dead_code) ]
1313 pub trait IpRegistry {
14- fn commit_ip ( env : Env , owner : Address , commitment_hash : BytesN < 32 > ) -> u64 ;
14+ fn commit_ip ( env : Env , owner : Address , commitment_hash : BytesN < 32 > , pow_difficulty : u32 ) -> u64 ;
1515 fn batch_commit_ip ( env : Env , owner : Address , commitment_hashes : Vec < BytesN < 32 > > ) -> Vec < u64 > ;
1616 fn get_ip ( env : Env , ip_id : u64 ) -> IpRecord ;
1717 fn verify_commitment (
@@ -33,6 +33,7 @@ mod tests {
3333 fn get_partial_disclosure ( env : Env , ip_id : u64 ) -> Option < BytesN < 32 > > ;
3434 fn validate_upgrade ( env : Env , new_wasm_hash : BytesN < 32 > ) ;
3535 fn upgrade ( env : Env , new_wasm_hash : BytesN < 32 > ) ;
36+ fn get_pow_difficulty ( env : Env ) -> u32 ;
3637 }
3738
3839 #[ test]
@@ -52,9 +53,9 @@ mod tests {
5253
5354 // Call commit_ip three times with proper authentication
5455 env. mock_all_auths ( ) ;
55- let id1 = client. commit_ip ( & owner1, & commitment1) ;
56- let id2 = client. commit_ip ( & owner2, & commitment2) ;
57- let id3 = client. commit_ip ( & owner1, & commitment3) ;
56+ let id1 = client. commit_ip ( & owner1, & commitment1, & 0u32 ) ;
57+ let id2 = client. commit_ip ( & owner2, & commitment2, & 0u32 ) ;
58+ let id3 = client. commit_ip ( & owner1, & commitment3, & 0u32 ) ;
5859
5960 // Assert IDs are sequential: 1, 2, 3 (first ID is 1, not 0)
6061 assert_eq ! ( id1, 1 , "First commit should return ID 1" ) ;
@@ -98,7 +99,7 @@ mod tests {
9899 env. mock_all_auths ( ) ;
99100
100101 // Call commit_ip which should emit an event
101- let ip_id = client. commit_ip ( & owner, & commitment) ;
102+ let ip_id = client. commit_ip ( & owner, & commitment, & 0u32 ) ;
102103
103104 // Check events immediately after commit_ip, before any other calls.
104105 let all_events = env. events ( ) . all ( ) ;
@@ -129,7 +130,7 @@ mod tests {
129130
130131 // All-zero hash has no cryptographic value — must panic with ContractError::ZeroCommitmentHash (code 2)
131132 let zero_hash = BytesN :: from_array ( & env, & [ 0u8 ; 32 ] ) ;
132- client. commit_ip ( & owner, & zero_hash) ;
133+ client. commit_ip ( & owner, & zero_hash, & 0u32 ) ;
133134 }
134135
135136 #[ test]
@@ -154,7 +155,7 @@ mod tests {
154155 let commitment = BytesN :: from_array ( & env, & [ 5u8 ; 32 ] ) ;
155156
156157 env. mock_all_auths ( ) ;
157- let ip_id = client. commit_ip ( & alice, & commitment) ;
158+ let ip_id = client. commit_ip ( & alice, & commitment, & 0u32 ) ;
158159
159160 client. transfer_ip ( & ip_id, & bob) ;
160161
@@ -183,7 +184,7 @@ mod tests {
183184 let commitment = BytesN :: from_array ( & env, & [ 6u8 ; 32 ] ) ;
184185
185186 env. mock_all_auths ( ) ;
186- let ip_id = client. commit_ip ( & alice, & commitment) ;
187+ let ip_id = client. commit_ip ( & alice, & commitment, & 0u32 ) ;
187188
188189 // Only mock bob's auth — alice's auth is not present, so transfer must panic
189190 env. mock_auths ( & [ soroban_sdk:: testutils:: MockAuth {
@@ -222,7 +223,7 @@ mod tests {
222223
223224 // Commit an IP for owner
224225 let commitment = BytesN :: from_array ( & env, & [ 1u8 ; 32 ] ) ;
225- let ip_id = client. commit_ip ( & owner, & commitment) ;
226+ let ip_id = client. commit_ip ( & owner, & commitment, & 0u32 ) ;
226227
227228 // Unknown owner returns empty Vec; known owner returns Vec with IPs.
228229 let unknown_ips = client. list_ip_by_owner ( & unknown_owner) ;
@@ -243,7 +244,7 @@ mod tests {
243244 let commitment = BytesN :: from_array ( & env, & [ 7u8 ; 32 ] ) ;
244245
245246 env. mock_all_auths ( ) ;
246- let ip_id = client. commit_ip ( & owner, & commitment) ;
247+ let ip_id = client. commit_ip ( & owner, & commitment, & 0u32 ) ;
247248
248249 assert ! ( !client. get_ip( & ip_id) . revoked) ;
249250 client. revoke_ip ( & ip_id) ;
@@ -260,7 +261,7 @@ mod tests {
260261 let commitment = BytesN :: from_array ( & env, & [ 9u8 ; 32 ] ) ;
261262
262263 env. mock_all_auths ( ) ;
263- let ip_id = client. commit_ip ( & owner, & commitment) ;
264+ let ip_id = client. commit_ip ( & owner, & commitment, & 0u32 ) ;
264265
265266 // Clear previous events (from commit_ip)
266267 env. events ( ) . clear ( ) ;
@@ -286,7 +287,7 @@ mod tests {
286287
287288 let owner = <Address as TestAddress >:: generate ( & env) ;
288289 env. mock_all_auths ( ) ;
289- let ip_id = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 8u8 ; 32 ] ) ) ;
290+ let ip_id = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 8u8 ; 32 ] ) , & 0u32 ) ;
290291 client. revoke_ip ( & ip_id) ;
291292 client. revoke_ip ( & ip_id) ; // must panic with IpAlreadyRevoked (code 4)
292293 }
@@ -300,9 +301,9 @@ mod tests {
300301 let client = IpRegistryClient :: new ( & env, & contract_id) ;
301302
302303 let owner = <Address as TestAddress >:: generate ( & env) ;
303- let id0 = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 1u8 ; 32 ] ) ) ;
304- let id1 = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 2u8 ; 32 ] ) ) ;
305- let id2 = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 3u8 ; 32 ] ) ) ;
304+ let id0 = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 1u8 ; 32 ] ) , & 0u32 ) ;
305+ let id1 = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 2u8 ; 32 ] ) , & 0u32 ) ;
306+ let id2 = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 3u8 ; 32 ] ) , & 0u32 ) ;
306307
307308 assert_eq ! ( id0, 1 ) ;
308309 assert_eq ! ( id1, 2 ) ;
@@ -327,7 +328,7 @@ mod tests {
327328 preimage. append ( & soroban_sdk:: Bytes :: from ( blinding. clone ( ) ) ) ;
328329 let commitment_hash: BytesN < 32 > = env. crypto ( ) . sha256 ( & preimage) . into ( ) ;
329330
330- let ip_id = client. commit_ip ( & owner, & commitment_hash) ;
331+ let ip_id = client. commit_ip ( & owner, & commitment_hash, & 0u32 ) ;
331332
332333 // Attempt verification with the wrong secret and assert the check fails.
333334 let wrong_secret = BytesN :: from_array ( & env, & [ 99u8 ; 32 ] ) ;
@@ -346,9 +347,9 @@ mod tests {
346347 let client = IpRegistryClient :: new ( & env, & contract_id) ;
347348
348349 let owner = <Address as TestAddress >:: generate ( & env) ;
349- let id0 = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 4u8 ; 32 ] ) ) ;
350- let id1 = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 5u8 ; 32 ] ) ) ;
351- let id2 = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 6u8 ; 32 ] ) ) ;
350+ let id0 = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 4u8 ; 32 ] ) , & 0u32 ) ;
351+ let id1 = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 5u8 ; 32 ] ) , & 0u32 ) ;
352+ let id2 = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 6u8 ; 32 ] ) , & 0u32 ) ;
352353
353354 let ids = client. list_ip_by_owner ( & owner) ;
354355 assert_eq ! ( ids. len( ) , 3 ) ;
@@ -367,7 +368,7 @@ mod tests {
367368 let owner = <Address as TestAddress >:: generate ( & env) ;
368369 let attacker = <Address as TestAddress >:: generate ( & env) ;
369370 env. mock_all_auths ( ) ;
370- let ip_id = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 9u8 ; 32 ] ) ) ;
371+ let ip_id = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 9u8 ; 32 ] ) , & 0u32 ) ;
371372
372373 // Only mock attacker's auth — owner's auth is absent, must panic
373374 env. mock_auths ( & [ soroban_sdk:: testutils:: MockAuth {
@@ -393,7 +394,7 @@ mod tests {
393394 let commitment = BytesN :: from_array ( & env, & [ 10u8 ; 32 ] ) ;
394395
395396 env. mock_all_auths ( ) ;
396- let ip_id = client. commit_ip ( & alice, & commitment) ;
397+ let ip_id = client. commit_ip ( & alice, & commitment, & 0u32 ) ;
397398
398399 // Alice should be the owner
399400 assert ! ( client. is_ip_owner( & ip_id, & alice) ) ;
@@ -426,7 +427,7 @@ mod tests {
426427 let blinding = BytesN :: from_array ( & env, & [ 0xcdu8 ; 32 ] ) ;
427428 let commitment = make_commitment ( & env, & partial_hash, & blinding) ;
428429
429- let ip_id = client. commit_ip ( & owner, & commitment) ;
430+ let ip_id = client. commit_ip ( & owner, & commitment, & 0u32 ) ;
430431
431432 // Valid proof: returns true
432433 assert ! ( client. reveal_partial( & ip_id, & partial_hash, & blinding) ) ;
@@ -448,7 +449,7 @@ mod tests {
448449 let wrong_blinding = BytesN :: from_array ( & env, & [ 0x33u8 ; 32 ] ) ;
449450 let commitment = make_commitment ( & env, & partial_hash, & blinding) ;
450451
451- let ip_id = client. commit_ip ( & owner, & commitment) ;
452+ let ip_id = client. commit_ip ( & owner, & commitment, & 0u32 ) ;
452453
453454 // Wrong blinding factor: proof fails
454455 assert ! ( !client. reveal_partial( & ip_id, & partial_hash, & wrong_blinding) ) ;
@@ -470,7 +471,7 @@ mod tests {
470471 let wrong_partial = BytesN :: from_array ( & env, & [ 0x66u8 ; 32 ] ) ;
471472 let commitment = make_commitment ( & env, & partial_hash, & blinding) ;
472473
473- let ip_id = client. commit_ip ( & owner, & commitment) ;
474+ let ip_id = client. commit_ip ( & owner, & commitment, & 0u32 ) ;
474475
475476 assert ! ( !client. reveal_partial( & ip_id, & wrong_partial, & blinding) ) ;
476477 assert_eq ! ( client. get_partial_disclosure( & ip_id) , None ) ;
@@ -490,7 +491,7 @@ mod tests {
490491 let commitment = make_commitment ( & env, & partial_hash, & blinding) ;
491492
492493 env. mock_all_auths ( ) ;
493- let ip_id = client. commit_ip ( & owner, & commitment) ;
494+ let ip_id = client. commit_ip ( & owner, & commitment, & 0u32 ) ;
494495
495496 // Only mock attacker's auth — must panic
496497 env. mock_auths ( & [ soroban_sdk:: testutils:: MockAuth {
@@ -514,7 +515,7 @@ mod tests {
514515
515516 let owner = <Address as TestAddress >:: generate ( & env) ;
516517 let commitment = BytesN :: from_array ( & env, & [ 0x99u8 ; 32 ] ) ;
517- let ip_id = client. commit_ip ( & owner, & commitment) ;
518+ let ip_id = client. commit_ip ( & owner, & commitment, & 0u32 ) ;
518519
519520 assert_eq ! ( client. get_partial_disclosure( & ip_id) , None ) ;
520521 }
@@ -587,7 +588,7 @@ mod tests {
587588 let owner = <Address as TestAddress >:: generate ( & env) ;
588589
589590 // Single commit
590- let id1 = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 10u8 ; 32 ] ) ) ;
591+ let id1 = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 10u8 ; 32 ] ) , & 0u32 ) ;
591592 assert_eq ! ( id1, 1 ) ;
592593
593594 // Batch commit 3
@@ -603,7 +604,7 @@ mod tests {
603604 assert_eq ! ( ids. get( 2 ) . unwrap( ) , 4 ) ;
604605
605606 // Another single
606- let id5 = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 14u8 ; 32 ] ) ) ;
607+ let id5 = client. commit_ip ( & owner, & BytesN :: from_array ( & env, & [ 14u8 ; 32 ] ) , & 0u32 ) ;
607608 assert_eq ! ( id5, 5 ) ;
608609 }
609610
@@ -628,4 +629,92 @@ mod tests {
628629 let zero_hash = BytesN :: from_array ( & env, & [ 0u8 ; 32 ] ) ;
629630 client. validate_upgrade ( & zero_hash) ;
630631 }
632+
633+ // ── PoW Tests ─────────────────────────────────────────────────────────────
634+
635+ #[ test]
636+ fn test_get_pow_difficulty_returns_default_four ( ) {
637+ let env = Env :: default ( ) ;
638+ let contract_id = env. register ( crate :: IpRegistry , ( ) ) ;
639+ let client = IpRegistryClient :: new ( & env, & contract_id) ;
640+ assert_eq ! ( client. get_pow_difficulty( ) , 4 ) ;
641+ }
642+
643+ #[ test]
644+ fn test_commit_ip_pow_difficulty_zero_always_passes ( ) {
645+ let env = Env :: default ( ) ;
646+ env. mock_all_auths ( ) ;
647+ let contract_id = env. register ( crate :: IpRegistry , ( ) ) ;
648+ let client = IpRegistryClient :: new ( & env, & contract_id) ;
649+
650+ let owner = <Address as TestAddress >:: generate ( & env) ;
651+ // Any non-zero hash passes when difficulty is 0
652+ let hash = BytesN :: from_array ( & env, & [ 0xffu8 ; 32 ] ) ;
653+ let ip_id = client. commit_ip ( & owner, & hash, & 0u32 ) ;
654+ assert_eq ! ( ip_id, 1 ) ;
655+ }
656+
657+ #[ test]
658+ fn test_commit_ip_pow_difficulty_eight_accepts_leading_zero_byte ( ) {
659+ let env = Env :: default ( ) ;
660+ env. mock_all_auths ( ) ;
661+ let contract_id = env. register ( crate :: IpRegistry , ( ) ) ;
662+ let client = IpRegistryClient :: new ( & env, & contract_id) ;
663+
664+ let owner = <Address as TestAddress >:: generate ( & env) ;
665+ // First byte 0x00 = 8 leading zero bits — satisfies difficulty 8
666+ let mut hash_bytes = [ 0x01u8 ; 32 ] ;
667+ hash_bytes[ 0 ] = 0x00 ;
668+ let hash = BytesN :: from_array ( & env, & hash_bytes) ;
669+ let ip_id = client. commit_ip ( & owner, & hash, & 8u32 ) ;
670+ assert_eq ! ( ip_id, 1 ) ;
671+ }
672+
673+ #[ test]
674+ fn test_commit_ip_pow_difficulty_four_accepts_half_zero_nibble ( ) {
675+ let env = Env :: default ( ) ;
676+ env. mock_all_auths ( ) ;
677+ let contract_id = env. register ( crate :: IpRegistry , ( ) ) ;
678+ let client = IpRegistryClient :: new ( & env, & contract_id) ;
679+
680+ let owner = <Address as TestAddress >:: generate ( & env) ;
681+ // 0x0f = 0000_1111 — 4 leading zero bits, satisfies difficulty 4
682+ let mut hash_bytes = [ 0x01u8 ; 32 ] ;
683+ hash_bytes[ 0 ] = 0x0f ;
684+ let hash = BytesN :: from_array ( & env, & hash_bytes) ;
685+ let ip_id = client. commit_ip ( & owner, & hash, & 4u32 ) ;
686+ assert_eq ! ( ip_id, 1 ) ;
687+ }
688+
689+ #[ test]
690+ #[ should_panic]
691+ fn test_commit_ip_pow_difficulty_four_rejects_insufficient_leading_zeros ( ) {
692+ let env = Env :: default ( ) ;
693+ env. mock_all_auths ( ) ;
694+ let contract_id = env. register ( crate :: IpRegistry , ( ) ) ;
695+ let client = IpRegistryClient :: new ( & env, & contract_id) ;
696+
697+ let owner = <Address as TestAddress >:: generate ( & env) ;
698+ // 0x1f = 0001_1111 — only 3 leading zero bits, fails difficulty 4
699+ let mut hash_bytes = [ 0x01u8 ; 32 ] ;
700+ hash_bytes[ 0 ] = 0x1f ;
701+ let hash = BytesN :: from_array ( & env, & hash_bytes) ;
702+ client. commit_ip ( & owner, & hash, & 4u32 ) ;
703+ }
704+
705+ #[ test]
706+ #[ should_panic]
707+ fn test_commit_ip_pow_difficulty_one_rejects_high_bit_set ( ) {
708+ let env = Env :: default ( ) ;
709+ env. mock_all_auths ( ) ;
710+ let contract_id = env. register ( crate :: IpRegistry , ( ) ) ;
711+ let client = IpRegistryClient :: new ( & env, & contract_id) ;
712+
713+ let owner = <Address as TestAddress >:: generate ( & env) ;
714+ // 0x80 = 1000_0000 — high bit set, fails difficulty 1
715+ let mut hash_bytes = [ 0x01u8 ; 32 ] ;
716+ hash_bytes[ 0 ] = 0x80 ;
717+ let hash = BytesN :: from_array ( & env, & hash_bytes) ;
718+ client. commit_ip ( & owner, & hash, & 1u32 ) ;
719+ }
631720}
0 commit comments