1
- use crate :: utils:: crypto:: sha256hash;
1
+ use crate :: utils:: crypto:: { encrypt_bytes , sha256hash, sign_bytes_recoverable } ;
2
2
use eyre:: Result ;
3
- use libsecp256k1:: SecretKey ;
3
+ use libsecp256k1:: { PublicKey , SecretKey } ;
4
4
use serde:: { Deserialize , Serialize } ;
5
5
6
6
/// A computation task is the task of computing a result from a given input. The result is encrypted with the public key of the requester.
@@ -27,28 +27,68 @@ impl TaskResponsePayload {
27
27
pub fn new (
28
28
result : impl AsRef < [ u8 ] > ,
29
29
task_id : & str ,
30
- encrypting_public_key : & [ u8 ] ,
30
+ encrypting_public_key : & PublicKey ,
31
31
signing_secret_key : & SecretKey ,
32
32
) -> Result < Self > {
33
33
// create the message `task_id || payload`
34
34
let mut preimage = Vec :: new ( ) ;
35
35
preimage. extend_from_slice ( task_id. as_ref ( ) ) ;
36
36
preimage. extend_from_slice ( result. as_ref ( ) ) ;
37
37
38
- // sign the message
39
- // TODO: use `sign_recoverable` here instead?
40
- let digest = libsecp256k1:: Message :: parse ( & sha256hash ( preimage) ) ;
41
- let ( signature, recid) = libsecp256k1:: sign ( & digest, signing_secret_key) ;
42
- let signature: [ u8 ; 64 ] = signature. serialize ( ) ;
43
- let recid: [ u8 ; 1 ] = [ recid. serialize ( ) ] ;
44
-
45
- // encrypt payload itself
46
- let ciphertext = ecies:: encrypt ( encrypting_public_key, result. as_ref ( ) ) ?;
38
+ let signature = sign_bytes_recoverable ( & sha256hash ( preimage) , signing_secret_key) ;
39
+ let ciphertext = encrypt_bytes ( result, encrypting_public_key) ?;
47
40
48
41
Ok ( TaskResponsePayload {
49
42
ciphertext : hex:: encode ( ciphertext) ,
50
- signature : format ! ( "{}{}" , hex :: encode ( signature ) , hex :: encode ( recid ) ) ,
43
+ signature,
51
44
task_id : task_id. to_string ( ) ,
52
45
} )
53
46
}
54
47
}
48
+
49
+ #[ cfg( test) ]
50
+ mod tests {
51
+ use super :: * ;
52
+ use ecies:: decrypt;
53
+ use libsecp256k1:: { recover, verify, Message , PublicKey , RecoveryId , Signature } ;
54
+ use rand:: thread_rng;
55
+
56
+ #[ test]
57
+ fn test_task_response_payload ( ) {
58
+ // this is the result that we are "sending"
59
+ const RESULT : & [ u8 ; 44 ] = b"hey im an LLM and I came up with this output" ;
60
+
61
+ // the signer will sign the payload, and it will be verified
62
+ let signer_sk = SecretKey :: random ( & mut thread_rng ( ) ) ;
63
+ let signer_pk = PublicKey :: from_secret_key ( & signer_sk) ;
64
+
65
+ // the payload will be encrypted with this key
66
+ let task_sk = SecretKey :: random ( & mut thread_rng ( ) ) ;
67
+ let task_pk = PublicKey :: from_secret_key ( & task_sk) ;
68
+ let task_id = uuid:: Uuid :: new_v4 ( ) . to_string ( ) ;
69
+
70
+ // creates a signed and encrypted payload
71
+ let payload = TaskResponsePayload :: new ( RESULT , & task_id, & task_pk, & signer_sk)
72
+ . expect ( "Should create payload" ) ;
73
+
74
+ // decrypt result and compare it to plaintext
75
+ let ciphertext_bytes = hex:: decode ( payload. ciphertext ) . unwrap ( ) ;
76
+ let result = decrypt ( & task_sk. serialize ( ) , & ciphertext_bytes) . expect ( "Could not decrypt" ) ;
77
+ assert_eq ! ( result, RESULT , "Result mismatch" ) ;
78
+
79
+ // verify signature
80
+ let signature_bytes = hex:: decode ( payload. signature ) . expect ( "Should decode" ) ;
81
+ let signature = Signature :: parse_standard_slice ( & signature_bytes[ ..64 ] ) . unwrap ( ) ;
82
+ let recid = RecoveryId :: parse ( signature_bytes[ 64 ] ) . unwrap ( ) ;
83
+ let mut preimage = vec ! [ ] ;
84
+ preimage. extend_from_slice ( task_id. as_bytes ( ) ) ;
85
+ preimage. extend_from_slice ( & result) ;
86
+ let message = Message :: parse ( & sha256hash ( preimage) ) ;
87
+ assert ! ( verify( & message, & signature, & signer_pk) , "Could not verify" ) ;
88
+
89
+ // recover verifying key (public key) from signature
90
+ let recovered_public_key =
91
+ recover ( & message, & signature, & recid) . expect ( "Could not recover" ) ;
92
+ assert_eq ! ( signer_pk, recovered_public_key, "Public key mismatch" ) ;
93
+ }
94
+ }
0 commit comments