230 lines
6.5 KiB
V
230 lines
6.5 KiB
V
module edwards25519
|
|
|
|
import sync
|
|
|
|
struct BasepointTablePrecomp {
|
|
mut:
|
|
table []AffineLookupTable
|
|
initonce sync.Once
|
|
}
|
|
|
|
// basepoint_table is a set of 32 affineLookupTables, where table i is generated
|
|
// from 256i * basepoint. It is precomputed the first time it's used.
|
|
fn basepoint_table() []AffineLookupTable {
|
|
mut bpt := &BasepointTablePrecomp{
|
|
table: []AffineLookupTable{len: 32}
|
|
initonce: sync.new_once()
|
|
}
|
|
|
|
// replaced to use do_with_param on newest sync lib
|
|
/*
|
|
bpt.initonce.do(fn [mut bpt] () {
|
|
mut p := new_generator_point()
|
|
for i := 0; i < 32; i++ {
|
|
bpt.table[i].from_p3(p)
|
|
for j := 0; j < 8; j++ {
|
|
p.add(p, p)
|
|
}
|
|
}
|
|
})*/
|
|
bpt.initonce.do_with_param(fn (mut o BasepointTablePrecomp) {
|
|
mut p := new_generator_point()
|
|
for i := 0; i < 32; i++ {
|
|
o.table[i].from_p3(p)
|
|
for j := 0; j < 8; j++ {
|
|
p.add(p, p)
|
|
}
|
|
}
|
|
}, bpt)
|
|
return bpt.table
|
|
}
|
|
|
|
// scalar_base_mult sets v = x * B, where B is the canonical generator, and
|
|
// returns v.
|
|
//
|
|
// The scalar multiplication is done in constant time.
|
|
pub fn (mut v Point) scalar_base_mult(mut x Scalar) Point {
|
|
mut bpt_table := basepoint_table()
|
|
|
|
// Write x = sum(x_i * 16^i) so x*B = sum( B*x_i*16^i )
|
|
// as described in the Ed25519 paper
|
|
//
|
|
// Group even and odd coefficients
|
|
// x*B = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B
|
|
// + x_1*16^1*B + x_3*16^3*B + ... + x_63*16^63*B
|
|
// x*B = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B
|
|
// + 16*( x_1*16^0*B + x_3*16^2*B + ... + x_63*16^62*B)
|
|
//
|
|
// We use a lookup table for each i to get x_i*16^(2*i)*B
|
|
// and do four doublings to multiply by 16.
|
|
digits := x.signed_radix16()
|
|
|
|
mut multiple := AffineCached{}
|
|
mut tmp1 := ProjectiveP1{}
|
|
mut tmp2 := ProjectiveP2{}
|
|
|
|
// Accumulate the odd components first
|
|
v.set(new_identity_point())
|
|
for i := 1; i < 64; i += 2 {
|
|
bpt_table[i / 2].select_into(mut multiple, digits[i])
|
|
tmp1.add_affine(v, multiple)
|
|
v.from_p1(tmp1)
|
|
}
|
|
|
|
// Multiply by 16
|
|
tmp2.from_p3(v) // tmp2 = v in P2 coords
|
|
tmp1.double(tmp2) // tmp1 = 2*v in P1xP1 coords
|
|
tmp2.from_p1(tmp1) // tmp2 = 2*v in P2 coords
|
|
tmp1.double(tmp2) // tmp1 = 4*v in P1xP1 coords
|
|
tmp2.from_p1(tmp1) // tmp2 = 4*v in P2 coords
|
|
tmp1.double(tmp2) // tmp1 = 8*v in P1xP1 coords
|
|
tmp2.from_p1(tmp1) // tmp2 = 8*v in P2 coords
|
|
tmp1.double(tmp2) // tmp1 = 16*v in P1xP1 coords
|
|
v.from_p1(tmp1) // now v = 16*(odd components)
|
|
|
|
// Accumulate the even components
|
|
for j := 0; j < 64; j += 2 {
|
|
bpt_table[j / 2].select_into(mut multiple, digits[j])
|
|
tmp1.add_affine(v, multiple)
|
|
v.from_p1(tmp1)
|
|
}
|
|
|
|
return v
|
|
}
|
|
|
|
// scalar_mult sets v = x * q, and returns v.
|
|
//
|
|
// The scalar multiplication is done in constant time.
|
|
pub fn (mut v Point) scalar_mult(mut x Scalar, q Point) Point {
|
|
check_initialized(q)
|
|
|
|
mut table := ProjLookupTable{}
|
|
table.from_p3(q)
|
|
|
|
// Write x = sum(x_i * 16^i)
|
|
// so x*Q = sum( Q*x_i*16^i )
|
|
// = Q*x_0 + 16*(Q*x_1 + 16*( ... + Q*x_63) ... )
|
|
// <------compute inside out---------
|
|
//
|
|
// We use the lookup table to get the x_i*Q values
|
|
// and do four doublings to compute 16*Q
|
|
digits := x.signed_radix16()
|
|
|
|
// Unwrap first loop iteration to save computing 16*identity
|
|
mut multiple := ProjectiveCached{}
|
|
mut tmp1 := ProjectiveP1{}
|
|
mut tmp2 := ProjectiveP2{}
|
|
table.select_into(mut multiple, digits[63])
|
|
|
|
v.set(new_identity_point())
|
|
tmp1.add(v, multiple) // tmp1 = x_63*Q in P1xP1 coords
|
|
for i := 62; i >= 0; i-- {
|
|
tmp2.from_p1(tmp1) // tmp2 = (prev) in P2 coords
|
|
tmp1.double(tmp2) // tmp1 = 2*(prev) in P1xP1 coords
|
|
tmp2.from_p1(tmp1) // tmp2 = 2*(prev) in P2 coords
|
|
tmp1.double(tmp2) // tmp1 = 4*(prev) in P1xP1 coords
|
|
tmp2.from_p1(tmp1) // tmp2 = 4*(prev) in P2 coords
|
|
tmp1.double(tmp2) // tmp1 = 8*(prev) in P1xP1 coords
|
|
tmp2.from_p1(tmp1) // tmp2 = 8*(prev) in P2 coords
|
|
tmp1.double(tmp2) // tmp1 = 16*(prev) in P1xP1 coords
|
|
v.from_p1(tmp1) // v = 16*(prev) in P3 coords
|
|
table.select_into(mut multiple, digits[i])
|
|
tmp1.add(v, multiple) // tmp1 = x_i*Q + 16*(prev) in P1xP1 coords
|
|
}
|
|
v.from_p1(tmp1)
|
|
return v
|
|
}
|
|
|
|
struct BasepointNaftablePrecomp {
|
|
mut:
|
|
table NafLookupTable8
|
|
initonce sync.Once
|
|
}
|
|
|
|
fn basepoint_naf_table() NafLookupTable8 {
|
|
mut bnft := &BasepointNaftablePrecomp{}
|
|
bnft.initonce.do_with_param(fn (mut o BasepointNaftablePrecomp) {
|
|
o.table.from_p3(new_generator_point())
|
|
}, bnft)
|
|
return bnft.table
|
|
}
|
|
|
|
// vartime_double_scalar_base_mult sets v = a * A + b * B, where B is the canonical
|
|
// generator, and returns v.
|
|
//
|
|
// Execution time depends on the inputs.
|
|
pub fn (mut v Point) vartime_double_scalar_base_mult(xa Scalar, aa Point, xb Scalar) Point {
|
|
check_initialized(aa)
|
|
|
|
// Similarly to the single variable-base approach, we compute
|
|
// digits and use them with a lookup table. However, because
|
|
// we are allowed to do variable-time operations, we don't
|
|
// need constant-time lookups or constant-time digit
|
|
// computations.
|
|
//
|
|
// So we use a non-adjacent form of some width w instead of
|
|
// radix 16. This is like a binary representation (one digit
|
|
// for each binary place) but we allow the digits to grow in
|
|
// magnitude up to 2^{w-1} so that the nonzero digits are as
|
|
// sparse as possible. Intuitively, this "condenses" the
|
|
// "mass" of the scalar onto sparse coefficients (meaning
|
|
// fewer additions).
|
|
|
|
mut bp_naftable := basepoint_naf_table()
|
|
mut atable := NafLookupTable5{}
|
|
atable.from_p3(aa)
|
|
// Because the basepoint is fixed, we can use a wider NAF
|
|
// corresponding to a bigger table.
|
|
mut a := xa
|
|
mut b := xb
|
|
anaf := a.non_adjacent_form(5)
|
|
bnaf := b.non_adjacent_form(8)
|
|
|
|
// Find the first nonzero coefficient.
|
|
mut i := 255
|
|
for j := i; j >= 0; j-- {
|
|
if anaf[j] != 0 || bnaf[j] != 0 {
|
|
break
|
|
}
|
|
}
|
|
|
|
mut multa := ProjectiveCached{}
|
|
mut multb := AffineCached{}
|
|
mut tmp1 := ProjectiveP1{}
|
|
mut tmp2 := ProjectiveP2{}
|
|
tmp2.zero()
|
|
|
|
// Move from high to low bits, doubling the accumulator
|
|
// at each iteration and checking whether there is a nonzero
|
|
// coefficient to look up a multiple of.
|
|
for ; i >= 0; i-- {
|
|
tmp1.double(tmp2)
|
|
|
|
// Only update v if we have a nonzero coeff to add in.
|
|
if anaf[i] > 0 {
|
|
v.from_p1(tmp1)
|
|
atable.select_into(mut multa, anaf[i])
|
|
tmp1.add(v, multa)
|
|
} else if anaf[i] < 0 {
|
|
v.from_p1(tmp1)
|
|
atable.select_into(mut multa, -anaf[i])
|
|
tmp1.sub(v, multa)
|
|
}
|
|
|
|
if bnaf[i] > 0 {
|
|
v.from_p1(tmp1)
|
|
bp_naftable.select_into(mut multb, bnaf[i])
|
|
tmp1.add_affine(v, multb)
|
|
} else if bnaf[i] < 0 {
|
|
v.from_p1(tmp1)
|
|
bp_naftable.select_into(mut multb, -bnaf[i])
|
|
tmp1.sub_affine(v, multb)
|
|
}
|
|
|
|
tmp2.from_p1(tmp1)
|
|
}
|
|
|
|
v.from_p2(tmp2)
|
|
return v
|
|
}
|