Finalise bls spec tests

This commit is contained in:
Kirk Baird 2019-05-21 12:46:22 +10:00
parent 6bab62e629
commit 7a96ad130e
No known key found for this signature in database
GPG Key ID: BF864B7ED0BEA33F
10 changed files with 295 additions and 55 deletions

View File

@ -16,7 +16,7 @@ use tree_hash::tree_hash_ssz_encoding_as_vector;
/// serialization). /// serialization).
#[derive(Debug, Clone, Eq)] #[derive(Debug, Clone, Eq)]
pub struct FakePublicKey { pub struct FakePublicKey {
bytes: Vec<u8> bytes: Vec<u8>,
} }
impl FakePublicKey { impl FakePublicKey {
@ -34,14 +34,14 @@ impl FakePublicKey {
/// Returns the underlying point as compressed bytes. /// Returns the underlying point as compressed bytes.
/// ///
/// Identical to `self.as_uncompressed_bytes()`. /// Identical to `self.as_uncompressed_bytes()`.
fn as_bytes(&self) -> Vec<u8> { pub fn as_bytes(&self) -> Vec<u8> {
self.bytes.clone() self.bytes.clone()
} }
/// Converts compressed bytes to FakePublicKey /// Converts compressed bytes to FakePublicKey
pub fn from_bytes(bytes: &[u8]) -> Result<Self, DecodeError> { pub fn from_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
Ok(Self { Ok(Self {
bytes: bytes.to_vec() bytes: bytes.to_vec(),
}) })
} }
@ -63,6 +63,11 @@ impl FakePublicKey {
let end_bytes = &bytes[bytes.len().saturating_sub(6)..bytes.len()]; let end_bytes = &bytes[bytes.len().saturating_sub(6)..bytes.len()];
hex_encode(end_bytes) hex_encode(end_bytes)
} }
// Returns itself
pub fn as_raw(&self) -> &Self {
self
}
} }
impl fmt::Display for FakePublicKey { impl fmt::Display for FakePublicKey {

View File

@ -2,15 +2,23 @@ use super::*;
use crate::yaml_decode::*; use crate::yaml_decode::*;
use yaml_rust::YamlLoader; use yaml_rust::YamlLoader;
mod ssz_generic;
mod ssz_static;
mod bls_aggregate_pubkeys; mod bls_aggregate_pubkeys;
mod bls_aggregate_sigs; mod bls_aggregate_sigs;
mod bls_g2_compressed;
mod bls_g2_uncompressed;
mod bls_priv_to_pub;
mod bls_sign_msg;
mod ssz_generic;
mod ssz_static;
pub use ssz_generic::*;
pub use ssz_static::*;
pub use bls_aggregate_pubkeys::*; pub use bls_aggregate_pubkeys::*;
pub use bls_aggregate_sigs::*; pub use bls_aggregate_sigs::*;
pub use bls_g2_compressed::*;
pub use bls_g2_uncompressed::*;
pub use bls_priv_to_pub::*;
pub use bls_sign_msg::*;
pub use ssz_generic::*;
pub use ssz_static::*;
#[derive(Debug)] #[derive(Debug)]
pub struct Cases<T> { pub struct Cases<T> {

View File

@ -1,10 +1,7 @@
use super::*; use super::*;
use crate::case_result::compare_result; use crate::case_result::compare_result;
use bls::{AggregatePublicKey, PublicKey}; use bls::{AggregatePublicKey, PublicKey};
use ethereum_types::{U128, U256};
use serde_derive::Deserialize; use serde_derive::Deserialize;
use ssz::Decode;
use std::fmt::Debug;
use types::EthSpec; use types::EthSpec;
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
@ -25,7 +22,7 @@ impl EfTest for Cases<BlsAggregatePubkeys> {
.iter() .iter()
.enumerate() .enumerate()
.map(|(i, tc)| { .map(|(i, tc)| {
let result = bls_add_aggregates::<AggregatePublicKey>(&tc.input, &tc.output); let result = bls_add_pubkeys(&tc.input, &tc.output);
CaseResult::new(i, tc, result) CaseResult::new(i, tc, result)
}) })
@ -34,20 +31,20 @@ impl EfTest for Cases<BlsAggregatePubkeys> {
} }
/// Execute a `aggregate_pubkeys` test case. /// Execute a `aggregate_pubkeys` test case.
fn bls_add_aggregates<T>( fn bls_add_pubkeys(inputs: &[String], output: &String) -> Result<(), Error> {
inputs: &[String],
output: &String,
) -> Result<(), Error> {
let mut aggregate_pubkey = AggregatePublicKey::new(); let mut aggregate_pubkey = AggregatePublicKey::new();
for key_str in inputs { for key_str in inputs {
let key = hex::decode(&key_str[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?; let key =
let key = PublicKey::from_bytes(&key).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?; hex::decode(&key_str[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
let key = PublicKey::from_bytes(&key)
.map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
aggregate_pubkey.add(&key); aggregate_pubkey.add(&key);
} }
let output_bytes = Some(hex::decode(&output[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?); let output_bytes =
Some(hex::decode(&output[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?);
let aggregate_pubkey = Ok(aggregate_pubkey.as_raw().as_bytes()); let aggregate_pubkey = Ok(aggregate_pubkey.as_raw().as_bytes());
compare_result::<Vec<u8>, Vec<u8>>(&aggregate_pubkey, &output_bytes) compare_result::<Vec<u8>, Vec<u8>>(&aggregate_pubkey, &output_bytes)

View File

@ -1,10 +1,7 @@
use super::*; use super::*;
use crate::case_result::compare_result; use crate::case_result::compare_result;
use bls::{AggregateSignature, Signature}; use bls::{AggregateSignature, Signature};
use ethereum_types::{U128, U256};
use serde_derive::Deserialize; use serde_derive::Deserialize;
use ssz::Decode;
use std::fmt::Debug;
use types::EthSpec; use types::EthSpec;
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
@ -25,7 +22,7 @@ impl EfTest for Cases<BlsAggregateSigs> {
.iter() .iter()
.enumerate() .enumerate()
.map(|(i, tc)| { .map(|(i, tc)| {
let result = bls_add_aggregates::<AggregateSignature>(&tc.input, &tc.output); let result = bls_add_signatures(&tc.input, &tc.output);
CaseResult::new(i, tc, result) CaseResult::new(i, tc, result)
}) })
@ -34,20 +31,20 @@ impl EfTest for Cases<BlsAggregateSigs> {
} }
/// Execute a `aggregate_sigs` test case. /// Execute a `aggregate_sigs` test case.
fn bls_add_aggregates<T>( fn bls_add_signatures(inputs: &[String], output: &String) -> Result<(), Error> {
inputs: &[String],
output: &String,
) -> Result<(), Error> {
let mut aggregate_signature = AggregateSignature::new(); let mut aggregate_signature = AggregateSignature::new();
for key_str in inputs { for key_str in inputs {
let sig = hex::decode(&key_str[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?; let sig =
let sig = Signature::from_bytes(&sig).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?; hex::decode(&key_str[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
let sig = Signature::from_bytes(&sig)
.map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
aggregate_signature.add(&sig); aggregate_signature.add(&sig);
} }
let output_bytes = Some(hex::decode(&output[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?); let output_bytes =
Some(hex::decode(&output[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?);
let aggregate_signature = Ok(aggregate_signature.as_bytes()); let aggregate_signature = Ok(aggregate_signature.as_bytes());
compare_result::<Vec<u8>, Vec<u8>>(&aggregate_signature, &output_bytes) compare_result::<Vec<u8>, Vec<u8>>(&aggregate_signature, &output_bytes)

View File

@ -1,10 +1,7 @@
use super::*; use super::*;
use crate::case_result::compare_result; use crate::case_result::compare_result;
use bls::{compress_g2, hash_on_g2}; use bls::{compress_g2, hash_on_g2};
use ethereum_types::{U128, U256};
use serde_derive::Deserialize; use serde_derive::Deserialize;
use ssz::Decode;
use std::fmt::Debug;
use types::EthSpec; use types::EthSpec;
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
@ -40,36 +37,35 @@ impl EfTest for Cases<BlsG2Compressed> {
} }
/// Execute a `compressed hash to g2` test case. /// Execute a `compressed hash to g2` test case.
fn compressed_hash<T>( fn compressed_hash(message: &String, domain: &String, output: &Vec<String>) -> Result<(), Error> {
message: &String, // Convert message and domain to required types
domain: &String, let msg =
output: &Vec<String>, hex::decode(&message[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
) -> Result<(), Error> {
let msg = hex::decode(&message[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
let d = hex::decode(&domain[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?; let d = hex::decode(&domain[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
let d = bytes_to_u64(&d); let d = bytes_to_u64(&d);
let point = hash_on_g2 // Calculate the point and convert it to compressed bytes
let mut point = hash_on_g2(&msg, d);
let point = compress_g2(&mut point);
// Convert the output to one set of bytes
let mut decoded =
hex::decode(&output[0][2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
let mut decoded_y =
hex::decode(&output[1][2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
decoded.append(&mut decoded_y);
let mut output = hex::decode(&output[0][2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?; compare_result::<Vec<u8>, Vec<u8>>(&Ok(point), &Some(decoded))
let output_y = hex::decode(&output[1][2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
output.append(&output_y);
let point = hash_on_g2(&msg, d);
let point = compress_g2(&point);
compare_result::<Vec<u8>, Vec<u8>>(Ok(point), Some(output))
} }
// Converts a vector to u64 (from little endian) // Converts a vector to u64 (from big endian)
fn bytes_to_u64(array: &Vec<u8>) -> u64 { fn bytes_to_u64(array: &Vec<u8>) -> u64 {
let mut result: u64 = 0; let mut result: u64 = 0;
for (i, value) in array.iter().enumerate() { for (i, value) in array.iter().rev().enumerate() {
if i == 8 { if i == 8 {
break; break;
} }
result += u64::pow(2, i * 8) * *value; result += u64::pow(2, i as u32 * 8) * (*value as u64);
} }
result result
} }

View File

@ -0,0 +1,85 @@
use super::*;
use crate::case_result::compare_result;
use bls::hash_on_g2;
use serde_derive::Deserialize;
use types::EthSpec;
#[derive(Debug, Clone, Deserialize)]
pub struct BlsG2UncompressedInput {
pub message: String,
pub domain: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct BlsG2Uncompressed {
pub input: BlsG2UncompressedInput,
pub output: Vec<Vec<String>>,
}
impl YamlDecode for BlsG2Uncompressed {
fn yaml_decode(yaml: &String) -> Result<Self, Error> {
Ok(serde_yaml::from_str(&yaml.as_str()).unwrap())
}
}
impl EfTest for Cases<BlsG2Uncompressed> {
fn test_results<E: EthSpec>(&self) -> Vec<CaseResult> {
self.test_cases
.iter()
.enumerate()
.map(|(i, tc)| {
let result = compressed_hash(&tc.input.message, &tc.input.domain, &tc.output);
CaseResult::new(i, tc, result)
})
.collect()
}
}
/// Execute a `compressed hash to g2` test case.
fn compressed_hash(
message: &String,
domain: &String,
output: &Vec<Vec<String>>,
) -> Result<(), Error> {
// Convert message and domain to required types
let msg =
hex::decode(&message[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
let d = hex::decode(&domain[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
let d = bytes_to_u64(&d);
// Calculate the point and convert it to compressed bytes
let point = hash_on_g2(&msg, d);
let mut point_bytes = [0 as u8; 288];
point.getpx().geta().tobytearray(&mut point_bytes, 0);
point.getpx().getb().tobytearray(&mut point_bytes, 48);
point.getpy().geta().tobytearray(&mut point_bytes, 96);
point.getpy().getb().tobytearray(&mut point_bytes, 144);
point.getpz().geta().tobytearray(&mut point_bytes, 192);
point.getpz().getb().tobytearray(&mut point_bytes, 240);
// Convert the output to one set of bytes (x.a, x.b, y.a, y.b, z.a, z.b)
let mut decoded: Vec<u8> = vec![];
for coordinate in output {
let mut decoded_part = hex::decode(&coordinate[0][2..])
.map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
decoded.append(&mut decoded_part);
decoded_part = hex::decode(&coordinate[1][2..])
.map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
decoded.append(&mut decoded_part);
}
compare_result::<Vec<u8>, Vec<u8>>(&Ok(point_bytes.to_vec()), &Some(decoded))
}
// Converts a vector to u64 (from big endian)
fn bytes_to_u64(array: &Vec<u8>) -> u64 {
let mut result: u64 = 0;
for (i, value) in array.iter().rev().enumerate() {
if i == 8 {
break;
}
result += u64::pow(2, i as u32 * 8) * (*value as u64);
}
result
}

View File

@ -0,0 +1,53 @@
use super::*;
use crate::case_result::compare_result;
use bls::{PublicKey, SecretKey};
use serde_derive::Deserialize;
use types::EthSpec;
#[derive(Debug, Clone, Deserialize)]
pub struct BlsPrivToPub {
pub input: String,
pub output: String,
}
impl YamlDecode for BlsPrivToPub {
fn yaml_decode(yaml: &String) -> Result<Self, Error> {
Ok(serde_yaml::from_str(&yaml.as_str()).unwrap())
}
}
impl EfTest for Cases<BlsPrivToPub> {
fn test_results<E: EthSpec>(&self) -> Vec<CaseResult> {
self.test_cases
.iter()
.enumerate()
.map(|(i, tc)| {
let result = secret_to_public(&tc.input, &tc.output);
CaseResult::new(i, tc, result)
})
.collect()
}
}
/// Execute a `Private key to public key` test case.
fn secret_to_public(secret: &String, output: &String) -> Result<(), Error> {
// Convert message and domain to required types
let mut sk =
hex::decode(&secret[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
pad_to_48(&mut sk);
let sk = SecretKey::from_bytes(&sk).unwrap();
let pk = PublicKey::from_secret_key(&sk);
let decoded =
hex::decode(&output[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
compare_result::<Vec<u8>, Vec<u8>>(&Ok(pk.as_raw().as_bytes()), &Some(decoded))
}
// Increase the size of an array to 48 bytes
fn pad_to_48(array: &mut Vec<u8>) {
while array.len() < 48 {
array.insert(0, 0);
}
}

View File

@ -0,0 +1,88 @@
use super::*;
use crate::case_result::compare_result;
use bls::{SecretKey, Signature};
use serde_derive::Deserialize;
use types::EthSpec;
#[derive(Debug, Clone, Deserialize)]
pub struct BlsSignInput {
pub privkey: String,
pub message: String,
pub domain: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct BlsSign {
pub input: BlsSignInput,
pub output: String,
}
impl YamlDecode for BlsSign {
fn yaml_decode(yaml: &String) -> Result<Self, Error> {
Ok(serde_yaml::from_str(&yaml.as_str()).unwrap())
}
}
impl EfTest for Cases<BlsSign> {
fn test_results<E: EthSpec>(&self) -> Vec<CaseResult> {
self.test_cases
.iter()
.enumerate()
.map(|(i, tc)| {
let result = sign_msg(
&tc.input.privkey,
&tc.input.message,
&tc.input.domain,
&tc.output,
);
CaseResult::new(i, tc, result)
})
.collect()
}
}
/// Execute a `compressed hash to g2` test case.
fn sign_msg(
private_key: &String,
message: &String,
domain: &String,
output: &String,
) -> Result<(), Error> {
// Convert private_key, message and domain to required types
let mut sk =
hex::decode(&private_key[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
pad_to_48(&mut sk);
let sk = SecretKey::from_bytes(&sk).unwrap();
let msg =
hex::decode(&message[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
let d = hex::decode(&domain[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
let d = bytes_to_u64(&d);
let signature = Signature::new(&msg, d, &sk);
// Convert the output to one set of bytes
let decoded =
hex::decode(&output[2..]).map_err(|e| Error::FailedToParseTest(format!("{:?}", e)))?;
compare_result::<Vec<u8>, Vec<u8>>(&Ok(signature.as_bytes()), &Some(decoded))
}
// Converts a vector to u64 (from big endian)
fn bytes_to_u64(array: &Vec<u8>) -> u64 {
let mut result: u64 = 0;
for (i, value) in array.iter().rev().enumerate() {
if i == 8 {
break;
}
result += u64::pow(2, i as u32 * 8) * (*value as u64);
}
result
}
// Increase the size of an array to 48 bytes
fn pad_to_48(array: &mut Vec<u8>) {
while array.len() < 48 {
array.insert(0, 0);
}
}

View File

@ -35,9 +35,22 @@ impl Doc {
("ssz", "uint", _) => run_test::<SszGeneric, MainnetEthSpec>(&self.yaml), ("ssz", "uint", _) => run_test::<SszGeneric, MainnetEthSpec>(&self.yaml),
("ssz", "static", "minimal") => run_test::<SszStatic, MinimalEthSpec>(&self.yaml), ("ssz", "static", "minimal") => run_test::<SszStatic, MinimalEthSpec>(&self.yaml),
("ssz", "static", "mainnet") => run_test::<SszStatic, MainnetEthSpec>(&self.yaml), ("ssz", "static", "mainnet") => run_test::<SszStatic, MainnetEthSpec>(&self.yaml),
("bls", "aggregate_pubkeys", "mainnet") => run_test::<BlsAggregatePubkeys, MainnetEthSpec>(&self.yaml), ("bls", "aggregate_pubkeys", "mainnet") => {
("bls", "aggregate_sigs", "mainnet") => run_test::<BlsAggregateSigs, MainnetEthSpec>(&self.yaml), run_test::<BlsAggregatePubkeys, MainnetEthSpec>(&self.yaml)
}
("bls", "aggregate_sigs", "mainnet") => {
run_test::<BlsAggregateSigs, MainnetEthSpec>(&self.yaml)
}
("bls", "msg_hash_compressed", "mainnet") => {
run_test::<BlsG2Compressed, MainnetEthSpec>(&self.yaml)
}
("bls", "msg_hash_uncompressed", "mainnet") => {
run_test::<BlsG2Uncompressed, MainnetEthSpec>(&self.yaml)
}
("bls", "priv_to_pub", "mainnet") => {
run_test::<BlsPrivToPub, MainnetEthSpec>(&self.yaml)
}
("bls", "sign_msg", "mainnet") => run_test::<BlsSign, MainnetEthSpec>(&self.yaml),
(runner, handler, config) => panic!( (runner, handler, config) => panic!(
"No implementation for runner: \"{}\", handler: \"{}\", config: \"{}\"", "No implementation for runner: \"{}\", handler: \"{}\", config: \"{}\"",
runner, handler, config runner, handler, config

View File

@ -26,7 +26,6 @@ fn yaml_files_in_test_dir(dir: &str) -> Vec<PathBuf> {
.collect() .collect()
} }
/*
#[test] #[test]
fn ssz_generic() { fn ssz_generic() {
yaml_files_in_test_dir("ssz_generic") yaml_files_in_test_dir("ssz_generic")
@ -44,7 +43,6 @@ fn ssz_static() {
Doc::assert_tests_pass(file); Doc::assert_tests_pass(file);
}); });
} }
*/
#[test] #[test]
fn bls() { fn bls() {