zcashtokenservice/api.go

107 lines
4.5 KiB
Go

package zcashtokenservice
import (
"cwtch.im/tapir/primitives/core"
"cwtch.im/tapir/primitives/privacypass"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"git.openprivacy.ca/openprivacy/libricochet-go/log"
"github.com/gtank/ristretto255"
"golang.org/x/crypto/sha3"
"strings"
)
type Context struct {
Y *ristretto255.Element
tokens []*privacypass.Token
blindedTokens []privacypass.BlindedToken
transcript *core.Transcript
ct *privacypass.Token
}
type ZcashTokenRequest struct {
BlindedTokens []privacypass.BlindedToken `json:"bts"`
ReturnAddress string `json:"ra"`
ConstraintToken []byte `json:"ct"`
}
// RequestTokens generates a zcash uri
func RequestTokenURI(tokenServiceZcashAddress string, tokenServicePublicKey *ristretto255.Element, zcashReturnAddress string, constraintToken *privacypass.Token) (Context, string) {
tokens, blinded := privacypass.GenerateBlindedTokenBatch(4)
transcript := core.NewTranscript("zcash-token-service")
transcript.AddToTranscript(zcashReturnAddress, []byte(zcashReturnAddress))
transcript.AddToTranscript("zcash-token-server", []byte(tokenServiceZcashAddress))
request := ZcashTokenRequest{BlindedTokens: blinded, ReturnAddress: zcashReturnAddress}
if constraintToken != nil {
transcript.AddToTranscript("constraint-token-t", constraintToken.GetT())
request.ConstraintToken = constraintToken.GetT()
}
data, _ := json.Marshal(request)
// NOTE: We are currently hardcoding this amount!
return Context{tokens: tokens, blindedTokens: blinded, Y: tokenServicePublicKey, transcript: transcript, ct: constraintToken}, fmt.Sprintf("zcash:%v?amt=%f&memo=%v", tokenServiceZcashAddress, 0.1, base64.StdEncoding.EncodeToString(data))
}
type ZcashTokenResponse struct {
privacypass.SignedBatchWithProof `json:"sb"`
Error error `json:",omitempty"`
}
func ProcessRequest(request string, tokenServiceZcashAddress string, server *privacypass.TokenServer) (string, string) {
log.Infof("Request: [%x]", request)
data, err := base64.StdEncoding.DecodeString(request)
log.Infof("Err: %s", data)
if err == nil {
zcashTokenRequest := new(ZcashTokenRequest)
err = json.Unmarshal(data, zcashTokenRequest)
if err == nil {
transcript := core.NewTranscript("zcash-token-service")
transcript.AddToTranscript(zcashTokenRequest.ReturnAddress, []byte(zcashTokenRequest.ReturnAddress))
transcript.AddToTranscript("zcash-token-server", []byte(tokenServiceZcashAddress))
if len(zcashTokenRequest.ConstraintToken) == 0 {
signedBatchWithProof := server.SignBlindedTokenBatch(zcashTokenRequest.BlindedTokens, transcript)
data, _ := json.Marshal(ZcashTokenResponse{signedBatchWithProof, nil})
return base64.StdEncoding.EncodeToString(data), zcashTokenRequest.ReturnAddress
} else {
transcript.AddToTranscript("constraint-token-t", zcashTokenRequest.ConstraintToken)
signedBatchWithProof := server.SignBlindedTokenBatchWithConstraint(zcashTokenRequest.BlindedTokens, zcashTokenRequest.ConstraintToken, transcript)
log.Debugf("Server Side Transcript: %s", transcript.OutputTranscriptToAudit())
data, _ := json.Marshal(ZcashTokenResponse{signedBatchWithProof, nil})
return base64.StdEncoding.EncodeToString(data), zcashTokenRequest.ReturnAddress
}
}
}
errorresponse, _ := json.Marshal(ZcashTokenResponse{privacypass.SignedBatchWithProof{}, err})
return base64.StdEncoding.EncodeToString(errorresponse), ""
}
func ProcessResponse(response string, ctx Context) ([]*privacypass.Token, error) {
response = strings.ReplaceAll(response, "\n", "")
response = strings.ReplaceAll(response, "\r", "")
data, err := base64.StdEncoding.DecodeString(response)
if err == nil {
zcashTokenResponse := new(ZcashTokenResponse)
err = json.Unmarshal(data, zcashTokenResponse)
if err == nil {
if ctx.ct == nil {
if privacypass.UnblindSignedTokenBatch(ctx.tokens, ctx.blindedTokens, zcashTokenResponse.SignedTokens, ctx.Y, zcashTokenResponse.Proof, ctx.transcript) {
return ctx.tokens, nil
}
} else {
Ht := sha3.Sum512(ctx.ct.GetT())
T := new(ristretto255.Element).FromUniformBytes(Ht[:])
if privacypass.UnblindSignedTokenBatch(ctx.tokens, append(ctx.blindedTokens, privacypass.BlindedToken{T}), append(zcashTokenResponse.SignedTokens, privacypass.SignedToken{ctx.ct.W}), ctx.Y, zcashTokenResponse.Proof, ctx.transcript) {
return ctx.tokens, nil
}
}
err = errors.New("failed to unblind signed tokens")
}
}
return nil, err
}