Melaksanakan rekonstruksi Berbagi Rahasia Shamir


11

Skema berbagi rahasia Shamir adalah cara sederhana untuk melindungi rahasia dengan memecahnya menjadi beberapa bagian yang diperlukan untuk merekonstruksi rahasia tersebut.

Tugas Anda adalah mengimplementasikan rekonstruksi Berbagi Rahasia Shamir atas Bidang Hingga yang ditentukan oleh perdana 1928049029. Jika Anda ragu tentang apa artinya ini, tanyakan atau lihat Bidang Hingga & Aritmatika Bidang Hingga di wikipedia (lebih banyak sumber daya di bawah).

Memasukkan

Input dilakukan menggunakan stdin. Pertama datang bilangan bulat k, lalu garis k mengikuti. Setiap baris ini berisi sepasang bilangan bulat x yyang mewakili rahasia. Dengan kata lain f(x) = ydalam polinomial asli yang digunakan untuk membangun rahasia.

Jumlah rahasia yang diberikan selalu cukup untuk membangun rahasia yang sesuai.

Keluaran

Output ke stdout rahasia yang direkonstruksi.

Contohnya

Memasukkan:

5         
1 564797566
2 804114535
4 1354242660
6 1818201132
7 503769263

Keluaran:

1234

Memasukkan:

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

Keluaran:

456457856

Sumber daya

Artikel Wikipedia

Kertas

Bidang terbatas Sumber: Wikipedia

Bidang hitung terbatas Sumber: Wikipedia

Sumber polinomial Lagrange : Wikipedia

Bab tentang bidang hitung hingga

Jawaban:


4

bash, 271 karakter

r () {
[$ {1/0 /}] && {r $ (($ 2% $ 1)) $ 1; ((t = u, u = v- $ 2 / $ 1 * u, v = t));}
}
Baca
((N = 1928049029, n = 0))
saat membaca x [$ n] y [$ n]
do ((n ++))
selesai
untuk ((i = n; z = (z + l)% N, i -;)) lakukan
untuk ((j = n, l = y [i]; j -;)) lakukan
((u = 0, v = 1, d = x [j] -x [i], M = N + d))
r MN
[$ {d / 0 /}] && ((l = l * x [j]% N * (u + N)% N))
selesai
selesai
echo $ z

Baris baru bisa diganti dalam banyak kasus dengan titik koma, tapi saya rasa tidak ada spasi putih yang tidak perlu.

(Saya tidak menyadari sebelumnya hari ini bahwa bash's integer 64-bit - sangat membantu).

Untuk bash, GCD rekursif (mengeksploitasi negara global) tampaknya lebih kompak daripada yang iteratif. Ini sebagian besar mudah; Trik yang menarik adalah [ ${d/0/} ]&&fooyang efektifif [ $d -ne 0 ];then foo;fi


Bagus! Saya tidak pernah berharap untuk melihat jawaban bash untuk masalah ini. +1
Juan

@Juan, saya mulai melakukannya di Perl, dan bosan harus memaksanya melakukan pembagian integer daripada mengapung. Dan aku tahu lebih baik tentang bash, jadi itu melibatkan lebih sedikit pemukulan terhadap dinding.
Peter Taylor

3

199 karakter dalam Oktaf:

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

Jika Anda tidak peduli untuk mendapatkan hasil minggu ini, 65 karakter sudah cukup:

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

Tetapi jika Anda mencari efisiensi, ini sedikit lebih lama di 86 karakter:

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

Ini dibedah jauh lebih detail daripada yang ingin saya ulangi di blog saya .


Terutama bukan pekerjaan saya, tetapi memberikan banyak dari Nabb memberi 47 karakter:

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

Catatan: Saya hanya beralasan tentang kode ini: mencoba menjalankannya tidak ada gunanya mengingat lamanya waktu dan jumlah memori yang akan digunakan.


3

Golfscript - 52 46 (67)

Pendekatan brute force untuk modular invers dalam 46 karakter. Menghitung a ((-2)) berulang kali dengan integer presisi yang berubah-ubah.

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

Menerapkan algoritma Euclidean yang diperluas hanya membebani kita 15 karakter tambahan.

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

Kode ini sepenuhnya terperinci pada posting blog saya , termasuk beberapa alternatif untuk menghitung modular multiplicative inverse.


1
Bagus, tapi saya pikir masih ada setidaknya dua karakter yang harus diselamatkan. Ganti {*N%2<}dengan {*N%1=}seperti di blog dan Anda bisa membuang (;setelahnya N,. Tetapi untuk entri yang tidak relevan dengan kinerja, Anda dapat menggunakan teorema kecil Fermat tanpa memedulikan sisi modular eksponensial - biarkan saja untuk rapi akhir - jadi penerima menjadi N((?.
Peter Taylor

1
@ Peter: {*N%1=}+akan kehilangan case dengan penyebut nol, yang akan membutuhkan setidaknya 3 karakter untuk ditangani. Bagus hanya dengan melakukan x ^ (N-2), kita sebenarnya bisa mendapatkan 46 karakter menggunakan ini.
Nabb

2

Lua 444 Chars

Berfungsi untuk contoh di halaman wiki

3
2 1942
4 3402
5 4414

Tetapi entah bagaimana tidak berhasil untuk contoh di sini di halaman ini. Adakah yang bisa menemukan kesalahan?

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

Golf (tidak menggunakan bidang terbatas), 444 karakter:

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

Contoh Wikipedia tidak menggunakan bidang terbatas, yang benar-benar memalukan, yang akan jauh lebih instruktif. Itu kemungkinan besar sumber kesalahan Anda.
aaaaaaaaaaaa

2

Jawa, 435 407 karakter

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

Tidak Disatukan:

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.