forked from cwtch.im/tapir
Updates given Erinns Comments
This commit is contained in:
parent
ff7a32722d
commit
a19204caf4
|
@ -27,7 +27,7 @@ pipeline:
|
||||||
commands:
|
commands:
|
||||||
- ./tor -f ./torrc
|
- ./tor -f ./torrc
|
||||||
- sleep 15
|
- sleep 15
|
||||||
- go test -v cwtch.im/tapir/testing
|
- go test -race -v cwtch.im/tapir/testing
|
||||||
notify-email:
|
notify-email:
|
||||||
image: drillster/drone-email
|
image: drillster/drone-email
|
||||||
host: build.openprivacy.ca
|
host: build.openprivacy.ca
|
||||||
|
|
|
@ -6,3 +6,4 @@ coverage.out
|
||||||
/applications/tor/
|
/applications/tor/
|
||||||
*.db
|
*.db
|
||||||
/applications/tokenboard/tor/
|
/applications/tokenboard/tor/
|
||||||
|
fuzzing/
|
||||||
|
|
|
@ -63,7 +63,7 @@ func (ea *AuthApp) Init(connection tapir.Connection) {
|
||||||
challengeRemote, _ := json.Marshal(remoteAuthMessage)
|
challengeRemote, _ := json.Marshal(remoteAuthMessage)
|
||||||
challengeLocal, _ := json.Marshal(authMessage)
|
challengeLocal, _ := json.Marshal(authMessage)
|
||||||
|
|
||||||
// Define canonical labels so both sides of the
|
// Define canonical labels so both sides of the connection can generate the same key
|
||||||
var outboundAuthMessage []byte
|
var outboundAuthMessage []byte
|
||||||
var outboundHostname string
|
var outboundHostname string
|
||||||
var inboundAuthMessage []byte
|
var inboundAuthMessage []byte
|
||||||
|
|
|
@ -18,16 +18,16 @@ type TokenApplication struct {
|
||||||
const HasTokensCapability = tapir.Capability("HasTokensCapability")
|
const HasTokensCapability = tapir.Capability("HasTokensCapability")
|
||||||
|
|
||||||
// NewInstance should always return a new instantiation of the application.
|
// NewInstance should always return a new instantiation of the application.
|
||||||
func (powapp *TokenApplication) NewInstance() tapir.Application {
|
func (tokenapp *TokenApplication) NewInstance() tapir.Application {
|
||||||
app := new(TokenApplication)
|
app := new(TokenApplication)
|
||||||
app.TokenService = powapp.TokenService
|
app.TokenService = tokenapp.TokenService
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init is run when the connection is first started.
|
// Init is run when the connection is first started.
|
||||||
func (powapp *TokenApplication) Init(connection tapir.Connection) {
|
func (tokenapp *TokenApplication) Init(connection tapir.Connection) {
|
||||||
powapp.Transcript().NewProtocol("token-app")
|
tokenapp.Transcript().NewProtocol("token-app")
|
||||||
log.Debugf(powapp.Transcript().OutputTranscriptToAudit())
|
log.Debugf(tokenapp.Transcript().OutputTranscriptToAudit())
|
||||||
if connection.IsOutbound() {
|
if connection.IsOutbound() {
|
||||||
tokens, blinded := privacypass.GenerateBlindedTokenBatch(10)
|
tokens, blinded := privacypass.GenerateBlindedTokenBatch(10)
|
||||||
data, _ := json.Marshal(blinded)
|
data, _ := json.Marshal(blinded)
|
||||||
|
@ -35,21 +35,24 @@ func (powapp *TokenApplication) Init(connection tapir.Connection) {
|
||||||
var signedBatch privacypass.SignedBatchWithProof
|
var signedBatch privacypass.SignedBatchWithProof
|
||||||
err := json.Unmarshal(connection.Expect(), &signedBatch)
|
err := json.Unmarshal(connection.Expect(), &signedBatch)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
verified := privacypass.UnblindSignedTokenBatch(tokens, blinded, signedBatch.SignedTokens, powapp.TokenService.Y, signedBatch.Proof, powapp.Transcript())
|
verified := privacypass.UnblindSignedTokenBatch(tokens, blinded, signedBatch.SignedTokens, tokenapp.TokenService.Y, signedBatch.Proof, tokenapp.Transcript())
|
||||||
if verified {
|
if verified {
|
||||||
log.Debugf("Successfully obtained signed tokens")
|
log.Debugf("Successfully obtained signed tokens")
|
||||||
powapp.Tokens = tokens
|
tokenapp.Tokens = tokens
|
||||||
connection.SetCapability(HasTokensCapability)
|
connection.SetCapability(HasTokensCapability)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// This will close the connection by default and no tokens will be available.
|
||||||
|
// This usecase can be checked by the existing WaitForCapabilityOrClose() function using the HasTokensCapability
|
||||||
|
// If the connection closes without the HasTokensCapability then the error can be handled by whatever client needs it
|
||||||
log.Debugf("Failed to verify signed token batch")
|
log.Debugf("Failed to verify signed token batch")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var blinded []privacypass.BlindedToken
|
var blinded []privacypass.BlindedToken
|
||||||
err := json.Unmarshal(connection.Expect(), &blinded)
|
err := json.Unmarshal(connection.Expect(), &blinded)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
batchProof := powapp.TokenService.SignBlindedTokenBatch(blinded, powapp.Transcript())
|
batchProof := tokenapp.TokenService.SignBlindedTokenBatch(blinded, tokenapp.Transcript())
|
||||||
log.Debugf(powapp.Transcript().OutputTranscriptToAudit())
|
log.Debugf(tokenapp.Transcript().OutputTranscriptToAudit())
|
||||||
data, _ := json.Marshal(batchProof)
|
data, _ := json.Marshal(batchProof)
|
||||||
connection.Send(data)
|
connection.Send(data)
|
||||||
return
|
return
|
||||||
|
|
|
@ -60,7 +60,6 @@ func (ta *Client) Listen() {
|
||||||
|
|
||||||
var message Message
|
var message Message
|
||||||
json.Unmarshal(data, &message)
|
json.Unmarshal(data, &message)
|
||||||
log.Debugf("Received a Message: %v", message)
|
|
||||||
switch message.MessageType {
|
switch message.MessageType {
|
||||||
case postResultMessage:
|
case postResultMessage:
|
||||||
log.Debugf("Post result: %x", message.PostResult.Proof)
|
log.Debugf("Post result: %x", message.PostResult.Proof)
|
||||||
|
@ -101,7 +100,7 @@ func (ta *Client) PurchaseTokens() {
|
||||||
|
|
||||||
// Post sends a Post Request to the server
|
// Post sends a Post Request to the server
|
||||||
func (ta *Client) Post(message auditable.Message) bool {
|
func (ta *Client) Post(message auditable.Message) bool {
|
||||||
token, err := ta.paymentHandler.NextToken(message)
|
token, err := ta.paymentHandler.NextToken(message, ta.connection.Hostname())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
data, _ := json.Marshal(Message{MessageType: postRequestMessage, PostRequest: postRequest{Token: token, Message: message}})
|
data, _ := json.Marshal(Message{MessageType: postRequestMessage, PostRequest: postRequest{Token: token, Message: message}})
|
||||||
ta.connection.Send(data)
|
ta.connection.Send(data)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package tokenboard
|
package tokenboard
|
||||||
|
|
||||||
|
// NOTE: This is a sketch implementation, Not suitable for production use. The real auditable store is still being designed.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cwtch.im/tapir"
|
"cwtch.im/tapir"
|
||||||
"cwtch.im/tapir/applications"
|
"cwtch.im/tapir/applications"
|
||||||
|
@ -55,7 +57,7 @@ func (ta *Server) Listen() {
|
||||||
|
|
||||||
var message Message
|
var message Message
|
||||||
json.Unmarshal(data, &message)
|
json.Unmarshal(data, &message)
|
||||||
log.Debugf("Received a Message: %v", message)
|
|
||||||
switch message.MessageType {
|
switch message.MessageType {
|
||||||
case postRequestMessage:
|
case postRequestMessage:
|
||||||
postrequest := message.PostRequest
|
postrequest := message.PostRequest
|
||||||
|
@ -77,7 +79,7 @@ func (ta *Server) Listen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ta *Server) postMessageRequest(token privacypass.SpentToken, message auditable.Message) {
|
func (ta *Server) postMessageRequest(token privacypass.SpentToken, message auditable.Message) {
|
||||||
if err := ta.TokenService.SpendToken(token, message); err == nil {
|
if err := ta.TokenService.SpendToken(token, append(message, ta.connection.ID().Hostname()...)); err == nil {
|
||||||
log.Debugf("Token is valid")
|
log.Debugf("Token is valid")
|
||||||
signedproof := ta.AuditableStore.Add(message)
|
signedproof := ta.AuditableStore.Add(message)
|
||||||
data, _ := json.Marshal(Message{MessageType: postResultMessage, PostResult: postResult{true, signedproof}})
|
data, _ := json.Marshal(Message{MessageType: postResultMessage, PostResult: postResult{true, signedproof}})
|
||||||
|
|
|
@ -47,23 +47,24 @@ func (fph *FreePaymentHandler) MakePayment() {
|
||||||
ChainApplication(new(applications.ProofOfWorkApplication), applications.SuccessfulProofOfWorkCapability).
|
ChainApplication(new(applications.ProofOfWorkApplication), applications.SuccessfulProofOfWorkCapability).
|
||||||
ChainApplication(tokenApplication, applications.HasTokensCapability)
|
ChainApplication(tokenApplication, applications.HasTokensCapability)
|
||||||
client.Connect(fph.ServerHostname, powTokenApp)
|
client.Connect(fph.ServerHostname, powTokenApp)
|
||||||
conn,err := client.WaitForCapabilityOrClose(fph.ServerHostname, applications.HasTokensCapability)
|
conn, err := client.WaitForCapabilityOrClose(fph.ServerHostname, applications.HasTokensCapability)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
powtapp, _ := conn.App().(*applications.TokenApplication)
|
powtapp, _ := conn.App().(*applications.TokenApplication)
|
||||||
fph.tokens = append(fph.tokens, powtapp.Tokens...)
|
fph.tokens = append(fph.tokens, powtapp.Tokens...)
|
||||||
log.Debugf("Transcript: %v", powtapp.Transcript().OutputTranscriptToAudit())
|
log.Debugf("Transcript: %v", powtapp.Transcript().OutputTranscriptToAudit())
|
||||||
conn.Close()
|
conn.Close()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
log.Debugf("Error making payment: %v", err)
|
log.Debugf("Error making payment: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fph *FreePaymentHandler) NextToken(data []byte) (privacypass.SpentToken, error) {
|
func (fph *FreePaymentHandler) NextToken(data []byte, hostname string) (privacypass.SpentToken, error) {
|
||||||
if len(fph.tokens) == 0 {
|
if len(fph.tokens) == 0 {
|
||||||
return privacypass.SpentToken{}, errors.New("No more tokens")
|
return privacypass.SpentToken{}, errors.New("No more tokens")
|
||||||
}
|
}
|
||||||
token := fph.tokens[0]
|
token := fph.tokens[0]
|
||||||
fph.tokens = fph.tokens[1:]
|
fph.tokens = fph.tokens[1:]
|
||||||
return token.SpendToken(data), nil
|
return token.SpendToken(append(data, hostname...)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTokenBoardApp(t *testing.T) {
|
func TestTokenBoardApp(t *testing.T) {
|
||||||
|
@ -96,7 +97,7 @@ func TestTokenBoardApp(t *testing.T) {
|
||||||
sg := new(sync.WaitGroup)
|
sg := new(sync.WaitGroup)
|
||||||
sg.Add(1)
|
sg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
service.Listen(NewTokenBoardServer(&tokenService, serverAuditableStore))
|
service.Listen(NewTokenBoardServer(tokenService, serverAuditableStore))
|
||||||
sg.Done()
|
sg.Done()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -108,7 +109,7 @@ func TestTokenBoardApp(t *testing.T) {
|
||||||
sg.Add(1)
|
sg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
tokenApplication := new(applications.TokenApplication)
|
tokenApplication := new(applications.TokenApplication)
|
||||||
tokenApplication.TokenService = &tokenService
|
tokenApplication.TokenService = tokenService
|
||||||
powTokenApp := new(applications.ApplicationChain).
|
powTokenApp := new(applications.ApplicationChain).
|
||||||
ChainApplication(new(applications.ProofOfWorkApplication), applications.SuccessfulProofOfWorkCapability).
|
ChainApplication(new(applications.ProofOfWorkApplication), applications.SuccessfulProofOfWorkCapability).
|
||||||
ChainApplication(tokenApplication, applications.HasTokensCapability)
|
ChainApplication(tokenApplication, applications.HasTokensCapability)
|
||||||
|
@ -121,7 +122,7 @@ func TestTokenBoardApp(t *testing.T) {
|
||||||
var client tapir.Service
|
var client tapir.Service
|
||||||
client = new(tor.BaseOnionService)
|
client = new(tor.BaseOnionService)
|
||||||
client.Init(acn, sk, &id)
|
client.Init(acn, sk, &id)
|
||||||
client.Connect(sid.Hostname(), NewTokenBoardClient(clientAuditableStore, Handler{Store: clientAuditableStore}, &FreePaymentHandler{ACN: acn, TokenService: &tokenService, ServerHostname: spowid.Hostname()}))
|
client.Connect(sid.Hostname(), NewTokenBoardClient(clientAuditableStore, Handler{Store: clientAuditableStore}, &FreePaymentHandler{ACN: acn, TokenService: tokenService, ServerHostname: spowid.Hostname()}))
|
||||||
client.WaitForCapabilityOrClose(sid.Hostname(), applications.AuthCapability)
|
client.WaitForCapabilityOrClose(sid.Hostname(), applications.AuthCapability)
|
||||||
conn, _ := client.GetConnection(sid.Hostname())
|
conn, _ := client.GetConnection(sid.Hostname())
|
||||||
tba, _ := conn.App().(*Client)
|
tba, _ := conn.App().(*Client)
|
||||||
|
|
|
@ -54,7 +54,6 @@ func (s *BaseOnionService) WaitForCapabilityOrClose(cid string, name tapir.Capab
|
||||||
func (s *BaseOnionService) GetConnection(hostname string) (tapir.Connection, error) {
|
func (s *BaseOnionService) GetConnection(hostname string) (tapir.Connection, error) {
|
||||||
var conn tapir.Connection
|
var conn tapir.Connection
|
||||||
s.connections.Range(func(key, value interface{}) bool {
|
s.connections.Range(func(key, value interface{}) bool {
|
||||||
log.Debugf("Checking %v", key)
|
|
||||||
connection := value.(tapir.Connection)
|
connection := value.(tapir.Connection)
|
||||||
if connection.Hostname() == hostname {
|
if connection.Hostname() == hostname {
|
||||||
if !connection.IsClosed() {
|
if !connection.IsClosed() {
|
||||||
|
|
|
@ -53,6 +53,7 @@ func (bp *BoltPersistence) Check(bucket string, name string) (bool, error) {
|
||||||
val = b.Get([]byte(name))
|
val = b.Get([]byte(name))
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
} else if val != nil {
|
} else if val != nil {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package auditable
|
package auditable
|
||||||
|
|
||||||
|
// WARNING NOTE: This is a sketch implementation, Not suitable for production use. The real auditable store is still being designed.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cwtch.im/tapir/persistence"
|
"cwtch.im/tapir/persistence"
|
||||||
"cwtch.im/tapir/primitives"
|
"cwtch.im/tapir/primitives"
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
package primitives
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/sha256"
|
|
||||||
"math"
|
|
||||||
"math/big"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BloomFilter implements a bloom filter
|
|
||||||
type BloomFilter struct {
|
|
||||||
B []bool
|
|
||||||
lock sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init constructs a bloom filter of size m
|
|
||||||
func (bf *BloomFilter) Init(m int64) {
|
|
||||||
bf.B = make([]bool, m)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash transforms a message to a set of bit flips
|
|
||||||
func (bf *BloomFilter) Hash(msg []byte) []int {
|
|
||||||
|
|
||||||
// Not the fastest hash function ever, but cryptographic security is more important than speed.
|
|
||||||
hash1 := sha256.Sum256(append([]byte("h1"), msg...))
|
|
||||||
hash2 := sha256.Sum256(append([]byte("h2"), msg...))
|
|
||||||
hash3 := sha256.Sum256(append([]byte("h3"), msg...))
|
|
||||||
hash4 := sha256.Sum256(append([]byte("h4"), msg...))
|
|
||||||
|
|
||||||
m := int64(len(bf.B))
|
|
||||||
// Number of bytes needed to pick a position from [0,m)
|
|
||||||
B := int(math.Ceil(math.Log2(float64(m)) / 8.0))
|
|
||||||
|
|
||||||
p1 := big.NewInt(0).SetBytes(hash1[:B]).Int64()
|
|
||||||
p2 := big.NewInt(0).SetBytes(hash2[:B]).Int64()
|
|
||||||
p3 := big.NewInt(0).SetBytes(hash3[:B]).Int64()
|
|
||||||
p4 := big.NewInt(0).SetBytes(hash4[:B]).Int64()
|
|
||||||
|
|
||||||
return []int{int(p1), int(p2), int(p3), int(p4)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert updates the BloomFilter (suitable for concurrent use)
|
|
||||||
func (bf *BloomFilter) Insert(msg []byte) {
|
|
||||||
pos := bf.Hash(msg)
|
|
||||||
bf.lock.Lock()
|
|
||||||
defer bf.lock.Unlock()
|
|
||||||
bf.B[pos[0]] = true
|
|
||||||
bf.B[pos[1]] = true
|
|
||||||
bf.B[pos[2]] = true
|
|
||||||
bf.B[pos[3]] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check returns true if the messages might be in the BloomFilter
|
|
||||||
// (No false positives, possible false negatives due to the probabilistic nature of the filter)
|
|
||||||
func (bf *BloomFilter) Check(msg []byte) bool {
|
|
||||||
pos := bf.Hash(msg)
|
|
||||||
if bf.B[pos[0]] && bf.B[pos[1]] && bf.B[pos[2]] && bf.B[pos[3]] {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
package primitives
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestBloomFilter_Insert(t *testing.T) {
|
|
||||||
bf := new(BloomFilter)
|
|
||||||
bf.Init(256)
|
|
||||||
|
|
||||||
fp := 0
|
|
||||||
for i := 0; i < 256; i++ {
|
|
||||||
input := []byte("test" + strconv.Itoa(256+i))
|
|
||||||
if bf.Check(input) {
|
|
||||||
t.Log("False Positive!")
|
|
||||||
fp++
|
|
||||||
}
|
|
||||||
bf.Insert(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("Num false positives %v %v%%", fp, (float64(fp)/256.0)*100)
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,186 +0,0 @@
|
||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
ristretto "github.com/gtank/ristretto255"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ScalarVector explicit type checking
|
|
||||||
type ScalarVector []*ristretto.Scalar
|
|
||||||
|
|
||||||
// PointVector explicit type checking
|
|
||||||
type PointVector []*ristretto.Element
|
|
||||||
|
|
||||||
// GeneratorVector explicit type checking
|
|
||||||
type GeneratorVector []*ristretto.Element
|
|
||||||
|
|
||||||
// CopyVector safely copies a vector
|
|
||||||
func CopyVector(G GeneratorVector) GeneratorVector {
|
|
||||||
H := make(GeneratorVector, len(G))
|
|
||||||
for i, g := range G {
|
|
||||||
H[i] = new(ristretto.Element).Add(new(ristretto.Element).Zero(), g)
|
|
||||||
}
|
|
||||||
return H
|
|
||||||
}
|
|
||||||
|
|
||||||
// InnerProduct takes the inner product of a and b i.e. <a,b>
|
|
||||||
func InnerProduct(a, b ScalarVector) *ristretto.Scalar {
|
|
||||||
if len(a) != len(b) {
|
|
||||||
panic(fmt.Sprintf("len(a) = %v ; len(b) = %v;", len(a), len(b)))
|
|
||||||
}
|
|
||||||
|
|
||||||
result := new(ristretto.Scalar).Zero()
|
|
||||||
for i, ai := range a {
|
|
||||||
result.Add(result, new(ristretto.Scalar).Multiply(ai, b[i]))
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// MultiExp takes in a vector of scalars = {a,b,c...} and a vector of generator = {A,B,C...} and outputs
|
|
||||||
// {aA,bB,cC}
|
|
||||||
func MultiExp(a ScalarVector, G GeneratorVector) *ristretto.Element {
|
|
||||||
if len(a) > len(G) {
|
|
||||||
panic(fmt.Sprintf("len(a) = %v ; len(b) = %v;", len(a), len(G)))
|
|
||||||
}
|
|
||||||
result := new(ristretto.Element).Zero()
|
|
||||||
for i, ai := range a {
|
|
||||||
aG := new(ristretto.Element).ScalarMult(ai, G[i])
|
|
||||||
result = new(ristretto.Element).Add(result, aG)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// SafeAppend is defined for a vector of Scalars
|
|
||||||
func (a ScalarVector) SafeAppend(b *ristretto.Scalar) ScalarVector {
|
|
||||||
list := make(ScalarVector, len(a)+1)
|
|
||||||
for i := 0; i < len(a); i++ {
|
|
||||||
list[i] = a[i]
|
|
||||||
}
|
|
||||||
list[len(a)] = b
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
// Join is defined for a vector of Scalars
|
|
||||||
func (a ScalarVector) Join(b ScalarVector) ScalarVector {
|
|
||||||
list := make(ScalarVector, len(a)+len(b))
|
|
||||||
for i := 0; i < len(a); i++ {
|
|
||||||
list[i] = a[i]
|
|
||||||
}
|
|
||||||
for i := len(a); i < len(a)+len(b); i++ {
|
|
||||||
list[i] = b[i-len(a)]
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
// SafeAppend as defined for a vector of Generators
|
|
||||||
func (a GeneratorVector) SafeAppend(b *ristretto.Element) GeneratorVector {
|
|
||||||
list := make(GeneratorVector, len(a)+1)
|
|
||||||
for i := 0; i < len(a); i++ {
|
|
||||||
list[i] = a[i]
|
|
||||||
}
|
|
||||||
list[len(a)] = b
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
// Join as defined for a vector of Generators
|
|
||||||
func (a GeneratorVector) Join(b GeneratorVector) GeneratorVector {
|
|
||||||
list := make(GeneratorVector, len(a)+len(b))
|
|
||||||
for i := 0; i < len(a); i++ {
|
|
||||||
list[i] = a[i]
|
|
||||||
}
|
|
||||||
for i := len(a); i < len(a)+len(b); i++ {
|
|
||||||
list[i] = b[i-len(a)]
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
// VectorAddScalar takes in a vector v = {a,b,c..} and a scalar s and outputs {a+s,b+s,c+s....}
|
|
||||||
func VectorAddScalar(vector ScalarVector, scalar *ristretto.Scalar) ScalarVector {
|
|
||||||
result := make(ScalarVector, len(vector))
|
|
||||||
for i := range vector {
|
|
||||||
result[i] = new(ristretto.Scalar)
|
|
||||||
result[i].Add(vector[i], scalar)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// VectorNegate takes in a vector v = {a,b,c..} and a scalar s and outputs {-a,-b,-c}
|
|
||||||
func VectorNegate(vector ScalarVector) ScalarVector {
|
|
||||||
result := make(ScalarVector, len(vector))
|
|
||||||
for i := range vector {
|
|
||||||
result[i] = new(ristretto.Scalar).Negate(vector[i])
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// VectorMulScalar takes in a vector v = {a,b,c..} and a scalar s and outputs {as,bs,cs....}
|
|
||||||
func VectorMulScalar(vector ScalarVector, scalar *ristretto.Scalar) ScalarVector {
|
|
||||||
result := make(ScalarVector, len(vector))
|
|
||||||
for i := range vector {
|
|
||||||
result[i] = new(ristretto.Scalar)
|
|
||||||
result[i].Multiply(vector[i], scalar)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// EntrywiseSum takes the entry wise sum of two vectors
|
|
||||||
func EntrywiseSum(vector ScalarVector, vector2 ScalarVector) ScalarVector {
|
|
||||||
result := make(ScalarVector, len(vector))
|
|
||||||
for i, v := range vector {
|
|
||||||
result[i] = new(ristretto.Scalar)
|
|
||||||
result[i].Add(v, vector2[i])
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// EntrywiseSub takes the entry wise subtraction of two vectors
|
|
||||||
func EntrywiseSub(vector ScalarVector, vector2 ScalarVector) ScalarVector {
|
|
||||||
result := make(ScalarVector, len(vector))
|
|
||||||
for i, v := range vector {
|
|
||||||
result[i] = new(ristretto.Scalar)
|
|
||||||
result[i].Subtract(v, vector2[i])
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// EntryWiseProduct takes the entry wise product of two vectors
|
|
||||||
func EntryWiseProduct(vector ScalarVector, vector2 ScalarVector) ScalarVector {
|
|
||||||
result := make(ScalarVector, len(vector))
|
|
||||||
for i, v := range vector {
|
|
||||||
result[i] = new(ristretto.Scalar)
|
|
||||||
result[i].Multiply(v, vector2[i])
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// One returns a ristretto scalar == 1
|
|
||||||
func One() *ristretto.Scalar {
|
|
||||||
one := new(ristretto.Scalar)
|
|
||||||
one.Decode([]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
|
|
||||||
return one
|
|
||||||
}
|
|
||||||
|
|
||||||
// IdentityVector is a convenience function to generate a vector v = {1,1,1...1}
|
|
||||||
func IdentityVector(n int) ScalarVector {
|
|
||||||
result := make(ScalarVector, n)
|
|
||||||
one := new(ristretto.Scalar)
|
|
||||||
one.Decode([]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
result[i] = one
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// PowerVector creates a vector v = {1,x,x^2,x^3..x^n}
|
|
||||||
func PowerVector(x *ristretto.Scalar, n int) ScalarVector {
|
|
||||||
result := make(ScalarVector, n)
|
|
||||||
one := new(ristretto.Scalar)
|
|
||||||
one.Decode([]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
|
|
||||||
result[0] = one
|
|
||||||
result[1] = x
|
|
||||||
for i := 2; i < n; i++ {
|
|
||||||
result[i] = new(ristretto.Scalar)
|
|
||||||
result[i].Multiply(result[i-1], x)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
|
@ -14,7 +14,7 @@ type DLEQProof struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DiscreteLogEquivalenceProof constructs a valid DLEQProof for the given parameters and transcript
|
// DiscreteLogEquivalenceProof constructs a valid DLEQProof for the given parameters and transcript
|
||||||
// Given P = kX, Q = kP, Y=kX
|
// Given Y = kX & Q = kP
|
||||||
// Peggy: t := choose randomly from Zq
|
// Peggy: t := choose randomly from Zq
|
||||||
// A := tX
|
// A := tX
|
||||||
// B := tP
|
// B := tP
|
||||||
|
@ -43,12 +43,12 @@ func DiscreteLogEquivalenceProof(k *ristretto.Scalar, X *ristretto.Element, Y *r
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyDiscreteLogEquivalenceProof verifies the DLEQ for the given parameters and transcript
|
// VerifyDiscreteLogEquivalenceProof verifies the DLEQ for the given parameters and transcript
|
||||||
// Given P = kX, Q = kP, Y=kX, and Proof = (c,s)
|
// Given Y = kX & Q = kP and Proof = (c,s)
|
||||||
// Vicky: X' := sX
|
// Vicky: X' := sX
|
||||||
// Y' := cY
|
// Y' := cY
|
||||||
// P' := sP
|
// P' := sP
|
||||||
// Q' := cQ
|
// Q' := cQ
|
||||||
// A' = X'+Y' == sX + cY ?= sX + ckX == (s+ck)X == tX == A
|
// A' = X'+Y' == sX + cY ?= sG + ckG == (s+ck)X == tX == A
|
||||||
// B' = P'+Q' == sP + cQ ?= sP + ckP == (s+ck)P == tP == B
|
// B' = P'+Q' == sP + cQ ?= sP + ckP == (s+ck)P == tP == B
|
||||||
// c' := H(transcript(X,Y,P,Q,A',B'))
|
// c' := H(transcript(X,Y,P,Q,A',B'))
|
||||||
// Tests c ?= c
|
// Tests c ?= c
|
||||||
|
|
|
@ -38,7 +38,8 @@ type SpentToken struct {
|
||||||
// TokenPaymentHandler defines an interface with external payment processors
|
// TokenPaymentHandler defines an interface with external payment processors
|
||||||
type TokenPaymentHandler interface {
|
type TokenPaymentHandler interface {
|
||||||
MakePayment()
|
MakePayment()
|
||||||
NextToken(data []byte) (SpentToken, error)
|
// Next Token
|
||||||
|
NextToken(data []byte, hostname string) (SpentToken, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenBlindedToken initializes the Token
|
// GenBlindedToken initializes the Token
|
||||||
|
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"cwtch.im/tapir/persistence"
|
"cwtch.im/tapir/persistence"
|
||||||
"cwtch.im/tapir/primitives/core"
|
"cwtch.im/tapir/primitives/core"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
||||||
|
"github.com/gtank/ristretto255"
|
||||||
|
"golang.org/x/crypto/sha3"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,11 +33,40 @@ func TestToken_SpendToken(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestToken_ConstrainToToken(t *testing.T) {
|
||||||
|
server := NewTokenServer()
|
||||||
|
|
||||||
|
token := new(Token)
|
||||||
|
blindedToken := token.GenBlindedToken()
|
||||||
|
|
||||||
|
signedToken := server.SignBlindedToken(blindedToken)
|
||||||
|
token.unblindSignedToken(signedToken)
|
||||||
|
|
||||||
|
spentToken := token.SpendToken([]byte("Hello"))
|
||||||
|
|
||||||
|
if server.SpendToken(spentToken, []byte("Hello World")) == nil {
|
||||||
|
t.Errorf("Token Should be InValid")
|
||||||
|
}
|
||||||
|
|
||||||
|
token2 := new(Token)
|
||||||
|
blindedToken2 := token2.GenBlindedToken()
|
||||||
|
Ht := sha3.Sum512(token.t)
|
||||||
|
T := new(ristretto255.Element).FromUniformBytes(Ht[:])
|
||||||
|
// Constraint forces T = kW to be part of the batch proof
|
||||||
|
// And because the batch proof must prove that *all* inputs share the same key and also checks the servers public key
|
||||||
|
// We get a consistency check for almost free.
|
||||||
|
signedTokens := server.SignBlindedTokenBatchWithConstraint([]BlindedToken{blindedToken2}, *token, core.NewTranscript(""))
|
||||||
|
transcript := core.NewTranscript("")
|
||||||
|
t.Logf("Result of constaint proof %v", UnblindSignedTokenBatch([]*Token{token2}, []BlindedToken{blindedToken2, {P: T}}, append(signedTokens.SignedTokens, SignedToken{token.W}), server.Y, signedTokens.Proof, transcript))
|
||||||
|
t.Log(transcript.OutputTranscriptToAudit())
|
||||||
|
}
|
||||||
|
|
||||||
func TestGenerateBlindedTokenBatch(t *testing.T) {
|
func TestGenerateBlindedTokenBatch(t *testing.T) {
|
||||||
log.SetLevel(log.LevelDebug)
|
log.SetLevel(log.LevelDebug)
|
||||||
db := new(persistence.BoltPersistence)
|
db := new(persistence.BoltPersistence)
|
||||||
db.Open("tokens.db")
|
db.Open("tokens.db")
|
||||||
server := NewTokenServer()
|
defer db.Close()
|
||||||
|
server := NewTokenServerFromStore(db)
|
||||||
|
|
||||||
clientTranscript := core.NewTranscript("privacyPass")
|
clientTranscript := core.NewTranscript("privacyPass")
|
||||||
serverTranscript := core.NewTranscript("privacyPass")
|
serverTranscript := core.NewTranscript("privacyPass")
|
||||||
|
@ -65,5 +96,4 @@ func TestGenerateBlindedTokenBatch(t *testing.T) {
|
||||||
if verified {
|
if verified {
|
||||||
t.Errorf("Something went wrong, the proof passed with wrong transcript: %s", wrongTranscript.OutputTranscriptToAudit())
|
t.Errorf("Something went wrong, the proof passed with wrong transcript: %s", wrongTranscript.OutputTranscriptToAudit())
|
||||||
}
|
}
|
||||||
db.Close()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,29 +23,48 @@ type TokenServer struct {
|
||||||
|
|
||||||
// SignedBatchWithProof encapsulates a signed batch of blinded tokens with a batch proof for verification
|
// SignedBatchWithProof encapsulates a signed batch of blinded tokens with a batch proof for verification
|
||||||
type SignedBatchWithProof struct {
|
type SignedBatchWithProof struct {
|
||||||
SignedTokens []SignedToken
|
SignedTokens []SignedToken `json:"st"`
|
||||||
Proof DLEQProof
|
Proof DLEQProof `json:"dp"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const tokenBucket = "tokens"
|
const tokenBucket = "tokens"
|
||||||
|
const keyBucket = "keys"
|
||||||
|
|
||||||
// NewTokenServer generates a new TokenServer (used mostly for testing with ephemeral instances)
|
// NewTokenServer generates a new TokenServer (used mostly for testing with ephemeral instances)
|
||||||
func NewTokenServer() TokenServer {
|
func NewTokenServer() *TokenServer {
|
||||||
k := new(ristretto.Scalar)
|
k := new(ristretto.Scalar)
|
||||||
b := make([]byte, 64)
|
b := make([]byte, 64)
|
||||||
rand.Read(b)
|
_, err := rand.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
// unable to generate secure random numbers
|
||||||
|
panic("unable to generate secure random numbers")
|
||||||
|
}
|
||||||
k.FromUniformBytes(b)
|
k.FromUniformBytes(b)
|
||||||
return TokenServer{k, new(ristretto.Element).ScalarBaseMult(k), make(map[string]bool), nil, sync.Mutex{}}
|
return &TokenServer{k, new(ristretto.Element).ScalarBaseMult(k), make(map[string]bool), nil, sync.Mutex{}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTokenServerFromStore generates a new TokenServer backed by a persistence service.
|
// NewTokenServerFromStore generates a new TokenServer backed by a persistence service.
|
||||||
func NewTokenServerFromStore(persistenceService persistence.Service) TokenServer {
|
func NewTokenServerFromStore(persistenceService persistence.Service) *TokenServer {
|
||||||
k := new(ristretto.Scalar)
|
tokenServer := NewTokenServer()
|
||||||
b := make([]byte, 64)
|
|
||||||
rand.Read(b)
|
|
||||||
k.FromUniformBytes(b)
|
|
||||||
persistenceService.Setup([]string{tokenBucket})
|
persistenceService.Setup([]string{tokenBucket})
|
||||||
return TokenServer{k, new(ristretto.Element).ScalarBaseMult(k), make(map[string]bool), persistenceService, sync.Mutex{}}
|
persistenceService.Setup([]string{keyBucket})
|
||||||
|
exists, err := persistenceService.Check(keyBucket, "k")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
// if we don't have a stored k then save the one we have generated
|
||||||
|
// otherwise use the k we have stored
|
||||||
|
if !exists {
|
||||||
|
persistenceService.Persist(keyBucket, "k", tokenServer.k)
|
||||||
|
} else {
|
||||||
|
persistenceService.Load(keyBucket, "k", tokenServer.k)
|
||||||
|
|
||||||
|
// recalculate public key from stored k
|
||||||
|
tokenServer.Y = new(ristretto.Element).ScalarBaseMult(tokenServer.k)
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenServer.persistanceService = persistenceService
|
||||||
|
return tokenServer
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignBlindedToken calculates kP for the given BlindedToken P
|
// SignBlindedToken calculates kP for the given BlindedToken P
|
||||||
|
@ -63,6 +82,20 @@ func (ts *TokenServer) SignBlindedTokenBatch(blindedTokens []BlindedToken, trans
|
||||||
return SignedBatchWithProof{signedTokens, ts.constructBatchProof(blindedTokens, signedTokens, transcript)}
|
return SignedBatchWithProof{signedTokens, ts.constructBatchProof(blindedTokens, signedTokens, transcript)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SignBlindedTokenBatchWithConstraint signs a batch of blinded tokens under a given transcript given a contraint that the tokens must be signed
|
||||||
|
// by the same public key as an existing token
|
||||||
|
func (ts *TokenServer) SignBlindedTokenBatchWithConstraint(blindedTokens []BlindedToken, token Token, transcript *core.Transcript) SignedBatchWithProof {
|
||||||
|
var signedTokens []SignedToken
|
||||||
|
for _, bt := range blindedTokens {
|
||||||
|
signedTokens = append(signedTokens, ts.SignBlindedToken(bt))
|
||||||
|
}
|
||||||
|
Ht := sha3.Sum512(token.t)
|
||||||
|
T := new(ristretto.Element).FromUniformBytes(Ht[:])
|
||||||
|
// W == kT
|
||||||
|
blindedTokens = append(blindedTokens, BlindedToken{P: T})
|
||||||
|
return SignedBatchWithProof{signedTokens, ts.constructBatchProof(blindedTokens, append(signedTokens, SignedToken{Q: token.W}), transcript)}
|
||||||
|
}
|
||||||
|
|
||||||
// constructBatchProof construct a batch proof that all the signed tokens have been signed correctly
|
// constructBatchProof construct a batch proof that all the signed tokens have been signed correctly
|
||||||
func (ts *TokenServer) constructBatchProof(blindedTokens []BlindedToken, signedTokens []SignedToken, transcript *core.Transcript) DLEQProof {
|
func (ts *TokenServer) constructBatchProof(blindedTokens []BlindedToken, signedTokens []SignedToken, transcript *core.Transcript) DLEQProof {
|
||||||
transcript.NewProtocol(BatchProofProtocol)
|
transcript.NewProtocol(BatchProofProtocol)
|
||||||
|
@ -102,8 +135,8 @@ func (ts *TokenServer) SpendToken(token SpentToken, data []byte) error {
|
||||||
W := new(ristretto.Element).ScalarMult(ts.k, T)
|
W := new(ristretto.Element).ScalarMult(ts.k, T)
|
||||||
key := sha3.Sum256(append(token.T, W.Encode(nil)...))
|
key := sha3.Sum256(append(token.T, W.Encode(nil)...))
|
||||||
mac := hmac.New(sha3.New512, key[:])
|
mac := hmac.New(sha3.New512, key[:])
|
||||||
K := mac.Sum(data)
|
computedMAC := mac.Sum(data)
|
||||||
result := hmac.Equal(token.MAC, K)
|
result := hmac.Equal(token.MAC, computedMAC)
|
||||||
if result == true {
|
if result == true {
|
||||||
if ts.persistanceService == nil {
|
if ts.persistanceService == nil {
|
||||||
ts.seen[hex.EncodeToString(token.T)] = true
|
ts.seen[hex.EncodeToString(token.T)] = true
|
||||||
|
|
20
service.go
20
service.go
|
@ -51,6 +51,7 @@ type connection struct {
|
||||||
outbound bool
|
outbound bool
|
||||||
closed bool
|
closed bool
|
||||||
MaxLength int
|
MaxLength int
|
||||||
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConnection creates a new Connection
|
// NewConnection creates a new Connection
|
||||||
|
@ -73,17 +74,23 @@ func (c *connection) ID() *primitives.Identity {
|
||||||
|
|
||||||
// App returns the overarching application using this Connection.
|
// App returns the overarching application using this Connection.
|
||||||
func (c *connection) App() Application {
|
func (c *connection) App() Application {
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
return c.app
|
return c.app
|
||||||
}
|
}
|
||||||
|
|
||||||
// App returns the overarching application using this Connection.
|
// App returns the overarching application using this Connection.
|
||||||
func (c *connection) SetApp(application Application) {
|
func (c *connection) SetApp(application Application) {
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
c.app = application
|
c.app = application
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hostname returns the hostname of the connection (if the connection has not been authorized it will return the
|
// Hostname returns the hostname of the connection (if the connection has not been authorized it will return the
|
||||||
// temporary hostname identifier)
|
// temporary hostname identifier)
|
||||||
func (c *connection) Hostname() string {
|
func (c *connection) Hostname() string {
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
return c.hostname
|
return c.hostname
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,11 +102,15 @@ func (c *connection) IsOutbound() bool {
|
||||||
|
|
||||||
// IsClosed returns true if the connection is closed (connections cannot be reopened)
|
// IsClosed returns true if the connection is closed (connections cannot be reopened)
|
||||||
func (c *connection) IsClosed() bool {
|
func (c *connection) IsClosed() bool {
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
return c.closed
|
return c.closed
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetHostname sets the hostname on the connection
|
// SetHostname sets the hostname on the connection
|
||||||
func (c *connection) SetHostname(hostname string) {
|
func (c *connection) SetHostname(hostname string) {
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
log.Debugf("[%v -- %v] Asserting Remote Hostname: %v", c.identity.Hostname(), c.hostname, hostname)
|
log.Debugf("[%v -- %v] Asserting Remote Hostname: %v", c.identity.Hostname(), c.hostname, hostname)
|
||||||
c.hostname = hostname
|
c.hostname = hostname
|
||||||
}
|
}
|
||||||
|
@ -118,6 +129,8 @@ func (c *connection) HasCapability(name Capability) bool {
|
||||||
|
|
||||||
// Close forcibly closes the connection
|
// Close forcibly closes the connection
|
||||||
func (c *connection) Close() {
|
func (c *connection) Close() {
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
c.closed = true
|
c.closed = true
|
||||||
c.conn.Close()
|
c.conn.Close()
|
||||||
}
|
}
|
||||||
|
@ -133,7 +146,8 @@ func (c *connection) Expect() []byte {
|
||||||
c.closed = true
|
c.closed = true
|
||||||
return []byte{}
|
return []byte{}
|
||||||
}
|
}
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
if c.encrypted {
|
if c.encrypted {
|
||||||
var decryptNonce [24]byte
|
var decryptNonce [24]byte
|
||||||
copy(decryptNonce[:], buffer[:24])
|
copy(decryptNonce[:], buffer[:24])
|
||||||
|
@ -157,6 +171,8 @@ func (c *connection) Expect() []byte {
|
||||||
|
|
||||||
// SetEncryptionKey turns on application-level encryption on the connection using the given key.
|
// SetEncryptionKey turns on application-level encryption on the connection using the given key.
|
||||||
func (c *connection) SetEncryptionKey(key [32]byte) {
|
func (c *connection) SetEncryptionKey(key [32]byte) {
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
c.key = key
|
c.key = key
|
||||||
c.encrypted = true
|
c.encrypted = true
|
||||||
}
|
}
|
||||||
|
@ -168,6 +184,8 @@ func (c *connection) Send(message []byte) {
|
||||||
binary.PutUvarint(buffer[0:2], uint64(len(message)))
|
binary.PutUvarint(buffer[0:2], uint64(len(message)))
|
||||||
copy(buffer[2:], message)
|
copy(buffer[2:], message)
|
||||||
|
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
if c.encrypted {
|
if c.encrypted {
|
||||||
var nonce [24]byte
|
var nonce [24]byte
|
||||||
if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
|
if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
pwd
|
pwd
|
||||||
go test ${1} -coverprofile=applications.cover.out -v ./applications
|
go test -race ${1} -coverprofile=applications.cover.out -v ./applications
|
||||||
go test ${1} -coverprofile=applications.tokenboard.cover.out -v ./applications/tokenboard
|
go test -race ${1} -coverprofile=applications.tokenboard.cover.out -v ./applications/tokenboard
|
||||||
go test ${1} -coverprofile=primitives.cover.out -v ./primitives
|
go test -race ${1} -coverprofile=primitives.cover.out -v ./primitives
|
||||||
go test ${1} -coverprofile=primitives.auditable.cover.out -v ./primitives/auditable
|
go test -race ${1} -coverprofile=primitives.auditable.cover.out -v ./primitives/auditable
|
||||||
go test ${1} -coverprofile=primitives.core.cover.out -v ./primitives/core
|
go test -race ${1} -coverprofile=primitives.core.cover.out -v ./primitives/core
|
||||||
go test ${1} -coverprofile=primitives.privacypass.cover.out -v ./primitives/privacypass
|
go test -race ${1} -coverprofile=primitives.privacypass.cover.out -v ./primitives/privacypass
|
||||||
go test -bench "BenchmarkAuditableStore" -benchtime 1000x primitives/auditable/*.go
|
go test -bench "BenchmarkAuditableStore" -benchtime 1000x primitives/auditable/*.go
|
||||||
echo "mode: set" > coverage.out && cat *.cover.out | grep -v mode: | sort -r | \
|
echo "mode: set" > coverage.out && cat *.cover.out | grep -v mode: | sort -r | \
|
||||||
awk '{if($1 != last) {print $0;last=$1}}' >> coverage.out
|
awk '{if($1 != last) {print $0;last=$1}}' >> coverage.out
|
||||||
|
|
Loading…
Reference in New Issue