2019-09-14 23:44:19 +00:00
package privacypass
import (
"crypto/hmac"
"crypto/rand"
2022-10-24 20:00:45 +00:00
"encoding/json"
2019-09-14 23:44:19 +00:00
"fmt"
2021-04-09 00:55:17 +00:00
"git.openprivacy.ca/cwtch.im/tapir/primitives/core"
2020-02-06 23:54:13 +00:00
"git.openprivacy.ca/openprivacy/log"
2019-09-15 21:20:05 +00:00
ristretto "github.com/gtank/ristretto255"
2019-09-14 23:44:19 +00:00
"golang.org/x/crypto/sha3"
)
// Token is an implementation of PrivacyPass
// Davidson A, Goldberg I, Sullivan N, Tankersley G, Valsorda F. Privacy pass: Bypassing internet challenges anonymously. Proceedings on Privacy Enhancing Technologies. 2018 Jun 1;2018(3):164-80.
type Token struct {
t [ ] byte
r * ristretto . Scalar
2019-09-15 21:20:05 +00:00
W * ristretto . Element
2019-09-14 23:44:19 +00:00
}
2019-12-02 20:37:25 +00:00
// GetT returns the underlying bytes for token for use in constraint proofs.
func ( t Token ) GetT ( ) [ ] byte {
return t . t
}
2019-09-14 23:44:19 +00:00
// BlindedToken encapsulates a Blinded Token
type BlindedToken struct {
2019-09-15 21:20:05 +00:00
P * ristretto . Element
2019-09-14 23:44:19 +00:00
}
// SignedToken encapsulates a Signed (Blinded) Token
type SignedToken struct {
2019-09-15 21:20:05 +00:00
Q * ristretto . Element
2019-09-14 23:44:19 +00:00
}
// SpentToken encapsulates the parameters needed to spend a Token
type SpentToken struct {
2019-09-15 05:50:06 +00:00
T [ ] byte
2019-09-14 23:44:19 +00:00
MAC [ ] byte
}
2019-09-15 05:50:06 +00:00
// TokenPaymentHandler defines an interface with external payment processors
type TokenPaymentHandler interface {
2019-09-15 21:20:05 +00:00
MakePayment ( )
2019-11-26 21:10:09 +00:00
// Next Token
NextToken ( data [ ] byte , hostname string ) ( SpentToken , error )
2019-09-15 05:50:06 +00:00
}
2019-09-14 23:44:19 +00:00
// GenBlindedToken initializes the Token
// GenToken() & Blind()
func ( t * Token ) GenBlindedToken ( ) BlindedToken {
t . t = make ( [ ] byte , 32 )
rand . Read ( t . t )
2019-09-15 21:20:05 +00:00
t . r = new ( ristretto . Scalar )
b := make ( [ ] byte , 64 )
rand . Read ( b )
2022-08-29 03:12:14 +00:00
t . r . SetUniformBytes ( b )
2019-09-14 23:44:19 +00:00
2019-09-15 21:20:05 +00:00
Ht := sha3 . Sum512 ( t . t )
2022-08-29 03:12:14 +00:00
T , _ := new ( ristretto . Element ) . SetUniformBytes ( Ht [ : ] )
2019-09-15 21:20:05 +00:00
P := new ( ristretto . Element ) . ScalarMult ( t . r , T )
2019-09-14 23:44:19 +00:00
return BlindedToken { P }
}
// unblindSignedToken unblinds a token that has been signed by a server
func ( t * Token ) unblindSignedToken ( token SignedToken ) {
2019-09-15 21:20:05 +00:00
t . W = new ( ristretto . Element ) . ScalarMult ( new ( ristretto . Scalar ) . Invert ( t . r ) , token . Q )
2019-09-14 23:44:19 +00:00
}
// SpendToken binds the token with data and then redeems the token
func ( t * Token ) SpendToken ( data [ ] byte ) SpentToken {
2022-08-29 03:12:14 +00:00
key := sha3 . Sum256 ( append ( t . t , t . W . Bytes ( ) ... ) )
2019-09-14 23:44:19 +00:00
mac := hmac . New ( sha3 . New512 , key [ : ] )
2020-07-21 00:41:50 +00:00
mac . Write ( data )
return SpentToken { t . t , mac . Sum ( nil ) }
2019-09-14 23:44:19 +00:00
}
// GenerateBlindedTokenBatch generates a batch of blinded tokens (and their unblinded equivalents)
func GenerateBlindedTokenBatch ( num int ) ( tokens [ ] * Token , blindedTokens [ ] BlindedToken ) {
for i := 0 ; i < num ; i ++ {
tokens = append ( tokens , new ( Token ) )
blindedTokens = append ( blindedTokens , tokens [ i ] . GenBlindedToken ( ) )
}
return
}
// verifyBatchProof verifies a given batch proof (see also UnblindSignedTokenBatch)
2019-09-15 21:20:05 +00:00
func verifyBatchProof ( dleq DLEQProof , Y * ristretto . Element , blindedTokens [ ] BlindedToken , signedTokens [ ] SignedToken , transcript * core . Transcript ) bool {
transcript . NewProtocol ( BatchProofProtocol )
2022-08-29 03:12:14 +00:00
transcript . AddToTranscript ( BatchProofX , ristretto . NewGeneratorElement ( ) . Bytes ( ) )
transcript . AddToTranscript ( BatchProofY , Y . Bytes ( ) )
2019-09-15 21:20:05 +00:00
transcript . AddToTranscript ( BatchProofPVector , [ ] byte ( fmt . Sprintf ( "%v" , blindedTokens ) ) )
transcript . AddToTranscript ( BatchProofQVector , [ ] byte ( fmt . Sprintf ( "%v" , signedTokens ) ) )
2019-09-14 23:44:19 +00:00
prng := transcript . CommitToPRNG ( "w" )
2022-08-29 03:12:14 +00:00
M := ristretto . NewIdentityElement ( )
Z := ristretto . NewIdentityElement ( )
2022-04-19 22:16:07 +00:00
buf := make ( [ ] byte , 64 )
c := new ( ristretto . Scalar )
2019-09-14 23:44:19 +00:00
for i := range blindedTokens {
2022-04-19 22:16:07 +00:00
err := prng . Next ( buf , c )
if err != nil {
log . Errorf ( "error verifying batch proof: %v" , err )
return false
}
2019-09-15 21:20:05 +00:00
M = new ( ristretto . Element ) . Add ( new ( ristretto . Element ) . ScalarMult ( c , blindedTokens [ i ] . P ) , M )
Z = new ( ristretto . Element ) . Add ( new ( ristretto . Element ) . ScalarMult ( c , signedTokens [ i ] . Q ) , Z )
2019-09-14 23:44:19 +00:00
}
2022-08-29 03:12:14 +00:00
return VerifyDiscreteLogEquivalenceProof ( dleq , ristretto . NewGeneratorElement ( ) , Y , M , Z , transcript )
2019-09-14 23:44:19 +00:00
}
// UnblindSignedTokenBatch taking in a set of tokens, their blinded & signed counterparts, a server public key (Y), a DLEQ proof and a transcript
// verifies that the signing procedure has taken place correctly and unblinds the tokens.
2019-09-15 21:20:05 +00:00
func UnblindSignedTokenBatch ( tokens [ ] * Token , blindedTokens [ ] BlindedToken , signedTokens [ ] SignedToken , Y * ristretto . Element , proof DLEQProof , transcript * core . Transcript ) bool {
2019-09-14 23:44:19 +00:00
verified := verifyBatchProof ( proof , Y , blindedTokens , signedTokens , transcript )
if ! verified {
2019-12-02 20:37:25 +00:00
log . Debugf ( "Failed to unblind tokens: %v" , transcript . OutputTranscriptToAudit ( ) )
2019-09-14 23:44:19 +00:00
return false
}
for i , t := range tokens {
t . unblindSignedToken ( signedTokens [ i ] )
}
return true
}
2022-10-24 20:00:45 +00:00
// MarshalJSON - in order to store tokens in a serialized form we need to expose the private, unexported value
// `t`. Note that `r` is not needed to spend the token, and as such we effectively destroy it when we serialize.
// Ideally, go would let us do this with an annotation, alas.
func ( t Token ) MarshalJSON ( ) ( [ ] byte , error ) {
return json . Marshal ( struct {
T [ ] byte ` json:"t" `
W * ristretto . Element
} {
T : t . t ,
W : t . W ,
} )
}