* clear

* feat: Add everything

* fix: Commenht
This commit is contained in:
Prad Nukala
2025-10-03 14:45:52 -04:00
committed by GitHub
parent 43b4a11c06
commit 13e6c3e84d
1935 changed files with 655061 additions and 40058 deletions
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)
}
}
+22
View File
@@ -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")
)
+97
View File
@@ -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
}
}
+62
View File
@@ -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))
}
}
+44
View File
@@ -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[:])
}
+21
View File
@@ -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
}