valence_crypto_utils/
request.rs1use alloc::vec::Vec;
2use serde_json::Value;
3use sha2::{Digest as _, Sha256};
4
5use crate::{Ecdsa, Signer};
6
7impl Signer {
8 pub fn sign_json(&self, json: &[u8]) -> anyhow::Result<Vec<u8>> {
10 let json: Value = serde_json::from_slice(json)?;
11 let canonical = serde_json_canonicalizer::to_string(&json)?;
12 let digest = Sha256::digest(canonical.as_bytes());
13
14 self.sign(&digest)
15 }
16
17 pub fn sign_json_with_id(&self, id: &[u8], json: &[u8]) -> anyhow::Result<Vec<u8>> {
19 let json: Value = serde_json::from_slice(json)?;
20 let canonical = serde_json_canonicalizer::to_string(&json)?;
21
22 let mut hasher = Sha256::new();
23
24 hasher.update(id);
25 hasher.update(canonical);
26
27 let digest = hasher.finalize();
28
29 self.sign(&digest)
30 }
31}
32
33impl Ecdsa {
34 pub fn recover_from_json(sig: &[u8], json: &[u8]) -> anyhow::Result<Vec<u8>> {
36 let json: Value = serde_json::from_slice(json)?;
37 let canonical = serde_json_canonicalizer::to_string(&json)?;
38 let digest = Sha256::digest(canonical.as_bytes());
39
40 Self::recover(sig, &digest)
41 }
42
43 pub fn recover_from_json_with_id(
45 sig: &[u8],
46 id: &[u8],
47 json: &[u8],
48 ) -> anyhow::Result<Vec<u8>> {
49 let json: Value = serde_json::from_slice(json)?;
50 let canonical = serde_json_canonicalizer::to_string(&json)?;
51
52 let mut hasher = Sha256::new();
53
54 hasher.update(id);
55 hasher.update(canonical);
56
57 let digest = hasher.finalize();
58
59 Self::recover(sig, &digest)
60 }
61}
62
63#[test]
64fn recover_from_request_works() {
65 let secret = "b0cb16ba60d3b770eb5e001efaa8f5b94270f4e8e858f673f5e896db11d21698";
66 let request = serde_json::json!({
67 "b": "foo",
68 "a": 42,
69 });
70 let requests = [
71 serde_json::to_string(&request).unwrap(),
72 serde_json::to_string_pretty(&request).unwrap(),
73 r#"{"b": "foo", "a": 42 }"#.into(),
74 ];
75
76 let secret = const_hex::decode(secret).unwrap();
77 let signer = crate::Signer::from_secret(&secret).unwrap();
78 let public = signer.to_public();
79
80 for r in requests {
81 let signature = signer.sign_json(r.as_bytes()).unwrap();
82 let recovered = Ecdsa::recover_from_json(&signature, r.as_bytes()).unwrap();
83
84 assert_eq!(public, recovered);
85 }
86}
87
88#[test]
89fn recover_from_request_with_id_works() {
90 let secret = "b0cb16ba60d3b770eb5e001efaa8f5b94270f4e8e858f673f5e896db11d21698";
91 let request = serde_json::json!({
92 "b": "foo",
93 "a": 42,
94 });
95 let requests = [
96 serde_json::to_string(&request).unwrap(),
97 serde_json::to_string_pretty(&request).unwrap(),
98 r#"{"b": "foo", "a": 42 }"#.into(),
99 ];
100
101 let secret = const_hex::decode(secret).unwrap();
102 let signer = crate::Signer::from_secret(&secret).unwrap();
103 let public = signer.to_public();
104
105 for r in requests {
106 let id = b"id";
107 let signature = signer.sign_json_with_id(id, r.as_bytes()).unwrap();
108 let recovered = Ecdsa::recover_from_json_with_id(&signature, id, r.as_bytes()).unwrap();
109
110 assert_eq!(public, recovered);
111 }
112}