107 lines
4.5 KiB
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
|
||
|
}
|