Diversify ViewPair/Scanner into ViewPair/GuaranteedViewPair and Scanner/GuaranteedScanner

Also cleans the Scanner impl.
This commit is contained in:
Luke Parker
2024-07-03 13:35:19 -04:00
parent 64e74c52ec
commit daa0f8f7d5
32 changed files with 1458 additions and 1233 deletions

View File

@@ -8,7 +8,7 @@ use std_shims::string::ToString;
use zeroize::Zeroize;
use curve25519_dalek::edwards::EdwardsPoint;
use curve25519_dalek::{traits::IsIdentity, EdwardsPoint};
use monero_io::*;
@@ -112,43 +112,6 @@ impl SubaddressIndex {
}
}
/// A specification for an address to be derived.
///
/// This contains all the information an address will embed once derived.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
pub enum AddressSpec {
/// A legacy address type.
Legacy,
/// A legacy address with a payment ID embedded.
LegacyIntegrated([u8; 8]),
/// A subaddress.
///
/// This is what SHOULD be used if specific functionality isn't needed.
Subaddress(SubaddressIndex),
/// A featured address.
///
/// Featured Addresses are an unofficial address specification which is meant to be extensible
/// and support a variety of functionality. This functionality includes being a subaddresses AND
/// having a payment ID, along with being immune to the burning bug.
///
/// At this time, support for featured addresses is limited to this crate. There should be no
/// expectation of interoperability.
Featured {
/// The subaddress index to derive this address with.
///
/// If None, no subaddress derivation occurs.
subaddress: Option<SubaddressIndex>,
/// The payment ID to embed in this address.
payment_id: Option<[u8; 8]>,
/// If this address should be guaranteed.
///
/// A guaranteed address is one where any outputs scanned to it are guaranteed to be spendable
/// under the hardness of various cryptographic problems (which are assumed hard). This is via
/// a modified shared-key derivation which eliminates the burning bug.
guaranteed: bool,
},
}
/// Bytes used as prefixes when encoding addresses.
///
/// These distinguish the address's type.
@@ -227,7 +190,7 @@ pub enum Network {
Testnet,
}
/// Error when decoding an address.
/// Errors when decoding an address.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "std", derive(thiserror::Error))]
pub enum AddressError {
@@ -257,6 +220,9 @@ pub enum AddressError {
/// The Network embedded within the Address.
actual: Network,
},
/// The view key was of small order despite being in a guaranteed address.
#[cfg_attr(feature = "std", error("small-order view key in guaranteed address"))]
SmallOrderView,
}
/// Bytes used as prefixes when encoding addresses, variable to the network instance.
@@ -375,6 +341,15 @@ pub const MONERO_BYTES: NetworkedAddressBytes = match NetworkedAddressBytes::new
None => panic!("Monero network byte constants conflicted"),
};
/// Errors when creating an address.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "std", derive(thiserror::Error))]
pub enum AddressCreationError {
/// The view key was of small order despite being in a guaranteed address.
#[cfg_attr(feature = "std", error("small-order view key in guaranteed address"))]
SmallOrderView,
}
/// A Monero address.
#[derive(Clone, Copy, PartialEq, Eq, Zeroize)]
pub struct Address<const ADDRESS_BYTES: u128> {
@@ -429,8 +404,16 @@ impl<const ADDRESS_BYTES: u128> fmt::Display for Address<ADDRESS_BYTES> {
impl<const ADDRESS_BYTES: u128> Address<ADDRESS_BYTES> {
/// Create a new address.
pub fn new(network: Network, kind: AddressType, spend: EdwardsPoint, view: EdwardsPoint) -> Self {
Address { network, kind, spend, view }
pub fn new(
network: Network,
kind: AddressType,
spend: EdwardsPoint,
view: EdwardsPoint,
) -> Result<Self, AddressCreationError> {
if kind.is_guaranteed() && view.mul_by_cofactor().is_identity() {
Err(AddressCreationError::SmallOrderView)?;
}
Ok(Address { network, kind, spend, view })
}
/// Parse an address from a String, accepting any network it is.
@@ -472,6 +455,11 @@ impl<const ADDRESS_BYTES: u128> Address<ADDRESS_BYTES> {
Err(AddressError::InvalidLength)?;
}
// If this is a guaranteed address, reject small-order view keys
if kind.is_guaranteed() && view.mul_by_cofactor().is_identity() {
Err(AddressError::SmallOrderView)?;
}
Ok(Address { network, kind, spend, view })
}

View File

@@ -125,7 +125,7 @@ fn featured() {
let guaranteed = (features & GUARANTEED_FEATURE_BIT) == GUARANTEED_FEATURE_BIT;
let kind = AddressType::Featured { subaddress, payment_id, guaranteed };
let addr = MoneroAddress::new(network, kind, spend, view);
let addr = MoneroAddress::new(network, kind, spend, view).unwrap();
assert_eq!(addr.to_string().chars().next().unwrap(), first);
assert_eq!(MoneroAddress::from_str(network, &addr.to_string()).unwrap(), addr);
@@ -198,6 +198,7 @@ fn featured_vectors() {
spend,
view
)
.unwrap()
.to_string(),
vector.address
);