components/golang/patches/0069-release-branch.go1.5-math-big-fix-carry-propagation-.patch
changeset 5331 9c955076ffe3
equal deleted inserted replaced
5330:c36e3195e3e9 5331:9c955076ffe3
       
     1 From 0027ed1872cdec08defe3b097c7123eaaf149e30 Mon Sep 17 00:00:00 2001
       
     2 From: Russ Cox <[email protected]>
       
     3 Date: Wed, 9 Dec 2015 11:49:53 -0500
       
     4 Subject: [PATCH 69/73] [release-branch.go1.5] math/big: fix carry propagation
       
     5  in Int.Exp Montgomery code
       
     6 
       
     7 Fixes #13515.
       
     8 
       
     9 Change-Id: I7dd5fbc816e5ea135f7d81f6735e7601f636fe4f
       
    10 Reviewed-on: https://go-review.googlesource.com/17672
       
    11 Reviewed-by: Robert Griesemer <[email protected]>
       
    12 Reviewed-on: https://go-review.googlesource.com/18585
       
    13 ---
       
    14  src/math/big/nat.go      | 29 +++++++++++----
       
    15  src/math/big/nat_test.go | 95 +++++++++++++++++++++++++++++++++++++++++-------
       
    16  2 files changed, 103 insertions(+), 21 deletions(-)
       
    17 
       
    18 diff --git a/src/math/big/nat.go b/src/math/big/nat.go
       
    19 index 6545bc1..c7362e6 100644
       
    20 --- a/src/math/big/nat.go
       
    21 +++ b/src/math/big/nat.go
       
    22 @@ -216,23 +216,36 @@ func basicMul(z, x, y nat) {
       
    23  	}
       
    24  }
       
    25  
       
    26 -// montgomery computes x*y*2^(-n*_W) mod m,
       
    27 -// assuming k = -1/m mod 2^_W.
       
    28 +// montgomery computes z mod m = x*y*2**(-n*_W) mod m,
       
    29 +// assuming k = -1/m mod 2**_W.
       
    30  // z is used for storing the result which is returned;
       
    31  // z must not alias x, y or m.
       
    32 +// See Gueron, "Efficient Software Implementations of Modular Exponentiation".
       
    33 +// https://eprint.iacr.org/2011/239.pdf
       
    34 +// In the terminology of that paper, this is an "Almost Montgomery Multiplication":
       
    35 +// x and y are required to satisfy 0 <= z < 2**(n*_W) and then the result
       
    36 +// z is guaranteed to satisfy 0 <= z < 2**(n*_W), but it may not be < m.
       
    37  func (z nat) montgomery(x, y, m nat, k Word, n int) nat {
       
    38 -	var c1, c2 Word
       
    39 +	// This code assumes x, y, m are all the same length, n.
       
    40 +	// (required by addMulVVW and the for loop).
       
    41 +	// It also assumes that x, y are already reduced mod m,
       
    42 +	// or else the result will not be properly reduced.
       
    43 +	if len(x) != n || len(y) != n || len(m) != n {
       
    44 +		panic("math/big: mismatched montgomery number lengths")
       
    45 +	}
       
    46 +	var c1, c2, c3 Word
       
    47  	z = z.make(n)
       
    48  	z.clear()
       
    49  	for i := 0; i < n; i++ {
       
    50  		d := y[i]
       
    51 -		c1 += addMulVVW(z, x, d)
       
    52 +		c2 = addMulVVW(z, x, d)
       
    53  		t := z[0] * k
       
    54 -		c2 = addMulVVW(z, m, t)
       
    55 -
       
    56 +		c3 = addMulVVW(z, m, t)
       
    57  		copy(z, z[1:])
       
    58 -		z[n-1] = c1 + c2
       
    59 -		if z[n-1] < c1 {
       
    60 +		cx := c1 + c2
       
    61 +		cy := cx + c3
       
    62 +		z[n-1] = cy
       
    63 +		if cx < c2 || cy < c3 {
       
    64  			c1 = 1
       
    65  		} else {
       
    66  			c1 = 0
       
    67 diff --git a/src/math/big/nat_test.go b/src/math/big/nat_test.go
       
    68 index 7ac3cb8..dce7de5 100644
       
    69 --- a/src/math/big/nat_test.go
       
    70 +++ b/src/math/big/nat_test.go
       
    71 @@ -341,25 +341,57 @@ var montgomeryTests = []struct {
       
    72  		"0xffffffffffffffffffffffffffffffffffffffffffffffffe",
       
    73  		"0xffffffffffffffffffffffffffffffffffffffffffffffffe",
       
    74  		"0xfffffffffffffffffffffffffffffffffffffffffffffffff",
       
    75 -		0x0000000000000000,
       
    76 -		"0xffffffffffffffffffffffffffffffffffffffffff",
       
    77 -		"0xffffffffffffffffffffffffffffffffff",
       
    78 +		1,
       
    79 +		"0x1000000000000000000000000000000000000000000",
       
    80 +		"0x10000000000000000000000000000000000",
       
    81  	},
       
    82  	{
       
    83 -		"0x0000000080000000",
       
    84 -		"0x00000000ffffffff",
       
    85 +		"0x000000000ffffff5",
       
    86 +		"0x000000000ffffff0",
       
    87  		"0x0000000010000001",
       
    88  		0xff0000000fffffff,
       
    89 -		"0x0000000088000000",
       
    90 -		"0x0000000007800001",
       
    91 +		"0x000000000bfffff4",
       
    92 +		"0x0000000003400001",
       
    93 +	},
       
    94 +	{
       
    95 +		"0x0000000080000000",
       
    96 +		"0x00000000ffffffff",
       
    97 +		"0x1000000000000001",
       
    98 +		0xfffffffffffffff,
       
    99 +		"0x0800000008000001",
       
   100 +		"0x0800000008000001",
       
   101  	},
       
   102  	{
       
   103 -		"0xffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
       
   104 -		"0xffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc",
       
   105 +		"0x0000000080000000",
       
   106 +		"0x0000000080000000",
       
   107 +		"0xffffffff00000001",
       
   108 +		0xfffffffeffffffff,
       
   109 +		"0xbfffffff40000001",
       
   110 +		"0xbfffffff40000001",
       
   111 +	},
       
   112 +	{
       
   113 +		"0x0000000080000000",
       
   114 +		"0x0000000080000000",
       
   115 +		"0x00ffffff00000001",
       
   116 +		0xfffffeffffffff,
       
   117 +		"0xbfffff40000001",
       
   118 +		"0xbfffff40000001",
       
   119 +	},
       
   120 +	{
       
   121 +		"0x0000000080000000",
       
   122 +		"0x0000000080000000",
       
   123 +		"0x0000ffff00000001",
       
   124 +		0xfffeffffffff,
       
   125 +		"0xbfff40000001",
       
   126 +		"0xbfff40000001",
       
   127 +	},
       
   128 +	{
       
   129 +		"0x3321ffffffffffffffffffffffffffff00000000000022222623333333332bbbb888c0",
       
   130 +		"0x3321ffffffffffffffffffffffffffff00000000000022222623333333332bbbb888c0",
       
   131  		"0x33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1",
       
   132  		0xdecc8f1249812adf,
       
   133 -		"0x22bb05b6d95eaaeca2bb7c05e51f807bce9064b5fbad177161695e4558f9474e91cd79",
       
   134 -		"0x14beb58d230f85b6d95eaaeca2bb7c05e51f807bce9064b5fb45669afa695f228e48cd",
       
   135 +		"0x04eb0e11d72329dc0915f86784820fc403275bf2f6620a20e0dd344c5cd0875e50deb5",
       
   136 +		"0x0d7144739a7d8e11d72329dc0915f86784820fc403275bf2f61ed96f35dd34dbb3d6a0",
       
   137  	},
       
   138  	{
       
   139  		"0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
       
   140 @@ -372,10 +404,27 @@ var montgomeryTests = []struct {
       
   141  }
       
   142  
       
   143  func TestMontgomery(t *testing.T) {
       
   144 +	one := NewInt(1)
       
   145 +	_B := new(Int).Lsh(one, _W)
       
   146  	for i, test := range montgomeryTests {
       
   147  		x := natFromString(test.x)
       
   148  		y := natFromString(test.y)
       
   149  		m := natFromString(test.m)
       
   150 +		for len(x) < len(m) {
       
   151 +			x = append(x, 0)
       
   152 +		}
       
   153 +		for len(y) < len(m) {
       
   154 +			y = append(y, 0)
       
   155 +		}
       
   156 +
       
   157 +		if x.cmp(m) > 0 {
       
   158 +			_, r := nat(nil).div(nil, x, m)
       
   159 +			t.Errorf("#%d: x > m (0x%s > 0x%s; use 0x%s)", i, x.utoa(16), m.utoa(16), r.utoa(16))
       
   160 +		}
       
   161 +		if y.cmp(m) > 0 {
       
   162 +			_, r := nat(nil).div(nil, x, m)
       
   163 +			t.Errorf("#%d: y > m (0x%s > 0x%s; use 0x%s)", i, y.utoa(16), m.utoa(16), r.utoa(16))
       
   164 +		}
       
   165  
       
   166  		var out nat
       
   167  		if _W == 32 {
       
   168 @@ -384,11 +433,31 @@ func TestMontgomery(t *testing.T) {
       
   169  			out = natFromString(test.out64)
       
   170  		}
       
   171  
       
   172 -		k0 := Word(test.k0 & _M) // mask k0 to ensure that it fits for 32-bit systems.
       
   173 +		// t.Logf("#%d: len=%d\n", i, len(m))
       
   174 +
       
   175 +		// check output in table
       
   176 +		xi := &Int{abs: x}
       
   177 +		yi := &Int{abs: y}
       
   178 +		mi := &Int{abs: m}
       
   179 +		p := new(Int).Mod(new(Int).Mul(xi, new(Int).Mul(yi, new(Int).ModInverse(new(Int).Lsh(one, uint(len(m))*_W), mi))), mi)
       
   180 +		if out.cmp(p.abs.norm()) != 0 {
       
   181 +			t.Errorf("#%d: out in table=0x%s, computed=0x%s", i, out.utoa(16), p.abs.norm().utoa(16))
       
   182 +		}
       
   183 +
       
   184 +		// check k0 in table
       
   185 +		k := new(Int).Mod(&Int{abs: m}, _B)
       
   186 +		k = new(Int).Sub(_B, k)
       
   187 +		k = new(Int).Mod(k, _B)
       
   188 +		k0 := Word(new(Int).ModInverse(k, _B).Uint64())
       
   189 +		if k0 != Word(test.k0) {
       
   190 +			t.Errorf("#%d: k0 in table=%#x, computed=%#x\n", i, test.k0, k0)
       
   191 +		}
       
   192 +
       
   193 +		// check montgomery with correct k0 produces correct output
       
   194  		z := nat(nil).montgomery(x, y, m, k0, len(m))
       
   195  		z = z.norm()
       
   196  		if z.cmp(out) != 0 {
       
   197 -			t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString())
       
   198 +			t.Errorf("#%d: got 0x%s want 0x%s", i, z.utoa(16), out.utoa(16))
       
   199  		}
       
   200  	}
       
   201  }
       
   202 -- 
       
   203 2.6.1
       
   204