nut12.rs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. //! NUT-12: Offline ecash signature validation
  2. //! https://github.com/cashubtc/nuts/blob/main/12.md
  3. use std::ops::Mul;
  4. use k256::Scalar;
  5. use log::{debug, warn};
  6. use serde::{Deserialize, Serialize};
  7. use thiserror::Error;
  8. use super::{BlindedSignature, Id, Proof, PublicKey, SecretKey};
  9. use crate::dhke::{hash_e, hash_to_curve};
  10. use crate::Amount;
  11. #[derive(Debug, Error)]
  12. pub enum Error {
  13. #[error("No Dleq Proof provided")]
  14. MissingDleqProof,
  15. #[error("Incomplete DLEQ Proof")]
  16. IncompleteDleqProof,
  17. #[error("Invalid Dleq Prood")]
  18. InvalidDleqProof,
  19. #[error("`{0}`")]
  20. EllipticCurve(#[from] k256::elliptic_curve::Error),
  21. #[error("`{0}`")]
  22. Cashu(#[from] crate::error::Error),
  23. }
  24. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
  25. pub struct BlindSignatureDleq {
  26. pub e: SecretKey,
  27. pub s: SecretKey,
  28. }
  29. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
  30. pub struct ProofDleq {
  31. pub e: SecretKey,
  32. pub s: SecretKey,
  33. pub r: SecretKey,
  34. }
  35. fn verify_dleq(
  36. blinded_message: k256::PublicKey,
  37. blinded_signature: k256::PublicKey,
  38. e: k256::SecretKey,
  39. s: k256::SecretKey,
  40. mint_pubkey: k256::PublicKey,
  41. ) -> Result<(), Error> {
  42. let r1 = s.public_key().to_projective()
  43. - mint_pubkey
  44. .as_affine()
  45. .mul(Scalar::from(e.as_scalar_primitive()));
  46. let r2 = blinded_message
  47. .as_affine()
  48. .mul(Scalar::from(s.as_scalar_primitive()))
  49. - blinded_signature
  50. .as_affine()
  51. .mul(Scalar::from(e.as_scalar_primitive()));
  52. let e_bytes = e.to_bytes().to_vec();
  53. let hash_e = hash_e(vec![
  54. k256::PublicKey::try_from(r1)?,
  55. k256::PublicKey::try_from(r2)?,
  56. mint_pubkey,
  57. blinded_signature,
  58. ]);
  59. if e_bytes.ne(&hash_e) {
  60. warn!("DLEQ on signature failed");
  61. debug!("e_bytes: {:?}, Hash e: {:?}", e_bytes, hash_e);
  62. return Err(Error::InvalidDleqProof);
  63. }
  64. Ok(())
  65. }
  66. fn calculate_dleq(
  67. blinded_signature: k256::PublicKey,
  68. blinded_message: &k256::PublicKey,
  69. mint_secretkey: &k256::SecretKey,
  70. ) -> Result<BlindSignatureDleq, Error> {
  71. // Random nonce
  72. let r: k256::SecretKey = SecretKey::random().into();
  73. let r1 = r.public_key();
  74. let r2: k256::PublicKey = blinded_message
  75. .as_affine()
  76. .mul(Scalar::from(r.as_scalar_primitive()))
  77. .try_into()?;
  78. let e = hash_e(vec![r1, r2, mint_secretkey.public_key(), blinded_signature]);
  79. let e_sk = k256::SecretKey::from_slice(&e)?;
  80. let s = Scalar::from(r.as_scalar_primitive())
  81. + Scalar::from(e_sk.as_scalar_primitive())
  82. * Scalar::from(mint_secretkey.as_scalar_primitive());
  83. let s: k256::SecretKey = k256::SecretKey::new(s.into());
  84. Ok(BlindSignatureDleq {
  85. e: e_sk.into(),
  86. s: s.into(),
  87. })
  88. }
  89. impl Proof {
  90. pub fn verify_dleq(&self, mint_pubkey: &PublicKey) -> Result<(), Error> {
  91. let (e, s, blinding_factor): (k256::SecretKey, k256::SecretKey, k256::SecretKey) =
  92. if let Some(dleq) = self.dleq.clone() {
  93. (dleq.e.into(), dleq.s.into(), dleq.r.into())
  94. } else {
  95. return Err(Error::MissingDleqProof);
  96. };
  97. let c: k256::PublicKey = (&self.c).into();
  98. let mint_pubkey: k256::PublicKey = mint_pubkey.into();
  99. let y = hash_to_curve(self.secret.0.as_bytes())?;
  100. let blinded_signature = c.to_projective()
  101. + mint_pubkey
  102. .as_affine()
  103. .mul(Scalar::from(blinding_factor.as_scalar_primitive()));
  104. let blinded_message = y.to_projective() + blinding_factor.public_key().to_projective();
  105. let blinded_signature = k256::PublicKey::try_from(blinded_signature)?;
  106. let blinded_message = k256::PublicKey::try_from(blinded_message)?;
  107. verify_dleq(blinded_message, blinded_signature, e, s, mint_pubkey)
  108. }
  109. }
  110. impl BlindedSignature {
  111. pub fn new_dleq(
  112. amount: Amount,
  113. blinded_signature: PublicKey,
  114. keyset_id: Id,
  115. blinded_message: &PublicKey,
  116. mint_secretkey: SecretKey,
  117. ) -> Result<Self, Error> {
  118. let blinded_message: k256::PublicKey = blinded_message.into();
  119. let mint_secretkey: k256::SecretKey = mint_secretkey.into();
  120. let dleq = calculate_dleq(
  121. blinded_signature.clone().into(),
  122. &blinded_message,
  123. &mint_secretkey,
  124. )?;
  125. Ok(BlindedSignature {
  126. amount,
  127. keyset_id,
  128. c: blinded_signature,
  129. dleq: Some(dleq),
  130. })
  131. }
  132. pub fn verify_dleq(
  133. &self,
  134. mint_pubkey: &PublicKey,
  135. blinded_message: &PublicKey,
  136. ) -> Result<(), Error> {
  137. let (e, s): (k256::SecretKey, k256::SecretKey) = if let Some(dleq) = &self.dleq {
  138. (dleq.e.clone().into(), dleq.s.clone().into())
  139. } else {
  140. return Err(Error::MissingDleqProof);
  141. };
  142. let mint_pubkey: k256::PublicKey = mint_pubkey.into();
  143. let blinded_message: k256::PublicKey = blinded_message.into();
  144. let c: k256::PublicKey = (&self.c).into();
  145. verify_dleq(blinded_message, c, e, s, mint_pubkey)
  146. }
  147. /*
  148. r = random nonce
  149. R1 = r*G
  150. R2 = r*B'
  151. e = hash(R1,R2,A,C')
  152. s = r + e*a
  153. */
  154. #[cfg(feature = "mint")]
  155. pub fn add_dleq_proof(
  156. &mut self,
  157. blinded_message: &PublicKey,
  158. mint_secretkey: &SecretKey,
  159. ) -> Result<(), Error> {
  160. let blinded_message: k256::PublicKey = blinded_message.into();
  161. let mint_secretkey: k256::SecretKey = mint_secretkey.clone().into();
  162. let dleq = calculate_dleq(self.c.clone().into(), &blinded_message, &mint_secretkey)?;
  163. self.dleq = Some(dleq);
  164. Ok(())
  165. }
  166. }
  167. #[cfg(test)]
  168. mod tests {
  169. use std::str::FromStr;
  170. use super::*;
  171. #[test]
  172. fn test_blind_signature_dleq() {
  173. let blinded_sig = r#"{"amount":8,"id":"00882760bfa2eb41","C_":"02a9acc1e48c25eeeb9289b5031cc57da9fe72f3fe2861d264bdc074209b107ba2","dleq":{"e":"9818e061ee51d5c8edc3342369a554998ff7b4381c8652d724cdf46429be73d9","s":"9818e061ee51d5c8edc3342369a554998ff7b4381c8652d724cdf46429be73da"}}"#;
  174. let blinded: BlindedSignature = serde_json::from_str(blinded_sig).unwrap();
  175. let secret_key =
  176. SecretKey::from_hex("0000000000000000000000000000000000000000000000000000000000000001")
  177. .unwrap();
  178. let mint_key = secret_key.public_key();
  179. let blinded_secret = PublicKey::from_str(
  180. "02a9acc1e48c25eeeb9289b5031cc57da9fe72f3fe2861d264bdc074209b107ba2",
  181. )
  182. .unwrap();
  183. blinded.verify_dleq(&mint_key, &blinded_secret).unwrap()
  184. }
  185. #[test]
  186. fn test_proof_dleq() {
  187. let proof = r#"{"amount": 1,"id": "00882760bfa2eb41","secret": "daf4dd00a2b68a0858a80450f52c8a7d2ccf87d375e43e216e0c571f089f63e9","C": "024369d2d22a80ecf78f3937da9d5f30c1b9f74f0c32684d583cca0fa6a61cdcfc","dleq": {"e": "b31e58ac6527f34975ffab13e70a48b6d2b0d35abc4b03f0151f09ee1a9763d4","s": "8fbae004c59e754d71df67e392b6ae4e29293113ddc2ec86592a0431d16306d8","r": "a6d13fcd7a18442e6076f5e1e7c887ad5de40a019824bdfa9fe740d302e8d861"}}"#;
  188. let proof: Proof = serde_json::from_str(proof).unwrap();
  189. // A
  190. let a: PublicKey = PublicKey::from_str(
  191. "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
  192. )
  193. .unwrap();
  194. assert!(proof.verify_dleq(&a).is_ok());
  195. }
  196. }