@@ -10,6 +10,7 @@ use bitcoin::secp256k1::ecdh::SharedSecret;
1010use bitcoin:: secp256k1:: ecdsa:: { RecoverableSignature , RecoveryId , Signature } ;
1111use bitcoin:: secp256k1:: { All , Message , Secp256k1 } ;
1212use bitcoin_hashes:: sha256;
13+ use data_encoding:: BASE32_NOPAD ;
1314
1415use crate :: error:: { CertsError , ReadError , StatusError } ;
1516use crate :: sats_chip:: SatsChip ;
@@ -78,6 +79,9 @@ pub trait Authentication {
7879 fn auth_delay ( & self ) -> & Option < usize > ;
7980 fn set_auth_delay ( & mut self , auth_delay : Option < usize > ) ;
8081 fn transport ( & self ) -> Arc < dyn CkTransport > ;
82+ fn card_ident ( & self ) -> String {
83+ card_pubkey_to_ident ( self . pubkey ( ) )
84+ }
8185
8286 /// Calculate ephemeral key pair and XOR'd CVC.
8387 /// ref: ["Authenticating Commands with CVC"](https://github.com/coinkite/coinkite-tap-proto/blob/master/docs/protocol.md#authenticating-commands-with-cvc)
@@ -111,6 +115,33 @@ pub trait Authentication {
111115 }
112116}
113117
118+ /// Convert a card's compressed pubkey into the standard public identifier.
119+ pub fn card_pubkey_to_ident ( pubkey : & PublicKey ) -> String {
120+ let serialized = pubkey. inner . serialize ( ) ;
121+ let digest = sha256:: Hash :: hash ( & serialized) ;
122+ let digest_bytes = digest. to_byte_array ( ) ;
123+ let encoded = BASE32_NOPAD . encode ( & digest_bytes[ 8 ..] ) ;
124+ let ident = & encoded[ ..20 ] ;
125+
126+ [ & ident[ 0 ..5 ] , & ident[ 5 ..10 ] , & ident[ 10 ..15 ] , & ident[ 15 ..20 ] ] . join ( "-" )
127+ }
128+
129+ #[ cfg( test) ]
130+ mod card_ident_tests {
131+ use super :: * ;
132+ use bitcoin:: hex:: FromHex ;
133+
134+ #[ test]
135+ fn converts_pubkey_to_ident ( ) {
136+ let pubkey_bytes = Vec :: < u8 > :: from_hex (
137+ "0312d005ca1501b1603c3b00412eefe27c6b20a74c29377263b357b3aff12de6fa" ,
138+ )
139+ . expect ( "valid pubkey hex" ) ;
140+ let pubkey = PublicKey :: from_slice ( & pubkey_bytes) . expect ( "compressed pubkey" ) ;
141+ assert_eq ! ( card_pubkey_to_ident( & pubkey) , "IYKC5-XN6ZN-3AGAA-BWABB" ) ;
142+ }
143+ }
144+
114145/// Trait for exchanging APDU data with cktap cards.
115146#[ async_trait]
116147pub trait CkTransport : Sync + Send {
0 commit comments