diff options
-rw-r--r-- | auction.go | 130 | ||||
-rw-r--r-- | bidder/auction.go | 67 | ||||
-rw-r--r-- | bidder/bid.go | 77 | ||||
-rw-r--r-- | bidder/bid_test.go | 27 | ||||
-rw-r--r-- | bidder/option.go | 18 | ||||
-rw-r--r-- | nizk/commit/commit.go | 22 | ||||
-rw-r--r-- | option.go | 15 |
7 files changed, 155 insertions, 201 deletions
@@ -6,7 +6,13 @@ import ( "crypto/sha512" "encoding/base32" "encoding/json" + "errors" + "fmt" + "log/slog" "time" + + "kesim.org/seal/nizk/commit" + "kesim.org/seal/nizk/stage1" ) type Type int @@ -55,4 +61,126 @@ func (d *Description) Hash() (hash string, e error) { } h := sha512.Sum512(buf.Bytes()) return base32.StdEncoding.EncodeToString(h[:]), nil -}
\ No newline at end of file +} + +func (d *Description) validate() error { + if d == nil { + return fmt.Errorf("description is nil") + } + if d.BitLength > MAXBITLENGTH { + return fmt.Errorf("invalid BitLength in description: %d", d.BitLength) + } + return nil +} + +type Auction interface { + Start() error + Cancel() error + Message(msg []byte) error +} + +type Result struct { + Price uint32 + Winner string + Error error +} + +type auction struct { + description *Description + + // non nil if run by an bidder, via Join() + bidder Bidder + // non nil if run by an observer, via Observe() + observer Observer + + // The commitments we received from the bidders. + bidders map[string][]*commit.Commitment + + // sorted list of the bidders. + bidder_ids []string + + // Stage 1 data per round + stage1 []*stage1.Statement + + log *slog.Logger +} + +func (a *auction) Start() error { + return errors.New("Start not implemented") +} + +func (a *auction) Cancel() error { + return errors.New("Cancel not implemented") +} + +// Message is called by the Bidder or Visitor +// whenever a message came in for the auction via the dashboard +// or other means of communication. +func (a *auction) Message(msg []byte) error { + return fmt.Errorf("Auction.Received not implemented") +} + +const MAXBITLENGTH = 64 + +// Bidder is the interface that the Auction engine uses to interact +type Bidder interface { + Broadcast([]byte) error + Result(Result) + Start() +} + +func Join( + bidder Bidder, + description *Description, + options ...Option) (Auction, error) { + + if bidder == nil { + return nil, fmt.Errorf("missing bidder") + } + if e := description.validate(); e != nil { + return nil, e + } + + a := &auction{ + description: description, + bidder: bidder, + log: slog.Default(), + } + + for _, opt := range options { + opt(a) + } + + return a, nil +} + +// Observer +type Observer interface { + Result(Result) + Start() +} + +func Observe( + observer Observer, + description *Description, + options ...Option) (Auction, error) { + + if observer == nil { + return nil, fmt.Errorf("missing observer") + } + if e := description.validate(); e != nil { + return nil, e + } + + a := &auction{ + description: description, + observer: observer, + log: slog.Default(), + } + + for _, opt := range options { + opt(a) + } + + return a, nil +} diff --git a/bidder/auction.go b/bidder/auction.go deleted file mode 100644 index a22f005..0000000 --- a/bidder/auction.go +++ /dev/null @@ -1,67 +0,0 @@ -package bidder - -import ( - "fmt" - "log" - "os" - - "kesim.org/seal" - "kesim.org/seal/nizk/commit" -) - -// Auction is the simple interface for the engine -type Auction interface { - Join(bidder Bidder) // A bidder calls this to join the auction - GotMessage(msg []byte, sig []byte) error // A bidder uses this method to publish a message -} - -// Bidder is the interface that the Auction engine uses to communicate -type Bidder interface { - Commitment() *commit.Commitment - Start(map[string]*commit.Commitment) - Result() - Receive(msg []byte) error -} - -type auction struct { - description *seal.Description - - bidder Bidder - - log func(string, ...any) - verbose func(string, ...any) - debug func(string, ...any) -} - -func nullf(string, ...any) {} - -func NewAuction(description *seal.Description, options ...Option) (a *auction, e error) { - if description.BitLength > 63 { - return nil, fmt.Errorf("Invalid BitLength in description: %d", description.BitLength) - } - - logger := log.New(os.Stdout, "[seal::client] ", log.LstdFlags) - - a = &auction{ - description: description, - log: logger.Printf, - verbose: nullf, - debug: nullf, - } - - for _, opt := range options { - opt(a) - } - - return a, nil -} - -func (a *auction) Join(bidder Bidder) { - a.bidder = bidder -} - -// Received is called by the bidder whenever a message came in for the auction via the dashboard -// or other means of communication. -func (a *auction) Received(msg []byte) error { - return fmt.Errorf("Auction.Received not implemented") -}
\ No newline at end of file diff --git a/bidder/bid.go b/bidder/bid.go deleted file mode 100644 index 5f98a0c..0000000 --- a/bidder/bid.go +++ /dev/null @@ -1,77 +0,0 @@ -package bidder - -import ( - "crypto/ed25519" - "fmt" - - . "kesim.org/seal/nizk" - - "kesim.org/seal/nizk/commit" - "kesim.org/seal/nizk/stage1" -) - -type bid struct { - id ed25519.PrivateKey - Id ed25519.PublicKey - - price uint64 // bigendian encoding of the bid - bitlength uint8 // number of bits encoded in price. - - // bits are derived from zbid and the zero element in - // the slice corresponds to the highest bit in zbid - bits []*commit.Statement - - // The commitments we received from the bidders. - bidders map[string][]*commit.Commitment - - // sorted list of the bidders. - bidder_ids []string - - // Stage 1 data per round - stage1 []*stage1.Statement -} - -// newBid creates a new Bidder for the given price, using the lower bits up to bitlength -func newBid(price uint64, bitlength uint8) (b *bid, e error) { - if bitlength > 63 { - return nil, fmt.Errorf("bitlength too large, maximum is 63") - } else if 0 != (price >> bitlength) { - return nil, fmt.Errorf("price %d too large for given bitlength %d", price, bitlength) - } - - b = &bid{ - price: price, - bitlength: bitlength, - } - - b.Id, b.id, e = ed25519.GenerateKey(nil) - if e != nil { - return nil, e - } - - b.bits = make([]*commit.Statement, bitlength) - for i := bitlength; i > 0; i-- { - set := (price>>(i-1)&1 != 0) - x, r := Curve.RandomScalar(), Curve.RandomScalar() - b.bits[i-1] = commit.NewStatement(x, r, set) - } - - return b, nil -} - -// Commit returns the public commitment to the bits and a signature -// TODO: return signature over bid -func (bid *bid) Commit() (c []*commit.Commitment) { - c = make([]*commit.Commitment, len(bid.bits)) - for i := range bid.bits { - c[i] = bid.bits[i].Commit(Bites(bid.Id)) - } - return c -} - -func (bid *bid) Result() { -} - -func (bid *bid) Send(msg []byte, sig []byte) error { - return fmt.Errorf("bidder.Send not implemented") -}
\ No newline at end of file diff --git a/bidder/bid_test.go b/bidder/bid_test.go deleted file mode 100644 index a479e5d..0000000 --- a/bidder/bid_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package bidder - -import ( - "testing" -) - -func TestBitlengthTooLarge(t *testing.T) { - bid, e := newBid(0xFFFFFF, 70) - if e == nil { - t.Fatalf("failure expected, but got bid: %#v", bid) - } -} - -func TestPriceTooLarge(t *testing.T) { - bid, e := newBid(0xFFFFFF, 8) - if e == nil { - t.Fatalf("failure expected, but got bid: %#v", bid) - } -} - -func TestBidOK(t *testing.T) { - bid, e := newBid(102400, 24) - if e != nil { - t.Fatalf("unexpected error: %v", e) - } - t.Logf("Bid: %+v", bid) -}
\ No newline at end of file diff --git a/bidder/option.go b/bidder/option.go deleted file mode 100644 index d1c9783..0000000 --- a/bidder/option.go +++ /dev/null @@ -1,18 +0,0 @@ -package bidder - -import ( - "log" - "os" -) - -type Option func(auction *auction) - -func OptVerbose(a *auction) { - logger := log.New(os.Stdout, "[seal::client][verbose] ", log.LstdFlags) - a.verbose = logger.Printf -} - -func OptDebug(a *auction) { - logger := log.New(os.Stdout, "[seal::client][debug] ", log.LstdFlags) - a.debug = logger.Printf -} diff --git a/nizk/commit/commit.go b/nizk/commit/commit.go index d044077..84ba8e5 100644 --- a/nizk/commit/commit.go +++ b/nizk/commit/commit.go @@ -12,10 +12,10 @@ import ( // for given C, A and B type Statement struct { + bitSet bool a *Scalar b *Scalar - plus bool - *Commitment + Commitment } type Commitment struct { @@ -25,25 +25,25 @@ type Commitment struct { Proof *Proof } -func NewStatement(a, b *Scalar, plus bool) *Statement { +func NewStatement(a, b *Scalar, bitSet bool) *Statement { return &Statement{ a: a, b: b, - plus: plus, - Commitment: commitment(a, b, plus), + bitSet: bitSet, + Commitment: commitment(a, b, bitSet), } } -func commitment(a, b *Scalar, plus bool) *Commitment { +func commitment(a, b *Scalar, bitSet bool) Commitment { var C *Point c := a.Mul(b) - if plus { + if bitSet { C = G.Exp(c.Add(One)) } else { C = G.Exp(c) } - return &Commitment{ + return Commitment{ C: C, A: G.Exp(a), B: G.Exp(b), @@ -52,7 +52,7 @@ func commitment(a, b *Scalar, plus bool) *Commitment { func (s *Statement) Commit(id Bytes) *Commitment { s.Commitment.Proof = s.Proof(id) - return s.Commitment + return &s.Commitment } type Proof struct { @@ -72,7 +72,7 @@ func (s *Statement) Proof(id Bytes) *Proof { r2 = Curve.RandomScalar() w = Curve.RandomScalar() - if s.plus { + if s.bitSet { e[0][0] = G.Exp(r1) e[0][1] = s.B.Exp(r1).Mul(G.Exp(w)) e[1][0] = G.Exp(r2) @@ -87,7 +87,7 @@ func (s *Statement) Proof(id Bytes) *Proof { ch := Challenge(G, s.C, s.A, s.B, e[0][0], e[0][1], e[1][0], e[1][1], id) pr := &Proof{Id: id} - if s.plus { + if s.bitSet { pr.C.Ch[0] = w pr.C.Ch[1] = ch.Sub(w) pr.C.R[0] = r1.Sub(s.a.Mul(pr.C.Ch[0])) diff --git a/option.go b/option.go new file mode 100644 index 0000000..8f7212f --- /dev/null +++ b/option.go @@ -0,0 +1,15 @@ +package seal + +import "log/slog" + +type Option func(auction *auction) + +func OptionSetLoggerLevel(level slog.Level) Option { + return func(_ *auction) { + slog.SetLogLoggerLevel(level) + } +} + +func OptionDebug() Option { + return OptionSetLoggerLevel(slog.LevelDebug) +} |