Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 6 additions & 26 deletions dcrec/secp256k1/field.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,32 +391,12 @@ func (f *FieldVal) Normalize() *FieldVal {
// following determines if either or these conditions are true and does
// the final reduction in constant time.
//
// Note that the if/else statements here intentionally do the bitwise
// operators even when it won't change the value to ensure constant time
// between the branches. Also note that 'm' will be zero when neither
// of the aforementioned conditions are true and the value will not be
// changed when 'm' is zero.
m = 1
if t9 == fieldMSBMask {
m &= 1
} else {
m &= 0
}
if t2&t3&t4&t5&t6&t7&t8 == fieldBaseMask {
m &= 1
} else {
m &= 0
}
if ((t0+977)>>fieldBase + t1 + 64) > fieldBaseMask {
m &= 1
} else {
m &= 0
}
if t9>>fieldMSBBits != 0 {
m |= 1
} else {
m |= 0
}
// Also note that 'm' will be zero when neither of the aforementioned
// conditions are true and the value will not be changed when 'm' is zero.
m = constantTimeEq(t9, fieldMSBMask)
m &= constantTimeEq(t8&t7&t6&t5&t4&t3&t2, fieldBaseMask)
m &= constantTimeGreater(t1+64+((t0+977)>>fieldBase), fieldBaseMask)
m |= t9 >> fieldMSBBits
t0 = t0 + m*977
t1 = (t0 >> fieldBase) + t1 + (m << 6)
t0 = t0 & fieldBaseMask
Expand Down
7 changes: 5 additions & 2 deletions dcrec/secp256k1/field_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ import (
// BenchmarkFieldNormalize benchmarks how long it takes the internal field
// to perform normalization (which includes modular reduction).
func BenchmarkFieldNormalize(b *testing.B) {
// The normalize function is constant time so default value is fine.
f := new(FieldVal)
// The function is constant time so any value is fine.
f := &FieldVal{n: [10]uint32{
0x000148f6, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff,
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x00000007,
}}
for i := 0; i < b.N; i++ {
f.Normalize()
}
Expand Down
67 changes: 67 additions & 0 deletions dcrec/secp256k1/field_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,73 @@ func TestFieldNormalize(t *testing.T) {
name: "Value > P with redux > P at mag 1 due to 1st and 2nd words and carry to bit 256",
raw: [10]uint32{0x03fffc30, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x07ffffff, 0x003fffff},
normalized: [10]uint32{0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001},
}, {
// ---------------------------------------------------------------------
// There are 3 main conditions that must be true if the final reduction
// is needed after the initial reduction to magnitude 1 when there was
// NOT a carry to bit 256 (in other words when the original value was <
// 2^256):
// 1) The final word of the reduced value is equal to the one of P
// 2) The 3rd through 9th words are equal to those of P
// 3) Either:
// - The 2nd word is greater than the one of P; or
// - The 2nd word is equal to that of P AND the 1st word is greater
//
// Therefore the eight possible combinations of those 3 main conditions
// can be thought of in binary where each bit starting from the left
// corresponds to the aforementioned conditions as such:
// 000, 001, 010, 011, 100, 101, 110, 111
//
// For example, combination 6 is when both conditons 1 and 2 are true,
// but condition 3 is NOT true.
//
// The following tests hit each of these combinations and refer to each
// by its decimal equivalent for ease of reference.
//
// NOTE: The final combination (7) is already tested above since it only
// happens when the original value is already the normalized
// representation of P.
// ---------------------------------------------------------------------

name: "Value < 2^256 final reduction combination 0",
raw: [10]uint32{0x03fff85e, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003ffffe},
normalized: [10]uint32{0x03fff85e, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003ffffe},
}, {
name: "Value < 2^256 final reduction combination 1 via 2nd word",
raw: [10]uint32{0x03fff85e, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003ffffe},
normalized: [10]uint32{0x03fff85e, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003ffffe},
}, {
name: "Value < 2^256 final reduction combination 1 via 1st word",
raw: [10]uint32{0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003ffffe},
normalized: [10]uint32{0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003ffffe},
}, {
name: "Value < 2^256 final reduction combination 2",
raw: [10]uint32{0x03fff85e, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003ffffe},
normalized: [10]uint32{0x03fff85e, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003ffffe},
}, {
name: "Value < 2^256 final reduction combination 3 via 2nd word",
raw: [10]uint32{0x03fff85e, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003ffffe},
normalized: [10]uint32{0x03fff85e, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003ffffe},
}, {
name: "Value < 2^256 final reduction combination 3 via 1st word",
raw: [10]uint32{0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003ffffe},
normalized: [10]uint32{0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003ffffe},
}, {
name: "Value < 2^256 final reduction combination 4",
raw: [10]uint32{0x03fff85e, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003fffff},
normalized: [10]uint32{0x03fff85e, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003fffff},
}, {
name: "Value < 2^256 final reduction combination 5 via 2nd word",
raw: [10]uint32{0x03fff85e, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003fffff},
normalized: [10]uint32{0x03fff85e, 0x03ffffc0, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003fffff},
}, {
name: "Value < 2^256 final reduction combination 5 via 1st word",
raw: [10]uint32{0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003fffff},
normalized: [10]uint32{0x03fffc2f, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03fffffe, 0x003fffff},
}, {
name: "Value < 2^256 final reduction combination 6",
raw: [10]uint32{0x03fff85e, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff},
normalized: [10]uint32{0x03fff85e, 0x03ffffbf, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x003fffff},
}}

for _, test := range tests {
Expand Down