o
    Ji $                     @   sh  d Z ddlZddlZddlmZmZ dededefddZdededefd	d
ZdedefddZ	dededefddZ
dee dedefddZd'deeeef  dedefddZ		d(dedededeeeef  fddZdeeeef  defddZ		d(dedededeeeef  fd d!Zdeeeef  defd"d#Zd$d% Zed&kre  dS dS ))u  
Shamir's Secret Sharing for BIP39 Mnemonics

Splits a mnemonic into N shares where any K shares can reconstruct it.
Default: 2-of-3 scheme.

Share distribution:
  Share 1: User writes down (paper, sealed envelope)
  Share 2: Encrypted to user's personal email
  Share 3: Stored on device (hardware-bound via OP-TEE HUK if available)

Any 2 of 3 shares reconstruct the mnemonic.

Uses GF(256) arithmetic for the secret sharing — each byte of the
mnemonic entropy is split independently.

Usage:
    from shamir import split_secret, combine_shares

    shares = split_secret(b"secret data", threshold=2, num_shares=3)
    # shares = [(1, b"..."), (2, b"..."), (3, b"...")]

    recovered = combine_shares([(1, shares[0][1]), (3, shares[2][1])])
    assert recovered == b"secret data"
    N)ListTupleabreturnc                 C   s   | |A S )zAddition in GF(256) is XOR. r   r   r   r   3/home/geodesix/Jetson/tests/../src/crypto/shamir.py
_gf256_add#   s   r
   c                 C   sN   d}t dD ]}|d@ r|| N }| d@ }| d> d@ } |r | dN } |dL }q|S )z?Multiplication in GF(256) using Russian peasant multiplication.r                  )range)r   r   p_hir   r   r	   
_gf256_mul'   s   
r   c                 C   sD   | dkrt d| }tdD ]}t||}t|| }qt||}|S )zDMultiplicative inverse in GF(256) via exponentiation (a^254 = a^-1).r   zNo inverse for 0 in GF(256)   )ZeroDivisionErrorr   r   )r   resultr   r   r   r	   
_gf256_inv4   s   

r   c                 C   s   t | t|S )zDivision in GF(256).)r   r   r   r   r   r	   
_gf256_div@   s   r   coeffsxc                 C   s&   d}t | D ]
}tt|||}q|S )z=Evaluate polynomial at x in GF(256). coeffs[0] is the secret.r   )reversedr
   r   )r   r   r   coeffr   r   r	   _eval_polynomialE   s   r   sharesc                 C   s   t | }d}t|D ];}| | \}}d}d}t|D ]}	||	kr!q| |	 d }
t|t||
}t|t||
}qt|t||}t||}q
|S )zDLagrange interpolation at x in GF(256) to recover the secret (f(0)).r   r   )lenr   r   r
   r   )r   r   kr   ixiyinumdenjxjtermr   r   r	   _lagrange_interpolateM   s   r*         secret	threshold
num_sharesc                    s   ||krt d|dk rt d|dkrt ddd t|D  | D ]%}|gdd t|d	 D  }t|D ]}|d	 } | t|| q7q# fd
dt|D S )aX  
    Split a secret into shares using Shamir's Secret Sharing.

    Args:
        secret: The secret to split (arbitrary bytes)
        threshold: Minimum shares needed to reconstruct (K)
        num_shares: Total shares to generate (N)

    Returns:
        List of (share_index, share_data) tuples.
        share_index is 1-based (1..N).
    z(Threshold cannot exceed number of sharesr+   zThreshold must be at least 2r   z"Maximum 255 shares (GF(256) limit)c                 S   s   g | ]}t  qS r   )	bytearray.0r   r   r   r	   
<listcomp>z   s    z split_secret.<locals>.<listcomp>c                 S   s   g | ]}t d qS )   )secrets	randbelowr1   r   r   r	   r3   ~   s    r   c                    s    g | ]}|d  t  | fqS )r   )bytes)r2   r"   r   r   r	   r3           )
ValueErrorr   appendr   )r-   r.   r/   byter   r"   r   r   r8   r	   split_secretb   s   r=   c                    sx   | st dt| d d tfdd| D st dt }tD ]  fdd| D }|t|d q$t|S )	z
    Reconstruct a secret from shares.

    Args:
        shares: List of (share_index, share_data) tuples.
                Need at least threshold shares.

    Returns:
        The reconstructed secret bytes.
    zNo shares providedr   r   c                 3   s     | ]}t |d   kV  qdS )r   N)r    r2   s)lengthr   r	   	<genexpr>   s    z!combine_shares.<locals>.<genexpr>z"All shares must be the same lengthc                    s    g | ]}|d  |d   fqS )r   r   r   r>   )byte_idxr   r	   r3      r9   z"combine_shares.<locals>.<listcomp>)r:   r    allr0   r   r;   r*   r7   )r   r   pointsr   )rB   r@   r	   combine_shares   s   rE   mnemonicc                 C   s$   |  d}t|||}dd |D S )z
    Split a BIP39 mnemonic into Shamir shares.

    Returns shares as (index, hex_string) tuples for easy storage/display.
    utf-8c                 S   s   g | ]
\}}||  fqS r   )hex)r2   idxdatar   r   r	   r3      s    z"split_mnemonic.<locals>.<listcomp>)encoder=   )rF   r.   r/   r-   
raw_sharesr   r   r	   split_mnemonic   s   

rM   c                 C   s    dd | D }t |}|dS )zy
    Reconstruct a BIP39 mnemonic from Shamir shares.

    Args:
        shares: List of (index, hex_string) tuples.
    c                 S   s   g | ]\}}|t |fqS r   )r7   fromhex)r2   rI   hex_datar   r   r	   r3      s    z+combine_mnemonic_shares.<locals>.<listcomp>rG   )rE   decode)r   rL   r-   r   r   r	   combine_mnemonic_shares   s   
rQ   c                  C   s  dd l } dd l}| jdd}|jdd}|jddd}|jd	d
dd |jddtddd |jddtddd |jddd}|jddd
dd |jddd}| }|jdkrt	|j
|j|j}tdt| d|j d |D ]\}	}
td |	 d!|
  qptd"|j d# d S |jdkrg }|jD ]}|d$d%\}}
|t||
f qt|}td&| d' d S |jdkritd( d)}t|dd}t|d |d% g|ksJ d*t|d |d g|ksJ d+t|d% |d g|ksJ d,td- t|dd.}t|d |d |d/ g|ksJ d0td1 d2}t	|dd}t|d |d g}||ks5J d3td4 d5D ]#}tt|gdd}t|d |d gt|gks]J d6| q;td7 td8 d S |  d S )9Nr   z"Shamir's Secret Sharing for Hermes)descriptioncommand)destsplitzSplit a mnemonic into shares)helpz
--mnemonicTzBIP39 mnemonic to split)requiredrV   z--thresholdz-kr+   zShares needed (default: 2))typedefaultrV   z--sharesz-nr,   zTotal shares (default: 3)combinez Reconstruct mnemonic from shares+z7Shares as 'index:hex' pairs (e.g., '1:ab12ef 3:cd34gh'))nargsrW   rV   testzRun self-testz
Mnemonic split into z shares (need z to recover):
z  Share z: z
Store these separately. Any z% shares can reconstruct the mnemonic.:r   z
Recovered mnemonic:
  
z,Running Shamir's Secret Sharing self-test...s   hello world testzFailed: shares 1,2zFailed: shares 1,3zFailed: shares 2,3z  [PASS] 2-of-3 basic      zFailed: 3-of-5z  [PASS] 3-of-5z]abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon aboutzFailed: mnemonic recoveryz  [PASS] Mnemonic round-trip)r   r      r      r   zFailed: byte z.  [PASS] Edge cases (0, 1, 127, 128, 254, 255)z
All tests passed!)argparsejsonArgumentParseradd_subparsers
add_parseradd_argumentint
parse_argsrS   rM   rF   r.   r   printr    rU   r;   rQ   r=   rE   r7   
print_help)rd   re   parsersub	split_cmdcombine_cmdtest_cmdargsr   rI   rO   parsedr?   idx_strrF   r-   shares5m_shares	recoveredvalr   r   r	   main   sb   



   (2rz   __main__)r   )r+   r,   )__doc__osr5   typingr   r   rj   r
   r   r   r   r   r*   r7   r=   rE   strrM   rQ   rz   __name__r   r   r   r	   <module>   sL   $
&#
F
