Secret remove pub properties (#782)

* refactor: add getters to Secret and SecretData

* refactor: use new getters for Secret and SecretData in wallet receive

* refactor: using SecretData constructor

---------

Co-authored-by: thesimplekid <tsk@thesimplekid.com>
This commit is contained in:
asmo
2025-06-05 13:25:56 +02:00
committed by GitHub
parent d665e2fc38
commit 548bbf1b40
8 changed files with 95 additions and 44 deletions

View File

@@ -34,21 +34,53 @@ pub enum Kind {
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct SecretData {
/// Unique random string
pub nonce: String,
nonce: String,
/// Expresses the spending condition specific to each kind
pub data: String,
data: String,
/// Additional data committed to and can be used for feature extensions
#[serde(skip_serializing_if = "Option::is_none")]
pub tags: Option<Vec<Vec<String>>>,
tags: Option<Vec<Vec<String>>>,
}
impl SecretData {
/// Create new [`SecretData`]
pub fn new<S, V>(data: S, tags: Option<V>) -> Self
where
S: Into<String>,
V: Into<Vec<Vec<String>>>,
{
let nonce = crate::secret::Secret::generate().to_string();
Self {
nonce,
data: data.into(),
tags: tags.map(|v| v.into()),
}
}
/// Get the nonce
pub fn nonce(&self) -> &str {
&self.nonce
}
/// Get the data
pub fn data(&self) -> &str {
&self.data
}
/// Get the tags
pub fn tags(&self) -> Option<&Vec<Vec<String>>> {
self.tags.as_ref()
}
}
/// NUT10 Secret
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Secret {
/// Kind of the spending condition
pub kind: Kind,
kind: Kind,
/// Secret Data
pub secret_data: SecretData,
secret_data: SecretData,
}
impl Secret {
@@ -58,16 +90,19 @@ impl Secret {
S: Into<String>,
V: Into<Vec<Vec<String>>>,
{
let nonce = crate::secret::Secret::generate().to_string();
let secret_data = SecretData {
nonce,
data: data.into(),
tags: tags.map(|v| v.into()),
};
let secret_data = SecretData::new(data, tags);
Self { kind, secret_data }
}
/// Get the kind
pub fn kind(&self) -> Kind {
self.kind
}
/// Get the secret data
pub fn secret_data(&self) -> &SecretData {
&self.secret_data
}
}
impl Serialize for Secret {

View File

@@ -127,8 +127,12 @@ impl Proof {
/// Verify P2PK signature on [Proof]
pub fn verify_p2pk(&self) -> Result<(), Error> {
let secret: Nut10Secret = self.secret.clone().try_into()?;
let spending_conditions: Conditions =
secret.secret_data.tags.unwrap_or_default().try_into()?;
let spending_conditions: Conditions = secret
.secret_data()
.tags()
.cloned()
.unwrap_or_default()
.try_into()?;
let msg: &[u8] = self.secret.as_bytes();
let mut verified_pubkeys = HashSet::new();
@@ -142,8 +146,8 @@ impl Proof {
let mut pubkeys = spending_conditions.pubkeys.clone().unwrap_or_default();
if secret.kind.eq(&Kind::P2PK) {
pubkeys.push(PublicKey::from_str(&secret.secret_data.data)?);
if secret.kind().eq(&Kind::P2PK) {
pubkeys.push(PublicKey::from_str(secret.secret_data().data())?);
}
for signature in witness_signatures.iter() {
@@ -394,15 +398,21 @@ impl TryFrom<&Secret> for SpendingConditions {
impl TryFrom<Nut10Secret> for SpendingConditions {
type Error = Error;
fn try_from(secret: Nut10Secret) -> Result<SpendingConditions, Error> {
match secret.kind {
match secret.kind() {
Kind::P2PK => Ok(SpendingConditions::P2PKConditions {
data: PublicKey::from_str(&secret.secret_data.data)?,
conditions: secret.secret_data.tags.and_then(|t| t.try_into().ok()),
data: PublicKey::from_str(secret.secret_data().data())?,
conditions: secret
.secret_data()
.tags()
.and_then(|t| t.clone().try_into().ok()),
}),
Kind::HTLC => Ok(Self::HTLCConditions {
data: Sha256Hash::from_str(&secret.secret_data.data)
data: Sha256Hash::from_str(secret.secret_data().data())
.map_err(|_| Error::InvalidHash)?,
conditions: secret.secret_data.tags.and_then(|t| t.try_into().ok()),
conditions: secret
.secret_data()
.tags()
.and_then(|t| t.clone().try_into().ok()),
}),
}
}
@@ -650,14 +660,14 @@ pub fn enforce_sig_flag(proofs: Proofs) -> EnforceSigFlag {
let mut sigs_required = 1;
for proof in proofs {
if let Ok(secret) = Nut10Secret::try_from(proof.secret) {
if secret.kind.eq(&Kind::P2PK) {
if let Ok(verifying_key) = PublicKey::from_str(&secret.secret_data.data) {
if secret.kind().eq(&Kind::P2PK) {
if let Ok(verifying_key) = PublicKey::from_str(secret.secret_data().data()) {
pubkeys.insert(verifying_key);
}
}
if let Some(tags) = secret.secret_data.tags {
if let Ok(conditions) = Conditions::try_from(tags) {
if let Some(tags) = secret.secret_data().tags() {
if let Ok(conditions) = Conditions::try_from(tags.clone()) {
if conditions.sig_flag.eq(&SigFlag::SigAll) {
sig_flag = SigFlag::SigAll;
}

View File

@@ -66,8 +66,10 @@ impl Proof {
/// Verify HTLC
pub fn verify_htlc(&self) -> Result<(), Error> {
let secret: Secret = self.secret.clone().try_into()?;
let conditions: Option<Conditions> =
secret.secret_data.tags.and_then(|c| c.try_into().ok());
let conditions: Option<Conditions> = secret
.secret_data()
.tags()
.and_then(|c| c.clone().try_into().ok());
let htlc_witness = match &self.witness {
Some(Witness::HTLCWitness(witness)) => witness,
@@ -118,12 +120,12 @@ impl Proof {
}
}
if secret.kind.ne(&super::Kind::HTLC) {
if secret.kind().ne(&super::Kind::HTLC) {
return Err(Error::IncorrectSecretKind);
}
let hash_lock =
Sha256Hash::from_str(&secret.secret_data.data).map_err(|_| Error::InvalidHash)?;
Sha256Hash::from_str(secret.secret_data().data()).map_err(|_| Error::InvalidHash)?;
let preimage_hash = Sha256Hash::hash(htlc_witness.preimage.as_bytes());

View File

@@ -343,14 +343,14 @@ mod tests {
let full_secret: crate::nuts::Nut10Secret = secret_request.clone().into();
// Check conversion
assert_eq!(full_secret.kind, Kind::P2PK);
assert_eq!(full_secret.kind(), Kind::P2PK);
assert_eq!(
full_secret.secret_data.data,
full_secret.secret_data().data(),
"026562efcfadc8e86d44da6a8adf80633d974302e62c850774db1fb36ff4cc7198"
);
assert_eq!(
full_secret.secret_data.tags,
Some(vec![vec!["key".to_string(), "value".to_string()]])
full_secret.secret_data().tags().clone(),
Some(vec![vec!["key".to_string(), "value".to_string()]]).as_ref()
);
// Convert back to Nut10SecretRequest

View File

@@ -47,12 +47,12 @@ impl Nut10SecretRequest {
impl From<Nut10Secret> for Nut10SecretRequest {
fn from(secret: Nut10Secret) -> Self {
let secret_data = SecretDataRequest {
data: secret.secret_data.data,
tags: secret.secret_data.tags,
data: secret.secret_data().data().to_string(),
tags: secret.secret_data().tags().cloned(),
};
Self {
kind: secret.kind,
kind: secret.kind(),
secret_data,
}
}

View File

@@ -78,7 +78,7 @@ impl Secret {
serde_json::from_str(&self.0);
if let Ok(secret) = secret {
if secret.kind.eq(&Kind::P2PK) {
if secret.kind().eq(&Kind::P2PK) {
return true;
}
}

View File

@@ -387,7 +387,7 @@ impl Mint {
// only supported secret kinds are used as there is no way for the mint to
// enforce only signing supported secrets as they are blinded at
// that point.
match secret.kind {
match secret.kind() {
Kind::P2PK => {
proof.verify_p2pk()?;
}

View File

@@ -80,19 +80,23 @@ impl Wallet {
proof.secret.clone(),
)
{
let conditions: Result<Conditions, _> =
secret.secret_data.tags.unwrap_or_default().try_into();
let conditions: Result<Conditions, _> = secret
.secret_data()
.tags()
.cloned()
.unwrap_or_default()
.try_into();
if let Ok(conditions) = conditions {
let mut pubkeys = conditions.pubkeys.unwrap_or_default();
match secret.kind {
match secret.kind() {
Kind::P2PK => {
let data_key = PublicKey::from_str(&secret.secret_data.data)?;
let data_key = PublicKey::from_str(secret.secret_data().data())?;
pubkeys.push(data_key);
}
Kind::HTLC => {
let hashed_preimage = &secret.secret_data.data;
let hashed_preimage = secret.secret_data().data();
let preimage = hashed_to_preimage
.get(hashed_preimage)
.ok_or(Error::PreimageNotProvided)?;