dcrd/dcrec/edwards/threshold_test.go
2017-12-07 21:46:25 -06:00

221 lines
6.3 KiB
Go

// Copyright (c) 2015-2016 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package edwards
import (
"bytes"
"encoding/hex"
"math/big"
"math/rand"
"testing"
)
func TestSchnorrThreshold(t *testing.T) {
tRand := rand.New(rand.NewSource(543212345))
maxSignatories := 10
numTests := 5
numSignatories := maxSignatories * numTests
curve := new(TwistedEdwardsCurve)
curve.InitParam25519()
msg, _ := hex.DecodeString(
"d04b98f48e8f8bcc15c6ae5ac050801cd6dcfd428fb5f9e65c4e16e7807340fa")
privkeys := randPrivScalarKeyList(curve, numSignatories)
for i := 0; i < numTests; i++ {
numKeysForTest := tRand.Intn(maxSignatories-2) + 2
keyIndex := i * maxSignatories
keysToUse := make([]*PrivateKey, numKeysForTest)
for j := 0; j < numKeysForTest; j++ {
keysToUse[j] = privkeys[j+keyIndex]
}
pubKeysToUse := make([]*PublicKey, numKeysForTest)
for j := 0; j < numKeysForTest; j++ {
_, pubkey, _ := PrivKeyFromScalar(curve,
keysToUse[j].Serialize())
pubKeysToUse[j] = pubkey
}
// Combine pubkeys.
allPubkeys := make([]*PublicKey, numKeysForTest)
copy(allPubkeys, pubKeysToUse)
allPksSum := CombinePubkeys(curve, allPubkeys)
privNoncesToUse := make([]*PrivateKey, numKeysForTest)
pubNoncesToUse := make([]*PublicKey, numKeysForTest)
for j := 0; j < numKeysForTest; j++ {
nonce := nonceRFC6979(curve, keysToUse[j].Serialize(), msg, nil,
Sha512VersionStringRFC6979)
nonceBig := new(big.Int).SetBytes(nonce)
nonceBig.Mod(nonceBig, curve.N)
nonce = copyBytes(nonceBig.Bytes())[:]
nonce[31] &= 248
privNonce, pubNonce, err := PrivKeyFromScalar(curve,
nonce[:])
cmp := privNonce != nil
if !cmp {
t.Fatalf("expected %v, got %v", true, cmp)
}
cmp = pubNonce != nil
if !cmp {
t.Fatalf("expected %v, got %v", true, cmp)
}
if err != nil {
t.Fatalf("unexpected error %s, ", err)
}
privNoncesToUse[j] = privNonce
pubNoncesToUse[j] = pubNonce
}
partialSignatures := make([]*Signature, numKeysForTest)
// Partial signature generation.
publicNonceSum := CombinePubkeys(curve, pubNoncesToUse)
cmp := publicNonceSum != nil
if !cmp {
t.Fatalf("expected %v, got %v", true, cmp)
}
for j := range keysToUse {
r, s, err := schnorrPartialSign(curve, msg, keysToUse[j].Serialize(),
allPksSum.Serialize(), privNoncesToUse[j].Serialize(),
publicNonceSum.Serialize())
if err != nil {
t.Fatalf("unexpected error %s, ", err)
}
localSig := NewSignature(r, s)
partialSignatures[j] = localSig
}
// Combine signatures.
combinedSignature, err := SchnorrCombineSigs(curve, partialSignatures)
if err != nil {
t.Fatalf("unexpected error %s, ", err)
}
// Make sure the combined signatures are the same as the
// signatures that would be generated by simply adding
// the private keys and private nonces.
combinedPrivkeysD := new(big.Int).SetInt64(0)
for _, priv := range keysToUse {
combinedPrivkeysD = ScalarAdd(combinedPrivkeysD, priv.GetD())
combinedPrivkeysD = combinedPrivkeysD.Mod(combinedPrivkeysD, curve.N)
}
combinedNonceD := new(big.Int).SetInt64(0)
for _, priv := range privNoncesToUse {
combinedNonceD.Add(combinedNonceD, priv.GetD())
combinedNonceD.Mod(combinedNonceD, curve.N)
}
combinedPrivkey, _, err := PrivKeyFromScalar(curve,
copyBytes(combinedPrivkeysD.Bytes())[:])
if err != nil {
t.Fatalf("unexpected error %s, ", err)
}
combinedNonce, _, err := PrivKeyFromScalar(curve,
copyBytes(combinedNonceD.Bytes())[:])
if err != nil {
t.Fatalf("unexpected error %s, ", err)
}
cSigR, cSigS, err := SignFromScalar(curve, combinedPrivkey,
combinedNonce.Serialize(), msg)
sumSig := NewSignature(cSigR, cSigS)
cmp = bytes.Equal(sumSig.Serialize(), combinedSignature.Serialize())
if !cmp {
t.Fatalf("expected %v, got %v", true, cmp)
}
if err != nil {
t.Fatalf("unexpected error %s, ", err)
}
// Verify the combined signature and public keys.
ok := Verify(allPksSum, msg, combinedSignature.GetR(),
combinedSignature.GetS())
if !ok {
t.Fatalf("expected %v, got %v", true, ok)
}
// Corrupt some memory and make sure it breaks something.
corruptWhat := tRand.Intn(3)
randItem := tRand.Intn(numKeysForTest - 1)
// Corrupt private key.
if corruptWhat == 0 {
privSerCorrupt := keysToUse[randItem].Serialize()
pos := tRand.Intn(31)
bitPos := tRand.Intn(7)
privSerCorrupt[pos] ^= 1 << uint8(bitPos)
keysToUse[randItem].ecPk.D.SetBytes(privSerCorrupt)
}
// Corrupt public key.
if corruptWhat == 1 {
pubXCorrupt := BigIntToEncodedBytes(pubKeysToUse[randItem].GetX())
pos := tRand.Intn(31)
bitPos := tRand.Intn(7)
pubXCorrupt[pos] ^= 1 << uint8(bitPos)
pubKeysToUse[randItem].GetX().SetBytes(pubXCorrupt[:])
}
// Corrupt private nonce.
if corruptWhat == 2 {
privSerCorrupt := privNoncesToUse[randItem].Serialize()
pos := tRand.Intn(31)
bitPos := tRand.Intn(7)
privSerCorrupt[pos] ^= 1 << uint8(bitPos)
privNoncesToUse[randItem].ecPk.D.SetBytes(privSerCorrupt)
}
// Corrupt public nonce.
if corruptWhat == 3 {
pubXCorrupt := BigIntToEncodedBytes(pubNoncesToUse[randItem].GetX())
pos := tRand.Intn(31)
bitPos := tRand.Intn(7)
pubXCorrupt[pos] ^= 1 << uint8(bitPos)
pubNoncesToUse[randItem].GetX().SetBytes(pubXCorrupt[:])
}
for j := range keysToUse {
thisPubNonce := pubNoncesToUse[j]
localPubNonces := make([]*PublicKey, numKeysForTest-1)
itr := 0
for _, pubNonce := range pubNoncesToUse {
if bytes.Equal(thisPubNonce.Serialize(), pubNonce.Serialize()) {
continue
}
localPubNonces[itr] = pubNonce
itr++
}
publicNonceSum := CombinePubkeys(curve, localPubNonces)
sigR, sigS, _ := schnorrPartialSign(curve, msg,
keysToUse[j].Serialize(), allPksSum.Serialize(),
privNoncesToUse[j].Serialize(),
publicNonceSum.Serialize())
localSig := NewSignature(sigR, sigS)
partialSignatures[j] = localSig
}
// Combine signatures.
combinedSignature, _ = SchnorrCombineSigs(curve, partialSignatures)
// Nothing that makes it here should be valid.
if allPksSum != nil && combinedSignature != nil {
ok = Verify(allPksSum, msg, combinedSignature.GetR(),
combinedSignature.GetS())
if ok {
t.Fatalf("expected %v, got %v", false, ok)
}
}
}
}