secp256k1_test_support.mx raw

   1  package secp256k1
   2  
   3  import "errors"
   4  
   5  // TestSignedRadix16 verifies the constant-time ScalarMult handles the
   6  // digits[64]==1 edge case. The scalar n-1 (group order minus one) has top
   7  // two nibbles 0xF/0xF, so carry propagates all the way through digit 63
   8  // into digit 64 during scalarToSignedRadix16 decomposition.
   9  //
  10  // (n-1)*G == -G, which has the same x-coordinate as G itself.
  11  // PubKeyFromSecKey(n-1) must therefore equal PubKeyFromSecKey(1) == Gx.
  12  func TestSignedRadix16() error {
  13  	// n-1 in big-endian (32 bytes): FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140
  14  	nMinus1 := [32]byte{
  15  		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  16  		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
  17  		0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
  18  		0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x40,
  19  	}
  20  
  21  	// Verify digits[64] == 1 for n-1.
  22  	k := scalarFromBytes(nMinus1[:])
  23  	digits := scalarToSignedRadix16(k)
  24  	if digits[64] != 1 {
  25  		return errors.New("scalarToSignedRadix16: expected digits[64]==1 for scalar n-1")
  26  	}
  27  
  28  	// Verify all digits[0..63] are in [-8, 7].
  29  	for i := 0; i < 64; i++ {
  30  		if digits[i] < -8 || digits[i] > 7 {
  31  			return errors.New("scalarToSignedRadix16: digit out of range")
  32  		}
  33  	}
  34  
  35  	// (n-1)*G == -G, x-coordinate equals Gx.
  36  	// PubKeyFromSecKey returns the x-coordinate of seckey*G.
  37  	pubNM1, ok := PubKeyFromSecKey(nMinus1)
  38  	if !ok {
  39  		return errors.New("PubKeyFromSecKey(n-1) failed")
  40  	}
  41  
  42  	// seckey 1: 1*G = G.
  43  	var one [32]byte
  44  	one[31] = 1
  45  	pub1, ok := PubKeyFromSecKey(one)
  46  	if !ok {
  47  		return errors.New("PubKeyFromSecKey(1) failed")
  48  	}
  49  
  50  	if pubNM1 != pub1 {
  51  		return errors.New("PubKeyFromSecKey(n-1) != PubKeyFromSecKey(1): x-coordinate mismatch")
  52  	}
  53  
  54  	// Also verify against the known Gx constant.
  55  	gx := feToBytes(G().X)
  56  	if pubNM1 != gx {
  57  		return errors.New("PubKeyFromSecKey(n-1) != Gx: wrong x-coordinate")
  58  	}
  59  
  60  	return nil
  61  }
  62