Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use half-aggregation for tm messages #346

Merged
merged 13 commits into from
Aug 21, 2023
676 changes: 316 additions & 360 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 1 addition & 3 deletions coins/monero/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ crc = { version = "3", default-features = false }
sha3 = { version = "0.10", default-features = false }
pbkdf2 = { version = "0.12", features = ["simple"], default-features = false }

curve25519-dalek = { version = "^3.2", default-features = false }
curve25519-dalek = { version = "4", default-features = false, features = ["alloc", "zeroize", "precomputed-tables"] }

# Used for the hash to curve, along with the more complicated proofs
group = { version = "0.13", default-features = false }
Expand Down Expand Up @@ -86,8 +86,6 @@ std = [

"sha3/std",

"curve25519-dalek/std",

"multiexp/std",

"monero-generators/std",
Expand Down
2 changes: 1 addition & 1 deletion coins/monero/generators/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ subtle = { version = "^2.4", default-features = false }

sha3 = { version = "0.10", default-features = false }

curve25519-dalek = { version = "3", default-features = false }
curve25519-dalek = { version = "4", default-features = false, features = ["alloc", "zeroize", "precomputed-tables"] }

group = { version = "0.13", default-features = false }
dalek-ff-group = { path = "../../../crypto/dalek-ff-group", version = "0.3" }
Expand Down
6 changes: 3 additions & 3 deletions coins/monero/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ impl core::fmt::Debug for Commitment {
impl Commitment {
/// A commitment to zero, defined with a mask of 1 (as to not be the identity).
pub fn zero() -> Commitment {
Commitment { mask: Scalar::one(), amount: 0 }
Commitment { mask: Scalar::ONE, amount: 0 }
}

pub fn new(mask: Scalar, amount: u64) -> Commitment {
Expand All @@ -194,7 +194,7 @@ impl Commitment {

/// Calculate a Pedersen commitment, as a point, from the transparent structure.
pub fn calculate(&self) -> EdwardsPoint {
(&self.mask * &ED25519_BASEPOINT_TABLE) + (Scalar::from(self.amount) * H())
(&self.mask * ED25519_BASEPOINT_TABLE) + (Scalar::from(self.amount) * H())
}
}

Expand All @@ -216,6 +216,6 @@ pub fn hash_to_scalar(data: &[u8]) -> Scalar {
// This library acknowledges its practical impossibility of it occurring, and doesn't bother to
// code in logic to handle it. That said, if it ever occurs, something must happen in order to
// not generate/verify a proof we believe to be valid when it isn't
assert!(scalar != Scalar::zero(), "ZERO HASH: {data:?}");
assert!(scalar != Scalar::ZERO, "ZERO HASH: {data:?}");
scalar
}
8 changes: 4 additions & 4 deletions coins/monero/src/ringct/clsag/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ fn core(
}

// Perform the core loop
let mut c1 = CtOption::new(Scalar::zero(), Choice::from(0));
let mut c1 = CtOption::new(Scalar::ZERO, Choice::from(0));
for i in (start .. end).map(|i| i % n) {
// This will only execute once and shouldn't need to be constant time. Making it constant time
// removes the risk of branch prediction creating timing differences depending on ring index
Expand All @@ -179,7 +179,7 @@ fn core(
let c_p = mu_P * c;
let c_c = mu_C * c;

let L = (&s[i] * &ED25519_BASEPOINT_TABLE) + (c_p * P[i]) + (c_c * C[i]);
let L = (&s[i] * ED25519_BASEPOINT_TABLE) + (c_p * P[i]) + (c_c * C[i]);
let PH = hash_to_point(P[i]);
// Shouldn't be an issue as all of the variables in this vartime statement are public
let R = (s[i] * PH) + images_precomp.vartime_multiscalar_mul([c_p, c_c]);
Expand Down Expand Up @@ -241,7 +241,7 @@ impl Clsag {
msg: [u8; 32],
) -> Vec<(Clsag, EdwardsPoint)> {
let mut res = Vec::with_capacity(inputs.len());
let mut sum_pseudo_outs = Scalar::zero();
let mut sum_pseudo_outs = Scalar::ZERO;
for i in 0 .. inputs.len() {
let mut mask = random_scalar(rng);
if i == (inputs.len() - 1) {
Expand All @@ -257,7 +257,7 @@ impl Clsag {
&inputs[i].2,
mask,
&msg,
nonce.deref() * &ED25519_BASEPOINT_TABLE,
nonce.deref() * ED25519_BASEPOINT_TABLE,
nonce.deref() *
hash_to_point(inputs[i].2.decoys.ring[usize::from(inputs[i].2.decoys.i)][0]),
);
Expand Down
2 changes: 1 addition & 1 deletion coins/monero/src/ringct/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use crate::{

/// Generate a key image for a given key. Defined as `x * hash_to_point(xG)`.
pub fn generate_key_image(secret: &Zeroizing<Scalar>) -> EdwardsPoint {
hash_to_point(&ED25519_BASEPOINT_TABLE * secret.deref()) * secret.deref()
hash_to_point(ED25519_BASEPOINT_TABLE * secret.deref()) * secret.deref()
}

#[derive(Clone, PartialEq, Eq, Debug)]
Expand Down
2 changes: 1 addition & 1 deletion coins/monero/src/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ pub(crate) fn read_varint<R: Read>(r: &mut R) -> io::Result<u64> {
// https://github.com/monero-project/monero/issues/8438, where some scalars had an archaic
// reduction applied
pub(crate) fn read_scalar<R: Read>(r: &mut R) -> io::Result<Scalar> {
Scalar::from_canonical_bytes(read_bytes(r)?)
Option::from(Scalar::from_canonical_bytes(read_bytes(r)?))
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "unreduced scalar"))
}

Expand Down
16 changes: 10 additions & 6 deletions coins/monero/src/tests/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ fn featured() {
[(Network::Mainnet, 'C'), (Network::Testnet, 'K'), (Network::Stagenet, 'F')]
{
for _ in 0 .. 100 {
let spend = &random_scalar(&mut OsRng) * &ED25519_BASEPOINT_TABLE;
let view = &random_scalar(&mut OsRng) * &ED25519_BASEPOINT_TABLE;
let spend = &random_scalar(&mut OsRng) * ED25519_BASEPOINT_TABLE;
let view = &random_scalar(&mut OsRng) * ED25519_BASEPOINT_TABLE;

for features in 0 .. (1 << 3) {
const SUBADDRESS_FEATURE_BIT: u8 = 1;
Expand Down Expand Up @@ -142,10 +142,14 @@ fn featured_vectors() {
}
_ => panic!("Unknown network"),
};
let spend =
CompressedEdwardsY::from_slice(&hex::decode(vector.spend).unwrap()).decompress().unwrap();
let view =
CompressedEdwardsY::from_slice(&hex::decode(vector.view).unwrap()).decompress().unwrap();
let spend = CompressedEdwardsY::from_slice(&hex::decode(vector.spend).unwrap())
.unwrap()
.decompress()
.unwrap();
let view = CompressedEdwardsY::from_slice(&hex::decode(vector.view).unwrap())
.unwrap()
.decompress()
.unwrap();

let addr = MoneroAddress::from_str(network, &vector.address).unwrap();
assert_eq!(addr.spend, spend);
Expand Down
2 changes: 1 addition & 1 deletion coins/monero/src/tests/bulletproofs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ macro_rules! bulletproofs_tests {
// Check Bulletproofs errors if we try to prove for too many outputs
let mut commitments = vec![];
for _ in 0 .. 17 {
commitments.push(Commitment::new(Scalar::zero(), 0));
commitments.push(Commitment::new(Scalar::ZERO, 0));
}
assert!(Bulletproofs::prove(&mut OsRng, &commitments, $plus).is_err());
}
Expand Down
6 changes: 3 additions & 3 deletions coins/monero/src/tests/clsag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fn clsag() {
for real in 0 .. RING_LEN {
let msg = [1; 32];

let mut secrets = (Zeroizing::new(Scalar::zero()), Scalar::zero());
let mut secrets = (Zeroizing::new(Scalar::ZERO), Scalar::ZERO);
let mut ring = vec![];
for i in 0 .. RING_LEN {
let dest = Zeroizing::new(random_scalar(&mut OsRng));
Expand All @@ -53,7 +53,7 @@ fn clsag() {
amount = OsRng.next_u64();
}
ring
.push([dest.deref() * &ED25519_BASEPOINT_TABLE, Commitment::new(mask, amount).calculate()]);
.push([dest.deref() * ED25519_BASEPOINT_TABLE, Commitment::new(mask, amount).calculate()]);
}

let image = generate_key_image(&secrets.0);
Expand Down Expand Up @@ -92,7 +92,7 @@ fn clsag_multisig() {
let mask;
let amount;
if i != u64::from(RING_INDEX) {
dest = &random_scalar(&mut OsRng) * &ED25519_BASEPOINT_TABLE;
dest = &random_scalar(&mut OsRng) * ED25519_BASEPOINT_TABLE;
mask = random_scalar(&mut OsRng);
amount = OsRng.next_u64();
} else {
Expand Down
4 changes: 2 additions & 2 deletions coins/monero/src/tests/seed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ fn test_classic_seed() {
let spend: [u8; 32] = hex::decode(vector.spend).unwrap().try_into().unwrap();
// For classical seeds, Monero directly uses the entropy as a spend key
assert_eq!(
Scalar::from_canonical_bytes(*seed.entropy()),
Scalar::from_canonical_bytes(spend)
Option::<Scalar>::from(Scalar::from_canonical_bytes(*seed.entropy())),
Option::<Scalar>::from(Scalar::from_canonical_bytes(spend)),
);

let view: [u8; 32] = hex::decode(vector.view).unwrap().try_into().unwrap();
Expand Down
6 changes: 3 additions & 3 deletions coins/monero/src/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ impl ViewPair {
}

pub fn view(&self) -> EdwardsPoint {
self.view.deref() * &ED25519_BASEPOINT_TABLE
self.view.deref() * ED25519_BASEPOINT_TABLE
}

fn subaddress_derivation(&self, index: SubaddressIndex) -> Scalar {
Expand All @@ -167,15 +167,15 @@ impl ViewPair {

fn subaddress_keys(&self, index: SubaddressIndex) -> (EdwardsPoint, EdwardsPoint) {
let scalar = self.subaddress_derivation(index);
let spend = self.spend + (&scalar * &ED25519_BASEPOINT_TABLE);
let spend = self.spend + (&scalar * ED25519_BASEPOINT_TABLE);
let view = self.view.deref() * spend;
(spend, view)
}

/// Returns an address with the provided specification.
pub fn address(&self, network: Network, spec: AddressSpec) -> MoneroAddress {
let mut spend = self.spend;
let mut view: EdwardsPoint = self.view.deref() * &ED25519_BASEPOINT_TABLE;
let mut view: EdwardsPoint = self.view.deref() * ED25519_BASEPOINT_TABLE;

// construct the address meta
let meta = match spec {
Expand Down
5 changes: 2 additions & 3 deletions coins/monero/src/wallet/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,9 +385,8 @@ impl Scanner {
}

// P - shared == spend
let subaddress = self
.subaddresses
.get(&(output_key - (&shared_key * &ED25519_BASEPOINT_TABLE)).compress());
let subaddress =
self.subaddresses.get(&(output_key - (&shared_key * ED25519_BASEPOINT_TABLE)).compress());
if subaddress.is_none() {
continue;
}
Expand Down
8 changes: 5 additions & 3 deletions coins/monero/src/wallet/seed/classic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,18 +261,20 @@ impl ClassicSeed {
let (lang, entropy) = seed_to_bytes(&words)?;

// Make sure this is a valid scalar
let mut scalar = Scalar::from_canonical_bytes(*entropy);
if scalar.is_none() {
let scalar = Scalar::from_canonical_bytes(*entropy);
if scalar.is_none().into() {
Err(SeedError::InvalidSeed)?;
}
let mut scalar = scalar.unwrap();
scalar.zeroize();

// Call from_entropy so a trimmed seed becomes a full seed
Ok(Self::from_entropy(lang, entropy).unwrap())
}

pub fn from_entropy(lang: Language, entropy: Zeroizing<[u8; 32]>) -> Option<ClassicSeed> {
Scalar::from_canonical_bytes(*entropy).map(|scalar| key_to_seed(lang, Zeroizing::new(scalar)))
Option::from(Scalar::from_canonical_bytes(*entropy))
.map(|scalar| key_to_seed(lang, Zeroizing::new(scalar)))
}

pub(crate) fn to_string(&self) -> Zeroizing<String> {
Expand Down
10 changes: 5 additions & 5 deletions coins/monero/src/wallet/send/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ impl SendOutput {
SendOutput {
R,
view_tag,
dest: ((&shared_key * &ED25519_BASEPOINT_TABLE) + output.0.spend),
dest: ((&shared_key * ED25519_BASEPOINT_TABLE) + output.0.spend),
commitment: Commitment::new(commitment_mask(shared_key), output.1),
amount: amount_encryption(output.1, shared_key),
},
Expand All @@ -105,7 +105,7 @@ impl SendOutput {
output,
r.deref() * address.view,
if !address.is_subaddress() {
r.deref() * &ED25519_BASEPOINT_TABLE
r.deref() * ED25519_BASEPOINT_TABLE
} else {
r.deref() * address.spend
},
Expand Down Expand Up @@ -580,7 +580,7 @@ impl SignableTransaction {

// Used for all non-subaddress outputs, or if there's only one subaddress output and a change
let tx_key = Zeroizing::new(random_scalar(&mut rng));
let mut tx_public_key = tx_key.deref() * &ED25519_BASEPOINT_TABLE;
let mut tx_public_key = tx_key.deref() * ED25519_BASEPOINT_TABLE;

// If any of these outputs are to a subaddress, we need keys distinct to them
// The only time this *does not* force having additional keys is when the only other output
Expand All @@ -600,7 +600,7 @@ impl SignableTransaction {
InternalPayment::Change(_, _) => {}
}
}
debug_assert!(tx_public_key != (tx_key.deref() * &ED25519_BASEPOINT_TABLE));
debug_assert!(tx_public_key != (tx_key.deref() * ED25519_BASEPOINT_TABLE));
}

// Actually create the outputs
Expand Down Expand Up @@ -814,7 +814,7 @@ impl SignableTransaction {
let mut images = Vec::with_capacity(self.inputs.len());
for (input, _) in &self.inputs {
let mut offset = Zeroizing::new(spend.deref() + input.key_offset());
if (offset.deref() * &ED25519_BASEPOINT_TABLE) != input.key() {
if (offset.deref() * ED25519_BASEPOINT_TABLE) != input.key() {
Err(TransactionError::WrongPrivateKey)?;
}

Expand Down
2 changes: 1 addition & 1 deletion coins/monero/src/wallet/send/multisig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ impl SignMachine<Transaction> for TransactionSignMachine {
sorted.sort_by(|x, y| key_image_sort(&x.0, &y.0));

let mut rng = ChaCha20Rng::from_seed(self.transcript.rng_seed(b"pseudo_out_masks"));
let mut sum_pseudo_outs = Scalar::zero();
let mut sum_pseudo_outs = Scalar::ZERO;
while !sorted.is_empty() {
let value = sorted.remove(0);

Expand Down
12 changes: 6 additions & 6 deletions coins/monero/tests/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ use monero_serai::{

pub fn random_address() -> (Scalar, ViewPair, MoneroAddress) {
let spend = random_scalar(&mut OsRng);
let spend_pub = &spend * &ED25519_BASEPOINT_TABLE;
let spend_pub = &spend * ED25519_BASEPOINT_TABLE;
let view = Zeroizing::new(random_scalar(&mut OsRng));
(
spend,
ViewPair::new(spend_pub, view.clone()),
MoneroAddress {
meta: AddressMeta::new(Network::Mainnet, AddressType::Standard),
spend: spend_pub,
view: view.deref() * &ED25519_BASEPOINT_TABLE,
view: view.deref() * ED25519_BASEPOINT_TABLE,
},
)
}
Expand Down Expand Up @@ -95,8 +95,8 @@ pub async fn rpc() -> Rpc<HttpRpc> {

let addr = MoneroAddress {
meta: AddressMeta::new(Network::Mainnet, AddressType::Standard),
spend: &random_scalar(&mut OsRng) * &ED25519_BASEPOINT_TABLE,
view: &random_scalar(&mut OsRng) * &ED25519_BASEPOINT_TABLE,
spend: &random_scalar(&mut OsRng) * ED25519_BASEPOINT_TABLE,
view: &random_scalar(&mut OsRng) * ED25519_BASEPOINT_TABLE,
}
.to_string();

Expand Down Expand Up @@ -193,7 +193,7 @@ macro_rules! test {
let keys = key_gen::<_, Ed25519>(&mut OsRng);

let spend_pub = if !multisig {
spend.deref() * &ED25519_BASEPOINT_TABLE
spend.deref() * ED25519_BASEPOINT_TABLE
} else {
#[cfg(not(feature = "multisig"))]
panic!("Multisig branch called without the multisig feature");
Expand All @@ -215,7 +215,7 @@ macro_rules! test {
rpc.get_fee(protocol, FeePriority::Low).await.unwrap(),
Some(Change::new(
&ViewPair::new(
&random_scalar(&mut OsRng) * &ED25519_BASEPOINT_TABLE,
&random_scalar(&mut OsRng) * ED25519_BASEPOINT_TABLE,
Zeroizing::new(random_scalar(&mut OsRng))
),
false
Expand Down
4 changes: 2 additions & 2 deletions coins/monero/tests/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ test!(
use monero_serai::wallet::FeePriority;

let change_view = ViewPair::new(
&random_scalar(&mut OsRng) * &ED25519_BASEPOINT_TABLE,
&random_scalar(&mut OsRng) * ED25519_BASEPOINT_TABLE,
Zeroizing::new(random_scalar(&mut OsRng)),
);

Expand All @@ -117,7 +117,7 @@ test!(

// Send to a subaddress
let sub_view = ViewPair::new(
&random_scalar(&mut OsRng) * &ED25519_BASEPOINT_TABLE,
&random_scalar(&mut OsRng) * ED25519_BASEPOINT_TABLE,
Zeroizing::new(random_scalar(&mut OsRng)),
);
builder.add_payment(
Expand Down
Loading