transaction signing

This commit is contained in:
Mark Spanbroek 2024-12-04 15:43:34 +01:00
parent ac4413fce5
commit 56ec9a03c2
8 changed files with 200 additions and 118 deletions

View File

@ -1,28 +0,0 @@
import pkg/protobuf_serialization
export protobuf_serialization
type
TransactionMessage* {.proto3.} = object
version* {.fieldNumber: 1, pint.}: uint32
kind* {.fieldNumber: 2, pint.}: uint32
requestId* {.fieldNumber: 3.}: seq[byte]
slotIndex* {.fieldNumber: 4, pint.}: uint32
period* {.fieldNumber: 5, pint.}: uint64
merkleRoot* {.fieldNumber: 6.}: seq[byte]
challenge* {.fieldNumber: 7.}: seq[byte]
proof* {.fieldNumber: 8.}: Groth16ProofMessage
Groth16ProofMessage* {.proto3.} = object
a* {.fieldNumber: 1.}: G1PointMessage
b* {.fieldNumber: 2.}: G2PointMessage
c* {.fieldNumber: 3.}: G1PointMessage
G1PointMessage* {.proto3.} = object
x* {.fieldNumber: 1.}: seq[byte]
y* {.fieldNumber: 2.}: seq[byte]
G2PointMessage* {.proto3.} = object
x* {.fieldNumber: 1.}: Fp2ElementMessage
y* {.fieldNumber: 2.}: Fp2ElementMessage
Fp2ElementMessage* {.proto3.} = object
real* {.fieldNumber: 1.}: seq[byte]
imag* {.fieldNumber: 2.}: seq[byte]

View File

@ -1,86 +1,7 @@
import ./basics
import ./transaction/storagerequest
import ./transaction/period
import ./transaction/groth16
import ./transaction/transaction
import ./transaction/signed
import ./transaction/serialization
export storagerequest
export period
export groth16
type
TransactionVersion* {.pure.} = enum
version0
TransactionKind* {.pure.} = enum
storageProof
missingProof
Transaction* = object
requestId: StorageRequestId
slotIndex: uint32
period: Period
merkleRoot: UInt256
challenge: UInt256
case kind: TransactionKind
of storageProof:
proof: Groth16Proof
of missingProof:
discard
func storageProof*(
_: type Transaction,
requestId: StorageRequestId,
slotIndex: uint32,
period: Period,
merkleRoot: UInt256,
challenge: UInt256,
proof: Groth16Proof
): Transaction =
Transaction(
kind: TransactionKind.storageProof,
requestId: requestId,
period: period,
slotIndex: slotIndex,
merkleRoot: merkleRoot,
challenge: challenge,
proof: proof
)
func missingProof*(
_: type Transaction,
requestId: StorageRequestId,
slotIndex: uint32,
period: Period,
merkleRoot: UInt256,
challenge: UInt256,
): Transaction =
Transaction(
kind: TransactionKind.missingProof,
requestId: requestId,
slotIndex: slotIndex,
period: period,
merkleRoot: merkleRoot,
challenge: challenge
)
func version*(transaction: Transaction): TransactionVersion =
TransactionVersion.version0
func kind*(transaction: Transaction): TransactionKind =
transaction.kind
func requestId*(transaction: Transaction): StorageRequestId =
transaction.requestId
func slotIndex*(transaction: Transaction): uint32 =
transaction.slotIndex
func period*(transaction: Transaction): Period =
transaction.period
func merkleRoot*(transaction: Transaction): UInt256 =
transaction.merkleRoot
func challenge*(transaction: Transaction): UInt256 =
transaction.challenge
func proof*(transaction: Transaction): Groth16Proof =
transaction.proof
export transaction
export signed
export serialization.toBytes

View File

@ -1,6 +1,33 @@
import ./basics
import pkg/protobuf_serialization
import ../basics
import ./transaction
import ./serialization/protobuf
export protobuf_serialization
type
TransactionMessage* {.proto3.} = object
version* {.fieldNumber: 1, pint.}: uint32
kind* {.fieldNumber: 2, pint.}: uint32
requestId* {.fieldNumber: 3.}: seq[byte]
slotIndex* {.fieldNumber: 4, pint.}: uint32
period* {.fieldNumber: 5, pint.}: uint64
merkleRoot* {.fieldNumber: 6.}: seq[byte]
challenge* {.fieldNumber: 7.}: seq[byte]
proof* {.fieldNumber: 8.}: Groth16ProofMessage
Groth16ProofMessage* {.proto3.} = object
a* {.fieldNumber: 1.}: G1PointMessage
b* {.fieldNumber: 2.}: G2PointMessage
c* {.fieldNumber: 3.}: G1PointMessage
G1PointMessage* {.proto3.} = object
x* {.fieldNumber: 1.}: seq[byte]
y* {.fieldNumber: 2.}: seq[byte]
G2PointMessage* {.proto3.} = object
x* {.fieldNumber: 1.}: Fp2ElementMessage
y* {.fieldNumber: 2.}: Fp2ElementMessage
Fp2ElementMessage* {.proto3.} = object
real* {.fieldNumber: 1.}: seq[byte]
imag* {.fieldNumber: 2.}: seq[byte]
func toBytes*(transaction: Transaction): seq[byte] =
var message = TransactionMessage(

View File

@ -0,0 +1,36 @@
import ../signatures
import ./transaction
import ./serialization
type SignedTransaction* = object
transaction: Transaction
signer: Identifier
signature: Signature
func init*(
_: type SignedTransaction,
transaction: Transaction,
signer: Identifier,
signature: Signature
): SignedTransaction =
SignedTransaction(
transaction: transaction,
signer: signer,
signature: signature
)
func sign*(identity: Identity, transaction: Transaction): SignedTransaction =
let signature = identity.sign(transaction.toBytes())
SignedTransaction.init(transaction, identity.identifier, signature)
func transaction*(signed: SignedTransaction): Transaction =
signed.transaction
func signer*(signed: SignedTransaction): Identifier =
signed.signer
func signature*(signed: SignedTransaction): Signature =
signed.signature
func verifySignature*(signed: SignedTransaction): bool =
signed.signer.verify(signed.transaction.toBytes(), signed.signature)

View File

@ -0,0 +1,105 @@
import ../basics
import ./storagerequest
import ./period
import ./groth16
export storagerequest
export period
export groth16
type
TransactionVersion* {.pure.} = enum
version0
TransactionKind* {.pure.} = enum
storageProof
missingProof
Transaction* = object
requestId: StorageRequestId
slotIndex: uint32
period: Period
merkleRoot: UInt256
challenge: UInt256
case kind: TransactionKind
of storageProof:
proof: Groth16Proof
of missingProof:
discard
func storageProof*(
_: type Transaction,
requestId: StorageRequestId,
slotIndex: uint32,
period: Period,
merkleRoot: UInt256,
challenge: UInt256,
proof: Groth16Proof
): Transaction =
Transaction(
kind: TransactionKind.storageProof,
requestId: requestId,
period: period,
slotIndex: slotIndex,
merkleRoot: merkleRoot,
challenge: challenge,
proof: proof
)
func missingProof*(
_: type Transaction,
requestId: StorageRequestId,
slotIndex: uint32,
period: Period,
merkleRoot: UInt256,
challenge: UInt256,
): Transaction =
Transaction(
kind: TransactionKind.missingProof,
requestId: requestId,
slotIndex: slotIndex,
period: period,
merkleRoot: merkleRoot,
challenge: challenge
)
func version*(transaction: Transaction): TransactionVersion =
TransactionVersion.version0
func kind*(transaction: Transaction): TransactionKind =
transaction.kind
func requestId*(transaction: Transaction): StorageRequestId =
transaction.requestId
func slotIndex*(transaction: Transaction): uint32 =
transaction.slotIndex
func period*(transaction: Transaction): Period =
transaction.period
func merkleRoot*(transaction: Transaction): UInt256 =
transaction.merkleRoot
func challenge*(transaction: Transaction): UInt256 =
transaction.challenge
func proof*(transaction: Transaction): Groth16Proof =
transaction.proof
func `==`*(a, b: Transaction): bool =
if a.kind != b.kind:
return false
if a.requestId != b.requestId:
return false
if a.slotIndex != b.slotIndex:
return false
if a.period != b.period:
return false
if a.merkleRoot != b.merkleRoot:
return false
if a.challenge != b.challenge:
return false
case a.kind
of TransactionKind.storageProof:
a.proof == b.proof
of TransactionKind.missingProof:
true

View File

@ -1,6 +1,7 @@
import std/random
import codexvalidator/basics
import codexvalidator/transaction
import codexvalidator/signatures
proc example*[T: SomeInteger](_: type T): T =
rand(T)
@ -67,3 +68,6 @@ proc example*(_: type Transaction): Transaction =
challenge,
proof
)
proc example*(_: type Identity): Identity =
Identity.random(result)

View File

@ -1,11 +1,10 @@
import std/unittest
import codexvalidator/basics
import codexvalidator/transaction
import codexvalidator/serialization
import codexvalidator/serialization/protobuf
import codexvalidator/transaction/serialization
import ./examples
suite "Serialization":
suite "Transaction serialization":
test "serializes a transaction with protobuf":
let transaction = Transaction.example

View File

@ -1,5 +1,6 @@
import std/unittest
import codexvalidator/basics
import codexvalidator/signatures
import codexvalidator/transaction
import ./examples
@ -40,3 +41,20 @@ suite "Transaction":
test "transactions have a fixed version":
let transaction = Transaction.example
check transaction.version == TransactionVersion.version0
test "transactions can be signed":
let identity = Identity.example
let transaction = Transaction.example
let signed = identity.sign(transaction)
check signed.transaction == transaction
check signed.signer == identity.identifier
check signed.signature == identity.sign(transaction.toBytes())
test "transaction signature can be verified":
let identity = Identity.example
let transaction = Transaction.example
let signed = identity.sign(transaction)
check signed.verifySignature()
let forger = Identity.example.identifier
let forged = SignedTransaction.init(transaction, forger, signed.signature)
check not forged.verifySignature()