From 1b777cf1086cd9ec5b54099b511d245abb517c8f Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ <me@jeandudey.tech> Date: Thu, 1 Aug 2024 14:22:54 +0200 Subject: [PATCH] SFT-3908: Switch to faster-hex from hex crate. --- Cargo.toml | 2 +- codecs/src/nostr.rs | 8 ++- firmware/Cargo.toml | 6 +-- firmware/src/bin/foundation-firmware.rs | 11 ++-- test-vectors/Cargo.toml | 14 ++--- test-vectors/src/bip32.rs | 2 +- test-vectors/src/lib.rs | 68 ++++--------------------- test-vectors/src/psbt.rs | 2 +- ur/Cargo.toml | 2 +- ur/src/fountain/encoder.rs | 13 +++-- urtypes/Cargo.toml | 2 +- urtypes/src/registry/passport.rs | 23 ++++++--- urtypes/src/supply_chain_validation.rs | 11 ++-- urtypes/tests/hdkey.rs | 5 +- 14 files changed, 70 insertions(+), 99 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 821eeec..ca2555b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,8 +28,8 @@ bs58 = "0.5" clap = { version = "4", features = ["cargo"] } crc = "3" criterion = { version = "0.4" } +faster-hex = { version = "0.9", default-features = false } heapless = { version = "0.8", default-features = false } -hex = { version = "0.4.2", default-features = false } itertools = { version = "0.10", default-features = false } libfuzzer-sys = "0.4" minicbor = { version = "0.24", features = ["derive"] } diff --git a/codecs/src/nostr.rs b/codecs/src/nostr.rs index 83d0ef4..036b990 100644 --- a/codecs/src/nostr.rs +++ b/codecs/src/nostr.rs @@ -98,7 +98,9 @@ pub mod tests { let vectors = NIP19Vector::new(); for vector in vectors.iter().filter(|t| t.kind == NPUB) { - let encoded = encode_npub(&vector.bytes); + let mut public_key = [0; 32]; + public_key.copy_from_slice(&vector.bytes); + let encoded = encode_npub(&public_key); assert_eq!(&encoded, &*vector.encoded); } } @@ -108,7 +110,9 @@ pub mod tests { let vectors = NIP19Vector::new(); for vector in vectors.iter().filter(|t| t.kind == NSEC) { - let encoded = encode_nsec(&vector.bytes); + let mut private_key = [0; 32]; + private_key.copy_from_slice(&vector.bytes); + let encoded = encode_nsec(&private_key); assert_eq!(&encoded, &*vector.encoded); } } diff --git a/firmware/Cargo.toml b/firmware/Cargo.toml index 12aedff..8f795f0 100644 --- a/firmware/Cargo.toml +++ b/firmware/Cargo.toml @@ -18,14 +18,14 @@ required-features = ["binary"] [features] default = ["std", "binary"] -std = ["anyhow/std", "hex?/std", "nom/std", "secp256k1/std"] -binary = ["anyhow", "clap", "hex", "secp256k1/global-context", "std"] +std = ["anyhow/std", "faster-hex?/std", "nom/std", "secp256k1/std"] +binary = ["anyhow", "clap", "faster-hex", "secp256k1/global-context", "std"] [dependencies] bitcoin_hashes = { workspace = true } clap = { workspace = true, optional = true } heapless = { workspace = true } -hex = { workspace = true, optional = true } +faster-hex = { workspace = true, optional = true } nom = { workspace = true } secp256k1 = { workspace = true } anyhow = { workspace = true, optional = true } diff --git a/firmware/src/bin/foundation-firmware.rs b/firmware/src/bin/foundation-firmware.rs index 7c1c2c6..94770d2 100644 --- a/firmware/src/bin/foundation-firmware.rs +++ b/firmware/src/bin/foundation-firmware.rs @@ -4,6 +4,7 @@ use anyhow::{anyhow, bail, Context, Result}; use bitcoin_hashes::{sha256, sha256d, Hash, HashEngine}; use clap::{command, value_parser, Arg, ArgAction}; +use faster_hex::hex_string; use foundation_firmware::{header, Header, Information, HEADER_LEN}; use nom::Finish; use secp256k1::{global::SECP256K1, PublicKey}; @@ -56,7 +57,7 @@ fn main() -> Result<()> { println!( "{:>17}: {}", "User Public Key", - hex::encode(public_key.serialize_uncompressed()) + hex_string(&public_key.serialize_uncompressed()) ); } @@ -86,9 +87,9 @@ fn print_header(header: &Header) { println!("{:>17}: {}", "Version", header.information.version); println!("{:>17}: {} bytes", "Length", header.information.length); println!("{:>17}: {}", "Key", header.signature.public_key1); - println!("{:>17}: {}", "Signature", hex::encode(signature1)); + println!("{:>17}: {}", "Signature", hex_string(&signature1)); println!("{:>17}: {}", "Key", header.signature.public_key2); - println!("{:>17}: {}", "Signature", hex::encode(signature2)); + println!("{:>17}: {}", "Signature", hex_string(&signature2)); } fn verify_signature( @@ -127,12 +128,12 @@ fn verify_signature( println!( "{:>17}: {}", "Validation Hash", - hex::encode(validation_hash.to_byte_array()) + hex_string(validation_hash.as_byte_array()) ); println!( "{:>17}: {}", "Single Hash", - hex::encode(single_hash.to_byte_array()) + hex_string(single_hash.as_byte_array()) ); println!(); diff --git a/test-vectors/Cargo.toml b/test-vectors/Cargo.toml index 114da96..bde41d7 100644 --- a/test-vectors/Cargo.toml +++ b/test-vectors/Cargo.toml @@ -12,18 +12,18 @@ edition = "2021" [features] default = ["std"] -std = ["hex/std", "serde/std"] -bip32 = ["bs58", "hex/serde"] +std = ["faster-hex/std", "serde/std"] +bip32 = ["bs58", "faster-hex/serde"] firmware = [] -nostr = ["hex/serde"] -psbt = ["hex/serde"] -seedqr = ["bip39/serde", "hex/serde"] -blockchain-commons = ["bitcoin/serde", "hex/serde"] +nostr = ["faster-hex/serde"] +psbt = ["faster-hex/serde"] +seedqr = ["bip39/serde", "faster-hex/serde"] +blockchain-commons = ["bitcoin/serde", "faster-hex/serde"] [dependencies] bip39 = { workspace = true, optional = true } bitcoin = { workspace = true, optional = true, features = ["std"] } bs58 = { workspace = true, optional = true } -hex = { workspace = true, optional = true } +faster-hex = { workspace = true, optional = true } serde = { workspace = true } serde_json = { workspace = true } diff --git a/test-vectors/src/bip32.rs b/test-vectors/src/bip32.rs index 89418f4..8895331 100644 --- a/test-vectors/src/bip32.rs +++ b/test-vectors/src/bip32.rs @@ -18,7 +18,7 @@ impl TestVectors { #[serde(rename_all = "kebab-case")] pub struct TestVector { pub name: String, - #[serde(rename = "seed-hex", with = "hex")] + #[serde(rename = "seed-hex", with = "faster_hex::nopfx_ignorecase")] pub seed: Vec<u8>, pub chains: Vec<Chain>, } diff --git a/test-vectors/src/lib.rs b/test-vectors/src/lib.rs index 02534f2..8a0849d 100644 --- a/test-vectors/src/lib.rs +++ b/test-vectors/src/lib.rs @@ -6,8 +6,8 @@ pub struct NIP19Vector { pub name: String, pub kind: String, - #[serde(with = "hex")] - pub bytes: [u8; 32], + #[serde(with = "faster_hex::nopfx_ignorecase")] + pub bytes: Vec<u8>, pub encoded: String, } @@ -26,7 +26,7 @@ pub struct SeedQRVector { pub seed: bip39::Mnemonic, pub as_digits: String, pub as_compact_bits: String, - #[serde(with = "hex")] + #[serde(with = "faster_hex::nopfx_ignorecase")] pub as_compact_bytes: Vec<u8>, } @@ -51,7 +51,7 @@ mod blockchain_commons { #[derive(Debug, Clone, Deserialize)] pub enum UR { - #[serde(rename = "bytes", with = "hex")] + #[serde(rename = "bytes", with = "faster_hex::nopfx_ignorecase")] Bytes(Vec<u8>), #[serde(rename = "address")] Address(AddressVector), @@ -59,7 +59,7 @@ mod blockchain_commons { ECKey(ECKeyVector), #[serde(rename = "hdkey")] HDKey(HDKeyVector), - #[serde(rename = "psbt", with = "hex")] + #[serde(rename = "psbt", with = "faster_hex::nopfx_ignorecase")] Psbt(Vec<u8>), #[serde(rename = "seed")] Seed(SeedVector), @@ -92,7 +92,7 @@ mod blockchain_commons { #[serde(rename_all = "kebab-case")] pub enum AddressVector { Bitcoin(bitcoin::Address<bitcoin::address::NetworkUnchecked>), - #[serde(with = "prefix_hex")] + #[serde(with = "faster_hex::withpfx_ignorecase")] Ethereum(Vec<u8>), } @@ -100,7 +100,7 @@ mod blockchain_commons { #[serde(rename_all = "kebab-case")] pub struct ECKeyVector { pub is_private: bool, - #[serde(with = "hex")] + #[serde(with = "faster_hex::nopfx_ignorecase")] pub data: Vec<u8>, } @@ -119,7 +119,7 @@ mod blockchain_commons { #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "kebab-case")] pub struct SeedVector { - #[serde(with = "hex")] + #[serde(with = "faster_hex::nopfx_ignorecase")] pub payload: Vec<u8>, pub creation_date: u64, } @@ -128,7 +128,7 @@ mod blockchain_commons { #[serde(rename_all = "kebab-case")] pub struct URVector { pub name: String, - #[serde(with = "hex")] + #[serde(with = "faster_hex::nopfx_ignorecase")] pub as_cbor: Vec<u8>, pub as_ur: String, pub ur: UR, @@ -152,56 +152,6 @@ mod blockchain_commons { vectors } } - - mod prefix_hex { - use std::{fmt::Display, fmt::Formatter, marker::PhantomData}; - - use hex::FromHex; - use serde::{ - de::{Error, Visitor}, - Deserializer, - }; - - pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error> - where - D: Deserializer<'de>, - T: FromHex, - <T as FromHex>::Error: Display, - { - struct HexStrVisitor<T>(PhantomData<T>); - impl<'de, T> Visitor<'de> for HexStrVisitor<T> - where - T: FromHex, - <T as FromHex>::Error: Display, - { - type Value = T; - - fn expecting(&self, f: &mut Formatter) -> std::fmt::Result { - f.write_str("hex encoded string with 0x prefix") - } - - fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> - where - E: Error, - { - let v = v - .strip_prefix("0x") - .ok_or_else(|| Error::custom("invalid prefix"))?; - - FromHex::from_hex(v).map_err(Error::custom) - } - - fn visit_string<E>(self, v: String) -> Result<Self::Value, E> - where - E: Error, - { - self.visit_str(&v) - } - } - - deserializer.deserialize_str(HexStrVisitor(PhantomData)) - } - } } #[cfg(feature = "blockchain-commons")] diff --git a/test-vectors/src/psbt.rs b/test-vectors/src/psbt.rs index 8bc46dd..07baf9e 100644 --- a/test-vectors/src/psbt.rs +++ b/test-vectors/src/psbt.rs @@ -17,7 +17,7 @@ impl TestVectors { #[derive(Debug, serde::Deserialize)] pub struct TestVector { pub description: String, - #[serde(with = "hex", rename = "as-hex")] + #[serde(with = "faster_hex::nopfx_ignorecase", rename = "as-hex")] pub data: Vec<u8>, } diff --git a/ur/Cargo.toml b/ur/Cargo.toml index dd6aabd..b37a8df 100644 --- a/ur/Cargo.toml +++ b/ur/Cargo.toml @@ -33,4 +33,4 @@ phf = { workspace = true } rand_xoshiro = { workspace = true } [dev-dependencies] -hex = { workspace = true, features = ["alloc"] } +faster-hex = { workspace = true, features = ["alloc"] } diff --git a/ur/src/fountain/encoder.rs b/ur/src/fountain/encoder.rs index fc84372..5a54780 100644 --- a/ur/src/fountain/encoder.rs +++ b/ur/src/fountain/encoder.rs @@ -235,7 +235,7 @@ pub mod tests { ); for &expected_fragment in EXPECTED_FRAGMENTS.iter() { let part = encoder.next_part(); - assert_eq!(hex::encode(part.data), expected_fragment); + assert_eq!(faster_hex::hex_string(part.data), expected_fragment); } } @@ -270,7 +270,11 @@ pub mod tests { for (i, data) in EXPECTED_DATA .iter() - .map(|v| hex::decode(v).unwrap()) + .map(|v| { + let mut tmp = vec![0; v.len() / 2]; + faster_hex::hex_decode(v.as_bytes(), &mut tmp).unwrap(); + tmp + }) .enumerate() { let sequence = u32::try_from(i).unwrap(); @@ -334,7 +338,10 @@ pub mod tests { u32::try_from(SEQUENCE_COUNT).unwrap() ); - for expected_cbor in EXPECTED_PARTS_CBOR.iter().map(|v| hex::decode(v).unwrap()) { + for expected_cbor_hex in EXPECTED_PARTS_CBOR.iter() { + let mut expected_cbor = vec![0; expected_cbor_hex.len() / 2]; + faster_hex::hex_decode(expected_cbor_hex.as_bytes(), &mut expected_cbor).unwrap(); + let mut cbor = alloc::vec::Vec::new(); minicbor::encode(encoder.next_part(), &mut cbor).unwrap(); diff --git a/urtypes/Cargo.toml b/urtypes/Cargo.toml index ea9a222..2995c12 100644 --- a/urtypes/Cargo.toml +++ b/urtypes/Cargo.toml @@ -23,7 +23,7 @@ alloc = ["minicbor/alloc"] bitcoin = { workspace = true, optional = true } foundation-arena = { workspace = true } heapless = { workspace = true } -hex = { workspace = true } +faster-hex = { workspace = true } minicbor = { workspace = true } uuid = { workspace = true } diff --git a/urtypes/src/registry/passport.rs b/urtypes/src/registry/passport.rs index e865ac5..8ec10c6 100644 --- a/urtypes/src/registry/passport.rs +++ b/urtypes/src/registry/passport.rs @@ -268,6 +268,8 @@ impl<'a, C> Encode<C> for PassportResponse<'a> { #[cfg(test)] mod tests { + use faster_hex::hex_decode; + use super::*; #[test] @@ -275,12 +277,15 @@ mod tests { let mut id = [0; 32]; let mut signature = [0; 64]; - hex::decode_to_slice( - "2e99758548972a8e8822ad47fa1017ff72f06f3ff6a016851f45c398732bc50c", + hex_decode( + "2e99758548972a8e8822ad47fa1017ff72f06f3ff6a016851f45c398732bc50c".as_bytes(), &mut id, ) .unwrap(); - hex::decode_to_slice("7d0a8468ed220400c0b8e6f335baa7e070ce880a37e2ac5995b9a97b809026de626da636ac7365249bb974c719edf543b52ed286646f437dc7f810cc2068375c", &mut signature).unwrap(); + hex_decode( + "7d0a8468ed220400c0b8e6f335baa7e070ce880a37e2ac5995b9a97b809026de626da636ac7365249bb974c719edf543b52ed286646f437dc7f810cc2068375c".as_bytes(), + &mut signature, + ).unwrap(); let request = PassportRequest { transaction_id: Default::default(), @@ -300,12 +305,15 @@ mod tests { let mut id = [0; 32]; let mut signature = [0; 64]; - hex::decode_to_slice( - "2e99758548972a8e8822ad47fa1017ff72f06f3ff6a016851f45c398732bc50c", + hex_decode( + "2e99758548972a8e8822ad47fa1017ff72f06f3ff6a016851f45c398732bc50c".as_bytes(), &mut id, ) .unwrap(); - hex::decode_to_slice("7d0a8468ed220400c0b8e6f335baa7e070ce880a37e2ac5995b9a97b809026de626da636ac7365249bb974c719edf543b52ed286646f437dc7f810cc2068375c", &mut signature).unwrap(); + hex_decode( + "7d0a8468ed220400c0b8e6f335baa7e070ce880a37e2ac5995b9a97b809026de626da636ac7365249bb974c719edf543b52ed286646f437dc7f810cc2068375c".as_bytes(), + &mut signature, + ).unwrap(); let response = PassportResponse { transaction_id: Default::default(), @@ -328,7 +336,8 @@ mod tests { #[test] fn test_request_decode() { const TEST_VECTOR: &str = "a201d8255083816f6064ff4046b93a85687f8f608202d902c6a30178403338633663303561633639613166623737626366333736333330383835326364336530383066653165343630346361613831623534383236653264613062643202788037393035306564663562386636343937663936626661633031333363396365663561303764613363343835613432373466646666396433616637346632393833636566386432303337663164626636613435356431356530666236346162313665333664643336353062363533323265333239303138313639633631356636610378603045022079050ec39f5bc28f64c297c3b96bc3bac380133cc29cc3af5a07c39a3c485a4274c3bdc3bfc29d3ac3b74f29c283022100c38ec3b8c392037f1dc2bf6a455d15c3a0c3bb64c2ab16c3a36dc393650b65322e32c2901816c29c615f6a"; - let cbor = hex::decode(TEST_VECTOR).unwrap(); + let mut cbor = vec![0; TEST_VECTOR.len() / 2]; + hex_decode(TEST_VECTOR.as_bytes(), &mut cbor).unwrap(); minicbor::decode::<'_, PassportRequest>(&cbor).unwrap(); } } diff --git a/urtypes/src/supply_chain_validation.rs b/urtypes/src/supply_chain_validation.rs index 0d41ffb..6fa6dde 100644 --- a/urtypes/src/supply_chain_validation.rs +++ b/urtypes/src/supply_chain_validation.rs @@ -29,6 +29,7 @@ use core::str; +use faster_hex::{hex_decode, hex_encode}; use minicbor::data::{Tag, Type}; use minicbor::decode::Error; use minicbor::encode::Write; @@ -58,13 +59,13 @@ impl<'b, C> Decode<'b, C> for Challenge { match d.u32()? { 1 => { let mut buf = [0; 32]; - hex::decode_to_slice(d.str()?, &mut buf) + hex_decode(d.str()?.as_bytes(), &mut buf) .map_err(|_| Error::message("invalid hex string (id)"))?; id = Some(buf); } 2 => { let mut buf = [0; 64]; - hex::decode_to_slice(d.str()?, &mut buf) + hex_decode(d.str()?.as_bytes(), &mut buf) .map_err(|_| Error::message("invalid hex string (signature)"))?; signature = Some(buf); } @@ -101,10 +102,8 @@ impl<C> Encode<C> for Challenge { let mut signature = [0; 128]; // unreachable errors. - hex::encode_to_slice(self.id, &mut id).unwrap(); - hex::encode_to_slice(self.signature, &mut signature).unwrap(); - let id = str::from_utf8(&id).unwrap(); - let signature = str::from_utf8(&signature).unwrap(); + let id = hex_encode(&self.id, &mut id).unwrap(); + let signature = hex_encode(&self.signature, &mut signature).unwrap(); e.map(2)?; e.u8(1)?.str(id)?; diff --git a/urtypes/tests/hdkey.rs b/urtypes/tests/hdkey.rs index 298444d..b415551 100644 --- a/urtypes/tests/hdkey.rs +++ b/urtypes/tests/hdkey.rs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: © 2023 Foundation Devices, Inc. <hello@foundationdevices.com> // SPDX-License-Identifier: GPL-3.0-or-later +use faster_hex::hex_string; use foundation_test_vectors::{HDKeyVector, URVector, UR}; use foundation_urtypes::registry::{HDKeyRef, KeypathRef}; @@ -26,8 +27,8 @@ fn test_roundtrip_ref() { }; let cbor = minicbor::to_vec(&hdkey).unwrap(); - println!("our cbor: {}", hex::encode(&cbor)); - println!("test vector cbor: {}", hex::encode(&vector.as_cbor)); + println!("our cbor: {}", hex_string(&cbor)); + println!("test vector cbor: {}", hex_string(&vector.as_cbor)); assert_eq!(cbor, vector.as_cbor); } }