Skip to content

Commit d264d0d

Browse files
authored
unit-tests: token/core/zkatdlog/nogh/v1/transfer #1331 (#1333)
Signed-off-by: Angelo De Caro <adc@zurich.ibm.com>
1 parent 412b9db commit d264d0d

10 files changed

Lines changed: 707 additions & 171 deletions

File tree

token/core/zkatdlog/nogh/v1/transfer.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -127,17 +127,18 @@ func (s *TransferService) Transfer(ctx context.Context, anchor driver.TokenReque
127127
return nil, nil, errors.New("failed to prepare transfer action: nil output token")
128128
}
129129

130-
// load tokens with the passed token identifiers
130+
// 1. Load tokens with the passed token identifiers from the vault.
131131
loadedTokens, err := s.TokenLoader.LoadTokens(ctx, ids)
132132
if err != nil {
133133
return nil, nil, errors.Wrapf(err, "failed to load tokens")
134134
}
135+
// 2. Deserialize the loaded tokens into a format usable for generating the ZK proof.
135136
prepareInputs, err := s.prepareInputs(ctx, loadedTokens)
136137
if err != nil {
137138
return nil, nil, errors.Wrapf(err, "failed to prepare inputs")
138139
}
139140

140-
// get sender
141+
// 3. Initialize the Sender which will coordinate the ZK proof generation.
141142
pp := s.PublicParametersManager.PublicParams()
142143
sender, err := transfer.NewSender(nil, prepareInputs.Tokens(), ids, prepareInputs.Metadata(), pp)
143144
if err != nil {
@@ -146,7 +147,7 @@ func (s *TransferService) Transfer(ctx context.Context, anchor driver.TokenReque
146147
values := make([]uint64, 0, len(outputs))
147148
owners := make([][]byte, 0, len(outputs))
148149
var isRedeem bool
149-
// get values and owners of outputs
150+
// 4. Extract target values and owners from the requested outputs.
150151
s.Logger.DebugfContext(ctx, "Prepare %d output tokens", len(outputs))
151152
for i, output := range outputs {
152153
q, err := token2.ToQuantity(output.Quantity, pp.Precision())
@@ -160,8 +161,7 @@ func (s *TransferService) Transfer(ctx context.Context, anchor driver.TokenReque
160161
isRedeem = true
161162
}
162163
}
163-
// produce zkatdlog transfer action
164-
// return for each output its information in the clear
164+
// 5. Generate the ZK-SNARK transfer action and the metadata for the new outputs.
165165
start := time.Now()
166166
s.Logger.DebugfContext(ctx, "Generate zk transfer")
167167
transfer, outputsMetadata, err := sender.GenerateZKTransfer(ctx, values, owners)
@@ -172,17 +172,16 @@ func (s *TransferService) Transfer(ctx context.Context, anchor driver.TokenReque
172172
}
173173
s.Metrics.zkTransferDuration.Observe(duration.Seconds())
174174

175-
// add transfer action's transferMetadata
175+
// 6. Enrich the transfer action with additional metadata and upgrade witnesses if present.
176176
if opts != nil {
177177
transfer.Metadata = meta.TransferActionMetadata(opts.Attributes)
178178
}
179179

180-
// add upgrade witness
181180
for i, input := range transfer.Inputs {
182181
input.UpgradeWitness = prepareInputs[i].UpgradeWitness
183182
}
184183

185-
// prepare transferMetadata
184+
// 7. Prepare the TransferMetadata which contains audit information for auditors.
186185
ws := s.AuditInfoProvider
187186

188187
var transferInputsMetadata []*driver.TransferInputMetadata
@@ -265,6 +264,7 @@ func (s *TransferService) Transfer(ctx context.Context, anchor driver.TokenReque
265264
ExtraSigners: nil,
266265
}
267266

267+
// 8. If this is a redeem, select an issuer who can authorize it.
268268
if isRedeem {
269269
issuer, err := common.SelectIssuerForRedeem(pp.Issuers(), opts)
270270
if err != nil {

token/core/zkatdlog/nogh/v1/transfer/action.go

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,15 @@ import (
2424

2525
const ProtocolV1 = 1
2626

27+
// ActionInput represents a single input to a transfer action.
28+
// It includes the token identifier, the token itself, and an optional upgrade witness.
2729
type ActionInput struct {
2830
ID *token2.ID
2931
Token *token.Token
3032
UpgradeWitness *token.UpgradeWitness
3133
}
3234

35+
// ToProtos converts the ActionInput to its protobuf representation.
3336
func (a *ActionInput) ToProtos() (*actions.TransferActionInput, error) {
3437
var id *actions.TokenID
3538
if a.ID != nil {
@@ -76,6 +79,7 @@ func (a *ActionInput) ToProtos() (*actions.TransferActionInput, error) {
7679
}, nil
7780
}
7881

82+
// FromProtos populates the ActionInput from its protobuf representation.
7983
func (a *ActionInput) FromProtos(input *actions.TransferActionInput) error {
8084
if input.TokenId != nil {
8185
a.ID = &token2.ID{
@@ -117,7 +121,7 @@ func (a *ActionInput) FromProtos(input *actions.TransferActionInput) error {
117121

118122
// Action specifies a transfer of one or more tokens
119123
type Action struct {
120-
// Inputs specify the identifiers in of the tokens to be spent
124+
// Inputs specify the tokens to be spent
121125
Inputs []*ActionInput
122126
// Outputs are the new tokens resulting from the transfer
123127
Outputs []*token.Token
@@ -129,13 +133,13 @@ type Action struct {
129133
Issuer driver.Identity
130134
}
131135

132-
// NewTransfer returns the Action that matches the passed arguments
133-
func NewTransfer(tokenIDs []*token2.ID, inputToken []*token.Token, commitments []*math.G1, owners [][]byte, proof []byte) (*Action, error) {
136+
// NewAction returns the Action that matches the passed arguments
137+
func NewAction(tokenIDs []*token2.ID, inputToken []*token.Token, commitments []*math.G1, owners [][]byte, proof []byte) (*Action, error) {
134138
if len(commitments) != len(owners) {
135-
return nil, errors.Errorf("number of recipients [%d] does not match number of outputs [%d]", len(commitments), len(owners))
139+
return nil, errors.Wrapf(ErrMismatchedRecipientsOutputs, "number of recipients [%d] does not match number of outputs [%d]", len(commitments), len(owners))
136140
}
137141
if len(tokenIDs) != len(inputToken) {
138-
return nil, errors.Errorf("number of inputs [%d] does not match number of input tokens [%d]", len(tokenIDs), len(inputToken))
142+
return nil, errors.Wrapf(ErrMismatchedInputsTokens, "number of inputs [%d] does not match number of input tokens [%d]", len(tokenIDs), len(inputToken))
139143
}
140144

141145
inputs := make([]*ActionInput, len(tokenIDs))
@@ -160,11 +164,23 @@ func NewTransfer(tokenIDs []*token2.ID, inputToken []*token.Token, commitments [
160164
}, nil
161165
}
162166

167+
// NewActionFromProtos creates a new action from protos
168+
func NewActionFromProtos(raw []byte) (*Action, error) {
169+
action := &Action{}
170+
err := action.Deserialize(raw)
171+
if err != nil {
172+
return nil, err
173+
}
174+
175+
return action, nil
176+
}
177+
178+
// NumInputs returns the number of inputs in the Action
163179
func (t *Action) NumInputs() int {
164180
return len(t.Inputs)
165181
}
166182

167-
// GetInputs returns the inputs in the Action
183+
// GetInputs returns the identifiers of the tokens spent in the Action
168184
func (t *Action) GetInputs() []*token2.ID {
169185
res := make([]*token2.ID, len(t.Inputs))
170186
for i, input := range t.Inputs {
@@ -174,6 +190,7 @@ func (t *Action) GetInputs() []*token2.ID {
174190
return res
175191
}
176192

193+
// GetSerializedInputs returns the serialized tokens spent in the Action
177194
func (t *Action) GetSerializedInputs() ([][]byte, error) {
178195
var res [][]byte
179196
for _, input := range t.Inputs {
@@ -201,6 +218,7 @@ func (t *Action) GetSerializedInputs() ([][]byte, error) {
201218
return res, nil
202219
}
203220

221+
// GetSerialNumbers returns nil as zkatdlog doesn't use serial numbers for graph hiding
204222
func (t *Action) GetSerialNumbers() []string {
205223
return nil
206224
}
@@ -225,7 +243,7 @@ func (t *Action) IsRedeemAt(index int) bool {
225243
return t.Outputs[index].IsRedeem()
226244
}
227245

228-
// IsRedeem checks if this action is a Redeem Transfer
246+
// IsRedeem checks if this action contains any redeemed outputs
229247
func (t *Action) IsRedeem() bool {
230248
for _, output := range t.Outputs {
231249
if output.IsRedeem() {
@@ -255,38 +273,38 @@ func (t *Action) GetSerializedOutputs() ([][]byte, error) {
255273
return res, nil
256274
}
257275

258-
// IsGraphHiding returns false
259-
// zkatdlog is not graph hiding
276+
// IsGraphHiding returns false as zkatdlog is not graph hiding
260277
func (t *Action) IsGraphHiding() bool {
261278
return false
262279
}
263280

264-
// GetMetadata returns metadata of the Action
281+
// GetMetadata returns the metadata of the Action
265282
func (t *Action) GetMetadata() map[string][]byte {
266283
return t.Metadata
267284
}
268285

269-
// GetIssuer returns the issuer to sign the transaction
286+
// GetIssuer returns the identity of the issuer who must sign the transaction
270287
func (t *Action) GetIssuer() driver.Identity {
271288
return t.Issuer
272289
}
273290

291+
// Validate ensures the Action is well-formed
274292
func (t *Action) Validate() error {
275293
if len(t.Inputs) == 0 {
276-
return errors.Errorf("invalid number of token inputs, expected at least 1")
294+
return ErrInvalidInputs
277295
}
278296
for i, in := range t.Inputs {
279297
if in == nil {
280-
return errors.Errorf("invalid input at index [%d], empty input", i)
298+
return errors.Wrapf(ErrEmptyInput, "invalid input at index [%d], empty input", i)
281299
}
282300
if in.ID == nil {
283-
return errors.Errorf("invalid input's ID at index [%d], it is empty", i)
301+
return errors.Wrapf(ErrEmptyInputID, "invalid input's ID at index [%d], it is empty", i)
284302
}
285303
if len(in.ID.TxId) == 0 {
286-
return errors.Errorf("invalid input's ID at index [%d], tx id is empty", i)
304+
return errors.Wrapf(ErrEmptyInputTxID, "invalid input's ID at index [%d], tx id is empty", i)
287305
}
288306
if in.Token == nil {
289-
return errors.Errorf("invalid input's token at index [%d], empty token", i)
307+
return errors.Wrapf(ErrEmptyInputToken, "invalid input's token at index [%d], empty token", i)
290308
}
291309
if err := in.Token.Validate(true); err != nil {
292310
return errors.Wrapf(err, "invalid input token at index [%d]", i)
@@ -299,28 +317,29 @@ func (t *Action) Validate() error {
299317
}
300318
}
301319
if len(t.Outputs) == 0 {
302-
return errors.Errorf("invalid number of token outputs, expected at least 1")
320+
return ErrInvalidOutputs
303321
}
304322
for i, out := range t.Outputs {
305323
if out == nil {
306-
return errors.Errorf("invalid output token at index [%d]", i)
324+
return errors.Wrapf(ErrEmptyOutputToken, "invalid output token at index [%d]", i)
307325
}
308326
if err := out.Validate(false); err != nil {
309327
return errors.Wrapf(err, "invalid output at index [%d]", i)
310328
}
311329
}
312330
if t.IsRedeem() && (t.Issuer == nil) {
313-
return errors.Errorf("Expected Issuer for a Redeem action")
331+
return ErrMissingIssuer
314332
}
315333

316334
return nil
317335
}
318336

337+
// ExtraSigners returns nil as zkatdlog doesn't require extra signers
319338
func (t *Action) ExtraSigners() []driver.Identity {
320339
return nil
321340
}
322341

323-
// Serialize marshal TransferAction
342+
// Serialize marshals the TransferAction to bytes
324343
func (t *Action) Serialize() ([]byte, error) {
325344
// inputs
326345
inputs, err := protos.ToProtosSlice[actions.TransferActionInput, *ActionInput](t.Inputs)
@@ -367,24 +386,24 @@ func (t *Action) Serialize() ([]byte, error) {
367386
return proto.Marshal(action)
368387
}
369388

370-
// Deserialize un-marshals TransferAction
389+
// Deserialize un-marshals a TransferAction from bytes
371390
func (t *Action) Deserialize(raw []byte) error {
372391
action := &actions.TransferAction{}
373392
err := proto.Unmarshal(raw, action)
374393
if err != nil {
375-
return errors.Wrap(err, "failed to deserialize issue action")
394+
return errors.Wrap(err, "failed to deserialize transfer action")
376395
}
377396

378397
// assert version
379398
if action.Version != ProtocolV1 {
380-
return errors.Errorf("invalid issue version, expected [%d], got [%d]", ProtocolV1, action.Version)
399+
return errors.Wrapf(ErrInvalidVersion, "expected [%d], got [%d]", ProtocolV1, action.Version)
381400
}
382401

383402
// inputs
384403
t.Inputs = make([]*ActionInput, len(action.Inputs))
385404
t.Inputs = slices.GenericSliceOfPointers[ActionInput](len(action.Inputs))
386405
if err := protos.FromProtosSlice(action.Inputs, t.Inputs); err != nil {
387-
return errors.Wrap(err, "failed unmarshalling receivers metadata")
406+
return errors.Wrap(err, "failed unmarshalling inputs")
388407
}
389408

390409
// outputs
@@ -417,12 +436,12 @@ func (t *Action) Deserialize(raw []byte) error {
417436
return nil
418437
}
419438

420-
// GetProof returns the proof in the Action
439+
// GetProof returns the zero-knowledge proof in the Action
421440
func (t *Action) GetProof() []byte {
422441
return t.Proof
423442
}
424443

425-
// GetOutputCommitments returns the Pedersen commitments in the Action
444+
// GetOutputCommitments returns the cryptographic commitments of the outputs
426445
func (t *Action) GetOutputCommitments() []*math.G1 {
427446
com := make([]*math.G1, len(t.Outputs))
428447
for i := 0; i < len(com); i++ {
@@ -432,6 +451,7 @@ func (t *Action) GetOutputCommitments() []*math.G1 {
432451
return com
433452
}
434453

454+
// InputTokens returns the tokens spent in the Action
435455
func (t *Action) InputTokens() []*token.Token {
436456
tokens := make([]*token.Token, len(t.Inputs))
437457
for i, in := range t.Inputs {

0 commit comments

Comments
 (0)