Implementiere Shamirs Secret Sharing-Rekonstruktion


11

Shamirs geheimes Freigabeschema ist eine einfache Möglichkeit, ein Geheimnis zu schützen, indem es in mehrere Teile aufgeteilt wird, die für die Rekonstruktion erforderlich sind.

Ihre Aufgabe ist es, Shamirs Rekonstruktion der geheimen Teilung über das durch die Primzahl definierte endliche Feld zu implementieren 1928049029. Wenn Sie Zweifel haben, was dies bedeutet, fragen Sie einfach nach oder sehen Sie sich Finite Field & Finite Field Arithmetic in Wikipedia an (weitere Ressourcen unten).

Eingang

Die Eingabe erfolgt mit stdin. Zuerst kommt eine ganze Zahl k, dann folgen k Zeilen. Jede dieser Zeilen enthält ein Paar Ganzzahlen x y, die ein Geheimnis darstellen. Mit anderen Worten f(x) = yim ursprünglichen Polynom, das zur Konstruktion der Geheimnisse verwendet wurde.

Die Anzahl der angegebenen Geheimnisse reicht immer aus, um das entsprechende Geheimnis zu konstruieren.

Ausgabe

Ausgabe, um das rekonstruierte Geheimnis herauszufinden.

Beispiele

Eingang:

5         
1 564797566
2 804114535
4 1354242660
6 1818201132
7 503769263

Ausgabe:

1234

Eingang:

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

Ausgabe:

456457856

Ressourcen

Wikipedia-Artikel

Papier

Endliches Feld Quelle: Wikipedia

Endliche Feldarithmetik Quelle: Wikipedia

Lagrange-Polynom Quelle: Wikipedia

Kapitel über endliche Feldarithmetik

Antworten:


4

Bash, 271 Zeichen

r () {
[$ {1/0 /}] && {r $ (($ 2% $ 1)) $ 1; ((t = u, u = v- $ 2 / $ 1 * u, v = t));}
}}
lesen
((N = 1928049029, n = 0))
während Sie x [$ n] y [$ n] lesen
do ((n ++))
erledigt
für ((i = n; z = (z + l)% N, i -;)) tun
für ((j = n, l = y [i]; j -;)) tun
((u = 0, v = 1, d = x [j] -x [i], M = N + d))
r MN
[$ {d / 0 /}] && ((l = l * x [j]% N * (u + N)% N))
erledigt
erledigt
echo $ z

Die Zeilenumbrüche könnten in den meisten Fällen durch Semikolons ersetzt werden, aber ich glaube nicht, dass unnötige Leerzeichen vorhanden sind.

(Ich hatte bis heute nicht bemerkt, dass die Ganzzahlen von bash 64-Bit sind - sehr hilfreich).

Für Bash scheint die rekursive GCD (Ausnutzung des globalen Zustands) kompakter zu sein als die iterative. Dies ist meist unkompliziert; Der interessante Trick ist, [ ${d/0/} ]&&foowelcher effektiv istif [ $d -ne 0 ];then foo;fi


Nett! Ich hätte nie erwartet, eine Bash-Antwort auf dieses Problem zu sehen. +1
Juan

@Juan, ich habe angefangen, es in Perl zu machen, und hatte es satt, es zwingen zu müssen, eine Ganzzahldivision durchzuführen, anstatt zu schweben. Und ich weiß, dass Bash sowieso besser ist, so dass weniger Kopf gegen Wand geschlagen wird.
Peter Taylor

3

199 Zeichen in Oktave:

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

Wenn Sie diese Woche keine Ergebnisse erzielen möchten, reichen 65 Zeichen aus:

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

Wenn Sie jedoch nach Effizienz suchen, ist sie mit 86 Zeichen etwas länger:

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

Dies wird weitaus detaillierter analysiert, als ich hier in meinem Blog wiederholen möchte .


Hauptsächlich nicht meine Arbeit, aber das starke Cribbing von Nabb ergibt 47 Zeichen:

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

Hinweis: Ich habe nur über diesen Code nachgedacht: Der Versuch, ihn auszuführen, wäre angesichts der Zeitdauer und der Menge des verwendeten Speichers sinnlos.


3

Golfscript - 52 46 (67)

Ein Brute-Force-Ansatz für modulare Inversen in 46 Zeichen. Berechnet wiederholt ein ^ (N-2) mit Ganzzahlen beliebiger Genauigkeit.

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

Die Implementierung des erweiterten euklidischen Algorithmus kostet uns nur zusätzliche 15 Zeichen.

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

Dieser Code ist in meinem Blog-Beitrag ausführlich beschrieben , einschließlich einiger Alternativen zur Berechnung der modularen multiplikativen Inversen.


1
Schön, aber ich denke, es müssen noch mindestens zwei Zeichen gespeichert werden. Ersetzen Sie {*N%2<}mit , {*N%1=}wie in dem Blog , und Sie können den Graben (;nach N,. Aber dann können Sie für den Eintrag "Leistung ist irrelevant" den kleinen Satz von Fermat verwenden, ohne sich um die modulare Seite der Potenzierung zu kümmern - lassen Sie das einfach für die endgültige Ordnung -, damit das Rezept wird N((?.
Peter Taylor

1
@Peter: Verpasst {*N%1=}+den Fall mit dem Nenner Null, für dessen Bearbeitung mindestens 3 Zeichen erforderlich wären. Guter Fang, einfach x ^ (N-2) zu machen, wir können damit tatsächlich 46 Zeichen erhalten.
Nabb

2

Lua 444 Zeichen

Funktioniert für das Beispiel auf der Wiki-Seite

3
2 1942
4 3402
5 4414

Aber irgendwie funktioniert das für die Beispiele hier auf dieser Seite nicht. Kann jemand den Fehler finden?

Nicht-Golf-Version:

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

Golf (ohne endliches Feld), 444 Zeichen:

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

Das Wikipedia-Beispiel verwendet kein endliches Feld, was wirklich schade ist, das wäre viel lehrreicher gewesen. Das ist höchstwahrscheinlich die Quelle Ihres Fehlers.
aaaaaaaaaaaa

2

Java, 435 407 Zeichen

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

Ungolfed:

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.