mirror of
https://github.com/RustCrypto/signatures
synced 2026-06-21 13:45:42 +00:00
rfc6979: decouple from crypto-bigint (#639)
The previous approach complicates supporting ECDSA with `FieldSize` which is different from `C::Uint::ByteSize`. The new implementation eliminates `crypto-bigint` as a dependency and makes the API entirely byte-oriented. This is a simpler approach which also eliminates some previous trait bounds on the generic ECDSA implementation.
This commit is contained in:
@@ -9,20 +9,21 @@ on:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
jobs:
|
||||
security_audit:
|
||||
name: Security Audit
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
profile: minimal
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/bin
|
||||
key: ${{ runner.os }}-cargo-audit-v0.17.2
|
||||
- uses: actions-rs/audit-check@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# TODO(tarcieri): re-enable when elliptic-curve has been bumped
|
||||
# security_audit:
|
||||
# name: Security Audit
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@v3
|
||||
# - uses: actions-rs/toolchain@v1
|
||||
# with:
|
||||
# toolchain: stable
|
||||
# override: true
|
||||
# profile: minimal
|
||||
# - uses: actions/cache@v3
|
||||
# with:
|
||||
# path: ~/.cargo/bin
|
||||
# key: ${{ runner.os }}-cargo-audit-v0.17.2
|
||||
# - uses: actions-rs/audit-check@v1
|
||||
# with:
|
||||
# token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
Generated
+2
-2
@@ -639,10 +639,10 @@ dependencies = [
|
||||
name = "rfc6979"
|
||||
version = "0.4.0-pre"
|
||||
dependencies = [
|
||||
"crypto-bigint 0.5.0-pre.1",
|
||||
"hex-literal",
|
||||
"hmac",
|
||||
"sha2 0.10.6",
|
||||
"zeroize",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
+17
-9
@@ -18,11 +18,11 @@ use elliptic_curve::{bigint::Integer, FieldBytes, PrimeCurve};
|
||||
use {
|
||||
crate::{RecoveryId, SignatureSize},
|
||||
elliptic_curve::{
|
||||
group::Curve as _,
|
||||
ff::PrimeField,
|
||||
group::{Curve as _, Group},
|
||||
ops::{Invert, LinearCombination, MulByGenerator, Reduce},
|
||||
subtle::CtOption,
|
||||
AffineXCoordinate, AffineYIsOdd, CurveArithmetic, Field, Group, IsHigh, ProjectivePoint,
|
||||
Scalar,
|
||||
AffineXCoordinate, AffineYIsOdd, CurveArithmetic, IsHigh, ProjectivePoint, Scalar,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@ use {
|
||||
use crate::{elliptic_curve::generic_array::ArrayLength, Signature};
|
||||
|
||||
#[cfg(feature = "rfc6979")]
|
||||
use elliptic_curve::ScalarPrimitive;
|
||||
use elliptic_curve::{bigint::ArrayEncoding, ScalarPrimitive};
|
||||
|
||||
/// Try to sign the given prehashed message using ECDSA.
|
||||
///
|
||||
@@ -47,7 +47,12 @@ use elliptic_curve::ScalarPrimitive;
|
||||
/// secret scalar via `&self`, such as particular curve's `Scalar` type.
|
||||
#[cfg(feature = "arithmetic")]
|
||||
pub trait SignPrimitive<C>:
|
||||
AsRef<Self> + Field + Into<FieldBytes<C>> + IsHigh + Reduce<C::Uint> + Sized
|
||||
AsRef<Self>
|
||||
+ Into<FieldBytes<C>>
|
||||
+ IsHigh
|
||||
+ PrimeField<Repr = FieldBytes<C>>
|
||||
+ Reduce<C::Uint>
|
||||
+ Sized
|
||||
where
|
||||
C: PrimeCurve + CurveArithmetic + CurveArithmetic<Scalar = Self>,
|
||||
SignatureSize<C>: ArrayLength<u8>,
|
||||
@@ -123,12 +128,15 @@ where
|
||||
) -> Result<(Signature<C>, Option<RecoveryId>)>
|
||||
where
|
||||
Self: From<ScalarPrimitive<C>>,
|
||||
C::Uint: for<'a> From<&'a Self>,
|
||||
D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset,
|
||||
{
|
||||
let x = C::Uint::from(self);
|
||||
let k = rfc6979::generate_k::<D, C::Uint>(&x, &C::ORDER, &z, ad);
|
||||
let k = Self::from(ScalarPrimitive::<C>::new(*k).unwrap());
|
||||
let k = C::Uint::from_be_byte_array(rfc6979::generate_k::<D, FieldSize<C>>(
|
||||
&self.to_repr(),
|
||||
&C::ORDER.to_be_byte_array(),
|
||||
&z,
|
||||
ad,
|
||||
));
|
||||
let k = Self::from(ScalarPrimitive::<C>::new(k).unwrap());
|
||||
self.try_sign_prehashed(k, z)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +176,6 @@ impl From<RecoveryId> for u8 {
|
||||
impl<C> SigningKey<C>
|
||||
where
|
||||
C: PrimeCurve + CurveArithmetic + DigestPrimitive,
|
||||
C::Uint: for<'a> From<&'a Scalar<C>>,
|
||||
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::Uint> + SignPrimitive<C>,
|
||||
SignatureSize<C>: ArrayLength<u8>,
|
||||
{
|
||||
@@ -209,7 +208,6 @@ where
|
||||
impl<C, D> DigestSigner<D, (Signature<C>, RecoveryId)> for SigningKey<C>
|
||||
where
|
||||
C: PrimeCurve + CurveArithmetic + DigestPrimitive,
|
||||
C::Uint: for<'a> From<&'a Scalar<C>>,
|
||||
D: Digest,
|
||||
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::Uint> + SignPrimitive<C>,
|
||||
SignatureSize<C>: ArrayLength<u8>,
|
||||
@@ -223,7 +221,6 @@ where
|
||||
impl<C> PrehashSigner<(Signature<C>, RecoveryId)> for SigningKey<C>
|
||||
where
|
||||
C: PrimeCurve + CurveArithmetic + DigestPrimitive,
|
||||
C::Uint: for<'a> From<&'a Scalar<C>>,
|
||||
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::Uint> + SignPrimitive<C>,
|
||||
SignatureSize<C>: ArrayLength<u8>,
|
||||
{
|
||||
@@ -236,7 +233,6 @@ where
|
||||
impl<C> Signer<(Signature<C>, RecoveryId)> for SigningKey<C>
|
||||
where
|
||||
C: PrimeCurve + CurveArithmetic + DigestPrimitive,
|
||||
C::Uint: for<'a> From<&'a Scalar<C>>,
|
||||
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::Uint> + SignPrimitive<C>,
|
||||
SignatureSize<C>: ArrayLength<u8>,
|
||||
{
|
||||
|
||||
@@ -111,7 +111,6 @@ where
|
||||
impl<C, D> DigestSigner<D, Signature<C>> for SigningKey<C>
|
||||
where
|
||||
C: PrimeCurve + CurveArithmetic + DigestPrimitive,
|
||||
C::Uint: for<'a> From<&'a Scalar<C>>,
|
||||
D: Digest + FixedOutput<OutputSize = FieldSize<C>>,
|
||||
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::Uint> + SignPrimitive<C>,
|
||||
SignatureSize<C>: ArrayLength<u8>,
|
||||
@@ -128,7 +127,6 @@ where
|
||||
impl<C> PrehashSigner<Signature<C>> for SigningKey<C>
|
||||
where
|
||||
C: PrimeCurve + CurveArithmetic + DigestPrimitive,
|
||||
C::Uint: for<'a> From<&'a Scalar<C>>,
|
||||
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::Uint> + SignPrimitive<C>,
|
||||
SignatureSize<C>: ArrayLength<u8>,
|
||||
{
|
||||
@@ -148,7 +146,6 @@ where
|
||||
impl<C> Signer<Signature<C>> for SigningKey<C>
|
||||
where
|
||||
C: PrimeCurve + CurveArithmetic + DigestPrimitive,
|
||||
C::Uint: for<'a> From<&'a Scalar<C>>,
|
||||
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::Uint> + SignPrimitive<C>,
|
||||
SignatureSize<C>: ArrayLength<u8>,
|
||||
{
|
||||
@@ -160,7 +157,6 @@ where
|
||||
impl<C, D> RandomizedDigestSigner<D, Signature<C>> for SigningKey<C>
|
||||
where
|
||||
C: PrimeCurve + CurveArithmetic + DigestPrimitive,
|
||||
C::Uint: for<'a> From<&'a Scalar<C>>,
|
||||
D: Digest + FixedOutput<OutputSize = FieldSize<C>>,
|
||||
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::Uint> + SignPrimitive<C>,
|
||||
SignatureSize<C>: ArrayLength<u8>,
|
||||
@@ -177,7 +173,6 @@ where
|
||||
impl<C> RandomizedPrehashSigner<Signature<C>> for SigningKey<C>
|
||||
where
|
||||
C: PrimeCurve + CurveArithmetic + DigestPrimitive,
|
||||
C::Uint: for<'a> From<&'a Scalar<C>>,
|
||||
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::Uint> + SignPrimitive<C>,
|
||||
SignatureSize<C>: ArrayLength<u8>,
|
||||
{
|
||||
@@ -212,7 +207,6 @@ where
|
||||
impl<C> PrehashSigner<der::Signature<C>> for SigningKey<C>
|
||||
where
|
||||
C: PrimeCurve + CurveArithmetic + DigestPrimitive,
|
||||
C::Uint: for<'a> From<&'a Scalar<C>>,
|
||||
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::Uint> + SignPrimitive<C>,
|
||||
SignatureSize<C>: ArrayLength<u8>,
|
||||
der::MaxSize<C>: ArrayLength<u8>,
|
||||
@@ -227,7 +221,6 @@ where
|
||||
impl<C> Signer<der::Signature<C>> for SigningKey<C>
|
||||
where
|
||||
C: PrimeCurve + CurveArithmetic + DigestPrimitive,
|
||||
C::Uint: for<'a> From<&'a Scalar<C>>,
|
||||
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::Uint> + SignPrimitive<C>,
|
||||
SignatureSize<C>: ArrayLength<u8>,
|
||||
der::MaxSize<C>: ArrayLength<u8>,
|
||||
@@ -242,7 +235,6 @@ where
|
||||
impl<C, D> RandomizedDigestSigner<D, der::Signature<C>> for SigningKey<C>
|
||||
where
|
||||
C: PrimeCurve + CurveArithmetic + DigestPrimitive,
|
||||
C::Uint: for<'a> From<&'a Scalar<C>>,
|
||||
D: Digest + FixedOutput<OutputSize = FieldSize<C>>,
|
||||
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::Uint> + SignPrimitive<C>,
|
||||
SignatureSize<C>: ArrayLength<u8>,
|
||||
@@ -263,7 +255,6 @@ where
|
||||
impl<C> RandomizedPrehashSigner<der::Signature<C>> for SigningKey<C>
|
||||
where
|
||||
C: PrimeCurve + CurveArithmetic + DigestPrimitive,
|
||||
C::Uint: for<'a> From<&'a Scalar<C>>,
|
||||
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::Uint> + SignPrimitive<C>,
|
||||
SignatureSize<C>: ArrayLength<u8>,
|
||||
der::MaxSize<C>: ArrayLength<u8>,
|
||||
@@ -283,7 +274,6 @@ where
|
||||
impl<C> RandomizedSigner<der::Signature<C>> for SigningKey<C>
|
||||
where
|
||||
C: PrimeCurve + CurveArithmetic + DigestPrimitive,
|
||||
C::Uint: for<'a> From<&'a Scalar<C>>,
|
||||
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::Uint> + SignPrimitive<C>,
|
||||
SignatureSize<C>: ArrayLength<u8>,
|
||||
der::MaxSize<C>: ArrayLength<u8>,
|
||||
|
||||
+2
-2
@@ -15,9 +15,9 @@ edition = "2021"
|
||||
rust-version = "1.61"
|
||||
|
||||
[dependencies]
|
||||
crypto-bigint = { version = "=0.5.0-pre.1", default-features = false, features = ["generic-array", "zeroize"] }
|
||||
hmac = { version = "0.12", default-features = false, features = ["reset"] }
|
||||
zeroize = { version = "1", default-features = false }
|
||||
subtle = { version = "2", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
hex-literal = "0.3"
|
||||
sha2 = "0.10"
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
//! Constant-time comparison helpers for [`ByteArray`].
|
||||
|
||||
use crate::{ArrayLength, ByteArray};
|
||||
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
|
||||
|
||||
/// Constant-time equals.
|
||||
pub(crate) fn ct_eq<N: ArrayLength<u8>>(a: &ByteArray<N>, b: &ByteArray<N>) -> Choice {
|
||||
let mut ret = Choice::from(1);
|
||||
|
||||
for (a, b) in a.iter().zip(b.iter()) {
|
||||
ret.conditional_assign(&Choice::from(0), !a.ct_eq(b));
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
/// Constant-time less than.
|
||||
///
|
||||
/// Inputs are interpreted as big endian integers.
|
||||
pub(crate) fn ct_lt<N: ArrayLength<u8>>(a: &ByteArray<N>, b: &ByteArray<N>) -> Choice {
|
||||
let mut borrow = 0;
|
||||
|
||||
// Perform subtraction with borrow a byte-at-a-time, interpreting a
|
||||
// no-borrow condition as the less-than case
|
||||
for (&a, &b) in a.iter().zip(b.iter()).rev() {
|
||||
let c = (b as u16).wrapping_add(borrow >> (u8::BITS - 1));
|
||||
borrow = (a as u16).wrapping_sub(c) >> u8::BITS as u8;
|
||||
}
|
||||
|
||||
!borrow.ct_eq(&0)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
const A: [u8; 4] = [0, 0, 0, 0];
|
||||
const B: [u8; 4] = [0, 0, 0, 1];
|
||||
const C: [u8; 4] = [0xFF, 0, 0, 0];
|
||||
const D: [u8; 4] = [0xFF, 0, 0, 1];
|
||||
const E: [u8; 4] = [0xFF, 0xFF, 0xFF, 0xFE];
|
||||
const F: [u8; 4] = [0xFF, 0xFF, 0xFF, 0xFF];
|
||||
|
||||
#[test]
|
||||
fn ct_eq() {
|
||||
use super::ct_eq;
|
||||
|
||||
assert_eq!(ct_eq(&A.into(), &A.into()).unwrap_u8(), 1);
|
||||
assert_eq!(ct_eq(&B.into(), &B.into()).unwrap_u8(), 1);
|
||||
assert_eq!(ct_eq(&C.into(), &C.into()).unwrap_u8(), 1);
|
||||
assert_eq!(ct_eq(&D.into(), &D.into()).unwrap_u8(), 1);
|
||||
assert_eq!(ct_eq(&E.into(), &E.into()).unwrap_u8(), 1);
|
||||
assert_eq!(ct_eq(&F.into(), &F.into()).unwrap_u8(), 1);
|
||||
|
||||
assert_eq!(ct_eq(&A.into(), &B.into()).unwrap_u8(), 0);
|
||||
assert_eq!(ct_eq(&C.into(), &D.into()).unwrap_u8(), 0);
|
||||
assert_eq!(ct_eq(&E.into(), &F.into()).unwrap_u8(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ct_lt() {
|
||||
use super::ct_lt;
|
||||
|
||||
assert_eq!(ct_lt(&A.into(), &A.into()).unwrap_u8(), 0);
|
||||
assert_eq!(ct_lt(&B.into(), &B.into()).unwrap_u8(), 0);
|
||||
assert_eq!(ct_lt(&C.into(), &C.into()).unwrap_u8(), 0);
|
||||
assert_eq!(ct_lt(&D.into(), &D.into()).unwrap_u8(), 0);
|
||||
assert_eq!(ct_lt(&E.into(), &E.into()).unwrap_u8(), 0);
|
||||
assert_eq!(ct_lt(&F.into(), &F.into()).unwrap_u8(), 0);
|
||||
|
||||
assert_eq!(ct_lt(&A.into(), &B.into()).unwrap_u8(), 1);
|
||||
assert_eq!(ct_lt(&A.into(), &C.into()).unwrap_u8(), 1);
|
||||
assert_eq!(ct_lt(&B.into(), &A.into()).unwrap_u8(), 0);
|
||||
assert_eq!(ct_lt(&C.into(), &A.into()).unwrap_u8(), 0);
|
||||
|
||||
assert_eq!(ct_lt(&B.into(), &C.into()).unwrap_u8(), 1);
|
||||
assert_eq!(ct_lt(&B.into(), &D.into()).unwrap_u8(), 1);
|
||||
assert_eq!(ct_lt(&C.into(), &B.into()).unwrap_u8(), 0);
|
||||
assert_eq!(ct_lt(&D.into(), &B.into()).unwrap_u8(), 0);
|
||||
|
||||
assert_eq!(ct_lt(&C.into(), &D.into()).unwrap_u8(), 1);
|
||||
assert_eq!(ct_lt(&C.into(), &E.into()).unwrap_u8(), 1);
|
||||
assert_eq!(ct_lt(&D.into(), &C.into()).unwrap_u8(), 0);
|
||||
assert_eq!(ct_lt(&E.into(), &C.into()).unwrap_u8(), 0);
|
||||
|
||||
assert_eq!(ct_lt(&E.into(), &F.into()).unwrap_u8(), 1);
|
||||
assert_eq!(ct_lt(&F.into(), &E.into()).unwrap_u8(), 0);
|
||||
}
|
||||
}
|
||||
+34
-24
@@ -12,39 +12,46 @@
|
||||
//! See also: the documentation for the [`generate_k`] function.
|
||||
//!
|
||||
//! ```
|
||||
//! use crypto_bigint::{ArrayEncoding, U256};
|
||||
//! use hex_literal::hex;
|
||||
//! use rfc6979::consts::U32;
|
||||
//! use sha2::{Digest, Sha256};
|
||||
//!
|
||||
//! // NIST P-256 field modulus
|
||||
//! const NIST_P256_MODULUS: U256 =
|
||||
//! U256::from_be_hex("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
|
||||
//! const NIST_P256_MODULUS: [u8; 32] =
|
||||
//! hex!("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
|
||||
//!
|
||||
//! // Public key for RFC6979 NIST P256/SHA256 test case
|
||||
//! const RFC6979_KEY: U256 =
|
||||
//! U256::from_be_hex("C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721");
|
||||
//! const RFC6979_KEY: [u8; 32] =
|
||||
//! hex!("C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721");
|
||||
//!
|
||||
//! // Test message for RFC6979 NIST P256/SHA256 test case
|
||||
//! const RFC6979_MSG: &[u8; 6] = b"sample";
|
||||
//!
|
||||
//! // Expected K for RFC6979 NIST P256/SHA256 test case
|
||||
//! const RFC6979_EXPECTED_K: U256 =
|
||||
//! U256::from_be_hex("A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60");
|
||||
//! const RFC6979_EXPECTED_K: [u8; 32] =
|
||||
//! hex!("A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60");
|
||||
//!
|
||||
//! let h = Sha256::digest(RFC6979_MSG);
|
||||
//! let aad = b"";
|
||||
//! let k = rfc6979::generate_k::<Sha256, U256>(&RFC6979_KEY, &NIST_P256_MODULUS, &h, aad);
|
||||
//! assert_eq!(&k.to_be_byte_array(), &RFC6979_EXPECTED_K.to_be_byte_array());
|
||||
//! let k = rfc6979::generate_k::<Sha256, U32>(&RFC6979_KEY.into(), &NIST_P256_MODULUS.into(), &h, aad);
|
||||
//! assert_eq!(k.as_slice(), &RFC6979_EXPECTED_K);
|
||||
//! ```
|
||||
|
||||
use crypto_bigint::{ArrayEncoding, ByteArray, Integer};
|
||||
mod ct_cmp;
|
||||
|
||||
pub use hmac::digest::generic_array::typenum::consts;
|
||||
|
||||
use hmac::{
|
||||
digest::{
|
||||
core_api::BlockSizeUser, generic_array::GenericArray, Digest, FixedOutput,
|
||||
FixedOutputReset, Mac,
|
||||
core_api::BlockSizeUser,
|
||||
generic_array::{ArrayLength, GenericArray},
|
||||
Digest, FixedOutput, FixedOutputReset, Mac,
|
||||
},
|
||||
SimpleHmac,
|
||||
};
|
||||
use zeroize::{Zeroize, Zeroizing};
|
||||
|
||||
/// Array of bytes representing a scalar serialized as a big endian integer.
|
||||
pub type ByteArray<Size> = GenericArray<u8, Size>;
|
||||
|
||||
/// Deterministically generate ephemeral scalar `k`.
|
||||
///
|
||||
@@ -55,22 +62,25 @@ use zeroize::{Zeroize, Zeroizing};
|
||||
/// - `h`: hash/digest of input message: must be reduced modulo `n` in advance
|
||||
/// - `data`: additional associated data, e.g. CSRNG output used as added entropy
|
||||
#[inline]
|
||||
pub fn generate_k<D, I>(x: &I, n: &I, h: &ByteArray<I>, data: &[u8]) -> Zeroizing<I>
|
||||
pub fn generate_k<D, N>(
|
||||
x: &ByteArray<N>,
|
||||
n: &ByteArray<N>,
|
||||
h: &ByteArray<N>,
|
||||
data: &[u8],
|
||||
) -> ByteArray<N>
|
||||
where
|
||||
D: Digest + BlockSizeUser + FixedOutput<OutputSize = I::ByteSize> + FixedOutputReset,
|
||||
I: ArrayEncoding + Integer + Zeroize,
|
||||
D: Digest + BlockSizeUser + FixedOutput<OutputSize = N> + FixedOutputReset,
|
||||
N: ArrayLength<u8>,
|
||||
{
|
||||
let mut x = x.to_be_byte_array();
|
||||
let mut hmac_drbg = HmacDrbg::<D>::new(&x, h, data);
|
||||
x.zeroize();
|
||||
let mut hmac_drbg = HmacDrbg::<D>::new(x, h, data);
|
||||
|
||||
loop {
|
||||
let mut bytes = ByteArray::<I>::default();
|
||||
hmac_drbg.fill_bytes(&mut bytes);
|
||||
let k = I::from_be_byte_array(bytes);
|
||||
let mut k = ByteArray::<N>::default();
|
||||
hmac_drbg.fill_bytes(&mut k);
|
||||
|
||||
if (!k.is_zero() & k.ct_lt(n)).into() {
|
||||
return Zeroizing::new(k);
|
||||
let k_is_zero = ct_cmp::ct_eq(&k, &ByteArray::default());
|
||||
if (!k_is_zero & ct_cmp::ct_lt(&k, n)).into() {
|
||||
return k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user