11use async_trait:: async_trait;
22use bcr_common:: core:: { BillId , NodeId } ;
33use bcr_ebill_core:: application:: ServiceTraitBounds ;
4- use bcr_ebill_core:: protocol:: { Email , event:: bill_events:: BillEventType , mint:: MintSignature } ;
5- use bitcoin:: { XOnlyPublicKey , base58} ;
4+ use bcr_ebill_core:: protocol:: Sha256Hash ;
5+ use bcr_ebill_core:: protocol:: {
6+ Email , EmailIdentityProofData , SchnorrSignature , SignedIdentityProof ,
7+ crypto:: Error as CryptoError , event:: bill_events:: BillEventType ,
8+ } ;
9+ use bitcoin:: base58;
610use borsh_derive:: BorshSerialize ;
7- use nostr:: hashes:: Hash ;
8- use nostr:: hashes:: sha256;
9- use nostr:: util:: SECP256K1 ;
1011use secp256k1:: schnorr:: Signature ;
11- use secp256k1:: { Keypair , Message , SecretKey } ;
12+ use secp256k1:: { Keypair , Message , SECP256K1 , SecretKey } ;
1213use serde:: { Deserialize , Serialize } ;
1314use thiserror:: Error ;
1415
@@ -27,16 +28,15 @@ pub enum Error {
2728 /// all hex errors
2829 #[ error( "External Email Base58 Error: {0}" ) ]
2930 Base58 ( #[ from] base58:: InvalidCharacterError ) ,
30- /// all signature errors
31- #[ error( "External Email Signature Error: {0}" ) ]
32- Signature ( #[ from] secp256k1:: Error ) ,
3331 /// all borsh errors
3432 #[ error( "External Email Borsh Error" ) ]
3533 Borsh ( #[ from] borsh:: io:: Error ) ,
3634 #[ error( "External Email Invalid Mint Id Error" ) ]
3735 InvalidMintId ,
3836 #[ error( "External Email Invalid Mint Signature Error" ) ]
3937 InvalidMintSignature ,
38+ #[ error( "External Email crypto Error" ) ]
39+ Crypto ( #[ from] CryptoError ) ,
4040}
4141
4242#[ cfg( test) ]
@@ -66,7 +66,7 @@ pub trait EmailClientApi: ServiceTraitBounds {
6666 company_node_id : & Option < NodeId > ,
6767 confirmation_code : & str ,
6868 private_key : & SecretKey ,
69- ) -> Result < MintSignature > ;
69+ ) -> Result < ( SignedIdentityProof , EmailIdentityProofData ) > ;
7070 /// Send a bill notification email
7171 async fn send_bill_notification (
7272 & self ,
@@ -100,38 +100,54 @@ impl EmailClient {
100100 }
101101 }
102102
103- async fn get_eic_challenge ( & self , mint_url : & url:: Url , node_id : & NodeId ) -> Result < String > {
104- let req = StartEmailRegisterRequest {
105- node_id : node_id. to_owned ( ) ,
106- } ;
107-
108- let resp: StartEmailRegisterResponse = self
109- . cl
110- . post ( to_url ( mint_url, "v1/eic/challenge" ) ?)
111- . json ( & req)
112- . send ( )
113- . await ?
114- . json ( )
115- . await ?;
103+ async fn get_eic_challenge (
104+ & self ,
105+ mint_url : & url:: Url ,
106+ node_id : & NodeId ,
107+ private_key : & SecretKey ,
108+ ) -> Result < Signature > {
109+ self . get_challenge ( "eic" , mint_url, node_id, private_key)
110+ . await
111+ }
116112
117- Ok ( resp. challenge )
113+ async fn get_ens_challenge (
114+ & self ,
115+ mint_url : & url:: Url ,
116+ node_id : & NodeId ,
117+ private_key : & SecretKey ,
118+ ) -> Result < Signature > {
119+ self . get_challenge ( "ens" , mint_url, node_id, private_key)
120+ . await
118121 }
119122
120- async fn get_ens_challenge ( & self , mint_url : & url:: Url , node_id : & NodeId ) -> Result < String > {
123+ async fn get_challenge (
124+ & self ,
125+ prefix : & str ,
126+ mint_url : & url:: Url ,
127+ node_id : & NodeId ,
128+ private_key : & SecretKey ,
129+ ) -> Result < Signature > {
121130 let req = StartEmailRegisterRequest {
122131 node_id : node_id. to_owned ( ) ,
123132 } ;
124133
125134 let resp: StartEmailRegisterResponse = self
126135 . cl
127- . post ( to_url ( mint_url, "v1/ens /challenge" ) ?)
136+ . post ( to_url ( mint_url, & format ! ( "v1/{} /challenge" , prefix ) ) ?)
128137 . json ( & req)
129138 . send ( )
130139 . await ?
131140 . json ( )
132141 . await ?;
133142
134- Ok ( resp. challenge )
143+ let decoded_challenge = base58:: decode ( & resp. challenge ) . map_err ( Error :: Base58 ) ?;
144+
145+ let key_pair = Keypair :: from_secret_key ( SECP256K1 , private_key) ;
146+ let msg = Message :: from_digest_slice ( & decoded_challenge)
147+ . map_err ( |e| Error :: Crypto ( CryptoError :: Signature ( e. to_string ( ) ) ) ) ?;
148+ let signature = SECP256K1 . sign_schnorr ( & msg, & key_pair) ;
149+
150+ Ok ( signature)
135151 }
136152}
137153
@@ -151,12 +167,9 @@ impl EmailClientApi for EmailClient {
151167 email : & Email ,
152168 private_key : & SecretKey ,
153169 ) -> Result < ( ) > {
154- let challenge = self . get_eic_challenge ( mint_url, node_id) . await ?;
155- let decoded_challenge = base58:: decode ( & challenge) . map_err ( Error :: Base58 ) ?;
156-
157- let key_pair = Keypair :: from_secret_key ( SECP256K1 , private_key) ;
158- let msg = Message :: from_digest_slice ( & decoded_challenge) . map_err ( Error :: Signature ) ?;
159- let signed_challenge = SECP256K1 . sign_schnorr ( & msg, & key_pair) ;
170+ let signed_challenge = self
171+ . get_eic_challenge ( mint_url, node_id, private_key)
172+ . await ?;
160173
161174 let req = RegisterEmailRequest {
162175 node_id : node_id. to_owned ( ) ,
@@ -183,18 +196,22 @@ impl EmailClientApi for EmailClient {
183196 company_node_id : & Option < NodeId > ,
184197 confirmation_code : & str ,
185198 private_key : & SecretKey ,
186- ) -> Result < MintSignature > {
199+ ) -> Result < ( SignedIdentityProof , EmailIdentityProofData ) > {
187200 let pl = EmailConfirmPayload {
188201 node_id : node_id. to_owned ( ) ,
189202 company_node_id : company_node_id. to_owned ( ) ,
190203 confirmation_code : confirmation_code. to_owned ( ) ,
191204 } ;
192205
193206 let serialized = borsh:: to_vec ( & pl) . map_err ( Error :: Borsh ) ?;
194- let signature = sign_payload ( & serialized, private_key) ;
207+ let hash = Sha256Hash :: from_bytes ( & serialized) ;
208+ let signature = SchnorrSignature :: sign ( & hash, private_key) . map_err ( Error :: Crypto ) ?;
195209 let payload = base58:: encode ( & serialized) ;
196210
197- let req = EmailConfirmRequest { payload, signature } ;
211+ let req = EmailConfirmRequest {
212+ payload,
213+ signature : signature. as_sig ( ) ,
214+ } ;
198215
199216 let res: EmailConfirmResponse = self
200217 . cl
@@ -210,18 +227,25 @@ impl EmailClientApi for EmailClient {
210227 }
211228
212229 let decoded_mint_sig = base58:: decode ( & res. payload ) . map_err ( Error :: Base58 ) ?;
230+ let hash = Sha256Hash :: from_bytes ( & decoded_mint_sig) ;
231+
232+ let signature = SchnorrSignature :: from ( res. signature ) ;
213233
214- if !verify_request (
215- & decoded_mint_sig,
216- & res. signature ,
217- & mint_node_id. pub_key ( ) . x_only_public_key ( ) . 0 ,
218- ) ? {
234+ if !signature
235+ . verify ( & hash, & mint_node_id. pub_key ( ) )
236+ . map_err ( Error :: Crypto ) ?
237+ {
219238 return Err ( Error :: InvalidMintSignature . into ( ) ) ;
220239 }
221240
222- let mint_sig: MintSignature = borsh:: from_slice ( & decoded_mint_sig) . map_err ( Error :: Borsh ) ?;
241+ let proof = SignedIdentityProof {
242+ signature,
243+ witness : res. mint_node_id ,
244+ } ;
245+ let data: EmailIdentityProofData =
246+ borsh:: from_slice ( & decoded_mint_sig) . map_err ( Error :: Borsh ) ?;
223247
224- Ok ( mint_sig )
248+ Ok ( ( proof , data ) )
225249 }
226250
227251 async fn send_bill_notification (
@@ -243,13 +267,17 @@ impl EmailClientApi for EmailClient {
243267 } ;
244268
245269 let serialized = borsh:: to_vec ( & pl) . map_err ( Error :: Borsh ) ?;
246- let signature = sign_payload ( & serialized, private_key) ;
270+ let hash = Sha256Hash :: from_bytes ( & serialized) ;
271+ let signature = SchnorrSignature :: sign ( & hash, private_key) . map_err ( Error :: Crypto ) ?;
247272 let payload = base58:: encode ( & serialized) ;
248273
249- let req = NotificationSendRequest { payload, signature } ;
274+ let req = NotificationSendRequest {
275+ payload,
276+ signature : signature. as_sig ( ) ,
277+ } ;
250278
251279 self . cl
252- . post ( to_url ( mint_url, "notifications/v1 /send" ) ?)
280+ . post ( to_url ( mint_url, "v1/ens/email /send" ) ?)
253281 . json ( & req)
254282 . send ( )
255283 . await ?
@@ -265,12 +293,9 @@ impl EmailClientApi for EmailClient {
265293 company_node_id : & Option < NodeId > ,
266294 private_key : & SecretKey ,
267295 ) -> Result < url:: Url > {
268- let challenge = self . get_ens_challenge ( mint_url, node_id) . await ?;
269- let decoded_challenge = base58:: decode ( & challenge) . map_err ( Error :: Base58 ) ?;
270-
271- let key_pair = Keypair :: from_secret_key ( SECP256K1 , private_key) ;
272- let msg = Message :: from_digest_slice ( & decoded_challenge) . map_err ( Error :: Signature ) ?;
273- let signed_challenge = SECP256K1 . sign_schnorr ( & msg, & key_pair) ;
296+ let signed_challenge = self
297+ . get_ens_challenge ( mint_url, node_id, private_key)
298+ . await ?;
274299
275300 let req = GetEmailPreferencesLinkRequest {
276301 node_id : node_id. to_owned ( ) ,
@@ -291,20 +316,6 @@ impl EmailClientApi for EmailClient {
291316 }
292317}
293318
294- pub fn sign_payload ( req : & [ u8 ] , private_key : & SecretKey ) -> Signature {
295- let key_pair = Keypair :: from_secret_key ( SECP256K1 , private_key) ;
296- let hash: sha256:: Hash = sha256:: Hash :: hash ( req) ;
297- let req = Message :: from_digest ( * hash. as_ref ( ) ) ;
298-
299- SECP256K1 . sign_schnorr ( & req, & key_pair)
300- }
301-
302- pub fn verify_request ( payload : & [ u8 ] , signature : & Signature , key : & XOnlyPublicKey ) -> Result < bool > {
303- let hash = sha256:: Hash :: hash ( payload) ;
304- let msg = Message :: from_digest ( * hash. as_ref ( ) ) ;
305- Ok ( SECP256K1 . verify_schnorr ( signature, & msg, key) . is_ok ( ) )
306- }
307-
308319#[ derive( Debug , Serialize ) ]
309320pub struct StartEmailRegisterRequest {
310321 pub node_id : NodeId ,
@@ -313,7 +324,7 @@ pub struct StartEmailRegisterRequest {
313324#[ derive( Debug , Deserialize ) ]
314325pub struct StartEmailRegisterResponse {
315326 pub challenge : String ,
316- pub ttl_seconds : u32 ,
327+ pub ttl : u32 ,
317328}
318329
319330#[ derive( Debug , Serialize ) ]
@@ -341,7 +352,7 @@ pub struct EmailConfirmPayload {
341352
342353#[ derive( Debug , Deserialize ) ]
343354pub struct EmailConfirmResponse {
344- /// A borsh-encoded MintSignature
355+ /// A borsh-encoded EmailIdentityProofData
345356 pub payload : String ,
346357 /// The mint signature of the payload
347358 pub signature : Signature ,
0 commit comments