Skip to content

Commit

Permalink
bump msrv to 1.63.0
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Davidson-Souza committed Jan 13, 2025
1 parent 1ee240f commit ee67c40
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 84 deletions.
54 changes: 18 additions & 36 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,63 +2,45 @@ name: Rust

on:
push:
branches: [ "main" ]
branches: [ "bump-msrv" ]
pull_request:
branches: [ "main" ]

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@${{ matrix.toolchain }}
with:
toolchain: ${{ matrix.rust }}
components: rustfmt, clippy

- name: Run Tests
run: cargo test --all

- name: Cross compile
run: cargo test --verbose --features ${{ matrix.feature }}
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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"]
Expand Down
62 changes: 30 additions & 32 deletions examples/custom-hash-type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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
Expand All @@ -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]),
}
}

Expand All @@ -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))
}
}

Expand All @@ -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::<PoseidonHash>::new_with_hash();
let mut p = MemForest::<CustomHash>::new_with_hash();
p.modify(&elements, &[]).unwrap();

// Create a proof that the first utxo is in the MemForest
Expand Down
4 changes: 4 additions & 0 deletions rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[toolchain]
channel = "1.63.0"
components = [ "rustfmt", "clippy" ]
profile = "default"
7 changes: 5 additions & 2 deletions src/accumulator/pollard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ impl<Hash: AccumulatorHash> Pollard<Hash> {

/// Creates a new empty [Pollard]
pub fn new() -> Pollard<Hash> {
let roots: [Option<Rc<PollardNode<Hash>>>; 64] = [const { None }; 64];
let roots: [Option<Rc<PollardNode<Hash>>>; 64] = std::array::from_fn(|_| None);
Pollard::<Hash> { roots, leaves: 0 }
}
}
Expand Down Expand Up @@ -849,7 +849,10 @@ impl<Hash: AccumulatorHash> Pollard<Hash> {
// 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() {
Expand Down
19 changes: 6 additions & 13 deletions src/accumulator/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,13 +462,9 @@ impl<Hash: AccumulatorHash> Proof<Hash> {
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;
Expand Down Expand Up @@ -547,13 +543,10 @@ impl<Hash: AccumulatorHash> Proof<Hash> {
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;
Expand Down
1 change: 1 addition & 0 deletions src/accumulator/stump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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];
}
Expand Down

0 comments on commit ee67c40

Please sign in to comment.