1# coding: utf-8
2from hmac import new as hmacNew
3from .binary import numberFromByteString, hexFromInt, byteStringFromHex
4
5try:
6 from secrets import randbelow as _randbelow
7except ImportError:
8 from random import SystemRandom
9 _systemRandom = SystemRandom()
10 _randbelow = lambda n: _systemRandom.randrange(n)
11
12
13class RandomInteger:
14
15 @classmethod
16 def between(cls, min, max):
17 """
18 Return integer x in the range: min <= x <= max
19
20 :param min: minimum value of the integer
21 :param max: maximum value of the integer
22 :return:
23 """
24
25 return min + _randbelow(max - min + 1)
26
27 @classmethod
28 def rfc6979(cls, hashBytes, secret, curve, hashfunc):
29 """Generate nonce values per hedged RFC 6979: deterministic k derivation
30 with fresh random entropy mixed into K-init (RFC 6979 §3.6). Same message
31 and key yield different signatures, while preserving RFC 6979's protection
32 against RNG failures."""
33 orderBitLen = curve.nBitLength
34 orderByteLen = (orderBitLen + 7) // 8
35
36 secretHex = hexFromInt(secret).zfill(orderByteLen * 2)
37 secretBytes = byteStringFromHex(secretHex)
38
39 hashReduced = numberFromByteString(hashBytes, orderBitLen) % curve.N
40 hashHex = hexFromInt(hashReduced).zfill(orderByteLen * 2)
41 hashOctets = byteStringFromHex(hashHex)
42
43 extraEntropy = byteStringFromHex(
44 hexFromInt(cls.between(0, (1 << (orderByteLen * 8)) - 1)).zfill(orderByteLen * 2)
45 )
46
47 hLen = hashfunc().digest_size
48 V = b'\x01' * hLen
49 K = b'\x00' * hLen
50
51 K = hmacNew(K, V + b'\x00' + secretBytes + hashOctets + extraEntropy, hashfunc).digest()
52 V = hmacNew(K, V, hashfunc).digest()
53 K = hmacNew(K, V + b'\x01' + secretBytes + hashOctets + extraEntropy, hashfunc).digest()
54 V = hmacNew(K, V, hashfunc).digest()
55
56 while True:
57 T = b''
58 while len(T) * 8 < orderBitLen:
59 V = hmacNew(K, V, hashfunc).digest()
60 T += V
61
62 k = numberFromByteString(T, orderBitLen)
63
64 if 1 <= k <= curve.N - 1:
65 yield k
66
67 K = hmacNew(K, V + b'\x00', hashfunc).digest()
68 V = hmacNew(K, V, hashfunc).digest()