Merge branch 'dalek-4.0' into develop

This commit is contained in:
Luke Parker 2023-08-17 02:00:36 -04:00
commit 34c6974311
No known key found for this signature in database
22 changed files with 65 additions and 102 deletions

50
Cargo.lock generated
View file

@ -1419,19 +1419,6 @@ dependencies = [
"syn 2.0.29",
]
[[package]]
name = "curve25519-dalek-ng"
version = "4.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8"
dependencies = [
"byteorder",
"digest 0.9.0",
"rand_core 0.6.4",
"subtle-ng",
"zeroize",
]
[[package]]
name = "cxx"
version = "1.0.105"
@ -1481,14 +1468,14 @@ name = "dalek-ff-group"
version = "0.3.0"
dependencies = [
"crypto-bigint",
"curve25519-dalek 3.2.0",
"curve25519-dalek 4.0.0",
"digest 0.10.7",
"ff",
"ff-group-tests",
"group",
"rand_core 0.6.4",
"rustversion",
"sha2 0.9.9",
"sha2 0.10.7",
"subtle",
"zeroize",
]
@ -2844,7 +2831,7 @@ dependencies = [
"modular-frost",
"rand_core 0.6.4",
"schnorr-signatures",
"schnorrkel 0.10.2",
"schnorrkel",
"zeroize",
]
@ -4707,7 +4694,7 @@ dependencies = [
name = "monero-generators"
version = "0.3.0"
dependencies = [
"curve25519-dalek 3.2.0",
"curve25519-dalek 4.0.0",
"dalek-ff-group",
"group",
"sha3",
@ -4722,7 +4709,7 @@ dependencies = [
"async-trait",
"base58-monero",
"crc",
"curve25519-dalek 3.2.0",
"curve25519-dalek 4.0.0",
"dalek-ff-group",
"digest_auth",
"dleq",
@ -7815,23 +7802,6 @@ dependencies = [
"zeroize",
]
[[package]]
name = "schnorrkel"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "844b7645371e6ecdf61ff246ba1958c29e802881a749ae3fb1993675d210d28d"
dependencies = [
"arrayref",
"arrayvec",
"curve25519-dalek-ng",
"merlin",
"rand_core 0.6.4",
"serde_bytes",
"sha2 0.9.9",
"subtle-ng",
"zeroize",
]
[[package]]
name = "schnorrkel"
version = "0.11.0"
@ -8899,7 +8869,7 @@ dependencies = [
"rand 0.8.5",
"regex",
"scale-info",
"schnorrkel 0.11.0",
"schnorrkel",
"secrecy",
"serde",
"sp-core-hashing",
@ -9495,7 +9465,7 @@ source = "git+https://github.com/serai-dex/substrate-bip39#4596f602481e08f629660
dependencies = [
"hmac",
"pbkdf2 0.12.2",
"schnorrkel 0.11.0",
"schnorrkel",
"sha2 0.10.7",
"zeroize",
]
@ -9560,12 +9530,6 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "subtle-ng"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142"
[[package]]
name = "subxt"
version = "0.29.0"

View file

@ -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 }
@ -86,8 +86,6 @@ std = [
"sha3/std",
"curve25519-dalek/std",
"multiexp/std",
"monero-generators/std",

View file

@ -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" }

View file

@ -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 {
@ -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())
}
}
@ -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
}

View file

@ -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
@ -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]);
@ -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) {
@ -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]),
);

View file

@ -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)]

View file

@ -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"))
}

View file

@ -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;
@ -143,9 +143,9 @@ fn featured_vectors() {
_ => panic!("Unknown network"),
};
let spend =
CompressedEdwardsY::from_slice(&hex::decode(vector.spend).unwrap()).decompress().unwrap();
CompressedEdwardsY::from_slice(&hex::decode(vector.spend).unwrap()).unwrap().decompress().unwrap();
let view =
CompressedEdwardsY::from_slice(&hex::decode(vector.view).unwrap()).decompress().unwrap();
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);

View file

@ -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());
}

View file

@ -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));
@ -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);
@ -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 {

View file

@ -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();

View file

@ -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 {
@ -167,7 +167,7 @@ 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)
}
@ -175,7 +175,7 @@ impl ViewPair {
/// 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 {

View file

@ -387,7 +387,7 @@ impl Scanner {
// P - shared == spend
let subaddress = self
.subaddresses
.get(&(output_key - (&shared_key * &ED25519_BASEPOINT_TABLE)).compress());
.get(&(output_key - (&shared_key * ED25519_BASEPOINT_TABLE)).compress());
if subaddress.is_none() {
continue;
}

View file

@ -261,10 +261,11 @@ 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
@ -272,7 +273,7 @@ impl ClassicSeed {
}
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> {

View file

@ -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),
},
@ -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
},
@ -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
@ -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
@ -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)?;
}

View file

@ -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);

View file

@ -21,7 +21,7 @@ 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,
@ -29,7 +29,7 @@ pub fn random_address() -> (Scalar, ViewPair, MoneroAddress) {
MoneroAddress {
meta: AddressMeta::new(Network::Mainnet, AddressType::Standard),
spend: spend_pub,
view: view.deref() * &ED25519_BASEPOINT_TABLE,
view: view.deref() * ED25519_BASEPOINT_TABLE,
},
)
}
@ -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();
@ -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");
@ -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

View file

@ -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)),
);
@ -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(

View file

@ -28,9 +28,8 @@ group = { version = "0.13", default-features = false }
crypto-bigint = { version = "0.5", default-features = false }
sha2 = { version = "0.9", default-features = false }
# The default features are ["std", "u64_backend"]
curve25519-dalek = { version = "^3.2", default-features = false, features = ["alloc", "u64_backend"] }
sha2 = { version = "0.10", default-features = false }
curve25519-dalek = { version = "4", default-features = false, features = ["alloc", "zeroize", "digest", "precomputed-tables", "legacy_compatibility"] }
[dev-dependencies]
rand_core = { version = "0.6", features = ["std"] }

View file

@ -1,3 +1,5 @@
#![allow(deprecated)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![no_std] // Prevents writing new code, in what should be a simple wrapper, which requires std
#![doc = include_str!("../README.md")]
@ -235,12 +237,8 @@ impl Scalar {
}
impl Field for Scalar {
const ZERO: Scalar = Scalar(DScalar::from_bits([0; 32]));
const ONE: Scalar = Scalar(DScalar::from_bits({
let mut bytes = [0; 32];
bytes[0] = 1;
bytes
}));
const ZERO: Scalar = Scalar(DScalar::ZERO);
const ONE: Scalar = Scalar(DScalar::ONE);
fn random(mut rng: impl RngCore) -> Self {
let mut r = [0; 64];
@ -322,7 +320,7 @@ impl PrimeField for Scalar {
fn from_repr(bytes: [u8; 32]) -> CtOption<Self> {
let scalar = DScalar::from_canonical_bytes(bytes);
// TODO: This unwrap_or_else isn't constant time, yet we don't exactly have an alternative...
CtOption::new(Scalar(scalar.unwrap_or_else(DScalar::zero)), choice(black_box(scalar).is_some()))
CtOption::new(Scalar(scalar.unwrap_or(DScalar::ZERO)), black_box(scalar).is_some())
}
fn to_repr(&self) -> [u8; 32] {
self.0.to_bytes()
@ -358,7 +356,7 @@ impl PrimeFieldBits for Scalar {
fn char_le_bits() -> FieldBits<Self::ReprBits> {
let mut bytes = (Scalar::ZERO - Scalar::ONE).to_repr();
bytes[0] += 1;
debug_assert_eq!(DScalar::from_bytes_mod_order(bytes), DScalar::zero());
debug_assert_eq!(DScalar::from_bytes_mod_order(bytes), DScalar::ZERO);
bytes.into()
}
}
@ -425,9 +423,12 @@ macro_rules! dalek_group {
type Scalar = Scalar;
fn random(mut rng: impl RngCore) -> Self {
loop {
let mut bytes = [0; 64];
let mut bytes = [0; 32];
rng.fill_bytes(&mut bytes);
let point = $Point($DPoint::hash_from_bytes::<sha2::Sha512>(&bytes));
let Some(point) = $DCompressed(bytes).decompress() else {
continue;
};
let point = $Point(point);
// Ban identity, per the trait specification
if !bool::from(point.is_identity()) {
return point;

View file

@ -25,7 +25,7 @@ ciphersuite = { path = "../ciphersuite", version = "0.3", features = ["std", "ri
schnorr = { package = "schnorr-signatures", path = "../schnorr", version = "0.4" }
frost = { path = "../frost", package = "modular-frost", version = "0.7", features = ["ristretto"] }
schnorrkel = "0.10"
schnorrkel = { version = "0.11", git = "https://github.com/serai-dex/schnorrkel" }
[dev-dependencies]
frost = { path = "../frost", package = "modular-frost", features = ["tests"] }

View file

@ -57,7 +57,7 @@ substrate-frame-rpc-system = { git = "https://github.com/serai-dex/substrate" }
pallet-transaction-payment-rpc = { git = "https://github.com/serai-dex/substrate" }
[build-dependencies]
substrate-build-script-utils = { git = "https://github.com/serai-dex/substrate.git" }
substrate-build-script-utils = { git = "https://github.com/serai-dex/substrate" }
[features]
default = []