Таємний обмін Шаміра


17

Враховуючи n(кількість гравців), t(порогове значення) та s(секрет), виведіть nсекрети, що генеруються алгоритмом «Таємного обміну Шаміра» .

Алгоритм

Для цілей цього виклику обчислення будуть проведені в GF (251) (кінцеве поле розміру 251, інакше відоме як цілі числа mod 251 ). Зазвичай поле було б вибране таким, щоб його розмір був просто більшим, ніж n. Щоб спростити виклик, розмір поля буде постійним. 251було обрано тому, що це найбільше просте представлене 8-бітне ціле число, яке не підписується.

  1. Створення t-1випадкових цілих чисел у (включно) діапазоні [0, 250]. Додайте ці з 1 через в Т-1 .
  2. Побудуйте t-1многочлен sпершого ступеня, використовуючи як постійне значення та випадкові цілі числа з кроку 1 як коефіцієнти потужностей x: f (x) = s + x * a 1 + x 2 * a 2 + ... + x t- 1 * a t-1 .
  3. Вихідні дані (f(z) mod 251)для кожного zв (включно) діапазоні [1, n].

Довідкова реалізація

#!/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)

Перевірка

Наступний фрагмент стека може бути використаний для перевірки результатів:

Правила

  • sбуде невід'ємним цілим числом менше 251, nі tбуде додатними цілими числами менше 251і більше, ніж 1. Крім того, ви гарантуєте, що введення є дійсними (сенс t <= n).
  • Введення та вихід можуть бути у будь-якому розумному, однозначному та послідовному форматі.
  • Випадкові числа слід вибирати з рівномірного розподілу - кожне можливе значення повинно мати однакову ймовірність вибору.

1
Чи маємо виводити z і f(z) ? Якщо я друкую масив f(z)s по порядку, zмається на увазі індекс. [[1, 5], [2, 2], [3, 9], [4, 14]]не містить більше інформації, ніж [5, 2, 9, 14].
orlp


@orlp Справедливий пункт.
Мего

Будь-які тести?
Leaky Nun

4
@LeakyNun Оскільки це запитання позначено випадковим чином , я думаю, що фрагмент перевірки набагато цінніший, ніж тестові випадки, які будуть різними для кожного запуску.
FryAmTheEggman

Відповіді:


13

Желе , 15 байт

251©xX€⁵0¦ḅЀ%®

Очікує t , n та s як аргументи командного рядка. Спробуйте в Інтернеті!

Як це працює

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
Заміна останнього цілого числа настільки елегантна :)
Лін

8

Математика, 59 56 байт

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

Бере три аргументи у порядку t , n та s . Побудує масив 2d з n рядками та t -1 стовпцями. Кожен рядовий вектор j , пронумерований від 1 до n , містить сили j через j t -1 . Потім створюється вектор випадкових цілих коефіцієнтів у діапазоні від 0 до 250 зі значеннями t -1. Це множиться на матрицю з 2d-масивом, а потім s додається елемент і береться модуль 251, щоб отримати значення полінома в кожній з n точок.


1
Якраз збирався опублікувати відповідь на 79 байт, приємний трюк Sum!
LegionMammal978

1
У мене інший підхід, але наразі це на два байти довше. Можливо, у вас є ідея, як її скоротити:Mod[x#+#2&~Fold~RandomInteger[250,#2-1]x+#3/.x->Range@#,251]&
Мартін Ендер



3

JavaScript, 181 байт

(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 _;}

Безумовно:

(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 _;
}

Я не знаю, як правильно це перевірити, але я знаю, що болісно було змусити JS відмітити новий масив, оскільки, мабуть, .mapпропускає невизначені значення. Якщо хтось бачить якісь способи покращити або недоліки, не соромтеся повідомити мене.


123 байт:(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))
Дендробіум

Ви не використовуєте n, що здається неправильним. Схоже, ваш код передбачає індексацію на основі 1. [...Array()]трохи коротше, ніж fiil(). Також останні два рядки можна зменшити доreturn _.map(f);
Ніл

3

C #, 138 134 байт

(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 # лямбда, де вхідні дані, intа вихід - це IEnumerable<double>. Ви можете спробувати мій код на .NetFiddle .

Я не на 100% впевнений у дійсності свого алгоритму, будь ласка, прокоментуйте, якщо я щось неправильно зрозумів.

4 байти збережено за допомогою хитрості @ raggy .


3

MATL , 20 19 байт

251tliq3$Yrihi:ZQw\

Вхідний замовлення t, s, n.

Спробуйте в Інтернеті!

Пояснення

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 байт

(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))

Мені хотілося б подумати, що це один з рідкісних випадків, коли reduceб’ється map.


1

Python 3 з NumPy , 103 байти

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

Я можу чесно сказати, що я ніколи не сподівався використовувати NumPy для кодового гольфу ...

Анонімна функція, яка приймає введення через аргумент і повертає список.

Як це працює

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

Спробуйте це на Ideone


1

J , 32 30 байт

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

Знімає список зі значеннями n , t і s .

Збережено 2 байта, використовуючи замінити на індекс 0 ідеї від @ Денніса рішення .

Пояснення

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 байти:

(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;};

Вираз Java 8 лямбда. Виводить цілочисельний масив, відокремлений комами, і працює ідеально, поки значення у вихідному масиві не виходять за межі діапазону типу даних Java longабо 64-бітного підписаного цілого числа, після чого -200виводяться в масив.

Спробуйте в Інтернеті! (Ідеон)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.