Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Changes from 1 commit
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
8c39821
Introduce bandersnatch vrf
davxy Jun 18, 2023
a9446fd
Some documentation
davxy Jun 18, 2023
bb3e022
Fix tests
davxy Jun 18, 2023
bdd3df4
Fix docs refs
davxy Jun 18, 2023
e0e493a
Some more docs
davxy Jun 19, 2023
b665397
Comments about key derivation
davxy Jun 19, 2023
1faf0e2
Make clippy happy
davxy Jun 21, 2023
2a55c7d
Merge branch 'master' into bandersnatch-vrf
davxy Jun 21, 2023
7812da8
Fix ring context enc/dec test
davxy Jun 21, 2023
dd53abc
Fix docs
davxy Jun 21, 2023
03ca535
Switch to upstream ring-vrf
davxy Jun 22, 2023
afb84c5
Use sub-domains to construct VrfInput
davxy Jun 26, 2023
b4e0279
Bandersnatch VRF experimental feature
davxy Jun 26, 2023
584e07e
Restore upstream dep
davxy Jun 29, 2023
7791d66
Fix feature flags
davxy Jun 29, 2023
13ad9ad
Merge branch 'master' into bandersnatch-vrf
davxy Jun 29, 2023
acaab76
Apply typo fix
davxy Jul 18, 2023
f22354d
Bump bandersnatch-vrfs
davxy Jul 18, 2023
62d2ed4
Weiestrass form has been selected
davxy Jul 18, 2023
759406e
Rename bandersnatch testing app crypto id
davxy Jul 18, 2023
935b87b
Merge branch 'master' into bandersnatch-vrf
davxy Jul 18, 2023
3ccdd86
Support for seed recovery
davxy Jul 22, 2023
e8a40ab
Clarified domain size <-> key size relationship
davxy Jul 25, 2023
b770f0d
Merge branch 'master' into bandersnatch-vrf
davxy Jul 25, 2023
84ad4ae
cargo fmt
davxy Jul 25, 2023
63aef58
Merge branch 'master' into bandersnatch-vrf
davxy Jul 25, 2023
ca11f8d
Trigger CI
davxy Jul 26, 2023
9d279fa
Merge branch 'master' into bandersnatch-vrf
davxy Jul 27, 2023
b27c61f
Some required tweaks to crypto types
davxy Jul 28, 2023
a5e4cd4
Remove leftovers from Cargo.toml
davxy Jul 28, 2023
7bf3c70
Remove some TODO notes
davxy Jul 28, 2023
efd39bd
Simplification of structs construction
davxy Jul 28, 2023
ad76f57
Merge branch 'master' into bandersnatch-vrf
davxy Aug 1, 2023
062b13e
Merge branch 'master' into bandersnatch-vrf
davxy Aug 2, 2023
c562181
Trigger CI
davxy Aug 2, 2023
b1f6c58
Apply review suggestion
davxy Aug 9, 2023
9342856
Docs typo
davxy Aug 9, 2023
64ec625
Merge branch 'master' into bandersnatch-vrf
davxy Aug 9, 2023
ece4016
Fix keystore tests
davxy Aug 9, 2023
3b553b6
Consistence
davxy Aug 9, 2023
c2b00b5
Add ref to git rependency
davxy Aug 9, 2023
b339b3a
Static check of MAX_VRF_IOS value
davxy Aug 9, 2023
2b2676b
Clarify behavior for out of ring keys signatures
davxy Aug 9, 2023
0739e0f
Add test for ring-vrf to the keystore
davxy Aug 9, 2023
a457359
Fix docs
davxy Aug 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Support for seed recovery
  • Loading branch information
davxy committed Jul 22, 2023
commit 3ccdd86a2973c5067b2e0c7ee4aab11b75eaff1b
69 changes: 41 additions & 28 deletions primitives/core/src/bandersnatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,18 @@ type Seed = [u8; SEED_SERIALIZED_LEN];
/// Bandersnatch secret key.
#[cfg(feature = "full_crypto")]
#[derive(Clone)]
pub struct Pair(SecretKey);
pub struct Pair {
secret: SecretKey,
seed: Seed,
}

#[cfg(feature = "full_crypto")]
impl Pair {
/// Get the key seed.
pub fn seed(&self) -> Seed {
self.seed
}
}

#[cfg(feature = "full_crypto")]
impl TraitPair for Pair {
Expand All @@ -230,10 +241,10 @@ impl TraitPair for Pair {
if seed_slice.len() != SEED_SERIALIZED_LEN {
return Err(SecretStringError::InvalidSeedLength)
}
let mut seed_raw = [0; SEED_SERIALIZED_LEN];
seed_raw.copy_from_slice(seed_slice);
let secret = SecretKey::from_seed(&seed_raw);
Ok(Pair(secret))
let mut seed = [0; SEED_SERIALIZED_LEN];
seed.copy_from_slice(seed_slice);
let secret = SecretKey::from_seed(&seed);
Ok(Pair { secret, seed })
}

/// Derive a child key from a series of given (hard) junctions.
Expand All @@ -244,24 +255,24 @@ impl TraitPair for Pair {
path: Iter,
_seed: Option<Seed>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a silly question, but why is this argument ignored? Perhaps put a comment here and/or return an error if it is Some?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tools which uses the InspectKeyCmd may end up calling (after some hopping) the from_string_with_seed which in turn will call pair.derive(junctions, seed).

With:

  • seed the seed generated from the secret phrase according to bip39.
  • Junctions are the hard/soft junctions after the phrase

Is left to the implementation what to do with the seed during the derive which has been already used to generate the pair itself.

The only implementation which uses it is sr25519 and frankly I don't know why it requires it.
But I don't find it of any usage for bandersnatch as to derive a subkey we use the junctions.

Returning an error is not an option since is called in the same way for all the possible pairs

) -> Result<(Pair, Option<Seed>), DeriveError> {
let derive_hard_junction = |secret_seed, cc| -> Seed {
("bandersnatch-vrf-HDKD", secret_seed, cc).using_encoded(sp_core_hashing::blake2_256)
let derive_hard = |seed, cc| -> Seed {
("bandersnatch-vrf-HDKD", seed, cc).using_encoded(sp_core_hashing::blake2_256)
};

// TODO @burdges : probably we need a serializable dleq_vrf::SecretKey to initialize acc
let mut acc = [0; 32];
for j in path {
match j {
DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath),
DeriveJunction::Hard(cc) => acc = derive_hard_junction(acc, cc),
let mut seed = self.seed();
for p in path {
if let DeriveJunction::Hard(cc) = p {
seed = derive_hard(seed, cc);
} else {
return Err(DeriveError::SoftKeyInPath)
}
}
Ok((Self::from_seed(&acc), Some(acc)))
Ok((Self::from_seed(&seed), Some(seed)))
}

/// Get the public key.
fn public(&self) -> Public {
let public = self.0.to_public();
let public = self.secret.to_public();
let mut raw = [0; PUBLIC_SERIALIZED_LEN];
public
.serialize_compressed(raw.as_mut_slice())
Expand All @@ -287,8 +298,7 @@ impl TraitPair for Pair {

/// Return a vector filled with seed raw data.
fn to_raw_vec(&self) -> Vec<u8> {
// TODO @burdges: for this we need a serializable dleq_vrfs::SecretKey
unimplemented!()
self.seed().to_vec()
}
}

Expand Down Expand Up @@ -323,7 +333,7 @@ pub mod vrf {
///
/// Each message tuple has the form: message_data := (sub-domain, data).
pub fn new(domain: &'static [u8], message_data: &[(&[u8], &[u8])]) -> Self {
// ⚠️ TODO @davxy @burdges (temporary hack and probably needs to be fixed)
// TODO @burdges (temporary hack?)
// In sassafras we want to construct a single `VrfInput` from multiple datas
// E.g. the ticket score uses: epoch-randomness, attempt-index, epoch-index
// Currently, `bandersnatch_vrfs::Message` has a single (domain, data) fields,
Expand Down Expand Up @@ -474,7 +484,7 @@ pub mod vrf {
}

fn vrf_output(&self, input: &Self::VrfInput) -> Self::VrfOutput {
let output = self.0 .0.vrf_preout(&input.0);
let output = self.secret.0.vrf_preout(&input.0);
VrfOutput(output)
}
}
Expand Down Expand Up @@ -510,11 +520,11 @@ pub mod vrf {
let ios: Vec<_> = data
.vrf_inputs
.iter()
.map(|i| self.0.clone().0.vrf_inout(i.0.clone()))
.map(|i| self.secret.clone().0.vrf_inout(i.0.clone()))
.collect();

let signature: ThinVrfSignature<N> =
self.0.sign_thin_vrf(data.transcript.clone(), ios.as_slice());
self.secret.sign_thin_vrf(data.transcript.clone(), ios.as_slice());

let mut sign_bytes = [0; SIGNATURE_SERIALIZED_LEN];
signature
Expand All @@ -534,7 +544,7 @@ pub mod vrf {
input: &VrfInput,
) -> [u8; N] {
let transcript = Transcript::new_labeled(context);
let inout = self.0.clone().0.vrf_inout(input.0.clone());
let inout = self.secret.clone().0.vrf_inout(input.0.clone());
inout.vrf_output_bytes(transcript)
}
}
Expand Down Expand Up @@ -710,11 +720,11 @@ pub mod ring_vrf {
let ios: Vec<_> = data
.vrf_inputs
.iter()
.map(|i| self.0.clone().0.vrf_inout(i.0.clone()))
.map(|i| self.secret.clone().0.vrf_inout(i.0.clone()))
.collect();

let ring_signature: bandersnatch_vrfs::RingVrfSignature<N> =
self.0.sign_ring_vrf(data.transcript.clone(), ios.as_slice(), prover);
self.secret.sign_ring_vrf(data.transcript.clone(), ios.as_slice(), prover);

let outputs: Vec<_> = ring_signature.preoutputs.into_iter().map(VrfOutput).collect();
let outputs = VrfIosVec::truncate_from(outputs);
Expand Down Expand Up @@ -814,11 +824,14 @@ mod tests {
}

#[test]
fn derive_hard_known_pair() {
let pair = Pair::from_string(&format!("{}//Alice", DEV_PHRASE), None).unwrap();
// known address of DEV_PHRASE
let known = h2b("646b261d8058ba8a3c4ebe152dc837fb2259433270dd5bdc79095874cc78b62f00");
fn derive_works() {
let pair = Pair::from_string(&format!("{}//Alice//Hard", DEV_PHRASE), None).unwrap();
let known = h2b("2b340c18b94dc1916979cb83daf3ed4ac106742ddc06afc42cf26be3b18a523f80");
assert_eq!(pair.public().as_ref(), known);

// Soft derivation not supported
let res = Pair::from_string(&format!("{}//Alice/Soft", DEV_PHRASE), None);
assert!(res.is_err());
}

#[test]
Expand Down