Skip to content

Commit

Permalink
Merge pull request #46 from elnosh/dup-blinded-msg
Browse files Browse the repository at this point in the history
mint: err on blinded messages already signed
  • Loading branch information
elnosh authored Aug 9, 2024
2 parents 26e9007 + 1fdf267 commit 27f8ea2
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 6 deletions.
6 changes: 4 additions & 2 deletions cashu/cashu.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,9 @@ const (
DBErrCode CashuErrCode = 1
LightningBackendErrCode CashuErrCode = 2

UnitErrCode CashuErrCode = 11005
PaymentMethodErrCode CashuErrCode = 11006
UnitErrCode CashuErrCode = 11005
PaymentMethodErrCode CashuErrCode = 11006
BlindedMessageAlreadySignedErrCode CashuErrCode = 10002

InvalidProofErrCode CashuErrCode = 10003
ProofAlreadyUsedErrCode CashuErrCode = 11001
Expand Down Expand Up @@ -249,6 +250,7 @@ var (
PaymentMethodNotSupportedErr = Error{Detail: "payment method not supported", Code: PaymentMethodErrCode}
UnitNotSupportedErr = Error{Detail: "unit not supported", Code: UnitErrCode}
InvalidBlindedMessageAmount = Error{Detail: "invalid amount in blinded message", Code: StandardErrCode}
BlindedMessageAlreadySigned = Error{Detail: "blinded message already signed", Code: BlindedMessageAlreadySignedErrCode}
MintQuoteRequestNotPaid = Error{Detail: "quote request has not been paid", Code: MintQuoteRequestNotPaidErrCode}
MintQuoteAlreadyIssued = Error{Detail: "quote already issued", Code: MintQuoteAlreadyIssuedErrCode}
MintingDisabled = Error{Detail: "minting is disabled", Code: MintingDisabledErrCode}
Expand Down
41 changes: 37 additions & 4 deletions mint/mint.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,13 @@ func (m *Mint) MintTokens(method, id string, blindedMessages cashu.BlindedMessag
return nil, cashu.MintQuoteAlreadyIssued
}

blindedMessagesAmount := blindedMessages.Amount()
// check overflow
var blindedMessagesAmount uint64
B_s := make([]string, len(blindedMessages))
for i, bm := range blindedMessages {
blindedMessagesAmount += bm.Amount
B_s[i] = bm.B_
}

if len(blindedMessages) > 0 {
for _, msg := range blindedMessages {
if blindedMessagesAmount < msg.Amount {
Expand All @@ -303,7 +308,15 @@ func (m *Mint) MintTokens(method, id string, blindedMessages cashu.BlindedMessag
return nil, cashu.OutputsOverQuoteAmountErr
}

var err error
sigs, err := m.db.GetBlindSignatures(B_s)
if err != nil {
msg := fmt.Sprintf("could not get signatures from db: %v", err)
return nil, cashu.BuildCashuError(msg, cashu.DBErrCode)
}
if len(sigs) > 0 {
return nil, cashu.BlindedMessageAlreadySigned
}

blindedSignatures, err = m.signBlindedMessages(blindedMessages)
if err != nil {
return nil, err
Expand Down Expand Up @@ -341,7 +354,13 @@ func (m *Mint) Swap(proofs cashu.Proofs, blindedMessages cashu.BlindedMessages)
Ys[i] = Yhex
}

blindedMessagesAmount := blindedMessages.Amount()
var blindedMessagesAmount uint64
B_s := make([]string, len(blindedMessages))
for i, bm := range blindedMessages {
blindedMessagesAmount += bm.Amount
B_s[i] = bm.B_
}

// check overflow
if len(blindedMessages) > 0 {
for _, msg := range blindedMessages {
Expand All @@ -360,6 +379,15 @@ func (m *Mint) Swap(proofs cashu.Proofs, blindedMessages cashu.BlindedMessages)
return nil, err
}

sigs, err := m.db.GetBlindSignatures(B_s)
if err != nil {
msg := fmt.Sprintf("could not get signatures from db: %v", err)
return nil, cashu.BuildCashuError(msg, cashu.DBErrCode)
}
if len(sigs) > 0 {
return nil, cashu.BlindedMessageAlreadySigned
}

// if verification complete, sign blinded messages
blindedSignatures, err := m.signBlindedMessages(blindedMessages)
if err != nil {
Expand Down Expand Up @@ -600,6 +628,11 @@ func (m *Mint) signBlindedMessages(blindedMessages cashu.BlindedMessages) (cashu
C_: C_hex, Id: keyset.Id}

blindedSignatures[i] = blindedSignature

if err := m.db.SaveBlindSignature(msg.B_, C_hex, msg.Id, msg.Amount); err != nil {
msg := fmt.Sprintf("error saving signatures: %v", err)
return nil, cashu.BuildCashuError(msg, cashu.DBErrCode)
}
}

return blindedSignatures, nil
Expand Down
30 changes: 30 additions & 0 deletions mint/mint_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,25 @@ func TestMintTokens(t *testing.T) {
if !errors.Is(err, cashu.MintQuoteAlreadyIssued) {
t.Fatalf("expected error '%v' but got '%v' instead", cashu.MintQuoteAlreadyIssued, err)
}

// test mint with blinded messages already signed
mintQuoteResponse, err = testMint.RequestMintQuote(testutils.BOLT11_METHOD, mintAmount, testutils.SAT_UNIT)
if err != nil {
t.Fatalf("error requesting mint quote: %v", err)
}

sendPaymentRequest = lnrpc.SendRequest{
PaymentRequest: mintQuoteResponse.PaymentRequest,
}
response, _ = lnd2.Client.SendPaymentSync(ctx, &sendPaymentRequest)
if len(response.PaymentError) > 0 {
t.Fatalf("error paying invoice: %v", response.PaymentError)
}

_, err = testMint.MintTokens(testutils.BOLT11_METHOD, mintQuoteResponse.Id, blindedMessages)
if !errors.Is(err, cashu.BlindedMessageAlreadySigned) {
t.Fatalf("expected error '%v' but got '%v' instead", cashu.BlindedMessageAlreadySigned, err)
}
}

func TestSwap(t *testing.T) {
Expand Down Expand Up @@ -280,6 +299,17 @@ func TestSwap(t *testing.T) {
t.Fatalf("expected error '%v' but got '%v' instead", cashu.ProofAlreadyUsedErr, err)
}

proofs, err = testutils.GetValidProofsForAmount(amount, testMint, lnd2)
if err != nil {
t.Fatalf("error generating valid proofs: %v", err)
}

// test with blinded messages already signed
_, err = testMint.Swap(proofs, newBlindedMessages)
if !errors.Is(err, cashu.BlindedMessageAlreadySigned) {
t.Fatalf("expected error '%v' but got '%v' instead", cashu.BlindedMessageAlreadySigned, err)
}

// mint with fees
mintFeesPath := filepath.Join(".", "mintfees")
mintFees, err := testutils.CreateTestMint(lnd1, mintFeesPath, dbMigrationPath, 100, mint.MintLimits{})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

DROP TABLE IF EXISTS blind_signatures;

DROP INDEX IF EXISTS idx_blind_signatures_b;
9 changes: 9 additions & 0 deletions mint/storage/sqlite/migrations/000003_blind_signatures.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

CREATE TABLE IF NOT EXISTS blind_signatures (
b_ TEXT NOT NULL PRIMARY KEY,
c_ TEXT NOT NULL,
keyset_id TEXT NOT NULL,
amount INTEGER NOT NULL
);

CREATE INDEX IF NOT EXISTS idx_blind_signatures_b ON blind_signatures(b_);
35 changes: 35 additions & 0 deletions mint/storage/sqlite/sqlite.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,3 +318,38 @@ func (sqlite *SQLiteDB) UpdateMeltQuote(quoteId, preimage string, state nut05.St
}
return nil
}

func (sqlite *SQLiteDB) SaveBlindSignature(B_, C_, keysetId string, amount uint64) error {
_, err := sqlite.db.Exec(`
INSERT INTO blind_signatures (b_, c_, keyset_id, amount) VALUES (?, ?, ?, ?)`,
B_, C_, keysetId, amount,
)
return err
}

func (sqlite *SQLiteDB) GetBlindSignatures(B_s []string) (cashu.BlindedSignatures, error) {
signatures := cashu.BlindedSignatures{}
query := `SELECT amount, c_, keyset_id FROM blind_signatures WHERE b_ in (?` + strings.Repeat(",?", len(B_s)-1) + `)`

args := make([]any, len(B_s))
for i, B_ := range B_s {
args[i] = B_
}

rows, err := sqlite.db.Query(query, args...)
if err != nil {
return nil, err
}
defer rows.Close()

for rows.Next() {
var blindSignature cashu.BlindedSignature
err := rows.Scan(&blindSignature.Amount, &blindSignature.C_, &blindSignature.Id)
if err != nil {
return nil, err
}
signatures = append(signatures, blindSignature)
}

return signatures, nil
}
3 changes: 3 additions & 0 deletions mint/storage/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ type MintDB interface {
GetMeltQuote(string) (*MeltQuote, error)
UpdateMeltQuote(quoteId string, preimage string, state nut05.State) error

SaveBlindSignature(B_, C_, keysetId string, amount uint64) error
GetBlindSignatures(B_s []string) (cashu.BlindedSignatures, error)

Close()
}

Expand Down

0 comments on commit 27f8ea2

Please sign in to comment.