-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- fixed a loooot of deserialisation errors for data model - add actual verification to the chained scheme - added some more tests and made the existing ones actually check things >.> - extracted some BLS logic into its own file
- Loading branch information
1 parent
62b9741
commit 078ca08
Showing
8 changed files
with
265 additions
and
180 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
use bls_signatures::{hash, PublicKey, Serialize, Signature, verify}; | ||
use crate::chain_info::ChainInfo; | ||
use crate::SchemeError; | ||
|
||
pub trait BlsVerifiable { | ||
fn signature(&self) -> &Vec<u8>; | ||
fn to_message(&self) -> Result<Vec<u8>, SchemeError>; | ||
} | ||
|
||
pub(crate) fn bls_verify<B: BlsVerifiable>(info: &ChainInfo, beacon: B) -> Result<B, SchemeError> { | ||
let public_key = PublicKey::from_bytes(info.public_key.as_slice()) | ||
.map_err(|_| SchemeError::InvalidChainInfo)?; | ||
|
||
let signature = Signature::from_bytes(&beacon.signature().as_slice()) | ||
.map_err(|_| SchemeError::InvalidBeacon)?; | ||
|
||
let bls_message_bytes = beacon.to_message() | ||
.map(|bytes| sha256::digest(bytes.as_slice())) | ||
.and_then(|hex_str| hex::decode(hex_str) | ||
.map_err(|_| SchemeError::InvalidBeacon) | ||
)?; | ||
|
||
|
||
let point_on_curve = hash(bls_message_bytes.as_slice()); | ||
if !verify(&signature, &[point_on_curve], &[public_key]) { | ||
return Err(SchemeError::InvalidBeacon); | ||
} | ||
|
||
return Ok(beacon); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
use serde::Deserialize; | ||
|
||
#[derive(Deserialize, Debug, PartialEq, Clone)] | ||
pub struct ChainInfo { | ||
#[serde(alias = "schemeID")] | ||
pub scheme_id: String, | ||
#[serde(with = "hex")] | ||
pub public_key: Vec<u8>, | ||
#[serde(with = "hex", alias = "hash")] | ||
pub chain_hash: Vec<u8>, | ||
#[serde(with = "hex", alias = "groupHash")] | ||
pub group_hash: Vec<u8>, | ||
pub genesis_time: u64, | ||
#[serde(alias = "period")] | ||
pub period_seconds: usize, | ||
pub metadata: ChainInfoMetadata, | ||
} | ||
|
||
#[derive(Deserialize, Debug, PartialEq, Clone)] | ||
pub struct ChainInfoMetadata { | ||
#[serde(alias = "beaconID")] | ||
pub beacon_id: String, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,113 +1,52 @@ | ||
use bls_signatures::{PublicKey, Serialize, Signature, verify}; | ||
use json::JsonValue; | ||
use crate::{ChainInfo, Scheme, SchemeError}; | ||
use thiserror::Error; | ||
|
||
pub(crate) struct ChainedBeacon { | ||
use std::io::{Write}; | ||
use crate::{bls, Scheme, SchemeError}; | ||
use crate::chain_info::ChainInfo; | ||
use serde::Deserialize; | ||
use crate::bls::BlsVerifiable; | ||
|
||
#[derive(Deserialize, Debug, PartialEq, Clone)] | ||
pub struct ChainedBeacon { | ||
#[serde(alias = "round")] | ||
pub round_number: u64, | ||
#[serde(with = "hex")] | ||
pub randomness: Vec<u8>, | ||
#[serde(with = "hex")] | ||
pub signature: Vec<u8>, | ||
#[serde(with = "hex")] | ||
pub previous_signature: Vec<u8>, | ||
} | ||
|
||
|
||
#[derive(Error, Debug)] | ||
pub enum JsonParseError { | ||
#[error("unknown error")] | ||
UnknownError, | ||
#[error("empty payload")] | ||
EmptyPayload, | ||
#[error("could not parse")] | ||
CouldNotParse, | ||
#[error("invalid json")] | ||
InvalidJson, | ||
#[error("invalid type")] | ||
InvalidType { key: String }, | ||
#[error("could not parse value")] | ||
CouldNotParseValue { key: String }, | ||
#[error("unknown key")] | ||
UnknownKey { key: String }, | ||
} | ||
|
||
impl TryFrom<JsonValue> for ChainedBeacon { | ||
type Error = JsonParseError; | ||
|
||
fn try_from(value: JsonValue) -> Result<Self, Self::Error> { | ||
if !value.is_object() { | ||
return Err(JsonParseError::CouldNotParse); | ||
} | ||
|
||
let mut out = ChainedBeacon { | ||
round_number: 0, | ||
randomness: vec![], | ||
signature: vec![], | ||
previous_signature: vec![], | ||
}; | ||
|
||
for (key, value) in value.entries() { | ||
match key { | ||
"round" => { | ||
if !value.is_number() { | ||
return Err(JsonParseError::CouldNotParseValue { key: key.to_string() }); | ||
} | ||
if let Some(round_number) = value.as_u64() { | ||
out.round_number = round_number | ||
} else { | ||
return Err(JsonParseError::CouldNotParseValue { key: key.to_string() }); | ||
} | ||
} | ||
"randomness" => { | ||
out.randomness = parse_bytes(key, value)? | ||
} | ||
"signature" => { | ||
out.signature = parse_bytes(key, value)? | ||
} | ||
"previous_signature" => { | ||
out.previous_signature = parse_bytes(key, value)? | ||
} | ||
_ => return Err(JsonParseError::UnknownKey { key: key.to_string() }) | ||
} | ||
} | ||
|
||
return Ok(out); | ||
} | ||
} | ||
|
||
fn parse_bytes<'a>(key: &str, value: &JsonValue) -> Result<Vec<u8>, JsonParseError> { | ||
if !value.is_string() { | ||
return Err(JsonParseError::InvalidType { key: key.to_string() }); | ||
} | ||
return match value.as_str() { | ||
None => | ||
Err(JsonParseError::CouldNotParseValue { key: key.to_string() }), | ||
Some(hex_str) => | ||
hex::decode(hex_str) | ||
.map_err(|_| JsonParseError::CouldNotParseValue { key: key.to_string() }) | ||
}; | ||
} | ||
|
||
pub struct ChainedScheme {} | ||
|
||
impl Scheme<ChainedBeacon> for ChainedScheme { | ||
fn supports(&self, scheme_id: &str) -> bool { | ||
return scheme_id.eq_ignore_ascii_case("bls-pedersen-chained"); | ||
return scheme_id.eq_ignore_ascii_case("pedersen-bls-chained"); | ||
} | ||
|
||
fn verify(&self, info: &ChainInfo, beacon: ChainedBeacon) -> Result<ChainedBeacon, SchemeError> { | ||
if !self.supports(&info.scheme_id) { | ||
return Err(SchemeError::InvalidScheme); | ||
} | ||
|
||
let public_key = PublicKey::from_bytes(info.public_key.as_slice()) | ||
.map_err(|_| SchemeError::InvalidChainInfo)?; | ||
return bls::bls_verify(info, beacon); | ||
} | ||
} | ||
|
||
impl BlsVerifiable for ChainedBeacon { | ||
fn signature(&self) -> &Vec<u8> { | ||
&self.signature | ||
} | ||
|
||
let signature = Signature::from_bytes(&beacon.signature.as_slice()) | ||
.map_err(|_| SchemeError::InvalidBeacon)?; | ||
fn to_message(&self) -> Result<Vec<u8>, SchemeError> { | ||
let mut bytes: Vec<u8> = vec![]; | ||
|
||
if !verify(&signature, &[], &[public_key]) { | ||
if bytes.write_all(self.previous_signature.as_slice()).is_err() { | ||
return Err(SchemeError::InvalidBeacon); | ||
} | ||
if bytes.write_all(&self.round_number.to_be_bytes()).is_err() { | ||
return Err(SchemeError::InvalidBeacon); | ||
}; | ||
|
||
return Ok(beacon); | ||
return Ok(bytes); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
use reqwest::blocking::Client; | ||
use reqwest::StatusCode; | ||
use thiserror::Error; | ||
|
||
#[derive(Error, Debug)] | ||
pub enum HttpError { | ||
#[error("not found")] | ||
NotFound, | ||
#[error("unexpected")] | ||
Unexpected, | ||
} | ||
|
||
pub struct HttpTransport { | ||
pub client: Client, | ||
} | ||
|
||
impl HttpTransport { | ||
pub fn fetch<'a>(&self, url: &str) -> Result<String, HttpError> { | ||
let res = self.client.get(url) | ||
.send() | ||
.map_err(|_| HttpError::Unexpected)?; | ||
|
||
return match res.status() { | ||
StatusCode::OK => res.text() | ||
.map_err(|_| HttpError::Unexpected), | ||
|
||
StatusCode::NOT_FOUND => | ||
Err(HttpError::NotFound), | ||
|
||
_ => Err(HttpError::Unexpected), | ||
}; | ||
} | ||
} |
Oops, something went wrong.