La condivisione segreta di Shamir


17

Dato n(il numero di giocatori), t(il valore di soglia) e s(il segreto), ngenera i segreti generati dall'algoritmo Shamir's Secret Sharing .

L'algoritmo

Ai fini di questa sfida, i calcoli verranno eseguiti in GF (251) (il campo di dimensioni finito 251, altrimenti noto come numeri interi mod 251 ). Di solito, il campo sarebbe scelto in modo tale che la sua dimensione sia un numero molto maggiore di n. Per semplificare la sfida, la dimensione del campo sarà costante. 251è stato scelto perché è il primo più grande rappresentabile da un numero intero senza segno a 8 bit.

  1. Genera t-1numeri interi casuali nell'intervallo (inclusivo) [0, 250]. Etichettare questi un 1 attraverso un t-1 .
  2. Costruisci un t-1polinomio di secondo grado usando scome valore costante e gli interi casuali dal passaggio 1 come coefficienti dei poteri di x: f (x) = s + x * a 1 + x 2 * a 2 + ... + x t- 1 * a t-1 .
  3. Output (f(z) mod 251)per ciascuno znel range (incluso) [1, n].

Implementazione di riferimento

#!/usr/bin/env python
from __future__ import print_function
import random
import sys

# Shamir's Secret Sharing algorithm
# Input is taken on the command line, in the format "python shamir.py n t s"

n, t, s = [int(x) for x in sys.argv[1:4]]
if t > n:
    print("Error: t must be less than or equal to n")
    exit()
if n not in range(2, 251):
    print("Error: n must be a positive integer less than 251")
    exit()
if t not in range(2, 251):
    print("Error: t must be a positive integer less than 251")
    exit()
if s not in range(251):
    print("Error: s must be a non-negative integer less than 251")
    exit()
p = 251
a = [random.randrange(0, 251) for x in range(t-1)]

def f(x):
    return s + sum(c*x**(i+1) for i,c in enumerate(a))

# Outputting the polynomial is for explanatory purposes only, and should not be included
#  in the output for the challenge
print("f(x) = {0} + {1}".format(s, ' + '.join('{0}*x^{1}'.format(c, i+1) for i,c in enumerate(a))))
for z in range(1, n+1):
    print(f(z) % p)

Verifica

Il seguente frammento di stack può essere utilizzato per verificare gli output:

Regole

  • ssarà un numero intero non negativo minore di 251e ne tsarà un numero intero positivo minore di 251e maggiore di1 . Inoltre, hai la garanzia che gli input siano validi (significato t <= n).
  • L'input e l'output possono essere in qualsiasi formato ragionevole, inequivocabile e coerente.
  • I numeri casuali devono essere campionati da una distribuzione uniforme - ogni valore possibile dovrebbe avere la stessa probabilità di essere scelto.

1
Dobbiamo produrre z e f(z) ? Se stampo una matrice di f(z)s in ordine, zè implicito dall'indice. [[1, 5], [2, 2], [3, 9], [4, 14]]non contiene più informazioni di [5, 2, 9, 14].
orlp,


@orlp Fair point.
Mego

Qualche testcase?
Leaky Nun,

4
@LeakyNun Dal momento che questa domanda è taggata in modo casuale , penso che lo snippet di verifica sia molto più prezioso dei casi di test che varieranno ad ogni esecuzione.
FryAmTheEggman

Risposte:


13

Gelatina , 15 byte

251©xX€⁵0¦ḅЀ%®

Si aspetta t , n e s come argomenti della riga di comando. Provalo online!

Come funziona

251©xX€⁵0¦ḅЀ%®  Main link. Left argument: t. Right argument: n Third argument: s

251©             Yield 251 and copy it to the register.
    x            Repeat [251] t times.
     X€          Random choice each; pseudo-randomly choose t integers from
                 [1, ..., 251]. Since 251 = 0 (mod 251), this is equivalent to
                 choosing them from [0, ..., 250].
       ⁵0¦       Replace the last generated integer (index 0) with s (⁵).
          ḅЀ    Interpret the resulting array as a base-k number, for each k in
                 [1, ..., n], and convert to integer.
              ®  Yield 251 from the register.
             %   Take the generated integers modulo 251.

3
La sostituzione dell'ultimo numero intero è così elegante :)
Lynn

8

Mathematica, 59 56 byte

Mod[Power~Array~{#2,#-1}.RandomInteger[250,#-1]+#3,251]&

Accetta tre argomenti nell'ordine t , n e s . Costruisce un array 2d con n righe e colonne t -1. Ogni vettore di riga j , numerato da 1 a n , contiene i poteri di j thru j t -1 . Quindi viene creato un vettore di coefficienti interi casuali nell'intervallo da 0 a 250 con valori di t -1. Ciò viene moltiplicato per matrice con la matrice 2d, quindi s viene aggiunto in termini di elementi e prende il modulo 251 per ottenere il valore del polinomio in ciascuno degli n punti.


1
Stavo per pubblicare una risposta di 79 byte, un bel trucco con Sum!
LegionMammal978,

1
Ho un approccio diverso, ma attualmente è più lungo di due byte. Forse hai idea di come accorciarlo:Mod[x#+#2&~Fold~RandomInteger[250,#2-1]x+#3/.x->Range@#,251]&
Martin Ender,



3

JavaScript, 181 byte

(n,t,s)=>{r=Array(t-1).fill(0).map($=>{return Math.random()*251});f=(x=>{p = 0;r.map((k,c)=>p+=k*Math.pow(x, c));return s+p});_=Array(t-1).fill(0);_.map((l,i)=>_[i]=f(i));return _;}

Ungolfed:

(n, t, s) => {
    r = Array(t - 1).fill(0).map($ =>{return Math.random() * 251});
    f = (x => {
        p = 0;
        r.map((k, c) => p += k * Math.pow(x, c));
        return s + p
    });
    _ = Array(t - 1).fill(0);
    _.map((l, i) => _[i] = f(i));
    return _;
}

Non so come controllarlo correttamente, ma so che è stato difficile far mappare JS su un nuovo array poiché apparentemente .mapsalta valori indefiniti. Se qualcuno vede qualche modo per migliorare, o difetti, non esitate a farmelo sapere.


123 byte:(n,t,s,A=f=>Array(t-1).fill(0).map(f),r=A($=>Math.random()*251))=> A((l,i,_,p=0)=>(r.map((k,c)=>p+=k*Math.pow(i,c)),s+p))
Dendrobium

Non stai usando n, il che sembra sbagliato. Il tuo codice sembra assumere anche l'indicizzazione basata su 1. [...Array()]è leggermente più corto di fiil(). Inoltre, le ultime due righe possono essere ridotte areturn _.map(f);
Neil

3

C #, 138 134 byte

(n,t,s)=>new int[n+1].Select((_,x)=>(s+new int[t-1].Select(k=>new Random(e).Next(251)).Select((c,i)=>c*Math.Pow(x+1,i+1)).Sum())%251);

C # lambda dove sono presenti gli input inte l'output è un IEnumerable<double>. Puoi provare il mio codice su .NetFiddle .

Non sono sicuro al 100% della validità del mio algoritmo, per favore commenta se ho frainteso qualcosa.

4 byte salvati con il trucco di @ raggy .


3

MATL , 20 19 byte

251tliq3$Yrihi:ZQw\

Ordine di ingresso è t, s, n.

Provalo online!

Spiegazione

251t    % Push 251 twice
l       % Push 1
iq      % Take input t. Subtract 1
3$Yr    % Generate t-1 random integers in [1 2 ... 251]
ih      % Take input s. Concatenate with the random integers
i:      % Take input n. Generate range [1 2 ... n]
ZQ      % Evvaluate polynomial at those values
w       % Swap to move copy og 251 to the top of the stack
\       % Modulo. Implicitly display


1

JavaScript (ES6), 116 byte

(n,t,s)=>[...Array(n)].map((_,i)=>++i&&t.reduce((r,a)=>r*i+a)%251,t=[...Array(t)].map(_=>--t?Math.random()*251|0:s))

Mi piacerebbe pensare che questo sia uno dei rari casi in cui reducebatte map.


1

Python 3 con NumPy , 103 byte

from numpy import*
lambda n,t,s:[poly1d(append(random.randint(0,251,t-1),s))(i+1)%251for i in range(n)]

Posso onestamente dire che non mi sarei mai aspettato di usare NumPy per il golf del codice ...

Una funzione anonima che accetta input tramite argomento e restituisce un elenco.

Come funziona

from numpy import*         Import everything in the NumPy library
lambda n,t,s...            Function with input number of players n, threshold value t and
                           secret s
random.randint(0,251,t-1)  Generate a NumPy array R of t-1 random integers in [0,250]
append(...,s)              Append s to R
poly1d(...)                Generate a polynomial p of order t-1 with coefficients R and
                           constant term s
...for i in range(n)       For all integers i in [0,n-1]...
...(i+1)                   ...evaluate p(i+1), so for all integers in [1,n]...
...%251                    ...and take modulo 251
...:[...]                  return as list

Provalo su Ideone


1

J , 32 30 byte

251|(1+i.@{.)p.~{:0}251?@#~1&{

Prende un elenco con i valori n , t e s .

Hai salvato 2 byte usando l' idea di sostituzione all'indice 0 dalla soluzione di @Dennis .

Spiegazione

251|(1+i.@{.)p.~{:0}251?@#~1&{  Input: [n t s]
                           1&{  Select at index 1 (t)
                    251  #~     Create that many copies of 251
                       ?@       Generate that many random integers in [0, 251)
                {:              Get the tail of the input (s)
                  0}            Replace the value at index 0 of the random integer list
                                with s to make a coefficient list of the polynomial
          {.                    Get the head of the input (n)
       i.@                      Make the range [0, n-1]
     1+                         Add 1 to each to get [1, n]
             p.~                Evaluate the polynomial at each value [1, n]
251|                            Take each value mod 251 and return

0

Java 8, 224 byte:

(n,t,s)->{int[]W=new int[t-1];for(int i=0;i<t-1;i++){W[i]=new java.util.Random().nextInt(251);};long[]O=new long[n];for(int i=1;i<=n;i++){long T=0;for(int h=1;h<t;h++){T+=W[h-1]*Math.pow(i,h);}O[i-1]=((T+s)%251);}return O;};

Un'espressione lambda di Java 8. Emette un array intero separato da virgole e funziona perfettamente fino a quando i valori nell'array output non superano l'intervallo del longtipo di dati Java o intero con segno a 64 bit, su cui-200 viene emesso l'array.

Provalo online! (Ideone)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.