Skip to content

Commit

Permalink
fixup! pointers, errors
Browse files Browse the repository at this point in the history
  • Loading branch information
altergui committed Dec 18, 2024
1 parent 362f029 commit 8e5ec26
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 47 deletions.
28 changes: 18 additions & 10 deletions circuits/statetransition/circuit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,27 +246,35 @@ func newMockState(t *testing.T) *state.State {
return s
}

const (
mockNullifiersOffset = 100 // mock, should really be a prefix, not an offset
mockAddressesOffset = 200 // mock, should really be a prefix, not an offset
)

// newMockVote creates a new vote
func newMockVote(nullifier, amount uint64) state.Vote {
var v state.Vote
v.Nullifier = arbo.BigIntToBytes(state.MaxKeyLen,
big.NewInt(int64(nullifier)+int64(state.KeyNullifiersOffset))) // mock
func newMockVote(index, amount int64) *state.Vote {
nullifier := arbo.BigIntToBytes(state.MaxKeyLen,
big.NewInt(int64(index)+int64(mockNullifiersOffset))) // mock

// generate a public mocked key
publicKey, _, err := elgamal.GenerateKey(state.Curve)
if err != nil {
panic(fmt.Errorf("error generating public key: %v", err))
}

c, err := elgamal.NewCiphertext(publicKey).Encrypt(big.NewInt(int64(amount)), publicKey, nil)
ballot, err := elgamal.NewCiphertext(publicKey).Encrypt(big.NewInt(int64(amount)), publicKey, nil)
if err != nil {
panic(fmt.Errorf("error encrypting: %v", err))
}

v.Ballot = c
address := arbo.BigIntToBytes(state.MaxKeyLen,
big.NewInt(int64(index)+int64(mockAddressesOffset))) // mock
commitment := big.NewInt(amount + 256)

v.Address = arbo.BigIntToBytes(state.MaxKeyLen,
big.NewInt(int64(nullifier)+int64(state.KeyAddressesOffset))) // mock
v.Commitment.SetUint64(amount + 256) // mock
return v
return &state.Vote{
Nullifier: nullifier,
Ballot: ballot,
Address: address,
Commitment: commitment,
}
}
2 changes: 1 addition & 1 deletion circuits/statetransition/witness_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func GenerateWitnesses(o *state.State) (*statetransition.Circuit, error) {
for i := range witness.Commitment {
if i < len(o.Votes()) {
witness.Commitment[i], err = o.MerkleTransitionFromAddOrUpdate(
o.Votes()[i].Address, arbo.BigIntToBytes(32, &o.Votes()[i].Commitment))
o.Votes()[i].Address, arbo.BigIntToBytes(32, o.Votes()[i].Commitment))
} else {
witness.Commitment[i], err = o.MerkleTransitionFromNoop()
}
Expand Down
29 changes: 14 additions & 15 deletions crypto/elgamal/ciphertext.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import (
"github.com/vocdoni/vocdoni-z-sandbox/crypto/ecc/format"
)

// size in bytes needed to serialize an ecc.Point coord
const sizePointCoord = 32

// Ciphertext represents an ElGamal encrypted message with homomorphic properties.
// It is a wrapper for convenience of the elGamal ciphersystem that encapsulates the two points of a ciphertext.
type Ciphertext struct {
Expand Down Expand Up @@ -61,39 +64,35 @@ func (z *Ciphertext) Serialize() []byte {
c1x, c1y := format.FromTEtoRTE(z.C1.Point())
c2x, c2y := format.FromTEtoRTE(z.C2.Point())
for _, bi := range []*big.Int{c1x, c1y, c2x, c2y} {
if _, err := buf.Write(arbo.BigIntToBytes(32, bi)); err != nil {
panic(err)
}
buf.Write(arbo.BigIntToBytes(sizePointCoord, bi))
}
return buf.Bytes()
}

// Deserialize reconstructs an Ciphertext from a slice of bytes.
// The input must be of len 4*32 bytes (otherwise it panics),
// The input must be of len 4*32 bytes (otherwise it returns an error),
// representing the C1.X, C1.Y, C2.X, C2.Y as little-endian,
// in reduced twisted edwards form.
func (z *Ciphertext) Deserialize(data []byte) {
const fieldSize = 32 // Each field element is 32 bytes
expectedLen := 4 * fieldSize

func (z *Ciphertext) Deserialize(data []byte) error {
// Validate the input length
if len(data) != expectedLen {
panic(fmt.Errorf("invalid input length: got %d bytes, expected %d bytes", len(data), expectedLen))
if len(data) != 4*sizePointCoord {
return fmt.Errorf("invalid input length: got %d bytes, expected %d bytes", len(data), 4*sizePointCoord)
}

// Helper function to extract *big.Int from a 32-byte slice
readBigInt := func(offset int) *big.Int {
return arbo.BytesToBigInt(data[offset : offset+fieldSize])
return arbo.BytesToBigInt(data[offset : offset+sizePointCoord])
}
// Deserialize each field
z.C1 = z.C1.SetPoint(format.FromRTEtoTE(
readBigInt(0*fieldSize),
readBigInt(1*fieldSize),
readBigInt(0*sizePointCoord),
readBigInt(1*sizePointCoord),
))
z.C2 = z.C2.SetPoint(format.FromRTEtoTE(
readBigInt(2*fieldSize),
readBigInt(3*fieldSize),
readBigInt(2*sizePointCoord),
readBigInt(3*sizePointCoord),
))
return nil
}

// Marshal converts Ciphertext to a byte slice.
Expand Down
11 changes: 5 additions & 6 deletions crypto/elgamal/ciphertext_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ func TestCiphertext_SerializeDeserialize(t *testing.T) {

// Test deserialization
deserialized := NewCiphertext(publicKey)
deserialized.Deserialize(serialized)
err = deserialized.Deserialize(serialized)
c.Assert(err, qt.IsNil)

// Compare points
x1, y1 := encrypted.C1.Point()
Expand Down Expand Up @@ -171,14 +172,12 @@ func TestCiphertext_String(t *testing.T) {
c.Assert(str, qt.Matches, `\{C1: .+, C2: .+\}`)
}

func TestCiphertext_DeserializePanic(t *testing.T) {
func TestCiphertext_DeserializeError(t *testing.T) {
c := qt.New(t)

cipher := NewCiphertext(curves.New(curves.CurveTypeBN254))

// Test with invalid length, should panic
c.Assert(func() {
cipher.Deserialize(make([]byte, 127)) // Should be 128
},
qt.PanicMatches, "invalid input length.*")
c.Assert(cipher.Deserialize(make([]byte, 127)), // Should be 128
qt.ErrorMatches, "invalid input length.*")
}
8 changes: 6 additions & 2 deletions state/merkleproof.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,15 @@ func (o *State) MerkleTransitionFromAddOrUpdate(k []byte, v []byte) (MerkleTrans

oldCiphertext, newCiphertext := elgamal.NewCiphertext(Curve), elgamal.NewCiphertext(Curve)
if len(mpBefore.Value) > 32 {
oldCiphertext.Deserialize(mpBefore.Value)
if err := oldCiphertext.Deserialize(mpBefore.Value); err != nil {
return MerkleTransition{}, err
}
mp.IsOldElGamal = 1
}
if len(mpAfter.Value) > 32 {
newCiphertext.Deserialize(mpAfter.Value)
if err := newCiphertext.Deserialize(mpAfter.Value); err != nil {
return MerkleTransition{}, err
}
mp.IsNewElGamal = 1
}

Expand Down
17 changes: 9 additions & 8 deletions state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ var (
KeyEncryptionKey = []byte{0x03}
KeyResultsAdd = []byte{0x04}
KeyResultsSub = []byte{0x05}

KeyNullifiersOffset = 100 // mock, should really be a prefix, not an offset
KeyAddressesOffset = 200 // mock, should really be a prefix, not an offsest
)

// State represents a state tree
Expand All @@ -53,7 +50,7 @@ type State struct {
OverwriteSum *encrypt.Ciphertext
ballotCount int
overwriteCount int
votes []Vote
votes []*Vote
}

// New creates or opens a State stored in the passed database.
Expand Down Expand Up @@ -121,21 +118,25 @@ func (o *State) StartBatch() error {
if err != nil {
return err
}
o.ResultsAdd.Deserialize(v)
if err := o.ResultsAdd.Deserialize(v); err != nil {
return err
}
}
{
_, v, err := o.tree.Get(KeyResultsSub)
if err != nil {
return err
}
o.ResultsSub.Deserialize(v)
if err := o.ResultsSub.Deserialize(v); err != nil {
return err
}
}

o.BallotSum = elgamal.NewCiphertext(Curve)
o.OverwriteSum = elgamal.NewCiphertext(Curve)
o.ballotCount = 0
o.overwriteCount = 0
o.votes = []Vote{}
o.votes = []*Vote{}
return nil
}

Expand All @@ -159,6 +160,6 @@ func (o *State) OverwriteCount() int {
return o.overwriteCount
}

func (o *State) Votes() []Vote {
func (o *State) Votes() []*Vote {
return o.votes
}
10 changes: 5 additions & 5 deletions state/vote.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,12 @@ type Vote struct {
Nullifier []byte
Ballot *elgamal.Ciphertext
Address []byte
Commitment big.Int
Commitment *big.Int
}

// AddVote adds a vote to the state
// - if nullifier exists, it counts as vote overwrite
//
// TODO: use Tx to rollback in case of failure
func (o *State) AddVote(v Vote) error {
func (o *State) AddVote(v *Vote) error {
if len(o.votes) >= VoteBatchSize {
return fmt.Errorf("too many votes for this batch")
}
Expand All @@ -28,7 +26,9 @@ func (o *State) AddVote(v Vote) error {
// so it's later added to circuit.ResultsSub
if _, value, err := o.tree.Get(v.Nullifier); err == nil {
oldVote := elgamal.NewCiphertext(Curve)
oldVote.Deserialize(value)
if err := oldVote.Deserialize(value); err != nil {
return err
}
o.OverwriteSum.Add(o.OverwriteSum, oldVote)
o.overwriteCount++
}
Expand Down

0 comments on commit 8e5ec26

Please sign in to comment.