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

[DRAFT] Add BLSCache struct / pyobject #408

Draft
wants to merge 23 commits into
base: main
Choose a base branch
from
Draft

[DRAFT] Add BLSCache struct / pyobject #408

wants to merge 23 commits into from

Conversation

matt-o-how
Copy link
Contributor

No description provided.

Copy link

coveralls-official bot commented Feb 21, 2024

Pull Request Test Coverage Report for Build 8006278210

Details

  • -21 of 197 (89.34%) changed or added relevant lines in 2 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.06%) to 85.229%

Changes Missing Coverage Covered Lines Changed/Added Lines %
chia-bls/src/cached_bls.rs 174 195 89.23%
Totals Coverage Status
Change from base Build 7932525567: 0.06%
Covered Lines: 11586
Relevant Lines: 13594

💛 - Coveralls

@@ -0,0 +1,275 @@
extern crate lru;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this line is necessary. I don't recall ever having to use extern crate. ChatGPT suggests that since the rust 2018 edition you can import with use instead.

impl BLSCache {

pub fn generator(cache_size: Option<usize>) -> Self {
let cache: LruCache<Bytes32, GTElement> = LruCache::new(NonZeroUsize::new(cache_size.unwrap_or(50000)).unwrap());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't familiar with NonZeroUsize. Seems a bit strange they'd use that in their API. Maybe too clever by half.

Note that using .unwrap is a bad smell because it panics on failure. There's probably a way to do this without .unwrap. Maybe just do cache_size = cache_size | 50000.

    pub fn generator(cache_size: usize) -> Self {
        let cache: LruCache<Bytes32, GTElement> = LruCache::new(NonZeroUsize::new(cache_size | 50000).unwrap());
        Self{cache}
    }

I haven't test this.

let mut aug_msg = pk.to_vec();
aug_msg.extend_from_slice(msg.borrow()); // pk + msg
let mut hasher = Sha256::new();
hasher.update(aug_msg);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can call hasher.update multiple times, which means you don't actually have to create aug_msg.

-            let mut aug_msg = pk.to_vec();
-            aug_msg.extend_from_slice(msg.borrow()); // pk + msg
             let mut hasher = Sha256::new();
+            hasher.update(pk);
+            hasher.update(msg);
-            hasher.update(aug_msg);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(also not tested, so some types may be off by a & or something)


}

// G1Element.from_bytes can be expensive due to subgroup check, so we avoid recomputing it with this cache
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why there are two loops instead of one. Seems like a natural way to do this would be do dig for the answer in the cache, and if it ain't there, calculate it (and possible cache the result). Maybe it has something to do with the heuristic above. I realize this is just a port so you may not know either.

});

let pairing: GTElement = aug_hash.pair(pk_parsed);
let mut hasher = Sha256::new();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do this same hash again, not sure why.

let res: bool = agg_ver(sig, data);
return res
}
let pairings_prod = pairings.pop(); // start with the first pairing
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the GT group has an "identity" element which acts like 1 for multiplication of "regular" (ie. real) numbers. If you set the partial product prod to this identity element, you don't have to do this weird .pop which treats the first argument as special. In fact, you can probably use .fold https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.fold

There are still two cases: an empty list and a non-empty list. It's a bit weird to me that you don't check the signature for the empty list case, but it might be a consensus change to do so depending on how empty blocks are treated (ie. blocks that don't have spends with any AGG_* conditions).

@@ -19,7 +19,8 @@ use pyo3::exceptions::PyValueError;
#[cfg(feature = "py-bindings")]
use pyo3::{pyclass, pymethods, IntoPy, PyAny, PyObject, PyResult, Python};

#[cfg_attr(feature = "py-bindings", pyclass, derive(PyStreamable, Clone))]
#[cfg_attr(feature = "py-bindings", pyclass, derive(PyStreamable))]
#[derive(Clone)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm puzzled as to why this might be necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to Clone the GTElement in Rust so we move it out of the py-binding exclusive derives

Copy link

socket-security bot commented Feb 22, 2024

@matt-o-how matt-o-how force-pushed the bls_cache branch 3 times, most recently from 6bdb0d2 to cb09152 Compare February 22, 2024 14:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants