From ba66ca3e88734b38865d5841c5452c7fb6eef46e Mon Sep 17 00:00:00 2001 From: Davidson Souza Date: Mon, 13 Jan 2025 14:48:23 -0300 Subject: [PATCH] bump msrv to 1.63.0 This is the same MSRV used by rust-bitcoin, and required to build the latest bitcoin-hashes. This commit does the following: - Creates a rust-toolchain.toml with our msrv - Adds the rust-version attribute to Cargo.toml - Makes some changes to make sure our code builds on 0.63.0 --- .github/workflows/rust.yml | 53 +++++++++++------------------- Cargo.toml | 2 +- examples/custom-hash-type.rs | 62 +++++++++++++++++------------------- rust-toolchain.toml | 4 +++ src/accumulator/pollard.rs | 7 ++-- src/accumulator/proof.rs | 19 ++++------- src/accumulator/stump.rs | 1 + 7 files changed, 65 insertions(+), 83 deletions(-) create mode 100644 rust-toolchain.toml diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index a0c6982..0616f61 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -10,55 +10,38 @@ env: CARGO_TERM_COLOR: always jobs: - build: + linting: runs-on: ubuntu-latest steps: - # try to build - - uses: actions/checkout@v3 - - name: Build - run: cargo build --verbose - # run all tests - - uses: actions/checkout@v3 - - name: Run tests - run: cargo test --verbose + - uses: actions/checkout@v4 - linting: + - name: Install latest nightly + uses: dtolnay/rust-toolchain@nightly + with: + components: rustfmt, clippy - runs-on: ubuntu-latest - steps: - # Install Rust nightly toolchain - - uses: actions/checkout@v3 - - name: Install nightly toolchain - uses: actions-rs/toolchain@v1 - with: - profile: default - toolchain: nightly - override: true - - # cargo fmt - - uses: actions/checkout@v3 - - name: fmt - run: cargo +nightly fmt --all --check + - name: Run cargo fmt + run: cargo +nightly fmt --all --check - # run cargo clippy - - uses: actions/checkout@v3 - - name: Clippy - run: cargo +nightly clippy --all + - name: Run cargo clippy + run: cargo +nightly clippy --all-targets cross-testing: strategy: matrix: - rust: [stable, nightly, 1.41] os: [ubuntu-latest, windows-latest, macos-latest] - feature: [default, with-serde] + toolchain: [nightly, stable, 1.63.0] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master with: - toolchain: ${{ matrix.rust }} + toolchain: ${{ matrix.toolchain }} + components: rustfmt, clippy + + - name: Run Tests + run: cargo +${{ matrix.toolchain }} test --all - - name: Cross compile - run: cargo test --verbose --features ${{ matrix.feature }} diff --git a/Cargo.toml b/Cargo.toml index 95c8044..cd2677e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ license = "MIT" repository = "https://github.com/mit-dci/rustreexo" readme = "README.md" homepage = "https://github.com/mit-dci/rustreexo" +rust-version = "1.63.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] @@ -17,7 +18,6 @@ serde = { version = "1.0", features = ["derive"], optional = true } [dev-dependencies] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.81" -starknet-crypto = "0.7.2" [features] with-serde = ["serde"] diff --git a/examples/custom-hash-type.rs b/examples/custom-hash-type.rs index e696b07..9b49a83 100644 --- a/examples/custom-hash-type.rs +++ b/examples/custom-hash-type.rs @@ -16,18 +16,16 @@ use rustreexo::accumulator::mem_forest::MemForest; use rustreexo::accumulator::node_hash::AccumulatorHash; -use starknet_crypto::poseidon_hash_many; -use starknet_crypto::Felt; #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] /// We need a stateful wrapper around the actual hash, this is because we use those different /// values inside our accumulator. Here we use an enum to represent the different states, you /// may want to use a struct with more data, depending on your needs. -enum PoseidonHash { +enum CustomHash { /// This means this holds an actual value /// /// It usually represents a node in the accumulator that haven't been deleted. - Hash(Felt), + Hash([u8; 32]), /// Placeholder is a value that haven't been deleted, but we don't have the actual value. /// The only thing that matters about it is that it's not empty. You can implement this /// the way you want, just make sure that [NodeHash::is_placeholder] and [NodeHash::placeholder] @@ -44,39 +42,39 @@ enum PoseidonHash { } // you'll need to implement Display for your hash type, so you can print it. -impl std::fmt::Display for PoseidonHash { +impl std::fmt::Display for CustomHash { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - PoseidonHash::Hash(h) => write!(f, "Hash({})", h), - PoseidonHash::Placeholder => write!(f, "Placeholder"), - PoseidonHash::Empty => write!(f, "Empty"), + CustomHash::Hash(h) => write!(f, "Hash({:?})", h), + CustomHash::Placeholder => write!(f, "Placeholder"), + CustomHash::Empty => write!(f, "Empty"), } } } // this is the implementation of the NodeHash trait for our custom hash type. And it's the only // thing you need to do to use your custom hash type with the accumulator data structures. -impl AccumulatorHash for PoseidonHash { +impl AccumulatorHash for CustomHash { // returns a new placeholder type such that is_placeholder returns true fn placeholder() -> Self { - PoseidonHash::Placeholder + CustomHash::Placeholder } // returns an empty hash such that is_empty returns true fn empty() -> Self { - PoseidonHash::Empty + CustomHash::Empty } // returns true if this is a placeholder. This should be true iff this type was created by // calling placeholder. fn is_placeholder(&self) -> bool { - matches!(self, PoseidonHash::Placeholder) + matches!(self, CustomHash::Placeholder) } // returns true if this is an empty hash. This should be true iff this type was created by // calling empty. fn is_empty(&self) -> bool { - matches!(self, PoseidonHash::Empty) + matches!(self, CustomHash::Empty) } // used for serialization, writes the hash to the writer @@ -87,9 +85,9 @@ impl AccumulatorHash for PoseidonHash { W: std::io::Write, { match self { - PoseidonHash::Hash(h) => writer.write_all(&h.to_bytes_be()), - PoseidonHash::Placeholder => writer.write_all(&[0u8; 32]), - PoseidonHash::Empty => writer.write_all(&[0u8; 32]), + CustomHash::Hash(h) => writer.write_all(h), + CustomHash::Placeholder => writer.write_all(&[0u8; 32]), + CustomHash::Empty => writer.write_all(&[0u8; 32]), } } @@ -100,12 +98,12 @@ impl AccumulatorHash for PoseidonHash { where R: std::io::Read, { - let mut buf = [0u8; 32]; - reader.read_exact(&mut buf)?; - if buf.iter().all(|&b| b == 0) { - Ok(PoseidonHash::Empty) + let mut h = [0u8; 32]; + reader.read_exact(&mut h)?; + if h.iter().all(|&x| x == 0) { + Ok(CustomHash::Placeholder) } else { - Ok(PoseidonHash::Hash(Felt::from_bytes_be(&buf))) + Ok(CustomHash::Hash(h)) } } @@ -114,25 +112,25 @@ impl AccumulatorHash for PoseidonHash { // exact same algorithm to calculate the next hash. Rustreexo won't call this method, unless // **both** children are not empty. fn parent_hash(left: &Self, right: &Self) -> Self { - if let (PoseidonHash::Hash(left), PoseidonHash::Hash(right)) = (left, right) { - return PoseidonHash::Hash(poseidon_hash_many(&[*left, *right])); + match (left, right) { + (CustomHash::Hash(l), CustomHash::Hash(r)) => { + let mut h = [0u8; 32]; + for i in 0..32 { + h[i] = l[i] ^ r[i]; + } + CustomHash::Hash(h) + } + _ => unreachable!(), } - - // This should never happen, since rustreexo won't call this method unless both children - // are not empty. - unreachable!() } } fn main() { // Create a vector with two utxos that will be added to the MemForest - let elements = vec![ - PoseidonHash::Hash(Felt::from(1)), - PoseidonHash::Hash(Felt::from(2)), - ]; + let elements = vec![CustomHash::Hash([1; 32]), CustomHash::Hash([2; 32])]; // Create a new MemForest, and add the utxos to it - let mut p = MemForest::::new_with_hash(); + let mut p = MemForest::::new_with_hash(); p.modify(&elements, &[]).unwrap(); // Create a proof that the first utxo is in the MemForest diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..d351940 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "1.63.0" +components = [ "rustfmt", "clippy" ] +profile = "default" diff --git a/src/accumulator/pollard.rs b/src/accumulator/pollard.rs index 4c9f38e..7572bf7 100644 --- a/src/accumulator/pollard.rs +++ b/src/accumulator/pollard.rs @@ -534,7 +534,7 @@ impl Pollard { /// Creates a new empty [Pollard] pub fn new() -> Pollard { - let roots: [Option>>; 64] = [const { None }; 64]; + let roots: [Option>>; 64] = std::array::from_fn(|_| None); Pollard:: { roots, leaves: 0 } } } @@ -849,7 +849,10 @@ impl Pollard { // my parent is a root, I'm a root now for i in 0..64 { let aunt = node.aunt().unwrap(); - let Some(root) = self.roots[i].as_ref() else { + + let root = if let Some(root) = self.roots[i].as_ref() { + root + } else { continue; }; if root.hash() == aunt.hash() { diff --git a/src/accumulator/proof.rs b/src/accumulator/proof.rs index 498dfd1..9df69c8 100644 --- a/src/accumulator/proof.rs +++ b/src/accumulator/proof.rs @@ -462,13 +462,9 @@ impl Proof { let mut computed = Vec::with_capacity(nodes.len() * 2); let mut computed_index = 0; let mut provided_index = 0; - loop { - let Some((next_pos, (next_hash_old, next_hash_new))) = - Self::get_next(&computed, &nodes, &mut computed_index, &mut provided_index) - else { - break; - }; - + while let Some((next_pos, (next_hash_old, next_hash_new))) = + Self::get_next(&computed, &nodes, &mut computed_index, &mut provided_index) + { if util::is_root_position(next_pos, num_leaves, total_rows) { calculated_root_hashes.push((next_hash_old, next_hash_new)); continue; @@ -547,13 +543,10 @@ impl Proof { let mut computed = Vec::with_capacity(nodes.len() * 2); let mut computed_index = 0; let mut provided_index = 0; - loop { - let Some((next_pos, next_hash)) = - Self::get_next(&computed, &nodes, &mut computed_index, &mut provided_index) - else { - break; - }; + while let Some((next_pos, next_hash)) = + Self::get_next(&computed, &nodes, &mut computed_index, &mut provided_index) + { if util::is_root_position(next_pos, num_leaves, total_rows) { calculated_root_hashes.push(next_hash); continue; diff --git a/src/accumulator/stump.rs b/src/accumulator/stump.rs index 631739c..5831011 100644 --- a/src/accumulator/stump.rs +++ b/src/accumulator/stump.rs @@ -389,6 +389,7 @@ mod test { } fn parent_hash(left: &Self, right: &Self) -> Self { let mut hash = [0; 32]; + #[allow(clippy::needless_range_loop)] for i in 0..32 { hash[i] = left.0[i] ^ right.0[i]; }