diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index c024304..a3e2c40 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -22,6 +22,5 @@ jobs: run: go build -v ./... - name: Test - run: | - go test -v --count=1 ./... + run: make test diff --git a/Makefile b/Makefile index 2c48e02..6125f5a 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,18 @@ -test: test_token test_type1 test_type2 test_type3 test_type5 test_typeBatched - go test ./... --count=1 +test: test_token test_type1 test_type1_amortized test_type2 test_type3 test_type5 test_type5_amortized test_typeBatched + go test ./... -run TestVectorVerifyToken --count=1 vectors: test + AMORTIZED_TYPE1_ISSUANCE_TEST_VECTORS_OUT=type1-issuance-test-vectors.json go test -v -run TestVectorGenerateAmortizedBasicPrivateIssuance ./... + AMORTIZED_TYPE5_ISSUANCE_TEST_VECTORS_OUT=type1-issuance-test-vectors.json go test -v -run TestVectorGenerateAmortizedRistrettoPrivateIssuance ./... BATCHED_ISSUANCE_TEST_VECTORS_OUT=batched-issuance-test-vectors.json go test -v -run TestVectorGenerateBatchedIssuance ./... ED25519_BLINDING_TEST_VECTORS_OUT=type3-ed25519-blinding-test-vectors.json go test -v -run TestVectorGenerateEd25519Blinding ./... ECDSA_BLINDING_TEST_VECTORS_OUT=type3-ecdsa-blinding-test-vectors.json go test -v -run TestVectorGenerateECDSABlinding ./... TOKEN_TEST_VECTORS_OUT=token-test-vectors.json go test -v -run TestVectorGenerateToken ./... TYPE1_ISSUANCE_TEST_VECTORS_OUT=type1-issuance-test-vectors.json go test -v -run TestVectorGenerateBasicPrivateIssuance ./... - TYPE5_ISSUANCE_TEST_VECTORS_OUT=type5-issuance-test-vectors.json go test -v -run TestVectorGenerateBatchedPrivateIssuance ./... TYPE2_ISSUANCE_TEST_VECTORS_OUT=type2-issuance-test-vectors.json go test -v -run TestVectorGenerateBasicIssuance ./... TYPE3_ANON_ORIGIN_ID_TEST_VECTORS_OUT=type3-anon-origin-id-test-vectors.json go test -v -run TestVectorGenerateAnonOriginID ./... TYPE3_ORIGIN_ENCRYPTION_TEST_VECTORS_OUT=type3-origin-encryption-test-vectors.json go test -v -run TestVectorGenerateOriginEncryption ./... + TYPE5_ISSUANCE_TEST_VECTORS_OUT=type5-issuance-test-vectors.json go test -v -run TestVectorGenerateRistrettoPrivateIssuance ./... bench: go test -bench=. @@ -21,9 +23,15 @@ test_token: test_type1: TYPE1_ISSUANCE_TEST_VECTORS_IN=type1-issuance-test-vectors.json \ - go test -v --count=1 ./tokens/type1/... + go test -v --count=1 -run TestVectorVerifyBasicPrivateIssuance ./tokens/private/... TYPE1_ISSUANCE_TEST_VECTORS_IN=type1-issuance-test-vectors.rust.json \ - go test -v --count=1 ./tokens/type1/... + go test -v --count=1 -run TestVectorVerifyBasicPrivateIssuance ./tokens/private/... + +test_type1_amortized: + AMORTIZED_TYPE1_ISSUANCE_TEST_VECTORS_IN=type1-issuance-test-vectors.json \ + go test -v --count=1 -run TestVectorVerifyAmortizedBasicPrivateIssuance ./tokens/amortized/... + AMORTIZED_TYPE1_ISSUANCE_TEST_VECTORS_IN=type1-issuance-test-vectors.rust.json \ + go test -v --count=1 -run TestVectorVerifyAmortizedBasicPrivateIssuance ./tokens/amortized/... test_type2: TYPE2_ISSUANCE_TEST_VECTORS_IN=type2-issuance-test-vectors.json \ @@ -40,9 +48,15 @@ test_type3: test_type5: TYPE5_ISSUANCE_TEST_VECTORS_IN=type5-issuance-test-vectors.json \ - go test -v --count=1 ./tokens/type5/... + go test -v --count=1 -run TestVectorVerifyRistrettoPrivateIssuance ./tokens/private/... TYPE5_ISSUANCE_TEST_VECTORS_IN=type5-issuance-test-vectors.rust.json \ - go test -v --count=1 ./tokens/type5/... + go test -v --count=1 -run TestVectorVerifyRistrettoPrivateIssuance ./tokens/private/... + +test_type5_amortized: + AMORTIZED_TYPE5_ISSUANCE_TEST_VECTORS_IN=type5-issuance-test-vectors.json \ + go test -v --count=1 -run TestVectorVerifyAmortizedRistrettoPrivateIssuance ./tokens/amortized/... + AMORTIZED_TYPE5_ISSUANCE_TEST_VECTORS_IN=type5-issuance-test-vectors.rust.json \ + go test -v --count=1 -run TestVectorVerifyAmortizedRistrettoPrivateIssuance ./tokens/amortized/... test_typeBatched: BATCHED_ISSUANCE_TEST_VECTORS_IN=batched-issuance-test-vectors.json \ diff --git a/scripts/format_test_vectors.py b/scripts/format_test_vectors.py index c764bf3..e107733 100644 --- a/scripts/format_test_vectors.py +++ b/scripts/format_test_vectors.py @@ -74,11 +74,12 @@ def format_vector(vector_keys, vector_fname): ] format_vector(ordered_keys, sys.argv[1]) -if "type5-issuance" in sys.argv[1]: +if "type1-issuance" in sys.argv[1]: ordered_keys = [ "skS", "pkS", "token_challenge", "nonces", "blinds", "salt", "token_request", "token_response", "tokens" ] format_vector(ordered_keys, sys.argv[1]) + exit(0) if "type1-issuance" in sys.argv[1]: ordered_keys = [ @@ -86,6 +87,12 @@ def format_vector(vector_keys, vector_fname): ] format_vector(ordered_keys, sys.argv[1]) +if "type5-issuance" in sys.argv[1]: + ordered_keys = [ + "skS", "pkS", "token_challenge", "nonce", "blind", "token_request", "token_response", "token" + ] + format_vector(ordered_keys, sys.argv[1]) + if "batched-issuance-test-vectors.json" in sys.argv[1]: ordered_keys = [ ("issuance", ["type", "skS", "pkS", "token_challenge", "nonce", "nonces", "blind", "blinds", "token", "tokens"]), diff --git a/tokens/type5/type5_test.go b/tokens/amortized/amortized_test.go similarity index 50% rename from tokens/type5/type5_test.go rename to tokens/amortized/amortized_test.go index 811d198..ad54c96 100644 --- a/tokens/type5/type5_test.go +++ b/tokens/amortized/amortized_test.go @@ -1,10 +1,12 @@ -package type5 +package amortized import ( "bytes" "crypto/rand" "crypto/sha256" + "encoding/binary" "encoding/json" + "fmt" "os" "testing" @@ -12,12 +14,15 @@ import ( "golang.org/x/crypto/hkdf" "github.com/cloudflare/pat-go/tokens" + "github.com/cloudflare/pat-go/tokens/private" "github.com/cloudflare/pat-go/util" ) const ( - outputBatchedPrivateIssuanceTestVectorEnvironmentKey = "TYPE5_ISSUANCE_TEST_VECTORS_OUT" - inputBatchedPrivateIssuanceTestVectorEnvironmentKey = "TYPE5_ISSUANCE_TEST_VECTORS_IN" + outputAmortizedBasicPrivateIssuanceTestVectorEnvironmentKey = "AMORTIZED_TYPE1_ISSUANCE_TEST_VECTORS_OUT" + inputAmortizedBasicPrivateIssuanceTestVectorEnvironmentKey = "AMORTIZED_TYPE1_ISSUANCE_TEST_VECTORS_IN" + outputAmortizedRistrettoPrivateIssuanceTestVectorEnvironmentKey = "AMORTIZED_TYPE5_ISSUANCE_TEST_VECTORS_OUT" + inputAmortizedRistrettoPrivateIssuanceTestVectorEnvironmentKey = "AMORTIZED_TYPE5_ISSUANCE_TEST_VECTORS_IN" ) func createTokenChallenge(tokenType uint16, redemptionContext []byte, issuerName string, originInfo []string) tokens.TokenChallenge { @@ -31,14 +36,14 @@ func createTokenChallenge(tokenType uint16, redemptionContext []byte, issuerName return challenge } -func TestBatchedPrivateIssuanceRoundTrip(t *testing.T) { +func TestAmortizedPrivateIssuanceRoundTrip(t *testing.T) { tokenKey, err := oprf.GenerateKey(oprf.SuiteRistretto255, rand.Reader) if err != nil { t.Fatal(err) } - issuer := NewBatchedPrivateIssuer(tokenKey) - client := BatchedPrivateClient{} + issuer := NewAmortizedRistrettoPrivateIssuer(tokenKey) + client := NewAmortizedRistrettoPrivateClient() challenge := make([]byte, 32) util.MustRead(t, rand.Reader, challenge) @@ -77,7 +82,7 @@ func TestBatchedPrivateIssuanceRoundTrip(t *testing.T) { // ///// // Batched issuance test vector -type rawBatchedPrivateIssuanceTestVector struct { +type rawAmortizedPrivateIssuanceTestVector struct { PrivateKey string `json:"skS"` PublicKey string `json:"pkS"` Challenge string `json:"token_challenge"` @@ -88,7 +93,7 @@ type rawBatchedPrivateIssuanceTestVector struct { Tokens []string `json:"tokens"` } -type BatchedPrivateIssuanceTestVector struct { +type AmortizedPrivateIssuanceTestVector struct { t *testing.T skS *oprf.PrivateKey challenge []byte @@ -99,16 +104,16 @@ type BatchedPrivateIssuanceTestVector struct { tokens []tokens.Token } -type BatchedPrivateIssuanceTestVectorArray struct { +type AmortizedPrivateIssuanceTestVectorArray struct { t *testing.T - vectors []BatchedPrivateIssuanceTestVector + vectors []AmortizedPrivateIssuanceTestVector } -func (tva BatchedPrivateIssuanceTestVectorArray) MarshalJSON() ([]byte, error) { +func (tva AmortizedPrivateIssuanceTestVectorArray) MarshalJSON() ([]byte, error) { return json.Marshal(tva.vectors) } -func (tva *BatchedPrivateIssuanceTestVectorArray) UnmarshalJSON(data []byte) error { +func (tva *AmortizedPrivateIssuanceTestVectorArray) UnmarshalJSON(data []byte) error { err := json.Unmarshal(data, &tva.vectors) if err != nil { return err @@ -120,13 +125,13 @@ func (tva *BatchedPrivateIssuanceTestVectorArray) UnmarshalJSON(data []byte) err return nil } -func (etv BatchedPrivateIssuanceTestVector) MarshalJSON() ([]byte, error) { +func (etv AmortizedPrivateIssuanceTestVector) MarshalJSON() ([]byte, error) { tokens := make([][]byte, len(etv.tokens)) for i := 0; i < len(tokens); i++ { tokens[i] = etv.tokens[i].Marshal() } - return json.Marshal(rawBatchedPrivateIssuanceTestVector{ + return json.Marshal(rawAmortizedPrivateIssuanceTestVector{ PrivateKey: util.MustHex(util.MustMarshalPrivateOPRFKey(etv.skS)), PublicKey: util.MustHex(util.MustMarshalPublicOPRFKey(etv.skS.Public())), Challenge: util.MustHex(etv.challenge), @@ -147,14 +152,13 @@ func mustUnmarshalBatchedPrivateOPRFKey(data []byte) *oprf.PrivateKey { return key } -func (etv *BatchedPrivateIssuanceTestVector) UnmarshalJSON(data []byte) error { - raw := rawBatchedPrivateIssuanceTestVector{} +func (etv *AmortizedPrivateIssuanceTestVector) UnmarshalJSON(data []byte) error { + raw := rawAmortizedPrivateIssuanceTestVector{} err := json.Unmarshal(data, &raw) if err != nil { return err } - etv.skS = mustUnmarshalBatchedPrivateOPRFKey(util.MustUnhex(nil, raw.PrivateKey)) etv.challenge = util.MustUnhex(nil, raw.Challenge) etv.tokenRequest = util.MustUnhex(nil, raw.TokenRequest) etv.tokenResponse = util.MustUnhex(nil, raw.TokenResponse) @@ -171,17 +175,31 @@ func (etv *BatchedPrivateIssuanceTestVector) UnmarshalJSON(data []byte) error { etv.tokens = make([]tokens.Token, len(raw.Tokens)) for i := 0; i < len(raw.Tokens); i++ { - token, err := UnmarshalBatchedPrivateToken(util.MustUnhex(nil, raw.Tokens[i])) + token, err := private.UnmarshalPrivateToken(util.MustUnhex(nil, raw.Tokens[i])) if err != nil { return err } etv.tokens[i] = token } + skS := util.MustUnhex(nil, raw.PrivateKey) + switch etv.tokens[0].TokenType { + case private.BasicPrivateTokenType: + etv.skS = util.MustUnmarshalPrivateOPRFKey(skS) + case private.RistrettoPrivateTokenType: + etv.skS = mustUnmarshalBatchedPrivateOPRFKey(skS) + default: + return fmt.Errorf("invalid private key format") + } + return nil } -func generateBatchedPrivateIssuanceBlindingTestVector(t *testing.T, client *BatchedPrivateClient, issuer *BatchedPrivateIssuer, tokenChallenge tokens.TokenChallenge) BatchedPrivateIssuanceTestVector { +func (etv *AmortizedPrivateIssuanceTestVector) TokenType() uint16 { + return binary.BigEndian.Uint16(etv.tokenRequest[:2]) +} + +func generateAmortizedPrivateIssuanceBlindingTestVector(t *testing.T, client *AmortizedPrivateClient, issuer *AmortizedPrivateIssuer, tokenChallenge tokens.TokenChallenge) AmortizedPrivateIssuanceTestVector { challenge := tokenChallenge.Marshal() nonces := make([][]byte, 3) @@ -224,7 +242,7 @@ func generateBatchedPrivateIssuanceBlindingTestVector(t *testing.T, client *Batc } } - return BatchedPrivateIssuanceTestVector{ + return AmortizedPrivateIssuanceTestVector{ t: t, skS: issuer.tokenKey, challenge: challenge, @@ -236,9 +254,19 @@ func generateBatchedPrivateIssuanceBlindingTestVector(t *testing.T, client *Batc } } -func verifyBatchedPrivateIssuanceTestVector(t *testing.T, vector BatchedPrivateIssuanceTestVector) { - issuer := NewBatchedPrivateIssuer(vector.skS) - client := BatchedPrivateClient{} +func verifyAmortizedPrivateIssuanceTestVector(t *testing.T, vector AmortizedPrivateIssuanceTestVector) { + var issuer *AmortizedPrivateIssuer + var client AmortizedPrivateClient + switch vector.TokenType() { + case private.BasicPrivateTokenType: + issuer = NewAmortizedBasicPrivateIssuer(vector.skS) + client = NewAmortizedBasicPrivateClient() + case private.RistrettoPrivateTokenType: + issuer = NewAmortizedRistrettoPrivateIssuer(vector.skS) + client = NewAmortizedRistrettoPrivateClient() + default: + t.Error(fmt.Errorf("invalid token type")) + } tokenKeyID := issuer.TokenKeyID() tokenPublicKey := issuer.TokenKey() @@ -265,35 +293,87 @@ func verifyBatchedPrivateIssuanceTestVector(t *testing.T, vector BatchedPrivateI } } -func verifyBatchedPrivateIssuanceTestVectors(t *testing.T, encoded []byte) { - vectors := BatchedPrivateIssuanceTestVectorArray{t: t} +func verifyAmortizedPrivateIssuanceTestVectors(t *testing.T, encoded []byte) { + vectors := AmortizedPrivateIssuanceTestVectorArray{t: t} err := json.Unmarshal(encoded, &vectors) if err != nil { t.Fatalf("Error decoding test vector string: %v", err) } for _, vector := range vectors.vectors { - verifyBatchedPrivateIssuanceTestVector(t, vector) + verifyAmortizedPrivateIssuanceTestVector(t, vector) + } +} + +func TestVectorGenerateAmortizedBasicPrivateIssuance(t *testing.T) { + hash := sha256.New + secret := []byte("test vector secret") + hkdf := hkdf.New(hash, secret, nil, []byte{0x00, byte(private.BasicPrivateTokenType & 0xFF)}) + + redemptionContext := make([]byte, 32) + util.MustRead(t, hkdf, redemptionContext) + + challenges := []tokens.TokenChallenge{ + createTokenChallenge(private.BasicPrivateTokenType, redemptionContext, "issuer.example", []string{"origin.example"}), + createTokenChallenge(private.BasicPrivateTokenType, nil, "issuer.example", []string{"origin.example"}), + createTokenChallenge(private.BasicPrivateTokenType, nil, "issuer.example", []string{"foo.example,bar.example"}), + createTokenChallenge(private.BasicPrivateTokenType, nil, "issuer.example", []string{}), + createTokenChallenge(private.BasicPrivateTokenType, redemptionContext, "issuer.example", []string{}), + } + + vectors := make([]AmortizedPrivateIssuanceTestVector, len(challenges)) + for i := 0; i < len(challenges); i++ { + challenge := challenges[i] + challengeEnc := challenge.Marshal() + + var seed [32]byte + util.MustRead(t, rand.Reader, seed[:]) + tokenKey, err := oprf.DeriveKey(oprf.SuiteP384, oprf.VerifiableMode, seed[:], challengeEnc) + if err != nil { + t.Fatal(err) + } + + issuer := NewAmortizedBasicPrivateIssuer(tokenKey) + client := NewAmortizedBasicPrivateClient() + + vectors[i] = generateAmortizedPrivateIssuanceBlindingTestVector(t, &client, issuer, challenge) + } + + // Encode the test vectors + encoded, err := json.Marshal(vectors) + if err != nil { + t.Fatalf("Error producing test vectors: %v", err) + } + + // Verify that we process them correctly + verifyAmortizedPrivateIssuanceTestVectors(t, encoded) + + var outputFile string + if outputFile = os.Getenv(outputAmortizedBasicPrivateIssuanceTestVectorEnvironmentKey); len(outputFile) > 0 { + err := os.WriteFile(outputFile, encoded, 0644) + if err != nil { + t.Fatalf("Error writing test vectors: %v", err) + } } } -func TestVectorGenerateBatchedPrivateIssuance(t *testing.T) { +func TestVectorGenerateAmortizedRistrettoPrivateIssuance(t *testing.T) { hash := sha256.New secret := []byte("test vector secret") - hkdf := hkdf.New(hash, secret, nil, []byte{0x00, byte(BatchedPrivateTokenType & 0xFF)}) + hkdf := hkdf.New(hash, secret, nil, []byte{0x00, byte(private.RistrettoPrivateTokenType & 0xFF)}) redemptionContext := make([]byte, 32) util.MustRead(t, hkdf, redemptionContext) challenges := []tokens.TokenChallenge{ - createTokenChallenge(BatchedPrivateTokenType, redemptionContext, "issuer.example", []string{"origin.example"}), - createTokenChallenge(BatchedPrivateTokenType, nil, "issuer.example", []string{"origin.example"}), - createTokenChallenge(BatchedPrivateTokenType, nil, "issuer.example", []string{"foo.example,bar.example"}), - createTokenChallenge(BatchedPrivateTokenType, nil, "issuer.example", []string{}), - createTokenChallenge(BatchedPrivateTokenType, redemptionContext, "issuer.example", []string{}), + createTokenChallenge(private.RistrettoPrivateTokenType, redemptionContext, "issuer.example", []string{"origin.example"}), + createTokenChallenge(private.RistrettoPrivateTokenType, nil, "issuer.example", []string{"origin.example"}), + createTokenChallenge(private.RistrettoPrivateTokenType, nil, "issuer.example", []string{"foo.example,bar.example"}), + createTokenChallenge(private.RistrettoPrivateTokenType, nil, "issuer.example", []string{}), + createTokenChallenge(private.RistrettoPrivateTokenType, redemptionContext, "issuer.example", []string{}), } - vectors := make([]BatchedPrivateIssuanceTestVector, len(challenges)) + vectors := make([]AmortizedPrivateIssuanceTestVector, len(challenges)) for i := 0; i < len(challenges); i++ { challenge := challenges[i] challengeEnc := challenge.Marshal() @@ -305,10 +385,10 @@ func TestVectorGenerateBatchedPrivateIssuance(t *testing.T) { t.Fatal(err) } - issuer := NewBatchedPrivateIssuer(tokenKey) - client := &BatchedPrivateClient{} + issuer := NewAmortizedRistrettoPrivateIssuer(tokenKey) + client := NewAmortizedRistrettoPrivateClient() - vectors[i] = generateBatchedPrivateIssuanceBlindingTestVector(t, client, issuer, challenge) + vectors[i] = generateAmortizedPrivateIssuanceBlindingTestVector(t, &client, issuer, challenge) } // Encode the test vectors @@ -318,10 +398,10 @@ func TestVectorGenerateBatchedPrivateIssuance(t *testing.T) { } // Verify that we process them correctly - verifyBatchedPrivateIssuanceTestVectors(t, encoded) + verifyAmortizedPrivateIssuanceTestVectors(t, encoded) var outputFile string - if outputFile = os.Getenv(outputBatchedPrivateIssuanceTestVectorEnvironmentKey); len(outputFile) > 0 { + if outputFile = os.Getenv(outputAmortizedRistrettoPrivateIssuanceTestVectorEnvironmentKey); len(outputFile) > 0 { err := os.WriteFile(outputFile, encoded, 0644) if err != nil { t.Fatalf("Error writing test vectors: %v", err) @@ -329,9 +409,23 @@ func TestVectorGenerateBatchedPrivateIssuance(t *testing.T) { } } -func TestVectorVerifyBatchedPrivateIssuance(t *testing.T) { +func TestVectorVerifyAmortizedBasicPrivateIssuance(t *testing.T) { + var inputFile string + if inputFile = os.Getenv(inputAmortizedBasicPrivateIssuanceTestVectorEnvironmentKey); len(inputFile) == 0 { + t.Skip("Test vectors were not provided") + } + + encoded, err := os.ReadFile(inputFile) + if err != nil { + t.Fatalf("Failed reading test vectors: %v", err) + } + + verifyAmortizedPrivateIssuanceTestVectors(t, encoded) +} + +func TestVectorVerifyAmortizedRistrettoPrivateIssuance(t *testing.T) { var inputFile string - if inputFile = os.Getenv(inputBatchedPrivateIssuanceTestVectorEnvironmentKey); len(inputFile) == 0 { + if inputFile = os.Getenv(inputAmortizedRistrettoPrivateIssuanceTestVectorEnvironmentKey); len(inputFile) == 0 { t.Skip("Test vectors were not provided") } @@ -340,5 +434,5 @@ func TestVectorVerifyBatchedPrivateIssuance(t *testing.T) { t.Fatalf("Failed reading test vectors: %v", err) } - verifyBatchedPrivateIssuanceTestVectors(t, encoded) + verifyAmortizedPrivateIssuanceTestVectors(t, encoded) } diff --git a/tokens/type5/client.go b/tokens/amortized/client.go similarity index 59% rename from tokens/type5/client.go rename to tokens/amortized/client.go index 60b804d..a0fb6b0 100644 --- a/tokens/type5/client.go +++ b/tokens/amortized/client.go @@ -1,4 +1,4 @@ -package type5 +package amortized import ( "crypto/sha256" @@ -9,33 +9,43 @@ import ( "github.com/cloudflare/circl/zk/dleq" "github.com/cloudflare/pat-go/quicwire" "github.com/cloudflare/pat-go/tokens" + "github.com/cloudflare/pat-go/tokens/private" "golang.org/x/crypto/cryptobyte" ) -type BatchedPrivateClient struct { +type AmortizedPrivateClient struct { + tokenType uint16 } -func NewBatchedPrivateClient() BatchedPrivateClient { - return BatchedPrivateClient{} +func NewAmortizedBasicPrivateClient() AmortizedPrivateClient { + return AmortizedPrivateClient{ + tokenType: private.BasicPrivateTokenType, + } +} + +func NewAmortizedRistrettoPrivateClient() AmortizedPrivateClient { + return AmortizedPrivateClient{ + tokenType: private.RistrettoPrivateTokenType, + } } -type BatchedPrivateTokenRequestState struct { +type AmortizedPrivateTokenRequestState struct { tokenInputs [][]byte - request *BatchedPrivateTokenRequest + request *AmortizedPrivateTokenRequest client oprf.VerifiableClient verificationKey *oprf.PublicKey verifier *oprf.FinalizeData } -func (s BatchedPrivateTokenRequestState) Request() *BatchedPrivateTokenRequest { +func (s AmortizedPrivateTokenRequestState) Request() *AmortizedPrivateTokenRequest { return s.request } -func (s BatchedPrivateTokenRequestState) ForTestsOnlyVerifier() *oprf.FinalizeData { +func (s AmortizedPrivateTokenRequestState) ForTestsOnlyVerifier() *oprf.FinalizeData { return s.verifier } -func (s BatchedPrivateTokenRequestState) FinalizeTokens(tokenResponseEnc []byte) ([]tokens.Token, error) { +func (s AmortizedPrivateTokenRequestState) FinalizeTokens(tokenResponseEnc []byte) ([]tokens.Token, error) { reader := cryptobyte.String(tokenResponseEnc) l, offset := quicwire.ConsumeVarint(tokenResponseEnc) @@ -46,7 +56,17 @@ func (s BatchedPrivateTokenRequestState) FinalizeTokens(tokenResponseEnc []byte) return nil, fmt.Errorf("invalid batch token response list encoding") } - elementLength := int(group.Ristretto255.Params().CompressedElementLength) + var g group.Group + switch s.request.Type() { + case private.BasicPrivateTokenType: + g = group.P384 + case private.RistrettoPrivateTokenType: + g = group.Ristretto255 + default: + return nil, fmt.Errorf("no group associated to the request token type") + } + + elementLength := int(g.Params().CompressedElementLength) if len(encodedElements)%elementLength != 0 { return nil, fmt.Errorf("invalid batch token response encoding") } @@ -56,7 +76,7 @@ func (s BatchedPrivateTokenRequestState) FinalizeTokens(tokenResponseEnc []byte) } elements := make([]group.Element, numElements) for i := 0; i < numElements; i++ { - elements[i] = group.Ristretto255.NewElement() + elements[i] = g.NewElement() err := elements[i].UnmarshalBinary(encodedElements[i*elementLength : (i+1)*elementLength]) if err != nil { return nil, err @@ -64,14 +84,14 @@ func (s BatchedPrivateTokenRequestState) FinalizeTokens(tokenResponseEnc []byte) } // XXX(caw): should we have a ProofLength parameter on the OPRF interface? - proofLength := int(2 * group.Ristretto255.Params().ScalarLength) + proofLength := int(2 * g.Params().ScalarLength) proofEnc := make([]byte, proofLength) if !reader.ReadBytes(&proofEnc, proofLength) { return nil, fmt.Errorf("invalid batch token response proof encoding") } proof := new(dleq.Proof) - err := proof.UnmarshalBinary(group.Ristretto255, proofEnc) + err := proof.UnmarshalBinary(g, proofEnc) if err != nil { return nil, err } @@ -88,7 +108,7 @@ func (s BatchedPrivateTokenRequestState) FinalizeTokens(tokenResponseEnc []byte) tokens := make([]tokens.Token, numElements) for i := 0; i < numElements; i++ { tokenData := append(s.tokenInputs[i], outputs[i]...) - tokens[i], err = UnmarshalBatchedPrivateToken(tokenData) + tokens[i], err = private.UnmarshalPrivateToken(tokenData) if err != nil { return nil, err } @@ -98,15 +118,24 @@ func (s BatchedPrivateTokenRequestState) FinalizeTokens(tokenResponseEnc []byte) } // https://datatracker.ietf.org/doc/html/draft-robert-privacypass-batched-tokens-00#name-client-to-issuer-request -func (c BatchedPrivateClient) CreateTokenRequest(challenge []byte, nonce [][]byte, tokenKeyID []byte, verificationKey *oprf.PublicKey) (BatchedPrivateTokenRequestState, error) { - client := oprf.NewVerifiableClient(oprf.SuiteRistretto255, verificationKey) +func (c AmortizedPrivateClient) CreateTokenRequest(challenge []byte, nonce [][]byte, tokenKeyID []byte, verificationKey *oprf.PublicKey) (AmortizedPrivateTokenRequestState, error) { + var s oprf.Suite + switch c.tokenType { + case private.BasicPrivateTokenType: + s = oprf.SuiteP384 + case private.RistrettoPrivateTokenType: + s = oprf.SuiteRistretto255 + default: + return AmortizedPrivateTokenRequestState{}, fmt.Errorf("no suite associated to the request token type") + } + client := oprf.NewVerifiableClient(s, verificationKey) numTokens := len(nonce) tokenInputs := make([][]byte, numTokens) for i := 0; i < numTokens; i++ { context := sha256.Sum256(challenge) token := tokens.Token{ - TokenType: BatchedPrivateTokenType, + TokenType: c.tokenType, Nonce: nonce[i], Context: context[:], KeyID: tokenKeyID, @@ -119,25 +148,26 @@ func (c BatchedPrivateClient) CreateTokenRequest(challenge []byte, nonce [][]byt finalizeData, evalRequest, err := client.Blind(tokenInputs) if err != nil { - return BatchedPrivateTokenRequestState{}, err + return AmortizedPrivateTokenRequestState{}, err } encodedElements := make([][]byte, numTokens) for i := 0; i < numTokens; i++ { encRequest, err := evalRequest.Elements[i].MarshalBinaryCompress() if err != nil { - return BatchedPrivateTokenRequestState{}, err + return AmortizedPrivateTokenRequestState{}, err } encodedElements[i] = make([]byte, len(encRequest)) copy(encodedElements[i], encRequest) } - request := &BatchedPrivateTokenRequest{ + request := &AmortizedPrivateTokenRequest{ + tokenType: c.tokenType, TokenKeyID: tokenKeyID[len(tokenKeyID)-1], BlindedReq: encodedElements, } - requestState := BatchedPrivateTokenRequestState{ + requestState := AmortizedPrivateTokenRequestState{ tokenInputs: tokenInputs, request: request, client: client, @@ -148,8 +178,17 @@ func (c BatchedPrivateClient) CreateTokenRequest(challenge []byte, nonce [][]byt return requestState, nil } -func (c BatchedPrivateClient) CreateTokenRequestWithBlinds(challenge []byte, nonces [][]byte, tokenKeyID []byte, verificationKey *oprf.PublicKey, encodedBlinds [][]byte) (BatchedPrivateTokenRequestState, error) { - client := oprf.NewVerifiableClient(oprf.SuiteRistretto255, verificationKey) +func (c AmortizedPrivateClient) CreateTokenRequestWithBlinds(challenge []byte, nonces [][]byte, tokenKeyID []byte, verificationKey *oprf.PublicKey, encodedBlinds [][]byte) (AmortizedPrivateTokenRequestState, error) { + var s oprf.Suite + switch c.tokenType { + case private.BasicPrivateTokenType: + s = oprf.SuiteP384 + case private.RistrettoPrivateTokenType: + s = oprf.SuiteRistretto255 + default: + return AmortizedPrivateTokenRequestState{}, fmt.Errorf("no suite associated to the request token type") + } + client := oprf.NewVerifiableClient(s, verificationKey) numTokens := len(nonces) tokenInputs := make([][]byte, numTokens) @@ -157,7 +196,7 @@ func (c BatchedPrivateClient) CreateTokenRequestWithBlinds(challenge []byte, non for i := 0; i < numTokens; i++ { context := sha256.Sum256(challenge) token := tokens.Token{ - TokenType: BatchedPrivateTokenType, + TokenType: c.tokenType, Nonce: nonces[i], Context: context[:], KeyID: tokenKeyID, @@ -167,34 +206,35 @@ func (c BatchedPrivateClient) CreateTokenRequestWithBlinds(challenge []byte, non tokenInputs[i] = make([]byte, len(tokenInput)) copy(tokenInputs[i], tokenInput) - blinds[i] = group.Ristretto255.NewScalar() + blinds[i] = s.Group().NewScalar() err := blinds[i].UnmarshalBinary(encodedBlinds[i]) if err != nil { - return BatchedPrivateTokenRequestState{}, err + return AmortizedPrivateTokenRequestState{}, err } } finalizeData, evalRequest, err := client.DeterministicBlind(tokenInputs, blinds) if err != nil { - return BatchedPrivateTokenRequestState{}, err + return AmortizedPrivateTokenRequestState{}, err } encodedElements := make([][]byte, numTokens) for i := 0; i < numTokens; i++ { encRequest, err := evalRequest.Elements[i].MarshalBinaryCompress() if err != nil { - return BatchedPrivateTokenRequestState{}, err + return AmortizedPrivateTokenRequestState{}, err } encodedElements[i] = make([]byte, len(encRequest)) copy(encodedElements[i], encRequest) } - request := &BatchedPrivateTokenRequest{ + request := &AmortizedPrivateTokenRequest{ + tokenType: c.tokenType, TokenKeyID: tokenKeyID[len(tokenKeyID)-1], BlindedReq: encodedElements, } - requestState := BatchedPrivateTokenRequestState{ + requestState := AmortizedPrivateTokenRequestState{ tokenInputs: tokenInputs, request: request, client: client, diff --git a/tokens/type5/issuer.go b/tokens/amortized/issuer.go similarity index 54% rename from tokens/type5/issuer.go rename to tokens/amortized/issuer.go index 75b7f1e..8e3d800 100644 --- a/tokens/type5/issuer.go +++ b/tokens/amortized/issuer.go @@ -1,4 +1,4 @@ -package type5 +package amortized import ( "bytes" @@ -9,24 +9,34 @@ import ( "github.com/cloudflare/circl/oprf" "github.com/cloudflare/pat-go/quicwire" "github.com/cloudflare/pat-go/tokens" + "github.com/cloudflare/pat-go/tokens/private" "golang.org/x/crypto/cryptobyte" ) -type BatchedPrivateIssuer struct { - tokenKey *oprf.PrivateKey +type AmortizedPrivateIssuer struct { + tokenType uint16 + tokenKey *oprf.PrivateKey } -func NewBatchedPrivateIssuer(key *oprf.PrivateKey) *BatchedPrivateIssuer { - return &BatchedPrivateIssuer{ - tokenKey: key, +func NewAmortizedBasicPrivateIssuer(key *oprf.PrivateKey) *AmortizedPrivateIssuer { + return &AmortizedPrivateIssuer{ + tokenType: private.BasicPrivateTokenType, + tokenKey: key, } } -func (i *BatchedPrivateIssuer) TokenKey() *oprf.PublicKey { +func NewAmortizedRistrettoPrivateIssuer(key *oprf.PrivateKey) *AmortizedPrivateIssuer { + return &AmortizedPrivateIssuer{ + tokenType: private.RistrettoPrivateTokenType, + tokenKey: key, + } +} + +func (i *AmortizedPrivateIssuer) TokenKey() *oprf.PublicKey { return i.tokenKey.Public() } -func (i *BatchedPrivateIssuer) TokenKeyID() []byte { +func (i *AmortizedPrivateIssuer) TokenKeyID() []byte { pkIEnc, err := i.tokenKey.Public().MarshalBinary() if err != nil { panic(err) @@ -35,14 +45,23 @@ func (i *BatchedPrivateIssuer) TokenKeyID() []byte { return keyID[:] } -func (i BatchedPrivateIssuer) Evaluate(req *BatchedPrivateTokenRequest) ([]byte, error) { - server := oprf.NewVerifiableServer(oprf.SuiteRistretto255, i.tokenKey) +func (i AmortizedPrivateIssuer) Evaluate(req *AmortizedPrivateTokenRequest) ([]byte, error) { + var s oprf.Suite + switch i.tokenType { + case private.BasicPrivateTokenType: + s = oprf.SuiteP384 + case private.RistrettoPrivateTokenType: + s = oprf.SuiteRistretto255 + default: + return nil, fmt.Errorf("no suite associated to the request token type") + } + server := oprf.NewVerifiableServer(s, i.tokenKey) - elementLength := int(oprf.SuiteRistretto255.Group().Params().CompressedElementLength) + elementLength := int(s.Group().Params().CompressedElementLength) numRequests := len(req.BlindedReq) elements := make([]group.Element, numRequests) for i := 0; i < numRequests; i++ { - elements[i] = group.Ristretto255.NewElement() + elements[i] = s.Group().NewElement() err := elements[i].UnmarshalBinary(req.BlindedReq[i]) if err != nil { return nil, err @@ -93,12 +112,21 @@ func (i BatchedPrivateIssuer) Evaluate(req *BatchedPrivateTokenRequest) ([]byte, return b.BytesOrPanic(), nil } -func (i BatchedPrivateIssuer) Type() uint16 { - return BatchedPrivateTokenType +func (i AmortizedPrivateIssuer) Type() uint16 { + return i.tokenType } -func (i BatchedPrivateIssuer) Verify(token tokens.Token) error { - server := oprf.NewVerifiableServer(oprf.SuiteRistretto255, i.tokenKey) +func (i AmortizedPrivateIssuer) Verify(token tokens.Token) error { + var s oprf.Suite + switch i.tokenType { + case private.BasicPrivateTokenType: + s = oprf.SuiteP384 + case private.RistrettoPrivateTokenType: + s = oprf.SuiteRistretto255 + default: + return fmt.Errorf("no suite associated to the request token type") + } + server := oprf.NewVerifiableServer(s, i.tokenKey) tokenInput := token.AuthenticatorInput() output, err := server.FullEvaluate(tokenInput) diff --git a/tokens/type5/token_request.go b/tokens/amortized/token_request.go similarity index 70% rename from tokens/type5/token_request.go rename to tokens/amortized/token_request.go index b55cee8..db848e4 100644 --- a/tokens/type5/token_request.go +++ b/tokens/amortized/token_request.go @@ -1,29 +1,29 @@ -package type5 +package amortized import ( "bytes" "github.com/cloudflare/pat-go/quicwire" + "github.com/cloudflare/pat-go/tokens/private" "golang.org/x/crypto/cryptobyte" ) -const BatchedPrivateTokenType = uint16(0x0005) - -type BatchedPrivateTokenRequest struct { +type AmortizedPrivateTokenRequest struct { raw []byte + tokenType uint16 TokenKeyID uint8 BlindedReq [][]byte } -func (r *BatchedPrivateTokenRequest) TruncatedTokenKeyID() uint8 { +func (r *AmortizedPrivateTokenRequest) TruncatedTokenKeyID() uint8 { return r.TokenKeyID } -func (r *BatchedPrivateTokenRequest) Type() uint16 { - return BatchedPrivateTokenType +func (r *AmortizedPrivateTokenRequest) Type() uint16 { + return r.tokenType } -func (r BatchedPrivateTokenRequest) Equal(r2 BatchedPrivateTokenRequest) bool { +func (r AmortizedPrivateTokenRequest) Equal(r2 AmortizedPrivateTokenRequest) bool { if r.TokenKeyID == r2.TokenKeyID && len(r.BlindedReq) == len(r2.BlindedReq) { equal := true for i := 0; i < len(r.BlindedReq); i++ { @@ -37,13 +37,13 @@ func (r BatchedPrivateTokenRequest) Equal(r2 BatchedPrivateTokenRequest) bool { return false } -func (r *BatchedPrivateTokenRequest) Marshal() []byte { +func (r *AmortizedPrivateTokenRequest) Marshal() []byte { if r.raw != nil { return r.raw } b := cryptobyte.NewBuilder(nil) - b.AddUint16(BatchedPrivateTokenType) + b.AddUint16(r.tokenType) b.AddUint8(r.TokenKeyID) bElmts := cryptobyte.NewBuilder(nil) @@ -61,12 +61,12 @@ func (r *BatchedPrivateTokenRequest) Marshal() []byte { return r.raw } -func (r *BatchedPrivateTokenRequest) Unmarshal(data []byte) bool { +func (r *AmortizedPrivateTokenRequest) Unmarshal(data []byte) bool { s := cryptobyte.String(data) var tokenType uint16 if !s.ReadUint16(&tokenType) || - tokenType != BatchedPrivateTokenType || + (tokenType != private.BasicPrivateTokenType && tokenType != private.RistrettoPrivateTokenType) || !s.ReadUint8(&r.TokenKeyID) { return false } diff --git a/tokens/amortized/type1-issuance-test-vectors.json b/tokens/amortized/type1-issuance-test-vectors.json new file mode 100644 index 0000000..ee5d832 --- /dev/null +++ b/tokens/amortized/type1-issuance-test-vectors.json @@ -0,0 +1 @@ +[{"skS":"16e66b97d6e2595c7c7bae5de140249d614ee3445b51f7519a8fe2a7c313031fef8ed1e15a614234561a4e43595c6126","pkS":"0244b47e6ae241020bfa4ec2fbabbad14c4a3e3dc43a796297121734089b70020759358b0a093e1b1ba3f8c4587741eb33","token_challenge":"0001000e6973737565722e6578616d706c65205de58a52fcdaef25ca3f65448d04e040fb1924e8264acfccfc6c5ad451d582b3000e6f726967696e2e6578616d706c65","nonces":["17a45811bae8ef4a3760e797f28fdefc5c505037411f2267f162faf8d0cc41bd","b2b631f29cce6e572c304046d064499db541adc6c300084e8d9a0a7530bd701a","2663bff99c32a5ca5faa21ccf0c5dea29dd33748694846296d94648b41802db1"],"blinds":["a1280097a2487cf90c2bf005ff6e4a7f31375dfb9fee6239f73b721edccce748b80dc6fe86da39701f2e6d3319fba297","d9ee73a1a1e231898f8b9a2e388baf1b7c421f8813b7bcf2b8cae0fb4b18ae3e3a0722300c79bd2e90d7158954730be8","9fc032fbaff9369fd5be37165f52394c59f4844567f77cb8d535d9e22488e6728694b11e33ce14e7cffa57c737b3a60a"],"token_request":"0001b840930262d785d05fd837d024775c659020a4872ca6ee56c13cbe15dadeec12e77cd5a32904e470bb0ca51f6f5611aa2900fd300226b2ee166aa5e2ec175ed24d9671572ad330a6648b781326e5951807bf56da95f7f7d5d6a1cedf5b58c3bc340917de6103766cf2d6a1b53b83a33089badfea3df0c4951f488a60f014f2a5e2d0c8a678f6d56f6507e4b647f39a742f1981a393db","token_response":"409302b94eed3e49b41609bfdccd700894cf559dc642f4b3397afe4a5124b2196acaae8514f24db9dd40b3ca4a5ddbb51f741202f72ade5e5cbd3917e17ecd9dbdbb0aaab57a637daa4c01193a93c8a28731222a182090b5ff5183f893d57e1e9782b51803d0ec40dfac4e3f5c4855810026680a12a2cb008858b5682f5e879de543e31dfb12febf8a430a68f5a25599768ec94930e8bbf80b4ba300527ce450bdeb98f4634e9caf368a10373f3eabe01fcfd75102c85731902062826852531964f215fc55aa0e3be32b08d7baae7134be5d92b1047b277d8ff7cb4f146c71a8c1b025ebaba510b634cd9f3035421cd00eced42d2f","tokens":["000117a45811bae8ef4a3760e797f28fdefc5c505037411f2267f162faf8d0cc41bd501370b494089dc462802af545e63809581ee6ef57890a12105c28368169514bce724a0a821c7294180eed5785e946e9f854e4ca3de7e6cfbf2588e08cabedb8a302aadff0a21aa348087e5290a305ee8e04a451bf73aab8b27ac4ac3761da0149064a932562c06d4054cddd850eaa85","0001b2b631f29cce6e572c304046d064499db541adc6c300084e8d9a0a7530bd701a501370b494089dc462802af545e63809581ee6ef57890a12105c28368169514bce724a0a821c7294180eed5785e946e9f854e4ca3de7e6cfbf2588e08cabedb8535392a7b69b6834d0cd9ce3ba99cc0424a652cbc91248815377bb5c71c1786243879595e312364690beda0ad2f77080","00012663bff99c32a5ca5faa21ccf0c5dea29dd33748694846296d94648b41802db1501370b494089dc462802af545e63809581ee6ef57890a12105c28368169514bce724a0a821c7294180eed5785e946e9f854e4ca3de7e6cfbf2588e08cabedb8d25f38c6b1ca8007b7d08462b93ebbacc740a56800b9c762bc032e082931956165f190f88567b5ce710af993bf7d4ebc"]},{"skS":"afe6fea6d6c21f9fc6986d2f6e138cea6edf61d332784415500c4fdfc2b848d9250e547d78d1e3ad4bb30938f7fd8b4c","pkS":"030ca71e4322481a968cc6cf7ef9017df93dc01defba57bd9af3a86705e3a66759cffadaa58130b5a1eec3834ee923fb18","token_challenge":"0001000e6973737565722e6578616d706c6500000e6f726967696e2e6578616d706c65","nonces":["f86364dac08de021f8454d22f76cb2e397db469d1e04e0e0fce1956bb29a1281","f41cda22fc5503294c23e9008183397c42257299c418e1d2a91d44cad1d00aec","57dbea8d2f4b0eebdf65526d18f5b328ca3d84c432b55d428400efaf2180d7ee"],"blinds":["f8a263582248dfe7f5be7dd66a1bf3db822700f65a9b0d3f48ae5171085ab50ccc2a41b72466b39756f4dd8771975b67","e477da7ee3b5246c0e4326da9a1bac457bb128830681502343eb13ad20667dbe68ff1169900e66eb549780e258553767","52620b4bf7f405830d5b45fdca7bfce51cd0486e282bea392d3e748279524edc77820f0a7b1f702768cdf8a7b2d4e4a8"],"token_request":"0001434093024cf79aabe62a93e92a00c9e7206baab3b11c0611071788e2a2c3f7573696984f9046f55122b2fbf9302c2af2ed8aa50f0284d82d9c9fe3fcbe0c9de967bf668ddf09ee3cb9d9f0c86339fd4642b6034bdaf1d2767fa649cb495bd51b9482178d4a024e71cee46ffaf6ab26fddd23a8af18752910fb73aff9a4ccc912574950386f5b88d2ba98b150c83a9aa46b6d4ed966ae","token_response":"409303ea334e7bb900a1f91b0eced551946082179fd530949b8e2d9746b2e7301c50862bdd0234a1c88c665639e4c0a2a9bb24031dcc4b73952506d100151634376ccd958ca811459f5eb7ba05e401a1264c63c95fd3ff99b577d1ad6eabf2ef0509a7300374e9e2b4bf10c0b82bd6415c945e52343f544e879c25e345b6dddc760bfd0bbaa0361c24d7f98d73967db9597c1736462440f1e5261c0785f59e1166855b817ea30615f5fd2a4fd6bafc4ac813efa1846dec0f160392966797b8bb913374a32e83cb57a77d289c3edcc189d0523e307bfe4ecb6e09b0a74d8361859aec9202f9551be379c9bc32e1f696219d87f6195c","tokens":["0001f86364dac08de021f8454d22f76cb2e397db469d1e04e0e0fce1956bb29a1281c994f7d5cdc2fb970b13d4e8eb6e6d8f9dcdaa65851fb091025dfe134bd5a62a8700efdbdce3a004c24dab7b030094b79c5f153c6005de0e74d9b11d07d1b0433c083e4d30045e8b692aaaef9cd6cd478a2f360ff253a361a7cc7f85cc901624ba902ed2dc0e4493d78167d53cf75a64","0001f41cda22fc5503294c23e9008183397c42257299c418e1d2a91d44cad1d00aecc994f7d5cdc2fb970b13d4e8eb6e6d8f9dcdaa65851fb091025dfe134bd5a62a8700efdbdce3a004c24dab7b030094b79c5f153c6005de0e74d9b11d07d1b043d4fc47ca614f0c5db31c770de014fb42e3fec98bed5fdaa097b34c357076f6b7ffded0624e3632519c816a516c753181","000157dbea8d2f4b0eebdf65526d18f5b328ca3d84c432b55d428400efaf2180d7eec994f7d5cdc2fb970b13d4e8eb6e6d8f9dcdaa65851fb091025dfe134bd5a62a8700efdbdce3a004c24dab7b030094b79c5f153c6005de0e74d9b11d07d1b04330927c142237a85faf350ea61e176903f58d6c1912a36b33940f792f1ecb99084758ff4b703357f093fcec8d8e619b7e"]},{"skS":"e94b1dd394dddcc64944cc7319f6a2631175db43abf15fb1a6ae4f8fc6cf8c1cf6b3385df511601620a2a67c3ecb6f8b","pkS":"03d4543fe9c7bf8481a15be8c46f1e45be21e67be9c988ebc5e17e794a0e8bd6a3e9ad0af978cf045f873def1aa69bf651","token_challenge":"0001000e6973737565722e6578616d706c65000017666f6f2e6578616d706c652c6261722e6578616d706c65","nonces":["03bf556ce55e4bf9b228fd8849e0bdf274975b360654a2b1996c2be536853f22","09ec15b069bdceea683bb40a23c156a0e31e3d6cb2d9832dcee033374e8cca57","d5a7df0f9ceda715c8e961a013efe99ac88f12479043551e4e015aab1d32ebf7"],"blinds":["1cf2f0ffea2df2fbd375c819c8f3069f74424a7ef0a2db5b362f41a9b293097f356cb8009f3619f88b4c65182c83fd4c","2e4d20ebf54e595a72c427c4d06df24d6f68824220e4a6db3642613027daad82237648823dc23e5ad2a96006072bfea7","7bc11a6f8193ae37629c11e38565efd320ef516688a1fca32c6d48f9be7a077e570ab8a15b3d37b7ef396fd31e75064c"],"token_request":"000115409302fad381dd1d611cf7fabacefc59936cc722830ff6664754159ee236faa0ea2b9874a670eede1d2ef395557500e7064b6c02c6648d0f8ce0ef455b6d12325727ea5f92ed40a29153a4bcddf459cbf90ff9be31bfdd8e1471245e0d6fd1dbc09d0f9f033d81c708f8f0957dda5b7949266dff8c1267e8ef93a83e574a959ff6c33e152f1833355f90279561efc021f988c2bbec","token_response":"409302c7a1b7f405585bccb1949da89b607e0d4851d7b8a0bf1eb2244d778a1e6031b95d56595ebb247cf3e18d4e212fedf22b03daa80b5b1f56d29ad82ccec5de24d66ac7de8eca2bf80b145399386b838ac8bf0e9987ded7afad94c002c4695294dc4402b748b04ad6e0115c672e274161f19258877906556ca57d9669a879f4808cdc8bb6c9df1e97ba0e0ee39b31766588bf0ea1d61415847f959064fcd9f54abb269945ca42c3548ba94b7ce12fb2c7c26889d2b87f83003b43a2489a64c1981b673b49a464b226026b4bf04ffc91d19913536f324683f436307a0d12fe4b32afee2dc61b036325bb39d3b690f0694d78fa52","tokens":["000103bf556ce55e4bf9b228fd8849e0bdf274975b360654a2b1996c2be536853f221949fd455872478ba87e2e6c513c3261cddbe57220581245e4c9c911dd1c0bb83233a0ff77c5d21b63fb3b018ecc4b5416ce4f081b5115456c43f2bd59dde1157e630427c081738078ba67f791af80fbd21c6c8342dfc90e39825e7ee85130cc2e29a977ff830b080dcf64865a8fd867","000109ec15b069bdceea683bb40a23c156a0e31e3d6cb2d9832dcee033374e8cca571949fd455872478ba87e2e6c513c3261cddbe57220581245e4c9c911dd1c0bb83233a0ff77c5d21b63fb3b018ecc4b5416ce4f081b5115456c43f2bd59dde1152adc03e35079112c47a664658293e13912268b30e1afb89f12e01dffc0dc0050cfe60ef20b91d2c5af85e1354213f198","0001d5a7df0f9ceda715c8e961a013efe99ac88f12479043551e4e015aab1d32ebf71949fd455872478ba87e2e6c513c3261cddbe57220581245e4c9c911dd1c0bb83233a0ff77c5d21b63fb3b018ecc4b5416ce4f081b5115456c43f2bd59dde115ecd05168dadf2deb5156106c2f35a6b55d26f4ff20f756c94c5e5d958e6d54e44271785d44c7805ea101f94a36e83a46"]},{"skS":"2d7c99b16084ee5ddd739e7e0d68ef104e5c1ad7b01f7a221d3356990c0fff87b5b95c64cdcd30838ea5f2ff15090270","pkS":"03934b1ad9b27aa7e9a7c917941849750db8342922c87a60b8a081768220e74a0157ca36582bfcc11eb84f455809ed4a23","token_challenge":"0001000e6973737565722e6578616d706c65000000","nonces":["76d9571cf508a54ad6a6ea8c477d9ef54b8795456fb8c2737bfd0554406fe5e8","0ecd34d2b1944d408d34b4ad8edb45047b5e412aa254c9f3dcbfa4a4082b9cdb","c4b6fd80945b9615ca88ba33ad4bf39d6063857c2e70fa091a30f0e96e7ac983"],"blinds":["bdb000ff394d1d7c9076284f10203a3868974c1cb9cf08ea08818b7683a4ebd38d67197683205c540b8a8e9e3216351d","9bfcd6c889e9b0b54b3f8cbf78076fc5dc0eb3d294cc9a30613f4693dc37a523c05bd3daf3526a6cc65aa0acb6137d4f","11627c3d68b963f0a233838cffe9e5440f66ba77cd06e7db9e7e38a824fa4fe569c9e37cc8fe8b5a10cef8362f6d442a"],"token_request":"0001064093033f33414705307090457029db7f26f71c04cae725e872c05aea3f243e5506f516c79688f098657fe913c0fd68903b407e0392e55b5e08e9cc6ae9188ed1e93bbdbba71773aa72a3112f00551be440c11cf1984d607ffbf8e5b0bca3d4c3f9d3b473031c74bff5c2b0e508e1da6562f44e82e3fb74a4e23cae76721ce92626d64be4dfada25f4d7c39e870edcbdd23632123a2","token_response":"409303f982b51f6c99ea124bdc3b28fd4eae5e9d8659f45a97242c2cc4eee9dd580a2dfdf2b9adabb41b974e3bc266967ef19e02a5630b001fe004a3c267152432c3d636134bdf647d06fee05734a6394c6a593645e762f9f87cc099b4f20e64dc46568d02fe22e17a5a01807c8cb2b87ed22fdbb38feaeb0b37d0f87b5f92e69d2781dcdc2475c18322ae926c2bdc270bee2cb26916f1290eef68be1578c5061549fdd0fa273c44442cd06536d2350f70d3996608268215a83755162e1400a1bebb840c301662a6e3df1e74336b6bb8e08fb3dbf5a603cdecba4256cffc5295bb37db9769b40c8120dac7bfe37fb0c2ce9af53b85","tokens":["000176d9571cf508a54ad6a6ea8c477d9ef54b8795456fb8c2737bfd0554406fe5e8085cb06952044c7655b412ab7d484c97b97c48c79c568140b8d49a02ca47a9cf5bcae9c2bff21fcb91cc8bc0f1d5c31697946de8eb005be5e10f1da70fdfab069d2e03d3ffcacb7ac8bef87ef2f44cfaf4daeeea960a465f100a66dd9bdfd09e45ed97ef658960af7f39a52264beca7e","00010ecd34d2b1944d408d34b4ad8edb45047b5e412aa254c9f3dcbfa4a4082b9cdb085cb06952044c7655b412ab7d484c97b97c48c79c568140b8d49a02ca47a9cf5bcae9c2bff21fcb91cc8bc0f1d5c31697946de8eb005be5e10f1da70fdfab068b315b225423613928c321f409697ab52d9a457740c834b8aa3837ac86351633e96ede8dc655c86dbec920d6a8795201","0001c4b6fd80945b9615ca88ba33ad4bf39d6063857c2e70fa091a30f0e96e7ac983085cb06952044c7655b412ab7d484c97b97c48c79c568140b8d49a02ca47a9cf5bcae9c2bff21fcb91cc8bc0f1d5c31697946de8eb005be5e10f1da70fdfab06efaa503383aed6feeca1e51820d3deb38cf24c6d0586ca34f852e68ee8b7f31065eaa1de7a00ee43c03020c575f68fe4"]},{"skS":"f5c71d296e046ede287571dfd75114dbfe524e7257f4a005fc4d0ebcc33bc0069affef99bb2ae601874718ca59de179a","pkS":"03eab8190ec64355abf0696539c0b86f68e50fb5dc73f4199d5a7952bf1ca58186fa4b0dd56368856e21c58df744317d02","token_challenge":"0001000e6973737565722e6578616d706c65205de58a52fcdaef25ca3f65448d04e040fb1924e8264acfccfc6c5ad451d582b30000","nonces":["2a83f6f1d72773dadf94974ebca27d64f5a7f469f96104d82e755369ddc2f2e4","e76c335f6acb4691d2ba332ba7a40f3819039555779ea66de6f6c739358c2772","a66b3ce5aeb75777a5178ac561b276240ce58406d6290a26e98786ec0e2ba5b7"],"blinds":["4315e207308e508b5b9981f035e77e46c9d45b2f1c0bc45f0d892ef75e105b15df7c8813d4044cc61c8ec0463c2641c1","461636f21f7822dacf01631562f4d16df31f6acd0a670d2e3b6506a0e25e38dfd75d335db5d2868eaed9bd060c4036eb","7b8a01654e0f8ad818e3a4e510c8dd5b5a115a0f2f03f1089d90512ffec2ebdac9a285c26ac598f17783feacd0eab8d0"],"token_request":"000161409303ed7c83c83e9576e6b8ad80339466f05bfd0de909670841a16a3abce1bd382deb05ce0e41680c0ccafae9467902d2bad8028b4884dd62baea1659b53049236f64745d086521a53259619b66ac62b1e7e64e54ea803133023c66dc1f3103903cdb520221998caf5f95b9f1c87887672795b05278b2e9c4828c532ca31668c80e6835a4de3fa09431d3e076826172ab0a232888","token_response":"409302429ae37954a49247504c79a77c040f05fcb1825c2e5cb25419319211ce1832ee4341f06cc2d44b1580e1e98040ed225402dd2bc6166084134a140109edce72ef74f87b14e6a0bf14a81809bb9e7aa9754d254a224c3a3aed22b5c2ff234a2035dd03b9afc0b48adfdd8d9600995c95b5bd8c468d546a092c4ff6b3198a0b77b137b52a4655ddd1555a9f19ffe90a8c9fa152e617ca3fbc252157c274292026367de0cf81f2e9ec31a00e47d6e12503a2845eecc26196530ecdd9c6f22d873e83513deba2f131f0c2ee39cf1f19c390cbf3245ee5f96b8e9b6cc2ad704914fcb5775c2823c07c11df3467d0fe8791631a2ec9","tokens":["00012a83f6f1d72773dadf94974ebca27d64f5a7f469f96104d82e755369ddc2f2e4d4380df12a1727f4e2ca1ee0d7abea0d0fb1e9506507a4dd618f9b87e79f9f35ee87b759084d891eb599846514ff6b778f8360e8a1db74e2d05aa8c088f8036107c24ae81dc5b6228f81345601d20e83c48c12e35c429469430d4d5785f72e1a215438c2b380df6bf53c284a1f928d15","0001e76c335f6acb4691d2ba332ba7a40f3819039555779ea66de6f6c739358c2772d4380df12a1727f4e2ca1ee0d7abea0d0fb1e9506507a4dd618f9b87e79f9f35ee87b759084d891eb599846514ff6b778f8360e8a1db74e2d05aa8c088f803615c8326b73f2c12f07d98a97f4371905e74a3940b8eead7a2e6fc9ff3f90c7b24bf938910ca4fb1680b78178bc83845e9","0001a66b3ce5aeb75777a5178ac561b276240ce58406d6290a26e98786ec0e2ba5b7d4380df12a1727f4e2ca1ee0d7abea0d0fb1e9506507a4dd618f9b87e79f9f35ee87b759084d891eb599846514ff6b778f8360e8a1db74e2d05aa8c088f803618619eaaee20d918ecb4b35f879b0ba9791fcfda086e25366a0848bdc8940b2ded244b1be025afa8c5403299196cf883f"]}] \ No newline at end of file diff --git a/tokens/amortized/type1-issuance-test-vectors.rust.json b/tokens/amortized/type1-issuance-test-vectors.rust.json new file mode 100644 index 0000000..09dc85e --- /dev/null +++ b/tokens/amortized/type1-issuance-test-vectors.rust.json @@ -0,0 +1,142 @@ +[ + { + "skS": "2795bea1931d9eb18ea8f341f9136d06825bf87900aadd5cba32f7e7501e7e05fd867ed88b7148676c4f747fd455012f", + "pkS": "03b1144afa40414bafc6d27a46ee314ecd183641c631b6d406b5d0311e7b6a64e9dc561223f38913a5fd299ee437275439", + "token_challenge": "0001000b497373756572204e616d65000005612c622c63", + "nonces": [ + "ba1832b01f112d463d35f3df65780a8af5186f5a036b4273f488020e6bcda4d7", + "2feb86d353b8af5e75e8533b1c17cd4c18c387fbe485a044a32a3164deb306df", + "d9d7d698370bf231c1b81766a750e285a6b860069d826a9d2367f28a79c5721a", + "733225c695c68f2524e364dd63d35bf5db28ac5c3cebf7bffdfc60dd76ed122e", + "2ca686cc3150f70093c492bccef6b40b34fb273be2ddd4faeaa51f14b1d1c3ef" + ], + "blinds": [ + "1845b65b595a9f07d737fcf1c9737489c1641bdcc889b9d6262a8f2d977c4b5e98ee502fe6e44e606c7bcaf4a2f74b04", + "123ce70d4ba8c0a3280381dc507f59c8e986e7bc3e71e1adecbbe5f800b9372901e651b3e9df66879d47af4d324b49b8", + "729ce122eada4cae8a9dae5b026daabaebf9a9c2f93cc74b4efabf6c1cce88b593dbe07c1196c2e2c5f83f3f5a11c999", + "5fe96b7399afb7fc5dfce3911fc586add59838a4130bd1bc9a39da4d3f0f61b2f778bb4b6de05f1e2fafda0d3de48670", + "f815705a65ed835081cf6cec6e72b110e4135bf559eba7cbd8757d90c7dcddc573d75bdc8ad86cf61cc1ae6b6883028c" + ], + "token_request": "0001e340f502290ec59ab9063137d3342c5618748059bbec2284f4e841a925fea9cfaff565634592e7fa066d0f4d355a4aa2d5b305f10246d9e28f9ec550954b22492bbdd21652da7c6ae64a8638757ffb48ba9fcdc46d5e44bf2cef90dd20c7c1cfbb203e05d003c2db7deb628339c677c9f8a39ed7cae0850284025025ca590ac60d9fa7e5a27d6eda67fd0b8c9ec79dafe3bac404839502a1a5ac19a2cd95121c602bd54184e7c8012199f05cbfa1af96d077130a25dc4edb0e55204611e76e2de7815a32f415ab03b7907caefc6d3acba400884ac5763eb022da05c134ab19186b4b5b51f41e8b0e8966047c482c50235cf01c5fd435ccf1", + "token_response": "40f5037fe5401091c1ec2fa44643227c2026195162e07f79492b0f19c13cc2fffbd8e1755f76614fb9bd1ff9c0467d9334d81b0285aed2f5c70a29dbee0c7081dae4ba76b75204b414a70e66e2d17cf7c0a108930182b88222f0b1ec1435b10dfb11a780037439fed66b56b8ecb393e1b2293cbd4a86ac141e047f1ad891f28c3f062f339c18318feb889c09c7ee84129bd88aad3e021098e238803cba587204424f89efe83513d8a66ed7f9c488d8ee1b17baf80a5a6e1b3cdcca07ae98ada345c28ca01f8103f74cf72200f0aa7d630232587c20c4c70f6bfd9636681919777699e63ecc85e8965333341f58cded92b46f30e9033d4e8c055f54fffd89089d8a979fb398b0e3d6de160b0d61bd83759057e642b77abef3b7be4ea424236c1a6d804f1974b1ec194bdfdc78458e252f8a3b08fbe2b18cb3c355b328a01d16cceb9485474854c006a5fab32e1a63cb98c739d761be2e7e", + "tokens": [ + "0001ba1832b01f112d463d35f3df65780a8af5186f5a036b4273f488020e6bcda4d74d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977cd3bd3967ac8049affe0727785606abba401320f4da956669c1fd8c3a6b544ff9831bde3cbb14b733c723655c93ad2e6c8d8d9a560665360486f1699b4cc1a2671334875e76f816a151f532607ee64f55793a6a5", + "00012feb86d353b8af5e75e8533b1c17cd4c18c387fbe485a044a32a3164deb306df4d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977cd3bd3967ac8049affe0727785606abba401320f4da956669c1fd8c3a6b544ff9831bde3e77d754efb404a1d034b4b6b1a8fc1520e8105f2cc4dd13465bc117b57ee2d256b69362407164d66cd4ffb91b46624e9", + "0001d9d7d698370bf231c1b81766a750e285a6b860069d826a9d2367f28a79c5721a4d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977cd3bd3967ac8049affe0727785606abba401320f4da956669c1fd8c3a6b544ff9831bde372afc55fb181d380ca3cb818466408427fffbc89094d2dcf282353f3f64a8cda8bfdc7918585a15683d3b40905f2f720", + "0001733225c695c68f2524e364dd63d35bf5db28ac5c3cebf7bffdfc60dd76ed122e4d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977cd3bd3967ac8049affe0727785606abba401320f4da956669c1fd8c3a6b544ff9831bde3054b234a476ad24ccc82fc8be0515b3be455fa831b849cdcfef2431c02880a27b6d7599fe93d7985db25262f3f0d5e3f", + "00012ca686cc3150f70093c492bccef6b40b34fb273be2ddd4faeaa51f14b1d1c3ef4d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977cd3bd3967ac8049affe0727785606abba401320f4da956669c1fd8c3a6b544ff9831bde3c9488481ad751c6e0e124d5b3da0f7386806e5beaed1fd31cf6e9a4954f0708e1c3a724d40077edb0f4a12975d35819c" + ] + }, + { + "skS": "00b22fc44750a0be95910b42350cf889428b29822137ae7c947dbbce12112252955eaa044c2d1bf04d7828a2c1a607f3", + "pkS": "03fe7d3412c17f4d9c95fd4b6664f980903de4ee3e33e4349cf6be53eb0fe5168aa9ba53388646cbbcf9742d63ec6d3ec3", + "token_challenge": "0001000b497373756572204e616d6520eb86d4628882f211a5a9901ef73bfc808681f803935eb278cc6741b67346d6520005612c622c63", + "nonces": [ + "777a3fd1afcc8fe4e2b69bad782aec122f7517530d5ffa813d2322b12165b0dd", + "7248c86afc2560aac6ae6725026f5dc2c7177c3d1bd9fb90eca9537b8f47f352", + "85f92c1d25208e349270deb3ebab68eb479befdab76a847943e80c98a64802cf", + "09dd90d14e95a707be4b4b0ac91f11eb2ae87573000996a824e7b53fd7f8eb49", + "7e7a5d87ae34c8f754baed42aff353ce54121441f6673e173324116e24d45d07" + ], + "blinds": [ + "0c413fc7b0ba7a07786863406b814afe49f98bef60dd6f4d94a322b5fc3b5fff0a67e147f427947b8c2d69d7a1a98d72", + "781478668ad9c06716addf134d89d8c5b67a7402db8c35c52cf62858519e6fa95232efd8f2202277263450bd68105db7", + "70be1eb3a8a03053d713f735b4f2981f8bf5bc0726e1014848af1942f25c0f6ec6a4138f6be7d44d093c2cade22951df", + "efb1173321ecc93ccc6a3292f532de3f8229d463dbac9a72ec9960335328f088faa7413c8f6f8df6000fcd842a024556", + "ead8b0b7e50cb3e138d49b8f7fd382b9c570b35fbf5afd7ce2441eac797d60c9911da2f964b231d5473d5629adc50932" + ], + "token_request": "00014140f5022fa0eae8e4413e1285554348c51a910b685703f535260e024efce29ddbd2b6afb661bb46d723ab0047db99b228716908037ac9ab495355f8aca5e300c6c8c429a5d6ad7596df529e87ee7873ff67b5bdd5ecee31b6a22ee0588bd03148247876bf0361222090acd961ee4c7d0928b4dfadfc950751ba8129cde0367665719f1da0a576323152954d6cdb49598a9f620a6e3903dfb42521831994cffac87a588e1ffedbf5c5bd617034bddfc3677efa5d95ec9b4dbcb91c26ca23b8c03ed431a1bac9e402a71d2ddf43f161b225b8e4f16dafe7fd2b904882e61336a3e461a02595ae602ff2007251a9b3b592a458c75ea5a0b769", + "token_response": "40f50243a2a7461641ab15ffb51a55d98bca33b28c75fba03f42cadcf4f8d4599b1cb26dd1cd284b03e4d52f9c509d72ccc9a70371df15226477fb1cf1a78b93db07b5f7c336ead3133c7fc72919dbe6249e7ce522911e68814766ae3255040caa62c5250358fecbda72a5a77a56ab674e6d76b55f2b4c5b9033a6f70cb4e56607ca0082d0d5ae82bd96985cd89c81e2acae628672027a50d7bc299756a65bcf708ba92b5d6e9eae44b76ac54344fdbc7e3b3ac7d202f046d96cef39c168645132aa31c669fc029ff3e9245c5158c7d2f87450ebd0d743996438aa82205501aa0c1f56d071ff5c3f2e98b09a738ab4f8f216dc3716ae7aa6d1f249f865a2f0b36b52b8f58a66ea985fcb9dcfcaaf3bc92c1ec5d97ed4d6d1c88bb909af64317c2885d140619c959dc6b2b58d8bd6e09fd1b8bba638bf142e282c1ae6ed134338cfea2cdfdf1f3265db8203875218b979883cca8216e394", + "tokens": [ + "0001777a3fd1afcc8fe4e2b69bad782aec122f7517530d5ffa813d2322b12165b0dd35889a45e95bbc66bb8b042482644693997d94cbc50853af61b342756828e81bd5cc36b0ae0c64bba34c5e560ffa2176a4a39fbf8fc57e2befddd20d8718e341f7dbfa4a5e5e603dc415eacf0389643f48abf09808fe83ee82ca082ac89c5857ce0b9043aa0ff3382e053a0a6401746c", + "00017248c86afc2560aac6ae6725026f5dc2c7177c3d1bd9fb90eca9537b8f47f35235889a45e95bbc66bb8b042482644693997d94cbc50853af61b342756828e81bd5cc36b0ae0c64bba34c5e560ffa2176a4a39fbf8fc57e2befddd20d8718e3415c5326a9a877916183bf8f04652d9df41e717eb4c4673030d4bd88bfa3ef0df371cdb2f50ec1a0f994f11bb324b355b2", + "000185f92c1d25208e349270deb3ebab68eb479befdab76a847943e80c98a64802cf35889a45e95bbc66bb8b042482644693997d94cbc50853af61b342756828e81bd5cc36b0ae0c64bba34c5e560ffa2176a4a39fbf8fc57e2befddd20d8718e3412965c9aa4d87dc58d91bf7ad2fc0b182d12e1019bbfc5c0875b763e2e4a1cebfc903f6c4d9c1e120ca62c0a1d409c1ce", + "000109dd90d14e95a707be4b4b0ac91f11eb2ae87573000996a824e7b53fd7f8eb4935889a45e95bbc66bb8b042482644693997d94cbc50853af61b342756828e81bd5cc36b0ae0c64bba34c5e560ffa2176a4a39fbf8fc57e2befddd20d8718e341a0e9642df13a86061747d852d1725508895a4f0c2e7b07057897fad4ca45ecbe6b4b0b7169edd2c6ad33e8cc4041e721", + "00017e7a5d87ae34c8f754baed42aff353ce54121441f6673e173324116e24d45d0735889a45e95bbc66bb8b042482644693997d94cbc50853af61b342756828e81bd5cc36b0ae0c64bba34c5e560ffa2176a4a39fbf8fc57e2befddd20d8718e341e49e1e468df8ebca7f2851a89b377c529b7857145d4c300228c9be2f9ba0ff9c97247bdad2a62d8b39daafa8ec7b914d" + ] + }, + { + "skS": "fe9dccf471b18e752daf169864b11d36d52774540d30ea3cfc956a9fa2ac356b15e3ca04357276f9f27575aa2264f0e2", + "pkS": "03ebbe14213fba10b5961b2ce6005c865ef27d8a10606886e5240fd5793d57f1c1d6136d20a20411d667180119dacca915", + "token_challenge": "0001000b497373756572204e616d652077c9f82ad689b6faeb0bf5e3b7bd72c220beeedf1ef15093facfa9685f3c88950005612c622c63", + "nonces": [ + "dea96b6ebfdbe8b3f228023159e3589e7cffe39fd79be31baebc3dd86fc2bf1f", + "df8231412e3f6e568886adfdb0bc270c417260de1f15aea9c20e81d0ad79c0c6", + "f9ac7d920db5da9430095b97030bdef8d60c387122a9a239d488fbb9b2331536", + "3caadeac6c38966e745e6c09b6d143fd8361463256de25d54cb056d5df305ed6", + "bc9a18f5d8188ed973fa11c346b985437aa3cb8e9cf2395a81a08804c8183e09" + ], + "blinds": [ + "261310108a900b80dac58206d0131b639d15ff3f44bef4aea760f286f4afffc804366c86e9d5c655310f3c5a4504dbba", + "edeb73cc4d10cd8e53f344c1d9f0d5713ca917a17ab2ced91289c74f6848abbe782b560879d8c1aab1d3a07ed0f59e9f", + "7675f2b9d18285f0c70f7f3c345e55cf10bf81acbfeaaca984314af4213314a6ac324f8db66d8ed541afc797827394cd", + "7f562368a21814fa3c9c062910cc74128315787af90ab4a74d7bd8750a069e1c83edff770f86cf518e28b34a75ccb243", + "d007777c470c5ce0fb2123466ac3139576be4e320e2a61bea4231c793af943281f84439f135536a8923d5aca4b40d0b6" + ], + "token_request": "0001e840f503de448f06485e806c46357acc187d1d935886d23061dd2bbefc18bb3abada39029d976a60b6afd7e03037736ff18efef20308fa70011010abac2ac2c2d014fbfa5d786a5954808c42e35038de42d9de3851653d78558273ce2fbde0c67948f06719020e9828ffa3a98380b902a85b1e1c94816a8dde721e66ce9c7f75fc36b5c035de03e61e6d8c6778dd6569f8ad7c6ff7bc0325dce1625d45cd0b6a82005cd217aef1352072efe56f73f69508296f3acf62e174c780f691b706af621b64be94ca38080334a147c42ff0dd7388ddaf981e5f5006eed7500fd222331def8dadba1e50175294823ccd0c6b73256b57dc6520f01cf3", + "token_response": "40f5037e24738ba84969dce153f7e87fe66b3e48409ac4c3c1d88d99cb0c624a9a98b707e9e00990ea57916c5bec20e588434a0266311282d5f269edb2fc082f34f25f680f091517cc0bfbd7bc0bfa9125a2d74f6081f2ae4e643e8917edc19454d049db038faa3c1093f701db56b2f1f14c422a127de6929b28e39ecfd3d8a1d632c9aed8b1728fa820f41f47bef2233a228f5bab0209909285bd479fe86c4c027417d826dfdb7636a969a849ddacda503c24de82b90897e7229b517fd3f0393ba9e19abb82023e1d5e41a056587748ef896704dcaa7695e80605faafb609b80788fd9899925736b581e6e4837a28725471ae677fd621c8ece95de3f1d98fac39823ac2921ec52c7b05cb5d30ab33e0cbcae377fe40c528e23ae88530d852d4928775d8c1f1def572087592ef6176d5790ab8adbe0523328a8e0925682347e6ca8fa502bcca05e8ece1ff86f1b50c102de347d08792dd", + "tokens": [ + "0001dea96b6ebfdbe8b3f228023159e3589e7cffe39fd79be31baebc3dd86fc2bf1f743229db4189b04ef5f90ecd3cf54a2476aab8c026a1f5af81b7d5425bc512318924fee28549cdf14f42cf3441cf39759c04f6e6a162a7c6189831585de491e892d9133664d98050e02dce92a157306e5d9eeb3a84bbb74d40b05dcb3ec286a32d247012198daf729a17f2f76210f4da", + "0001df8231412e3f6e568886adfdb0bc270c417260de1f15aea9c20e81d0ad79c0c6743229db4189b04ef5f90ecd3cf54a2476aab8c026a1f5af81b7d5425bc512318924fee28549cdf14f42cf3441cf39759c04f6e6a162a7c6189831585de491e8596e9a710d28167de1aaa8e9bba5ccaba514ca7774a890496441e5fbc50ffbc8187c2b9015ae728800d190c48496cd38", + "0001f9ac7d920db5da9430095b97030bdef8d60c387122a9a239d488fbb9b2331536743229db4189b04ef5f90ecd3cf54a2476aab8c026a1f5af81b7d5425bc512318924fee28549cdf14f42cf3441cf39759c04f6e6a162a7c6189831585de491e8a431c43cab90b664077608e2b34a06ac56c1827a2f6f78b77368480e4517744e8a3e10a690a1b173b745540e68fc4f5d", + "00013caadeac6c38966e745e6c09b6d143fd8361463256de25d54cb056d5df305ed6743229db4189b04ef5f90ecd3cf54a2476aab8c026a1f5af81b7d5425bc512318924fee28549cdf14f42cf3441cf39759c04f6e6a162a7c6189831585de491e86ebcab5874aa2a52b7dc764addcfd76839718a13a048fcb8c2abd22c3a7b90fc3f48e38ae21072b01a415af65b36a2b8", + "0001bc9a18f5d8188ed973fa11c346b985437aa3cb8e9cf2395a81a08804c8183e09743229db4189b04ef5f90ecd3cf54a2476aab8c026a1f5af81b7d5425bc512318924fee28549cdf14f42cf3441cf39759c04f6e6a162a7c6189831585de491e8e7f0f3a47d721b4a408670ffad7b27627421a6be3af7f75068196fa26fe53a62c3693b5a1092985795f799c30ca73d72" + ] + }, + { + "skS": "fa1a7f2ccb6651e82aefef530837b518946ca8df30bfb6b629cadccea96550a2848b649cee5c91e3dbaf30e62fe6b407", + "pkS": "037bd0654b77d1b4ae8d7a4775b04d06f2c406496ff07274f79e956e6ee8e6b0668457894b84dd18733017b2fbec89c3f9", + "token_challenge": "0001000b497373756572204e616d65000005612c622c63", + "nonces": [ + "8bc16d866d0193d20b435d49f58cf869f8c3891e7e6f7bf0cce5c5e29a4859fd", + "3cdf1e2db7a86eb1e75fdbfcac7fc044c29cafa3d40ddc769c0c21f4286ac5b9", + "99e334d0713e797bc836545e0dd7dcdee1993436ef6889b2d6157426657408fc", + "32f356152811342c0b4ab9e34ef16939bc6422bed4e73449b09065f19c057364", + "6cf58474ca44d5f86f22f44da98f15939a97645f4c60e565c2be332800ba544a" + ], + "blinds": [ + "85c3c875b12d4578fe905a61fa37cc3a16ee77d87f09705e684833951b692993a5bb663427b8dd10915804e091fe5aa2", + "205c94ad910c602bd3f29404d10ebb89b9148b0ff4adf065ea04f6fc5e24064d86bdf7b2e00962cde1d1ab48b42b3ac5", + "7dbf232de16945358b5ef69b2740940530b651d37708e70735dcfece2e9b218dc82d75a60f6499aa5d0df6c818407405", + "9c3c5cf1182f26d0fca4c9c1c883ac78aa7b4dbecf560cce8d495a0952b5e2377384facac0ccfe30afd3cb50c132fd87", + "83a0546a413a3dc5dab902dfcc21deb38769cf860288b6bf2971ffa93aace8f4ec8d024eb5962e84fa67967b53bc4201" + ], + "token_request": "00017840f503741b71eaf59345fc7f7dc8d7e2f55561ef90534da58150b51b7e5e97cf7bb20d8486b252f162c5feefc4ec52b222751803fcbefbb50a51f7c0c28a5f078bb3be47f0f14989ad8a07490ac39423e4d5bdb8e13e40ece67295e5fe7d9af6bcb2fe9f034feaf7cd856dbdfaf4517913ae44720e4b18448f4f1bee274a56a31fb62de0fe49b280d19212609b41c6ed90c4919ff403e77b87842ed6160d1d36ad218fe35d8c6f077e8b48a978ad0373546c0fe4066fad073acd2ee25dd22535b2c2fc20dffe029f41b5b88625eb8cd94787bebf272ea5c7564ccaadeb1ada97ceda15212c2c4f8efdc00c4fe2e2ad58263a2ccc4c0ed2", + "token_response": "40f502e6fad442191944d14d5c8b467b9c0c11ac06b0cdc1f3f5a9a2d55974f2f2125e0475e83b50f13620b3a817e1795436d703e76c34d0bcd846876ca664ccd97452104c3f7bfc035f3c7c09f0ef6a9b81c9aecb6c8bb58bf02edca7bb21590db2bd650225cd40a928588f1511c4603616151f69661393a42c3126ff3622187cf7916872b898c633790cf7ce42a126e4413ec593037b2bc3a2c135098f7c69315db242693e411838ecddc1cf88d968ed8d72b5611dbbaadb4988f0f7c53a936ba39a68f81e028ff4bf6fd737a137adee95d2fb773cfc8102514859fa419c5e8866dd64d7c0544ec39793bab6384d1d129085cc8af450c8689751c3a15f32c0e950624831c8525614e4e7cf92645e8747d0b1a6c95648bca2d96d20ee5b44ca44491787af6382049ee400b719035a7e3fe2dec5f9155e332fe24b5bb8071c2f3fd00cab8d2a1dc685f6983d043d6591fe00e2ae5a9f89", + "tokens": [ + "00018bc16d866d0193d20b435d49f58cf869f8c3891e7e6f7bf0cce5c5e29a4859fd4d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977cd3bd3969e07ecffb1faa3a20d061c88f1e5292fb4cebefa1311c28eb5f37d475606b278ff35f1fcf8ed7ce3aa10bc2f0f3302d20b0bbc1fa5c45be9d912d97303b9aa8aa0d28dd80d7efb86c9073211f811d93d", + "00013cdf1e2db7a86eb1e75fdbfcac7fc044c29cafa3d40ddc769c0c21f4286ac5b94d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977cd3bd3969e07ecffb1faa3a20d061c88f1e5292fb4cebefa1311c28eb5f37d475606b27882e60cfc6e7ed2b433bdfdad3d225ed09ad3626f67025a263116080a9ce17142d8565fd9ceba77182757e6202185ca6e", + "000199e334d0713e797bc836545e0dd7dcdee1993436ef6889b2d6157426657408fc4d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977cd3bd3969e07ecffb1faa3a20d061c88f1e5292fb4cebefa1311c28eb5f37d475606b2788d8095ab268d6715fb89370bfb3c837493039506dd1a3a8d07a63f065e8e7cd2e57dc3a210b24b7636c8484273eccc17", + "000132f356152811342c0b4ab9e34ef16939bc6422bed4e73449b09065f19c0573644d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977cd3bd3969e07ecffb1faa3a20d061c88f1e5292fb4cebefa1311c28eb5f37d475606b278729e03e210cc2486c4f747b5ff67a239767e32f611f6da82a0ff36c2dc047e1f48fe920677c4f53c60ae1c735644ac55", + "00016cf58474ca44d5f86f22f44da98f15939a97645f4c60e565c2be332800ba544a4d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977cd3bd3969e07ecffb1faa3a20d061c88f1e5292fb4cebefa1311c28eb5f37d475606b278911447f48e89e5d66c5c52e2c0af0729300e69ee6e5e39d465b83641058cf4f6460bcb4672fe37de8b0efa1bcdf33c16" + ] + }, + { + "skS": "88afd78d73efbd37b94183cc1d6fb8e3a0dfaed2ca7f715d76e44843e3c936a266dc3335cf16a63ef31fb6fb4a81771a", + "pkS": "0363010d08ed8eb12d29e6d11059b7a02d6d665d8212ead2f19b43a96a5df6211b2be769f8cc87a730b814cd1013e039e6", + "token_challenge": "0001000b497373756572204e616d65000005612c622c63", + "nonces": [ + "cbb64dbf9e920048a1c5517a8a12b44a294b5ac5ccb3b366178f1031f7c4656c", + "3156fffdf77f4f0dcd23406bb121d3eb18e4d0a8b7286dc7c10bfeb58305fe97", + "ad0930ca85e54145cd8e02bc6508a0e9bc525ba9feee3c19ec3d6258e368a674", + "a70ecbb14478c7c5af0c5f7a9ca4dfe50c7ebc5ad0c06f1addcd3e406520af23", + "7ecf841fb195b155fc443f46c504840a0270464d7e10862cf134438049c66f7c" + ], + "blinds": [ + "421c533dce493799fc44c217d2999e75f1158b256bad86e4f13dc94e0f9aca2dc09ec3ad286cb011d63766a0f0679c0e", + "480fbbcb53834cddabea02c0bdf2f7d7af1d9fad3f71534cf2cc92818262e6c25dfd39a7d69489ba1c110dd97497735d", + "819d08bbde696e245e7987b7bf5b0cd5bc5e188565a8e3191bf9f11b064626f504e1fe6d5d1c7ebe4e096cdbed79a79f", + "3341d181e8c09af12a3a653a290c5977607f85ed5e6394d1b52e0f89768081561aa46016b917d9502cc207f10e164a89", + "dcb1b2f72a5f88b4182fb431911468b4f1d1225391900c9d21c2a0ad1b795c7801648c4f8e3f88c488d3b6d5109bb72c" + ], + "token_request": "0001af40f50201016fa016b79e0ac32a62f05e4b3c05a8a98f2a91d3345222e7b45d464530919bdf7e13009d41dc7d80ff968a5749d702c13ce880d0198173e4f527fb18999e9920dfb6fefbaa758723b962643bf72d09d4305f622757fc54a7a99b718812f91403024b6117c0953f53e1c582b6847288616bc9734bbafc4feec7d9b6bde5c768db1cb4e7d2d3abac5e709f861d9e4a0c8b03c05c15addd2a8a68caf2630d432ba5fd1d56e458869df8885db54d006a17897919e0895b5a570efcadb08b81063ebb830232404a0ef1947bc79773ce4648c35bfbd2e2542578fbb0fcdacd9e87c39ed33b36a27678f5746cfc4f94099ca588ee54", + "token_response": "40f5032fe65c3e5244e485c42953503b950cb9d481fd559a0415593120b164366d51229eab2b0f9c75fc8d56b6a163ac71192b02d5a761c49caf9c4b9a0c3019bd1f45a59b8f3d9acaee9af7d0f72e7bb47dc4da80324387a221b0872321188e6410fa0e038fd7f3d7e60caa7cabdc765d8feb463a2f5c7fac6063119dac9feb658d7b331657156aee7794ca77e68ed6b2986a55ee02a18cdd372c76bc9ff8a9b6ae47324345c515e8114df9392eea70960bb2820370a71c66fae48520ffc475fdbb88993f0c03005755be30a542d4c0861ae1f7ffd584355eecb8b2f0277254a6917661ae91a708eb5cb550cce6955fa873e755fede7310d34e5552f3d542910c3ed98792d670df9b82731ca82b8e674ca4245f6fb89b95f114e4252aa1e477707cb016f39a297b2755043b34bbd1bbc32583e8b240fd0dda4c8a67641992c04f6d56b46b195507b7ee05c3c67004ef9f059a864c7f52", + "tokens": [ + "0001cbb64dbf9e920048a1c5517a8a12b44a294b5ac5ccb3b366178f1031f7c4656c4d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977cd3bd39698517059067b3eb2bd6112ce46b67b6724ae86d1767cf8f171daeb0f8bb213afc44c046b33ba4f0f0d404b19bcd73e7c88a4691af2ebb660592df60d6d090abb7711a34c8c78ebd075918f792804e221", + "00013156fffdf77f4f0dcd23406bb121d3eb18e4d0a8b7286dc7c10bfeb58305fe974d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977cd3bd39698517059067b3eb2bd6112ce46b67b6724ae86d1767cf8f171daeb0f8bb213af46c306c3497f96478f6040344d4981665eeef7b8e4cf5ce14da0d1f98773bb5a1be37252dc7ec61f814304270640572c", + "0001ad0930ca85e54145cd8e02bc6508a0e9bc525ba9feee3c19ec3d6258e368a6744d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977cd3bd39698517059067b3eb2bd6112ce46b67b6724ae86d1767cf8f171daeb0f8bb213af6823c16eabf6871797ce45c17985ed3c29ff08cb61d53be4fefd4b81087590826e679e2cea1cfeffbfcc82993731e5d6", + "0001a70ecbb14478c7c5af0c5f7a9ca4dfe50c7ebc5ad0c06f1addcd3e406520af234d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977cd3bd39698517059067b3eb2bd6112ce46b67b6724ae86d1767cf8f171daeb0f8bb213af60e3e68ada8f217c129fa2eeef3a3c312794eac23f1fb4eb8b12ce672b9963443bf1c80583b4150d35b6c16871f10321", + "00017ecf841fb195b155fc443f46c504840a0270464d7e10862cf134438049c66f7c4d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977cd3bd39698517059067b3eb2bd6112ce46b67b6724ae86d1767cf8f171daeb0f8bb213afbe9b2790151db3683b3ba4865e71aa2b0e6f60c500e30995217e88b772caa1f5b26f94e4766872d764656e268c274ce0" + ] + } +] \ No newline at end of file diff --git a/tokens/type5/type5-issuance-test-vectors.json b/tokens/amortized/type5-issuance-test-vectors.json similarity index 100% rename from tokens/type5/type5-issuance-test-vectors.json rename to tokens/amortized/type5-issuance-test-vectors.json diff --git a/tokens/type5/type5-issuance-test-vectors.rust.json b/tokens/amortized/type5-issuance-test-vectors.rust.json similarity index 100% rename from tokens/type5/type5-issuance-test-vectors.rust.json rename to tokens/amortized/type5-issuance-test-vectors.rust.json diff --git a/tokens/batched/batched_test.go b/tokens/batched/batched_test.go index 5353069..d2a0877 100644 --- a/tokens/batched/batched_test.go +++ b/tokens/batched/batched_test.go @@ -16,9 +16,8 @@ import ( "github.com/cloudflare/circl/oprf" "github.com/cloudflare/pat-go/tokens" - "github.com/cloudflare/pat-go/tokens/type1" + "github.com/cloudflare/pat-go/tokens/private" "github.com/cloudflare/pat-go/tokens/type2" - "github.com/cloudflare/pat-go/tokens/type5" "github.com/cloudflare/pat-go/util" "golang.org/x/crypto/hkdf" ) @@ -83,11 +82,11 @@ func createTokenChallenge(tokenType uint16, redemptionContext []byte, issuerName return challenge } -type basicIssuer[T type1.BasicPrivateIssuer | type2.BasicPublicIssuer] struct { +type basicIssuer[T private.PrivateIssuer | type2.BasicPublicIssuer] struct { inner T } -func newBasicIssuer[T type1.BasicPrivateIssuer | type2.BasicPublicIssuer](inner T) basicIssuer[T] { +func newBasicIssuer[T private.PrivateIssuer | type2.BasicPublicIssuer](inner T) basicIssuer[T] { return basicIssuer[T]{ inner, } @@ -95,8 +94,8 @@ func newBasicIssuer[T type1.BasicPrivateIssuer | type2.BasicPublicIssuer](inner func (i basicIssuer[T]) Evaluate(req tokens.TokenRequest) ([]byte, error) { switch inner := any(i.inner).(type) { - case type1.BasicPrivateIssuer: - req, ok := req.(*type1.BasicPrivateTokenRequest) + case private.PrivateIssuer: + req, ok := req.(*private.PrivateTokenRequest) if !ok { return nil, errors.New("TokenRequest does not match issuer type") } @@ -114,12 +113,10 @@ func (i basicIssuer[T]) Evaluate(req tokens.TokenRequest) ([]byte, error) { func (i basicIssuer[T]) TokenKeyID() []byte { switch inner := any(i.inner).(type) { - case type1.BasicPrivateIssuer: + case private.PrivateIssuer: return inner.TokenKeyID() case type2.BasicPublicIssuer: return inner.TokenKeyID() - case type5.BatchedPrivateIssuer: - return inner.TokenKeyID() default: panic("unreachable") } @@ -127,7 +124,7 @@ func (i basicIssuer[T]) TokenKeyID() []byte { func (i basicIssuer[T]) Type() uint16 { switch inner := any(i.inner).(type) { - case type1.BasicPrivateIssuer: + case private.PrivateIssuer: return inner.Type() case type2.BasicPublicIssuer: return inner.Type() @@ -138,8 +135,8 @@ func (i basicIssuer[T]) Type() uint16 { func UnmarshalArbitratyToken(tokenType uint16, data []byte) (tokens.Token, error) { switch tokenType { - case type1.BasicPrivateTokenType: - return type1.UnmarshalPrivateToken(data) + case private.BasicPrivateTokenType, private.RistrettoPrivateTokenType: + return private.UnmarshalPrivateToken(data) case type2.BasicPublicTokenType: return type2.UnmarshalToken(data) default: @@ -316,11 +313,11 @@ func (etv *BatchedIssuanceTestVector) UnmarshalJSON(data []byte) error { return nil } -type innerGenerateType1 struct { +type innerGeneratePrivate struct { challenge tokens.TokenChallenge sk *oprf.PrivateKey - issuer *type1.BasicPrivateIssuer - client *type1.BasicPrivateClient + issuer *private.PrivateIssuer + client *private.PrivateClient } type innerGenerateType2 struct { @@ -331,11 +328,11 @@ type innerGenerateType2 struct { } type innerGenerate struct { - inner1 *innerGenerateType1 + inner1 *innerGeneratePrivate inner2 *innerGenerateType2 } -func newInnerGenerateType1(i *innerGenerateType1) innerGenerate { +func newInnerGeneratePrivate(i *innerGeneratePrivate) innerGenerate { return innerGenerate{ inner1: i, inner2: nil, @@ -390,7 +387,7 @@ func (i innerGenerate) CreateTokenRequest(challenge []byte, nonce nonceOption) ( if err != nil { return nil, err } - state := newTokenRequestStateType1(&requestState) + state := newTokenRequestStatePrivate(&requestState) return &state, nil } if i.inner2 != nil { @@ -425,11 +422,11 @@ type type2BasicPublicTokenRequestState struct { } type tokenRequestState struct { - state1 *type1.BasicPrivateTokenRequestState + state1 *private.PrivateTokenRequestState state2 *type2BasicPublicTokenRequestState } -func newTokenRequestStateType1(req *type1.BasicPrivateTokenRequestState) tokenRequestState { +func newTokenRequestStatePrivate(req *private.PrivateTokenRequestState) tokenRequestState { return tokenRequestState{ state1: req, state2: nil, @@ -525,7 +522,7 @@ func generateNonceOption(tokenType uint16) (*nonceOption, error) { } switch tokenType { - case type1.BasicPrivateTokenType, type2.BasicPublicTokenType: + case private.BasicPrivateTokenType, private.RistrettoPrivateTokenType, type2.BasicPublicTokenType: option := newSingleNonceOption(nonces[0]) return &option, nil default: @@ -665,7 +662,7 @@ func verifyBasicPrivateIssuanceTestVector(t *testing.T, vector BatchedIssuanceTe issuers := make([]Issuer, len(vector.issuance)) for i, issuance := range vector.issuance { switch issuance.tokenType { - case type1.BasicPrivateTokenType: + case private.BasicPrivateTokenType: challengeEnc := issuance.challenge challenge, err := tokens.UnmarshalTokenChallenge(challengeEnc) if err != nil { @@ -675,20 +672,45 @@ func verifyBasicPrivateIssuanceTestVector(t *testing.T, vector BatchedIssuanceTe if err != nil { t.Fatal(err) } - issuer := type1.NewBasicPrivateIssuer(sk) + issuer := private.NewBasicPrivateIssuer(sk) issuers[i] = newBasicIssuer(*issuer) - client := &type1.BasicPrivateClient{} + client := private.NewBasicPrivateClient() requestState, err := client.CreateTokenRequestWithBlind(challengeEnc, issuance.nonce, issuer.TokenKeyID(), issuer.TokenKey(), issuance.blind) if err != nil { t.Error(err) } - requestStates[i] = newTokenRequestStateType1(&requestState) + requestStates[i] = newTokenRequestStatePrivate(&requestState) requests[i] = requestState.Request() - tokenGenerate[i] = newInnerGenerateType1(&innerGenerateType1{ + tokenGenerate[i] = newInnerGeneratePrivate(&innerGeneratePrivate{ challenge, sk, issuer, - client, + &client, + }) + case private.RistrettoPrivateTokenType: + challengeEnc := issuance.challenge + challenge, err := tokens.UnmarshalTokenChallenge(challengeEnc) + if err != nil { + t.Error(err) + } + sk := util.MustUnmarshalBatchedPrivateOPRFKey(issuance.skS) + if err != nil { + t.Fatal(err) + } + issuer := private.NewRistrettoPrivateIssuer(sk) + issuers[i] = newBasicIssuer(*issuer) + client := private.NewRistrettoPrivateClient() + requestState, err := client.CreateTokenRequestWithBlind(challengeEnc, issuance.nonce, issuer.TokenKeyID(), issuer.TokenKey(), issuance.blind) + if err != nil { + t.Error(err) + } + requestStates[i] = newTokenRequestStatePrivate(&requestState) + requests[i] = requestState.Request() + tokenGenerate[i] = newInnerGeneratePrivate(&innerGeneratePrivate{ + challenge, + sk, + issuer, + &client, }) case type2.BasicPublicTokenType: challengeEnc := issuance.challenge @@ -745,7 +767,7 @@ func verifyBasicPrivateIssuanceTestVector(t *testing.T, vector BatchedIssuanceTe issuance := vector.issuance[i] switch issuance.tokenType { - case type1.BasicPrivateTokenType, type2.BasicPublicTokenType: + case private.BasicPrivateTokenType, private.RistrettoPrivateTokenType, type2.BasicPublicTokenType: if !bytes.Equal(option.token.Marshal(), issuance.token.Marshal()) { t.Fatal("Token mismatch") } @@ -768,28 +790,28 @@ func verifyBatchedIssuanceTestVectors(t *testing.T, encoded []byte) { func TestVectorGenerateBatchedIssuance(t *testing.T) { hash := sha256.New secret := []byte("test vector secret") - hkdf := hkdf.New(hash, secret, nil, []byte{0x00, byte(type1.BasicPrivateTokenType & 0xFF)}) + hkdf := hkdf.New(hash, secret, nil, []byte{0x00, byte(private.BasicPrivateTokenType & 0xFF)}) redemptionContext := make([]byte, 32) util.MustRead(t, hkdf, redemptionContext) challenges := [][]tokens.TokenChallenge{ { - createTokenChallenge(type1.BasicPrivateTokenType, redemptionContext, "issuer.example", []string{"origin.example"}), + createTokenChallenge(private.BasicPrivateTokenType, redemptionContext, "issuer.example", []string{"origin.example"}), }, { createTokenChallenge(type2.BasicPublicTokenType, redemptionContext, "issuer.example", []string{"origin.example"}), }, { - createTokenChallenge(type1.BasicPrivateTokenType, redemptionContext, "issuer.example", []string{"origin.example"}), - createTokenChallenge(type1.BasicPrivateTokenType, nil, "issuer.example", []string{"origin.example"}), + createTokenChallenge(private.BasicPrivateTokenType, redemptionContext, "issuer.example", []string{"origin.example"}), + createTokenChallenge(private.BasicPrivateTokenType, nil, "issuer.example", []string{"origin.example"}), }, { createTokenChallenge(type2.BasicPublicTokenType, redemptionContext, "issuer.example", []string{"origin.example"}), createTokenChallenge(type2.BasicPublicTokenType, nil, "issuer.example", []string{"origin.example"}), }, { - createTokenChallenge(type1.BasicPrivateTokenType, redemptionContext, "issuer.example", []string{"origin.example"}), + createTokenChallenge(private.BasicPrivateTokenType, redemptionContext, "issuer.example", []string{"origin.example"}), createTokenChallenge(type2.BasicPublicTokenType, redemptionContext, "issuer.example", []string{"origin.example"}), }, } @@ -803,23 +825,41 @@ func TestVectorGenerateBatchedIssuance(t *testing.T) { challengeEnc := challenge.Marshal() switch challenge.TokenType { - case type1.BasicPrivateTokenType: + case private.BasicPrivateTokenType: var seed [32]byte sk, err := oprf.DeriveKey(oprf.SuiteP384, oprf.VerifiableMode, seed[:], challengeEnc) if err != nil { t.Fatal(err) } - issuer := type1.NewBasicPrivateIssuer(sk) + issuer := private.NewBasicPrivateIssuer(sk) if issuer == nil { t.Fatal("Error creating type1 issuer") } issuers = append(issuers, newBasicIssuer(*issuer)) - client := &type1.BasicPrivateClient{} - generateArgs[j] = newInnerGenerateType1(&innerGenerateType1{ + client := private.NewBasicPrivateClient() + generateArgs[j] = newInnerGeneratePrivate(&innerGeneratePrivate{ challenge, sk, issuer, - client, + &client, + }) + case private.RistrettoPrivateTokenType: + var seed [32]byte + sk, err := oprf.DeriveKey(oprf.SuiteRistretto255, oprf.VerifiableMode, seed[:], challengeEnc) + if err != nil { + t.Fatal(err) + } + issuer := private.NewRistrettoPrivateIssuer(sk) + if issuer == nil { + t.Fatal("Error creating type1 issuer") + } + issuers = append(issuers, newBasicIssuer(*issuer)) + client := private.NewRistrettoPrivateClient() + generateArgs[j] = newInnerGeneratePrivate(&innerGeneratePrivate{ + challenge, + sk, + issuer, + &client, }) case type2.BasicPublicTokenType: sk := loadPrivateKey(t) diff --git a/tokens/batched/client.go b/tokens/batched/client.go index 38a8471..b4bbfc8 100644 --- a/tokens/batched/client.go +++ b/tokens/batched/client.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/cloudflare/pat-go/tokens" - "github.com/cloudflare/pat-go/tokens/type1" + "github.com/cloudflare/pat-go/tokens/private" "github.com/cloudflare/pat-go/tokens/type2" ) @@ -23,9 +23,14 @@ func (c BatchedClient) CreateTokenRequest(tokenRequests []tokens.TokenRequestWit for _, tokenRequest := range tokenRequests { switch tokenRequest.Type() { - case type1.BasicPrivateTokenType: - casted, ok := tokenRequest.(*type1.BasicPrivateTokenRequest) - if !ok || casted.Type() != type1.BasicPrivateTokenType { + case private.BasicPrivateTokenType: + casted, ok := tokenRequest.(*private.PrivateTokenRequest) + if !ok || casted.Type() != private.BasicPrivateTokenType { + return nil, fmt.Errorf("invalid token request type") + } + case private.RistrettoPrivateTokenType: + casted, ok := tokenRequest.(*private.PrivateTokenRequest) + if !ok || casted.Type() != private.RistrettoPrivateTokenType { return nil, fmt.Errorf("invalid token request type") } case type2.BasicPublicTokenType: diff --git a/tokens/batched/token_request.go b/tokens/batched/token_request.go index 779f36b..3729014 100644 --- a/tokens/batched/token_request.go +++ b/tokens/batched/token_request.go @@ -5,7 +5,7 @@ import ( "github.com/cloudflare/pat-go/quicwire" "github.com/cloudflare/pat-go/tokens" - "github.com/cloudflare/pat-go/tokens/type1" + "github.com/cloudflare/pat-go/tokens/private" "github.com/cloudflare/pat-go/tokens/type2" "golang.org/x/crypto/cryptobyte" ) @@ -50,8 +50,8 @@ func (r *BatchedTokenRequest) Unmarshal(data []byte) bool { var token_request tokens.TokenRequestWithDetails token_type := binary.BigEndian.Uint16(data[i : i+2]) switch token_type { - case type1.BasicPrivateTokenType: - token_request = new(type1.BasicPrivateTokenRequest) + case private.BasicPrivateTokenType, private.RistrettoPrivateTokenType: + token_request = new(private.PrivateTokenRequest) case type2.BasicPublicTokenType: token_request = new(type2.BasicPublicTokenRequest) default: diff --git a/tokens/batched/tokens.go b/tokens/batched/tokens.go index d288f7e..42aee17 100644 --- a/tokens/batched/tokens.go +++ b/tokens/batched/tokens.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/cloudflare/pat-go/quicwire" - "github.com/cloudflare/pat-go/tokens/type1" + "github.com/cloudflare/pat-go/tokens/private" "github.com/cloudflare/pat-go/tokens/type2" "golang.org/x/crypto/cryptobyte" ) @@ -37,8 +37,10 @@ func UnmarshalBatchedTokenResponses(data []byte) ([][]byte, error) { var token_response_length uint16 switch token_type { - case type1.BasicPrivateTokenType: - token_response_length = uint16(type1.Ne + 2*type1.Nk) // Ne + 2*Ns + case private.BasicPrivateTokenType: + token_response_length = uint16(private.BasicNe + 2*private.BasicNk) // Ne + 2*Ns + case private.RistrettoPrivateTokenType: + token_response_length = uint16(private.RistrettoNe + 2*private.RistrettoNk) // Ne + 2*Ns case type2.BasicPublicTokenType: token_response_length = uint16(type2.Nk) // Nk default: diff --git a/tokens/private/client.go b/tokens/private/client.go new file mode 100644 index 0000000..589d9a3 --- /dev/null +++ b/tokens/private/client.go @@ -0,0 +1,182 @@ +package private + +import ( + "crypto/sha256" + "fmt" + + "github.com/cloudflare/circl/group" + "github.com/cloudflare/circl/oprf" + "github.com/cloudflare/circl/zk/dleq" + "github.com/cloudflare/pat-go/tokens" +) + +type PrivateClient struct { + tokenType uint16 +} + +func NewBasicPrivateClient() PrivateClient { + return PrivateClient{tokenType: BasicPrivateTokenType} +} + +func NewRistrettoPrivateClient() PrivateClient { + return PrivateClient{tokenType: RistrettoPrivateTokenType} +} + +type PrivateTokenRequestState struct { + tokenInput []byte + request *PrivateTokenRequest + client oprf.VerifiableClient + verificationKey *oprf.PublicKey + verifier *oprf.FinalizeData +} + +func (s PrivateTokenRequestState) Request() *PrivateTokenRequest { + return s.request +} + +func (s PrivateTokenRequestState) ForTestsOnlyVerifier() *oprf.FinalizeData { + return s.verifier +} + +func (s PrivateTokenRequestState) FinalizeToken(tokenResponseEnc []byte) (tokens.Token, error) { + var g group.Group + + switch s.request.Type() { + case BasicPrivateTokenType: + g = group.P384 + case RistrettoPrivateTokenType: + g = group.Ristretto255 + default: + return tokens.Token{}, fmt.Errorf("no group associated to the request token type") + } + evaluatedElement := g.NewElement() + err := evaluatedElement.UnmarshalBinary(tokenResponseEnc[:g.Params().CompressedElementLength]) + if err != nil { + return tokens.Token{}, err + } + + proof := new(dleq.Proof) + err = proof.UnmarshalBinary(g, tokenResponseEnc[g.Params().CompressedElementLength:]) + if err != nil { + return tokens.Token{}, err + } + + evaluation := &oprf.Evaluation{ + Elements: []oprf.Evaluated{evaluatedElement}, + Proof: proof, + } + outputs, err := s.client.Finalize(s.verifier, evaluation) + if err != nil { + return tokens.Token{}, err + } + + tokenData := append(s.tokenInput, outputs[0]...) + token, err := UnmarshalPrivateToken(tokenData) + if err != nil { + return tokens.Token{}, err + } + + return token, nil +} + +// https://ietf-wg-privacypass.github.io/base-drafts/caw/pp-issuance/draft-ietf-privacypass-protocol.html#name-issuance-protocol-for-publi +func (c PrivateClient) CreateTokenRequest(challenge, nonce []byte, tokenKeyID []byte, verificationKey *oprf.PublicKey) (PrivateTokenRequestState, error) { + var s oprf.Suite + switch c.tokenType { + case BasicPrivateTokenType: + s = oprf.SuiteP384 + case RistrettoPrivateTokenType: + s = oprf.SuiteRistretto255 + default: + return PrivateTokenRequestState{}, fmt.Errorf("no suite associated to the request token type") + } + client := oprf.NewVerifiableClient(s, verificationKey) + + context := sha256.Sum256(challenge) + token := tokens.Token{ + TokenType: c.tokenType, + Nonce: nonce, + Context: context[:], + KeyID: tokenKeyID, + Authenticator: nil, // No OPRF computed yet + } + tokenInput := token.AuthenticatorInput() + finalizeData, evalRequest, err := client.Blind([][]byte{tokenInput}) + if err != nil { + return PrivateTokenRequestState{}, err + } + + encRequest, err := evalRequest.Elements[0].MarshalBinaryCompress() + if err != nil { + return PrivateTokenRequestState{}, err + } + request := &PrivateTokenRequest{ + tokenType: c.tokenType, + TokenKeyID: tokenKeyID[len(tokenKeyID)-1], + BlindedReq: encRequest, + } + + requestState := PrivateTokenRequestState{ + tokenInput: tokenInput, + request: request, + client: client, + verifier: finalizeData, + verificationKey: verificationKey, + } + + return requestState, nil +} + +func (c PrivateClient) CreateTokenRequestWithBlind(challenge, nonce []byte, tokenKeyID []byte, verificationKey *oprf.PublicKey, blindEnc []byte) (PrivateTokenRequestState, error) { + var s oprf.Suite + switch c.tokenType { + case BasicPrivateTokenType: + s = oprf.SuiteP384 + case RistrettoPrivateTokenType: + s = oprf.SuiteRistretto255 + default: + return PrivateTokenRequestState{}, fmt.Errorf("no suite associated to the request token type") + } + client := oprf.NewVerifiableClient(s, verificationKey) + + context := sha256.Sum256(challenge) + token := tokens.Token{ + TokenType: c.tokenType, + Nonce: nonce, + Context: context[:], + KeyID: tokenKeyID, + Authenticator: nil, // No OPRF output computed yet + } + tokenInput := token.AuthenticatorInput() + + blind := s.Group().NewScalar() + err := blind.UnmarshalBinary(blindEnc) + if err != nil { + return PrivateTokenRequestState{}, err + } + + finalizeData, evalRequest, err := client.DeterministicBlind([][]byte{tokenInput}, []oprf.Blind{blind}) + if err != nil { + return PrivateTokenRequestState{}, err + } + + encRequest, err := evalRequest.Elements[0].MarshalBinaryCompress() + if err != nil { + return PrivateTokenRequestState{}, err + } + request := &PrivateTokenRequest{ + tokenType: c.tokenType, + TokenKeyID: tokenKeyID[len(tokenKeyID)-1], + BlindedReq: encRequest, + } + + requestState := PrivateTokenRequestState{ + tokenInput: tokenInput, + request: request, + client: client, + verifier: finalizeData, + verificationKey: verificationKey, + } + + return requestState, nil +} diff --git a/tokens/private/issuer.go b/tokens/private/issuer.go new file mode 100644 index 0000000..2249951 --- /dev/null +++ b/tokens/private/issuer.go @@ -0,0 +1,114 @@ +package private + +import ( + "bytes" + "crypto/sha256" + "fmt" + + "github.com/cloudflare/circl/oprf" + "github.com/cloudflare/pat-go/tokens" +) + +type PrivateIssuer struct { + tokenType uint16 + tokenKey *oprf.PrivateKey +} + +func NewBasicPrivateIssuer(key *oprf.PrivateKey) *PrivateIssuer { + return &PrivateIssuer{ + tokenType: BasicPrivateTokenType, + tokenKey: key, + } +} + +func NewRistrettoPrivateIssuer(key *oprf.PrivateKey) *PrivateIssuer { + return &PrivateIssuer{ + tokenType: RistrettoPrivateTokenType, + tokenKey: key, + } +} + +func (i *PrivateIssuer) TokenKey() *oprf.PublicKey { + return i.tokenKey.Public() +} + +func (i *PrivateIssuer) TokenKeyID() []byte { + pkIEnc, err := i.tokenKey.Public().MarshalBinary() + if err != nil { + panic(err) + } + keyID := sha256.Sum256(pkIEnc) + return keyID[:] +} + +func (i PrivateIssuer) Evaluate(req *PrivateTokenRequest) ([]byte, error) { + var s oprf.Suite + switch i.tokenType { + case BasicPrivateTokenType: + s = oprf.SuiteP384 + case RistrettoPrivateTokenType: + s = oprf.SuiteRistretto255 + default: + return nil, fmt.Errorf("no suite associated to the request token type") + } + + server := oprf.NewVerifiableServer(s, i.tokenKey) + + e := s.Group().NewElement() + err := e.UnmarshalBinary(req.BlindedReq) + if err != nil { + return nil, err + } + evalRequest := &oprf.EvaluationRequest{ + Elements: []oprf.Blinded{e}, + } + + // Evaluate the input + evaluation, err := server.Evaluate(evalRequest) + if err != nil { + return nil, err + } + + // Build TokenResponse + // XXX(caw) move this to token_response.go + encEvaluatedElement, err := evaluation.Elements[0].MarshalBinaryCompress() + if err != nil { + return nil, err + } + encProof, err := evaluation.Proof.MarshalBinary() + if err != nil { + return nil, err + } + tokenResponse := append(encEvaluatedElement, encProof...) + + return tokenResponse, nil +} + +func (i PrivateIssuer) Type() uint16 { + return i.tokenType +} + +func (i PrivateIssuer) Verify(token tokens.Token) error { + var s oprf.Suite + switch i.tokenType { + case BasicPrivateTokenType: + s = oprf.SuiteP384 + case RistrettoPrivateTokenType: + s = oprf.SuiteRistretto255 + default: + return fmt.Errorf("no suite associated to the request token type") + } + + server := oprf.NewVerifiableServer(s, i.tokenKey) + + tokenInput := token.AuthenticatorInput() + output, err := server.FullEvaluate(tokenInput) + if err != nil { + return err + } + if !bytes.Equal(output, token.Authenticator) { + return fmt.Errorf("token authentication mismatch") + } + + return nil +} diff --git a/tokens/type1/type1_test.go b/tokens/private/private_test.go similarity index 57% rename from tokens/type1/type1_test.go rename to tokens/private/private_test.go index e6e7348..1154769 100644 --- a/tokens/type1/type1_test.go +++ b/tokens/private/private_test.go @@ -1,10 +1,12 @@ -package type1 +package private import ( "bytes" "crypto/rand" "crypto/sha256" + "encoding/binary" "encoding/json" + "fmt" "os" "testing" @@ -16,8 +18,10 @@ import ( ) const ( - outputBasicPrivateIssuanceTestVectorEnvironmentKey = "TYPE1_ISSUANCE_TEST_VECTORS_OUT" - inputBasicPrivateIssuanceTestVectorEnvironmentKey = "TYPE1_ISSUANCE_TEST_VECTORS_IN" + outputBasicPrivateIssuanceTestVectorEnvironmentKey = "TYPE1_ISSUANCE_TEST_VECTORS_OUT" + inputBasicPrivateIssuanceTestVectorEnvironmentKey = "TYPE1_ISSUANCE_TEST_VECTORS_IN" + outputRistrettoPrivateIssuanceTestVectorEnvironmentKey = "TYPE5_ISSUANCE_TEST_VECTORS_OUT" + inputRistrettoPrivateIssuanceTestVectorEnvironmentKey = "TYPE5_ISSUANCE_TEST_VECTORS_IN" ) func createTokenChallenge(tokenType uint16, redemptionContext []byte, issuerName string, originInfo []string) tokens.TokenChallenge { @@ -31,14 +35,14 @@ func createTokenChallenge(tokenType uint16, redemptionContext []byte, issuerName return challenge } -func TestBasicPrivateIssuanceRoundTrip(t *testing.T) { +func TestPrivateIssuanceRoundTrip(t *testing.T) { tokenKey, err := oprf.GenerateKey(oprf.SuiteP384, rand.Reader) if err != nil { t.Fatal(err) } issuer := NewBasicPrivateIssuer(tokenKey) - client := BasicPrivateClient{} + client := PrivateClient{} challenge := make([]byte, 32) util.MustRead(t, rand.Reader, challenge) @@ -72,7 +76,7 @@ func TestBasicPrivateIssuanceRoundTrip(t *testing.T) { // ///// // Basic issuance test vector -type rawBasicPrivateIssuanceTestVector struct { +type rawPrivateIssuanceTestVector struct { PrivateKey string `json:"skS"` PublicKey string `json:"pkS"` Challenge string `json:"token_challenge"` @@ -83,7 +87,7 @@ type rawBasicPrivateIssuanceTestVector struct { Token string `json:"token"` } -type BasicPrivateIssuanceTestVector struct { +type PrivateIssuanceTestVector struct { t *testing.T skS *oprf.PrivateKey challenge []byte @@ -94,16 +98,16 @@ type BasicPrivateIssuanceTestVector struct { token []byte } -type BasicPrivateIssuanceTestVectorArray struct { +type PrivateIssuanceTestVectorArray struct { t *testing.T - vectors []BasicPrivateIssuanceTestVector + vectors []PrivateIssuanceTestVector } -func (tva BasicPrivateIssuanceTestVectorArray) MarshalJSON() ([]byte, error) { +func (tva PrivateIssuanceTestVectorArray) MarshalJSON() ([]byte, error) { return json.Marshal(tva.vectors) } -func (tva *BasicPrivateIssuanceTestVectorArray) UnmarshalJSON(data []byte) error { +func (tva *PrivateIssuanceTestVectorArray) UnmarshalJSON(data []byte) error { err := json.Unmarshal(data, &tva.vectors) if err != nil { return err @@ -115,8 +119,8 @@ func (tva *BasicPrivateIssuanceTestVectorArray) UnmarshalJSON(data []byte) error return nil } -func (etv BasicPrivateIssuanceTestVector) MarshalJSON() ([]byte, error) { - return json.Marshal(rawBasicPrivateIssuanceTestVector{ +func (etv PrivateIssuanceTestVector) MarshalJSON() ([]byte, error) { + return json.Marshal(rawPrivateIssuanceTestVector{ PrivateKey: util.MustHex(util.MustMarshalPrivateOPRFKey(etv.skS)), PublicKey: util.MustHex(util.MustMarshalPublicOPRFKey(etv.skS.Public())), Challenge: util.MustHex(etv.challenge), @@ -128,14 +132,13 @@ func (etv BasicPrivateIssuanceTestVector) MarshalJSON() ([]byte, error) { }) } -func (etv *BasicPrivateIssuanceTestVector) UnmarshalJSON(data []byte) error { - raw := rawBasicPrivateIssuanceTestVector{} +func (etv *PrivateIssuanceTestVector) UnmarshalJSON(data []byte) error { + raw := rawPrivateIssuanceTestVector{} err := json.Unmarshal(data, &raw) if err != nil { return err } - etv.skS = util.MustUnmarshalPrivateOPRFKey(util.MustUnhex(nil, raw.PrivateKey)) etv.challenge = util.MustUnhex(nil, raw.Challenge) etv.nonce = util.MustUnhex(nil, raw.Nonce) etv.blind = util.MustUnhex(nil, raw.Blind) @@ -143,10 +146,23 @@ func (etv *BasicPrivateIssuanceTestVector) UnmarshalJSON(data []byte) error { etv.tokenResponse = util.MustUnhex(nil, raw.TokenResponse) etv.token = util.MustUnhex(nil, raw.Token) + skS := util.MustUnhex(nil, raw.PrivateKey) + switch etv.TokenType() { + case BasicPrivateTokenType: + etv.skS = util.MustUnmarshalPrivateOPRFKey(skS) + case RistrettoPrivateTokenType: + etv.skS = util.MustUnmarshalBatchedPrivateOPRFKey(skS) + default: + return fmt.Errorf("invalid private key format") + } return nil } -func generateBasicPrivateIssuanceBlindingTestVector(t *testing.T, client *BasicPrivateClient, issuer *BasicPrivateIssuer, tokenChallenge tokens.TokenChallenge) BasicPrivateIssuanceTestVector { +func (etv *PrivateIssuanceTestVector) TokenType() uint16 { + return binary.BigEndian.Uint16(etv.tokenRequest[:2]) +} + +func generatePrivateIssuanceBlindingTestVector(t *testing.T, client *PrivateClient, issuer *PrivateIssuer, tokenChallenge tokens.TokenChallenge) PrivateIssuanceTestVector { challenge := tokenChallenge.Marshal() nonce := make([]byte, 32) @@ -176,7 +192,7 @@ func generateBasicPrivateIssuanceBlindingTestVector(t *testing.T, client *BasicP t.Error(err) } - return BasicPrivateIssuanceTestVector{ + return PrivateIssuanceTestVector{ t: t, skS: issuer.tokenKey, challenge: challenge, @@ -188,9 +204,19 @@ func generateBasicPrivateIssuanceBlindingTestVector(t *testing.T, client *BasicP } } -func verifyBasicPrivateIssuanceTestVector(t *testing.T, vector BasicPrivateIssuanceTestVector) { - issuer := NewBasicPrivateIssuer(vector.skS) - client := BasicPrivateClient{} +func verifyPrivateIssuanceTestVector(t *testing.T, vector PrivateIssuanceTestVector) { + var issuer *PrivateIssuer + var client PrivateClient + switch vector.TokenType() { + case BasicPrivateTokenType: + issuer = NewBasicPrivateIssuer(vector.skS) + client = NewBasicPrivateClient() + case RistrettoPrivateTokenType: + issuer = NewRistrettoPrivateIssuer(vector.skS) + client = NewRistrettoPrivateClient() + default: + t.Error(fmt.Errorf("invalid token type")) + } tokenKeyID := issuer.TokenKeyID() tokenPublicKey := issuer.TokenKey() @@ -211,19 +237,20 @@ func verifyBasicPrivateIssuanceTestVector(t *testing.T, vector BasicPrivateIssua } if !bytes.Equal(token.Marshal(), vector.token) { + fmt.Printf("%v\n%v\n", util.MustHex(token.Marshal()), util.MustHex(vector.token)) t.Fatal("Token mismatch") } } -func verifyBasicPrivateIssuanceTestVectors(t *testing.T, encoded []byte) { - vectors := BasicPrivateIssuanceTestVectorArray{t: t} +func verifyPrivateIssuanceTestVectors(t *testing.T, encoded []byte) { + vectors := PrivateIssuanceTestVectorArray{t: t} err := json.Unmarshal(encoded, &vectors) if err != nil { t.Fatalf("Error decoding test vector string: %v", err) } for _, vector := range vectors.vectors { - verifyBasicPrivateIssuanceTestVector(t, vector) + verifyPrivateIssuanceTestVector(t, vector) } } @@ -243,7 +270,7 @@ func TestVectorGenerateBasicPrivateIssuance(t *testing.T) { createTokenChallenge(BasicPrivateTokenType, redemptionContext, "issuer.example", []string{}), } - vectors := make([]BasicPrivateIssuanceTestVector, len(challenges)) + vectors := make([]PrivateIssuanceTestVector, len(challenges)) for i := 0; i < len(challenges); i++ { challenge := challenges[i] challengeEnc := challenge.Marshal() @@ -256,9 +283,9 @@ func TestVectorGenerateBasicPrivateIssuance(t *testing.T) { } issuer := NewBasicPrivateIssuer(tokenKey) - client := &BasicPrivateClient{} + client := NewBasicPrivateClient() - vectors[i] = generateBasicPrivateIssuanceBlindingTestVector(t, client, issuer, challenge) + vectors[i] = generatePrivateIssuanceBlindingTestVector(t, &client, issuer, challenge) } // Encode the test vectors @@ -268,7 +295,7 @@ func TestVectorGenerateBasicPrivateIssuance(t *testing.T) { } // Verify that we process them correctly - verifyBasicPrivateIssuanceTestVectors(t, encoded) + verifyPrivateIssuanceTestVectors(t, encoded) var outputFile string if outputFile = os.Getenv(outputBasicPrivateIssuanceTestVectorEnvironmentKey); len(outputFile) > 0 { @@ -279,6 +306,58 @@ func TestVectorGenerateBasicPrivateIssuance(t *testing.T) { } } +func TestVectorGenerateRistrettoPrivateIssuance(t *testing.T) { + hash := sha256.New + secret := []byte("test vector secret") + hkdf := hkdf.New(hash, secret, nil, []byte{0x00, byte(RistrettoPrivateTokenType & 0xFF)}) + + redemptionContext := make([]byte, 32) + util.MustRead(t, hkdf, redemptionContext) + + challenges := []tokens.TokenChallenge{ + createTokenChallenge(RistrettoPrivateTokenType, redemptionContext, "issuer.example", []string{"origin.example"}), + createTokenChallenge(RistrettoPrivateTokenType, nil, "issuer.example", []string{"origin.example"}), + createTokenChallenge(RistrettoPrivateTokenType, nil, "issuer.example", []string{"foo.example,bar.example"}), + createTokenChallenge(RistrettoPrivateTokenType, nil, "issuer.example", []string{}), + createTokenChallenge(RistrettoPrivateTokenType, redemptionContext, "issuer.example", []string{}), + } + + vectors := make([]PrivateIssuanceTestVector, len(challenges)) + for i := 0; i < len(challenges); i++ { + challenge := challenges[i] + challengeEnc := challenge.Marshal() + + var seed [32]byte + util.MustRead(t, hkdf, seed[:]) + tokenKey, err := oprf.DeriveKey(oprf.SuiteRistretto255, oprf.VerifiableMode, seed[:], challengeEnc) + if err != nil { + t.Fatal(err) + } + + issuer := NewRistrettoPrivateIssuer(tokenKey) + client := NewRistrettoPrivateClient() + + vectors[i] = generatePrivateIssuanceBlindingTestVector(t, &client, issuer, challenge) + } + + // Encode the test vectors + encoded, err := json.Marshal(vectors) + if err != nil { + t.Fatalf("Error producing test vectors: %v", err) + } + + // Verify that we process them correctly + verifyPrivateIssuanceTestVectors(t, encoded) + + var outputFile string + if outputFile = os.Getenv(outputRistrettoPrivateIssuanceTestVectorEnvironmentKey); len(outputFile) > 0 { + err := os.WriteFile(outputFile, encoded, 0644) + if err != nil { + t.Fatalf("Error writing test vectors: %v", err) + } + } +} + func TestVectorVerifyBasicPrivateIssuance(t *testing.T) { var inputFile string if inputFile = os.Getenv(inputBasicPrivateIssuanceTestVectorEnvironmentKey); len(inputFile) == 0 { @@ -290,5 +369,19 @@ func TestVectorVerifyBasicPrivateIssuance(t *testing.T) { t.Fatalf("Failed reading test vectors: %v", err) } - verifyBasicPrivateIssuanceTestVectors(t, encoded) + verifyPrivateIssuanceTestVectors(t, encoded) +} + +func TestVectorVerifyRistrettoPrivateIssuance(t *testing.T) { + var inputFile string + if inputFile = os.Getenv(inputRistrettoPrivateIssuanceTestVectorEnvironmentKey); len(inputFile) == 0 { + t.Skip("Test vectors were not provided") + } + + encoded, err := os.ReadFile(inputFile) + if err != nil { + t.Fatalf("Failed reading test vectors: %v", err) + } + + verifyPrivateIssuanceTestVectors(t, encoded) } diff --git a/tokens/private/token.go b/tokens/private/token.go new file mode 100644 index 0000000..f516b43 --- /dev/null +++ b/tokens/private/token.go @@ -0,0 +1,39 @@ +package private + +import ( + "fmt" + + "github.com/cloudflare/pat-go/tokens" + "golang.org/x/crypto/cryptobyte" +) + +const BasicNk int = 48 // defined in RFC 9578 Section 8.2.1 https://datatracker.ietf.org/doc/html/rfc9578#name-token-type-voprfp-384-sha-3 +const BasicNe int = 49 // defined in RFC 9497 Section 4.4 https://datatracker.ietf.org/doc/html/rfc9497#name-oprfp-384-sha-384 +const RistrettoNk int = 64 // defined in draft-ietf-privacypass-batched-tokens-04 Section 8.1 https://datatracker.ietf.org/doc/html/draft-ietf-privacypass-batched-tokens-04#name-token-type +const RistrettoNe int = 32 // defined in RFC 9497 Section 4.1 https://datatracker.ietf.org/doc/html/rfc9497#name-oprfristretto255-sha-512 + +func UnmarshalPrivateToken(data []byte) (tokens.Token, error) { + s := cryptobyte.String(data) + + token := tokens.Token{} + if !s.ReadUint16(&token.TokenType) { + return tokens.Token{}, fmt.Errorf("invalid Token encoding") + } + var nk int + switch token.TokenType { + case BasicPrivateTokenType: + nk = BasicNk + case RistrettoPrivateTokenType: + nk = RistrettoNk + default: + return tokens.Token{}, fmt.Errorf("invalid Token type") + } + if !s.ReadBytes(&token.Nonce, 32) || + !s.ReadBytes(&token.Context, 32) || + !s.ReadBytes(&token.KeyID, 32) || + !s.ReadBytes(&token.Authenticator, nk) { + return tokens.Token{}, fmt.Errorf("invalid Token encoding") + } + + return token, nil +} diff --git a/tokens/private/token_request.go b/tokens/private/token_request.go new file mode 100644 index 0000000..f943713 --- /dev/null +++ b/tokens/private/token_request.go @@ -0,0 +1,59 @@ +package private + +import ( + "bytes" + + "golang.org/x/crypto/cryptobyte" +) + +const BasicPrivateTokenType = uint16(0x0001) +const RistrettoPrivateTokenType = uint16(0x0005) + +type PrivateTokenRequest struct { + raw []byte + tokenType uint16 + TokenKeyID uint8 + BlindedReq []byte // 48 bytes +} + +func (r *PrivateTokenRequest) TruncatedTokenKeyID() uint8 { + return r.TokenKeyID +} + +func (r *PrivateTokenRequest) Type() uint16 { + return r.tokenType +} + +func (r PrivateTokenRequest) Equal(r2 PrivateTokenRequest) bool { + return r.tokenType == r2.tokenType && + r.TokenKeyID == r2.TokenKeyID && + bytes.Equal(r.BlindedReq, r2.BlindedReq) +} + +func (r *PrivateTokenRequest) Marshal() []byte { + if r.raw != nil { + return r.raw + } + + b := cryptobyte.NewBuilder(nil) + b.AddUint16(r.tokenType) + b.AddUint8(r.TokenKeyID) + b.AddBytes(r.BlindedReq) + + r.raw = b.BytesOrPanic() + return r.raw +} + +func (r *PrivateTokenRequest) Unmarshal(data []byte) bool { + s := cryptobyte.String(data) + + var tokenType uint16 + if !s.ReadUint16(&tokenType) || + (tokenType != BasicPrivateTokenType && tokenType != RistrettoPrivateTokenType) || + !s.ReadUint8(&r.TokenKeyID) || + !s.ReadBytes(&r.BlindedReq, 48) { + return false + } + + return true +} diff --git a/tokens/type1/type1-issuance-test-vectors.json b/tokens/private/type1-issuance-test-vectors.json similarity index 100% rename from tokens/type1/type1-issuance-test-vectors.json rename to tokens/private/type1-issuance-test-vectors.json diff --git a/tokens/type1/type1-issuance-test-vectors.rust.json b/tokens/private/type1-issuance-test-vectors.rust.json similarity index 100% rename from tokens/type1/type1-issuance-test-vectors.rust.json rename to tokens/private/type1-issuance-test-vectors.rust.json diff --git a/tokens/private/type5-issuance-test-vectors.json b/tokens/private/type5-issuance-test-vectors.json new file mode 100644 index 0000000..234ca81 --- /dev/null +++ b/tokens/private/type5-issuance-test-vectors.json @@ -0,0 +1 @@ +[{"skS":"065cca6457eac53b38c4f174ea1498fee99bb0c724035e1ed0baace5c3223201","pkS":"28c68b4c454bb67e0138e2ca3ce77a4a92bb570de7023a1d0fc885f9b6fa7d44","token_challenge":"0005000e6973737565722e6578616d706c65208278149d3094c9138347d7a2bcbf1188a262a10b1a5696c41549eabed84c129d000e6f726967696e2e6578616d706c65","nonce":"678dd032dc3dd290a524c9525b59e9fa2a1426f2ebe07d71be44e410235c5bc9","blind":"f16cd9d7b9618a5a434439f6edd5e5d053f2781f90169eb4057ef94b65a9f900","token_request":"0005a3987bcba79eb7bb4afbdd3acd2500417f68eb109b420f871ae0964481d1cfc64c","token_response":"a85598dd8eeb0e4e8ad61672a1b60cb879dcb6e2bb577f53a6c5799605adad73fc085894a651a29be45d10431eb3a60948f594eb1a0b82fdb21fa1bcba1bd20e7e16d160b6ae31c1e3b612145b406920f9d206a2213b8b13beea076c2ed4dd05","token":"0005678dd032dc3dd290a524c9525b59e9fa2a1426f2ebe07d71be44e410235c5bc9ead0d1e696ccbef94da0dd33e0e265d97a8015532f429d968fa41fb0af0cb38547fe05e1fd8dac4eb493924ea617a4d5b950e2d6deec99806bce058929d0d3a386b38c783958b8f975795b2e3544cb58ea24eadb236c970641bb275095aedfa5da76bb808f55ba51aa407be433d5598fe708cfc3d2a1f6c9b40fa9d9a7fa65c5"},{"skS":"9f24660c54374169e9605c7c5431ff93547ec2a5de0a6a5f4178720be1c6a00f","pkS":"fa1a06593483ef048e77d54214697dc5734672bb927db0b3c7e08b6db8adce4b","token_challenge":"0005000e6973737565722e6578616d706c6500000e6f726967696e2e6578616d706c65","nonce":"1543cf07d8f64f9163b2487376e3e23aa36224b64b56d982838ef6a2f5a0c32a","blind":"e3632369f86f13da22089761dae12c829fcc7d9c7f41ca8b072a2765104a7e05","token_request":"00051e4a0ef58c0f18db88f5fa97324cce8e8c642d92bfc4525a58bb857a51c4b9645a","token_response":"30e4110f871a6b8ef610153df24a0ce3d025979462e379c103908fa5fe95c8295cc5f771b69422fe711e436a791d10fbfb86dd18300c25fcd77ee0a6c72bdc022421875e5bfd78055fb79d8e6fc4c475899578127e5959810308738d58f7ed0b","token":"00051543cf07d8f64f9163b2487376e3e23aa36224b64b56d982838ef6a2f5a0c32a69b53830c9e88ce2285efc18a8bdc36d2225a41c4afdd0ce1337411f9e7ec0ae50d42f2b86fe4657a5f2363d89c542d11a7e290d2c48ccf06c941dcd301e181eb52beac7a9bcb001e25ea61095ac7249c5923e8aedd542a608362d65d59c3bcd3a53c0f1910be2de4c746f2846f722d07dd239b0d193c670bb4eea1b01d4a978"},{"skS":"57a14d07df82a820c9c9d01386ef80850ef61690cea21432bec1366d6d997200","pkS":"184f826f89d9349e78d71715f1e3e91e51ecaa4a307def65905ce3ac76c8427c","token_challenge":"0005000e6973737565722e6578616d706c65000017666f6f2e6578616d706c652c6261722e6578616d706c65","nonce":"ff94318c0a49c08b421888076a8bf8b8223bb25685ffacd1e8001ddb71ce874e","blind":"8f23a75ac79fd6361654a9d5bdb06063366c0f918c0dfeb18b2aaa4046a8300f","token_request":"0005d90c8f332d31ac1fafc4d4efbb10d83a56e0c4db0bd3daa729e7123522bfa76c4e","token_response":"30fc1468e7e0fc9ed1d58df1b781c4a12a65b0ffb05ecaf6e642e678259cf944c1201fffd9382d149def2b36a24ad5eab8daf39878ce24b3a3b33d0a9088f5000a25afc2c442a5caef39d55d862b267f59d575ac2e190990cecc9111414d2203","token":"0005ff94318c0a49c08b421888076a8bf8b8223bb25685ffacd1e8001ddb71ce874e8a73b15843d93251b73e17d484d3e5467e6db28a74a042d83a311005dfdb9c61d38db1eae5d88760e75355ff0060861137b5e5a45bd6e64e8d3da4f5e38155d98c06ff991b907b45d512d5f4cb39aeef67c0d6e738792e1457e29c1402bf5feb4c55f0337aa7f73dc366fcdf8d2c9b823bb99ba2efe39ab31fa4d561e8dbb408"},{"skS":"14b3821a3b383d384141a8135191944d74b07371fb78a465521f0867b7628006","pkS":"4429d3c5dbc68f9280dfde3ceeb4bcc0da37c681b83065a7319e16c886d4c856","token_challenge":"0005000e6973737565722e6578616d706c65000000","nonce":"a53148ef0e37785a51950efc46ee1c959a9f2511f8d5570dfcd609d3001a1dbd","blind":"d85f5a0096304a954d4d7feba0faaa3011a004337d70197b3b607547ed2e6508","token_request":"0005f656c94386183dee559fee3953b04fb9b97dcad9b5bc1e1ec8d2513804e8f71b03","token_response":"6c2c459fe0975d59d4f38dcf26f81dfc28a83d45840897da03d729e805867843aae4c66edae05f2fce4b755d41c245e0841aff2a61e152515655b03eee2cab00660a5c9d4263f83e6e4cd9c7ce7ec7c0b4dd45b6fa8ae9b2d1cff124273e6d00","token":"0005a53148ef0e37785a51950efc46ee1c959a9f2511f8d5570dfcd609d3001a1dbdb2174d8c51b010f2f8d73a85a8595138f02c4082a27c5348a47679456d9e350f3fb7498d84e1b9d4f5171b1c5d238eab7d7c18cbb6829ab9a441be65bb4e9bf67147573bee5e5a5bb9b50efac2880bd281b99eaff7e681acdbbe42910674884de84f4d120f7a17f0088405174e08d08776f13836d8a64643653466302865d722"},{"skS":"c113b4d6182fd5a7918b8cfc938692364ad310f56f0b0a448e07c915e2c88c0c","pkS":"4c6859406c73339ed11059cb203e95aed9de0d29a8232bc09a02d0e6c0aeb934","token_challenge":"0005000e6973737565722e6578616d706c65208278149d3094c9138347d7a2bcbf1188a262a10b1a5696c41549eabed84c129d0000","nonce":"d8af21d3f0f186c2219f00d408df3fdec225b3a385b05a14d074270e76db6adb","blind":"607253ecc7635b7d308af78dc139bf8e50c5267836d62ec1dc45078d8401b90c","token_request":"0005576afdd999a852d2b692a0112ffaff3b52188526659343dd29edbf15ffa3a30940","token_response":"8cfd757a54027713c8d0726403d85d7870826d9eaadfb3320e5464e446c4442b1dd74493d28f594e240a705c69ada8edad32e3ea0afb8ae214e31ccaebabde0602782c0e3a3960f0c6ff008fe32e511a5ecedd9b073d769f0c69cc6be5197509","token":"0005d8af21d3f0f186c2219f00d408df3fdec225b3a385b05a14d074270e76db6adb76ee4d34d93248d8759177310d19ff8690ccc42f86793cdac0698466c3c70da435ab57a2874d19f43300be9f3b86b9862af2dbf5c08c0e2103b9f8a95ded2157acfc7a194756803d5b8e183bfeff8ebe723f89db36b2647730efeed7af2f2130394d57349fd2c9cb13efb9b59160c73b2ee005aaad76ddc0a7d93112b09fdeda"}] \ No newline at end of file diff --git a/tokens/private/type5-issuance-test-vectors.rust.json b/tokens/private/type5-issuance-test-vectors.rust.json new file mode 100644 index 0000000..bb7f592 --- /dev/null +++ b/tokens/private/type5-issuance-test-vectors.rust.json @@ -0,0 +1,52 @@ +[ + { + "skS": "0b52bee01606bb873f3659b220bedf6d8a796e191e0879c22d0667fe0fe2db0d", + "pkS": "46a454edf9beab6d688dd5e3b5a12ebfd0f05057eaa07198cb59d8d77090e970", + "token_challenge": "0005000b497373756572204e616d6520152f7d5c268f3e2782afe1bd8cb5fedd71fd63148f629aafec159475876b65fb0005612c622c63", + "nonce": "9558a6deb372d9028cf207997e3ec07698f7acf4015c5bcc8e750da5127927fd", + "blind": "6ae499850850845939dbb3c8777d15bd01ffeda38ba8c6530cde4b4a80ec9a0f", + "token_request": "00053aa6d0b8af416e2848e26fc07ec0969362944e7f7635ddbb2fc95c48abbf6d0961", + "token_response": "c8b7904959477a8845c27d9028d78c9a20485b5f2c3af091e7831f63a3ea0418f65ba122c97f6a999f9efa3685eaf94a10297bc31bd73566fc6eacf7e51c0f085c5f0e20ec6edc0d4ec162b5bab19dedb1bc3888b483b664d7e5cc084e1b2b08", + "token": "00059558a6deb372d9028cf207997e3ec07698f7acf4015c5bcc8e750da5127927fd90ce141c3793e0d80e94fbb79493144aeea28a1c99dbcfa29443f355f8c4059050682a941d571317fd1b8f5c45d8927e35dcbf4d0c83c7caabd0168bee66083a4028260f80b850bfbe6255ac45ee2131ffecf807789a1baf999232fdc431f2ea0a834b4fea79b5c859cc36b991e5dd038d8905677a9275c3fa13d853b6e546b9" + }, + { + "skS": "89b33741579a50c0ca3ed6a10173aa2104c7f15aeade355eca70532d33e8ce0f", + "pkS": "3c512af0aed3b1bcf06cc960dc8a01a3b82b49851656a07c62afed245137711f", + "token_challenge": "0005000b497373756572204e616d6520fffbb92c0d294ce770961273017fe928deaa4a3d6a68572cf47822b1c06da0fc0005612c622c63", + "nonce": "4de0f814cfd5a07bdb8dce302a62f10e4f0ec642dd7aaeac3d5695876aed28e7", + "blind": "141c6c01876170f6ce2438cf61298c7b47231f49e810c786c7d8b80d7214ff00", + "token_request": "0005d950cf438660b794ab27ac0dda4e6e3a6c6f636a91ab30028aa5bf56c57c76fc01", + "token_response": "8cf6de6a0db0477fad0f53d6d4830bc83baa48c316536aaeb709940af129360155620a67d59c5d0325f6fe6c80f981b68eb4fdacaf03f280cd58d238e0cdae035f626db1686e067bf71a5ec57b28524e29ef43566e0d62340907a517c1449008", + "token": "00054de0f814cfd5a07bdb8dce302a62f10e4f0ec642dd7aaeac3d5695876aed28e728e7ff011ffa8bfb9de3e9988ee658468c5ea71a782b0a19151c2931386d985c3994d7c7ca66670f7216a63f33ef207d109be93f22931be749d5bf60bae00ed9c84827127118a32d35f796f0a9da4e572f8f285cb89c087bc2d096568d933ece24440a9a83cc0a0bbd18558c6e3f7b95a14f7b1a48477b15f3f6f8f7aaa8b207" + }, + { + "skS": "36b4ef4f7a058008d0e6a7c58caee618c8cece7938b02a1a3e0c358a52929909", + "pkS": "4826b0952527afb56f3f413ddc08ee36cfc8432ea96e1430f73317f85cd2a016", + "token_challenge": "0005000b497373756572204e616d65000005612c622c63", + "nonce": "9c527eed31a94d8ba30bbce96d21cb509e15ec9fb476445a71d24109bcb9fbb4", + "blind": "13987995de579c6ebd0b342bd471973eaecff20f17aef43e7da41b0aa2ae6800", + "token_request": "000555003bfa2896dd98ca70c7f4c3f8ca7742551dc14f4a32cb55a6df94a3f4ca2f08", + "token_response": "32a1744ac3e0930c1990049a8b3dcef91086183ef68706f0ed51eb21f2842e62301f444f2fc20e9090d7d0d6ac4e0ca382f51ef9cb269ee79cdcf67643ac9d0127248b43dbf6d2dd04bcbf8df3650dea73219fd3fb3c5e3c9158e87b2a6e8d05", + "token": "00059c527eed31a94d8ba30bbce96d21cb509e15ec9fb476445a71d24109bcb9fbb405bebf3881b04fbb652613bd335710fce992e473ae4c5d860066d5f15535bcd1a68d26e07550e8a291e69efedf4265e6917c2dbf300fa8e4ba52a78059d60b55421c5f6041507a7da0f81a38065df7b8e9d924c8a6dd1871add0f10a7ca3a04049baec89a325795143b5e433af21ed4ca5b737c0c7203ebb9427bdd7bd73cdd6" + }, + { + "skS": "701e295fd5029617371bc3ac4faa7d2c2bb647968ba34d566f4354166982bf02", + "pkS": "de4d50871abce9e1b57032a000bd21e3070faf625beb1f9cce6f5b9aa4cec51c", + "token_challenge": "0005000b497373756572204e616d65207155d0bd2647b8be3a23cc7dd3953d26bfc9a6853f090ded0ef64cb9cca93d560005612c622c63", + "nonce": "b6adc3a36190bca49444b59577860f9f864e1aa4a7aeda5a9ce3526577362c49", + "blind": "ca73930131684a2babbf620fe09e6a934793372c9c741537c3400c6a7c11110f", + "token_request": "0005a33220003093091692ad22fcd51a387300eb793563643dab8502c32a8b173fd947", + "token_response": "b0075c499f42fa8165bf8e41de97e0277a17e9a850011329fd6358fdaf44964e579a741312b9f8e68254226a623c5eb68973e019005a15a547bccae1a471fa0087bb26fb8a5c7c7ed6051ef7e733012736a498c4db5272d7eba2776e43e2b30a", + "token": "0005b6adc3a36190bca49444b59577860f9f864e1aa4a7aeda5a9ce3526577362c495b62fc0a15bc5ec774ca8fc347798f19574c6e90df5c4686eabefbf2327c2432b77b1e5e8f7ae641c6b216efcaeef85afc8818a90dd8e2e1a1696be76c716ca3726283f6a85aa96974b3c13312d82cebe4cc54998851dce409ee1051712f1a3c7f7a0aa8ccdd090b80d2783de4a42f6805107a9339431fe04aaaaed4ed52e48a" + }, + { + "skS": "c7b5f8752844843602027071f1d1e017b2affa11c9827c3983ffbc4373473e00", + "pkS": "1ca72bdfd657985b44afb8f79ceda220916f37a567afd0c5943b6eeda40e5203", + "token_challenge": "0005000b497373756572204e616d6520e5850b1428e2990700d074cf6907cefa2dfe8126b91f6403f1412dc89640f3a50005612c622c63", + "nonce": "5b5f7bd44239c9e3501468fb7f8fb9915ec0734429a8f71fe03d39a5e4f4293a", + "blind": "f2803bcf58776ea00dca81e6279c5292ddf396977ae63188ad5beff405140f0f", + "token_request": "00058272861ee9d184ab674ed54525a3b0ae1f2d9df41d6dcb742ec4a4ebc0e0f5087c", + "token_response": "fa074701c0f023e6637e1467f955d11209e65bcbdb8d25b16db7c8ddf8c7025fbdcb7a471f1657ce0abb0f2be50cc79ab3a7ed37043b4bcb2b443d2e4290f10de96e9e7daf30b293d4872b0280d488256e7689d3b1fbf0e1ea1e47762f763504", + "token": "00055b5f7bd44239c9e3501468fb7f8fb9915ec0734429a8f71fe03d39a5e4f4293ada9fb87f5409504de46bdce952f2ceca19bd6d354007fcdf043506f5e3288d1e7abc4b6addf26139a05275fe0594375d059df746a75211be85ff7754252dfe82ee6403733961414f6818eac608c70b48975ee5e571e1b7d6019aeabb2cb7133a0b72fdf912089bf66a977f97c88badb9976f0e20a7c138f991cf4963d20e1768" + } +] \ No newline at end of file diff --git a/tokens/type1/client.go b/tokens/type1/client.go deleted file mode 100644 index e4c5fd7..0000000 --- a/tokens/type1/client.go +++ /dev/null @@ -1,146 +0,0 @@ -package type1 - -import ( - "crypto/sha256" - - "github.com/cloudflare/circl/group" - "github.com/cloudflare/circl/oprf" - "github.com/cloudflare/circl/zk/dleq" - "github.com/cloudflare/pat-go/tokens" -) - -type BasicPrivateClient struct { -} - -func NewBasicPrivateClient() BasicPrivateClient { - return BasicPrivateClient{} -} - -type BasicPrivateTokenRequestState struct { - tokenInput []byte - request *BasicPrivateTokenRequest - client oprf.VerifiableClient - verificationKey *oprf.PublicKey - verifier *oprf.FinalizeData -} - -func (s BasicPrivateTokenRequestState) Request() *BasicPrivateTokenRequest { - return s.request -} - -func (s BasicPrivateTokenRequestState) ForTestsOnlyVerifier() *oprf.FinalizeData { - return s.verifier -} - -func (s BasicPrivateTokenRequestState) FinalizeToken(tokenResponseEnc []byte) (tokens.Token, error) { - evaluatedElement := group.P384.NewElement() - err := evaluatedElement.UnmarshalBinary(tokenResponseEnc[:group.P384.Params().CompressedElementLength]) - if err != nil { - return tokens.Token{}, err - } - - proof := new(dleq.Proof) - err = proof.UnmarshalBinary(group.P384, tokenResponseEnc[group.P384.Params().CompressedElementLength:]) - if err != nil { - return tokens.Token{}, err - } - - evaluation := &oprf.Evaluation{ - Elements: []oprf.Evaluated{evaluatedElement}, - Proof: proof, - } - outputs, err := s.client.Finalize(s.verifier, evaluation) - if err != nil { - return tokens.Token{}, err - } - - tokenData := append(s.tokenInput, outputs[0]...) - token, err := UnmarshalPrivateToken(tokenData) - if err != nil { - return tokens.Token{}, err - } - - return token, nil -} - -// https://ietf-wg-privacypass.github.io/base-drafts/caw/pp-issuance/draft-ietf-privacypass-protocol.html#name-issuance-protocol-for-publi -func (c BasicPrivateClient) CreateTokenRequest(challenge, nonce []byte, tokenKeyID []byte, verificationKey *oprf.PublicKey) (BasicPrivateTokenRequestState, error) { - client := oprf.NewVerifiableClient(oprf.SuiteP384, verificationKey) - - context := sha256.Sum256(challenge) - token := tokens.Token{ - TokenType: BasicPrivateTokenType, - Nonce: nonce, - Context: context[:], - KeyID: tokenKeyID, - Authenticator: nil, // No OPRF computed yet - } - tokenInput := token.AuthenticatorInput() - finalizeData, evalRequest, err := client.Blind([][]byte{tokenInput}) - if err != nil { - return BasicPrivateTokenRequestState{}, err - } - - encRequest, err := evalRequest.Elements[0].MarshalBinaryCompress() - if err != nil { - return BasicPrivateTokenRequestState{}, err - } - request := &BasicPrivateTokenRequest{ - TokenKeyID: tokenKeyID[len(tokenKeyID)-1], - BlindedReq: encRequest, - } - - requestState := BasicPrivateTokenRequestState{ - tokenInput: tokenInput, - request: request, - client: client, - verifier: finalizeData, - verificationKey: verificationKey, - } - - return requestState, nil -} - -func (c BasicPrivateClient) CreateTokenRequestWithBlind(challenge, nonce []byte, tokenKeyID []byte, verificationKey *oprf.PublicKey, blindEnc []byte) (BasicPrivateTokenRequestState, error) { - client := oprf.NewVerifiableClient(oprf.SuiteP384, verificationKey) - - context := sha256.Sum256(challenge) - token := tokens.Token{ - TokenType: BasicPrivateTokenType, - Nonce: nonce, - Context: context[:], - KeyID: tokenKeyID, - Authenticator: nil, // No OPRF output computed yet - } - tokenInput := token.AuthenticatorInput() - - blind := group.P384.NewScalar() - err := blind.UnmarshalBinary(blindEnc) - if err != nil { - return BasicPrivateTokenRequestState{}, err - } - - finalizeData, evalRequest, err := client.DeterministicBlind([][]byte{tokenInput}, []oprf.Blind{blind}) - if err != nil { - return BasicPrivateTokenRequestState{}, err - } - - encRequest, err := evalRequest.Elements[0].MarshalBinaryCompress() - if err != nil { - return BasicPrivateTokenRequestState{}, err - } - request := &BasicPrivateTokenRequest{ - TokenKeyID: tokenKeyID[len(tokenKeyID)-1], - BlindedReq: encRequest, - } - - requestState := BasicPrivateTokenRequestState{ - tokenInput: tokenInput, - request: request, - client: client, - verifier: finalizeData, - verificationKey: verificationKey, - } - - return requestState, nil -} diff --git a/tokens/type1/issuer.go b/tokens/type1/issuer.go deleted file mode 100644 index f203a15..0000000 --- a/tokens/type1/issuer.go +++ /dev/null @@ -1,86 +0,0 @@ -package type1 - -import ( - "bytes" - "crypto/sha256" - "fmt" - - "github.com/cloudflare/circl/group" - "github.com/cloudflare/circl/oprf" - "github.com/cloudflare/pat-go/tokens" -) - -type BasicPrivateIssuer struct { - tokenKey *oprf.PrivateKey -} - -func NewBasicPrivateIssuer(key *oprf.PrivateKey) *BasicPrivateIssuer { - return &BasicPrivateIssuer{ - tokenKey: key, - } -} - -func (i *BasicPrivateIssuer) TokenKey() *oprf.PublicKey { - return i.tokenKey.Public() -} - -func (i *BasicPrivateIssuer) TokenKeyID() []byte { - pkIEnc, err := i.tokenKey.Public().MarshalBinary() - if err != nil { - panic(err) - } - keyID := sha256.Sum256(pkIEnc) - return keyID[:] -} - -func (i BasicPrivateIssuer) Evaluate(req *BasicPrivateTokenRequest) ([]byte, error) { - server := oprf.NewVerifiableServer(oprf.SuiteP384, i.tokenKey) - - e := group.P384.NewElement() - err := e.UnmarshalBinary(req.BlindedReq) - if err != nil { - return nil, err - } - evalRequest := &oprf.EvaluationRequest{ - Elements: []oprf.Blinded{e}, - } - - // Evaluate the input - evaluation, err := server.Evaluate(evalRequest) - if err != nil { - return nil, err - } - - // Build TokenResponse - // XXX(caw) move this to token_response.go - encEvaluatedElement, err := evaluation.Elements[0].MarshalBinaryCompress() - if err != nil { - return nil, err - } - encProof, err := evaluation.Proof.MarshalBinary() - if err != nil { - return nil, err - } - tokenResponse := append(encEvaluatedElement, encProof...) - - return tokenResponse, nil -} - -func (i BasicPrivateIssuer) Type() uint16 { - return BasicPrivateTokenType -} - -func (i BasicPrivateIssuer) Verify(token tokens.Token) error { - server := oprf.NewVerifiableServer(oprf.SuiteP384, i.tokenKey) - - tokenInput := token.AuthenticatorInput() - output, err := server.FullEvaluate(tokenInput) - if err != nil { - return err - } - if !bytes.Equal(output, token.Authenticator) { - return fmt.Errorf("token authentication mismatch") - } - - return nil -} diff --git a/tokens/type1/token.go b/tokens/type1/token.go deleted file mode 100644 index 54562a2..0000000 --- a/tokens/type1/token.go +++ /dev/null @@ -1,26 +0,0 @@ -package type1 - -import ( - "fmt" - - "github.com/cloudflare/pat-go/tokens" - "golang.org/x/crypto/cryptobyte" -) - -const Nk int = 48 // defined in RFC 9578 Section 8.2.1 https://datatracker.ietf.org/doc/html/rfc9578#name-token-type-voprfp-384-sha-3 -const Ne int = 49 // defined in RFC 9497 Section 4.4 https://datatracker.ietf.org/doc/html/rfc9497#name-oprfp-384-sha-384 - -func UnmarshalPrivateToken(data []byte) (tokens.Token, error) { - s := cryptobyte.String(data) - - token := tokens.Token{} - if !s.ReadUint16(&token.TokenType) || - !s.ReadBytes(&token.Nonce, 32) || - !s.ReadBytes(&token.Context, 32) || - !s.ReadBytes(&token.KeyID, 32) || - !s.ReadBytes(&token.Authenticator, Nk) { - return tokens.Token{}, fmt.Errorf("invalid Token encoding") - } - - return token, nil -} diff --git a/tokens/type1/token_request.go b/tokens/type1/token_request.go deleted file mode 100644 index 14e3819..0000000 --- a/tokens/type1/token_request.go +++ /dev/null @@ -1,59 +0,0 @@ -package type1 - -import ( - "bytes" - - "golang.org/x/crypto/cryptobyte" -) - -const BasicPrivateTokenType = uint16(0x0001) - -type BasicPrivateTokenRequest struct { - raw []byte - TokenKeyID uint8 - BlindedReq []byte // 48 bytes -} - -func (r *BasicPrivateTokenRequest) TruncatedTokenKeyID() uint8 { - return r.TokenKeyID -} - -func (r *BasicPrivateTokenRequest) Type() uint16 { - return BasicPrivateTokenType -} - -func (r BasicPrivateTokenRequest) Equal(r2 BasicPrivateTokenRequest) bool { - if r.TokenKeyID == r2.TokenKeyID && - bytes.Equal(r.BlindedReq, r2.BlindedReq) { - return true - } - return false -} - -func (r *BasicPrivateTokenRequest) Marshal() []byte { - if r.raw != nil { - return r.raw - } - - b := cryptobyte.NewBuilder(nil) - b.AddUint16(BasicPrivateTokenType) - b.AddUint8(r.TokenKeyID) - b.AddBytes(r.BlindedReq) - - r.raw = b.BytesOrPanic() - return r.raw -} - -func (r *BasicPrivateTokenRequest) Unmarshal(data []byte) bool { - s := cryptobyte.String(data) - - var tokenType uint16 - if !s.ReadUint16(&tokenType) || - tokenType != BasicPrivateTokenType || - !s.ReadUint8(&r.TokenKeyID) || - !s.ReadBytes(&r.BlindedReq, 48) { - return false - } - - return true -} diff --git a/tokens/type5/token.go b/tokens/type5/token.go deleted file mode 100644 index ced3027..0000000 --- a/tokens/type5/token.go +++ /dev/null @@ -1,23 +0,0 @@ -package type5 - -import ( - "fmt" - - "github.com/cloudflare/pat-go/tokens" - "golang.org/x/crypto/cryptobyte" -) - -func UnmarshalBatchedPrivateToken(data []byte) (tokens.Token, error) { - s := cryptobyte.String(data) - - token := tokens.Token{} - if !s.ReadUint16(&token.TokenType) || - !s.ReadBytes(&token.Nonce, 32) || - !s.ReadBytes(&token.Context, 32) || - !s.ReadBytes(&token.KeyID, 32) || - !s.ReadBytes(&token.Authenticator, 64) { - return tokens.Token{}, fmt.Errorf("invalid Token encoding") - } - - return token, nil -} diff --git a/x b/x new file mode 100644 index 0000000..b56f252 --- /dev/null +++ b/x @@ -0,0 +1,626 @@ +// Test vector 1: +skS: 16e66b97d6e2595c7c7bae5de140249d614ee3445b51f7519a8fe2a7c313 +031fef8ed1e15a614234561a4e43595c6126 +pkS: 0244b47e6ae241020bfa4ec2fbabbad14c4a3e3dc43a796297121734089b +70020759358b0a093e1b1ba3f8c4587741eb33 +token_challenge: 0001000e6973737565722e6578616d706c65205de58a52fc +daef25ca3f65448d04e040fb1924e8264acfccfc6c5ad451d582b3000e6f72696 +7696e2e6578616d706c65 +nonces: + - 17a45811bae8ef4a3760e797f28fdefc5c505037411f2267f162faf8d0cc4 + 1bd + - b2b631f29cce6e572c304046d064499db541adc6c300084e8d9a0a7530bd7 + 01a + - 2663bff99c32a5ca5faa21ccf0c5dea29dd33748694846296d94648b41802 + db1 +blinds: + - a1280097a2487cf90c2bf005ff6e4a7f31375dfb9fee6239f73b721edccce + 748b80dc6fe86da39701f2e6d3319fba297 + - d9ee73a1a1e231898f8b9a2e388baf1b7c421f8813b7bcf2b8cae0fb4b18a + e3e3a0722300c79bd2e90d7158954730be8 + - 9fc032fbaff9369fd5be37165f52394c59f4844567f77cb8d535d9e22488e + 6728694b11e33ce14e7cffa57c737b3a60a +token_request: 0001b840930262d785d05fd837d024775c659020a4872ca6ee +56c13cbe15dadeec12e77cd5a32904e470bb0ca51f6f5611aa2900fd300226b2e +e166aa5e2ec175ed24d9671572ad330a6648b781326e5951807bf56da95f7f7d5 +d6a1cedf5b58c3bc340917de6103766cf2d6a1b53b83a33089badfea3df0c4951 +f488a60f014f2a5e2d0c8a678f6d56f6507e4b647f39a742f1981a393db +token_response: 409302b94eed3e49b41609bfdccd700894cf559dc642f4b33 +97afe4a5124b2196acaae8514f24db9dd40b3ca4a5ddbb51f741202f72ade5e5c +bd3917e17ecd9dbdbb0aaab57a637daa4c01193a93c8a28731222a182090b5ff5 +183f893d57e1e9782b51803d0ec40dfac4e3f5c4855810026680a12a2cb008858 +b5682f5e879de543e31dfb12febf8a430a68f5a25599768ec94930e8bbf80b4ba +300527ce450bdeb98f4634e9caf368a10373f3eabe01fcfd75102c85731902062 +826852531964f215fc55aa0e3be32b08d7baae7134be5d92b1047b277d8ff7cb4 +f146c71a8c1b025ebaba510b634cd9f3035421cd00eced42d2f +tokens: + - 000117a45811bae8ef4a3760e797f28fdefc5c505037411f2267f162faf8d + 0cc41bd501370b494089dc462802af545e63809581ee6ef57890a12105c2836 + 8169514bce724a0a821c7294180eed5785e946e9f854e4ca3de7e6cfbf2588e + 08cabedb8a302aadff0a21aa348087e5290a305ee8e04a451bf73aab8b27ac4 + ac3761da0149064a932562c06d4054cddd850eaa85 + - 0001b2b631f29cce6e572c304046d064499db541adc6c300084e8d9a0a753 + 0bd701a501370b494089dc462802af545e63809581ee6ef57890a12105c2836 + 8169514bce724a0a821c7294180eed5785e946e9f854e4ca3de7e6cfbf2588e + 08cabedb8535392a7b69b6834d0cd9ce3ba99cc0424a652cbc91248815377bb + 5c71c1786243879595e312364690beda0ad2f77080 + - 00012663bff99c32a5ca5faa21ccf0c5dea29dd33748694846296d94648b4 + 1802db1501370b494089dc462802af545e63809581ee6ef57890a12105c2836 + 8169514bce724a0a821c7294180eed5785e946e9f854e4ca3de7e6cfbf2588e + 08cabedb8d25f38c6b1ca8007b7d08462b93ebbacc740a56800b9c762bc032e + 082931956165f190f88567b5ce710af993bf7d4ebc + +// Test vector 2: +skS: afe6fea6d6c21f9fc6986d2f6e138cea6edf61d332784415500c4fdfc2b8 +48d9250e547d78d1e3ad4bb30938f7fd8b4c +pkS: 030ca71e4322481a968cc6cf7ef9017df93dc01defba57bd9af3a86705e3 +a66759cffadaa58130b5a1eec3834ee923fb18 +token_challenge: 0001000e6973737565722e6578616d706c6500000e6f7269 +67696e2e6578616d706c65 +nonces: + - f86364dac08de021f8454d22f76cb2e397db469d1e04e0e0fce1956bb29a1 + 281 + - f41cda22fc5503294c23e9008183397c42257299c418e1d2a91d44cad1d00 + aec + - 57dbea8d2f4b0eebdf65526d18f5b328ca3d84c432b55d428400efaf2180d + 7ee +blinds: + - f8a263582248dfe7f5be7dd66a1bf3db822700f65a9b0d3f48ae5171085ab + 50ccc2a41b72466b39756f4dd8771975b67 + - e477da7ee3b5246c0e4326da9a1bac457bb128830681502343eb13ad20667 + dbe68ff1169900e66eb549780e258553767 + - 52620b4bf7f405830d5b45fdca7bfce51cd0486e282bea392d3e748279524 + edc77820f0a7b1f702768cdf8a7b2d4e4a8 +token_request: 0001434093024cf79aabe62a93e92a00c9e7206baab3b11c06 +11071788e2a2c3f7573696984f9046f55122b2fbf9302c2af2ed8aa50f0284d82 +d9c9fe3fcbe0c9de967bf668ddf09ee3cb9d9f0c86339fd4642b6034bdaf1d276 +7fa649cb495bd51b9482178d4a024e71cee46ffaf6ab26fddd23a8af18752910f +b73aff9a4ccc912574950386f5b88d2ba98b150c83a9aa46b6d4ed966ae +token_response: 409303ea334e7bb900a1f91b0eced551946082179fd530949 +b8e2d9746b2e7301c50862bdd0234a1c88c665639e4c0a2a9bb24031dcc4b7395 +2506d100151634376ccd958ca811459f5eb7ba05e401a1264c63c95fd3ff99b57 +7d1ad6eabf2ef0509a7300374e9e2b4bf10c0b82bd6415c945e52343f544e879c +25e345b6dddc760bfd0bbaa0361c24d7f98d73967db9597c1736462440f1e5261 +c0785f59e1166855b817ea30615f5fd2a4fd6bafc4ac813efa1846dec0f160392 +966797b8bb913374a32e83cb57a77d289c3edcc189d0523e307bfe4ecb6e09b0a +74d8361859aec9202f9551be379c9bc32e1f696219d87f6195c +tokens: + - 0001f86364dac08de021f8454d22f76cb2e397db469d1e04e0e0fce1956bb + 29a1281c994f7d5cdc2fb970b13d4e8eb6e6d8f9dcdaa65851fb091025dfe13 + 4bd5a62a8700efdbdce3a004c24dab7b030094b79c5f153c6005de0e74d9b11 + d07d1b0433c083e4d30045e8b692aaaef9cd6cd478a2f360ff253a361a7cc7f + 85cc901624ba902ed2dc0e4493d78167d53cf75a64 + - 0001f41cda22fc5503294c23e9008183397c42257299c418e1d2a91d44cad + 1d00aecc994f7d5cdc2fb970b13d4e8eb6e6d8f9dcdaa65851fb091025dfe13 + 4bd5a62a8700efdbdce3a004c24dab7b030094b79c5f153c6005de0e74d9b11 + d07d1b043d4fc47ca614f0c5db31c770de014fb42e3fec98bed5fdaa097b34c + 357076f6b7ffded0624e3632519c816a516c753181 + - 000157dbea8d2f4b0eebdf65526d18f5b328ca3d84c432b55d428400efaf2 + 180d7eec994f7d5cdc2fb970b13d4e8eb6e6d8f9dcdaa65851fb091025dfe13 + 4bd5a62a8700efdbdce3a004c24dab7b030094b79c5f153c6005de0e74d9b11 + d07d1b04330927c142237a85faf350ea61e176903f58d6c1912a36b33940f79 + 2f1ecb99084758ff4b703357f093fcec8d8e619b7e + +// Test vector 3: +skS: e94b1dd394dddcc64944cc7319f6a2631175db43abf15fb1a6ae4f8fc6cf +8c1cf6b3385df511601620a2a67c3ecb6f8b +pkS: 03d4543fe9c7bf8481a15be8c46f1e45be21e67be9c988ebc5e17e794a0e +8bd6a3e9ad0af978cf045f873def1aa69bf651 +token_challenge: 0001000e6973737565722e6578616d706c65000017666f6f +2e6578616d706c652c6261722e6578616d706c65 +nonces: + - 03bf556ce55e4bf9b228fd8849e0bdf274975b360654a2b1996c2be536853 + f22 + - 09ec15b069bdceea683bb40a23c156a0e31e3d6cb2d9832dcee033374e8cc + a57 + - d5a7df0f9ceda715c8e961a013efe99ac88f12479043551e4e015aab1d32e + bf7 +blinds: + - 1cf2f0ffea2df2fbd375c819c8f3069f74424a7ef0a2db5b362f41a9b2930 + 97f356cb8009f3619f88b4c65182c83fd4c + - 2e4d20ebf54e595a72c427c4d06df24d6f68824220e4a6db3642613027daa + d82237648823dc23e5ad2a96006072bfea7 + - 7bc11a6f8193ae37629c11e38565efd320ef516688a1fca32c6d48f9be7a0 + 77e570ab8a15b3d37b7ef396fd31e75064c +token_request: 000115409302fad381dd1d611cf7fabacefc59936cc722830f +f6664754159ee236faa0ea2b9874a670eede1d2ef395557500e7064b6c02c6648 +d0f8ce0ef455b6d12325727ea5f92ed40a29153a4bcddf459cbf90ff9be31bfdd +8e1471245e0d6fd1dbc09d0f9f033d81c708f8f0957dda5b7949266dff8c1267e +8ef93a83e574a959ff6c33e152f1833355f90279561efc021f988c2bbec +token_response: 409302c7a1b7f405585bccb1949da89b607e0d4851d7b8a0b +f1eb2244d778a1e6031b95d56595ebb247cf3e18d4e212fedf22b03daa80b5b1f +56d29ad82ccec5de24d66ac7de8eca2bf80b145399386b838ac8bf0e9987ded7a +fad94c002c4695294dc4402b748b04ad6e0115c672e274161f19258877906556c +a57d9669a879f4808cdc8bb6c9df1e97ba0e0ee39b31766588bf0ea1d61415847 +f959064fcd9f54abb269945ca42c3548ba94b7ce12fb2c7c26889d2b87f83003b +43a2489a64c1981b673b49a464b226026b4bf04ffc91d19913536f324683f4363 +07a0d12fe4b32afee2dc61b036325bb39d3b690f0694d78fa52 +tokens: + - 000103bf556ce55e4bf9b228fd8849e0bdf274975b360654a2b1996c2be53 + 6853f221949fd455872478ba87e2e6c513c3261cddbe57220581245e4c9c911 + dd1c0bb83233a0ff77c5d21b63fb3b018ecc4b5416ce4f081b5115456c43f2b + d59dde1157e630427c081738078ba67f791af80fbd21c6c8342dfc90e39825e + 7ee85130cc2e29a977ff830b080dcf64865a8fd867 + - 000109ec15b069bdceea683bb40a23c156a0e31e3d6cb2d9832dcee033374 + e8cca571949fd455872478ba87e2e6c513c3261cddbe57220581245e4c9c911 + dd1c0bb83233a0ff77c5d21b63fb3b018ecc4b5416ce4f081b5115456c43f2b + d59dde1152adc03e35079112c47a664658293e13912268b30e1afb89f12e01d + ffc0dc0050cfe60ef20b91d2c5af85e1354213f198 + - 0001d5a7df0f9ceda715c8e961a013efe99ac88f12479043551e4e015aab1 + d32ebf71949fd455872478ba87e2e6c513c3261cddbe57220581245e4c9c911 + dd1c0bb83233a0ff77c5d21b63fb3b018ecc4b5416ce4f081b5115456c43f2b + d59dde115ecd05168dadf2deb5156106c2f35a6b55d26f4ff20f756c94c5e5d + 958e6d54e44271785d44c7805ea101f94a36e83a46 + +// Test vector 4: +skS: 2d7c99b16084ee5ddd739e7e0d68ef104e5c1ad7b01f7a221d3356990c0f +ff87b5b95c64cdcd30838ea5f2ff15090270 +pkS: 03934b1ad9b27aa7e9a7c917941849750db8342922c87a60b8a081768220 +e74a0157ca36582bfcc11eb84f455809ed4a23 +token_challenge: 0001000e6973737565722e6578616d706c65000000 +nonces: + - 76d9571cf508a54ad6a6ea8c477d9ef54b8795456fb8c2737bfd0554406fe + 5e8 + - 0ecd34d2b1944d408d34b4ad8edb45047b5e412aa254c9f3dcbfa4a4082b9 + cdb + - c4b6fd80945b9615ca88ba33ad4bf39d6063857c2e70fa091a30f0e96e7ac + 983 +blinds: + - bdb000ff394d1d7c9076284f10203a3868974c1cb9cf08ea08818b7683a4e + bd38d67197683205c540b8a8e9e3216351d + - 9bfcd6c889e9b0b54b3f8cbf78076fc5dc0eb3d294cc9a30613f4693dc37a + 523c05bd3daf3526a6cc65aa0acb6137d4f + - 11627c3d68b963f0a233838cffe9e5440f66ba77cd06e7db9e7e38a824fa4 + fe569c9e37cc8fe8b5a10cef8362f6d442a +token_request: 0001064093033f33414705307090457029db7f26f71c04cae7 +25e872c05aea3f243e5506f516c79688f098657fe913c0fd68903b407e0392e55 +b5e08e9cc6ae9188ed1e93bbdbba71773aa72a3112f00551be440c11cf1984d60 +7ffbf8e5b0bca3d4c3f9d3b473031c74bff5c2b0e508e1da6562f44e82e3fb74a +4e23cae76721ce92626d64be4dfada25f4d7c39e870edcbdd23632123a2 +token_response: 409303f982b51f6c99ea124bdc3b28fd4eae5e9d8659f45a9 +7242c2cc4eee9dd580a2dfdf2b9adabb41b974e3bc266967ef19e02a5630b001f +e004a3c267152432c3d636134bdf647d06fee05734a6394c6a593645e762f9f87 +cc099b4f20e64dc46568d02fe22e17a5a01807c8cb2b87ed22fdbb38feaeb0b37 +d0f87b5f92e69d2781dcdc2475c18322ae926c2bdc270bee2cb26916f1290eef6 +8be1578c5061549fdd0fa273c44442cd06536d2350f70d3996608268215a83755 +162e1400a1bebb840c301662a6e3df1e74336b6bb8e08fb3dbf5a603cdecba425 +6cffc5295bb37db9769b40c8120dac7bfe37fb0c2ce9af53b85 +tokens: + - 000176d9571cf508a54ad6a6ea8c477d9ef54b8795456fb8c2737bfd05544 + 06fe5e8085cb06952044c7655b412ab7d484c97b97c48c79c568140b8d49a02 + ca47a9cf5bcae9c2bff21fcb91cc8bc0f1d5c31697946de8eb005be5e10f1da + 70fdfab069d2e03d3ffcacb7ac8bef87ef2f44cfaf4daeeea960a465f100a66 + dd9bdfd09e45ed97ef658960af7f39a52264beca7e + - 00010ecd34d2b1944d408d34b4ad8edb45047b5e412aa254c9f3dcbfa4a40 + 82b9cdb085cb06952044c7655b412ab7d484c97b97c48c79c568140b8d49a02 + ca47a9cf5bcae9c2bff21fcb91cc8bc0f1d5c31697946de8eb005be5e10f1da + 70fdfab068b315b225423613928c321f409697ab52d9a457740c834b8aa3837 + ac86351633e96ede8dc655c86dbec920d6a8795201 + - 0001c4b6fd80945b9615ca88ba33ad4bf39d6063857c2e70fa091a30f0e96 + e7ac983085cb06952044c7655b412ab7d484c97b97c48c79c568140b8d49a02 + ca47a9cf5bcae9c2bff21fcb91cc8bc0f1d5c31697946de8eb005be5e10f1da + 70fdfab06efaa503383aed6feeca1e51820d3deb38cf24c6d0586ca34f852e6 + 8ee8b7f31065eaa1de7a00ee43c03020c575f68fe4 + +// Test vector 5: +skS: f5c71d296e046ede287571dfd75114dbfe524e7257f4a005fc4d0ebcc33b +c0069affef99bb2ae601874718ca59de179a +pkS: 03eab8190ec64355abf0696539c0b86f68e50fb5dc73f4199d5a7952bf1c +a58186fa4b0dd56368856e21c58df744317d02 +token_challenge: 0001000e6973737565722e6578616d706c65205de58a52fc +daef25ca3f65448d04e040fb1924e8264acfccfc6c5ad451d582b30000 +nonces: + - 2a83f6f1d72773dadf94974ebca27d64f5a7f469f96104d82e755369ddc2f + 2e4 + - e76c335f6acb4691d2ba332ba7a40f3819039555779ea66de6f6c739358c2 + 772 + - a66b3ce5aeb75777a5178ac561b276240ce58406d6290a26e98786ec0e2ba + 5b7 +blinds: + - 4315e207308e508b5b9981f035e77e46c9d45b2f1c0bc45f0d892ef75e105 + b15df7c8813d4044cc61c8ec0463c2641c1 + - 461636f21f7822dacf01631562f4d16df31f6acd0a670d2e3b6506a0e25e3 + 8dfd75d335db5d2868eaed9bd060c4036eb + - 7b8a01654e0f8ad818e3a4e510c8dd5b5a115a0f2f03f1089d90512ffec2e + bdac9a285c26ac598f17783feacd0eab8d0 +token_request: 000161409303ed7c83c83e9576e6b8ad80339466f05bfd0de9 +09670841a16a3abce1bd382deb05ce0e41680c0ccafae9467902d2bad8028b488 +4dd62baea1659b53049236f64745d086521a53259619b66ac62b1e7e64e54ea80 +3133023c66dc1f3103903cdb520221998caf5f95b9f1c87887672795b05278b2e +9c4828c532ca31668c80e6835a4de3fa09431d3e076826172ab0a232888 +token_response: 409302429ae37954a49247504c79a77c040f05fcb1825c2e5 +cb25419319211ce1832ee4341f06cc2d44b1580e1e98040ed225402dd2bc61660 +84134a140109edce72ef74f87b14e6a0bf14a81809bb9e7aa9754d254a224c3a3 +aed22b5c2ff234a2035dd03b9afc0b48adfdd8d9600995c95b5bd8c468d546a09 +2c4ff6b3198a0b77b137b52a4655ddd1555a9f19ffe90a8c9fa152e617ca3fbc2 +52157c274292026367de0cf81f2e9ec31a00e47d6e12503a2845eecc26196530e +cdd9c6f22d873e83513deba2f131f0c2ee39cf1f19c390cbf3245ee5f96b8e9b6 +cc2ad704914fcb5775c2823c07c11df3467d0fe8791631a2ec9 +tokens: + - 00012a83f6f1d72773dadf94974ebca27d64f5a7f469f96104d82e755369d + dc2f2e4d4380df12a1727f4e2ca1ee0d7abea0d0fb1e9506507a4dd618f9b87 + e79f9f35ee87b759084d891eb599846514ff6b778f8360e8a1db74e2d05aa8c + 088f8036107c24ae81dc5b6228f81345601d20e83c48c12e35c429469430d4d + 5785f72e1a215438c2b380df6bf53c284a1f928d15 + - 0001e76c335f6acb4691d2ba332ba7a40f3819039555779ea66de6f6c7393 + 58c2772d4380df12a1727f4e2ca1ee0d7abea0d0fb1e9506507a4dd618f9b87 + e79f9f35ee87b759084d891eb599846514ff6b778f8360e8a1db74e2d05aa8c + 088f803615c8326b73f2c12f07d98a97f4371905e74a3940b8eead7a2e6fc9f + f3f90c7b24bf938910ca4fb1680b78178bc83845e9 + - 0001a66b3ce5aeb75777a5178ac561b276240ce58406d6290a26e98786ec0 + e2ba5b7d4380df12a1727f4e2ca1ee0d7abea0d0fb1e9506507a4dd618f9b87 + e79f9f35ee87b759084d891eb599846514ff6b778f8360e8a1db74e2d05aa8c + 088f803618619eaaee20d918ecb4b35f879b0ba9791fcfda086e25366a0848b + dc8940b2ded244b1be025afa8c5403299196cf883f + +// Test vector 6: +skS: 2795bea1931d9eb18ea8f341f9136d06825bf87900aadd5cba32f7e7501e +7e05fd867ed88b7148676c4f747fd455012f +pkS: 03b1144afa40414bafc6d27a46ee314ecd183641c631b6d406b5d0311e7b +6a64e9dc561223f38913a5fd299ee437275439 +token_challenge: 0001000b497373756572204e616d65000005612c622c63 +nonces: + - ba1832b01f112d463d35f3df65780a8af5186f5a036b4273f488020e6bcda + 4d7 + - 2feb86d353b8af5e75e8533b1c17cd4c18c387fbe485a044a32a3164deb30 + 6df + - d9d7d698370bf231c1b81766a750e285a6b860069d826a9d2367f28a79c57 + 21a + - 733225c695c68f2524e364dd63d35bf5db28ac5c3cebf7bffdfc60dd76ed1 + 22e + - 2ca686cc3150f70093c492bccef6b40b34fb273be2ddd4faeaa51f14b1d1c + 3ef +blinds: + - 1845b65b595a9f07d737fcf1c9737489c1641bdcc889b9d6262a8f2d977c4 + b5e98ee502fe6e44e606c7bcaf4a2f74b04 + - 123ce70d4ba8c0a3280381dc507f59c8e986e7bc3e71e1adecbbe5f800b93 + 72901e651b3e9df66879d47af4d324b49b8 + - 729ce122eada4cae8a9dae5b026daabaebf9a9c2f93cc74b4efabf6c1cce8 + 8b593dbe07c1196c2e2c5f83f3f5a11c999 + - 5fe96b7399afb7fc5dfce3911fc586add59838a4130bd1bc9a39da4d3f0f6 + 1b2f778bb4b6de05f1e2fafda0d3de48670 + - f815705a65ed835081cf6cec6e72b110e4135bf559eba7cbd8757d90c7dcd + dc573d75bdc8ad86cf61cc1ae6b6883028c +token_request: 0001e340f502290ec59ab9063137d3342c5618748059bbec22 +84f4e841a925fea9cfaff565634592e7fa066d0f4d355a4aa2d5b305f10246d9e +28f9ec550954b22492bbdd21652da7c6ae64a8638757ffb48ba9fcdc46d5e44bf +2cef90dd20c7c1cfbb203e05d003c2db7deb628339c677c9f8a39ed7cae085028 +4025025ca590ac60d9fa7e5a27d6eda67fd0b8c9ec79dafe3bac404839502a1a5 +ac19a2cd95121c602bd54184e7c8012199f05cbfa1af96d077130a25dc4edb0e5 +5204611e76e2de7815a32f415ab03b7907caefc6d3acba400884ac5763eb022da +05c134ab19186b4b5b51f41e8b0e8966047c482c50235cf01c5fd435ccf1 +token_response: 40f5037fe5401091c1ec2fa44643227c2026195162e07f794 +92b0f19c13cc2fffbd8e1755f76614fb9bd1ff9c0467d9334d81b0285aed2f5c7 +0a29dbee0c7081dae4ba76b75204b414a70e66e2d17cf7c0a108930182b88222f +0b1ec1435b10dfb11a780037439fed66b56b8ecb393e1b2293cbd4a86ac141e04 +7f1ad891f28c3f062f339c18318feb889c09c7ee84129bd88aad3e021098e2388 +03cba587204424f89efe83513d8a66ed7f9c488d8ee1b17baf80a5a6e1b3cdcca +07ae98ada345c28ca01f8103f74cf72200f0aa7d630232587c20c4c70f6bfd963 +6681919777699e63ecc85e8965333341f58cded92b46f30e9033d4e8c055f54ff +fd89089d8a979fb398b0e3d6de160b0d61bd83759057e642b77abef3b7be4ea42 +4236c1a6d804f1974b1ec194bdfdc78458e252f8a3b08fbe2b18cb3c355b328a0 +1d16cceb9485474854c006a5fab32e1a63cb98c739d761be2e7e +tokens: + - 0001ba1832b01f112d463d35f3df65780a8af5186f5a036b4273f488020e6 + bcda4d74d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977 + cd3bd3967ac8049affe0727785606abba401320f4da956669c1fd8c3a6b544f + f9831bde3cbb14b733c723655c93ad2e6c8d8d9a560665360486f1699b4cc1a + 2671334875e76f816a151f532607ee64f55793a6a5 + - 00012feb86d353b8af5e75e8533b1c17cd4c18c387fbe485a044a32a3164d + eb306df4d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977 + cd3bd3967ac8049affe0727785606abba401320f4da956669c1fd8c3a6b544f + f9831bde3e77d754efb404a1d034b4b6b1a8fc1520e8105f2cc4dd13465bc11 + 7b57ee2d256b69362407164d66cd4ffb91b46624e9 + - 0001d9d7d698370bf231c1b81766a750e285a6b860069d826a9d2367f28a7 + 9c5721a4d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977 + cd3bd3967ac8049affe0727785606abba401320f4da956669c1fd8c3a6b544f + f9831bde372afc55fb181d380ca3cb818466408427fffbc89094d2dcf282353 + f3f64a8cda8bfdc7918585a15683d3b40905f2f720 + - 0001733225c695c68f2524e364dd63d35bf5db28ac5c3cebf7bffdfc60dd7 + 6ed122e4d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977 + cd3bd3967ac8049affe0727785606abba401320f4da956669c1fd8c3a6b544f + f9831bde3054b234a476ad24ccc82fc8be0515b3be455fa831b849cdcfef243 + 1c02880a27b6d7599fe93d7985db25262f3f0d5e3f + - 00012ca686cc3150f70093c492bccef6b40b34fb273be2ddd4faeaa51f14b + 1d1c3ef4d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977 + cd3bd3967ac8049affe0727785606abba401320f4da956669c1fd8c3a6b544f + f9831bde3c9488481ad751c6e0e124d5b3da0f7386806e5beaed1fd31cf6e9a + 4954f0708e1c3a724d40077edb0f4a12975d35819c + +// Test vector 7: +skS: 00b22fc44750a0be95910b42350cf889428b29822137ae7c947dbbce1211 +2252955eaa044c2d1bf04d7828a2c1a607f3 +pkS: 03fe7d3412c17f4d9c95fd4b6664f980903de4ee3e33e4349cf6be53eb0f +e5168aa9ba53388646cbbcf9742d63ec6d3ec3 +token_challenge: 0001000b497373756572204e616d6520eb86d4628882f211 +a5a9901ef73bfc808681f803935eb278cc6741b67346d6520005612c622c63 +nonces: + - 777a3fd1afcc8fe4e2b69bad782aec122f7517530d5ffa813d2322b12165b + 0dd + - 7248c86afc2560aac6ae6725026f5dc2c7177c3d1bd9fb90eca9537b8f47f + 352 + - 85f92c1d25208e349270deb3ebab68eb479befdab76a847943e80c98a6480 + 2cf + - 09dd90d14e95a707be4b4b0ac91f11eb2ae87573000996a824e7b53fd7f8e + b49 + - 7e7a5d87ae34c8f754baed42aff353ce54121441f6673e173324116e24d45 + d07 +blinds: + - 0c413fc7b0ba7a07786863406b814afe49f98bef60dd6f4d94a322b5fc3b5 + fff0a67e147f427947b8c2d69d7a1a98d72 + - 781478668ad9c06716addf134d89d8c5b67a7402db8c35c52cf62858519e6 + fa95232efd8f2202277263450bd68105db7 + - 70be1eb3a8a03053d713f735b4f2981f8bf5bc0726e1014848af1942f25c0 + f6ec6a4138f6be7d44d093c2cade22951df + - efb1173321ecc93ccc6a3292f532de3f8229d463dbac9a72ec9960335328f + 088faa7413c8f6f8df6000fcd842a024556 + - ead8b0b7e50cb3e138d49b8f7fd382b9c570b35fbf5afd7ce2441eac797d6 + 0c9911da2f964b231d5473d5629adc50932 +token_request: 00014140f5022fa0eae8e4413e1285554348c51a910b685703 +f535260e024efce29ddbd2b6afb661bb46d723ab0047db99b228716908037ac9a +b495355f8aca5e300c6c8c429a5d6ad7596df529e87ee7873ff67b5bdd5ecee31 +b6a22ee0588bd03148247876bf0361222090acd961ee4c7d0928b4dfadfc95075 +1ba8129cde0367665719f1da0a576323152954d6cdb49598a9f620a6e3903dfb4 +2521831994cffac87a588e1ffedbf5c5bd617034bddfc3677efa5d95ec9b4dbcb +91c26ca23b8c03ed431a1bac9e402a71d2ddf43f161b225b8e4f16dafe7fd2b90 +4882e61336a3e461a02595ae602ff2007251a9b3b592a458c75ea5a0b769 +token_response: 40f50243a2a7461641ab15ffb51a55d98bca33b28c75fba03 +f42cadcf4f8d4599b1cb26dd1cd284b03e4d52f9c509d72ccc9a70371df152264 +77fb1cf1a78b93db07b5f7c336ead3133c7fc72919dbe6249e7ce522911e68814 +766ae3255040caa62c5250358fecbda72a5a77a56ab674e6d76b55f2b4c5b9033 +a6f70cb4e56607ca0082d0d5ae82bd96985cd89c81e2acae628672027a50d7bc2 +99756a65bcf708ba92b5d6e9eae44b76ac54344fdbc7e3b3ac7d202f046d96cef +39c168645132aa31c669fc029ff3e9245c5158c7d2f87450ebd0d743996438aa8 +2205501aa0c1f56d071ff5c3f2e98b09a738ab4f8f216dc3716ae7aa6d1f249f8 +65a2f0b36b52b8f58a66ea985fcb9dcfcaaf3bc92c1ec5d97ed4d6d1c88bb909a +f64317c2885d140619c959dc6b2b58d8bd6e09fd1b8bba638bf142e282c1ae6ed +134338cfea2cdfdf1f3265db8203875218b979883cca8216e394 +tokens: + - 0001777a3fd1afcc8fe4e2b69bad782aec122f7517530d5ffa813d2322b12 + 165b0dd35889a45e95bbc66bb8b042482644693997d94cbc50853af61b34275 + 6828e81bd5cc36b0ae0c64bba34c5e560ffa2176a4a39fbf8fc57e2befddd20 + d8718e341f7dbfa4a5e5e603dc415eacf0389643f48abf09808fe83ee82ca08 + 2ac89c5857ce0b9043aa0ff3382e053a0a6401746c + - 00017248c86afc2560aac6ae6725026f5dc2c7177c3d1bd9fb90eca9537b8 + f47f35235889a45e95bbc66bb8b042482644693997d94cbc50853af61b34275 + 6828e81bd5cc36b0ae0c64bba34c5e560ffa2176a4a39fbf8fc57e2befddd20 + d8718e3415c5326a9a877916183bf8f04652d9df41e717eb4c4673030d4bd88 + bfa3ef0df371cdb2f50ec1a0f994f11bb324b355b2 + - 000185f92c1d25208e349270deb3ebab68eb479befdab76a847943e80c98a + 64802cf35889a45e95bbc66bb8b042482644693997d94cbc50853af61b34275 + 6828e81bd5cc36b0ae0c64bba34c5e560ffa2176a4a39fbf8fc57e2befddd20 + d8718e3412965c9aa4d87dc58d91bf7ad2fc0b182d12e1019bbfc5c0875b763 + e2e4a1cebfc903f6c4d9c1e120ca62c0a1d409c1ce + - 000109dd90d14e95a707be4b4b0ac91f11eb2ae87573000996a824e7b53fd + 7f8eb4935889a45e95bbc66bb8b042482644693997d94cbc50853af61b34275 + 6828e81bd5cc36b0ae0c64bba34c5e560ffa2176a4a39fbf8fc57e2befddd20 + d8718e341a0e9642df13a86061747d852d1725508895a4f0c2e7b07057897fa + d4ca45ecbe6b4b0b7169edd2c6ad33e8cc4041e721 + - 00017e7a5d87ae34c8f754baed42aff353ce54121441f6673e173324116e2 + 4d45d0735889a45e95bbc66bb8b042482644693997d94cbc50853af61b34275 + 6828e81bd5cc36b0ae0c64bba34c5e560ffa2176a4a39fbf8fc57e2befddd20 + d8718e341e49e1e468df8ebca7f2851a89b377c529b7857145d4c300228c9be + 2f9ba0ff9c97247bdad2a62d8b39daafa8ec7b914d + +// Test vector 8: +skS: fe9dccf471b18e752daf169864b11d36d52774540d30ea3cfc956a9fa2ac +356b15e3ca04357276f9f27575aa2264f0e2 +pkS: 03ebbe14213fba10b5961b2ce6005c865ef27d8a10606886e5240fd5793d +57f1c1d6136d20a20411d667180119dacca915 +token_challenge: 0001000b497373756572204e616d652077c9f82ad689b6fa +eb0bf5e3b7bd72c220beeedf1ef15093facfa9685f3c88950005612c622c63 +nonces: + - dea96b6ebfdbe8b3f228023159e3589e7cffe39fd79be31baebc3dd86fc2b + f1f + - df8231412e3f6e568886adfdb0bc270c417260de1f15aea9c20e81d0ad79c + 0c6 + - f9ac7d920db5da9430095b97030bdef8d60c387122a9a239d488fbb9b2331 + 536 + - 3caadeac6c38966e745e6c09b6d143fd8361463256de25d54cb056d5df305 + ed6 + - bc9a18f5d8188ed973fa11c346b985437aa3cb8e9cf2395a81a08804c8183 + e09 +blinds: + - 261310108a900b80dac58206d0131b639d15ff3f44bef4aea760f286f4aff + fc804366c86e9d5c655310f3c5a4504dbba + - edeb73cc4d10cd8e53f344c1d9f0d5713ca917a17ab2ced91289c74f6848a + bbe782b560879d8c1aab1d3a07ed0f59e9f + - 7675f2b9d18285f0c70f7f3c345e55cf10bf81acbfeaaca984314af421331 + 4a6ac324f8db66d8ed541afc797827394cd + - 7f562368a21814fa3c9c062910cc74128315787af90ab4a74d7bd8750a069 + e1c83edff770f86cf518e28b34a75ccb243 + - d007777c470c5ce0fb2123466ac3139576be4e320e2a61bea4231c793af94 + 3281f84439f135536a8923d5aca4b40d0b6 +token_request: 0001e840f503de448f06485e806c46357acc187d1d935886d2 +3061dd2bbefc18bb3abada39029d976a60b6afd7e03037736ff18efef20308fa7 +0011010abac2ac2c2d014fbfa5d786a5954808c42e35038de42d9de3851653d78 +558273ce2fbde0c67948f06719020e9828ffa3a98380b902a85b1e1c94816a8dd +e721e66ce9c7f75fc36b5c035de03e61e6d8c6778dd6569f8ad7c6ff7bc0325dc +e1625d45cd0b6a82005cd217aef1352072efe56f73f69508296f3acf62e174c78 +0f691b706af621b64be94ca38080334a147c42ff0dd7388ddaf981e5f5006eed7 +500fd222331def8dadba1e50175294823ccd0c6b73256b57dc6520f01cf3 +token_response: 40f5037e24738ba84969dce153f7e87fe66b3e48409ac4c3c +1d88d99cb0c624a9a98b707e9e00990ea57916c5bec20e588434a0266311282d5 +f269edb2fc082f34f25f680f091517cc0bfbd7bc0bfa9125a2d74f6081f2ae4e6 +43e8917edc19454d049db038faa3c1093f701db56b2f1f14c422a127de6929b28 +e39ecfd3d8a1d632c9aed8b1728fa820f41f47bef2233a228f5bab0209909285b +d479fe86c4c027417d826dfdb7636a969a849ddacda503c24de82b90897e7229b +517fd3f0393ba9e19abb82023e1d5e41a056587748ef896704dcaa7695e80605f +aafb609b80788fd9899925736b581e6e4837a28725471ae677fd621c8ece95de3 +f1d98fac39823ac2921ec52c7b05cb5d30ab33e0cbcae377fe40c528e23ae8853 +0d852d4928775d8c1f1def572087592ef6176d5790ab8adbe0523328a8e092568 +2347e6ca8fa502bcca05e8ece1ff86f1b50c102de347d08792dd +tokens: + - 0001dea96b6ebfdbe8b3f228023159e3589e7cffe39fd79be31baebc3dd86 + fc2bf1f743229db4189b04ef5f90ecd3cf54a2476aab8c026a1f5af81b7d542 + 5bc512318924fee28549cdf14f42cf3441cf39759c04f6e6a162a7c61898315 + 85de491e892d9133664d98050e02dce92a157306e5d9eeb3a84bbb74d40b05d + cb3ec286a32d247012198daf729a17f2f76210f4da + - 0001df8231412e3f6e568886adfdb0bc270c417260de1f15aea9c20e81d0a + d79c0c6743229db4189b04ef5f90ecd3cf54a2476aab8c026a1f5af81b7d542 + 5bc512318924fee28549cdf14f42cf3441cf39759c04f6e6a162a7c61898315 + 85de491e8596e9a710d28167de1aaa8e9bba5ccaba514ca7774a890496441e5 + fbc50ffbc8187c2b9015ae728800d190c48496cd38 + - 0001f9ac7d920db5da9430095b97030bdef8d60c387122a9a239d488fbb9b + 2331536743229db4189b04ef5f90ecd3cf54a2476aab8c026a1f5af81b7d542 + 5bc512318924fee28549cdf14f42cf3441cf39759c04f6e6a162a7c61898315 + 85de491e8a431c43cab90b664077608e2b34a06ac56c1827a2f6f78b7736848 + 0e4517744e8a3e10a690a1b173b745540e68fc4f5d + - 00013caadeac6c38966e745e6c09b6d143fd8361463256de25d54cb056d5d + f305ed6743229db4189b04ef5f90ecd3cf54a2476aab8c026a1f5af81b7d542 + 5bc512318924fee28549cdf14f42cf3441cf39759c04f6e6a162a7c61898315 + 85de491e86ebcab5874aa2a52b7dc764addcfd76839718a13a048fcb8c2abd2 + 2c3a7b90fc3f48e38ae21072b01a415af65b36a2b8 + - 0001bc9a18f5d8188ed973fa11c346b985437aa3cb8e9cf2395a81a08804c + 8183e09743229db4189b04ef5f90ecd3cf54a2476aab8c026a1f5af81b7d542 + 5bc512318924fee28549cdf14f42cf3441cf39759c04f6e6a162a7c61898315 + 85de491e8e7f0f3a47d721b4a408670ffad7b27627421a6be3af7f75068196f + a26fe53a62c3693b5a1092985795f799c30ca73d72 + +// Test vector 9: +skS: fa1a7f2ccb6651e82aefef530837b518946ca8df30bfb6b629cadccea965 +50a2848b649cee5c91e3dbaf30e62fe6b407 +pkS: 037bd0654b77d1b4ae8d7a4775b04d06f2c406496ff07274f79e956e6ee8 +e6b0668457894b84dd18733017b2fbec89c3f9 +token_challenge: 0001000b497373756572204e616d65000005612c622c63 +nonces: + - 8bc16d866d0193d20b435d49f58cf869f8c3891e7e6f7bf0cce5c5e29a485 + 9fd + - 3cdf1e2db7a86eb1e75fdbfcac7fc044c29cafa3d40ddc769c0c21f4286ac + 5b9 + - 99e334d0713e797bc836545e0dd7dcdee1993436ef6889b2d615742665740 + 8fc + - 32f356152811342c0b4ab9e34ef16939bc6422bed4e73449b09065f19c057 + 364 + - 6cf58474ca44d5f86f22f44da98f15939a97645f4c60e565c2be332800ba5 + 44a +blinds: + - 85c3c875b12d4578fe905a61fa37cc3a16ee77d87f09705e684833951b692 + 993a5bb663427b8dd10915804e091fe5aa2 + - 205c94ad910c602bd3f29404d10ebb89b9148b0ff4adf065ea04f6fc5e240 + 64d86bdf7b2e00962cde1d1ab48b42b3ac5 + - 7dbf232de16945358b5ef69b2740940530b651d37708e70735dcfece2e9b2 + 18dc82d75a60f6499aa5d0df6c818407405 + - 9c3c5cf1182f26d0fca4c9c1c883ac78aa7b4dbecf560cce8d495a0952b5e + 2377384facac0ccfe30afd3cb50c132fd87 + - 83a0546a413a3dc5dab902dfcc21deb38769cf860288b6bf2971ffa93aace + 8f4ec8d024eb5962e84fa67967b53bc4201 +token_request: 00017840f503741b71eaf59345fc7f7dc8d7e2f55561ef9053 +4da58150b51b7e5e97cf7bb20d8486b252f162c5feefc4ec52b222751803fcbef +bb50a51f7c0c28a5f078bb3be47f0f14989ad8a07490ac39423e4d5bdb8e13e40 +ece67295e5fe7d9af6bcb2fe9f034feaf7cd856dbdfaf4517913ae44720e4b184 +48f4f1bee274a56a31fb62de0fe49b280d19212609b41c6ed90c4919ff403e77b +87842ed6160d1d36ad218fe35d8c6f077e8b48a978ad0373546c0fe4066fad073 +acd2ee25dd22535b2c2fc20dffe029f41b5b88625eb8cd94787bebf272ea5c756 +4ccaadeb1ada97ceda15212c2c4f8efdc00c4fe2e2ad58263a2ccc4c0ed2 +token_response: 40f502e6fad442191944d14d5c8b467b9c0c11ac06b0cdc1f +3f5a9a2d55974f2f2125e0475e83b50f13620b3a817e1795436d703e76c34d0bc +d846876ca664ccd97452104c3f7bfc035f3c7c09f0ef6a9b81c9aecb6c8bb58bf +02edca7bb21590db2bd650225cd40a928588f1511c4603616151f69661393a42c +3126ff3622187cf7916872b898c633790cf7ce42a126e4413ec593037b2bc3a2c +135098f7c69315db242693e411838ecddc1cf88d968ed8d72b5611dbbaadb4988 +f0f7c53a936ba39a68f81e028ff4bf6fd737a137adee95d2fb773cfc810251485 +9fa419c5e8866dd64d7c0544ec39793bab6384d1d129085cc8af450c8689751c3 +a15f32c0e950624831c8525614e4e7cf92645e8747d0b1a6c95648bca2d96d20e +e5b44ca44491787af6382049ee400b719035a7e3fe2dec5f9155e332fe24b5bb8 +071c2f3fd00cab8d2a1dc685f6983d043d6591fe00e2ae5a9f89 +tokens: + - 00018bc16d866d0193d20b435d49f58cf869f8c3891e7e6f7bf0cce5c5e29 + a4859fd4d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977 + cd3bd3969e07ecffb1faa3a20d061c88f1e5292fb4cebefa1311c28eb5f37d4 + 75606b278ff35f1fcf8ed7ce3aa10bc2f0f3302d20b0bbc1fa5c45be9d912d9 + 7303b9aa8aa0d28dd80d7efb86c9073211f811d93d + - 00013cdf1e2db7a86eb1e75fdbfcac7fc044c29cafa3d40ddc769c0c21f42 + 86ac5b94d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977 + cd3bd3969e07ecffb1faa3a20d061c88f1e5292fb4cebefa1311c28eb5f37d4 + 75606b27882e60cfc6e7ed2b433bdfdad3d225ed09ad3626f67025a26311608 + 0a9ce17142d8565fd9ceba77182757e6202185ca6e + - 000199e334d0713e797bc836545e0dd7dcdee1993436ef6889b2d61574266 + 57408fc4d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977 + cd3bd3969e07ecffb1faa3a20d061c88f1e5292fb4cebefa1311c28eb5f37d4 + 75606b2788d8095ab268d6715fb89370bfb3c837493039506dd1a3a8d07a63f + 065e8e7cd2e57dc3a210b24b7636c8484273eccc17 + - 000132f356152811342c0b4ab9e34ef16939bc6422bed4e73449b09065f19 + c0573644d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977 + cd3bd3969e07ecffb1faa3a20d061c88f1e5292fb4cebefa1311c28eb5f37d4 + 75606b278729e03e210cc2486c4f747b5ff67a239767e32f611f6da82a0ff36 + c2dc047e1f48fe920677c4f53c60ae1c735644ac55 + - 00016cf58474ca44d5f86f22f44da98f15939a97645f4c60e565c2be33280 + 0ba544a4d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977 + cd3bd3969e07ecffb1faa3a20d061c88f1e5292fb4cebefa1311c28eb5f37d4 + 75606b278911447f48e89e5d66c5c52e2c0af0729300e69ee6e5e39d465b836 + 41058cf4f6460bcb4672fe37de8b0efa1bcdf33c16 + +// Test vector 10: +skS: 88afd78d73efbd37b94183cc1d6fb8e3a0dfaed2ca7f715d76e44843e3c9 +36a266dc3335cf16a63ef31fb6fb4a81771a +pkS: 0363010d08ed8eb12d29e6d11059b7a02d6d665d8212ead2f19b43a96a5d +f6211b2be769f8cc87a730b814cd1013e039e6 +token_challenge: 0001000b497373756572204e616d65000005612c622c63 +nonces: + - cbb64dbf9e920048a1c5517a8a12b44a294b5ac5ccb3b366178f1031f7c46 + 56c + - 3156fffdf77f4f0dcd23406bb121d3eb18e4d0a8b7286dc7c10bfeb58305f + e97 + - ad0930ca85e54145cd8e02bc6508a0e9bc525ba9feee3c19ec3d6258e368a + 674 + - a70ecbb14478c7c5af0c5f7a9ca4dfe50c7ebc5ad0c06f1addcd3e406520a + f23 + - 7ecf841fb195b155fc443f46c504840a0270464d7e10862cf134438049c66 + f7c +blinds: + - 421c533dce493799fc44c217d2999e75f1158b256bad86e4f13dc94e0f9ac + a2dc09ec3ad286cb011d63766a0f0679c0e + - 480fbbcb53834cddabea02c0bdf2f7d7af1d9fad3f71534cf2cc92818262e + 6c25dfd39a7d69489ba1c110dd97497735d + - 819d08bbde696e245e7987b7bf5b0cd5bc5e188565a8e3191bf9f11b06462 + 6f504e1fe6d5d1c7ebe4e096cdbed79a79f + - 3341d181e8c09af12a3a653a290c5977607f85ed5e6394d1b52e0f8976808 + 1561aa46016b917d9502cc207f10e164a89 + - dcb1b2f72a5f88b4182fb431911468b4f1d1225391900c9d21c2a0ad1b795 + c7801648c4f8e3f88c488d3b6d5109bb72c +token_request: 0001af40f50201016fa016b79e0ac32a62f05e4b3c05a8a98f +2a91d3345222e7b45d464530919bdf7e13009d41dc7d80ff968a5749d702c13ce +880d0198173e4f527fb18999e9920dfb6fefbaa758723b962643bf72d09d4305f +622757fc54a7a99b718812f91403024b6117c0953f53e1c582b6847288616bc97 +34bbafc4feec7d9b6bde5c768db1cb4e7d2d3abac5e709f861d9e4a0c8b03c05c +15addd2a8a68caf2630d432ba5fd1d56e458869df8885db54d006a17897919e08 +95b5a570efcadb08b81063ebb830232404a0ef1947bc79773ce4648c35bfbd2e2 +542578fbb0fcdacd9e87c39ed33b36a27678f5746cfc4f94099ca588ee54 +token_response: 40f5032fe65c3e5244e485c42953503b950cb9d481fd559a0 +415593120b164366d51229eab2b0f9c75fc8d56b6a163ac71192b02d5a761c49c +af9c4b9a0c3019bd1f45a59b8f3d9acaee9af7d0f72e7bb47dc4da80324387a22 +1b0872321188e6410fa0e038fd7f3d7e60caa7cabdc765d8feb463a2f5c7fac60 +63119dac9feb658d7b331657156aee7794ca77e68ed6b2986a55ee02a18cdd372 +c76bc9ff8a9b6ae47324345c515e8114df9392eea70960bb2820370a71c66fae4 +8520ffc475fdbb88993f0c03005755be30a542d4c0861ae1f7ffd584355eecb8b +2f0277254a6917661ae91a708eb5cb550cce6955fa873e755fede7310d34e5552 +f3d542910c3ed98792d670df9b82731ca82b8e674ca4245f6fb89b95f114e4252 +aa1e477707cb016f39a297b2755043b34bbd1bbc32583e8b240fd0dda4c8a6764 +1992c04f6d56b46b195507b7ee05c3c67004ef9f059a864c7f52 +tokens: + - 0001cbb64dbf9e920048a1c5517a8a12b44a294b5ac5ccb3b366178f1031f + 7c4656c4d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977 + cd3bd39698517059067b3eb2bd6112ce46b67b6724ae86d1767cf8f171daeb0 + f8bb213afc44c046b33ba4f0f0d404b19bcd73e7c88a4691af2ebb660592df6 + 0d6d090abb7711a34c8c78ebd075918f792804e221 + - 00013156fffdf77f4f0dcd23406bb121d3eb18e4d0a8b7286dc7c10bfeb58 + 305fe974d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977 + cd3bd39698517059067b3eb2bd6112ce46b67b6724ae86d1767cf8f171daeb0 + f8bb213af46c306c3497f96478f6040344d4981665eeef7b8e4cf5ce14da0d1 + f98773bb5a1be37252dc7ec61f814304270640572c + - 0001ad0930ca85e54145cd8e02bc6508a0e9bc525ba9feee3c19ec3d6258e + 368a6744d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977 + cd3bd39698517059067b3eb2bd6112ce46b67b6724ae86d1767cf8f171daeb0 + f8bb213af6823c16eabf6871797ce45c17985ed3c29ff08cb61d53be4fefd4b + 81087590826e679e2cea1cfeffbfcc82993731e5d6 + - 0001a70ecbb14478c7c5af0c5f7a9ca4dfe50c7ebc5ad0c06f1addcd3e406 + 520af234d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977 + cd3bd39698517059067b3eb2bd6112ce46b67b6724ae86d1767cf8f171daeb0 + f8bb213af60e3e68ada8f217c129fa2eeef3a3c312794eac23f1fb4eb8b12ce + 672b9963443bf1c80583b4150d35b6c16871f10321 + - 00017ecf841fb195b155fc443f46c504840a0270464d7e10862cf13443804 + 9c66f7c4d1a8f1a708ab7ec6f9ddfe97074859fdf87737790491e4b3afd0977 + cd3bd39698517059067b3eb2bd6112ce46b67b6724ae86d1767cf8f171daeb0 + f8bb213afbe9b2790151db3683b3ba4865e71aa2b0e6f60c500e30995217e88 + b772caa1f5b26f94e4766872d764656e268c274ce0 \ No newline at end of file