use alloc::vec::Vec;
use serde_json::Value;
use sha2::{Digest as _, Sha256};
use crate::{Ecdsa, Signer};
impl Signer {
pub fn sign_json(&self, json: &[u8]) -> anyhow::Result<Vec<u8>> {
let json: Value = serde_json::from_slice(json)?;
let canonical = serde_json_canonicalizer::to_string(&json)?;
let digest = Sha256::digest(canonical.as_bytes());
self.sign(&digest)
}
pub fn sign_json_with_id(&self, id: &[u8], json: &[u8]) -> anyhow::Result<Vec<u8>> {
let json: Value = serde_json::from_slice(json)?;
let canonical = serde_json_canonicalizer::to_string(&json)?;
let mut hasher = Sha256::new();
hasher.update(id);
hasher.update(canonical);
let digest = hasher.finalize();
self.sign(&digest)
}
}
impl Ecdsa {
pub fn recover_from_json(sig: &[u8], json: &[u8]) -> anyhow::Result<Vec<u8>> {
let json: Value = serde_json::from_slice(json)?;
let canonical = serde_json_canonicalizer::to_string(&json)?;
let digest = Sha256::digest(canonical.as_bytes());
Self::recover(sig, &digest)
}
pub fn recover_from_json_with_id(
sig: &[u8],
id: &[u8],
json: &[u8],
) -> anyhow::Result<Vec<u8>> {
let json: Value = serde_json::from_slice(json)?;
let canonical = serde_json_canonicalizer::to_string(&json)?;
let mut hasher = Sha256::new();
hasher.update(id);
hasher.update(canonical);
let digest = hasher.finalize();
Self::recover(sig, &digest)
}
}
#[test]
fn recover_from_request_works() {
let secret = "b0cb16ba60d3b770eb5e001efaa8f5b94270f4e8e858f673f5e896db11d21698";
let request = serde_json::json!({
"b": "foo",
"a": 42,
});
let requests = [
serde_json::to_string(&request).unwrap(),
serde_json::to_string_pretty(&request).unwrap(),
r#"{"b": "foo", "a": 42 }"#.into(),
];
let secret = const_hex::decode(secret).unwrap();
let signer = crate::Signer::from_secret(&secret).unwrap();
let public = signer.to_public();
for r in requests {
let signature = signer.sign_json(r.as_bytes()).unwrap();
let recovered = Ecdsa::recover_from_json(&signature, r.as_bytes()).unwrap();
assert_eq!(public, recovered);
}
}
#[test]
fn recover_from_request_with_id_works() {
let secret = "b0cb16ba60d3b770eb5e001efaa8f5b94270f4e8e858f673f5e896db11d21698";
let request = serde_json::json!({
"b": "foo",
"a": 42,
});
let requests = [
serde_json::to_string(&request).unwrap(),
serde_json::to_string_pretty(&request).unwrap(),
r#"{"b": "foo", "a": 42 }"#.into(),
];
let secret = const_hex::decode(secret).unwrap();
let signer = crate::Signer::from_secret(&secret).unwrap();
let public = signer.to_public();
for r in requests {
let id = b"id";
let signature = signer.sign_json_with_id(id, r.as_bytes()).unwrap();
let recovered = Ecdsa::recover_from_json_with_id(&signature, id, r.as_bytes()).unwrap();
assert_eq!(public, recovered);
}
}