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

Generating random secret key for secp256k1 is not correct #62

Closed
kigawas opened this issue Sep 4, 2019 · 6 comments · May be fixed by #61
Closed

Generating random secret key for secp256k1 is not correct #62

kigawas opened this issue Sep 4, 2019 · 6 comments · May be fixed by #61

Comments

@kigawas
Copy link
Contributor

kigawas commented Sep 4, 2019

impl ECScalar<SK> for Secp256k1Scalar {
    fn new_random() -> Self {
        let mut arr = [0u8; 32];
        thread_rng().fill(&mut arr[..]);
        Self {
            purpose: "random",
            fe: SK::from_slice(&arr[0..arr.len()]).unwrap(),
        }
    }
   // ...
}

This is not enough, a valid secret key should be [1, Group order), and group order is fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141

@omershlo
Copy link
Contributor

omershlo commented Sep 4, 2019

You claim that the group order must be explicitly stated?
Btw, this is not a secret key , just a random field element...

@kigawas
Copy link
Contributor Author

kigawas commented Sep 4, 2019

No, actually you can just use SK::new(&mut thread_rng());

I mean for this code:

impl Secp256k1Point {
    pub fn random_point() -> Self {
        let random_scalar: Secp256k1Scalar = Secp256k1Scalar::new_random();  // <- if it's not a valid secret key, the whole thing crashes
        let base_point = Self::generator();
        let pk = base_point.scalar_mul(&random_scalar.get_element());
        Self {
            purpose: "random_point",
            ge: pk.get_element(),
        }
    }
}

@omershlo
Copy link
Contributor

omershlo commented Sep 4, 2019

Using SK::new(&mut thread_rng()); is the same as what I am doing.
The secp256k1 library is taking care on how to securely sample the number in the field. When the consumed library provide this service (and in this case it's even constant time) then I prefer to use it than to write my own random sampler. i.e. to avoid stuff like the first vulnerability in the audit:
https://github.com/KZen-networks/curv/blob/master/audit/kzen-curv-audit%20final%2003.01.2019.pdf

@kigawas
Copy link
Contributor Author

kigawas commented Sep 4, 2019

Hmm...It's little different since it's possibly continuously generating valid random bytes in the library:

impl SecretKey {
    /// Creates a new random secret key. Requires compilation with the "rand" feature.
    #[inline]
    #[cfg(any(test, feature = "rand"))]
    pub fn new<R: Rng + ?Sized>(rng: &mut R) -> SecretKey {
        let mut data = random_32_bytes(rng);
        unsafe {
            while ffi::secp256k1_ec_seckey_verify(
                ffi::secp256k1_context_no_precomp,
                data.as_ptr(),
            ) == 0
            {
                data = random_32_bytes(rng);
            }
        }
        SecretKey(data)
    }
    // ...
}

@kigawas
Copy link
Contributor Author

kigawas commented Sep 4, 2019

Suggest changing it to

    fn new_random() -> Self {
        Self {
            purpose: "random",
            fe: SK::new(&mut thread_rng()),
        }
    }

which looks nicer :)

@omershlo
Copy link
Contributor

omershlo commented Sep 4, 2019

this is called rejection sampling and this is the right and secure way to generate this random number.

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

Successfully merging a pull request may close this issue.

2 participants