Skip to content

Commit

Permalink
Implemented new keyshare protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
David Venhoek committed Nov 27, 2020
1 parent 4346d7f commit eede1db
Show file tree
Hide file tree
Showing 14 changed files with 565 additions and 86 deletions.
20 changes: 18 additions & 2 deletions builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ func (b *CredentialBuilder) ConstructCredential(msg *IssueSignatureMessage, attr
func (b *CredentialBuilder) proveCommitment(nonce1 *big.Int) Proof {
sCommit, _ := common.RandomBigInt(b.pk.Params.LsCommit)
contrib := b.Commit(map[string]*big.Int{"secretkey": sCommit})
c := createChallenge(b.context, nonce1, contrib, false)
c := createChallenge(b.context, nonce1, contrib, nil, false)
return b.CreateProof(c)
}

Expand All @@ -210,6 +210,8 @@ type CredentialBuilder struct {

mUser map[int]*big.Int // Map of users shares of random blind attributes
mUserCommit map[int]*big.Int

newStyleKeyshareSession bool
}

func (b *CredentialBuilder) MergeProofPCommitment(commitment *ProofPCommitment) {
Expand All @@ -220,6 +222,11 @@ func (b *CredentialBuilder) MergeProofPCommitment(commitment *ProofPCommitment)
)
}

func (b *CredentialBuilder) MergeKeyshareP(keyshareP *big.Int) {
b.proofPcomm = &ProofPCommitment{P: new(big.Int).Set(keyshareP)}
b.newStyleKeyshareSession = true
}

// PublicKey returns the Idemix public key against which the credential will verify.
func (b *CredentialBuilder) PublicKey() *PublicKey {
return b.pk
Expand Down Expand Up @@ -265,8 +272,17 @@ func (b *CredentialBuilder) CreateProof(challenge *big.Int) Proof {
mUserResponses[i] = new(big.Int).Add(b.mUserCommit[i], new(big.Int).Mul(challenge, miUser))
}

var U *big.Int
if b.newStyleKeyshareSession {
U = new(big.Int).Mul(b.u, b.proofPcomm.P)
U.Mod(U, b.pk.N)
} else {
// U can be modified in the proof, so make sure this is a copy
U = new(big.Int).Set(b.u)
}

return &ProofU{
U: b.u,
U: U,
C: challenge,
VPrimeResponse: vPrimeResponse,
SResponse: sResponse,
Expand Down
6 changes: 5 additions & 1 deletion credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func (ic *Credential) CreateDisclosureProof(disclosedAttributes []int, nonrev bo
if err != nil {
return nil, err
}
challenge := ProofBuilderList{builder}.Challenge(context, nonce1, false)
challenge := ProofBuilderList{builder}.Challenge(context, nonce1, nil, false)
return builder.CreateProof(challenge).(*ProofD), nil
}

Expand Down Expand Up @@ -224,6 +224,10 @@ func (d *DisclosureProofBuilder) MergeProofPCommitment(commitment *ProofPCommitm
)
}

func (d *DisclosureProofBuilder) MergeKeyshareP(keyshareP *big.Int) {
//nop
}

// PublicKey returns the Idemix public key against which this disclosure proof will verify.
func (d *DisclosureProofBuilder) PublicKey() *PublicKey {
return d.pk
Expand Down
357 changes: 337 additions & 20 deletions gabi_test.go

Large diffs are not rendered by default.

20 changes: 14 additions & 6 deletions internal/common/hashtool.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
package common

import "crypto/sha256"
import "encoding/asn1"
import "github.com/privacybydesign/gabi/big"
import gobig "math/big"
import (
"crypto/sha256"
"encoding/asn1"

"github.com/privacybydesign/gabi/big"

gobig "math/big"
)

// hashCommit computes the sha256 hash over the asn1 representation of a slice
// of big integers and returns a positive big integer that can be represented
// with that hash.
func HashCommit(values []*big.Int, issig bool) *big.Int {
func HashCommit(values []*big.Int, issig bool, iskeyshare bool) *big.Int {
// The first element is the number of elements
var tmp []interface{}
offset := 0
if issig {
tmp = make([]interface{}, len(values)+2)
tmp[0] = true
offset++
} else if iskeyshare {
tmp = make([]interface{}, len(values)+2)
tmp[0] = false
offset++
} else {
tmp = make([]interface{}, len(values)+1)
}
Expand Down Expand Up @@ -47,7 +55,7 @@ func GetHashNumber(a *big.Int, b *big.Int, index int, bitlen uint) *big.Int {
k := uint(0)
res := big.NewInt(0)
for k < bitlen {
cur := HashCommit(tmp, false)
cur := HashCommit(tmp, false, false)
cur.Lsh(cur, uint(k))
res.Add(res, cur)
k += 256
Expand Down
13 changes: 8 additions & 5 deletions internal/common/hashtool_test.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package common

import "testing"
import "github.com/privacybydesign/gabi/big"
import (
"testing"

"github.com/privacybydesign/gabi/big"
)

func TestHashCommit(t *testing.T) {
listA := []*big.Int{
big.NewInt(1),
big.NewInt(2),
big.NewInt(3),
}
hashA := HashCommit(listA, false)
hashA := HashCommit(listA, false, false)
if hashA == nil {
t.Error("Failed to generate hash for A")
return
Expand All @@ -20,7 +23,7 @@ func TestHashCommit(t *testing.T) {
nil,
big.NewInt(3),
}
hashB := HashCommit(listB, false)
hashB := HashCommit(listB, false, false)
if hashB == nil {
t.Error("Failed to generate hash for B")
return
Expand All @@ -30,7 +33,7 @@ func TestHashCommit(t *testing.T) {
big.NewInt(1),
big.NewInt(2),
}
hashC := HashCommit(listC, false)
hashC := HashCommit(listC, false, false)
if hashC == nil {
t.Error("Failed to generate hash for C")
return
Expand Down
2 changes: 1 addition & 1 deletion issuer.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func (i *Issuer) proveSignature(signature *CLSignature, nonce2 *big.Int) *ProofS
eCommit := randomElementMultiplicativeGroup(groupModulus)
ACommit := new(big.Int).Exp(Q, eCommit, i.Pk.N)

c := common.HashCommit([]*big.Int{i.Context, Q, signature.A, nonce2, ACommit}, false)
c := common.HashCommit([]*big.Int{i.Context, Q, signature.A, nonce2, ACommit}, false, false)
eResponse := new(big.Int).Mul(c, d)
eResponse.Sub(eCommit, eResponse).Mod(eResponse, groupModulus)

Expand Down
4 changes: 2 additions & 2 deletions keyproof/quasisafeprimeproduct_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func TestQuasiSafePrimeProductFullCycle(t *testing.T) {
const p = 13451
const q = 13901
listBefore, commit := quasiSafePrimeProductBuildCommitments([]*big.Int{}, big.NewInt(p), big.NewInt(q))
challengeBefore := common.HashCommit(listBefore, false)
challengeBefore := common.HashCommit(listBefore, false, false)
proofBefore := quasiSafePrimeProductBuildProof(big.NewInt(p), big.NewInt(q), challengeBefore, commit)
proofJSON, err := json.Marshal(proofBefore)
require.NoError(t, err, "error during json marshal")
Expand All @@ -38,7 +38,7 @@ func TestQuasiSafePrimeProductFullCycle(t *testing.T) {
err = json.Unmarshal(proofJSON, &proofAfter)
require.NoError(t, err, "error during json unmarshal")
listAfter := quasiSafePrimeProductExtractCommitments([]*big.Int{}, proofAfter)
challengeAfter := common.HashCommit(listAfter, false)
challengeAfter := common.HashCommit(listAfter, false, false)
ok := quasiSafePrimeProductVerifyProof(big.NewInt((2*p+1)*(2*q+1)), challengeAfter, proofAfter)
assert.True(t, ok, "JSON proof rejected")
}
Expand Down
4 changes: 2 additions & 2 deletions keyproof/validkeyproof.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func (s *ValidKeyProofStructure) BuildProof(Pprime *big.Int, Qprime *big.Int) Va

Follower.StepStart("Generating proof", 0)
// Calculate challenge
challenge := common.HashCommit(list, false)
challenge := common.HashCommit(list, false, false)

// Calculate proofs
proof := ValidKeyProof{
Expand Down Expand Up @@ -232,7 +232,7 @@ func (s *ValidKeyProofStructure) VerifyProof(proof ValidKeyProof) bool {
Follower.StepStart("Verifying proof", 0)

// Check challenge
if proof.Challenge.Cmp(common.HashCommit(list, false)) != 0 {
if proof.Challenge.Cmp(common.HashCommit(list, false, false)) != 0 {
return false
}

Expand Down
1 change: 1 addition & 0 deletions keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ type PublicKey struct {
EpochLength EpochLength `xml:"Features"`
Params *SystemParameters `xml:"-"`
Issuer string `xml:"-"`
KeyID string `xml:"-"` // Used during new keyshare protocol
ECDSA string `xml:",omitempty"`

revocationKey *revocation.PublicKey
Expand Down
72 changes: 58 additions & 14 deletions keyshare.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"

"github.com/privacybydesign/gabi/big"
"github.com/privacybydesign/gabi/internal/common"
)

var (
Expand All @@ -18,8 +19,16 @@ func NewKeyshareSecret() (*big.Int, error) {
return big.RandInt(rand.Reader, new(big.Int).Lsh(big.NewInt(1), DefaultSystemParameters[1024].Lm-1))
}

// Generate commitments for the keyshare server for given set of keys
func NewKeyshareCommitments(secret *big.Int, keys []*PublicKey) (*big.Int, []*ProofPCommitment, error) {
// Generate keyshare parts of P for given set of keys
func KeysharePs(secret *big.Int, keys []*PublicKey) map[string]*big.Int {
Ps := make(map[string]*big.Int)
for _, key := range keys {
Ps[key.KeyID] = new(big.Int).Exp(key.R[0], secret, key.N)
}
return Ps
}

func NewKeyshareCommitments(keys []*PublicKey) (*big.Int, map[string]*big.Int, error) {
// Determine required randomizer length
var lRand uint = 0
for _, key := range keys {
Expand All @@ -37,23 +46,58 @@ func NewKeyshareCommitments(secret *big.Int, keys []*PublicKey) (*big.Int, []*Pr
}

// And exponentiate it with all keys
var exponentiatedCommitments []*ProofPCommitment
Ws := make(map[string]*big.Int)
for _, key := range keys {
exponentiatedCommitments = append(exponentiatedCommitments,
&ProofPCommitment{
P: new(big.Int).Exp(key.R[0], secret, key.N),
Pcommit: new(big.Int).Exp(key.R[0], commit, key.N),
})
Ws[key.KeyID] = new(big.Int).Exp(key.R[0], commit, key.N)
}

return commit, exponentiatedCommitments, nil
return commit, Ws, nil
}

// Generate keyshare response for a given challenge and commit, given a secret
func KeyshareResponse(secret, commit, challenge *big.Int, key *PublicKey) *ProofP {
// Generate commitments for the keyshare server for given set of keys
func NewProofPCommitments(secret *big.Int, keys []*PublicKey) (*big.Int, []*ProofPCommitment, error) {
Ps := KeysharePs(secret, keys)
commit, Ws, err := NewKeyshareCommitments(keys)

if err != nil {
return nil, nil, err
}

// Merge Ps and Ws
ppCommitments := make([]*ProofPCommitment, len(keys))
for i, key := range keys {
ppCommitments[i] = &ProofPCommitment{
P: Ps[key.KeyID],
Pcommit: Ws[key.KeyID],
}
}

return commit, ppCommitments, nil
}

// Generate keyshare response for a givven challenge and commit, given a secret
func KeyshareResponse(userS, secret, commit, challenge *big.Int) *KeyshareContribution {
return &KeyshareContribution{
S: new(big.Int).Add(userS, new(big.Int).Add(commit, new(big.Int).Mul(challenge, secret))),
C: new(big.Int).Set(challenge),
}
}

// Generate keyshare ProofP for a given challenge and commit, given a secret
func KeyshareProofP(secret, commit, challenge *big.Int, key *PublicKey) *ProofP {
P := KeysharePs(secret, []*PublicKey{key})
response := KeyshareResponse(big.NewInt(0), secret, commit, challenge)
return &ProofP{
P: new(big.Int).Exp(key.R[0], secret, key.N),
C: new(big.Int).Set(challenge),
SResponse: new(big.Int).Add(commit, new(big.Int).Mul(challenge, secret)),
P: P[key.KeyID],
C: response.C,
SResponse: response.S,
}
}

func KeyshareChallenge(userK *big.Int, Ws map[string]*big.Int) *big.Int {
Wcontrib := prepareKeyshareContributions(Ws)
hashList := make([]*big.Int, 1+len(Wcontrib))
hashList[0] = userK
copy(hashList[1:], Wcontrib)
return common.HashCommit(hashList, false, true)
}
Loading

0 comments on commit eede1db

Please sign in to comment.