...

Source file src/github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr/signature_test.go

Documentation: github.com/decred/dcrd/dcrec/secp256k1/v4/schnorr

     1  // Copyright (c) 2015-2020 The Decred developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package schnorr
     6  
     7  import (
     8  	"bytes"
     9  	"errors"
    10  	"math/rand"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/decred/dcrd/crypto/blake256"
    15  	"github.com/decred/dcrd/dcrec/secp256k1/v4"
    16  )
    17  
    18  // TestSignatureParsing ensures that signatures are properly parsed including
    19  // error paths.
    20  func TestSignatureParsing(t *testing.T) {
    21  	tests := []struct {
    22  		name string // test description
    23  		sig  string // hex encoded signature to parse
    24  		err  error  // expected error
    25  	}{{
    26  		name: "valid signature 1",
    27  		sig: "c6ec70969d8367538c442f8e13eb20ff0c9143690f31cd3a384da54dd29ec0aa" +
    28  			"4b78a1b0d6b4186195d42a85614d3befd9f12ed26542d0dd1045f38c98b4a405",
    29  		err: nil,
    30  	}, {
    31  		name: "valid signature 2",
    32  		sig: "adc21db084fa1765f9372c2021fb298720f3d13e6d844e2dff751a2d46a69277" +
    33  			"0b989e316f7faf308a5f4a7343c0569465287cf6bff457250d6dacbb361f6e63",
    34  		err: nil,
    35  	}, {
    36  		name: "empty",
    37  		sig:  "",
    38  		err:  ErrSigTooShort,
    39  	}, {
    40  		name: "too short by one byte",
    41  		sig: "adc21db084fa1765f9372c2021fb298720f3d13e6d844e2dff751a2d46a69277" +
    42  			"0b989e316f7faf308a5f4a7343c0569465287cf6bff457250d6dacbb361f6e",
    43  		err: ErrSigTooShort,
    44  	}, {
    45  		name: "too long by one byte",
    46  		sig: "adc21db084fa1765f9372c2021fb298720f3d13e6d844e2dff751a2d46a69277" +
    47  			"0b989e316f7faf308a5f4a7343c0569465287cf6bff457250d6dacbb361f6e6300",
    48  		err: ErrSigTooLong,
    49  	}, {
    50  		name: "r == p",
    51  		sig: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f" +
    52  			"181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d09",
    53  		err: ErrSigRTooBig,
    54  	}, {
    55  		name: "r > p",
    56  		sig: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30" +
    57  			"181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d09",
    58  		err: ErrSigRTooBig,
    59  	}, {
    60  		name: "s == n",
    61  		sig: "4e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd41" +
    62  			"fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
    63  		err: ErrSigSTooBig,
    64  	}, {
    65  		name: "s > n",
    66  		sig: "4e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd41" +
    67  			"fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142",
    68  		err: ErrSigSTooBig,
    69  	}}
    70  
    71  	for _, test := range tests {
    72  		_, err := ParseSignature(hexToBytes(test.sig))
    73  		if !errors.Is(err, test.err) {
    74  			t.Errorf("%s mismatched err -- got %v, want %v", test.name, err,
    75  				test.err)
    76  			continue
    77  		}
    78  	}
    79  }
    80  
    81  // TestSchnorrSignAndVerify ensures the Schnorr signing function produces the
    82  // expected signatures for a selected set of private keys, messages, and nonces
    83  // that have been independently verified with the Sage computer algebra system.
    84  // It also ensures verifying the signature works as expected.
    85  func TestSchnorrSignAndVerify(t *testing.T) {
    86  	tests := []struct {
    87  		name     string // test description
    88  		key      string // hex encded private key
    89  		msg      string // hex encoded message to sign before hashing
    90  		hash     string // hex encoded hash of the message to sign
    91  		nonce    string // hex encoded nonce to use in the signature calculation
    92  		rfc6979  bool   // whether or not the nonce is an RFC6979 nonce
    93  		expected string // expected signature
    94  	}{{
    95  		name:    "key 0x1, blake256(0x01020304), rfc6979 nonce",
    96  		key:     "0000000000000000000000000000000000000000000000000000000000000001",
    97  		msg:     "01020304",
    98  		hash:    "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
    99  		nonce:   "d4e18f08eb87073cb2a6707def02007315f7349c3c132590a0088fefece557ef",
   100  		rfc6979: true,
   101  		expected: "4c68976afe187ff0167919ad181cb30f187e2af1c8233b2cbebbbe0fc97fff61" +
   102  			"e9ae2d0e306497236d4e328dc1a34244045745e87da69d806859348bc2a74525",
   103  	}, {
   104  		name:    "key 0x1, blake256(0x01020304), random nonce",
   105  		key:     "0000000000000000000000000000000000000000000000000000000000000001",
   106  		msg:     "01020304",
   107  		hash:    "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
   108  		nonce:   "a6df66500afeb7711d4c8e2220960855d940a5ed57260d2c98fbf6066cca283e",
   109  		rfc6979: false,
   110  		expected: "b073759a96a835b09b79e7b93c37fdbe48fb82b000c4a0e1404ba5d1fbc15d0a" +
   111  			"299d614b02dec30f8261ae43d09a224b233f3221405c9ffd3d2b00a3d2188fd4",
   112  	}, {
   113  		name:    "key 0x2, blake256(0x01020304), rfc6979 nonce",
   114  		key:     "0000000000000000000000000000000000000000000000000000000000000002",
   115  		msg:     "01020304",
   116  		hash:    "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
   117  		nonce:   "341682d3064ec802646be9c4a0fd97f8480807fcac3179e97098b8597de909dc",
   118  		rfc6979: true,
   119  		expected: "c6deb3a26c08842612bfd4411a91c90f64cfea2206c758cd1352ff2b93cc3611" +
   120  			"c9ffe5dd240f52d3ee199e29373030a5d795b674cd4da991fd07f5edefc3817d",
   121  	}, {
   122  		name:    "key 0x2, blake256(0x01020304), random nonce",
   123  		key:     "0000000000000000000000000000000000000000000000000000000000000002",
   124  		msg:     "01020304",
   125  		hash:    "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
   126  		nonce:   "679a6d36e7fe6c02d7668af86d78186e8f9ccc04371ac1c8c37939d1f5cae07a",
   127  		rfc6979: false,
   128  		expected: "4a090d82f48ca12d9e7aa24b5dcc187ee0db2920496f671d63e86036aaa7997e" +
   129  			"16d33ae10eade4db33dda17873948b4803d6eb9b10781616880a6f66ba2d1b78",
   130  	}, {
   131  		name:    "key 0x1, blake256(0x0102030405), rfc6979 nonce",
   132  		key:     "0000000000000000000000000000000000000000000000000000000000000001",
   133  		msg:     "0102030405",
   134  		hash:    "dc063eba3c8d52a159e725c1a161506f6cb6b53478ad5ef3f08d534efa871d9f",
   135  		nonce:   "cfbabebb15824ff3cfa5f4080a8608aaa9db891541851b27275c61db9d6d7e1c",
   136  		rfc6979: true,
   137  		expected: "461646005002d673c2e903f3c9ff2c2455e60810445ee486b9c36152287bc41a" +
   138  			"1b54733190ed128e466c5263a404f17344b73426d7faf00325c7a0af04be6cfe",
   139  	}, {
   140  		name:    "key 0x1, blake256(0x0102030405), random nonce",
   141  		key:     "0000000000000000000000000000000000000000000000000000000000000001",
   142  		msg:     "0102030405",
   143  		hash:    "dc063eba3c8d52a159e725c1a161506f6cb6b53478ad5ef3f08d534efa871d9f",
   144  		nonce:   "65f880c892fdb6e7f74f76b18c7c942cfd037ef9cf97c39c36e08bbc36b41616",
   145  		rfc6979: false,
   146  		expected: "72e5666f4e9d1099447b825cf737ee32112f17a67e2ca7017ae098da31dfbb8b" +
   147  			"c19f5a4f815e9737f1b635075c50b3fa28dbbbebfcb98749b9f3c7b0fa748422",
   148  	}, {
   149  		name:    "key 0x2, blake256(0x0102030405), rfc6979 nonce",
   150  		key:     "0000000000000000000000000000000000000000000000000000000000000002",
   151  		msg:     "0102030405",
   152  		hash:    "dc063eba3c8d52a159e725c1a161506f6cb6b53478ad5ef3f08d534efa871d9f",
   153  		nonce:   "f7a8f640df67ba21b619eb742a73cbfc58739153b8772d5b2f8781f33d45e554",
   154  		rfc6979: true,
   155  		expected: "f3632492a72eb8e175b93e1eb31ef382e49f3f3fe385892523beaef9171aa15d" +
   156  			"441e1a94ab9b1dafa93e0d48d08c26513d53449197e761c74bebb2fae97525c3",
   157  	}, {
   158  		name:    "key 0x2, blake256(0x0102030405), random nonce",
   159  		key:     "0000000000000000000000000000000000000000000000000000000000000002",
   160  		msg:     "0102030405",
   161  		hash:    "dc063eba3c8d52a159e725c1a161506f6cb6b53478ad5ef3f08d534efa871d9f",
   162  		nonce:   "026ece4cfb704733dd5eef7898e44c33bd5a0d749eb043f48705e40fa9e9afa0",
   163  		rfc6979: false,
   164  		expected: "3c4c5a2f217ea758113fd4e89eb756314dfad101a300f48e5bd764d3b6e0f8bf" +
   165  			"c29f43beed7d84348386152f1c43fc606d0887fa5b6f5c0b7875687f53b344f0",
   166  	}, {
   167  		name:    "random key 1, blake256(0x01), rfc6979 nonce",
   168  		key:     "a1becef2069444a9dc6331c3247e113c3ee142edda683db8643f9cb0af7cbe33",
   169  		msg:     "01",
   170  		hash:    "4a6c419a1e25c85327115c4ace586decddfe2990ed8f3d4d801871158338501d",
   171  		nonce:   "c23097718bd90c10ba2e99abff92f21c0eec71796712a772f0ce10f2b1bc6f5f",
   172  		rfc6979: true,
   173  		expected: "0b89d1fb10635e4a5da463c7339fd0f8d2e7d205a8288d4f973635beb8b59f7f" +
   174  			"e7c69c94ac665d14c105c2b4ba3b4c59a7819f8ecfe0d9f5f0c93a9f6d7ef447",
   175  	}, {
   176  		name:    "random key 2, blake256(0x02), rfc6979 nonce",
   177  		key:     "59930b76d4b15767ec0e8c8e5812aa2e57db30c6af7963e2a6295ba02af5416b",
   178  		msg:     "02",
   179  		hash:    "49af37ab5270015fe25276ea5a3bb159d852943df23919522a202205fb7d175c",
   180  		nonce:   "342d8326464a0b5866091126e2aa29a960eba8e47dba7bef355b18b3f9011793",
   181  		rfc6979: true,
   182  		expected: "533e99ee9c838af4cc0280b0223ab0560e7e2083694bd5b0cab3c0cb80bc2e1e" +
   183  			"cf4f777f046a18b7f8eb2c29325945025e6d5a145176b1a1de9aca7d882ca5d2",
   184  	}, {
   185  		name:    "random key 3, blake256(0x03), rfc6979 nonce",
   186  		key:     "c5b205c36bb7497d242e96ec19a2a4f086d8daa919135cf490d2b7c0230f0e91",
   187  		msg:     "03",
   188  		hash:    "b706d561742ad3671703c247eb927ee8a386369c79644131cdeb2c5c26bf6c5d",
   189  		nonce:   "710a4f1a3bee3567b53bd4dd0c9c0e55d76981a5ed488223ca0583bf8a563951",
   190  		rfc6979: true,
   191  		expected: "95c966fd6435d505a492548370b29a3c40efc3fefa3e1d997b3e2788cc33836e" +
   192  			"84a19d1d32c98f266f57f12c4363c0d9d432ca76985c6b7cb21c9970e14c75d8",
   193  	}, {
   194  		name:    "random key 4, blake256(0x04), rfc6979 nonce",
   195  		key:     "65b46d4eb001c649a86309286aaf94b18386effe62c2e1586d9b1898ccf0099b",
   196  		msg:     "04",
   197  		hash:    "4c6eb9e38415034f4c93d3304d10bef38bf0ad420eefd0f72f940f11c5857786",
   198  		nonce:   "cb4727000027551b8c2c3b717696dcff46f9ad088050571cb8634038003fc136",
   199  		rfc6979: true,
   200  		expected: "327f4e1dc74948df95dba34f26b63317568325316742fc8276be8cd2544a105c" +
   201  			"ecd401dcd37834c2c007bb3402130fcac0cca549326b81727097d4420e73268c",
   202  	}, {
   203  		name:    "random key 5, blake256(0x05), rfc6979 nonce",
   204  		key:     "915cb9ba4675de06a182088b182abcf79fa8ac989328212c6b866fa3ec2338f9",
   205  		msg:     "05",
   206  		hash:    "bdd15db13448905791a70b68137445e607cca06cc71c7a58b9b2e84a06c54d08",
   207  		nonce:   "665a2ba74200aaee038de3248c1acb8d92ca9c0a89ff63d140755834e04d55e8",
   208  		rfc6979: true,
   209  		expected: "b3ac51091150852794914e12f12b8db00ec517ca8eeca0175a20e62b1a413a5c" +
   210  			"f942de4435ff6016a3faf233100b82c66d2e6efa423b2df0f3f1ee115dfc39f5",
   211  	}, {
   212  		name:    "random key 6, blake256(0x06), rfc6979 nonce",
   213  		key:     "93e9d81d818f08ba1f850c6dfb82256b035b42f7d43c1fe090804fb009aca441",
   214  		msg:     "06",
   215  		hash:    "19b7506ad9c189a9f8b063d2aee15953d335f5c88480f8515d7d848e7771c4ae",
   216  		nonce:   "b817c907f71b11359bc2857e39f0f13d3a2cbaaadb722665ea73d7edf38c4342",
   217  		rfc6979: true,
   218  		expected: "01bfb35cf41d809d572d1d891eb474e2c0decf67ebb0f1432edce06b75d73fe0" +
   219  			"36a1015a13c6bcf50a94b87f5ef2725cf892c40e0e0fbaa5ca33e02dc6d3f19d",
   220  	}, {
   221  		name:    "random key 7, blake256(0x07), rfc6979 nonce",
   222  		key:     "c249bbd5f533672b7dcd514eb1256854783531c2b85fe60bf4ce6ea1f26afc2b",
   223  		msg:     "07",
   224  		hash:    "53d661e71e47a0a7e416591200175122d83f8af31be6a70af7417ad6f54d0038",
   225  		nonce:   "7eaa64ba668b3c77b0586695645707236f165a76ed7a53a04c833048995f8bc7",
   226  		rfc6979: true,
   227  		expected: "cb5bd3805bdd0a2e4daf58b30aa26b48c81ca59421ca320ad983c1eef672ad52" +
   228  			"5be5b6de8c0c343830bb803e0384a3942404485e8797cb48ac9ea332831fb5ad",
   229  	}, {
   230  		name:    "random key 8, blake256(0x08), rfc6979 nonce",
   231  		key:     "ec0be92fcec66cf1f97b5c39f83dfd4ddcad0dad468d3685b5eec556c6290bcc",
   232  		msg:     "08",
   233  		hash:    "9bff7982eab6f7883322edf7bdc86a23c87ca1c07906fbb1584f57b197dc6253",
   234  		nonce:   "63e12aa7d19a413577fbf6a0896f13040befb5b675f9238a09b9db400d9f454a",
   235  		rfc6979: true,
   236  		expected: "9fbd427ddaef7c7ab87e5555c1faca398695e423ce44e5fc648b9203e38b69a0" +
   237  			"47f0752e1d421e24b3eb8666c9a966b86fd49438dda1a4987cb77f3147b8fa6a",
   238  	}, {
   239  		name:    "random key 9, blake256(0x09), rfc6979 nonce",
   240  		key:     "6847b071a7cba6a85099b26a9c3e57a964e4990620e1e1c346fecc4472c4d834",
   241  		msg:     "09",
   242  		hash:    "4c2231813064f8500edae05b40195416bd543fd3e76c16d6efb10c816d92e8b6",
   243  		nonce:   "95adf9b15f485dc961061053838dbd0fb1fa8663ac344d78f3833acb5fdbfdc6",
   244  		rfc6979: true,
   245  		expected: "cd9e9100f0fc8b631b40c4d93437eaf608e25ab6ad295d8b6460289ce571fb1e" +
   246  			"a91d3c16da2fb15ce0090702df4d824dc167a205af5824579a3e587646bf4251",
   247  	}, {
   248  		name:    "random key 10, blake256(0x0a), rfc6979 nonce",
   249  		key:     "b7548540f52fe20c161a0d623097f827608c56023f50442cc00cc50ad674f6b5",
   250  		msg:     "0a",
   251  		hash:    "e81db4f0d76e02805155441f50c861a8f86374f3ae34c7a3ff4111d3a634ecb1",
   252  		nonce:   "014c6f95c371ba1dd62e759229b65a7ffced18680f34789a204e1044926722ff",
   253  		rfc6979: true,
   254  		expected: "c379f1c2a35b2f9712a5573fb59c4c29dfdc54cef833dc211716248d5c7e28e1" +
   255  			"6e180f905cd4459551eed45b2f85b4222d21d66eb2374d9f340920b42ff9807e",
   256  	}}
   257  
   258  	for _, test := range tests {
   259  		privKey := hexToModNScalar(test.key)
   260  		msg := hexToBytes(test.msg)
   261  		hash := hexToBytes(test.hash)
   262  		nonce := hexToModNScalar(test.nonce)
   263  		wantSig := hexToBytes(test.expected)
   264  
   265  		// Ensure the test data is sane by comparing the provided hashed message
   266  		// and nonce, in the case rfc6979 was used, to their calculated values.
   267  		// These values could just be calculated instead of specified in the
   268  		// test data, but it's nice to have all of the calculated values
   269  		// available in the test data for cross implementation testing and
   270  		// verification.
   271  		calcHash := blake256.Sum256(msg)
   272  		if !bytes.Equal(calcHash[:], hash) {
   273  			t.Errorf("%s: mismatched test hash -- expected: %x, given: %x",
   274  				test.name, calcHash[:], hash)
   275  			continue
   276  		}
   277  		if test.rfc6979 {
   278  			privKeyBytes := hexToBytes(test.key)
   279  			nonceBytes := hexToBytes(test.nonce)
   280  			calcNonce := secp256k1.NonceRFC6979(privKeyBytes, hash,
   281  				rfc6979ExtraDataV0[:], nil, 0)
   282  			calcNonceBytes := calcNonce.Bytes()
   283  			if !bytes.Equal(calcNonceBytes[:], nonceBytes) {
   284  				t.Errorf("%s: mismatched test nonce -- expected: %x, given: %x",
   285  					test.name, calcNonceBytes, nonceBytes)
   286  				continue
   287  			}
   288  		}
   289  
   290  		// Sign the hash of the message with the given private key and nonce.
   291  		gotSig, err := schnorrSign(privKey, nonce, hash)
   292  		if err != nil {
   293  			t.Errorf("%s: unexpected error when signing: %v", test.name, err)
   294  			continue
   295  		}
   296  
   297  		// Ensure the generated signature is the expected value.
   298  		gotSigBytes := gotSig.Serialize()
   299  		if !bytes.Equal(gotSigBytes, wantSig) {
   300  			t.Errorf("%s: unexpected signature -- got %x, want %x", test.name,
   301  				gotSigBytes, wantSig)
   302  			continue
   303  		}
   304  
   305  		// Ensure the produced signature verifies as well.
   306  		pubKey := secp256k1.NewPrivateKey(hexToModNScalar(test.key)).PubKey()
   307  		err = schnorrVerify(gotSig, hash, pubKey)
   308  		if err != nil {
   309  			t.Errorf("%s: signature failed to verify: %v", test.name, err)
   310  			continue
   311  		}
   312  	}
   313  }
   314  
   315  // TestSchnorrSignAndVerifyRandom ensures the Schnorr signing and verification
   316  // work as expected for randomly-generated private keys and messages.  It also
   317  // ensures invalid signatures are not improperly verified by mutating the valid
   318  // signature and changing the message the signature covers.
   319  func TestSchnorrSignAndVerifyRandom(t *testing.T) {
   320  	// Use a unique random seed each test instance and log it if the tests fail.
   321  	seed := time.Now().Unix()
   322  	rng := rand.New(rand.NewSource(seed))
   323  	defer func(t *testing.T, seed int64) {
   324  		if t.Failed() {
   325  			t.Logf("random seed: %d", seed)
   326  		}
   327  	}(t, seed)
   328  
   329  	for i := 0; i < 100; i++ {
   330  		// Generate a random private key.
   331  		var buf [32]byte
   332  		if _, err := rng.Read(buf[:]); err != nil {
   333  			t.Fatalf("failed to read random private key: %v", err)
   334  		}
   335  		var privKeyScalar secp256k1.ModNScalar
   336  		privKeyScalar.SetBytes(&buf)
   337  		privKey := secp256k1.NewPrivateKey(&privKeyScalar)
   338  
   339  		// Generate a random hash to sign.
   340  		var hash [32]byte
   341  		if _, err := rng.Read(hash[:]); err != nil {
   342  			t.Fatalf("failed to read random hash: %v", err)
   343  		}
   344  
   345  		// Sign the hash with the private key and then ensure the produced
   346  		// signature is valid for the hash and public key associated with the
   347  		// private key.
   348  		sig, err := Sign(privKey, hash[:])
   349  		if err != nil {
   350  			t.Fatalf("failed to sign\nprivate key: %x\nhash: %x",
   351  				privKey.Serialize(), hash)
   352  		}
   353  		pubKey := privKey.PubKey()
   354  		if !sig.Verify(hash[:], pubKey) {
   355  			t.Fatalf("failed to verify signature\nsig: %x\nhash: %x\n"+
   356  				"private key: %x\npublic key: %x", sig.Serialize(), hash,
   357  				privKey.Serialize(), pubKey.SerializeCompressed())
   358  		}
   359  
   360  		// Change a random bit in the signature and ensure the bad signature
   361  		// fails to verify the original message.
   362  		goodSigBytes := sig.Serialize()
   363  		badSigBytes := make([]byte, len(goodSigBytes))
   364  		copy(badSigBytes, goodSigBytes)
   365  		randByte := rng.Intn(len(badSigBytes))
   366  		randBit := rng.Intn(7)
   367  		badSigBytes[randByte] ^= 1 << randBit
   368  		badSig, err := ParseSignature(badSigBytes)
   369  		if err != nil {
   370  			t.Fatalf("failed to create bad signature: %v", err)
   371  		}
   372  		if badSig.Verify(hash[:], pubKey) {
   373  			t.Fatalf("verified bad signature\nsig: %x\nhash: %x\n"+
   374  				"private key: %x\npublic key: %x", badSig.Serialize(), hash,
   375  				privKey.Serialize(), pubKey.SerializeCompressed())
   376  		}
   377  
   378  		// Change a random bit in the hash that was originally signed and ensure
   379  		// the original good signature fails to verify the new bad message.
   380  		badHash := make([]byte, len(hash))
   381  		copy(badHash, hash[:])
   382  		randByte = rng.Intn(len(badHash))
   383  		randBit = rng.Intn(7)
   384  		badHash[randByte] ^= 1 << randBit
   385  		if sig.Verify(badHash[:], pubKey) {
   386  			t.Fatalf("verified signature for bad hash\nsig: %x\nhash: %x\n"+
   387  				"pubkey: %x", sig.Serialize(), badHash,
   388  				pubKey.SerializeCompressed())
   389  		}
   390  	}
   391  }
   392  
   393  // TestVerifyErrors ensures several error paths in Schnorr verification are
   394  // detected as expected.  When possible, the signatures are otherwise valid with
   395  // the exception of the specific failure to ensure it's robust against things
   396  // like fault attacks.
   397  func TestVerifyErrors(t *testing.T) {
   398  	tests := []struct {
   399  		name string // test description
   400  		sigR string // hex encoded r component of signature to verify against
   401  		sigS string // hex encoded s component of signature to verify against
   402  		hash string // hex encoded hash of message to verify
   403  		pubX string // hex encoded x component of pubkey to verify against
   404  		pubY string //  hex encoded y component of pubkey to verify against
   405  		err  error  // expected error
   406  	}{{
   407  		// Signature created from private key 0x01, blake256(0x01020304) || 00.
   408  		// It is otherwise valid.
   409  		name: "hash too long",
   410  		sigR: "4c68976afe187ff0167919ad181cb30f187e2af1c8233b2cbebbbe0fc97fff61",
   411  		sigS: "e77c69035738000caed6ab0ce1eabe5f7e105498f84d0e8982e87ee4da21948e",
   412  		hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b700",
   413  		pubX: "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
   414  		pubY: "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
   415  		err:  ErrInvalidHashLen,
   416  	}, {
   417  		// Signature created from private key 0x01, blake256(0x40) and removing
   418  		// the leading zero byte.  It is otherwise valid.
   419  		name: "hash too short",
   420  		sigR: "938de23d0785c7d4775f47bbcadaa2a56447dd98029c8196f2bbed0ab4b8457f",
   421  		sigS: "7de65bf205e14f81e5f75ad2fd80ea715a391f7b51e10fa43f0a1961039b1a6c",
   422  		hash: "0e0f08e2ee912478b77004ec62845b5e01418f03837b76cbdc8b1fb0480322",
   423  		pubX: "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
   424  		pubY: "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
   425  		err:  ErrInvalidHashLen,
   426  	}, {
   427  		// Signature created from private key 0x01, blake256(0x01020304) over
   428  		// the secp256r1 curve (note the r1 instead of k1).
   429  		name: "pubkey not on the curve, signature valid for secp256r1 instead",
   430  		sigR: "c6c62660176b3daa90dbf4d7e21d9406ce93895771a16c7c5c91258a9b522174",
   431  		sigS: "f5b5583956a6b30e18ff5e865c77a8c4adf47b147d11ea3822b4de63c9f7b909",
   432  		hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
   433  		pubX: "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
   434  		pubY: "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5",
   435  		err:  ErrPubKeyNotOnCurve,
   436  	}, {
   437  		// Signature invented since finding a signature with an r value that is
   438  		// exactly the field prime prior to the modular reduction is not
   439  		// calculable without breaking the underlying crypto.
   440  		name: "r == field prime",
   441  		sigR: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
   442  		sigS: "e9ae2d0e306497236d4e328dc1a34244045745e87da69d806859348bc2a74525",
   443  		hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
   444  		pubX: "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
   445  		pubY: "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
   446  		err:  ErrSigRTooBig,
   447  	}, {
   448  		// Likewise, signature invented since finding a signature with an r
   449  		// value that would be valid modulo the field prime and is still 32
   450  		// bytes is not calculable without breaking the underlying crypto.
   451  		name: "r > field prime (prime + 1)",
   452  		sigR: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc30",
   453  		sigS: "e9ae2d0e306497236d4e328dc1a34244045745e87da69d806859348bc2a74525",
   454  		hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
   455  		pubX: "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
   456  		pubY: "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
   457  		err:  ErrSigRTooBig,
   458  	}, {
   459  		// Signature invented since finding a signature with an s value that is
   460  		// exactly the group order prior to the modular reduction is not
   461  		// calculable without breaking the underlying crypto.
   462  		name: "s == group order",
   463  		sigR: "4c68976afe187ff0167919ad181cb30f187e2af1c8233b2cbebbbe0fc97fff61",
   464  		sigS: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
   465  		hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
   466  		pubX: "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
   467  		pubY: "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
   468  		err:  ErrSigSTooBig,
   469  	}, {
   470  		// Likewise, signature invented since finding a signature with an s
   471  		// value that would be valid modulo the group order and is still 32
   472  		// bytes is not calculable without breaking the underlying crypto.
   473  		name: "s > group order and still 32 bytes (order + 1)",
   474  		sigR: "4c68976afe187ff0167919ad181cb30f187e2af1c8233b2cbebbbe0fc97fff61",
   475  		sigS: "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364142",
   476  		hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
   477  		pubX: "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
   478  		pubY: "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
   479  		err:  ErrSigSTooBig,
   480  	}, {
   481  		// Signature created from private key 0x01, blake256(0x01020304) and
   482  		// manually setting s = -ed.
   483  		//
   484  		// Signature is otherwise invalid too since finding a signature where
   485  		// the two points add to infinity while still having a matching r is not
   486  		// calculable.
   487  		name: "calculated R point at infinity",
   488  		sigR: "4c68976afe187ff0167919ad181cb30f187e2af1c8233b2cbebbbe0fc97fff61",
   489  		sigS: "14cc9e0544dd8fe6baa7c20fd2a141d0ee60114c419377efc850a49bd5c1ed36",
   490  		hash: "c301ba9de5d6053caad9f5eb46523f007702add2c62fa39de03146a36b8026b7",
   491  		pubX: "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
   492  		pubY: "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
   493  		err:  ErrSigRNotOnCurve,
   494  	}, {
   495  		// Signature created from private key 0x01, blake256(0x01020304050607).
   496  		// It is otherwise valid.
   497  		name: "odd R",
   498  		sigR: "2c2c71f7bf3e183238b1f20d856e068dc6d37805c8b2d872d0f23d906bc95789",
   499  		sigS: "eb7670ca6ff95c1d5c6785bc72e0781f27c9778758317d82d3053fdbcc9c17b0",
   500  		hash: "ccf8c53a7631aad469d412963d495c729ff219dd2ae9a0c4de4bd1b4c777d49c",
   501  		pubX: "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
   502  		pubY: "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
   503  		err:  ErrSigRYIsOdd,
   504  	}, {
   505  		// Signature created from private key 0x01, blake256(0x01020304).  Thus,
   506  		// it is valid for that message.  Attempting to verify wrong message
   507  		// blake256(0x01020307).
   508  		name: "mismatched R",
   509  		sigR: "4c68976afe187ff0167919ad181cb30f187e2af1c8233b2cbebbbe0fc97fff61",
   510  		sigS: "e9ae2d0e306497236d4e328dc1a34244045745e87da69d806859348bc2a74525",
   511  		hash: "d4f9aea8c329f57a81397f0418269a8bd495957ea56ae0af0dfa886fb5977046",
   512  		pubX: "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
   513  		pubY: "483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
   514  		err:  ErrUnequalRValues,
   515  	}}
   516  	// NOTE: There is no test for e >= group order because it would require
   517  	// finding a preimage that hashes to the value range [n, 2^256) and n is
   518  	// close enough to 2^256 that there is only roughly a 1 in 2^128 chance of
   519  	// a given hash falling in that range.  In other words, it's not feasible
   520  	// to calculate.
   521  
   522  	for _, test := range tests {
   523  		// Parse test data into types.
   524  		hash := hexToBytes(test.hash)
   525  		pubX, pubY := hexToFieldVal(test.pubX), hexToFieldVal(test.pubY)
   526  		pubKey := secp256k1.NewPublicKey(pubX, pubY)
   527  
   528  		// Create the serialized signature from the bytes and attempt to parse
   529  		// it to ensure the cases where the r and s components exceed the
   530  		// allowed range is caught.
   531  		sig, err := ParseSignature(hexToBytes(test.sigR + test.sigS))
   532  		if err != nil {
   533  			if !errors.Is(err, test.err) {
   534  				t.Errorf("%s: mismatched err -- got %v, want %v", test.name, err,
   535  					test.err)
   536  			}
   537  
   538  			continue
   539  		}
   540  
   541  		// Ensure the expected error is hit.
   542  		err = schnorrVerify(sig, hash, pubKey)
   543  		if !errors.Is(err, test.err) {
   544  			t.Errorf("%s: mismatched err -- got %v, want %v", test.name, err,
   545  				test.err)
   546  			continue
   547  		}
   548  	}
   549  }
   550  

View as plain text