Skip to content

Commit ec02f3f

Browse files
committed
Move hex code to new submodule
In preparation for adding separate errors move the hex code to its own private module.
1 parent ebfb3e2 commit ec02f3f

File tree

8 files changed

+91
-94
lines changed

8 files changed

+91
-94
lines changed

src/ecdh.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use secp256k1_sys::types::{c_int, c_uchar, c_void};
1010

1111
use crate::ffi::{self, CPtr};
1212
use crate::key::{PublicKey, SecretKey};
13-
use crate::{constants, Error};
13+
use crate::{constants, hex, Error};
1414

1515
// The logic for displaying shared secrets relies on this (see `secret.rs`).
1616
const SHARED_SECRET_SIZE: usize = constants::SECRET_KEY_SIZE;
@@ -81,7 +81,7 @@ impl str::FromStr for SharedSecret {
8181
type Err = Error;
8282
fn from_str(s: &str) -> Result<Self, Self::Err> {
8383
let mut res = [0u8; SHARED_SECRET_SIZE];
84-
match crate::from_hex(s, &mut res) {
84+
match hex::from_hex(s, &mut res) {
8585
Ok(SHARED_SECRET_SIZE) => Ok(SharedSecret::from_bytes(res)),
8686
_ => Err(Error::InvalidSharedSecret),
8787
}
@@ -160,7 +160,7 @@ impl ::serde::Serialize for SharedSecret {
160160
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
161161
if s.is_human_readable() {
162162
let mut buf = [0u8; SHARED_SECRET_SIZE * 2];
163-
s.serialize_str(crate::to_hex(&self.0, &mut buf).expect("fixed-size hex serialization"))
163+
s.serialize_str(hex::to_hex(&self.0, &mut buf).expect("fixed-size hex serialization"))
164164
} else {
165165
s.serialize_bytes(self.as_ref())
166166
}

src/ecdsa/mod.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@ pub use self::serialized_signature::SerializedSignature;
1515
use crate::ffi::CPtr;
1616
#[cfg(feature = "global-context")]
1717
use crate::SECP256K1;
18-
use crate::{
19-
ffi, from_hex, Error, Message, PublicKey, Secp256k1, SecretKey, Signing, Verification,
20-
};
18+
use crate::{ffi, hex, Error, Message, PublicKey, Secp256k1, SecretKey, Signing, Verification};
2119

2220
/// An ECDSA signature
2321
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
@@ -39,7 +37,7 @@ impl str::FromStr for Signature {
3937
type Err = Error;
4038
fn from_str(s: &str) -> Result<Self, Self::Err> {
4139
let mut res = [0u8; 72];
42-
match from_hex(s, &mut res) {
40+
match hex::from_hex(s, &mut res) {
4341
Ok(x) => Signature::from_der(&res[0..x]),
4442
_ => Err(Error::InvalidSignature),
4543
}

src/ellswift.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ use core::str::FromStr;
4242
use ffi::CPtr;
4343
use secp256k1_sys::types::{c_int, c_uchar, c_void};
4444

45-
use crate::{constants, ffi, from_hex, Error, PublicKey, Secp256k1, SecretKey, Verification};
45+
use crate::{constants, ffi, hex, Error, PublicKey, Secp256k1, SecretKey, Verification};
4646

4747
unsafe extern "C" fn hash_callback<F>(
4848
output: *mut c_uchar,
@@ -292,7 +292,7 @@ impl FromStr for ElligatorSwift {
292292

293293
fn from_str(hex: &str) -> Result<Self, Self::Err> {
294294
let mut ser = [0u8; 64];
295-
let parsed = from_hex(hex, &mut ser);
295+
let parsed = hex::from_hex(hex, &mut ser);
296296
match parsed {
297297
Ok(64) => Ok(ElligatorSwift::from_array(ser)),
298298
_ => Err(Error::InvalidEllSwift),
@@ -329,7 +329,7 @@ mod tests {
329329
use crate::ellswift::{ElligatorSwiftParty, ElligatorSwiftSharedSecret};
330330
#[cfg(all(not(secp256k1_fuzz), feature = "alloc"))]
331331
use crate::SecretKey;
332-
use crate::{from_hex, PublicKey, XOnlyPublicKey};
332+
use crate::{hex, PublicKey, XOnlyPublicKey};
333333

334334
#[test]
335335
#[cfg(all(not(secp256k1_fuzz), feature = "alloc"))]
@@ -604,7 +604,7 @@ mod tests {
604604
#[inline]
605605
fn parse_test(ell: &str, x: &str, parity: u32) -> EllswiftDecodeTest {
606606
let mut enc = [0u8; 64];
607-
from_hex(ell, &mut enc).unwrap();
607+
hex::from_hex(ell, &mut enc).unwrap();
608608
let xo = XOnlyPublicKey::from_str(x).unwrap();
609609
let parity = if parity == 0 { crate::Parity::Even } else { crate::Parity::Odd };
610610
let pk = PublicKey::from_x_only_public_key(xo, parity);

src/hex.rs

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// SPDX-License-Identifier: CC0-1.0
2+
3+
//! Conversion to and from hexadecimal strings.
4+
5+
use core::str;
6+
7+
/// Utility function used to parse hex into a target u8 buffer. Returns
8+
/// the number of bytes converted or an error if it encounters an invalid
9+
/// character or unexpected end of string.
10+
pub(crate) fn from_hex(hex: &str, target: &mut [u8]) -> Result<usize, ()> {
11+
if hex.len() % 2 == 1 || hex.len() > target.len() * 2 {
12+
return Err(());
13+
}
14+
15+
let mut b = 0;
16+
let mut idx = 0;
17+
for c in hex.bytes() {
18+
b <<= 4;
19+
match c {
20+
b'A'..=b'F' => b |= c - b'A' + 10,
21+
b'a'..=b'f' => b |= c - b'a' + 10,
22+
b'0'..=b'9' => b |= c - b'0',
23+
_ => return Err(()),
24+
}
25+
if (idx & 1) == 1 {
26+
target[idx / 2] = b;
27+
b = 0;
28+
}
29+
idx += 1;
30+
}
31+
Ok(idx / 2)
32+
}
33+
34+
/// Utility function used to encode hex into a target u8 buffer. Returns
35+
/// a reference to the target buffer as an str. Returns an error if the target
36+
/// buffer isn't big enough.
37+
#[inline]
38+
pub(crate) fn to_hex<'a>(src: &[u8], target: &'a mut [u8]) -> Result<&'a str, ()> {
39+
let hex_len = src.len() * 2;
40+
if target.len() < hex_len {
41+
return Err(());
42+
}
43+
const HEX_TABLE: [u8; 16] = *b"0123456789abcdef";
44+
45+
let mut i = 0;
46+
for &b in src {
47+
target[i] = HEX_TABLE[usize::from(b >> 4)];
48+
target[i + 1] = HEX_TABLE[usize::from(b & 0b00001111)];
49+
i += 2;
50+
}
51+
let result = &target[..hex_len];
52+
debug_assert!(str::from_utf8(result).is_ok());
53+
return unsafe { Ok(str::from_utf8_unchecked(result)) };
54+
}

src/key.rs

+11-14
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@ use crate::ffi::{self, CPtr};
1616
use crate::Error::{self, InvalidPublicKey, InvalidPublicKeySum, InvalidSecretKey};
1717
#[cfg(feature = "global-context")]
1818
use crate::SECP256K1;
19-
use crate::{
20-
constants, ecdsa, from_hex, schnorr, Message, Scalar, Secp256k1, Signing, Verification,
21-
};
19+
use crate::{constants, ecdsa, hex, schnorr, Message, Scalar, Secp256k1, Signing, Verification};
2220
#[cfg(feature = "hashes")]
2321
use crate::{hashes, ThirtyTwoByteHash};
2422

@@ -114,7 +112,7 @@ impl str::FromStr for SecretKey {
114112
type Err = Error;
115113
fn from_str(s: &str) -> Result<Self, Self::Err> {
116114
let mut res = [0u8; constants::SECRET_KEY_SIZE];
117-
match from_hex(s, &mut res) {
115+
match hex::from_hex(s, &mut res) {
118116
Ok(constants::SECRET_KEY_SIZE) => SecretKey::from_slice(&res),
119117
_ => Err(Error::InvalidSecretKey),
120118
}
@@ -167,7 +165,7 @@ impl str::FromStr for PublicKey {
167165
type Err = Error;
168166
fn from_str(s: &str) -> Result<Self, Self::Err> {
169167
let mut res = [0u8; constants::UNCOMPRESSED_PUBLIC_KEY_SIZE];
170-
match from_hex(s, &mut res) {
168+
match hex::from_hex(s, &mut res) {
171169
Ok(constants::PUBLIC_KEY_SIZE) =>
172170
PublicKey::from_slice(&res[0..constants::PUBLIC_KEY_SIZE]),
173171
Ok(constants::UNCOMPRESSED_PUBLIC_KEY_SIZE) => PublicKey::from_slice(&res),
@@ -385,7 +383,7 @@ impl serde::Serialize for SecretKey {
385383
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
386384
if s.is_human_readable() {
387385
let mut buf = [0u8; constants::SECRET_KEY_SIZE * 2];
388-
s.serialize_str(crate::to_hex(&self.0, &mut buf).expect("fixed-size hex serialization"))
386+
s.serialize_str(hex::to_hex(&self.0, &mut buf).expect("fixed-size hex serialization"))
389387
} else {
390388
let mut tuple = s.serialize_tuple(constants::SECRET_KEY_SIZE)?;
391389
for byte in self.0.iter() {
@@ -859,7 +857,7 @@ impl Keypair {
859857
#[inline]
860858
pub fn from_seckey_str<C: Signing>(secp: &Secp256k1<C>, s: &str) -> Result<Keypair, Error> {
861859
let mut res = [0u8; constants::SECRET_KEY_SIZE];
862-
match from_hex(s, &mut res) {
860+
match hex::from_hex(s, &mut res) {
863861
Ok(constants::SECRET_KEY_SIZE) =>
864862
Keypair::from_seckey_slice(secp, &res[0..constants::SECRET_KEY_SIZE]),
865863
_ => Err(Error::InvalidPublicKey),
@@ -1041,8 +1039,7 @@ impl serde::Serialize for Keypair {
10411039
if s.is_human_readable() {
10421040
let mut buf = [0u8; constants::SECRET_KEY_SIZE * 2];
10431041
s.serialize_str(
1044-
crate::to_hex(&self.secret_bytes(), &mut buf)
1045-
.expect("fixed-size hex serialization"),
1042+
hex::to_hex(&self.secret_bytes(), &mut buf).expect("fixed-size hex serialization"),
10461043
)
10471044
} else {
10481045
let mut tuple = s.serialize_tuple(constants::SECRET_KEY_SIZE)?;
@@ -1134,7 +1131,7 @@ impl str::FromStr for XOnlyPublicKey {
11341131
type Err = Error;
11351132
fn from_str(s: &str) -> Result<Self, Self::Err> {
11361133
let mut res = [0u8; constants::SCHNORR_PUBLIC_KEY_SIZE];
1137-
match from_hex(s, &mut res) {
1134+
match hex::from_hex(s, &mut res) {
11381135
Ok(constants::SCHNORR_PUBLIC_KEY_SIZE) =>
11391136
XOnlyPublicKey::from_slice(&res[0..constants::SCHNORR_PUBLIC_KEY_SIZE]),
11401137
_ => Err(Error::InvalidPublicKey),
@@ -1559,13 +1556,13 @@ mod test {
15591556

15601557
use super::{Keypair, Parity, PublicKey, Secp256k1, SecretKey, XOnlyPublicKey, *};
15611558
use crate::Error::{InvalidPublicKey, InvalidSecretKey};
1562-
use crate::{constants, from_hex, to_hex, Scalar};
1559+
use crate::{constants, hex, Scalar};
15631560

15641561
#[cfg(not(secp256k1_fuzz))]
15651562
macro_rules! hex {
15661563
($hex:expr) => {{
15671564
let mut result = vec![0; $hex.len() / 2];
1568-
from_hex($hex, &mut result).expect("valid hex string");
1565+
hex::from_hex($hex, &mut result).expect("valid hex string");
15691566
result
15701567
}};
15711568
}
@@ -1745,7 +1742,7 @@ mod test {
17451742

17461743
let mut buf = [0u8; constants::SECRET_KEY_SIZE * 2];
17471744
assert_eq!(
1748-
to_hex(&sk[..], &mut buf).unwrap(),
1745+
hex::to_hex(&sk[..], &mut buf).unwrap(),
17491746
"0100000000000000020000000000000003000000000000000400000000000000"
17501747
);
17511748
}
@@ -2422,7 +2419,7 @@ mod test {
24222419
let ctx = crate::Secp256k1::new();
24232420
let keypair = Keypair::new(&ctx, &mut rand::thread_rng());
24242421
let mut buf = [0_u8; constants::SECRET_KEY_SIZE * 2]; // Holds hex digits.
2425-
let s = to_hex(&keypair.secret_key().secret_bytes(), &mut buf).unwrap();
2422+
let s = hex::to_hex(&keypair.secret_key().secret_bytes(), &mut buf).unwrap();
24262423
let parsed_key = Keypair::from_str(s).unwrap();
24272424
assert_eq!(parsed_key, keypair);
24282425
}

src/lib.rs

+11-61
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ mod macros;
159159
#[macro_use]
160160
mod secret;
161161
mod context;
162+
mod hex;
162163
mod key;
163164

164165
pub mod constants;
@@ -172,7 +173,7 @@ mod serde_util;
172173

173174
use core::marker::PhantomData;
174175
use core::ptr::NonNull;
175-
use core::{fmt, mem, str};
176+
use core::{fmt, mem};
176177

177178
#[cfg(feature = "global-context")]
178179
pub use context::global::SECP256K1;
@@ -483,55 +484,6 @@ pub fn generate_keypair<R: rand::Rng + ?Sized>(rng: &mut R) -> (key::SecretKey,
483484
SECP256K1.generate_keypair(rng)
484485
}
485486

486-
/// Utility function used to parse hex into a target u8 buffer. Returns
487-
/// the number of bytes converted or an error if it encounters an invalid
488-
/// character or unexpected end of string.
489-
fn from_hex(hex: &str, target: &mut [u8]) -> Result<usize, ()> {
490-
if hex.len() % 2 == 1 || hex.len() > target.len() * 2 {
491-
return Err(());
492-
}
493-
494-
let mut b = 0;
495-
let mut idx = 0;
496-
for c in hex.bytes() {
497-
b <<= 4;
498-
match c {
499-
b'A'..=b'F' => b |= c - b'A' + 10,
500-
b'a'..=b'f' => b |= c - b'a' + 10,
501-
b'0'..=b'9' => b |= c - b'0',
502-
_ => return Err(()),
503-
}
504-
if (idx & 1) == 1 {
505-
target[idx / 2] = b;
506-
b = 0;
507-
}
508-
idx += 1;
509-
}
510-
Ok(idx / 2)
511-
}
512-
513-
/// Utility function used to encode hex into a target u8 buffer. Returns
514-
/// a reference to the target buffer as an str. Returns an error if the target
515-
/// buffer isn't big enough.
516-
#[inline]
517-
fn to_hex<'a>(src: &[u8], target: &'a mut [u8]) -> Result<&'a str, ()> {
518-
let hex_len = src.len() * 2;
519-
if target.len() < hex_len {
520-
return Err(());
521-
}
522-
const HEX_TABLE: [u8; 16] = *b"0123456789abcdef";
523-
524-
let mut i = 0;
525-
for &b in src {
526-
target[i] = HEX_TABLE[usize::from(b >> 4)];
527-
target[i + 1] = HEX_TABLE[usize::from(b & 0b00001111)];
528-
i += 2;
529-
}
530-
let result = &target[..hex_len];
531-
debug_assert!(str::from_utf8(result).is_ok());
532-
return unsafe { Ok(str::from_utf8_unchecked(result)) };
533-
}
534-
535487
#[cfg(feature = "rand")]
536488
pub(crate) fn random_32_bytes<R: rand::Rng + ?Sized>(rng: &mut R) -> [u8; 32] {
537489
let mut ret = [0u8; 32];
@@ -551,7 +503,7 @@ mod tests {
551503
macro_rules! hex {
552504
($hex:expr) => {{
553505
let mut result = vec![0; $hex.len() / 2];
554-
from_hex($hex, &mut result).expect("valid hex string");
506+
hex::from_hex($hex, &mut result).expect("valid hex string");
555507
result
556508
}};
557509
}
@@ -888,8 +840,6 @@ mod tests {
888840
fn test_hex() {
889841
use rand::RngCore;
890842

891-
use super::to_hex;
892-
893843
let mut rng = rand::thread_rng();
894844
const AMOUNT: usize = 1024;
895845
for i in 0..AMOUNT {
@@ -900,17 +850,17 @@ mod tests {
900850
let src = &mut src_buf[0..i];
901851
rng.fill_bytes(src);
902852

903-
let hex = to_hex(src, &mut hex_buf).unwrap();
904-
assert_eq!(from_hex(hex, &mut result_buf).unwrap(), i);
853+
let hex = hex::to_hex(src, &mut hex_buf).unwrap();
854+
assert_eq!(hex::from_hex(hex, &mut result_buf).unwrap(), i);
905855
assert_eq!(src, &result_buf[..i]);
906856
}
907857

908-
assert!(to_hex(&[1; 2], &mut [0u8; 3]).is_err());
909-
assert!(to_hex(&[1; 2], &mut [0u8; 4]).is_ok());
910-
assert!(from_hex("deadbeaf", &mut [0u8; 3]).is_err());
911-
assert!(from_hex("deadbeaf", &mut [0u8; 4]).is_ok());
912-
assert!(from_hex("a", &mut [0u8; 4]).is_err());
913-
assert!(from_hex("ag", &mut [0u8; 4]).is_err());
858+
assert!(hex::to_hex(&[1; 2], &mut [0u8; 3]).is_err());
859+
assert!(hex::to_hex(&[1; 2], &mut [0u8; 4]).is_ok());
860+
assert!(hex::from_hex("deadbeaf", &mut [0u8; 3]).is_err());
861+
assert!(hex::from_hex("deadbeaf", &mut [0u8; 4]).is_ok());
862+
assert!(hex::from_hex("a", &mut [0u8; 4]).is_err());
863+
assert!(hex::from_hex("ag", &mut [0u8; 4]).is_err());
914864
}
915865

916866
#[test]

src/schnorr.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@ use crate::ffi::{self, CPtr};
1212
use crate::key::{Keypair, XOnlyPublicKey};
1313
#[cfg(feature = "global-context")]
1414
use crate::SECP256K1;
15-
use crate::{
16-
constants, from_hex, impl_array_newtype, Error, Message, Secp256k1, Signing, Verification,
17-
};
15+
use crate::{constants, hex, impl_array_newtype, Error, Message, Secp256k1, Signing, Verification};
1816

1917
/// Represents a schnorr signature.
2018
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -66,7 +64,7 @@ impl str::FromStr for Signature {
6664
type Err = Error;
6765
fn from_str(s: &str) -> Result<Self, Self::Err> {
6866
let mut res = [0u8; constants::SCHNORR_SIGNATURE_SIZE];
69-
match from_hex(s, &mut res) {
67+
match hex::from_hex(s, &mut res) {
7068
Ok(constants::SCHNORR_SIGNATURE_SIZE) =>
7169
Signature::from_slice(&res[0..constants::SCHNORR_SIGNATURE_SIZE]),
7270
_ => Err(Error::InvalidSignature),
@@ -200,13 +198,13 @@ mod tests {
200198
use super::*;
201199
use crate::schnorr::{Keypair, Signature, XOnlyPublicKey};
202200
use crate::Error::InvalidPublicKey;
203-
use crate::{constants, from_hex, Message, Secp256k1, SecretKey};
201+
use crate::{constants, hex, Message, Secp256k1, SecretKey};
204202

205203
#[cfg(all(not(secp256k1_fuzz), feature = "alloc"))]
206204
macro_rules! hex_32 {
207205
($hex:expr) => {{
208206
let mut result = [0u8; 32];
209-
from_hex($hex, &mut result).expect("valid hex string");
207+
hex::from_hex($hex, &mut result).expect("valid hex string");
210208
result
211209
}};
212210
}

0 commit comments

Comments
 (0)