182 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			V
		
	
	
			
		
		
	
	
			182 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			V
		
	
	
| module ed25519
 | |
| 
 | |
| import crypto.rand
 | |
| import crypto.sha512
 | |
| import crypto.internal.subtle
 | |
| import crypto.ed25519.internal.edwards25519
 | |
| 
 | |
| // public_key_size is the sizeof public keys in bytes
 | |
| pub const public_key_size = 32
 | |
| 
 | |
| // private_key_size is the sizeof private keys in bytes
 | |
| pub const private_key_size = 64
 | |
| 
 | |
| // signature_size is the size of signatures generated and verified by this modules, in bytes.
 | |
| pub const signature_size = 64
 | |
| 
 | |
| // seed_size is the size of private key seeds in bytes
 | |
| pub const seed_size = 32
 | |
| 
 | |
| // `PublicKey` is Ed25519 public keys.
 | |
| pub type PublicKey = []u8
 | |
| 
 | |
| // equal reports whether p and x have the same value.
 | |
| pub fn (p PublicKey) equal(x []u8) bool {
 | |
| 	return subtle.constant_time_compare(p, PublicKey(x)) == 1
 | |
| }
 | |
| 
 | |
| // PrivateKey is Ed25519 private keys
 | |
| pub type PrivateKey = []u8
 | |
| 
 | |
| // seed returns the private key seed corresponding to priv.
 | |
| // RFC 8032's private keys correspond to seeds in this module.
 | |
| pub fn (priv PrivateKey) seed() []u8 {
 | |
| 	mut seed := []u8{len: ed25519.seed_size}
 | |
| 	copy(mut seed, priv[..32])
 | |
| 	return seed
 | |
| }
 | |
| 
 | |
| // public_key returns the []u8 corresponding to priv.
 | |
| pub fn (priv PrivateKey) public_key() PublicKey {
 | |
| 	assert priv.len == ed25519.private_key_size
 | |
| 	mut publickey := []u8{len: ed25519.public_key_size}
 | |
| 	copy(mut publickey, priv[32..])
 | |
| 	return PublicKey(publickey)
 | |
| }
 | |
| 
 | |
| // currentyly x not `crypto.PrivateKey`
 | |
| pub fn (priv PrivateKey) equal(x []u8) bool {
 | |
| 	return subtle.constant_time_compare(priv, PrivateKey(x)) == 1
 | |
| }
 | |
| 
 | |
| // sign signs the given message with priv.
 | |
| pub fn (priv PrivateKey) sign(message []u8) ?[]u8 {
 | |
| 	/*
 | |
| 	if opts.HashFunc() != crypto.Hash(0) {
 | |
| 		return nil, errors.New("ed25519: cannot sign hashed message")
 | |
| 	}*/
 | |
| 
 | |
| 	return sign(priv, message)
 | |
| }
 | |
| 
 | |
| // sign`signs the message with privatekey and returns a signature
 | |
| pub fn sign(privatekey PrivateKey, message []u8) ?[]u8 {
 | |
| 	mut signature := []u8{len: ed25519.signature_size}
 | |
| 	sign_generic(mut signature, privatekey, message) ?
 | |
| 	return signature
 | |
| }
 | |
| 
 | |
| fn sign_generic(mut signature []u8, privatekey []u8, message []u8) ? {
 | |
| 	if privatekey.len != ed25519.private_key_size {
 | |
| 		panic('ed25519: bad private key length: $privatekey.len')
 | |
| 	}
 | |
| 	seed, publickey := privatekey[..ed25519.seed_size], privatekey[ed25519.seed_size..]
 | |
| 
 | |
| 	mut h := sha512.sum512(seed)
 | |
| 	mut s := edwards25519.new_scalar()
 | |
| 	s.set_bytes_with_clamping(h[..32]) ?
 | |
| 	mut prefix := h[32..]
 | |
| 
 | |
| 	mut mh := sha512.new()
 | |
| 	mh.write(prefix) ?
 | |
| 	mh.write(message) ?
 | |
| 
 | |
| 	mut msg_digest := []u8{cap: sha512.size}
 | |
| 	msg_digest = mh.sum(msg_digest)
 | |
| 
 | |
| 	mut r := edwards25519.new_scalar()
 | |
| 	r.set_uniform_bytes(msg_digest) ?
 | |
| 
 | |
| 	mut rr := edwards25519.Point{}
 | |
| 	rr.scalar_base_mult(mut r)
 | |
| 
 | |
| 	mut kh := sha512.new()
 | |
| 	kh.write(rr.bytes()) ?
 | |
| 	kh.write(publickey) ?
 | |
| 	kh.write(message) ?
 | |
| 
 | |
| 	mut hram_digest := []u8{cap: sha512.size}
 | |
| 	hram_digest = kh.sum(hram_digest)
 | |
| 	mut k := edwards25519.new_scalar()
 | |
| 	k.set_uniform_bytes(hram_digest) ?
 | |
| 
 | |
| 	mut ss := edwards25519.new_scalar()
 | |
| 	ss.multiply_add(k, s, r)
 | |
| 
 | |
| 	copy(mut signature[..32], rr.bytes())
 | |
| 	copy(mut signature[32..], ss.bytes())
 | |
| }
 | |
| 
 | |
| // verify reports whether sig is a valid signature of message by publickey.
 | |
| pub fn verify(publickey PublicKey, message []u8, sig []u8) ?bool {
 | |
| 	if publickey.len != ed25519.public_key_size {
 | |
| 		return error('ed25519: bad public key length: $publickey.len')
 | |
| 	}
 | |
| 
 | |
| 	if sig.len != ed25519.signature_size || sig[63] & 224 != 0 {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	mut aa := edwards25519.Point{}
 | |
| 	aa.set_bytes(publickey) ?
 | |
| 
 | |
| 	mut kh := sha512.new()
 | |
| 	kh.write(sig[..32]) ?
 | |
| 	kh.write(publickey) ?
 | |
| 	kh.write(message) ?
 | |
| 
 | |
| 	mut hram_digest := []u8{cap: sha512.size}
 | |
| 	hram_digest = kh.sum(hram_digest)
 | |
| 
 | |
| 	mut k := edwards25519.new_scalar()
 | |
| 	k.set_uniform_bytes(hram_digest) ?
 | |
| 
 | |
| 	mut ss := edwards25519.new_scalar()
 | |
| 	ss.set_canonical_bytes(sig[32..]) ?
 | |
| 
 | |
| 	// [S]B = R + [k]A --> [k](-A) + [S]B = R
 | |
| 	mut minus_a := edwards25519.Point{}
 | |
| 	minus_a.negate(aa)
 | |
| 	mut rr := edwards25519.Point{}
 | |
| 	rr.vartime_double_scalar_base_mult(k, minus_a, ss)
 | |
| 
 | |
| 	return subtle.constant_time_compare(sig[..32], rr.bytes()) == 1
 | |
| }
 | |
| 
 | |
| // generate_key generates a public/private key pair entropy using `crypto.rand`.
 | |
| pub fn generate_key() ?(PublicKey, PrivateKey) {
 | |
| 	mut seed := rand.bytes(ed25519.seed_size) ?
 | |
| 
 | |
| 	privatekey := new_key_from_seed(seed)
 | |
| 	mut publickey := []u8{len: ed25519.public_key_size}
 | |
| 	copy(mut publickey, privatekey[32..])
 | |
| 
 | |
| 	return publickey, privatekey
 | |
| }
 | |
| 
 | |
| // new_key_from_seed calculates a private key from a seed. private keys of RFC 8032
 | |
| // correspond to seeds in this module
 | |
| pub fn new_key_from_seed(seed []u8) PrivateKey {
 | |
| 	// Outline the function body so that the returned key can be stack-allocated.
 | |
| 	mut privatekey := []u8{len: ed25519.private_key_size}
 | |
| 	new_key_from_seed_generic(mut privatekey, seed)
 | |
| 	return PrivateKey(privatekey)
 | |
| }
 | |
| 
 | |
| fn new_key_from_seed_generic(mut privatekey []u8, seed []u8) {
 | |
| 	if seed.len != ed25519.seed_size {
 | |
| 		panic('ed25519: bad seed length: $seed.len')
 | |
| 	}
 | |
| 
 | |
| 	mut h := sha512.sum512(seed)
 | |
| 	mut s := edwards25519.new_scalar()
 | |
| 	s.set_bytes_with_clamping(h[..32]) or { panic(err) }
 | |
| 	mut aa := edwards25519.Point{}
 | |
| 	aa.scalar_base_mult(mut s)
 | |
| 
 | |
| 	mut publickey := aa.bytes()
 | |
| 
 | |
| 	copy(mut privatekey, seed)
 | |
| 	copy(mut privatekey[32..], publickey)
 | |
| }
 |