mirror of https://github.com/gtank/ristretto255
internal/scalar: add non-adjacent form
Closes #13 This code is adapted from code I wrote for curve25519-dalek.
This commit is contained in:
parent
94a47ae390
commit
f2b1a09ecb
|
@ -896,3 +896,65 @@ func scMinimal(sc *Scalar) bool {
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Computes a width-w non-adjacent form for this scalar.
|
||||||
|
func (s *Scalar) NonAdjacentForm(w uint) [256]int8 {
|
||||||
|
// This implementation is adapted from the one
|
||||||
|
// in curve25519-dalek and is documented there:
|
||||||
|
// https://github.com/dalek-cryptography/curve25519-dalek/blob/f630041af28e9a405255f98a8a93adca18e4315b/src/scalar.rs#L800-L871
|
||||||
|
if w < 2 {
|
||||||
|
panic("w must be at least 2 by the definition of NAF")
|
||||||
|
} else if w > 8 {
|
||||||
|
panic("NAF digits must fit in int8")
|
||||||
|
}
|
||||||
|
|
||||||
|
var naf [256]int8
|
||||||
|
var digits [5]uint64
|
||||||
|
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
digits[i] = binary.LittleEndian.Uint64(s[i*8:])
|
||||||
|
}
|
||||||
|
|
||||||
|
width := uint64(1 << w)
|
||||||
|
windowMask := uint64(width - 1)
|
||||||
|
|
||||||
|
pos := uint(0)
|
||||||
|
carry := uint64(0)
|
||||||
|
for pos < 256 {
|
||||||
|
indexU64 := pos / 64
|
||||||
|
indexBit := pos % 64
|
||||||
|
var bitBuf uint64
|
||||||
|
if indexBit < 64-w {
|
||||||
|
// This window's bits are contained in a single u64
|
||||||
|
bitBuf = digits[indexU64] >> indexBit
|
||||||
|
} else {
|
||||||
|
// Combine the current 64 bits with bits from the next 64
|
||||||
|
bitBuf = (digits[indexU64] >> indexBit) | (digits[1+indexU64] << (64 - indexBit))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add carry into the current window
|
||||||
|
window := carry + (bitBuf & windowMask)
|
||||||
|
|
||||||
|
if window&1 == 0 {
|
||||||
|
// If the window value is even, preserve the carry and continue.
|
||||||
|
// Why is the carry preserved?
|
||||||
|
// If carry == 0 and window & 1 == 0,
|
||||||
|
// then the next carry should be 0
|
||||||
|
// If carry == 1 and window & 1 == 0,
|
||||||
|
// then bit_buf & 1 == 1 so the next carry should be 1
|
||||||
|
pos += 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if window < width/2 {
|
||||||
|
carry = 0
|
||||||
|
naf[pos] = int8(window)
|
||||||
|
} else {
|
||||||
|
carry = 1
|
||||||
|
naf[pos] = int8(window) - int8(width)
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += w
|
||||||
|
}
|
||||||
|
return naf
|
||||||
|
}
|
||||||
|
|
|
@ -55,3 +55,30 @@ func TestMulDistributesOverAdd(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNonAdjacentForm(t *testing.T) {
|
||||||
|
s := Scalar([32]byte{
|
||||||
|
0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d,
|
||||||
|
0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, 0x26, 0x4d,
|
||||||
|
0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1,
|
||||||
|
0x58, 0x9e, 0x7b, 0x7f, 0x23, 0x76, 0xef, 0x09,
|
||||||
|
})
|
||||||
|
expectedNaf := [256]int8{
|
||||||
|
0, 13, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, -9, 0, 0, 0, 0, -11, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1,
|
||||||
|
0, 0, 0, 0, 9, 0, 0, 0, 0, -5, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 11, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0,
|
||||||
|
-9, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 9, 0,
|
||||||
|
0, 0, 0, -15, 0, 0, 0, 0, -7, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, -3, 0,
|
||||||
|
0, 0, 0, -11, 0, 0, 0, 0, -7, 0, 0, 0, 0, -13, 0, 0, 0, 0, 11, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, 1, 0, 0,
|
||||||
|
0, 0, 0, -15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 13, 0, 0, 0,
|
||||||
|
0, 0, 0, 11, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 7,
|
||||||
|
0, 0, 0, 0, 0, -15, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 15, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
sNaf := s.NonAdjacentForm(5)
|
||||||
|
|
||||||
|
for i := 0; i < 256; i++ {
|
||||||
|
if expectedNaf[i] != sNaf[i] {
|
||||||
|
t.Errorf("Wrong digit at position %d, got %d, expected %d", i, sNaf[i], expectedNaf[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue