Csaba Kiraly 36a4fbdbe5
renaming pos.nim to rsa.nim
Signed-off-by: Csaba Kiraly <csaba.kiraly@gmail.com>
2022-01-17 11:26:37 -06:00

196 lines
5.7 KiB
Nim

## 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 nimcrypto # for SHA512
import random
import ./bigint/stint2
#import ./bigint/bigints2
const keysize = 2048
const sectorsperblock = 4.int64
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(f: File, blockid: int64, sectorid: int64, spb: int64): ZChar =
f.setFilePos(blockid * spb + sectorid)
let r = f.readBytes(result, 0, sizeof(result))
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.getPublicKey().get()
return (pubkey, seckey)
proc split(f: File): (int64, int64) =
let size = f.getFileSize()
let n = ((size - 1) div (sectorsperblock * sizeof(ZChar))) + 1
return (sectorsperblock, 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, f: File, 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(f, 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, filename: string): (Tau, seq[BigInt]) =
let file = open(filename)
let (s, n) = split(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, file, ssk)) #TODO: int64 sizes?
file.close()
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, filename: string): (seq[BigInt], BigInt) =
let file = open(filename)
let N = spk.getModulus()
let s = sectorsperblock
var mu: seq[BigInt]
for j in 0 ..< s :
var muj = BigInt.zero
for qelem in q :
let sector = fromBytesBE(getSector(file, 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)
file.close()
return (mu, sigma)
proc verifyProof*(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)