Skip to content

Commit 784067c

Browse files
committed
Use Wscalar instead of DlogProverInput in ExtSecretKey
Now that DlogProverInput eagerly evaluates public key, it's a bad fit for ExtSecretKey since it causes unnecessary EC operations
1 parent d6bed99 commit 784067c

File tree

5 files changed

+57
-26
lines changed

5 files changed

+57
-26
lines changed

Cargo.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,12 @@ ergotree-interpreter = { version = "^0.28.0", path = "./ergotree-interpreter" }
3535
ergo-nipopow = { version = "^0.15", path = "./ergo-nipopow" }
3636
ergo-merkle-tree = { version = "^0.15.0", path = "./ergo-merkle-tree" }
3737
ergo-rest = { version = "^0.13.0", path = "./ergo-rest" }
38-
ergo-lib = { version = "^0.28.0", path = "./ergo-lib"}
39-
k256 = { version = "0.13.1", features = ["arithmetic", "ecdsa", "precomputed-tables"] }
38+
ergo-lib = { version = "^0.28.0", path = "./ergo-lib" }
39+
k256 = { version = "0.13.1", features = [
40+
"arithmetic",
41+
"ecdsa",
42+
"precomputed-tables",
43+
] }
4044
elliptic-curve = { version = "0.13.8", features = ["ff"] }
4145
thiserror = "1"
4246
bounded-vec = { version = "^0.7.0" }

ergo-lib/src/wallet/ext_pub_key.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ type HmacSha512 = Hmac<Sha512>;
2727
pub struct ExtPubKey {
2828
/// Parsed public key (EcPoint)
2929
pub public_key: EcPoint,
30-
chain_code: ChainCode,
30+
/// Chain code bytes
31+
pub chain_code: ChainCode,
3132
/// Derivation path for this extended public key
3233
pub derivation_path: DerivationPath,
3334
}

ergo-lib/src/wallet/ext_secret_key.rs

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
//! Extended private key operations according to BIP-32
2-
use std::convert::TryInto;
32
43
use super::{
54
derivation_path::{ChildIndex, ChildIndexError, DerivationPath},
@@ -27,14 +26,23 @@ type HmacSha512 = Hmac<Sha512>;
2726

2827
/// Extended secret key
2928
/// implemented according to BIP-32
30-
#[derive(PartialEq, Eq, Debug, Clone)]
29+
#[derive(PartialEq, Eq, Clone)]
3130
pub struct ExtSecretKey {
32-
/// The secret key
33-
private_input: DlogProverInput,
31+
private_input: Wscalar,
3432
chain_code: ChainCode,
3533
derivation_path: DerivationPath,
3634
}
3735

36+
impl std::fmt::Debug for ExtSecretKey {
37+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38+
f.debug_struct("ExtSecretKey")
39+
.field("private_input", &"*****") // disable debug output for secret key to prevent key leakage in logs
40+
.field("chain_code", &self.chain_code)
41+
.field("derivation_path", &self.derivation_path)
42+
.finish()
43+
}
44+
}
45+
3846
/// Extended secret key errors
3947
#[derive(Error, PartialEq, Eq, Debug, Clone)]
4048
pub enum ExtSecretKeyError {
@@ -65,8 +73,8 @@ impl ExtSecretKey {
6573
chain_code: ChainCode,
6674
derivation_path: DerivationPath,
6775
) -> Result<Self, ExtSecretKeyError> {
68-
let private_input = DlogProverInput::from_bytes(&secret_key_bytes)
69-
.ok_or(ExtSecretKeyError::ScalarEncodingError)?;
76+
let private_input =
77+
Wscalar::from_bytes(&secret_key_bytes).ok_or(ExtSecretKeyError::ScalarEncodingError)?;
7078
Ok(Self {
7179
private_input,
7280
chain_code,
@@ -81,7 +89,7 @@ impl ExtSecretKey {
8189

8290
/// Returns secret key
8391
pub fn secret_key(&self) -> SecretKey {
84-
self.private_input.clone().into()
92+
DlogProverInput::new(self.private_input.clone()).into()
8593
}
8694

8795
/// Byte representation of the underlying scalar
@@ -91,7 +99,7 @@ impl ExtSecretKey {
9199

92100
/// Public image associated with the private input
93101
pub fn public_image(&self) -> ProveDlog {
94-
self.private_input.public_image()
102+
DlogProverInput::new(self.private_input.clone()).public_image()
95103
}
96104

97105
/// Public image bytes in SEC-1 encoded & compressed format
@@ -102,12 +110,11 @@ impl ExtSecretKey {
102110
/// The extended public key associated with this secret key
103111
pub fn public_key(&self) -> Result<ExtPubKey, ExtSecretKeyError> {
104112
#[allow(clippy::unwrap_used)]
105-
Ok(ExtPubKey::new(
106-
// unwrap is safe as it is used on an Infallible result type
107-
self.public_image_bytes()?.try_into().unwrap(),
108-
self.chain_code,
109-
self.derivation_path.clone(),
110-
)?)
113+
Ok(ExtPubKey {
114+
public_key: *self.public_image().h,
115+
chain_code: self.chain_code,
116+
derivation_path: self.derivation_path.clone(),
117+
})
111118
}
112119

113120
/// Derive a child extended secret key using the provided index
@@ -126,16 +133,14 @@ impl ExtSecretKey {
126133
let mac_bytes = mac.finalize().into_bytes();
127134
let mut secret_key_bytes = [0; SecretKeyBytes::LEN];
128135
secret_key_bytes.copy_from_slice(&mac_bytes[..32]);
129-
if let Some(dlog_prover) = DlogProverInput::from_bytes(&secret_key_bytes) {
136+
if let Some(wscalar) = Wscalar::from_bytes(&secret_key_bytes) {
130137
// parse256(IL) + kpar (mod n).
131138
// via https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#child-key-derivation-ckd-functions
132-
let child_secret_key: DlogProverInput = Wscalar::from(
133-
dlog_prover
134-
.w
139+
let child_secret_key = Wscalar::from(
140+
wscalar
135141
.as_scalar_ref()
136-
.add(self.private_input.w.as_scalar_ref()),
137-
)
138-
.into();
142+
.add(self.private_input.as_scalar_ref()),
143+
);
139144
if child_secret_key.is_zero() {
140145
// ki == 0 case of:
141146
// > In case parse256(IL) ≥ n or ki = 0, the resulting key is invalid, and one

ergotree-interpreter/src/sigma_protocol/wscalar.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::fmt::Formatter;
77

88
use derive_more::From;
99
use derive_more::Into;
10+
use elliptic_curve::PrimeField;
1011
use ergo_chain_types::Base16DecodedBytes;
1112
use ergo_chain_types::Base16EncodedBytes;
1213
use k256::elliptic_curve::generic_array::GenericArray;
@@ -31,10 +32,30 @@ use super::SOUNDNESS_BYTES;
3132
pub struct Wscalar(Scalar);
3233

3334
impl Wscalar {
35+
/// Scalar(secret key) size in bytes
36+
pub const SIZE_BYTES: usize = 32;
37+
3438
/// Returns a reference to underlying Scalar
3539
pub fn as_scalar_ref(&self) -> &Scalar {
3640
&self.0
3741
}
42+
43+
/// Attempts to parse the given byte array as an SEC-1-encoded scalar(secret key).
44+
/// Returns None if the byte array does not contain a big-endian integer in the range [0, modulus).
45+
pub fn from_bytes(bytes: &[u8; Self::SIZE_BYTES]) -> Option<Self> {
46+
k256::Scalar::from_repr((*bytes).into())
47+
.map(Wscalar::from)
48+
.into()
49+
}
50+
51+
/// Convert scalar to big-endian byte representation
52+
pub fn to_bytes(&self) -> [u8; Self::SIZE_BYTES] {
53+
self.0.to_bytes().into()
54+
}
55+
/// Return true if the scalar is 0
56+
pub fn is_zero(&self) -> bool {
57+
self.0.is_zero().into()
58+
}
3859
}
3960

4061
impl From<GroupSizedBytes> for Wscalar {

ergotree-ir/src/chain/address.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -535,8 +535,8 @@ impl AddressEncoder {
535535
let mut address_bytes = address.content_bytes();
536536
let mut bytes = vec![prefix_byte];
537537
bytes.append(&mut address_bytes);
538-
let mut calculated_checksum = AddressEncoder::calc_checksum(&bytes[..]).to_vec();
539-
bytes.append(&mut calculated_checksum);
538+
let calculated_checksum = AddressEncoder::calc_checksum(&bytes[..]);
539+
bytes.extend_from_slice(&calculated_checksum);
540540
bytes
541541
}
542542

0 commit comments

Comments
 (0)