Implementar la reconstrucción de Shamir's Secret Sharing


11

El esquema de intercambio de secretos de Shamir es una forma simple de proteger un secreto dividiéndolo en varias partes necesarias para reconstruirlo.

Su tarea es implementar la reconstrucción de Shamir's Secret Sharing sobre el campo finito definido por el primo 1928049029. Si tiene alguna duda sobre lo que esto significa, solo pregunte o vea Campo finito y Aritmética de campo finito en wikipedia (más recursos a continuación).

Entrada

La entrada se realiza usando stdin. Primero viene un número entero k, luego siguen las líneas k. Cada una de estas líneas contiene un par de enteros x yque representan un secreto. En otras palabras, f(x) = yen el polinomio original que se utilizó para construir los secretos.

El número de secretos dados siempre es suficiente para construir el secreto correspondiente.

Salida

Salida para stdout el secreto reconstruido.

Ejemplos

Entrada:

5         
1 564797566
2 804114535
4 1354242660
6 1818201132
7 503769263

Salida:

1234

Entrada:

7
1 819016192
2 1888749673
3 1737609270
4 365594983
5 1628804870
6 1671140873
7 492602992

Salida:

456457856

Recursos

Artículo de Wikipedia

Papel

Campo finito Fuente: Wikipedia

Aritmética de campo finito Fuente: Wikipedia

Polinomio de Lagrange Fuente: Wikipedia

Capítulo sobre aritmética de campo finito

Respuestas:


4

bash, 271 caracteres

r () {
[$ {1/0 /}] && {r $ (($ 2% $ 1)) $ 1; ((t = u, u = v- $ 2 / $ 1 * u, v = t));}
}
leer
((N = 1928049029, n = 0))
mientras lee x [$ n] y [$ n]
hacer ((n ++))
hecho
para ((i = n; z = (z + l)% N, i -;)) do
para ((j = n, l = y [i]; j -;)) do
((u = 0, v = 1, d = x [j] -x [i], M = N + d))
r MN
[$ {d / 0 /}] && ((l = l * x [j]% N * (u + N)% N))
hecho
hecho
echo $ z

Las nuevas líneas podrían reemplazarse en la mayoría de los casos con punto y coma, pero no creo que haya espacios en blanco innecesarios.

(No me había dado cuenta hasta hoy que los enteros de bash son de 64 bits, muy útil).

Para bash, el GCD recursivo (explotación del estado global) parece ser más compacto que el iterativo. Esto es principalmente sencillo; el truco interesante es [ ${d/0/} ]&&foocuál es efectivamenteif [ $d -ne 0 ];then foo;fi


¡Agradable! Nunca esperé ver una respuesta contundente a este problema. +1
Juan

@Juan, comencé a hacerlo en Perl, y me cansé de tener que obligarlo a hacer una división entera en lugar de flotar. Y sé que golpear mejor de todos modos, así que implica menos golpes de cabeza contra la pared.
Peter Taylor

3

199 caracteres en octava:

m=@(x)mod(x,1928049029);[d,l]=scanf('%d');c=d(1);e=repmat(int64(d(2:2:l)),1,c);[_,b]=gcd(e-e',1928049029*ones(c));b=eye(c)+m(e.*b);x=b(1,:);for i=2:c;x=m(x.*b(i,:));end;disp(m(sum(m(x'.*d(3:2:l)))))

3

Golfscript, 114 112 111 110 109 65 (86) caracteres

Si no le interesa obtener resultados esta semana, 65 caracteres son suficientes:

~](;2/0\:X{~\.X{0=}%^\{\.@- 1928049029:P.,\@{@*\%(!}++?**}+/+P%}/

Pero si buscas eficiencia, es un poco más largo con 86 caracteres:

~](;2/0\:X{~\.X{0=}%^\{\[.0](@-[1928049029:P%P]{.~/{\.(;@@~@*-+\}+2*.1=}do;0=*}+/+P%}/

Esto se analiza con mucho más detalle de lo que quiero repetir aquí en mi blog .


Principalmente no es mi trabajo, pero el hecho de que Nabb se mueva fuertemente da 47 caracteres:

n%(!\:A{~A{~;.3$- 1928049029:N((?1or**}/\/+N%}/

Nota: Solo he razonado sobre este código: intentar ejecutarlo no tendría sentido dada la cantidad de tiempo y la cantidad de memoria que usaría.


3

Golfscript - 52 46 (67)

Un enfoque de fuerza bruta para inversas modulares en 46 caracteres. Calcula repetidamente a ^ (N-2) con enteros de precisión arbitraria.

n%(!\:A{~A{~;.3$-.!+1928049029:N((?**}/\/+N%}/

La implementación del algoritmo euclidiano extendido solo nos cuesta 15 caracteres adicionales.

n%(!\:A{~A{~;.3$-:|!1\1928049029:N{@2$|3$/*-\|\:|%.}do;;**}/\/+N%}/

Este código está completamente detallado en mi publicación de blog , incluidas algunas alternativas para calcular el inverso multiplicativo modular.


1
Bien, pero creo que todavía hay al menos dos caracteres para guardar. Reemplace {*N%2<}con {*N%1=}como en el blog y puede deshacerse del (;después N,. Pero luego, para la entrada de rendimiento es irrelevante, puede usar el pequeño teorema de Fermat sin preocuparse por el lado modular de la exponenciación, solo déjelo para el orden final, de modo que recip se convierta N((?.
Peter Taylor

1
@Peter: {*N%1=}+perderá el caso con el denominador cero, que tomaría al menos 3 caracteres para manejar. Sin embargo, es bueno hacer simplemente x ^ (N-2), de hecho podemos obtener 46 caracteres con esto.
Nabb

2

Lua 444 Chars

Funciona para el ejemplo en la página wiki

3
2 1942
4 3402
5 4414

Pero de alguna manera no funciona para los ejemplos aquí en esta página. Si alguien puede encontrar el error?

Versión sin golf:

-- Reconstruct shamir secret
-- convention, poly = {[0]=a0,a1,...,an}
i=io.read
f=math.fmod
w=1928049029
k=i():match"%d+"
x={} -- Will contain X values
y={} -- Will contain Y values
p={} -- will contain lagrange polynomials

-- Read data
for j=0,k-1 do
    x[j],y[j]=i():match("(%d+) (%d+)")
    print(j,x[j],y[j])
end
-- Multiplication and scaling function
function mul(p,q,s)
    -- multiply polies
    r={} -- poly to be returned
    for k=0,#p do 
        for l=0,#q do
            r[l+k]=r[l+k] or 0 -- if the coeff for degree l+k of x doesn't exist, put 0
            p[k]=p[k] or 0 -- if p hasn't got a coeff for x^k
            q[l]=q[l] or 0 -- idem for q
            r[l+k]=(r[l+k]+s*p[k]*q[l]%w -- calculate increment for coeff for x^(l+k) 
        end
    end
    -- Debugging
    io.write"Multiplied "
    printPoly(p)
    io.write"With       "
    printPoly(q)
    io.write("And scaling factor ",tostring(s),"\n")
    io.write"Yielding   "
    printPoly(r)
    return r
end

function printPoly(p) -- "Pretty" printing of the polynomial
    for k=#p,1,-1 do
        io.write(tostring(p[k] or 0),"x^",tostring(k),"+")
    end
    io.write(p[0])
    io.write"\n"
end
function egcd(a,b)
    if a == 0 then
        return b, 0, 1
    else
        local g, y, x = egcd(b % a, a)
        return g, x - math.floor(b / a) * y, y
    end
end

function inv(a,m)
    a=a>=0 and a or a+m
    local g,x,y = egcd(a,m)
    if g== 1 then
        return x%m
    else
        print(a,"has no inverse mod",m)
    end
end


-- generate lagrange polynomials
for j=0,#x do
    print("j=",j,"*********")
    for m=0,k-1 do
        if m~=j then -- if m==j, continue
            p[j]=p[j]or{[0]=1} -- if this poly doesn't exist, take 1
            p[j]=mul( p[j], {[0]=-x[m],1},inv(x[j]-x[m],w))-- multiply with (x-x_m)/(x_j-x_m)
            io.write"---------------------------------\n"
        end
    end
end
r=0 -- Result for x^0
for k=0,#p do
    print("l_"..k)
    printPoly(p[k]) -- print l_k
    r=r+f(y[k]*p[k][0],w) -- add coeff for x^0 to result
end
print("Secret was",f(r,w)) -- display result

Golfizado (sin campo finito), 444 caracteres:

i=io.read f=math.fmod w=1928049029 k=i():match"%d+"x={}y={}p={}for j=0,k-1 do x[j],y[j]=i():match("(%d+) (%d+)")end
function mul(p,q,s)r={}for k=0,#p do for l=0,#q do r[l+k]=r[l+k]or 0 p[k]=p[k]or 0 q[l]=q[l]or 0 r[l+k]=f(r[l+k]+s*p[k]*q[l],w)end end return r end
for j=0,#x do for m=0,k-1 do if m~=j then p[j]=p[j]or{[0]=1}p[j]=mul(p[j],{[0]=-x[m],1},1/(x[j]-x[m]))end end end r=0 for k=0,#p do r=r+f(y[k]*p[k][0],w)end
print(f(r,w))

El ejemplo de Wikipedia no usa un campo finito, lo cual es realmente una pena, eso habría sido mucho más instructivo. Es muy probable que sea la fuente de su error.
aaaaaaaaaaaa

2

Java, 435 407 caracteres

import java.util.*;public class G{public static void main(String[]args){Scanner s=new Scanner(System.in);int i,k,n=s.nextInt();long N=1928049029L,x[]=new long[n],y[]=new long[n],z=0,l,c;for(i=n;i-->0;){x[i]=s.nextInt();y[i]=s.nextInt();}for(i=n;i-->0;){l=y[i];for(long j:x)if(x[i]!=j){c=1;for(long a=N+j-x[i],b=N,d=0,t;b>0;){t=d;d=c-a/b*d;c=t;t=b;b=a%b;a=t;}l=l*j%N*(c+N)%N;}z+=l;}System.out.println(z%N);}}

Sin golf:

import java.util.*;
public class G {
    public static void main(String[] args) {
        Scanner s=new Scanner(System.in);
        int i,k,n=s.nextInt();
        long N=1928049029L,x[]=new long[n],y[]=new long[n],z=0,l,c;
        for (i=n; i-->0;) {
            x[i]=s.nextInt();
            y[i]=s.nextInt();
        }
        for (i=n; i-->0;) {
            l=y[i];
            for (long j:x)
                if (x[i]!=j) {
                    // Extended Euclid algorithm - iterative version -
                    // to find the reciprocal of j-x[i] (mod N)
                    c=1;
                    for (long a=N+j-x[i], b=N, d=0, t; b>0;) {
                        t=d; d=c-a/b*d; c=t;
                        t=b; b=a%b; a=t;
                    }
                    l = l*j%N;
                    l = l*(c+N)%N;
                }
                z+=l;
        }
        System.out.println(z%N);
    }
}

2

Haskell, 183

p=1928049029
a#0=(1,0)
a#b=let(s,t)=b#mod a b in(t,s-div a b*t)
s d=sum[y*product[z*fst((z-x)#p)|[z,_]<-d,z/=x]|[x,y]<-d]
main=interact$show.(`mod`p).s.map(map read.words).tail.lines
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.