2026-02-13 18:53:09 +00:00
|
|
|
package returncodes
|
|
|
|
|
|
|
|
|
|
import (
|
2026-07-06 13:23:56 +00:00
|
|
|
"fmt"
|
2026-02-13 18:53:09 +00:00
|
|
|
"math/big"
|
|
|
|
|
)
|
|
|
|
|
|
2026-07-06 13:23:56 +00:00
|
|
|
// DecodeVote factorizes a vote product back into the indices of selected
|
|
|
|
|
// options. It panics if the product is not a smooth product of the encoding
|
|
|
|
|
// primes; use DecodeVoteChecked when the input may be untrusted.
|
2026-02-13 18:53:09 +00:00
|
|
|
func DecodeVote(product *big.Int, primes []*big.Int) []int {
|
2026-07-06 13:23:56 +00:00
|
|
|
selected, err := DecodeVoteChecked(product, primes)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err.Error())
|
|
|
|
|
}
|
|
|
|
|
return selected
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DecodeVoteChecked is like DecodeVote but returns an error instead of panicking
|
|
|
|
|
// when the product does not fully factor over the encoding primes (which can
|
|
|
|
|
// happen for a corrupted or malicious ciphertext once inputs are remote).
|
|
|
|
|
func DecodeVoteChecked(product *big.Int, primes []*big.Int) ([]int, error) {
|
2026-02-13 18:53:09 +00:00
|
|
|
remaining := new(big.Int).Set(product)
|
|
|
|
|
var selected []int
|
|
|
|
|
|
|
|
|
|
for idx, p := range primes {
|
|
|
|
|
for {
|
|
|
|
|
quo, rem := new(big.Int).DivMod(remaining, p, new(big.Int))
|
|
|
|
|
if rem.Sign() == 0 {
|
|
|
|
|
selected = append(selected, idx)
|
|
|
|
|
remaining = quo
|
|
|
|
|
} else {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if remaining.Cmp(big.NewInt(1)) != 0 {
|
2026-07-06 13:23:56 +00:00
|
|
|
return nil, fmt.Errorf("vote does not factor over encoding primes (remaining %s)", remaining.String())
|
2026-02-13 18:53:09 +00:00
|
|
|
}
|
2026-07-06 13:23:56 +00:00
|
|
|
return selected, nil
|
2026-02-13 18:53:09 +00:00
|
|
|
}
|