mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-08 01:05:47 +00:00
Directory Restructure (#1163)
* Move tests -> testing * Directory restructure * Update Cargo.toml during restructure * Update Makefile during restructure * Fix arbitrary path
This commit is contained in:
20
common/eth2_interop_keypairs/Cargo.toml
Normal file
20
common/eth2_interop_keypairs/Cargo.toml
Normal file
@@ -0,0 +1,20 @@
|
||||
[package]
|
||||
name = "eth2_interop_keypairs"
|
||||
version = "0.2.0"
|
||||
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
lazy_static = "1.4.0"
|
||||
num-bigint = "0.2.6"
|
||||
eth2_hashing = "0.1.0"
|
||||
hex = "0.4.2"
|
||||
milagro_bls = { git = "https://github.com/sigp/milagro_bls", tag = "v1.0.1" }
|
||||
serde_yaml = "0.8.11"
|
||||
serde = "1.0.110"
|
||||
serde_derive = "1.0.110"
|
||||
|
||||
[dev-dependencies]
|
||||
base64 = "0.12.1"
|
||||
20
common/eth2_interop_keypairs/specs/keygen_10_validators.yaml
Normal file
20
common/eth2_interop_keypairs/specs/keygen_10_validators.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
- {privkey: '0x25295f0d1d592a90b333e26e85149708208e9f8e8bc18f6c77bd62f8ad7a6866',
|
||||
pubkey: '0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c'}
|
||||
- {privkey: '0x51d0b65185db6989ab0b560d6deed19c7ead0e24b9b6372cbecb1f26bdfad000',
|
||||
pubkey: '0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b'}
|
||||
- {privkey: '0x315ed405fafe339603932eebe8dbfd650ce5dafa561f6928664c75db85f97857',
|
||||
pubkey: '0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b'}
|
||||
- {privkey: '0x25b1166a43c109cb330af8945d364722757c65ed2bfed5444b5a2f057f82d391',
|
||||
pubkey: '0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e'}
|
||||
- {privkey: '0x3f5615898238c4c4f906b507ee917e9ea1bb69b93f1dbd11a34d229c3b06784b',
|
||||
pubkey: '0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e'}
|
||||
- {privkey: '0x055794614bc85ed5436c1f5cab586aab6ca84835788621091f4f3b813761e7a8',
|
||||
pubkey: '0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34'}
|
||||
- {privkey: '0x1023c68852075965e0f7352dee3f76a84a83e7582c181c10179936c6d6348893',
|
||||
pubkey: '0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373'}
|
||||
- {privkey: '0x3a941600dc41e5d20e818473b817a28507c23cdfdb4b659c15461ee5c71e41f5',
|
||||
pubkey: '0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac'}
|
||||
- {privkey: '0x066e3bdc0415530e5c7fed6382d5c822c192b620203cf669903e1810a8c67d06',
|
||||
pubkey: '0xa6d310dbbfab9a22450f59993f87a4ce5db6223f3b5f1f30d2c4ec718922d400e0b3c7741de8e59960f72411a0ee10a7'}
|
||||
- {privkey: '0x2b3b88a041168a1c4cd04bdd8de7964fd35238f95442dc678514f9dadb81ec34',
|
||||
pubkey: '0x9893413c00283a3f9ed9fd9845dda1cea38228d22567f9541dccc357e54a2d6a6e204103c92564cbc05f4905ac7c493a'}
|
||||
133
common/eth2_interop_keypairs/src/lib.rs
Normal file
133
common/eth2_interop_keypairs/src/lib.rs
Normal file
@@ -0,0 +1,133 @@
|
||||
//! Produces the "deterministic" validator private keys used for inter-operability testing for
|
||||
//! Ethereum 2.0 clients.
|
||||
//!
|
||||
//! Each private key is the sha2 hash of the validator index (little-endian, padded to 32 bytes),
|
||||
//! modulo the BLS-381 curve order.
|
||||
//!
|
||||
//! Keys generated here are **not secret** and are **not for production use**. It is trivial to
|
||||
//! know the secret key for any validator.
|
||||
//!
|
||||
//!## Reference
|
||||
//!
|
||||
//! Reference implementation:
|
||||
//!
|
||||
//! https://github.com/ethereum/eth2.0-pm/blob/6e41fcf383ebeb5125938850d8e9b4e9888389b4/interop/mocked_start/keygen.py
|
||||
//!
|
||||
//!
|
||||
//! This implementation passes the [reference implementation
|
||||
//! tests](https://github.com/ethereum/eth2.0-pm/blob/6e41fcf383ebeb5125938850d8e9b4e9888389b4/interop/mocked_start/keygen_test_vector.yaml).
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
use eth2_hashing::hash;
|
||||
use milagro_bls::{Keypair, PublicKey, SecretKey};
|
||||
use num_bigint::BigUint;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::convert::TryInto;
|
||||
use std::fs::File;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub const PRIVATE_KEY_BYTES: usize = 32;
|
||||
pub const PUBLIC_KEY_BYTES: usize = 48;
|
||||
pub const HASH_BYTES: usize = 32;
|
||||
|
||||
lazy_static! {
|
||||
static ref CURVE_ORDER: BigUint =
|
||||
"52435875175126190479447740508185965837690552500527637822603658699938581184513"
|
||||
.parse::<BigUint>()
|
||||
.expect("Curve order should be valid");
|
||||
}
|
||||
|
||||
/// Return a G1 point for the given `validator_index`, encoded as a compressed point in
|
||||
/// big-endian byte-ordering.
|
||||
pub fn be_private_key(validator_index: usize) -> [u8; PRIVATE_KEY_BYTES] {
|
||||
let preimage = {
|
||||
let mut bytes = [0; HASH_BYTES];
|
||||
let index = validator_index.to_le_bytes();
|
||||
bytes[0..index.len()].copy_from_slice(&index);
|
||||
bytes
|
||||
};
|
||||
|
||||
let privkey = BigUint::from_bytes_le(&hash(&preimage)) % &*CURVE_ORDER;
|
||||
|
||||
let mut bytes = [0; PRIVATE_KEY_BYTES];
|
||||
let privkey_bytes = privkey.to_bytes_be();
|
||||
bytes[PRIVATE_KEY_BYTES - privkey_bytes.len()..].copy_from_slice(&privkey_bytes);
|
||||
bytes
|
||||
}
|
||||
|
||||
/// Return a public and private keypair for a given `validator_index`.
|
||||
pub fn keypair(validator_index: usize) -> Keypair {
|
||||
let sk = SecretKey::from_bytes(&be_private_key(validator_index)).unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"Should build valid private key for validator index {}",
|
||||
validator_index
|
||||
)
|
||||
});
|
||||
|
||||
Keypair {
|
||||
pk: PublicKey::from_secret_key(&sk),
|
||||
sk,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct YamlKeypair {
|
||||
/// Big-endian.
|
||||
privkey: String,
|
||||
/// Big-endian.
|
||||
pubkey: String,
|
||||
}
|
||||
|
||||
impl TryInto<Keypair> for YamlKeypair {
|
||||
type Error = String;
|
||||
|
||||
fn try_into(self) -> Result<Keypair, Self::Error> {
|
||||
let privkey = string_to_bytes(&self.privkey)?;
|
||||
let pubkey = string_to_bytes(&self.pubkey)?;
|
||||
|
||||
if (privkey.len() > PRIVATE_KEY_BYTES) || (pubkey.len() > PUBLIC_KEY_BYTES) {
|
||||
return Err("Public or private key is too long".into());
|
||||
}
|
||||
|
||||
let sk = {
|
||||
let mut bytes = vec![0; PRIVATE_KEY_BYTES - privkey.len()];
|
||||
bytes.extend_from_slice(&privkey);
|
||||
SecretKey::from_bytes(&bytes)
|
||||
.map_err(|e| format!("Failed to decode bytes into secret key: {:?}", e))?
|
||||
};
|
||||
|
||||
let pk = {
|
||||
let mut bytes = vec![0; PUBLIC_KEY_BYTES - pubkey.len()];
|
||||
bytes.extend_from_slice(&pubkey);
|
||||
PublicKey::from_bytes(&bytes)
|
||||
.map_err(|e| format!("Failed to decode bytes into public key: {:?}", e))?
|
||||
};
|
||||
|
||||
Ok(Keypair { pk, sk })
|
||||
}
|
||||
}
|
||||
|
||||
fn string_to_bytes(string: &str) -> Result<Vec<u8>, String> {
|
||||
let string = if string.starts_with("0x") {
|
||||
&string[2..]
|
||||
} else {
|
||||
string
|
||||
};
|
||||
|
||||
hex::decode(string).map_err(|e| format!("Unable to decode public or private key: {}", e))
|
||||
}
|
||||
|
||||
/// Loads keypairs from a YAML encoded file.
|
||||
///
|
||||
/// Uses this as reference:
|
||||
/// https://github.com/ethereum/eth2.0-pm/blob/9a9dbcd95e2b8e10287797bd768014ab3d842e99/interop/mocked_start/keygen_10_validators.yaml
|
||||
pub fn keypairs_from_yaml_file(path: PathBuf) -> Result<Vec<Keypair>, String> {
|
||||
let file = File::open(path).map_err(|e| format!("Unable to open YAML key file: {}", e))?;
|
||||
|
||||
serde_yaml::from_reader::<_, Vec<YamlKeypair>>(file)
|
||||
.map_err(|e| format!("Could not parse YAML: {:?}", e))?
|
||||
.into_iter()
|
||||
.map(TryInto::try_into)
|
||||
.collect::<Result<Vec<_>, String>>()
|
||||
}
|
||||
23
common/eth2_interop_keypairs/tests/from_file.rs
Normal file
23
common/eth2_interop_keypairs/tests/from_file.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
#![cfg(test)]
|
||||
use eth2_interop_keypairs::{keypair as reference_keypair, keypairs_from_yaml_file};
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn yaml_path() -> PathBuf {
|
||||
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("specs")
|
||||
.join("keygen_10_validators.yaml")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_from_yaml() {
|
||||
let keypairs = keypairs_from_yaml_file(yaml_path()).expect("should read keypairs from file");
|
||||
|
||||
keypairs.into_iter().enumerate().for_each(|(i, keypair)| {
|
||||
assert_eq!(
|
||||
keypair,
|
||||
reference_keypair(i),
|
||||
"Decoded key {} does not match generated key",
|
||||
i
|
||||
)
|
||||
});
|
||||
}
|
||||
58
common/eth2_interop_keypairs/tests/generation.rs
Normal file
58
common/eth2_interop_keypairs/tests/generation.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
#![cfg(test)]
|
||||
use eth2_interop_keypairs::{be_private_key, keypair};
|
||||
use num_bigint::BigUint;
|
||||
|
||||
#[test]
|
||||
fn reference_private_keys() {
|
||||
// Sourced from:
|
||||
//
|
||||
// https://github.com/ethereum/eth2.0-pm/blob/6e41fcf383ebeb5125938850d8e9b4e9888389b4/interop/mocked_start/keygen_test_vector.yaml
|
||||
let reference = [
|
||||
"16808672146709759238327133555736750089977066230599028589193936481731504400486",
|
||||
"37006103240406073079686739739280712467525465637222501547219594975923976982528",
|
||||
"22330876536127119444572216874798222843352868708084730796787004036811744442455",
|
||||
"17048462031355941381150076874414096388968985457797372268770826099852902060945",
|
||||
"28647806952216650698330424381872693846361470773871570637461872359310549743691",
|
||||
"2416304019107052589452838695606585506736351107897780798170812672519914514344",
|
||||
"7300215445567548136411883691093515822872548648751398235557229381530420545683",
|
||||
"26495790445032093722332687600112008700915252495659977774957922313678954054133",
|
||||
"2908643403277969554503670470854573663206729491025062456164283925661321952518",
|
||||
"19554639423851580804889717218680781396599791537051606512605582393920758869044",
|
||||
];
|
||||
reference.iter().enumerate().for_each(|(i, reference)| {
|
||||
let bytes = be_private_key(i);
|
||||
let num = BigUint::from_bytes_be(&bytes);
|
||||
assert_eq!(&num.to_str_radix(10), reference)
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reference_public_keys() {
|
||||
// Sourced from:
|
||||
//
|
||||
// https://github.com/ethereum/eth2.0-pm/blob/6e41fcf383ebeb5125938850d8e9b4e9888389b4/interop/mocked_start/keygen_test_vector.yaml
|
||||
let reference = [
|
||||
"qZp27XeW974i1bfoXe63xWd+iOUR4LM3YY+MTrYTSbS/LRU/ZJ97UzWf6LlKOORM",
|
||||
"uJvrxpl2lyajGMjplxvTFxKXxhrqSmV4p6T5S1R9y6W6wWqJEItrah/jaV0ah0oL",
|
||||
"o6MrD4tN24PxoKhT2B3XJd/ld9T0w9uOzlLOKwJuyoSBXBp+jpKk3j11VzO/fkqb",
|
||||
"iMFB33fNnY16cadcgmxBqcnwPG7hsYDz54UvaigAmd7TUbWNZuZTr45CgWpNj1Mu",
|
||||
"gSg7eiDhykYOvZu9dwBdVXNwyrsfmkT1MMTExmIw9nX434tMKBiFGqfXeoDKWkpe",
|
||||
"qwvdoPhfhC9DG+rM8SUL8f17pRtBAP1kNktkAf2oW7AGmz5xW1iBloTn/AsQpyo0",
|
||||
"mXfxyLcxqNVVgUa/uGyuomQ088WHi1ib8oCkLJFZ5wDp3w5AhilsILAR0ueMJ9Nz",
|
||||
"qNTHwneVpyWWExfvWVOnAy7W2Dc524sOinI1PRuLRDlCf376LInKoDzJ8o+Muris",
|
||||
"ptMQ27+rmiJFD1mZP4ekzl22Ij87Xx8w0sTscYki1ADgs8d0HejlmWD3JBGg7hCn",
|
||||
"mJNBPAAoOj+e2f2YRd2hzqOCKNIlZ/lUHczDV+VKLWpuIEEDySVky8BfSQWsfEk6",
|
||||
];
|
||||
reference.iter().enumerate().for_each(|(i, reference)| {
|
||||
let pair = keypair(i);
|
||||
let reference = base64::decode(reference).expect("Reference should be valid base64");
|
||||
|
||||
assert_eq!(
|
||||
reference.len(),
|
||||
48,
|
||||
"Reference should be 48 bytes (public key size)"
|
||||
);
|
||||
|
||||
assert_eq!(pair.pk.as_bytes(), reference);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user