scalar_test.go raw

   1  package p256k1
   2  
   3  import (
   4  	"crypto/rand"
   5  	"testing"
   6  )
   7  
   8  func TestScalarBasics(t *testing.T) {
   9  	// Test zero scalar
  10  	var zero Scalar
  11  	if !zero.isZero() {
  12  		t.Error("Zero scalar should be zero")
  13  	}
  14  
  15  	// Test one scalar
  16  	var one Scalar
  17  	one.setInt(1)
  18  	if !one.isOne() {
  19  		t.Error("One scalar should be one")
  20  	}
  21  
  22  	// Test equality
  23  	var one2 Scalar
  24  	one2.setInt(1)
  25  	if !one.equal(&one2) {
  26  		t.Error("Two ones should be equal")
  27  	}
  28  }
  29  
  30  func TestScalarSetB32(t *testing.T) {
  31  	// Test setting from 32-byte array
  32  	testCases := []struct {
  33  		name  string
  34  		bytes [32]byte
  35  	}{
  36  		{
  37  			name:  "zero",
  38  			bytes: [32]byte{},
  39  		},
  40  		{
  41  			name:  "one",
  42  			bytes: [32]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
  43  		},
  44  		{
  45  			name:  "group_order_minus_one",
  46  			bytes: [32]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x40},
  47  		},
  48  		{
  49  			name:  "group_order",
  50  			bytes: [32]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41},
  51  		},
  52  	}
  53  
  54  	for _, tc := range testCases {
  55  		t.Run(tc.name, func(t *testing.T) {
  56  			var s Scalar
  57  			overflow := s.setB32(tc.bytes[:])
  58  
  59  			// Test round-trip
  60  			var result [32]byte
  61  			s.getB32(result[:])
  62  
  63  			// For group order, should reduce to zero
  64  			if tc.name == "group_order" {
  65  				if !s.isZero() {
  66  					t.Error("Group order should reduce to zero")
  67  				}
  68  				if !overflow {
  69  					t.Error("Group order should cause overflow")
  70  				}
  71  			}
  72  		})
  73  	}
  74  }
  75  
  76  func TestScalarSetB32Seckey(t *testing.T) {
  77  	// Test valid secret key
  78  	validKey := [32]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
  79  	var s Scalar
  80  	if !s.setB32Seckey(validKey[:]) {
  81  		t.Error("Valid secret key should be accepted")
  82  	}
  83  
  84  	// Test zero key (invalid)
  85  	zeroKey := [32]byte{}
  86  	if s.setB32Seckey(zeroKey[:]) {
  87  		t.Error("Zero secret key should be rejected")
  88  	}
  89  
  90  	// Test group order key (invalid)
  91  	orderKey := [32]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41}
  92  	if s.setB32Seckey(orderKey[:]) {
  93  		t.Error("Group order secret key should be rejected")
  94  	}
  95  }
  96  
  97  func TestScalarArithmetic(t *testing.T) {
  98  	// Test addition
  99  	var a, b, c Scalar
 100  	a.setInt(5)
 101  	b.setInt(7)
 102  	c.add(&a, &b)
 103  
 104  	var expected Scalar
 105  	expected.setInt(12)
 106  	if !c.equal(&expected) {
 107  		t.Error("5 + 7 should equal 12")
 108  	}
 109  
 110  	// Test multiplication
 111  	var mult Scalar
 112  	mult.mul(&a, &b)
 113  
 114  	expected.setInt(35)
 115  	if !mult.equal(&expected) {
 116  		t.Error("5 * 7 should equal 35")
 117  	}
 118  
 119  	// Test negation
 120  	var neg Scalar
 121  	neg.negate(&a)
 122  
 123  	var sum Scalar
 124  	sum.add(&a, &neg)
 125  
 126  	if !sum.isZero() {
 127  		t.Error("a + (-a) should equal zero")
 128  	}
 129  }
 130  
 131  func TestScalarInverse(t *testing.T) {
 132  	// Test inverse of small numbers
 133  	for i := uint(1); i <= 10; i++ {
 134  		var a, inv, product Scalar
 135  		a.setInt(i)
 136  		inv.inverse(&a)
 137  		product.mul(&a, &inv)
 138  
 139  		if !product.isOne() {
 140  			t.Errorf("a * a^(-1) should equal 1 for a = %d", i)
 141  		}
 142  	}
 143  }
 144  
 145  func TestScalarHalf(t *testing.T) {
 146  	// Test halving
 147  	var a, half, doubled Scalar
 148  
 149  	// Test even number
 150  	a.setInt(14)
 151  	half.half(&a)
 152  	doubled.add(&half, &half)
 153  	if !doubled.equal(&a) {
 154  		t.Error("2 * (14/2) should equal 14")
 155  	}
 156  
 157  	// Test odd number
 158  	a.setInt(7)
 159  	half.half(&a)
 160  	doubled.add(&half, &half)
 161  	if !doubled.equal(&a) {
 162  		t.Error("2 * (7/2) should equal 7")
 163  	}
 164  }
 165  
 166  func TestScalarProperties(t *testing.T) {
 167  	var a Scalar
 168  	a.setInt(6)
 169  
 170  	// Test even/odd
 171  	if !a.isEven() {
 172  		t.Error("6 should be even")
 173  	}
 174  
 175  	a.setInt(7)
 176  	if a.isEven() {
 177  		t.Error("7 should be odd")
 178  	}
 179  }
 180  
 181  func TestScalarConditionalNegate(t *testing.T) {
 182  	var a, original Scalar
 183  	a.setInt(5)
 184  	original = a
 185  
 186  	// Test conditional negate with flag = 0
 187  	a.condNegate(0)
 188  	if !a.equal(&original) {
 189  		t.Error("Conditional negate with flag=0 should not change value")
 190  	}
 191  
 192  	// Test conditional negate with flag = 1
 193  	a.condNegate(1)
 194  	var neg Scalar
 195  	neg.negate(&original)
 196  	if !a.equal(&neg) {
 197  		t.Error("Conditional negate with flag=1 should negate value")
 198  	}
 199  }
 200  
 201  func TestScalarGetBits(t *testing.T) {
 202  	var a Scalar
 203  	a.setInt(0x12345678)
 204  
 205  	// Test getting bits
 206  	bits := a.getBits(0, 8)
 207  	if bits != 0x78 {
 208  		t.Errorf("Expected 0x78, got 0x%x", bits)
 209  	}
 210  
 211  	bits = a.getBits(8, 8)
 212  	if bits != 0x56 {
 213  		t.Errorf("Expected 0x56, got 0x%x", bits)
 214  	}
 215  }
 216  
 217  func TestScalarConditionalMove(t *testing.T) {
 218  	var a, b, original Scalar
 219  	a.setInt(5)
 220  	b.setInt(10)
 221  	original = a
 222  
 223  	// Test conditional move with flag = 0
 224  	a.cmov(&b, 0)
 225  	if !a.equal(&original) {
 226  		t.Error("Conditional move with flag=0 should not change value")
 227  	}
 228  
 229  	// Test conditional move with flag = 1
 230  	a.cmov(&b, 1)
 231  	if !a.equal(&b) {
 232  		t.Error("Conditional move with flag=1 should copy value")
 233  	}
 234  }
 235  
 236  func TestScalarClear(t *testing.T) {
 237  	var s Scalar
 238  	s.setInt(12345)
 239  
 240  	s.clear()
 241  
 242  	// After clearing, should be zero
 243  	if !s.isZero() {
 244  		t.Error("Cleared scalar should be zero")
 245  	}
 246  }
 247  
 248  func TestScalarRandomOperations(t *testing.T) {
 249  	// Test with random values
 250  	for i := 0; i < 50; i++ {
 251  		var aBytes, bBytes [32]byte
 252  		rand.Read(aBytes[:])
 253  		rand.Read(bBytes[:])
 254  
 255  		var a, b Scalar
 256  		a.setB32(aBytes[:])
 257  		b.setB32(bBytes[:])
 258  
 259  		// Skip if either is zero
 260  		if a.isZero() || b.isZero() {
 261  			continue
 262  		}
 263  
 264  		// Test (a + b) - a = b
 265  		var sum, diff Scalar
 266  		sum.add(&a, &b)
 267  		diff.sub(&sum, &a)
 268  		if !diff.equal(&b) {
 269  			t.Errorf("Random test %d: (a + b) - a should equal b", i)
 270  		}
 271  
 272  		// Test (a * b) / a = b
 273  		var prod, quot Scalar
 274  		prod.mul(&a, &b)
 275  		var aInv Scalar
 276  		aInv.inverse(&a)
 277  		quot.mul(&prod, &aInv)
 278  		if !quot.equal(&b) {
 279  			t.Errorf("Random test %d: (a * b) / a should equal b", i)
 280  		}
 281  	}
 282  }
 283  
 284  func TestScalarEdgeCases(t *testing.T) {
 285  	// Test n-1 + 1 = 0
 286  	nMinus1 := [32]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x40}
 287  
 288  	var s Scalar
 289  	s.setB32(nMinus1[:])
 290  
 291  	// Add 1 should give 0
 292  	var one Scalar
 293  	one.setInt(1)
 294  	s.add(&s, &one)
 295  
 296  	if !s.isZero() {
 297  		t.Error("(n-1) + 1 should equal 0 in scalar arithmetic")
 298  	}
 299  }
 300