159 lines
3.0 KiB
Go
159 lines
3.0 KiB
Go
package chaos
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/binary"
|
|
"log"
|
|
)
|
|
|
|
// Define parameters for the Lorenz attractor.
|
|
const sigma = 10
|
|
const rho = 28
|
|
const beta = 8.0 / 3.0
|
|
|
|
// The function that represents the Lorenz system of equations.
|
|
func lorenz(x, y, z float64) (float64, float64, float64) {
|
|
dx := sigma * (y - x)
|
|
dy := x*(rho-z) - y
|
|
dz := x*y - beta*z
|
|
return dx, dy, dz
|
|
}
|
|
|
|
// The Runge-Kutta method (4th order) for a single step.
|
|
func (c *ChaosSystem) step() (float64, float64, float64) {
|
|
x := c.X
|
|
y := c.Y
|
|
z := c.Z
|
|
if c.Debug {
|
|
log.Printf("In stepping Old vals : x = %f ; y = %f ; z = %f\n", x, y, z)
|
|
}
|
|
h := c.H
|
|
k1x, k1y, k1z := lorenz(x, y, z)
|
|
k2x, k2y, k2z := lorenz(x+h*k1x/2, y+h*k1y/2, z+h*k1z/2)
|
|
k3x, k3y, k3z := lorenz(x+h*k2x/2, y+h*k2y/2, z+h*k2z/2)
|
|
k4x, k4y, k4z := lorenz(x+h*k3x, y+h*k3y, z+h*k3z)
|
|
|
|
// Combine the slopes and update the positions.
|
|
newX := x + h*(k1x+2*k2x+2*k3x+k4x)/6
|
|
newY := y + h*(k1y+2*k2y+2*k3y+k4y)/6
|
|
newZ := z + h*(k1z+2*k2z+2*k3z+k4z)/6
|
|
if c.Debug {
|
|
log.Printf("In stepping New vals : x = %f ; y = %f ; z = %f\n", newX, newY, newZ)
|
|
}
|
|
c.X = newX
|
|
c.Y = newY
|
|
c.Z = newZ
|
|
|
|
return newX, newY, newZ
|
|
}
|
|
|
|
type ChaosSystem struct {
|
|
Version int
|
|
X float64
|
|
Y float64
|
|
Z float64
|
|
H float64
|
|
Debug bool
|
|
XMult float64
|
|
YMult float64
|
|
ZMult float64
|
|
}
|
|
|
|
func CreateNewChaosSystem() *ChaosSystem {
|
|
var _c ChaosSystem
|
|
_c.Version = LATEST_VERSION
|
|
return &_c
|
|
}
|
|
|
|
func (c *ChaosSystem) Init(x, y, z, h float64) {
|
|
c.X = x
|
|
c.Y = y
|
|
c.Z = z
|
|
c.H = h
|
|
c.Debug = false
|
|
c.Version = LATEST_VERSION
|
|
}
|
|
|
|
func randomFloat64() (float64, error) {
|
|
var b [8]byte
|
|
if _, err := rand.Read(b[:]); err != nil {
|
|
return 0, err
|
|
}
|
|
return float64(binary.LittleEndian.Uint64(b[:])) / (1 << 64), nil
|
|
}
|
|
|
|
func (c *ChaosSystem) InitRandom() error {
|
|
x, err := randomFloat64()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
y, err := randomFloat64()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
z, err := randomFloat64()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
c.Init(x, y, z, 0.1)
|
|
return nil
|
|
}
|
|
|
|
func (c *ChaosSystem) Burn(h uint) {
|
|
var i uint
|
|
for i = 0; i < h; i++ {
|
|
c.step()
|
|
}
|
|
}
|
|
|
|
func (c *ChaosSystem) SetMults(xM, yM, zM float64) {
|
|
c.XMult = xM
|
|
c.YMult = yM
|
|
c.ZMult = zM
|
|
}
|
|
|
|
func (c *ChaosSystem) ToggleDebug() {
|
|
c.Debug = !c.Debug
|
|
}
|
|
|
|
func (c *ChaosSystem) getByteVal() uint8 {
|
|
var xM, yM, zM float64
|
|
if c.XMult != 0 {
|
|
xM = c.XMult
|
|
} else {
|
|
xM = 13
|
|
}
|
|
if c.YMult != 0 {
|
|
yM = c.YMult
|
|
} else {
|
|
yM = 19
|
|
}
|
|
if c.ZMult != 0 {
|
|
zM = c.ZMult
|
|
} else {
|
|
zM = 11
|
|
}
|
|
hash := func(val float64, mult float64) uint8 {
|
|
scaledVal := val * mult * mult
|
|
// Convert to an int and take the bits we're interested in
|
|
intVal := int(scaledVal * scaledVal * scaledVal)
|
|
// XOR the parts of the integer to spread out the impact
|
|
return uint8((intVal>>8)^intVal) & 0xFF
|
|
}
|
|
xVal := hash(c.X, xM)
|
|
yVal := hash(c.Y, yM)
|
|
zVal := hash(c.Z, zM)
|
|
return xVal ^ yVal ^ zVal
|
|
}
|
|
|
|
func (c *ChaosSystem) GetPassword(lenght uint) []byte {
|
|
var i uint
|
|
var ret []byte
|
|
for i = 0; i < lenght; i++ {
|
|
c.step()
|
|
ret = append(ret, c.getByteVal())
|
|
}
|
|
return ret
|
|
}
|