Skip to content

Commit 7bdbdd3

Browse files
committed
Improve handling of extra entropy
o Remove option for Fixed entropy o Better handle entropy with only DC signal o Always suggest extra entropy (SHA-512) for Create controls
1 parent 47b8a6d commit 7bdbdd3

File tree

5 files changed

+27
-34
lines changed

5 files changed

+27
-34
lines changed

slip39/gui/SLIP-39-SD.org

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ BIP-39 Mnemonic using SLIP-39.
1111
| Create | Random | Create SLIP-39 Mnemonics from secure randomnes |
1212
| Recover | SLIP-39 | Recover Seed from SLIP-39 Mnemonics |
1313
| Pro | BIP-39 Seed | Backup 512-bit BIP-39 Seed from Mnemonics + passphrase |
14-
| Pro | Fixed | Hex data may be supplied for the Seed |
1514
#+END_ABSTRACT
1615

1716
* BIP-39

slip39/gui/SLIP-39-SD.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ your insecure/unreliable BIP-39 Mnemonic using SLIP-39.
88
Create Random Create SLIP-39 Mnemonics from secure randomnes
99
Recover SLIP-39 Recover Seed from SLIP-39 Mnemonics
1010
Pro BIP-39 Seed Backup 512-bit BIP-39 Seed from Mnemonics + passphrase
11-
Pro Fixed Hex data may be supplied for the Seed
1211
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1312

1413

slip39/gui/main.py

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -285,11 +285,6 @@ def groups_layout(
285285
sg.Checkbox( 'Passphrase', key='-SD-PASS-C-', visible=False, **T_hue( B_kwds, 2/20 )),
286286
],
287287
[
288-
sg.Text("Fixed: ", visible=LO_PRO, **T_hue( T_kwds, 1/20 )),
289-
] + [
290-
sg.Radio( f"{b}-bit", "SD", key=f"-SD-{b}-FIX-", visible=LO_PRO, **T_hue( B_kwds, 1/20 ))
291-
for b in BITS
292-
] + [
293288
sg.Frame( passphrase_trezor_incompatible, [
294289
[
295290
sg.Text( "Passphrase (decrypt): ", **T_kwds ),
@@ -319,19 +314,20 @@ def groups_layout(
319314
sg.Frame( SE_SEED_FRAME, [
320315
[
321316
sg.Radio( "None", "SE", key='-SE-NON-', visible=LO_REC,
322-
default=True, **B_kwds ),
317+
default=LO_BAK, **B_kwds ),
323318
sg.Radio( "Hex", "SE", key='-SE-HEX-', visible=LO_PRO, **B_kwds ),
324-
sg.Radio( "Die rolls, ... (SHA-512)", "SE", key='-SE-SHA-', visible=LO_REC, **B_kwds ),
319+
sg.Radio( "Die rolls, ... (SHA-512)", "SE", key='-SE-SHA-', visible=LO_REC,
320+
default=LO_CRE or LO_PRO, **B_kwds ),
325321
sg.Checkbox( 'Ignore Bad Entropy', key='-SE-SIGS-C-', visible=LO_REC or LO_PRO,
326322
disabled=False, **T_hue( B_kwds, 3/20 )),
327323
],
328324
[
329-
sg.Frame( 'Entropy', [
325+
sg.Column( [
330326
[
331-
sg.Text( "Hex digits: ", key='-SE-DATA-T-', size=prefix, **T_kwds ),
327+
sg.Text( "Die rolls, etc.:",key='-SE-DATA-T-', size=prefix, **T_kwds ),
332328
sg.Input( "", key='-SE-DATA-', size=inlong, **I_kwds ),
333329
],
334-
], key='-SE-DATA-F-', visible=False, **F_kwds ),
330+
], key='-SE-DATA-F-', visible=False ),
335331
],
336332
[
337333
sg.Text( "Seed XOR Data: ", visible=LO_REC,
@@ -532,9 +528,6 @@ def update_seed_data( event, window, values ):
532528
'-SD-128-RND-',
533529
'-SD-256-RND-',
534530
'-SD-512-RND-',
535-
'-SD-128-FIX-',
536-
'-SD-256-FIX-',
537-
'-SD-512-FIX-',
538531
'-SD-BIP-', # Recover 128- to 256-bit Mnemonic Seed Entropy
539532
'-SD-BIP-SEED-', # Recover 512-bit Generated Seed w/ passphrase
540533
'-SD-SLIP-',
@@ -775,9 +768,13 @@ def stretch_seed_entropy( entropy, n, bits, encoding=None ):
775768
# Other encoding was provided, eg 'UTF-8', 'ASCII', ...; stretch for the 0th Seed, too.
776769
n += 1
777770
entropy = codecs.encode( entropy, encoding ) # '012abc' --> b'012abc'
778-
for _ in range( n ):
779-
entropy = hashlib.sha512( entropy ).digest()
780771
octets = ( bits + 7 ) // 8
772+
if entropy:
773+
for _ in range( n ):
774+
entropy = hashlib.sha512( entropy ).digest()
775+
else:
776+
# If no entropy provided, result is all 0
777+
entropy = b'\0' * octets
781778
assert len( entropy ) >= octets, \
782779
"Insufficient extra Seed Entropy provided for {ordinal(n+1)} {bits}-bit Seed"
783780
return entropy[:octets]
@@ -809,7 +806,9 @@ def update_seed_entropy( event, window, values ):
809806
update_seed_entropy.src = src
810807
window['-SE-DATA-'].update( data )
811808
values['-SE-DATA-'] = data
812-
if 'HEX' in update_seed_entropy.src:
809+
if 'NON' in update_seed_entropy.src:
810+
window['-SE-DATA-T-'].update( "" )
811+
elif 'HEX' in update_seed_entropy.src:
813812
window['-SE-DATA-T-'].update( "Hex digits: " )
814813
else:
815814
window['-SE-DATA-T-'].update( "Die rolls, etc.: " )

slip39/recovery/entropy.py

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -197,11 +197,15 @@ def denoise_mags( mags, threshold, middle=None, stride=8 ):
197197
]
198198
cavg = avg( curs ) if middle is None else middle( curs )
199199
target = cavg * threshold
200-
#print( f"dnoi: {' '.join( f'{c:{stride}.1f}({mags[i] / target:{stride-2}.1f})' for i,c in enumerate( curs ))}: {target=:7.1f}" )
200+
#print( f"dnoi: {' '.join( f'{c:{stride}.1f}({mags[i] / target if target else 0:{stride-2}.1f})' for i,c in enumerate( curs ))}: {target=:7.1f}" )
201201

202202
# Return the noise threshold target magnitude deduced, and the index,SNR for each signal bin,
203203
# sorted by SNR
204-
return target, sorted( ( (i, mags[i] / target) for i in snrs ), key=lambda e: e[1], reverse=True )
204+
return target, sorted(
205+
( (i, mags[i] / target if target else 0) for i in snrs ),
206+
key = lambda e: e[1],
207+
reverse = True,
208+
)
205209

206210

207211
def signal_recover_real( dfts, scale=None, integer=False, amplify=None ):
@@ -414,7 +418,7 @@ def signal_entropy(
414418
dB. Using something like statistics.median is problematic for low-noise signals, because if a
415419
sufficient number of bins have 0 energy, the noise will be 0, and a "default" SNR (signal/noise
416420
*ratio*) of 1.0 will be used (0.0 dB), allowing any more legitimate signal to be used instead of
417-
the unlikely "perfect" noise-free signal.
421+
the unlikely "perfect" noise-free signal (or signals w/ *only* a DC component if we ignore_dc.)
418422
419423
So, the result can be sorted by greatest power, and if any power is found to be > 0.0dB, the
420424
entropy can be rejected as having too much "signal" vs "noise" (entropy).
@@ -465,16 +469,6 @@ def signal_entropy(
465469
snrd = dict( snrs ) # i: snr
466470
#print( f"snrs: {' '.join( f'{snrd[i]:{stride*2}.1f}' if i in snrd else (' ' * stride*2) for i in range( len( mags )))}: {target=:7.1f}" )
467471

468-
# mid = nrms if middle is None else middle( mags )
469-
# target = mid * threshold
470-
# # Find the magnitude, offset of the top magnitudes exceeding target, sorted high to low
471-
# tops = sorted( ( (m,i) for i,m in enumerate( mags ) if m > target ), reverse=True )
472-
# # Compute total signal dB SNR vs. target. If all mags are 0 (all sigs were 0), then top
473-
# # and target will all be 0. However, this means that the signal is totally predictable
474-
# # (contains infinitely strong signal), so pick an small but non-passing snr (1.0 ==
475-
# # 0.0dB), so that any other more "legitimate" non-passing signals will likely be chosen
476-
# # as strongest. If no signal; report how far below the target our strongest bin is.
477-
478472
# When we have multiple signals, a Signal with several strong signals should have an SNR
479473
# higher than something with fewer/weaker signals. However, only the portion *above*
480474
# the target threshold count. So, sum the tops, and compute the overall Signal SNR.
@@ -565,7 +559,9 @@ def signal_entropy(
565559
# scale the signal by the ratio of the removed DC to the largest other signal. Since we know that
566560
# the other signals were DC "higher" in the original signal, amplifying the signal by this ratio
567561
# shouldn't exceed the maximum dynamic range of the eg. integer signal values.
568-
dc_amplify = 1 + abs( dc ) / max( abs( b ) for b in dfts )
562+
peak = max( abs( b ) for b in dfts )
563+
if peak:
564+
dc_amplify = 1 + abs( dc ) / peak
569565

570566
# Compute the resolution for the inverse DFT required to properly cover the binary
571567
# entropy. However, limit size of the resultant DFT, as idft is O(N^2). For a 512-bit
@@ -588,7 +584,7 @@ def signal_entropy(
588584
#print( f" - {i=:3} --> {o=:3} ==> {sigs[o]:7}" )
589585
pos += signal_draw( sigs[o], pos=True )
590586
neg += signal_draw( sigs[o], neg=True )
591-
harmonic_dBs = [ f"{ordinal(h) if h else 'DC'} {into_dB(mags[h]/target):.1f}dB" for h in harmonic ]
587+
harmonic_dBs = [ f"{ordinal(h) if h else 'DC'} {into_dB(mags[h]/target) if target else 0.0:.1f}dB" for h in harmonic ]
592588
details += f"{offpref}{pos} {len(harmonic)} harmonics: {commas( harmonic_dBs, final='and' )}\n"
593589
details += f"{offpref}{neg} - "
594590
if 0 in harmonic:

slip39/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
__version_info__ = ( 11, 0, 2 )
1+
__version_info__ = ( 11, 0, 3 )
22
__version__ = '.'.join( map( str, __version_info__ ))

0 commit comments

Comments
 (0)