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

Serializing SecretKey to bytes #104

Open
iancoleman opened this issue Sep 28, 2020 · 2 comments
Open

Serializing SecretKey to bytes #104

iancoleman opened this issue Sep 28, 2020 · 2 comments

Comments

@iancoleman
Copy link

Converting a SecretKey to json gives [u64; 4]

let sk = SecretKey::random();
let skj = serde_json::to_string(&SerdeSecret(&sk)).unwrap();
println!("{:?}", skj);
// "[13835017372499487413,8530528684116874606,14604090506237340830,7436755248230544869]"

Javascript will happily but incorrectly parse this (javascript uses f64 for all numbers):

sk = JSON.parse("[13835017372499487413,8530528684116874606,14604090506237340830,7436755248230544869]");
console.log(sk);
// [ 13835017372499487000, 8530528684116874000, 14604090506237342000, 7436755248230544000 ]

Being able to convert to bytes would be handy in these sorts of cases, maybe to_bytes and from_bytes method?

Here's a SecretKey method that works for converting to bytes:

/// Reveals the prime field as bytes
pub fn to_bytes(&self) -> Vec<u8> {
    use ff::PrimeField;
    let mut bytes = Vec::<u8>::new();
    self.0.into_repr().0.iter().for_each(|n| bytes.extend(&n.to_le_bytes()));
    bytes.reverse();
    bytes
}

But I'm not sure if this logic is best to be in the SecretKey impl or if it's something that should be added to serde_impl.rs, since it depends on how much the library wants to insulate the secret key and how it would achieve that.

@iancoleman
Copy link
Author

iancoleman commented Nov 9, 2020

A to_bytes method would be useful to ensure consistency across bls12-381 implementations, specifically in reference to endianness.

eip-2333 specifies big endian

blst uses big endian

threshold_crypto uses byteorder::BigEndian but only in src/mock/ms8.rs

bincode defaults to little endian (see Options docs) but it seems most common for bls12-381 implementations to specify big endian.

Some code examples to illustrate where this may cause grief:

threshold_crypto SecretKey.reveal():

println!("sk.reveal: {:?}", sk.reveal());
// sk.reveal: "SecretKey(Fr(0x408157791befddd702672dcfcfc99da3512f9c0ea818890fcb6ab749580ef2cf"))

threshold_crypto using default bincode:

let skb = bincode::serialize(&SerdeSecret(&sk)).unwrap();
println!("threshold_crypto bincode: {:?}", hex::encode(skb));
// threshold_crypto bincode: "cff20e5849b76acb0f8918a80e9c2f51a39dc9cfcf2d6702d7ddef1b79578140"
// this is little endian, reversing the bytes gives same as sk.reveal()

threshold_crypto using big_endian bincode v1.2.1 (bincode config changes in later versions):

let skb = bincode::config().big_endian().serialize(&SerdeSecret(&sk)).unwrap();
println!("threshold_crypto bincode big_endian: {:?}", hex::encode(skb));
// threshold_crypto bincode big_endian: "cb6ab749580ef2cf512f9c0ea818890f02672dcfcfc99da3408157791befddd7"
// it becomes clearer what is going on when splitting into 4x u64 as per the underlying data type
// cb6ab749580ef2cf 512f9c0ea818890f 02672dcfcfc99da3 408157791befddd7

blst (which is explicitly big endian via blst_bendian_from_scalar):

println!("blst: {:?}", hex::encode(blst_sk.to_bytes());
// blst: "408157791befddd702672dcfcfc99da3512f9c0ea818890fcb6ab749580ef2cf"

It seems like a to_bytes method could be useful to increase interoperability. reveal is not a very ergonomic way to export the secret key.

edit: code to generate above values can be found at https://github.com/iancoleman/bls_interop

@dan-da
Copy link

dan-da commented May 24, 2021

+1. I just came here looking for a to_bytes() method myself. It is asymmetric that PublicKey has a to_bytes() method, but there is no equivalent for SecretKey/Share.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants