diff --git a/crypto/batchverifier.go b/crypto/batchverifier.go index 65b2febeaa..cd0168ae1f 100644 --- a/crypto/batchverifier.go +++ b/crypto/batchverifier.go @@ -73,16 +73,35 @@ func ed25519_randombytes_unsafe(p unsafe.Pointer, len C.size_t) { const minBatchVerifierAlloc = 16 const useSingleVerifierDefault = true -// MakeBatchVerifier creates a BatchVerifier instance with the provided options. +// ed25519BatchVerifierFactory is the global singleton used for batch signature verification. +// By default it uses the libsodium implementation. This can be changed during initialization +// (e.g., by the config package when algod loads) to use the ed25519consensus implementation. +var ed25519BatchVerifierFactory func(hint int) BatchVerifier = makeLibsodiumBatchVerifier + +// SetEd25519BatchVerifier allows the config package to switch the implementation +// at startup based on configuration. Pass true to use ed25519consensus, false for libsodium. +func SetEd25519BatchVerifier(useEd25519Consensus bool) { + if useEd25519Consensus { + ed25519BatchVerifierFactory = makeEd25519ConsensusBatchVerifier + } else { + ed25519BatchVerifierFactory = makeLibsodiumBatchVerifier + } +} + +// MakeBatchVerifier creates a BatchVerifier instance. func MakeBatchVerifier() BatchVerifier { - return MakeBatchVerifierWithHint(minBatchVerifierAlloc) + return ed25519BatchVerifierFactory(minBatchVerifierAlloc) } -// MakeBatchVerifierWithHint creates a cgoBatchVerifier instance. This function pre-allocates -// amount of free space to enqueue signatures without expanding +// MakeBatchVerifierWithHint creates a BatchVerifier instance. This function pre-allocates +// space to enqueue signatures without expanding. func MakeBatchVerifierWithHint(hint int) BatchVerifier { + return ed25519BatchVerifierFactory(hint) +} + +func makeLibsodiumBatchVerifier(hint int) BatchVerifier { // preallocate enough storage for the expected usage. We will reallocate as needed. - if hint < minBatchVerifierAlloc { + if hint <= 0 { hint = minBatchVerifierAlloc } return &cgoBatchVerifier{ @@ -152,7 +171,7 @@ func (b *cgoBatchVerifier) VerifyWithFeedback() (failed []bool, err error) { } allValid, failed := cgoBatchVerificationImpl(messages, msgLengths, b.publicKeys, b.signatures) if allValid { - return failed, nil + return nil, nil } return failed, ErrBatchHasFailedSigs } @@ -170,7 +189,7 @@ func (b *cgoBatchVerifier) singleVerify() (failed []bool, err error) { if containsFailed { return failed, ErrBatchHasFailedSigs } - return failed, nil + return nil, nil } // cgoBatchVerificationImpl invokes the ed25519 batch verification algorithm. @@ -185,18 +204,26 @@ func cgoBatchVerificationImpl(messages []byte, msgLengths []uint64, publicKeys [ signatures2D := make([]*C.uchar, numberOfSignatures) // call the batch verifier + // Use unsafe.SliceData to safely get pointers to underlying arrays allValid := C.ed25519_batch_wrapper( - &messages2D[0], &publicKeys2D[0], &signatures2D[0], - (*C.uchar)(&messages[0]), - (*C.ulonglong)(&msgLengths[0]), - (*C.uchar)(&publicKeys[0][0]), - (*C.uchar)(&signatures[0][0]), + (**C.uchar)(unsafe.SliceData(messages2D)), + (**C.uchar)(unsafe.SliceData(publicKeys2D)), + (**C.uchar)(unsafe.SliceData(signatures2D)), + (*C.uchar)(unsafe.SliceData(messages)), + (*C.ulonglong)(unsafe.SliceData(msgLengths)), + (*C.uchar)(unsafe.SliceData(publicKeys[0][:])), + (*C.uchar)(unsafe.SliceData(signatures[0][:])), C.size_t(numberOfSignatures), - (*C.int)(&valid[0])) + (*C.int)(unsafe.SliceData(valid))) + + if allValid == 0 { // all signatures valid + return true, nil + } + // not all signatures valid, identify the failed signatures failed = make([]bool, numberOfSignatures) for i := 0; i < numberOfSignatures; i++ { failed[i] = (valid[i] == 0) } - return allValid == 0, failed + return false, failed } diff --git a/crypto/batchverifier_bench_test.go b/crypto/batchverifier_bench_test.go new file mode 100644 index 0000000000..c676a5265e --- /dev/null +++ b/crypto/batchverifier_bench_test.go @@ -0,0 +1,123 @@ +// Copyright (C) 2019-2025 Algorand, Inc. +// This file is part of go-algorand +// +// go-algorand is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// go-algorand is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with go-algorand. If not, see . + +package crypto + +import ( + cryptorand "crypto/rand" + "io" + "testing" + + "github.com/algorand/go-algorand/test/partitiontest" + "github.com/stretchr/testify/require" +) + +func randSignedMsg(t testing.TB, r io.Reader) (SignatureVerifier, Hashable, Signature) { + mlen := 100 + msg := TestingHashable{data: make([]byte, mlen)} + n, err := r.Read(msg.data) + require.NoError(t, err) + require.Equal(t, n, mlen) + var s Seed + n, err = r.Read(s[:]) + require.NoError(t, err) + require.Equal(t, 32, n) + secrets := GenerateSignatureSecrets(s) + return secrets.SignatureVerifier, msg, secrets.Sign(msg) +} + +// BenchmarkBatchVerifierImpls benchmarks different batch verification implementations +// with realistic batch sizes (100 batches of 64 signatures each) +func BenchmarkBatchVerifierImpls(b *testing.B) { + partitiontest.PartitionTest(b) + + numBatches := 100 + batchSize := 64 + msgs := make([][]Hashable, numBatches) + pks := make([][]SignatureVerifier, numBatches) + sigs := make([][]Signature, numBatches) + r := cryptorand.Reader + for i := 0; i < numBatches; i++ { + for j := 0; j < batchSize; j++ { + pk, msg, sig := randSignedMsg(b, r) + msgs[i] = append(msgs[i], msg) + pks[i] = append(pks[i], pk) + sigs[i] = append(sigs[i], sig) + } + } + + b.Log("running with", b.N, "iterations using", len(msgs), "batches of", batchSize, "signatures") + runImpl := func(b *testing.B, bv BatchVerifier, + msgs [][]Hashable, pks [][]SignatureVerifier, sigs [][]Signature) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + batchIdx := i % numBatches + for j := range msgs[batchIdx] { + bv.EnqueueSignature(pks[batchIdx][j], msgs[batchIdx][j], sigs[batchIdx][j]) + } + require.NoError(b, bv.Verify()) + } + } + + b.Run("libsodium_single", func(b *testing.B) { + bv := makeLibsodiumBatchVerifier(batchSize) + bv.(*cgoBatchVerifier).useSingle = true + runImpl(b, bv, msgs, pks, sigs) + }) + b.Run("libsodium_batch", func(b *testing.B) { + bv := makeLibsodiumBatchVerifier(batchSize) + bv.(*cgoBatchVerifier).useSingle = false + runImpl(b, bv, msgs, pks, sigs) + }) + b.Run("ed25519consensus", func(b *testing.B) { + bv := makeEd25519ConsensusBatchVerifier(batchSize) + runImpl(b, bv, msgs, pks, sigs) + }) +} + +func BenchmarkCanonicalityCheck(b *testing.B) { + partitiontest.PartitionTest(b) + + const maxN = 10000 + pubkeys := make([]SignatureVerifier, maxN) + sigs := make([]Signature, maxN) + for i := 0; i < maxN; i++ { + var s Seed + RandBytes(s[:]) + sigSecrets := GenerateSignatureSecrets(s) + pubkeys[i] = sigSecrets.SignatureVerifier + msg := randString() + sigs[i] = sigSecrets.Sign(msg) + } + + b.Run("pubkey_check", func(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = isCanonicalPoint(pubkeys[i%maxN]) + } + }) + + b.Run("signature_R_check", func(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = isCanonicalPoint([32]byte(sigs[i%maxN][:32])) + } + }) + + b.Run("both_checks", func(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = !isCanonicalPoint(pubkeys[i%maxN]) || !isCanonicalPoint([32]byte(sigs[i%maxN][:32])) + } + }) +} diff --git a/crypto/batchverifier_test.go b/crypto/batchverifier_test.go index 6f3c5954fc..ac91c19023 100644 --- a/crypto/batchverifier_test.go +++ b/crypto/batchverifier_test.go @@ -27,10 +27,42 @@ import ( "github.com/algorand/go-algorand/test/partitiontest" ) +// runnableTB is an interface constraint for types that have both testing.TB methods and Run +type runnableTB[T any] interface { + testing.TB + Run(string, func(T)) bool +} + +// runBatchVerifierImpls runs testing.{T,B}.Run against 3 batch verifier implementations as subtests. +func runBatchVerifierImpls[T runnableTB[T]](tb T, runFunc func(T, func(int) BatchVerifier)) { + tb.Run("libsodium_single", func(t T) { + runFunc(t, func(hint int) BatchVerifier { + bv := makeLibsodiumBatchVerifier(hint) + bv.(*cgoBatchVerifier).useSingle = true + return bv + }) + }) + tb.Run("libsodium_batch", func(t T) { + runFunc(t, func(hint int) BatchVerifier { + bv := makeLibsodiumBatchVerifier(hint) + bv.(*cgoBatchVerifier).useSingle = false + return bv + }) + }) + tb.Run("ed25519consensus", func(t T) { + runFunc(t, func(hint int) BatchVerifier { + return makeEd25519ConsensusBatchVerifier(hint) + }) + }) +} + func TestBatchVerifierSingle(t *testing.T) { partitiontest.PartitionTest(t) + runBatchVerifierImpls(t, testBatchVerifierSingle) +} +func testBatchVerifierSingle(t *testing.T, makeBV func(int) BatchVerifier) { // test expected success - bv := MakeBatchVerifier() + bv := makeBV(0) msg := randString() var s Seed RandBytes(s[:]) @@ -40,7 +72,7 @@ func TestBatchVerifierSingle(t *testing.T) { require.NoError(t, bv.Verify()) // test expected failure - bv = MakeBatchVerifier() + bv = makeBV(0) msg = randString() RandBytes(s[:]) sigSecrets = GenerateSignatureSecrets(s) @@ -53,9 +85,12 @@ func TestBatchVerifierSingle(t *testing.T) { func TestBatchVerifierBulk(t *testing.T) { partitiontest.PartitionTest(t) + runBatchVerifierImpls(t, testBatchVerifierBulk) +} +func testBatchVerifierBulk(t *testing.T, makeBV func(int) BatchVerifier) { for i := 1; i < 64*2+3; i++ { n := i - bv := MakeBatchVerifierWithHint(n) + bv := makeBV(n) var s Seed for i := 0; i < n; i++ { @@ -68,13 +103,15 @@ func TestBatchVerifierBulk(t *testing.T) { require.Equal(t, n, bv.GetNumberOfEnqueuedSignatures()) require.NoError(t, bv.Verify()) } - } func TestBatchVerifierBulkWithExpand(t *testing.T) { partitiontest.PartitionTest(t) + runBatchVerifierImpls(t, testBatchVerifierBulkWithExpand) +} +func testBatchVerifierBulkWithExpand(t *testing.T, makeBV func(int) BatchVerifier) { n := 64 - bv := MakeBatchVerifier() + bv := makeBV(0) // Start with no hint to test expansion var s Seed RandBytes(s[:]) @@ -89,8 +126,11 @@ func TestBatchVerifierBulkWithExpand(t *testing.T) { func TestBatchVerifierWithInvalidSiganture(t *testing.T) { partitiontest.PartitionTest(t) + runBatchVerifierImpls(t, testBatchVerifierWithInvalidSignature) +} +func testBatchVerifierWithInvalidSignature(t *testing.T, makeBV func(int) BatchVerifier) { n := 64 - bv := MakeBatchVerifier() + bv := makeBV(0) var s Seed RandBytes(s[:]) @@ -111,8 +151,11 @@ func TestBatchVerifierWithInvalidSiganture(t *testing.T) { } func BenchmarkBatchVerifier(b *testing.B) { + runBatchVerifierImpls(b, benchmarkBatchVerifier) +} +func benchmarkBatchVerifier(b *testing.B, makeBV func(int) BatchVerifier) { c := makeCurve25519Secret() - bv := MakeBatchVerifierWithHint(1) + bv := makeBV(1) for i := 0; i < b.N; i++ { str := randString() bv.EnqueueSignature(c.SignatureVerifier, str, c.Sign(str)) @@ -125,9 +168,12 @@ func BenchmarkBatchVerifier(b *testing.B) { // BenchmarkBatchVerifierBig with b.N over 1000 will report the expected performance // gain as the batchsize increases. All sigs are valid. func BenchmarkBatchVerifierBig(b *testing.B) { + runBatchVerifierImpls(b, benchmarkBatchVerifierBig) +} +func benchmarkBatchVerifierBig(b *testing.B, makeBV func(int) BatchVerifier) { c := makeCurve25519Secret() for batchSize := 1; batchSize <= 96; batchSize++ { - bv := MakeBatchVerifierWithHint(batchSize) + bv := makeBV(batchSize) for i := 0; i < batchSize; i++ { str := randString() bv.EnqueueSignature(c.SignatureVerifier, str, c.Sign(str)) @@ -149,16 +195,23 @@ func BenchmarkBatchVerifierBig(b *testing.B) { // invalid sigs to even numbered batch sizes. This shows the impact of invalid sigs on the // performance. Basically, all the gains from batching disappear. func BenchmarkBatchVerifierBigWithInvalid(b *testing.B) { + runBatchVerifierImpls(b, benchmarkBatchVerifierBigWithInvalid) +} +func benchmarkBatchVerifierBigWithInvalid(b *testing.B, makeBV func(int) BatchVerifier) { c := makeCurve25519Secret() badSig := Signature{} for batchSize := 1; batchSize <= 96; batchSize++ { - bv := MakeBatchVerifierWithHint(batchSize) + bv := makeBV(batchSize) + sigs := make([]Signature, batchSize) for i := 0; i < batchSize; i++ { str := randString() if batchSize%2 == 0 && (i == 0 || rand.Float32() < 0.1) { bv.EnqueueSignature(c.SignatureVerifier, str, badSig) + sigs[i] = badSig } else { - bv.EnqueueSignature(c.SignatureVerifier, str, c.Sign(str)) + sig := c.Sign(str) + bv.EnqueueSignature(c.SignatureVerifier, str, sig) + sigs[i] = sig } } b.Run(fmt.Sprintf("running batchsize %d", batchSize), func(b *testing.B) { @@ -170,13 +223,16 @@ func BenchmarkBatchVerifierBigWithInvalid(b *testing.B) { for x := 0; x < count; x++ { failed, err := bv.VerifyWithFeedback() if err != nil { + require.Len(b, failed, batchSize) for i, f := range failed { - if bv.(*cgoBatchVerifier).signatures[i] == badSig { + if sigs[i] == badSig { require.True(b, f) } else { require.False(b, f) } } + } else { + require.Nil(b, failed) } } }) @@ -185,22 +241,27 @@ func BenchmarkBatchVerifierBigWithInvalid(b *testing.B) { func TestEmpty(t *testing.T) { partitiontest.PartitionTest(t) - bv := MakeBatchVerifier() + runBatchVerifierImpls(t, testEmpty) +} +func testEmpty(t *testing.T, makeBV func(int) BatchVerifier) { + bv := makeBV(0) require.NoError(t, bv.Verify()) failed, err := bv.VerifyWithFeedback() require.NoError(t, err) - require.Empty(t, failed) + require.Nil(t, failed) } // TestBatchVerifierIndividualResults tests that VerifyWithFeedback // returns the correct failed signature indexes func TestBatchVerifierIndividualResults(t *testing.T) { partitiontest.PartitionTest(t) - + runBatchVerifierImpls(t, testBatchVerifierIndividualResults) +} +func testBatchVerifierIndividualResults(t *testing.T, makeBV func(int) BatchVerifier) { for i := 1; i < 64*2+3; i++ { n := i - bv := MakeBatchVerifierWithHint(n) + bv := makeBV(n) var s Seed badSigs := make([]bool, n, n) hasBadSig := false @@ -221,12 +282,13 @@ func TestBatchVerifierIndividualResults(t *testing.T) { failed, err := bv.VerifyWithFeedback() if hasBadSig { require.ErrorIs(t, err, ErrBatchHasFailedSigs) + require.Equal(t, len(badSigs), len(failed)) + for i := range badSigs { + require.Equal(t, badSigs[i], failed[i]) + } } else { require.NoError(t, err) - } - require.Equal(t, len(badSigs), len(failed)) - for i := range badSigs { - require.Equal(t, badSigs[i], failed[i]) + require.Nil(t, failed) } } } @@ -235,10 +297,12 @@ func TestBatchVerifierIndividualResults(t *testing.T) { // returns the correct failed signature indexes when all are valid func TestBatchVerifierIndividualResultsAllValid(t *testing.T) { partitiontest.PartitionTest(t) - + runBatchVerifierImpls(t, testBatchVerifierIndividualResultsAllValid) +} +func testBatchVerifierIndividualResultsAllValid(t *testing.T, makeBV func(int) BatchVerifier) { for i := 1; i < 64*2+3; i++ { n := i - bv := MakeBatchVerifierWithHint(n) + bv := makeBV(n) var s Seed for i := 0; i < n; i++ { msg := randString() @@ -250,10 +314,7 @@ func TestBatchVerifierIndividualResultsAllValid(t *testing.T) { require.Equal(t, n, bv.GetNumberOfEnqueuedSignatures()) failed, err := bv.VerifyWithFeedback() require.NoError(t, err) - require.Equal(t, bv.GetNumberOfEnqueuedSignatures(), len(failed)) - for _, f := range failed { - require.False(t, f) - } + require.Nil(t, failed) } } @@ -265,7 +326,7 @@ func TestBatchVerifierGC(t *testing.T) { t.Run("", func(t *testing.T) { t.Parallel() - bv := MakeBatchVerifierWithHint(n) + bv := makeLibsodiumBatchVerifier(n) var s Seed for i := 0; i < n; i++ { diff --git a/crypto/gobatchverifier.go b/crypto/gobatchverifier.go new file mode 100644 index 0000000000..46fcd0cae5 --- /dev/null +++ b/crypto/gobatchverifier.go @@ -0,0 +1,203 @@ +// Copyright (C) 2019-2025 Algorand, Inc. +// This file is part of go-algorand +// +// go-algorand is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// go-algorand is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with go-algorand. If not, see . + +package crypto + +import ( + "bytes" + + "github.com/hdevalence/ed25519consensus" +) + +// ed25519ConsensusVerifySingle performs single signature verification using ed25519consensus, +// with additional checks to reject non-canonical encodings and small-order public keys. +func ed25519ConsensusVerifySingle(publicKey [32]byte, message []byte, signature [64]byte) bool { + // Check for non-canonical public key or R (first 32 bytes of signature), and reject small-order public keys + if !isCanonicalPoint(publicKey) || !isCanonicalPoint([32]byte(signature[:32])) || hasSmallOrder(publicKey) { + return false + } + + return ed25519consensus.Verify(publicKey[:], message, signature[:]) +} + +type ed25519ConsensusVerifyEntry struct { + msgHashRep []byte + publicKey SignatureVerifier + signature Signature + failedChecks bool +} + +type ed25519ConsensusBatchVerifier struct { + entries []ed25519ConsensusVerifyEntry // used in VerifyWithFeedback to identify failed signatures + failedChecks bool // true if any entry failed non-canonical or small-order checks + bv ed25519consensus.BatchVerifier +} + +func makeEd25519ConsensusBatchVerifier(hint int) BatchVerifier { + if hint <= 0 { + hint = minBatchVerifierAlloc + } + return &ed25519ConsensusBatchVerifier{ + entries: make([]ed25519ConsensusVerifyEntry, 0, hint), + bv: ed25519consensus.NewPreallocatedBatchVerifier(hint), + } +} + +func (b *ed25519ConsensusBatchVerifier) EnqueueSignature(sigVerifier SignatureVerifier, message Hashable, sig Signature) { + msgHashRep := HashRep(message) + failedChecks := !isCanonicalPoint(sigVerifier) || !isCanonicalPoint([32]byte(sig[:32])) || hasSmallOrder(sigVerifier) + + entry := ed25519ConsensusVerifyEntry{ + msgHashRep: msgHashRep, + publicKey: sigVerifier, + signature: sig, + failedChecks: failedChecks, + } + b.entries = append(b.entries, entry) + + if failedChecks { + b.failedChecks = true + } else { + b.bv.Add(sigVerifier[:], msgHashRep, sig[:]) + } +} + +func (b *ed25519ConsensusBatchVerifier) GetNumberOfEnqueuedSignatures() int { + return len(b.entries) +} + +func (b *ed25519ConsensusBatchVerifier) Verify() error { + if len(b.entries) == 0 { + return nil + } + + // Fail if any pre-checks failed or if batch verification fails + if b.failedChecks || !b.bv.Verify() { + return ErrBatchHasFailedSigs + } + return nil +} + +func (b *ed25519ConsensusBatchVerifier) VerifyWithFeedback() (failed []bool, err error) { + if len(b.entries) == 0 { + return nil, nil + } + + if !b.failedChecks && b.bv.Verify() { + return nil, nil + } + + failed = make([]bool, len(b.entries)) + for i := range b.entries { + if b.entries[i].failedChecks { + failed[i] = true + } else { + failed[i] = !ed25519ConsensusVerifySingle(b.entries[i].publicKey, b.entries[i].msgHashRep, b.entries[i].signature) + } + } + + return failed, ErrBatchHasFailedSigs +} + +// Check that Y is canonical, using the succeed-fast algorithm from +// the "Taming the many EdDSAs" paper. +func isCanonicalY(p [32]byte) bool { + if p[0] < 237 { + return true + } + for i := 1; i < 31; i++ { + if p[i] != 255 { + return true + } + } + return (p[31] | 128) != 255 +} + +// isCanonicalPoint is a variable-time check that returns true if the +// 32-byte ed25519 point encoding is canonical. +func isCanonicalPoint(p [32]byte) bool { + if !isCanonicalY(p) { + return false + } + + // Test for the two cases with a non-canonical sign bit not caught by the + // non-canonical y-coordinate check above. They are points number 9 and 10 + // from Table 1 of the "Taming the many EdDSAs" paper. + if p == [32]byte{ // (−0, 1) + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + } || p == [32]byte{ // (-0, 2^255-20) + 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + } { + return false + } + + return true +} + +// from libsodium/crypto_core/ed25519/ref10/ed25519_ref10.c ge25519_has_small_order +var smallOrderPoints = [][32]byte{ + /* 0 (order 4) */ { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + /* 1 (order 1) */ { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + /* 2707385501144840649318225287225658788936804267575313519463743609750303402022 + (order 8) */{ + 0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 0x45, 0xc3, 0xf4, + 0x89, 0xf2, 0xef, 0x98, 0xf0, 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, + 0x33, 0x39, 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05}, + /* 55188659117513257062467267217118295137698188065244968500265048394206261417927 + (order 8) */{ + 0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 0xba, 0x3c, 0x0b, + 0x76, 0x0d, 0x10, 0x67, 0x0f, 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, + 0xcc, 0xc6, 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a}, + /* p-1 (order 2) */ { + 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}, + /* p (=0, order 4) */ { + 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}, + /* p+1 (=1, order 1) */ { + 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}, +} + +// hasSmallOrder checks if a point is in the small-order blacklist. +// Based on libsodium ge25519_has_small_order, but this version is variable-time. +func hasSmallOrder(p [32]byte) bool { + for _, point := range smallOrderPoints { + if !bytes.Equal(p[:31], point[:31]) { + continue + } + // For the last byte, ignore the sign bit (bit 7) + if (p[31] & 0x7f) == point[31] { + return true + } + } + return false +} diff --git a/crypto/gobatchverifier_test.go b/crypto/gobatchverifier_test.go new file mode 100644 index 0000000000..36ed799fab --- /dev/null +++ b/crypto/gobatchverifier_test.go @@ -0,0 +1,1184 @@ +// Copyright (C) 2019-2025 Algorand, Inc. +// This file is part of go-algorand +// +// go-algorand is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// go-algorand is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with go-algorand. If not, see . + +package crypto + +import ( + "bufio" + "compress/gzip" + "crypto/ed25519" + "encoding/hex" + "encoding/json" + "fmt" + "math/rand" + "os" + "regexp" + "slices" + "strconv" + "strings" + "testing" + + "github.com/algorand/go-algorand/protocol" + "github.com/algorand/go-algorand/test/partitiontest" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// ensure internal ed25519 types match the expected []byte lengths used by ed25519consensus package +func TestEd25519ConsensusBatchVerifierTypes(t *testing.T) { + partitiontest.PartitionTest(t) + + require.Len(t, ed25519PublicKey{}, ed25519.PublicKeySize) + require.Len(t, ed25519Signature{}, ed25519.SignatureSize) +} + +// Test vectors for 12 edge cases listed in Appendix C of "Taming the many EdDSAs" https://eprint.iacr.org/2020/1244 +// These are also checked in test_edge_cases in go-algorand/crypto/libsodium-fork/test/default/batch.c +func TestBatchVerifierTamingEdDSAsEdgeCases(t *testing.T) { + partitiontest.PartitionTest(t) + + hexVecs := make([]batchTestCaseHex, len(tamingEdDSAsTestVectors)) + expectedFail := make([]bool, len(tamingEdDSAsTestVectors)) + for i, tc := range tamingEdDSAsTestVectors { + hexVecs[i] = batchTestCaseHex{pkHex: tc.pk, sigHex: tc.sig, msgHex: tc.msg} + expectedFail[i] = tc.expectedFail + } + runBatchVerifierImpls(t, func(t *testing.T, makeBV func(int) BatchVerifier) { + testBatchVectors(t, makeBV, decodeHexTestCases(t, hexVecs), expectedFail) + }) +} + +// Test vectors from "It's 255:19AM" blog post about ZIP-215 development, also used to create the +// 14x14 visualizations of different criteria across implementations in Henry de Valence's blog post +// "It's 255:19AM..." https://hdevalence.ca/blog/2020-10-04-its-25519am/ +func TestBatchVerifierEd25519ConsensusTestData(t *testing.T) { + partitiontest.PartitionTest(t) + + const msgHex = "5a63617368" // used for all signatures in this test + hexVecs := make([]batchTestCaseHex, len(ed25519consensusCases)) + for i, tc := range ed25519consensusCases { + hexVecs[i] = batchTestCaseHex{pkHex: tc.pk, sigHex: tc.sig, msgHex: msgHex} + } + // All of these test vectors should fail, matching our strict criteria + expectedFail := make([]bool, len(hexVecs)) + for i := range expectedFail { + expectedFail[i] = true + } + runBatchVerifierImpls(t, func(t *testing.T, makeBV func(int) BatchVerifier) { + testBatchVectors(t, makeBV, decodeHexTestCases(t, hexVecs), expectedFail) + }) +} + +// Test vectors from unit tests for our libsodium- and ed25519-donna-based batch verification implementation +// introduced in PR #3031. +func TestBatchVerifierLibsodiumTestData(t *testing.T) { + partitiontest.PartitionTest(t) + + // read vectors hard-coded in test source file + const testVectorFile = "./libsodium-fork/test/default/batch.c" + const testVectorSize = 1025 + f, err := os.Open(testVectorFile) + if err != nil { + panic(err) + } + defer f.Close() + scanner := bufio.NewScanner(f) + + type testCase struct { + seed, pk, sig []byte + m string + } + var testCases []testCase + // each line is {{sk},{pk},{sig},"m"} where sk, pk, sig are comma-delimited lists of hex-encoded bytes + re := regexp.MustCompile(`\{\{(.*?)\},\{(.*?)\},\{(.*?)\},(.*?)\}`) + for i := 0; scanner.Scan(); i++ { + var tc testCase + line := scanner.Text() + matches := re.FindStringSubmatch(line) + if matches == nil || len(matches) != 5 { + continue + } + tc.seed = decodeCByteArray(matches[1], ed25519.SeedSize) + tc.pk = decodeCByteArray(matches[2], ed25519.PublicKeySize) + tc.sig = decodeCByteArray(matches[3], ed25519.SignatureSize) + tc.m, err = strconv.Unquote(matches[4]) + require.NoError(t, err) + testCases = append(testCases, tc) + } + t.Logf("loaded %d test vectors from %s", len(testCases), testVectorFile) + require.Len(t, testCases, testVectorSize, "not enough test vectors found") + + // check test data with libsodium-based ed25519Verify + for _, tc := range testCases { + require.True(t, ed25519Verify(ed25519PublicKey(tc.pk), []byte(tc.m), ed25519Signature(tc.sig))) + } + + // assert signing with test vector sk produces sig + for _, tc := range testCases { + pk, sk := ed25519GenerateKeySeed(ed25519Seed(tc.seed)) + require.Equal(t, tc.pk, []byte(pk[:])) + sig := ed25519Sign(sk, []byte(tc.m)) + require.Equal(t, tc.sig, []byte(sig[:])) + } + + // test different BatchVerifier implementations and batch sizes + testVectors := make([]batchTestCase, len(testCases)) + for i, tc := range testCases { + testVectors[i] = batchTestCase{pk: tc.pk, sig: tc.sig, msg: []byte(tc.m)} + } + expectedFail := make([]bool, len(testVectors)) // all should pass + runBatchVerifierImpls(t, func(t *testing.T, makeBV func(int) BatchVerifier) { + testBatchVectors(t, makeBV, testVectors, expectedFail) + }) +} + +// based on TestEd25519Vectors from go/src/crypto/ed25519/ed25519vectors_test.go +// which uses test vectors from filippo.io/mostly-harmless/ed25519vectors +func TestBatchVerifierFilippoVectors(t *testing.T) { + var vectors []struct { + A, R, S, M string + Flags []string + } + f, err := os.Open("./testdata/ed25519vectors.json.gz") + require.NoError(t, err) + defer f.Close() + rd, err := gzip.NewReader(f) + require.NoError(t, err) + defer rd.Close() + err = json.NewDecoder(rd).Decode(&vectors) + require.NoError(t, err) + + expectedFail := make([]bool, len(vectors)) + hexVecs := make([]batchTestCaseHex, len(vectors)) + for i, v := range vectors { + for _, f := range v.Flags { + switch f { + case "LowOrderA": // reject small-order A + expectedFail[i] = true + case "NonCanonicalA", "NonCanonicalR": // reject non-canonical A or R + expectedFail[i] = true + case "LowOrderR": // small-order R allowed + case "LowOrderComponentR", "LowOrderComponentA": // torsion component allowed + case "LowOrderResidue": // cofactorless batch verification + default: + require.Fail(t, "unknown flag %q in test vector %d", f, i) + } + } + hexVecs[i] = batchTestCaseHex{pkHex: v.A, sigHex: v.R + v.S, msgHex: hex.EncodeToString([]byte(v.M))} + } + runBatchVerifierImpls(t, func(t *testing.T, makeBV func(int) BatchVerifier) { + testBatchVectors(t, makeBV, decodeHexTestCases(t, hexVecs), expectedFail) + }) + + // test isCanonicalPoint and hasSmallOrder against A and R + t.Run("ARchecks", func(t *testing.T) { + for _, v := range vectors { + A, err := hex.DecodeString(v.A) + require.NoError(t, err) + require.Equal(t, !slices.Contains(v.Flags, "NonCanonicalA"), isCanonicalPoint([32]byte(A))) + require.Equal(t, slices.Contains(v.Flags, "LowOrderA"), hasSmallOrder([32]byte(A))) + + R, err := hex.DecodeString(v.R) + require.NoError(t, err) + require.Equal(t, !slices.Contains(v.Flags, "NonCanonicalR"), isCanonicalPoint([32]byte(R))) + require.Equal(t, slices.Contains(v.Flags, "LowOrderR"), hasSmallOrder([32]byte(R))) + } + }) + +} + +// testBatchVectors tests a batch of signatures with expected pass/fail results using various batch sizes +func testBatchVectors(t *testing.T, makeBV func(int) BatchVerifier, testVectors []batchTestCase, expectedFail []bool) { + require.Len(t, expectedFail, len(testVectors)) + + // run a single batch of test vectors and compare to expected failures + runBatch := func(t *testing.T, vecs []batchTestCase, expFail []bool) { + bv := makeBV(len(vecs)) + for _, tv := range vecs { + bv.EnqueueSignature(SignatureVerifier(tv.pk), noHashID(tv.msg), Signature(tv.sig)) + } + failed, err := bv.VerifyWithFeedback() + if slices.Contains(expFail, true) { // some failures expected + require.Error(t, err) + require.NotNil(t, failed) + require.Len(t, failed, len(vecs)) + for i := range expFail { + assert.Equal(t, expFail[i], failed[i]) + } + } else { // no failures expected + require.NoError(t, err) + require.Nil(t, failed) + } + } + + // run all the test vectors in a single batch + t.Run("all", func(t *testing.T) { runBatch(t, testVectors, expectedFail) }) + + // split into multiple batches of different sizes, optionally shuffled + runBatchSizes := func(shuffle bool, vecs []batchTestCase, expFail []bool) { + if shuffle { + vecs, expFail = slices.Clone(vecs), slices.Clone(expFail) + rand.Shuffle(len(vecs), func(i, j int) { + vecs[i], vecs[j], expFail[i], expFail[j] = vecs[j], vecs[i], expFail[j], expFail[i] + }) + } + + for _, batchSize := range []int{1, 2, 4, 8, 16, 32, 64, 100, 128, 256, 512, 1024} { + if batchSize > len(vecs) { + continue + } + t.Run(fmt.Sprintf("batchSize=%d", batchSize), func(t *testing.T) { + vectorBatches := splitBatches(vecs, batchSize) + failBatches := splitBatches(expFail, batchSize) + require.Equal(t, len(vectorBatches), len(failBatches)) + //t.Logf("Testing with batch size %d: %d total signatures in %d batches", batchSize, n, len(vectorBatches)) + for i, batch := range vectorBatches { + batchExpectedFail := failBatches[i] + //t.Logf("Batch %d/%d: signatures [%d-%d), size=%d", i+1, len(vectorBatches), i*batchSize, i*batchSize+len(batch), len(batch)) + runBatch(t, batch, batchExpectedFail) + } + }) + } + } + + t.Run("unshuffled", func(t *testing.T) { runBatchSizes(false, testVectors, expectedFail) }) + t.Run("shuffled", func(t *testing.T) { runBatchSizes(true, testVectors, expectedFail) }) +} + +// splitBatches splits items into batches of the specified size +func splitBatches[T any](items []T, batchSize int) [][]T { + if batchSize <= 0 { + return nil + } + numBatches := len(items) / batchSize + if len(items)%batchSize != 0 { + numBatches++ + } + batches := make([][]T, numBatches) + + for i, item := range items { + batchIdx := i / batchSize + batches[batchIdx] = append(batches[batchIdx], item) + } + + return batches +} + +// decodeCByteArray decodes a string like "0x27,0x81," into a byte array of length n +func decodeCByteArray(hexList string, n int) []byte { + bytes := make([]byte, n) + words := strings.Split(hexList, ",") + // remove trailing empty string + if words[len(words)-1] == "" { + words = words[:len(words)-1] + } else { + panic("missing trailing comma") + } + if len(words) != n { + panic("wrong number of words") + } + for i, word := range words { + _, err := fmt.Sscanf(word, "0x%02x", &bytes[i]) + if err != nil { + panic(err) + } + } + return bytes +} + +type batchTestCaseHex struct{ pkHex, sigHex, msgHex string } +type batchTestCase struct{ pk, sig, msg []byte } + +// decodeHexTestCases converts hex-encoded test cases to byte arrays +func decodeHexTestCases(t *testing.T, hexCases []batchTestCaseHex) []batchTestCase { + cases := make([]batchTestCase, len(hexCases)) + for i, hc := range hexCases { + pk, err := hex.DecodeString(hc.pkHex) + require.NoError(t, err) + require.Len(t, pk, ed25519.PublicKeySize) + + sig, err := hex.DecodeString(hc.sigHex) + require.NoError(t, err) + require.Len(t, sig, ed25519.SignatureSize) + + msg, err := hex.DecodeString(hc.msgHex) + require.NoError(t, err) + + cases[i] = batchTestCase{pk: pk, sig: sig, msg: msg} + } + return cases +} + +// noHashID implements Hashable but returns an empty protocol.HashID for use +// with the test vectors, which should not be prefixed +type noHashID []byte + +func (n noHashID) ToBeHashed() (protocol.HashID, []byte) { return "", n } + +// Test vectors from Appendix C of "Taming the many EdDSAs" https://eprint.iacr.org/2020/1244 +var tamingEdDSAsTestVectors = []struct { + desc, msg, pk, sig string + expectedFail bool // Algorand-specific criteria +}{ + {"S = 0, small-order A, small-order R", + "8c93255d71dcab10e8f379c26200f3c7bd5f09d9bc3068d3ef4edeb4853022b6", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + true}, + {"0 < S < L, small-order A, mixed-order R", + "9bd9f44f4dcc75bd531b56b2cd280b0bb38fc1cd6d1230e14861d861de092e79", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43a5bb704786be79fc476f91d3f3f89b03984d8068dcf1bb7dfc6637b45450ac04", + true}, + {"0 < S < L, mixed-order A, small-order R", + "aebf3f2601a0c8c5d39cc7d8911642f740b78168218da8471772b35f9d35b9ab", + "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa8c4bd45aecaca5b24fb97bc10ac27ac8751a7dfe1baff8b953ec9f5833ca260e", + false}, + {"0 < S < L, mixed-order A, mixed-order R", + "9bd9f44f4dcc75bd531b56b2cd280b0bb38fc1cd6d1230e14861d861de092e79", + "cdb267ce40c5cd45306fa5d2f29731459387dbf9eb933b7bd5aed9a765b88d4d", + "9046a64750444938de19f227bb80485e92b83fdb4b6506c160484c016cc1852f87909e14428a7a1d62e9f22f3d3ad7802db02eb2e688b6c52fcd6648a98bd009", + false}, + {"0 < S < L, mixed-order A, mixed-order R, SB != R + hA", + "e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec4011eaccd55b53f56c", + "cdb267ce40c5cd45306fa5d2f29731459387dbf9eb933b7bd5aed9a765b88d4d", + "160a1cb0dc9c0258cd0a7d23e94d8fa878bcb1925f2c64246b2dee1796bed5125ec6bc982a269b723e0668e540911a9a6a58921d6925e434ab10aa7940551a09", + false}, + {`0 < S < L, mixed-order A, L-order R, SB != R + hA ("#5 fails any cofactored verification that pre-reduces scalar 8h")`, + "e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec4011eaccd55b53f56c", + "cdb267ce40c5cd45306fa5d2f29731459387dbf9eb933b7bd5aed9a765b88d4d", + "21122a84e0b5fca4052f5b1235c80a537878b38f3142356b2c2384ebad4668b7e40bc836dac0f71076f9abe3a53f9c03c1ceeeddb658d0030494ace586687405", + false}, + {"S > L, L-order A, L-order R", + "85e241a07d148b41e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec40", + "442aad9f089ad9e14647b1ef9099a1ff4798d78589e66f28eca69c11f582a623", + "e96f66be976d82e60150baecff9906684aebb1ef181f67a7189ac78ea23b6c0e547f7690a0e2ddcd04d87dbc3490dc19b3b3052f7ff0538cb68afb369ba3a514", + true}, + {`S >> L, L-order A, L-order R ("#7 fails bitwise tests that S > L")`, + "85e241a07d148b41e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec40", + "442aad9f089ad9e14647b1ef9099a1ff4798d78589e66f28eca69c11f582a623", + "8ce5b96c8f26d0ab6c47958c9e68b937104cd36e13c33566acd2fe8d38aa19427e71f98a4734e74f2f13f06f97c20d58cc3f54b8bd0d272f42b695dd7e89a8c2", + true}, + {`0 < S < L, mixed-order A, small-order R ("#8-9 have non-canonical R; implementations that reduce R before hashing will accept #8 and reject #9, while those that do not will reject #8 and accept #9")`, + "9bedc267423725d473888631ebf45988bad3db83851ee85c85e241a07d148b41", + "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03be9678ac102edcd92b0210bb34d7428d12ffc5df5f37e359941266a4e35f0f", + true}, + {`0 < S < L, mixed-order A, small-order R ("#8-9 have non-canonical R; implementations that reduce R before hashing will accept #8 and reject #9, while those that do not will reject #8 and accept #9")`, + "9bedc267423725d473888631ebf45988bad3db83851ee85c85e241a07d148b41", + "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffca8c5b64cd208982aa38d4936621a4775aa233aa0505711d8fdcfdaa943d4908", + true}, + {`0 < S < L, small-order A, mixed-order R ("#10-11 have a non-canonical A; implementations that reduce A before hashing will accept #10 and reject #11, while those that do not will reject #10 and accept #11")`, + "e96b7021eb39c1a163b6da4e3093dcd3f21387da4cc4572be588fafae23c155b", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "a9d55260f765261eb9b84e106f665e00b867287a761990d7135963ee0a7d59dca5bb704786be79fc476f91d3f3f89b03984d8068dcf1bb7dfc6637b45450ac04", + true}, + {`0 < S < L, small-order A, mixed-order R ("#10-11 have a non-canonical A; implementations that reduce A before hashing will accept #10 and reject #11, while those that do not will reject #10 and accept #11")`, + "39a591f5321bbe07fd5a23dc2f39d025d74526615746727ceefd6e82ae65c06f", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "a9d55260f765261eb9b84e106f665e00b867287a761990d7135963ee0a7d59dca5bb704786be79fc476f91d3f3f89b03984d8068dcf1bb7dfc6637b45450ac04", + true}, +} + +// "It's 255:19AM" blog post test vectors, from the ed25519consensus package +var ed25519consensusCases = [196]struct{ pk, sig string }{ + { + "0100000000000000000000000000000000000000000000000000000000000000", + "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000000", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000080", + "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000080", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000080", + "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000080", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000080", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000080", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000080", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000080", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000080", + "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000080", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000080", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000080", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000080", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000080", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0000000000000000000000000000000000000000000000000000000000000000", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000080", + "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000080", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000080", + "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000080", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000080", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000080", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000080", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000080", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000080", + "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000080", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000080", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000080", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000080", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "0100000000000000000000000000000000000000000000000000000000000080", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + }, + { + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + }, +} diff --git a/crypto/libsodium-fork/src/libsodium/crypto_sign/ed25519/ref10/batch.c b/crypto/libsodium-fork/src/libsodium/crypto_sign/ed25519/ref10/batch.c index 83f93a857d..030c64592d 100644 --- a/crypto/libsodium-fork/src/libsodium/crypto_sign/ed25519/ref10/batch.c +++ b/crypto/libsodium-fork/src/libsodium/crypto_sign/ed25519/ref10/batch.c @@ -118,7 +118,7 @@ heap_get_top2(batch_heap *heap, heap_index_t *max1, heap_index_t *max2, size_t l /* */ void ge25519_multi_scalarmult_vartime_final(ge25519_p3 *r, ge25519_p3 *point, sc25519 scalar) { - const sc25519_element_t topbit = ((sc25519_element_t)1 << (SC25519_LIMB_SIZE - 1)); + const sc25519_element_t topbit = ((sc25519_element_t)1 << (SC25519_BITS_PER_LIMB - 1)); size_t limb = limb128bits; sc25519_element_t flag; ge25519_p1p1 p1p1_r; diff --git a/crypto/onetimesig.go b/crypto/onetimesig.go index df22138c23..420ae442e8 100644 --- a/crypto/onetimesig.go +++ b/crypto/onetimesig.go @@ -391,25 +391,11 @@ func (v OneTimeSignatureVerifier) Verify(id OneTimeSignatureIdentifier, message } func (v OneTimeSignatureVerifier) batchVerify(batchID OneTimeSignatureSubkeyBatchID, offsetID OneTimeSignatureSubkeyOffsetID, message Hashable, sig OneTimeSignature) bool { - // serialize encoded batchID, offsetID, message into a continuous memory buffer with the layout - // hashRep(batchID)... hashRep(offsetID)... hashRep(message)... - const estimatedSize = 256 - messageBuffer := make([]byte, 0, estimatedSize) - - messageBuffer = HashRepToBuff(batchID, messageBuffer) - batchIDLen := uint64(len(messageBuffer)) - messageBuffer = HashRepToBuff(offsetID, messageBuffer) - offsetIDLen := uint64(len(messageBuffer)) - batchIDLen - messageBuffer = HashRepToBuff(message, messageBuffer) - messageLen := uint64(len(messageBuffer)) - offsetIDLen - batchIDLen - msgLengths := []uint64{batchIDLen, offsetIDLen, messageLen} - allValid, _ := cgoBatchVerificationImpl( - messageBuffer, - msgLengths, - []PublicKey{PublicKey(v), PublicKey(batchID.SubKeyPK), PublicKey(offsetID.SubKeyPK)}, - []Signature{Signature(sig.PK2Sig), Signature(sig.PK1Sig), Signature(sig.Sig)}, - ) - return allValid + bv := MakeBatchVerifierWithHint(3) + bv.EnqueueSignature(PublicKey(v), batchID, Signature(sig.PK2Sig)) + bv.EnqueueSignature(PublicKey(batchID.SubKeyPK), offsetID, Signature(sig.PK1Sig)) + bv.EnqueueSignature(PublicKey(offsetID.SubKeyPK), message, Signature(sig.Sig)) + return bv.Verify() == nil } // DeleteBeforeFineGrained deletes ephemeral keys before (but not including) the given id. diff --git a/crypto/testdata/ed25519vectors.json.gz b/crypto/testdata/ed25519vectors.json.gz new file mode 100644 index 0000000000..52605c9690 Binary files /dev/null and b/crypto/testdata/ed25519vectors.json.gz differ diff --git a/go.mod b/go.mod index c3ccdf86d4..f50967dc09 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( github.com/google/go-querystring v1.0.0 github.com/google/uuid v1.6.0 github.com/gorilla/mux v1.8.1 + github.com/hdevalence/ed25519consensus v0.2.0 github.com/ipfs/go-log v1.0.5 github.com/ipfs/go-log/v2 v2.5.1 github.com/jmoiron/sqlx v1.2.0 @@ -63,6 +64,7 @@ require ( ) require ( + filippo.io/edwards25519 v1.0.0 // indirect github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect diff --git a/go.sum b/go.sum index 0d7b065bca..26ef319213 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= +filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -259,6 +261,8 @@ github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU= +github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= diff --git a/tools/block-generator/go.mod b/tools/block-generator/go.mod index 59961ea55a..567085d74f 100644 --- a/tools/block-generator/go.mod +++ b/tools/block-generator/go.mod @@ -18,6 +18,7 @@ require ( ) require ( + filippo.io/edwards25519 v1.0.0 // indirect github.com/DataDog/zstd v1.5.2 // indirect github.com/algorand/falcon v0.1.0 // indirect github.com/algorand/go-sumhash v0.1.0 // indirect @@ -64,6 +65,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/hdevalence/ed25519consensus v0.2.0 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/ipfs/boxo v0.24.3 // indirect diff --git a/tools/block-generator/go.sum b/tools/block-generator/go.sum index d7caa73f45..c24cb3a494 100644 --- a/tools/block-generator/go.sum +++ b/tools/block-generator/go.sum @@ -6,6 +6,8 @@ dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= +filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -236,6 +238,8 @@ github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU= +github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=