Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Andrew testing correct syed pop #10

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
19 changes: 17 additions & 2 deletions Cargo.lock

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

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,8 @@ members = [
"substrate/primitives/crypto/ec-utils",
"substrate/primitives/crypto/hashing",
"substrate/primitives/crypto/hashing/proc-macro",
"substrate/primitives/crypto/pubkeycrypto",
"substrate/primitives/crypto/pubkeycrypto/proc-macro",
"substrate/primitives/database",
"substrate/primitives/debug-derive",
"substrate/primitives/externalities",
Expand Down Expand Up @@ -1259,6 +1261,8 @@ sp-consensus-slots = { path = "substrate/primitives/consensus/slots", default-fe
sp-core = { path = "substrate/primitives/core", default-features = false }
sp-core-hashing = { default-features = false, path = "substrate/deprecated/hashing" }
sp-core-hashing-proc-macro = { default-features = false, path = "substrate/deprecated/hashing/proc-macro" }
sp-crypto-pubkeycrypto = {default-features = false, path = "substrate/primitives/crypto/pubkeycrypto"}
sp-crypto-pubkeycrypto-proc-macro = {default-features = false, path = "substrate/primitives/crypto/pubkeycrypto/proc-macro"}
sp-crypto-ec-utils = { default-features = false, path = "substrate/primitives/crypto/ec-utils" }
sp-crypto-hashing = { path = "substrate/primitives/crypto/hashing", default-features = false }
sp-crypto-hashing-proc-macro = { path = "substrate/primitives/crypto/hashing/proc-macro", default-features = false }
Expand Down Expand Up @@ -1369,7 +1373,7 @@ twox-hash = { version = "1.6.3", default-features = false }
unsigned-varint = { version = "0.7.2" }
url = { version = "2.4.0" }
void = { version = "1.0.2" }
w3f-bls = { version = "0.1.3", default-features = false }
w3f-bls = { version = "0.1.8", default-features = false }
wait-timeout = { version = "0.2" }
walkdir = { version = "2.5.0" }
wasm-instrument = { version = "0.4", default-features = false }
Expand Down
2 changes: 2 additions & 0 deletions substrate/primitives/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ secp256k1 = { features = [

# bls crypto
w3f-bls = { optional = true, workspace = true }
sha2 = { workspace = true }

# bandersnatch crypto
bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", rev = "0fef826", default-features = false, features = [
"substrate-curves",
Expand Down
15 changes: 13 additions & 2 deletions substrate/primitives/core/src/bandersnatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@
use crate::crypto::VrfSecret;
use crate::crypto::{
ByteArray, CryptoType, CryptoTypeId, DeriveError, DeriveJunction, Pair as TraitPair,
PublicBytes, SecretStringError, SignatureBytes, UncheckedFrom, VrfPublic,
ProofOfPossessionGenerator, ProofOfPossessionVerifier, PublicBytes, SecretStringError,
SignatureBytes, UncheckedFrom, VrfPublic,
};
use sp_crypto_pubkeycrypto_proc_macro::ProofOfPossession;

use bandersnatch_vrfs::{CanonicalSerialize, SecretKey};
use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};
Expand Down Expand Up @@ -75,7 +77,7 @@ impl CryptoType for Signature {
type Seed = [u8; SEED_SERIALIZED_SIZE];

/// Bandersnatch secret key.
#[derive(Clone)]
#[derive(Clone, ProofOfPossession)]
pub struct Pair {
secret: SecretKey,
seed: Seed,
Expand Down Expand Up @@ -1087,4 +1089,13 @@ mod tests {

assert_eq!(enc1, enc2);
}

#[test]
fn good_proof_of_possession_should_work_bad_pop_should_fail() {
let mut pair = Pair::from_seed(b"12345678901234567890123456789012");
let other_pair = Pair::from_seed(b"23456789012345678901234567890123");
let pop = pair.generate_proof_of_possession();
assert!(Pair::verify_proof_of_possession(&pop, &pair.public()));
assert_eq!(Pair::verify_proof_of_possession(&pop, &other_pair.public()), false);
}
}
117 changes: 108 additions & 9 deletions substrate/primitives/core/src/bls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,22 @@
//! curve.

use crate::crypto::{
CryptoType, DeriveError, DeriveJunction, Pair as TraitPair, PublicBytes, SecretStringError,
SignatureBytes, UncheckedFrom,
CryptoType, DeriveError, DeriveJunction, Pair as TraitPair, ProofOfPossessionGenerator,
ProofOfPossessionVerifier, PublicBytes, SecretStringError, SignatureBytes, UncheckedFrom,
};

use alloc::vec::Vec;

use w3f_bls::{
DoublePublicKey, DoublePublicKeyScheme, DoubleSignature, EngineBLS, Keypair, Message,
SecretKey, SerializableToBytes, TinyBLS381,
NuggetBLSnCPPoP, ProofOfPossession as BlsProofOfPossession,
ProofOfPossessionGenerator as BlsProofOfPossessionGenerator, SecretKey, SerializableToBytes,
TinyBLS381,
};

/// Required to generate PoP
use sha2::Sha256;

/// BLS-377 specialized types
pub mod bls377 {
pub use super::{PUBLIC_KEY_SERIALIZED_SIZE, SIGNATURE_SERIALIZED_SIZE};
Expand Down Expand Up @@ -99,6 +104,10 @@ pub const PUBLIC_KEY_SERIALIZED_SIZE: usize =
pub const SIGNATURE_SERIALIZED_SIZE: usize =
<DoubleSignature<TinyBLS381> as SerializableToBytes>::SERIALIZED_BYTES_SIZE;

/// Signature serialized size
pub const POP_SERIALIZED_SIZE: usize =
<NuggetBLSnCPPoP<TinyBLS381> as SerializableToBytes>::SERIALIZED_BYTES_SIZE;

/// A secret seed.
///
/// It's not called a "secret key" because ring doesn't expose the secret keys
Expand Down Expand Up @@ -227,6 +236,48 @@ impl<T: BlsBound> TraitPair for Pair<T> {
}
}

impl<T: BlsBound> ProofOfPossessionGenerator for Pair<T> {
fn generate_proof_of_possession(&mut self) -> Self::Signature {
let r: [u8; SIGNATURE_SERIALIZED_SIZE] = <Keypair<T> as BlsProofOfPossessionGenerator<
T,
Sha256,
DoublePublicKey<T>,
NuggetBLSnCPPoP<T>,
>>::generate_pok(&mut self.0)
.to_bytes()
.try_into()
.expect("NuggetBLSnCPPoP serializer returns vectors of SIGNATURE_SERIALIZED_SIZE size");
Self::Signature::unchecked_from(r)
}
}

impl<T: BlsBound> ProofOfPossessionVerifier for Pair<T>
where
Pair<T>: TraitPair,
{
fn verify_proof_of_possession(
proof_of_possession: &Self::Signature,
allegedly_possessed_pubkey: &Self::Public,
) -> bool {
let proof_of_possession =
match NuggetBLSnCPPoP::<T>::from_bytes(proof_of_possession.as_ref()) {
Ok(s) => s,
Err(_) => return false,
};

let allegedly_possessed_pubkey_as_bls_pubkey =
match DoublePublicKey::<T>::from_bytes(allegedly_possessed_pubkey.as_ref()) {
Ok(pk) => pk,
Err(_) => return false,
};

BlsProofOfPossession::<T, Sha256, _>::verify(
&proof_of_possession,
&allegedly_possessed_pubkey_as_bls_pubkey,
)
}
}

impl<T: BlsBound> CryptoType for Pair<T> {
type Pair = Pair<T>;
}
Expand Down Expand Up @@ -301,8 +352,6 @@ mod tests {
hex_expected_signature: &str,
) {
let public = pair.public();
let public_bytes: &[u8] = public.as_ref();
println!("pub key is: {:?}", array_bytes::bytes2hex("", public_bytes));
assert_eq!(
public,
Public::unchecked_from(array_bytes::hex2array_unchecked(hex_expected_pub_key))
Expand All @@ -312,6 +361,7 @@ mod tests {

let expected_signature = Signature::unchecked_from(expected_signature_bytes);
let signature = pair.sign(&message[..]);

assert!(signature == expected_signature);
assert!(Pair::verify(&signature, &message[..], &public));
}
Expand All @@ -323,7 +373,7 @@ mod tests {
));
test_vector_should_work(pair,
"7a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400",
"d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b"
"124571b4bf23083b5d07e720fde0a984d4d592868156ece77487e97a1ba4b29397dbdc454f13e3aed1ad4b6a99af2501c68ab88ec0495f962a4f55c7c460275a8d356cfa344c27778ca4c641bd9a3604ce5c28f9ed566e1d29bf3b5d3591e46ae28be3ece035e8e4db53a40fc5826002"
)
}

Expand All @@ -334,7 +384,7 @@ mod tests {
));
test_vector_should_work(pair,
"88ff6c3a32542bc85f2adf1c490a929b7fcee50faeb95af9a036349390e9b3ea7326247c4fc4ebf88050688fd6265de0806284eec09ba0949f5df05dc93a787a14509749f36e4a0981bb748d953435483740907bb5c2fe8ffd97e8509e1a038b05fb08488db628ea0638b8d48c3ddf62ed437edd8b23d5989d6c65820fc70f80fb39b486a3766813e021124aec29a566",
"8c29473f44ac4f0a8ac4dc8c8da09adf9d2faa2dbe0cfdce3ce7c920714196a1b7bf48dc05048e453c161ebc2db9f44fae060b3be77e14e66d1a5262f14d3da0c3a18e650018761a7402b31abc7dd803d466bdcb71bc28c77eb73c610cbff53c00130b79116831e520a04a8ef6630e6f"
"8f4fe16cbb1b7f26ddbfbcde864a3c2f68802fbca5bd59920a135ed7e0f74cd9ba160e61c85e9acee3b4fe277862f226e60ac1958b57ed4487daf4673af420e8bf036ee8169190a927ede2e8eb3d6600633c69b2a84eb017473988fdfde082e150cbef05b77018c1f8ccc06da9e80421"
)
}

Expand All @@ -347,7 +397,7 @@ mod tests {
.unwrap();
test_vector_should_work(pair,
"7a84ca8ce4c37c93c95ecee6a3c0c9a7b9c225093cf2f12dc4f69cbfb847ef9424a18f5755d5a742247d386ff2aabb806bcf160eff31293ea9616976628f77266c8a8cc1d8753be04197bd6cdd8c5c87a148f782c4c1568d599b48833fd539001e580cff64bbc71850605433fcd051f3afc3b74819786f815ffb5272030a8d03e5df61e6183f8fd8ea85f26defa83400",
"d1e3013161991e142d8751017d4996209c2ff8a9ee160f373733eda3b4b785ba6edce9f45f87104bbe07aa6aa6eb2780aa705efb2c13d3b317d6409d159d23bdc7cdd5c2a832d1551cf49d811d49c901495e527dbd532e3a462335ce2686009104aba7bc11c5b22be78f3198d2727a0b"
"124571b4bf23083b5d07e720fde0a984d4d592868156ece77487e97a1ba4b29397dbdc454f13e3aed1ad4b6a99af2501c68ab88ec0495f962a4f55c7c460275a8d356cfa344c27778ca4c641bd9a3604ce5c28f9ed566e1d29bf3b5d3591e46ae28be3ece035e8e4db53a40fc5826002"
)
}

Expand All @@ -360,7 +410,7 @@ mod tests {
.unwrap();
test_vector_should_work(pair,
"88ff6c3a32542bc85f2adf1c490a929b7fcee50faeb95af9a036349390e9b3ea7326247c4fc4ebf88050688fd6265de0806284eec09ba0949f5df05dc93a787a14509749f36e4a0981bb748d953435483740907bb5c2fe8ffd97e8509e1a038b05fb08488db628ea0638b8d48c3ddf62ed437edd8b23d5989d6c65820fc70f80fb39b486a3766813e021124aec29a566",
"8c29473f44ac4f0a8ac4dc8c8da09adf9d2faa2dbe0cfdce3ce7c920714196a1b7bf48dc05048e453c161ebc2db9f44fae060b3be77e14e66d1a5262f14d3da0c3a18e650018761a7402b31abc7dd803d466bdcb71bc28c77eb73c610cbff53c00130b79116831e520a04a8ef6630e6f"
"8f4fe16cbb1b7f26ddbfbcde864a3c2f68802fbca5bd59920a135ed7e0f74cd9ba160e61c85e9acee3b4fe277862f226e60ac1958b57ed4487daf4673af420e8bf036ee8169190a927ede2e8eb3d6600633c69b2a84eb017473988fdfde082e150cbef05b77018c1f8ccc06da9e80421"
)
}

Expand Down Expand Up @@ -524,6 +574,7 @@ mod tests {
fn signature_serialization_works_for_bls381() {
signature_serialization_works::<bls381::BlsEngine>();
}

fn signature_serialization_doesnt_panic<E: BlsBound>() {
fn deserialize_signature<E: BlsBound>(
text: &str,
Expand All @@ -544,4 +595,52 @@ mod tests {
fn signature_serialization_doesnt_panic_for_bls381() {
signature_serialization_doesnt_panic::<bls381::BlsEngine>();
}

fn must_generate_proof_of_possession<E: BlsBound>() {
let mut pair = Pair::<E>::from_seed(b"12345678901234567890123456789012");
pair.generate_proof_of_possession();
}

#[test]
fn must_generate_proof_of_possession_for_bls377() {
must_generate_proof_of_possession::<bls377::BlsEngine>();
}

#[test]
fn must_generate_proof_of_possession_for_bls381() {
must_generate_proof_of_possession::<bls381::BlsEngine>();
}

fn good_proof_of_possession_must_verify<E: BlsBound>() {
let mut pair = Pair::<E>::from_seed(b"12345678901234567890123456789012");
let pop = pair.generate_proof_of_possession();
assert!(Pair::<E>::verify_proof_of_possession(&pop, &pair.public()));
}

#[test]
fn good_proof_of_possession_must_verify_for_bls377() {
good_proof_of_possession_must_verify::<bls377::BlsEngine>();
}

#[test]
fn good_proof_of_possession_must_verify_for_bls381() {
good_proof_of_possession_must_verify::<bls381::BlsEngine>();
}

fn proof_of_possession_must_fail_if_prover_does_not_possess_secret_key<E: BlsBound>() {
let mut pair = Pair::<E>::from_seed(b"12345678901234567890123456789012");
let other_pair = Pair::<E>::from_seed(b"23456789012345678901234567890123");
let pop = pair.generate_proof_of_possession();
assert_eq!(Pair::<E>::verify_proof_of_possession(&pop, &other_pair.public()), false);
}

#[test]
fn proof_of_possession_must_fail_if_prover_does_not_possess_secret_key_for_bls377() {
proof_of_possession_must_fail_if_prover_does_not_possess_secret_key::<bls377::BlsEngine>();
}

#[test]
fn proof_of_possession_must_fail_if_prover_does_not_possess_secret_key_for_bls381() {
proof_of_possession_must_fail_if_prover_does_not_possess_secret_key::<bls381::BlsEngine>();
}
}
48 changes: 48 additions & 0 deletions substrate/primitives/core/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -971,6 +971,54 @@ pub trait Pair: CryptoType + Sized {
fn to_raw_vec(&self) -> Vec<u8>;
}

/// Pair which is able to generate proof of possession. This is implemented
/// in different trait to provide default behavoir
pub trait ProofOfPossessionGenerator: Pair
where
Self::Public: CryptoType,
{
/// The proof of possession generator is supposed to
/// to produce a "signature" with unique hash context that should
/// never be used in other signatures. This proves that
/// that the secret key is known to the prover. While prevent
/// malicious actors to trick an honest party to sign their
/// public key to mount a rogue key attack (See: Section 4.3 of
/// - Ristenpart, T., & Yilek, S. (2007). The power of proofs-of-possession: Securing multiparty
/// signatures against rogue-key attacks. In , Annual {{International Conference}} on the
/// {{Theory}} and {{Applications}} of {{Cryptographic Techniques} (pp. 228–245). : Springer.
fn generate_proof_of_possession(&mut self) -> Self::Signature {
let pub_key_as_bytes = self.public().to_raw_vec();
let pop_context_tag: &[u8] = b"POP_";
let pop_statement = [pop_context_tag, pub_key_as_bytes.as_slice()].concat();
self.sign(pop_statement.as_slice())
}
}

///The context which attached to pop message to attest its purpose
const POP_CONTEXT_TAG: &[u8; 4] = b"POP_";

/// Pair which is able to generate proof of possession. While you don't need a keypair
/// to verify a proof of possession (you only need a public key) we constrain on Pair
/// to use the Public and Signature types associated to Pair. This is implemented
/// in different trait (than Public Key) to provide default behavoir
pub trait ProofOfPossessionVerifier: Pair
where
Self::Public: CryptoType,
{
/// The proof of possession verifier is supposed to
/// to verify a signature with unique hash context that is
/// produced solely for this reason. This proves that
/// that the secret key is known to the prover.
fn verify_proof_of_possession(
proof_of_possession: &Self::Signature,
allegedly_possessesd_pubkey: &Self::Public,
) -> bool {
let pub_key_as_bytes = allegedly_possessesd_pubkey.to_raw_vec();
let pop_statement = [POP_CONTEXT_TAG, pub_key_as_bytes.as_slice()].concat();
Self::verify(&proof_of_possession, pop_statement, allegedly_possessesd_pubkey)
}
}

/// One type is wrapped by another.
pub trait IsWrappedBy<Outer>: From<Outer> + Into<Outer> {
/// Get a reference to the inner from the outer.
Expand Down
Loading
Loading