mirror of
https://github.com/logos-storage/logos-storage-nim.git
synced 2026-01-09 08:53:10 +00:00
initial commit of the Shacham RSA-based public scheme
Minimal working version with lots of error checks and corrections still needed. - using Bearssl RSA code through libp2p - with selecteble BigInt library for experimentation Signed-off-by: Csaba Kiraly <csaba.kiraly@gmail.com>
This commit is contained in:
parent
5f48de6a44
commit
6559ff6f04
1
dagger/storageproofs/README.md
Normal file
1
dagger/storageproofs/README.md
Normal file
@ -0,0 +1 @@
|
||||
Nim implementation of Proof of Storage related schemes
|
||||
46
dagger/storageproofs/bigint/bigints2.nim
Normal file
46
dagger/storageproofs/bigint/bigints2.nim
Normal file
@ -0,0 +1,46 @@
|
||||
## Nim-POS
|
||||
## Copyright (c) 2021 Status Research & Development GmbH
|
||||
## Licensed under either of
|
||||
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
## at your option.
|
||||
## This file may not be copied, modified, or distributed except according to
|
||||
## those terms.
|
||||
|
||||
import bigints
|
||||
export bigints
|
||||
|
||||
func zero*(T: typedesc): T {.inline.} =
|
||||
bigints.zero
|
||||
|
||||
func one*(T: typedesc): T {.inline.} =
|
||||
bigints.one
|
||||
|
||||
func mulmod*(a, b, m: BigInt): BigInt =
|
||||
(a * b) mod m
|
||||
|
||||
proc powmod*(b, e, m: BigInt): BigInt =
|
||||
assert e >= 0
|
||||
var e = e
|
||||
var b = b
|
||||
result = bigints.one
|
||||
while e > 0:
|
||||
if e mod 2 == 1:
|
||||
result = (result * b) mod m
|
||||
e = e div 2
|
||||
b = (b.pow 2) mod m
|
||||
|
||||
proc fromBytesBE*(nptr: openArray[byte], nlen: int): BigInt =
|
||||
result = bigints.zero
|
||||
for i in 0 ..< nlen:
|
||||
result = result * 256 + cast[int32](nptr[i])
|
||||
|
||||
proc to256BytesBE*(n: BigInt): array[256, byte] =
|
||||
var nn = n
|
||||
|
||||
let nlen = 256
|
||||
for i in 0 ..< nlen:
|
||||
result[nlen - 1 - i] = cast[uint8](nn.limbs[0] mod 256)
|
||||
nn = nn div 256
|
||||
# if nn == 0:
|
||||
# break
|
||||
22
dagger/storageproofs/bigint/stint2.nim
Normal file
22
dagger/storageproofs/bigint/stint2.nim
Normal file
@ -0,0 +1,22 @@
|
||||
## Nim-POS
|
||||
## Copyright (c) 2021 Status Research & Development GmbH
|
||||
## Licensed under either of
|
||||
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
## at your option.
|
||||
## This file may not be copied, modified, or distributed except according to
|
||||
## those terms.
|
||||
|
||||
import stint
|
||||
export stint
|
||||
|
||||
type BigInt* = StUInt[4096] #TODO: check why 2048 is not enough
|
||||
|
||||
proc fromBytesBE*(x: openArray[byte], l: int): BigInt =
|
||||
result = BigInt.fromBytesBE(x[0..l-1])
|
||||
|
||||
proc to256BytesBE*(msg: BigInt): array[256, byte] =
|
||||
stuint(msg, 2048).toBytesBE()
|
||||
|
||||
proc initBigInt*(n: SomeInteger): (BigInt) =
|
||||
result = stuint(n, BigInt.bits)
|
||||
1
dagger/storageproofs/example.txt
Normal file
1
dagger/storageproofs/example.txt
Normal file
@ -0,0 +1 @@
|
||||
The quick brown fox jumps over the lazy dog!
|
||||
217
dagger/storageproofs/pos.nim
Normal file
217
dagger/storageproofs/pos.nim
Normal file
@ -0,0 +1,217 @@
|
||||
## Nim-POS
|
||||
## Copyright (c) 2021 Status Research & Development GmbH
|
||||
## Licensed under either of
|
||||
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
## at your option.
|
||||
## This file may not be copied, modified, or distributed except according to
|
||||
## those terms.
|
||||
|
||||
import libp2p/crypto/crypto # for RSA
|
||||
import bearssl
|
||||
import memfiles
|
||||
import math
|
||||
import nimcrypto # for SHA512
|
||||
import random
|
||||
|
||||
import ./bigint/stint2
|
||||
#import ./bigint/bigints2
|
||||
|
||||
const keysize = 2048
|
||||
const sectorsperblock = 4
|
||||
const bytespersector = 128
|
||||
const querylen = 22
|
||||
assert bytespersector < keysize div 8 # TODO: not strict
|
||||
|
||||
type ZChar = array[bytespersector, byte]
|
||||
|
||||
proc fromBytesBE(nptr: ptr cuchar, nlen: int): BigInt =
|
||||
let nptra = cast[ptr array[0xffffffff,byte]](nptr)
|
||||
result = fromBytesBE(nptra[], nlen)
|
||||
|
||||
proc getSector(filep: ptr ZChar, blockid: int64, sectorid: int64, spb: int64): Zchar =
|
||||
result = cast[ptr array[0xffffffff, ZChar]](filep)[blockid * spb + sectorid]
|
||||
|
||||
proc fromBytesBE(sector: ZChar): BigInt =
|
||||
result = fromBytesBE(sector, sizeof(ZChar))
|
||||
|
||||
proc getModulus(pubkey: PublicKey): BigInt =
|
||||
result = fromBytesBE(pubkey.rsakey.key.n, pubkey.rsakey.key.nlen)
|
||||
|
||||
proc getModulus(seckey: PrivateKey): BigInt =
|
||||
result = fromBytesBE(seckey.rsakey.pubk.n, seckey.rsakey.pubk.nlen)
|
||||
|
||||
proc getPubex(pubkey: PublicKey): BigInt =
|
||||
## get RSA E exponent
|
||||
result = fromBytesBE(pubkey.rsakey.key.e, pubkey.rsakey.key.elen)
|
||||
|
||||
proc getPrivex(seckey: PrivateKey): BigInt =
|
||||
## get RSA D exponent
|
||||
result = fromBytesBE(seckey.rsakey.pexp, seckey.rsakey.pexplen)
|
||||
|
||||
proc rsaDecode(msg: var array[256,byte], ssk: PrivateKey): array[256,byte] =
|
||||
let RsaPrivate = rsaPrivateGetDefault()
|
||||
let r = RsaPrivate(cast[ptr cuchar](addr(msg)), addr(ssk.rsakey.seck))
|
||||
result = msg
|
||||
|
||||
proc rsaDecode(msg: BigInt, ssk: PrivateKey): BigInt =
|
||||
assert msg < ssk.getModulus()
|
||||
var msgarray = msg.to256BytesBE()
|
||||
let enc = rsaDecode(msgarray, ssk)
|
||||
result = fromBytesBE(enc, 256)
|
||||
assert result < ssk.getModulus()
|
||||
|
||||
proc rsaEncode(msg: var array[256,byte], spk: PublicKey): array[256,byte] =
|
||||
let RsaPublic = rsaPublicGetDefault()
|
||||
let r = RsaPublic(cast[ptr cuchar](addr(msg)), 256, addr(spk.rsakey.key))
|
||||
result = msg
|
||||
|
||||
proc rsaEncode(msg: BigInt, spk: PublicKey): BigInt =
|
||||
assert msg < spk.getModulus()
|
||||
var msgarray = msg.to256BytesBE()
|
||||
let enc = rsaEncode(msgarray, spk)
|
||||
result = fromBytesBE(enc, 256)
|
||||
assert result < spk.getModulus()
|
||||
|
||||
type TauZero = object
|
||||
name: array[512,byte]
|
||||
n: int64
|
||||
u: seq[BigInt]
|
||||
|
||||
type Tau = object
|
||||
t: TauZero
|
||||
signature: array[512, byte]
|
||||
|
||||
proc rsaKeygen(): (PublicKey, PrivateKey) =
|
||||
let rng = newRng()
|
||||
var seckey = PrivateKey.random(RSA, rng[], keysize).get()
|
||||
var pubkey = seckey.getKey().get()
|
||||
return (pubkey, seckey)
|
||||
|
||||
proc openFile(file: string, s = sectorsperblock, c = sizeof(ZChar)): (ptr ZChar, int64, int64) =
|
||||
let mm = memfiles.open(file)
|
||||
|
||||
let size = mm.size
|
||||
let n = int64(ceil(float64(size / (s * c))))
|
||||
|
||||
return (cast[ptr ZChar](mm.mem), int64(s), n)
|
||||
|
||||
proc hashNameI(name: openArray[byte], i: int64): BigInt =
|
||||
let hashString = $sha512.digest($name & $i)
|
||||
return fromBytesBE(cast[seq[byte]](hashString), hashString.len()) # TODO: use better way to convert
|
||||
|
||||
proc generateAuthenticator(i: int64, s: int64, t: TauZero, filep: ptr ZChar, ssk: PrivateKey): BigInt =
|
||||
let N = ssk.getModulus()
|
||||
|
||||
var productory = BigInt.one
|
||||
for j in 0 ..< s:
|
||||
productory = mulmod(productory,
|
||||
powmod(t.u[j], fromBytesBE(getSector(filep, i, j, s)), N),
|
||||
N)
|
||||
|
||||
# result = (hashNameI(t.name, i) * productory).powmod(getPrivex(ssk), N)
|
||||
result = rsaDecode((hashNameI(t.name, i) * productory) mod N, ssk)
|
||||
|
||||
proc st(ssk: PrivateKey, file: string): (Tau, seq[BigInt]) =
|
||||
let (filep, s, n) = openFile(file)
|
||||
var t = TauZero(n: n)
|
||||
|
||||
# generate a random name
|
||||
for i in 0 ..< 512 :
|
||||
t.name[i] = rand(byte)
|
||||
|
||||
# generate the coefficient vector for combining sectors of a block: U
|
||||
for i in 0 ..< s :
|
||||
t.u.add(initBigInt(rand(uint32))) #TODO: fix limit
|
||||
|
||||
#TODO: sign for tau
|
||||
let tau = Tau(t: t)
|
||||
|
||||
#generate sigmas
|
||||
var sigmas: seq[BigInt]
|
||||
for i in 0 ..< n :
|
||||
sigmas.add(generateAuthenticator(i, s, t, filep, ssk)) #TODO: int64 sizes?
|
||||
|
||||
result = (tau, sigmas)
|
||||
|
||||
type QElement = object
|
||||
I: int64
|
||||
V: BigInt
|
||||
|
||||
proc generateQuery(
|
||||
tau: Tau,
|
||||
spk: PublicKey,
|
||||
l: int = querylen # query elements
|
||||
): seq[QElement] =
|
||||
# verify signature on Tau
|
||||
|
||||
let n = tau.t.n # number of blocks
|
||||
|
||||
for i in 0 ..< l :
|
||||
var q: QElement
|
||||
q.I = rand((int)n-1) #TODO: dedup
|
||||
q.V = initBigInt(rand(uint64)) #TODO: fix range
|
||||
result.add(q)
|
||||
|
||||
proc generateProof(q: openArray[QElement], authenticators: openArray[BigInt], spk: PublicKey, file: string): (seq[BigInt], BigInt) =
|
||||
let (filep, s, _) = openFile(file)
|
||||
let N = spk.getModulus()
|
||||
|
||||
var mu: seq[BigInt]
|
||||
for j in 0 ..< s :
|
||||
var muj = BigInt.zero
|
||||
for qelem in q :
|
||||
let sector = fromBytesBE(getSector(filep, qelem.I, j, s))
|
||||
muj += qelem.V * sector
|
||||
#muj = addmod(muj, mulmod(qelem.V, sector, N), N)
|
||||
mu.add(muj)
|
||||
|
||||
var sigma = BigInt.one
|
||||
for qelem in q:
|
||||
sigma = mulmod(sigma,
|
||||
powmod(authenticators[qelem.I], qelem.V, N),
|
||||
N)
|
||||
|
||||
return (mu, sigma)
|
||||
|
||||
proc Verify_two(tau: Tau, q: openArray[QElement], mus: openArray[BigInt], sigma: BigInt, spk: PublicKey): bool =
|
||||
# TODO: check that values are in range
|
||||
let N = spk.getModulus()
|
||||
|
||||
var first = BigInt.one
|
||||
for qelem in q :
|
||||
first = mulmod(first,
|
||||
powmod(hashNameI(tau.t.name, qelem.I), qelem.V, N),
|
||||
N)
|
||||
|
||||
let us = tau.t.u
|
||||
var second = BigInt.one
|
||||
for j in 0 ..< len(us) :
|
||||
second = mulmod(second,
|
||||
powmod(us[j], mus[j], N),
|
||||
N)
|
||||
|
||||
return mulmod(first, second, N) == rsaEncode(sigma, spk)
|
||||
|
||||
proc test() : bool =
|
||||
let (spk, ssk) = pos.rsaKeygen()
|
||||
echo "Key generated!"
|
||||
|
||||
let (tau, authenticators) = pos.st(ssk, "example.txt")
|
||||
echo "Signed!"
|
||||
echo "Auth: ", authenticators
|
||||
|
||||
echo "Generating challenge..."
|
||||
let q = pos.generateQuery(tau, spk)
|
||||
echo "Generated!", " q:", q
|
||||
|
||||
echo "Issuing proof..."
|
||||
let (mu, sigma) = pos.generateProof(q, authenticators, spk, "example.txt")
|
||||
echo "Issued!", " mu:", mu, " sigma:", sigma
|
||||
|
||||
echo "Verifying proof..."
|
||||
result = pos.Verify_two(tau, q, mu, sigma, spk)
|
||||
echo "Result: ", result
|
||||
|
||||
randomize()
|
||||
let r = test()
|
||||
Loading…
x
Reference in New Issue
Block a user