Skip to content

Commit

Permalink
feat: extract axon-tools, add serialization & deserialization
Browse files Browse the repository at this point in the history
  • Loading branch information
wenyuanhust committed Oct 30, 2023
1 parent a088cf8 commit f52f0da
Show file tree
Hide file tree
Showing 12 changed files with 532 additions and 31 deletions.
36 changes: 35 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ members = [
"core/storage",
"devtools/abi-generator",
"devtools/keypair",
"devtools/axon-tools",
"protocol",
]

Expand Down
85 changes: 85 additions & 0 deletions devtools/axon-tools/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
[package]
name = "axon-tools"
version = "0.1.1"
edition = "2021"
authors = ["Axon Dev <[email protected]>"]
license = "MIT"
include = ["src/*", "README.md", "LICENSE"]
readme = "README.md"
keywords = ["axon", "tool"]
categories = ["cryptography"]
repository = "https://github.com/axonweb3/axon"
description = """
Some axon related utilities.
"""

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies.bit-vec]
version = "0.6"
default_features = false
optional = true

[dependencies.blst]
version = "0.3"
optional = true

[dependencies.bytes]
version = "1.4"
default-features = false
features = ["serde"]

[dependencies.cita_trie]
version = "4.0"
optional = true

[dependencies.ethereum-types]
version = "0.14"
default-features = false
features = ["serialize"]

[dependencies.faster-hex]
version = "0.8"
optional = true

[dependencies.rlp]
version = "0.5"
default-features = false
optional = true

[dependencies.rlp-derive]
version = "0.1"
optional = true

[dependencies.serde]
version = "1.0"
default_features = false
optional = true
features = ["derive"]

[dependencies.tiny-keccak]
version = "2.0"
optional = true
features = ["keccak"]

[dev-dependencies]
ethereum = "0.14"
rand = "0.8"

[dependencies]
derive_more = "0.99"
serde_json = "1.0"
log = "0.4.19"
overlord = "0.4"
protocol = { path = "../../protocol", features = ["hex-deserialize"], package = "axon-protocol" }

[features]
default = ["proof", "hash"]
proof = ["blst", "bit-vec", "cita_trie", "hash", "impl-rlp"]
hash = ["tiny-keccak"]
hex = ["faster-hex"]
impl-rlp = ["rlp", "rlp-derive", "ethereum-types/rlp"]
impl-serde = ["serde", "ethereum-types/serialize", "hex"]

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "doc_cfg"]
63 changes: 63 additions & 0 deletions devtools/axon-tools/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use std::fmt::{self, Display};

#[allow(dead_code)]
#[derive(Debug)]
pub enum Error {
InvalidProofBlockHash,
NotEnoughSignatures,
VerifyMptProof,
HexPrefix,

#[cfg(feature = "hex")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "hex")))]
Hex(faster_hex::Error),

#[cfg(feature = "proof")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "proof")))]
Bls(blst::BLST_ERROR),

#[cfg(feature = "proof")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "proof")))]
Trie(cita_trie::TrieError),
}

#[cfg(feature = "hex")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "hex")))]
impl From<faster_hex::Error> for Error {
fn from(value: faster_hex::Error) -> Self {
Self::Hex(value)
}
}

#[cfg(feature = "proof")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "proof")))]
impl From<blst::BLST_ERROR> for Error {
fn from(e: blst::BLST_ERROR) -> Self {
Self::Bls(e)
}
}

#[cfg(feature = "proof")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "proof")))]
impl From<cita_trie::TrieError> for Error {
fn from(e: cita_trie::TrieError) -> Self {
Self::Trie(e)
}
}

impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::InvalidProofBlockHash => write!(f, "Invalid proof block hash"),
Error::NotEnoughSignatures => write!(f, "Not enough signatures"),
Error::VerifyMptProof => write!(f, "Verify mpt proof"),
Error::HexPrefix => write!(f, "Hex prefix"),
#[cfg(feature = "hex")]
Error::Hex(e) => write!(f, "Hex error: {:?}", e),
#[cfg(feature = "proof")]
Error::Bls(e) => write!(f, "Bls error: {:?}", e),
#[cfg(feature = "proof")]
Error::Trie(e) => write!(f, "Trie error: {:?}", e),
}
}
}
22 changes: 22 additions & 0 deletions devtools/axon-tools/src/hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use tiny_keccak::{Hasher, Keccak};

#[cfg(feature = "hash")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "hash")))]
pub fn keccak_256(data: &[u8]) -> [u8; 32] {
let mut ret = [0u8; 32];
let mut hasher = Keccak::v256();
hasher.update(data);
hasher.finalize(&mut ret);
ret
}

#[derive(Default)]
pub(crate) struct InnerKeccak;

impl cita_trie::Hasher for InnerKeccak {
const LENGTH: usize = 32;

fn digest(&self, data: &[u8]) -> Vec<u8> {
keccak_256(data).to_vec()
}
}
12 changes: 12 additions & 0 deletions devtools/axon-tools/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#![cfg_attr(doc_cfg, feature(doc_cfg))]

extern crate alloc;

mod error;
mod hash;
mod proof;
pub mod types;

#[cfg(feature = "proof")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "proof")))]
pub use proof::{verify_proof, verify_trie_proof};
108 changes: 108 additions & 0 deletions devtools/axon-tools/src/proof.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use alloc::vec::Vec;

use bit_vec::BitVec;
use blst::min_pk::{AggregatePublicKey, PublicKey, Signature};
use blst::BLST_ERROR;
use bytes::Bytes;
use ethereum_types::H256;
use rlp::Encodable;

use crate::{
error::Error,
hash::{keccak_256, InnerKeccak},
types::{Block, Proof, Proposal, ValidatorExtend},
};
use overlord::types::{Vote, VoteType::Precommit};

const DST: &str = "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RONUL";

pub fn verify_trie_proof(
root: H256,
key: &[u8],
proof: Vec<Vec<u8>>,
) -> Result<Option<Vec<u8>>, Error> {
let value = cita_trie::verify_proof(&root.0, key, proof, InnerKeccak::default())?;
log::debug!("key: {:?}, value: {:?}", key, value);
Ok(value)
}

pub fn verify_proof(
block: Block,
previous_state_root: H256,
validator_list: &mut [ValidatorExtend],
proof: Proof,
) -> Result<(), Error> {
let raw_proposal = Proposal {
version: block.header.version,
prev_hash: block.header.prev_hash,
proposer: block.header.proposer,
prev_state_root: previous_state_root,
transactions_root: block.header.transactions_root,
signed_txs_hash: block.header.signed_txs_hash,
timestamp: block.header.timestamp,
number: block.header.number,
gas_limit: block.header.gas_limit,
extra_data: block.header.extra_data,
base_fee_per_gas: block.header.base_fee_per_gas,
proof: block.header.proof,
chain_id: block.header.chain_id,
call_system_script_count: block.header.call_system_script_count,
tx_hashes: block.tx_hashes,
}
.rlp_bytes();

if keccak_256(&raw_proposal) != proof.block_hash.0 {
return Err(Error::InvalidProofBlockHash);
}

let vote = Vote {
height: proof.number,
round: proof.round,
vote_type: Precommit,
block_hash: Bytes::from(proof.block_hash.0.to_vec()),
};

let hash_vote = keccak_256(rlp::encode(&vote).as_ref());
let pks = extract_pks(&proof, validator_list)?;
let pks = pks.iter().collect::<Vec<_>>();
let c_pk = PublicKey::from_aggregate(&AggregatePublicKey::aggregate(&pks, true)?);
let sig = Signature::from_bytes(&proof.signature)?;
let res = sig.verify(true, &hash_vote, DST.as_bytes(), &[], &c_pk, true);

if res == BLST_ERROR::BLST_SUCCESS {
return Ok(());
}

Err(res.into())
}

fn extract_pks(
proof: &Proof,
validator_list: &mut [ValidatorExtend],
) -> Result<Vec<PublicKey>, Error> {
validator_list.sort();

let bit_map = BitVec::from_bytes(&proof.bitmap);
let mut pks = Vec::with_capacity(validator_list.len());
let mut count = 0usize;

for (v, bit) in validator_list.iter().zip(bit_map.iter()) {
if !bit {
continue;
}

pks.push(PublicKey::from_bytes(&v.bls_pub_key.as_bytes())?);
count += 1;
}

log::debug!(
"extract_pks count: {}, validator len: {}",
count,
validator_list.len()
);
if count * 3 <= validator_list.len() * 2 {
return Err(Error::NotEnoughSignatures);
}

Ok(pks)
}
3 changes: 3 additions & 0 deletions devtools/axon-tools/src/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub use protocol::types::{
Block, CkbRelatedInfo, Header, Metadata, Proof, Proposal, ValidatorExtend,
};
1 change: 1 addition & 0 deletions protocol/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,4 @@ common-merkle = { path = "../common/merkle" }
[features]
default = ["hex-serialize"]
hex-serialize = []
hex-deserialize = []
Loading

0 comments on commit f52f0da

Please sign in to comment.