mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-12 22:19:26 +00:00
Remove non-small-order view key bound
Guaranteed addresses are in fact guaranteed even with this due to prefixing key images causing zeroing the ECDH to not zero the shared key.
This commit is contained in:
@@ -8,7 +8,7 @@ use std_shims::string::ToString;
|
||||
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use curve25519_dalek::{traits::IsIdentity, EdwardsPoint};
|
||||
use curve25519_dalek::EdwardsPoint;
|
||||
|
||||
use monero_io::*;
|
||||
|
||||
@@ -341,15 +341,6 @@ 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> {
|
||||
@@ -404,16 +395,8 @@ 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,
|
||||
) -> Result<Self, AddressCreationError> {
|
||||
if kind.is_guaranteed() && view.mul_by_cofactor().is_identity() {
|
||||
Err(AddressCreationError::SmallOrderView)?;
|
||||
}
|
||||
Ok(Address { network, kind, spend, view })
|
||||
pub fn new(network: Network, kind: AddressType, spend: EdwardsPoint, view: EdwardsPoint) -> Self {
|
||||
Address { network, kind, spend, view }
|
||||
}
|
||||
|
||||
/// Parse an address from a String, accepting any network it is.
|
||||
@@ -455,11 +438,6 @@ 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 })
|
||||
}
|
||||
|
||||
|
||||
@@ -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).unwrap();
|
||||
let addr = MoneroAddress::new(network, kind, spend, view);
|
||||
|
||||
assert_eq!(addr.to_string().chars().next().unwrap(), first);
|
||||
assert_eq!(MoneroAddress::from_str(network, &addr.to_string()).unwrap(), addr);
|
||||
@@ -198,7 +198,6 @@ fn featured_vectors() {
|
||||
spend,
|
||||
view
|
||||
)
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
vector.address
|
||||
);
|
||||
|
||||
@@ -231,7 +231,7 @@ impl InternalScanner {
|
||||
key: output_key,
|
||||
key_offset,
|
||||
commitment,
|
||||
additional_timelock: tx.prefix().timelock,
|
||||
additional_timelock: tx.prefix().additional_timelock,
|
||||
},
|
||||
metadata: Metadata { subaddress, payment_id, arbitrary_data: extra.data() },
|
||||
});
|
||||
|
||||
@@ -62,7 +62,7 @@ impl Eventuality {
|
||||
}
|
||||
|
||||
// Also ensure no timelock was set
|
||||
if tx.prefix().timelock != Timelock::None {
|
||||
if tx.prefix().additional_timelock != Timelock::None {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ impl SignableTransaction {
|
||||
// `- 1` to remove the one byte for the 0 fee
|
||||
Transaction::V2 {
|
||||
prefix: TransactionPrefix {
|
||||
timelock: Timelock::None,
|
||||
additional_timelock: Timelock::None,
|
||||
inputs: self.inputs(&key_images),
|
||||
outputs: self.outputs(&key_images),
|
||||
extra: self.extra(),
|
||||
@@ -239,7 +239,7 @@ impl SignableTransactionWithKeyImages {
|
||||
|
||||
Transaction::V2 {
|
||||
prefix: TransactionPrefix {
|
||||
timelock: Timelock::None,
|
||||
additional_timelock: Timelock::None,
|
||||
inputs: self.intent.inputs(&self.key_images),
|
||||
outputs: self.intent.outputs(&self.key_images),
|
||||
extra: self.intent.extra(),
|
||||
|
||||
@@ -6,7 +6,7 @@ use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, Scalar, EdwardsPoint}
|
||||
|
||||
use crate::{
|
||||
primitives::keccak256_to_scalar,
|
||||
address::{Network, AddressType, SubaddressIndex, AddressCreationError, MoneroAddress},
|
||||
address::{Network, AddressType, SubaddressIndex, MoneroAddress},
|
||||
};
|
||||
|
||||
/// The pair of keys necessary to scan transactions.
|
||||
@@ -57,40 +57,20 @@ impl ViewPair {
|
||||
///
|
||||
/// Subaddresses SHOULD be used instead.
|
||||
pub fn legacy_address(&self, network: Network) -> MoneroAddress {
|
||||
match MoneroAddress::new(network, AddressType::Legacy, self.spend, self.view()) {
|
||||
Ok(addr) => addr,
|
||||
Err(AddressCreationError::SmallOrderView) => {
|
||||
panic!("small-order view key error despite not making a guaranteed address")
|
||||
}
|
||||
}
|
||||
MoneroAddress::new(network, AddressType::Legacy, self.spend, self.view())
|
||||
}
|
||||
|
||||
/// Derive a legacy integrated address from this ViewPair.
|
||||
///
|
||||
/// Subaddresses SHOULD be used instead.
|
||||
pub fn legacy_integrated_address(&self, network: Network, payment_id: [u8; 8]) -> MoneroAddress {
|
||||
match MoneroAddress::new(
|
||||
network,
|
||||
AddressType::LegacyIntegrated(payment_id),
|
||||
self.spend,
|
||||
self.view(),
|
||||
) {
|
||||
Ok(addr) => addr,
|
||||
Err(AddressCreationError::SmallOrderView) => {
|
||||
panic!("small-order view key error despite not making a guaranteed address")
|
||||
}
|
||||
}
|
||||
MoneroAddress::new(network, AddressType::LegacyIntegrated(payment_id), self.spend, self.view())
|
||||
}
|
||||
|
||||
/// Derive a subaddress from this ViewPair.
|
||||
pub fn subaddress(&self, network: Network, subaddress: SubaddressIndex) -> MoneroAddress {
|
||||
let (spend, view) = self.subaddress_keys(subaddress);
|
||||
match MoneroAddress::new(network, AddressType::Subaddress, spend, view) {
|
||||
Ok(addr) => addr,
|
||||
Err(AddressCreationError::SmallOrderView) => {
|
||||
panic!("small-order view key error despite not making a guaranteed address")
|
||||
}
|
||||
}
|
||||
MoneroAddress::new(network, AddressType::Subaddress, spend, view)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,14 +86,8 @@ pub struct GuaranteedViewPair(pub(crate) ViewPair);
|
||||
|
||||
impl GuaranteedViewPair {
|
||||
/// Create a new GuaranteedViewPair.
|
||||
///
|
||||
/// This will return None if the view key is of small order (if it's zero).
|
||||
// Internal doc comment: These scalars are of prime order so 0 is the only small order Scalar
|
||||
pub fn new(spend: EdwardsPoint, view: Zeroizing<Scalar>) -> Option<Self> {
|
||||
if view.deref() == &Scalar::ZERO {
|
||||
None?;
|
||||
}
|
||||
Some(GuaranteedViewPair(ViewPair::new(spend, view)))
|
||||
pub fn new(spend: EdwardsPoint, view: Zeroizing<Scalar>) -> Self {
|
||||
GuaranteedViewPair(ViewPair::new(spend, view))
|
||||
}
|
||||
|
||||
/// The public spend key for this GuaranteedViewPair.
|
||||
@@ -142,16 +116,11 @@ impl GuaranteedViewPair {
|
||||
(self.spend(), self.view())
|
||||
};
|
||||
|
||||
match MoneroAddress::new(
|
||||
MoneroAddress::new(
|
||||
network,
|
||||
AddressType::Featured { subaddress: subaddress.is_some(), payment_id, guaranteed: true },
|
||||
spend,
|
||||
view,
|
||||
) {
|
||||
Ok(addr) => addr,
|
||||
Err(AddressCreationError::SmallOrderView) => {
|
||||
panic!("created a ViewPair with identity as the view key")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,7 @@ test!(
|
||||
AddressType::Legacy,
|
||||
ED25519_BASEPOINT_POINT,
|
||||
ED25519_BASEPOINT_POINT,
|
||||
)
|
||||
.unwrap(),
|
||||
),
|
||||
1,
|
||||
);
|
||||
builder.add_payment(
|
||||
@@ -31,8 +30,7 @@ test!(
|
||||
AddressType::LegacyIntegrated([0xaa; 8]),
|
||||
ED25519_BASEPOINT_POINT,
|
||||
ED25519_BASEPOINT_POINT,
|
||||
)
|
||||
.unwrap(),
|
||||
),
|
||||
2,
|
||||
);
|
||||
builder.add_payment(
|
||||
@@ -41,8 +39,7 @@ test!(
|
||||
AddressType::Subaddress,
|
||||
ED25519_BASEPOINT_POINT,
|
||||
ED25519_BASEPOINT_POINT,
|
||||
)
|
||||
.unwrap(),
|
||||
),
|
||||
3,
|
||||
);
|
||||
builder.add_payment(
|
||||
@@ -51,8 +48,7 @@ test!(
|
||||
AddressType::Featured { subaddress: false, payment_id: None, guaranteed: true },
|
||||
ED25519_BASEPOINT_POINT,
|
||||
ED25519_BASEPOINT_POINT,
|
||||
)
|
||||
.unwrap(),
|
||||
),
|
||||
4,
|
||||
);
|
||||
let tx = builder.build().unwrap();
|
||||
|
||||
@@ -41,8 +41,7 @@ pub fn random_address() -> (Scalar, ViewPair, MoneroAddress) {
|
||||
AddressType::Legacy,
|
||||
spend_pub,
|
||||
view.deref() * ED25519_BASEPOINT_TABLE,
|
||||
)
|
||||
.unwrap(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -53,14 +52,13 @@ pub fn random_guaranteed_address() -> (Scalar, GuaranteedViewPair, MoneroAddress
|
||||
let view = Zeroizing::new(Scalar::random(&mut OsRng));
|
||||
(
|
||||
spend,
|
||||
GuaranteedViewPair::new(spend_pub, view.clone()).unwrap(),
|
||||
GuaranteedViewPair::new(spend_pub, view.clone()),
|
||||
MoneroAddress::new(
|
||||
Network::Mainnet,
|
||||
AddressType::Legacy,
|
||||
spend_pub,
|
||||
view.deref() * ED25519_BASEPOINT_TABLE,
|
||||
)
|
||||
.unwrap(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -141,7 +139,6 @@ pub async fn rpc() -> SimpleRequestRpc {
|
||||
&Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE,
|
||||
&Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE,
|
||||
)
|
||||
.unwrap()
|
||||
.to_string();
|
||||
|
||||
// Mine 40 blocks to ensure decoy availability
|
||||
|
||||
Reference in New Issue
Block a user