샤미르의 비밀 나눔


17

주어진 n(플레이어 수), t(임계 값) 및 s(비밀) nShamir의 비밀 공유 알고리즘에 의해 생성 된 비밀을 출력합니다 .

알고리즘

이 도전의 목적을 위해, 계산은 GF (251) (크기의 유한 필드 251, 그렇지 않으면 정수 mod 251 로 알려진 ) 에서 수행 될 것이다 . 일반적으로 필드의 크기가보다 큰 소수를 갖도록 선택 n됩니다. 도전을 단순화하기 위해 필드 크기는 일정합니다. 251부호없는 8 비트 정수로 표현할 수있는 가장 큰 소수이므로 선택되었습니다.

  1. t-1(포함) 범위에서 임의의 정수를 생성하십시오 [0, 250]. 이 a 1 에서 t-1 까지 레이블을 지정하십시오 .
  2. 컨스 t-1사용 번째 다항식 s상수 값으로 그리고 힘의 계수로서 1 단계의 임의의 정수 x: F (X) = S + X *는 1 + X (2) *는 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, 및 nt보다 적은 양의 정수 것 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 페어 포인트.
Mego

모든 테스트 케이스?
Leaky Nun

4
@LeakyNun이 질문은 random 태그로 지정되었으므로 확인 스 니펫은 각 실행마다 달라지는 테스트 사례보다 훨씬 가치가 있다고 생각합니다.
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
마지막 정수를 교체하는 것은 매우 우아합니다 :)
Lynn

8

Mathematica, 59 56 바이트

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

t , ns 순서로 세 개의 인수를 사용합니다 . n 개의 행과 t -1 개의 열로 2 차원 배열을 구성합니다 . 1부터 n 까지 번호가 매겨진 각 행 벡터 j 에는 j ~ j t -1 의 거듭 제곱이 포함 됩니다. 그 다음, 0 내지 250 범위의 랜덤 정수 계수의 벡터가 t -1 값으로 생성된다 . 이는 2d- 배열과 행렬 곱한 다음, s 를 요소 단위로 더하고 n 개의 각각의 포인트 에서 다항식의 값을 얻기 위해 모듈 (251)을 취한다 .


1
79 바이트 답변을 게시하려고했지만 멋진 트릭입니다 Sum!
LegionMammal978

1
다른 접근 방식이 있지만 현재 2 바이트가 더 깁니다. 어쩌면 당신은 그것을 단축하는 방법을 알고있다 :Mod[x#+#2&~Fold~RandomInteger[250,#2-1]x+#3/.x->Range@#,251]&
Martin Ender



3

자바 스크립트, 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 _;
}

제대로 확인하는 방법을 모르지만 .map정의되지 않은 값을 건너 뛰기 때문에 JS가 새 배열을 통해 매핑하는 것이 고통 스럽다는 것을 알고 있습니다. 누구든지 개선 또는 결함을 발견 할 수있는 방법을 알고 있다면 주저하지 말고 알려주십시오.


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

사용하지 않는 n것 같습니다. 귀하의 코드는 1 기반 인덱싱을 가정하는 것 같습니다. [...Array()]보다 약간 짧습니다 fiil(). 또한 마지막 두 줄을 다음과 같이 줄일 수 있습니다.return _.map(f);
Neil

3

C #, 138134 바이트

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

입력이 int있고 출력이 C # 람다 인 경우 IEnumerable<double>. .NetFiddle에서 내 코드를 사용해 볼 수 있습니다 .

내 알고리즘의 유효성에 대해 100 % 확신하지 못합니다. 무언가를 잘못 이해하면 의견을 말하십시오.

@ raggy 's trick으로 4 바이트가 저장되었습니다 .


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

자바 스크립트 (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

NumPy가있는 Python 3 , 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 , ts 인 목록을 가져옵니다 .

@ Dennis 's solutionindex at index 0 아이디어를 사용하여 2 바이트를 절약했습니다 .

설명

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

자바 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.

온라인으로 사용해보십시오! (아이디어)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.