python-dirbtuves / internet-voting

Internet voting system.
1 stars 2 forks source link

Incremental signing #7

Open sirex opened 9 years ago

sirex commented 9 years ago

There are several places, where CEC has to sign something. For this, we need a function that can incrementally sign data stream.

Function signature could look something like this:

for hash, signature in sign(data, state):
    pass

Here hash is SHA-1 hash, signature is a hash of hash signature made with CEC private key. hash and signature both have to be incremental, meaning that if you will hash all data you will get hash from the last sign call with last passed data.

data is an iterable of strings.

state is an optional argument and if state is given, then it should continue hashing from where it left. I'm not sure how to implement this, if will have to find-out it yourself. But the idea, that it should be enough to hash only new items, not everything from the beginning.

sirex commented 9 years ago

It looks, like this should be implemented as asynchronous single thread process, that performs incremental signing and hashing, because we need to handle concurrent requests.

So I would say, that a daemon should be created for this task. This daemon would be responsible for single task - to do incremental hashing.

I think this daemon could communicate over a socket or inet port and should be associated with a file, where <data>\t<hash>\n will be written.

Also, this can be implemented in some different way, but you need to keep in mind, that it should be able to handle concurrency.

sirex commented 9 years ago

tai kaip aš įsivaizduoju, kad klientas (balsuotojas) per socket'ą (socket prisijungimą padariau per standartinę built-in python socket biblioteką) prisijungia prie serverio (VRK), o serveryje jau veikia visa programa, visos funkcijos kiek tik įmanoma, išskyrus tik pasirašymą kliento privačiu raktu. Tai mano funkcija turėtų sukurti naują thread serverio pusėje.

Ši dalis visiškai neliečia kliento ir kalba eina apie serverio dalį. Užduotis aprašyta kliento/bibliotekos dalyje, todėl, kad tas dalykas turės būti panaudotas tie Django serverio dalyje, tiek microframewrok serverio dalyje, todėl tai turi eiti į biblioteką, kurią naudos abu serverio įgyvendinimai.

Ar konkrečiai reikia naudoti socketus, nežinau, tai yra vienas iš galimų įgyvendinimo variantų. Gal būt socketai yra per daug žemas lygis ir galime naudoti tiesiog kokį aiohttp. Arba galima naudoti kažką visai kitą.

ir šituos griaučius naudosim visi mes savo funkcijų įgyvendinimui kaip suprantu, ar nereikia to įkelti į githubą, kad galėtume kelti savo funkcijas į vieną bendrą schemą, į serverio ar kliento kodo dalį. Nes dabar aš nežinau kaip tiksliai ištestuoti savo funkcijos veikimą, kaip ji atrodys šalia kitų funkcijų, į ką integruojasi.

Tai turi keliauti į kliento/bibliotekos repozitoriją [1].

[1] https://github.com/python-dirbtuves/internet-voting

Dėl pačios funkcijos esmės, tai skaičiau daug kartų tą tavo duotą funkcijos aprašymą, bandžiau suprasti, bet vis tik perėjau prie tų trijų punktų, kuriuos minėjau, kad išmokau (vieši privatūs raktai, threading ir sockets) ir pačios funkcijos kaip ji turėtų atrodyti neįsivaizduoju vis dar.

pavyzdžiui Here hash is SHA-1 hash, signature is a hash of hash signature made with CEC private key.

kas yra šitas hash? balsuotojo balsas pasirašytas su jo private key?

taip pat paties incremental veikimo principo nesuprantu.

kiekvienas balsas turi būti pasirašytas balsuotojo privačiu ir VRK viešu raktais, tą procedūrą įsivaizduoju kaip funkciją, kuri vykdoma kiekvienam balsui, o ką būtent tas incremental reiškia? yra dar hash vertė visiem balsuotojų balsam kaip vienam duomenų vienetui ar kaip?

Pabandysiu į visus šiuos klausimus atsakyti vienu paaiškinimu.

Visų pirma štai kaip veikia hash funkcija:

>>> import hashlib
>>> h = hashlib.sha1()
>>> h.update(b'data')
>>> h.hexdigest()
'a17c9aaa61e80a1bf71d0d850af4e5baa9800bbd'
>>> h.update(b'more data')
>>> h.hexdigest()
'8e8c2113851f57816d57a1f2fb8b012c9d89ff3a'
>>> h.update(b'even more date')
>>> h.hexdigest()
'25edf74e9fe7230d7f5ec3198c04709d9bd9cede'

Iš šio pavyzdžio matyti, kad hash funkcija, kuri šiuo atveju yra SHA-1, buvo paduoti tokie duomenys:

data
more data
even more date

Iš kiekvieno gauto duomenų gabalo buvo progresyviai (incremental) generuojama hash reikšmė:

'data'                                  -> 'a17c9aaa61e80a1bf71d0d850af4e5baa9800bbd'
'data' + 'more data'                    -> '8e8c2113851f57816d57a1f2fb8b012c9d89ff3a'
'data' + 'more data' + 'even more date' -> '25edf74e9fe7230d7f5ec3198c04709d9bd9cede'

Jei kas nors pakartotų hash reikšmių generavimą, tokia pačia tvarka ir tokiais pat gabalais, jis gautų identiškai tas pačias hash reikšmes.

Tuo pačiu, visų duomenų galutinę hash reikšmę galima gauti tik sumaitinus visus duomenis, pavyzdžiui:

>>> hashlib.sha1(b'data' + b'more data' + b'even more date').hexdigest()
'25edf74e9fe7230d7f5ec3198c04709d9bd9cede'

Čia gavom identiškai tą pačią hash funkciją.

O viso to esmė yra ta, kad kiekvienas balsuojantis gauna hash reikšmę toje vietoje, kai jo pateikti duomenys buvo įtraukti į bendrą duomenų srautą. Galiausiai, kai VRK paskelbia galutinius duomenis ir galutinę hash reikšmę, kiekvienas balsuojantysis, žinodamas kokius duomenis padavė, kokia buvo tų duomenų hash reikšmė ir kokia yra galutinių duomenų hash reikšmė, gali įsitikinti ar duomenys nebuvo pakeisti.

Todėl tavo užduotis - padaryti galimybę prie esamų duomenų pridėti naują duomenų bloką ir grąžinto galutinę hash reikšmę.

Pats paprasčiausias būdas tai padaryti - kiekvieną kartą perskaičiuoti hash reikšmę iš visų turimų duomenų.

Tačiau, reikia atkreipti dėmesį, kad duomenų integralumui užtikrinti, pridėti naujus duomenis gali tik viena gija, visos kitos turi laukti. Jei darytum šį paprasčiausią variantą, tai sistema greičiausiai stabdytų, kadangi kiekvieną kartą reikėtų perskaičiuoti hash reikšmę. Žinoma, stabdymas pasijaustų, tik turint didelį skaičių balsuojančiųjų.

Žodžiu, aš matau du variantus:

  1. Arba gali daryti paprastai, kiekvieną kartą perskaičiuojant visus duomenis, su užrakinimu, kad išspręsti concurency problemą.
  2. Arba gali daryti atskirą vienos proceso ir vienos gijos demoną, kuris išsaugo esamą būseną ir padavus naujus duomenis visko neperskaičiuoja, o perskaičiuoja tik naujai paduotus duomenis h.update(data).

Su pasirašymu yra lygiai taip pat, galima generuoti progresyvų parašą, paduodant vis daugiau naujų duomenų.

Tikiuosi pasidarė aiškiau, galėsime pasiaiškinti rytoj.