mirror of
https://github.com/sonr-io/crypto.git
synced 2026-08-02 15:31:38 +00:00
No commit suggestions generated
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,267 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package edwards25519
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestScNegMulAddIdentity(t *testing.T) {
|
||||
one := [32]byte{1}
|
||||
var seed [64]byte
|
||||
var a, minusA, x [32]byte
|
||||
|
||||
rand.Reader.Read(seed[:])
|
||||
ScReduce(&a, &seed)
|
||||
copy(minusA[:], a[:])
|
||||
ScNeg(&minusA, &minusA)
|
||||
ScMulAdd(&x, &one, &a, &minusA)
|
||||
if x != [32]byte{} {
|
||||
t.Errorf("%x --neg--> %x --sum--> %x", a, minusA, x)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGeAddAgainstgeAdd(t *testing.T) {
|
||||
var x, y [32]byte
|
||||
rand.Reader.Read(x[:])
|
||||
rand.Reader.Read(y[:])
|
||||
var X, Y ExtendedGroupElement
|
||||
x[31] &= 127
|
||||
y[31] &= 127
|
||||
GeScalarMultBase(&X, &x)
|
||||
GeScalarMultBase(&Y, &y)
|
||||
|
||||
var SBytesRef [32]byte
|
||||
var SRef ExtendedGroupElement
|
||||
var Ycached CachedGroupElement
|
||||
var SCompletedRef CompletedGroupElement
|
||||
Y.ToCached(&Ycached)
|
||||
geAdd(&SCompletedRef, &X, &Ycached)
|
||||
SCompletedRef.ToExtended(&SRef)
|
||||
SRef.ToBytes(&SBytesRef)
|
||||
|
||||
var SBytes [32]byte
|
||||
var S ExtendedGroupElement
|
||||
GeAdd(&S, &X, &Y)
|
||||
S.ToBytes(&SBytes)
|
||||
|
||||
if SBytes != SBytesRef {
|
||||
t.Errorf("GeAdd does not match geAdd: %x != %x", SBytes, SBytesRef)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGeScalarMultAgainstDoubleScalarMult(t *testing.T) {
|
||||
var zero [32]byte
|
||||
|
||||
var x [32]byte
|
||||
rand.Reader.Read(x[:])
|
||||
var X ExtendedGroupElement
|
||||
x[31] &= 127
|
||||
GeScalarMultBase(&X, &x)
|
||||
|
||||
var a [32]byte
|
||||
rand.Reader.Read(a[:])
|
||||
a[31] &= 127
|
||||
|
||||
var ABytesRef [32]byte
|
||||
var Aref ProjectiveGroupElement
|
||||
GeDoubleScalarMultVartime(&Aref, &a, &X, &zero)
|
||||
Aref.ToBytes(&ABytesRef)
|
||||
|
||||
var ABytes [32]byte
|
||||
var A ExtendedGroupElement
|
||||
GeScalarMult(&A, &a, &X)
|
||||
A.ToBytes(&ABytes)
|
||||
|
||||
if ABytes != ABytesRef {
|
||||
t.Errorf(
|
||||
"GeScalarMult does not match GeDoubleScalarMultVartime: %x != %x",
|
||||
ABytes,
|
||||
ABytesRef,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func inc(b *[32]byte) {
|
||||
acc := uint(1)
|
||||
for i := 0; i < 32; i++ {
|
||||
acc += uint(b[i])
|
||||
acc, b[i] = uint(acc>>8), byte(acc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGeAddAgainstScalarMult(t *testing.T) {
|
||||
var x, s [32]byte
|
||||
rand.Reader.Read(x[:])
|
||||
x[31] &= 127
|
||||
var X ExtendedGroupElement
|
||||
GeScalarMultBase(&X, &x)
|
||||
var A ExtendedGroupElement
|
||||
A.Zero()
|
||||
var ABytes, ABytesMult [32]byte
|
||||
A.ToBytes(&ABytes)
|
||||
var AMult ExtendedGroupElement
|
||||
GeScalarMult(&AMult, &s, &X)
|
||||
AMult.ToBytes(&ABytesMult)
|
||||
if ABytes != ABytesMult {
|
||||
t.Errorf("addition does not match multiplication (%x) -> %x != %x", s, ABytes, ABytesMult)
|
||||
}
|
||||
|
||||
GeAdd(&A, &A, &X)
|
||||
inc(&s)
|
||||
}
|
||||
|
||||
func TestGeAddAgainstDoubleScalarMult(t *testing.T) {
|
||||
var zero, x, s [32]byte
|
||||
rand.Reader.Read(x[:])
|
||||
x[31] &= 127
|
||||
var X ExtendedGroupElement
|
||||
GeScalarMultBase(&X, &x)
|
||||
var A ExtendedGroupElement
|
||||
A.Zero()
|
||||
var ABytes, ABytesMult [32]byte
|
||||
A.ToBytes(&ABytes)
|
||||
var AMult ProjectiveGroupElement
|
||||
GeDoubleScalarMultVartime(&AMult, &s, &X, &zero)
|
||||
AMult.ToBytes(&ABytesMult)
|
||||
if ABytes != ABytesMult {
|
||||
t.Errorf("addition does not match multiplication (%x)", s)
|
||||
}
|
||||
|
||||
GeAdd(&A, &A, &X)
|
||||
inc(&s)
|
||||
}
|
||||
|
||||
func TestGeScalarMultiBaseScalarMultDH(t *testing.T) {
|
||||
var a, b [32]byte
|
||||
rand.Reader.Read(a[:])
|
||||
rand.Reader.Read(b[:])
|
||||
|
||||
var A, B ExtendedGroupElement
|
||||
a[31] &= 127
|
||||
b[31] &= 127
|
||||
GeScalarMultBase(&A, &a)
|
||||
GeScalarMultBase(&B, &b)
|
||||
|
||||
var kA, kB ExtendedGroupElement
|
||||
GeScalarMult(&kA, &a, &B)
|
||||
GeScalarMult(&kB, &b, &A)
|
||||
|
||||
var ka, kb [32]byte
|
||||
kA.ToBytes(&ka)
|
||||
kB.ToBytes(&kb)
|
||||
|
||||
if ka != kb {
|
||||
t.Fatal("DH shared secrets do not match")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGeScalarMultDH(t *testing.T) {
|
||||
var one [32]byte
|
||||
one[0] = 1
|
||||
var base ExtendedGroupElement
|
||||
GeScalarMultBase(&base, &one)
|
||||
|
||||
var a, b [32]byte
|
||||
rand.Reader.Read(a[:])
|
||||
rand.Reader.Read(b[:])
|
||||
|
||||
var A, B ExtendedGroupElement
|
||||
GeScalarMult(&A, &a, &base)
|
||||
GeScalarMult(&B, &b, &base)
|
||||
|
||||
var kA, kB ExtendedGroupElement
|
||||
GeScalarMult(&kA, &a, &B)
|
||||
GeScalarMult(&kB, &b, &A)
|
||||
|
||||
var ka, kb [32]byte
|
||||
kA.ToBytes(&ka)
|
||||
kB.ToBytes(&kb)
|
||||
|
||||
if ka != kb {
|
||||
t.Fatal("DH shared secrets do not match")
|
||||
}
|
||||
|
||||
var bytesA, bytesB [32]byte
|
||||
A.ToBytes(&bytesA)
|
||||
B.ToBytes(&bytesB)
|
||||
|
||||
if bytesA == bytesB {
|
||||
t.Fatalf("DH public key collision: g^%x = g^%x = %x", a, b, A)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGeScalarMultBase(b *testing.B) {
|
||||
var s [32]byte
|
||||
rand.Reader.Read(s[:])
|
||||
var P ExtendedGroupElement
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
GeScalarMultBase(&P, &s)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGeScalarMult(b *testing.B) {
|
||||
var s [32]byte
|
||||
rand.Reader.Read(s[:])
|
||||
|
||||
var P ExtendedGroupElement
|
||||
s[31] &= 127
|
||||
GeScalarMultBase(&P, &s)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
GeScalarMult(&P, &s, &P)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGeDoubleScalarMultVartime(b *testing.B) {
|
||||
var s [32]byte
|
||||
rand.Reader.Read(s[:])
|
||||
|
||||
var P, Pout ExtendedGroupElement
|
||||
s[31] &= 127
|
||||
GeScalarMultBase(&P, &s)
|
||||
|
||||
var out ProjectiveGroupElement
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
GeDoubleScalarMultVartime(&out, &s, &P, &[32]byte{})
|
||||
out.ToExtended(&Pout)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGeAdd(b *testing.B) {
|
||||
var s [32]byte
|
||||
rand.Reader.Read(s[:])
|
||||
|
||||
var R, P ExtendedGroupElement
|
||||
s[31] &= 127
|
||||
GeScalarMultBase(&P, &s)
|
||||
R = P
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
GeAdd(&R, &R, &P)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGeDouble(b *testing.B) {
|
||||
var s [32]byte
|
||||
rand.Reader.Read(s[:])
|
||||
|
||||
var R, P ExtendedGroupElement
|
||||
s[31] &= 127
|
||||
GeScalarMultBase(&P, &s)
|
||||
R = P
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
GeDouble(&R, &P)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,377 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package extra25519 implements fast arithmetic on the extended twisted Edwards curve.
|
||||
package extra25519
|
||||
|
||||
import (
|
||||
"crypto/sha512"
|
||||
|
||||
"github.com/sonr-io/sonr/crypto/internal/ed25519/edwards25519"
|
||||
)
|
||||
|
||||
// PrivateKeyToCurve25519 converts an ed25519 private key into a corresponding
|
||||
// curve25519 private key such that the resulting curve25519 public key will
|
||||
// equal the result from PublicKeyToCurve25519.
|
||||
func PrivateKeyToCurve25519(curve25519Private *[32]byte, privateKey *[64]byte) {
|
||||
h := sha512.New()
|
||||
h.Write(privateKey[:32])
|
||||
digest := h.Sum(nil)
|
||||
|
||||
digest[0] &= 248
|
||||
digest[31] &= 127
|
||||
digest[31] |= 64
|
||||
|
||||
copy(curve25519Private[:], digest)
|
||||
}
|
||||
|
||||
func edwardsToMontgomeryX(outX, y *edwards25519.FieldElement) {
|
||||
// We only need the x-coordinate of the curve25519 point, which I'll
|
||||
// call u. The isomorphism is u=(y+1)/(1-y), since y=Y/Z, this gives
|
||||
// u=(Y+Z)/(Z-Y). We know that Z=1, thus u=(Y+1)/(1-Y).
|
||||
var oneMinusY edwards25519.FieldElement
|
||||
edwards25519.FeOne(&oneMinusY)
|
||||
edwards25519.FeSub(&oneMinusY, &oneMinusY, y)
|
||||
edwards25519.FeInvert(&oneMinusY, &oneMinusY)
|
||||
|
||||
edwards25519.FeOne(outX)
|
||||
edwards25519.FeAdd(outX, outX, y)
|
||||
|
||||
edwards25519.FeMul(outX, outX, &oneMinusY)
|
||||
}
|
||||
|
||||
// PublicKeyToCurve25519 converts an Ed25519 public key into the curve25519
|
||||
// public key that would be generated from the same private key.
|
||||
func PublicKeyToCurve25519(curve25519Public *[32]byte, publicKey *[32]byte) bool {
|
||||
var A edwards25519.ExtendedGroupElement
|
||||
if !A.FromBytes(publicKey) {
|
||||
return false
|
||||
}
|
||||
|
||||
// A.Z = 1 as a postcondition of FromBytes.
|
||||
var x edwards25519.FieldElement
|
||||
edwardsToMontgomeryX(&x, &A.Y)
|
||||
edwards25519.FeToBytes(curve25519Public, &x)
|
||||
return true
|
||||
}
|
||||
|
||||
// sqrtMinusA is sqrt(-486662)
|
||||
var sqrtMinusA = edwards25519.FieldElement{
|
||||
12222970, 8312128, 11511410, -9067497, 15300785, 241793, -25456130, -14121551, 12187136, -3972024,
|
||||
}
|
||||
|
||||
// sqrtMinusHalf is sqrt(-1/2)
|
||||
var sqrtMinusHalf = edwards25519.FieldElement{
|
||||
-17256545, 3971863, 28865457, -1750208, 27359696, -16640980, 12573105, 1002827, -163343, 11073975,
|
||||
}
|
||||
|
||||
// halfQMinus1Bytes is (2^255-20)/2 expressed in little endian form.
|
||||
var halfQMinus1Bytes = [32]byte{
|
||||
0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f,
|
||||
}
|
||||
|
||||
// feBytesLess returns one if a <= b and zero otherwise.
|
||||
func feBytesLE(a, b *[32]byte) int32 {
|
||||
equalSoFar := int32(-1)
|
||||
greater := int32(0)
|
||||
|
||||
for i := uint(31); i < 32; i-- {
|
||||
x := int32(a[i])
|
||||
y := int32(b[i])
|
||||
|
||||
greater = (^equalSoFar & greater) | (equalSoFar & ((x - y) >> 31))
|
||||
equalSoFar = equalSoFar & (((x ^ y) - 1) >> 31)
|
||||
}
|
||||
|
||||
return int32(^equalSoFar & 1 & greater)
|
||||
}
|
||||
|
||||
// ScalarBaseMult computes a curve25519 public key from a private key and also
|
||||
// a uniform representative for that public key. Note that this function will
|
||||
// fail and return false for about half of private keys.
|
||||
// See http://elligator.cr.yp.to/elligator-20130828.pdf.
|
||||
func ScalarBaseMult(publicKey, representative, privateKey *[32]byte) bool {
|
||||
var maskedPrivateKey [32]byte
|
||||
copy(maskedPrivateKey[:], privateKey[:])
|
||||
|
||||
maskedPrivateKey[0] &= 248
|
||||
maskedPrivateKey[31] &= 127
|
||||
maskedPrivateKey[31] |= 64
|
||||
|
||||
var A edwards25519.ExtendedGroupElement
|
||||
edwards25519.GeScalarMultBase(&A, &maskedPrivateKey)
|
||||
|
||||
var inv1 edwards25519.FieldElement
|
||||
edwards25519.FeSub(&inv1, &A.Z, &A.Y)
|
||||
edwards25519.FeMul(&inv1, &inv1, &A.X)
|
||||
edwards25519.FeInvert(&inv1, &inv1)
|
||||
|
||||
var t0, u edwards25519.FieldElement
|
||||
edwards25519.FeMul(&u, &inv1, &A.X)
|
||||
edwards25519.FeAdd(&t0, &A.Y, &A.Z)
|
||||
edwards25519.FeMul(&u, &u, &t0)
|
||||
|
||||
var v edwards25519.FieldElement
|
||||
edwards25519.FeMul(&v, &t0, &inv1)
|
||||
edwards25519.FeMul(&v, &v, &A.Z)
|
||||
edwards25519.FeMul(&v, &v, &sqrtMinusA)
|
||||
|
||||
var b edwards25519.FieldElement
|
||||
edwards25519.FeAdd(&b, &u, &edwards25519.A)
|
||||
|
||||
var c, b3, b8 edwards25519.FieldElement
|
||||
edwards25519.FeSquare(&b3, &b) // 2
|
||||
edwards25519.FeMul(&b3, &b3, &b) // 3
|
||||
edwards25519.FeSquare(&c, &b3) // 6
|
||||
edwards25519.FeMul(&c, &c, &b) // 7
|
||||
edwards25519.FeMul(&b8, &c, &b) // 8
|
||||
edwards25519.FeMul(&c, &c, &u)
|
||||
q58(&c, &c)
|
||||
|
||||
var chi edwards25519.FieldElement
|
||||
edwards25519.FeSquare(&chi, &c)
|
||||
edwards25519.FeSquare(&chi, &chi)
|
||||
|
||||
edwards25519.FeSquare(&t0, &u)
|
||||
edwards25519.FeMul(&chi, &chi, &t0)
|
||||
|
||||
edwards25519.FeSquare(&t0, &b) // 2
|
||||
edwards25519.FeMul(&t0, &t0, &b) // 3
|
||||
edwards25519.FeSquare(&t0, &t0) // 6
|
||||
edwards25519.FeMul(&t0, &t0, &b) // 7
|
||||
edwards25519.FeSquare(&t0, &t0) // 14
|
||||
edwards25519.FeMul(&chi, &chi, &t0)
|
||||
edwards25519.FeNeg(&chi, &chi)
|
||||
|
||||
var chiBytes [32]byte
|
||||
edwards25519.FeToBytes(&chiBytes, &chi)
|
||||
// chi[1] is either 0 or 0xff
|
||||
if chiBytes[1] == 0xff {
|
||||
return false
|
||||
}
|
||||
|
||||
// Calculate r1 = sqrt(-u/(2*(u+A)))
|
||||
var r1 edwards25519.FieldElement
|
||||
edwards25519.FeMul(&r1, &c, &u)
|
||||
edwards25519.FeMul(&r1, &r1, &b3)
|
||||
edwards25519.FeMul(&r1, &r1, &sqrtMinusHalf)
|
||||
|
||||
var maybeSqrtM1 edwards25519.FieldElement
|
||||
edwards25519.FeSquare(&t0, &r1)
|
||||
edwards25519.FeMul(&t0, &t0, &b)
|
||||
edwards25519.FeAdd(&t0, &t0, &t0)
|
||||
edwards25519.FeAdd(&t0, &t0, &u)
|
||||
|
||||
edwards25519.FeOne(&maybeSqrtM1)
|
||||
edwards25519.FeCMove(&maybeSqrtM1, &edwards25519.SqrtM1, edwards25519.FeIsNonZero(&t0))
|
||||
edwards25519.FeMul(&r1, &r1, &maybeSqrtM1)
|
||||
|
||||
// Calculate r = sqrt(-(u+A)/(2u))
|
||||
var r edwards25519.FieldElement
|
||||
edwards25519.FeSquare(&t0, &c) // 2
|
||||
edwards25519.FeMul(&t0, &t0, &c) // 3
|
||||
edwards25519.FeSquare(&t0, &t0) // 6
|
||||
edwards25519.FeMul(&r, &t0, &c) // 7
|
||||
|
||||
edwards25519.FeSquare(&t0, &u) // 2
|
||||
edwards25519.FeMul(&t0, &t0, &u) // 3
|
||||
edwards25519.FeMul(&r, &r, &t0)
|
||||
|
||||
edwards25519.FeSquare(&t0, &b8) // 16
|
||||
edwards25519.FeMul(&t0, &t0, &b8) // 24
|
||||
edwards25519.FeMul(&t0, &t0, &b) // 25
|
||||
edwards25519.FeMul(&r, &r, &t0)
|
||||
edwards25519.FeMul(&r, &r, &sqrtMinusHalf)
|
||||
|
||||
edwards25519.FeSquare(&t0, &r)
|
||||
edwards25519.FeMul(&t0, &t0, &u)
|
||||
edwards25519.FeAdd(&t0, &t0, &t0)
|
||||
edwards25519.FeAdd(&t0, &t0, &b)
|
||||
edwards25519.FeOne(&maybeSqrtM1)
|
||||
edwards25519.FeCMove(&maybeSqrtM1, &edwards25519.SqrtM1, edwards25519.FeIsNonZero(&t0))
|
||||
edwards25519.FeMul(&r, &r, &maybeSqrtM1)
|
||||
|
||||
var vBytes [32]byte
|
||||
edwards25519.FeToBytes(&vBytes, &v)
|
||||
vInSquareRootImage := feBytesLE(&vBytes, &halfQMinus1Bytes)
|
||||
edwards25519.FeCMove(&r, &r1, vInSquareRootImage)
|
||||
|
||||
edwards25519.FeToBytes(publicKey, &u)
|
||||
edwards25519.FeToBytes(representative, &r)
|
||||
return true
|
||||
}
|
||||
|
||||
// q58 calculates out = z^((p-5)/8).
|
||||
func q58(out, z *edwards25519.FieldElement) {
|
||||
var t1, t2, t3 edwards25519.FieldElement
|
||||
var i int
|
||||
|
||||
edwards25519.FeSquare(&t1, z) // 2^1
|
||||
edwards25519.FeMul(&t1, &t1, z) // 2^1 + 2^0
|
||||
edwards25519.FeSquare(&t1, &t1) // 2^2 + 2^1
|
||||
edwards25519.FeSquare(&t2, &t1) // 2^3 + 2^2
|
||||
edwards25519.FeSquare(&t2, &t2) // 2^4 + 2^3
|
||||
edwards25519.FeMul(&t2, &t2, &t1) // 4,3,2,1
|
||||
edwards25519.FeMul(&t1, &t2, z) // 4..0
|
||||
edwards25519.FeSquare(&t2, &t1) // 5..1
|
||||
for i = 1; i < 5; i++ { // 9,8,7,6,5
|
||||
edwards25519.FeSquare(&t2, &t2)
|
||||
}
|
||||
edwards25519.FeMul(&t1, &t2, &t1) // 9,8,7,6,5,4,3,2,1,0
|
||||
edwards25519.FeSquare(&t2, &t1) // 10..1
|
||||
for i = 1; i < 10; i++ { // 19..10
|
||||
edwards25519.FeSquare(&t2, &t2)
|
||||
}
|
||||
edwards25519.FeMul(&t2, &t2, &t1) // 19..0
|
||||
edwards25519.FeSquare(&t3, &t2) // 20..1
|
||||
for i = 1; i < 20; i++ { // 39..20
|
||||
edwards25519.FeSquare(&t3, &t3)
|
||||
}
|
||||
edwards25519.FeMul(&t2, &t3, &t2) // 39..0
|
||||
edwards25519.FeSquare(&t2, &t2) // 40..1
|
||||
for i = 1; i < 10; i++ { // 49..10
|
||||
edwards25519.FeSquare(&t2, &t2)
|
||||
}
|
||||
edwards25519.FeMul(&t1, &t2, &t1) // 49..0
|
||||
edwards25519.FeSquare(&t2, &t1) // 50..1
|
||||
for i = 1; i < 50; i++ { // 99..50
|
||||
edwards25519.FeSquare(&t2, &t2)
|
||||
}
|
||||
edwards25519.FeMul(&t2, &t2, &t1) // 99..0
|
||||
edwards25519.FeSquare(&t3, &t2) // 100..1
|
||||
for i = 1; i < 100; i++ { // 199..100
|
||||
edwards25519.FeSquare(&t3, &t3)
|
||||
}
|
||||
edwards25519.FeMul(&t2, &t3, &t2) // 199..0
|
||||
edwards25519.FeSquare(&t2, &t2) // 200..1
|
||||
for i = 1; i < 50; i++ { // 249..50
|
||||
edwards25519.FeSquare(&t2, &t2)
|
||||
}
|
||||
edwards25519.FeMul(&t1, &t2, &t1) // 249..0
|
||||
edwards25519.FeSquare(&t1, &t1) // 250..1
|
||||
edwards25519.FeSquare(&t1, &t1) // 251..2
|
||||
edwards25519.FeMul(out, &t1, z) // 251..2,0
|
||||
}
|
||||
|
||||
// chi calculates out = z^((p-1)/2). The result is either 1, 0, or -1 depending
|
||||
// on whether z is a non-zero square, zero, or a non-square.
|
||||
func chi(out, z *edwards25519.FieldElement) {
|
||||
var t0, t1, t2, t3 edwards25519.FieldElement
|
||||
var i int
|
||||
|
||||
edwards25519.FeSquare(&t0, z) // 2^1
|
||||
edwards25519.FeMul(&t1, &t0, z) // 2^1 + 2^0
|
||||
edwards25519.FeSquare(&t0, &t1) // 2^2 + 2^1
|
||||
edwards25519.FeSquare(&t2, &t0) // 2^3 + 2^2
|
||||
edwards25519.FeSquare(&t2, &t2) // 4,3
|
||||
edwards25519.FeMul(&t2, &t2, &t0) // 4,3,2,1
|
||||
edwards25519.FeMul(&t1, &t2, z) // 4..0
|
||||
edwards25519.FeSquare(&t2, &t1) // 5..1
|
||||
for i = 1; i < 5; i++ { // 9,8,7,6,5
|
||||
edwards25519.FeSquare(&t2, &t2)
|
||||
}
|
||||
edwards25519.FeMul(&t1, &t2, &t1) // 9,8,7,6,5,4,3,2,1,0
|
||||
edwards25519.FeSquare(&t2, &t1) // 10..1
|
||||
for i = 1; i < 10; i++ { // 19..10
|
||||
edwards25519.FeSquare(&t2, &t2)
|
||||
}
|
||||
edwards25519.FeMul(&t2, &t2, &t1) // 19..0
|
||||
edwards25519.FeSquare(&t3, &t2) // 20..1
|
||||
for i = 1; i < 20; i++ { // 39..20
|
||||
edwards25519.FeSquare(&t3, &t3)
|
||||
}
|
||||
edwards25519.FeMul(&t2, &t3, &t2) // 39..0
|
||||
edwards25519.FeSquare(&t2, &t2) // 40..1
|
||||
for i = 1; i < 10; i++ { // 49..10
|
||||
edwards25519.FeSquare(&t2, &t2)
|
||||
}
|
||||
edwards25519.FeMul(&t1, &t2, &t1) // 49..0
|
||||
edwards25519.FeSquare(&t2, &t1) // 50..1
|
||||
for i = 1; i < 50; i++ { // 99..50
|
||||
edwards25519.FeSquare(&t2, &t2)
|
||||
}
|
||||
edwards25519.FeMul(&t2, &t2, &t1) // 99..0
|
||||
edwards25519.FeSquare(&t3, &t2) // 100..1
|
||||
for i = 1; i < 100; i++ { // 199..100
|
||||
edwards25519.FeSquare(&t3, &t3)
|
||||
}
|
||||
edwards25519.FeMul(&t2, &t3, &t2) // 199..0
|
||||
edwards25519.FeSquare(&t2, &t2) // 200..1
|
||||
for i = 1; i < 50; i++ { // 249..50
|
||||
edwards25519.FeSquare(&t2, &t2)
|
||||
}
|
||||
edwards25519.FeMul(&t1, &t2, &t1) // 249..0
|
||||
edwards25519.FeSquare(&t1, &t1) // 250..1
|
||||
for i = 1; i < 4; i++ { // 253..4
|
||||
edwards25519.FeSquare(&t1, &t1)
|
||||
}
|
||||
edwards25519.FeMul(out, &t1, &t0) // 253..4,2,1
|
||||
}
|
||||
|
||||
// RepresentativeToPublicKey converts a uniform representative value for a
|
||||
// curve25519 public key, as produced by ScalarBaseMult, to a curve25519 public
|
||||
// key.
|
||||
func RepresentativeToPublicKey(publicKey, representative *[32]byte) {
|
||||
var rr2, v edwards25519.FieldElement
|
||||
edwards25519.FeFromBytes(&rr2, representative)
|
||||
representativeToMontgomeryX(&v, &rr2)
|
||||
edwards25519.FeToBytes(publicKey, &v)
|
||||
}
|
||||
|
||||
// representativeToMontgomeryX consumes the rr2 input
|
||||
func representativeToMontgomeryX(v, rr2 *edwards25519.FieldElement) {
|
||||
var e edwards25519.FieldElement
|
||||
edwards25519.FeSquare2(rr2, rr2)
|
||||
rr2[0]++
|
||||
edwards25519.FeInvert(rr2, rr2)
|
||||
edwards25519.FeMul(v, &edwards25519.A, rr2)
|
||||
edwards25519.FeNeg(v, v)
|
||||
|
||||
var v2, v3 edwards25519.FieldElement
|
||||
edwards25519.FeSquare(&v2, v)
|
||||
edwards25519.FeMul(&v3, v, &v2)
|
||||
edwards25519.FeAdd(&e, &v3, v)
|
||||
edwards25519.FeMul(&v2, &v2, &edwards25519.A)
|
||||
edwards25519.FeAdd(&e, &v2, &e)
|
||||
chi(&e, &e)
|
||||
var eBytes [32]byte
|
||||
edwards25519.FeToBytes(&eBytes, &e)
|
||||
// eBytes[1] is either 0 (for e = 1) or 0xff (for e = -1)
|
||||
eIsMinus1 := int32(eBytes[1]) & 1
|
||||
var negV edwards25519.FieldElement
|
||||
edwards25519.FeNeg(&negV, v)
|
||||
edwards25519.FeCMove(v, &negV, eIsMinus1)
|
||||
|
||||
edwards25519.FeZero(&v2)
|
||||
edwards25519.FeCMove(&v2, &edwards25519.A, eIsMinus1)
|
||||
edwards25519.FeSub(v, v, &v2)
|
||||
}
|
||||
|
||||
func montgomeryXToEdwardsY(out, x *edwards25519.FieldElement) {
|
||||
var t, tt edwards25519.FieldElement
|
||||
edwards25519.FeOne(&t)
|
||||
edwards25519.FeAdd(&tt, x, &t) // u+1
|
||||
edwards25519.FeInvert(&tt, &tt) // 1/(u+1)
|
||||
edwards25519.FeSub(&t, x, &t) // u-1
|
||||
edwards25519.FeMul(out, &tt, &t) // (u-1)/(u+1)
|
||||
}
|
||||
|
||||
// HashToEdwards converts a 256-bit hash output into a point on the Edwards
|
||||
// curve isomorphic to Curve25519 in a manner that preserves
|
||||
// collision-resistance. The returned curve points are NOT indistinguishable
|
||||
// from random even if the hash value is.
|
||||
// Specifically, first one bit of the hash output is set aside for parity and
|
||||
// the rest is truncated and fed into the elligator bijection (which covers half
|
||||
// of the points on the elliptic curve).
|
||||
func HashToEdwards(out *edwards25519.ExtendedGroupElement, h *[32]byte) {
|
||||
hh := *h
|
||||
bit := hh[31] >> 7
|
||||
hh[31] &= 127
|
||||
edwards25519.FeFromBytes(&out.Y, &hh)
|
||||
representativeToMontgomeryX(&out.X, &out.Y)
|
||||
montgomeryXToEdwardsY(&out.Y, &out.X)
|
||||
if ok := out.FromParityAndY(bit, &out.Y); !ok {
|
||||
panic("HashToEdwards: point not on curve")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package extra25519
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"crypto/sha512"
|
||||
"testing"
|
||||
|
||||
"github.com/sonr-io/sonr/crypto/internal/ed25519/edwards25519"
|
||||
"golang.org/x/crypto/curve25519"
|
||||
"golang.org/x/crypto/ed25519"
|
||||
)
|
||||
|
||||
func TestCurve25519Conversion(t *testing.T) {
|
||||
public, private, _ := ed25519.GenerateKey(rand.Reader)
|
||||
var pubBytes [32]byte
|
||||
copy(pubBytes[:], public)
|
||||
var privBytes [64]byte
|
||||
copy(privBytes[:], private)
|
||||
|
||||
var curve25519Public, curve25519Public2, curve25519Private [32]byte
|
||||
PrivateKeyToCurve25519(&curve25519Private, &privBytes)
|
||||
curve25519.ScalarBaseMult(&curve25519Public, &curve25519Private)
|
||||
|
||||
if !PublicKeyToCurve25519(&curve25519Public2, &pubBytes) {
|
||||
t.Fatalf("PublicKeyToCurve25519 failed")
|
||||
}
|
||||
|
||||
if !bytes.Equal(curve25519Public[:], curve25519Public2[:]) {
|
||||
t.Errorf(
|
||||
"Values didn't match: curve25519 produced %x, conversion produced %x",
|
||||
curve25519Public[:],
|
||||
curve25519Public2[:],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHashNoCollisions(t *testing.T) {
|
||||
type intpair struct {
|
||||
i int
|
||||
j uint
|
||||
}
|
||||
rainbow := make(map[[32]byte]intpair)
|
||||
N := 25
|
||||
if testing.Short() {
|
||||
N = 3
|
||||
}
|
||||
var h [32]byte
|
||||
// NOTE: hash values 0b100000000000... and 0b00000000000... both map to
|
||||
// the identity. this is a core part of the elligator function and not a
|
||||
// collision we need to worry about because an attacker would need to find
|
||||
// the preimages of these hashes to exploit it.
|
||||
h[0] = 1
|
||||
for i := 0; i < N; i++ {
|
||||
for j := range uint(257) {
|
||||
if j < 256 {
|
||||
h[j>>3] ^= byte(1) << (j & 7)
|
||||
}
|
||||
|
||||
var P edwards25519.ExtendedGroupElement
|
||||
HashToEdwards(&P, &h)
|
||||
var p [32]byte
|
||||
P.ToBytes(&p)
|
||||
if c, ok := rainbow[p]; ok {
|
||||
t.Fatalf("found collision: (%d, %d) and (%d, %d)", i, j, c.i, c.j)
|
||||
}
|
||||
rainbow[p] = intpair{i, j}
|
||||
|
||||
if j < 256 {
|
||||
h[j>>3] ^= byte(1) << (j & 7)
|
||||
}
|
||||
}
|
||||
hh := sha512.Sum512(h[:]) // this package already imports sha512
|
||||
copy(h[:], hh[:])
|
||||
}
|
||||
}
|
||||
|
||||
func TestElligator(t *testing.T) {
|
||||
var publicKey, publicKey2, publicKey3, representative, privateKey [32]byte
|
||||
|
||||
for range 1000 {
|
||||
rand.Reader.Read(privateKey[:])
|
||||
|
||||
if !ScalarBaseMult(&publicKey, &representative, &privateKey) {
|
||||
continue
|
||||
}
|
||||
RepresentativeToPublicKey(&publicKey2, &representative)
|
||||
if !bytes.Equal(publicKey[:], publicKey2[:]) {
|
||||
t.Fatal("The resulting public key doesn't match the initial one.")
|
||||
}
|
||||
|
||||
curve25519.ScalarBaseMult(&publicKey3, &privateKey)
|
||||
if !bytes.Equal(publicKey[:], publicKey3[:]) {
|
||||
t.Fatal("The public key doesn't match the value that curve25519 produced.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkKeyGeneration(b *testing.B) {
|
||||
var publicKey, representative, privateKey [32]byte
|
||||
|
||||
// Find the private key that results in a point that's in the image of the map.
|
||||
for {
|
||||
rand.Reader.Read(privateKey[:])
|
||||
if ScalarBaseMult(&publicKey, &representative, &privateKey) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for b.Loop() {
|
||||
ScalarBaseMult(&publicKey, &representative, &privateKey)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMap(b *testing.B) {
|
||||
var publicKey, representative [32]byte
|
||||
rand.Reader.Read(representative[:])
|
||||
|
||||
for b.Loop() {
|
||||
RepresentativeToPublicKey(&publicKey, &representative)
|
||||
}
|
||||
}
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package internal
|
||||
|
||||
import "fmt"
|
||||
|
||||
var (
|
||||
ErrNotOnCurve = fmt.Errorf("point not on the curve")
|
||||
ErrPointsDistinctCurves = fmt.Errorf("points must be from the same curve")
|
||||
ErrZmMembership = fmt.Errorf("x ∉ Z_m")
|
||||
ErrResidueOne = fmt.Errorf("value must be 1 (mod N)")
|
||||
ErrNCannotBeZero = fmt.Errorf("n cannot be 0")
|
||||
ErrNilArguments = fmt.Errorf("arguments cannot be nil")
|
||||
ErrZeroValue = fmt.Errorf("arguments cannot be 0")
|
||||
ErrInvalidRound = fmt.Errorf("invalid round method called")
|
||||
ErrIncorrectCount = fmt.Errorf("incorrect number of inputs")
|
||||
ErrInvalidJson = fmt.Errorf("json format does not contain the necessary data")
|
||||
)
|
||||
Executable
+97
@@ -0,0 +1,97 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/crypto/hkdf"
|
||||
)
|
||||
|
||||
// Hash computes the HKDF over many values
|
||||
// iteratively such that each value is hashed separately
|
||||
// and based on preceding values
|
||||
//
|
||||
// The first value is computed as okm_0 = KDF(f || value) where
|
||||
// f is a byte slice of 32 0xFF
|
||||
// salt is zero-filled byte slice with length equal to the hash output length
|
||||
// info is the protocol name
|
||||
// okm is the 32 byte output
|
||||
//
|
||||
// The each subsequent iteration is computed by as okm_i = KDF(f_i || value || okm_{i-1})
|
||||
// where f_i = 2^b - 1 - i such that there are 0xFF bytes prior to the value.
|
||||
// f_1 changes the first byte to 0xFE, f_2 to 0xFD. The previous okm is appended to the value
|
||||
// to provide cryptographic domain separation.
|
||||
// See https://signal.org/docs/specifications/x3dh/#cryptographic-notation
|
||||
// and https://signal.org/docs/specifications/xeddsa/#hash-functions
|
||||
// for more details.
|
||||
// This uses the KDF function similar to X3DH for each `value`
|
||||
// But changes the key just like XEdDSA where the prefix bytes change by a single bit
|
||||
func Hash(info []byte, values ...[]byte) ([]byte, error) {
|
||||
// Don't accept any nil arguments
|
||||
if anyNil(values...) {
|
||||
return nil, ErrNilArguments
|
||||
}
|
||||
|
||||
salt := make([]byte, 32)
|
||||
okm := make([]byte, 32)
|
||||
f := bytes.Repeat([]byte{0xFF}, 32)
|
||||
|
||||
for _, b := range values {
|
||||
ikm := append(f, b...)
|
||||
ikm = append(ikm, okm...)
|
||||
kdf := hkdf.New(sha256.New, ikm, salt, info)
|
||||
n, err := kdf.Read(okm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n != len(okm) {
|
||||
return nil, fmt.Errorf(
|
||||
"unable to read expected number of bytes want=%v got=%v",
|
||||
len(okm),
|
||||
n,
|
||||
)
|
||||
}
|
||||
ByteSub(f)
|
||||
}
|
||||
return okm, nil
|
||||
}
|
||||
|
||||
func anyNil(values ...[]byte) bool {
|
||||
for _, x := range values {
|
||||
if x == nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ByteSub is a constant time algorithm for subtracting
|
||||
// 1 from the array as if it were a big number.
|
||||
// 0 is considered a wrap which resets to 0xFF
|
||||
func ByteSub(b []byte) {
|
||||
m := byte(1)
|
||||
for i := 0; i < len(b); i++ {
|
||||
b[i] -= m
|
||||
|
||||
// If b[i] > 0, s == 0
|
||||
// If b[i] == 0, s == 1
|
||||
// Computing IsNonZero(b[i])
|
||||
s1 := int8(b[i]) >> 7
|
||||
s2 := -int8(b[i]) >> 7
|
||||
s := byte((s1 | s2) + 1)
|
||||
|
||||
// If s == 0, don't subtract anymore
|
||||
// s == 1, continue subtracting
|
||||
m = s & m
|
||||
// If s == 0 this does nothing
|
||||
// If s == 1 reset this value to 0xFF
|
||||
b[i] |= -s
|
||||
}
|
||||
}
|
||||
Executable
+62
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestByteSub(t *testing.T) {
|
||||
f := bytes.Repeat([]byte{0xFF}, 32)
|
||||
ByteSub(f)
|
||||
require.Equal(t, f[0], byte(0xFE))
|
||||
for i := 1; i < len(f); i++ {
|
||||
require.Equal(t, f[i], byte(0xFF))
|
||||
}
|
||||
ByteSub(f)
|
||||
require.Equal(t, f[0], byte(0xFD))
|
||||
for i := 1; i < len(f); i++ {
|
||||
require.Equal(t, f[i], byte(0xFF))
|
||||
}
|
||||
f[0] = 0x2
|
||||
ByteSub(f)
|
||||
for i := 1; i < len(f); i++ {
|
||||
require.Equal(t, f[i], byte(0xFF))
|
||||
}
|
||||
ByteSub(f)
|
||||
require.Equal(t, f[0], byte(0xFF))
|
||||
require.Equal(t, f[1], byte(0xFE))
|
||||
for i := 2; i < len(f); i++ {
|
||||
require.Equal(t, f[i], byte(0xFF))
|
||||
}
|
||||
ByteSub(f)
|
||||
require.Equal(t, f[0], byte(0xFE))
|
||||
require.Equal(t, f[1], byte(0xFE))
|
||||
for i := 2; i < len(f); i++ {
|
||||
require.Equal(t, f[i], byte(0xFF))
|
||||
}
|
||||
f[0] = 1
|
||||
f[1] = 1
|
||||
ByteSub(f)
|
||||
require.Equal(t, f[0], byte(0xFF))
|
||||
require.Equal(t, f[1], byte(0xFF))
|
||||
require.Equal(t, f[2], byte(0xFE))
|
||||
for i := 3; i < len(f); i++ {
|
||||
require.Equal(t, f[i], byte(0xFF))
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteSubAll1(t *testing.T) {
|
||||
f := bytes.Repeat([]byte{0x1}, 32)
|
||||
ByteSub(f)
|
||||
for i := 0; i < len(f); i++ {
|
||||
require.Equal(t, f[i], byte(0xFF))
|
||||
}
|
||||
}
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"math/big"
|
||||
|
||||
"filippo.io/edwards25519"
|
||||
)
|
||||
|
||||
func CalcFieldSize(curve elliptic.Curve) int {
|
||||
bits := curve.Params().BitSize
|
||||
return (bits + 7) / 8
|
||||
}
|
||||
|
||||
func ReverseScalarBytes(inBytes []byte) []byte {
|
||||
outBytes := make([]byte, len(inBytes))
|
||||
|
||||
for i, j := 0, len(inBytes)-1; j >= 0; i, j = i+1, j-1 {
|
||||
outBytes[i] = inBytes[j]
|
||||
}
|
||||
|
||||
return outBytes
|
||||
}
|
||||
|
||||
func BigInt2Ed25519Point(y *big.Int) (*edwards25519.Point, error) {
|
||||
b := y.Bytes()
|
||||
var arr [32]byte
|
||||
copy(arr[32-len(b):], b)
|
||||
return edwards25519.NewIdentityPoint().SetBytes(arr[:])
|
||||
}
|
||||
|
||||
func BigInt2Ed25519Scalar(x *big.Int) (*edwards25519.Scalar, error) {
|
||||
// big.Int is big endian; ed25519 assumes little endian encoding
|
||||
kBytes := ReverseScalarBytes(x.Bytes())
|
||||
var arr [32]byte
|
||||
copy(arr[:], kBytes)
|
||||
return edwards25519.NewScalar().SetCanonicalBytes(arr[:])
|
||||
}
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// B10 creating a big.Int from a base 10 string. panics on failure to
|
||||
// ensure zero-values aren't used in place of malformed strings.
|
||||
func B10(s string) *big.Int {
|
||||
x, ok := new(big.Int).SetString(s, 10)
|
||||
if !ok {
|
||||
panic("Couldn't derive big.Int from string")
|
||||
}
|
||||
return x
|
||||
}
|
||||
Reference in New Issue
Block a user