peerbadge_protocol/
authorization.rs1use serde::{Deserialize, Serialize};
7use sha2::{digest::Output, Digest, Sha256};
8use std::str::FromStr;
9
10use crate::{
11 canonical::canonicalize_holder_authorization,
12 types::{
13 verify_identity_signature_with_key, CredentialDigest, HolderId, ProtocolV1,
14 SchnorrSignatureProof, SignedCredential, Timestamp,
15 },
16 CredentialsError,
17};
18
19pub const HOLDER_AUTHORIZATION_SIGNATURE_DOMAIN_SEPARATOR: &[u8] =
21 b"fedi-credential/holder-authorization-signature/v1\0";
22
23#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
27#[serde(transparent)]
28pub struct SubjectPubkey(pub nostr::PublicKey);
29
30impl FromStr for SubjectPubkey {
31 type Err = nostr::key::Error;
32
33 fn from_str(value: &str) -> Result<Self, Self::Err> {
34 nostr::PublicKey::parse(value).map(Self)
35 }
36}
37
38#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
43pub struct HolderAuthorizationRequest {
44 pub subject_pubkey: SubjectPubkey,
46}
47
48impl HolderAuthorizationRequest {
49 pub fn into_statement(
51 self,
52 holder_id_pubkey: HolderId,
53 issued_at: Timestamp,
54 credential: &SignedCredential,
55 ) -> Result<HolderAuthorizationStatement, CredentialsError> {
56 let credential_digest = CredentialDigest(credential.credential.digest()?);
57
58 Ok(HolderAuthorizationStatement {
59 holder_id_pubkey,
60 subject_pubkey: self.subject_pubkey,
61 credential_digest,
62 issued_at,
63 })
64 }
65}
66
67#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
69pub struct HolderAuthorizationStatement {
70 pub holder_id_pubkey: HolderId,
72
73 pub subject_pubkey: SubjectPubkey,
75
76 pub credential_digest: CredentialDigest,
78
79 pub issued_at: Timestamp,
81}
82
83impl HolderAuthorizationStatement {
84 pub fn digest(&self) -> Result<Output<Sha256>, CredentialsError> {
86 let canonical = canonicalize_holder_authorization(self)?;
87 Ok(Sha256::new()
88 .chain_update(HOLDER_AUTHORIZATION_SIGNATURE_DOMAIN_SEPARATOR)
89 .chain_update(canonical)
90 .finalize())
91 }
92}
93
94#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
101pub struct HolderAuthorization {
102 pub version: ProtocolV1,
104
105 pub authorization: HolderAuthorizationStatement,
107
108 pub proof: SchnorrSignatureProof,
111}
112
113impl HolderAuthorization {
114 pub fn digest(&self) -> Result<Output<Sha256>, CredentialsError> {
116 self.authorization.digest()
117 }
118
119 pub fn verify(&self) -> Result<HolderAuthorizationStatement, CredentialsError> {
121 verify_identity_signature_with_key(
122 &self.authorization.holder_id_pubkey.0,
123 &self.proof.signature,
124 nostr::secp256k1::Message::from_digest(self.digest()?.into()),
125 )?;
126
127 Ok(self.authorization.clone())
128 }
129}