Skip to content

Commit ca6d063

Browse files
committed
feat: support uncompressed transparent private keys (5XXX)
1 parent ad1ee78 commit ca6d063

8 files changed

Lines changed: 168 additions & 58 deletions

File tree

Cargo.lock

Lines changed: 11 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,25 @@ orchard = {git = "https://github.com/hhanh00/orchard.git", rev = "714e2e8feaf708
1212

1313
zcash_note_encryption = {git = "https://github.com/zcash/zcash_note_encryption.git", rev = "ede44ea608e667c78309c598fbf4d70f69c15c29"}
1414

15-
pczt = {git = "https://github.com/hhanh00/librustzcash.git", rev = "9a7f84682f97b1ba5fdd5eead84a66c818cb500e"}
16-
reddsa = {git = "https://github.com/ZcashFoundation/reddsa.git", rev = "975f9ca835c4b9196c81608e55192b0f711e951d"}
1715
sapling-crypto = {git = "https://github.com/hhanh00/sapling-crypto.git", rev = "50f15ecc5c292a7738e3c43d6879601bd7d241c8"}
18-
zcash_address = {git = "https://github.com/hhanh00/librustzcash.git", rev = "9a7f84682f97b1ba5fdd5eead84a66c818cb500e"}
19-
zcash_encoding = {git = "https://github.com/hhanh00/librustzcash.git", rev = "9a7f84682f97b1ba5fdd5eead84a66c818cb500e"}
20-
zcash_keys = {git = "https://github.com/hhanh00/librustzcash.git", rev = "9a7f84682f97b1ba5fdd5eead84a66c818cb500e"}
21-
zcash_primitives = {git = "https://github.com/hhanh00/librustzcash.git", rev = "9a7f84682f97b1ba5fdd5eead84a66c818cb500e"}
22-
zcash_proofs = {git = "https://github.com/hhanh00/librustzcash.git", rev = "9a7f84682f97b1ba5fdd5eead84a66c818cb500e"}
23-
zcash_protocol = {git = "https://github.com/hhanh00/librustzcash.git", rev = "9a7f84682f97b1ba5fdd5eead84a66c818cb500e"}
24-
zcash_transparent = {git = "https://github.com/hhanh00/librustzcash.git", rev = "9a7f84682f97b1ba5fdd5eead84a66c818cb500e"}
25-
zip321 = {git = "https://github.com/hhanh00/librustzcash.git", rev = "9a7f84682f97b1ba5fdd5eead84a66c818cb500e"}
16+
reddsa = {git = "https://github.com/ZcashFoundation/reddsa.git", rev = "975f9ca835c4b9196c81608e55192b0f711e951d"}
17+
18+
pczt = {git = "https://github.com/hhanh00/librustzcash.git", rev = "883d2883a319b7e9d0eae206e15626c90f317e28"}
19+
zcash_address = {git = "https://github.com/hhanh00/librustzcash.git", rev = "883d2883a319b7e9d0eae206e15626c90f317e28"}
20+
zcash_encoding = {git = "https://github.com/hhanh00/librustzcash.git", rev = "883d2883a319b7e9d0eae206e15626c90f317e28"}
21+
zcash_keys = {git = "https://github.com/hhanh00/librustzcash.git", rev = "883d2883a319b7e9d0eae206e15626c90f317e28"}
22+
zcash_primitives = {git = "https://github.com/hhanh00/librustzcash.git", rev = "883d2883a319b7e9d0eae206e15626c90f317e28"}
23+
zcash_proofs = {git = "https://github.com/hhanh00/librustzcash.git", rev = "883d2883a319b7e9d0eae206e15626c90f317e28"}
24+
zcash_protocol = {git = "https://github.com/hhanh00/librustzcash.git", rev = "883d2883a319b7e9d0eae206e15626c90f317e28"}
25+
zcash_transparent = {git = "https://github.com/hhanh00/librustzcash.git", rev = "883d2883a319b7e9d0eae206e15626c90f317e28"}
26+
zip321 = {git = "https://github.com/hhanh00/librustzcash.git", rev = "883d2883a319b7e9d0eae206e15626c90f317e28"}
27+
28+
#pczt = {path = "../librustzcash/pczt"}
29+
#zcash_address = {path = "../librustzcash/components/zcash_address"}
30+
#zcash_encoding = {path = "../librustzcash/components/zcash_encoding"}
31+
#zcash_keys = {path = "../librustzcash/zcash_keys"}
32+
#zcash_primitives = {path = "../librustzcash/zcash_primitives"}
33+
#zcash_proofs = {path = "../librustzcash/zcash_proofs"}
34+
#zcash_protocol = {path = "../librustzcash/components/zcash_protocol"}
35+
#zcash_transparent = {path = "../librustzcash/zcash_transparent"}
36+
#zip321 = {path = "../librustzcash/components/zip321"}

rust/src/account.rs

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ pub async fn new_account(
143143
None,
144144
&pk,
145145
&taddr.encode(network),
146+
false,
146147
)
147148
.await?;
148149
}
@@ -180,7 +181,7 @@ pub async fn new_account(
180181
store_account_transparent_vk(&mut db_tx, account, tvk).await?;
181182
for di in &[0, dindex] {
182183
let sk = derive_transparent_sk(tsk, 0, *di)?;
183-
let (pk, taddr) = derive_transparent_address(tvk, 0, *di)?;
184+
let (pk, taddr) = derive_transparent_address(tvk, 0, *di, false)?;
184185
store_account_transparent_addr(
185186
&mut db_tx,
186187
account,
@@ -189,6 +190,7 @@ pub async fn new_account(
189190
Some(sk),
190191
&pk,
191192
&taddr.encode(&network),
193+
false,
192194
)
193195
.await?;
194196
// do not create two taddrs if dindex == 0
@@ -224,7 +226,7 @@ pub async fn new_account(
224226
let xvk = xsk.to_account_pubkey();
225227
store_account_transparent_vk(&mut db_tx, account, &xvk).await?;
226228
let sk = derive_transparent_sk(&xsk, 0, 0)?;
227-
let (pk, address) = derive_transparent_address(&xvk, 0, 0)?;
229+
let (pk, address) = derive_transparent_address(&xvk, 0, 0, false)?;
228230
store_account_transparent_addr(
229231
&mut db_tx,
230232
account,
@@ -233,6 +235,7 @@ pub async fn new_account(
233235
Some(sk),
234236
&pk,
235237
&address.encode(&network),
238+
false,
236239
)
237240
.await?;
238241
} else if let Ok(xvk) = ExtendedPublicKey::<PublicKey>::from_str(&key) {
@@ -241,7 +244,7 @@ pub async fn new_account(
241244
buf.extend_from_slice(&xvk.to_bytes());
242245
let xvk = AccountPubKey::deserialize(&buf.try_into().unwrap()).unwrap();
243246
store_account_transparent_vk(&mut db_tx, account, &xvk).await?;
244-
let (pk, address) = derive_transparent_address(&xvk, 0, 0)?;
247+
let (pk, address) = derive_transparent_address(&xvk, 0, 0, false)?;
245248
store_account_transparent_addr(
246249
&mut db_tx,
247250
account,
@@ -250,25 +253,45 @@ pub async fn new_account(
250253
None,
251254
&pk,
252255
&address.encode(&network),
256+
false,
253257
)
254258
.await?;
255259
} else if let Ok(sk) = bip38::import_tsk(&key) {
256260
let secp = secp256k1::Secp256k1::new();
257-
let pk = sk.public_key(&secp);
258-
let tpk = pk.serialize().to_vec();
261+
let pk = sk.0.public_key(&secp);
262+
let tpk = if sk.1 {
263+
pk.serialize_uncompressed().to_vec()
264+
} else {
265+
pk.serialize().to_vec()
266+
};
259267
let pkh: [u8; 20] = Ripemd160::digest(Sha256::digest(&tpk)).into();
260268
let addr = TransparentAddress::PublicKeyHash(pkh);
269+
let address_str = addr.encode(&network);
261270
store_account_transparent_addr(
262271
&mut db_tx,
263272
account,
264273
0,
265274
0,
266-
Some(sk.to_bytes().to_vec()),
275+
Some(sk.0.to_bytes().to_vec()),
276+
&tpk,
277+
&address_str,
278+
sk.1,
279+
)
280+
.await?;
281+
} else if let Ok((_hrp, tpk)) = bech32::decode(&key) {
282+
let pkh: [u8; 20] = Ripemd160::digest(Sha256::digest(&tpk)).into();
283+
let addr = TransparentAddress::PublicKeyHash(pkh);
284+
store_account_transparent_addr(
285+
&mut db_tx,
286+
account,
287+
0,
288+
0,
289+
None,
267290
&tpk,
268291
&addr.encode(&network),
292+
false,
269293
)
270294
.await?;
271-
} else if let Ok((_, tpk)) = bech32::decode(&key) {
272295
let pkh: [u8; 20] = Ripemd160::digest(Sha256::digest(&tpk)).into();
273296
let addr = TransparentAddress::PublicKeyHash(pkh);
274297
store_account_transparent_addr(
@@ -279,6 +302,7 @@ pub async fn new_account(
279302
None,
280303
&tpk,
281304
&addr.encode(&network),
305+
false,
282306
)
283307
.await?;
284308
}
@@ -323,7 +347,7 @@ pub async fn new_account(
323347
Some(tvk) if pools & 1 != 0 => {
324348
init_account_transparent(&mut db_tx, account, birth).await?;
325349
store_account_transparent_vk(&mut db_tx, account, tvk).await?;
326-
let (pk, address) = derive_transparent_address(tvk, 0, dindex)?;
350+
let (pk, address) = derive_transparent_address(tvk, 0, dindex, false)?;
327351
store_account_transparent_addr(
328352
&mut db_tx,
329353
account,
@@ -332,6 +356,7 @@ pub async fn new_account(
332356
None,
333357
&pk,
334358
&address.encode(&network),
359+
false,
335360
)
336361
.await?;
337362
}
@@ -355,6 +380,9 @@ pub async fn new_account(
355380
}
356381
update_dindex(&mut db_tx, account, dindex, true).await?;
357382
}
383+
else {
384+
anyhow::bail!("Unsupported key");
385+
}
358386
db_tx.commit().await?;
359387
Ok(account)
360388
}
@@ -376,15 +404,20 @@ pub fn derive_transparent_address(
376404
tvk: &AccountPubKey,
377405
scope: u32,
378406
dindex: u32,
407+
uncompressed: bool,
379408
) -> Result<(Vec<u8>, TransparentAddress)> {
380409
let sindex = TransparentKeyScope::custom(scope).unwrap();
381-
let tpk = tvk
410+
let pk = tvk
382411
.derive_address_pubkey(sindex, NonHardenedChildIndex::from_index(dindex).unwrap())
383-
.unwrap()
384-
.serialize();
385-
let pkh: [u8; 20] = Ripemd160::digest(Sha256::digest(tpk)).into();
412+
.unwrap();
413+
let tpk = if uncompressed {
414+
pk.serialize_uncompressed().to_vec()
415+
} else {
416+
pk.serialize().to_vec()
417+
};
418+
let pkh: [u8; 20] = Ripemd160::digest(Sha256::digest(&tpk)).into();
386419
let addr = TransparentAddress::PublicKeyHash(pkh);
387-
Ok((tpk.to_vec(), addr))
420+
Ok((tpk, addr))
388421
}
389422

390423
pub async fn get_account_seed(
@@ -737,7 +770,7 @@ pub async fn generate_next_dindex(
737770
.xsk
738771
.as_ref()
739772
.map(|tsk| derive_transparent_sk(tsk, 0, dindex).unwrap());
740-
let (pk, address) = derive_transparent_address(&xvk, 0, dindex)?;
773+
let (pk, address) = derive_transparent_address(&xvk, 0, dindex, false)?;
741774
(sk, pk, Some(address))
742775
}
743776
None if hw != 0 => {
@@ -758,6 +791,7 @@ pub async fn generate_next_dindex(
758791
sk,
759792
&pk,
760793
&address.encode(network),
794+
false,
761795
)
762796
.await?;
763797
}
@@ -790,7 +824,7 @@ pub async fn generate_next_change_address(
790824
let sk = xsk
791825
.as_ref()
792826
.map(|tsk| derive_transparent_sk(tsk, 1, dindex).unwrap());
793-
let (change_pk, change_address) = derive_transparent_address(tvk, 1, dindex)?;
827+
let (change_pk, change_address) = derive_transparent_address(tvk, 1, dindex, false)?;
794828
let change_address = change_address.encode(network);
795829

796830
store_account_transparent_addr(
@@ -801,6 +835,7 @@ pub async fn generate_next_change_address(
801835
sk,
802836
&change_pk,
803837
&change_address,
838+
false,
804839
)
805840
.await?;
806841

@@ -848,7 +883,7 @@ pub async fn get_addresses(
848883
let taddr = tkeys
849884
.xvk
850885
.as_ref()
851-
.map(|xvk| derive_transparent_address(xvk, 0, dindex).unwrap().1);
886+
.map(|xvk| derive_transparent_address(xvk, 0, dindex, false).unwrap().1);
852887

853888
let dindex = dindex as u64;
854889
let saddr = skeys.address;

rust/src/bip38.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
11
use anyhow::Result;
22
use secp256k1::SecretKey;
33

4-
pub fn export_tsk(sk: &SecretKey) -> String {
5-
let mut v = sk.secret_bytes().to_vec();
6-
v.push(0x01);
4+
pub struct TSecretKey(pub SecretKey, pub bool);
5+
6+
pub fn export_tsk(sk: &TSecretKey) -> String {
7+
let mut v = sk.0.secret_bytes().to_vec();
8+
if !sk.1 {
9+
v.push(0x01);
10+
}
711
bs58::encode(v).with_check_version(0x80).into_string()
812
}
913

10-
pub fn import_tsk(tsk: &str) -> Result<SecretKey> {
14+
pub fn import_tsk(tsk: &str) -> Result<TSecretKey> {
1115
let v = bs58::decode(tsk).with_check(Some(0x80)).into_vec()?;
12-
if v.len() != 34 {
13-
return Err(anyhow::anyhow!("Invalid TSK length"));
16+
tracing::info!("{}", hex::encode(&v));
17+
if v.len() != 33 && v.len() != 34 {
18+
return Err(anyhow::anyhow!("Invalid TSK length {}", v.len()));
1419
}
1520
let sk = SecretKey::from_slice(&v[1..33]).unwrap();
16-
Ok(sk)
21+
let compressed = v.len() == 34 && v[33] == 0x01;
22+
Ok(TSecretKey(sk, !compressed))
1723
}

0 commit comments

Comments
 (0)