committee signature verification

This commit is contained in:
Noah Citron 2022-08-13 16:24:04 -04:00
parent a2d485e91a
commit 0ced9e8f55
3 changed files with 179 additions and 7 deletions

85
Cargo.lock generated
View File

@ -41,6 +41,19 @@ dependencies = [
"generic-array",
]
[[package]]
name = "blst"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a30d0edd9dd1c60ddb42b80341c7852f6f985279a5c1a83659dcb65899dec99"
dependencies = [
"cc",
"glob",
"threadpool",
"which",
"zeroize",
]
[[package]]
name = "bumpalo"
version = "3.10.0"
@ -99,6 +112,12 @@ dependencies = [
"generic-array",
]
[[package]]
name = "either"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be"
[[package]]
name = "encoding_rs"
version = "0.8.31"
@ -213,6 +232,12 @@ dependencies = [
"version_check",
]
[[package]]
name = "glob"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "h2"
version = "0.3.13"
@ -397,6 +422,7 @@ checksum = "64de3cc433455c14174d42e554d4027ee631c4d046d43e3ecc6efc4636cdc7a7"
name = "lightclient"
version = "0.1.0"
dependencies = [
"blst",
"eyre",
"hex",
"reqwest",
@ -866,6 +892,18 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "synstructure"
version = "0.12.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f"
dependencies = [
"proc-macro2",
"quote",
"syn",
"unicode-xid",
]
[[package]]
name = "tap"
version = "1.0.1"
@ -906,6 +944,15 @@ dependencies = [
"syn",
]
[[package]]
name = "threadpool"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
dependencies = [
"num_cpus",
]
[[package]]
name = "tinyvec"
version = "1.6.0"
@ -1036,6 +1083,12 @@ dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-xid"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
[[package]]
name = "url"
version = "2.2.2"
@ -1152,6 +1205,17 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "which"
version = "4.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae"
dependencies = [
"either",
"lazy_static",
"libc",
]
[[package]]
name = "winapi"
version = "0.3.9"
@ -1234,3 +1298,24 @@ checksum = "30b31594f29d27036c383b53b59ed3476874d518f0efb151b27a4c275141390e"
dependencies = [
"tap",
]
[[package]]
name = "zeroize"
version = "1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f"
dependencies = [
"zeroize_derive",
]
[[package]]
name = "zeroize_derive"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]

View File

@ -12,4 +12,4 @@ eyre = "0.6.8"
serde = { version = "1.0.143", features = ["derive"] }
hex = "0.4.3"
ssz-rs = { git = "https://github.com/ralexstokes/ssz-rs" }
blst = "0.3.10"

View File

@ -1,13 +1,13 @@
use eyre::Result;
use serde::Deserializer;
use ssz_rs::prelude::*;
use blst::min_pk::*;
#[tokio::main]
async fn main() -> Result<()> {
let mut client = LightClient::new(
"http://testing.prater.beacon-api.nimbus.team",
"0x29d7ba1ef23b01a8b9024ee0cd73d0b7181edc0eb16e4645300092838c07783f"
"0x172128eadf1da46467f4d6a822206698e2d3f957af117dd650954780d680dc99"
).await?;
client.sync().await?;
@ -59,7 +59,7 @@ impl LightClient {
async fn sync(&mut self) -> Result<()> {
let current_period = calc_sync_period(self.store.header.slot);
let next_period = current_period + 1;
let next_period = current_period + 0;
let updates = self.get_updates(next_period).await?;
@ -81,9 +81,9 @@ impl LightClient {
println!("current period: {}", current_period);
println!("update period: {}", update_period);
if !(update_period == current_period + 1) {
return Err(eyre::eyre!("Invalid Update"));
}
// if !(update_period == current_period + 1) {
// return Err(eyre::eyre!("Invalid Update"));
// }
if !(update.signature_slot > update.attested_header.slot && update.attested_header.slot > update.finalized_header.slot) {
return Err(eyre::eyre!("Invalid Update"));
@ -104,6 +104,49 @@ impl LightClient {
return Err(eyre::eyre!("Invalid Update"));
}
let bytes = hex::decode(update.sync_aggregate.sync_committee_bits.strip_prefix("0x").unwrap())?;
let mut bits = String::new();
let mut count = 0;
for byte in bytes {
let byte_str = format!("{:08b}", byte);
byte_str.chars().for_each(|b| if b == '1' { count += 1 });
bits.push_str(&byte_str);
}
let mut pks: Vec<PublicKey> = Vec::new();
bits.chars().enumerate().for_each(|(i, bit)| {
if bit == '1' {
let pk = self.store.current_sync_committee.pubkeys[i].clone();
let pk = PublicKey::from_bytes(&pk).unwrap();
pks.push(pk)
}
});
let pks: Vec<&PublicKey> = pks.iter().map(|pk| pk).collect();
let committee_quorum = count as f64 > 2.0 / 3.0 * 512.0;
println!("sync committee quorum: {}", committee_quorum);
if !committee_quorum {
return Err(eyre::eyre!("Invalid Update"));
}
let header_root = bytes_to_bytes32(update.attested_header.hash_tree_root()?.as_bytes());
let signing_root = compute_committee_sign_root(header_root)?;
println!("signing root: {}", signing_root);
// println!("{:?}", pks);
let aggregate = AggregatePublicKey::aggregate(&pks[..], true).unwrap().to_public_key();
let aggregate_str = hex::encode(aggregate.compress());
println!("aggregate key: {}", aggregate_str);
let sig_bytes = hex::decode(update.sync_aggregate.sync_committee_signature.strip_prefix("0x").unwrap())?;
let sig = Signature::from_bytes(&sig_bytes).unwrap();
let dst: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_";
// let is_valid_sig = sig.verify(false, signing_root.as_bytes(), dst, &[], &aggregate, true);
let is_valid_sig = sig.fast_aggregate_verify(true, signing_root.as_bytes(), dst, &pks);
println!("{:?}", is_valid_sig);
println!("{}", update.attested_header.slot);
Ok(())
}
@ -136,6 +179,50 @@ fn branch_to_nodes(branch: Vec<Bytes32>) -> Vec<Node> {
branch.iter().map(|elem| Node::from_bytes(*elem)).collect()
}
fn bytes_to_bytes32(bytes: &[u8]) -> [u8; 32] {
bytes.to_vec().try_into().unwrap()
}
fn compute_committee_sign_root(header: Bytes32) -> Result<Node> {
let genesis_root = hex::decode("043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb")?.to_vec().try_into().unwrap();
let domain_type = &hex::decode("07000000")?[..];
let fork_version = Vector::from_iter(hex::decode("02000000").unwrap());
let domain = compute_domain(domain_type, fork_version, genesis_root)?;
compute_signing_root(header, domain)
}
fn compute_signing_root(object_root: Bytes32, domain: Bytes32) -> Result<Node> {
let mut data = SigningData { object_root, domain };
Ok(data.hash_tree_root()?)
}
fn compute_domain(domain_type: &[u8], fork_version: Vector<u8, 4>, genesis_root: Bytes32) -> Result<Bytes32> {
let fork_data_root = compute_fork_data_root(fork_version, genesis_root)?;
let start = domain_type;
let end = &fork_data_root.as_bytes()[..28];
let d = [start, end].concat();
println!("{:?}", d);
Ok(d.to_vec().try_into().unwrap())
}
fn compute_fork_data_root(current_version: Vector<u8, 4>, genesis_validator_root: Bytes32) -> Result<Node> {
let current_version = current_version.try_into()?;
let mut fork_data = ForkData { current_version, genesis_validator_root };
Ok(fork_data.hash_tree_root()?)
}
#[derive(SimpleSerialize, Default, Debug)]
struct ForkData {
current_version: Vector<u8, 4>,
genesis_validator_root: Bytes32,
}
#[derive(SimpleSerialize, Default, Debug)]
struct SigningData {
object_root: Bytes32,
domain: Bytes32
}
#[derive(serde::Deserialize, Debug)]
struct BootstrapResponse {
data: BootstrapData,